22#include <freerdp/config.h>
24#include "../core/update.h"
26#include <winpr/assert.h>
27#include <winpr/cast.h>
29#include <freerdp/api.h>
30#include <freerdp/log.h>
31#include <freerdp/gdi/gfx.h>
32#include <freerdp/gdi/region.h>
33#include <freerdp/utils/gfx.h>
36#define TAG FREERDP_TAG("gdi")
40#define GDI_GFX_MAX_INVALID_RECTS 256
43static BOOL is_rect_valid(
const RECTANGLE_16* rect,
size_t width,
size_t height)
47 if ((rect->left > rect->right) || (rect->right > width))
49 if ((rect->top > rect->bottom) || (rect->bottom > height))
60 rect.left = (UINT16)MIN(UINT16_MAX, cmd->left);
61 rect.top = (UINT16)MIN(UINT16_MAX, cmd->top);
62 rect.right = (UINT16)MIN(UINT16_MAX, cmd->right);
63 rect.bottom = (UINT16)MIN(UINT16_MAX, cmd->bottom);
64 if (!is_rect_valid(&rect, surface->width, surface->height))
67 "Command rect %" PRIu32
"x%" PRIu32
"-%" PRIu32
"x%" PRIu32
68 " not within bounds of %" PRIu32
"x%" PRIu32,
69 rect.left, rect.top, cmd->width, cmd->height, surface->width, surface->height);
72 if (rect.left > surface->width)
74 if (rect.right > surface->width)
76 if (rect.top > surface->height)
78 if (rect.bottom > surface->height)
96static BOOL gdi_surface_invalidate_rect(gdiGfxSurface* surface,
const RECTANGLE_16* rect)
98 WINPR_ASSERT(surface);
100 REGION16* region = &surface->invalidRegion;
101 if (!region16_union_rect(region, region, rect))
104 if (region16_n_rects(region) <= GDI_GFX_MAX_INVALID_RECTS)
108 region16_clear(region);
109 return region16_union_rect(region, region, &extents);
113static DWORD gfx_align_scanline(DWORD widthInBytes, DWORD alignment)
115 const UINT32 align = alignment;
116 const UINT32 pad = align - (widthInBytes % alignment);
117 UINT32 scanline = widthInBytes;
131static UINT gdi_ResetGraphics(RdpgfxClientContext* context,
134 UINT rc = ERROR_INTERNAL_ERROR;
136 UINT16* pSurfaceIds =
nullptr;
138 WINPR_ASSERT(context);
139 WINPR_ASSERT(resetGraphics);
141 rdpGdi* gdi = (rdpGdi*)context->custom;
144 rdpUpdate* update = gdi->context->update;
145 WINPR_ASSERT(update);
147 rdpSettings* settings = gdi->context->settings;
148 WINPR_ASSERT(settings);
149 EnterCriticalSection(&context->mux);
150 const UINT32 DesktopWidth = resetGraphics->width;
151 const UINT32 DesktopHeight = resetGraphics->height;
153 WLog_DBG(TAG,
"new size: %" PRIu32
"x%" PRIu32, DesktopWidth, DesktopHeight);
162 WINPR_ASSERT(update->DesktopResize);
165 rdp_update_lock(update);
166 const BOOL resized = update->DesktopResize(gdi->context);
167 rdp_update_unlock(update);
172 WINPR_ASSERT(context->GetSurfaceIds);
173 const UINT res = context->GetSurfaceIds(context, &pSurfaceIds, &count);
174 if (res != CHANNEL_RC_OK)
180 for (UINT32 index = 0; index < count; index++)
182 WINPR_ASSERT(context->GetSurfaceData);
183 gdiGfxSurface* surface =
184 (gdiGfxSurface*)context->GetSurfaceData(context, pSurfaceIds[index]);
189 memset(surface->data, 0xFF, (
size_t)surface->scanline * surface->height);
190 region16_clear(&surface->invalidRegion);
197 const UINT32 width = (UINT32)MAX(0, gdi->width);
198 const UINT32 height = (UINT32)MAX(0, gdi->height);
200 if (!freerdp_client_codecs_reset(
209 LeaveCriticalSection(&context->mux);
214static UINT gdi_OutputUpdate(rdpGdi* gdi, gdiGfxSurface* surface)
216 UINT rc = ERROR_INTERNAL_ERROR;
222 rdpUpdate* update =
nullptr;
225 WINPR_ASSERT(gdi->context);
226 WINPR_ASSERT(surface);
228 update = gdi->context->update;
229 WINPR_ASSERT(update);
231 if (gdi->suppressOutput)
232 return CHANNEL_RC_OK;
234 surfaceX = surface->outputOriginX;
235 surfaceY = surface->outputOriginY;
236 surfaceRect.left = 0;
238 surfaceRect.right = (UINT16)MIN(UINT16_MAX, surface->mappedWidth);
239 surfaceRect.bottom = (UINT16)MIN(UINT16_MAX, surface->mappedHeight);
240 if (!region16_intersect_rect(&(surface->invalidRegion), &(surface->invalidRegion),
244 const double sx = surface->outputTargetWidth / (double)surface->mappedWidth;
245 const double sy = surface->outputTargetHeight / (double)surface->mappedHeight;
247 rects = region16_rects(&surface->invalidRegion, &nbRects);
248 if (!rects || (nbRects == 0))
254 if (!update_begin_paint(update))
257 for (UINT32 i = 0; i < nbRects; i++)
259 const UINT32 nXSrc = rects[i].left;
260 const UINT32 nYSrc = rects[i].top;
261 const double xDst = surfaceX + nXSrc * sx;
262 const double yDst = surfaceY + nYSrc * sy;
267 const UINT32 outWidth = (UINT32)MAX(0, gdi->width);
268 const UINT32 outHeight = (UINT32)MAX(0, gdi->height);
269 if ((xDst >= outWidth) || (yDst >= outHeight))
272 const UINT32 nXDst = (UINT32)xDst;
273 const UINT32 nYDst = (UINT32)yDst;
274 UINT32 swidth = rects[i].right - rects[i].left;
275 UINT32 sheight = rects[i].bottom - rects[i].top;
276 UINT32 dwidth = (UINT32)(swidth * sx);
277 UINT32 dheight = (UINT32)(sheight * sy);
283 if (dwidth > outWidth - nXDst)
285 dwidth = outWidth - nXDst;
286 swidth = MAX(1, MIN(swidth, (UINT32)(dwidth / sx)));
288 if (dheight > outHeight - nYDst)
290 dheight = outHeight - nYDst;
291 sheight = MAX(1, MIN(sheight, (UINT32)(dheight / sy)));
294 if (!freerdp_image_scale(gdi->primary_buffer, gdi->dstFormat, gdi->stride, nXDst, nYDst,
295 dwidth, dheight, surface->data, surface->format, surface->scanline,
296 nXSrc, nYSrc, swidth, sheight))
298 rc = CHANNEL_RC_NULL_DATA;
302 if (!gdi_InvalidateRegion(gdi->primary->hdc, (INT32)nXDst, (INT32)nYDst, (INT32)dwidth,
310 if (!update_end_paint(update))
311 rc = ERROR_INTERNAL_ERROR;
314 region16_clear(&(surface->invalidRegion));
319static UINT gdi_WindowUpdate(RdpgfxClientContext* context, gdiGfxSurface* surface)
321 WINPR_ASSERT(context);
322 WINPR_ASSERT(surface);
323 return IFCALLRESULT(CHANNEL_RC_OK, context->UpdateWindowFromSurface, context, surface);
327static UINT gdi_UpdateSurfaces(RdpgfxClientContext* context)
330 UINT16* pSurfaceIds =
nullptr;
332 WINPR_ASSERT(context);
334 rdpGdi* gdi = (rdpGdi*)context->custom;
337 EnterCriticalSection(&context->mux);
339 WINPR_ASSERT(context->GetSurfaceIds);
340 UINT status = context->GetSurfaceIds(context, &pSurfaceIds, &count);
341 if (status != CHANNEL_RC_OK)
344 for (UINT32 index = 0; index < count; index++)
346 WINPR_ASSERT(context->GetSurfaceData);
347 gdiGfxSurface* surface =
348 (gdiGfxSurface*)context->GetSurfaceData(context, pSurfaceIds[index]);
354 if (context->UpdateSurfaceArea)
356 if (surface->handleInUpdateSurfaceArea)
360 if (surface->outputMapped)
361 status = gdi_OutputUpdate(gdi, surface);
362 else if (surface->windowMapped)
363 status = gdi_WindowUpdate(context, surface);
365 if (status != CHANNEL_RC_OK)
371 LeaveCriticalSection(&context->mux);
383 rdpGdi* gdi =
nullptr;
385 WINPR_ASSERT(context);
386 WINPR_ASSERT(startFrame);
388 gdi = (rdpGdi*)context->custom;
390 gdi->inGfxFrame = TRUE;
391 gdi->frameId = startFrame->frameId;
392 return CHANNEL_RC_OK;
396static UINT gdi_call_update_surfaces(RdpgfxClientContext* context)
398 WINPR_ASSERT(context);
399 return IFCALLRESULT(CHANNEL_RC_OK, context->UpdateSurfaces, context);
408static UINT gdi_EndFrame(RdpgfxClientContext* context,
411 WINPR_ASSERT(context);
412 WINPR_ASSERT(endFrame);
414 rdpGdi* gdi = (rdpGdi*)context->custom;
416 const UINT status = gdi_call_update_surfaces(context);
417 gdi->inGfxFrame = FALSE;
422static UINT gdi_interFrameUpdate(rdpGdi* gdi, RdpgfxClientContext* context)
425 UINT status = CHANNEL_RC_OK;
426 if (!gdi->inGfxFrame)
427 status = gdi_call_update_surfaces(context);
437static UINT gdi_SurfaceCommand_Uncompressed(rdpGdi* gdi, RdpgfxClientContext* context,
440 UINT status = CHANNEL_RC_OK;
441 gdiGfxSurface* surface =
nullptr;
446 WINPR_ASSERT(context);
449 WINPR_ASSERT(context->GetSurfaceData);
451 (gdiGfxSurface*)context->GetSurfaceData(context, (UINT16)MIN(UINT16_MAX, cmd->surfaceId));
455 WLog_ERR(TAG,
"unable to retrieve surfaceData for surfaceId=%" PRIu32
"", cmd->surfaceId);
456 return ERROR_NOT_FOUND;
459 if (!is_within_surface(surface, cmd))
460 return ERROR_INVALID_DATA;
462 bpp = FreeRDPGetBytesPerPixel(cmd->format);
463 size = 1ull * bpp * cmd->width * cmd->height;
464 if (cmd->length < size)
466 WLog_ERR(TAG,
"Not enough data, got %" PRIu32
", expected %" PRIuz, cmd->length, size);
467 return ERROR_INVALID_DATA;
470 if (!freerdp_image_copy_no_overlap(surface->data, surface->format, surface->scanline, cmd->left,
471 cmd->top, cmd->width, cmd->height, cmd->data, cmd->format, 0,
472 0, 0,
nullptr, FREERDP_FLIP_NONE))
473 return ERROR_INTERNAL_ERROR;
475 invalidRect.left = (UINT16)MIN(UINT16_MAX, cmd->left);
476 invalidRect.top = (UINT16)MIN(UINT16_MAX, cmd->top);
477 invalidRect.right = (UINT16)MIN(UINT16_MAX, cmd->right);
478 invalidRect.bottom = (UINT16)MIN(UINT16_MAX, cmd->bottom);
479 if (!gdi_surface_invalidate_rect(surface, &invalidRect))
481 status = IFCALLRESULT(CHANNEL_RC_OK, context->UpdateSurfaceArea, context, surface->surfaceId, 1,
484 if (status != CHANNEL_RC_OK)
487 status = gdi_interFrameUpdate(gdi, context);
493#if defined(WITH_GFX_AV1)
495static UINT gdi_SurfaceCommand_AV1(rdpGdi* gdi, RdpgfxClientContext* context,
499 UINT status = CHANNEL_RC_OK;
500 gdiGfxSurface* surface =
nullptr;
504 WINPR_ASSERT(context);
507 WINPR_ASSERT(context->GetSurfaceData);
509 (gdiGfxSurface*)context->GetSurfaceData(context, (UINT16)MIN(UINT16_MAX, cmd->surfaceId));
513 WLog_ERR(TAG,
"unable to retrieve surfaceData for surfaceId=%" PRIu32
"", cmd->surfaceId);
514 return ERROR_NOT_FOUND;
519 surface->av1 = freerdp_av1_context_new(FALSE);
523 WLog_ERR(TAG,
"unable to create av1 context");
524 return ERROR_NOT_ENOUGH_MEMORY;
527 if (!freerdp_av1_context_reset(surface->av1, surface->width, surface->height))
528 return ERROR_INTERNAL_ERROR;
532 return ERROR_NOT_SUPPORTED;
534 if (!is_within_surface(surface, cmd))
535 return ERROR_INVALID_DATA;
540 return ERROR_INTERNAL_ERROR;
543 rc = freerdp_av1_decompress(surface->av1, bs->data, bs->length, surface->data, surface->format,
544 surface->scanline, surface->width, surface->height,
545 meta->regionRects, meta->numRegionRects);
549 WLog_WARN(TAG,
"freerdp_av1_decompress failure: %" PRId32
", ignoring update.", rc);
550 return CHANNEL_RC_OK;
553 for (UINT32 i = 0; i < meta->numRegionRects; i++)
555 if (!gdi_surface_invalidate_rect(surface, &(meta->regionRects[i])))
559 status = IFCALLRESULT(CHANNEL_RC_OK, context->UpdateSurfaceArea, context, surface->surfaceId,
560 meta->numRegionRects, meta->regionRects);
562 if (status != CHANNEL_RC_OK)
565 status = gdi_interFrameUpdate(gdi, context);
572#if defined(WITH_GFX_AV2)
574static UINT gdi_SurfaceCommand_AV2(rdpGdi* gdi, RdpgfxClientContext* context,
578 UINT status = CHANNEL_RC_OK;
579 gdiGfxSurface* surface =
nullptr;
583 WINPR_ASSERT(context);
586 WINPR_ASSERT(context->GetSurfaceData);
588 (gdiGfxSurface*)context->GetSurfaceData(context, (UINT16)MIN(UINT16_MAX, cmd->surfaceId));
592 WLog_ERR(TAG,
"unable to retrieve surfaceData for surfaceId=%" PRIu32
"", cmd->surfaceId);
593 return ERROR_NOT_FOUND;
598 surface->av2 = freerdp_av2_context_new(FALSE);
602 WLog_ERR(TAG,
"unable to create av2 context");
603 return ERROR_NOT_ENOUGH_MEMORY;
606 if (!freerdp_av2_context_reset(surface->av2, surface->width, surface->height))
607 return ERROR_INTERNAL_ERROR;
611 return ERROR_NOT_SUPPORTED;
613 if (!is_within_surface(surface, cmd))
614 return ERROR_INVALID_DATA;
619 return ERROR_INTERNAL_ERROR;
622 rc = freerdp_av2_decompress(surface->av2, bs->data, bs->length, surface->data, surface->format,
623 surface->scanline, surface->width, surface->height,
624 meta->regionRects, meta->numRegionRects);
628 WLog_WARN(TAG,
"freerdp_av2_decompress failure: %" PRId32
", ignoring update.", rc);
629 return CHANNEL_RC_OK;
632 for (UINT32 i = 0; i < meta->numRegionRects; i++)
634 if (!region16_union_rect(&(surface->invalidRegion), &(surface->invalidRegion),
635 &(meta->regionRects[i])))
639 status = IFCALLRESULT(CHANNEL_RC_OK, context->UpdateSurfaceArea, context, surface->surfaceId,
640 meta->numRegionRects, meta->regionRects);
642 if (status != CHANNEL_RC_OK)
645 status = gdi_interFrameUpdate(gdi, context);
658static UINT gdi_SurfaceCommand_RemoteFX(rdpGdi* gdi, RdpgfxClientContext* context,
661 UINT status = ERROR_INTERNAL_ERROR;
662 gdiGfxSurface* surface =
nullptr;
667 WINPR_ASSERT(context);
670 WINPR_ASSERT(context->GetSurfaceData);
672 (gdiGfxSurface*)context->GetSurfaceData(context, (UINT16)MIN(UINT16_MAX, cmd->surfaceId));
676 WLog_ERR(TAG,
"unable to retrieve surfaceData for surfaceId=%" PRIu32
"", cmd->surfaceId);
677 return ERROR_NOT_FOUND;
680 if (!is_within_surface(surface, cmd))
681 return ERROR_INVALID_DATA;
683 WINPR_ASSERT(surface->codecs);
684 rfx_context_set_pixel_format(surface->codecs->rfx, cmd->format);
685 region16_init(&invalidRegion);
687 if (!rfx_process_message(surface->codecs->rfx, cmd->data, cmd->length, cmd->left, cmd->top,
688 surface->data, surface->format, surface->scanline, surface->height,
691 WLog_ERR(TAG,
"Failed to process RemoteFX message");
695 rects = region16_rects(&invalidRegion, &nrRects);
696 status = IFCALLRESULT(CHANNEL_RC_OK, context->UpdateSurfaceArea, context, surface->surfaceId,
699 if (status != CHANNEL_RC_OK)
702 for (UINT32 x = 0; x < nrRects; x++)
704 if (!gdi_surface_invalidate_rect(surface, &rects[x]))
708 status = gdi_interFrameUpdate(gdi, context);
711 region16_uninit(&invalidRegion);
721static UINT gdi_SurfaceCommand_ClearCodec(rdpGdi* gdi, RdpgfxClientContext* context,
725 UINT status = CHANNEL_RC_OK;
726 gdiGfxSurface* surface =
nullptr;
729 WINPR_ASSERT(context);
732 WINPR_ASSERT(context->GetSurfaceData);
734 (gdiGfxSurface*)context->GetSurfaceData(context, (UINT16)MIN(UINT16_MAX, cmd->surfaceId));
738 WLog_ERR(TAG,
"unable to retrieve surfaceData for surfaceId=%" PRIu32
"", cmd->surfaceId);
739 return ERROR_NOT_FOUND;
742 if (!is_within_surface(surface, cmd))
743 return ERROR_INVALID_DATA;
745 WINPR_ASSERT(surface->codecs);
746 rc = clear_decompress(surface->codecs->clear, cmd->data, cmd->length, cmd->width, cmd->height,
747 surface->data, surface->format, surface->scanline, cmd->left, cmd->top,
748 surface->width, surface->height, &gdi->palette);
752 WLog_ERR(TAG,
"clear_decompress failure: %" PRId32
"", rc);
753 return ERROR_INTERNAL_ERROR;
756 invalidRect.left = (UINT16)MIN(UINT16_MAX, cmd->left);
757 invalidRect.top = (UINT16)MIN(UINT16_MAX, cmd->top);
758 invalidRect.right = (UINT16)MIN(UINT16_MAX, cmd->right);
759 invalidRect.bottom = (UINT16)MIN(UINT16_MAX, cmd->bottom);
760 if (!gdi_surface_invalidate_rect(surface, &invalidRect))
762 status = IFCALLRESULT(CHANNEL_RC_OK, context->UpdateSurfaceArea, context, surface->surfaceId, 1,
765 if (status != CHANNEL_RC_OK)
768 status = gdi_interFrameUpdate(gdi, context);
780static UINT gdi_SurfaceCommand_Planar(rdpGdi* gdi, RdpgfxClientContext* context,
783 UINT status = CHANNEL_RC_OK;
784 BYTE* DstData =
nullptr;
785 gdiGfxSurface* surface =
nullptr;
788 WINPR_ASSERT(context);
791 WINPR_ASSERT(context->GetSurfaceData);
793 (gdiGfxSurface*)context->GetSurfaceData(context, (UINT16)MIN(UINT16_MAX, cmd->surfaceId));
797 WLog_ERR(TAG,
"unable to retrieve surfaceData for surfaceId=%" PRIu32
"", cmd->surfaceId);
798 return ERROR_NOT_FOUND;
801 DstData = surface->data;
803 if (!is_within_surface(surface, cmd))
804 return ERROR_INVALID_DATA;
806 if (!freerdp_bitmap_decompress_planar(surface->codecs->planar, cmd->data, cmd->length,
807 cmd->width, cmd->height, DstData, surface->format,
808 surface->scanline, cmd->left, cmd->top, cmd->width,
810 return ERROR_INTERNAL_ERROR;
812 invalidRect.left = (UINT16)MIN(UINT16_MAX, cmd->left);
813 invalidRect.top = (UINT16)MIN(UINT16_MAX, cmd->top);
814 invalidRect.right = (UINT16)MIN(UINT16_MAX, cmd->right);
815 invalidRect.bottom = (UINT16)MIN(UINT16_MAX, cmd->bottom);
816 if (!gdi_surface_invalidate_rect(surface, &invalidRect))
818 status = IFCALLRESULT(CHANNEL_RC_OK, context->UpdateSurfaceArea, context, surface->surfaceId, 1,
821 if (status != CHANNEL_RC_OK)
824 status = gdi_interFrameUpdate(gdi, context);
836static UINT gdi_SurfaceCommand_AVC420(rdpGdi* gdi, RdpgfxClientContext* context,
841 UINT status = CHANNEL_RC_OK;
842 gdiGfxSurface* surface =
nullptr;
846 WINPR_ASSERT(context);
849 WINPR_ASSERT(context->GetSurfaceData);
851 (gdiGfxSurface*)context->GetSurfaceData(context, (UINT16)MIN(UINT16_MAX, cmd->surfaceId));
855 WLog_ERR(TAG,
"unable to retrieve surfaceData for surfaceId=%" PRIu32
"", cmd->surfaceId);
856 return ERROR_NOT_FOUND;
861 surface->h264 = h264_context_new(FALSE);
865 WLog_ERR(TAG,
"unable to create h264 context");
866 return ERROR_NOT_ENOUGH_MEMORY;
869 if (!h264_context_set_option(surface->h264, H264_CONTEXT_OPTION_HW_ACCEL,
871 FreeRDP_SoftwareGdi) == 0))
872 return ERROR_INTERNAL_ERROR;
874 if (!h264_context_reset(surface->h264, surface->width, surface->height))
875 return ERROR_INTERNAL_ERROR;
879 return ERROR_NOT_SUPPORTED;
881 if (!is_within_surface(surface, cmd))
882 return ERROR_INVALID_DATA;
887 return ERROR_INTERNAL_ERROR;
890 rc = avc420_decompress(surface->h264, bs->data, bs->length, surface->data, surface->format,
891 surface->scanline, surface->width, surface->height, meta->regionRects,
892 meta->numRegionRects);
896 WLog_WARN(TAG,
"avc420_decompress failure: %" PRId32
", ignoring update.", rc);
897 return CHANNEL_RC_OK;
900 for (UINT32 i = 0; i < meta->numRegionRects; i++)
902 if (!gdi_surface_invalidate_rect(surface, &(meta->regionRects[i])))
906 status = IFCALLRESULT(CHANNEL_RC_OK, context->UpdateSurfaceArea, context, surface->surfaceId,
907 meta->numRegionRects, meta->regionRects);
909 if (status != CHANNEL_RC_OK)
912 status = gdi_interFrameUpdate(gdi, context);
917 return ERROR_NOT_SUPPORTED;
927static UINT gdi_SurfaceCommand_AVC444(rdpGdi* gdi, RdpgfxClientContext* context,
932 UINT status = CHANNEL_RC_OK;
933 gdiGfxSurface* surface =
nullptr;
940 WINPR_ASSERT(context);
943 WINPR_ASSERT(context->GetSurfaceData);
945 (gdiGfxSurface*)context->GetSurfaceData(context, (UINT16)MIN(UINT16_MAX, cmd->surfaceId));
949 WLog_ERR(TAG,
"unable to retrieve surfaceData for surfaceId=%" PRIu32
"", cmd->surfaceId);
950 return ERROR_NOT_FOUND;
955 surface->h264 = h264_context_new(FALSE);
959 WLog_ERR(TAG,
"unable to create h264 context");
960 return ERROR_NOT_ENOUGH_MEMORY;
963 if (!h264_context_set_option(surface->h264, H264_CONTEXT_OPTION_HW_ACCEL,
965 FreeRDP_SoftwareGdi) == 0))
966 return ERROR_INTERNAL_ERROR;
967 if (!h264_context_reset(surface->h264, surface->width, surface->height))
968 return ERROR_INTERNAL_ERROR;
972 return ERROR_NOT_SUPPORTED;
974 if (!is_within_surface(surface, cmd))
975 return ERROR_INVALID_DATA;
980 return ERROR_INTERNAL_ERROR;
982 avc1 = &bs->bitstream[0];
983 avc2 = &bs->bitstream[1];
986 rc = avc444_decompress(surface->h264, bs->LC, meta1->regionRects, meta1->numRegionRects,
987 avc1->data, avc1->length, meta2->regionRects, meta2->numRegionRects,
988 avc2->data, avc2->length, surface->data, surface->format,
989 surface->scanline, surface->width, surface->height, cmd->codecId);
993 WLog_WARN(TAG,
"avc444_decompress failure: %" PRId32
", ignoring update.", rc);
994 return CHANNEL_RC_OK;
997 for (UINT32 i = 0; i < meta1->numRegionRects; i++)
999 if (!gdi_surface_invalidate_rect(surface, &(meta1->regionRects[i])))
1003 status = IFCALLRESULT(CHANNEL_RC_OK, context->UpdateSurfaceArea, context, surface->surfaceId,
1004 meta1->numRegionRects, meta1->regionRects);
1006 if (status != CHANNEL_RC_OK)
1009 for (UINT32 i = 0; i < meta2->numRegionRects; i++)
1011 if (!gdi_surface_invalidate_rect(surface, &(meta2->regionRects[i])))
1015 status = IFCALLRESULT(CHANNEL_RC_OK, context->UpdateSurfaceArea, context, surface->surfaceId,
1016 meta2->numRegionRects, meta2->regionRects);
1018 if (status != CHANNEL_RC_OK)
1021 status = gdi_interFrameUpdate(gdi, context);
1026 return ERROR_NOT_SUPPORTED;
1031static BOOL gdi_apply_alpha(BYTE* data, UINT32 format, UINT32 stride,
RECTANGLE_16* rect,
1032 UINT32 startOffsetX, UINT32 count, BYTE a)
1036 const UINT32 bpp = FreeRDPGetBytesPerPixel(format);
1039 for (
size_t y = rect->top; y < rect->bottom; y++)
1041 BYTE* line = &data[y * stride];
1043 for (
size_t x = first ? rect->left + startOffsetX : rect->left; x < rect->right; x++)
1049 if (written == count)
1052 BYTE* src = &line[x * bpp];
1053 UINT32 color = FreeRDPReadColor(src, format);
1054 FreeRDPSplitColor(color, format, &r, &g, &b,
nullptr,
nullptr);
1055 color = FreeRDPGetColor(format, r, g, b, a);
1056 FreeRDPWriteColor(src, format, color);
1071static UINT gdi_SurfaceCommand_Alpha(rdpGdi* gdi, RdpgfxClientContext* context,
1074 UINT status = CHANNEL_RC_OK;
1075 UINT16 alphaSig = 0;
1076 UINT16 compressed = 0;
1078 wStream buffer = WINPR_C_ARRAY_INIT;
1080 WINPR_ASSERT(context);
1083 wStream* s = Stream_StaticConstInit(&buffer, cmd->data, cmd->length);
1085 if (!Stream_CheckAndLogRequiredLength(TAG, s, 4))
1086 return ERROR_INVALID_DATA;
1088 WINPR_ASSERT(context->GetSurfaceData);
1089 gdiGfxSurface* surface =
1090 (gdiGfxSurface*)context->GetSurfaceData(context, (UINT16)MIN(UINT16_MAX, cmd->surfaceId));
1094 WLog_ERR(TAG,
"unable to retrieve surfaceData for surfaceId=%" PRIu32
"", cmd->surfaceId);
1095 return ERROR_NOT_FOUND;
1098 if (!is_within_surface(surface, cmd))
1099 return ERROR_INVALID_DATA;
1101 Stream_Read_UINT16(s, alphaSig);
1102 Stream_Read_UINT16(s, compressed);
1104 if (alphaSig != 0x414C)
1105 return ERROR_INVALID_DATA;
1107 if (compressed == 0)
1109 if (!Stream_CheckAndLogRequiredLengthOfSize(TAG, s, cmd->height, cmd->width))
1110 return ERROR_INVALID_DATA;
1112 for (
size_t y = cmd->top; y < cmd->top + cmd->height; y++)
1114 BYTE* line = &surface->data[y * surface->scanline];
1116 for (
size_t x = cmd->left; x < cmd->left + cmd->width; x++)
1123 BYTE* src = &line[x * FreeRDPGetBytesPerPixel(surface->format)];
1124 Stream_Read_UINT8(s, a);
1125 color = FreeRDPReadColor(src, surface->format);
1126 FreeRDPSplitColor(color, surface->format, &r, &g, &b,
nullptr,
nullptr);
1127 color = FreeRDPGetColor(surface->format, r, g, b, a);
1128 FreeRDPWriteColor(src, surface->format, color);
1134 UINT32 startOffsetX = 0;
1136 rect.left = (UINT16)MIN(UINT16_MAX, cmd->left);
1137 rect.top = (UINT16)MIN(UINT16_MAX, cmd->top);
1138 rect.right = (UINT16)MIN(UINT16_MAX, cmd->left + cmd->width);
1139 rect.bottom = (UINT16)MIN(UINT16_MAX, cmd->top + cmd->height);
1141 while (rect.top < rect.bottom)
1146 if (!Stream_CheckAndLogRequiredLength(TAG, s, 2))
1147 return ERROR_INVALID_DATA;
1149 Stream_Read_UINT8(s, a);
1150 Stream_Read_UINT8(s, count);
1154 if (!Stream_CheckAndLogRequiredLength(TAG, s, 2))
1155 return ERROR_INVALID_DATA;
1157 Stream_Read_UINT16(s, count);
1159 if (count >= 0xFFFF)
1161 if (!Stream_CheckAndLogRequiredLength(TAG, s, 4))
1162 return ERROR_INVALID_DATA;
1164 Stream_Read_UINT32(s, count);
1168 if (!gdi_apply_alpha(surface->data, surface->format, surface->scanline, &rect,
1169 startOffsetX, count, a))
1170 return ERROR_INTERNAL_ERROR;
1172 startOffsetX += count;
1174 while (startOffsetX >= cmd->width)
1176 startOffsetX -= cmd->width;
1182 invalidRect.left = (UINT16)MIN(UINT16_MAX, cmd->left);
1183 invalidRect.top = (UINT16)MIN(UINT16_MAX, cmd->top);
1184 invalidRect.right = (UINT16)MIN(UINT16_MAX, cmd->right);
1185 invalidRect.bottom = (UINT16)MIN(UINT16_MAX, cmd->bottom);
1186 if (!gdi_surface_invalidate_rect(surface, &invalidRect))
1188 status = IFCALLRESULT(CHANNEL_RC_OK, context->UpdateSurfaceArea, context, surface->surfaceId, 1,
1191 if (status != CHANNEL_RC_OK)
1194 status = gdi_interFrameUpdate(gdi, context);
1200#if defined(WITH_GFX_FRAME_DUMP)
1203 static UINT64 xxx = 0;
1204 const char* path =
"/tmp/dump/";
1206 char fname[1024] = WINPR_C_ARRAY_INIT;
1208 if (_snprintf(fname,
sizeof(fname),
"%s/%08" PRIx64
".raw", path, xxx++) < 0)
1211 FILE* fp = fopen(fname,
"w");
1214 (void)fprintf(fp,
"frameid: %" PRIu32
"\n", frameId);
1215 (void)fprintf(fp,
"surfaceId: %" PRIu32
"\n", cmd->surfaceId);
1216 (void)fprintf(fp,
"codecId: %" PRIu32
"\n", cmd->codecId);
1217 (void)fprintf(fp,
"contextId: %" PRIu32
"\n", cmd->contextId);
1218 (void)fprintf(fp,
"format: %" PRIu32
"\n", cmd->format);
1219 (void)fprintf(fp,
"left: %" PRIu32
"\n", cmd->left);
1220 (void)fprintf(fp,
"top: %" PRIu32
"\n", cmd->top);
1221 (void)fprintf(fp,
"right: %" PRIu32
"\n", cmd->right);
1222 (void)fprintf(fp,
"bottom: %" PRIu32
"\n", cmd->bottom);
1223 (void)fprintf(fp,
"width: %" PRIu32
"\n", cmd->width);
1224 (void)fprintf(fp,
"height: %" PRIu32
"\n", cmd->height);
1225 (void)fprintf(fp,
"length: %" PRIu32
"\n", cmd->length);
1227 char* bdata = crypto_base64_encode_ex(cmd->data, cmd->length, FALSE);
1228 (void)fprintf(fp,
"data: %s\n", bdata);
1240static UINT gdi_SurfaceCommand_Progressive(rdpGdi* gdi, RdpgfxClientContext* context,
1244 UINT status = ERROR_INTERNAL_ERROR;
1245 gdiGfxSurface* surface =
nullptr;
1255 WINPR_ASSERT(context);
1257 const UINT16 surfaceId = (UINT16)MIN(UINT16_MAX, cmd->surfaceId);
1259 WINPR_ASSERT(context->GetSurfaceData);
1260 surface = (gdiGfxSurface*)context->GetSurfaceData(context, surfaceId);
1264 WLog_ERR(TAG,
"unable to retrieve surfaceData for surfaceId=%" PRIu32
"", cmd->surfaceId);
1265 return ERROR_NOT_FOUND;
1268 if (!is_within_surface(surface, cmd))
1269 return ERROR_INVALID_DATA;
1271 WINPR_ASSERT(surface->codecs);
1272 rc = progressive_create_surface_context(surface->codecs->progressive, surfaceId, surface->width,
1277 WLog_ERR(TAG,
"progressive_create_surface_context failure: %" PRId32
"", rc);
1278 return ERROR_INTERNAL_ERROR;
1281 region16_init(&invalidRegion);
1283 rc = progressive_decompress(surface->codecs->progressive, cmd->data, cmd->length, surface->data,
1284 surface->format, surface->scanline, cmd->left, cmd->top,
1285 &invalidRegion, surfaceId, gdi->frameId);
1289 WLog_ERR(TAG,
"progressive_decompress failure: %" PRId32
"", rc);
1293 rects = region16_rects(&invalidRegion, &nrRects);
1294 status = IFCALLRESULT(CHANNEL_RC_OK, context->UpdateSurfaceArea, context, surface->surfaceId,
1297 if (status != CHANNEL_RC_OK)
1300 status = ERROR_INTERNAL_ERROR;
1301 for (UINT32 x = 0; x < nrRects; x++)
1303 if (!gdi_surface_invalidate_rect(surface, &rects[x]))
1307 status = gdi_interFrameUpdate(gdi, context);
1311 region16_uninit(&invalidRegion);
1323 UINT status = CHANNEL_RC_OK;
1324 rdpGdi* gdi =
nullptr;
1326 if (!context || !cmd)
1327 return ERROR_INVALID_PARAMETER;
1329 gdi = (rdpGdi*)context->custom;
1331 EnterCriticalSection(&context->mux);
1332 const UINT16 codecId = WINPR_ASSERTING_INT_CAST(UINT16, cmd->codecId);
1333 WLog_Print(gdi->log, WLOG_TRACE,
1334 "surfaceId=%" PRIu32
", codec=%s [%" PRIu32
"], contextId=%" PRIu32
", format=%s, "
1335 "left=%" PRIu32
", top=%" PRIu32
", right=%" PRIu32
", bottom=%" PRIu32
1336 ", width=%" PRIu32
", height=%" PRIu32
" "
1337 "length=%" PRIu32
", data=%p, extra=%p",
1338 cmd->surfaceId, rdpgfx_get_codec_id_string(codecId), cmd->codecId, cmd->contextId,
1339 FreeRDPGetColorFormatName(cmd->format), cmd->left, cmd->top, cmd->right, cmd->bottom,
1340 cmd->width, cmd->height, cmd->length, (
void*)cmd->data, (
void*)cmd->extra);
1341#if defined(WITH_GFX_FRAME_DUMP)
1342 dump_cmd(cmd, gdi->frameId);
1347 case RDPGFX_CODECID_UNCOMPRESSED:
1348 status = gdi_SurfaceCommand_Uncompressed(gdi, context, cmd);
1351#if defined(WITH_GFX_AV1) || defined(WITH_GFX_AV2)
1352 case RDPGFX_CODECID_AV1:
1354 switch (context->CapsVersion)
1356#if defined(WITH_GFX_AV1)
1357 case RDPGFX_CAPVERSION_FRDP_1:
1358 status = gdi_SurfaceCommand_AV1(gdi, context, cmd);
1361#if defined(WITH_GFX_AV2)
1362 case RDPGFX_CAPVERSION_FRDP_2:
1363 status = gdi_SurfaceCommand_AV2(gdi, context, cmd);
1368 "SurfaceCommand %s [0x%08" PRIX16
"] not valid with caps 0x%08" PRIX32,
1369 rdpgfx_get_codec_id_string(codecId), codecId, context->CapsVersion);
1370 status = ERROR_INVALID_DATA;
1376 case RDPGFX_CODECID_CAVIDEO:
1377 status = gdi_SurfaceCommand_RemoteFX(gdi, context, cmd);
1380 case RDPGFX_CODECID_CLEARCODEC:
1381 status = gdi_SurfaceCommand_ClearCodec(gdi, context, cmd);
1384 case RDPGFX_CODECID_PLANAR:
1385 status = gdi_SurfaceCommand_Planar(gdi, context, cmd);
1388 case RDPGFX_CODECID_AVC420:
1389 status = gdi_SurfaceCommand_AVC420(gdi, context, cmd);
1392 case RDPGFX_CODECID_AVC444v2:
1393 case RDPGFX_CODECID_AVC444:
1394 status = gdi_SurfaceCommand_AVC444(gdi, context, cmd);
1397 case RDPGFX_CODECID_ALPHA:
1398 status = gdi_SurfaceCommand_Alpha(gdi, context, cmd);
1401 case RDPGFX_CODECID_CAPROGRESSIVE:
1402 status = gdi_SurfaceCommand_Progressive(gdi, context, cmd);
1405 case RDPGFX_CODECID_CAPROGRESSIVE_V2:
1406 WLog_WARN(TAG,
"SurfaceCommand %s [0x%08" PRIX16
"] not implemented",
1407 rdpgfx_get_codec_id_string(codecId), codecId);
1411 WLog_WARN(TAG,
"Invalid SurfaceCommand %s [0x%08" PRIX16
"]",
1412 rdpgfx_get_codec_id_string(codecId), codecId);
1416 LeaveCriticalSection(&context->mux);
1427gdi_DeleteEncodingContext(RdpgfxClientContext* context,
1430 WINPR_ASSERT(context);
1431 WINPR_ASSERT(deleteEncodingContext);
1432 WINPR_UNUSED(context);
1433 WINPR_UNUSED(deleteEncodingContext);
1434 return CHANNEL_RC_OK;
1443static UINT gdi_CreateSurface(RdpgfxClientContext* context,
1446 UINT rc = ERROR_INTERNAL_ERROR;
1447 gdiGfxSurface* surface =
nullptr;
1448 rdpGdi* gdi =
nullptr;
1449 WINPR_ASSERT(context);
1450 WINPR_ASSERT(createSurface);
1451 gdi = (rdpGdi*)context->custom;
1453 WINPR_ASSERT(gdi->context);
1454 EnterCriticalSection(&context->mux);
1455 surface = (gdiGfxSurface*)calloc(1,
sizeof(gdiGfxSurface));
1462 WINPR_ASSERT(context->codecs);
1463 surface->codecs = context->codecs;
1465 if (!surface->codecs)
1472 surface->surfaceId = createSurface->surfaceId;
1473 surface->width = gfx_align_scanline(createSurface->width, 16);
1474 surface->height = gfx_align_scanline(createSurface->height, 16);
1475 surface->mappedWidth = createSurface->width;
1476 surface->mappedHeight = createSurface->height;
1477 surface->outputTargetWidth = createSurface->width;
1478 surface->outputTargetHeight = createSurface->height;
1482 switch (createSurface->pixelFormat)
1484 case GFX_PIXEL_FORMAT_ARGB_8888:
1485 surface->format = PIXEL_FORMAT_BGRA32;
1488 case GFX_PIXEL_FORMAT_XRGB_8888:
1489 surface->format = rails ? PIXEL_FORMAT_BGRA32 : PIXEL_FORMAT_BGRX32;
1497 if (surface->width > UINT32_MAX / 4 - 2 * 16)
1505 surface->scanline = gfx_align_scanline(surface->width * 4UL, 16) + 16ul;
1506 surface->data = (BYTE*)winpr_aligned_calloc(surface->scanline, surface->height, 16);
1514 for (UINT64 y = 0; y < surface->height; y++)
1515 memset(&surface->data[surface->scanline * y], 0xFF, surface->scanline);
1516 region16_init(&surface->invalidRegion);
1518 WINPR_ASSERT(context->SetSurfaceData);
1519 rc = context->SetSurfaceData(context, surface->surfaceId, (
void*)surface);
1521 LeaveCriticalSection(&context->mux);
1531static UINT gdi_DeleteSurface(RdpgfxClientContext* context,
1534 UINT rc = CHANNEL_RC_OK;
1535 UINT res = ERROR_INTERNAL_ERROR;
1536 rdpCodecs* codecs =
nullptr;
1537 gdiGfxSurface* surface =
nullptr;
1538 EnterCriticalSection(&context->mux);
1540 WINPR_ASSERT(context->GetSurfaceData);
1541 surface = (gdiGfxSurface*)context->GetSurfaceData(context, deleteSurface->surfaceId);
1545 if (surface->windowMapped)
1546 rc = IFCALLRESULT(CHANNEL_RC_OK, context->UnmapWindowForSurface, context,
1550 h264_context_free(surface->h264);
1552#if defined(WITH_GFX_AV1)
1553 freerdp_av1_context_free(surface->av1);
1555#if defined(WITH_GFX_AV2)
1556 freerdp_av2_context_free(surface->av2);
1558 region16_uninit(&surface->invalidRegion);
1559 codecs = surface->codecs;
1560 winpr_aligned_free(surface->data);
1564 WINPR_ASSERT(context->SetSurfaceData);
1565 res = context->SetSurfaceData(context, deleteSurface->surfaceId,
nullptr);
1569 if (codecs && codecs->progressive)
1570 progressive_delete_surface_context(codecs->progressive, deleteSurface->surfaceId);
1572 LeaveCriticalSection(&context->mux);
1577static BOOL intersect_rect(
const RECTANGLE_16* rect,
const gdiGfxSurface* surface,
1581 WINPR_ASSERT(surface);
1582 WINPR_ASSERT(prect);
1584 if (rect->left > rect->right)
1586 if (rect->left > surface->width)
1588 if (rect->top > rect->bottom)
1590 if (rect->top > surface->height)
1592 prect->left = rect->left;
1593 prect->top = rect->top;
1595 prect->right = MIN(rect->right, WINPR_ASSERTING_INT_CAST(UINT16, surface->width));
1596 prect->bottom = MIN(rect->bottom, WINPR_ASSERTING_INT_CAST(UINT16, surface->height));
1608 UINT status = ERROR_INTERNAL_ERROR;
1611 rdpGdi* gdi = (rdpGdi*)context->custom;
1613 EnterCriticalSection(&context->mux);
1615 WINPR_ASSERT(context->GetSurfaceData);
1616 gdiGfxSurface* surface = (gdiGfxSurface*)context->GetSurfaceData(context, solidFill->surfaceId);
1622 const BYTE b = solidFill->fillPixel.B;
1623 const BYTE g = solidFill->fillPixel.G;
1624 const BYTE r = solidFill->fillPixel.R;
1631 const UINT32 color = FreeRDPGetColor(surface->format, r, g, b, a);
1632 for (UINT16 index = 0; index < solidFill->fillRectCount; index++)
1634 const RECTANGLE_16* rect = &(solidFill->fillRects[index]);
1636 if (!intersect_rect(rect, surface, &invalidRect))
1639 const UINT32 nWidth = invalidRect.right - invalidRect.left;
1640 const UINT32 nHeight = invalidRect.bottom - invalidRect.top;
1642 if (!freerdp_image_fill(surface->data, surface->format, surface->scanline,
1643 invalidRect.left, invalidRect.top, nWidth, nHeight, color))
1646 if (!gdi_surface_invalidate_rect(surface, &invalidRect))
1651 status = IFCALLRESULT(CHANNEL_RC_OK, context->UpdateSurfaceArea, context, surface->surfaceId,
1652 solidFill->fillRectCount, solidFill->fillRects);
1654 if (status != CHANNEL_RC_OK)
1657 LeaveCriticalSection(&context->mux);
1659 return gdi_interFrameUpdate(gdi, context);
1661 LeaveCriticalSection(&context->mux);
1671static UINT gdi_SurfaceToSurface(RdpgfxClientContext* context,
1674 UINT status = ERROR_INTERNAL_ERROR;
1675 BOOL sameSurface = 0;
1678 gdiGfxSurface* surfaceSrc =
nullptr;
1679 gdiGfxSurface* surfaceDst =
nullptr;
1680 rdpGdi* gdi = (rdpGdi*)context->custom;
1681 EnterCriticalSection(&context->mux);
1682 rectSrc = &(surfaceToSurface->rectSrc);
1684 WINPR_ASSERT(context->GetSurfaceData);
1685 surfaceSrc = (gdiGfxSurface*)context->GetSurfaceData(context, surfaceToSurface->surfaceIdSrc);
1686 sameSurface = (surfaceToSurface->surfaceIdSrc == surfaceToSurface->surfaceIdDest);
1690 (gdiGfxSurface*)context->GetSurfaceData(context, surfaceToSurface->surfaceIdDest);
1692 surfaceDst = surfaceSrc;
1694 if (!surfaceSrc || !surfaceDst)
1697 if (!is_rect_valid(rectSrc, surfaceSrc->width, surfaceSrc->height))
1701 const UINT32 nWidth = rectSrc->right - rectSrc->left;
1702 const UINT32 nHeight = rectSrc->bottom - rectSrc->top;
1704 for (UINT16 index = 0; index < surfaceToSurface->destPtsCount; index++)
1706 const RDPGFX_POINT16* destPt = &surfaceToSurface->destPts[index];
1708 (UINT16)MIN(UINT16_MAX, destPt->x + nWidth),
1709 (UINT16)MIN(UINT16_MAX, destPt->y + nHeight) };
1710 if (!is_rect_valid(&rect, surfaceDst->width, surfaceDst->height))
1713 const UINT32 rwidth = rect.right - rect.left;
1714 const UINT32 rheight = rect.bottom - rect.top;
1715 if (!freerdp_image_copy(surfaceDst->data, surfaceDst->format, surfaceDst->scanline,
1716 destPt->x, destPt->y, rwidth, rheight, surfaceSrc->data,
1717 surfaceSrc->format, surfaceSrc->scanline, rectSrc->left,
1718 rectSrc->top,
nullptr, FREERDP_FLIP_NONE))
1722 if (!gdi_surface_invalidate_rect(surfaceDst, &invalidRect))
1724 status = IFCALLRESULT(CHANNEL_RC_OK, context->UpdateSurfaceArea, context,
1725 surfaceDst->surfaceId, 1, &invalidRect);
1727 if (status != CHANNEL_RC_OK)
1732 LeaveCriticalSection(&context->mux);
1734 return gdi_interFrameUpdate(gdi, context);
1736 LeaveCriticalSection(&context->mux);
1740static void gdi_GfxCacheEntryFree(gdiGfxCacheEntry* entry)
1748WINPR_ATTR_MALLOC(gdi_GfxCacheEntryFree, 1)
1749static gdiGfxCacheEntry* gdi_GfxCacheEntryNew(UINT64 cacheKey, UINT32 width, UINT32 height,
1752 gdiGfxCacheEntry* cacheEntry = (gdiGfxCacheEntry*)calloc(1,
sizeof(gdiGfxCacheEntry));
1756 cacheEntry->cacheKey = cacheKey;
1757 cacheEntry->width = width;
1758 cacheEntry->height = height;
1759 cacheEntry->format = format;
1761 const UINT32 bpp = MAX(4, FreeRDPGetBytesPerPixel(format));
1762 cacheEntry->scanline = gfx_align_scanline(cacheEntry->width * bpp, 16);
1764 if ((cacheEntry->width > 0) && (cacheEntry->height > 0))
1766 cacheEntry->data = (BYTE*)calloc(cacheEntry->height, cacheEntry->scanline);
1768 if (!cacheEntry->data)
1773 gdi_GfxCacheEntryFree(cacheEntry);
1783static UINT gdi_SurfaceToCache(RdpgfxClientContext* context,
1786 gdiGfxCacheEntry* cacheEntry =
nullptr;
1787 UINT rc = ERROR_INTERNAL_ERROR;
1788 EnterCriticalSection(&context->mux);
1791 WINPR_ASSERT(context->GetSurfaceData);
1792 gdiGfxSurface* surface =
1793 (gdiGfxSurface*)context->GetSurfaceData(context, surfaceToCache->surfaceId);
1798 if (!is_rect_valid(rect, surface->width, surface->height))
1801 cacheEntry = gdi_GfxCacheEntryNew(surfaceToCache->cacheKey, (UINT32)(rect->right - rect->left),
1802 (UINT32)(rect->bottom - rect->top), surface->format);
1807 if (!cacheEntry->data)
1810 if (!freerdp_image_copy_no_overlap(cacheEntry->data, cacheEntry->format, cacheEntry->scanline,
1811 0, 0, cacheEntry->width, cacheEntry->height, surface->data,
1812 surface->format, surface->scanline, rect->left, rect->top,
1813 nullptr, FREERDP_FLIP_NONE))
1818 WINPR_ASSERT(context->EvictCacheEntry);
1819 rc = context->EvictCacheEntry(context, &evict);
1820 if (rc != CHANNEL_RC_OK)
1824 WINPR_ASSERT(context->SetCacheSlotData);
1825 rc = context->SetCacheSlotData(context, surfaceToCache->cacheSlot, (
void*)cacheEntry);
1827 if (rc != CHANNEL_RC_OK)
1828 gdi_GfxCacheEntryFree(cacheEntry);
1829 LeaveCriticalSection(&context->mux);
1839static UINT gdi_CacheToSurface(RdpgfxClientContext* context,
1842 UINT status = ERROR_INTERNAL_ERROR;
1843 gdiGfxSurface* surface =
nullptr;
1844 gdiGfxCacheEntry* cacheEntry =
nullptr;
1846 rdpGdi* gdi = (rdpGdi*)context->custom;
1848 EnterCriticalSection(&context->mux);
1850 WINPR_ASSERT(context->GetSurfaceData);
1851 surface = (gdiGfxSurface*)context->GetSurfaceData(context, cacheToSurface->surfaceId);
1853 WINPR_ASSERT(context->GetCacheSlotData);
1854 cacheEntry = (gdiGfxCacheEntry*)context->GetCacheSlotData(context, cacheToSurface->cacheSlot);
1856 if (!surface || !cacheEntry)
1859 for (UINT16 index = 0; index < cacheToSurface->destPtsCount; index++)
1863 (UINT16)MIN(UINT16_MAX, destPt->x + cacheEntry->width),
1864 (UINT16)MIN(UINT16_MAX, destPt->y + cacheEntry->height) };
1866 if (rectangle_is_empty(&rect))
1869 if (!is_rect_valid(&rect, surface->width, surface->height))
1872 const UINT32 w = rect.right - rect.left;
1873 const UINT32 h = rect.bottom - rect.top;
1874 if (!freerdp_image_copy_no_overlap(surface->data, surface->format, surface->scanline,
1875 destPt->x, destPt->y, w, h, cacheEntry->data,
1876 cacheEntry->format, cacheEntry->scanline, 0, 0,
nullptr,
1881 if (!gdi_surface_invalidate_rect(surface, &invalidRect))
1883 status = IFCALLRESULT(CHANNEL_RC_OK, context->UpdateSurfaceArea, context,
1884 surface->surfaceId, 1, &invalidRect);
1886 if (status != CHANNEL_RC_OK)
1890 LeaveCriticalSection(&context->mux);
1892 return gdi_interFrameUpdate(gdi, context);
1895 LeaveCriticalSection(&context->mux);
1905static UINT gdi_CacheImportReply(RdpgfxClientContext* context,
1909 const UINT16* slots =
nullptr;
1910 UINT error = CHANNEL_RC_OK;
1912 slots = cacheImportReply->cacheSlots;
1913 count = cacheImportReply->importedEntriesCount;
1915 for (UINT16 index = 0; index < count; index++)
1917 UINT16 cacheSlot = slots[index];
1922 WINPR_ASSERT(context->GetCacheSlotData);
1923 gdiGfxCacheEntry* cacheEntry =
1924 (gdiGfxCacheEntry*)context->GetCacheSlotData(context, cacheSlot);
1929 cacheEntry = gdi_GfxCacheEntryNew(cacheSlot, 0, 0, PIXEL_FORMAT_BGRX32);
1932 return ERROR_INTERNAL_ERROR;
1934 WINPR_ASSERT(context->SetCacheSlotData);
1935 error = context->SetCacheSlotData(context, cacheSlot, (
void*)cacheEntry);
1939 WLog_ERR(TAG,
"CacheImportReply: SetCacheSlotData failed with error %" PRIu32
"",
1941 gdi_GfxCacheEntryFree(cacheEntry);
1950static UINT gdi_ImportCacheEntry(RdpgfxClientContext* context, UINT16 cacheSlot,
1953 UINT error = ERROR_INTERNAL_ERROR;
1954 gdiGfxCacheEntry* cacheEntry =
nullptr;
1957 return CHANNEL_RC_OK;
1959 cacheEntry = gdi_GfxCacheEntryNew(importCacheEntry->key64, importCacheEntry->width,
1960 importCacheEntry->height, PIXEL_FORMAT_BGRX32);
1965 if (!freerdp_image_copy_no_overlap(cacheEntry->data, cacheEntry->format, cacheEntry->scanline,
1966 0, 0, cacheEntry->width, cacheEntry->height,
1967 importCacheEntry->data, PIXEL_FORMAT_BGRX32, 0, 0, 0,
1968 nullptr, FREERDP_FLIP_NONE))
1973 WINPR_ASSERT(context->EvictCacheEntry);
1974 error = context->EvictCacheEntry(context, &evict);
1976 if (error != CHANNEL_RC_OK)
1979 WINPR_ASSERT(context->SetCacheSlotData);
1980 error = context->SetCacheSlotData(context, cacheSlot, (
void*)cacheEntry);
1985 gdi_GfxCacheEntryFree(cacheEntry);
1986 WLog_ERR(TAG,
"ImportCacheEntry: SetCacheSlotData failed with error %" PRIu32
"", error);
1993static UINT gdi_ExportCacheEntry(RdpgfxClientContext* context, UINT16 cacheSlot,
1996 WINPR_ASSERT(context->GetCacheSlotData);
1997 gdiGfxCacheEntry* cacheEntry = (gdiGfxCacheEntry*)context->GetCacheSlotData(context, cacheSlot);
2001 exportCacheEntry->key64 = cacheEntry->cacheKey;
2002 exportCacheEntry->width = (UINT16)MIN(UINT16_MAX, cacheEntry->width);
2003 exportCacheEntry->height = (UINT16)MIN(UINT16_MAX, cacheEntry->height);
2004 const UINT64 size = 4ull * cacheEntry->width * cacheEntry->height;
2005 if (size > UINT32_MAX)
2006 return ERROR_NOT_FOUND;
2008 exportCacheEntry->size = WINPR_ASSERTING_INT_CAST(UINT32, size);
2009 exportCacheEntry->flags = 0;
2010 exportCacheEntry->data = cacheEntry->data;
2011 return CHANNEL_RC_OK;
2014 return ERROR_NOT_FOUND;
2023static UINT gdi_EvictCacheEntry(RdpgfxClientContext* context,
2026 gdiGfxCacheEntry* cacheEntry =
nullptr;
2027 UINT rc = ERROR_NOT_FOUND;
2029 WINPR_ASSERT(context);
2030 WINPR_ASSERT(evictCacheEntry);
2032 EnterCriticalSection(&context->mux);
2034 WINPR_ASSERT(context->GetCacheSlotData);
2035 cacheEntry = (gdiGfxCacheEntry*)context->GetCacheSlotData(context, evictCacheEntry->cacheSlot);
2037 gdi_GfxCacheEntryFree(cacheEntry);
2039 WINPR_ASSERT(context->SetCacheSlotData);
2040 rc = context->SetCacheSlotData(context, evictCacheEntry->cacheSlot,
nullptr);
2041 LeaveCriticalSection(&context->mux);
2051static UINT gdi_MapSurfaceToOutput(RdpgfxClientContext* context,
2054 UINT rc = ERROR_INTERNAL_ERROR;
2055 gdiGfxSurface* surface =
nullptr;
2056 EnterCriticalSection(&context->mux);
2058 WINPR_ASSERT(context->GetSurfaceData);
2059 surface = (gdiGfxSurface*)context->GetSurfaceData(context, surfaceToOutput->surfaceId);
2064 if (surface->windowMapped)
2066 WLog_WARN(TAG,
"surface already windowMapped when trying to set outputMapped");
2070 surface->outputMapped = TRUE;
2071 surface->outputOriginX = surfaceToOutput->outputOriginX;
2072 surface->outputOriginY = surfaceToOutput->outputOriginY;
2073 surface->outputTargetWidth = surface->mappedWidth;
2074 surface->outputTargetHeight = surface->mappedHeight;
2075 region16_clear(&surface->invalidRegion);
2078 LeaveCriticalSection(&context->mux);
2084gdi_MapSurfaceToScaledOutput(RdpgfxClientContext* context,
2087 UINT rc = ERROR_INTERNAL_ERROR;
2088 gdiGfxSurface* surface =
nullptr;
2089 EnterCriticalSection(&context->mux);
2091 WINPR_ASSERT(context->GetSurfaceData);
2092 surface = (gdiGfxSurface*)context->GetSurfaceData(context, surfaceToOutput->surfaceId);
2097 if (surface->windowMapped)
2099 WLog_WARN(TAG,
"surface already windowMapped when trying to set outputMapped");
2103 surface->outputMapped = TRUE;
2104 surface->outputOriginX = surfaceToOutput->outputOriginX;
2105 surface->outputOriginY = surfaceToOutput->outputOriginY;
2106 surface->outputTargetWidth = surfaceToOutput->targetWidth;
2107 surface->outputTargetHeight = surfaceToOutput->targetHeight;
2108 region16_clear(&surface->invalidRegion);
2111 LeaveCriticalSection(&context->mux);
2121static UINT gdi_MapSurfaceToWindow(RdpgfxClientContext* context,
2124 UINT rc = ERROR_INTERNAL_ERROR;
2125 gdiGfxSurface* surface =
nullptr;
2126 EnterCriticalSection(&context->mux);
2128 WINPR_ASSERT(context->GetSurfaceData);
2129 surface = (gdiGfxSurface*)context->GetSurfaceData(context, surfaceToWindow->surfaceId);
2134 if (surface->outputMapped)
2136 WLog_WARN(TAG,
"surface already outputMapped when trying to set windowMapped");
2140 if (surface->windowMapped)
2142 if (surface->windowId != surfaceToWindow->windowId)
2144 WLog_WARN(TAG,
"surface windowId mismatch, has %" PRIu64
", expected %" PRIu64,
2145 surface->windowId, surfaceToWindow->windowId);
2149 surface->windowMapped = TRUE;
2151 surface->windowId = surfaceToWindow->windowId;
2152 surface->mappedWidth = surfaceToWindow->mappedWidth;
2153 if (surface->mappedWidth > surface->width)
2155 WLog_WARN(TAG,
"surface mappedWidth[%" PRIu32
"] > width[%" PRIu32
"]",
2156 surface->mappedWidth, surface->width);
2159 surface->mappedHeight = surfaceToWindow->mappedHeight;
2160 if (surface->mappedHeight > surface->height)
2162 WLog_WARN(TAG,
"surface mappedHeight[%" PRIu32
"] > height[%" PRIu32
"]",
2163 surface->mappedHeight, surface->height);
2166 surface->outputTargetWidth = surfaceToWindow->mappedWidth;
2167 surface->outputTargetHeight = surfaceToWindow->mappedHeight;
2168 rc = IFCALLRESULT(CHANNEL_RC_OK, context->MapWindowForSurface, context,
2169 surfaceToWindow->surfaceId, surfaceToWindow->windowId);
2171 LeaveCriticalSection(&context->mux);
2177gdi_MapSurfaceToScaledWindow(RdpgfxClientContext* context,
2180 UINT rc = ERROR_INTERNAL_ERROR;
2181 gdiGfxSurface* surface =
nullptr;
2182 EnterCriticalSection(&context->mux);
2184 WINPR_ASSERT(context->GetSurfaceData);
2185 surface = (gdiGfxSurface*)context->GetSurfaceData(context, surfaceToWindow->surfaceId);
2190 if (surface->outputMapped)
2192 WLog_WARN(TAG,
"surface already outputMapped when trying to set windowMapped");
2196 if (surface->windowMapped)
2198 if (surface->windowId != surfaceToWindow->windowId)
2200 WLog_WARN(TAG,
"surface windowId mismatch, has %" PRIu64
", expected %" PRIu64,
2201 surface->windowId, surfaceToWindow->windowId);
2205 surface->windowMapped = TRUE;
2207 surface->windowId = surfaceToWindow->windowId;
2208 surface->mappedWidth = surfaceToWindow->mappedWidth;
2209 if (surface->mappedWidth > surface->width)
2211 WLog_WARN(TAG,
"surface mappedWidth[%" PRIu32
"] > width[%" PRIu32
"]",
2212 surface->mappedWidth, surface->width);
2216 surface->mappedHeight = surfaceToWindow->mappedHeight;
2217 if (surface->mappedHeight > surface->height)
2219 WLog_WARN(TAG,
"surface mappedHeight[%" PRIu32
"] > height[%" PRIu32
"]",
2220 surface->mappedHeight, surface->height);
2223 surface->outputTargetWidth = surfaceToWindow->targetWidth;
2224 surface->outputTargetHeight = surfaceToWindow->targetHeight;
2225 rc = IFCALLRESULT(CHANNEL_RC_OK, context->MapWindowForSurface, context,
2226 surfaceToWindow->surfaceId, surfaceToWindow->windowId);
2228 LeaveCriticalSection(&context->mux);
2232BOOL gdi_graphics_pipeline_init(rdpGdi* gdi, RdpgfxClientContext* gfx)
2234 return gdi_graphics_pipeline_init_ex(gdi, gfx,
nullptr,
nullptr,
nullptr);
2237BOOL gdi_graphics_pipeline_init_ex(rdpGdi* gdi, RdpgfxClientContext* gfx,
2238 pcRdpgfxMapWindowForSurface map,
2239 pcRdpgfxUnmapWindowForSurface unmap,
2240 pcRdpgfxUpdateSurfaceArea update)
2242 if (!gdi || !gfx || !gdi->context || !gdi->context->settings)
2245 rdpContext* context = gdi->context;
2246 rdpSettings* settings = context->settings;
2249 gfx->custom = (
void*)gdi;
2250 gfx->ResetGraphics = gdi_ResetGraphics;
2251 gfx->StartFrame = gdi_StartFrame;
2252 gfx->EndFrame = gdi_EndFrame;
2253 gfx->SurfaceCommand = gdi_SurfaceCommand;
2254 gfx->DeleteEncodingContext = gdi_DeleteEncodingContext;
2255 gfx->CreateSurface = gdi_CreateSurface;
2256 gfx->DeleteSurface = gdi_DeleteSurface;
2257 gfx->SolidFill = gdi_SolidFill;
2258 gfx->SurfaceToSurface = gdi_SurfaceToSurface;
2259 gfx->SurfaceToCache = gdi_SurfaceToCache;
2260 gfx->CacheToSurface = gdi_CacheToSurface;
2261 gfx->CacheImportReply = gdi_CacheImportReply;
2262 gfx->ImportCacheEntry = gdi_ImportCacheEntry;
2263 gfx->ExportCacheEntry = gdi_ExportCacheEntry;
2264 gfx->EvictCacheEntry = gdi_EvictCacheEntry;
2265 gfx->MapSurfaceToOutput = gdi_MapSurfaceToOutput;
2266 gfx->MapSurfaceToWindow = gdi_MapSurfaceToWindow;
2267 gfx->MapSurfaceToScaledOutput = gdi_MapSurfaceToScaledOutput;
2268 gfx->MapSurfaceToScaledWindow = gdi_MapSurfaceToScaledWindow;
2269 gfx->UpdateSurfaces = gdi_UpdateSurfaces;
2270 gfx->MapWindowForSurface = map;
2271 gfx->UnmapWindowForSurface = unmap;
2272 gfx->UpdateSurfaceArea = update;
2280 gfx->codecs = freerdp_client_codecs_new(flags);
2283 if (!freerdp_client_codecs_prepare(gfx->codecs, FREERDP_CODEC_ALL, w, h))
2286 InitializeCriticalSection(&gfx->mux);
2287 PROFILER_CREATE(gfx->SurfaceProfiler,
"GFX-PROFILER")
2295 gdi->graphicsReset = TRUE;
2298 gfx->UpdateSurfaceArea =
nullptr;
2299 gfx->UpdateSurfaces =
nullptr;
2300 gfx->SurfaceCommand =
nullptr;
2306void gdi_graphics_pipeline_uninit(rdpGdi* gdi, RdpgfxClientContext* gfx)
2314 gfx->custom =
nullptr;
2315 freerdp_client_codecs_free(gfx->codecs);
2316 gfx->codecs =
nullptr;
2317 DeleteCriticalSection(&gfx->mux);
2318 PROFILER_PRINT_HEADER
2319 PROFILER_PRINT(gfx->SurfaceProfiler)
2320 PROFILER_PRINT_FOOTER
2321 PROFILER_FREE(gfx->SurfaceProfiler)
WINPR_ATTR_NODISCARD FREERDP_API UINT32 freerdp_settings_get_codecs_flags(const rdpSettings *settings)
helper function to get a mask of supported codec flags.
WINPR_ATTR_NODISCARD FREERDP_API BOOL freerdp_settings_set_uint32(rdpSettings *settings, FreeRDP_Settings_Keys_UInt32 id, UINT32 val)
Sets a UINT32 settings value.
WINPR_ATTR_NODISCARD FREERDP_API UINT32 freerdp_settings_get_uint32(const rdpSettings *settings, FreeRDP_Settings_Keys_UInt32 id)
Returns a UINT32 settings value.
WINPR_ATTR_NODISCARD FREERDP_API BOOL freerdp_settings_get_bool(const rdpSettings *settings, FreeRDP_Settings_Keys_Bool id)
Returns a boolean settings value.