From 198f94fe03e75ed233e5b8e93faa59619d521b22 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Moreau?= Date: Fri, 12 Sep 2014 14:57:44 -0400 Subject: [PATCH] libfreerdp-gdi: add RDP8 graphics pipeline support --- client/X11/xf_channels.c | 12 +- client/X11/xf_gfx.c | 51 +- client/X11/xf_gfx.h | 2 + include/freerdp/codec/clear.h | 2 +- include/freerdp/codec/h264.h | 2 + include/freerdp/codec/interleaved.h | 2 + include/freerdp/codec/nsc.h | 7 +- include/freerdp/codec/planar.h | 2 + include/freerdp/codec/progressive.h | 2 +- include/freerdp/codec/rfx.h | 8 +- include/freerdp/codecs.h | 2 + include/freerdp/gdi/gdi.h | 9 + include/freerdp/gdi/gfx.h | 52 ++ libfreerdp/codec/clear.c | 3 +- libfreerdp/codec/h264.c | 5 + libfreerdp/codec/interleaved.c | 5 + libfreerdp/codec/nsc.c | 5 + libfreerdp/codec/planar.c | 5 + libfreerdp/codec/progressive.c | 84 ++- libfreerdp/codec/rfx.c | 3 +- libfreerdp/core/codecs.c | 66 +++ libfreerdp/gdi/CMakeLists.txt | 1 + libfreerdp/gdi/gdi.c | 1 + libfreerdp/gdi/gfx.c | 817 ++++++++++++++++++++++++++++ 24 files changed, 1071 insertions(+), 77 deletions(-) create mode 100644 include/freerdp/gdi/gfx.h create mode 100644 libfreerdp/gdi/gfx.c diff --git a/client/X11/xf_channels.c b/client/X11/xf_channels.c index e8e06ab31..9eabd86e8 100644 --- a/client/X11/xf_channels.c +++ b/client/X11/xf_channels.c @@ -31,6 +31,7 @@ void xf_OnChannelConnectedEventHandler(rdpContext* context, ChannelConnectedEventArgs* e) { xfContext* xfc = (xfContext*) context; + rdpSettings* settings = context->settings; if (strcmp(e->name, RDPEI_DVC_CHANNEL_NAME) == 0) { @@ -38,7 +39,10 @@ void xf_OnChannelConnectedEventHandler(rdpContext* context, ChannelConnectedEven } else if (strcmp(e->name, RDPGFX_DVC_CHANNEL_NAME) == 0) { - xf_graphics_pipeline_init(xfc, (RdpgfxClientContext*) e->pInterface); + if (settings->SoftwareGdi) + gdi_graphics_pipeline_init(context->gdi, (RdpgfxClientContext*) e->pInterface); + else + xf_graphics_pipeline_init(xfc, (RdpgfxClientContext*) e->pInterface); } else if (strcmp(e->name, ENCOMSP_SVC_CHANNEL_NAME) == 0) { @@ -49,6 +53,7 @@ void xf_OnChannelConnectedEventHandler(rdpContext* context, ChannelConnectedEven void xf_OnChannelDisconnectedEventHandler(rdpContext* context, ChannelDisconnectedEventArgs* e) { xfContext* xfc = (xfContext*) context; + rdpSettings* settings = context->settings; if (strcmp(e->name, RDPEI_DVC_CHANNEL_NAME) == 0) { @@ -56,7 +61,10 @@ void xf_OnChannelDisconnectedEventHandler(rdpContext* context, ChannelDisconnect } else if (strcmp(e->name, RDPGFX_DVC_CHANNEL_NAME) == 0) { - xf_graphics_pipeline_uninit(xfc, (RdpgfxClientContext*) e->pInterface); + if (settings->SoftwareGdi) + gdi_graphics_pipeline_uninit(context->gdi, (RdpgfxClientContext*) e->pInterface); + else + xf_graphics_pipeline_uninit(xfc, (RdpgfxClientContext*) e->pInterface); } else if (strcmp(e->name, ENCOMSP_SVC_CHANNEL_NAME) == 0) { diff --git a/client/X11/xf_gfx.c b/client/X11/xf_gfx.c index 476679364..5b67af51a 100644 --- a/client/X11/xf_gfx.c +++ b/client/X11/xf_gfx.c @@ -27,53 +27,7 @@ int xf_ResetGraphics(RdpgfxClientContext* context, RDPGFX_RESET_GRAPHICS_PDU* re { xfContext* xfc = (xfContext*) context->custom; - if (xfc->codecs->rfx) - { - rfx_context_free(xfc->codecs->rfx); - xfc->codecs->rfx = NULL; - } - - xfc->codecs->rfx = rfx_context_new(FALSE); - - xfc->codecs->rfx->width = resetGraphics->width; - xfc->codecs->rfx->height = resetGraphics->height; - rfx_context_set_pixel_format(xfc->codecs->rfx, RDP_PIXEL_FORMAT_B8G8R8A8); - - if (xfc->codecs->nsc) - { - nsc_context_free(xfc->codecs->nsc); - xfc->codecs->nsc = NULL; - } - - xfc->codecs->nsc = nsc_context_new(); - - xfc->codecs->nsc->width = resetGraphics->width; - xfc->codecs->nsc->height = resetGraphics->height; - nsc_context_set_pixel_format(xfc->codecs->nsc, RDP_PIXEL_FORMAT_B8G8R8A8); - - if (xfc->codecs->clear) - { - clear_context_free(xfc->codecs->clear); - xfc->codecs->clear = NULL; - } - - xfc->codecs->clear = clear_context_new(FALSE); - - if (xfc->codecs->h264) - { - h264_context_free(xfc->codecs->h264); - xfc->codecs->h264 = NULL; - } - - xfc->codecs->h264 = h264_context_new(FALSE); - - if (xfc->codecs->progressive) - { - progressive_context_free(xfc->codecs->progressive); - xfc->codecs->progressive = NULL; - } - - xfc->codecs->progressive = progressive_context_new(TRUE); + freerdp_client_codecs_reset(xfc->codecs, FREERDP_CODEC_ALL); region16_init(&(xfc->invalidRegion)); @@ -618,7 +572,8 @@ int xf_DeleteSurface(RdpgfxClientContext* context, RDPGFX_DELETE_SURFACE_PDU* de context->SetSurfaceData(context, deleteSurface->surfaceId, NULL); - progressive_delete_surface_context(xfc->codecs->progressive, deleteSurface->surfaceId); + if (xfc->codecs->progressive) + progressive_delete_surface_context(xfc->codecs->progressive, deleteSurface->surfaceId); return 1; } diff --git a/client/X11/xf_gfx.h b/client/X11/xf_gfx.h index ba937ee92..4b650259a 100644 --- a/client/X11/xf_gfx.h +++ b/client/X11/xf_gfx.h @@ -23,6 +23,8 @@ #include "xf_client.h" #include "xfreerdp.h" +#include + struct xf_gfx_surface { UINT16 surfaceId; diff --git a/include/freerdp/codec/clear.h b/include/freerdp/codec/clear.h index e49d1d572..cc946d578 100644 --- a/include/freerdp/codec/clear.h +++ b/include/freerdp/codec/clear.h @@ -71,7 +71,7 @@ FREERDP_API int clear_compress(CLEAR_CONTEXT* clear, BYTE* pSrcData, UINT32 SrcS FREERDP_API int clear_decompress(CLEAR_CONTEXT* clear, BYTE* pSrcData, UINT32 SrcSize, BYTE** ppDstData, DWORD DstFormat, int nDstStep, int nXDst, int nYDst, int nWidth, int nHeight); -FREERDP_API void clear_context_reset(CLEAR_CONTEXT* clear); +FREERDP_API int clear_context_reset(CLEAR_CONTEXT* clear); FREERDP_API CLEAR_CONTEXT* clear_context_new(BOOL Compressor); FREERDP_API void clear_context_free(CLEAR_CONTEXT* clear); diff --git a/include/freerdp/codec/h264.h b/include/freerdp/codec/h264.h index e539cb0b3..8e835a9e7 100644 --- a/include/freerdp/codec/h264.h +++ b/include/freerdp/codec/h264.h @@ -63,6 +63,8 @@ FREERDP_API int h264_compress(H264_CONTEXT* h264, BYTE* pSrcData, UINT32 SrcSize FREERDP_API int h264_decompress(H264_CONTEXT* h264, BYTE* pSrcData, UINT32 SrcSize, BYTE** ppDstData, DWORD DstFormat, int nDstStep, int nDstHeight, RDPGFX_RECT16* regionRects, int numRegionRect); +FREERDP_API int h264_context_reset(H264_CONTEXT* h264); + FREERDP_API H264_CONTEXT* h264_context_new(BOOL Compressor); FREERDP_API void h264_context_free(H264_CONTEXT* h264); diff --git a/include/freerdp/codec/interleaved.h b/include/freerdp/codec/interleaved.h index 2eb9febca..dfc0afb52 100644 --- a/include/freerdp/codec/interleaved.h +++ b/include/freerdp/codec/interleaved.h @@ -39,6 +39,8 @@ struct _BITMAP_INTERLEAVED_CONTEXT FREERDP_API int interleaved_decompress(BITMAP_INTERLEAVED_CONTEXT* interleaved, BYTE* pSrcData, UINT32 SrcSize, int bpp, BYTE** ppDstData, DWORD DstFormat, int nDstStep, int nXDst, int nYDst, int nWidth, int nHeight); +FREERDP_API int bitmap_interleaved_context_reset(BITMAP_INTERLEAVED_CONTEXT* interleaved); + FREERDP_API BITMAP_INTERLEAVED_CONTEXT* bitmap_interleaved_context_new(BOOL Compressor); FREERDP_API void bitmap_interleaved_context_free(BITMAP_INTERLEAVED_CONTEXT* interleaved); diff --git a/include/freerdp/codec/nsc.h b/include/freerdp/codec/nsc.h index ebd5a416b..951a46f94 100644 --- a/include/freerdp/codec/nsc.h +++ b/include/freerdp/codec/nsc.h @@ -82,19 +82,22 @@ struct _NSC_CONTEXT NSC_CONTEXT_PRIV* priv; }; -FREERDP_API NSC_CONTEXT* nsc_context_new(void); FREERDP_API void nsc_context_set_pixel_format(NSC_CONTEXT* context, RDP_PIXEL_FORMAT pixel_format); FREERDP_API int nsc_process_message(NSC_CONTEXT* context, UINT16 bpp, UINT16 width, UINT16 height, BYTE* data, UINT32 length); FREERDP_API void nsc_compose_message(NSC_CONTEXT* context, wStream* s, BYTE* bmpdata, int width, int height, int rowstride); -FREERDP_API void nsc_context_free(NSC_CONTEXT* context); FREERDP_API NSC_MESSAGE* nsc_encode_messages(NSC_CONTEXT* context, BYTE* data, int x, int y, int width, int height, int scanline, int* numMessages, int maxDataSize); FREERDP_API int nsc_write_message(NSC_CONTEXT* context, wStream* s, NSC_MESSAGE* message); FREERDP_API int nsc_message_free(NSC_CONTEXT* context, NSC_MESSAGE* message); +FREERDP_API int nsc_context_reset(NSC_CONTEXT* context); + +FREERDP_API NSC_CONTEXT* nsc_context_new(void); +FREERDP_API void nsc_context_free(NSC_CONTEXT* context); + #ifdef __cplusplus } #endif diff --git a/include/freerdp/codec/planar.h b/include/freerdp/codec/planar.h index a06f2db3d..218295c92 100644 --- a/include/freerdp/codec/planar.h +++ b/include/freerdp/codec/planar.h @@ -102,6 +102,8 @@ FREERDP_API int freerdp_bitmap_planar_delta_encode_planes(BYTE* inPlanes[4], int FREERDP_API BYTE* freerdp_bitmap_compress_planar(BITMAP_PLANAR_CONTEXT* context, BYTE* data, UINT32 format, int width, int height, int scanline, BYTE* dstData, int* dstSize); +FREERDP_API int freerdp_bitmap_planar_context_reset(BITMAP_PLANAR_CONTEXT* context); + FREERDP_API BITMAP_PLANAR_CONTEXT* freerdp_bitmap_planar_context_new(DWORD flags, int maxWidth, int maxHeight); FREERDP_API void freerdp_bitmap_planar_context_free(BITMAP_PLANAR_CONTEXT* context); diff --git a/include/freerdp/codec/progressive.h b/include/freerdp/codec/progressive.h index be702a158..8bc0b935e 100644 --- a/include/freerdp/codec/progressive.h +++ b/include/freerdp/codec/progressive.h @@ -316,7 +316,7 @@ FREERDP_API int progressive_decompress(PROGRESSIVE_CONTEXT* progressive, BYTE* p FREERDP_API int progressive_create_surface_context(PROGRESSIVE_CONTEXT* progressive, UINT16 surfaceId, UINT32 width, UINT32 height); FREERDP_API int progressive_delete_surface_context(PROGRESSIVE_CONTEXT* progressive, UINT16 surfaceId); -FREERDP_API void progressive_context_reset(PROGRESSIVE_CONTEXT* progressive); +FREERDP_API int progressive_context_reset(PROGRESSIVE_CONTEXT* progressive); FREERDP_API PROGRESSIVE_CONTEXT* progressive_context_new(BOOL Compressor); FREERDP_API void progressive_context_free(PROGRESSIVE_CONTEXT* progressive); diff --git a/include/freerdp/codec/rfx.h b/include/freerdp/codec/rfx.h index 2a68d14d7..c6ee0c937 100644 --- a/include/freerdp/codec/rfx.h +++ b/include/freerdp/codec/rfx.h @@ -153,10 +153,7 @@ struct _RFX_CONTEXT RFX_CONTEXT_PRIV* priv; }; -FREERDP_API RFX_CONTEXT* rfx_context_new(BOOL encoder); -FREERDP_API void rfx_context_free(RFX_CONTEXT* context); FREERDP_API void rfx_context_set_pixel_format(RFX_CONTEXT* context, RDP_PIXEL_FORMAT pixel_format); -FREERDP_API void rfx_context_reset(RFX_CONTEXT* context); FREERDP_API int rfx_rlgr_decode(const BYTE* pSrcData, UINT32 SrcSize, INT16* pDstData, UINT32 DstSize, int mode); @@ -177,6 +174,11 @@ FREERDP_API RFX_MESSAGE* rfx_encode_messages(RFX_CONTEXT* context, const RFX_REC BYTE* data, int width, int height, int scanline, int* numMessages, int maxDataSize); FREERDP_API void rfx_write_message(RFX_CONTEXT* context, wStream* s, RFX_MESSAGE* message); +FREERDP_API int rfx_context_reset(RFX_CONTEXT* context); + +FREERDP_API RFX_CONTEXT* rfx_context_new(BOOL encoder); +FREERDP_API void rfx_context_free(RFX_CONTEXT* context); + #ifdef __cplusplus } #endif diff --git a/include/freerdp/codecs.h b/include/freerdp/codecs.h index 15b311415..2f1e4d4ab 100644 --- a/include/freerdp/codecs.h +++ b/include/freerdp/codecs.h @@ -40,6 +40,7 @@ #define FREERDP_CODEC_ALPHACODEC 0x00000020 #define FREERDP_CODEC_PROGRESSIVE 0x00000040 #define FREERDP_CODEC_H264 0x00000080 +#define FREERDP_CODEC_ALL 0xFFFFFFFF struct rdp_codecs { @@ -55,6 +56,7 @@ struct rdp_codecs }; FREERDP_API int freerdp_client_codecs_prepare(rdpCodecs* codecs, UINT32 flags); +FREERDP_API int freerdp_client_codecs_reset(rdpCodecs* codecs, UINT32 flags); FREERDP_API rdpCodecs* codecs_new(rdpContext* context); FREERDP_API void codecs_free(rdpCodecs* codecs); diff --git a/include/freerdp/gdi/gdi.h b/include/freerdp/gdi/gdi.h index 878ec4341..34125061e 100644 --- a/include/freerdp/gdi/gdi.h +++ b/include/freerdp/gdi/gdi.h @@ -25,6 +25,9 @@ #include #include #include +#include + +#include /* For more information, see [MS-RDPEGDI] */ @@ -291,6 +294,12 @@ struct rdp_gdi GDI_COLOR textColor; gdiBitmap* tile; gdiBitmap* image; + + BOOL inGfxFrame; + BOOL graphicsReset; + UINT16 outputSurfaceId; + REGION16 invalidRegion; + RdpgfxClientContext* gfx; }; #ifdef __cplusplus diff --git a/include/freerdp/gdi/gfx.h b/include/freerdp/gdi/gfx.h new file mode 100644 index 000000000..12d3a2ec3 --- /dev/null +++ b/include/freerdp/gdi/gfx.h @@ -0,0 +1,52 @@ +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * GDI Graphics Pipeline + * + * Copyright 2014 Marc-Andre Moreau + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef FREERDP_GDI_GFX_H +#define FREERDP_GDI_GFX_H + +#include +#include + +struct gdi_gfx_surface +{ + UINT16 surfaceId; + UINT32 width; + UINT32 height; + BOOL alpha; + BYTE* data; + int scanline; +}; +typedef struct gdi_gfx_surface gdiGfxSurface; + +struct gdi_gfx_cache_entry +{ + UINT64 cacheKey; + UINT32 width; + UINT32 height; + BOOL alpha; + BYTE* data; + int scanline; +}; +typedef struct gdi_gfx_cache_entry gdiGfxCacheEntry; + +FREERDP_API void gdi_graphics_pipeline_init(rdpGdi* gdi, RdpgfxClientContext* gfx); +FREERDP_API void gdi_graphics_pipeline_uninit(rdpGdi* gdi, RdpgfxClientContext* gfx); + +#endif /* FREERDP_GDI_GFX_H */ + diff --git a/libfreerdp/codec/clear.c b/libfreerdp/codec/clear.c index 35b6c04a5..cb00986f0 100644 --- a/libfreerdp/codec/clear.c +++ b/libfreerdp/codec/clear.c @@ -751,11 +751,12 @@ int clear_compress(CLEAR_CONTEXT* clear, BYTE* pSrcData, UINT32 SrcSize, BYTE** return 1; } -void clear_context_reset(CLEAR_CONTEXT* clear) +int clear_context_reset(CLEAR_CONTEXT* clear) { clear->seqNumber = 0; clear->VBarStorageCursor = 0; clear->ShortVBarStorageCursor = 0; + return 1; } CLEAR_CONTEXT* clear_context_new(BOOL Compressor) diff --git a/libfreerdp/codec/h264.c b/libfreerdp/codec/h264.c index cf5d2be58..5043a6678 100644 --- a/libfreerdp/codec/h264.c +++ b/libfreerdp/codec/h264.c @@ -510,6 +510,11 @@ BOOL h264_context_init(H264_CONTEXT* h264) return FALSE; } +int h264_context_reset(H264_CONTEXT* h264) +{ + return 1; +} + H264_CONTEXT* h264_context_new(BOOL Compressor) { H264_CONTEXT* h264; diff --git a/libfreerdp/codec/interleaved.c b/libfreerdp/codec/interleaved.c index 3e2cfb3a3..c17bac727 100644 --- a/libfreerdp/codec/interleaved.c +++ b/libfreerdp/codec/interleaved.c @@ -344,6 +344,11 @@ int interleaved_decompress(BITMAP_INTERLEAVED_CONTEXT* interleaved, BYTE* pSrcDa return 1; } +int bitmap_interleaved_context_reset(BITMAP_INTERLEAVED_CONTEXT* interleaved) +{ + return 1; +} + BITMAP_INTERLEAVED_CONTEXT* bitmap_interleaved_context_new(BOOL Compressor) { BITMAP_INTERLEAVED_CONTEXT* interleaved; diff --git a/libfreerdp/codec/nsc.c b/libfreerdp/codec/nsc.c index 3379e5a49..c412302d9 100644 --- a/libfreerdp/codec/nsc.c +++ b/libfreerdp/codec/nsc.c @@ -252,6 +252,11 @@ static void nsc_profiler_print(NSC_CONTEXT* context) PROFILER_PRINT_FOOTER; } +int nsc_context_reset(NSC_CONTEXT* context) +{ + return 1; +} + NSC_CONTEXT* nsc_context_new(void) { UINT8 i; diff --git a/libfreerdp/codec/planar.c b/libfreerdp/codec/planar.c index 7c08cc0eb..5f8187bbf 100644 --- a/libfreerdp/codec/planar.c +++ b/libfreerdp/codec/planar.c @@ -1107,6 +1107,11 @@ BYTE* freerdp_bitmap_compress_planar(BITMAP_PLANAR_CONTEXT* context, BYTE* data, return dstData; } +int freerdp_bitmap_planar_context_reset(BITMAP_PLANAR_CONTEXT* context) +{ + return 1; +} + BITMAP_PLANAR_CONTEXT* freerdp_bitmap_planar_context_new(DWORD flags, int maxWidth, int maxHeight) { BITMAP_PLANAR_CONTEXT* context; diff --git a/libfreerdp/codec/progressive.c b/libfreerdp/codec/progressive.c index a8d042fda..4c9aaa580 100644 --- a/libfreerdp/codec/progressive.c +++ b/libfreerdp/codec/progressive.c @@ -247,6 +247,53 @@ void* progressive_get_surface_data(PROGRESSIVE_CONTEXT* progressive, UINT16 surf return pData; } +PROGRESSIVE_SURFACE_CONTEXT* progressive_surface_context_new(UINT16 surfaceId, UINT32 width, UINT32 height) +{ + PROGRESSIVE_SURFACE_CONTEXT* surface; + + surface = (PROGRESSIVE_SURFACE_CONTEXT*) calloc(1, sizeof(PROGRESSIVE_SURFACE_CONTEXT)); + + if (!surface) + return NULL; + + surface->id = surfaceId; + surface->width = width; + surface->height = height; + surface->gridWidth = (width + (width % 64)) / 64; + surface->gridHeight = (height + (height % 64)) / 64; + surface->gridSize = surface->gridWidth * surface->gridHeight; + + surface->tiles = (RFX_PROGRESSIVE_TILE*) calloc(surface->gridSize, sizeof(RFX_PROGRESSIVE_TILE)); + + if (!surface->tiles) + return NULL; + + return surface; +} + +void progressive_surface_context_free(PROGRESSIVE_SURFACE_CONTEXT* surface) +{ + UINT32 index; + RFX_PROGRESSIVE_TILE* tile; + + for (index = 0; index < surface->gridSize; index++) + { + tile = &(surface->tiles[index]); + + if (tile->data) + _aligned_free(tile->data); + + if (tile->sign) + _aligned_free(tile->sign); + + if (tile->current) + _aligned_free(tile->current); + } + + free(surface->tiles); + free(surface); +} + int progressive_create_surface_context(PROGRESSIVE_CONTEXT* progressive, UINT16 surfaceId, UINT32 width, UINT32 height) { PROGRESSIVE_SURFACE_CONTEXT* surface; @@ -255,23 +302,11 @@ int progressive_create_surface_context(PROGRESSIVE_CONTEXT* progressive, UINT16 if (!surface) { - surface = (PROGRESSIVE_SURFACE_CONTEXT*) malloc(sizeof(PROGRESSIVE_SURFACE_CONTEXT)); + surface = progressive_surface_context_new(surfaceId, width, height); if (!surface) return -1; - surface->id = surfaceId; - surface->width = width; - surface->height = height; - surface->gridWidth = (width + (width % 64)) / 64; - surface->gridHeight = (height + (height % 64)) / 64; - surface->gridSize = surface->gridWidth * surface->gridHeight; - - surface->tiles = (RFX_PROGRESSIVE_TILE*) calloc(surface->gridSize, sizeof(RFX_PROGRESSIVE_TILE)); - - if (!surface->tiles) - return -1; - progressive_set_surface_data(progressive, surfaceId, (void*) surface); } @@ -287,9 +322,7 @@ int progressive_delete_surface_context(PROGRESSIVE_CONTEXT* progressive, UINT16 if (surface) { progressive_set_surface_data(progressive, surfaceId, NULL); - - free(surface->tiles); - free(surface); + progressive_surface_context_free(surface); } return 1; @@ -1758,9 +1791,9 @@ int progressive_compress(PROGRESSIVE_CONTEXT* progressive, BYTE* pSrcData, UINT3 return 1; } -void progressive_context_reset(PROGRESSIVE_CONTEXT* progressive) +int progressive_context_reset(PROGRESSIVE_CONTEXT* progressive) { - + return 1; } PROGRESSIVE_CONTEXT* progressive_context_new(BOOL Compressor) @@ -1814,6 +1847,11 @@ PROGRESSIVE_CONTEXT* progressive_context_new(BOOL Compressor) void progressive_context_free(PROGRESSIVE_CONTEXT* progressive) { + int count; + int index; + ULONG_PTR* pKeys = NULL; + PROGRESSIVE_SURFACE_CONTEXT* surface; + if (!progressive) return; @@ -1824,6 +1862,16 @@ void progressive_context_free(PROGRESSIVE_CONTEXT* progressive) free(progressive->quantVals); free(progressive->quantProgVals); + count = HashTable_GetKeys(progressive->SurfaceContexts, &pKeys); + + for (index = 0; index < count; index++) + { + surface = (PROGRESSIVE_SURFACE_CONTEXT*) HashTable_GetItemValue(progressive->SurfaceContexts, (void*) pKeys[index]); + progressive_surface_context_free(surface); + } + + free(pKeys); + HashTable_Free(progressive->SurfaceContexts); free(progressive); diff --git a/libfreerdp/codec/rfx.c b/libfreerdp/codec/rfx.c index 3f23c6818..6a9743f35 100644 --- a/libfreerdp/codec/rfx.c +++ b/libfreerdp/codec/rfx.c @@ -416,10 +416,11 @@ void rfx_context_set_pixel_format(RFX_CONTEXT* context, RDP_PIXEL_FORMAT pixel_f } } -void rfx_context_reset(RFX_CONTEXT* context) +int rfx_context_reset(RFX_CONTEXT* context) { context->state = RFX_STATE_SEND_HEADERS; context->frameIdx = 0; + return 1; } static BOOL rfx_process_message_sync(RFX_CONTEXT* context, wStream* s) diff --git a/libfreerdp/core/codecs.c b/libfreerdp/core/codecs.c index 7aaf1367a..a29024245 100644 --- a/libfreerdp/core/codecs.c +++ b/libfreerdp/core/codecs.c @@ -91,6 +91,72 @@ int freerdp_client_codecs_prepare(rdpCodecs* codecs, UINT32 flags) return 1; } +int freerdp_client_codecs_reset(rdpCodecs* codecs, UINT32 flags) +{ + if (flags & FREERDP_CODEC_INTERLEAVED) + { + if (codecs->interleaved) + { + bitmap_interleaved_context_reset(codecs->interleaved); + } + } + + if (flags & FREERDP_CODEC_PLANAR) + { + if (codecs->planar) + { + freerdp_bitmap_planar_context_reset(codecs->planar); + } + } + + if (flags & FREERDP_CODEC_NSCODEC) + { + if (codecs->nsc) + { + nsc_context_reset(codecs->nsc); + } + } + + if (flags & FREERDP_CODEC_REMOTEFX) + { + if (codecs->rfx) + { + rfx_context_reset(codecs->rfx); + } + } + + if (flags & FREERDP_CODEC_CLEARCODEC) + { + if (codecs->clear) + { + clear_context_reset(codecs->clear); + } + } + + if (flags & FREERDP_CODEC_ALPHACODEC) + { + + } + + if (flags & FREERDP_CODEC_PROGRESSIVE) + { + if (codecs->progressive) + { + progressive_context_reset(codecs->progressive); + } + } + + if (flags & FREERDP_CODEC_H264) + { + if (codecs->h264) + { + h264_context_reset(codecs->h264); + } + } + + return 1; +} + rdpCodecs* codecs_new(rdpContext* context) { rdpCodecs* codecs; diff --git a/libfreerdp/gdi/CMakeLists.txt b/libfreerdp/gdi/CMakeLists.txt index c831bbd04..0a2624385 100644 --- a/libfreerdp/gdi/CMakeLists.txt +++ b/libfreerdp/gdi/CMakeLists.txt @@ -36,6 +36,7 @@ set(${MODULE_PREFIX}_SRCS shape.c graphics.c graphics.h + gfx.c gdi.c gdi.h) diff --git a/libfreerdp/gdi/gdi.c b/libfreerdp/gdi/gdi.c index 672e3bc45..03d85b8c5 100644 --- a/libfreerdp/gdi/gdi.c +++ b/libfreerdp/gdi/gdi.c @@ -1139,6 +1139,7 @@ int gdi_init(freerdp* instance, UINT32 flags, BYTE* buffer) return -1; instance->context->gdi = gdi; + gdi->context = instance->context; cache = instance->context->cache; gdi->codecs = instance->context->codecs; diff --git a/libfreerdp/gdi/gfx.c b/libfreerdp/gdi/gfx.c new file mode 100644 index 000000000..5b7638aeb --- /dev/null +++ b/libfreerdp/gdi/gfx.c @@ -0,0 +1,817 @@ +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * GDI Graphics Pipeline + * + * Copyright 2014 Marc-Andre Moreau + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include + +int gdi_ResetGraphics(RdpgfxClientContext* context, RDPGFX_RESET_GRAPHICS_PDU* resetGraphics) +{ + rdpGdi* gdi = (rdpGdi*) context->custom; + + freerdp_client_codecs_reset(gdi->codecs, FREERDP_CODEC_ALL); + + region16_init(&(gdi->invalidRegion)); + + gdi->graphicsReset = TRUE; + + return 1; +} + +int gdi_OutputUpdate(rdpGdi* gdi) +{ + int nDstStep; + BYTE* pDstData; + int nXDst, nYDst; + int nXSrc, nYSrc; + int nWidth, nHeight; + gdiGfxSurface* surface; + RECTANGLE_16 surfaceRect; + const RECTANGLE_16* extents; + rdpUpdate* update = gdi->context->update; + + if (!gdi->graphicsReset) + return 1; + + nDstStep = gdi->width * 4; + pDstData = gdi->primary_buffer; + + surface = (gdiGfxSurface*) gdi->gfx->GetSurfaceData(gdi->gfx, gdi->outputSurfaceId); + + if (!surface) + return -1; + + surfaceRect.left = 0; + surfaceRect.top = 0; + surfaceRect.right = gdi->width; + surfaceRect.bottom = gdi->height; + + region16_intersect_rect(&(gdi->invalidRegion), &(gdi->invalidRegion), &surfaceRect); + + if (!region16_is_empty(&(gdi->invalidRegion))) + { + extents = region16_extents(&(gdi->invalidRegion)); + + nXDst = extents->left; + nYDst = extents->top; + + nXSrc = extents->left; + nYSrc = extents->top; + + nWidth = extents->right - extents->left; + nHeight = extents->bottom - extents->top; + + update->BeginPaint(gdi->context); + + freerdp_image_copy(pDstData, PIXEL_FORMAT_XRGB32, nDstStep, nXDst, nYDst, nWidth, nHeight, + surface->data, PIXEL_FORMAT_XRGB32, surface->scanline, nXSrc, nYSrc); + + gdi_InvalidateRegion(gdi->primary->hdc, nXDst, nYDst, nWidth, nHeight); + + update->EndPaint(gdi->context); + } + + region16_clear(&(gdi->invalidRegion)); + + return 1; +} + +int gdi_OutputExpose(rdpGdi* gdi, int x, int y, int width, int height) +{ + RECTANGLE_16 invalidRect; + + invalidRect.left = x; + invalidRect.top = y; + invalidRect.right = x + width; + invalidRect.bottom = y + height; + + region16_union_rect(&(gdi->invalidRegion), &(gdi->invalidRegion), &invalidRect); + + gdi_OutputUpdate(gdi); + + return 1; +} + +int gdi_StartFrame(RdpgfxClientContext* context, RDPGFX_START_FRAME_PDU* startFrame) +{ + rdpGdi* gdi = (rdpGdi*) context->custom; + + gdi->inGfxFrame = TRUE; + + return 1; +} + +int gdi_EndFrame(RdpgfxClientContext* context, RDPGFX_END_FRAME_PDU* endFrame) +{ + rdpGdi* gdi = (rdpGdi*) context->custom; + + gdi_OutputUpdate(gdi); + + gdi->inGfxFrame = FALSE; + + return 1; +} + +int gdi_SurfaceCommand_Uncompressed(rdpGdi* gdi, RdpgfxClientContext* context, RDPGFX_SURFACE_COMMAND* cmd) +{ + gdiGfxSurface* surface; + RECTANGLE_16 invalidRect; + + surface = (gdiGfxSurface*) context->GetSurfaceData(context, cmd->surfaceId); + + if (!surface) + return -1; + + freerdp_image_copy(surface->data, PIXEL_FORMAT_XRGB32, surface->scanline, cmd->left, cmd->top, + cmd->width, cmd->height, cmd->data, PIXEL_FORMAT_XRGB32, cmd->width * 4, 0, 0); + + invalidRect.left = cmd->left; + invalidRect.top = cmd->top; + invalidRect.right = cmd->right; + invalidRect.bottom = cmd->bottom; + + region16_union_rect(&(gdi->invalidRegion), &(gdi->invalidRegion), &invalidRect); + + if (!gdi->inGfxFrame) + gdi_OutputUpdate(gdi); + + return 1; +} + +int gdi_SurfaceCommand_RemoteFX(rdpGdi* gdi, RdpgfxClientContext* context, RDPGFX_SURFACE_COMMAND* cmd) +{ + int j; + UINT16 i; + RFX_RECT* rect; + RFX_TILE* tile; + int nXDst, nYDst; + int nWidth, nHeight; + int nbUpdateRects; + RFX_MESSAGE* message; + gdiGfxSurface* surface; + REGION16 updateRegion; + RECTANGLE_16 updateRect; + RECTANGLE_16* updateRects; + REGION16 clippingRects; + RECTANGLE_16 clippingRect; + + freerdp_client_codecs_prepare(gdi->codecs, FREERDP_CODEC_REMOTEFX); + + surface = (gdiGfxSurface*) context->GetSurfaceData(context, cmd->surfaceId); + + if (!surface) + return -1; + + message = rfx_process_message(gdi->codecs->rfx, cmd->data, cmd->length); + + if (!message) + return -1; + + region16_init(&clippingRects); + + for (i = 0; i < message->numRects; i++) + { + rect = &(message->rects[i]); + + clippingRect.left = cmd->left + rect->x; + clippingRect.top = cmd->top + rect->y; + clippingRect.right = clippingRect.left + rect->width; + clippingRect.bottom = clippingRect.top + rect->height; + + region16_union_rect(&clippingRects, &clippingRects, &clippingRect); + } + + for (i = 0; i < message->numTiles; i++) + { + tile = message->tiles[i]; + + updateRect.left = cmd->left + tile->x; + updateRect.top = cmd->top + tile->y; + updateRect.right = updateRect.left + 64; + updateRect.bottom = updateRect.top + 64; + + region16_init(&updateRegion); + region16_intersect_rect(&updateRegion, &clippingRects, &updateRect); + updateRects = (RECTANGLE_16*) region16_rects(&updateRegion, &nbUpdateRects); + + for (j = 0; j < nbUpdateRects; j++) + { + nXDst = updateRects[j].left; + nYDst = updateRects[j].top; + nWidth = updateRects[j].right - updateRects[j].left; + nHeight = updateRects[j].bottom - updateRects[j].top; + + freerdp_image_copy(surface->data, PIXEL_FORMAT_XRGB32, surface->scanline, + nXDst, nYDst, nWidth, nHeight, + tile->data, PIXEL_FORMAT_XRGB32, 64 * 4, 0, 0); + + region16_union_rect(&(gdi->invalidRegion), &(gdi->invalidRegion), &updateRects[j]); + } + + region16_uninit(&updateRegion); + } + + rfx_message_free(gdi->codecs->rfx, message); + + if (!gdi->inGfxFrame) + gdi_OutputUpdate(gdi); + + return 1; +} + +int gdi_SurfaceCommand_ClearCodec(rdpGdi* gdi, RdpgfxClientContext* context, RDPGFX_SURFACE_COMMAND* cmd) +{ + int status; + BYTE* DstData = NULL; + gdiGfxSurface* surface; + RECTANGLE_16 invalidRect; + + freerdp_client_codecs_prepare(gdi->codecs, FREERDP_CODEC_CLEARCODEC); + + surface = (gdiGfxSurface*) context->GetSurfaceData(context, cmd->surfaceId); + + if (!surface) + return -1; + + DstData = surface->data; + + status = clear_decompress(gdi->codecs->clear, cmd->data, cmd->length, &DstData, + PIXEL_FORMAT_XRGB32, surface->scanline, cmd->left, cmd->top, cmd->width, cmd->height); + + if (status < 0) + { + printf("clear_decompress failure: %d\n", status); + return -1; + } + + invalidRect.left = cmd->left; + invalidRect.top = cmd->top; + invalidRect.right = cmd->right; + invalidRect.bottom = cmd->bottom; + + region16_union_rect(&(gdi->invalidRegion), &(gdi->invalidRegion), &invalidRect); + + + if (!gdi->inGfxFrame) + gdi_OutputUpdate(gdi); + + return 1; +} + +int gdi_SurfaceCommand_Planar(rdpGdi* gdi, RdpgfxClientContext* context, RDPGFX_SURFACE_COMMAND* cmd) +{ + int status; + BYTE* DstData = NULL; + gdiGfxSurface* surface; + RECTANGLE_16 invalidRect; + + freerdp_client_codecs_prepare(gdi->codecs, FREERDP_CODEC_PLANAR); + + surface = (gdiGfxSurface*) context->GetSurfaceData(context, cmd->surfaceId); + + if (!surface) + return -1; + + DstData = surface->data; + + status = planar_decompress(gdi->codecs->planar, cmd->data, cmd->length, &DstData, + PIXEL_FORMAT_XRGB32, surface->scanline, cmd->left, cmd->top, cmd->width, cmd->height); + + invalidRect.left = cmd->left; + invalidRect.top = cmd->top; + invalidRect.right = cmd->right; + invalidRect.bottom = cmd->bottom; + + region16_union_rect(&(gdi->invalidRegion), &(gdi->invalidRegion), &invalidRect); + + if (!gdi->inGfxFrame) + gdi_OutputUpdate(gdi); + + return 1; +} + +int gdi_SurfaceCommand_H264(rdpGdi* gdi, RdpgfxClientContext* context, RDPGFX_SURFACE_COMMAND* cmd) +{ + int status; + UINT32 i; + BYTE* DstData = NULL; + H264_CONTEXT* h264; + gdiGfxSurface* surface; + RDPGFX_H264_METABLOCK* meta; + RDPGFX_H264_BITMAP_STREAM* bs; + + freerdp_client_codecs_prepare(gdi->codecs, FREERDP_CODEC_H264); + + h264 = gdi->codecs->h264; + + bs = (RDPGFX_H264_BITMAP_STREAM*) cmd->extra; + + if (!bs) + return -1; + + meta = &(bs->meta); + + surface = (gdiGfxSurface*) context->GetSurfaceData(context, cmd->surfaceId); + + if (!surface) + return -1; + + DstData = surface->data; + + status = h264_decompress(gdi->codecs->h264, bs->data, bs->length, &DstData, + PIXEL_FORMAT_XRGB32, surface->scanline , surface->height, meta->regionRects, meta->numRegionRects); + + if (status < 0) + { + printf("h264_decompress failure: %d\n",status); + return -1; + } + + for (i = 0; i < meta->numRegionRects; i++) + { + region16_union_rect(&(gdi->invalidRegion), &(gdi->invalidRegion), (RECTANGLE_16*) &(meta->regionRects[i])); + } + + if (!gdi->inGfxFrame) + gdi_OutputUpdate(gdi); + + return 1; +} + +int gdi_SurfaceCommand_Alpha(rdpGdi* gdi, RdpgfxClientContext* context, RDPGFX_SURFACE_COMMAND* cmd) +{ + int status = 0; + gdiGfxSurface* surface; + RECTANGLE_16 invalidRect; + + freerdp_client_codecs_prepare(gdi->codecs, FREERDP_CODEC_ALPHACODEC); + + surface = (gdiGfxSurface*) context->GetSurfaceData(context, cmd->surfaceId); + + if (!surface) + return -1; + + printf("gdi_SurfaceCommand_Alpha: status: %d\n", status); + + /* fill with green for now to distinguish from the rest */ + + freerdp_image_fill(surface->data, PIXEL_FORMAT_XRGB32, surface->scanline, + cmd->left, cmd->top, cmd->width, cmd->height, 0x00FF00); + + invalidRect.left = cmd->left; + invalidRect.top = cmd->top; + invalidRect.right = cmd->right; + invalidRect.bottom = cmd->bottom; + + region16_union_rect(&(gdi->invalidRegion), &(gdi->invalidRegion), &invalidRect); + + if (!gdi->inGfxFrame) + gdi_OutputUpdate(gdi); + + return 1; +} + +int gdi_SurfaceCommand_Progressive(rdpGdi* gdi, RdpgfxClientContext* context, RDPGFX_SURFACE_COMMAND* cmd) +{ + int i, j; + int status; + BYTE* DstData; + RFX_RECT* rect; + int nXDst, nYDst; + int nXSrc, nYSrc; + int nWidth, nHeight; + int nbUpdateRects; + gdiGfxSurface* surface; + REGION16 updateRegion; + RECTANGLE_16 updateRect; + RECTANGLE_16* updateRects; + REGION16 clippingRects; + RECTANGLE_16 clippingRect; + RFX_PROGRESSIVE_TILE* tile; + PROGRESSIVE_BLOCK_REGION* region; + + freerdp_client_codecs_prepare(gdi->codecs, FREERDP_CODEC_PROGRESSIVE); + + surface = (gdiGfxSurface*) context->GetSurfaceData(context, cmd->surfaceId); + + if (!surface) + return -1; + + progressive_create_surface_context(gdi->codecs->progressive, cmd->surfaceId, surface->width, surface->height); + + DstData = surface->data; + + status = progressive_decompress(gdi->codecs->progressive, cmd->data, cmd->length, &DstData, + PIXEL_FORMAT_XRGB32, surface->scanline, cmd->left, cmd->top, cmd->width, cmd->height, cmd->surfaceId); + + if (status < 0) + { + printf("progressive_decompress failure: %d\n", status); + return -1; + } + + region = &(gdi->codecs->progressive->region); + + region16_init(&clippingRects); + + for (i = 0; i < region->numRects; i++) + { + rect = &(region->rects[i]); + + clippingRect.left = cmd->left + rect->x; + clippingRect.top = cmd->top + rect->y; + clippingRect.right = clippingRect.left + rect->width; + clippingRect.bottom = clippingRect.top + rect->height; + + region16_union_rect(&clippingRects, &clippingRects, &clippingRect); + } + + for (i = 0; i < region->numTiles; i++) + { + tile = region->tiles[i]; + + updateRect.left = cmd->left + tile->x; + updateRect.top = cmd->top + tile->y; + updateRect.right = updateRect.left + 64; + updateRect.bottom = updateRect.top + 64; + + region16_init(&updateRegion); + region16_intersect_rect(&updateRegion, &clippingRects, &updateRect); + updateRects = (RECTANGLE_16*) region16_rects(&updateRegion, &nbUpdateRects); + + for (j = 0; j < nbUpdateRects; j++) + { + nXDst = updateRects[j].left; + nYDst = updateRects[j].top; + nWidth = updateRects[j].right - updateRects[j].left; + nHeight = updateRects[j].bottom - updateRects[j].top; + + nXSrc = nXDst - (cmd->left + tile->x); + nYSrc = nYDst - (cmd->top + tile->y); + + freerdp_image_copy(surface->data, PIXEL_FORMAT_XRGB32, + surface->scanline, nXDst, nYDst, nWidth, nHeight, + tile->data, PIXEL_FORMAT_XRGB32, 64 * 4, nXSrc, nYSrc); + + region16_union_rect(&(gdi->invalidRegion), &(gdi->invalidRegion), &updateRects[j]); + } + + region16_uninit(&updateRegion); + } + + if (!gdi->inGfxFrame) + gdi_OutputUpdate(gdi); + + return 1; +} + +int gdi_SurfaceCommand(RdpgfxClientContext* context, RDPGFX_SURFACE_COMMAND* cmd) +{ + int status = 1; + rdpGdi* gdi = (rdpGdi*) context->custom; + + switch (cmd->codecId) + { + case RDPGFX_CODECID_UNCOMPRESSED: + status = gdi_SurfaceCommand_Uncompressed(gdi, context, cmd); + break; + + case RDPGFX_CODECID_CAVIDEO: + status = gdi_SurfaceCommand_RemoteFX(gdi, context, cmd); + break; + + case RDPGFX_CODECID_CLEARCODEC: + status = gdi_SurfaceCommand_ClearCodec(gdi, context, cmd); + break; + + case RDPGFX_CODECID_PLANAR: + status = gdi_SurfaceCommand_Planar(gdi, context, cmd); + break; + + case RDPGFX_CODECID_H264: + status = gdi_SurfaceCommand_H264(gdi, context, cmd); + break; + + case RDPGFX_CODECID_ALPHA: + status = gdi_SurfaceCommand_Alpha(gdi, context, cmd); + break; + + case RDPGFX_CODECID_CAPROGRESSIVE: + status = gdi_SurfaceCommand_Progressive(gdi, context, cmd); + break; + + case RDPGFX_CODECID_CAPROGRESSIVE_V2: + break; + } + + return 1; +} + +int gdi_DeleteEncodingContext(RdpgfxClientContext* context, RDPGFX_DELETE_ENCODING_CONTEXT_PDU* deleteEncodingContext) +{ + return 1; +} + +int gdi_CreateSurface(RdpgfxClientContext* context, RDPGFX_CREATE_SURFACE_PDU* createSurface) +{ + gdiGfxSurface* surface; + + surface = (gdiGfxSurface*) calloc(1, sizeof(gdiGfxSurface)); + + if (!surface) + return -1; + + surface->surfaceId = createSurface->surfaceId; + surface->width = (UINT32) createSurface->width; + surface->height = (UINT32) createSurface->height; + surface->alpha = (createSurface->pixelFormat == PIXEL_FORMAT_ARGB_8888) ? TRUE : FALSE; + + surface->scanline = (surface->width + (surface->width % 4)) * 4; + surface->data = (BYTE*) calloc(1, surface->scanline * surface->height); + + if (!surface->data) + return -1; + + context->SetSurfaceData(context, surface->surfaceId, (void*) surface); + + return 1; +} + +int gdi_DeleteSurface(RdpgfxClientContext* context, RDPGFX_DELETE_SURFACE_PDU* deleteSurface) +{ + gdiGfxSurface* surface = NULL; + rdpGdi* gdi = (rdpGdi*) context->custom; + + surface = (gdiGfxSurface*) context->GetSurfaceData(context, deleteSurface->surfaceId); + + if (surface) + { + free(surface->data); + free(surface); + } + + context->SetSurfaceData(context, deleteSurface->surfaceId, NULL); + + if (gdi->codecs->progressive) + progressive_delete_surface_context(gdi->codecs->progressive, deleteSurface->surfaceId); + + return 1; +} + +int gdi_SolidFill(RdpgfxClientContext* context, RDPGFX_SOLID_FILL_PDU* solidFill) +{ + UINT16 index; + UINT32 color; + BYTE a, r, g, b; + int nWidth, nHeight; + RDPGFX_RECT16* rect; + gdiGfxSurface* surface; + RECTANGLE_16 invalidRect; + rdpGdi* gdi = (rdpGdi*) context->custom; + + surface = (gdiGfxSurface*) context->GetSurfaceData(context, solidFill->surfaceId); + + if (!surface) + return -1; + + b = solidFill->fillPixel.B; + g = solidFill->fillPixel.G; + r = solidFill->fillPixel.R; + a = solidFill->fillPixel.XA; + + color = ARGB32(a, r, g, b); + + for (index = 0; index < solidFill->fillRectCount; index++) + { + rect = &(solidFill->fillRects[index]); + + 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(&(gdi->invalidRegion), &(gdi->invalidRegion), &invalidRect); + } + + if (!gdi->inGfxFrame) + gdi_OutputUpdate(gdi); + + return 1; +} + +int gdi_SurfaceToSurface(RdpgfxClientContext* context, RDPGFX_SURFACE_TO_SURFACE_PDU* surfaceToSurface) +{ + UINT16 index; + int nWidth, nHeight; + RDPGFX_RECT16* rectSrc; + RDPGFX_POINT16* destPt; + RECTANGLE_16 invalidRect; + gdiGfxSurface* surfaceSrc; + gdiGfxSurface* surfaceDst; + rdpGdi* gdi = (rdpGdi*) context->custom; + + rectSrc = &(surfaceToSurface->rectSrc); + destPt = &surfaceToSurface->destPts[0]; + + surfaceSrc = (gdiGfxSurface*) context->GetSurfaceData(context, surfaceToSurface->surfaceIdSrc); + + if (surfaceToSurface->surfaceIdSrc != surfaceToSurface->surfaceIdDest) + surfaceDst = (gdiGfxSurface*) context->GetSurfaceData(context, surfaceToSurface->surfaceIdDest); + else + surfaceDst = surfaceSrc; + + if (!surfaceSrc || !surfaceDst) + return -1; + + nWidth = rectSrc->right - rectSrc->left; + nHeight = rectSrc->bottom - rectSrc->top; + + for (index = 0; index < surfaceToSurface->destPtsCount; index++) + { + destPt = &surfaceToSurface->destPts[index]; + + freerdp_image_copy(surfaceDst->data, PIXEL_FORMAT_XRGB32, surfaceDst->scanline, + destPt->x, destPt->y, nWidth, nHeight, surfaceSrc->data, PIXEL_FORMAT_XRGB32, + surfaceSrc->scanline, rectSrc->left, rectSrc->top); + + invalidRect.left = destPt->x; + invalidRect.top = destPt->y; + invalidRect.right = destPt->x + rectSrc->right; + invalidRect.bottom = destPt->y + rectSrc->bottom; + + region16_union_rect(&(gdi->invalidRegion), &(gdi->invalidRegion), &invalidRect); + } + + if (!gdi->inGfxFrame) + gdi_OutputUpdate(gdi); + + return 1; +} + +int gdi_SurfaceToCache(RdpgfxClientContext* context, RDPGFX_SURFACE_TO_CACHE_PDU* surfaceToCache) +{ + RDPGFX_RECT16* rect; + gdiGfxSurface* surface; + gdiGfxCacheEntry* cacheEntry; + + rect = &(surfaceToCache->rectSrc); + + surface = (gdiGfxSurface*) context->GetSurfaceData(context, surfaceToCache->surfaceId); + + if (!surface) + return -1; + + cacheEntry = (gdiGfxCacheEntry*) calloc(1, sizeof(gdiGfxCacheEntry)); + + 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 + (cacheEntry->width % 4)) * 4; + cacheEntry->data = (BYTE*) calloc(1, cacheEntry->scanline * cacheEntry->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 gdi_CacheToSurface(RdpgfxClientContext* context, RDPGFX_CACHE_TO_SURFACE_PDU* cacheToSurface) +{ + UINT16 index; + RDPGFX_POINT16* destPt; + gdiGfxSurface* surface; + gdiGfxCacheEntry* cacheEntry; + RECTANGLE_16 invalidRect; + rdpGdi* gdi = (rdpGdi*) context->custom; + + surface = (gdiGfxSurface*) context->GetSurfaceData(context, cacheToSurface->surfaceId); + cacheEntry = (gdiGfxCacheEntry*) context->GetCacheSlotData(context, 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(&(gdi->invalidRegion), &(gdi->invalidRegion), &invalidRect); + } + + if (!gdi->inGfxFrame) + gdi_OutputUpdate(gdi); + + return 1; +} + +int gdi_CacheImportReply(RdpgfxClientContext* context, RDPGFX_CACHE_IMPORT_REPLY_PDU* cacheImportReply) +{ + return 1; +} + +int gdi_EvictCacheEntry(RdpgfxClientContext* context, RDPGFX_EVICT_CACHE_ENTRY_PDU* evictCacheEntry) +{ + gdiGfxCacheEntry* cacheEntry; + + cacheEntry = (gdiGfxCacheEntry*) context->GetCacheSlotData(context, evictCacheEntry->cacheSlot); + + if (cacheEntry) + { + free(cacheEntry->data); + free(cacheEntry); + } + + context->SetCacheSlotData(context, evictCacheEntry->cacheSlot, NULL); + + return 1; +} + +int gdi_MapSurfaceToOutput(RdpgfxClientContext* context, RDPGFX_MAP_SURFACE_TO_OUTPUT_PDU* surfaceToOutput) +{ + rdpGdi* gdi = (rdpGdi*) context->custom; + + gdi->outputSurfaceId = surfaceToOutput->surfaceId; + + return 1; +} + +int gdi_MapSurfaceToWindow(RdpgfxClientContext* context, RDPGFX_MAP_SURFACE_TO_WINDOW_PDU* surfaceToWindow) +{ + return 1; +} + +void gdi_graphics_pipeline_init(rdpGdi* gdi, RdpgfxClientContext* gfx) +{ + gdi->gfx = gfx; + gfx->custom = (void*) gdi; + + gfx->ResetGraphics = gdi_ResetGraphics; + gfx->StartFrame = gdi_StartFrame; + gfx->EndFrame = gdi_EndFrame; + gfx->SurfaceCommand = gdi_SurfaceCommand; + gfx->DeleteEncodingContext = gdi_DeleteEncodingContext; + gfx->CreateSurface = gdi_CreateSurface; + gfx->DeleteSurface = gdi_DeleteSurface; + gfx->SolidFill = gdi_SolidFill; + gfx->SurfaceToSurface = gdi_SurfaceToSurface; + gfx->SurfaceToCache = gdi_SurfaceToCache; + gfx->CacheToSurface = gdi_CacheToSurface; + gfx->CacheImportReply = gdi_CacheImportReply; + gfx->EvictCacheEntry = gdi_EvictCacheEntry; + gfx->MapSurfaceToOutput = gdi_MapSurfaceToOutput; + gfx->MapSurfaceToWindow = gdi_MapSurfaceToWindow; + + region16_init(&(gdi->invalidRegion)); +} + +void gdi_graphics_pipeline_uninit(rdpGdi* gdi, RdpgfxClientContext* gfx) +{ + region16_uninit(&(gdi->invalidRegion)); + + gdi->gfx = NULL; + gfx->custom = NULL; +} +