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