channels/cliprdr: start server-side implementation

This commit is contained in:
Marc-André Moreau 2013-08-16 16:46:47 -04:00
parent 1d3cf89cbc
commit 0fd705c6c7
18 changed files with 383 additions and 20 deletions

View File

@ -21,3 +21,6 @@ if(WITH_CLIENT_CHANNELS)
add_channel_client(${MODULE_PREFIX} ${CHANNEL_NAME}) add_channel_client(${MODULE_PREFIX} ${CHANNEL_NAME})
endif() endif()
if(WITH_SERVER_CHANNELS)
add_channel_server(${MODULE_PREFIX} ${CHANNEL_NAME})
endif()

View File

@ -1,7 +1,7 @@
set(OPTION_DEFAULT OFF) set(OPTION_DEFAULT OFF)
set(OPTION_CLIENT_DEFAULT ON) set(OPTION_CLIENT_DEFAULT ON)
set(OPTION_SERVER_DEFAULT OFF) set(OPTION_SERVER_DEFAULT ON)
define_channel_options(NAME "cliprdr" TYPE "static" define_channel_options(NAME "cliprdr" TYPE "static"
DESCRIPTION "Clipboard Virtual Channel Extension" DESCRIPTION "Clipboard Virtual Channel Extension"

View File

@ -0,0 +1,35 @@
# FreeRDP: A Remote Desktop Protocol Implementation
# FreeRDP cmake build script
#
# Copyright 2012 Marc-Andre Moreau <marcandre.moreau@gmail.com>
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
define_channel_server("cliprdr")
set(${MODULE_PREFIX}_SRCS
cliprdr_main.c
cliprdr_main.h)
add_channel_server_library(${MODULE_PREFIX} ${MODULE_NAME} ${CHANNEL_NAME} FALSE "VirtualChannelEntry")
set_target_properties(${MODULE_NAME} PROPERTIES PREFIX "")
set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS
MONOLITHIC ${MONOLITHIC_BUILD}
MODULE freerdp
MODULES freerdp-utils)
target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS})
set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "Channels/${CHANNEL_NAME}/Server")

View File

