xfreerdp: fix egfx multimonitor support

This commit is contained in:
Marc-André Moreau 2015-02-10 16:32:07 -05:00
parent 9b9fbd2ab1
commit 22ac46957a
7 changed files with 130 additions and 139 deletions

View File

@ -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;

View File

@ -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;
}
}

View File

@ -25,13 +25,6 @@
#include <freerdp/gdi/gfx.h>
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;

View File

@ -125,7 +125,6 @@ struct xf_context
BYTE* primary_buffer;
BOOL inGfxFrame;
BOOL graphicsReset;
wArrayList* gfxMappedSurfaceIds;
BOOL frame_begin;
UINT16 frame_x1;

View File

@ -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;

View File

@ -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);

View File

@ -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)