From 22ac46957aa4a4068d2634d9a7a0d4ad841bf853 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Moreau?= Date: Tue, 10 Feb 2015 16:32:07 -0500 Subject: [PATCH] xfreerdp: fix egfx multimonitor support --- channels/rdpgfx/client/rdpgfx_main.c | 30 +++ client/X11/xf_gfx.c | 195 ++++++++----------- client/X11/xf_gfx.h | 22 +-- client/X11/xfreerdp.h | 1 - include/freerdp/client/rdpgfx.h | 2 + libfreerdp/core/client.c | 11 +- winpr/libwinpr/utils/collections/HashTable.c | 8 + 7 files changed, 130 insertions(+), 139 deletions(-) diff --git a/channels/rdpgfx/client/rdpgfx_main.c b/channels/rdpgfx/client/rdpgfx_main.c index 875a84a8e..1a8ef5913 100644 --- a/channels/rdpgfx/client/rdpgfx_main.c +++ b/channels/rdpgfx/client/rdpgfx_main.c @@ -1020,6 +1020,35 @@ int rdpgfx_set_surface_data(RdpgfxClientContext* context, UINT16 surfaceId, void return 1; } +int rdpgfx_get_surface_ids(RdpgfxClientContext* context, UINT16** ppSurfaceIds) +{ + int count; + int index; + UINT16* pSurfaceIds; + ULONG_PTR* pKeys = NULL; + RDPGFX_PLUGIN* gfx = (RDPGFX_PLUGIN*) context->handle; + + count = HashTable_GetKeys(gfx->SurfaceTable, &pKeys); + + if (count < 1) + return 0; + + pSurfaceIds = (UINT16*) malloc(count * sizeof(UINT16)); + + if (!pSurfaceIds) + return -1; + + for (index = 0; index < count; index++) + { + pSurfaceIds[index] = pKeys[index] - 1; + } + + free(pKeys); + *ppSurfaceIds = pSurfaceIds; + + return count; +} + void* rdpgfx_get_surface_data(RdpgfxClientContext* context, UINT16 surfaceId) { ULONG_PTR key; @@ -1117,6 +1146,7 @@ int DVCPluginEntry(IDRDYNVC_ENTRY_POINTS* pEntryPoints) context->handle = (void*) gfx; + context->GetSurfaceIds = rdpgfx_get_surface_ids; context->SetSurfaceData = rdpgfx_set_surface_data; context->GetSurfaceData = rdpgfx_get_surface_data; context->SetCacheSlotData = rdpgfx_set_cache_slot_data; diff --git a/client/X11/xf_gfx.c b/client/X11/xf_gfx.c index 22a98acc6..3cc1723a4 100644 --- a/client/X11/xf_gfx.c +++ b/client/X11/xf_gfx.c @@ -26,50 +26,30 @@ #define TAG CLIENT_TAG("x11") -static int xf_call_for_each_surface(xfContext* xfc, wArrayList* surfaceList, int (*processSurface)(xfContext*, xfGfxSurface*, void*), void* param) -{ - int status = 1; - int surfaceIndex; - RdpgfxClientContext* context = xfc->gfx; - - /* Iterating backwards to be able to remove surfaces from the list */ - surfaceIndex = ArrayList_Count(surfaceList) - 1; - - for (; surfaceIndex >= 0; surfaceIndex--) - { - UINT32 surfaceId; - xfGfxSurface* surface; - - surfaceId = (UINT32) (ULONG_PTR) ArrayList_GetItem(xfc->gfxMappedSurfaceIds, surfaceIndex); - surface = (xfGfxSurface*) context->GetSurfaceData(context, surfaceId); - - if (!surface) - { - ArrayList_RemoveAt(surfaceList, surfaceIndex); - continue; - } - - if (processSurface(xfc, surface, param) < 0) - status = -1; - } - - return status; -} - -static int do_clearInvalidRegion(xfContext* xfc, xfGfxSurface* surface, void* param) -{ - region16_clear(&surface->invalidRegion); - - return 1; -} - int xf_ResetGraphics(RdpgfxClientContext* context, RDPGFX_RESET_GRAPHICS_PDU* resetGraphics) { + int count; + int index; + int status = 1; + xfGfxSurface* surface; + UINT16* pSurfaceIds = NULL; xfContext* xfc = (xfContext*) context->custom; freerdp_client_codecs_reset(xfc->codecs, FREERDP_CODEC_ALL); - xf_call_for_each_surface(xfc, xfc->gfxMappedSurfaceIds, do_clearInvalidRegion, NULL); + count = context->GetSurfaceIds(context, &pSurfaceIds); + + for (index = 0; index < count; index++) + { + surface = (xfGfxSurface*) context->GetSurfaceData(context, pSurfaceIds[index]); + + if (!surface || !surface->outputMapped) + continue; + + region16_clear(&surface->invalidRegion); + } + + free(pSurfaceIds); xfc->graphicsReset = TRUE; @@ -83,8 +63,8 @@ int xf_OutputUpdate(xfContext* xfc, xfGfxSurface* surface) RECTANGLE_16 surfaceRect; const RECTANGLE_16* extents; - surfaceX = surface->mapping.output.originX; - surfaceY = surface->mapping.output.originY; + surfaceX = surface->outputOriginX; + surfaceY = surface->outputOriginY; surfaceRect.left = surfaceX; surfaceRect.top = surfaceY; @@ -138,87 +118,82 @@ int xf_OutputUpdate(xfContext* xfc, xfGfxSurface* surface) return 1; } -static int xf_UpdateSurface(xfContext* xfc, xfGfxSurface* surface, void* param) +int xf_UpdateSurfaces(xfContext* xfc) { + int count; + int index; int status = 1; + xfGfxSurface* surface; + UINT16* pSurfaceIds = NULL; + RdpgfxClientContext* context = xfc->gfx; - switch (surface->mapping.mode) + if (!xfc->graphicsReset) + return 1; + + count = context->GetSurfaceIds(context, &pSurfaceIds); + + for (index = 0; index < count; index++) { - case GFX_MAP_OUTPUT: - status = xf_OutputUpdate(xfc, surface); - break; + surface = (xfGfxSurface*) context->GetSurfaceData(context, pSurfaceIds[index]); - case GFX_MAP_NONE: + if (!surface || !surface->outputMapped) + continue; + + status = xf_OutputUpdate(xfc, surface); + + if (status < 0) break; } + free(pSurfaceIds); + return status; } -int xf_UpdateSurfaces(xfContext* xfc) -{ - if (!xfc->graphicsReset) - return 1; - - return xf_call_for_each_surface(xfc, xfc->gfxMappedSurfaceIds, xf_UpdateSurface, NULL); -} - -BOOL xf_MappedSurfaceRect(xfContext* xfc, xfGfxSurface* surface, RECTANGLE_16* rect) -{ - BOOL mapped = FALSE; - - switch (surface->mapping.mode) - { - case GFX_MAP_OUTPUT: - mapped = TRUE; - rect->left = surface->mapping.output.originX; - rect->top = surface->mapping.output.originY; - rect->right = surface->mapping.output.originX + surface->width; - rect->bottom = surface->mapping.output.originY + surface->height; - break; - - case GFX_MAP_NONE: - break; - } - - return mapped; -} - -static int do_OutputExpose(xfContext* xfc, xfGfxSurface* surface, void* param) -{ - RECTANGLE_16 surfaceRect; - RECTANGLE_16 intersection; - RECTANGLE_16* invalidRect = param; - - if (!xf_MappedSurfaceRect(xfc, surface, &surfaceRect)) - return -1; - - if (rectangles_intersection(invalidRect, &surfaceRect, &intersection)) - { - /* Invalid rects are specified relative to surface origin */ - intersection.left -= surfaceRect.left; - intersection.top -= surfaceRect.top; - intersection.right -= surfaceRect.left; - intersection.bottom -= surfaceRect.top; - - region16_union_rect(&surface->invalidRegion, &surface->invalidRegion, &intersection); - } - - return 1; -} - int xf_OutputExpose(xfContext* xfc, int x, int y, int width, int height) { + int count; + int index; int status = 1; + xfGfxSurface* surface; RECTANGLE_16 invalidRect; + RECTANGLE_16 surfaceRect; + RECTANGLE_16 intersection; + UINT16* pSurfaceIds = NULL; + RdpgfxClientContext* context = xfc->gfx; invalidRect.left = x; invalidRect.top = y; invalidRect.right = x + width; invalidRect.bottom = y + height; - if (xf_call_for_each_surface(xfc, xfc->gfxMappedSurfaceIds, do_OutputExpose, &invalidRect) < 0) - status = -1; + count = context->GetSurfaceIds(context, &pSurfaceIds); + + for (index = 0; index < count; index++) + { + surface = (xfGfxSurface*) context->GetSurfaceData(context, pSurfaceIds[index]); + + if (!surface || !surface->outputMapped) + continue; + + surfaceRect.left = surface->outputOriginX; + surfaceRect.top = surface->outputOriginY; + surfaceRect.right = surface->outputOriginX + surface->width; + surfaceRect.bottom = surface->outputOriginY + surface->height; + + if (rectangles_intersection(&invalidRect, &surfaceRect, &intersection)) + { + /* Invalid rects are specified relative to surface origin */ + intersection.left -= surfaceRect.left; + intersection.top -= surfaceRect.top; + intersection.right -= surfaceRect.left; + intersection.bottom -= surfaceRect.top; + + region16_union_rect(&surface->invalidRegion, &surface->invalidRegion, &intersection); + } + } + + free(pSurfaceIds); if (xf_UpdateSurfaces(xfc) < 0) status = -1; @@ -708,7 +683,7 @@ int xf_CreateSurface(RdpgfxClientContext* context, RDPGFX_CREATE_SURFACE_PDU* cr (char*) surface->stage, surface->width, surface->height, xfc->scanline_pad, surface->stageStep); } - surface->mapping.mode = GFX_MAP_NONE; + surface->outputMapped = FALSE; region16_init(&surface->invalidRegion); @@ -733,7 +708,6 @@ int xf_DeleteSurface(RdpgfxClientContext* context, RDPGFX_DELETE_SURFACE_PDU* de free(surface); } - ArrayList_Remove(xfc->gfxMappedSurfaceIds, (void*) (ULONG_PTR) deleteSurface->surfaceId); context->SetSurfaceData(context, deleteSurface->surfaceId, NULL); if (xfc->codecs->progressive) @@ -959,18 +933,15 @@ int xf_EvictCacheEntry(RdpgfxClientContext* context, RDPGFX_EVICT_CACHE_ENTRY_PD int xf_MapSurfaceToOutput(RdpgfxClientContext* context, RDPGFX_MAP_SURFACE_TO_OUTPUT_PDU* surfaceToOutput) { xfGfxSurface* surface; - xfContext* xfc = (xfContext*) context->custom; surface = (xfGfxSurface*) context->GetSurfaceData(context, surfaceToOutput->surfaceId); - surface->mapping.mode = GFX_MAP_OUTPUT; - surface->mapping.output.originX = surfaceToOutput->outputOriginX; - surface->mapping.output.originY = surfaceToOutput->outputOriginY; + surface->outputMapped = TRUE; + surface->outputOriginX = surfaceToOutput->outputOriginX; + surface->outputOriginY = surfaceToOutput->outputOriginY; region16_clear(&surface->invalidRegion); - ArrayList_Add(xfc->gfxMappedSurfaceIds, (void*) (ULONG_PTR) surfaceToOutput->surfaceId); - return 1; } @@ -999,15 +970,9 @@ void xf_graphics_pipeline_init(xfContext* xfc, RdpgfxClientContext* gfx) gfx->EvictCacheEntry = xf_EvictCacheEntry; gfx->MapSurfaceToOutput = xf_MapSurfaceToOutput; gfx->MapSurfaceToWindow = xf_MapSurfaceToWindow; - - xfc->gfxMappedSurfaceIds = ArrayList_New(FALSE); } void xf_graphics_pipeline_uninit(xfContext* xfc, RdpgfxClientContext* gfx) { - if (xfc->gfxMappedSurfaceIds) - { - ArrayList_Free(xfc->gfxMappedSurfaceIds); - xfc->gfxMappedSurfaceIds = NULL; - } + } diff --git a/client/X11/xf_gfx.h b/client/X11/xf_gfx.h index b20ea6727..6748d6a6f 100644 --- a/client/X11/xf_gfx.h +++ b/client/X11/xf_gfx.h @@ -25,13 +25,6 @@ #include -enum xf_gfx_mapping_mode -{ - GFX_MAP_NONE, - GFX_MAP_OUTPUT -}; -typedef enum xf_gfx_mapping_mode xfGfxMappingMode; - struct xf_gfx_surface { UINT16 surfaceId; @@ -44,18 +37,9 @@ struct xf_gfx_surface int scanline; int stageStep; UINT32 format; - struct - { - xfGfxMappingMode mode; - union - { - struct - { - UINT32 originX; - UINT32 originY; - } output; - }; - } mapping; + BOOL outputMapped; + UINT32 outputOriginX; + UINT32 outputOriginY; REGION16 invalidRegion; }; typedef struct xf_gfx_surface xfGfxSurface; diff --git a/client/X11/xfreerdp.h b/client/X11/xfreerdp.h index 7397e48ca..7bdce32b7 100644 --- a/client/X11/xfreerdp.h +++ b/client/X11/xfreerdp.h @@ -125,7 +125,6 @@ struct xf_context BYTE* primary_buffer; BOOL inGfxFrame; BOOL graphicsReset; - wArrayList* gfxMappedSurfaceIds; BOOL frame_begin; UINT16 frame_x1; diff --git a/include/freerdp/client/rdpgfx.h b/include/freerdp/client/rdpgfx.h index f44cfbbeb..d768f9ea2 100644 --- a/include/freerdp/client/rdpgfx.h +++ b/include/freerdp/client/rdpgfx.h @@ -47,6 +47,7 @@ typedef int (*pcRdpgfxMapSurfaceToWindow)(RdpgfxClientContext* context, RDPGFX_M typedef int (*pcRdpgfxSetSurfaceData)(RdpgfxClientContext* context, UINT16 surfaceId, void* pData); typedef void* (*pcRdpgfxGetSurfaceData)(RdpgfxClientContext* context, UINT16 surfaceId); +typedef int (*pcRdpgfxGetSurfaceIds)(RdpgfxClientContext* context, UINT16** ppSurfaceIds); typedef int (*pcRdpgfxSetCacheSlotData)(RdpgfxClientContext* context, UINT16 cacheSlot, void* pData); typedef void* (*pcRdpgfxGetCacheSlotData)(RdpgfxClientContext* context, UINT16 cacheSlot); @@ -72,6 +73,7 @@ struct _rdpgfx_client_context pcRdpgfxMapSurfaceToOutput MapSurfaceToOutput; pcRdpgfxMapSurfaceToWindow MapSurfaceToWindow; + pcRdpgfxGetSurfaceIds GetSurfaceIds; pcRdpgfxSetSurfaceData SetSurfaceData; pcRdpgfxGetSurfaceData GetSurfaceData; pcRdpgfxSetCacheSlotData SetCacheSlotData; diff --git a/libfreerdp/core/client.c b/libfreerdp/core/client.c index 81f5e6dfe..e7ddde579 100644 --- a/libfreerdp/core/client.c +++ b/libfreerdp/core/client.c @@ -99,9 +99,9 @@ rdpChannels* freerdp_channels_new(void) void freerdp_channels_free(rdpChannels* channels) { int index; - CHANNEL_OPEN_DATA* pChannelOpenData; - ULONG_PTR* pKeys; int nkeys; + ULONG_PTR* pKeys = NULL; + CHANNEL_OPEN_DATA* pChannelOpenData; if (channels->queue) { @@ -126,12 +126,15 @@ void freerdp_channels_free(rdpChannels* channels) if (g_OpenHandles) { nkeys = HashTable_GetKeys(g_OpenHandles, &pKeys); - free(pKeys); - if ( nkeys == 0 ) { + + if (nkeys == 0) + { HashTable_Free(g_OpenHandles); DeleteCriticalSection(&g_channels_lock); g_OpenHandles = NULL; } + + free(pKeys); } free(channels); diff --git a/winpr/libwinpr/utils/collections/HashTable.c b/winpr/libwinpr/utils/collections/HashTable.c index 089b6ea67..4f98d8c5e 100644 --- a/winpr/libwinpr/utils/collections/HashTable.c +++ b/winpr/libwinpr/utils/collections/HashTable.c @@ -457,6 +457,14 @@ int HashTable_GetKeys(wHashTable* table, ULONG_PTR** ppKeys) iKey = 0; count = table->numOfElements; + if (count < 1) + { + if (table->synchronized) + LeaveCriticalSection(&table->lock); + + return 0; + } + pKeys = (ULONG_PTR*) calloc(count, sizeof(ULONG_PTR)); if (!pKeys)