@ -0,0 +1,184 @@
/**
* FreeRDP: A Remote Desktop Protocol Implementation
* Clipboard Virtual Channel Extension
*
* Copyright 2013 Marc-Andre Moreau <marcandre.moreau@gmail.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <winpr/crt.h>
#include <winpr/stream.h>
#include "cliprdr_main.h"
/**
* Initialization Sequence\n
* Client Server\n
* | |\n
* |<----------------------Server Clipboard Capabilities PDU-----------------|\n
* |<-----------------------------Monitor Ready PDU--------------------------|\n
* |-----------------------Client Clipboard Capabilities PDU---------------->|\n
* |---------------------------Temporary Directory PDU---------------------->|\n
* |-------------------------------Format List PDU-------------------------->|\n
* |<--------------------------Format List Response PDU----------------------|\n
*
*/
static int cliprdr_server_send_capabilities(CliprdrServerContext* context)
{
return 0;
}
static int cliprdr_server_send_monitor_ready(CliprdrServerContext* context)
{
return 0;
}
static int cliprdr_server_send_format_list_response(CliprdrServerContext* context)
{
return 0;
}
static void* cliprdr_server_thread(void* arg)
{
wStream* s;
DWORD status;
DWORD nCount;
void* buffer;
HANDLE events[8];
HANDLE ChannelEvent;
UINT32 BytesReturned;
CliprdrServerContext* context;
context = (CliprdrServerContext*) arg;
buffer = NULL;
BytesReturned = 0;
ChannelEvent = NULL;
s = Stream_New(NULL, 4096);
if (WTSVirtualChannelQuery(context->priv->ChannelHandle, WTSVirtualEventHandle, &buffer, &BytesReturned) == TRUE)
{
if (BytesReturned == sizeof(HANDLE))
CopyMemory(&ChannelEvent, buffer, sizeof(HANDLE));
WTSFreeMemory(buffer);
}
nCount = 0;
events[nCount++] = ChannelEvent;
events[nCount++] = context->priv->StopEvent;
while (1)
{
status = WaitForMultipleObjects(nCount, events, FALSE, INFINITE);
if (WaitForSingleObject(context->priv->StopEvent, 0) == WAIT_OBJECT_0)
{
break;
}
if (WTSVirtualChannelRead(context->priv->ChannelHandle, 0,
Stream_Buffer(s), Stream_Capacity(s), &BytesReturned) == FALSE)
{
if (BytesReturned == 0)
break;
Stream_EnsureRemainingCapacity(s, (int) BytesReturned);
if (WTSVirtualChannelRead(context->priv->ChannelHandle, 0,
Stream_Buffer(s), Stream_Capacity(s), &BytesReturned) == FALSE)
{
break;
}
}
}
Stream_Free(s, TRUE);
return NULL;
}
static int cliprdr_server_start(CliprdrServerContext* context)
{
context->priv->ChannelHandle = WTSVirtualChannelOpenEx(context->vcm, "cliprdr", 0);
if (!context->priv->ChannelHandle)
return -1;
context->priv->StopEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
context->priv->Thread = CreateThread(NULL, 0,
(LPTHREAD_START_ROUTINE) cliprdr_server_thread, (void*) context, 0, NULL);
return 0;
}
static int cliprdr_server_stop(CliprdrServerContext* context)
{
SetEvent(context->priv->StopEvent);
WaitForSingleObject(context->priv->Thread, INFINITE);
CloseHandle(context->priv->Thread);
return 0;
}
CliprdrServerContext* cliprdr_server_context_new(WTSVirtualChannelManager* vcm)
{
CliprdrServerContext* context;
context = (CliprdrServerContext*) malloc(sizeof(CliprdrServerContext));
if (context)
{
ZeroMemory(context, sizeof(CliprdrServerContext));
context->vcm = vcm;
context->Start = cliprdr_server_start;
context->Stop = cliprdr_server_stop;
context->SendCapabilities = cliprdr_server_send_capabilities;
context->SendMonitorReady = cliprdr_server_send_monitor_ready;
context->SendFormatListResponse = cliprdr_server_send_format_list_response;
context->priv = (CliprdrServerPrivate*) malloc(sizeof(CliprdrServerPrivate));
if (context->priv)
{
ZeroMemory(context->priv, sizeof(CliprdrServerPrivate));
}
}
return context;
}
void cliprdr_server_context_free(CliprdrServerContext* context)
{
if (context)
{
if (context->priv)
{
free(context->priv);
}
free(context);
}
}

View File

@ -0,0 +1,36 @@
/**
* FreeRDP: A Remote Desktop Protocol Implementation
* Clipboard Virtual Channel Extension
*
* Copyright 2013 Marc-Andre Moreau <marcandre.moreau@gmail.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef FREERDP_CHANNEL_SERVER_CLIPRDR_MAIN_H
#define FREERDP_CHANNEL_SERVER_CLIPRDR_MAIN_H
#include <winpr/crt.h>
#include <winpr/synch.h>
#include <winpr/thread.h>
#include <freerdp/server/cliprdr.h>
struct _cliprdr_server_private
{
HANDLE Thread;
HANDLE StopEvent;
void* ChannelHandle;
};
#endif /* FREERDP_CHANNEL_SERVER_CLIPRDR_MAIN_H */

View File

