xfreerdp: fix egfx multimon on reconnect

This commit is contained in:
Marc-André Moreau 2015-02-06 17:46:15 -05:00
parent 3258c887a4
commit 8b524021f1
3 changed files with 194 additions and 55 deletions

View File

@ -26,58 +26,87 @@
#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)
{
xfContext* xfc = (xfContext*) context->custom;
freerdp_client_codecs_reset(xfc->codecs, FREERDP_CODEC_ALL);
region16_uninit(&(xfc->invalidRegion));
region16_init(&(xfc->invalidRegion));
xf_call_for_each_surface(xfc, xfc->gfxMappedSurfaceIds, do_clearInvalidRegion, NULL);
xfc->graphicsReset = TRUE;
return 1;
}
int xf_OutputUpdate(xfContext* xfc)
int xf_OutputUpdate(xfContext* xfc, xfGfxSurface* surface)
{
UINT16 width, height;
xfGfxSurface* surface;
UINT32 surfaceX, surfaceY;
RECTANGLE_16 surfaceRect;
const RECTANGLE_16* extents;
if (!xfc->graphicsReset)
return 1;
surfaceX = surface->mapping.output.originX;
surfaceY = surface->mapping.output.originY;
surface = (xfGfxSurface*) xfc->gfx->GetSurfaceData(xfc->gfx, xfc->outputSurfaceId);
if (!surface)
return -1;
surfaceRect.left = 0;
surfaceRect.top = 0;
surfaceRect.right = xfc->width;
surfaceRect.bottom = xfc->height;
region16_intersect_rect(&(xfc->invalidRegion), &(xfc->invalidRegion), &surfaceRect);
surfaceRect.left = surfaceX;
surfaceRect.top = surfaceY;
surfaceRect.right = surfaceX + surface->width;
surfaceRect.bottom = surfaceY + surface->height;
XSetClipMask(xfc->display, xfc->gc, None);
XSetFunction(xfc->display, xfc->gc, GXcopy);
XSetFillStyle(xfc->display, xfc->gc, FillSolid);
if (!region16_is_empty(&(xfc->invalidRegion)))
if (!region16_is_empty(&surface->invalidRegion))
{
extents = region16_extents(&(xfc->invalidRegion));
extents = region16_extents(&surface->invalidRegion);
width = extents->right - extents->left;
height = extents->bottom - extents->top;
if (width > xfc->width)
width = xfc->width;
if (width > surface->width)
width = surface->width;
if (height > xfc->height)
height = xfc->height;
if (height > surface->height)
height = surface->height;
if (surface->stage)
{
@ -89,7 +118,7 @@ int xf_OutputUpdate(xfContext* xfc)
if (xfc->settings->SmartSizing || xfc->settings->MultiTouchGestures)
{
XPutImage(xfc->display, xfc->primary, xfc->gc, surface->image,
extents->left, extents->top, extents->left, extents->top, width, height);
extents->left, extents->top, extents->left + surfaceX, extents->top + surfaceY, width, height);
xf_draw_screen(xfc, extents->left, extents->top, width, height);
}
@ -97,11 +126,11 @@ int xf_OutputUpdate(xfContext* xfc)
#endif
{
XPutImage(xfc->display, xfc->drawable, xfc->gc, surface->image,
extents->left, extents->top, extents->left, extents->top, width, height);
extents->left, extents->top, extents->left + surfaceX, extents->top + surfaceY, width, height);
}
}
region16_clear(&(xfc->invalidRegion));
region16_clear(&surface->invalidRegion);
XSetClipMask(xfc->display, xfc->gc, None);
XSync(xfc->display, True);
@ -109,8 +138,78 @@ int xf_OutputUpdate(xfContext* xfc)
return 1;
}
static int xf_UpdateSurface(xfContext* xfc, xfGfxSurface* surface, void* param)
{
int status = 1;
switch (surface->mapping.mode)
{
case GFX_MAP_OUTPUT:
status = xf_OutputUpdate(xfc, surface);
break;
case GFX_MAP_NONE:
break;
}
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 status = 1;
RECTANGLE_16 invalidRect;
invalidRect.left = x;
@ -118,11 +217,13 @@ int xf_OutputExpose(xfContext* xfc, int x, int y, int width, int height)
invalidRect.right = x + width;
invalidRect.bottom = y + height;
region16_union_rect(&(xfc->invalidRegion), &(xfc->invalidRegion), &invalidRect);
if (xf_call_for_each_surface(xfc, xfc->gfxMappedSurfaceIds, do_OutputExpose, &invalidRect) < 0)
status = -1;
xf_OutputUpdate(xfc);
if (xf_UpdateSurfaces(xfc) < 0)
status = -1;
return 1;
return status;
}
int xf_StartFrame(RdpgfxClientContext* context, RDPGFX_START_FRAME_PDU* startFrame)
@ -138,7 +239,7 @@ int xf_EndFrame(RdpgfxClientContext* context, RDPGFX_END_FRAME_PDU* endFrame)
{
xfContext* xfc = (xfContext*) context->custom;
xf_OutputUpdate(xfc);
xf_UpdateSurfaces(xfc);
xfc->inGfxFrame = FALSE;
@ -163,10 +264,10 @@ int xf_SurfaceCommand_Uncompressed(xfContext* xfc, RdpgfxClientContext* context,
invalidRect.right = cmd->right;
invalidRect.bottom = cmd->bottom;
region16_union_rect(&(xfc->invalidRegion), &(xfc->invalidRegion), &invalidRect);
region16_union_rect(&surface->invalidRegion, &surface->invalidRegion, &invalidRect);
if (!xfc->inGfxFrame)
xf_OutputUpdate(xfc);
xf_UpdateSurfaces(xfc);
return 1;
}
@ -238,7 +339,7 @@ int xf_SurfaceCommand_RemoteFX(xfContext* xfc, RdpgfxClientContext* context, RDP
nXDst, nYDst, nWidth, nHeight,
tile->data, PIXEL_FORMAT_XRGB32, 64 * 4, 0, 0, NULL);
region16_union_rect(&(xfc->invalidRegion), &(xfc->invalidRegion), &updateRects[j]);
region16_union_rect(&surface->invalidRegion, &surface->invalidRegion, &updateRects[j]);
}
region16_uninit(&updateRegion);
@ -249,7 +350,7 @@ int xf_SurfaceCommand_RemoteFX(xfContext* xfc, RdpgfxClientContext* context, RDP
region16_uninit(&clippingRects);
if (!xfc->inGfxFrame)
xf_OutputUpdate(xfc);
xf_UpdateSurfaces(xfc);
return 1;
}
@ -284,10 +385,10 @@ int xf_SurfaceCommand_ClearCodec(xfContext* xfc, RdpgfxClientContext* context, R
invalidRect.right = cmd->right;
invalidRect.bottom = cmd->bottom;
region16_union_rect(&(xfc->invalidRegion), &(xfc->invalidRegion), &invalidRect);
region16_union_rect(&surface->invalidRegion, &surface->invalidRegion, &invalidRect);
if (!xfc->inGfxFrame)
xf_OutputUpdate(xfc);
xf_UpdateSurfaces(xfc);
return 1;
}
@ -316,10 +417,10 @@ int xf_SurfaceCommand_Planar(xfContext* xfc, RdpgfxClientContext* context, RDPGF
invalidRect.right = cmd->right;
invalidRect.bottom = cmd->bottom;
region16_union_rect(&(xfc->invalidRegion), &(xfc->invalidRegion), &invalidRect);
region16_union_rect(&surface->invalidRegion, &surface->invalidRegion, &invalidRect);
if (!xfc->inGfxFrame)
xf_OutputUpdate(xfc);
xf_UpdateSurfaces(xfc);
return 1;
}
@ -364,11 +465,11 @@ int xf_SurfaceCommand_H264(xfContext* xfc, RdpgfxClientContext* context, RDPGFX_
for (i = 0; i < meta->numRegionRects; i++)
{
region16_union_rect(&(xfc->invalidRegion), &(xfc->invalidRegion), (RECTANGLE_16*) &(meta->regionRects[i]));
region16_union_rect(&surface->invalidRegion, &surface->invalidRegion, (RECTANGLE_16*) &(meta->regionRects[i]));
}
if (!xfc->inGfxFrame)
xf_OutputUpdate(xfc);
xf_UpdateSurfaces(xfc);
return 1;
}
@ -397,10 +498,10 @@ int xf_SurfaceCommand_Alpha(xfContext* xfc, RdpgfxClientContext* context, RDPGFX
invalidRect.right = cmd->right;
invalidRect.bottom = cmd->bottom;
region16_union_rect(&(xfc->invalidRegion), &(xfc->invalidRegion), &invalidRect);
region16_union_rect(&surface->invalidRegion, &surface->invalidRegion, &invalidRect);
if (!xfc->inGfxFrame)
xf_OutputUpdate(xfc);
xf_UpdateSurfaces(xfc);
return 1;
}
@ -487,7 +588,7 @@ int xf_SurfaceCommand_Progressive(xfContext* xfc, RdpgfxClientContext* context,
surface->scanline, nXDst, nYDst, nWidth, nHeight,
tile->data, PIXEL_FORMAT_XRGB32, 64 * 4, nXSrc, nYSrc, NULL);
region16_union_rect(&(xfc->invalidRegion), &(xfc->invalidRegion), &updateRects[j]);
region16_union_rect(&surface->invalidRegion, &surface->invalidRegion, &updateRects[j]);
}
region16_uninit(&updateRegion);
@ -496,7 +597,7 @@ int xf_SurfaceCommand_Progressive(xfContext* xfc, RdpgfxClientContext* context,
region16_uninit(&clippingRects);
if (!xfc->inGfxFrame)
xf_OutputUpdate(xfc);
xf_UpdateSurfaces(xfc);
return 1;
}
@ -607,6 +708,10 @@ 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;
region16_init(&surface->invalidRegion);
context->SetSurfaceData(context, surface->surfaceId, (void*) surface);
return 1;
@ -624,9 +729,11 @@ int xf_DeleteSurface(RdpgfxClientContext* context, RDPGFX_DELETE_SURFACE_PDU* de
XFree(surface->image);
_aligned_free(surface->data);
_aligned_free(surface->stage);
region16_uninit(&surface->invalidRegion);
free(surface);
}
ArrayList_Remove(xfc->gfxMappedSurfaceIds, (void*) (ULONG_PTR) deleteSurface->surfaceId);
context->SetSurfaceData(context, deleteSurface->surfaceId, NULL);
if (xfc->codecs->progressive)
@ -673,11 +780,11 @@ int xf_SolidFill(RdpgfxClientContext* context, RDPGFX_SOLID_FILL_PDU* solidFill)
freerdp_image_fill(surface->data, surface->format, surface->scanline,
rect->left, rect->top, nWidth, nHeight, color);
region16_union_rect(&(xfc->invalidRegion), &(xfc->invalidRegion), &invalidRect);
region16_union_rect(&surface->invalidRegion, &surface->invalidRegion, &invalidRect);
}
if (!xfc->inGfxFrame)
xf_OutputUpdate(xfc);
xf_UpdateSurfaces(xfc);
return 1;
}
@ -733,11 +840,11 @@ int xf_SurfaceToSurface(RdpgfxClientContext* context, RDPGFX_SURFACE_TO_SURFACE_
invalidRect.right = destPt->x + rectSrc->right;
invalidRect.bottom = destPt->y + rectSrc->bottom;
region16_union_rect(&(xfc->invalidRegion), &(xfc->invalidRegion), &invalidRect);
region16_union_rect(&surfaceDst->invalidRegion, &surfaceDst->invalidRegion, &invalidRect);
}
if (!xfc->inGfxFrame)
xf_OutputUpdate(xfc);
xf_UpdateSurfaces(xfc);
return 1;
}
@ -818,11 +925,11 @@ int xf_CacheToSurface(RdpgfxClientContext* context, RDPGFX_CACHE_TO_SURFACE_PDU*
invalidRect.right = destPt->x + cacheEntry->width - 1;
invalidRect.bottom = destPt->y + cacheEntry->height - 1;
region16_union_rect(&(xfc->invalidRegion), &(xfc->invalidRegion), &invalidRect);
region16_union_rect(&surface->invalidRegion, &surface->invalidRegion, &invalidRect);
}
if (!xfc->inGfxFrame)
xf_OutputUpdate(xfc);
xf_UpdateSurfaces(xfc);
return 1;
}
@ -851,9 +958,18 @@ 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;
xfc->outputSurfaceId = surfaceToOutput->surfaceId;
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;
region16_clear(&surface->invalidRegion);
ArrayList_Add(xfc->gfxMappedSurfaceIds, (void*) (ULONG_PTR) surfaceToOutput->surfaceId);
return 1;
}
@ -884,10 +1000,14 @@ void xf_graphics_pipeline_init(xfContext* xfc, RdpgfxClientContext* gfx)
gfx->MapSurfaceToOutput = xf_MapSurfaceToOutput;
gfx->MapSurfaceToWindow = xf_MapSurfaceToWindow;
region16_init(&(xfc->invalidRegion));
xfc->gfxMappedSurfaceIds = ArrayList_New(FALSE);
}
void xf_graphics_pipeline_uninit(xfContext* xfc, RdpgfxClientContext* gfx)
{
region16_uninit(&(xfc->invalidRegion));
if (xfc->gfxMappedSurfaceIds)
{
ArrayList_Free(xfc->gfxMappedSurfaceIds);
xfc->gfxMappedSurfaceIds = NULL;
}
}

View File

@ -25,6 +25,13 @@
#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;
@ -37,6 +44,19 @@ struct xf_gfx_surface
int scanline;
int stageStep;
UINT32 format;
struct
{
xfGfxMappingMode mode;
union
{
struct
{
UINT32 originX;
UINT32 originY;
} output;
};
} mapping;
REGION16 invalidRegion;
};
typedef struct xf_gfx_surface xfGfxSurface;

View File

@ -122,10 +122,9 @@ struct xf_context
UINT32 bitmap_size;
BYTE* bitmap_buffer;
BYTE* primary_buffer;
REGION16 invalidRegion;
BOOL inGfxFrame;
BOOL graphicsReset;
UINT16 outputSurfaceId;
wArrayList* gfxMappedSurfaceIds;
BOOL frame_begin;
UINT16 frame_x1;