FreeRDP
Loading...
Searching...
No Matches
gdi/gfx.c
1
22#include <freerdp/config.h>
23
24#include "../core/update.h"
25
26#include <winpr/assert.h>
27#include <winpr/cast.h>
28
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>
34#include <math.h>
35
36#define TAG FREERDP_TAG("gdi")
37
38static BOOL is_rect_valid(const RECTANGLE_16* rect, size_t width, size_t height)
39{
40 if (!rect)
41 return FALSE;
42 if ((rect->left > rect->right) || (rect->right > width))
43 return FALSE;
44 if ((rect->top > rect->bottom) || (rect->bottom > height))
45 return FALSE;
46 return TRUE;
47}
48
49static BOOL is_within_surface(const gdiGfxSurface* surface, const RDPGFX_SURFACE_COMMAND* cmd)
50{
51 RECTANGLE_16 rect;
52 if (!surface || !cmd)
53 return FALSE;
54 rect.left = (UINT16)MIN(UINT16_MAX, cmd->left);
55 rect.top = (UINT16)MIN(UINT16_MAX, cmd->top);
56 rect.right = (UINT16)MIN(UINT16_MAX, cmd->right);
57 rect.bottom = (UINT16)MIN(UINT16_MAX, cmd->bottom);
58 if (!is_rect_valid(&rect, surface->width, surface->height))
59 {
60 WLog_ERR(TAG,
61 "Command rect %" PRIu32 "x%" PRIu32 "-%" PRIu32 "x%" PRIu32
62 " not within bounds of %" PRIu32 "x%" PRIu32,
63 rect.left, rect.top, cmd->width, cmd->height, surface->width, surface->height);
64 return FALSE;
65 }
66
67 return TRUE;
68}
69
70static DWORD gfx_align_scanline(DWORD widthInBytes, DWORD alignment)
71{
72 const UINT32 align = alignment;
73 const UINT32 pad = align - (widthInBytes % alignment);
74 UINT32 scanline = widthInBytes;
75
76 if (align != pad)
77 scanline += pad;
78
79 return scanline;
80}
81
87static UINT gdi_ResetGraphics(RdpgfxClientContext* context,
88 const RDPGFX_RESET_GRAPHICS_PDU* resetGraphics)
89{
90 UINT rc = ERROR_INTERNAL_ERROR;
91 UINT16 count = 0;
92 UINT32 DesktopWidth = 0;
93 UINT32 DesktopHeight = 0;
94 UINT16* pSurfaceIds = nullptr;
95 rdpGdi* gdi = nullptr;
96 rdpUpdate* update = nullptr;
97 rdpSettings* settings = nullptr;
98
99 WINPR_ASSERT(context);
100 WINPR_ASSERT(resetGraphics);
101
102 gdi = (rdpGdi*)context->custom;
103 WINPR_ASSERT(gdi);
104
105 update = gdi->context->update;
106 WINPR_ASSERT(update);
107
108 settings = gdi->context->settings;
109 WINPR_ASSERT(settings);
110 EnterCriticalSection(&context->mux);
111 DesktopWidth = resetGraphics->width;
112 DesktopHeight = resetGraphics->height;
113
114 if (!freerdp_settings_set_uint32(settings, FreeRDP_DesktopWidth, DesktopWidth))
115 goto fail;
116 if (!freerdp_settings_set_uint32(settings, FreeRDP_DesktopHeight, DesktopHeight))
117 goto fail;
118
119 if (update)
120 {
121 WINPR_ASSERT(update->DesktopResize);
122 if (!update->DesktopResize(gdi->context))
123 goto fail;
124 }
125
126 WINPR_ASSERT(context->GetSurfaceIds);
127 rc = context->GetSurfaceIds(context, &pSurfaceIds, &count);
128 if (rc != CHANNEL_RC_OK)
129 goto fail;
130
131 for (UINT32 index = 0; index < count; index++)
132 {
133 WINPR_ASSERT(context->GetSurfaceData);
134 gdiGfxSurface* surface =
135 (gdiGfxSurface*)context->GetSurfaceData(context, pSurfaceIds[index]);
136
137 if (!surface)
138 continue;
139
140 memset(surface->data, 0xFF, (size_t)surface->scanline * surface->height);
141 region16_clear(&surface->invalidRegion);
142 }
143
144 free(pSurfaceIds);
145
146 if (!freerdp_settings_get_bool(gdi->context->settings, FreeRDP_DeactivateClientDecoding))
147 {
148 const UINT32 width = (UINT32)MAX(0, gdi->width);
149 const UINT32 height = (UINT32)MAX(0, gdi->height);
150
151 if (!freerdp_client_codecs_reset(
152 context->codecs, freerdp_settings_get_codecs_flags(settings), width, height))
153 {
154 goto fail;
155 }
156 if (!freerdp_client_codecs_reset(
157 gdi->context->codecs, freerdp_settings_get_codecs_flags(settings), width, height))
158 {
159 goto fail;
160 }
161 }
162
163 rc = CHANNEL_RC_OK;
164fail:
165 LeaveCriticalSection(&context->mux);
166 return rc;
167}
168
169static UINT gdi_OutputUpdate(rdpGdi* gdi, gdiGfxSurface* surface)
170{
171 UINT rc = ERROR_INTERNAL_ERROR;
172 UINT32 surfaceX = 0;
173 UINT32 surfaceY = 0;
174 RECTANGLE_16 surfaceRect;
175 const RECTANGLE_16* rects = nullptr;
176 UINT32 nbRects = 0;
177 rdpUpdate* update = nullptr;
178
179 WINPR_ASSERT(gdi);
180 WINPR_ASSERT(gdi->context);
181 WINPR_ASSERT(surface);
182
183 update = gdi->context->update;
184 WINPR_ASSERT(update);
185
186 if (gdi->suppressOutput)
187 return CHANNEL_RC_OK;
188
189 surfaceX = surface->outputOriginX;
190 surfaceY = surface->outputOriginY;
191 surfaceRect.left = 0;
192 surfaceRect.top = 0;
193 surfaceRect.right = (UINT16)MIN(UINT16_MAX, surface->mappedWidth);
194 surfaceRect.bottom = (UINT16)MIN(UINT16_MAX, surface->mappedHeight);
195 if (!region16_intersect_rect(&(surface->invalidRegion), &(surface->invalidRegion),
196 &surfaceRect))
197 goto fail;
198
199 const double sx = surface->outputTargetWidth / (double)surface->mappedWidth;
200 const double sy = surface->outputTargetHeight / (double)surface->mappedHeight;
201
202 if (!(rects = region16_rects(&surface->invalidRegion, &nbRects)) || !nbRects)
203 return CHANNEL_RC_OK;
204
205 if (!update_begin_paint(update))
206 goto fail;
207
208 for (UINT32 i = 0; i < nbRects; i++)
209 {
210 const UINT32 nXSrc = rects[i].left;
211 const UINT32 nYSrc = rects[i].top;
212 const UINT32 nXDst = (UINT32)MIN(surfaceX + nXSrc * sx, gdi->width - 1);
213 const UINT32 nYDst = (UINT32)MIN(surfaceY + nYSrc * sy, gdi->height - 1);
214 const UINT32 swidth = rects[i].right - rects[i].left;
215 const UINT32 sheight = rects[i].bottom - rects[i].top;
216 const UINT32 dwidth = MIN((UINT32)(swidth * sx), (UINT32)gdi->width - nXDst);
217 const UINT32 dheight = MIN((UINT32)(sheight * sy), (UINT32)gdi->height - nYDst);
218
219 if (!freerdp_image_scale(gdi->primary_buffer, gdi->dstFormat, gdi->stride, nXDst, nYDst,
220 dwidth, dheight, surface->data, surface->format, surface->scanline,
221 nXSrc, nYSrc, swidth, sheight))
222 {
223 rc = CHANNEL_RC_NULL_DATA;
224 goto fail;
225 }
226
227 if (!gdi_InvalidateRegion(gdi->primary->hdc, (INT32)nXDst, (INT32)nYDst, (INT32)dwidth,
228 (INT32)dheight))
229 goto fail;
230 }
231
232 rc = CHANNEL_RC_OK;
233fail:
234
235 if (!update_end_paint(update))
236 rc = ERROR_INTERNAL_ERROR;
237
238 region16_clear(&(surface->invalidRegion));
239 return rc;
240}
241
242static UINT gdi_WindowUpdate(RdpgfxClientContext* context, gdiGfxSurface* surface)
243{
244 WINPR_ASSERT(context);
245 WINPR_ASSERT(surface);
246 return IFCALLRESULT(CHANNEL_RC_OK, context->UpdateWindowFromSurface, context, surface);
247}
248
249static UINT gdi_UpdateSurfaces(RdpgfxClientContext* context)
250{
251 UINT16 count = 0;
252 UINT16* pSurfaceIds = nullptr;
253
254 WINPR_ASSERT(context);
255
256 rdpGdi* gdi = (rdpGdi*)context->custom;
257 WINPR_ASSERT(gdi);
258
259 EnterCriticalSection(&context->mux);
260
261 WINPR_ASSERT(context->GetSurfaceIds);
262 UINT status = context->GetSurfaceIds(context, &pSurfaceIds, &count);
263 if (status != CHANNEL_RC_OK)
264 goto fail;
265
266 for (UINT32 index = 0; index < count; index++)
267 {
268 WINPR_ASSERT(context->GetSurfaceData);
269 gdiGfxSurface* surface =
270 (gdiGfxSurface*)context->GetSurfaceData(context, pSurfaceIds[index]);
271
272 if (!surface)
273 continue;
274
275 /* Already handled in UpdateSurfaceArea callbacks */
276 if (context->UpdateSurfaceArea)
277 {
278 if (surface->handleInUpdateSurfaceArea)
279 continue;
280 }
281
282 if (surface->outputMapped)
283 status = gdi_OutputUpdate(gdi, surface);
284 else if (surface->windowMapped)
285 status = gdi_WindowUpdate(context, surface);
286
287 if (status != CHANNEL_RC_OK)
288 break;
289 }
290
291fail:
292 free(pSurfaceIds);
293 LeaveCriticalSection(&context->mux);
294 return status;
295}
296
302static UINT gdi_StartFrame(RdpgfxClientContext* context, const RDPGFX_START_FRAME_PDU* startFrame)
303{
304 rdpGdi* gdi = nullptr;
305
306 WINPR_ASSERT(context);
307 WINPR_ASSERT(startFrame);
308
309 gdi = (rdpGdi*)context->custom;
310 WINPR_ASSERT(gdi);
311 gdi->inGfxFrame = TRUE;
312 gdi->frameId = startFrame->frameId;
313 return CHANNEL_RC_OK;
314}
315
316static UINT gdi_call_update_surfaces(RdpgfxClientContext* context)
317{
318 WINPR_ASSERT(context);
319 return IFCALLRESULT(CHANNEL_RC_OK, context->UpdateSurfaces, context);
320}
321
327static UINT gdi_EndFrame(RdpgfxClientContext* context,
328 WINPR_ATTR_UNUSED const RDPGFX_END_FRAME_PDU* endFrame)
329{
330 WINPR_ASSERT(context);
331 WINPR_ASSERT(endFrame);
332
333 rdpGdi* gdi = (rdpGdi*)context->custom;
334 WINPR_ASSERT(gdi);
335 const UINT status = gdi_call_update_surfaces(context);
336 gdi->inGfxFrame = FALSE;
337 return status;
338}
339
340static UINT gdi_interFrameUpdate(rdpGdi* gdi, RdpgfxClientContext* context)
341{
342 WINPR_ASSERT(gdi);
343 UINT status = CHANNEL_RC_OK;
344 if (!gdi->inGfxFrame)
345 status = gdi_call_update_surfaces(context);
346 return status;
347}
348
354static UINT gdi_SurfaceCommand_Uncompressed(rdpGdi* gdi, RdpgfxClientContext* context,
355 const RDPGFX_SURFACE_COMMAND* cmd)
356{
357 UINT status = CHANNEL_RC_OK;
358 gdiGfxSurface* surface = nullptr;
359 RECTANGLE_16 invalidRect;
360 DWORD bpp = 0;
361 size_t size = 0;
362 WINPR_ASSERT(gdi);
363 WINPR_ASSERT(context);
364 WINPR_ASSERT(cmd);
365
366 WINPR_ASSERT(context->GetSurfaceData);
367 surface =
368 (gdiGfxSurface*)context->GetSurfaceData(context, (UINT16)MIN(UINT16_MAX, cmd->surfaceId));
369
370 if (!surface)
371 {
372 WLog_ERR(TAG, "unable to retrieve surfaceData for surfaceId=%" PRIu32 "", cmd->surfaceId);
373 return ERROR_NOT_FOUND;
374 }
375
376 if (!is_within_surface(surface, cmd))
377 return ERROR_INVALID_DATA;
378
379 bpp = FreeRDPGetBytesPerPixel(cmd->format);
380 size = 1ull * bpp * cmd->width * cmd->height;
381 if (cmd->length < size)
382 {
383 WLog_ERR(TAG, "Not enough data, got %" PRIu32 ", expected %" PRIuz, cmd->length, size);
384 return ERROR_INVALID_DATA;
385 }
386
387 if (!freerdp_image_copy_no_overlap(surface->data, surface->format, surface->scanline, cmd->left,
388 cmd->top, cmd->width, cmd->height, cmd->data, cmd->format, 0,
389 0, 0, nullptr, FREERDP_FLIP_NONE))
390 return ERROR_INTERNAL_ERROR;
391
392 invalidRect.left = (UINT16)MIN(UINT16_MAX, cmd->left);
393 invalidRect.top = (UINT16)MIN(UINT16_MAX, cmd->top);
394 invalidRect.right = (UINT16)MIN(UINT16_MAX, cmd->right);
395 invalidRect.bottom = (UINT16)MIN(UINT16_MAX, cmd->bottom);
396 if (!region16_union_rect(&(surface->invalidRegion), &(surface->invalidRegion), &invalidRect))
397 goto fail;
398 status = IFCALLRESULT(CHANNEL_RC_OK, context->UpdateSurfaceArea, context, surface->surfaceId, 1,
399 &invalidRect);
400
401 if (status != CHANNEL_RC_OK)
402 goto fail;
403
404 status = gdi_interFrameUpdate(gdi, context);
405
406fail:
407 return status;
408}
409
415static UINT gdi_SurfaceCommand_RemoteFX(rdpGdi* gdi, RdpgfxClientContext* context,
416 const RDPGFX_SURFACE_COMMAND* cmd)
417{
418 UINT status = ERROR_INTERNAL_ERROR;
419 gdiGfxSurface* surface = nullptr;
420 REGION16 invalidRegion;
421 const RECTANGLE_16* rects = nullptr;
422 UINT32 nrRects = 0;
423 WINPR_ASSERT(gdi);
424 WINPR_ASSERT(context);
425 WINPR_ASSERT(cmd);
426
427 WINPR_ASSERT(context->GetSurfaceData);
428 surface =
429 (gdiGfxSurface*)context->GetSurfaceData(context, (UINT16)MIN(UINT16_MAX, cmd->surfaceId));
430
431 if (!surface)
432 {
433 WLog_ERR(TAG, "unable to retrieve surfaceData for surfaceId=%" PRIu32 "", cmd->surfaceId);
434 return ERROR_NOT_FOUND;
435 }
436
437 WINPR_ASSERT(surface->codecs);
438 rfx_context_set_pixel_format(surface->codecs->rfx, cmd->format);
439 region16_init(&invalidRegion);
440
441 if (!rfx_process_message(surface->codecs->rfx, cmd->data, cmd->length, cmd->left, cmd->top,
442 surface->data, surface->format, surface->scanline, surface->height,
443 &invalidRegion))
444 {
445 WLog_ERR(TAG, "Failed to process RemoteFX message");
446 goto fail;
447 }
448
449 rects = region16_rects(&invalidRegion, &nrRects);
450 status = IFCALLRESULT(CHANNEL_RC_OK, context->UpdateSurfaceArea, context, surface->surfaceId,
451 nrRects, rects);
452
453 if (status != CHANNEL_RC_OK)
454 goto fail;
455
456 for (UINT32 x = 0; x < nrRects; x++)
457 {
458 if (!region16_union_rect(&surface->invalidRegion, &surface->invalidRegion, &rects[x]))
459 goto fail;
460 }
461
462 status = gdi_interFrameUpdate(gdi, context);
463
464fail:
465 region16_uninit(&invalidRegion);
466 return status;
467}
468
474static UINT gdi_SurfaceCommand_ClearCodec(rdpGdi* gdi, RdpgfxClientContext* context,
475 const RDPGFX_SURFACE_COMMAND* cmd)
476{
477 INT32 rc = 0;
478 UINT status = CHANNEL_RC_OK;
479 gdiGfxSurface* surface = nullptr;
480 RECTANGLE_16 invalidRect;
481 WINPR_ASSERT(gdi);
482 WINPR_ASSERT(context);
483 WINPR_ASSERT(cmd);
484
485 WINPR_ASSERT(context->GetSurfaceData);
486 surface =
487 (gdiGfxSurface*)context->GetSurfaceData(context, (UINT16)MIN(UINT16_MAX, cmd->surfaceId));
488
489 if (!surface)
490 {
491 WLog_ERR(TAG, "unable to retrieve surfaceData for surfaceId=%" PRIu32 "", cmd->surfaceId);
492 return ERROR_NOT_FOUND;
493 }
494
495 WINPR_ASSERT(surface->codecs);
496 rc = clear_decompress(surface->codecs->clear, cmd->data, cmd->length, cmd->width, cmd->height,
497 surface->data, surface->format, surface->scanline, cmd->left, cmd->top,
498 surface->width, surface->height, &gdi->palette);
499
500 if (rc < 0)
501 {
502 WLog_ERR(TAG, "clear_decompress failure: %" PRId32 "", rc);
503 return ERROR_INTERNAL_ERROR;
504 }
505
506 invalidRect.left = (UINT16)MIN(UINT16_MAX, cmd->left);
507 invalidRect.top = (UINT16)MIN(UINT16_MAX, cmd->top);
508 invalidRect.right = (UINT16)MIN(UINT16_MAX, cmd->right);
509 invalidRect.bottom = (UINT16)MIN(UINT16_MAX, cmd->bottom);
510 if (!region16_union_rect(&(surface->invalidRegion), &(surface->invalidRegion), &invalidRect))
511 goto fail;
512 status = IFCALLRESULT(CHANNEL_RC_OK, context->UpdateSurfaceArea, context, surface->surfaceId, 1,
513 &invalidRect);
514
515 if (status != CHANNEL_RC_OK)
516 goto fail;
517
518 status = gdi_interFrameUpdate(gdi, context);
519
520fail:
521 return status;
522}
523
529static UINT gdi_SurfaceCommand_Planar(rdpGdi* gdi, RdpgfxClientContext* context,
530 const RDPGFX_SURFACE_COMMAND* cmd)
531{
532 UINT status = CHANNEL_RC_OK;
533 BYTE* DstData = nullptr;
534 gdiGfxSurface* surface = nullptr;
535 RECTANGLE_16 invalidRect;
536 WINPR_ASSERT(gdi);
537 WINPR_ASSERT(context);
538 WINPR_ASSERT(cmd);
539
540 WINPR_ASSERT(context->GetSurfaceData);
541 surface =
542 (gdiGfxSurface*)context->GetSurfaceData(context, (UINT16)MIN(UINT16_MAX, cmd->surfaceId));
543
544 if (!surface)
545 {
546 WLog_ERR(TAG, "unable to retrieve surfaceData for surfaceId=%" PRIu32 "", cmd->surfaceId);
547 return ERROR_NOT_FOUND;
548 }
549
550 DstData = surface->data;
551
552 if (!is_within_surface(surface, cmd))
553 return ERROR_INVALID_DATA;
554
555 if (!freerdp_bitmap_decompress_planar(surface->codecs->planar, cmd->data, cmd->length,
556 cmd->width, cmd->height, DstData, surface->format,
557 surface->scanline, cmd->left, cmd->top, cmd->width,
558 cmd->height, FALSE))
559 return ERROR_INTERNAL_ERROR;
560
561 invalidRect.left = (UINT16)MIN(UINT16_MAX, cmd->left);
562 invalidRect.top = (UINT16)MIN(UINT16_MAX, cmd->top);
563 invalidRect.right = (UINT16)MIN(UINT16_MAX, cmd->right);
564 invalidRect.bottom = (UINT16)MIN(UINT16_MAX, cmd->bottom);
565 if (!region16_union_rect(&(surface->invalidRegion), &(surface->invalidRegion), &invalidRect))
566 goto fail;
567 status = IFCALLRESULT(CHANNEL_RC_OK, context->UpdateSurfaceArea, context, surface->surfaceId, 1,
568 &invalidRect);
569
570 if (status != CHANNEL_RC_OK)
571 goto fail;
572
573 status = gdi_interFrameUpdate(gdi, context);
574
575fail:
576 return status;
577}
578
584static UINT gdi_SurfaceCommand_AVC420(rdpGdi* gdi, RdpgfxClientContext* context,
585 const RDPGFX_SURFACE_COMMAND* cmd)
586{
587#ifdef WITH_GFX_H264
588 INT32 rc = 0;
589 UINT status = CHANNEL_RC_OK;
590 gdiGfxSurface* surface = nullptr;
591 RDPGFX_H264_METABLOCK* meta = nullptr;
592 RDPGFX_AVC420_BITMAP_STREAM* bs = nullptr;
593 WINPR_ASSERT(gdi);
594 WINPR_ASSERT(context);
595 WINPR_ASSERT(cmd);
596
597 WINPR_ASSERT(context->GetSurfaceData);
598 surface =
599 (gdiGfxSurface*)context->GetSurfaceData(context, (UINT16)MIN(UINT16_MAX, cmd->surfaceId));
600
601 if (!surface)
602 {
603 WLog_ERR(TAG, "unable to retrieve surfaceData for surfaceId=%" PRIu32 "", cmd->surfaceId);
604 return ERROR_NOT_FOUND;
605 }
606
607 if (!surface->h264)
608 {
609 surface->h264 = h264_context_new(FALSE);
610
611 if (!surface->h264)
612 {
613 WLog_ERR(TAG, "unable to create h264 context");
614 return ERROR_NOT_ENOUGH_MEMORY;
615 }
616
617 if (!h264_context_reset(surface->h264, surface->width, surface->height))
618 return ERROR_INTERNAL_ERROR;
619 }
620
621 if (!surface->h264)
622 return ERROR_NOT_SUPPORTED;
623
624 bs = (RDPGFX_AVC420_BITMAP_STREAM*)cmd->extra;
625
626 if (!bs)
627 return ERROR_INTERNAL_ERROR;
628
629 meta = &(bs->meta);
630 rc = avc420_decompress(surface->h264, bs->data, bs->length, surface->data, surface->format,
631 surface->scanline, surface->width, surface->height, meta->regionRects,
632 meta->numRegionRects);
633
634 if (rc < 0)
635 {
636 WLog_WARN(TAG, "avc420_decompress failure: %" PRId32 ", ignoring update.", rc);
637 return CHANNEL_RC_OK;
638 }
639
640 for (UINT32 i = 0; i < meta->numRegionRects; i++)
641 {
642 if (!region16_union_rect(&(surface->invalidRegion), &(surface->invalidRegion),
643 &(meta->regionRects[i])))
644 goto fail;
645 }
646
647 status = IFCALLRESULT(CHANNEL_RC_OK, context->UpdateSurfaceArea, context, surface->surfaceId,
648 meta->numRegionRects, meta->regionRects);
649
650 if (status != CHANNEL_RC_OK)
651 goto fail;
652
653 status = gdi_interFrameUpdate(gdi, context);
654
655fail:
656 return status;
657#else
658 return ERROR_NOT_SUPPORTED;
659#endif
660}
661
667static UINT gdi_SurfaceCommand_AVC444(rdpGdi* gdi, RdpgfxClientContext* context,
668 const RDPGFX_SURFACE_COMMAND* cmd)
669{
670#ifdef WITH_GFX_H264
671 INT32 rc = 0;
672 UINT status = CHANNEL_RC_OK;
673 gdiGfxSurface* surface = nullptr;
674 RDPGFX_AVC444_BITMAP_STREAM* bs = nullptr;
675 RDPGFX_AVC420_BITMAP_STREAM* avc1 = nullptr;
676 RDPGFX_H264_METABLOCK* meta1 = nullptr;
677 RDPGFX_AVC420_BITMAP_STREAM* avc2 = nullptr;
678 RDPGFX_H264_METABLOCK* meta2 = nullptr;
679 WINPR_ASSERT(gdi);
680 WINPR_ASSERT(context);
681 WINPR_ASSERT(cmd);
682
683 WINPR_ASSERT(context->GetSurfaceData);
684 surface =
685 (gdiGfxSurface*)context->GetSurfaceData(context, (UINT16)MIN(UINT16_MAX, cmd->surfaceId));
686
687 if (!surface)
688 {
689 WLog_ERR(TAG, "unable to retrieve surfaceData for surfaceId=%" PRIu32 "", cmd->surfaceId);
690 return ERROR_NOT_FOUND;
691 }
692
693 if (!surface->h264)
694 {
695 surface->h264 = h264_context_new(FALSE);
696
697 if (!surface->h264)
698 {
699 WLog_ERR(TAG, "unable to create h264 context");
700 return ERROR_NOT_ENOUGH_MEMORY;
701 }
702
703 if (!h264_context_reset(surface->h264, surface->width, surface->height))
704 return ERROR_INTERNAL_ERROR;
705 }
706
707 if (!surface->h264)
708 return ERROR_NOT_SUPPORTED;
709
710 bs = (RDPGFX_AVC444_BITMAP_STREAM*)cmd->extra;
711
712 if (!bs)
713 return ERROR_INTERNAL_ERROR;
714
715 avc1 = &bs->bitstream[0];
716 avc2 = &bs->bitstream[1];
717 meta1 = &avc1->meta;
718 meta2 = &avc2->meta;
719 rc = avc444_decompress(surface->h264, bs->LC, meta1->regionRects, meta1->numRegionRects,
720 avc1->data, avc1->length, meta2->regionRects, meta2->numRegionRects,
721 avc2->data, avc2->length, surface->data, surface->format,
722 surface->scanline, surface->width, surface->height, cmd->codecId);
723
724 if (rc < 0)
725 {
726 WLog_WARN(TAG, "avc444_decompress failure: %" PRIu32 ", ignoring update.", status);
727 return CHANNEL_RC_OK;
728 }
729
730 for (UINT32 i = 0; i < meta1->numRegionRects; i++)
731 {
732 if (!region16_union_rect(&(surface->invalidRegion), &(surface->invalidRegion),
733 &(meta1->regionRects[i])))
734 goto fail;
735 }
736
737 status = IFCALLRESULT(CHANNEL_RC_OK, context->UpdateSurfaceArea, context, surface->surfaceId,
738 meta1->numRegionRects, meta1->regionRects);
739
740 if (status != CHANNEL_RC_OK)
741 goto fail;
742
743 for (UINT32 i = 0; i < meta2->numRegionRects; i++)
744 {
745 if (!region16_union_rect(&(surface->invalidRegion), &(surface->invalidRegion),
746 &(meta2->regionRects[i])))
747 goto fail;
748 }
749
750 status = IFCALLRESULT(CHANNEL_RC_OK, context->UpdateSurfaceArea, context, surface->surfaceId,
751 meta2->numRegionRects, meta2->regionRects);
752
753 if (status != CHANNEL_RC_OK)
754 goto fail;
755
756 status = gdi_interFrameUpdate(gdi, context);
757
758fail:
759 return status;
760#else
761 return ERROR_NOT_SUPPORTED;
762#endif
763}
764
765static BOOL gdi_apply_alpha(BYTE* data, UINT32 format, UINT32 stride, RECTANGLE_16* rect,
766 UINT32 startOffsetX, UINT32 count, BYTE a)
767{
768 UINT32 written = 0;
769 BOOL first = TRUE;
770 const UINT32 bpp = FreeRDPGetBytesPerPixel(format);
771 WINPR_ASSERT(rect);
772
773 for (size_t y = rect->top; y < rect->bottom; y++)
774 {
775 BYTE* line = &data[y * stride];
776
777 for (size_t x = first ? rect->left + startOffsetX : rect->left; x < rect->right; x++)
778 {
779 BYTE r = 0;
780 BYTE g = 0;
781 BYTE b = 0;
782
783 if (written == count)
784 return TRUE;
785
786 BYTE* src = &line[x * bpp];
787 UINT32 color = FreeRDPReadColor(src, format);
788 FreeRDPSplitColor(color, format, &r, &g, &b, nullptr, nullptr);
789 color = FreeRDPGetColor(format, r, g, b, a);
790 FreeRDPWriteColor(src, format, color);
791 written++;
792 }
793
794 first = FALSE;
795 }
796
797 return TRUE;
798}
804static UINT gdi_SurfaceCommand_Alpha(rdpGdi* gdi, RdpgfxClientContext* context,
805 const RDPGFX_SURFACE_COMMAND* cmd)
806{
807 UINT status = CHANNEL_RC_OK;
808 UINT16 alphaSig = 0;
809 UINT16 compressed = 0;
810 gdiGfxSurface* surface = nullptr;
811 RECTANGLE_16 invalidRect;
812 wStream buffer;
813 wStream* s = nullptr;
814 WINPR_ASSERT(gdi);
815 WINPR_ASSERT(context);
816 WINPR_ASSERT(cmd);
817
818 s = Stream_StaticConstInit(&buffer, cmd->data, cmd->length);
819
820 if (!Stream_CheckAndLogRequiredLength(TAG, s, 4))
821 return ERROR_INVALID_DATA;
822
823 WINPR_ASSERT(context->GetSurfaceData);
824 surface =
825 (gdiGfxSurface*)context->GetSurfaceData(context, (UINT16)MIN(UINT16_MAX, cmd->surfaceId));
826
827 if (!surface)
828 {
829 WLog_ERR(TAG, "unable to retrieve surfaceData for surfaceId=%" PRIu32 "", cmd->surfaceId);
830 return ERROR_NOT_FOUND;
831 }
832
833 if (!is_within_surface(surface, cmd))
834 return ERROR_INVALID_DATA;
835
836 Stream_Read_UINT16(s, alphaSig);
837 Stream_Read_UINT16(s, compressed);
838
839 if (alphaSig != 0x414C)
840 return ERROR_INVALID_DATA;
841
842 if (compressed == 0)
843 {
844 if (!Stream_CheckAndLogRequiredLengthOfSize(TAG, s, cmd->height, cmd->width))
845 return ERROR_INVALID_DATA;
846
847 for (size_t y = cmd->top; y < cmd->top + cmd->height; y++)
848 {
849 BYTE* line = &surface->data[y * surface->scanline];
850
851 for (size_t x = cmd->left; x < cmd->left + cmd->width; x++)
852 {
853 UINT32 color = 0;
854 BYTE r = 0;
855 BYTE g = 0;
856 BYTE b = 0;
857 BYTE a = 0;
858 BYTE* src = &line[x * FreeRDPGetBytesPerPixel(surface->format)];
859 Stream_Read_UINT8(s, a);
860 color = FreeRDPReadColor(src, surface->format);
861 FreeRDPSplitColor(color, surface->format, &r, &g, &b, nullptr, nullptr);
862 color = FreeRDPGetColor(surface->format, r, g, b, a);
863 FreeRDPWriteColor(src, surface->format, color);
864 }
865 }
866 }
867 else
868 {
869 UINT32 startOffsetX = 0;
870 RECTANGLE_16 rect = WINPR_C_ARRAY_INIT;
871 rect.left = (UINT16)MIN(UINT16_MAX, cmd->left);
872 rect.top = (UINT16)MIN(UINT16_MAX, cmd->top);
873 rect.right = (UINT16)MIN(UINT16_MAX, cmd->left + cmd->width);
874 rect.bottom = (UINT16)MIN(UINT16_MAX, cmd->top + cmd->height);
875
876 while (rect.top < rect.bottom)
877 {
878 UINT32 count = 0;
879 BYTE a = 0;
880
881 if (!Stream_CheckAndLogRequiredLength(TAG, s, 2))
882 return ERROR_INVALID_DATA;
883
884 Stream_Read_UINT8(s, a);
885 Stream_Read_UINT8(s, count);
886
887 if (count >= 0xFF)
888 {
889 if (!Stream_CheckAndLogRequiredLength(TAG, s, 2))
890 return ERROR_INVALID_DATA;
891
892 Stream_Read_UINT16(s, count);
893
894 if (count >= 0xFFFF)
895 {
896 if (!Stream_CheckAndLogRequiredLength(TAG, s, 4))
897 return ERROR_INVALID_DATA;
898
899 Stream_Read_UINT32(s, count);
900 }
901 }
902
903 if (!gdi_apply_alpha(surface->data, surface->format, surface->scanline, &rect,
904 startOffsetX, count, a))
905 return ERROR_INTERNAL_ERROR;
906
907 startOffsetX += count;
908
909 while (startOffsetX >= cmd->width)
910 {
911 startOffsetX -= cmd->width;
912 rect.top++;
913 }
914 }
915 }
916
917 invalidRect.left = (UINT16)MIN(UINT16_MAX, cmd->left);
918 invalidRect.top = (UINT16)MIN(UINT16_MAX, cmd->top);
919 invalidRect.right = (UINT16)MIN(UINT16_MAX, cmd->right);
920 invalidRect.bottom = (UINT16)MIN(UINT16_MAX, cmd->bottom);
921 if (!region16_union_rect(&(surface->invalidRegion), &(surface->invalidRegion), &invalidRect))
922 goto fail;
923 status = IFCALLRESULT(CHANNEL_RC_OK, context->UpdateSurfaceArea, context, surface->surfaceId, 1,
924 &invalidRect);
925
926 if (status != CHANNEL_RC_OK)
927 goto fail;
928
929 status = gdi_interFrameUpdate(gdi, context);
930
931fail:
932 return status;
933}
934
935#if defined(WITH_GFX_FRAME_DUMP)
936static void dump_cmd(const RDPGFX_SURFACE_COMMAND* cmd, UINT32 frameId)
937{
938 static UINT64 xxx = 0;
939 const char* path = "/tmp/dump/";
940 WINPR_ASSERT(cmd);
941 char fname[1024] = WINPR_C_ARRAY_INIT;
942
943 snprintf(fname, sizeof(fname), "%s/%08" PRIx64 ".raw", path, xxx++);
944 FILE* fp = fopen(fname, "w");
945 if (!fp)
946 return;
947 (void)fprintf(fp, "frameid: %" PRIu32 "\n", frameId);
948 (void)fprintf(fp, "surfaceId: %" PRIu32 "\n", cmd->surfaceId);
949 (void)fprintf(fp, "codecId: %" PRIu32 "\n", cmd->codecId);
950 (void)fprintf(fp, "contextId: %" PRIu32 "\n", cmd->contextId);
951 (void)fprintf(fp, "format: %" PRIu32 "\n", cmd->format);
952 (void)fprintf(fp, "left: %" PRIu32 "\n", cmd->left);
953 (void)fprintf(fp, "top: %" PRIu32 "\n", cmd->top);
954 (void)fprintf(fp, "right: %" PRIu32 "\n", cmd->right);
955 (void)fprintf(fp, "bottom: %" PRIu32 "\n", cmd->bottom);
956 (void)fprintf(fp, "width: %" PRIu32 "\n", cmd->width);
957 (void)fprintf(fp, "height: %" PRIu32 "\n", cmd->height);
958 (void)fprintf(fp, "length: %" PRIu32 "\n", cmd->length);
959
960 char* bdata = crypto_base64_encode_ex(cmd->data, cmd->length, FALSE);
961 (void)fprintf(fp, "data: %s\n", bdata);
962 free(bdata);
963 fclose(fp);
964}
965#endif
966
972static UINT gdi_SurfaceCommand_Progressive(rdpGdi* gdi, RdpgfxClientContext* context,
973 const RDPGFX_SURFACE_COMMAND* cmd)
974{
975 INT32 rc = 0;
976 UINT status = ERROR_INTERNAL_ERROR;
977 gdiGfxSurface* surface = nullptr;
978 REGION16 invalidRegion;
979 const RECTANGLE_16* rects = nullptr;
980 UINT32 nrRects = 0;
986 WINPR_ASSERT(gdi);
987 WINPR_ASSERT(context);
988 WINPR_ASSERT(cmd);
989 const UINT16 surfaceId = (UINT16)MIN(UINT16_MAX, cmd->surfaceId);
990
991 WINPR_ASSERT(context->GetSurfaceData);
992 surface = (gdiGfxSurface*)context->GetSurfaceData(context, surfaceId);
993
994 if (!surface)
995 {
996 WLog_ERR(TAG, "unable to retrieve surfaceData for surfaceId=%" PRIu32 "", cmd->surfaceId);
997 return ERROR_NOT_FOUND;
998 }
999
1000 if (!is_within_surface(surface, cmd))
1001 return ERROR_INVALID_DATA;
1002
1003 WINPR_ASSERT(surface->codecs);
1004 rc = progressive_create_surface_context(surface->codecs->progressive, surfaceId, surface->width,
1005 surface->height);
1006
1007 if (rc < 0)
1008 {
1009 WLog_ERR(TAG, "progressive_create_surface_context failure: %" PRId32 "", rc);
1010 return ERROR_INTERNAL_ERROR;
1011 }
1012
1013 region16_init(&invalidRegion);
1014
1015 rc = progressive_decompress(surface->codecs->progressive, cmd->data, cmd->length, surface->data,
1016 surface->format, surface->scanline, cmd->left, cmd->top,
1017 &invalidRegion, surfaceId, gdi->frameId);
1018
1019 if (rc < 0)
1020 {
1021 WLog_ERR(TAG, "progressive_decompress failure: %" PRId32 "", rc);
1022 goto fail;
1023 }
1024
1025 rects = region16_rects(&invalidRegion, &nrRects);
1026 status = IFCALLRESULT(CHANNEL_RC_OK, context->UpdateSurfaceArea, context, surface->surfaceId,
1027 nrRects, rects);
1028
1029 if (status != CHANNEL_RC_OK)
1030 goto fail;
1031
1032 status = ERROR_INTERNAL_ERROR;
1033 for (UINT32 x = 0; x < nrRects; x++)
1034 {
1035 if (!region16_union_rect(&surface->invalidRegion, &surface->invalidRegion, &rects[x]))
1036 goto fail;
1037 }
1038
1039 status = gdi_interFrameUpdate(gdi, context);
1040
1041fail:
1042
1043 region16_uninit(&invalidRegion);
1044 return status;
1045}
1046
1052static UINT gdi_SurfaceCommand(RdpgfxClientContext* context, const RDPGFX_SURFACE_COMMAND* cmd)
1053{
1054 UINT status = CHANNEL_RC_OK;
1055 rdpGdi* gdi = nullptr;
1056
1057 if (!context || !cmd)
1058 return ERROR_INVALID_PARAMETER;
1059
1060 gdi = (rdpGdi*)context->custom;
1061
1062 EnterCriticalSection(&context->mux);
1063 const UINT16 codecId = WINPR_ASSERTING_INT_CAST(UINT16, cmd->codecId);
1064 WLog_Print(gdi->log, WLOG_TRACE,
1065 "surfaceId=%" PRIu32 ", codec=%s [%" PRIu32 "], contextId=%" PRIu32 ", format=%s, "
1066 "left=%" PRIu32 ", top=%" PRIu32 ", right=%" PRIu32 ", bottom=%" PRIu32
1067 ", width=%" PRIu32 ", height=%" PRIu32 " "
1068 "length=%" PRIu32 ", data=%p, extra=%p",
1069 cmd->surfaceId, rdpgfx_get_codec_id_string(codecId), cmd->codecId, cmd->contextId,
1070 FreeRDPGetColorFormatName(cmd->format), cmd->left, cmd->top, cmd->right, cmd->bottom,
1071 cmd->width, cmd->height, cmd->length, (void*)cmd->data, (void*)cmd->extra);
1072#if defined(WITH_GFX_FRAME_DUMP)
1073 dump_cmd(cmd, gdi->frameId);
1074#endif
1075
1076 switch (codecId)
1077 {
1078 case RDPGFX_CODECID_UNCOMPRESSED:
1079 status = gdi_SurfaceCommand_Uncompressed(gdi, context, cmd);
1080 break;
1081
1082 case RDPGFX_CODECID_CAVIDEO:
1083 status = gdi_SurfaceCommand_RemoteFX(gdi, context, cmd);
1084 break;
1085
1086 case RDPGFX_CODECID_CLEARCODEC:
1087 status = gdi_SurfaceCommand_ClearCodec(gdi, context, cmd);
1088 break;
1089
1090 case RDPGFX_CODECID_PLANAR:
1091 status = gdi_SurfaceCommand_Planar(gdi, context, cmd);
1092 break;
1093
1094 case RDPGFX_CODECID_AVC420:
1095 status = gdi_SurfaceCommand_AVC420(gdi, context, cmd);
1096 break;
1097
1098 case RDPGFX_CODECID_AVC444v2:
1099 case RDPGFX_CODECID_AVC444:
1100 status = gdi_SurfaceCommand_AVC444(gdi, context, cmd);
1101 break;
1102
1103 case RDPGFX_CODECID_ALPHA:
1104 status = gdi_SurfaceCommand_Alpha(gdi, context, cmd);
1105 break;
1106
1107 case RDPGFX_CODECID_CAPROGRESSIVE:
1108 status = gdi_SurfaceCommand_Progressive(gdi, context, cmd);
1109 break;
1110
1111 case RDPGFX_CODECID_CAPROGRESSIVE_V2:
1112 WLog_WARN(TAG, "SurfaceCommand %s [0x%08" PRIX16 "] not implemented",
1113 rdpgfx_get_codec_id_string(codecId), codecId);
1114 break;
1115
1116 default:
1117 WLog_WARN(TAG, "Invalid SurfaceCommand %s [0x%08" PRIX16 "]",
1118 rdpgfx_get_codec_id_string(codecId), codecId);
1119 break;
1120 }
1121
1122 LeaveCriticalSection(&context->mux);
1123 return status;
1124}
1125
1131static UINT
1132gdi_DeleteEncodingContext(RdpgfxClientContext* context,
1133 const RDPGFX_DELETE_ENCODING_CONTEXT_PDU* deleteEncodingContext)
1134{
1135 WINPR_ASSERT(context);
1136 WINPR_ASSERT(deleteEncodingContext);
1137 WINPR_UNUSED(context);
1138 WINPR_UNUSED(deleteEncodingContext);
1139 return CHANNEL_RC_OK;
1140}
1141
1147static UINT gdi_CreateSurface(RdpgfxClientContext* context,
1148 const RDPGFX_CREATE_SURFACE_PDU* createSurface)
1149{
1150 UINT rc = ERROR_INTERNAL_ERROR;
1151 gdiGfxSurface* surface = nullptr;
1152 rdpGdi* gdi = nullptr;
1153 WINPR_ASSERT(context);
1154 WINPR_ASSERT(createSurface);
1155 gdi = (rdpGdi*)context->custom;
1156 WINPR_ASSERT(gdi);
1157 WINPR_ASSERT(gdi->context);
1158 EnterCriticalSection(&context->mux);
1159 surface = (gdiGfxSurface*)calloc(1, sizeof(gdiGfxSurface));
1160
1161 if (!surface)
1162 goto fail;
1163
1164 if (!freerdp_settings_get_bool(gdi->context->settings, FreeRDP_DeactivateClientDecoding))
1165 {
1166 WINPR_ASSERT(context->codecs);
1167 surface->codecs = context->codecs;
1168
1169 if (!surface->codecs)
1170 {
1171 free(surface);
1172 goto fail;
1173 }
1174 }
1175
1176 surface->surfaceId = createSurface->surfaceId;
1177 surface->width = gfx_align_scanline(createSurface->width, 16);
1178 surface->height = gfx_align_scanline(createSurface->height, 16);
1179 surface->mappedWidth = createSurface->width;
1180 surface->mappedHeight = createSurface->height;
1181 surface->outputTargetWidth = createSurface->width;
1182 surface->outputTargetHeight = createSurface->height;
1183
1184 switch (createSurface->pixelFormat)
1185 {
1186 case GFX_PIXEL_FORMAT_ARGB_8888:
1187 surface->format = PIXEL_FORMAT_BGRA32;
1188 break;
1189
1190 case GFX_PIXEL_FORMAT_XRGB_8888:
1191 surface->format = PIXEL_FORMAT_BGRX32;
1192 break;
1193
1194 default:
1195 free(surface);
1196 goto fail;
1197 }
1198
1199 surface->scanline = gfx_align_scanline(surface->width * 4UL, 16);
1200 surface->data = (BYTE*)winpr_aligned_malloc(1ull * surface->scanline * surface->height, 16);
1201
1202 if (!surface->data)
1203 {
1204 free(surface);
1205 goto fail;
1206 }
1207
1208 memset(surface->data, 0xFF, (size_t)surface->scanline * surface->height);
1209 region16_init(&surface->invalidRegion);
1210
1211 WINPR_ASSERT(context->SetSurfaceData);
1212 rc = context->SetSurfaceData(context, surface->surfaceId, (void*)surface);
1213fail:
1214 LeaveCriticalSection(&context->mux);
1215 return rc;
1216}
1217
1223static UINT gdi_DeleteSurface(RdpgfxClientContext* context,
1224 const RDPGFX_DELETE_SURFACE_PDU* deleteSurface)
1225{
1226 UINT rc = CHANNEL_RC_OK;
1227 UINT res = ERROR_INTERNAL_ERROR;
1228 rdpCodecs* codecs = nullptr;
1229 gdiGfxSurface* surface = nullptr;
1230 EnterCriticalSection(&context->mux);
1231
1232 WINPR_ASSERT(context->GetSurfaceData);
1233 surface = (gdiGfxSurface*)context->GetSurfaceData(context, deleteSurface->surfaceId);
1234
1235 if (surface)
1236 {
1237 if (surface->windowMapped)
1238 rc = IFCALLRESULT(CHANNEL_RC_OK, context->UnmapWindowForSurface, context,
1239 surface->windowId);
1240
1241#ifdef WITH_GFX_H264
1242 h264_context_free(surface->h264);
1243#endif
1244 region16_uninit(&surface->invalidRegion);
1245 codecs = surface->codecs;
1246 winpr_aligned_free(surface->data);
1247 free(surface);
1248 }
1249
1250 WINPR_ASSERT(context->SetSurfaceData);
1251 res = context->SetSurfaceData(context, deleteSurface->surfaceId, nullptr);
1252 if (res)
1253 rc = res;
1254
1255 if (codecs && codecs->progressive)
1256 progressive_delete_surface_context(codecs->progressive, deleteSurface->surfaceId);
1257
1258 LeaveCriticalSection(&context->mux);
1259 return rc;
1260}
1261
1262static BOOL intersect_rect(const RECTANGLE_16* rect, const gdiGfxSurface* surface,
1263 RECTANGLE_16* prect)
1264{
1265 WINPR_ASSERT(rect);
1266 WINPR_ASSERT(surface);
1267 WINPR_ASSERT(prect);
1268
1269 if (rect->left > rect->right)
1270 return FALSE;
1271 if (rect->left > surface->width)
1272 return FALSE;
1273 if (rect->top > rect->bottom)
1274 return FALSE;
1275 if (rect->top > surface->height)
1276 return FALSE;
1277 prect->left = rect->left;
1278 prect->top = rect->top;
1279
1280 prect->right = MIN(rect->right, WINPR_ASSERTING_INT_CAST(UINT16, surface->width));
1281 prect->bottom = MIN(rect->bottom, WINPR_ASSERTING_INT_CAST(UINT16, surface->height));
1282 return TRUE;
1283}
1284
1290static UINT gdi_SolidFill(RdpgfxClientContext* context, const RDPGFX_SOLID_FILL_PDU* solidFill)
1291{
1292 UINT status = ERROR_INTERNAL_ERROR;
1293 BYTE a = 0xff;
1294 RECTANGLE_16 invalidRect = WINPR_C_ARRAY_INIT;
1295 rdpGdi* gdi = (rdpGdi*)context->custom;
1296
1297 EnterCriticalSection(&context->mux);
1298
1299 WINPR_ASSERT(context->GetSurfaceData);
1300 gdiGfxSurface* surface = (gdiGfxSurface*)context->GetSurfaceData(context, solidFill->surfaceId);
1301
1302 if (!surface)
1303 goto fail;
1304
1305 {
1306 const BYTE b = solidFill->fillPixel.B;
1307 const BYTE g = solidFill->fillPixel.G;
1308 const BYTE r = solidFill->fillPixel.R;
1309
1310 /* [MS-RDPEGFX] 3.3.5.4 Processing an RDPGFX_SOLIDFILL_PDU message
1311 * https://learn.microsoft.com/en-us/windows/win32/gdi/binary-raster-operations
1312 *
1313 * this sounds like the alpha value is always ignored.
1314 */
1315 const UINT32 color = FreeRDPGetColor(surface->format, r, g, b, a);
1316 for (UINT16 index = 0; index < solidFill->fillRectCount; index++)
1317 {
1318 const RECTANGLE_16* rect = &(solidFill->fillRects[index]);
1319
1320 if (!intersect_rect(rect, surface, &invalidRect))
1321 goto fail;
1322
1323 const UINT32 nWidth = invalidRect.right - invalidRect.left;
1324 const UINT32 nHeight = invalidRect.bottom - invalidRect.top;
1325
1326 if (!freerdp_image_fill(surface->data, surface->format, surface->scanline,
1327 invalidRect.left, invalidRect.top, nWidth, nHeight, color))
1328 goto fail;
1329
1330 if (!region16_union_rect(&(surface->invalidRegion), &(surface->invalidRegion),
1331 &invalidRect))
1332 goto fail;
1333 }
1334 }
1335
1336 status = IFCALLRESULT(CHANNEL_RC_OK, context->UpdateSurfaceArea, context, surface->surfaceId,
1337 solidFill->fillRectCount, solidFill->fillRects);
1338
1339 if (status != CHANNEL_RC_OK)
1340 goto fail;
1341
1342 LeaveCriticalSection(&context->mux);
1343
1344 return gdi_interFrameUpdate(gdi, context);
1345fail:
1346 LeaveCriticalSection(&context->mux);
1347 return status;
1348}
1349
1355static UINT gdi_SurfaceToSurface(RdpgfxClientContext* context,
1356 const RDPGFX_SURFACE_TO_SURFACE_PDU* surfaceToSurface)
1357{
1358 UINT status = ERROR_INTERNAL_ERROR;
1359 BOOL sameSurface = 0;
1360 const RECTANGLE_16* rectSrc = nullptr;
1361 RECTANGLE_16 invalidRect;
1362 gdiGfxSurface* surfaceSrc = nullptr;
1363 gdiGfxSurface* surfaceDst = nullptr;
1364 rdpGdi* gdi = (rdpGdi*)context->custom;
1365 EnterCriticalSection(&context->mux);
1366 rectSrc = &(surfaceToSurface->rectSrc);
1367
1368 WINPR_ASSERT(context->GetSurfaceData);
1369 surfaceSrc = (gdiGfxSurface*)context->GetSurfaceData(context, surfaceToSurface->surfaceIdSrc);
1370 sameSurface = (surfaceToSurface->surfaceIdSrc == surfaceToSurface->surfaceIdDest);
1371
1372 if (!sameSurface)
1373 surfaceDst =
1374 (gdiGfxSurface*)context->GetSurfaceData(context, surfaceToSurface->surfaceIdDest);
1375 else
1376 surfaceDst = surfaceSrc;
1377
1378 if (!surfaceSrc || !surfaceDst)
1379 goto fail;
1380
1381 if (!is_rect_valid(rectSrc, surfaceSrc->width, surfaceSrc->height))
1382 goto fail;
1383
1384 {
1385 const UINT32 nWidth = rectSrc->right - rectSrc->left;
1386 const UINT32 nHeight = rectSrc->bottom - rectSrc->top;
1387
1388 for (UINT16 index = 0; index < surfaceToSurface->destPtsCount; index++)
1389 {
1390 const RDPGFX_POINT16* destPt = &surfaceToSurface->destPts[index];
1391 const RECTANGLE_16 rect = { destPt->x, destPt->y,
1392 (UINT16)MIN(UINT16_MAX, destPt->x + nWidth),
1393 (UINT16)MIN(UINT16_MAX, destPt->y + nHeight) };
1394 if (!is_rect_valid(&rect, surfaceDst->width, surfaceDst->height))
1395 goto fail;
1396
1397 const UINT32 rwidth = rect.right - rect.left;
1398 const UINT32 rheight = rect.bottom - rect.top;
1399 if (!freerdp_image_copy(surfaceDst->data, surfaceDst->format, surfaceDst->scanline,
1400 destPt->x, destPt->y, rwidth, rheight, surfaceSrc->data,
1401 surfaceSrc->format, surfaceSrc->scanline, rectSrc->left,
1402 rectSrc->top, nullptr, FREERDP_FLIP_NONE))
1403 goto fail;
1404
1405 invalidRect = rect;
1406 if (!region16_union_rect(&surfaceDst->invalidRegion, &surfaceDst->invalidRegion,
1407 &invalidRect))
1408 goto fail;
1409 status = IFCALLRESULT(CHANNEL_RC_OK, context->UpdateSurfaceArea, context,
1410 surfaceDst->surfaceId, 1, &invalidRect);
1411
1412 if (status != CHANNEL_RC_OK)
1413 goto fail;
1414 }
1415 }
1416
1417 LeaveCriticalSection(&context->mux);
1418
1419 return gdi_interFrameUpdate(gdi, context);
1420fail:
1421 LeaveCriticalSection(&context->mux);
1422 return status;
1423}
1424
1425static void gdi_GfxCacheEntryFree(gdiGfxCacheEntry* entry)
1426{
1427 if (!entry)
1428 return;
1429 free(entry->data);
1430 free(entry);
1431}
1432
1433static gdiGfxCacheEntry* gdi_GfxCacheEntryNew(UINT64 cacheKey, UINT32 width, UINT32 height,
1434 UINT32 format)
1435{
1436 gdiGfxCacheEntry* cacheEntry = (gdiGfxCacheEntry*)calloc(1, sizeof(gdiGfxCacheEntry));
1437 if (!cacheEntry)
1438 goto fail;
1439
1440 cacheEntry->cacheKey = cacheKey;
1441 cacheEntry->width = width;
1442 cacheEntry->height = height;
1443 cacheEntry->format = format;
1444 cacheEntry->scanline = gfx_align_scanline(cacheEntry->width * 4, 16);
1445
1446 if ((cacheEntry->width > 0) && (cacheEntry->height > 0))
1447 {
1448 cacheEntry->data = (BYTE*)calloc(cacheEntry->height, cacheEntry->scanline);
1449
1450 if (!cacheEntry->data)
1451 goto fail;
1452 }
1453 return cacheEntry;
1454fail:
1455 gdi_GfxCacheEntryFree(cacheEntry);
1456 return nullptr;
1457}
1458
1464static UINT gdi_SurfaceToCache(RdpgfxClientContext* context,
1465 const RDPGFX_SURFACE_TO_CACHE_PDU* surfaceToCache)
1466{
1467 gdiGfxCacheEntry* cacheEntry = nullptr;
1468 UINT rc = ERROR_INTERNAL_ERROR;
1469 EnterCriticalSection(&context->mux);
1470 const RECTANGLE_16* rect = &(surfaceToCache->rectSrc);
1471
1472 WINPR_ASSERT(context->GetSurfaceData);
1473 gdiGfxSurface* surface =
1474 (gdiGfxSurface*)context->GetSurfaceData(context, surfaceToCache->surfaceId);
1475
1476 if (!surface)
1477 goto fail;
1478
1479 if (!is_rect_valid(rect, surface->width, surface->height))
1480 goto fail;
1481
1482 cacheEntry = gdi_GfxCacheEntryNew(surfaceToCache->cacheKey, (UINT32)(rect->right - rect->left),
1483 (UINT32)(rect->bottom - rect->top), surface->format);
1484
1485 if (!cacheEntry)
1486 goto fail;
1487
1488 if (!cacheEntry->data)
1489 goto fail;
1490
1491 if (!freerdp_image_copy_no_overlap(cacheEntry->data, cacheEntry->format, cacheEntry->scanline,
1492 0, 0, cacheEntry->width, cacheEntry->height, surface->data,
1493 surface->format, surface->scanline, rect->left, rect->top,
1494 nullptr, FREERDP_FLIP_NONE))
1495 goto fail;
1496
1497 {
1498 RDPGFX_EVICT_CACHE_ENTRY_PDU evict = { surfaceToCache->cacheSlot };
1499 WINPR_ASSERT(context->EvictCacheEntry);
1500 rc = context->EvictCacheEntry(context, &evict);
1501 if (rc != CHANNEL_RC_OK)
1502 goto fail;
1503 }
1504
1505 WINPR_ASSERT(context->SetCacheSlotData);
1506 rc = context->SetCacheSlotData(context, surfaceToCache->cacheSlot, (void*)cacheEntry);
1507fail:
1508 if (rc != CHANNEL_RC_OK)
1509 gdi_GfxCacheEntryFree(cacheEntry);
1510 LeaveCriticalSection(&context->mux);
1511 return rc;
1512}
1513
1519static UINT gdi_CacheToSurface(RdpgfxClientContext* context,
1520 const RDPGFX_CACHE_TO_SURFACE_PDU* cacheToSurface)
1521{
1522 UINT status = ERROR_INTERNAL_ERROR;
1523 gdiGfxSurface* surface = nullptr;
1524 gdiGfxCacheEntry* cacheEntry = nullptr;
1525 RECTANGLE_16 invalidRect;
1526 rdpGdi* gdi = (rdpGdi*)context->custom;
1527
1528 EnterCriticalSection(&context->mux);
1529
1530 WINPR_ASSERT(context->GetSurfaceData);
1531 surface = (gdiGfxSurface*)context->GetSurfaceData(context, cacheToSurface->surfaceId);
1532
1533 WINPR_ASSERT(context->GetCacheSlotData);
1534 cacheEntry = (gdiGfxCacheEntry*)context->GetCacheSlotData(context, cacheToSurface->cacheSlot);
1535
1536 if (!surface || !cacheEntry)
1537 goto fail;
1538
1539 for (UINT16 index = 0; index < cacheToSurface->destPtsCount; index++)
1540 {
1541 const RDPGFX_POINT16* destPt = &cacheToSurface->destPts[index];
1542 const RECTANGLE_16 rect = { destPt->x, destPt->y,
1543 (UINT16)MIN(UINT16_MAX, destPt->x + cacheEntry->width),
1544 (UINT16)MIN(UINT16_MAX, destPt->y + cacheEntry->height) };
1545
1546 if (rectangle_is_empty(&rect))
1547 continue;
1548
1549 if (!is_rect_valid(&rect, surface->width, surface->height))
1550 goto fail;
1551
1552 if (!freerdp_image_copy_no_overlap(surface->data, surface->format, surface->scanline,
1553 destPt->x, destPt->y, cacheEntry->width,
1554 cacheEntry->height, cacheEntry->data, cacheEntry->format,
1555 cacheEntry->scanline, 0, 0, nullptr, FREERDP_FLIP_NONE))
1556 goto fail;
1557
1558 invalidRect = rect;
1559 if (!region16_union_rect(&surface->invalidRegion, &surface->invalidRegion, &invalidRect))
1560 goto fail;
1561 status = IFCALLRESULT(CHANNEL_RC_OK, context->UpdateSurfaceArea, context,
1562 surface->surfaceId, 1, &invalidRect);
1563
1564 if (status != CHANNEL_RC_OK)
1565 goto fail;
1566 }
1567
1568 LeaveCriticalSection(&context->mux);
1569
1570 return gdi_interFrameUpdate(gdi, context);
1571
1572fail:
1573 LeaveCriticalSection(&context->mux);
1574 return status;
1575}
1576
1582static UINT gdi_CacheImportReply(RdpgfxClientContext* context,
1583 const RDPGFX_CACHE_IMPORT_REPLY_PDU* cacheImportReply)
1584{
1585 UINT16 count = 0;
1586 const UINT16* slots = nullptr;
1587 UINT error = CHANNEL_RC_OK;
1588
1589 slots = cacheImportReply->cacheSlots;
1590 count = cacheImportReply->importedEntriesCount;
1591
1592 for (UINT16 index = 0; index < count; index++)
1593 {
1594 UINT16 cacheSlot = slots[index];
1595
1596 if (cacheSlot == 0)
1597 continue;
1598
1599 WINPR_ASSERT(context->GetCacheSlotData);
1600 gdiGfxCacheEntry* cacheEntry =
1601 (gdiGfxCacheEntry*)context->GetCacheSlotData(context, cacheSlot);
1602
1603 if (cacheEntry)
1604 continue;
1605
1606 cacheEntry = gdi_GfxCacheEntryNew(cacheSlot, 0, 0, PIXEL_FORMAT_BGRX32);
1607
1608 if (!cacheEntry)
1609 return ERROR_INTERNAL_ERROR;
1610
1611 WINPR_ASSERT(context->SetCacheSlotData);
1612 error = context->SetCacheSlotData(context, cacheSlot, (void*)cacheEntry);
1613
1614 if (error)
1615 {
1616 WLog_ERR(TAG, "CacheImportReply: SetCacheSlotData failed with error %" PRIu32 "",
1617 error);
1618 gdi_GfxCacheEntryFree(cacheEntry);
1619 break;
1620 }
1621 }
1622
1623 return error;
1624}
1625
1626static UINT gdi_ImportCacheEntry(RdpgfxClientContext* context, UINT16 cacheSlot,
1627 const PERSISTENT_CACHE_ENTRY* importCacheEntry)
1628{
1629 UINT error = ERROR_INTERNAL_ERROR;
1630 gdiGfxCacheEntry* cacheEntry = nullptr;
1631
1632 if (cacheSlot == 0)
1633 return CHANNEL_RC_OK;
1634
1635 cacheEntry = gdi_GfxCacheEntryNew(importCacheEntry->key64, importCacheEntry->width,
1636 importCacheEntry->height, PIXEL_FORMAT_BGRX32);
1637
1638 if (!cacheEntry)
1639 goto fail;
1640
1641 if (!freerdp_image_copy_no_overlap(cacheEntry->data, cacheEntry->format, cacheEntry->scanline,
1642 0, 0, cacheEntry->width, cacheEntry->height,
1643 importCacheEntry->data, PIXEL_FORMAT_BGRX32, 0, 0, 0,
1644 nullptr, FREERDP_FLIP_NONE))
1645 goto fail;
1646
1647 {
1648 RDPGFX_EVICT_CACHE_ENTRY_PDU evict = { cacheSlot };
1649 WINPR_ASSERT(context->EvictCacheEntry);
1650 error = context->EvictCacheEntry(context, &evict);
1651 }
1652 if (error != CHANNEL_RC_OK)
1653 goto fail;
1654
1655 WINPR_ASSERT(context->SetCacheSlotData);
1656 error = context->SetCacheSlotData(context, cacheSlot, (void*)cacheEntry);
1657
1658fail:
1659 if (error)
1660 {
1661 gdi_GfxCacheEntryFree(cacheEntry);
1662 WLog_ERR(TAG, "ImportCacheEntry: SetCacheSlotData failed with error %" PRIu32 "", error);
1663 }
1664
1665 return error;
1666}
1667
1668static UINT gdi_ExportCacheEntry(RdpgfxClientContext* context, UINT16 cacheSlot,
1669 PERSISTENT_CACHE_ENTRY* exportCacheEntry)
1670{
1671 gdiGfxCacheEntry* cacheEntry = nullptr;
1672
1673 WINPR_ASSERT(context->GetCacheSlotData);
1674 cacheEntry = (gdiGfxCacheEntry*)context->GetCacheSlotData(context, cacheSlot);
1675
1676 if (cacheEntry)
1677 {
1678 exportCacheEntry->key64 = cacheEntry->cacheKey;
1679 exportCacheEntry->width = (UINT16)MIN(UINT16_MAX, cacheEntry->width);
1680 exportCacheEntry->height = (UINT16)MIN(UINT16_MAX, cacheEntry->height);
1681 exportCacheEntry->size = cacheEntry->width * cacheEntry->height * 4;
1682 exportCacheEntry->flags = 0;
1683 exportCacheEntry->data = cacheEntry->data;
1684 return CHANNEL_RC_OK;
1685 }
1686
1687 return ERROR_NOT_FOUND;
1688}
1689
1695static UINT gdi_EvictCacheEntry(RdpgfxClientContext* context,
1696 const RDPGFX_EVICT_CACHE_ENTRY_PDU* evictCacheEntry)
1697{
1698 gdiGfxCacheEntry* cacheEntry = nullptr;
1699 UINT rc = ERROR_NOT_FOUND;
1700
1701 WINPR_ASSERT(context);
1702 WINPR_ASSERT(evictCacheEntry);
1703
1704 EnterCriticalSection(&context->mux);
1705
1706 WINPR_ASSERT(context->GetCacheSlotData);
1707 cacheEntry = (gdiGfxCacheEntry*)context->GetCacheSlotData(context, evictCacheEntry->cacheSlot);
1708
1709 gdi_GfxCacheEntryFree(cacheEntry);
1710
1711 WINPR_ASSERT(context->SetCacheSlotData);
1712 rc = context->SetCacheSlotData(context, evictCacheEntry->cacheSlot, nullptr);
1713 LeaveCriticalSection(&context->mux);
1714 return rc;
1715}
1716
1722static UINT gdi_MapSurfaceToOutput(RdpgfxClientContext* context,
1723 const RDPGFX_MAP_SURFACE_TO_OUTPUT_PDU* surfaceToOutput)
1724{
1725 UINT rc = ERROR_INTERNAL_ERROR;
1726 gdiGfxSurface* surface = nullptr;
1727 EnterCriticalSection(&context->mux);
1728
1729 WINPR_ASSERT(context->GetSurfaceData);
1730 surface = (gdiGfxSurface*)context->GetSurfaceData(context, surfaceToOutput->surfaceId);
1731
1732 if (!surface)
1733 goto fail;
1734
1735 if (surface->windowMapped)
1736 {
1737 WLog_WARN(TAG, "surface already windowMapped when trying to set outputMapped");
1738 goto fail;
1739 }
1740
1741 surface->outputMapped = TRUE;
1742 surface->outputOriginX = surfaceToOutput->outputOriginX;
1743 surface->outputOriginY = surfaceToOutput->outputOriginY;
1744 surface->outputTargetWidth = surface->mappedWidth;
1745 surface->outputTargetHeight = surface->mappedHeight;
1746 region16_clear(&surface->invalidRegion);
1747 rc = CHANNEL_RC_OK;
1748fail:
1749 LeaveCriticalSection(&context->mux);
1750 return rc;
1751}
1752
1753static UINT
1754gdi_MapSurfaceToScaledOutput(RdpgfxClientContext* context,
1755 const RDPGFX_MAP_SURFACE_TO_SCALED_OUTPUT_PDU* surfaceToOutput)
1756{
1757 UINT rc = ERROR_INTERNAL_ERROR;
1758 gdiGfxSurface* surface = nullptr;
1759 EnterCriticalSection(&context->mux);
1760
1761 WINPR_ASSERT(context->GetSurfaceData);
1762 surface = (gdiGfxSurface*)context->GetSurfaceData(context, surfaceToOutput->surfaceId);
1763
1764 if (!surface)
1765 goto fail;
1766
1767 if (surface->windowMapped)
1768 {
1769 WLog_WARN(TAG, "surface already windowMapped when trying to set outputMapped");
1770 goto fail;
1771 }
1772
1773 surface->outputMapped = TRUE;
1774 surface->outputOriginX = surfaceToOutput->outputOriginX;
1775 surface->outputOriginY = surfaceToOutput->outputOriginY;
1776 surface->outputTargetWidth = surfaceToOutput->targetWidth;
1777 surface->outputTargetHeight = surfaceToOutput->targetHeight;
1778 region16_clear(&surface->invalidRegion);
1779 rc = CHANNEL_RC_OK;
1780fail:
1781 LeaveCriticalSection(&context->mux);
1782 return rc;
1783}
1784
1790static UINT gdi_MapSurfaceToWindow(RdpgfxClientContext* context,
1791 const RDPGFX_MAP_SURFACE_TO_WINDOW_PDU* surfaceToWindow)
1792{
1793 UINT rc = ERROR_INTERNAL_ERROR;
1794 gdiGfxSurface* surface = nullptr;
1795 EnterCriticalSection(&context->mux);
1796
1797 WINPR_ASSERT(context->GetSurfaceData);
1798 surface = (gdiGfxSurface*)context->GetSurfaceData(context, surfaceToWindow->surfaceId);
1799
1800 if (!surface)
1801 goto fail;
1802
1803 if (surface->outputMapped)
1804 {
1805 WLog_WARN(TAG, "surface already outputMapped when trying to set windowMapped");
1806 goto fail;
1807 }
1808
1809 if (surface->windowMapped)
1810 {
1811 if (surface->windowId != surfaceToWindow->windowId)
1812 {
1813 WLog_WARN(TAG, "surface windowId mismatch, has %" PRIu64 ", expected %" PRIu64,
1814 surface->windowId, surfaceToWindow->windowId);
1815 goto fail;
1816 }
1817 }
1818 surface->windowMapped = TRUE;
1819
1820 surface->windowId = surfaceToWindow->windowId;
1821 surface->mappedWidth = surfaceToWindow->mappedWidth;
1822 surface->mappedHeight = surfaceToWindow->mappedHeight;
1823 surface->outputTargetWidth = surfaceToWindow->mappedWidth;
1824 surface->outputTargetHeight = surfaceToWindow->mappedHeight;
1825 rc = IFCALLRESULT(CHANNEL_RC_OK, context->MapWindowForSurface, context,
1826 surfaceToWindow->surfaceId, surfaceToWindow->windowId);
1827fail:
1828 LeaveCriticalSection(&context->mux);
1829 return rc;
1830}
1831
1832static UINT
1833gdi_MapSurfaceToScaledWindow(RdpgfxClientContext* context,
1834 const RDPGFX_MAP_SURFACE_TO_SCALED_WINDOW_PDU* surfaceToWindow)
1835{
1836 UINT rc = ERROR_INTERNAL_ERROR;
1837 gdiGfxSurface* surface = nullptr;
1838 EnterCriticalSection(&context->mux);
1839
1840 WINPR_ASSERT(context->GetSurfaceData);
1841 surface = (gdiGfxSurface*)context->GetSurfaceData(context, surfaceToWindow->surfaceId);
1842
1843 if (!surface)
1844 goto fail;
1845
1846 if (surface->outputMapped)
1847 {
1848 WLog_WARN(TAG, "surface already outputMapped when trying to set windowMapped");
1849 goto fail;
1850 }
1851
1852 if (surface->windowMapped)
1853 {
1854 if (surface->windowId != surfaceToWindow->windowId)
1855 {
1856 WLog_WARN(TAG, "surface windowId mismatch, has %" PRIu64 ", expected %" PRIu64,
1857 surface->windowId, surfaceToWindow->windowId);
1858 goto fail;
1859 }
1860 }
1861 surface->windowMapped = TRUE;
1862
1863 surface->windowId = surfaceToWindow->windowId;
1864 surface->mappedWidth = surfaceToWindow->mappedWidth;
1865 surface->mappedHeight = surfaceToWindow->mappedHeight;
1866 surface->outputTargetWidth = surfaceToWindow->targetWidth;
1867 surface->outputTargetHeight = surfaceToWindow->targetHeight;
1868 rc = IFCALLRESULT(CHANNEL_RC_OK, context->MapWindowForSurface, context,
1869 surfaceToWindow->surfaceId, surfaceToWindow->windowId);
1870fail:
1871 LeaveCriticalSection(&context->mux);
1872 return rc;
1873}
1874
1875BOOL gdi_graphics_pipeline_init(rdpGdi* gdi, RdpgfxClientContext* gfx)
1876{
1877 return gdi_graphics_pipeline_init_ex(gdi, gfx, nullptr, nullptr, nullptr);
1878}
1879
1880BOOL gdi_graphics_pipeline_init_ex(rdpGdi* gdi, RdpgfxClientContext* gfx,
1881 pcRdpgfxMapWindowForSurface map,
1882 pcRdpgfxUnmapWindowForSurface unmap,
1883 pcRdpgfxUpdateSurfaceArea update)
1884{
1885 if (!gdi || !gfx || !gdi->context || !gdi->context->settings)
1886 return FALSE;
1887
1888 rdpContext* context = gdi->context;
1889 rdpSettings* settings = context->settings;
1890
1891 gdi->gfx = gfx;
1892 gfx->custom = (void*)gdi;
1893 gfx->ResetGraphics = gdi_ResetGraphics;
1894 gfx->StartFrame = gdi_StartFrame;
1895 gfx->EndFrame = gdi_EndFrame;
1896 gfx->SurfaceCommand = gdi_SurfaceCommand;
1897 gfx->DeleteEncodingContext = gdi_DeleteEncodingContext;
1898 gfx->CreateSurface = gdi_CreateSurface;
1899 gfx->DeleteSurface = gdi_DeleteSurface;
1900 gfx->SolidFill = gdi_SolidFill;
1901 gfx->SurfaceToSurface = gdi_SurfaceToSurface;
1902 gfx->SurfaceToCache = gdi_SurfaceToCache;
1903 gfx->CacheToSurface = gdi_CacheToSurface;
1904 gfx->CacheImportReply = gdi_CacheImportReply;
1905 gfx->ImportCacheEntry = gdi_ImportCacheEntry;
1906 gfx->ExportCacheEntry = gdi_ExportCacheEntry;
1907 gfx->EvictCacheEntry = gdi_EvictCacheEntry;
1908 gfx->MapSurfaceToOutput = gdi_MapSurfaceToOutput;
1909 gfx->MapSurfaceToWindow = gdi_MapSurfaceToWindow;
1910 gfx->MapSurfaceToScaledOutput = gdi_MapSurfaceToScaledOutput;
1911 gfx->MapSurfaceToScaledWindow = gdi_MapSurfaceToScaledWindow;
1912 gfx->UpdateSurfaces = gdi_UpdateSurfaces;
1913 gfx->MapWindowForSurface = map;
1914 gfx->UnmapWindowForSurface = unmap;
1915 gfx->UpdateSurfaceArea = update;
1916
1917 if (!freerdp_settings_get_bool(settings, FreeRDP_DeactivateClientDecoding))
1918 {
1919 const UINT32 w = freerdp_settings_get_uint32(settings, FreeRDP_DesktopWidth);
1920 const UINT32 h = freerdp_settings_get_uint32(settings, FreeRDP_DesktopHeight);
1921 const UINT32 flags = freerdp_settings_get_uint32(settings, FreeRDP_ThreadingFlags);
1922
1923 gfx->codecs = freerdp_client_codecs_new(flags);
1924 if (!gfx->codecs)
1925 return FALSE;
1926 if (!freerdp_client_codecs_prepare(gfx->codecs, FREERDP_CODEC_ALL, w, h))
1927 return FALSE;
1928 }
1929 InitializeCriticalSection(&gfx->mux);
1930 PROFILER_CREATE(gfx->SurfaceProfiler, "GFX-PROFILER")
1931
1932
1938 gdi->graphicsReset = TRUE;
1939 if (freerdp_settings_get_bool(settings, FreeRDP_DeactivateClientDecoding))
1940 {
1941 gfx->UpdateSurfaceArea = nullptr;
1942 gfx->UpdateSurfaces = nullptr;
1943 gfx->SurfaceCommand = nullptr;
1944 }
1945
1946 return TRUE;
1947}
1948
1949void gdi_graphics_pipeline_uninit(rdpGdi* gdi, RdpgfxClientContext* gfx)
1950{
1951 if (gdi)
1952 gdi->gfx = nullptr;
1953
1954 if (!gfx)
1955 return;
1956
1957 gfx->custom = nullptr;
1958 freerdp_client_codecs_free(gfx->codecs);
1959 gfx->codecs = nullptr;
1960 DeleteCriticalSection(&gfx->mux);
1961 PROFILER_PRINT_HEADER
1962 PROFILER_PRINT(gfx->SurfaceProfiler)
1963 PROFILER_PRINT_FOOTER
1964 PROFILER_FREE(gfx->SurfaceProfiler)
1965}
1966
1967const char* rdpgfx_caps_version_str(UINT32 capsVersion)
1968{
1969 switch (capsVersion)
1970 {
1971 case RDPGFX_CAPVERSION_8:
1972 return "RDPGFX_CAPVERSION_8";
1973 case RDPGFX_CAPVERSION_81:
1974 return "RDPGFX_CAPVERSION_81";
1975 case RDPGFX_CAPVERSION_10:
1976 return "RDPGFX_CAPVERSION_10";
1977 case RDPGFX_CAPVERSION_101:
1978 return "RDPGFX_CAPVERSION_101";
1979 case RDPGFX_CAPVERSION_102:
1980 return "RDPGFX_CAPVERSION_102";
1981 case RDPGFX_CAPVERSION_103:
1982 return "RDPGFX_CAPVERSION_103";
1983 case RDPGFX_CAPVERSION_104:
1984 return "RDPGFX_CAPVERSION_104";
1985 case RDPGFX_CAPVERSION_105:
1986 return "RDPGFX_CAPVERSION_105";
1987 case RDPGFX_CAPVERSION_106:
1988 return "RDPGFX_CAPVERSION_106";
1989 case RDPGFX_CAPVERSION_106_ERR:
1990 return "RDPGFX_CAPVERSION_106_ERR";
1991 case RDPGFX_CAPVERSION_107:
1992 return "RDPGFX_CAPVERSION_107";
1993 default:
1994 return "RDPGFX_CAPVERSION_UNKNOWN";
1995 }
1996}
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_codecs_flags(const rdpSettings *settings)
helper function to get a mask of supported codec flags.
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.
Definition persistent.h:70