@ -42,6 +42,7 @@
#include <freerdp/server/audin.h> #include <freerdp/server/audin.h>
#include <freerdp/server/rdpsnd.h> #include <freerdp/server/rdpsnd.h>
#include <freerdp/server/cliprdr.h>
void freerdp_channels_dummy() void freerdp_channels_dummy()
{ {
@ -50,6 +51,9 @@ void freerdp_channels_dummy()
rdpsnd_server_context_new(NULL); rdpsnd_server_context_new(NULL);
rdpsnd_server_context_free(NULL); rdpsnd_server_context_free(NULL);
cliprdr_server_context_new(NULL);
cliprdr_server_context_free(NULL);
} }
/** /**
@ -420,7 +424,7 @@ WTSVirtualChannelManager* WTSCreateVirtualChannelManager(freerdp_peer* client)
vcm = (WTSVirtualChannelManager*) malloc(sizeof(WTSVirtualChannelManager)); vcm = (WTSVirtualChannelManager*) malloc(sizeof(WTSVirtualChannelManager));
if (vcm != NULL) if (vcm)
{ {
ZeroMemory(vcm, sizeof(WTSVirtualChannelManager)); ZeroMemory(vcm, sizeof(WTSVirtualChannelManager));
@ -659,6 +663,7 @@ BOOL WTSVirtualChannelQuery(
BOOL result = FALSE; BOOL result = FALSE;
rdpPeerChannel* channel = (rdpPeerChannel*) hChannelHandle; rdpPeerChannel* channel = (rdpPeerChannel*) hChannelHandle;
ZeroMemory(fds, sizeof(fds)); ZeroMemory(fds, sizeof(fds));
switch (WtsVirtualClass) switch (WtsVirtualClass)
{ {
case WTSVirtualFileHandle: case WTSVirtualFileHandle:
@ -677,6 +682,13 @@ BOOL WTSVirtualChannelQuery(
result = TRUE; result = TRUE;
break; break;
case WTSVirtualEventHandle:
*ppBuffer = malloc(sizeof(HANDLE));
CopyMemory(*ppBuffer, &(channel->receive_event), sizeof(HANDLE));
*pBytesReturned = sizeof(void*);
result = TRUE;
break;
case WTSVirtualChannelReady: case WTSVirtualChannelReady:
if (channel->channel_type == RDP_PEER_CHANNEL_TYPE_SVC) if (channel->channel_type == RDP_PEER_CHANNEL_TYPE_SVC)
{ {

View File

@ -371,7 +371,7 @@ BOOL wf_post_connect(freerdp* instance)
if (settings->RemoteFxCodec) if (settings->RemoteFxCodec)
{ {
wfc->tile = wf_image_new(wfc, 64, 64, 32, NULL); wfc->tile = wf_image_new(wfc, 64, 64, 32, NULL);
wfc->rfx_context = rfx_context_new(); wfc->rfx_context = rfx_context_new(FALSE);
} }
if (settings->NSCodec) if (settings->NSCodec)

View File

@ -893,7 +893,7 @@ BOOL xf_post_connect(freerdp* instance)
if (instance->settings->RemoteFxCodec) if (instance->settings->RemoteFxCodec)
{ {
rfx_context = (void*) rfx_context_new(); rfx_context = (void*) rfx_context_new(FALSE);
xfc->rfx_context = rfx_context; xfc->rfx_context = rfx_context;
} }

View File

@ -43,6 +43,7 @@ typedef enum _WTS_VIRTUAL_CLASS
{ {
WTSVirtualClientData, WTSVirtualClientData,
WTSVirtualFileHandle, WTSVirtualFileHandle,
WTSVirtualEventHandle,
WTSVirtualChannelReady WTSVirtualChannelReady
} WTS_VIRTUAL_CLASS; } WTS_VIRTUAL_CLASS;

View File

@ -20,6 +20,8 @@
#ifndef FREERDP_CHANNEL_CLIENT_CLIPRDR_H #ifndef FREERDP_CHANNEL_CLIENT_CLIPRDR_H
#define FREERDP_CHANNEL_CLIENT_CLIPRDR_H #define FREERDP_CHANNEL_CLIENT_CLIPRDR_H
#include <freerdp/types.h>
/** /**
* Client Interface * Client Interface
*/ */

View File

