From eeb7cd2cb2191ba082e4a68a5f3de823da99a7a6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Moreau?= Date: Fri, 13 Jun 2014 08:36:09 -0400 Subject: [PATCH] xfreerdp: initial egfx bitmap caching --- channels/rdpgfx/client/rdpgfx_main.c | 32 ++++++++ channels/rdpgfx/client/rdpgfx_main.h | 3 + client/X11/xf_gfx.c | 112 +++++++++++++++++++-------- client/X11/xf_gfx.h | 12 +++ include/freerdp/client/rdpgfx.h | 4 + include/freerdp/codec/color.h | 2 + libfreerdp/codec/color.c | 55 ++++++++++++- 7 files changed, 187 insertions(+), 33 deletions(-) diff --git a/channels/rdpgfx/client/rdpgfx_main.c b/channels/rdpgfx/client/rdpgfx_main.c index 66074976b..0bb29bb8c 100644 --- a/channels/rdpgfx/client/rdpgfx_main.c +++ b/channels/rdpgfx/client/rdpgfx_main.c @@ -60,6 +60,8 @@ int rdpgfx_send_caps_advertise_pdu(RDPGFX_CHANNEL_CALLBACK* callback) gfx->SmallCache = FALSE; gfx->H264 = FALSE; + gfx->MaxCacheSlot = (gfx->ThinClient) ? 4096 : 25600; + header.flags = 0; header.cmdId = RDPGFX_CMDID_CAPSADVERTISE; @@ -892,6 +894,31 @@ void* rdpgfx_get_surface_data(RdpgfxClientContext* context, UINT16 surfaceId) return pData; } +int rdpgfx_set_cache_slot_data(RdpgfxClientContext* context, UINT16 cacheSlot, void* pData) +{ + RDPGFX_PLUGIN* gfx = (RDPGFX_PLUGIN*) context->handle; + + if (cacheSlot >= gfx->MaxCacheSlot) + return -1; + + gfx->CacheSlots[cacheSlot] = pData; + + return 1; +} + +void* rdpgfx_get_cache_slot_data(RdpgfxClientContext* context, UINT16 cacheSlot) +{ + void* pData = NULL; + RDPGFX_PLUGIN* gfx = (RDPGFX_PLUGIN*) context->handle; + + if (cacheSlot >= gfx->MaxCacheSlot) + return NULL; + + pData = gfx->CacheSlots[cacheSlot]; + + return pData; +} + #ifdef STATIC_CHANNELS #define DVCPluginEntry rdpgfx_DVCPluginEntry #endif @@ -923,6 +950,9 @@ int DVCPluginEntry(IDRDYNVC_ENTRY_POINTS* pEntryPoints) if (!gfx->SurfaceTable) return -1; + gfx->ThinClient = TRUE; + gfx->MaxCacheSlot = (gfx->ThinClient) ? 4096 : 25600; + context = (RdpgfxClientContext*) calloc(1, sizeof(RdpgfxClientContext)); if (!context) @@ -932,6 +962,8 @@ int DVCPluginEntry(IDRDYNVC_ENTRY_POINTS* pEntryPoints) context->SetSurfaceData = rdpgfx_set_surface_data; context->GetSurfaceData = rdpgfx_get_surface_data; + context->SetCacheSlotData = rdpgfx_set_cache_slot_data; + context->GetCacheSlotData = rdpgfx_get_cache_slot_data; gfx->iface.pInterface = (void*) context; diff --git a/channels/rdpgfx/client/rdpgfx_main.h b/channels/rdpgfx/client/rdpgfx_main.h index da0e64822..e1dc362ea 100644 --- a/channels/rdpgfx/client/rdpgfx_main.h +++ b/channels/rdpgfx/client/rdpgfx_main.h @@ -69,6 +69,9 @@ struct _RDPGFX_PLUGIN UINT32 TotalDecodedFrames; wHashTable* SurfaceTable; + + UINT16 MaxCacheSlot; + void* CacheSlots[25600]; }; typedef struct _RDPGFX_PLUGIN RDPGFX_PLUGIN; diff --git a/client/X11/xf_gfx.c b/client/X11/xf_gfx.c index 3e27dd604..55dffb2c1 100644 --- a/client/X11/xf_gfx.c +++ b/client/X11/xf_gfx.c @@ -167,9 +167,6 @@ int xf_SurfaceCommand_Uncompressed(xfContext* xfc, RdpgfxClientContext* context, invalidRect.right = cmd->right; invalidRect.bottom = cmd->bottom; - printf("xf_SurfaceCommand_Uncompressed: x: %d y: %d w: %d h: %d r: %d b: %d\n", - cmd->left, cmd->top, cmd->width, cmd->height, cmd->right, cmd->bottom); - region16_union_rect(&(xfc->invalidRegion), &(xfc->invalidRegion), &invalidRect); if (!xfc->inGfxFrame) @@ -382,13 +379,19 @@ int xf_SolidFill(RdpgfxClientContext* context, RDPGFX_SOLID_FILL_PDU* solidFill) UINT16 index; UINT32 color; BYTE a, r, g, b; - XRectangle* xrects; + int nWidth, nHeight; RDPGFX_RECT16* rect; + xfGfxSurface* surface; RECTANGLE_16 invalidRect; xfContext* xfc = (xfContext*) context->custom; + surface = (xfGfxSurface*) context->GetSurfaceData(context, solidFill->surfaceId); + printf("xf_SolidFill\n"); + if (!surface) + return -1; + b = solidFill->fillPixel.B; g = solidFill->fillPixel.G; r = solidFill->fillPixel.R; @@ -396,36 +399,24 @@ int xf_SolidFill(RdpgfxClientContext* context, RDPGFX_SOLID_FILL_PDU* solidFill) color = ARGB32(a, r, g, b); - xrects = (XRectangle*) malloc(solidFill->fillRectCount * sizeof(XRectangle)); - - if (!xrects) - return -1; - for (index = 0; index < solidFill->fillRectCount; index++) { rect = &(solidFill->fillRects[index]); - xrects[index].x = rect->left; - xrects[index].y = rect->top; - xrects[index].width = rect->right - rect->left + 1; - xrects[index].height = rect->bottom - rect->top + 1; + nWidth = rect->right - rect->left; + nHeight = rect->bottom - rect->top; invalidRect.left = rect->left; invalidRect.top = rect->top; invalidRect.right = rect->right; invalidRect.bottom = rect->bottom; + freerdp_image_fill(surface->data, PIXEL_FORMAT_XRGB32, surface->scanline, + rect->left, rect->top, nWidth, nHeight, color); + region16_union_rect(&(xfc->invalidRegion), &(xfc->invalidRegion), &invalidRect); } - XSetFunction(xfc->display, xfc->gc, GXcopy); - XSetFillStyle(xfc->display, xfc->gc, FillSolid); - XSetForeground(xfc->display, xfc->gc, color); - - XFillRectangles(xfc->display, xfc->drawing, xfc->gc, xrects, solidFill->fillRectCount); - - free(xrects); - if (!xfc->inGfxFrame) xf_OutputUpdate(xfc); @@ -446,12 +437,6 @@ int xf_SurfaceToSurface(RdpgfxClientContext* context, RDPGFX_SURFACE_TO_SURFACE_ rectSrc = &(surfaceToSurface->rectSrc); destPt = &surfaceToSurface->destPts[0]; - printf("xf_SurfaceToSurface: srcId: %d dstId: %d rect: x: %d y: %d w: %d h: %d ptsCount: %d x: %d y: %d\n", - (int) surfaceToSurface->surfaceIdSrc, (int) surfaceToSurface->surfaceIdDest, - rectSrc->left, rectSrc->top, rectSrc->right - rectSrc->left, - rectSrc->bottom - rectSrc->top, (int) surfaceToSurface->destPtsCount, - destPt->x, destPt->y); - surfaceSrc = (xfGfxSurface*) context->GetSurfaceData(context, surfaceToSurface->surfaceIdSrc); if (surfaceToSurface->surfaceIdSrc != surfaceToSurface->surfaceIdDest) @@ -489,14 +474,80 @@ int xf_SurfaceToSurface(RdpgfxClientContext* context, RDPGFX_SURFACE_TO_SURFACE_ int xf_SurfaceToCache(RdpgfxClientContext* context, RDPGFX_SURFACE_TO_CACHE_PDU* surfaceToCache) { - printf("xf_SurfaceToCache\n"); + RDPGFX_RECT16* rect; + xfGfxSurface* surface; + xfGfxCacheEntry* cacheEntry; + + rect = &(surfaceToCache->rectSrc); + + surface = (xfGfxSurface*) context->GetSurfaceData(context, surfaceToCache->surfaceId); + + printf("xf_SurfaceToCache: cacheKey: 0x%016X cacheSlot: %ld\n", + surfaceToCache->cacheKey, surfaceToCache->cacheSlot); + + if (!surface) + return -1; + + cacheEntry = (xfGfxCacheEntry*) calloc(1, sizeof(xfGfxCacheEntry)); + + if (!cacheEntry) + return -1; + + cacheEntry->width = (UINT32) (rect->right - rect->left); + cacheEntry->height = (UINT32) (rect->bottom - rect->top); + cacheEntry->alpha = surface->alpha; + + cacheEntry->scanline = cacheEntry->width * 4; + cacheEntry->data = (BYTE*) calloc(1, surface->scanline * surface->height); + + if (!cacheEntry->data) + return -1; + + freerdp_image_copy(cacheEntry->data, PIXEL_FORMAT_XRGB32, cacheEntry->scanline, + 0, 0, cacheEntry->width, cacheEntry->height, surface->data, + PIXEL_FORMAT_XRGB32, surface->scanline, rect->left, rect->top); + + context->SetCacheSlotData(context, surfaceToCache->cacheSlot, (void*) cacheEntry); return 1; } int xf_CacheToSurface(RdpgfxClientContext* context, RDPGFX_CACHE_TO_SURFACE_PDU* cacheToSurface) { - printf("xf_CacheToSurface\n"); + UINT16 index; + RDPGFX_POINT16* destPt; + xfGfxSurface* surface; + xfGfxCacheEntry* cacheEntry; + RECTANGLE_16 invalidRect; + xfContext* xfc = (xfContext*) context->custom; + + surface = (xfGfxSurface*) context->GetSurfaceData(context, cacheToSurface->surfaceId); + cacheEntry = (xfGfxCacheEntry*) context->GetCacheSlotData(context, cacheToSurface->cacheSlot); + + printf("xf_CacheToSurface: cacheEntry: %d\n", + cacheToSurface->cacheSlot); + + if (!surface || !cacheEntry) + return -1; + + for (index = 0; index < cacheToSurface->destPtsCount; index++) + { + destPt = &cacheToSurface->destPts[index]; + + freerdp_image_copy(surface->data, PIXEL_FORMAT_XRGB32, surface->scanline, + destPt->x, destPt->y, cacheEntry->width, cacheEntry->height, + cacheEntry->data, PIXEL_FORMAT_XRGB32, cacheEntry->scanline, 0, 0); + + invalidRect.left = destPt->x; + invalidRect.top = destPt->y; + invalidRect.right = destPt->x + cacheEntry->width - 1; + invalidRect.bottom = destPt->y + cacheEntry->height - 1; + + region16_union_rect(&(xfc->invalidRegion), &(xfc->invalidRegion), &invalidRect); + } + + if (!xfc->inGfxFrame) + xf_OutputUpdate(xfc); return 1; } @@ -517,9 +568,6 @@ int xf_MapSurfaceToOutput(RdpgfxClientContext* context, RDPGFX_MAP_SURFACE_TO_OU { xfContext* xfc = (xfContext*) context->custom; - printf("xf_MapSurfaceToOutput: surfaceId: %d outputOriginX: %d outputOriginY: %d\n", - surfaceToOutput->surfaceId, surfaceToOutput->outputOriginX, surfaceToOutput->outputOriginY); - xfc->outputSurfaceId = surfaceToOutput->surfaceId; return 1; diff --git a/client/X11/xf_gfx.h b/client/X11/xf_gfx.h index 623df31b0..6451d258c 100644 --- a/client/X11/xf_gfx.h +++ b/client/X11/xf_gfx.h @@ -35,6 +35,18 @@ struct xf_gfx_surface }; typedef struct xf_gfx_surface xfGfxSurface; +struct xf_gfx_cache_entry +{ + UINT64 cacheKey; + UINT32 width; + UINT32 height; + BOOL alpha; + BYTE* data; + XImage* image; + int scanline; +}; +typedef struct xf_gfx_cache_entry xfGfxCacheEntry; + int xf_OutputExpose(xfContext* xfc, int x, int y, int width, int height); void xf_register_graphics_pipeline(xfContext* xfc, RdpgfxClientContext* gfx); diff --git a/include/freerdp/client/rdpgfx.h b/include/freerdp/client/rdpgfx.h index 64c1155a1..f44cfbbeb 100644 --- a/include/freerdp/client/rdpgfx.h +++ b/include/freerdp/client/rdpgfx.h @@ -47,6 +47,8 @@ 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 (*pcRdpgfxSetCacheSlotData)(RdpgfxClientContext* context, UINT16 cacheSlot, void* pData); +typedef void* (*pcRdpgfxGetCacheSlotData)(RdpgfxClientContext* context, UINT16 cacheSlot); struct _rdpgfx_client_context { @@ -72,6 +74,8 @@ struct _rdpgfx_client_context pcRdpgfxSetSurfaceData SetSurfaceData; pcRdpgfxGetSurfaceData GetSurfaceData; + pcRdpgfxSetCacheSlotData SetCacheSlotData; + pcRdpgfxGetCacheSlotData GetCacheSlotData; }; #endif /* FREERDP_CHANNEL_CLIENT_RDPGFX_H */ diff --git a/include/freerdp/codec/color.h b/include/freerdp/codec/color.h index 489aab960..0d72ed07c 100644 --- a/include/freerdp/codec/color.h +++ b/include/freerdp/codec/color.h @@ -398,6 +398,8 @@ FREERDP_API void freerdp_clrconv_free(HCLRCONV clrconv); FREERDP_API int freerdp_image_copy(BYTE* pDstData, DWORD dwDstFormat, int nDstStep, int nXDst, int nYDst, int nWidth, int nHeight, BYTE* pSrcData, DWORD dwSrcFormat, int nSrcStep, int nXSrc, int nYSrc); +FREERDP_API int freerdp_image_fill(BYTE* pDstData, DWORD dwDstFormat, int nDstStep, int nXDst, int nYDst, + int nWidth, int nHeight, UINT32 color); #ifdef __cplusplus } diff --git a/libfreerdp/codec/color.c b/libfreerdp/codec/color.c index f2fc9116d..bd5b1c238 100644 --- a/libfreerdp/codec/color.c +++ b/libfreerdp/codec/color.c @@ -1175,7 +1175,7 @@ void freerdp_clrconv_free(HCLRCONV clrconv) int freerdp_image_copy(BYTE* pDstData, DWORD dwDstFormat, int nDstStep, int nXDst, int nYDst, int nWidth, int nHeight, BYTE* pSrcData, DWORD dwSrcFormat, int nSrcStep, int nXSrc, int nYSrc) { - int y, x; + int x, y; BYTE a, r, g, b; int beg, end, inc; int srcBitsPerPixel; @@ -1350,3 +1350,56 @@ int freerdp_image_copy(BYTE* pDstData, DWORD dwDstFormat, int nDstStep, int nXDs return 0; } + +void* freerdp_image_memset32(UINT32* ptr, UINT32 fill, size_t length) +{ + while (length--) + { + *ptr++ = fill; + } + + return (void*) ptr; +} + +int freerdp_image_fill(BYTE* pDstData, DWORD dwDstFormat, int nDstStep, int nXDst, int nYDst, + int nWidth, int nHeight, UINT32 color) +{ + int y; + int dstBitsPerPixel; + int dstBytesPerPixel; + + dstBitsPerPixel = FREERDP_PIXEL_FORMAT_DEPTH(dwDstFormat); + dstBytesPerPixel = (FREERDP_PIXEL_FORMAT_BPP(dwDstFormat) / 8); + + if (dstBytesPerPixel == 4) + { + UINT32* pDstPixel; + + if (nDstStep < 0) + nDstStep = dstBytesPerPixel * nWidth; + + for (y = 0; y < nHeight; y++) + { + pDstPixel = (UINT32*) &pDstData[((nYDst + y) * nDstStep) + (nXDst * dstBytesPerPixel)]; + freerdp_image_memset32(pDstPixel, color, nWidth); + } + } + else if (dstBytesPerPixel == 3) + { + + } + else if (dstBytesPerPixel == 2) + { + if (dstBitsPerPixel == 16) + { + + } + else if (dstBitsPerPixel == 15) + { + + } + } + + return 0; +} +