Fix remoteFx encoder with topleft and bottomright rectangle

This patch fixes the case where with a topleft and a bottomright
rectangle, the encoder would send the full screen instead of only the
intersected tiles.
This commit is contained in:
Hardening 2014-02-04 12:02:55 +01:00
parent d1e75efb8c
commit 2d16d929b6
2 changed files with 316 additions and 169 deletions

View File

@ -39,6 +39,7 @@
#include <freerdp/codec/rfx.h> #include <freerdp/codec/rfx.h>
#include <freerdp/constants.h> #include <freerdp/constants.h>
#include <freerdp/primitives.h> #include <freerdp/primitives.h>
#include <freerdp/utils/region.h>
#include "rfx_constants.h" #include "rfx_constants.h"
#include "rfx_types.h" #include "rfx_types.h"
@ -51,6 +52,15 @@
#include "rfx_sse2.h" #include "rfx_sse2.h"
#include "rfx_neon.h" #include "rfx_neon.h"
void *zmalloc(int size) {
void *ret;
ret = malloc(size);
if (ret)
ZeroMemory(ret, size);
return ret;
}
#ifndef RFX_INIT_SIMD #ifndef RFX_INIT_SIMD
#define RFX_INIT_SIMD(_rfx_context) do { } while (0) #define RFX_INIT_SIMD(_rfx_context) do { } while (0)
#endif #endif
@ -183,24 +193,13 @@ void rfx_decoder_tile_free(RFX_TILE* tile)
RFX_TILE* rfx_encoder_tile_new() RFX_TILE* rfx_encoder_tile_new()
{ {
RFX_TILE* tile = NULL; return (RFX_TILE *)zmalloc( sizeof(RFX_TILE) );
tile = (RFX_TILE*) malloc(sizeof(RFX_TILE));
if (tile)
{
ZeroMemory(tile, sizeof(RFX_TILE));
}
return tile;
} }
void rfx_encoder_tile_free(RFX_TILE* tile) void rfx_encoder_tile_free(RFX_TILE* tile)
{ {
if (tile) if (tile)
{
free(tile); free(tile);
}
} }
RFX_CONTEXT* rfx_context_new(BOOL encoder) RFX_CONTEXT* rfx_context_new(BOOL encoder)
@ -212,36 +211,42 @@ RFX_CONTEXT* rfx_context_new(BOOL encoder)
DWORD dwValue; DWORD dwValue;
SYSTEM_INFO sysinfo; SYSTEM_INFO sysinfo;
RFX_CONTEXT* context; RFX_CONTEXT* context;
wObject *pool;
RFX_CONTEXT_PRIV *priv;
context = (RFX_CONTEXT*) malloc(sizeof(RFX_CONTEXT)); context = (RFX_CONTEXT*) zmalloc(sizeof(RFX_CONTEXT));
ZeroMemory(context, sizeof(RFX_CONTEXT)); if (!context)
return NULL;
context->encoder = encoder; context->encoder = encoder;
context->priv = priv = (RFX_CONTEXT_PRIV *)zmalloc( sizeof(RFX_CONTEXT_PRIV) );
context->priv = (RFX_CONTEXT_PRIV*) malloc(sizeof(RFX_CONTEXT_PRIV)); if (!priv)
ZeroMemory(context->priv, sizeof(RFX_CONTEXT_PRIV)); goto error_priv;
WLog_Init(); WLog_Init();
context->priv->log = WLog_Get("com.freerdp.codec.rfx"); priv->log = WLog_Get("com.freerdp.codec.rfx");
WLog_OpenAppender(context->priv->log); WLog_OpenAppender(priv->log);
#ifdef WITH_DEBUG_RFX #ifdef WITH_DEBUG_RFX
WLog_SetLogLevel(context->priv->log, WLOG_DEBUG); WLog_SetLogLevel(priv->log, WLOG_DEBUG);
#endif #endif
context->priv->TilePool = ObjectPool_New(TRUE); priv->TilePool = ObjectPool_New(TRUE);
ObjectPool_Object(context->priv->TilePool)->fnObjectInit = (OBJECT_INIT_FN) rfx_tile_init; if (!priv->TilePool)
goto error_tilePool;
pool = ObjectPool_Object(priv->TilePool);
pool->fnObjectInit = (OBJECT_INIT_FN) rfx_tile_init;
if (context->encoder) if (context->encoder)
{ {
ObjectPool_Object(context->priv->TilePool)->fnObjectNew = (OBJECT_NEW_FN) rfx_encoder_tile_new; pool->fnObjectNew = (OBJECT_NEW_FN) rfx_encoder_tile_new;
ObjectPool_Object(context->priv->TilePool)->fnObjectFree = (OBJECT_FREE_FN) rfx_encoder_tile_free; pool->fnObjectFree = (OBJECT_FREE_FN) rfx_encoder_tile_free;
} }
else else
{ {
ObjectPool_Object(context->priv->TilePool)->fnObjectNew = (OBJECT_NEW_FN) rfx_decoder_tile_new; pool->fnObjectNew = (OBJECT_NEW_FN) rfx_decoder_tile_new;
ObjectPool_Object(context->priv->TilePool)->fnObjectFree = (OBJECT_FREE_FN) rfx_decoder_tile_free; pool->fnObjectFree = (OBJECT_FREE_FN) rfx_decoder_tile_free;
} }
/* /*
@ -258,7 +263,9 @@ RFX_CONTEXT* rfx_context_new(BOOL encoder)
* We then multiply by 3 to use a single, partioned buffer for all 3 channels. * We then multiply by 3 to use a single, partioned buffer for all 3 channels.
*/ */
context->priv->BufferPool = BufferPool_New(TRUE, (8192 + 32) * 3, 16); priv->BufferPool = BufferPool_New(TRUE, (8192 + 32) * 3, 16);
if (!priv->BufferPool)
goto error_BufferPool;
#ifdef _WIN32 #ifdef _WIN32
{ {
@ -271,16 +278,16 @@ RFX_CONTEXT* rfx_context_new(BOOL encoder)
GetVersionExA(&verinfo); GetVersionExA(&verinfo);
isVistaOrLater = ((verinfo.dwMajorVersion >= 6) && (verinfo.dwMinorVersion >= 0)) ? TRUE : FALSE; isVistaOrLater = ((verinfo.dwMajorVersion >= 6) && (verinfo.dwMinorVersion >= 0)) ? TRUE : FALSE;
context->priv->UseThreads = isVistaOrLater; priv->UseThreads = isVistaOrLater;
} }
#else #else
context->priv->UseThreads = TRUE; priv->UseThreads = TRUE;
#endif #endif
GetNativeSystemInfo(&sysinfo); GetNativeSystemInfo(&sysinfo);
context->priv->MinThreadCount = sysinfo.dwNumberOfProcessors; priv->MinThreadCount = sysinfo.dwNumberOfProcessors;
context->priv->MaxThreadCount = 0; priv->MaxThreadCount = 0;
status = RegOpenKeyEx(HKEY_LOCAL_MACHINE, _T("Software\\FreeRDP\\RemoteFX"), 0, KEY_READ | KEY_WOW64_64KEY, &hKey); status = RegOpenKeyEx(HKEY_LOCAL_MACHINE, _T("Software\\FreeRDP\\RemoteFX"), 0, KEY_READ | KEY_WOW64_64KEY, &hKey);
@ -289,33 +296,35 @@ RFX_CONTEXT* rfx_context_new(BOOL encoder)
dwSize = sizeof(dwValue); dwSize = sizeof(dwValue);
if (RegQueryValueEx(hKey, _T("UseThreads"), NULL, &dwType, (BYTE*) &dwValue, &dwSize) == ERROR_SUCCESS) if (RegQueryValueEx(hKey, _T("UseThreads"), NULL, &dwType, (BYTE*) &dwValue, &dwSize) == ERROR_SUCCESS)
context->priv->UseThreads = dwValue ? 1 : 0; priv->UseThreads = dwValue ? 1 : 0;
if (RegQueryValueEx(hKey, _T("MinThreadCount"), NULL, &dwType, (BYTE*) &dwValue, &dwSize) == ERROR_SUCCESS) if (RegQueryValueEx(hKey, _T("MinThreadCount"), NULL, &dwType, (BYTE*) &dwValue, &dwSize) == ERROR_SUCCESS)
context->priv->MinThreadCount = dwValue; priv->MinThreadCount = dwValue;
if (RegQueryValueEx(hKey, _T("MaxThreadCount"), NULL, &dwType, (BYTE*) &dwValue, &dwSize) == ERROR_SUCCESS) if (RegQueryValueEx(hKey, _T("MaxThreadCount"), NULL, &dwType, (BYTE*) &dwValue, &dwSize) == ERROR_SUCCESS)
context->priv->MaxThreadCount = dwValue; priv->MaxThreadCount = dwValue;
RegCloseKey(hKey); RegCloseKey(hKey);
} }
if (context->priv->UseThreads) if (priv->UseThreads)
{ {
/* Call primitives_get here in order to avoid race conditions when using primitives_get */ /* Call primitives_get here in order to avoid race conditions when using primitives_get */
/* from multiple threads. This call will initialize all function pointers correctly */ /* from multiple threads. This call will initialize all function pointers correctly */
/* before any decoding threads are started */ /* before any decoding threads are started */
primitives_get(); primitives_get();
context->priv->ThreadPool = CreateThreadpool(NULL); priv->ThreadPool = CreateThreadpool(NULL);
InitializeThreadpoolEnvironment(&context->priv->ThreadPoolEnv); if (!priv->ThreadPool)
SetThreadpoolCallbackPool(&context->priv->ThreadPoolEnv, context->priv->ThreadPool); goto error_threadPool;
InitializeThreadpoolEnvironment(&priv->ThreadPoolEnv);
SetThreadpoolCallbackPool(&priv->ThreadPoolEnv, priv->ThreadPool);
if (context->priv->MinThreadCount) if (priv->MinThreadCount)
SetThreadpoolThreadMinimum(context->priv->ThreadPool, context->priv->MinThreadCount); SetThreadpoolThreadMinimum(priv->ThreadPool, priv->MinThreadCount);
if (context->priv->MaxThreadCount) if (priv->MaxThreadCount)
SetThreadpoolThreadMaximum(context->priv->ThreadPool, context->priv->MaxThreadCount); SetThreadpoolThreadMaximum(priv->ThreadPool, priv->MaxThreadCount);
} }
/* initialize the default pixel format */ /* initialize the default pixel format */
@ -335,29 +344,47 @@ RFX_CONTEXT* rfx_context_new(BOOL encoder)
RFX_INIT_SIMD(context); RFX_INIT_SIMD(context);
context->state = RFX_STATE_SEND_HEADERS; context->state = RFX_STATE_SEND_HEADERS;
return context; return context;
error_threadPool:
BufferPool_Free(priv->BufferPool);
error_BufferPool:
ObjectPool_Free(priv->TilePool);
error_tilePool:
free(priv);
error_priv:
free(context);
return NULL;
} }
void rfx_context_free(RFX_CONTEXT* context) void rfx_context_free(RFX_CONTEXT* context)
{ {
RFX_CONTEXT_PRIV *priv;
assert(NULL != context); assert(NULL != context);
assert(NULL != context->priv); assert(NULL != context->priv);
assert(NULL != context->priv->TilePool); assert(NULL != context->priv->TilePool);
assert(NULL != context->priv->BufferPool); assert(NULL != context->priv->BufferPool);
priv = context->priv;
if (context->quants) if (context->quants)
free(context->quants); free(context->quants);
ObjectPool_Free(context->priv->TilePool); ObjectPool_Free(priv->TilePool);
rfx_profiler_print(context); rfx_profiler_print(context);
rfx_profiler_free(context); rfx_profiler_free(context);
if (context->priv->UseThreads) if (priv->UseThreads)
{ {
CloseThreadpool(context->priv->ThreadPool); CloseThreadpool(context->priv->ThreadPool);
DestroyThreadpoolEnvironment(&context->priv->ThreadPoolEnv); DestroyThreadpoolEnvironment(&context->priv->ThreadPoolEnv);
if (priv->workObjects)
free(priv->workObjects);
if (priv->tileWorkParams)
free(priv->tileWorkParams);
#ifdef WITH_PROFILER #ifdef WITH_PROFILER
fprintf(stderr, "\nWARNING: Profiling results probably unusable with multithreaded RemoteFX codec!\n"); fprintf(stderr, "\nWARNING: Profiling results probably unusable with multithreaded RemoteFX codec!\n");
#endif #endif
@ -610,10 +637,7 @@ static BOOL rfx_process_message_region(RFX_CONTEXT* context, RFX_MESSAGE* messag
return FALSE; return FALSE;
} }
if (message->rects) message->rects = (RFX_RECT*) realloc(message->rects, message->numRects * sizeof(RFX_RECT));
message->rects = (RFX_RECT*) realloc(message->rects, message->numRects * sizeof(RFX_RECT));
else
message->rects = (RFX_RECT*) malloc(message->numRects * sizeof(RFX_RECT));
/* rects */ /* rects */
for (i = 0; i < message->numRects; i++) for (i = 0; i < message->numRects; i++)
@ -624,8 +648,9 @@ static BOOL rfx_process_message_region(RFX_CONTEXT* context, RFX_MESSAGE* messag
Stream_Read_UINT16(s, message->rects[i].width); /* width (2 bytes) */ Stream_Read_UINT16(s, message->rects[i].width); /* width (2 bytes) */
Stream_Read_UINT16(s, message->rects[i].height); /* height (2 bytes) */ Stream_Read_UINT16(s, message->rects[i].height); /* height (2 bytes) */
WLog_Print(context->priv->log, WLOG_DEBUG, "rect %d (%d %d %d %d).", WLog_Print(context->priv->log, WLOG_DEBUG, "rect %d (x,y=%d,%d w,h=%d %d).", i,
i, message->rects[i].x, message->rects[i].y, message->rects[i].width, message->rects[i].height); message->rects[i].x, message->rects[i].y,
message->rects[i].width, message->rects[i].height);
} }
return TRUE; return TRUE;
@ -695,10 +720,7 @@ static BOOL rfx_process_message_tileset(RFX_CONTEXT* context, RFX_MESSAGE* messa
Stream_Read_UINT32(s, tilesDataSize); /* tilesDataSize (4 bytes) */ Stream_Read_UINT32(s, tilesDataSize); /* tilesDataSize (4 bytes) */
if (context->quants != NULL) context->quants = (UINT32 *)realloc((void*) context->quants, context->numQuant * 10 * sizeof(UINT32));
context->quants = (UINT32*) realloc((void*) context->quants, context->numQuant * 10 * sizeof(UINT32));
else
context->quants = (UINT32*) malloc(context->numQuant * 10 * sizeof(UINT32));
quants = context->quants; quants = context->quants;
@ -1127,37 +1149,84 @@ void CALLBACK rfx_compose_message_tile_work_callback(PTP_CALLBACK_INSTANCE insta
rfx_encode_rgb(param->context, param->tile); rfx_encode_rgb(param->context, param->tile);
} }
RFX_MESSAGE* rfx_encode_message(RFX_CONTEXT* context, const RFX_RECT* rects, #define ALIGN_DOWN(value, alignto) ((value) - ((value) % (alignto)))
int numRects, BYTE* data, int width, int height, int scanline) #define ALIGN_UP(value, alignto) ( (((value) + (alignto) - 1) / (alignto) ) * (alignto) )
static BOOL computeRegion(const RFX_RECT* rects, int numRects, REGION16 *region)
{ {
int i, close_cnt; int i;
int xIdx; const RFX_RECT *rect = rects;
int yIdx;
int numTilesX; for(i = 0; i < numRects; i++, rect++) {
int numTilesY; RECTANGLE_16 rect16;
UINT16 ax, ay;
rect16.left = rect->x;
rect16.top = rect->y;
rect16.right = rect->x + rect->width;
rect16.bottom = rect->y + rect->height;
if (!region16_union_rect(region, region, &rect16))
return FALSE;
}
return TRUE;
}
BOOL setupWorkers(RFX_CONTEXT *context, int nbTiles)
{
RFX_CONTEXT_PRIV *priv = context->priv;
if (!context->priv->UseThreads)
return TRUE;
priv->workObjects = (PTP_WORK *)realloc(priv->workObjects, sizeof(PTP_WORK) * nbTiles);
if (!priv->workObjects)
return FALSE;
priv->tileWorkParams = (RFX_TILE_COMPOSE_WORK_PARAM *)
realloc(priv->tileWorkParams, sizeof(RFX_TILE_COMPOSE_WORK_PARAM) * nbTiles);
if (!priv->tileWorkParams)
return FALSE;
return TRUE;
}
RFX_MESSAGE* rfx_encode_message(RFX_CONTEXT* context, const RFX_RECT* rects, int numRects,
BYTE* data, int width, int height, int scanline)
{
int i, maxNbTiles, maxTilesX, maxTilesY;
int xIdx, yIdx, regionNbRects;
int gridRelX, gridRelY, ax, ay, bytesPerPixel;
RFX_TILE* tile; RFX_TILE* tile;
RFX_RECT* rect; RFX_RECT* rfxRect;
int BytesPerPixel;
RFX_MESSAGE* message = NULL; RFX_MESSAGE* message = NULL;
PTP_WORK* work_objects = NULL; PTP_WORK* workObject;
RFX_TILE_COMPOSE_WORK_PARAM* params = NULL; RFX_TILE_COMPOSE_WORK_PARAM *workParam;
message = (RFX_MESSAGE*) malloc(sizeof(RFX_MESSAGE)); REGION16 rectsRegion, tilesRegion;
RECTANGLE_16 currentTileRect;
const RECTANGLE_16 *regionRect;
const RECTANGLE_16 *extents;
#if 0
const RFX_RECT *tt = rects;
fprintf(stderr, "input with %d rect(s)\n", numRects);
for (i = 0; i < numRects; i++, tt++)
fprintf(stderr, "%d: %d,%d -> %d,%d (w=%d h=%d)\n", i,
tt->x, tt->y, tt->x + tt->width, tt->y + tt->height,
tt->width, tt->height
);
#endif
message = (RFX_MESSAGE *)zmalloc(sizeof(RFX_MESSAGE));
if (!message) if (!message)
return NULL; return NULL;
ZeroMemory(message, sizeof(RFX_MESSAGE));
if (context->state == RFX_STATE_SEND_HEADERS) if (context->state == RFX_STATE_SEND_HEADERS)
rfx_update_context_properties(context); rfx_update_context_properties(context);
message->frameIdx = context->frameIdx++; message->frameIdx = context->frameIdx++;
message->numRects = numRects;
message->rects = (RFX_RECT*) rects;
if (!context->numQuant) if (!context->numQuant)
{ {
context->numQuant = 1; context->numQuant = 1;
@ -1167,133 +1236,210 @@ RFX_MESSAGE* rfx_encode_message(RFX_CONTEXT* context, const RFX_RECT* rects,
context->quantIdxCb = 0; context->quantIdxCb = 0;
context->quantIdxCr = 0; context->quantIdxCr = 0;
} }
rect = (RFX_RECT*) &rects[0];
BytesPerPixel = (context->bits_per_pixel / 8);
message->numQuant = context->numQuant; message->numQuant = context->numQuant;
message->quantVals = context->quants; message->quantVals = context->quants;
numTilesX = (width + 63) / 64; rfxRect = (RFX_RECT*) &rects[0];
numTilesY = (height + 63) / 64; bytesPerPixel = (context->bits_per_pixel / 8);
message->numTiles = numTilesX * numTilesY; region16_init(&rectsRegion);
if (message->numTiles) if (!computeRegion(rects, numRects, &rectsRegion))
{ goto out_free_message;
message->tiles = (RFX_TILE**) malloc(sizeof(RFX_TILE*) * message->numTiles); extents = region16_extents(&rectsRegion);
ZeroMemory(message->tiles, sizeof(RFX_TILE*) * message->numTiles); /* fprintf(stderr, "\n\n%s: nrects(in/simplified)=%d/%d width=%d height=%d bounds=(%d,%d-%d,%d)\n", __FUNCTION__,
} numRects, region16_n_rects(&rectsRegion),
width, height,
extents->left, extents->top,
extents->right, extents->bottom);*/
WLog_Print(context->priv->log, WLOG_DEBUG, "x: %d y: %d width: %d height: %d scanline: %d BytesPerPixel: %d", maxTilesX = ALIGN_UP(extents->right - extents->left, 64) / 64;
rect->x, rect->y, width, height, scanline, BytesPerPixel); maxTilesY = ALIGN_UP(extents->bottom - extents->top, 64) / 64;
maxNbTiles = maxTilesX * maxTilesY;
message->tiles = zmalloc(maxNbTiles * sizeof(RFX_TILE*));
if (!message->tiles)
goto out_free_message;
if (!setupWorkers(context, maxNbTiles))
goto out_clean_tiles;
if (context->priv->UseThreads) if (context->priv->UseThreads)
{ {
if (message->numTiles) workObject = context->priv->workObjects;
work_objects = (PTP_WORK*) malloc(sizeof(PTP_WORK) * message->numTiles); workParam = context->priv->tileWorkParams;
if (!work_objects)
{
free(message);
return NULL;
}
params = (RFX_TILE_COMPOSE_WORK_PARAM*)
malloc(sizeof(RFX_TILE_COMPOSE_WORK_PARAM) * message->numTiles);
if (!params)
{
if (message->tiles)
free(message->tiles);
free(message);
free(work_objects);
return NULL;
}
ZeroMemory(work_objects, sizeof(PTP_WORK) * message->numTiles);
ZeroMemory(params, sizeof(RFX_TILE_COMPOSE_WORK_PARAM) * message->numTiles);
} }
close_cnt = 0; regionRect = region16_rects(&rectsRegion, &regionNbRects);
for (yIdx = 0; yIdx < numTilesY; yIdx++) message->rects = rfxRect = zmalloc(regionNbRects * sizeof(RFX_RECT));
if (!message->rects)
goto out_clean_tiles;
message->numRects = regionNbRects;
region16_init(&tilesRegion);
for (i = 0; i < regionNbRects; i++, regionRect++, rfxRect++)
{ {
for (xIdx = 0; xIdx < numTilesX; xIdx++) int startTileX = regionRect->left / 64;
int endTileX = (regionRect->right - 1) / 64;
int startTileY = regionRect->top / 64;
int endTileY = (regionRect->bottom - 1) / 64;
rfxRect->x = regionRect->left;
rfxRect->y = regionRect->top;
rfxRect->width = (regionRect->right - regionRect->left);
rfxRect->height = (regionRect->bottom - regionRect->top);
/*fprintf(stderr, "%s: rect[%d,%d->%d,%d] start=(%d,%d) end=(%d,%d)\n",
__FUNCTION__,
regionRect->left, regionRect->top, regionRect->right, regionRect->bottom,
startTileX, startTileY,
endTileX, endTileY
);
fprintf(stderr, "rfxRect=%d,%d w/h=%d,%d\n", rfxRect->x, rfxRect->y, rfxRect->width, rfxRect->height);*/
for (yIdx = startTileY, gridRelY = startTileY * 64; yIdx <= endTileY; yIdx++, gridRelY += 64 )
{ {
i = yIdx * numTilesX + xIdx; int tileHeight = 64;
if ((yIdx == endTileY) && (gridRelY + 64 > height))
tileHeight = height - gridRelY;
tile = message->tiles[i] = (RFX_TILE*) ObjectPool_Take(context->priv->TilePool); currentTileRect.top = gridRelY;
currentTileRect.bottom = gridRelY + tileHeight;
tile->xIdx = xIdx; for (xIdx = startTileX, gridRelX = startTileX * 64; xIdx <= endTileX; xIdx++, gridRelX += 64)
tile->yIdx = yIdx;
tile->x = tile->xIdx * 64;
tile->y = tile->yIdx * 64;
tile->scanline = scanline;
tile->width = (xIdx < numTilesX - 1) ? 64 : width - xIdx * 64;
tile->height = (yIdx < numTilesY - 1) ? 64 : height - yIdx * 64;
ax = rect->x + tile->x;
ay = rect->y + tile->y;
if (tile->data && tile->allocated)
{ {
free(tile->data); int tileWidth = 64;
tile->allocated = FALSE; if ((xIdx == endTileX) && (gridRelX + 64 > width))
} tileWidth = width - gridRelX;
tile->data = &data[(ay * scanline) + (ax * BytesPerPixel)];
tile->quantIdxY = context->quantIdxY; currentTileRect.left = gridRelX;
tile->quantIdxCb = context->quantIdxCb; currentTileRect.right = gridRelX + tileWidth;
tile->quantIdxCr = context->quantIdxCr;
tile->YLen = 0; /* checks if this tile is already treated */
tile->CbLen = 0; if (region16_intersects_rect(&tilesRegion, &currentTileRect)) {
tile->CrLen = 0; /*fprintf(stderr, "skipping %d,%d -> %d,%d\n",
currentTileRect.left, currentTileRect.top,
currentTileRect.right, currentTileRect.bottom
);*/
continue;
}
tile->YCbCrData = (BYTE*) BufferPool_Take(context->priv->BufferPool, -1); tile = (RFX_TILE *)ObjectPool_Take(context->priv->TilePool);
if (!tile)
goto out_clean_rects;;
tile->YData = (BYTE*) &(tile->YCbCrData[((8192 + 32) * 0) + 16]); tile->xIdx = xIdx;
tile->CbData = (BYTE*) &(tile->YCbCrData[((8192 + 32) * 1) + 16]); tile->yIdx = yIdx;
tile->CrData = (BYTE*) &(tile->YCbCrData[((8192 + 32) * 2) + 16]); tile->x = gridRelX;
tile->y = gridRelY;
tile->scanline = scanline;
tile->width = tileWidth;
tile->height = tileHeight;
if (context->priv->UseThreads) /*fprintf(stderr, "tile(%d,%d) - %d,%d->%d,%d (x=%d,y=%d,w=%d,h=%d),\n",
{ tile->xIdx, tile->yIdx,
assert(params); currentTileRect.left, currentTileRect.top,
currentTileRect.right, currentTileRect.bottom,
tile->x, tile->y,
tile->width, tile->height
);*/
params[i].context = context; ax = gridRelX;
params[i].tile = tile; ay = gridRelY;
if (tile->data && tile->allocated)
{
free(tile->data);
tile->allocated = FALSE;
}
tile->data = &data[(ay * scanline) + (ax * bytesPerPixel)];
work_objects[i] = CreateThreadpoolWork((PTP_WORK_CALLBACK) rfx_compose_message_tile_work_callback, tile->quantIdxY = context->quantIdxY;
(void*) &params[i], &context->priv->ThreadPoolEnv); tile->quantIdxCb = context->quantIdxCb;
tile->quantIdxCr = context->quantIdxCr;
SubmitThreadpoolWork(work_objects[i]); tile->YLen = tile->CbLen = tile->CrLen = 0;
close_cnt = i + 1;
} tile->YCbCrData = (BYTE *)BufferPool_Take(context->priv->BufferPool, -1);
else if (!tile->YCbCrData)
{ goto out_clean_rects;
rfx_encode_rgb(context, tile);
} tile->YData = (BYTE*) &(tile->YCbCrData[((8192 + 32) * 0) + 16]);
} tile->CbData = (BYTE*) &(tile->YCbCrData[((8192 + 32) * 1) + 16]);
tile->CrData = (BYTE*) &(tile->YCbCrData[((8192 + 32) * 2) + 16]);
if (context->priv->UseThreads)
{
workParam->context = context;
workParam->tile = tile;
*workObject = CreateThreadpoolWork(
(PTP_WORK_CALLBACK)rfx_compose_message_tile_work_callback,
(void *)workParam,
&context->priv->ThreadPoolEnv
);
SubmitThreadpoolWork(*workObject);
workObject++;
workParam++;
}
else
{
rfx_encode_rgb(context, tile);
}
message->tiles[message->numTiles] = tile;
message->numTiles++;
if (!region16_union_rect(&tilesRegion, &tilesRegion, &currentTileRect))
goto out_clean_rects;
} /* xIdx */
} /* yIdx */
} /* rects */
if (message->numTiles != maxNbTiles)
{
message->tiles = realloc(message->tiles, sizeof(RFX_TILE *) * message->numTiles);
if (!message->tiles)
goto out_clean_rects;
} }
message->tilesDataSize = 0; region16_uninit(&tilesRegion);
for (i = 0; i < close_cnt; i++) /* when using threads ensure all computations are done */
message->tilesDataSize = 0;
workObject = context->priv->workObjects;
for (i = 0; i < message->numTiles; i++)
{ {
tile = message->tiles[i]; tile = message->tiles[i];
if (context->priv->UseThreads)
if (context->priv->UseThreads && work_objects)
{ {
WaitForThreadpoolWorkCallbacks(work_objects[i], FALSE); WaitForThreadpoolWorkCallbacks(*workObject, FALSE);
CloseThreadpoolWork(work_objects[i]); CloseThreadpoolWork(*workObject);
workObject++;
} }
message->tilesDataSize += rfx_tile_length(tile); message->tilesDataSize += rfx_tile_length(tile);
} }
if (work_objects)
free(work_objects);
if (params)
free(params);
region16_uninit(&rectsRegion);
return message; return message;
out_clean_rects:
free(message->rects);
out_clean_tiles:
free(message->tiles);
region16_uninit(&tilesRegion);
out_free_message:
fprintf(stderr, "remoteFx error\n");
region16_uninit(&rectsRegion);
free(message);
return 0;
} }
RFX_MESSAGE* rfx_split_message(RFX_CONTEXT* context, RFX_MESSAGE* message, int* numMessages, int maxDataSize) RFX_MESSAGE* rfx_split_message(RFX_CONTEXT* context, RFX_MESSAGE* message, int* numMessages, int maxDataSize)
{ {
int i, j; int i, j;
@ -1432,14 +1578,8 @@ void rfx_write_message_region(RFX_CONTEXT* context, wStream* s, RFX_MESSAGE* mes
{ {
/* Clipping rectangles are relative to destLeft, destTop */ /* Clipping rectangles are relative to destLeft, destTop */
#if 1
Stream_Write_UINT16(s, 0); /* x (2 bytes) */
Stream_Write_UINT16(s, 0); /* y (2 bytes) */
#else
Stream_Write_UINT16(s, message->rects[i].x); /* x (2 bytes) */ Stream_Write_UINT16(s, message->rects[i].x); /* x (2 bytes) */
Stream_Write_UINT16(s, message->rects[i].y); /* y (2 bytes) */ Stream_Write_UINT16(s, message->rects[i].y); /* y (2 bytes) */
#endif
Stream_Write_UINT16(s, message->rects[i].width); /* width (2 bytes) */ Stream_Write_UINT16(s, message->rects[i].width); /* width (2 bytes) */
Stream_Write_UINT16(s, message->rects[i].height); /* height (2 bytes) */ Stream_Write_UINT16(s, message->rects[i].height); /* height (2 bytes) */
} }
@ -1483,3 +1623,4 @@ void rfx_compose_message(RFX_CONTEXT* context, wStream* s,
rfx_message_free(context, message); rfx_message_free(context, message);
} }

View File

@ -38,12 +38,18 @@
#define DEBUG_RFX(fmt, ...) DEBUG_NULL(fmt, ## __VA_ARGS__) #define DEBUG_RFX(fmt, ...) DEBUG_NULL(fmt, ## __VA_ARGS__)
#endif #endif
struct _RFX_TILE_COMPOSE_WORK_PARAM;
typedef struct _RFX_TILE_COMPOSE_WORK_PARAM RFX_TILE_COMPOSE_WORK_PARAM;
struct _RFX_CONTEXT_PRIV struct _RFX_CONTEXT_PRIV
{ {
wLog* log; wLog* log;
wObjectPool* TilePool; wObjectPool* TilePool;
BOOL UseThreads; BOOL UseThreads;
PTP_WORK* workObjects;
RFX_TILE_COMPOSE_WORK_PARAM* tileWorkParams;
DWORD MinThreadCount; DWORD MinThreadCount;
DWORD MaxThreadCount; DWORD MaxThreadCount;