21#include <freerdp/config.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>
33#include <freerdp/log.h>
34#include <freerdp/utils/gfx.h>
35#include <freerdp/channels/drdynvc.h>
38#include "shadow_rfx_dirty.h"
39#include "shadow_autodetect.h"
41#define TAG CLIENT_TAG("shadow")
43#define SHADOW_CLIENT_MAX_INVALID_RECTS 256
48 BOOL gfxSurfaceCreated;
52static BOOL shadow_avc420_enabled(
const rdpShadowClient* client);
54static BOOL shadow_avc444_enabled(
const rdpShadowClient* client);
63#define BitmapUpdateProxy(client, bitmap) \
64 BitmapUpdateProxyEx((client), (bitmap), __FILE__, __LINE__, __func__)
66static BOOL BitmapUpdateProxyEx(rdpShadowClient* client,
const BITMAP_UPDATE* bitmap,
67 const char* file,
size_t line,
const char* fkt)
72 rdpShadowServer* server = client->server;
75 rdpContext* context = (rdpContext*)client;
77 rdpUpdate* update = context->update;
80 if (server->SupportMultiRectBitmapUpdates)
82 const BOOL rc = IFCALLRESULT(FALSE, update->BitmapUpdate, context, bitmap);
85 const DWORD log_level = WLOG_ERROR;
86 wLog* log = WLog_Get(TAG);
87 if (WLog_IsLevelActive(log, log_level))
89 WLog_PrintTextMessage(log, log_level, line, file, fkt,
90 "BitmapUpdate[count %" PRIu32
"] failed", bitmap->number);
97 for (UINT32 x = 0; x < bitmap->number; x++)
101 cur.rectangles = bmp;
103 cur.skipCompression = bitmap->skipCompression;
104 const BOOL rc = IFCALLRESULT(FALSE, update->BitmapUpdate, context, &cur);
107 const DWORD log_level = WLOG_ERROR;
108 wLog* log = WLog_Get(TAG);
109 if (WLog_IsLevelActive(log, log_level))
111 WLog_PrintTextMessage(log, log_level, line, file, fkt,
112 "BitmapUpdate[count 1, at %" PRIu32
"] failed", x);
123static inline BOOL shadow_client_rdpgfx_new_surface(rdpShadowClient* client)
125 UINT error = CHANNEL_RC_OK;
128 RdpgfxServerContext* context =
nullptr;
129 rdpSettings* settings =
nullptr;
131 WINPR_ASSERT(client);
132 context = client->rdpgfx;
133 WINPR_ASSERT(context);
134 settings = ((rdpContext*)client)->settings;
135 WINPR_ASSERT(settings);
141 createSurface.pixelFormat = GFX_PIXEL_FORMAT_XRGB_8888;
142 createSurface.surfaceId = client->surfaceId;
143 surfaceToOutput.outputOriginX = 0;
144 surfaceToOutput.outputOriginY = 0;
145 surfaceToOutput.surfaceId = client->surfaceId;
146 surfaceToOutput.reserved = 0;
147 IFCALLRET(context->CreateSurface, error, context, &createSurface);
151 WLog_ERR(TAG,
"CreateSurface failed with error %" PRIu32
"", error);
155 IFCALLRET(context->MapSurfaceToOutput, error, context, &surfaceToOutput);
159 WLog_ERR(TAG,
"MapSurfaceToOutput failed with error %" PRIu32
"", error);
167static inline BOOL shadow_client_rdpgfx_release_surface(rdpShadowClient* client)
169 UINT error = CHANNEL_RC_OK;
171 RdpgfxServerContext* context =
nullptr;
173 WINPR_ASSERT(client);
175 context = client->rdpgfx;
176 WINPR_ASSERT(context);
178 pdu.surfaceId = client->surfaceId++;
179 IFCALLRET(context->DeleteSurface, error, context, &pdu);
183 WLog_ERR(TAG,
"DeleteSurface failed with error %" PRIu32
"", error);
191static inline BOOL shadow_client_rdpgfx_reset_graphic(rdpShadowClient* client)
193 UINT error = CHANNEL_RC_OK;
195 RdpgfxServerContext* context =
nullptr;
196 rdpSettings* settings =
nullptr;
198 WINPR_ASSERT(client);
199 WINPR_ASSERT(client->rdpgfx);
201 context = client->rdpgfx;
202 WINPR_ASSERT(context);
204 settings = client->context.settings;
205 WINPR_ASSERT(settings);
209 pdu.monitorCount = client->subsystem->numMonitors;
210 pdu.monitorDefArray = client->subsystem->monitors;
211 IFCALLRET(context->ResetGraphics, error, context, &pdu);
215 WLog_ERR(TAG,
"ResetGraphics failed with error %" PRIu32
"", error);
219 client->first_frame = TRUE;
223static inline void shadow_client_free_queued_message(
void* obj)
225 wMessage* message = (wMessage*)obj;
227 WINPR_ASSERT(message);
230 message->Free(message);
231 message->Free =
nullptr;
235static void shadow_client_context_free(freerdp_peer* peer, rdpContext* context)
237 rdpShadowClient* client = (rdpShadowClient*)context;
238 rdpShadowServer* server =
nullptr;
244 server = client->server;
245 if (server && server->clients)
246 ArrayList_Remove(server->clients, (
void*)client);
248 shadow_client_autodetect_uninit(client);
249 shadow_encoder_free(client->encoder);
252 MessageQueue_Free(client->MsgQueue);
253 MessageQueue_Free(client->SoundQueue);
254 WTSCloseServer(client->vcm);
255 region16_uninit(&(client->invalidRegion));
256 DeleteCriticalSection(&(client->vcmLock));
257 DeleteCriticalSection(&(client->lock));
259 client->MsgQueue =
nullptr;
260 client->SoundQueue =
nullptr;
261 client->encoder =
nullptr;
262 client->vcm =
nullptr;
266static BOOL shadow_client_context_new(freerdp_peer* peer, rdpContext* context)
269 const char bind_address[] =
"bind-address,";
270 rdpShadowClient* client = (rdpShadowClient*)context;
271 rdpSettings* settings =
nullptr;
272 const rdpSettings* srvSettings =
nullptr;
273 rdpShadowServer* server =
nullptr;
274 const wObject cb = {
nullptr,
nullptr,
nullptr, shadow_client_free_queued_message,
nullptr };
276 WINPR_ASSERT(client);
278 WINPR_ASSERT(peer->context);
280 server = (rdpShadowServer*)peer->ContextExtra;
281 WINPR_ASSERT(server);
283 srvSettings = server->settings;
284 WINPR_ASSERT(srvSettings);
286 client->surfaceId = 1;
287 client->server = server;
288 client->subsystem = server->subsystem;
289 WINPR_ASSERT(client->subsystem);
291 settings = peer->context->settings;
292 WINPR_ASSERT(settings);
304 settings, FreeRDP_RemoteFxRlgrMode,
314 settings, FreeRDP_SupportGraphicsPipeline,
329 if (server->ipcSocket && (strncmp(bind_address, server->ipcSocket,
330 strnlen(bind_address,
sizeof(bind_address))) != 0))
338 client->inLobby = TRUE;
339 client->mayView = server->mayView;
340 client->mayInteract = server->mayInteract;
342 if (!InitializeCriticalSectionAndSpinCount(&(client->lock), 4000))
345 if (!InitializeCriticalSectionAndSpinCount(&(client->vcmLock), 4000))
348 region16_init(&(client->invalidRegion));
349 client->vcm = WTSOpenServerA((LPSTR)peer->context);
351 if (!client->vcm || client->vcm == INVALID_HANDLE_VALUE)
354 if (!(client->MsgQueue = MessageQueue_New(&cb)))
357 if (!(client->SoundQueue = MessageQueue_New(&cb)))
360 if (!(client->encoder = shadow_encoder_new(client)))
363 if (!shadow_client_autodetect_init(client))
366 if (!ArrayList_Append(server->clients, (
void*)client))
372 shadow_client_context_free(peer, context);
389static BOOL shadow_client_invalidate_rect(rdpShadowClient* client,
const RECTANGLE_16* rect)
391 WINPR_ASSERT(client);
393 REGION16* region = &(client->invalidRegion);
394 if (!region16_union_rect(region, region, rect))
397 if (region16_n_rects(region) <= SHADOW_CLIENT_MAX_INVALID_RECTS)
401 region16_clear(region);
402 return region16_union_rect(region, region, &extents);
405static inline void shadow_client_mark_invalid(rdpShadowClient* client, UINT32 numRects,
408 WINPR_ASSERT(client);
409 WINPR_ASSERT(rects || (numRects == 0));
411 rdpSettings* settings = client->context.settings;
412 WINPR_ASSERT(settings);
414 EnterCriticalSection(&(client->lock));
419 for (UINT32 index = 0; index < numRects; index++)
421 if (!shadow_client_invalidate_rect(client, &rects[index]))
432 if (!shadow_client_invalidate_rect(client, &screenRegion))
436 LeaveCriticalSection(&(client->lock));
446static inline BOOL shadow_client_recalc_desktop_size(rdpShadowClient* client)
450 rdpShadowServer* server =
nullptr;
451 rdpSettings* settings =
nullptr;
454 WINPR_ASSERT(client);
455 server = client->server;
456 settings = client->context.settings;
458 WINPR_ASSERT(server);
459 WINPR_ASSERT(server->surface);
460 WINPR_ASSERT(settings);
462 WINPR_ASSERT(server->surface->width <= UINT16_MAX);
463 WINPR_ASSERT(server->surface->height <= UINT16_MAX);
464 viewport.right = (UINT16)server->surface->width;
465 viewport.bottom = (UINT16)server->surface->height;
467 if (server->shareSubRect)
469 if (!rectangles_intersection(&viewport, &(server->subRect), &viewport))
473 width = viewport.right - viewport.left;
474 height = viewport.bottom - viewport.top;
476 WINPR_ASSERT(width >= 0);
477 WINPR_ASSERT(width <= UINT16_MAX);
478 WINPR_ASSERT(height >= 0);
479 WINPR_ASSERT(height <= UINT16_MAX);
485static BOOL shadow_client_capabilities(freerdp_peer* peer)
487 rdpShadowSubsystem* subsystem =
nullptr;
488 rdpShadowClient* client =
nullptr;
493 client = (rdpShadowClient*)peer->context;
494 WINPR_ASSERT(client);
495 WINPR_ASSERT(client->server);
497 subsystem = client->server->subsystem;
498 WINPR_ASSERT(subsystem);
500 IFCALLRET(subsystem->ClientCapabilities, ret, subsystem, client);
503 WLog_WARN(TAG,
"subsystem->ClientCapabilities failed");
508static void shadow_reset_desktop_resize(rdpShadowClient* client)
510 WINPR_ASSERT(client);
511 client->resizeRequested = FALSE;
515static BOOL shadow_send_desktop_resize(rdpShadowClient* client)
518 rdpUpdate* update =
nullptr;
519 rdpSettings* settings =
nullptr;
520 const freerdp_peer* peer =
nullptr;
522 WINPR_ASSERT(client);
524 settings = client->context.settings;
525 peer = client->context.peer;
527 WINPR_ASSERT(client->server);
528 WINPR_ASSERT(client->server->surface);
530 const UINT32 resizeWidth = client->server->surface->width;
531 const UINT32 resizeHeight = client->server->surface->height;
533 if (client->resizeRequested)
535 if ((resizeWidth == client->resizeWidth) && (resizeHeight == client->resizeHeight))
540 "detected previous resize request for resolution %" PRIu32
"x%" PRIu32
541 ", still have %" PRIu32
"x%" PRIu32
", disconnecting peer",
542 resizeWidth, resizeHeight, w, h);
547 update = client->context.update;
548 WINPR_ASSERT(update);
549 WINPR_ASSERT(update->DesktopResize);
557 rc = update->DesktopResize(update->context);
558 WLog_INFO(TAG,
"Client %s resize requested (%" PRIu32
"x%" PRIu32
"@%" PRIu32
")",
559 peer->hostname, resizeWidth, resizeHeight,
561 client->resizeRequested = TRUE;
562 client->resizeWidth = resizeWidth;
563 client->resizeHeight = resizeHeight;
569static BOOL shadow_client_post_connect(freerdp_peer* peer)
572 rdpSettings* settings =
nullptr;
573 rdpShadowClient* client =
nullptr;
574 rdpShadowServer* server =
nullptr;
575 rdpShadowSubsystem* subsystem =
nullptr;
579 client = (rdpShadowClient*)peer->context;
580 WINPR_ASSERT(client);
582 settings = peer->context->settings;
583 WINPR_ASSERT(settings);
585 server = client->server;
586 WINPR_ASSERT(server);
588 subsystem = server->subsystem;
589 WINPR_ASSERT(subsystem);
597 const UINT32 MultifragMaxRequestSize =
599 if (MultifragMaxRequestSize < 0x3F0000)
602 settings, FreeRDP_NSCodec,
608 WLog_INFO(TAG,
"Client from %s is activated (%" PRIu32
"x%" PRIu32
"@%" PRIu32
")",
613 if (shadow_client_channels_post_connect(client) != CHANNEL_RC_OK)
616 shadow_client_mark_invalid(client, 0,
nullptr);
623 if (Username && Password)
632 if (subsystem->Authenticate)
634 authStatus = subsystem->Authenticate(subsystem, client, Username, Domain, Password);
639 WLog_ERR(TAG,
"client authentication failure: %d", authStatus);
642 freerdp_set_error_info(peer->context->rdp, ERRINFO_SERVER_INSUFFICIENT_PRIVILEGES);
643 WINPR_ASSERT(peer->Close);
644 if (!peer->Close(peer))
645 WLog_WARN(TAG,
"failed to send the disconnect sequence to the client");
650 if (subsystem->ClientConnect)
652 return subsystem->ClientConnect(subsystem, client);
659static inline void shadow_client_convert_rects(rdpShadowClient* client,
RECTANGLE_16* dst,
662 WINPR_ASSERT(client);
663 WINPR_ASSERT(client->server);
665 WINPR_ASSERT(src || (numRects == 0));
667 if (client->server->shareSubRect)
669 UINT16 offsetX = client->server->subRect.left;
670 UINT16 offsetY = client->server->subRect.top;
672 for (UINT32 i = 0; i < numRects; i++)
677 d->left = s->left + offsetX;
678 d->right = s->right + offsetX;
679 d->top = s->top + offsetY;
680 d->bottom = s->bottom + offsetY;
693static BOOL shadow_client_refresh_request(rdpShadowClient* client)
695 wMessage message = WINPR_C_ARRAY_INIT;
698 WINPR_ASSERT(client);
699 WINPR_ASSERT(client->subsystem);
701 MsgPipe = client->subsystem->MsgPipe;
702 WINPR_ASSERT(MsgPipe);
704 message.id = SHADOW_MSG_IN_REFRESH_REQUEST_ID;
705 message.wParam =
nullptr;
706 message.lParam =
nullptr;
707 message.context = (
void*)client;
708 message.Free =
nullptr;
709 return MessageQueue_Dispatch(MsgPipe->In, &message);
713static BOOL shadow_client_refresh_rect(rdpContext* context, BYTE count,
const RECTANGLE_16* areas)
715 rdpShadowClient* client = (rdpShadowClient*)context;
731 shadow_client_convert_rects(client, rects, areas, count);
732 shadow_client_mark_invalid(client, count, rects);
737 shadow_client_mark_invalid(client, 0,
nullptr);
740 return shadow_client_refresh_request(client);
744static BOOL shadow_client_suppress_output(rdpContext* context, BYTE allow,
const RECTANGLE_16* area)
746 rdpShadowClient* client = (rdpShadowClient*)context;
749 WINPR_ASSERT(client);
751 client->suppressOutput = !(allow);
757 shadow_client_convert_rects(client, ®ion, area, 1);
758 shadow_client_mark_invalid(client, 1, ®ion);
762 shadow_client_mark_invalid(client, 0,
nullptr);
766 return shadow_client_refresh_request(client);
770static BOOL shadow_client_activate(freerdp_peer* peer)
774 rdpShadowClient* client = (rdpShadowClient*)peer->context;
775 WINPR_ASSERT(client);
778 if (shadow_client_recalc_desktop_size(client))
779 return shadow_send_desktop_resize(client);
781 shadow_reset_desktop_resize(client);
782 client->activated = TRUE;
783 client->inLobby = !(client->mayView);
785 if (shadow_encoder_reset(client->encoder) < 0)
787 WLog_ERR(TAG,
"Failed to reset encoder");
792 return shadow_client_refresh_rect(&client->context, 0,
nullptr);
796static BOOL shadow_client_logon(freerdp_peer* peer,
const SEC_WINNT_AUTH_IDENTITY* identity,
800 char* user =
nullptr;
801 char* domain =
nullptr;
802 char* password =
nullptr;
803 rdpSettings* settings =
nullptr;
805 WINPR_UNUSED(automatic);
808 WINPR_ASSERT(identity);
810 WINPR_ASSERT(peer->context);
812 settings = peer->context->settings;
813 WINPR_ASSERT(settings);
815 if (identity->Flags & SEC_WINNT_AUTH_IDENTITY_UNICODE)
818 user = ConvertWCharNToUtf8Alloc(identity->User, identity->UserLength,
nullptr);
820 if (identity->Domain)
821 domain = ConvertWCharNToUtf8Alloc(identity->Domain, identity->DomainLength,
nullptr);
823 if (identity->Password)
825 ConvertWCharNToUtf8Alloc(identity->Password, identity->PasswordLength,
nullptr);
830 user = _strdup((
char*)identity->User);
832 if (identity->Domain)
833 domain = _strdup((
char*)identity->Domain);
835 if (identity->Password)
836 password = _strdup((
char*)identity->Password);
839 if ((identity->User && !user) || (identity->Domain && !domain) ||
840 (identity->Password && !password))
867static inline void shadow_client_common_frame_acknowledge(rdpShadowClient* client, UINT32 frameId)
877 WINPR_ASSERT(client);
878 WINPR_ASSERT(client->encoder);
879 client->encoder->lastAckframeId = frameId;
880 client->encoder->lastAckTick = GetTickCount64();
881 client->encoder->everAcked = TRUE;
885static BOOL shadow_client_surface_frame_acknowledge(rdpContext* context, UINT32 frameId)
887 rdpShadowClient* client = (rdpShadowClient*)context;
888 shadow_client_common_frame_acknowledge(client, frameId);
892 WINPR_ASSERT(client);
893 WINPR_ASSERT(client->encoder);
894 client->encoder->queueDepth = QUEUE_DEPTH_UNAVAILABLE;
900shadow_client_rdpgfx_frame_acknowledge(RdpgfxServerContext* context,
903 rdpShadowClient* client =
nullptr;
905 WINPR_ASSERT(context);
906 WINPR_ASSERT(frameAcknowledge);
908 client = (rdpShadowClient*)context->custom;
909 shadow_client_common_frame_acknowledge(client, frameAcknowledge->frameId);
911 WINPR_ASSERT(client);
912 WINPR_ASSERT(client->encoder);
913 client->encoder->queueDepth = frameAcknowledge->queueDepth;
914 return CHANNEL_RC_OK;
918static BOOL shadow_are_caps_filtered(
const rdpSettings* settings, UINT32 caps)
920 const UINT32 capList[] = {
921#if defined(WITH_GFX_AV1)
922 RDPGFX_CAPVERSION_FRDP_1,
924#if defined(WITH_GFX_AV2)
925 RDPGFX_CAPVERSION_FRDP_2,
928 RDPGFX_CAPVERSION_81,
929 RDPGFX_CAPVERSION_10,
930 RDPGFX_CAPVERSION_101,
931 RDPGFX_CAPVERSION_102,
932 RDPGFX_CAPVERSION_103,
933 RDPGFX_CAPVERSION_104,
934 RDPGFX_CAPVERSION_105,
935 RDPGFX_CAPVERSION_106,
936 RDPGFX_CAPVERSION_106_ERR,
937 RDPGFX_CAPVERSION_107
938#if defined(WITH_GFX_AZURE)
940 RDPGFX_CAPVERSION_111,
941 RDPGFX_CAPVERSION_112,
942 RDPGFX_CAPVERSION_113,
943 RDPGFX_CAPVERSION_115
947 WINPR_ASSERT(settings);
950 for (UINT32 x = 0; x < ARRAYSIZE(capList); x++)
952 if (caps == capList[x])
953 return (filter & (1u << x)) != 0;
963static BOOL shadow_client_caps_allow_avc420(
const RDPGFX_CAPSET* caps)
966 if (caps->version == RDPGFX_CAPVERSION_81)
967 return (caps->flags & RDPGFX_CAPS_FLAG_AVC420_ENABLED) != 0;
968 return (caps->flags & RDPGFX_CAPS_FLAG_AVC_DISABLED) == 0;
972static UINT shadow_client_send_caps_confirm(RdpgfxServerContext* context, rdpShadowClient* client,
975 WINPR_ASSERT(context);
976 WINPR_ASSERT(client);
979 WINPR_ASSERT(context->CapsConfirm);
980 UINT rc = context->CapsConfirm(context, pdu);
981 client->areGfxCapsReady = (rc == CHANNEL_RC_OK);
982 client->confirmedCaps = *pdu->capsSet;
984 rdpSettings* clientSettings = client->context.settings;
985 WINPR_ASSERT(clientSettings);
987#if defined(WITH_GFX_AV2)
988 if (pdu->capsSet->version == RDPGFX_CAPVERSION_FRDP_2)
990 UINT32 flags = FREERDP_CODEC_AV2_I420;
991 if ((pdu->capsSet->flags & RDPGFX_CAPS_FLAG_AV1_I444_DISABLED) == 0)
992 flags = FREERDP_CODEC_AV2_I444;
994 if (shadow_encoder_prepare(client->encoder, flags) < 0)
995 return ERROR_INVALID_PARAMETER;
999#if defined(WITH_GFX_AV1)
1000 if (pdu->capsSet->version == RDPGFX_CAPVERSION_FRDP_1)
1002 UINT32 flags = FREERDP_CODEC_AV1_I420;
1003 if ((pdu->capsSet->flags & RDPGFX_CAPS_FLAG_AV1_I444_DISABLED) == 0)
1004 flags = FREERDP_CODEC_AV1_I444;
1006 if (shadow_encoder_prepare(client->encoder, flags) < 0)
1007 return ERROR_INVALID_PARAMETER;
1011 if (shadow_avc444_enabled(client) || shadow_avc420_enabled(client))
1014 const BOOL h264 = (shadow_encoder_prepare(client->encoder, FREERDP_CODEC_AVC420 |
1015 FREERDP_CODEC_AVC444) >= 0);
1020 clientSettings, FreeRDP_GfxH264,
1021 shadow_client_caps_allow_avc420(pdu->capsSet) &&
1044static BOOL shadow_client_caps_test_version(RdpgfxServerContext* context, rdpShadowClient* client,
1046 UINT32 capsSetCount, UINT32 capsVersion, UINT* rc)
1048 WINPR_ASSERT(context);
1049 WINPR_ASSERT(client);
1050 WINPR_ASSERT(capsSets || (capsSetCount == 0));
1053 WINPR_ASSERT(context->rdpcontext);
1054 const rdpSettings* srvSettings = context->rdpcontext->settings;
1055 WINPR_ASSERT(srvSettings);
1057 rdpSettings* clientSettings = client->context.settings;
1058 WINPR_ASSERT(clientSettings);
1060 if (shadow_are_caps_filtered(srvSettings, capsVersion))
1063 for (UINT32 index = 0; index < capsSetCount; index++)
1067 WLog_INFO(TAG,
"testing %s vs %s[0x%08" PRIx32
"]",
1068 rdpgfx_caps_version_str(currentCaps->version),
1069 rdpgfx_caps_version_str(capsVersion), capsVersion);
1070 if (currentCaps->version == capsVersion)
1074 pdu.capsSet = ∩︀
1076 const UINT32 flags = pdu.capsSet->flags;
1079 (flags & RDPGFX_CAPS_FLAG_SMALL_CACHE) != 0))
1083 BOOL avc444 = !(flags & RDPGFX_CAPS_FLAG_AVC_DISABLED);
1084 BOOL avc444v2 = avc444;
1101 const BOOL progressivev2 =
1113#if defined(WITH_GFX_AV1)
1117 const UINT32 av1Profile =
1123#if defined(WITH_GFX_AV2)
1127 const UINT32 av2Profile =
1134 if (!h264 || (!avc444v2 && !avc444 && !avc420))
1135 pdu.capsSet->flags |= RDPGFX_CAPS_FLAG_AVC_DISABLED;
1137#if defined(WITH_GFX_AV1)
1138 if (currentCaps->version == RDPGFX_CAPVERSION_FRDP_1)
1143 pdu.capsSet->flags &=
1144 ~(RDPGFX_CAPS_FLAG_AV1_I444_SUPPORTED | RDPGFX_CAPS_FLAG_AV1_I444_DISABLED);
1146 if ((currentCaps->flags & RDPGFX_CAPS_FLAG_AV1_I444_SUPPORTED) != 0)
1148 if (av1Profile == 0)
1152 if ((av1Profile == 0) ||
1153 ((currentCaps->flags & RDPGFX_CAPS_FLAG_AV1_I444_SUPPORTED) == 0))
1154 pdu.capsSet->flags |= RDPGFX_CAPS_FLAG_AV1_I444_DISABLED;
1155 if ((currentCaps->flags & RDPGFX_CAPS_FLAG_AV1_I444_DISABLED) != 0)
1156 pdu.capsSet->flags |= RDPGFX_CAPS_FLAG_AV1_I444_DISABLED;
1159#if defined(WITH_GFX_AV2)
1160 if (currentCaps->version == RDPGFX_CAPVERSION_FRDP_2)
1165 pdu.capsSet->flags &=
1166 ~(RDPGFX_CAPS_FLAG_AV1_I444_SUPPORTED | RDPGFX_CAPS_FLAG_AV1_I444_DISABLED);
1168 if ((currentCaps->flags & RDPGFX_CAPS_FLAG_AV1_I444_SUPPORTED) != 0)
1170 if (av2Profile == 0)
1174 if ((av2Profile == 0) ||
1175 ((currentCaps->flags & RDPGFX_CAPS_FLAG_AV1_I444_SUPPORTED) == 0))
1176 pdu.capsSet->flags |= RDPGFX_CAPS_FLAG_AV1_I444_DISABLED;
1177 if ((currentCaps->flags & RDPGFX_CAPS_FLAG_AV1_I444_DISABLED) != 0)
1178 pdu.capsSet->flags |= RDPGFX_CAPS_FLAG_AV1_I444_DISABLED;
1181 *rc = shadow_client_send_caps_confirm(context, client, &pdu);
1195static UINT shadow_client_rdpgfx_caps_advertise(RdpgfxServerContext* context,
1198 UINT rc = ERROR_INTERNAL_ERROR;
1202 WINPR_ASSERT(context);
1203 WINPR_ASSERT(capsAdvertise);
1205 rdpShadowClient* client = (rdpShadowClient*)context->custom;
1206 WINPR_ASSERT(client);
1207 WINPR_ASSERT(context->rdpcontext);
1209 const rdpSettings* srvSettings = context->rdpcontext->settings;
1210 WINPR_ASSERT(srvSettings);
1212 rdpSettings* clientSettings = client->context.settings;
1213 WINPR_ASSERT(clientSettings);
1216 if (!shadow_client_refresh_rect(&client->context, 0,
nullptr))
1219 const UINT32 capsVersions[] = {
1220#if defined(WITH_GFX_AV2)
1221 RDPGFX_CAPVERSION_FRDP_2,
1223#if defined(WITH_GFX_AV1)
1224 RDPGFX_CAPVERSION_FRDP_1,
1226#if defined(WITH_GFX_AZURE)
1227 RDPGFX_CAPVERSION_115, RDPGFX_CAPVERSION_113, RDPGFX_CAPVERSION_112,
1228 RDPGFX_CAPVERSION_111,
1230 RDPGFX_CAPVERSION_107, RDPGFX_CAPVERSION_106, RDPGFX_CAPVERSION_106_ERR,
1231 RDPGFX_CAPVERSION_105, RDPGFX_CAPVERSION_104, RDPGFX_CAPVERSION_103,
1232 RDPGFX_CAPVERSION_102, RDPGFX_CAPVERSION_101, RDPGFX_CAPVERSION_10,
1236 shadow_encoder_prepare(client->encoder, FREERDP_CODEC_AVC420 | FREERDP_CODEC_AVC444) >= 0;
1238#if defined(WITH_GFX_AV1)
1242 const UINT32 profile =
1247 codec = FREERDP_CODEC_AV1_I420;
1250 codec = FREERDP_CODEC_AV1_I444;
1253 return ERROR_BAD_PROFILE;
1255 const BOOL av1 = shadow_encoder_prepare(client->encoder, codec) >= 0;
1259 return ERROR_INTERNAL_ERROR;
1263#if defined(WITH_GFX_AV2)
1267 const UINT32 profile =
1272 codec = FREERDP_CODEC_AV2_I420;
1275 codec = FREERDP_CODEC_AV2_I444;
1278 return ERROR_BAD_PROFILE;
1280 const BOOL av2 = shadow_encoder_prepare(client->encoder, codec) >= 0;
1284 return ERROR_INTERNAL_ERROR;
1289 for (
size_t x = 0; x < ARRAYSIZE(capsVersions); x++)
1291 const UINT32 cur = capsVersions[x];
1292 if (shadow_client_caps_test_version(context, client, h264, capsAdvertise->capsSets,
1293 capsAdvertise->capsSetCount, cur, &rc))
1297 if (!shadow_are_caps_filtered(srvSettings, RDPGFX_CAPVERSION_81))
1299 for (UINT32 index = 0; index < capsAdvertise->capsSetCount; index++)
1301 const RDPGFX_CAPSET* currentCaps = &capsAdvertise->capsSets[index];
1303 if (currentCaps->version == RDPGFX_CAPVERSION_81)
1307 pdu.capsSet = ∩︀
1309 flags = pdu.capsSet->flags;
1317 (flags & RDPGFX_CAPS_FLAG_THINCLIENT) != 0))
1320 (flags & RDPGFX_CAPS_FLAG_SMALL_CACHE) != 0))
1323#ifndef WITH_GFX_H264
1327 pdu.capsSet->flags &= ~RDPGFX_CAPS_FLAG_AVC420_ENABLED;
1332 return shadow_client_send_caps_confirm(context, client, &pdu);
1337 if (!shadow_are_caps_filtered(srvSettings, RDPGFX_CAPVERSION_8))
1339 for (UINT32 index = 0; index < capsAdvertise->capsSetCount; index++)
1341 const RDPGFX_CAPSET* currentCaps = &capsAdvertise->capsSets[index];
1343 if (currentCaps->version == RDPGFX_CAPVERSION_8)
1347 pdu.capsSet = ∩︀
1348 flags = pdu.capsSet->flags;
1358 (flags & RDPGFX_CAPS_FLAG_THINCLIENT) != 0))
1361 (flags & RDPGFX_CAPS_FLAG_SMALL_CACHE) != 0))
1364 return shadow_client_send_caps_confirm(context, client, &pdu);
1369 return CHANNEL_RC_UNSUPPORTED_VERSION;
1376 WINPR_ASSERT(havc420);
1377 return sizeof(UINT32)
1379 * havc420->meta.numRegionRects +
1383#if defined(WITH_GFX_AV1)
1385static BOOL shadow_client_av1_enabled(
const rdpShadowClient* client)
1387 WINPR_ASSERT(client);
1389 (client->confirmedCaps.version == RDPGFX_CAPVERSION_FRDP_1);
1393static BOOL shadow_client_send_av1(rdpShadowClient* client,
const BYTE* pSrcData, UINT32 nSrcStep,
1394 UINT32 SrcFormat, UINT16 nWidth, UINT16 nHeight,
1399 WINPR_ASSERT(client);
1401 rdpShadowEncoder* encoder = client->encoder;
1402 WINPR_ASSERT(encoder);
1404 UINT error = CHANNEL_RC_OK;
1408 UINT32 flags = FREERDP_CODEC_AV1_I444;
1409 if ((client->confirmedCaps.flags & RDPGFX_CAPS_FLAG_AV1_I444_DISABLED) != 0)
1410 flags = FREERDP_CODEC_AV1_I420;
1412 if (shadow_encoder_prepare(encoder, flags) < 0)
1414 WLog_ERR(TAG,
"Failed to prepare encoder FREERDP_CODEC_AV1");
1419 WINPR_ASSERT(damage);
1420 rc = freerdp_av1_compress(encoder->av1, pSrcData, SrcFormat, nSrcStep, nWidth, nHeight, damage,
1421 &avc420.data, &avc420.length, &avc420.meta);
1424 WLog_ERR(TAG,
"freerdp_av1_compress failed");
1431 cmd->codecId = RDPGFX_CODECID_AV1;
1432 cmd->extra = (
void*)&avc420;
1434 IFCALLRET(client->rdpgfx->SurfaceFrameCommand, error, client->rdpgfx, cmd, cmdstart,
1436 cmd->extra =
nullptr;
1438 free_h264_metablock(&avc420.meta);
1442 WLog_ERR(TAG,
"SurfaceFrameCommand failed with error %" PRIu32
"", error);
1449#if defined(WITH_GFX_AV2)
1451static BOOL shadow_client_send_av2(rdpShadowClient* client,
const BYTE* pSrcData, UINT32 nSrcStep,
1452 UINT32 SrcFormat, UINT16 nWidth, UINT16 nHeight,
1457 WINPR_ASSERT(client);
1459 rdpShadowEncoder* encoder = client->encoder;
1460 WINPR_ASSERT(encoder);
1462 UINT error = CHANNEL_RC_OK;
1467 UINT32 flags = FREERDP_CODEC_AV2_I444;
1468 if ((client->confirmedCaps.flags & RDPGFX_CAPS_FLAG_AV1_I444_DISABLED) != 0)
1469 flags = FREERDP_CODEC_AV2_I420;
1471 if (shadow_encoder_prepare(encoder, flags) < 0)
1473 WLog_ERR(TAG,
"Failed to prepare encoder FREERDP_CODEC_AV2");
1477 WINPR_ASSERT(cmd->left <= UINT16_MAX);
1478 WINPR_ASSERT(cmd->top <= UINT16_MAX);
1479 WINPR_ASSERT(cmd->right <= UINT16_MAX);
1480 WINPR_ASSERT(cmd->bottom <= UINT16_MAX);
1481 regionRect.left = (UINT16)cmd->left;
1482 regionRect.top = (UINT16)cmd->top;
1483 regionRect.right = (UINT16)cmd->right;
1484 regionRect.bottom = (UINT16)cmd->bottom;
1485 rc = freerdp_av2_compress(encoder->av2, pSrcData, SrcFormat, nSrcStep, nWidth, nHeight,
1486 ®ionRect, &avc420.data, &avc420.length, &avc420.meta);
1489 WLog_ERR(TAG,
"freerdp_av2_compress failed");
1497 cmd->codecId = RDPGFX_CODECID_AV1;
1498 cmd->extra = (
void*)&avc420;
1500 IFCALLRET(client->rdpgfx->SurfaceFrameCommand, error, client->rdpgfx, cmd, cmdstart,
1502 cmd->extra =
nullptr;
1504 free_h264_metablock(&avc420.meta);
1508 WLog_ERR(TAG,
"SurfaceFrameCommand failed with error %" PRIu32
"", error);
1516static BOOL shadow_client_send_avc444(rdpShadowClient* client,
const BYTE* pSrcData,
1517 UINT32 nSrcStep, UINT32 SrcFormat, UINT16 nWidth,
1522 WINPR_ASSERT(client);
1524 rdpShadowEncoder* encoder = client->encoder;
1525 WINPR_ASSERT(encoder);
1527 UINT error = CHANNEL_RC_OK;
1531 const BOOL GfxAVC444v2 = (cmd->codecId == RDPGFX_CODECID_AVC444v2);
1532 BYTE version = GfxAVC444v2 ? 2 : 1;
1534 if (shadow_encoder_prepare(encoder, FREERDP_CODEC_AVC444) < 0)
1536 WLog_ERR(TAG,
"Failed to prepare encoder FREERDP_CODEC_AVC444");
1540 WINPR_ASSERT(cmd->left <= UINT16_MAX);
1541 WINPR_ASSERT(cmd->top <= UINT16_MAX);
1542 WINPR_ASSERT(cmd->right <= UINT16_MAX);
1543 WINPR_ASSERT(cmd->bottom <= UINT16_MAX);
1544 regionRect.left = (UINT16)cmd->left;
1545 regionRect.top = (UINT16)cmd->top;
1546 regionRect.right = (UINT16)cmd->right;
1547 regionRect.bottom = (UINT16)cmd->bottom;
1548 rc = avc444_compress(encoder->h264, pSrcData, SrcFormat, nSrcStep, nWidth, nHeight, version,
1549 ®ionRect, &avc444.LC, &avc444.bitstream[0].data,
1550 &avc444.bitstream[0].length, &avc444.bitstream[1].data,
1551 &avc444.bitstream[1].length, &avc444.bitstream[0].meta,
1552 &avc444.bitstream[1].meta);
1555 WLog_ERR(TAG,
"avc420_compress failed for avc444");
1562 avc444.cbAvc420EncodedBitstream1 = rdpgfx_estimate_h264_avc420(&avc444.bitstream[0]);
1563 cmd->extra = (
void*)&avc444;
1564 IFCALLRET(client->rdpgfx->SurfaceFrameCommand, error, client->rdpgfx, cmd, cmdstart,
1566 cmd->extra =
nullptr;
1569 free_h264_metablock(&avc444.bitstream[0].meta);
1570 free_h264_metablock(&avc444.bitstream[1].meta);
1573 WLog_ERR(TAG,
"SurfaceFrameCommand failed with error %" PRIu32
"", error);
1580static BOOL shadow_client_send_avc420(rdpShadowClient* client,
const BYTE* pSrcData,
1581 UINT32 nSrcStep, UINT32 SrcFormat, UINT16 nWidth,
1586 WINPR_ASSERT(client);
1588 rdpShadowEncoder* encoder = client->encoder;
1589 WINPR_ASSERT(encoder);
1591 UINT error = CHANNEL_RC_OK;
1596 if (shadow_encoder_prepare(encoder, FREERDP_CODEC_AVC420) < 0)
1598 WLog_ERR(TAG,
"Failed to prepare encoder FREERDP_CODEC_AVC420");
1602 WINPR_ASSERT(cmd->left <= UINT16_MAX);
1603 WINPR_ASSERT(cmd->top <= UINT16_MAX);
1604 WINPR_ASSERT(cmd->right <= UINT16_MAX);
1605 WINPR_ASSERT(cmd->bottom <= UINT16_MAX);
1606 regionRect.left = (UINT16)cmd->left;
1607 regionRect.top = (UINT16)cmd->top;
1608 regionRect.right = (UINT16)cmd->right;
1609 regionRect.bottom = (UINT16)cmd->bottom;
1610 rc = avc420_compress(encoder->h264, pSrcData, SrcFormat, nSrcStep, nWidth, nHeight, ®ionRect,
1611 &avc420.data, &avc420.length, &avc420.meta);
1614 WLog_ERR(TAG,
"avc420_compress failed");
1621 cmd->codecId = RDPGFX_CODECID_AVC420;
1622 cmd->extra = (
void*)&avc420;
1623 IFCALLRET(client->rdpgfx->SurfaceFrameCommand, error, client->rdpgfx, cmd, cmdstart,
1625 cmd->extra =
nullptr;
1627 free_h264_metablock(&avc420.meta);
1631 WLog_ERR(TAG,
"SurfaceFrameCommand failed with error %" PRIu32
"", error);
1638static BOOL shadow_client_send_rfx(rdpShadowClient* client,
const BYTE* pSrcData, UINT32 nSrcStep,
1639 UINT32 SrcFormat, UINT16 nWidth, UINT16 nHeight,
1644 WINPR_ASSERT(client);
1646 rdpShadowEncoder* encoder = client->encoder;
1647 WINPR_ASSERT(encoder);
1649 UINT error = CHANNEL_RC_OK;
1652 if (shadow_encoder_prepare(encoder, FREERDP_CODEC_REMOTEFX) < 0)
1654 WLog_ERR(TAG,
"Failed to prepare encoder FREERDP_CODEC_REMOTEFX");
1658 const UINT32 rfxFormat = rfx_context_get_pixel_format(encoder->rfx);
1659 if (rfxFormat != SrcFormat)
1661 WLog_ERR(TAG,
"RFX context pixel format mismatch %s, expected %s",
1662 FreeRDPGetColorFormatName(rfxFormat), FreeRDPGetColorFormatName(SrcFormat));
1666 wStream* s = Stream_New(
nullptr, 1024);
1669 WINPR_ASSERT(cmd->left <= UINT16_MAX);
1670 WINPR_ASSERT(cmd->top <= UINT16_MAX);
1671 WINPR_ASSERT(cmd->right <= UINT16_MAX);
1672 WINPR_ASSERT(cmd->bottom <= UINT16_MAX);
1681 UINT16 numRects = 0;
1684 if (shadow_rfx_plan_tiles(encoder, pSrcData, nSrcStep, cmd, nWidth, nHeight, &rects,
1687 WLog_ERR(TAG,
"shadow_rfx_plan_tiles failed");
1688 Stream_Free(s, TRUE);
1703 Stream_Free(s, TRUE);
1708 rc = rfx_compose_message(encoder->rfx, s, rects, numRects, pSrcData, nWidth, nHeight,
1713 const size_t pos = Stream_GetPosition(s);
1714 shadow_rfx_commit_tiles(encoder, pSrcData, nSrcStep, rects, numRects,
1715 WINPR_ASSERTING_INT_CAST(UINT32, pos));
1723 WLog_ERR(TAG,
"rfx_compose_message failed");
1724 Stream_Free(s, TRUE);
1731 const size_t pos = Stream_GetPosition(s);
1732 WINPR_ASSERT(pos <= UINT32_MAX);
1734 cmd->codecId = RDPGFX_CODECID_CAVIDEO;
1735 cmd->data = Stream_Buffer(s);
1736 cmd->length = (UINT32)pos;
1738 IFCALLRET(client->rdpgfx->SurfaceFrameCommand, error, client->rdpgfx, cmd, cmdstart,
1740 cmd->data =
nullptr;
1743 Stream_Free(s, TRUE);
1746 WLog_ERR(TAG,
"SurfaceFrameCommand failed with error %" PRIu32
"", error);
1753static BOOL shadow_client_send_progressive(rdpShadowClient* client,
const BYTE* pSrcData,
1754 UINT32 nSrcStep, UINT32 SrcFormat, UINT16 nWidth,
1759 WINPR_ASSERT(client);
1761 rdpShadowEncoder* encoder = client->encoder;
1762 WINPR_ASSERT(encoder);
1764 UINT error = CHANNEL_RC_OK;
1769 if (shadow_encoder_prepare(encoder, FREERDP_CODEC_PROGRESSIVE) < 0)
1771 WLog_ERR(TAG,
"Failed to prepare encoder FREERDP_CODEC_PROGRESSIVE");
1775 WINPR_ASSERT(cmd->left <= UINT16_MAX);
1776 WINPR_ASSERT(cmd->top <= UINT16_MAX);
1777 WINPR_ASSERT(cmd->right <= UINT16_MAX);
1778 WINPR_ASSERT(cmd->bottom <= UINT16_MAX);
1779 regionRect.left = (UINT16)cmd->left;
1780 regionRect.top = (UINT16)cmd->top;
1781 regionRect.right = (UINT16)cmd->right;
1782 regionRect.bottom = (UINT16)cmd->bottom;
1783 region16_init(®ion);
1784 if (!region16_union_rect(®ion, ®ion, ®ionRect))
1786 region16_uninit(®ion);
1789 rc = progressive_compress(encoder->progressive, pSrcData, nSrcStep * nHeight, SrcFormat, nWidth,
1790 nHeight, nSrcStep, ®ion, &cmd->data, &cmd->length);
1791 region16_uninit(®ion);
1794 WLog_ERR(TAG,
"progressive_compress failed");
1801 cmd->codecId = RDPGFX_CODECID_CAPROGRESSIVE;
1803 IFCALLRET(client->rdpgfx->SurfaceFrameCommand, error, client->rdpgfx, cmd, cmdstart,
1806 cmd->data =
nullptr;
1810 WLog_ERR(TAG,
"SurfaceFrameCommand failed with error %" PRIu32
"", error);
1817static BOOL shadow_client_send_planar(rdpShadowClient* client,
const BYTE* pSrcData,
1818 UINT32 nSrcStep, UINT32 SrcFormat,
1823 WINPR_ASSERT(client);
1825 rdpShadowEncoder* encoder = client->encoder;
1826 WINPR_ASSERT(encoder);
1828 UINT error = CHANNEL_RC_OK;
1829 const UINT32 w = cmd->right - cmd->left;
1830 const UINT32 h = cmd->bottom - cmd->top;
1832 &pSrcData[cmd->top * nSrcStep + cmd->left * FreeRDPGetBytesPerPixel(SrcFormat)];
1833 if (shadow_encoder_prepare(encoder, FREERDP_CODEC_PLANAR) < 0)
1835 WLog_ERR(TAG,
"Failed to prepare encoder FREERDP_CODEC_PLANAR");
1839 const BOOL rc = freerdp_bitmap_planar_context_reset(encoder->planar, w, h);
1843 freerdp_planar_topdown_image(encoder->planar, TRUE);
1845 cmd->data = freerdp_bitmap_compress_planar(encoder->planar, src, SrcFormat, w, h, nSrcStep,
1846 nullptr, &cmd->length);
1847 WINPR_ASSERT(cmd->data || (cmd->length == 0));
1849 cmd->codecId = RDPGFX_CODECID_PLANAR;
1851 IFCALLRET(client->rdpgfx->SurfaceFrameCommand, error, client->rdpgfx, cmd, cmdstart, cmdend);
1853 cmd->data =
nullptr;
1857 WLog_ERR(TAG,
"SurfaceFrameCommand failed with error %" PRIu32
"", error);
1864static BOOL shadow_client_send_uncompressed(rdpShadowClient* client,
const BYTE* pSrcData,
1865 UINT32 nSrcStep, UINT32 SrcFormat,
1870 WINPR_ASSERT(client);
1872 WINPR_ASSERT(pSrcData);
1873 WINPR_ASSERT(cmdstart);
1874 WINPR_ASSERT(cmdend);
1876 UINT error = CHANNEL_RC_OK;
1878 WINPR_ASSERT(cmd->right >= cmd->left);
1879 WINPR_ASSERT(cmd->bottom >= cmd->top);
1881 const UINT32 w = cmd->right - cmd->left;
1882 const UINT32 h = cmd->bottom - cmd->top;
1883 if ((w == 0) || (h == 0) || (w > UINT32_MAX / 4 / h))
1885 WLog_ERR(TAG,
"input width=%" PRIu32
" x height=%" PRIu32
" is 0 or exceeds UINT32_MAX", w,
1889 const UINT32 length = w * 4ul * h;
1893 WLog_ERR(TAG,
"input length == 0");
1897 BYTE* data = malloc(length);
1901 BOOL rc = freerdp_image_copy_no_overlap(data, cmd->format, 0, 0, 0, w, h, pSrcData, SrcFormat,
1902 nSrcStep, cmd->left, cmd->top,
nullptr, 0);
1910 cmd->length = length;
1911 cmd->codecId = RDPGFX_CODECID_UNCOMPRESSED;
1913 IFCALLRET(client->rdpgfx->SurfaceFrameCommand, error, client->rdpgfx, cmd, cmdstart, cmdend);
1915 cmd->data =
nullptr;
1918 WLog_ERR(TAG,
"SurfaceFrameCommand failed with error %" PRIu32
"", error);
1925static BOOL shadow_avc444_enabled(
const rdpShadowClient* client)
1927 WINPR_ASSERT(client);
1928 switch (client->confirmedCaps.version)
1930 case RDPGFX_CAPVERSION_10:
1931 case RDPGFX_CAPVERSION_101:
1932 case RDPGFX_CAPVERSION_102:
1933 case RDPGFX_CAPVERSION_103:
1934 case RDPGFX_CAPVERSION_104:
1935 case RDPGFX_CAPVERSION_105:
1936 case RDPGFX_CAPVERSION_106:
1937 case RDPGFX_CAPVERSION_107:
1938#if defined(WITH_GFX_AZURE)
1939 case RDPGFX_CAPVERSION_111:
1940 case RDPGFX_CAPVERSION_112:
1941 case RDPGFX_CAPVERSION_113:
1942 case RDPGFX_CAPVERSION_115:
1944 return (client->confirmedCaps.flags & RDPGFX_CAPS_FLAG_AVC_DISABLED) == 0;
1952static BOOL shadow_avc420_enabled(
const rdpShadowClient* client)
1954 if (shadow_avc444_enabled(client))
1956 if (client->confirmedCaps.version != RDPGFX_CAPVERSION_81)
1958 return (client->confirmedCaps.flags & RDPGFX_CAPS_FLAG_AVC420_ENABLED) != 0;
1967static BOOL shadow_client_send_surface_gfx(rdpShadowClient* client,
const BYTE* pSrcData,
1968 UINT32 nSrcStep, UINT32 SrcFormat, UINT16 nXSrc,
1969 UINT16 nYSrc, UINT16 nWidth, UINT16 nHeight,
1970 UINT16 srcWidth, UINT16 srcHeight,
1973 const rdpContext* context = (
const rdpContext*)client;
1979 if (!context || !pSrcData || !damage)
1982 const rdpSettings* settings = context->settings;
1983 rdpShadowEncoder* encoder = client->encoder;
1985 if (!settings || !encoder)
1988 if (client->first_frame)
1992 if (!rfx_context_reset(encoder->rfx, nWidth, nHeight))
1998 shadow_rfx_invalidate_snapshot(encoder);
1999 client->first_frame = FALSE;
2002 cmdstart.frameId = shadow_encoder_create_frame_id(encoder);
2003 GetSystemTime(&sTime);
2004 cmdstart.timestamp = (UINT32)(sTime.wHour << 22U | sTime.wMinute << 16U | sTime.wSecond << 10U |
2005 sTime.wMilliseconds);
2006 cmdend.frameId = cmdstart.frameId;
2007 cmd.surfaceId = client->surfaceId;
2008 cmd.format = PIXEL_FORMAT_BGRX32;
2011 cmd.right = cmd.left + nWidth;
2012 cmd.bottom = cmd.top + nHeight;
2014 cmd.height = nHeight;
2016#if defined(WITH_GFX_AV2)
2019 if (client->confirmedCaps.version == RDPGFX_CAPVERSION_FRDP_2)
2021 return shadow_client_send_av2(client, pSrcData, nSrcStep, SrcFormat, nWidth, nHeight,
2022 &cmd, &cmdstart, &cmdend);
2027#if defined(WITH_GFX_AV1)
2028 if (shadow_client_av1_enabled(client))
2030 return shadow_client_send_av1(client, pSrcData, nSrcStep, SrcFormat, nWidth, nHeight,
2031 damage, &cmd, &cmdstart, &cmdend);
2040 if (GfxAVC444 || GfxAVC444v2)
2042 if (shadow_avc444_enabled(client))
2044 cmd.codecId = GfxAVC444v2 ? RDPGFX_CODECID_AVC444v2 : RDPGFX_CODECID_AVC444;
2045 return shadow_client_send_avc444(client, pSrcData, nSrcStep, SrcFormat, nWidth, nHeight,
2046 &cmd, &cmdstart, &cmdend);
2050 if (GfxH264 && shadow_avc420_enabled(client))
2052 return shadow_client_send_avc420(client, pSrcData, nSrcStep, SrcFormat, nWidth, nHeight,
2053 &cmd, &cmdstart, &cmdend);
2062 return shadow_client_send_rfx(client, pSrcData, nSrcStep, SrcFormat, srcWidth, srcHeight,
2063 &cmd, &cmdstart, &cmdend);
2068 return shadow_client_send_progressive(client, pSrcData, nSrcStep, SrcFormat, nWidth,
2069 nHeight, &cmd, &cmdstart, &cmdend);
2074 return shadow_client_send_planar(client, pSrcData, nSrcStep, SrcFormat, &cmd, &cmdstart,
2078 return shadow_client_send_uncompressed(client, pSrcData, nSrcStep, SrcFormat, &cmd, &cmdstart,
2083static BOOL stream_surface_bits_supported(
const rdpSettings* settings)
2085 const UINT32 supported =
2087 return ((supported & SURFCMDS_STREAM_SURFACE_BITS) != 0);
2091static BOOL set_surface_bits_supported(
const rdpSettings* settings)
2093 const UINT32 supported =
2095 return ((supported & SURFCMDS_SET_SURFACE_BITS) != 0);
2099static BOOL is_surface_command_supported(
const rdpSettings* settings)
2101 if (stream_surface_bits_supported(settings))
2105 if (supported && (rfxID != 0))
2108 if (set_surface_bits_supported(settings))
2112 if (supported && (nsID != 0))
2124static BOOL shadow_client_send_surface_bits(rdpShadowClient* client, BYTE* pSrcData,
2125 UINT32 nSrcStep, UINT16 nXSrc, UINT16 nYSrc,
2126 UINT16 nWidth, UINT16 nHeight)
2132 size_t numMessages = 0;
2134 rdpUpdate* update =
nullptr;
2135 rdpContext* context = (rdpContext*)client;
2136 rdpSettings* settings =
nullptr;
2137 rdpShadowEncoder* encoder =
nullptr;
2140 if (!context || !pSrcData)
2143 update = context->update;
2144 settings = context->settings;
2145 encoder = client->encoder;
2147 if (!update || !settings || !encoder)
2150 if (encoder->frameAck)
2151 frameId = shadow_encoder_create_frame_id(encoder);
2156 if (stream_surface_bits_supported(settings) &&
2159 RFX_RECT rect = WINPR_C_ARRAY_INIT;
2161 if (shadow_encoder_prepare(encoder, FREERDP_CODEC_REMOTEFX) < 0)
2163 WLog_ERR(TAG,
"Failed to prepare encoder FREERDP_CODEC_REMOTEFX");
2170 rect.width = nWidth;
2171 rect.height = nHeight;
2173 const UINT32 MultifragMaxRequestSize =
2175 RFX_MESSAGE_LIST* messages =
2176 rfx_encode_messages(encoder->rfx, &rect, 1, pSrcData,
2179 nSrcStep, &numMessages, MultifragMaxRequestSize);
2182 WLog_ERR(TAG,
"rfx_encode_messages failed");
2186 cmd.cmdType = CMDTYPE_STREAM_SURFACE_BITS;
2187 WINPR_ASSERT(rfxID <= UINT16_MAX);
2188 cmd.bmp.codecID = (UINT16)rfxID;
2199 cmd.skipCompression = TRUE;
2201 for (
size_t i = 0; i < numMessages; i++)
2203 Stream_ResetPosition(s);
2205 const RFX_MESSAGE* msg = rfx_message_list_get(messages, i);
2206 if (!rfx_write_message(encoder->rfx, s, msg))
2208 WLog_ERR(TAG,
"rfx_write_message failed");
2213 cmd.bmp.bitmapDataLength = WINPR_ASSERTING_INT_CAST(UINT32, Stream_GetPosition(s));
2214 cmd.bmp.bitmapData = Stream_Buffer(s);
2216 last = ((i + 1) == numMessages);
2218 if (!encoder->frameAck)
2219 IFCALLRET(update->SurfaceBits, ret, update->context, &cmd);
2221 IFCALLRET(update->SurfaceFrameBits, ret, update->context, &cmd, first, last,
2226 WLog_ERR(TAG,
"Send surface bits(RemoteFxCodec) failed");
2231 rfx_message_list_free(messages);
2233 else if (set_surface_bits_supported(settings) &&
2236 if (shadow_encoder_prepare(encoder, FREERDP_CODEC_NSCODEC) < 0)
2238 WLog_ERR(TAG,
"Failed to prepare encoder FREERDP_CODEC_NSCODEC");
2243 Stream_ResetPosition(s);
2244 pSrcData = &pSrcData[(nYSrc * nSrcStep) + (nXSrc * 4)];
2245 if (!nsc_compose_message(encoder->nsc, s, pSrcData, nWidth, nHeight, nSrcStep))
2248 cmd.cmdType = CMDTYPE_SET_SURFACE_BITS;
2250 WINPR_ASSERT(nsID <= UINT16_MAX);
2251 cmd.bmp.codecID = (UINT16)nsID;
2252 cmd.destLeft = nXSrc;
2253 cmd.destTop = nYSrc;
2254 cmd.destRight = cmd.destLeft + nWidth;
2255 cmd.destBottom = cmd.destTop + nHeight;
2256 cmd.bmp.width = nWidth;
2257 cmd.bmp.height = nHeight;
2259 cmd.bmp.bitmapDataLength = WINPR_ASSERTING_INT_CAST(UINT32, Stream_GetPosition(s));
2260 cmd.bmp.bitmapData = Stream_Buffer(s);
2264 if (!encoder->frameAck)
2265 IFCALLRET(update->SurfaceBits, ret, update->context, &cmd);
2267 IFCALLRET(update->SurfaceFrameBits, ret, update->context, &cmd, first, last, frameId);
2271 WLog_ERR(TAG,
"Send surface bits(NSCodec) failed");
2284static BOOL shadow_client_send_bitmap_update(rdpShadowClient* client, BYTE* pSrcData,
2285 UINT32 nSrcStep, UINT16 nXSrc, UINT16 nYSrc,
2286 UINT16 nWidth, UINT16 nHeight)
2289 BYTE* data =
nullptr;
2290 BYTE* buffer =
nullptr;
2297 UINT32 SrcFormat = 0;
2299 rdpContext* context = (rdpContext*)client;
2300 UINT32 totalBitmapSize = 0;
2301 UINT32 updateSizeEstimate = 0;
2305 if (!context || !pSrcData)
2308 rdpUpdate* update = context->update;
2309 rdpSettings* settings = context->settings;
2310 rdpShadowEncoder* encoder = client->encoder;
2312 if (!update || !settings || !encoder)
2315 const UINT32 maxUpdateSize =
2319 if (shadow_encoder_prepare(encoder, FREERDP_CODEC_INTERLEAVED) < 0)
2321 WLog_ERR(TAG,
"Failed to prepare encoder FREERDP_CODEC_INTERLEAVED");
2327 if (shadow_encoder_prepare(encoder, FREERDP_CODEC_PLANAR) < 0)
2329 WLog_ERR(TAG,
"Failed to prepare encoder FREERDP_CODEC_PLANAR");
2334 SrcFormat = PIXEL_FORMAT_BGRX32;
2336 if ((nXSrc % 4) != 0)
2338 nWidth += (nXSrc % 4);
2339 nXSrc -= (nXSrc % 4);
2342 if ((nYSrc % 4) != 0)
2344 nHeight += (nYSrc % 4);
2345 nYSrc -= (nYSrc % 4);
2348 rows = (nHeight / 64) + ((nHeight % 64) ? 1 : 0);
2349 cols = (nWidth / 64) + ((nWidth % 64) ? 1 : 0);
2351 totalBitmapSize = 0;
2352 bitmapUpdate.number = rows * cols;
2357 bitmapUpdate.rectangles = bitmapData;
2359 if ((nWidth % 4) != 0)
2361 nWidth += (4 - (nWidth % 4));
2364 if ((nHeight % 4) != 0)
2366 nHeight += (4 - (nHeight % 4));
2369 for (yIdx = 0; yIdx < rows; yIdx++)
2371 for (xIdx = 0; xIdx < cols; xIdx++)
2373 bitmap = &bitmapData[k];
2375 bitmap->height = 64;
2376 bitmap->destLeft = nXSrc + (xIdx * 64);
2377 bitmap->destTop = nYSrc + (yIdx * 64);
2379 if (((INT64)bitmap->destLeft + bitmap->width) > (nXSrc + nWidth))
2380 bitmap->width = (UINT32)(nXSrc + nWidth) - bitmap->destLeft;
2382 if (((INT64)bitmap->destTop + bitmap->height) > (nYSrc + nHeight))
2383 bitmap->height = (UINT32)(nYSrc + nHeight) - bitmap->destTop;
2385 bitmap->destRight = bitmap->destLeft + bitmap->width - 1;
2386 bitmap->destBottom = bitmap->destTop + bitmap->height - 1;
2387 bitmap->compressed = TRUE;
2389 if ((bitmap->width < 4) || (bitmap->height < 4))
2395 UINT32 bytesPerPixel = (bitsPerPixel + 7) / 8;
2396 DstSize = 64 * 64 * 4;
2397 buffer = encoder->grid[k];
2399 ret = interleaved_compress(
2400 encoder->interleaved, buffer, &DstSize, bitmap->width, bitmap->height, pSrcData,
2401 SrcFormat, nSrcStep, bitmap->destLeft, bitmap->destTop,
nullptr, bitsPerPixel);
2404 bitmap->bitmapDataStream = buffer;
2405 bitmap->bitmapLength = DstSize;
2406 bitmap->bitsPerPixel = bitsPerPixel;
2407 bitmap->cbScanWidth = bitmap->width * bytesPerPixel;
2408 bitmap->cbUncompressedSize = bitmap->width * bitmap->height * bytesPerPixel;
2413 buffer = encoder->grid[k];
2414 data = &pSrcData[(bitmap->destTop * nSrcStep) + (bitmap->destLeft * 4)];
2417 freerdp_bitmap_compress_planar(encoder->planar, data, SrcFormat, bitmap->width,
2418 bitmap->height, nSrcStep, buffer, &dstSize);
2419 bitmap->bitmapDataStream = buffer;
2420 bitmap->bitmapLength = dstSize;
2421 bitmap->bitsPerPixel = 32;
2422 bitmap->cbScanWidth = bitmap->width * 4;
2423 bitmap->cbUncompressedSize = bitmap->width * bitmap->height * 4;
2426 bitmap->cbCompFirstRowSize = 0;
2427 bitmap->cbCompMainBodySize = bitmap->bitmapLength;
2428 totalBitmapSize += bitmap->bitmapLength;
2433 bitmapUpdate.number = k;
2434 updateSizeEstimate = totalBitmapSize + (k * bitmapUpdate.number) + 16;
2436 if (updateSizeEstimate > maxUpdateSize)
2440 UINT32 updateSize = 0;
2441 UINT32 newUpdateSize = 0;
2447 if (!fragBitmapData)
2449 WLog_ERR(TAG,
"Failed to allocate memory for fragBitmapData");
2454 bitmapUpdate.rectangles = fragBitmapData;
2460 newUpdateSize = updateSize + (bitmapData[i].bitmapLength + 16);
2462 if (newUpdateSize < maxUpdateSize)
2464 CopyMemory(&fragBitmapData[j++], &bitmapData[i++],
sizeof(
BITMAP_DATA));
2465 updateSize = newUpdateSize;
2468 if ((newUpdateSize >= maxUpdateSize) || (i + 1) >= k)
2470 bitmapUpdate.number = j;
2471 ret = BitmapUpdateProxy(client, &bitmapUpdate);
2481 free(fragBitmapData);
2485 ret = BitmapUpdateProxy(client, &bitmapUpdate);
2499static BOOL shadow_client_send_surface_update(rdpShadowClient* client, SHADOW_GFX_STATUS* pStatus)
2506 rdpContext* context = (rdpContext*)client;
2507 rdpSettings* settings =
nullptr;
2508 rdpShadowServer* server =
nullptr;
2509 rdpShadowSurface* surface =
nullptr;
2513 BYTE* pSrcData =
nullptr;
2514 UINT32 nSrcStep = 0;
2515 UINT32 SrcFormat = 0;
2516 UINT32 numRects = 0;
2519 if (!context || !pStatus)
2522 settings = context->settings;
2523 server = client->server;
2525 if (!settings || !server)
2528 surface = client->inLobby ? server->lobby : server->surface;
2534 EnterCriticalSection(&(client->lock));
2535 region16_init(&invalidRegion);
2537 const BOOL res = region16_copy(&invalidRegion, &(client->invalidRegion));
2538 region16_clear(&(client->invalidRegion));
2539 LeaveCriticalSection(&(client->lock));
2544 EnterCriticalSection(&surface->lock);
2545 rects = region16_rects(&(surface->invalidRegion), &numRects);
2547 for (UINT32 index = 0; index < numRects; index++)
2549 if (!region16_union_rect(&invalidRegion, &invalidRegion, &rects[index]))
2553 surfaceRect.left = 0;
2554 surfaceRect.top = 0;
2555 WINPR_ASSERT(surface->width <= UINT16_MAX);
2556 WINPR_ASSERT(surface->height <= UINT16_MAX);
2557 surfaceRect.right = (UINT16)surface->width;
2558 surfaceRect.bottom = (UINT16)surface->height;
2559 if (!region16_intersect_rect(&invalidRegion, &invalidRegion, &surfaceRect))
2562 if (server->shareSubRect)
2564 if (!region16_intersect_rect(&invalidRegion, &invalidRegion, &(server->subRect)))
2568 if (region16_is_empty(&invalidRegion))
2574 extents = region16_extents(&invalidRegion);
2575 nXSrc = extents->left;
2576 nYSrc = extents->top;
2577 nWidth = extents->right - extents->left;
2578 nHeight = extents->bottom - extents->top;
2579 pSrcData = surface->data;
2580 nSrcStep = surface->scanline;
2581 SrcFormat = surface->format;
2584 if (server->shareSubRect)
2588 subX = server->subRect.left;
2589 subY = server->subRect.top;
2592 WINPR_ASSERT(nXSrc >= 0);
2593 WINPR_ASSERT(nXSrc <= UINT16_MAX);
2594 WINPR_ASSERT(nYSrc >= 0);
2595 WINPR_ASSERT(nYSrc <= UINT16_MAX);
2596 pSrcData = &pSrcData[((UINT16)subY * nSrcStep) + ((UINT16)subX * 4U)];
2605 if (pStatus->gfxOpened && client->areGfxCapsReady)
2613 const RECTANGLE_16 damage = { .left = WINPR_ASSERTING_INT_CAST(UINT16, nXSrc),
2614 .top = WINPR_ASSERTING_INT_CAST(UINT16, nYSrc),
2615 .right = WINPR_ASSERTING_INT_CAST(UINT16, nXSrc + nWidth),
2617 WINPR_ASSERTING_INT_CAST(UINT16, nYSrc + nHeight) };
2618 const BOOL fullframegfx =
2619#if defined(WITH_GFX_AV1)
2620 shadow_client_av1_enabled(client) ||
2635 if (!pStatus->gfxSurfaceCreated)
2638 if (!(ret = shadow_client_rdpgfx_reset_graphic(client)))
2641 if (!(ret = shadow_client_rdpgfx_new_surface(client)))
2644 pStatus->gfxSurfaceCreated = TRUE;
2647 WINPR_ASSERT(nWidth >= 0);
2648 WINPR_ASSERT(nWidth <= UINT16_MAX);
2649 WINPR_ASSERT(nHeight >= 0);
2650 WINPR_ASSERT(nHeight <= UINT16_MAX);
2651 ret = shadow_client_send_surface_gfx(
2652 client, pSrcData, nSrcStep, SrcFormat, fullframegfx ? 0 : (UINT16)nXSrc,
2653 fullframegfx ? 0 : (UINT16)nYSrc, (UINT16)nWidth, (UINT16)nHeight,
2654 (UINT16)surface->width, (UINT16)surface->height, &damage);
2661 else if (is_surface_command_supported(settings))
2663 WINPR_ASSERT(nXSrc >= 0);
2664 WINPR_ASSERT(nXSrc <= UINT16_MAX);
2665 WINPR_ASSERT(nYSrc >= 0);
2666 WINPR_ASSERT(nYSrc <= UINT16_MAX);
2667 WINPR_ASSERT(nWidth >= 0);
2668 WINPR_ASSERT(nWidth <= UINT16_MAX);
2669 WINPR_ASSERT(nHeight >= 0);
2670 WINPR_ASSERT(nHeight <= UINT16_MAX);
2671 ret = shadow_client_send_surface_bits(client, pSrcData, nSrcStep, (UINT16)nXSrc,
2672 (UINT16)nYSrc, (UINT16)nWidth, (UINT16)nHeight);
2676 WINPR_ASSERT(nXSrc >= 0);
2677 WINPR_ASSERT(nXSrc <= UINT16_MAX);
2678 WINPR_ASSERT(nYSrc >= 0);
2679 WINPR_ASSERT(nYSrc <= UINT16_MAX);
2680 WINPR_ASSERT(nWidth >= 0);
2681 WINPR_ASSERT(nWidth <= UINT16_MAX);
2682 WINPR_ASSERT(nHeight >= 0);
2683 WINPR_ASSERT(nHeight <= UINT16_MAX);
2684 ret = shadow_client_send_bitmap_update(client, pSrcData, nSrcStep, (UINT16)nXSrc,
2685 (UINT16)nYSrc, (UINT16)nWidth, (UINT16)nHeight);
2689 LeaveCriticalSection(&surface->lock);
2690 region16_uninit(&invalidRegion);
2696static BOOL shadow_client_gfx_can_reset(rdpShadowClient* client,
const SHADOW_GFX_STATUS* pStatus)
2698 WINPR_ASSERT(client);
2699 WINPR_ASSERT(pStatus);
2701 return pStatus->gfxOpened && pStatus->gfxSurfaceCreated && client->areGfxCapsReady &&
2717static BOOL shadow_client_gfx_resize(rdpShadowClient* client, SHADOW_GFX_STATUS* pStatus)
2719 WINPR_ASSERT(client);
2720 WINPR_ASSERT(pStatus);
2721 WINPR_ASSERT(client->server);
2722 WINPR_ASSERT(client->server->surface);
2724 rdpSettings* settings = client->context.settings;
2725 WINPR_ASSERT(settings);
2730 .right = WINPR_ASSERTING_INT_CAST(UINT16, client->server->surface->width),
2731 .bottom = WINPR_ASSERTING_INT_CAST(UINT16, client->server->surface->height)
2733 if (client->server->shareSubRect)
2735 if (!rectangles_intersection(&viewport, &(client->server->subRect), &viewport))
2738 const UINT32 width = viewport.right - viewport.left;
2739 const UINT32 height = viewport.bottom - viewport.top;
2741 if (!shadow_client_rdpgfx_release_surface(client))
2743 pStatus->gfxSurfaceCreated = FALSE;
2750 if (!shadow_client_rdpgfx_reset_graphic(client))
2752 if (!shadow_client_rdpgfx_new_surface(client))
2754 pStatus->gfxSurfaceCreated = TRUE;
2757 if (shadow_encoder_reset(client->encoder) < 0)
2759 WLog_ERR(TAG,
"Failed to reset encoder");
2763 EnterCriticalSection(&(client->lock));
2764 region16_clear(&(client->invalidRegion));
2765 LeaveCriticalSection(&(client->lock));
2766 shadow_client_mark_invalid(client, 0,
nullptr);
2768 WLog_INFO(TAG,
"Client %s resized to %" PRIu32
"x%" PRIu32
" by Reset Graphics",
2769 client->context.peer->hostname, width, height);
2781static BOOL shadow_client_send_resize(rdpShadowClient* client, SHADOW_GFX_STATUS* pStatus)
2783 rdpContext* context = (rdpContext*)client;
2784 rdpSettings* settings =
nullptr;
2785 freerdp_peer* peer =
nullptr;
2787 if (!context || !pStatus)
2790 peer = context->peer;
2791 settings = context->settings;
2793 if (!peer || !settings)
2801 client->activated = FALSE;
2804 if (pStatus->gfxSurfaceCreated)
2806 if (!shadow_client_rdpgfx_release_surface(client))
2809 pStatus->gfxSurfaceCreated = FALSE;
2813 if (!shadow_send_desktop_resize(client))
2815 shadow_reset_desktop_resize(client);
2818 EnterCriticalSection(&(client->lock));
2819 region16_clear(&(client->invalidRegion));
2820 LeaveCriticalSection(&(client->lock));
2831static BOOL shadow_client_surface_update(rdpShadowClient* client,
REGION16* region)
2833 UINT32 numRects = 0;
2835 rects = region16_rects(region, &numRects);
2836 shadow_client_mark_invalid(client, numRects, rects);
2847static inline BOOL shadow_client_no_surface_update(rdpShadowClient* client,
2848 SHADOW_GFX_STATUS* pStatus)
2850 rdpShadowServer* server =
nullptr;
2851 rdpShadowSurface* surface =
nullptr;
2852 WINPR_UNUSED(pStatus);
2853 WINPR_ASSERT(client);
2854 server = client->server;
2855 WINPR_ASSERT(server);
2856 surface = client->inLobby ? server->lobby : server->surface;
2857 EnterCriticalSection(&surface->lock);
2858 const BOOL rc = shadow_client_surface_update(client, &(surface->invalidRegion));
2859 LeaveCriticalSection(&surface->lock);
2864static int shadow_client_subsystem_process_message(rdpShadowClient* client, wMessage* message)
2866 rdpContext* context = (rdpContext*)client;
2868 WINPR_ASSERT(message);
2869 WINPR_ASSERT(context);
2871 rdpUpdate* update = context->update;
2872 WINPR_ASSERT(update);
2876 switch (message->id)
2878 case SHADOW_MSG_OUT_POINTER_POSITION_UPDATE_ID:
2883 pointerPosition.xPos = msg->xPos;
2884 pointerPosition.yPos = msg->yPos;
2886 WINPR_ASSERT(client->server);
2887 if (client->server->shareSubRect)
2889 pointerPosition.xPos -= client->server->subRect.left;
2890 pointerPosition.yPos -= client->server->subRect.top;
2893 if (client->activated)
2895 if ((msg->xPos != client->pointerX) || (msg->yPos != client->pointerY))
2897 WINPR_ASSERT(update->pointer);
2898 if (!IFCALLRESULT(TRUE, update->pointer->PointerPosition, context,
2901 client->pointerX = msg->xPos;
2902 client->pointerY = msg->yPos;
2909 case SHADOW_MSG_OUT_POINTER_ALPHA_UPDATE_ID:
2918 pointerNew.xorBpp = 24;
2919 pointerColor = &(pointerNew.colorPtrAttr);
2920 pointerColor->cacheIndex = 0;
2921 pointerColor->hotSpotX = WINPR_ASSERTING_INT_CAST(UINT16, msg->xHot);
2922 pointerColor->hotSpotY = WINPR_ASSERTING_INT_CAST(UINT16, msg->yHot);
2923 pointerColor->width = WINPR_ASSERTING_INT_CAST(UINT16, msg->width);
2924 pointerColor->height = WINPR_ASSERTING_INT_CAST(UINT16, msg->height);
2925 pointerColor->lengthAndMask = WINPR_ASSERTING_INT_CAST(UINT16, msg->lengthAndMask);
2926 pointerColor->lengthXorMask = WINPR_ASSERTING_INT_CAST(UINT16, msg->lengthXorMask);
2927 pointerColor->xorMaskData = msg->xorMaskData;
2928 pointerColor->andMaskData = msg->andMaskData;
2929 pointerCached.cacheIndex = pointerColor->cacheIndex;
2931 if (client->activated)
2933 if (client->server->ShowMouseCursor)
2935 if (!IFCALLRESULT(TRUE, update->pointer->PointerNew, context, &pointerNew))
2937 if (!IFCALLRESULT(TRUE, update->pointer->PointerCached, context,
2944 pointer_system.type = SYSPTR_DEFAULT;
2945 if (!IFCALLRESULT(TRUE, update->pointer->PointerSystem, context,
2954 case SHADOW_MSG_OUT_AUDIO_OUT_SAMPLES_ID:
2963 if (client->activated && client->rdpsnd && client->rdpsnd->Activated &&
2964 (client->rdpsnd->selected_client_format < client->rdpsnd->num_client_formats))
2966 client->rdpsnd->src_format = msg->audio_format;
2969 IFCALLRESULT(CHANNEL_RC_OK, client->rdpsnd->SendSamples, client->rdpsnd,
2970 msg->buf, msg->nFrames, msg->wTimestamp);
2971 if (CHANNEL_RC_OK != error)
2973 shadow_client_free_queued_message(message);
2981 case SHADOW_MSG_OUT_AUDIO_OUT_VOLUME_ID:
2986 if (client->activated && client->rdpsnd && client->rdpsnd->Activated)
2988 const UINT error = IFCALLRESULT(CHANNEL_RC_OK, client->rdpsnd->SetVolume,
2989 client->rdpsnd, msg->left, msg->right);
2990 if (CHANNEL_RC_OK != error)
2992 shadow_client_free_queued_message(message);
3001 WLog_ERR(TAG,
"Unknown message id: %" PRIu32
"", message->id);
3005 shadow_client_free_queued_message(message);
3013static BOOL shadow_client_drain_channels(rdpShadowClient* client, BOOL autoOpen)
3015 WINPR_ASSERT(client);
3017 EnterCriticalSection(&client->vcmLock);
3018 const BOOL rc = WTSVirtualChannelManagerCheckFileDescriptorEx(client->vcm, autoOpen);
3019 LeaveCriticalSection(&client->vcmLock);
3026static DWORD WINAPI shadow_client_sound_thread(LPVOID arg)
3028 rdpShadowClient* client = (rdpShadowClient*)arg;
3029 WINPR_ASSERT(client);
3030 wMessageQueue* queue = client->SoundQueue;
3031 WINPR_ASSERT(queue);
3032 BOOL warned = FALSE;
3033 BOOL broken = FALSE;
3035 while (MessageQueue_Wait(queue))
3037 wMessage message = WINPR_C_ARRAY_INIT;
3039 BOOL queued = FALSE;
3041 while (MessageQueue_Peek(queue, &message, TRUE))
3043 if (message.id == WMQ_QUIT)
3052 shadow_client_free_queued_message(&message);
3057 const int rc = shadow_client_subsystem_process_message(client, &message);
3058 if ((rc < 0) && !warned)
3061 WLog_WARN(TAG,
"sound: the samples or the volume could not be sent");
3069 if (queued && !broken && !shadow_client_drain_channels(client, FALSE))
3072 WLog_DBG(TAG,
"sound: the channel data was not sent, no more sound for this client");
3083static void shadow_client_sound_thread_stop(rdpShadowClient* client)
3085 WINPR_ASSERT(client);
3087 if (!client->soundThread)
3091 if (!MessageQueue_PostQuit(client->SoundQueue, 0))
3092 WLog_ERR(TAG,
"sound: cannot ask the sound thread to stop");
3093 (void)WaitForSingleObject(client->soundThread, INFINITE);
3094 (void)CloseHandle(client->soundThread);
3095 client->soundThread =
nullptr;
3101#define SHADOW_GFX_ACK_STALL_MS 2000u
3109static BOOL shadow_client_gfx_must_wait(rdpShadowClient* client,
const SHADOW_GFX_STATUS* status)
3111 WINPR_ASSERT(client);
3112 WINPR_ASSERT(status);
3113 rdpShadowEncoder* encoder = client->encoder;
3114 WINPR_ASSERT(encoder);
3116 if ((encoder->maxInFlight == 0) || !status->gfxOpened || !client->areGfxCapsReady ||
3121 const UINT32 inFlight = shadow_encoder_inflight_frames(encoder);
3122 encoder->statsMaxInFlight = MAX(encoder->statsMaxInFlight, inFlight);
3123 if (inFlight < encoder->maxInFlight)
3126 const UINT64 now = GetTickCount64();
3127 if (!encoder->everAcked && (now - encoder->lastAckTick >= SHADOW_GFX_ACK_STALL_MS))
3129 if (!encoder->warnedNoAck)
3131 encoder->warnedNoAck = TRUE;
3133 "gfx: the client acknowledges no frame, one frame every %u ms (%" PRIu32
3135 SHADOW_GFX_ACK_STALL_MS, inFlight);
3138 encoder->lastAckTick = now;
3145static void shadow_client_gfx_stats(rdpShadowClient* client)
3147 WINPR_ASSERT(client);
3148 rdpShadowEncoder* encoder = client->encoder;
3149 WINPR_ASSERT(encoder);
3151 const UINT64 now = GetTickCount64();
3152 if (now - encoder->statsLogged < 5000)
3154 if (encoder->statsLogged != 0)
3156 "gfx: at most %" PRIu32
" of %" PRIu32
" frames in flight, %" PRIu64
3158 encoder->statsMaxInFlight, encoder->maxInFlight, encoder->statsHeld);
3159 encoder->statsMaxInFlight = 0;
3160 encoder->statsHeld = 0;
3161 encoder->statsLogged = now;
3165static DWORD WINAPI shadow_client_thread(LPVOID arg)
3167 rdpShadowClient* client = (rdpShadowClient*)arg;
3170 wMessage message = WINPR_C_ARRAY_INIT;
3171 wMessage pointerPositionMsg = WINPR_C_ARRAY_INIT;
3172 wMessage pointerAlphaMsg = WINPR_C_ARRAY_INIT;
3173 wMessage audioVolumeMsg = WINPR_C_ARRAY_INIT;
3174 HANDLE ChannelEvent =
nullptr;
3175 void* UpdateSubscriber =
nullptr;
3176 HANDLE UpdateEvent =
nullptr;
3177 freerdp_peer* peer =
nullptr;
3178 rdpContext* context =
nullptr;
3179 rdpSettings* settings =
nullptr;
3180 rdpShadowServer* server =
nullptr;
3181 rdpShadowSubsystem* subsystem =
nullptr;
3182 wMessageQueue* MsgQueue =
nullptr;
3184 SHADOW_GFX_STATUS gfxstatus = WINPR_C_ARRAY_INIT;
3185 rdpUpdate* update =
nullptr;
3187 WINPR_ASSERT(client);
3189 MsgQueue = client->MsgQueue;
3190 WINPR_ASSERT(MsgQueue);
3192 server = client->server;
3193 WINPR_ASSERT(server);
3194 subsystem = server->subsystem;
3195 context = (rdpContext*)client;
3196 peer = context->peer;
3198 WINPR_ASSERT(peer->context);
3200 settings = peer->context->settings;
3201 WINPR_ASSERT(settings);
3203 peer->Capabilities = shadow_client_capabilities;
3204 peer->PostConnect = shadow_client_post_connect;
3205 peer->Activate = shadow_client_activate;
3206 peer->Logon = shadow_client_logon;
3207 shadow_input_register_callbacks(peer->context->input);
3209 rc = peer->Initialize(peer);
3213 update = peer->context->update;
3214 WINPR_ASSERT(update);
3216 update->RefreshRect = shadow_client_refresh_rect;
3217 update->SuppressOutput = shadow_client_suppress_output;
3218 update->SurfaceFrameAcknowledge = shadow_client_surface_frame_acknowledge;
3220 if ((!client->vcm) || (!subsystem->updateEvent))
3223 ChannelEvent = WTSVirtualChannelManagerGetEventHandle(client->vcm);
3224 WINPR_ASSERT(ChannelEvent);
3235 client->soundThread = CreateThread(
nullptr, 0, shadow_client_sound_thread, client, 0,
nullptr);
3236 if (!client->soundThread)
3238 WLog_ERR(TAG,
"Failed to start the sound thread");
3244 HANDLE events[MAXIMUM_WAIT_OBJECTS] = WINPR_C_ARRAY_INIT;
3252 if (!UpdateSubscriber && client->activated)
3254 UpdateSubscriber = shadow_multiclient_get_subscriber(subsystem->updateEvent);
3256 if (!UpdateSubscriber)
3259 UpdateEvent = shadow_multiclient_getevent(UpdateSubscriber);
3260 WINPR_ASSERT(UpdateEvent);
3264 if (!shadow_client_refresh_request(client))
3269 events[nCount++] = UpdateEvent;
3271 DWORD tmp = peer->GetEventHandles(peer, &events[nCount], 64 - nCount);
3275 WLog_ERR(TAG,
"Failed to get FreeRDP transport event handles");
3281 events[nCount++] = ChannelEvent;
3282 events[nCount++] = MessageQueue_Event(MsgQueue);
3284#if defined(CHANNEL_RDPGFX_SERVER)
3285 HANDLE gfxevent = rdpgfx_server_get_event_handle(client->rdpgfx);
3288 events[nCount++] = gfxevent;
3292 const DWORD timeout = MIN(client->encoder->gfxHeld ? 100 : INFINITE,
3293 shadow_client_autodetect_timeout(client));
3294 status = WaitForMultipleObjects(nCount, events, FALSE, timeout);
3296 if (status == WAIT_FAILED)
3299 if (UpdateEvent && (WaitForSingleObject(UpdateEvent, 0) == WAIT_OBJECT_0))
3308 if (client->activated && !client->suppressOutput)
3313 if (shadow_client_recalc_desktop_size(client))
3315 if (shadow_client_gfx_can_reset(client, &gfxstatus))
3318 if (!shadow_client_gfx_resize(client, &gfxstatus))
3320 WLog_ERR(TAG,
"Failed to resize the graphics pipeline");
3323 if (!shadow_client_send_surface_update(client, &gfxstatus))
3325 WLog_ERR(TAG,
"Failed to send surface update");
3328 client->encoder->gfxHeld = FALSE;
3331 else if (!shadow_client_send_resize(client, &gfxstatus))
3333 WLog_ERR(TAG,
"Failed to send resize message");
3337 else if (shadow_client_gfx_must_wait(client, &gfxstatus))
3340 if (!shadow_client_no_surface_update(client, &gfxstatus))
3342 WLog_ERR(TAG,
"Failed to handle surface update");
3345 client->encoder->gfxHeld = TRUE;
3346 client->encoder->statsHeld++;
3351 if (!shadow_client_send_surface_update(client, &gfxstatus))
3353 WLog_ERR(TAG,
"Failed to send surface update");
3356 client->encoder->gfxHeld = FALSE;
3362 if (!shadow_client_no_surface_update(client, &gfxstatus))
3364 WLog_ERR(TAG,
"Failed to handle surface update");
3373 (void)shadow_multiclient_consume(UpdateSubscriber);
3376 WINPR_ASSERT(peer->CheckFileDescriptor);
3377 if (!peer->CheckFileDescriptor(peer))
3379 WLog_ERR(TAG,
"Failed to check FreeRDP file descriptor");
3383 if (!shadow_client_autodetect_poll(client))
3385 WLog_ERR(TAG,
"Failed to send an RTT Measure Request");
3389 if (client->activated &&
3390 WTSVirtualChannelManagerIsChannelJoined(client->vcm, DRDYNVC_SVC_CHANNEL_NAME))
3392 switch (WTSVirtualChannelManagerGetDrdynvcState(client->vcm))
3395 case DRDYNVC_STATE_NONE:
3398 if (!shadow_client_drain_channels(client, TRUE))
3400 WLog_ERR(TAG,
"Failed to initialize drdynvc channel");
3406 case DRDYNVC_STATE_READY:
3407#if defined(CHANNEL_AUDIN_SERVER)
3408 if (client->audin && !IFCALLRESULT(TRUE, client->audin->IsOpen, client->audin))
3410 if (!IFCALLRESULT(FALSE, client->audin->Open, client->audin))
3412 WLog_ERR(TAG,
"Failed to initialize audin channel");
3420 client->rdpgfx && !gfxstatus.gfxOpened)
3422 client->rdpgfx->FrameAcknowledge = shadow_client_rdpgfx_frame_acknowledge;
3423 client->rdpgfx->CapsAdvertise = shadow_client_rdpgfx_caps_advertise;
3425 if (!client->rdpgfx->Open(client->rdpgfx))
3427 WLog_WARN(TAG,
"Failed to open GraphicsPipeline");
3429 FreeRDP_SupportGraphicsPipeline, FALSE))
3434 gfxstatus.gfxOpened = TRUE;
3435 WLog_INFO(TAG,
"Gfx Pipeline Opened");
3446 if (WaitForSingleObject(ChannelEvent, 0) == WAIT_OBJECT_0)
3448 if (!shadow_client_drain_channels(client, TRUE))
3450 WLog_ERR(TAG,
"WTSVirtualChannelManagerCheckFileDescriptor failure");
3455#if defined(CHANNEL_RDPGFX_SERVER)
3458 if (WaitForSingleObject(gfxevent, 0) == WAIT_OBJECT_0)
3460 const UINT error = rdpgfx_server_handle_messages(client->rdpgfx);
3461 if (error != CHANNEL_RC_OK)
3469 if (client->encoder->gfxHeld && client->activated && !client->suppressOutput &&
3470 !shadow_client_gfx_must_wait(client, &gfxstatus))
3472 if (!shadow_client_send_surface_update(client, &gfxstatus))
3474 WLog_ERR(TAG,
"Failed to send surface update");
3477 client->encoder->gfxHeld = FALSE;
3479 if (client->activated)
3480 shadow_client_gfx_stats(client);
3482 if (WaitForSingleObject(MessageQueue_Event(MsgQueue), 0) == WAIT_OBJECT_0)
3485 pointerPositionMsg.id = 0;
3486 pointerPositionMsg.Free =
nullptr;
3487 pointerAlphaMsg.id = 0;
3488 pointerAlphaMsg.Free =
nullptr;
3489 audioVolumeMsg.id = 0;
3490 audioVolumeMsg.Free =
nullptr;
3492 while (MessageQueue_Peek(MsgQueue, &message, TRUE))
3494 if (message.id == WMQ_QUIT)
3501 case SHADOW_MSG_OUT_POINTER_POSITION_UPDATE_ID:
3503 shadow_client_free_queued_message(&pointerPositionMsg);
3504 pointerPositionMsg = message;
3507 case SHADOW_MSG_OUT_POINTER_ALPHA_UPDATE_ID:
3509 shadow_client_free_queued_message(&pointerAlphaMsg);
3510 pointerAlphaMsg = message;
3513 case SHADOW_MSG_OUT_AUDIO_OUT_VOLUME_ID:
3515 shadow_client_free_queued_message(&audioVolumeMsg);
3516 audioVolumeMsg = message;
3520 if (!shadow_client_subsystem_process_message(client, &message))
3526 if (message.id == WMQ_QUIT)
3529 shadow_client_free_queued_message(&pointerPositionMsg);
3530 shadow_client_free_queued_message(&pointerAlphaMsg);
3531 shadow_client_free_queued_message(&audioVolumeMsg);
3537 if (pointerPositionMsg.id)
3539 if (!shadow_client_subsystem_process_message(client, &pointerPositionMsg))
3543 if (pointerAlphaMsg.id)
3545 if (!shadow_client_subsystem_process_message(client, &pointerAlphaMsg))
3549 if (audioVolumeMsg.id)
3551 if (!shadow_client_subsystem_process_message(client, &audioVolumeMsg))
3561 shadow_client_sound_thread_stop(client);
3564#if defined(CHANNEL_AUDIN_SERVER)
3565 if (client->audin && !IFCALLRESULT(TRUE, client->audin->IsOpen, client->audin))
3567 if (!IFCALLRESULT(FALSE, client->audin->Close, client->audin))
3569 WLog_WARN(TAG,
"AUDIN shutdown failure!");
3574 if (gfxstatus.gfxOpened)
3576 if (gfxstatus.gfxSurfaceCreated)
3578 if (!shadow_client_rdpgfx_release_surface(client))
3579 WLog_WARN(TAG,
"GFX release surface failure!");
3582 WINPR_ASSERT(client->rdpgfx);
3583 WINPR_ASSERT(client->rdpgfx->Close);
3584 rc = client->rdpgfx->Close(client->rdpgfx);
3588 shadow_client_channels_free(client);
3590 if (UpdateSubscriber)
3592 shadow_multiclient_release_subscriber(UpdateSubscriber);
3593 UpdateSubscriber =
nullptr;
3596 if (peer->connected && subsystem->ClientDisconnect)
3598 subsystem->ClientDisconnect(subsystem, client);
3603 if (!shadow_input_release_keys(client))
3604 WLog_WARN(TAG,
"not every key the client held could be released");
3605 WINPR_ASSERT(peer->Disconnect);
3606 peer->Disconnect(peer);
3607 freerdp_peer_context_free(peer);
3608 freerdp_peer_free(peer);
3613BOOL shadow_client_accepted(freerdp_listener* listener, freerdp_peer* peer)
3615 rdpShadowClient* client =
nullptr;
3616 rdpShadowServer* server =
nullptr;
3618 if (!listener || !peer)
3621 server = (rdpShadowServer*)listener->info;
3622 WINPR_ASSERT(server);
3624 peer->ContextExtra = (
void*)server;
3625 peer->ContextSize =
sizeof(rdpShadowClient);
3626 peer->ContextNew = shadow_client_context_new;
3627 peer->ContextFree = shadow_client_context_free;
3629 if (!freerdp_peer_context_new_ex(peer, server->settings))
3632 client = (rdpShadowClient*)peer->context;
3633 WINPR_ASSERT(client);
3635 if (!(client->thread = CreateThread(
nullptr, 0, shadow_client_thread, client, 0,
nullptr)))
3637 freerdp_peer_context_free(peer);
3643 (void)CloseHandle(client->thread);
3644 client->thread =
nullptr;
3650static void shadow_msg_out_addref(wMessage* message)
3652 SHADOW_MSG_OUT* msg =
nullptr;
3654 WINPR_ASSERT(message);
3655 msg = (SHADOW_MSG_OUT*)message->wParam;
3658 InterlockedIncrement(&(msg->refCount));
3661static void shadow_msg_out_release(wMessage* message)
3663 SHADOW_MSG_OUT* msg =
nullptr;
3665 WINPR_ASSERT(message);
3666 msg = (SHADOW_MSG_OUT*)message->wParam;
3669 if (InterlockedDecrement(&(msg->refCount)) <= 0)
3671 IFCALL(msg->Free, message->id, msg);
3676static BOOL shadow_client_dispatch_msg(rdpShadowClient* client, wMessage* message)
3678 if (!client || !message)
3682 shadow_msg_out_addref(message);
3685 wMessageQueue* queue = client->MsgQueue;
3686 if ((message->id == SHADOW_MSG_OUT_AUDIO_OUT_SAMPLES_ID) ||
3687 (message->id == SHADOW_MSG_OUT_AUDIO_OUT_VOLUME_ID))
3688 queue = client->SoundQueue;
3690 WINPR_ASSERT(queue);
3691 if (MessageQueue_Dispatch(queue, message))
3696 shadow_msg_out_release(message);
3701BOOL shadow_client_post_msg(rdpShadowClient* client,
void* context, UINT32 type,
3702 SHADOW_MSG_OUT* msg,
void* lParam)
3704 wMessage message = WINPR_C_ARRAY_INIT;
3705 message.context = context;
3707 message.wParam = (
void*)msg;
3708 message.lParam = lParam;
3709 message.Free = shadow_msg_out_release;
3710 return shadow_client_dispatch_msg(client, &message);
3713int shadow_client_boardcast_msg(rdpShadowServer* server,
void* context, UINT32 type,
3714 SHADOW_MSG_OUT* msg,
void* lParam)
3716 wMessage message = WINPR_C_ARRAY_INIT;
3719 WINPR_ASSERT(server);
3722 message.context = context;
3724 message.wParam = (
void*)msg;
3725 message.lParam = lParam;
3726 message.Free = shadow_msg_out_release;
3729 shadow_msg_out_addref(&message);
3731 WINPR_ASSERT(server->clients);
3732 ArrayList_Lock(server->clients);
3734 for (
size_t index = 0; index < ArrayList_Count(server->clients); index++)
3736 rdpShadowClient* client = (rdpShadowClient*)ArrayList_GetItem(server->clients, index);
3738 if (shadow_client_dispatch_msg(client, &message))
3744 ArrayList_Unlock(server->clients);
3746 shadow_msg_out_release(&message);
3750int shadow_client_boardcast_quit(rdpShadowServer* server,
int nExitCode)
3752 wMessageQueue* queue =
nullptr;
3755 WINPR_ASSERT(server);
3756 WINPR_ASSERT(server->clients);
3758 ArrayList_Lock(server->clients);
3760 for (
size_t index = 0; index < ArrayList_Count(server->clients); index++)
3762 queue = ((rdpShadowClient*)ArrayList_GetItem(server->clients, index))->MsgQueue;
3764 if (MessageQueue_PostQuit(queue, nExitCode))
3770 ArrayList_Unlock(server->clients);
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.
This struct contains function pointer to initialize/free objects.