@ -55,7 +55,6 @@ struct _RFX_TILE
int height; int height;
BYTE* data; BYTE* data;
int scanline; int scanline;
BYTE quantIdxY; BYTE quantIdxY;
BYTE quantIdxCb; BYTE quantIdxCb;
BYTE quantIdxCr; BYTE quantIdxCr;
@ -117,6 +116,7 @@ struct _RFX_CONTEXT
{ {
RFX_STATE state; RFX_STATE state;
BOOL encoder;
UINT16 flags; UINT16 flags;
UINT16 properties; UINT16 properties;
UINT16 width; UINT16 width;
@ -152,7 +152,7 @@ struct _RFX_CONTEXT
}; };
typedef struct _RFX_CONTEXT RFX_CONTEXT; typedef struct _RFX_CONTEXT RFX_CONTEXT;
FREERDP_API RFX_CONTEXT* rfx_context_new(void); FREERDP_API RFX_CONTEXT* rfx_context_new(BOOL encoder);
FREERDP_API void rfx_context_free(RFX_CONTEXT* context); FREERDP_API void rfx_context_free(RFX_CONTEXT* context);
FREERDP_API void rfx_context_set_pixel_format(RFX_CONTEXT* context, RDP_PIXEL_FORMAT pixel_format); FREERDP_API void rfx_context_set_pixel_format(RFX_CONTEXT* context, RDP_PIXEL_FORMAT pixel_format);
FREERDP_API void rfx_context_reset(RFX_CONTEXT* context); FREERDP_API void rfx_context_reset(RFX_CONTEXT* context);

View File

@ -0,0 +1,59 @@
/**
* FreeRDP: A Remote Desktop Protocol Implementation
* Clipboard Virtual Channel Server Interface
*
* Copyright 2013 Marc-Andre Moreau <marcandre.moreau@gmail.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef FREERDP_CHANNEL_SERVER_CLIPRDR_H
#define FREERDP_CHANNEL_SERVER_CLIPRDR_H
#include <freerdp/api.h>
#include <freerdp/types.h>
#include <freerdp/channels/wtsvc.h>
#include <freerdp/client/cliprdr.h>
/**
* Server Interface
*/
typedef struct _cliprdr_server_context CliprdrServerContext;
typedef struct _cliprdr_server_private CliprdrServerPrivate;
typedef int (*psCliprdrStart)(CliprdrServerContext* context);
typedef int (*psCliprdrStop)(CliprdrServerContext* context);
typedef int (*psCliprdrSendCapabilities)(CliprdrServerContext* context);
typedef int (*psCliprdrSendMonitorReady)(CliprdrServerContext* context);
typedef int (*psCliprdrSendFormatListResponse)(CliprdrServerContext* context);
struct _cliprdr_server_context
{
WTSVirtualChannelManager* vcm;
psCliprdrStart Start;
psCliprdrStop Stop;
psCliprdrSendCapabilities SendCapabilities;
psCliprdrSendMonitorReady SendMonitorReady;
psCliprdrSendFormatListResponse SendFormatListResponse;
CliprdrServerPrivate* priv;
};
FREERDP_API CliprdrServerContext* cliprdr_server_context_new(WTSVirtualChannelManager* vcm);
FREERDP_API void cliprdr_server_context_free(CliprdrServerContext* context);
#endif /* FREERDP_CHANNEL_SERVER_CLIPRDR_H */

View File

