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