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:
parent
d1e75efb8c
commit
2d16d929b6
@ -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, ®ionNbRects);
|
||||||
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, ¤tTileRect)) {
|
||||||
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*) ¶ms[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, ¤tTileRect))
|
||||||
|
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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;
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user