@ -153,7 +153,7 @@ void rfx_tile_init(RFX_TILE* tile)
} }
} }
RFX_TILE* rfx_tile_new() RFX_TILE* rfx_decoder_tile_new()
{ {
RFX_TILE* tile = NULL; RFX_TILE* tile = NULL;
@ -169,7 +169,7 @@ RFX_TILE* rfx_tile_new()
return tile; return tile;
} }
void rfx_tile_free(RFX_TILE* tile) void rfx_decoder_tile_free(RFX_TILE* tile)
{ {
if (tile) if (tile)
{ {
@ -178,7 +178,29 @@ void rfx_tile_free(RFX_TILE* tile)
} }
} }
RFX_CONTEXT* rfx_context_new(void) RFX_TILE* rfx_encoder_tile_new()
{
RFX_TILE* tile = NULL;
tile = (RFX_TILE*) malloc(sizeof(RFX_TILE));
if (tile)
{
ZeroMemory(tile, sizeof(RFX_TILE));
}
return tile;
}
void rfx_encoder_tile_free(RFX_TILE* tile)
{
if (tile)
{
free(tile);
}
}
RFX_CONTEXT* rfx_context_new(BOOL encoder)
{ {
HKEY hKey; HKEY hKey;
LONG status; LONG status;
@ -191,13 +213,24 @@ RFX_CONTEXT* rfx_context_new(void)
context = (RFX_CONTEXT*) malloc(sizeof(RFX_CONTEXT)); context = (RFX_CONTEXT*) malloc(sizeof(RFX_CONTEXT));
ZeroMemory(context, sizeof(RFX_CONTEXT)); ZeroMemory(context, sizeof(RFX_CONTEXT));
context->encoder = encoder;
context->priv = (RFX_CONTEXT_PRIV*) malloc(sizeof(RFX_CONTEXT_PRIV)); context->priv = (RFX_CONTEXT_PRIV*) malloc(sizeof(RFX_CONTEXT_PRIV));
ZeroMemory(context->priv, sizeof(RFX_CONTEXT_PRIV)); ZeroMemory(context->priv, sizeof(RFX_CONTEXT_PRIV));
context->priv->TilePool = ObjectPool_New(TRUE); context->priv->TilePool = ObjectPool_New(TRUE);
ObjectPool_Object(context->priv->TilePool)->fnObjectNew = (OBJECT_NEW_FN) rfx_tile_new;
ObjectPool_Object(context->priv->TilePool)->fnObjectInit = (OBJECT_INIT_FN) rfx_tile_init; ObjectPool_Object(context->priv->TilePool)->fnObjectInit = (OBJECT_INIT_FN) rfx_tile_init;
ObjectPool_Object(context->priv->TilePool)->fnObjectFree = (OBJECT_FREE_FN) rfx_tile_free;
if (context->encoder)
{
ObjectPool_Object(context->priv->TilePool)->fnObjectNew = (OBJECT_NEW_FN) rfx_encoder_tile_new;
ObjectPool_Object(context->priv->TilePool)->fnObjectFree = (OBJECT_FREE_FN) rfx_encoder_tile_free;
}
else
{
ObjectPool_Object(context->priv->TilePool)->fnObjectNew = (OBJECT_NEW_FN) rfx_decoder_tile_new;
ObjectPool_Object(context->priv->TilePool)->fnObjectFree = (OBJECT_FREE_FN) rfx_decoder_tile_free;
}
/* /*
* align buffers to 16 byte boundary (needed for SSE/NEON instructions) * align buffers to 16 byte boundary (needed for SSE/NEON instructions)
@ -1065,7 +1098,8 @@ RFX_MESSAGE* rfx_encode_message(RFX_CONTEXT* context, const RFX_RECT* rects,
if (!context->numQuant) if (!context->numQuant)
{ {
context->numQuant = 1; context->numQuant = 1;
context->quants = (UINT32*) rfx_default_quantization_values; context->quants = (UINT32*) malloc(sizeof(rfx_default_quantization_values));
CopyMemory(context->quants, &rfx_default_quantization_values, sizeof(rfx_default_quantization_values));
context->quantIdxY = 0; context->quantIdxY = 0;
context->quantIdxCb = 0; context->quantIdxCb = 0;
context->quantIdxCr = 0; context->quantIdxCr = 0;
@ -1225,9 +1259,6 @@ RFX_MESSAGE* rfx_encode_messages(RFX_CONTEXT* context, const RFX_RECT* rects, in
RFX_MESSAGE* message; RFX_MESSAGE* message;
RFX_MESSAGE* messages; RFX_MESSAGE* messages;
printf("rfx_encode_messages: numRects: %d maxDataSize: %d x: %d y: %d w: %d/%d h: %d/%d\n", numRects, maxDataSize,
rects[0].x, rects[0].y, rects[0].width, width, rects[0].height, height);
message = rfx_encode_message(context, rects, numRects, data, width, height, scanline); message = rfx_encode_message(context, rects, numRects, data, width, height, scanline);
messages = rfx_split_message(context, message, numMessages, maxDataSize); messages = rfx_split_message(context, message, numMessages, maxDataSize);
rfx_message_free(context, message); rfx_message_free(context, message);

View File

@ -1042,7 +1042,7 @@ int gdi_init(freerdp* instance, UINT32 flags, BYTE* buffer)
gdi_register_graphics(instance->context->graphics); gdi_register_graphics(instance->context->graphics);
gdi->rfx_context = rfx_context_new(); gdi->rfx_context = rfx_context_new(FALSE);
gdi->nsc_context = nsc_context_new(); gdi->nsc_context = nsc_context_new();
return 0; return 0;

View File

@ -175,7 +175,7 @@ void mf_peer_rfx_update(freerdp_peer* client)
int mf_peer_context_new(freerdp_peer* client, mfPeerContext* context) int mf_peer_context_new(freerdp_peer* client, mfPeerContext* context)
{ {
context->info = mf_info_get_instance(); context->info = mf_info_get_instance();
context->rfx_context = rfx_context_new(); context->rfx_context = rfx_context_new(TRUE);
context->rfx_context->mode = RLGR3; context->rfx_context->mode = RLGR3;
context->rfx_context->width = client->settings->DesktopWidth; context->rfx_context->width = client->settings->DesktopWidth;
context->rfx_context->height = client->settings->DesktopHeight; context->rfx_context->height = client->settings->DesktopHeight;

View File

@ -49,7 +49,7 @@ static BOOL test_dump_rfx_realtime = TRUE;
void test_peer_context_new(freerdp_peer* client, testPeerContext* context) void test_peer_context_new(freerdp_peer* client, testPeerContext* context)
{ {
context->rfx_context = rfx_context_new(); context->rfx_context = rfx_context_new(TRUE);
context->rfx_context->mode = RLGR3; context->rfx_context->mode = RLGR3;
context->rfx_context->width = SAMPLE_SERVER_DEFAULT_WIDTH; context->rfx_context->width = SAMPLE_SERVER_DEFAULT_WIDTH;
context->rfx_context->height = SAMPLE_SERVER_DEFAULT_HEIGHT; context->rfx_context->height = SAMPLE_SERVER_DEFAULT_HEIGHT;

View File

@ -198,7 +198,7 @@ void wf_update_encoder_reset(wfInfo* wfi)
} }
else else
{ {
wfi->rfx_context = rfx_context_new(); wfi->rfx_context = rfx_context_new(TRUE);
wfi->rfx_context->mode = RLGR3; wfi->rfx_context->mode = RLGR3;
wfi->rfx_context->width = wfi->servscreen_width; wfi->rfx_context->width = wfi->servscreen_width;
wfi->rfx_context->height = wfi->servscreen_height; wfi->rfx_context->height = wfi->servscreen_height;

View File

@ -295,7 +295,7 @@ xfInfo* xf_info_init()
void xf_peer_context_new(freerdp_peer* client, xfPeerContext* context) void xf_peer_context_new(freerdp_peer* client, xfPeerContext* context)
{ {
context->info = xf_info_init(); context->info = xf_info_init();
context->rfx_context = rfx_context_new(); context->rfx_context = rfx_context_new(TRUE);
context->rfx_context->mode = RLGR3; context->rfx_context->mode = RLGR3;
context->rfx_context->width = context->info->width; context->rfx_context->width = context->info->width;
context->rfx_context->height = context->info->height; context->rfx_context->height = context->info->height;