FreeRDP
Loading...
Searching...
No Matches
shadow_client.c
1
21#include <freerdp/config.h>
22
23#include <winpr/crt.h>
24#include <winpr/assert.h>
25#include <winpr/cast.h>
26#include <winpr/file.h>
27#include <winpr/path.h>
28#include <winpr/synch.h>
29#include <winpr/thread.h>
30#include <winpr/sysinfo.h>
31#include <winpr/interlocked.h>
32
33#include <freerdp/log.h>
34#include <freerdp/utils/gfx.h>
35#include <freerdp/channels/drdynvc.h>
36
37#include "shadow.h"
38#include "shadow_rfx_dirty.h"
39
40#define TAG CLIENT_TAG("shadow")
41
42typedef struct
43{
44 BOOL gfxOpened;
45 BOOL gfxSurfaceCreated;
46} SHADOW_GFX_STATUS;
47
48WINPR_ATTR_NODISCARD
49static BOOL shadow_avc420_enabled(const rdpShadowClient* client);
50WINPR_ATTR_NODISCARD
51static BOOL shadow_avc444_enabled(const rdpShadowClient* client);
52
53/* See https://github.com/FreeRDP/FreeRDP/issues/10413
54 *
55 * Microsoft ditched support for RFX and multiple rectangles in BitmapUpdate for
56 * windows 11 24H2.
57 *
58 * So send all updates only with a single rectangle.
59 */
60#define BitmapUpdateProxy(client, bitmap) \
61 BitmapUpdateProxyEx((client), (bitmap), __FILE__, __LINE__, __func__)
62WINPR_ATTR_NODISCARD
63static BOOL BitmapUpdateProxyEx(rdpShadowClient* client, const BITMAP_UPDATE* bitmap,
64 const char* file, size_t line, const char* fkt)
65{
66 WINPR_ASSERT(client);
67 WINPR_ASSERT(bitmap);
68
69 rdpShadowServer* server = client->server;
70 WINPR_ASSERT(server);
71
72 rdpContext* context = (rdpContext*)client;
73
74 rdpUpdate* update = context->update;
75 WINPR_ASSERT(update);
76
77 if (server->SupportMultiRectBitmapUpdates)
78 {
79 const BOOL rc = IFCALLRESULT(FALSE, update->BitmapUpdate, context, bitmap);
80 if (!rc)
81 {
82 const DWORD log_level = WLOG_ERROR;
83 wLog* log = WLog_Get(TAG);
84 if (WLog_IsLevelActive(log, log_level))
85 {
86 WLog_PrintTextMessage(log, log_level, line, file, fkt,
87 "BitmapUpdate[count %" PRIu32 "] failed", bitmap->number);
88 }
89 return FALSE;
90 }
91 }
92 else
93 {
94 for (UINT32 x = 0; x < bitmap->number; x++)
95 {
96 BITMAP_UPDATE cur = WINPR_C_ARRAY_INIT;
97 BITMAP_DATA* bmp = &bitmap->rectangles[x];
98 cur.rectangles = bmp;
99 cur.number = 1;
100 cur.skipCompression = bitmap->skipCompression;
101 const BOOL rc = IFCALLRESULT(FALSE, update->BitmapUpdate, context, &cur);
102 if (!rc)
103 {
104 const DWORD log_level = WLOG_ERROR;
105 wLog* log = WLog_Get(TAG);
106 if (WLog_IsLevelActive(log, log_level))
107 {
108 WLog_PrintTextMessage(log, log_level, line, file, fkt,
109 "BitmapUpdate[count 1, at %" PRIu32 "] failed", x);
110 }
111 return FALSE;
112 }
113 }
114 }
115
116 return TRUE;
117}
118
119WINPR_ATTR_NODISCARD
120static inline BOOL shadow_client_rdpgfx_new_surface(rdpShadowClient* client)
121{
122 UINT error = CHANNEL_RC_OK;
123 RDPGFX_CREATE_SURFACE_PDU createSurface;
124 RDPGFX_MAP_SURFACE_TO_OUTPUT_PDU surfaceToOutput;
125 RdpgfxServerContext* context = nullptr;
126 rdpSettings* settings = nullptr;
127
128 WINPR_ASSERT(client);
129 context = client->rdpgfx;
130 WINPR_ASSERT(context);
131 settings = ((rdpContext*)client)->settings;
132 WINPR_ASSERT(settings);
133
134 WINPR_ASSERT(freerdp_settings_get_uint32(settings, FreeRDP_DesktopWidth) <= UINT16_MAX);
135 WINPR_ASSERT(freerdp_settings_get_uint32(settings, FreeRDP_DesktopHeight) <= UINT16_MAX);
136 createSurface.width = (UINT16)freerdp_settings_get_uint32(settings, FreeRDP_DesktopWidth);
137 createSurface.height = (UINT16)freerdp_settings_get_uint32(settings, FreeRDP_DesktopHeight);
138 createSurface.pixelFormat = GFX_PIXEL_FORMAT_XRGB_8888;
139 createSurface.surfaceId = client->surfaceId;
140 surfaceToOutput.outputOriginX = 0;
141 surfaceToOutput.outputOriginY = 0;
142 surfaceToOutput.surfaceId = client->surfaceId;
143 surfaceToOutput.reserved = 0;
144 IFCALLRET(context->CreateSurface, error, context, &createSurface);
145
146 if (error)
147 {
148 WLog_ERR(TAG, "CreateSurface failed with error %" PRIu32 "", error);
149 return FALSE;
150 }
151
152 IFCALLRET(context->MapSurfaceToOutput, error, context, &surfaceToOutput);
153
154 if (error)
155 {
156 WLog_ERR(TAG, "MapSurfaceToOutput failed with error %" PRIu32 "", error);
157 return FALSE;
158 }
159
160 return TRUE;
161}
162
163WINPR_ATTR_NODISCARD
164static inline BOOL shadow_client_rdpgfx_release_surface(rdpShadowClient* client)
165{
166 UINT error = CHANNEL_RC_OK;
168 RdpgfxServerContext* context = nullptr;
169
170 WINPR_ASSERT(client);
171
172 context = client->rdpgfx;
173 WINPR_ASSERT(context);
174
175 pdu.surfaceId = client->surfaceId++;
176 IFCALLRET(context->DeleteSurface, error, context, &pdu);
177
178 if (error)
179 {
180 WLog_ERR(TAG, "DeleteSurface failed with error %" PRIu32 "", error);
181 return FALSE;
182 }
183
184 return TRUE;
185}
186
187WINPR_ATTR_NODISCARD
188static inline BOOL shadow_client_rdpgfx_reset_graphic(rdpShadowClient* client)
189{
190 UINT error = CHANNEL_RC_OK;
191 RDPGFX_RESET_GRAPHICS_PDU pdu = WINPR_C_ARRAY_INIT;
192 RdpgfxServerContext* context = nullptr;
193 rdpSettings* settings = nullptr;
194
195 WINPR_ASSERT(client);
196 WINPR_ASSERT(client->rdpgfx);
197
198 context = client->rdpgfx;
199 WINPR_ASSERT(context);
200
201 settings = client->context.settings;
202 WINPR_ASSERT(settings);
203
204 pdu.width = freerdp_settings_get_uint32(settings, FreeRDP_DesktopWidth);
205 pdu.height = freerdp_settings_get_uint32(settings, FreeRDP_DesktopHeight);
206 pdu.monitorCount = client->subsystem->numMonitors;
207 pdu.monitorDefArray = client->subsystem->monitors;
208 IFCALLRET(context->ResetGraphics, error, context, &pdu);
209
210 if (error)
211 {
212 WLog_ERR(TAG, "ResetGraphics failed with error %" PRIu32 "", error);
213 return FALSE;
214 }
215
216 client->first_frame = TRUE;
217 return TRUE;
218}
219
220static inline void shadow_client_free_queued_message(void* obj)
221{
222 wMessage* message = (wMessage*)obj;
223
224 WINPR_ASSERT(message);
225 if (message->Free)
226 {
227 message->Free(message);
228 message->Free = nullptr;
229 }
230}
231
232static void shadow_client_context_free(freerdp_peer* peer, rdpContext* context)
233{
234 rdpShadowClient* client = (rdpShadowClient*)context;
235 rdpShadowServer* server = nullptr;
236
237 WINPR_UNUSED(peer);
238 if (!client)
239 return;
240
241 server = client->server;
242 if (server && server->clients)
243 ArrayList_Remove(server->clients, (void*)client);
244
245 shadow_encoder_free(client->encoder);
246
247 /* Clear queued messages and free resource */
248 MessageQueue_Free(client->MsgQueue);
249 WTSCloseServer(client->vcm);
250 region16_uninit(&(client->invalidRegion));
251 DeleteCriticalSection(&(client->lock));
252
253 client->MsgQueue = nullptr;
254 client->encoder = nullptr;
255 client->vcm = nullptr;
256}
257
258WINPR_ATTR_NODISCARD
259static BOOL shadow_client_context_new(freerdp_peer* peer, rdpContext* context)
260{
261 BOOL NSCodec = 0;
262 const char bind_address[] = "bind-address,";
263 rdpShadowClient* client = (rdpShadowClient*)context;
264 rdpSettings* settings = nullptr;
265 const rdpSettings* srvSettings = nullptr;
266 rdpShadowServer* server = nullptr;
267 const wObject cb = { nullptr, nullptr, nullptr, shadow_client_free_queued_message, nullptr };
268
269 WINPR_ASSERT(client);
270 WINPR_ASSERT(peer);
271 WINPR_ASSERT(peer->context);
272
273 server = (rdpShadowServer*)peer->ContextExtra;
274 WINPR_ASSERT(server);
275
276 srvSettings = server->settings;
277 WINPR_ASSERT(srvSettings);
278
279 client->surfaceId = 1;
280 client->server = server;
281 client->subsystem = server->subsystem;
282 WINPR_ASSERT(client->subsystem);
283
284 settings = peer->context->settings;
285 WINPR_ASSERT(settings);
286
287 if (!freerdp_settings_set_uint32(settings, FreeRDP_ColorDepth,
288 freerdp_settings_get_uint32(srvSettings, FreeRDP_ColorDepth)))
289 return FALSE;
290 NSCodec = freerdp_settings_get_bool(srvSettings, FreeRDP_NSCodec);
291 if (!freerdp_settings_set_bool(settings, FreeRDP_NSCodec, NSCodec))
292 return FALSE;
293 if (!freerdp_settings_set_bool(settings, FreeRDP_RemoteFxCodec,
294 freerdp_settings_get_bool(srvSettings, FreeRDP_RemoteFxCodec)))
295 return FALSE;
297 settings, FreeRDP_RemoteFxRlgrMode,
298 freerdp_settings_get_uint32(srvSettings, FreeRDP_RemoteFxRlgrMode)))
299 return FALSE;
300 if (!freerdp_settings_set_bool(settings, FreeRDP_BitmapCacheV3Enabled, TRUE))
301 return FALSE;
302 if (!freerdp_settings_set_bool(settings, FreeRDP_FrameMarkerCommandEnabled, TRUE))
303 return FALSE;
304 if (!freerdp_settings_set_bool(settings, FreeRDP_SurfaceFrameMarkerEnabled, TRUE))
305 return FALSE;
307 settings, FreeRDP_SupportGraphicsPipeline,
308 freerdp_settings_get_bool(srvSettings, FreeRDP_SupportGraphicsPipeline)))
309 return FALSE;
310 if (!freerdp_settings_set_bool(settings, FreeRDP_GfxH264,
311 freerdp_settings_get_bool(srvSettings, FreeRDP_GfxH264)))
312 return FALSE;
313 if (!freerdp_settings_set_bool(settings, FreeRDP_DrawAllowSkipAlpha, TRUE))
314 return FALSE;
315 if (!freerdp_settings_set_bool(settings, FreeRDP_DrawAllowColorSubsampling, TRUE))
316 return FALSE;
317 if (!freerdp_settings_set_bool(settings, FreeRDP_DrawAllowDynamicColorFidelity, TRUE))
318 return FALSE;
319 if (!freerdp_settings_set_uint32(settings, FreeRDP_CompressionLevel, PACKET_COMPR_TYPE_RDP8))
320 return FALSE;
321
322 if (server->ipcSocket && (strncmp(bind_address, server->ipcSocket,
323 strnlen(bind_address, sizeof(bind_address))) != 0))
324 {
325 if (!freerdp_settings_set_bool(settings, FreeRDP_LyncRdpMode, TRUE))
326 return FALSE;
327 if (!freerdp_settings_set_bool(settings, FreeRDP_CompressionEnabled, FALSE))
328 return FALSE;
329 }
330
331 client->inLobby = TRUE;
332 client->mayView = server->mayView;
333 client->mayInteract = server->mayInteract;
334
335 if (!InitializeCriticalSectionAndSpinCount(&(client->lock), 4000))
336 goto fail;
337
338 region16_init(&(client->invalidRegion));
339 client->vcm = WTSOpenServerA((LPSTR)peer->context);
340
341 if (!client->vcm || client->vcm == INVALID_HANDLE_VALUE)
342 goto fail;
343
344 if (!(client->MsgQueue = MessageQueue_New(&cb)))
345 goto fail;
346
347 if (!(client->encoder = shadow_encoder_new(client)))
348 goto fail;
349
350 if (!ArrayList_Append(server->clients, (void*)client))
351 goto fail;
352
353 return TRUE;
354
355fail:
356 shadow_client_context_free(peer, context);
357 return FALSE;
358}
359
360static inline void shadow_client_mark_invalid(rdpShadowClient* client, UINT32 numRects,
361 const RECTANGLE_16* rects)
362{
363 WINPR_ASSERT(client);
364 WINPR_ASSERT(rects || (numRects == 0));
365
366 rdpSettings* settings = client->context.settings;
367 WINPR_ASSERT(settings);
368
369 EnterCriticalSection(&(client->lock));
370
371 /* Mark client invalid region. No rectangle means full screen */
372 if (numRects > 0)
373 {
374 for (UINT32 index = 0; index < numRects; index++)
375 {
376 if (!region16_union_rect(&(client->invalidRegion), &(client->invalidRegion),
377 &rects[index]))
378 goto fail;
379 }
380 }
381 else
382 {
383 RECTANGLE_16 screenRegion = WINPR_C_ARRAY_INIT;
384 WINPR_ASSERT(freerdp_settings_get_uint32(settings, FreeRDP_DesktopWidth) <= UINT16_MAX);
385 WINPR_ASSERT(freerdp_settings_get_uint32(settings, FreeRDP_DesktopHeight) <= UINT16_MAX);
386 screenRegion.right = (UINT16)freerdp_settings_get_uint32(settings, FreeRDP_DesktopWidth);
387 screenRegion.bottom = (UINT16)freerdp_settings_get_uint32(settings, FreeRDP_DesktopHeight);
388 if (!region16_union_rect(&(client->invalidRegion), &(client->invalidRegion), &screenRegion))
389 goto fail;
390 }
391fail:
392 LeaveCriticalSection(&(client->lock));
393}
394
401WINPR_ATTR_NODISCARD
402static inline BOOL shadow_client_recalc_desktop_size(rdpShadowClient* client)
403{
404 INT32 width = 0;
405 INT32 height = 0;
406 rdpShadowServer* server = nullptr;
407 rdpSettings* settings = nullptr;
408 RECTANGLE_16 viewport = WINPR_C_ARRAY_INIT;
409
410 WINPR_ASSERT(client);
411 server = client->server;
412 settings = client->context.settings;
413
414 WINPR_ASSERT(server);
415 WINPR_ASSERT(server->surface);
416 WINPR_ASSERT(settings);
417
418 WINPR_ASSERT(server->surface->width <= UINT16_MAX);
419 WINPR_ASSERT(server->surface->height <= UINT16_MAX);
420 viewport.right = (UINT16)server->surface->width;
421 viewport.bottom = (UINT16)server->surface->height;
422
423 if (server->shareSubRect)
424 {
425 if (!rectangles_intersection(&viewport, &(server->subRect), &viewport))
426 return FALSE;
427 }
428
429 width = viewport.right - viewport.left;
430 height = viewport.bottom - viewport.top;
431
432 WINPR_ASSERT(width >= 0);
433 WINPR_ASSERT(width <= UINT16_MAX);
434 WINPR_ASSERT(height >= 0);
435 WINPR_ASSERT(height <= UINT16_MAX);
436 return (freerdp_settings_get_uint32(settings, FreeRDP_DesktopWidth) != (UINT32)width ||
437 freerdp_settings_get_uint32(settings, FreeRDP_DesktopHeight) != (UINT32)height);
438}
439
440WINPR_ATTR_NODISCARD
441static BOOL shadow_client_capabilities(freerdp_peer* peer)
442{
443 rdpShadowSubsystem* subsystem = nullptr;
444 rdpShadowClient* client = nullptr;
445 BOOL ret = TRUE;
446
447 WINPR_ASSERT(peer);
448
449 client = (rdpShadowClient*)peer->context;
450 WINPR_ASSERT(client);
451 WINPR_ASSERT(client->server);
452
453 subsystem = client->server->subsystem;
454 WINPR_ASSERT(subsystem);
455
456 IFCALLRET(subsystem->ClientCapabilities, ret, subsystem, client);
457
458 if (!ret)
459 WLog_WARN(TAG, "subsystem->ClientCapabilities failed");
460
461 return ret;
462}
463
464static void shadow_reset_desktop_resize(rdpShadowClient* client)
465{
466 WINPR_ASSERT(client);
467 client->resizeRequested = FALSE;
468}
469
470WINPR_ATTR_NODISCARD
471static BOOL shadow_send_desktop_resize(rdpShadowClient* client)
472{
473 BOOL rc = 0;
474 rdpUpdate* update = nullptr;
475 rdpSettings* settings = nullptr;
476 const freerdp_peer* peer = nullptr;
477
478 WINPR_ASSERT(client);
479
480 settings = client->context.settings;
481 peer = client->context.peer;
482 WINPR_ASSERT(peer);
483 WINPR_ASSERT(client->server);
484 WINPR_ASSERT(client->server->surface);
485
486 const UINT32 resizeWidth = client->server->surface->width;
487 const UINT32 resizeHeight = client->server->surface->height;
488
489 if (client->resizeRequested)
490 {
491 if ((resizeWidth == client->resizeWidth) && (resizeHeight == client->resizeHeight))
492 {
493 const UINT32 w = freerdp_settings_get_uint32(settings, FreeRDP_DesktopWidth);
494 const UINT32 h = freerdp_settings_get_uint32(settings, FreeRDP_DesktopHeight);
495 WLog_WARN(TAG,
496 "detected previous resize request for resolution %" PRIu32 "x%" PRIu32
497 ", still have %" PRIu32 "x%" PRIu32 ", disconnecting peer",
498 resizeWidth, resizeHeight, w, h);
499 return FALSE;
500 }
501 }
502
503 update = client->context.update;
504 WINPR_ASSERT(update);
505 WINPR_ASSERT(update->DesktopResize);
506
507 // Update peer resolution, required so that during disconnect/reconnect the correct resolution
508 // is sent to the client.
509 if (!freerdp_settings_set_uint32(settings, FreeRDP_DesktopWidth, resizeWidth))
510 return FALSE;
511 if (!freerdp_settings_set_uint32(settings, FreeRDP_DesktopHeight, resizeHeight))
512 return FALSE;
513 rc = update->DesktopResize(update->context);
514 WLog_INFO(TAG, "Client %s resize requested (%" PRIu32 "x%" PRIu32 "@%" PRIu32 ")",
515 peer->hostname, resizeWidth, resizeHeight,
516 freerdp_settings_get_uint32(settings, FreeRDP_ColorDepth));
517 client->resizeRequested = TRUE;
518 client->resizeWidth = resizeWidth;
519 client->resizeHeight = resizeHeight;
520
521 return rc;
522}
523
524WINPR_ATTR_NODISCARD
525static BOOL shadow_client_post_connect(freerdp_peer* peer)
526{
527 int authStatus = 0;
528 rdpSettings* settings = nullptr;
529 rdpShadowClient* client = nullptr;
530 rdpShadowServer* server = nullptr;
531 rdpShadowSubsystem* subsystem = nullptr;
532
533 WINPR_ASSERT(peer);
534
535 client = (rdpShadowClient*)peer->context;
536 WINPR_ASSERT(client);
537
538 settings = peer->context->settings;
539 WINPR_ASSERT(settings);
540
541 server = client->server;
542 WINPR_ASSERT(server);
543
544 subsystem = server->subsystem;
545 WINPR_ASSERT(subsystem);
546
547 if (freerdp_settings_get_uint32(settings, FreeRDP_ColorDepth) == 24)
548 {
549 if (!freerdp_settings_set_uint32(settings, FreeRDP_ColorDepth, 16)) /* disable 24bpp */
550 return FALSE;
551 }
552
553 const UINT32 MultifragMaxRequestSize =
554 freerdp_settings_get_uint32(settings, FreeRDP_MultifragMaxRequestSize);
555 if (MultifragMaxRequestSize < 0x3F0000)
556 {
558 settings, FreeRDP_NSCodec,
559 FALSE); /* NSCodec compressor does not support fragmentation yet */
560 if (!rc)
561 return FALSE;
562 }
563
564 WLog_INFO(TAG, "Client from %s is activated (%" PRIu32 "x%" PRIu32 "@%" PRIu32 ")",
565 peer->hostname, freerdp_settings_get_uint32(settings, FreeRDP_DesktopWidth),
566 freerdp_settings_get_uint32(settings, FreeRDP_DesktopHeight),
567 freerdp_settings_get_uint32(settings, FreeRDP_ColorDepth));
568
569 if (shadow_client_channels_post_connect(client) != CHANNEL_RC_OK)
570 return FALSE;
571
572 shadow_client_mark_invalid(client, 0, nullptr);
573 authStatus = -1;
574
575 const char* Username = freerdp_settings_get_string(settings, FreeRDP_Username);
576 const char* Domain = freerdp_settings_get_string(settings, FreeRDP_Domain);
577 const char* Password = freerdp_settings_get_string(settings, FreeRDP_Password);
578
579 if (Username && Password)
580 {
581 if (!freerdp_settings_set_bool(settings, FreeRDP_AutoLogonEnabled, TRUE))
582 return FALSE;
583 }
584
585 if (server->authentication && !(freerdp_settings_get_bool(settings, FreeRDP_NlaSecurity) ||
586 freerdp_settings_get_bool(settings, FreeRDP_ExtSecurity)))
587 {
588 if (subsystem->Authenticate)
589 {
590 authStatus = subsystem->Authenticate(subsystem, client, Username, Domain, Password);
591 }
592
593 if (authStatus < 0)
594 {
595 WLog_ERR(TAG, "client authentication failure: %d", authStatus);
596 return FALSE;
597 }
598 }
599
600 if (subsystem->ClientConnect)
601 {
602 return subsystem->ClientConnect(subsystem, client);
603 }
604
605 return TRUE;
606}
607
608/* Convert rects in sub rect coordinate to client/surface coordinate */
609static inline void shadow_client_convert_rects(rdpShadowClient* client, RECTANGLE_16* dst,
610 const RECTANGLE_16* src, UINT32 numRects)
611{
612 WINPR_ASSERT(client);
613 WINPR_ASSERT(client->server);
614 WINPR_ASSERT(dst);
615 WINPR_ASSERT(src || (numRects == 0));
616
617 if (client->server->shareSubRect)
618 {
619 UINT16 offsetX = client->server->subRect.left;
620 UINT16 offsetY = client->server->subRect.top;
621
622 for (UINT32 i = 0; i < numRects; i++)
623 {
624 const RECTANGLE_16* s = &src[i];
625 RECTANGLE_16* d = &dst[i];
626
627 d->left = s->left + offsetX;
628 d->right = s->right + offsetX;
629 d->top = s->top + offsetY;
630 d->bottom = s->bottom + offsetY;
631 }
632 }
633 else
634 {
635 if (src != dst)
636 {
637 CopyMemory(dst, src, numRects * sizeof(RECTANGLE_16));
638 }
639 }
640}
641
642WINPR_ATTR_NODISCARD
643static BOOL shadow_client_refresh_request(rdpShadowClient* client)
644{
645 wMessage message = WINPR_C_ARRAY_INIT;
646 wMessagePipe* MsgPipe = nullptr;
647
648 WINPR_ASSERT(client);
649 WINPR_ASSERT(client->subsystem);
650
651 MsgPipe = client->subsystem->MsgPipe;
652 WINPR_ASSERT(MsgPipe);
653
654 message.id = SHADOW_MSG_IN_REFRESH_REQUEST_ID;
655 message.wParam = nullptr;
656 message.lParam = nullptr;
657 message.context = (void*)client;
658 message.Free = nullptr;
659 return MessageQueue_Dispatch(MsgPipe->In, &message);
660}
661
662WINPR_ATTR_NODISCARD
663static BOOL shadow_client_refresh_rect(rdpContext* context, BYTE count, const RECTANGLE_16* areas)
664{
665 rdpShadowClient* client = (rdpShadowClient*)context;
666 RECTANGLE_16* rects = nullptr;
667
668 /* It is invalid if we have area count but no actual area */
669 if (count && !areas)
670 return FALSE;
671
672 if (count)
673 {
674 rects = (RECTANGLE_16*)calloc(count, sizeof(RECTANGLE_16));
675
676 if (!rects)
677 {
678 return FALSE;
679 }
680
681 shadow_client_convert_rects(client, rects, areas, count);
682 shadow_client_mark_invalid(client, count, rects);
683 free(rects);
684 }
685 else
686 {
687 shadow_client_mark_invalid(client, 0, nullptr);
688 }
689
690 return shadow_client_refresh_request(client);
691}
692
693WINPR_ATTR_NODISCARD
694static BOOL shadow_client_suppress_output(rdpContext* context, BYTE allow, const RECTANGLE_16* area)
695{
696 rdpShadowClient* client = (rdpShadowClient*)context;
697 RECTANGLE_16 region;
698
699 WINPR_ASSERT(client);
700
701 client->suppressOutput = !(allow);
702
703 if (allow)
704 {
705 if (area)
706 {
707 shadow_client_convert_rects(client, &region, area, 1);
708 shadow_client_mark_invalid(client, 1, &region);
709 }
710 else
711 {
712 shadow_client_mark_invalid(client, 0, nullptr);
713 }
714 }
715
716 return shadow_client_refresh_request(client);
717}
718
719WINPR_ATTR_NODISCARD
720static BOOL shadow_client_activate(freerdp_peer* peer)
721{
722 WINPR_ASSERT(peer);
723
724 rdpShadowClient* client = (rdpShadowClient*)peer->context;
725 WINPR_ASSERT(client);
726
727 /* Resize client if necessary */
728 if (shadow_client_recalc_desktop_size(client))
729 return shadow_send_desktop_resize(client);
730
731 shadow_reset_desktop_resize(client);
732 client->activated = TRUE;
733 client->inLobby = !(client->mayView);
734
735 if (shadow_encoder_reset(client->encoder) < 0)
736 {
737 WLog_ERR(TAG, "Failed to reset encoder");
738 return FALSE;
739 }
740
741 /* Update full screen in next update */
742 return shadow_client_refresh_rect(&client->context, 0, nullptr);
743}
744
745WINPR_ATTR_NODISCARD
746static BOOL shadow_client_logon(freerdp_peer* peer, const SEC_WINNT_AUTH_IDENTITY* identity,
747 BOOL automatic)
748{
749 BOOL rc = FALSE;
750 char* user = nullptr;
751 char* domain = nullptr;
752 char* password = nullptr;
753 rdpSettings* settings = nullptr;
754
755 WINPR_UNUSED(automatic);
756
757 WINPR_ASSERT(peer);
758 WINPR_ASSERT(identity);
759
760 WINPR_ASSERT(peer->context);
761
762 settings = peer->context->settings;
763 WINPR_ASSERT(settings);
764
765 if (identity->Flags & SEC_WINNT_AUTH_IDENTITY_UNICODE)
766 {
767 if (identity->User)
768 user = ConvertWCharNToUtf8Alloc(identity->User, identity->UserLength, nullptr);
769
770 if (identity->Domain)
771 domain = ConvertWCharNToUtf8Alloc(identity->Domain, identity->DomainLength, nullptr);
772
773 if (identity->Password)
774 password =
775 ConvertWCharNToUtf8Alloc(identity->Password, identity->PasswordLength, nullptr);
776 }
777 else
778 {
779 if (identity->User)
780 user = _strdup((char*)identity->User);
781
782 if (identity->Domain)
783 domain = _strdup((char*)identity->Domain);
784
785 if (identity->Password)
786 password = _strdup((char*)identity->Password);
787 }
788
789 if ((identity->User && !user) || (identity->Domain && !domain) ||
790 (identity->Password && !password))
791 goto fail;
792
793 if (user)
794 {
795 if (!freerdp_settings_set_string(settings, FreeRDP_Username, user))
796 goto fail;
797 }
798
799 if (domain)
800 {
801 if (!freerdp_settings_set_string(settings, FreeRDP_Domain, domain))
802 goto fail;
803 }
804 if (password)
805 {
806 if (!freerdp_settings_set_string(settings, FreeRDP_Password, password))
807 goto fail;
808 }
809 rc = TRUE;
810fail:
811 free(user);
812 free(domain);
813 free(password);
814 return rc;
815}
816
817static inline void shadow_client_common_frame_acknowledge(rdpShadowClient* client, UINT32 frameId)
818{
819 /*
820 * Record the last client acknowledged frame id to
821 * calculate how much frames are in progress.
822 * Some rdp clients (win7 mstsc) skips frame ACK if it is
823 * inactive, we should not expect ACK for each frame.
824 * So it is OK to calculate in-flight frame count according to
825 * a latest acknowledged frame id.
826 */
827 WINPR_ASSERT(client);
828 WINPR_ASSERT(client->encoder);
829 client->encoder->lastAckframeId = frameId;
830}
831
832WINPR_ATTR_NODISCARD
833static BOOL shadow_client_surface_frame_acknowledge(rdpContext* context, UINT32 frameId)
834{
835 rdpShadowClient* client = (rdpShadowClient*)context;
836 shadow_client_common_frame_acknowledge(client, frameId);
837 /*
838 * Reset queueDepth for legacy none RDPGFX acknowledge
839 */
840 WINPR_ASSERT(client);
841 WINPR_ASSERT(client->encoder);
842 client->encoder->queueDepth = QUEUE_DEPTH_UNAVAILABLE;
843 return TRUE;
844}
845
846WINPR_ATTR_NODISCARD
847static UINT
848shadow_client_rdpgfx_frame_acknowledge(RdpgfxServerContext* context,
849 const RDPGFX_FRAME_ACKNOWLEDGE_PDU* frameAcknowledge)
850{
851 rdpShadowClient* client = nullptr;
852
853 WINPR_ASSERT(context);
854 WINPR_ASSERT(frameAcknowledge);
855
856 client = (rdpShadowClient*)context->custom;
857 shadow_client_common_frame_acknowledge(client, frameAcknowledge->frameId);
858
859 WINPR_ASSERT(client);
860 WINPR_ASSERT(client->encoder);
861 client->encoder->queueDepth = frameAcknowledge->queueDepth;
862 return CHANNEL_RC_OK;
863}
864
865WINPR_ATTR_NODISCARD
866static BOOL shadow_are_caps_filtered(const rdpSettings* settings, UINT32 caps)
867{
868 const UINT32 capList[] = {
869#if defined(WITH_GFX_AV1)
870 RDPGFX_CAPVERSION_FRDP_1,
871#endif
872 RDPGFX_CAPVERSION_8,
873 RDPGFX_CAPVERSION_81,
874 RDPGFX_CAPVERSION_10,
875 RDPGFX_CAPVERSION_101,
876 RDPGFX_CAPVERSION_102,
877 RDPGFX_CAPVERSION_103,
878 RDPGFX_CAPVERSION_104,
879 RDPGFX_CAPVERSION_105,
880 RDPGFX_CAPVERSION_106,
881 RDPGFX_CAPVERSION_106_ERR,
882 RDPGFX_CAPVERSION_107
883#if defined(WITH_GFX_AZURE)
884 ,
885 RDPGFX_CAPVERSION_111,
886 RDPGFX_CAPVERSION_112,
887 RDPGFX_CAPVERSION_113,
888 RDPGFX_CAPVERSION_115
889#endif
890 };
891
892 WINPR_ASSERT(settings);
893 const UINT32 filter = freerdp_settings_get_uint32(settings, FreeRDP_GfxCapsFilter);
894
895 for (UINT32 x = 0; x < ARRAYSIZE(capList); x++)
896 {
897 if (caps == capList[x])
898 return (filter & (1u << x)) != 0;
899 }
900
901 return TRUE;
902}
903
904/* The 8.1 capability set turns AVC420 on with a flag; from 10.0 on AVC420 is part of the set
905 * unless the AVC codecs are disabled (the 8.1 flag is not defined there, so a 10.x client never
906 * sets it). */
907WINPR_ATTR_NODISCARD
908static BOOL shadow_client_caps_allow_avc420(const RDPGFX_CAPSET* caps)
909{
910 WINPR_ASSERT(caps);
911 if (caps->version == RDPGFX_CAPVERSION_81)
912 return (caps->flags & RDPGFX_CAPS_FLAG_AVC420_ENABLED) != 0;
913 return (caps->flags & RDPGFX_CAPS_FLAG_AVC_DISABLED) == 0;
914}
915
916WINPR_ATTR_NODISCARD
917static UINT shadow_client_send_caps_confirm(RdpgfxServerContext* context, rdpShadowClient* client,
918 const RDPGFX_CAPS_CONFIRM_PDU* pdu)
919{
920 WINPR_ASSERT(context);
921 WINPR_ASSERT(client);
922 WINPR_ASSERT(pdu);
923
924 WINPR_ASSERT(context->CapsConfirm);
925 UINT rc = context->CapsConfirm(context, pdu);
926 client->areGfxCapsReady = (rc == CHANNEL_RC_OK);
927 client->confirmedCaps = *pdu->capsSet;
928
929 rdpSettings* clientSettings = client->context.settings;
930 WINPR_ASSERT(clientSettings);
931
932#if defined(WITH_GFX_AV1)
933 if (pdu->capsSet->version == RDPGFX_CAPVERSION_FRDP_1)
934 {
935 UINT32 flags = FREERDP_CODEC_AV1_I420;
936 if ((pdu->capsSet->flags & RDPGFX_CAPS_FLAG_AV1_I444_DISABLED) == 0)
937 flags = FREERDP_CODEC_AV1_I444;
938
939 if (shadow_encoder_prepare(client->encoder, flags) < 0)
940 return ERROR_INVALID_PARAMETER;
941 }
942 else
943#endif
944 if (shadow_avc444_enabled(client) || shadow_avc420_enabled(client))
945 {
946#ifdef WITH_GFX_H264
947 const BOOL h264 = (shadow_encoder_prepare(client->encoder, FREERDP_CODEC_AVC420 |
948 FREERDP_CODEC_AVC444) >= 0);
949 if (h264)
950 {
951 /* the server's own setting (-gfx-avc420) still counts */
953 clientSettings, FreeRDP_GfxH264,
954 shadow_client_caps_allow_avc420(pdu->capsSet) &&
955 freerdp_settings_get_bool(clientSettings, FreeRDP_GfxH264)))
956 return rc;
957 }
958 else
959 {
960 if (!freerdp_settings_set_bool(clientSettings, FreeRDP_GfxH264, FALSE))
961 return rc;
962 }
963#else
964 if (!freerdp_settings_set_bool(clientSettings, FreeRDP_GfxAVC444v2, FALSE))
965 return rc;
966 if (!freerdp_settings_set_bool(clientSettings, FreeRDP_GfxAVC444, FALSE))
967 return rc;
968 if (!freerdp_settings_set_bool(clientSettings, FreeRDP_GfxH264, FALSE))
969 return rc;
970#endif
971 }
972
973 return rc;
974}
975
976WINPR_ATTR_NODISCARD
977static BOOL shadow_client_caps_test_version(RdpgfxServerContext* context, rdpShadowClient* client,
978 BOOL h264, const RDPGFX_CAPSET* capsSets,
979 UINT32 capsSetCount, UINT32 capsVersion, UINT* rc)
980{
981 WINPR_ASSERT(context);
982 WINPR_ASSERT(client);
983 WINPR_ASSERT(capsSets || (capsSetCount == 0));
984 WINPR_ASSERT(rc);
985
986 WINPR_ASSERT(context->rdpcontext);
987 const rdpSettings* srvSettings = context->rdpcontext->settings;
988 WINPR_ASSERT(srvSettings);
989
990 rdpSettings* clientSettings = client->context.settings;
991 WINPR_ASSERT(clientSettings);
992
993 if (shadow_are_caps_filtered(srvSettings, capsVersion))
994 return FALSE;
995
996 for (UINT32 index = 0; index < capsSetCount; index++)
997 {
998 const RDPGFX_CAPSET* currentCaps = &capsSets[index];
999
1000 WLog_INFO(TAG, "testing %s vs %s[0x%08" PRIx32 "]",
1001 rdpgfx_caps_version_str(currentCaps->version),
1002 rdpgfx_caps_version_str(capsVersion), capsVersion);
1003 if (currentCaps->version == capsVersion)
1004 {
1005 RDPGFX_CAPSET caps = *currentCaps;
1006 RDPGFX_CAPS_CONFIRM_PDU pdu = WINPR_C_ARRAY_INIT;
1007 pdu.capsSet = &caps;
1008
1009 const UINT32 flags = pdu.capsSet->flags;
1010
1011 if (!freerdp_settings_set_bool(clientSettings, FreeRDP_GfxSmallCache,
1012 (flags & RDPGFX_CAPS_FLAG_SMALL_CACHE) != 0))
1013 return FALSE;
1014
1015 BOOL avc420 = TRUE;
1016 BOOL avc444 = !(flags & RDPGFX_CAPS_FLAG_AVC_DISABLED);
1017 BOOL avc444v2 = avc444;
1018 if (!freerdp_settings_get_bool(srvSettings, FreeRDP_GfxAVC444v2) || !h264)
1019 avc444v2 = FALSE;
1020 if (!freerdp_settings_set_bool(clientSettings, FreeRDP_GfxAVC444v2, avc444v2))
1021 return FALSE;
1022 if (!freerdp_settings_get_bool(srvSettings, FreeRDP_GfxAVC444) || !h264)
1023 avc444 = FALSE;
1024 if (!freerdp_settings_set_bool(clientSettings, FreeRDP_GfxAVC444, avc444))
1025 return FALSE;
1026 if (!freerdp_settings_get_bool(srvSettings, FreeRDP_GfxH264) || !h264)
1027 avc420 = FALSE;
1028 if (!freerdp_settings_set_bool(clientSettings, FreeRDP_GfxH264, avc420))
1029 return FALSE;
1030
1031 const BOOL progressive = freerdp_settings_get_bool(srvSettings, FreeRDP_GfxProgressive);
1032 if (!freerdp_settings_set_bool(clientSettings, FreeRDP_GfxProgressive, progressive))
1033 return FALSE;
1034 const BOOL progressivev2 =
1035 freerdp_settings_get_bool(srvSettings, FreeRDP_GfxProgressiveV2);
1036 if (!freerdp_settings_set_bool(clientSettings, FreeRDP_GfxProgressiveV2, progressivev2))
1037 return FALSE;
1038
1039 const BOOL rfx = freerdp_settings_get_bool(srvSettings, FreeRDP_RemoteFxCodec);
1040 if (!freerdp_settings_set_bool(clientSettings, FreeRDP_RemoteFxCodec, rfx))
1041 return FALSE;
1042
1043 const BOOL planar = freerdp_settings_get_bool(srvSettings, FreeRDP_GfxPlanar);
1044 if (!freerdp_settings_set_bool(clientSettings, FreeRDP_GfxPlanar, planar))
1045 return FALSE;
1046#if defined(WITH_GFX_AV1)
1047 const BOOL av1 = freerdp_settings_get_bool(srvSettings, FreeRDP_GfxCodecAV1);
1048 if (!freerdp_settings_set_bool(clientSettings, FreeRDP_GfxCodecAV1, av1))
1049 return FALSE;
1050 const UINT32 av1Profile =
1051 freerdp_settings_get_uint32(srvSettings, FreeRDP_GfxCodecAV1Profile);
1052 if (!freerdp_settings_set_uint32(clientSettings, FreeRDP_GfxCodecAV1Profile,
1053 av1Profile))
1054 return FALSE;
1055#endif
1056
1057 if (!h264 || (!avc444v2 && !avc444 && !avc420))
1058 pdu.capsSet->flags |= RDPGFX_CAPS_FLAG_AVC_DISABLED;
1059
1060#if defined(WITH_GFX_AV1)
1061 if (currentCaps->version == RDPGFX_CAPVERSION_FRDP_1)
1062 {
1063 if (!av1)
1064 return FALSE;
1065
1066 pdu.capsSet->flags &=
1067 ~(RDPGFX_CAPS_FLAG_AV1_I444_SUPPORTED | RDPGFX_CAPS_FLAG_AV1_I444_DISABLED);
1068
1069 if ((currentCaps->flags & RDPGFX_CAPS_FLAG_AV1_I444_SUPPORTED) != 0)
1070 {
1071 if (av1Profile == 0)
1072 return FALSE;
1073 }
1074
1075 if ((av1Profile == 0) ||
1076 ((currentCaps->flags & RDPGFX_CAPS_FLAG_AV1_I444_SUPPORTED) == 0))
1077 pdu.capsSet->flags |= RDPGFX_CAPS_FLAG_AV1_I444_DISABLED;
1078 if ((currentCaps->flags & RDPGFX_CAPS_FLAG_AV1_I444_DISABLED) != 0)
1079 pdu.capsSet->flags |= RDPGFX_CAPS_FLAG_AV1_I444_DISABLED;
1080 }
1081#endif
1082 *rc = shadow_client_send_caps_confirm(context, client, &pdu);
1083 return TRUE;
1084 }
1085 }
1086
1087 return FALSE;
1088}
1089
1095WINPR_ATTR_NODISCARD
1096static UINT shadow_client_rdpgfx_caps_advertise(RdpgfxServerContext* context,
1097 const RDPGFX_CAPS_ADVERTISE_PDU* capsAdvertise)
1098{
1099 UINT rc = ERROR_INTERNAL_ERROR;
1100
1101 UINT32 flags = 0;
1102
1103 WINPR_ASSERT(context);
1104 WINPR_ASSERT(capsAdvertise);
1105
1106 rdpShadowClient* client = (rdpShadowClient*)context->custom;
1107 WINPR_ASSERT(client);
1108 WINPR_ASSERT(context->rdpcontext);
1109
1110 const rdpSettings* srvSettings = context->rdpcontext->settings;
1111 WINPR_ASSERT(srvSettings);
1112
1113 rdpSettings* clientSettings = client->context.settings;
1114 WINPR_ASSERT(clientSettings);
1115
1116 /* Request full screen update for new gfx channel */
1117 if (!shadow_client_refresh_rect(&client->context, 0, nullptr))
1118 return rc;
1119
1120 const UINT32 capsVersions[] = {
1121#if defined(WITH_GFX_AV1)
1122 RDPGFX_CAPVERSION_FRDP_1,
1123#endif
1124#if defined(WITH_GFX_AZURE)
1125 RDPGFX_CAPVERSION_115, RDPGFX_CAPVERSION_113, RDPGFX_CAPVERSION_112,
1126 RDPGFX_CAPVERSION_111,
1127#endif
1128 RDPGFX_CAPVERSION_107, RDPGFX_CAPVERSION_106, RDPGFX_CAPVERSION_106_ERR,
1129 RDPGFX_CAPVERSION_105, RDPGFX_CAPVERSION_104, RDPGFX_CAPVERSION_103,
1130 RDPGFX_CAPVERSION_102, RDPGFX_CAPVERSION_101, RDPGFX_CAPVERSION_10,
1131 };
1132
1133 const BOOL h264 =
1134 shadow_encoder_prepare(client->encoder, FREERDP_CODEC_AVC420 | FREERDP_CODEC_AVC444) >= 0;
1135
1136#if defined(WITH_GFX_AV1)
1137 if (freerdp_settings_get_bool(clientSettings, FreeRDP_GfxCodecAV1))
1138 {
1139 UINT32 codec = 0;
1140 const UINT32 profile =
1141 freerdp_settings_get_uint32(clientSettings, FreeRDP_GfxCodecAV1Profile);
1142 switch (profile)
1143 {
1144 case 0:
1145 codec = FREERDP_CODEC_AV1_I420;
1146 break;
1147 case 1:
1148 codec = FREERDP_CODEC_AV1_I444;
1149 break;
1150 default:
1151 return ERROR_BAD_PROFILE;
1152 }
1153 const BOOL av1 = shadow_encoder_prepare(client->encoder, codec) >= 0;
1154 if (!av1)
1155 {
1156 if (!freerdp_settings_set_bool(clientSettings, FreeRDP_GfxCodecAV1, FALSE))
1157 return ERROR_INTERNAL_ERROR;
1158 }
1159 }
1160#endif
1161
1162 for (size_t x = 0; x < ARRAYSIZE(capsVersions); x++)
1163 {
1164 const UINT32 cur = capsVersions[x];
1165 if (shadow_client_caps_test_version(context, client, h264, capsAdvertise->capsSets,
1166 capsAdvertise->capsSetCount, cur, &rc))
1167 return rc;
1168 }
1169
1170 if (!shadow_are_caps_filtered(srvSettings, RDPGFX_CAPVERSION_81))
1171 {
1172 for (UINT32 index = 0; index < capsAdvertise->capsSetCount; index++)
1173 {
1174 const RDPGFX_CAPSET* currentCaps = &capsAdvertise->capsSets[index];
1175
1176 if (currentCaps->version == RDPGFX_CAPVERSION_81)
1177 {
1178 RDPGFX_CAPSET caps = *currentCaps;
1180 pdu.capsSet = &caps;
1181
1182 flags = pdu.capsSet->flags;
1183
1184 if (!freerdp_settings_set_bool(clientSettings, FreeRDP_GfxAVC444v2, FALSE))
1185 return rc;
1186 if (!freerdp_settings_set_bool(clientSettings, FreeRDP_GfxAVC444, FALSE))
1187 return rc;
1188
1189 if (!freerdp_settings_set_bool(clientSettings, FreeRDP_GfxThinClient,
1190 (flags & RDPGFX_CAPS_FLAG_THINCLIENT) != 0))
1191 return rc;
1192 if (!freerdp_settings_set_bool(clientSettings, FreeRDP_GfxSmallCache,
1193 (flags & RDPGFX_CAPS_FLAG_SMALL_CACHE) != 0))
1194 return rc;
1195
1196#ifndef WITH_GFX_H264
1197 if (!freerdp_settings_set_bool(clientSettings, FreeRDP_GfxH264, FALSE))
1198 return rc;
1199 if (h264)
1200 pdu.capsSet->flags &= ~RDPGFX_CAPS_FLAG_AVC420_ENABLED;
1201#else
1202
1203#endif
1204
1205 return shadow_client_send_caps_confirm(context, client, &pdu);
1206 }
1207 }
1208 }
1209
1210 if (!shadow_are_caps_filtered(srvSettings, RDPGFX_CAPVERSION_8))
1211 {
1212 for (UINT32 index = 0; index < capsAdvertise->capsSetCount; index++)
1213 {
1214 const RDPGFX_CAPSET* currentCaps = &capsAdvertise->capsSets[index];
1215
1216 if (currentCaps->version == RDPGFX_CAPVERSION_8)
1217 {
1218 RDPGFX_CAPSET caps = *currentCaps;
1220 pdu.capsSet = &caps;
1221 flags = pdu.capsSet->flags;
1222
1223 if (!freerdp_settings_set_bool(clientSettings, FreeRDP_GfxAVC444v2, FALSE))
1224 return rc;
1225 if (!freerdp_settings_set_bool(clientSettings, FreeRDP_GfxAVC444, FALSE))
1226 return rc;
1227 if (!freerdp_settings_set_bool(clientSettings, FreeRDP_GfxH264, FALSE))
1228 return rc;
1229
1230 if (!freerdp_settings_set_bool(clientSettings, FreeRDP_GfxThinClient,
1231 (flags & RDPGFX_CAPS_FLAG_THINCLIENT) != 0))
1232 return rc;
1233 if (!freerdp_settings_set_bool(clientSettings, FreeRDP_GfxSmallCache,
1234 (flags & RDPGFX_CAPS_FLAG_SMALL_CACHE) != 0))
1235 return rc;
1236
1237 return shadow_client_send_caps_confirm(context, client, &pdu);
1238 }
1239 }
1240 }
1241
1242 return CHANNEL_RC_UNSUPPORTED_VERSION;
1243}
1244
1245WINPR_ATTR_NODISCARD
1246static inline UINT32 rdpgfx_estimate_h264_avc420(RDPGFX_AVC420_BITMAP_STREAM* havc420)
1247{
1248 /* H264 metadata + H264 stream. See rdpgfx_write_h264_avc420 */
1249 WINPR_ASSERT(havc420);
1250 return sizeof(UINT32) /* numRegionRects */
1251 + 10ULL /* regionRects + quantQualityVals */
1252 * havc420->meta.numRegionRects +
1253 havc420->length;
1254}
1255
1256#if defined(WITH_GFX_AV1)
1257WINPR_ATTR_NODISCARD
1258static BOOL shadow_client_av1_enabled(const rdpShadowClient* client)
1259{
1260 WINPR_ASSERT(client);
1261 return freerdp_settings_get_bool(client->context.settings, FreeRDP_GfxCodecAV1) &&
1262 (client->confirmedCaps.version == RDPGFX_CAPVERSION_FRDP_1);
1263}
1264
1265WINPR_ATTR_NODISCARD
1266static BOOL shadow_client_send_av1(rdpShadowClient* client, const BYTE* pSrcData, UINT32 nSrcStep,
1267 UINT32 SrcFormat, UINT16 nWidth, UINT16 nHeight,
1268 const RECTANGLE_16* damage, RDPGFX_SURFACE_COMMAND* cmd,
1269 const RDPGFX_START_FRAME_PDU* cmdstart,
1270 const RDPGFX_END_FRAME_PDU* cmdend)
1271{
1272 WINPR_ASSERT(client);
1273
1274 rdpShadowEncoder* encoder = client->encoder;
1275 WINPR_ASSERT(encoder);
1276
1277 UINT error = CHANNEL_RC_OK;
1278 INT32 rc = 0;
1279 RDPGFX_AVC420_BITMAP_STREAM avc420 = WINPR_C_ARRAY_INIT;
1280
1281 UINT32 flags = FREERDP_CODEC_AV1_I444;
1282 if ((client->confirmedCaps.flags & RDPGFX_CAPS_FLAG_AV1_I444_DISABLED) != 0)
1283 flags = FREERDP_CODEC_AV1_I420;
1284
1285 if (shadow_encoder_prepare(encoder, flags) < 0)
1286 {
1287 WLog_ERR(TAG, "Failed to prepare encoder FREERDP_CODEC_AV1");
1288 return FALSE;
1289 }
1290
1291 /* The whole surface is encoded, but only the damaged part needs converting to YUV. */
1292 WINPR_ASSERT(damage);
1293 rc = freerdp_av1_compress(encoder->av1, pSrcData, SrcFormat, nSrcStep, nWidth, nHeight, damage,
1294 &avc420.data, &avc420.length, &avc420.meta);
1295 if (rc < 0)
1296 {
1297 WLog_ERR(TAG, "freerdp_av1_compress failed");
1298 return FALSE;
1299 }
1300
1301 /* rc > 0 means new data */
1302 if (rc > 0)
1303 {
1304 cmd->codecId = RDPGFX_CODECID_AV1;
1305 cmd->extra = (void*)&avc420;
1306
1307 IFCALLRET(client->rdpgfx->SurfaceFrameCommand, error, client->rdpgfx, cmd, cmdstart,
1308 cmdend);
1309 cmd->extra = nullptr;
1310 }
1311 free_h264_metablock(&avc420.meta);
1312
1313 if (error)
1314 {
1315 WLog_ERR(TAG, "SurfaceFrameCommand failed with error %" PRIu32 "", error);
1316 return FALSE;
1317 }
1318 return TRUE;
1319}
1320#endif
1321
1322WINPR_ATTR_NODISCARD
1323static BOOL shadow_client_send_avc444(rdpShadowClient* client, const BYTE* pSrcData,
1324 UINT32 nSrcStep, UINT32 SrcFormat, UINT16 nWidth,
1325 UINT16 nHeight, RDPGFX_SURFACE_COMMAND* cmd,
1326 const RDPGFX_START_FRAME_PDU* cmdstart,
1327 const RDPGFX_END_FRAME_PDU* cmdend)
1328{
1329 WINPR_ASSERT(client);
1330
1331 rdpShadowEncoder* encoder = client->encoder;
1332 WINPR_ASSERT(encoder);
1333
1334 UINT error = CHANNEL_RC_OK;
1335 INT32 rc = 0;
1336 RDPGFX_AVC444_BITMAP_STREAM avc444 = WINPR_C_ARRAY_INIT;
1337 RECTANGLE_16 regionRect = WINPR_C_ARRAY_INIT;
1338 const BOOL GfxAVC444v2 = (cmd->codecId == RDPGFX_CODECID_AVC444v2);
1339 BYTE version = GfxAVC444v2 ? 2 : 1;
1340
1341 if (shadow_encoder_prepare(encoder, FREERDP_CODEC_AVC444) < 0)
1342 {
1343 WLog_ERR(TAG, "Failed to prepare encoder FREERDP_CODEC_AVC444");
1344 return FALSE;
1345 }
1346
1347 WINPR_ASSERT(cmd->left <= UINT16_MAX);
1348 WINPR_ASSERT(cmd->top <= UINT16_MAX);
1349 WINPR_ASSERT(cmd->right <= UINT16_MAX);
1350 WINPR_ASSERT(cmd->bottom <= UINT16_MAX);
1351 regionRect.left = (UINT16)cmd->left;
1352 regionRect.top = (UINT16)cmd->top;
1353 regionRect.right = (UINT16)cmd->right;
1354 regionRect.bottom = (UINT16)cmd->bottom;
1355 rc = avc444_compress(encoder->h264, pSrcData, SrcFormat, nSrcStep, nWidth, nHeight, version,
1356 &regionRect, &avc444.LC, &avc444.bitstream[0].data,
1357 &avc444.bitstream[0].length, &avc444.bitstream[1].data,
1358 &avc444.bitstream[1].length, &avc444.bitstream[0].meta,
1359 &avc444.bitstream[1].meta);
1360 if (rc < 0)
1361 {
1362 WLog_ERR(TAG, "avc420_compress failed for avc444");
1363 return FALSE;
1364 }
1365
1366 /* rc > 0 means new data */
1367 if (rc > 0)
1368 {
1369 avc444.cbAvc420EncodedBitstream1 = rdpgfx_estimate_h264_avc420(&avc444.bitstream[0]);
1370 cmd->extra = (void*)&avc444;
1371 IFCALLRET(client->rdpgfx->SurfaceFrameCommand, error, client->rdpgfx, cmd, cmdstart,
1372 cmdend);
1373 cmd->extra = nullptr;
1374 }
1375
1376 free_h264_metablock(&avc444.bitstream[0].meta);
1377 free_h264_metablock(&avc444.bitstream[1].meta);
1378 if (error)
1379 {
1380 WLog_ERR(TAG, "SurfaceFrameCommand failed with error %" PRIu32 "", error);
1381 return FALSE;
1382 }
1383 return TRUE;
1384}
1385
1386WINPR_ATTR_NODISCARD
1387static BOOL shadow_client_send_avc420(rdpShadowClient* client, const BYTE* pSrcData,
1388 UINT32 nSrcStep, UINT32 SrcFormat, UINT16 nWidth,
1389 UINT16 nHeight, RDPGFX_SURFACE_COMMAND* cmd,
1390 const RDPGFX_START_FRAME_PDU* cmdstart,
1391 const RDPGFX_END_FRAME_PDU* cmdend)
1392{
1393 WINPR_ASSERT(client);
1394
1395 rdpShadowEncoder* encoder = client->encoder;
1396 WINPR_ASSERT(encoder);
1397
1398 UINT error = CHANNEL_RC_OK;
1399 INT32 rc = 0;
1400 RDPGFX_AVC420_BITMAP_STREAM avc420 = WINPR_C_ARRAY_INIT;
1401 RECTANGLE_16 regionRect;
1402
1403 if (shadow_encoder_prepare(encoder, FREERDP_CODEC_AVC420) < 0)
1404 {
1405 WLog_ERR(TAG, "Failed to prepare encoder FREERDP_CODEC_AVC420");
1406 return FALSE;
1407 }
1408
1409 WINPR_ASSERT(cmd->left <= UINT16_MAX);
1410 WINPR_ASSERT(cmd->top <= UINT16_MAX);
1411 WINPR_ASSERT(cmd->right <= UINT16_MAX);
1412 WINPR_ASSERT(cmd->bottom <= UINT16_MAX);
1413 regionRect.left = (UINT16)cmd->left;
1414 regionRect.top = (UINT16)cmd->top;
1415 regionRect.right = (UINT16)cmd->right;
1416 regionRect.bottom = (UINT16)cmd->bottom;
1417 rc = avc420_compress(encoder->h264, pSrcData, SrcFormat, nSrcStep, nWidth, nHeight, &regionRect,
1418 &avc420.data, &avc420.length, &avc420.meta);
1419 if (rc < 0)
1420 {
1421 WLog_ERR(TAG, "avc420_compress failed");
1422 return FALSE;
1423 }
1424
1425 /* rc > 0 means new data */
1426 if (rc > 0)
1427 {
1428 cmd->codecId = RDPGFX_CODECID_AVC420;
1429 cmd->extra = (void*)&avc420;
1430 IFCALLRET(client->rdpgfx->SurfaceFrameCommand, error, client->rdpgfx, cmd, cmdstart,
1431 cmdend);
1432 cmd->extra = nullptr;
1433 }
1434 free_h264_metablock(&avc420.meta);
1435
1436 if (error)
1437 {
1438 WLog_ERR(TAG, "SurfaceFrameCommand failed with error %" PRIu32 "", error);
1439 return FALSE;
1440 }
1441 return TRUE;
1442}
1443
1444WINPR_ATTR_NODISCARD
1445static BOOL shadow_client_send_rfx(rdpShadowClient* client, const BYTE* pSrcData, UINT32 nSrcStep,
1446 UINT32 SrcFormat, UINT16 nWidth, UINT16 nHeight,
1448 const RDPGFX_START_FRAME_PDU* cmdstart,
1449 const RDPGFX_END_FRAME_PDU* cmdend)
1450{
1451 WINPR_ASSERT(client);
1452
1453 rdpShadowEncoder* encoder = client->encoder;
1454 WINPR_ASSERT(encoder);
1455
1456 UINT error = CHANNEL_RC_OK;
1457 BOOL rc = 0;
1458
1459 if (shadow_encoder_prepare(encoder, FREERDP_CODEC_REMOTEFX) < 0)
1460 {
1461 WLog_ERR(TAG, "Failed to prepare encoder FREERDP_CODEC_REMOTEFX");
1462 return FALSE;
1463 }
1464
1465 const UINT32 rfxFormat = rfx_context_get_pixel_format(encoder->rfx);
1466 if (rfxFormat != SrcFormat)
1467 {
1468 WLog_ERR(TAG, "RFX context pixel format mismatch %s, expected %s",
1469 FreeRDPGetColorFormatName(rfxFormat), FreeRDPGetColorFormatName(SrcFormat));
1470 return FALSE;
1471 }
1472
1473 wStream* s = Stream_New(nullptr, 1024);
1474 WINPR_ASSERT(s);
1475
1476 WINPR_ASSERT(cmd->left <= UINT16_MAX);
1477 WINPR_ASSERT(cmd->top <= UINT16_MAX);
1478 WINPR_ASSERT(cmd->right <= UINT16_MAX);
1479 WINPR_ASSERT(cmd->bottom <= UINT16_MAX);
1480
1481 /* GFX RFX dirty tile skipping: split the dirty rect onto the 64x64
1482 * surface tile grid and compare each tile against the encoder snapshot
1483 * of the last encoded content (shadow_rfx_dirty.c). Only tiles whose
1484 * content changed are passed to the RFX encoder. A missing or
1485 * mismatching snapshot (first frame, ResetGraphics, resize, new client)
1486 * treats every tile as changed and degrades to full encoding. */
1487 {
1488 UINT16 numRects = 0;
1489 RFX_RECT* rects = nullptr;
1490
1491 if (shadow_rfx_plan_tiles(encoder, pSrcData, nSrcStep, cmd, nWidth, nHeight, &rects,
1492 &numRects) < 0)
1493 {
1494 WLog_ERR(TAG, "shadow_rfx_plan_tiles failed");
1495 Stream_Free(s, TRUE);
1496 free(rects);
1497 return FALSE;
1498 }
1499
1500 if (numRects == 0)
1501 {
1502 /* Every tile of this frame is byte-identical to the last encoded
1503 * content: skip the whole frame (no surface command: StartFrame/
1504 * EndFrame are sent paired with SurfaceFrameCommand, so no
1505 * dangling frame semantics). Give the frame id back to the
1506 * encoder: skipped frames are never acknowledged by the client,
1507 * not returning it would permanently inflate the in-flight depth
1508 * and stall the preferred_fps backpressure. */
1509 encoder->frameId--;
1510 Stream_Free(s, TRUE);
1511 free(rects);
1512 return TRUE;
1513 }
1514
1515 rc = rfx_compose_message(encoder->rfx, s, rects, numRects, pSrcData, nWidth, nHeight,
1516 nSrcStep);
1517
1518 if (rc)
1519 {
1520 const size_t pos = Stream_GetPosition(s);
1521 shadow_rfx_commit_tiles(encoder, pSrcData, nSrcStep, rects, numRects,
1522 WINPR_ASSERTING_INT_CAST(UINT32, pos));
1523 }
1524
1525 free(rects);
1526 }
1527
1528 if (!rc)
1529 {
1530 WLog_ERR(TAG, "rfx_compose_message failed");
1531 Stream_Free(s, TRUE);
1532 return FALSE;
1533 }
1534
1535 /* rc > 0 means new data */
1536 if (rc > 0)
1537 {
1538 const size_t pos = Stream_GetPosition(s);
1539 WINPR_ASSERT(pos <= UINT32_MAX);
1540
1541 cmd->codecId = RDPGFX_CODECID_CAVIDEO;
1542 cmd->data = Stream_Buffer(s);
1543 cmd->length = (UINT32)pos;
1544
1545 IFCALLRET(client->rdpgfx->SurfaceFrameCommand, error, client->rdpgfx, cmd, cmdstart,
1546 cmdend);
1547 cmd->data = nullptr;
1548 }
1549
1550 Stream_Free(s, TRUE);
1551 if (error)
1552 {
1553 WLog_ERR(TAG, "SurfaceFrameCommand failed with error %" PRIu32 "", error);
1554 return FALSE;
1555 }
1556 return TRUE;
1557}
1558
1559WINPR_ATTR_NODISCARD
1560static BOOL shadow_client_send_progressive(rdpShadowClient* client, const BYTE* pSrcData,
1561 UINT32 nSrcStep, UINT32 SrcFormat, UINT16 nWidth,
1562 UINT16 nHeight, RDPGFX_SURFACE_COMMAND* cmd,
1563 const RDPGFX_START_FRAME_PDU* cmdstart,
1564 const RDPGFX_END_FRAME_PDU* cmdend)
1565{
1566 WINPR_ASSERT(client);
1567
1568 rdpShadowEncoder* encoder = client->encoder;
1569 WINPR_ASSERT(encoder);
1570
1571 UINT error = CHANNEL_RC_OK;
1572 INT32 rc = 0;
1573 REGION16 region;
1574 RECTANGLE_16 regionRect;
1575
1576 if (shadow_encoder_prepare(encoder, FREERDP_CODEC_PROGRESSIVE) < 0)
1577 {
1578 WLog_ERR(TAG, "Failed to prepare encoder FREERDP_CODEC_PROGRESSIVE");
1579 return FALSE;
1580 }
1581
1582 WINPR_ASSERT(cmd->left <= UINT16_MAX);
1583 WINPR_ASSERT(cmd->top <= UINT16_MAX);
1584 WINPR_ASSERT(cmd->right <= UINT16_MAX);
1585 WINPR_ASSERT(cmd->bottom <= UINT16_MAX);
1586 regionRect.left = (UINT16)cmd->left;
1587 regionRect.top = (UINT16)cmd->top;
1588 regionRect.right = (UINT16)cmd->right;
1589 regionRect.bottom = (UINT16)cmd->bottom;
1590 region16_init(&region);
1591 if (!region16_union_rect(&region, &region, &regionRect))
1592 {
1593 region16_uninit(&region);
1594 return FALSE;
1595 }
1596 rc = progressive_compress(encoder->progressive, pSrcData, nSrcStep * nHeight, SrcFormat, nWidth,
1597 nHeight, nSrcStep, &region, &cmd->data, &cmd->length);
1598 region16_uninit(&region);
1599 if (rc < 0)
1600 {
1601 WLog_ERR(TAG, "progressive_compress failed");
1602 return FALSE;
1603 }
1604
1605 /* rc > 0 means new data */
1606 if (rc > 0)
1607 {
1608 cmd->codecId = RDPGFX_CODECID_CAPROGRESSIVE;
1609
1610 IFCALLRET(client->rdpgfx->SurfaceFrameCommand, error, client->rdpgfx, cmd, cmdstart,
1611 cmdend);
1612 }
1613 cmd->data = nullptr;
1614
1615 if (error)
1616 {
1617 WLog_ERR(TAG, "SurfaceFrameCommand failed with error %" PRIu32 "", error);
1618 return FALSE;
1619 }
1620 return TRUE;
1621}
1622
1623WINPR_ATTR_NODISCARD
1624static BOOL shadow_client_send_planar(rdpShadowClient* client, const BYTE* pSrcData,
1625 UINT32 nSrcStep, UINT32 SrcFormat,
1627 const RDPGFX_START_FRAME_PDU* cmdstart,
1628 const RDPGFX_END_FRAME_PDU* cmdend)
1629{
1630 WINPR_ASSERT(client);
1631
1632 rdpShadowEncoder* encoder = client->encoder;
1633 WINPR_ASSERT(encoder);
1634
1635 UINT error = CHANNEL_RC_OK;
1636 const UINT32 w = cmd->right - cmd->left;
1637 const UINT32 h = cmd->bottom - cmd->top;
1638 const BYTE* src =
1639 &pSrcData[cmd->top * nSrcStep + cmd->left * FreeRDPGetBytesPerPixel(SrcFormat)];
1640 if (shadow_encoder_prepare(encoder, FREERDP_CODEC_PLANAR) < 0)
1641 {
1642 WLog_ERR(TAG, "Failed to prepare encoder FREERDP_CODEC_PLANAR");
1643 return FALSE;
1644 }
1645
1646 const BOOL rc = freerdp_bitmap_planar_context_reset(encoder->planar, w, h);
1647 if (!rc)
1648 return FALSE;
1649
1650 freerdp_planar_topdown_image(encoder->planar, TRUE);
1651
1652 cmd->data = freerdp_bitmap_compress_planar(encoder->planar, src, SrcFormat, w, h, nSrcStep,
1653 nullptr, &cmd->length);
1654 WINPR_ASSERT(cmd->data || (cmd->length == 0));
1655
1656 cmd->codecId = RDPGFX_CODECID_PLANAR;
1657
1658 IFCALLRET(client->rdpgfx->SurfaceFrameCommand, error, client->rdpgfx, cmd, cmdstart, cmdend);
1659 free(cmd->data);
1660 cmd->data = nullptr;
1661
1662 if (error)
1663 {
1664 WLog_ERR(TAG, "SurfaceFrameCommand failed with error %" PRIu32 "", error);
1665 return FALSE;
1666 }
1667 return TRUE;
1668}
1669
1670WINPR_ATTR_NODISCARD
1671static BOOL shadow_client_send_uncompressed(rdpShadowClient* client, const BYTE* pSrcData,
1672 UINT32 nSrcStep, UINT32 SrcFormat,
1674 const RDPGFX_START_FRAME_PDU* cmdstart,
1675 const RDPGFX_END_FRAME_PDU* cmdend)
1676{
1677 WINPR_ASSERT(client);
1678 WINPR_ASSERT(cmd);
1679 WINPR_ASSERT(pSrcData);
1680 WINPR_ASSERT(cmdstart);
1681 WINPR_ASSERT(cmdend);
1682
1683 UINT error = CHANNEL_RC_OK;
1684
1685 WINPR_ASSERT(cmd->right >= cmd->left);
1686 WINPR_ASSERT(cmd->bottom >= cmd->top);
1687
1688 const UINT32 w = cmd->right - cmd->left;
1689 const UINT32 h = cmd->bottom - cmd->top;
1690 if ((w == 0) || (h == 0) || (w > UINT32_MAX / 4 / h))
1691 {
1692 WLog_ERR(TAG, "input width=%" PRIu32 " x height=%" PRIu32 " is 0 or exceeds UINT32_MAX", w,
1693 h);
1694 return FALSE;
1695 }
1696 const UINT32 length = w * 4ul * h;
1697
1698 if (length == 0)
1699 {
1700 WLog_ERR(TAG, "input length == 0");
1701 return FALSE;
1702 }
1703
1704 BYTE* data = malloc(length);
1705 if (!data)
1706 return FALSE;
1707
1708 BOOL rc = freerdp_image_copy_no_overlap(data, cmd->format, 0, 0, 0, w, h, pSrcData, SrcFormat,
1709 nSrcStep, cmd->left, cmd->top, nullptr, 0);
1710 if (!rc)
1711 {
1712 free(data);
1713 return FALSE;
1714 }
1715
1716 cmd->data = data;
1717 cmd->length = length;
1718 cmd->codecId = RDPGFX_CODECID_UNCOMPRESSED;
1719
1720 IFCALLRET(client->rdpgfx->SurfaceFrameCommand, error, client->rdpgfx, cmd, cmdstart, cmdend);
1721 free(data);
1722 cmd->data = nullptr;
1723 if (error)
1724 {
1725 WLog_ERR(TAG, "SurfaceFrameCommand failed with error %" PRIu32 "", error);
1726 return FALSE;
1727 }
1728 return TRUE;
1729}
1730
1731WINPR_ATTR_NODISCARD
1732static BOOL shadow_avc444_enabled(const rdpShadowClient* client)
1733{
1734 WINPR_ASSERT(client);
1735 switch (client->confirmedCaps.version)
1736 {
1737 case RDPGFX_CAPVERSION_10:
1738 case RDPGFX_CAPVERSION_101:
1739 case RDPGFX_CAPVERSION_102:
1740 case RDPGFX_CAPVERSION_103:
1741 case RDPGFX_CAPVERSION_104:
1742 case RDPGFX_CAPVERSION_105:
1743 case RDPGFX_CAPVERSION_106:
1744 case RDPGFX_CAPVERSION_107:
1745#if defined(WITH_GFX_AZURE)
1746 case RDPGFX_CAPVERSION_111:
1747 case RDPGFX_CAPVERSION_112:
1748 case RDPGFX_CAPVERSION_113:
1749 case RDPGFX_CAPVERSION_115:
1750#endif
1751 return (client->confirmedCaps.flags & RDPGFX_CAPS_FLAG_AVC_DISABLED) == 0;
1752
1753 default:
1754 return FALSE;
1755 }
1756}
1757
1758WINPR_ATTR_NODISCARD
1759static BOOL shadow_avc420_enabled(const rdpShadowClient* client)
1760{
1761 if (shadow_avc444_enabled(client))
1762 return TRUE;
1763 if (client->confirmedCaps.version != RDPGFX_CAPVERSION_81)
1764 return FALSE;
1765 return (client->confirmedCaps.flags & RDPGFX_CAPS_FLAG_AVC420_ENABLED) != 0;
1766}
1767
1773WINPR_ATTR_NODISCARD
1774static BOOL shadow_client_send_surface_gfx(rdpShadowClient* client, const BYTE* pSrcData,
1775 UINT32 nSrcStep, UINT32 SrcFormat, UINT16 nXSrc,
1776 UINT16 nYSrc, UINT16 nWidth, UINT16 nHeight,
1777 UINT16 srcWidth, UINT16 srcHeight,
1778 const RECTANGLE_16* damage)
1779{
1780 const rdpContext* context = (const rdpContext*)client;
1781 RDPGFX_SURFACE_COMMAND cmd = WINPR_C_ARRAY_INIT;
1782 RDPGFX_START_FRAME_PDU cmdstart = WINPR_C_ARRAY_INIT;
1783 RDPGFX_END_FRAME_PDU cmdend = WINPR_C_ARRAY_INIT;
1784 SYSTEMTIME sTime = WINPR_C_ARRAY_INIT;
1785
1786 if (!context || !pSrcData || !damage)
1787 return FALSE;
1788
1789 const rdpSettings* settings = context->settings;
1790 rdpShadowEncoder* encoder = client->encoder;
1791
1792 if (!settings || !encoder)
1793 return FALSE;
1794
1795 if (client->first_frame)
1796 {
1797 if (encoder->rfx)
1798 {
1799 if (!rfx_context_reset(encoder->rfx, nWidth, nHeight))
1800 return FALSE;
1801 }
1802 /* After ResetGraphics the client surface has no dependable state:
1803 * invalidate the RFX dirty skip snapshot so the next frame is
1804 * encoded in full. */
1805 shadow_rfx_invalidate_snapshot(encoder);
1806 client->first_frame = FALSE;
1807 }
1808
1809 cmdstart.frameId = shadow_encoder_create_frame_id(encoder);
1810 GetSystemTime(&sTime);
1811 cmdstart.timestamp = (UINT32)(sTime.wHour << 22U | sTime.wMinute << 16U | sTime.wSecond << 10U |
1812 sTime.wMilliseconds);
1813 cmdend.frameId = cmdstart.frameId;
1814 cmd.surfaceId = client->surfaceId;
1815 cmd.format = PIXEL_FORMAT_BGRX32;
1816 cmd.left = nXSrc;
1817 cmd.top = nYSrc;
1818 cmd.right = cmd.left + nWidth;
1819 cmd.bottom = cmd.top + nHeight;
1820 cmd.width = nWidth;
1821 cmd.height = nHeight;
1822
1823#if defined(WITH_GFX_AV1)
1824 if (shadow_client_av1_enabled(client))
1825 {
1826 return shadow_client_send_av1(client, pSrcData, nSrcStep, SrcFormat, nWidth, nHeight,
1827 damage, &cmd, &cmdstart, &cmdend);
1828 }
1829#endif
1830
1831 const UINT32 id = freerdp_settings_get_uint32(settings, FreeRDP_RemoteFxCodecId);
1832#ifdef WITH_GFX_H264
1833 const BOOL GfxH264 = freerdp_settings_get_bool(settings, FreeRDP_GfxH264);
1834 const BOOL GfxAVC444 = freerdp_settings_get_bool(settings, FreeRDP_GfxAVC444);
1835 const BOOL GfxAVC444v2 = freerdp_settings_get_bool(settings, FreeRDP_GfxAVC444v2);
1836 if (GfxAVC444 || GfxAVC444v2)
1837 {
1838 if (shadow_avc444_enabled(client))
1839 {
1840 cmd.codecId = GfxAVC444v2 ? RDPGFX_CODECID_AVC444v2 : RDPGFX_CODECID_AVC444;
1841 return shadow_client_send_avc444(client, pSrcData, nSrcStep, SrcFormat, nWidth, nHeight,
1842 &cmd, &cmdstart, &cmdend);
1843 }
1844 }
1845
1846 if (GfxH264 && shadow_avc420_enabled(client))
1847 {
1848 return shadow_client_send_avc420(client, pSrcData, nSrcStep, SrcFormat, nWidth, nHeight,
1849 &cmd, &cmdstart, &cmdend);
1850 }
1851
1852#endif
1853 if (freerdp_settings_get_bool(settings, FreeRDP_RemoteFxCodec) && (id != 0))
1854 {
1855 /* The RFX source image dims must be the whole surface: the tile grid
1856 * is aligned to absolute surface coordinates and edge tiles are
1857 * truncated at the surface bounds. */
1858 return shadow_client_send_rfx(client, pSrcData, nSrcStep, SrcFormat, srcWidth, srcHeight,
1859 &cmd, &cmdstart, &cmdend);
1860 }
1861
1862 if (freerdp_settings_get_bool(settings, FreeRDP_GfxProgressive))
1863 {
1864 return shadow_client_send_progressive(client, pSrcData, nSrcStep, SrcFormat, nWidth,
1865 nHeight, &cmd, &cmdstart, &cmdend);
1866 }
1867
1868 if (freerdp_settings_get_bool(settings, FreeRDP_GfxPlanar))
1869 {
1870 return shadow_client_send_planar(client, pSrcData, nSrcStep, SrcFormat, &cmd, &cmdstart,
1871 &cmdend);
1872 }
1873
1874 return shadow_client_send_uncompressed(client, pSrcData, nSrcStep, SrcFormat, &cmd, &cmdstart,
1875 &cmdend);
1876}
1877
1878WINPR_ATTR_NODISCARD
1879static BOOL stream_surface_bits_supported(const rdpSettings* settings)
1880{
1881 const UINT32 supported =
1882 freerdp_settings_get_uint32(settings, FreeRDP_SurfaceCommandsSupported);
1883 return ((supported & SURFCMDS_STREAM_SURFACE_BITS) != 0);
1884}
1885
1886WINPR_ATTR_NODISCARD
1887static BOOL set_surface_bits_supported(const rdpSettings* settings)
1888{
1889 const UINT32 supported =
1890 freerdp_settings_get_uint32(settings, FreeRDP_SurfaceCommandsSupported);
1891 return ((supported & SURFCMDS_SET_SURFACE_BITS) != 0);
1892}
1893
1894WINPR_ATTR_NODISCARD
1895static BOOL is_surface_command_supported(const rdpSettings* settings)
1896{
1897 if (stream_surface_bits_supported(settings))
1898 {
1899 const UINT32 rfxID = freerdp_settings_get_uint32(settings, FreeRDP_RemoteFxCodecId);
1900 const BOOL supported = freerdp_settings_get_bool(settings, FreeRDP_RemoteFxCodec);
1901 if (supported && (rfxID != 0))
1902 return TRUE;
1903 }
1904 if (set_surface_bits_supported(settings))
1905 {
1906 const UINT32 nsID = freerdp_settings_get_uint32(settings, FreeRDP_NSCodecId);
1907 const BOOL supported = freerdp_settings_get_bool(settings, FreeRDP_NSCodec);
1908 if (supported && (nsID != 0))
1909 return TRUE;
1910 }
1911 return FALSE;
1912}
1913
1919WINPR_ATTR_NODISCARD
1920static BOOL shadow_client_send_surface_bits(rdpShadowClient* client, BYTE* pSrcData,
1921 UINT32 nSrcStep, UINT16 nXSrc, UINT16 nYSrc,
1922 UINT16 nWidth, UINT16 nHeight)
1923{
1924 BOOL ret = TRUE;
1925 BOOL first = 0;
1926 BOOL last = 0;
1927 wStream* s = nullptr;
1928 size_t numMessages = 0;
1929 UINT32 frameId = 0;
1930 rdpUpdate* update = nullptr;
1931 rdpContext* context = (rdpContext*)client;
1932 rdpSettings* settings = nullptr;
1933 rdpShadowEncoder* encoder = nullptr;
1934 SURFACE_BITS_COMMAND cmd = WINPR_C_ARRAY_INIT;
1935
1936 if (!context || !pSrcData)
1937 return FALSE;
1938
1939 update = context->update;
1940 settings = context->settings;
1941 encoder = client->encoder;
1942
1943 if (!update || !settings || !encoder)
1944 return FALSE;
1945
1946 if (encoder->frameAck)
1947 frameId = shadow_encoder_create_frame_id(encoder);
1948
1949 // TODO: Check FreeRDP_RemoteFxCodecMode if we should send RFX IMAGE or VIDEO data
1950 const UINT32 nsID = freerdp_settings_get_uint32(settings, FreeRDP_NSCodecId);
1951 const UINT32 rfxID = freerdp_settings_get_uint32(settings, FreeRDP_RemoteFxCodecId);
1952 if (stream_surface_bits_supported(settings) &&
1953 freerdp_settings_get_bool(settings, FreeRDP_RemoteFxCodec) && (rfxID != 0))
1954 {
1955 RFX_RECT rect = WINPR_C_ARRAY_INIT;
1956
1957 if (shadow_encoder_prepare(encoder, FREERDP_CODEC_REMOTEFX) < 0)
1958 {
1959 WLog_ERR(TAG, "Failed to prepare encoder FREERDP_CODEC_REMOTEFX");
1960 return FALSE;
1961 }
1962
1963 s = encoder->bs;
1964 rect.x = nXSrc;
1965 rect.y = nYSrc;
1966 rect.width = nWidth;
1967 rect.height = nHeight;
1968
1969 const UINT32 MultifragMaxRequestSize =
1970 freerdp_settings_get_uint32(settings, FreeRDP_MultifragMaxRequestSize);
1971 RFX_MESSAGE_LIST* messages =
1972 rfx_encode_messages(encoder->rfx, &rect, 1, pSrcData,
1973 freerdp_settings_get_uint32(settings, FreeRDP_DesktopWidth),
1974 freerdp_settings_get_uint32(settings, FreeRDP_DesktopHeight),
1975 nSrcStep, &numMessages, MultifragMaxRequestSize);
1976 if (!messages)
1977 {
1978 WLog_ERR(TAG, "rfx_encode_messages failed");
1979 return FALSE;
1980 }
1981
1982 cmd.cmdType = CMDTYPE_STREAM_SURFACE_BITS;
1983 WINPR_ASSERT(rfxID <= UINT16_MAX);
1984 cmd.bmp.codecID = (UINT16)rfxID;
1985 cmd.destLeft = 0;
1986 cmd.destTop = 0;
1987 cmd.destRight = freerdp_settings_get_uint32(settings, FreeRDP_DesktopWidth);
1988 cmd.destBottom = freerdp_settings_get_uint32(settings, FreeRDP_DesktopHeight);
1989 cmd.bmp.bpp = 32;
1990 cmd.bmp.flags = 0;
1991 WINPR_ASSERT(freerdp_settings_get_uint32(settings, FreeRDP_DesktopWidth) <= UINT16_MAX);
1992 WINPR_ASSERT(freerdp_settings_get_uint32(settings, FreeRDP_DesktopHeight) <= UINT16_MAX);
1993 cmd.bmp.width = (UINT16)freerdp_settings_get_uint32(settings, FreeRDP_DesktopWidth);
1994 cmd.bmp.height = (UINT16)freerdp_settings_get_uint32(settings, FreeRDP_DesktopHeight);
1995 cmd.skipCompression = TRUE;
1996
1997 for (size_t i = 0; i < numMessages; i++)
1998 {
1999 Stream_ResetPosition(s);
2000
2001 const RFX_MESSAGE* msg = rfx_message_list_get(messages, i);
2002 if (!rfx_write_message(encoder->rfx, s, msg))
2003 {
2004 WLog_ERR(TAG, "rfx_write_message failed");
2005 ret = FALSE;
2006 break;
2007 }
2008
2009 cmd.bmp.bitmapDataLength = WINPR_ASSERTING_INT_CAST(UINT32, Stream_GetPosition(s));
2010 cmd.bmp.bitmapData = Stream_Buffer(s);
2011 first = (i == 0);
2012 last = ((i + 1) == numMessages);
2013
2014 if (!encoder->frameAck)
2015 IFCALLRET(update->SurfaceBits, ret, update->context, &cmd);
2016 else
2017 IFCALLRET(update->SurfaceFrameBits, ret, update->context, &cmd, first, last,
2018 frameId);
2019
2020 if (!ret)
2021 {
2022 WLog_ERR(TAG, "Send surface bits(RemoteFxCodec) failed");
2023 break;
2024 }
2025 }
2026
2027 rfx_message_list_free(messages);
2028 }
2029 else if (set_surface_bits_supported(settings) &&
2030 freerdp_settings_get_bool(settings, FreeRDP_NSCodec) && (nsID != 0))
2031 {
2032 if (shadow_encoder_prepare(encoder, FREERDP_CODEC_NSCODEC) < 0)
2033 {
2034 WLog_ERR(TAG, "Failed to prepare encoder FREERDP_CODEC_NSCODEC");
2035 return FALSE;
2036 }
2037
2038 s = encoder->bs;
2039 Stream_ResetPosition(s);
2040 pSrcData = &pSrcData[(nYSrc * nSrcStep) + (nXSrc * 4)];
2041 if (!nsc_compose_message(encoder->nsc, s, pSrcData, nWidth, nHeight, nSrcStep))
2042 return FALSE;
2043
2044 cmd.cmdType = CMDTYPE_SET_SURFACE_BITS;
2045 cmd.bmp.bpp = 32;
2046 WINPR_ASSERT(nsID <= UINT16_MAX);
2047 cmd.bmp.codecID = (UINT16)nsID;
2048 cmd.destLeft = nXSrc;
2049 cmd.destTop = nYSrc;
2050 cmd.destRight = cmd.destLeft + nWidth;
2051 cmd.destBottom = cmd.destTop + nHeight;
2052 cmd.bmp.width = nWidth;
2053 cmd.bmp.height = nHeight;
2054
2055 cmd.bmp.bitmapDataLength = WINPR_ASSERTING_INT_CAST(UINT32, Stream_GetPosition(s));
2056 cmd.bmp.bitmapData = Stream_Buffer(s);
2057 first = TRUE;
2058 last = TRUE;
2059
2060 if (!encoder->frameAck)
2061 IFCALLRET(update->SurfaceBits, ret, update->context, &cmd);
2062 else
2063 IFCALLRET(update->SurfaceFrameBits, ret, update->context, &cmd, first, last, frameId);
2064
2065 if (!ret)
2066 {
2067 WLog_ERR(TAG, "Send surface bits(NSCodec) failed");
2068 }
2069 }
2070
2071 return ret;
2072}
2073
2079WINPR_ATTR_NODISCARD
2080static BOOL shadow_client_send_bitmap_update(rdpShadowClient* client, BYTE* pSrcData,
2081 UINT32 nSrcStep, UINT16 nXSrc, UINT16 nYSrc,
2082 UINT16 nWidth, UINT16 nHeight)
2083{
2084 BOOL ret = TRUE;
2085 BYTE* data = nullptr;
2086 BYTE* buffer = nullptr;
2087 UINT32 k = 0;
2088 UINT32 yIdx = 0;
2089 UINT32 xIdx = 0;
2090 UINT32 rows = 0;
2091 UINT32 cols = 0;
2092 UINT32 DstSize = 0;
2093 UINT32 SrcFormat = 0;
2094 BITMAP_DATA* bitmap = nullptr;
2095 rdpContext* context = (rdpContext*)client;
2096 UINT32 totalBitmapSize = 0;
2097 UINT32 updateSizeEstimate = 0;
2098 BITMAP_DATA* bitmapData = nullptr;
2099 BITMAP_UPDATE bitmapUpdate = WINPR_C_ARRAY_INIT;
2100
2101 if (!context || !pSrcData)
2102 return FALSE;
2103
2104 rdpUpdate* update = context->update;
2105 rdpSettings* settings = context->settings;
2106 rdpShadowEncoder* encoder = client->encoder;
2107
2108 if (!update || !settings || !encoder)
2109 return FALSE;
2110
2111 const UINT32 maxUpdateSize =
2112 freerdp_settings_get_uint32(settings, FreeRDP_MultifragMaxRequestSize);
2113 if (freerdp_settings_get_uint32(settings, FreeRDP_ColorDepth) < 32)
2114 {
2115 if (shadow_encoder_prepare(encoder, FREERDP_CODEC_INTERLEAVED) < 0)
2116 {
2117 WLog_ERR(TAG, "Failed to prepare encoder FREERDP_CODEC_INTERLEAVED");
2118 return FALSE;
2119 }
2120 }
2121 else
2122 {
2123 if (shadow_encoder_prepare(encoder, FREERDP_CODEC_PLANAR) < 0)
2124 {
2125 WLog_ERR(TAG, "Failed to prepare encoder FREERDP_CODEC_PLANAR");
2126 return FALSE;
2127 }
2128 }
2129
2130 SrcFormat = PIXEL_FORMAT_BGRX32;
2131
2132 if ((nXSrc % 4) != 0)
2133 {
2134 nWidth += (nXSrc % 4);
2135 nXSrc -= (nXSrc % 4);
2136 }
2137
2138 if ((nYSrc % 4) != 0)
2139 {
2140 nHeight += (nYSrc % 4);
2141 nYSrc -= (nYSrc % 4);
2142 }
2143
2144 rows = (nHeight / 64) + ((nHeight % 64) ? 1 : 0);
2145 cols = (nWidth / 64) + ((nWidth % 64) ? 1 : 0);
2146 k = 0;
2147 totalBitmapSize = 0;
2148 bitmapUpdate.number = rows * cols;
2149
2150 if (!(bitmapData = (BITMAP_DATA*)calloc(bitmapUpdate.number, sizeof(BITMAP_DATA))))
2151 return FALSE;
2152
2153 bitmapUpdate.rectangles = bitmapData;
2154
2155 if ((nWidth % 4) != 0)
2156 {
2157 nWidth += (4 - (nWidth % 4));
2158 }
2159
2160 if ((nHeight % 4) != 0)
2161 {
2162 nHeight += (4 - (nHeight % 4));
2163 }
2164
2165 for (yIdx = 0; yIdx < rows; yIdx++)
2166 {
2167 for (xIdx = 0; xIdx < cols; xIdx++)
2168 {
2169 bitmap = &bitmapData[k];
2170 bitmap->width = 64;
2171 bitmap->height = 64;
2172 bitmap->destLeft = nXSrc + (xIdx * 64);
2173 bitmap->destTop = nYSrc + (yIdx * 64);
2174
2175 if (((INT64)bitmap->destLeft + bitmap->width) > (nXSrc + nWidth))
2176 bitmap->width = (UINT32)(nXSrc + nWidth) - bitmap->destLeft;
2177
2178 if (((INT64)bitmap->destTop + bitmap->height) > (nYSrc + nHeight))
2179 bitmap->height = (UINT32)(nYSrc + nHeight) - bitmap->destTop;
2180
2181 bitmap->destRight = bitmap->destLeft + bitmap->width - 1;
2182 bitmap->destBottom = bitmap->destTop + bitmap->height - 1;
2183 bitmap->compressed = TRUE;
2184
2185 if ((bitmap->width < 4) || (bitmap->height < 4))
2186 continue;
2187
2188 if (freerdp_settings_get_uint32(settings, FreeRDP_ColorDepth) < 32)
2189 {
2190 UINT32 bitsPerPixel = freerdp_settings_get_uint32(settings, FreeRDP_ColorDepth);
2191 UINT32 bytesPerPixel = (bitsPerPixel + 7) / 8;
2192 DstSize = 64 * 64 * 4;
2193 buffer = encoder->grid[k];
2194
2195 ret = interleaved_compress(
2196 encoder->interleaved, buffer, &DstSize, bitmap->width, bitmap->height, pSrcData,
2197 SrcFormat, nSrcStep, bitmap->destLeft, bitmap->destTop, nullptr, bitsPerPixel);
2198 if (!ret)
2199 goto out;
2200 bitmap->bitmapDataStream = buffer;
2201 bitmap->bitmapLength = DstSize;
2202 bitmap->bitsPerPixel = bitsPerPixel;
2203 bitmap->cbScanWidth = bitmap->width * bytesPerPixel;
2204 bitmap->cbUncompressedSize = bitmap->width * bitmap->height * bytesPerPixel;
2205 }
2206 else
2207 {
2208 UINT32 dstSize = 0;
2209 buffer = encoder->grid[k];
2210 data = &pSrcData[(bitmap->destTop * nSrcStep) + (bitmap->destLeft * 4)];
2211
2212 buffer =
2213 freerdp_bitmap_compress_planar(encoder->planar, data, SrcFormat, bitmap->width,
2214 bitmap->height, nSrcStep, buffer, &dstSize);
2215 bitmap->bitmapDataStream = buffer;
2216 bitmap->bitmapLength = dstSize;
2217 bitmap->bitsPerPixel = 32;
2218 bitmap->cbScanWidth = bitmap->width * 4;
2219 bitmap->cbUncompressedSize = bitmap->width * bitmap->height * 4;
2220 }
2221
2222 bitmap->cbCompFirstRowSize = 0;
2223 bitmap->cbCompMainBodySize = bitmap->bitmapLength;
2224 totalBitmapSize += bitmap->bitmapLength;
2225 k++;
2226 }
2227 }
2228
2229 bitmapUpdate.number = k;
2230 updateSizeEstimate = totalBitmapSize + (k * bitmapUpdate.number) + 16;
2231
2232 if (updateSizeEstimate > maxUpdateSize)
2233 {
2234 UINT32 i = 0;
2235 UINT32 j = 0;
2236 UINT32 updateSize = 0;
2237 UINT32 newUpdateSize = 0;
2238 BITMAP_DATA* fragBitmapData = nullptr;
2239
2240 if (k > 0)
2241 fragBitmapData = (BITMAP_DATA*)calloc(k, sizeof(BITMAP_DATA));
2242
2243 if (!fragBitmapData)
2244 {
2245 WLog_ERR(TAG, "Failed to allocate memory for fragBitmapData");
2246 ret = FALSE;
2247 goto out;
2248 }
2249
2250 bitmapUpdate.rectangles = fragBitmapData;
2251 i = j = 0;
2252 updateSize = 1024;
2253
2254 while (i < k)
2255 {
2256 newUpdateSize = updateSize + (bitmapData[i].bitmapLength + 16);
2257
2258 if (newUpdateSize < maxUpdateSize)
2259 {
2260 CopyMemory(&fragBitmapData[j++], &bitmapData[i++], sizeof(BITMAP_DATA));
2261 updateSize = newUpdateSize;
2262 }
2263
2264 if ((newUpdateSize >= maxUpdateSize) || (i + 1) >= k)
2265 {
2266 bitmapUpdate.number = j;
2267 ret = BitmapUpdateProxy(client, &bitmapUpdate);
2268
2269 if (!ret)
2270 break;
2271
2272 updateSize = 1024;
2273 j = 0;
2274 }
2275 }
2276
2277 free(fragBitmapData);
2278 }
2279 else
2280 {
2281 ret = BitmapUpdateProxy(client, &bitmapUpdate);
2282 }
2283
2284out:
2285 free(bitmapData);
2286 return ret;
2287}
2288
2294WINPR_ATTR_NODISCARD
2295static BOOL shadow_client_send_surface_update(rdpShadowClient* client, SHADOW_GFX_STATUS* pStatus)
2296{
2297 BOOL ret = TRUE;
2298 INT64 nXSrc = 0;
2299 INT64 nYSrc = 0;
2300 INT64 nWidth = 0;
2301 INT64 nHeight = 0;
2302 rdpContext* context = (rdpContext*)client;
2303 rdpSettings* settings = nullptr;
2304 rdpShadowServer* server = nullptr;
2305 rdpShadowSurface* surface = nullptr;
2306 REGION16 invalidRegion;
2307 RECTANGLE_16 surfaceRect;
2308 const RECTANGLE_16* extents = nullptr;
2309 BYTE* pSrcData = nullptr;
2310 UINT32 nSrcStep = 0;
2311 UINT32 SrcFormat = 0;
2312 UINT32 numRects = 0;
2313 const RECTANGLE_16* rects = nullptr;
2314
2315 if (!context || !pStatus)
2316 return FALSE;
2317
2318 settings = context->settings;
2319 server = client->server;
2320
2321 if (!settings || !server)
2322 return FALSE;
2323
2324 surface = client->inLobby ? server->lobby : server->surface;
2325
2326 if (!surface)
2327 return FALSE;
2328
2329 {
2330 EnterCriticalSection(&(client->lock));
2331 region16_init(&invalidRegion);
2332
2333 const BOOL res = region16_copy(&invalidRegion, &(client->invalidRegion));
2334 region16_clear(&(client->invalidRegion));
2335 LeaveCriticalSection(&(client->lock));
2336 if (!res)
2337 goto out;
2338 }
2339
2340 EnterCriticalSection(&surface->lock);
2341 rects = region16_rects(&(surface->invalidRegion), &numRects);
2342
2343 for (UINT32 index = 0; index < numRects; index++)
2344 {
2345 if (!region16_union_rect(&invalidRegion, &invalidRegion, &rects[index]))
2346 goto out;
2347 }
2348
2349 surfaceRect.left = 0;
2350 surfaceRect.top = 0;
2351 WINPR_ASSERT(surface->width <= UINT16_MAX);
2352 WINPR_ASSERT(surface->height <= UINT16_MAX);
2353 surfaceRect.right = (UINT16)surface->width;
2354 surfaceRect.bottom = (UINT16)surface->height;
2355 if (!region16_intersect_rect(&invalidRegion, &invalidRegion, &surfaceRect))
2356 goto out;
2357
2358 if (server->shareSubRect)
2359 {
2360 if (!region16_intersect_rect(&invalidRegion, &invalidRegion, &(server->subRect)))
2361 goto out;
2362 }
2363
2364 if (region16_is_empty(&invalidRegion))
2365 {
2366 /* No image region need to be updated. Success */
2367 goto out;
2368 }
2369
2370 extents = region16_extents(&invalidRegion);
2371 nXSrc = extents->left;
2372 nYSrc = extents->top;
2373 nWidth = extents->right - extents->left;
2374 nHeight = extents->bottom - extents->top;
2375 pSrcData = surface->data;
2376 nSrcStep = surface->scanline;
2377 SrcFormat = surface->format;
2378
2379 /* Move to new pSrcData / nXSrc / nYSrc according to sub rect */
2380 if (server->shareSubRect)
2381 {
2382 INT32 subX = 0;
2383 INT32 subY = 0;
2384 subX = server->subRect.left;
2385 subY = server->subRect.top;
2386 nXSrc -= subX;
2387 nYSrc -= subY;
2388 WINPR_ASSERT(nXSrc >= 0);
2389 WINPR_ASSERT(nXSrc <= UINT16_MAX);
2390 WINPR_ASSERT(nYSrc >= 0);
2391 WINPR_ASSERT(nYSrc <= UINT16_MAX);
2392 pSrcData = &pSrcData[((UINT16)subY * nSrcStep) + ((UINT16)subX * 4U)];
2393 }
2394
2395 // WLog_INFO(TAG, "shadow_client_send_surface_update: x: %" PRId64 " y: %" PRId64 " width: %"
2396 // PRId64 " height: %" PRId64 " right: %" PRId64 " bottom: %" PRId64, nXSrc, nYSrc, nWidth,
2397 // nHeight, nXSrc + nWidth, nYSrc + nHeight);
2398
2399 if (freerdp_settings_get_bool(settings, FreeRDP_SupportGraphicsPipeline))
2400 {
2401 if (pStatus->gfxOpened && client->areGfxCapsReady)
2402 {
2403 /* Only codecs that need constant full-frame dimensions (SPS/PPS
2404 * bind the resolution, AV1 the sequence header) must encode the
2405 * whole desktop. rfx and progressive interpret nWidth/nHeight as
2406 * source image dims with the cmd rect as the dirty region, and
2407 * planar/uncompressed encode the cmd rect directly, so those may
2408 * keep the dirty extents. */
2409 const RECTANGLE_16 damage = { .left = WINPR_ASSERTING_INT_CAST(UINT16, nXSrc),
2410 .top = WINPR_ASSERTING_INT_CAST(UINT16, nYSrc),
2411 .right = WINPR_ASSERTING_INT_CAST(UINT16, nXSrc + nWidth),
2412 .bottom =
2413 WINPR_ASSERTING_INT_CAST(UINT16, nYSrc + nHeight) };
2414 const BOOL fullframegfx =
2415#if defined(WITH_GFX_AV1)
2416 shadow_client_av1_enabled(client) ||
2417#endif
2418 freerdp_settings_get_bool(settings, FreeRDP_GfxH264) ||
2419 freerdp_settings_get_bool(settings, FreeRDP_GfxAVC444) ||
2420 freerdp_settings_get_bool(settings, FreeRDP_GfxAVC444v2) ||
2421 (freerdp_settings_get_bool(settings, FreeRDP_RemoteFxCodec) &&
2422 (freerdp_settings_get_uint32(settings, FreeRDP_RemoteFxCodecId) != 0)) ||
2423 freerdp_settings_get_bool(settings, FreeRDP_GfxProgressive);
2424 if (fullframegfx)
2425 {
2426 nWidth = freerdp_settings_get_uint32(settings, FreeRDP_DesktopWidth);
2427 nHeight = freerdp_settings_get_uint32(settings, FreeRDP_DesktopHeight);
2428 }
2429
2430 /* Create primary surface if have not */
2431 if (!pStatus->gfxSurfaceCreated)
2432 {
2433 /* Only init surface when we have h264 supported */
2434 if (!(ret = shadow_client_rdpgfx_reset_graphic(client)))
2435 goto out;
2436
2437 if (!(ret = shadow_client_rdpgfx_new_surface(client)))
2438 goto out;
2439
2440 pStatus->gfxSurfaceCreated = TRUE;
2441 }
2442
2443 WINPR_ASSERT(nWidth >= 0);
2444 WINPR_ASSERT(nWidth <= UINT16_MAX);
2445 WINPR_ASSERT(nHeight >= 0);
2446 WINPR_ASSERT(nHeight <= UINT16_MAX);
2447 ret = shadow_client_send_surface_gfx(
2448 client, pSrcData, nSrcStep, SrcFormat, fullframegfx ? 0 : (UINT16)nXSrc,
2449 fullframegfx ? 0 : (UINT16)nYSrc, (UINT16)nWidth, (UINT16)nHeight,
2450 (UINT16)surface->width, (UINT16)surface->height, &damage);
2451 }
2452 else
2453 {
2454 ret = TRUE;
2455 }
2456 }
2457 else if (is_surface_command_supported(settings))
2458 {
2459 WINPR_ASSERT(nXSrc >= 0);
2460 WINPR_ASSERT(nXSrc <= UINT16_MAX);
2461 WINPR_ASSERT(nYSrc >= 0);
2462 WINPR_ASSERT(nYSrc <= UINT16_MAX);
2463 WINPR_ASSERT(nWidth >= 0);
2464 WINPR_ASSERT(nWidth <= UINT16_MAX);
2465 WINPR_ASSERT(nHeight >= 0);
2466 WINPR_ASSERT(nHeight <= UINT16_MAX);
2467 ret = shadow_client_send_surface_bits(client, pSrcData, nSrcStep, (UINT16)nXSrc,
2468 (UINT16)nYSrc, (UINT16)nWidth, (UINT16)nHeight);
2469 }
2470 else
2471 {
2472 WINPR_ASSERT(nXSrc >= 0);
2473 WINPR_ASSERT(nXSrc <= UINT16_MAX);
2474 WINPR_ASSERT(nYSrc >= 0);
2475 WINPR_ASSERT(nYSrc <= UINT16_MAX);
2476 WINPR_ASSERT(nWidth >= 0);
2477 WINPR_ASSERT(nWidth <= UINT16_MAX);
2478 WINPR_ASSERT(nHeight >= 0);
2479 WINPR_ASSERT(nHeight <= UINT16_MAX);
2480 ret = shadow_client_send_bitmap_update(client, pSrcData, nSrcStep, (UINT16)nXSrc,
2481 (UINT16)nYSrc, (UINT16)nWidth, (UINT16)nHeight);
2482 }
2483
2484out:
2485 LeaveCriticalSection(&surface->lock);
2486 region16_uninit(&invalidRegion);
2487 return ret;
2488}
2489
2497WINPR_ATTR_NODISCARD
2498static BOOL shadow_client_send_resize(rdpShadowClient* client, SHADOW_GFX_STATUS* pStatus)
2499{
2500 rdpContext* context = (rdpContext*)client;
2501 rdpSettings* settings = nullptr;
2502 freerdp_peer* peer = nullptr;
2503
2504 if (!context || !pStatus)
2505 return FALSE;
2506
2507 peer = context->peer;
2508 settings = context->settings;
2509
2510 if (!peer || !settings)
2511 return FALSE;
2512
2518 client->activated = FALSE;
2519
2520 /* Close Gfx surfaces */
2521 if (pStatus->gfxSurfaceCreated)
2522 {
2523 if (!shadow_client_rdpgfx_release_surface(client))
2524 return FALSE;
2525
2526 pStatus->gfxSurfaceCreated = FALSE;
2527 }
2528
2529 /* Send Resize */
2530 if (!shadow_send_desktop_resize(client))
2531 return FALSE;
2532 shadow_reset_desktop_resize(client);
2533
2534 /* Clear my invalidRegion. shadow_client_activate refreshes fullscreen */
2535 EnterCriticalSection(&(client->lock));
2536 region16_clear(&(client->invalidRegion));
2537 LeaveCriticalSection(&(client->lock));
2538 return TRUE;
2539}
2540
2547WINPR_ATTR_NODISCARD
2548static BOOL shadow_client_surface_update(rdpShadowClient* client, REGION16* region)
2549{
2550 UINT32 numRects = 0;
2551 const RECTANGLE_16* rects = nullptr;
2552 rects = region16_rects(region, &numRects);
2553 shadow_client_mark_invalid(client, numRects, rects);
2554 return TRUE;
2555}
2556
2563WINPR_ATTR_NODISCARD
2564static inline BOOL shadow_client_no_surface_update(rdpShadowClient* client,
2565 SHADOW_GFX_STATUS* pStatus)
2566{
2567 rdpShadowServer* server = nullptr;
2568 rdpShadowSurface* surface = nullptr;
2569 WINPR_UNUSED(pStatus);
2570 WINPR_ASSERT(client);
2571 server = client->server;
2572 WINPR_ASSERT(server);
2573 surface = client->inLobby ? server->lobby : server->surface;
2574 EnterCriticalSection(&surface->lock);
2575 const BOOL rc = shadow_client_surface_update(client, &(surface->invalidRegion));
2576 LeaveCriticalSection(&surface->lock);
2577 return rc;
2578}
2579
2580WINPR_ATTR_NODISCARD
2581static int shadow_client_subsystem_process_message(rdpShadowClient* client, wMessage* message)
2582{
2583 rdpContext* context = (rdpContext*)client;
2584
2585 WINPR_ASSERT(message);
2586 WINPR_ASSERT(context);
2587
2588 rdpUpdate* update = context->update;
2589 WINPR_ASSERT(update);
2590
2591 /* FIXME: the pointer updates appear to be broken when used with bulk compression and mstsc */
2592
2593 switch (message->id)
2594 {
2595 case SHADOW_MSG_OUT_POINTER_POSITION_UPDATE_ID:
2596 {
2597 POINTER_POSITION_UPDATE pointerPosition;
2599 (const SHADOW_MSG_OUT_POINTER_POSITION_UPDATE*)message->wParam;
2600 pointerPosition.xPos = msg->xPos;
2601 pointerPosition.yPos = msg->yPos;
2602
2603 WINPR_ASSERT(client->server);
2604 if (client->server->shareSubRect)
2605 {
2606 pointerPosition.xPos -= client->server->subRect.left;
2607 pointerPosition.yPos -= client->server->subRect.top;
2608 }
2609
2610 if (client->activated)
2611 {
2612 if ((msg->xPos != client->pointerX) || (msg->yPos != client->pointerY))
2613 {
2614 WINPR_ASSERT(update->pointer);
2615 if (!IFCALLRESULT(TRUE, update->pointer->PointerPosition, context,
2616 &pointerPosition))
2617 return -1;
2618 client->pointerX = msg->xPos;
2619 client->pointerY = msg->yPos;
2620 }
2621 }
2622
2623 break;
2624 }
2625
2626 case SHADOW_MSG_OUT_POINTER_ALPHA_UPDATE_ID:
2627 {
2628 POINTER_NEW_UPDATE pointerNew = WINPR_C_ARRAY_INIT;
2629 POINTER_COLOR_UPDATE* pointerColor = WINPR_C_ARRAY_INIT;
2630 POINTER_CACHED_UPDATE pointerCached = WINPR_C_ARRAY_INIT;
2632 (const SHADOW_MSG_OUT_POINTER_ALPHA_UPDATE*)message->wParam;
2633
2634 WINPR_ASSERT(msg);
2635 pointerNew.xorBpp = 24;
2636 pointerColor = &(pointerNew.colorPtrAttr);
2637 pointerColor->cacheIndex = 0;
2638 pointerColor->hotSpotX = WINPR_ASSERTING_INT_CAST(UINT16, msg->xHot);
2639 pointerColor->hotSpotY = WINPR_ASSERTING_INT_CAST(UINT16, msg->yHot);
2640 pointerColor->width = WINPR_ASSERTING_INT_CAST(UINT16, msg->width);
2641 pointerColor->height = WINPR_ASSERTING_INT_CAST(UINT16, msg->height);
2642 pointerColor->lengthAndMask = WINPR_ASSERTING_INT_CAST(UINT16, msg->lengthAndMask);
2643 pointerColor->lengthXorMask = WINPR_ASSERTING_INT_CAST(UINT16, msg->lengthXorMask);
2644 pointerColor->xorMaskData = msg->xorMaskData;
2645 pointerColor->andMaskData = msg->andMaskData;
2646 pointerCached.cacheIndex = pointerColor->cacheIndex;
2647
2648 if (client->activated)
2649 {
2650 if (client->server->ShowMouseCursor)
2651 {
2652 if (!IFCALLRESULT(TRUE, update->pointer->PointerNew, context, &pointerNew))
2653 return -1;
2654 if (!IFCALLRESULT(TRUE, update->pointer->PointerCached, context,
2655 &pointerCached))
2656 return -1;
2657 }
2658 else
2659 {
2660 POINTER_SYSTEM_UPDATE pointer_system = WINPR_C_ARRAY_INIT;
2661 pointer_system.type = SYSPTR_DEFAULT;
2662 if (!IFCALLRESULT(TRUE, update->pointer->PointerSystem, context,
2663 &pointer_system))
2664 return -1;
2665 }
2666 }
2667
2668 break;
2669 }
2670
2671 case SHADOW_MSG_OUT_AUDIO_OUT_SAMPLES_ID:
2672 {
2674 (const SHADOW_MSG_OUT_AUDIO_OUT_SAMPLES*)message->wParam;
2675
2676 WINPR_ASSERT(msg);
2677
2678 /* Samples that arrive before the client agreed on a format (or when it
2679 * agreed on none) are dropped */
2680 if (client->activated && client->rdpsnd && client->rdpsnd->Activated &&
2681 (client->rdpsnd->selected_client_format < client->rdpsnd->num_client_formats))
2682 {
2683 client->rdpsnd->src_format = msg->audio_format;
2684
2685 const UINT error =
2686 IFCALLRESULT(CHANNEL_RC_OK, client->rdpsnd->SendSamples, client->rdpsnd,
2687 msg->buf, msg->nFrames, msg->wTimestamp);
2688 if (CHANNEL_RC_OK != error)
2689 {
2690 shadow_client_free_queued_message(message);
2691 return -1;
2692 }
2693 }
2694
2695 break;
2696 }
2697
2698 case SHADOW_MSG_OUT_AUDIO_OUT_VOLUME_ID:
2699 {
2701 (const SHADOW_MSG_OUT_AUDIO_OUT_VOLUME*)message->wParam;
2702
2703 if (client->activated && client->rdpsnd && client->rdpsnd->Activated)
2704 {
2705 const UINT error = IFCALLRESULT(CHANNEL_RC_OK, client->rdpsnd->SetVolume,
2706 client->rdpsnd, msg->left, msg->right);
2707 if (CHANNEL_RC_OK != error)
2708 return -1;
2709 }
2710
2711 break;
2712 }
2713
2714 default:
2715 WLog_ERR(TAG, "Unknown message id: %" PRIu32 "", message->id);
2716 break;
2717 }
2718
2719 shadow_client_free_queued_message(message);
2720 return 1;
2721}
2722
2723WINPR_ATTR_NODISCARD
2724static DWORD WINAPI shadow_client_thread(LPVOID arg)
2725{
2726 rdpShadowClient* client = (rdpShadowClient*)arg;
2727 BOOL rc = FALSE;
2728 DWORD status = 0;
2729 wMessage message = WINPR_C_ARRAY_INIT;
2730 wMessage pointerPositionMsg = WINPR_C_ARRAY_INIT;
2731 wMessage pointerAlphaMsg = WINPR_C_ARRAY_INIT;
2732 wMessage audioVolumeMsg = WINPR_C_ARRAY_INIT;
2733 HANDLE ChannelEvent = nullptr;
2734 void* UpdateSubscriber = nullptr;
2735 HANDLE UpdateEvent = nullptr;
2736 freerdp_peer* peer = nullptr;
2737 rdpContext* context = nullptr;
2738 rdpSettings* settings = nullptr;
2739 rdpShadowServer* server = nullptr;
2740 rdpShadowSubsystem* subsystem = nullptr;
2741 wMessageQueue* MsgQueue = nullptr;
2742 /* This should only be visited in client thread */
2743 SHADOW_GFX_STATUS gfxstatus = WINPR_C_ARRAY_INIT;
2744 rdpUpdate* update = nullptr;
2745
2746 WINPR_ASSERT(client);
2747
2748 MsgQueue = client->MsgQueue;
2749 WINPR_ASSERT(MsgQueue);
2750
2751 server = client->server;
2752 WINPR_ASSERT(server);
2753 subsystem = server->subsystem;
2754 context = (rdpContext*)client;
2755 peer = context->peer;
2756 WINPR_ASSERT(peer);
2757 WINPR_ASSERT(peer->context);
2758
2759 settings = peer->context->settings;
2760 WINPR_ASSERT(settings);
2761
2762 peer->Capabilities = shadow_client_capabilities;
2763 peer->PostConnect = shadow_client_post_connect;
2764 peer->Activate = shadow_client_activate;
2765 peer->Logon = shadow_client_logon;
2766 shadow_input_register_callbacks(peer->context->input);
2767
2768 rc = peer->Initialize(peer);
2769 if (!rc)
2770 goto out;
2771
2772 update = peer->context->update;
2773 WINPR_ASSERT(update);
2774
2775 update->RefreshRect = shadow_client_refresh_rect;
2776 update->SuppressOutput = shadow_client_suppress_output;
2777 update->SurfaceFrameAcknowledge = shadow_client_surface_frame_acknowledge;
2778
2779 if ((!client->vcm) || (!subsystem->updateEvent))
2780 goto out;
2781
2782 ChannelEvent = WTSVirtualChannelManagerGetEventHandle(client->vcm);
2783 WINPR_ASSERT(ChannelEvent);
2784
2785 rc = freerdp_settings_set_bool(settings, FreeRDP_UnicodeInput, TRUE);
2786 WINPR_ASSERT(rc);
2787 rc = freerdp_settings_set_bool(settings, FreeRDP_HasHorizontalWheel, TRUE);
2788 WINPR_ASSERT(rc);
2789 rc = freerdp_settings_set_bool(settings, FreeRDP_HasExtendedMouseEvent, TRUE);
2790 WINPR_ASSERT(rc);
2791 rc = freerdp_settings_set_bool(settings, FreeRDP_SupportMonitorLayoutPdu, TRUE);
2792 WINPR_ASSERT(rc);
2793 while (1)
2794 {
2795 HANDLE events[MAXIMUM_WAIT_OBJECTS] = WINPR_C_ARRAY_INIT;
2796 DWORD nCount = 0;
2797
2798 /* The subsystem and all other clients wait until every subscriber has
2799 * consumed the current frame. Only subscribe once the connection sequence
2800 * is done: peer->CheckFileDescriptor blocks this thread during the TLS
2801 * and NLA handshake for as long as the (not yet authenticated) peer wants,
2802 * and before activation there is nothing to send anyway. */
2803 if (!UpdateSubscriber && client->activated)
2804 {
2805 UpdateSubscriber = shadow_multiclient_get_subscriber(subsystem->updateEvent);
2806
2807 if (!UpdateSubscriber)
2808 goto fail;
2809
2810 UpdateEvent = shadow_multiclient_getevent(UpdateSubscriber);
2811 WINPR_ASSERT(UpdateEvent);
2812
2813 /* The full screen refresh requested by shadow_client_activate may
2814 * already have been published without us, request it again */
2815 if (!shadow_client_refresh_request(client))
2816 goto fail;
2817 }
2818
2819 if (UpdateEvent)
2820 events[nCount++] = UpdateEvent;
2821 {
2822 DWORD tmp = peer->GetEventHandles(peer, &events[nCount], 64 - nCount);
2823
2824 if (tmp == 0)
2825 {
2826 WLog_ERR(TAG, "Failed to get FreeRDP transport event handles");
2827 goto fail;
2828 }
2829
2830 nCount += tmp;
2831 }
2832 events[nCount++] = ChannelEvent;
2833 events[nCount++] = MessageQueue_Event(MsgQueue);
2834
2835#if defined(CHANNEL_RDPGFX_SERVER)
2836 HANDLE gfxevent = rdpgfx_server_get_event_handle(client->rdpgfx);
2837
2838 if (gfxevent)
2839 events[nCount++] = gfxevent;
2840#endif
2841
2842 status = WaitForMultipleObjects(nCount, events, FALSE, INFINITE);
2843
2844 if (status == WAIT_FAILED)
2845 goto fail;
2846
2847 if (UpdateEvent && (WaitForSingleObject(UpdateEvent, 0) == WAIT_OBJECT_0))
2848 {
2849 /* The UpdateEvent means to start sending current frame. It is
2850 * triggered from subsystem implementation and it should ensure
2851 * that the screen and primary surface meta data (width, height,
2852 * scanline, invalid region, etc) is not changed until it is reset
2853 * (at shadow_multiclient_consume). As best practice, subsystem
2854 * implementation should invoke shadow_subsystem_frame_update which
2855 * triggers the event and then wait for completion */
2856 if (client->activated && !client->suppressOutput)
2857 {
2858 /* Send screen update or resize to this client */
2859
2860 /* Check resize */
2861 if (shadow_client_recalc_desktop_size(client))
2862 {
2863 /* Screen size changed, do resize */
2864 if (!shadow_client_send_resize(client, &gfxstatus))
2865 {
2866 WLog_ERR(TAG, "Failed to send resize message");
2867 break;
2868 }
2869 }
2870 else
2871 {
2872 /* Send frame */
2873 if (!shadow_client_send_surface_update(client, &gfxstatus))
2874 {
2875 WLog_ERR(TAG, "Failed to send surface update");
2876 break;
2877 }
2878 }
2879 }
2880 else
2881 {
2882 /* Our client don't receive graphic updates. Just save the invalid region */
2883 if (!shadow_client_no_surface_update(client, &gfxstatus))
2884 {
2885 WLog_ERR(TAG, "Failed to handle surface update");
2886 break;
2887 }
2888 }
2889
2890 /*
2891 * The return value of shadow_multiclient_consume is whether or not
2892 * the subscriber really consumes the event. It's not cared currently.
2893 */
2894 (void)shadow_multiclient_consume(UpdateSubscriber);
2895 }
2896
2897 WINPR_ASSERT(peer->CheckFileDescriptor);
2898 if (!peer->CheckFileDescriptor(peer))
2899 {
2900 WLog_ERR(TAG, "Failed to check FreeRDP file descriptor");
2901 goto fail;
2902 }
2903
2904 if (client->activated &&
2905 WTSVirtualChannelManagerIsChannelJoined(client->vcm, DRDYNVC_SVC_CHANNEL_NAME))
2906 {
2907 switch (WTSVirtualChannelManagerGetDrdynvcState(client->vcm))
2908 {
2909 /* Dynamic channel status may have been changed after processing */
2910 case DRDYNVC_STATE_NONE:
2911
2912 /* Call this routine to Initialize drdynvc channel */
2913 if (!WTSVirtualChannelManagerCheckFileDescriptor(client->vcm))
2914 {
2915 WLog_ERR(TAG, "Failed to initialize drdynvc channel");
2916 goto fail;
2917 }
2918
2919 break;
2920
2921 case DRDYNVC_STATE_READY:
2922#if defined(CHANNEL_AUDIN_SERVER)
2923 if (client->audin && !IFCALLRESULT(TRUE, client->audin->IsOpen, client->audin))
2924 {
2925 if (!IFCALLRESULT(FALSE, client->audin->Open, client->audin))
2926 {
2927 WLog_ERR(TAG, "Failed to initialize audin channel");
2928 goto fail;
2929 }
2930 }
2931#endif
2932
2933 /* Init RDPGFX dynamic channel */
2934 if (freerdp_settings_get_bool(settings, FreeRDP_SupportGraphicsPipeline) &&
2935 client->rdpgfx && !gfxstatus.gfxOpened)
2936 {
2937 client->rdpgfx->FrameAcknowledge = shadow_client_rdpgfx_frame_acknowledge;
2938 client->rdpgfx->CapsAdvertise = shadow_client_rdpgfx_caps_advertise;
2939
2940 if (!client->rdpgfx->Open(client->rdpgfx))
2941 {
2942 WLog_WARN(TAG, "Failed to open GraphicsPipeline");
2943 if (!freerdp_settings_set_bool(settings,
2944 FreeRDP_SupportGraphicsPipeline, FALSE))
2945 goto fail;
2946 }
2947 else
2948 {
2949 gfxstatus.gfxOpened = TRUE;
2950 WLog_INFO(TAG, "Gfx Pipeline Opened");
2951 }
2952 }
2953
2954 break;
2955
2956 default:
2957 break;
2958 }
2959 }
2960
2961 if (WaitForSingleObject(ChannelEvent, 0) == WAIT_OBJECT_0)
2962 {
2963 if (!WTSVirtualChannelManagerCheckFileDescriptor(client->vcm))
2964 {
2965 WLog_ERR(TAG, "WTSVirtualChannelManagerCheckFileDescriptor failure");
2966 goto fail;
2967 }
2968 }
2969
2970#if defined(CHANNEL_RDPGFX_SERVER)
2971 if (gfxevent)
2972 {
2973 if (WaitForSingleObject(gfxevent, 0) == WAIT_OBJECT_0)
2974 {
2975 const UINT error = rdpgfx_server_handle_messages(client->rdpgfx);
2976 if (error != CHANNEL_RC_OK)
2977 goto fail;
2978 }
2979 }
2980#endif
2981
2982 if (WaitForSingleObject(MessageQueue_Event(MsgQueue), 0) == WAIT_OBJECT_0)
2983 {
2984 /* Drain messages. Pointer update could be accumulated. */
2985 pointerPositionMsg.id = 0;
2986 pointerPositionMsg.Free = nullptr;
2987 pointerAlphaMsg.id = 0;
2988 pointerAlphaMsg.Free = nullptr;
2989 audioVolumeMsg.id = 0;
2990 audioVolumeMsg.Free = nullptr;
2991
2992 while (MessageQueue_Peek(MsgQueue, &message, TRUE))
2993 {
2994 if (message.id == WMQ_QUIT)
2995 {
2996 break;
2997 }
2998
2999 switch (message.id)
3000 {
3001 case SHADOW_MSG_OUT_POINTER_POSITION_UPDATE_ID:
3002 /* Abandon previous message */
3003 shadow_client_free_queued_message(&pointerPositionMsg);
3004 pointerPositionMsg = message;
3005 break;
3006
3007 case SHADOW_MSG_OUT_POINTER_ALPHA_UPDATE_ID:
3008 /* Abandon previous message */
3009 shadow_client_free_queued_message(&pointerAlphaMsg);
3010 pointerAlphaMsg = message;
3011 break;
3012
3013 case SHADOW_MSG_OUT_AUDIO_OUT_VOLUME_ID:
3014 /* Abandon previous message */
3015 shadow_client_free_queued_message(&audioVolumeMsg);
3016 audioVolumeMsg = message;
3017 break;
3018
3019 default:
3020 if (!shadow_client_subsystem_process_message(client, &message))
3021 goto fail;
3022 break;
3023 }
3024 }
3025
3026 if (message.id == WMQ_QUIT)
3027 {
3028 /* Release stored message */
3029 shadow_client_free_queued_message(&pointerPositionMsg);
3030 shadow_client_free_queued_message(&pointerAlphaMsg);
3031 shadow_client_free_queued_message(&audioVolumeMsg);
3032 goto fail;
3033 }
3034 else
3035 {
3036 /* Process accumulated messages if needed */
3037 if (pointerPositionMsg.id)
3038 {
3039 if (!shadow_client_subsystem_process_message(client, &pointerPositionMsg))
3040 goto fail;
3041 }
3042
3043 if (pointerAlphaMsg.id)
3044 {
3045 if (!shadow_client_subsystem_process_message(client, &pointerAlphaMsg))
3046 goto fail;
3047 }
3048
3049 if (audioVolumeMsg.id)
3050 {
3051 if (!shadow_client_subsystem_process_message(client, &audioVolumeMsg))
3052 goto fail;
3053 }
3054 }
3055 }
3056 }
3057
3058fail:
3059
3060 /* Free channels early because we establish channels in post connect */
3061#if defined(CHANNEL_AUDIN_SERVER)
3062 if (client->audin && !IFCALLRESULT(TRUE, client->audin->IsOpen, client->audin))
3063 {
3064 if (!IFCALLRESULT(FALSE, client->audin->Close, client->audin))
3065 {
3066 WLog_WARN(TAG, "AUDIN shutdown failure!");
3067 }
3068 }
3069#endif
3070
3071 if (gfxstatus.gfxOpened)
3072 {
3073 if (gfxstatus.gfxSurfaceCreated)
3074 {
3075 if (!shadow_client_rdpgfx_release_surface(client))
3076 WLog_WARN(TAG, "GFX release surface failure!");
3077 }
3078
3079 WINPR_ASSERT(client->rdpgfx);
3080 WINPR_ASSERT(client->rdpgfx->Close);
3081 rc = client->rdpgfx->Close(client->rdpgfx);
3082 WINPR_ASSERT(rc);
3083 }
3084
3085 shadow_client_channels_free(client);
3086
3087 if (UpdateSubscriber)
3088 {
3089 shadow_multiclient_release_subscriber(UpdateSubscriber);
3090 UpdateSubscriber = nullptr;
3091 }
3092
3093 if (peer->connected && subsystem->ClientDisconnect)
3094 {
3095 subsystem->ClientDisconnect(subsystem, client);
3096 }
3097
3098out:
3099 WINPR_ASSERT(peer->Disconnect);
3100 peer->Disconnect(peer);
3101 freerdp_peer_context_free(peer);
3102 freerdp_peer_free(peer);
3103 ExitThread(0);
3104 return 0;
3105}
3106
3107BOOL shadow_client_accepted(freerdp_listener* listener, freerdp_peer* peer)
3108{
3109 rdpShadowClient* client = nullptr;
3110 rdpShadowServer* server = nullptr;
3111
3112 if (!listener || !peer)
3113 return FALSE;
3114
3115 server = (rdpShadowServer*)listener->info;
3116 WINPR_ASSERT(server);
3117
3118 peer->ContextExtra = (void*)server;
3119 peer->ContextSize = sizeof(rdpShadowClient);
3120 peer->ContextNew = shadow_client_context_new;
3121 peer->ContextFree = shadow_client_context_free;
3122
3123 if (!freerdp_peer_context_new_ex(peer, server->settings))
3124 return FALSE;
3125
3126 client = (rdpShadowClient*)peer->context;
3127 WINPR_ASSERT(client);
3128
3129 if (!(client->thread = CreateThread(nullptr, 0, shadow_client_thread, client, 0, nullptr)))
3130 {
3131 freerdp_peer_context_free(peer);
3132 return FALSE;
3133 }
3134 else
3135 {
3136 /* Close the thread handle to make it detached. */
3137 (void)CloseHandle(client->thread);
3138 client->thread = nullptr;
3139 }
3140
3141 return TRUE;
3142}
3143
3144static void shadow_msg_out_addref(wMessage* message)
3145{
3146 SHADOW_MSG_OUT* msg = nullptr;
3147
3148 WINPR_ASSERT(message);
3149 msg = (SHADOW_MSG_OUT*)message->wParam;
3150 WINPR_ASSERT(msg);
3151
3152 InterlockedIncrement(&(msg->refCount));
3153}
3154
3155static void shadow_msg_out_release(wMessage* message)
3156{
3157 SHADOW_MSG_OUT* msg = nullptr;
3158
3159 WINPR_ASSERT(message);
3160 msg = (SHADOW_MSG_OUT*)message->wParam;
3161 WINPR_ASSERT(msg);
3162
3163 if (InterlockedDecrement(&(msg->refCount)) <= 0)
3164 {
3165 IFCALL(msg->Free, message->id, msg);
3166 }
3167}
3168
3169WINPR_ATTR_NODISCARD
3170static BOOL shadow_client_dispatch_msg(rdpShadowClient* client, wMessage* message)
3171{
3172 if (!client || !message)
3173 return FALSE;
3174
3175 /* Add reference when it is posted */
3176 shadow_msg_out_addref(message);
3177
3178 WINPR_ASSERT(client->MsgQueue);
3179 if (MessageQueue_Dispatch(client->MsgQueue, message))
3180 return TRUE;
3181 else
3182 {
3183 /* Release the reference since post failed */
3184 shadow_msg_out_release(message);
3185 return FALSE;
3186 }
3187}
3188
3189BOOL shadow_client_post_msg(rdpShadowClient* client, void* context, UINT32 type,
3190 SHADOW_MSG_OUT* msg, void* lParam)
3191{
3192 wMessage message = WINPR_C_ARRAY_INIT;
3193 message.context = context;
3194 message.id = type;
3195 message.wParam = (void*)msg;
3196 message.lParam = lParam;
3197 message.Free = shadow_msg_out_release;
3198 return shadow_client_dispatch_msg(client, &message);
3199}
3200
3201int shadow_client_boardcast_msg(rdpShadowServer* server, void* context, UINT32 type,
3202 SHADOW_MSG_OUT* msg, void* lParam)
3203{
3204 wMessage message = WINPR_C_ARRAY_INIT;
3205 int count = 0;
3206
3207 WINPR_ASSERT(server);
3208 WINPR_ASSERT(msg);
3209
3210 message.context = context;
3211 message.id = type;
3212 message.wParam = (void*)msg;
3213 message.lParam = lParam;
3214 message.Free = shadow_msg_out_release;
3215 /* First add reference as we reference it in this function.
3216 * Therefore it would not be free'ed during post. */
3217 shadow_msg_out_addref(&message);
3218
3219 WINPR_ASSERT(server->clients);
3220 ArrayList_Lock(server->clients);
3221
3222 for (size_t index = 0; index < ArrayList_Count(server->clients); index++)
3223 {
3224 rdpShadowClient* client = (rdpShadowClient*)ArrayList_GetItem(server->clients, index);
3225
3226 if (shadow_client_dispatch_msg(client, &message))
3227 {
3228 count++;
3229 }
3230 }
3231
3232 ArrayList_Unlock(server->clients);
3233 /* Release the reference for this function */
3234 shadow_msg_out_release(&message);
3235 return count;
3236}
3237
3238int shadow_client_boardcast_quit(rdpShadowServer* server, int nExitCode)
3239{
3240 wMessageQueue* queue = nullptr;
3241 int count = 0;
3242
3243 WINPR_ASSERT(server);
3244 WINPR_ASSERT(server->clients);
3245
3246 ArrayList_Lock(server->clients);
3247
3248 for (size_t index = 0; index < ArrayList_Count(server->clients); index++)
3249 {
3250 queue = ((rdpShadowClient*)ArrayList_GetItem(server->clients, index))->MsgQueue;
3251
3252 if (MessageQueue_PostQuit(queue, nExitCode))
3253 {
3254 count++;
3255 }
3256 }
3257
3258 ArrayList_Unlock(server->clients);
3259 return count;
3260}
WINPR_ATTR_NODISCARD FREERDP_API const char * freerdp_settings_get_string(const rdpSettings *settings, FreeRDP_Settings_Keys_String id)
Returns a immutable string settings value.
WINPR_ATTR_NODISCARD FREERDP_API BOOL freerdp_settings_set_bool(rdpSettings *settings, FreeRDP_Settings_Keys_Bool id, BOOL val)
Sets a BOOL settings value.
WINPR_ATTR_NODISCARD FREERDP_API BOOL freerdp_settings_set_uint32(rdpSettings *settings, FreeRDP_Settings_Keys_UInt32 id, UINT32 val)
Sets a UINT32 settings value.
WINPR_ATTR_NODISCARD FREERDP_API UINT32 freerdp_settings_get_uint32(const rdpSettings *settings, FreeRDP_Settings_Keys_UInt32 id)
Returns a UINT32 settings value.
WINPR_ATTR_NODISCARD FREERDP_API BOOL freerdp_settings_set_string(rdpSettings *settings, FreeRDP_Settings_Keys_String id, const char *val)
Sets a string settings value. The param is copied.
WINPR_ATTR_NODISCARD FREERDP_API BOOL freerdp_settings_get_bool(const rdpSettings *settings, FreeRDP_Settings_Keys_Bool id)
Returns a boolean settings value.
Definition rfx.h:44
This struct contains function pointer to initialize/free objects.
Definition collections.h:52