24#include <freerdp/config.h>
26#include <winpr/assert.h>
27#include <winpr/cast.h>
30#include <winpr/wlog.h>
31#include <winpr/print.h>
32#include <winpr/synch.h>
33#include <winpr/thread.h>
34#include <winpr/stream.h>
35#include <winpr/sysinfo.h>
36#include <winpr/cmdline.h>
37#include <winpr/collections.h>
39#include <freerdp/addin.h>
40#include <freerdp/channels/log.h>
42#include "rdpgfx_common.h"
43#include "rdpgfx_codec.h"
45#include "rdpgfx_main.h"
47#define GFXTAG CHANNELS_TAG("rdpgfx.client")
49#define RDPGFX_NUMBER_CAPSETS 0x100
51static BOOL delete_surface(
const void* key,
void* value,
void* arg)
53 const UINT16
id = (UINT16)(uintptr_t)(key);
57 RdpgfxClientContext* context = arg;
64 UINT error = CHANNEL_RC_OK;
65 IFCALLRET(context->DeleteSurface, error, context, &pdu);
71 WLog_Print(gfx->base.log, WLOG_ERROR,
72 "context->DeleteSurface failed with error %" PRIu32
"", error);
78static void free_surfaces(RdpgfxClientContext* context, wHashTable* SurfaceTable)
80 WINPR_ASSERT(context);
81 if (!HashTable_Foreach(SurfaceTable, delete_surface, context))
85 WLog_Print(gfx->base.log, WLOG_WARN,
"delete_surface failed");
89static UINT evict_cache_slots(RdpgfxClientContext* context, UINT16 MaxCacheSlots,
void** CacheSlots)
91 UINT error = CHANNEL_RC_OK;
93 WINPR_ASSERT(CacheSlots);
94 for (UINT16 index = 0; index < MaxCacheSlots; index++)
96 if (CacheSlots[index])
100 if (context && context->EvictCacheEntry)
102 const UINT rc = context->EvictCacheEntry(context, &pdu);
103 if (rc != CHANNEL_RC_OK)
107 CacheSlots[index] =
nullptr;
118static UINT rdpgfx_send_caps_advertise_pdu(RdpgfxClientContext* context,
121 UINT error = CHANNEL_RC_OK;
124 WINPR_ASSERT(context);
128 if (!gfx || !gfx->base.listener_callback)
129 return ERROR_BAD_ARGUMENTS;
134 .cmdId = RDPGFX_CMDID_CAPSADVERTISE,
135 .pduLength = RDPGFX_HEADER_SIZE + 2 };
137 for (UINT16 index = 0; index < pdu->capsSetCount; index++)
140 header.pduLength += RDPGFX_CAPSET_BASE_SIZE + capsSet->length;
143 WLog_Print(gfx->base.log, WLOG_DEBUG,
"SendCapsAdvertisePdu %" PRIu16
"", pdu->capsSetCount);
144 wStream* s = Stream_New(
nullptr, header.pduLength);
148 WLog_Print(gfx->base.log, WLOG_ERROR,
"Stream_New failed!");
149 return CHANNEL_RC_NO_MEMORY;
152 if ((error = rdpgfx_write_header(s, &header)))
156 Stream_Write_UINT16(s, pdu->capsSetCount);
158 for (UINT16 index = 0; index < pdu->capsSetCount; index++)
162 WLog_Print(gfx->base.log, WLOG_DEBUG,
"Sending %s [0x%08" PRIx32
"] flags=0x%08" PRIx32,
163 rdpgfx_caps_version_str(capsSet->version), capsSet->version, capsSet->flags);
165 Stream_Write_UINT32(s, capsSet->version);
166 Stream_Write_UINT32(s, capsSet->length);
167 Stream_Write_UINT32(s, capsSet->flags);
168 Stream_Zero(s, capsSet->length - 4);
171 Stream_SealLength(s);
172 error = callback->channel->Write(callback->channel, (UINT32)Stream_Length(s), Stream_Buffer(s),
175 Stream_Free(s, TRUE);
179static BOOL rdpgfx_is_capability_filtered(
RDPGFX_PLUGIN* gfx, UINT32 caps)
182 const UINT32 filter =
184 const UINT32 capList[] = {
185#if defined(WITH_GFX_AV1)
186 RDPGFX_CAPVERSION_FRDP_1,
188 RDPGFX_CAPVERSION_8, RDPGFX_CAPVERSION_81, RDPGFX_CAPVERSION_10,
189 RDPGFX_CAPVERSION_101, RDPGFX_CAPVERSION_102, RDPGFX_CAPVERSION_103,
190 RDPGFX_CAPVERSION_104, RDPGFX_CAPVERSION_105, RDPGFX_CAPVERSION_106,
191 RDPGFX_CAPVERSION_106_ERR, RDPGFX_CAPVERSION_107
194 for (
size_t x = 0; x < ARRAYSIZE(capList); x++)
196 if (caps == capList[x])
197 return (filter & (1u << x)) != 0;
207 WINPR_ASSERT(pdu->capsSets);
208 WINPR_ASSERT(count > 0);
209 WINPR_ASSERT(pdu->capsSetCount < count);
210 if (pdu->capsSetCount >= count)
212 return &pdu->capsSets[pdu->capsSetCount++];
222 RDPGFX_CAPSET capsSets[RDPGFX_NUMBER_CAPSETS] = WINPR_C_ARRAY_INIT;
225 return ERROR_BAD_ARGUMENTS;
230 return ERROR_BAD_CONFIGURATION;
232 RdpgfxClientContext* context = gfx->context;
235 return ERROR_BAD_CONFIGURATION;
239 if (!rdpgfx_is_capability_filtered(gfx, RDPGFX_CAPVERSION_8))
241 RDPGFX_CAPSET* capsSet = nextCapset(&pdu, ARRAYSIZE(capsSets));
243 return ERROR_BAD_CONFIGURATION;
244 capsSet->version = RDPGFX_CAPVERSION_8;
249 capsSet->flags |= RDPGFX_CAPS_FLAG_THINCLIENT;
256 capsSet->flags |= RDPGFX_CAPS_FLAG_SMALL_CACHE;
259 if (!rdpgfx_is_capability_filtered(gfx, RDPGFX_CAPVERSION_81))
261 RDPGFX_CAPSET* capsSet = nextCapset(&pdu, ARRAYSIZE(capsSets));
263 return ERROR_BAD_CONFIGURATION;
264 capsSet->version = RDPGFX_CAPVERSION_81;
269 capsSet->flags |= RDPGFX_CAPS_FLAG_THINCLIENT;
272 capsSet->flags |= RDPGFX_CAPS_FLAG_SMALL_CACHE;
277 capsSet->flags |= RDPGFX_CAPS_FLAG_AVC420_ENABLED;
282 UINT32 caps10Flags = 0;
287 caps10Flags |= RDPGFX_CAPS_FLAG_SMALL_CACHE;
292 caps10Flags |= RDPGFX_CAPS_FLAG_AVC_DISABLED;
295 caps10Flags |= RDPGFX_CAPS_FLAG_AVC_DISABLED;
298 if (!rdpgfx_is_capability_filtered(gfx, RDPGFX_CAPVERSION_10))
300 RDPGFX_CAPSET* capsSet = nextCapset(&pdu, ARRAYSIZE(capsSets));
302 return ERROR_BAD_CONFIGURATION;
303 capsSet->version = RDPGFX_CAPVERSION_10;
305 capsSet->flags = caps10Flags;
308 if (!rdpgfx_is_capability_filtered(gfx, RDPGFX_CAPVERSION_101))
310 RDPGFX_CAPSET* capsSet = nextCapset(&pdu, ARRAYSIZE(capsSets));
312 return ERROR_BAD_CONFIGURATION;
313 capsSet->version = RDPGFX_CAPVERSION_101;
314 capsSet->length = 0x10;
318 if (!rdpgfx_is_capability_filtered(gfx, RDPGFX_CAPVERSION_102))
320 RDPGFX_CAPSET* capsSet = nextCapset(&pdu, ARRAYSIZE(capsSets));
322 return ERROR_BAD_CONFIGURATION;
323 capsSet->version = RDPGFX_CAPVERSION_102;
324 capsSet->length = 0x4;
325 capsSet->flags = caps10Flags;
330 if ((caps10Flags & RDPGFX_CAPS_FLAG_AVC_DISABLED) == 0)
331 caps10Flags |= RDPGFX_CAPS_FLAG_AVC_THINCLIENT;
334 if (!rdpgfx_is_capability_filtered(gfx, RDPGFX_CAPVERSION_103))
336 RDPGFX_CAPSET* capsSet = nextCapset(&pdu, ARRAYSIZE(capsSets));
338 return ERROR_BAD_CONFIGURATION;
339 capsSet->version = RDPGFX_CAPVERSION_103;
340 capsSet->length = 0x4;
341 capsSet->flags = caps10Flags & ~RDPGFX_CAPS_FLAG_SMALL_CACHE;
344 if (!rdpgfx_is_capability_filtered(gfx, RDPGFX_CAPVERSION_104))
346 RDPGFX_CAPSET* capsSet = nextCapset(&pdu, ARRAYSIZE(capsSets));
348 return ERROR_BAD_CONFIGURATION;
349 capsSet->version = RDPGFX_CAPVERSION_104;
350 capsSet->length = 0x4;
351 capsSet->flags = caps10Flags;
357#if defined(WITH_CAIRO) || defined(WITH_SWSCALE)
358 if (!rdpgfx_is_capability_filtered(gfx, RDPGFX_CAPVERSION_105))
360 RDPGFX_CAPSET* capsSet = nextCapset(&pdu, ARRAYSIZE(capsSets));
362 return ERROR_BAD_CONFIGURATION;
363 capsSet->version = RDPGFX_CAPVERSION_105;
364 capsSet->length = 0x4;
365 capsSet->flags = caps10Flags;
368 if (!rdpgfx_is_capability_filtered(gfx, RDPGFX_CAPVERSION_106))
370 RDPGFX_CAPSET* capsSet = nextCapset(&pdu, ARRAYSIZE(capsSets));
372 return ERROR_BAD_CONFIGURATION;
373 capsSet->version = RDPGFX_CAPVERSION_106;
374 capsSet->length = 0x4;
375 capsSet->flags = caps10Flags;
378 if (!rdpgfx_is_capability_filtered(gfx, RDPGFX_CAPVERSION_106_ERR))
380 RDPGFX_CAPSET* capsSet = nextCapset(&pdu, ARRAYSIZE(capsSets));
382 return ERROR_BAD_CONFIGURATION;
383 capsSet->version = RDPGFX_CAPVERSION_106_ERR;
384 capsSet->length = 0x4;
385 capsSet->flags = caps10Flags;
389 if (!rdpgfx_is_capability_filtered(gfx, RDPGFX_CAPVERSION_107))
391 RDPGFX_CAPSET* capsSet = nextCapset(&pdu, ARRAYSIZE(capsSets));
393 return ERROR_BAD_CONFIGURATION;
394 capsSet->version = RDPGFX_CAPVERSION_107;
395 capsSet->length = 0x4;
396 capsSet->flags = caps10Flags;
397#if !defined(WITH_CAIRO) && !defined(WITH_SWSCALE)
398 capsSet->flags |= RDPGFX_CAPS_FLAG_SCALEDMAP_DISABLE;
403#if defined(WITH_GFX_AV1)
406 if (!rdpgfx_is_capability_filtered(gfx, RDPGFX_CAPVERSION_FRDP_1))
408 RDPGFX_CAPSET* capsSet = nextCapset(&pdu, ARRAYSIZE(capsSets));
410 return ERROR_BAD_CONFIGURATION;
411 capsSet->version = RDPGFX_CAPVERSION_FRDP_1;
412 capsSet->length = 0x4;
414 capsSet->flags = caps10Flags | RDPGFX_CAPS_FLAG_AV1_I444_SUPPORTED;
415 const UINT32 profile =
418 capsSet->flags |= RDPGFX_CAPS_FLAG_AV1_I444_DISABLED;
420#if !defined(WITH_CAIRO) && !defined(WITH_SWSCALE)
421 capsSet->flags |= RDPGFX_CAPS_FLAG_SCALEDMAP_DISABLE;
427 return IFCALLRESULT(ERROR_BAD_CONFIGURATION, context->CapsAdvertise, context, &pdu);
437 WINPR_ASSERT(callback);
441 RdpgfxClientContext* context = gfx->context;
446 if (!Stream_CheckAndLogRequiredLengthWLog(gfx->base.log, s, 12))
447 return ERROR_INVALID_DATA;
449 Stream_Read_UINT32(s, capsSet.version);
450 Stream_Read_UINT32(s, capsSet.length);
451 Stream_Read_UINT32(s, capsSet.flags);
452 gfx->TotalDecodedFrames = 0;
453 gfx->ConnectionCaps = capsSet;
454 WLog_Print(gfx->base.log, WLOG_DEBUG,
455 "RecvCapsConfirmPdu: version: %s [0x%08" PRIX32
"] flags: 0x%08" PRIX32
"",
456 rdpgfx_caps_version_str(capsSet.version), capsSet.version, capsSet.flags);
459 return ERROR_BAD_CONFIGURATION;
461 return IFCALLRESULT(CHANNEL_RC_OK, context->CapsConfirm, context, &pdu);
469static UINT rdpgfx_send_frame_acknowledge_pdu(RdpgfxClientContext* context,
474 if (!context || !pdu)
475 return ERROR_BAD_ARGUMENTS;
479 if (!gfx || !gfx->base.listener_callback)
480 return ERROR_BAD_CONFIGURATION;
485 return ERROR_BAD_CONFIGURATION;
488 .cmdId = RDPGFX_CMDID_FRAMEACKNOWLEDGE,
489 .pduLength = RDPGFX_HEADER_SIZE + 12 };
491 WLog_Print(gfx->base.log, WLOG_TRACE,
"SendFrameAcknowledgePdu: %" PRIu32
"", pdu->frameId);
493 wStream* s = Stream_New(
nullptr, header.pduLength);
497 WLog_Print(gfx->base.log, WLOG_ERROR,
"Stream_New failed!");
498 return CHANNEL_RC_NO_MEMORY;
501 if ((error = rdpgfx_write_header(s, &header)))
505 Stream_Write_UINT32(s, pdu->queueDepth);
506 Stream_Write_UINT32(s, pdu->frameId);
507 Stream_Write_UINT32(s, pdu->totalFramesDecoded);
508 error = callback->channel->Write(callback->channel, (UINT32)Stream_Length(s), Stream_Buffer(s),
511 if (error == CHANNEL_RC_OK)
512 gfx->UnacknowledgedFrames--;
515 Stream_Free(s, TRUE);
519static UINT rdpgfx_send_qoe_frame_acknowledge_pdu(RdpgfxClientContext* context,
522 UINT error = CHANNEL_RC_OK;
524 .cmdId = RDPGFX_CMDID_QOEFRAMEACKNOWLEDGE,
525 .pduLength = RDPGFX_HEADER_SIZE + 12 };
527 if (!context || !pdu)
528 return ERROR_BAD_ARGUMENTS;
532 if (!gfx || !gfx->base.listener_callback)
533 return ERROR_BAD_CONFIGURATION;
538 return ERROR_BAD_CONFIGURATION;
540 WLog_Print(gfx->base.log, WLOG_TRACE,
"SendQoeFrameAcknowledgePdu: %" PRIu32
"", pdu->frameId);
541 wStream* s = Stream_New(
nullptr, header.pduLength);
545 WLog_Print(gfx->base.log, WLOG_ERROR,
"Stream_New failed!");
546 return CHANNEL_RC_NO_MEMORY;
549 if ((error = rdpgfx_write_header(s, &header)))
553 Stream_Write_UINT32(s, pdu->frameId);
554 Stream_Write_UINT32(s, pdu->timestamp);
555 Stream_Write_UINT16(s, pdu->timeDiffSE);
556 Stream_Write_UINT16(s, pdu->timeDiffEDR);
557 error = callback->channel->Write(callback->channel, (UINT32)Stream_Length(s), Stream_Buffer(s),
560 Stream_Free(s, TRUE);
572 WINPR_ASSERT(callback);
578 RdpgfxClientContext* context = gfx->context;
579 UINT error = CHANNEL_RC_OK;
580 GraphicsResetEventArgs graphicsReset = WINPR_C_ARRAY_INIT;
582 if (!Stream_CheckAndLogRequiredLengthWLog(gfx->base.log, s, 12))
583 return ERROR_INVALID_DATA;
585 Stream_Read_UINT32(s, pdu.width);
586 Stream_Read_UINT32(s, pdu.height);
587 Stream_Read_UINT32(s, pdu.monitorCount);
589 if (!Stream_CheckAndLogRequiredLengthOfSizeWLog(gfx->base.log, s, pdu.monitorCount, 20ull))
590 return ERROR_INVALID_DATA;
594 if (!pdu.monitorDefArray)
596 WLog_Print(gfx->base.log, WLOG_ERROR,
"calloc failed!");
597 return CHANNEL_RC_NO_MEMORY;
600 for (UINT32 index = 0; index < pdu.monitorCount; index++)
602 MONITOR_DEF* monitor = &(pdu.monitorDefArray[index]);
603 Stream_Read_INT32(s, monitor->left);
604 Stream_Read_INT32(s, monitor->top);
605 Stream_Read_INT32(s, monitor->right);
606 Stream_Read_INT32(s, monitor->bottom);
607 Stream_Read_UINT32(s, monitor->flags);
610 const size_t size = (RDPGFX_HEADER_SIZE + 12ULL + (pdu.monitorCount * 20ULL));
613 free(pdu.monitorDefArray);
614 return CHANNEL_RC_NULL_DATA;
616 const size_t pad = 340ULL - size;
618 if (!Stream_CheckAndLogRequiredLengthWLog(gfx->base.log, s, (
size_t)pad))
620 free(pdu.monitorDefArray);
621 return CHANNEL_RC_NO_MEMORY;
625 WLog_Print(gfx->base.log, WLOG_DEBUG,
626 "RecvResetGraphicsPdu: width: %" PRIu32
" height: %" PRIu32
" count: %" PRIu32
"",
627 pdu.width, pdu.height, pdu.monitorCount);
629 for (UINT32 index = 0; index < pdu.monitorCount; index++)
631 MONITOR_DEF* monitor = &(pdu.monitorDefArray[index]);
632 WLog_Print(gfx->base.log, WLOG_TRACE,
633 "RecvResetGraphicsPdu: monitor left:%" PRIi32
" top:%" PRIi32
" right:%" PRIi32
634 " bottom:%" PRIi32
" flags:0x%" PRIx32
"",
635 monitor->left, monitor->top, monitor->right, monitor->bottom, monitor->flags);
640 IFCALLRET(context->ResetGraphics, error, context, &pdu);
643 WLog_Print(gfx->base.log, WLOG_ERROR,
644 "context->ResetGraphics failed with error %" PRIu32
"", error);
647 free(pdu.monitorDefArray);
650 EventArgsInit(&graphicsReset,
"libfreerdp");
651 graphicsReset.width = pdu.width;
652 graphicsReset.height = pdu.height;
653 if (PubSub_OnGraphicsReset(gfx->rdpcontext->pubSub, gfx->rdpcontext, &graphicsReset) < 0)
654 return ERROR_INTERNAL_ERROR;
666 WINPR_ASSERT(callback);
669 RdpgfxClientContext* context = gfx->context;
670 UINT error = CHANNEL_RC_OK;
672 if (!Stream_CheckAndLogRequiredLengthWLog(gfx->base.log, s, 2))
673 return ERROR_INVALID_DATA;
675 Stream_Read_UINT16(s, pdu.cacheSlot);
676 WLog_Print(gfx->base.log, WLOG_DEBUG,
"RecvEvictCacheEntryPdu: cacheSlot: %" PRIu16
"",
681 IFCALLRET(context->EvictCacheEntry, error, context, &pdu);
684 WLog_Print(gfx->base.log, WLOG_ERROR,
685 "context->EvictCacheEntry failed with error %" PRIu32
"", error);
698 UINT error = CHANNEL_RC_OK;
701 WINPR_ASSERT(gfx->rdpcontext);
702 rdpSettings* settings = gfx->rdpcontext->settings;
703 RdpgfxClientContext* context = gfx->context;
705 WINPR_ASSERT(context);
706 WINPR_ASSERT(settings);
709 return CHANNEL_RC_OK;
711 const char* BitmapCachePersistFile =
713 if (!BitmapCachePersistFile)
714 return CHANNEL_RC_OK;
716 if (!context->ExportCacheEntry)
717 return CHANNEL_RC_INITIALIZATION_ERROR;
719 rdpPersistentCache* persistent = persistent_cache_new();
722 return CHANNEL_RC_NO_MEMORY;
724 if (persistent_cache_open(persistent, BitmapCachePersistFile, TRUE, 3) < 1)
726 error = CHANNEL_RC_INITIALIZATION_ERROR;
730 for (UINT16 idx = 0; idx < gfx->MaxCacheSlots; idx++)
732 if (gfx->CacheSlots[idx])
734 const UINT16 cacheSlot = idx;
737 if (context->ExportCacheEntry(context, cacheSlot, &cacheEntry) != CHANNEL_RC_OK)
740 if (persistent_cache_write_entry(persistent, &cacheEntry) < 0)
745 persistent_cache_free(persistent);
749 persistent_cache_free(persistent);
758static UINT rdpgfx_send_cache_import_offer_pdu(RdpgfxClientContext* context,
761 UINT error = CHANNEL_RC_OK;
763 if (!context || !pdu)
764 return ERROR_BAD_ARGUMENTS;
768 if (!gfx || !gfx->base.listener_callback)
769 return ERROR_BAD_CONFIGURATION;
774 return ERROR_BAD_CONFIGURATION;
777 .cmdId = RDPGFX_CMDID_CACHEIMPORTOFFER,
779 RDPGFX_HEADER_SIZE + 2ul + pdu->cacheEntriesCount * 12ul };
781 WLog_Print(gfx->base.log, WLOG_DEBUG,
"SendCacheImportOfferPdu: cacheEntriesCount: %" PRIu16
"",
782 pdu->cacheEntriesCount);
783 wStream* s = Stream_New(
nullptr, header.pduLength);
787 WLog_Print(gfx->base.log, WLOG_ERROR,
"Stream_New failed!");
788 return CHANNEL_RC_NO_MEMORY;
791 if ((error = rdpgfx_write_header(s, &header)))
794 if (pdu->cacheEntriesCount <= 0)
796 WLog_Print(gfx->base.log, WLOG_ERROR,
"Invalid cacheEntriesCount: %" PRIu16
"",
797 pdu->cacheEntriesCount);
798 error = ERROR_INVALID_DATA;
803 Stream_Write_UINT16(s, pdu->cacheEntriesCount);
805 for (UINT16 index = 0; index < pdu->cacheEntriesCount; index++)
808 Stream_Write_UINT64(s, cacheEntry->cacheKey);
809 Stream_Write_UINT32(s, cacheEntry->bitmapLength);
812 error = callback->channel->Write(callback->channel, (UINT32)Stream_Length(s), Stream_Buffer(s),
816 Stream_Free(s, TRUE);
828 UINT error = CHANNEL_RC_OK;
833 WINPR_ASSERT(gfx->rdpcontext);
835 RdpgfxClientContext* context = gfx->context;
836 rdpSettings* settings = gfx->rdpcontext->settings;
839 return CHANNEL_RC_OK;
841 const char* BitmapCachePersistFile =
843 if (!BitmapCachePersistFile)
844 return CHANNEL_RC_OK;
846 rdpPersistentCache* persistent = persistent_cache_new();
849 return CHANNEL_RC_NO_MEMORY;
851 if (persistent_cache_open(persistent, BitmapCachePersistFile, FALSE, 3) < 1)
853 error = CHANNEL_RC_INITIALIZATION_ERROR;
857 if (persistent_cache_get_version(persistent) != 3)
859 error = ERROR_INVALID_DATA;
863 count = persistent_cache_get_count(persistent);
866 error = ERROR_INVALID_DATA;
870 if (count >= RDPGFX_CACHE_ENTRY_MAX_COUNT)
871 count = RDPGFX_CACHE_ENTRY_MAX_COUNT - 1;
873 if (count > gfx->MaxCacheSlots)
874 count = gfx->MaxCacheSlots;
879 error = CHANNEL_RC_NO_MEMORY;
883 WINPR_ASSERT(count <= UINT16_MAX);
884 offer->cacheEntriesCount = (UINT16)count;
886 WLog_Print(gfx->base.log, WLOG_DEBUG,
"Sending Cache Import Offer: %d", count);
888 for (
int idx = 0; idx < count; idx++)
890 if (persistent_cache_read_entry(persistent, &entry) < 1)
892 error = ERROR_INVALID_DATA;
896 offer->cacheEntries[idx].cacheKey = entry.key64;
897 offer->cacheEntries[idx].bitmapLength = entry.size;
900 if (offer->cacheEntriesCount > 0)
902 error = rdpgfx_send_cache_import_offer_pdu(context, offer);
903 if (error != CHANNEL_RC_OK)
905 WLog_Print(gfx->base.log, WLOG_ERROR,
"Failed to send cache import offer PDU");
911 persistent_cache_free(persistent);
921static UINT rdpgfx_load_cache_import_reply(
RDPGFX_PLUGIN* gfx,
924 UINT error = CHANNEL_RC_OK;
925 rdpPersistentCache* persistent =
nullptr;
927 WINPR_ASSERT(gfx->rdpcontext);
928 rdpSettings* settings = gfx->rdpcontext->settings;
929 RdpgfxClientContext* context = gfx->context;
931 WINPR_ASSERT(settings);
934 return CHANNEL_RC_OK;
936 const char* BitmapCachePersistFile =
938 if (!BitmapCachePersistFile)
939 return CHANNEL_RC_OK;
941 persistent = persistent_cache_new();
944 return CHANNEL_RC_NO_MEMORY;
946 if (persistent_cache_open(persistent, BitmapCachePersistFile, FALSE, 3) < 1)
948 error = CHANNEL_RC_INITIALIZATION_ERROR;
952 if (persistent_cache_get_version(persistent) != 3)
954 error = ERROR_INVALID_DATA;
958 int count = persistent_cache_get_count(persistent);
960 count = (count < reply->importedEntriesCount) ? count : reply->importedEntriesCount;
962 WLog_Print(gfx->base.log, WLOG_DEBUG,
"Receiving Cache Import Reply: %d", count);
964 for (
int idx = 0; idx < count; idx++)
967 if (persistent_cache_read_entry(persistent, &entry) < 1)
969 error = ERROR_INVALID_DATA;
973 const UINT16 cacheSlot = reply->cacheSlots[idx];
974 if (context && context->ImportCacheEntry)
976 error = context->ImportCacheEntry(context, cacheSlot, &entry);
977 if (error != CHANNEL_RC_OK)
982 persistent_cache_free(persistent);
986 persistent_cache_free(persistent);
998 WINPR_ASSERT(callback);
1001 RdpgfxClientContext* context = gfx->context;
1002 UINT error = CHANNEL_RC_OK;
1004 if (!Stream_CheckAndLogRequiredLengthWLog(gfx->base.log, s, 2))
1005 return ERROR_INVALID_DATA;
1007 Stream_Read_UINT16(s, pdu.importedEntriesCount);
1009 if (!Stream_CheckAndLogRequiredLengthOfSizeWLog(gfx->base.log, s, pdu.importedEntriesCount,
1011 return ERROR_INVALID_DATA;
1013 if (pdu.importedEntriesCount > RDPGFX_CACHE_ENTRY_MAX_COUNT)
1014 return ERROR_INVALID_DATA;
1016 for (UINT16 idx = 0; idx < pdu.importedEntriesCount; idx++)
1018 Stream_Read_UINT16(s, pdu.cacheSlots[idx]);
1021 WLog_Print(gfx->base.log, WLOG_TRACE,
1022 "RecvCacheImportReplyPdu: importedEntriesCount: %" PRIu16
"",
1023 pdu.importedEntriesCount);
1025 error = rdpgfx_load_cache_import_reply(gfx, &pdu);
1029 WLog_Print(gfx->base.log, WLOG_ERROR,
1030 "rdpgfx_load_cache_import_reply failed with error %" PRIu32
"", error);
1036 IFCALLRET(context->CacheImportReply, error, context, &pdu);
1039 WLog_Print(gfx->base.log, WLOG_ERROR,
1040 "context->CacheImportReply failed with error %" PRIu32
"", error);
1054 WINPR_ASSERT(callback);
1057 RdpgfxClientContext* context = gfx->context;
1058 UINT error = CHANNEL_RC_OK;
1060 if (!Stream_CheckAndLogRequiredLengthWLog(gfx->base.log, s, 7))
1061 return ERROR_INVALID_DATA;
1063 Stream_Read_UINT16(s, pdu.surfaceId);
1064 Stream_Read_UINT16(s, pdu.width);
1065 Stream_Read_UINT16(s, pdu.height);
1066 Stream_Read_UINT8(s, pdu.pixelFormat);
1067 WLog_Print(gfx->base.log, WLOG_DEBUG,
1068 "RecvCreateSurfacePdu: surfaceId: %" PRIu16
" width: %" PRIu16
" height: %" PRIu16
1069 " pixelFormat: 0x%02" PRIX8
"",
1070 pdu.surfaceId, pdu.width, pdu.height, pdu.pixelFormat);
1079 const UINT drc = IFCALLRESULT(CHANNEL_RC_OK, context->DeleteSurface, context, &deletePdu);
1080 if (drc != CHANNEL_RC_OK)
1081 WLog_Print(gfx->base.log, WLOG_WARN,
1082 "context->DeleteSurface failed with error %" PRIu32
", ignoring", error);
1084 IFCALLRET(context->CreateSurface, error, context, &pdu);
1087 WLog_Print(gfx->base.log, WLOG_ERROR,
1088 "context->CreateSurface failed with error %" PRIu32
"", error);
1102 WINPR_ASSERT(callback);
1105 RdpgfxClientContext* context = gfx->context;
1106 UINT error = CHANNEL_RC_OK;
1108 if (!Stream_CheckAndLogRequiredLengthWLog(gfx->base.log, s, 2))
1109 return ERROR_INVALID_DATA;
1111 Stream_Read_UINT16(s, pdu.surfaceId);
1112 WLog_Print(gfx->base.log, WLOG_DEBUG,
"RecvDeleteSurfacePdu: surfaceId: %" PRIu16
"",
1117 IFCALLRET(context->DeleteSurface, error, context, &pdu);
1120 WLog_Print(gfx->base.log, WLOG_ERROR,
1121 "context->DeleteSurface failed with error %" PRIu32
"", error);
1135 WINPR_ASSERT(callback);
1138 RdpgfxClientContext* context = gfx->context;
1139 UINT error = CHANNEL_RC_OK;
1141 if (!Stream_CheckAndLogRequiredLengthWLog(gfx->base.log, s, RDPGFX_START_FRAME_PDU_SIZE))
1142 return ERROR_INVALID_DATA;
1144 Stream_Read_UINT32(s, pdu.timestamp);
1145 Stream_Read_UINT32(s, pdu.frameId);
1146 WLog_Print(gfx->base.log, WLOG_TRACE,
1147 "RecvStartFramePdu: frameId: %" PRIu32
" timestamp: 0x%08" PRIX32
"", pdu.frameId,
1149 gfx->StartDecodingTime = GetTickCount64();
1153 IFCALLRET(context->StartFrame, error, context, &pdu);
1156 WLog_Print(gfx->base.log, WLOG_ERROR,
1157 "context->StartFrame failed with error %" PRIu32
"", error);
1160 gfx->UnacknowledgedFrames++;
1173 WINPR_ASSERT(callback);
1176 RdpgfxClientContext* context = gfx->context;
1177 UINT error = CHANNEL_RC_OK;
1179 if (!Stream_CheckAndLogRequiredLengthWLog(gfx->base.log, s, RDPGFX_END_FRAME_PDU_SIZE))
1180 return ERROR_INVALID_DATA;
1182 Stream_Read_UINT32(s, pdu.frameId);
1183 WLog_Print(gfx->base.log, WLOG_TRACE,
"RecvEndFramePdu: frameId: %" PRIu32
"", pdu.frameId);
1185 const UINT64 start = GetTickCount64();
1188 IFCALLRET(context->EndFrame, error, context, &pdu);
1192 WLog_Print(gfx->base.log, WLOG_ERROR,
"context->EndFrame failed with error %" PRIu32
"",
1197 const UINT64 end = GetTickCount64();
1198 const UINT64 EndFrameTime = end - start;
1199 gfx->TotalDecodedFrames++;
1201 if (!gfx->sendFrameAcks)
1204 ack.frameId = pdu.frameId;
1205 ack.totalFramesDecoded = gfx->TotalDecodedFrames;
1207 if (gfx->suspendFrameAcks)
1209 ack.queueDepth = SUSPEND_FRAME_ACKNOWLEDGEMENT;
1211 if (gfx->TotalDecodedFrames == 1)
1212 if ((error = rdpgfx_send_frame_acknowledge_pdu(context, &ack)))
1213 WLog_Print(gfx->base.log, WLOG_ERROR,
1214 "rdpgfx_send_frame_acknowledge_pdu failed with error %" PRIu32
"",
1219 ack.queueDepth = QUEUE_DEPTH_UNAVAILABLE;
1221 if ((error = rdpgfx_send_frame_acknowledge_pdu(context, &ack)))
1222 WLog_Print(gfx->base.log, WLOG_ERROR,
1223 "rdpgfx_send_frame_acknowledge_pdu failed with error %" PRIu32
"", error);
1226 switch (gfx->ConnectionCaps.version)
1228#if defined(WITH_GFX_AV1)
1229 case RDPGFX_CAPVERSION_FRDP_1:
1231 case RDPGFX_CAPVERSION_10:
1232 case RDPGFX_CAPVERSION_102:
1233 case RDPGFX_CAPVERSION_103:
1234 case RDPGFX_CAPVERSION_104:
1235 case RDPGFX_CAPVERSION_105:
1236 case RDPGFX_CAPVERSION_106:
1237 case RDPGFX_CAPVERSION_106_ERR:
1238 case RDPGFX_CAPVERSION_107:
1242 UINT64 diff = (GetTickCount64() - gfx->StartDecodingTime);
1247 qoe.frameId = pdu.frameId;
1248 qoe.timestamp = gfx->StartDecodingTime % UINT32_MAX;
1249 qoe.timeDiffSE = WINPR_ASSERTING_INT_CAST(UINT16, diff);
1250 qoe.timeDiffEDR = WINPR_ASSERTING_INT_CAST(UINT16, EndFrameTime);
1252 if ((error = rdpgfx_send_qoe_frame_acknowledge_pdu(context, &qoe)))
1253 WLog_Print(gfx->base.log, WLOG_ERROR,
1254 "rdpgfx_send_qoe_frame_acknowledge_pdu failed with error %" PRIu32
1277 WINPR_ASSERT(callback);
1282 if (!Stream_CheckAndLogRequiredLengthWLog(gfx->base.log, s, RDPGFX_WIRE_TO_SURFACE_PDU_1_SIZE))
1283 return ERROR_INVALID_DATA;
1285 Stream_Read_UINT16(s, pdu.surfaceId);
1286 Stream_Read_UINT16(s, pdu.codecId);
1287 Stream_Read_UINT8(s, pdu.pixelFormat);
1289 if ((error = rdpgfx_read_rect16(gfx->base.log, s, &(pdu.destRect))))
1291 WLog_Print(gfx->base.log, WLOG_ERROR,
"rdpgfx_read_rect16 failed with error %" PRIu32
"",
1296 Stream_Read_UINT32(s, pdu.bitmapDataLength);
1298 if (!Stream_CheckAndLogRequiredLengthWLog(gfx->base.log, s, pdu.bitmapDataLength))
1299 return ERROR_INVALID_DATA;
1301 pdu.bitmapData = Stream_Pointer(s);
1302 Stream_Seek(s, pdu.bitmapDataLength);
1304 WLog_Print(gfx->base.log, WLOG_TRACE,
1305 "RecvWireToSurface1Pdu: surfaceId: %" PRIu16
" codecId: %s (0x%04" PRIX16
1306 ") pixelFormat: 0x%02" PRIX8
" "
1307 "destRect: left: %" PRIu16
" top: %" PRIu16
" right: %" PRIu16
" bottom: %" PRIu16
1308 " bitmapDataLength: %" PRIu32
"",
1309 pdu.surfaceId, rdpgfx_get_codec_id_string(pdu.codecId), pdu.codecId, pdu.pixelFormat,
1310 pdu.destRect.left, pdu.destRect.top, pdu.destRect.right, pdu.destRect.bottom,
1311 pdu.bitmapDataLength);
1312 cmd.surfaceId = pdu.surfaceId;
1313 cmd.codecId = pdu.codecId;
1316 switch (pdu.pixelFormat)
1318 case GFX_PIXEL_FORMAT_XRGB_8888:
1319 cmd.format = PIXEL_FORMAT_BGRX32;
1322 case GFX_PIXEL_FORMAT_ARGB_8888:
1323 cmd.format = PIXEL_FORMAT_BGRA32;
1327 return ERROR_INVALID_DATA;
1330 cmd.left = pdu.destRect.left;
1331 cmd.top = pdu.destRect.top;
1332 cmd.right = pdu.destRect.right;
1333 cmd.bottom = pdu.destRect.bottom;
1334 cmd.width = cmd.right - cmd.left;
1335 cmd.height = cmd.bottom - cmd.top;
1336 cmd.length = pdu.bitmapDataLength;
1337 cmd.data = pdu.bitmapData;
1338 cmd.extra =
nullptr;
1340 if (cmd.right < cmd.left)
1342 WLog_Print(gfx->base.log, WLOG_ERROR,
1343 "RecvWireToSurface1Pdu right=%" PRIu32
" < left=%" PRIu32, cmd.right, cmd.left);
1344 return ERROR_INVALID_DATA;
1346 if (cmd.bottom < cmd.top)
1348 WLog_Print(gfx->base.log, WLOG_ERROR,
1349 "RecvWireToSurface1Pdu bottom=%" PRIu32
" < top=%" PRIu32, cmd.bottom, cmd.top);
1350 return ERROR_INVALID_DATA;
1353 if ((error = rdpgfx_decode(gfx, &cmd)))
1354 WLog_Print(gfx->base.log, WLOG_ERROR,
"rdpgfx_decode failed with error %" PRIu32
"!",
1370 WINPR_ASSERT(callback);
1373 RdpgfxClientContext* context = gfx->context;
1374 UINT error = CHANNEL_RC_OK;
1376 if (!Stream_CheckAndLogRequiredLengthWLog(gfx->base.log, s, RDPGFX_WIRE_TO_SURFACE_PDU_2_SIZE))
1377 return ERROR_INVALID_DATA;
1379 Stream_Read_UINT16(s, pdu.surfaceId);
1380 Stream_Read_UINT16(s, pdu.codecId);
1381 Stream_Read_UINT32(s, pdu.codecContextId);
1382 Stream_Read_UINT8(s, pdu.pixelFormat);
1383 Stream_Read_UINT32(s, pdu.bitmapDataLength);
1384 pdu.bitmapData = Stream_Pointer(s);
1385 if (!Stream_SafeSeek(s, pdu.bitmapDataLength))
1386 return ERROR_INVALID_DATA;
1388 WLog_Print(gfx->base.log, WLOG_TRACE,
1389 "RecvWireToSurface2Pdu: surfaceId: %" PRIu16
" codecId: %s (0x%04" PRIX16
") "
1390 "codecContextId: %" PRIu32
" pixelFormat: 0x%02" PRIX8
" bitmapDataLength: %" PRIu32
1392 pdu.surfaceId, rdpgfx_get_codec_id_string(pdu.codecId), pdu.codecId,
1393 pdu.codecContextId, pdu.pixelFormat, pdu.bitmapDataLength);
1395 cmd.surfaceId = pdu.surfaceId;
1396 cmd.codecId = pdu.codecId;
1397 cmd.contextId = pdu.codecContextId;
1399 switch (pdu.pixelFormat)
1401 case GFX_PIXEL_FORMAT_XRGB_8888:
1402 cmd.format = PIXEL_FORMAT_BGRX32;
1405 case GFX_PIXEL_FORMAT_ARGB_8888:
1406 cmd.format = PIXEL_FORMAT_BGRA32;
1410 return ERROR_INVALID_DATA;
1413 cmd.length = pdu.bitmapDataLength;
1414 cmd.data = pdu.bitmapData;
1415 cmd.extra =
nullptr;
1419 IFCALLRET(context->SurfaceCommand, error, context, &cmd);
1422 WLog_Print(gfx->base.log, WLOG_ERROR,
1423 "context->SurfaceCommand failed with error %" PRIu32
"", error);
1437 WINPR_ASSERT(callback);
1440 RdpgfxClientContext* context = gfx->context;
1441 UINT error = CHANNEL_RC_OK;
1443 if (!Stream_CheckAndLogRequiredLengthWLog(gfx->base.log, s, 6))
1444 return ERROR_INVALID_DATA;
1446 Stream_Read_UINT16(s, pdu.surfaceId);
1447 Stream_Read_UINT32(s, pdu.codecContextId);
1449 WLog_Print(gfx->base.log, WLOG_DEBUG,
1450 "RecvDeleteEncodingContextPdu: surfaceId: %" PRIu16
" codecContextId: %" PRIu32
"",
1451 pdu.surfaceId, pdu.codecContextId);
1455 IFCALLRET(context->DeleteEncodingContext, error, context, &pdu);
1458 WLog_Print(gfx->base.log, WLOG_ERROR,
1459 "context->DeleteEncodingContext failed with error %" PRIu32
"", error);
1473 WINPR_ASSERT(callback);
1476 RdpgfxClientContext* context = gfx->context;
1478 if (!Stream_CheckAndLogRequiredLengthWLog(gfx->base.log, s, 8))
1479 return ERROR_INVALID_DATA;
1481 Stream_Read_UINT16(s, pdu.surfaceId);
1483 UINT error = rdpgfx_read_color32(gfx->base.log, s, &(pdu.fillPixel));
1484 if (error != CHANNEL_RC_OK)
1486 WLog_Print(gfx->base.log, WLOG_ERROR,
"rdpgfx_read_color32 failed with error %" PRIu32
"!",
1491 Stream_Read_UINT16(s, pdu.fillRectCount);
1493 if (!Stream_CheckAndLogRequiredLengthOfSizeWLog(gfx->base.log, s, pdu.fillRectCount, 8ull))
1494 return ERROR_INVALID_DATA;
1500 WLog_Print(gfx->base.log, WLOG_ERROR,
"calloc failed!");
1501 return CHANNEL_RC_NO_MEMORY;
1504 for (UINT16 index = 0; index < pdu.fillRectCount; index++)
1508 if ((error = rdpgfx_read_rect16(gfx->base.log, s, fillRect)))
1510 WLog_Print(gfx->base.log, WLOG_ERROR,
1511 "rdpgfx_read_rect16 failed with error %" PRIu32
"!", error);
1512 free(pdu.fillRects);
1516 WLog_Print(gfx->base.log, WLOG_TRACE,
1517 "RecvSolidFillPdu: surfaceId: %" PRIu16
" fillRectCount: %" PRIu16
"", pdu.surfaceId,
1522 IFCALLRET(context->SolidFill, error, context, &pdu);
1525 WLog_Print(gfx->base.log, WLOG_ERROR,
1526 "context->SolidFill failed with error %" PRIu32
"", error);
1529 free(pdu.fillRects);
1541 WINPR_ASSERT(callback);
1544 RdpgfxClientContext* context = gfx->context;
1547 if (!Stream_CheckAndLogRequiredLengthWLog(gfx->base.log, s, 14))
1548 return ERROR_INVALID_DATA;
1550 Stream_Read_UINT16(s, pdu.surfaceIdSrc);
1551 Stream_Read_UINT16(s, pdu.surfaceIdDest);
1553 if ((error = rdpgfx_read_rect16(gfx->base.log, s, &(pdu.rectSrc))))
1555 WLog_Print(gfx->base.log, WLOG_ERROR,
"rdpgfx_read_rect16 failed with error %" PRIu32
"!",
1560 Stream_Read_UINT16(s, pdu.destPtsCount);
1562 if (!Stream_CheckAndLogRequiredLengthOfSizeWLog(gfx->base.log, s, pdu.destPtsCount, 4ull))
1563 return ERROR_INVALID_DATA;
1569 WLog_Print(gfx->base.log, WLOG_ERROR,
"calloc failed!");
1570 return CHANNEL_RC_NO_MEMORY;
1573 for (UINT16 index = 0; index < pdu.destPtsCount; index++)
1577 if ((error = rdpgfx_read_point16(gfx->base.log, s, destPt)))
1579 WLog_Print(gfx->base.log, WLOG_ERROR,
1580 "rdpgfx_read_point16 failed with error %" PRIu32
"!", error);
1586 WLog_Print(gfx->base.log, WLOG_TRACE,
1587 "RecvSurfaceToSurfacePdu: surfaceIdSrc: %" PRIu16
" surfaceIdDest: %" PRIu16
" "
1588 "left: %" PRIu16
" top: %" PRIu16
" right: %" PRIu16
" bottom: %" PRIu16
1589 " destPtsCount: %" PRIu16
"",
1590 pdu.surfaceIdSrc, pdu.surfaceIdDest, pdu.rectSrc.left, pdu.rectSrc.top,
1591 pdu.rectSrc.right, pdu.rectSrc.bottom, pdu.destPtsCount);
1595 IFCALLRET(context->SurfaceToSurface, error, context, &pdu);
1598 WLog_Print(gfx->base.log, WLOG_ERROR,
1599 "context->SurfaceToSurface failed with error %" PRIu32
"", error);
1614 WINPR_ASSERT(callback);
1618 RdpgfxClientContext* context = gfx->context;
1620 if (!Stream_CheckAndLogRequiredLengthWLog(gfx->base.log, s, 20))
1621 return ERROR_INVALID_DATA;
1623 Stream_Read_UINT16(s, pdu.surfaceId);
1624 Stream_Read_UINT64(s, pdu.cacheKey);
1625 Stream_Read_UINT16(s, pdu.cacheSlot);
1627 UINT error = rdpgfx_read_rect16(gfx->base.log, s, &(pdu.rectSrc));
1628 if (error != CHANNEL_RC_OK)
1630 WLog_Print(gfx->base.log, WLOG_ERROR,
"rdpgfx_read_rect16 failed with error %" PRIu32
"!",
1635 WLog_Print(gfx->base.log, WLOG_TRACE,
1636 "RecvSurfaceToCachePdu: surfaceId: %" PRIu16
" cacheKey: 0x%016" PRIX64
1637 " cacheSlot: %" PRIu16
" "
1638 "left: %" PRIu16
" top: %" PRIu16
" right: %" PRIu16
" bottom: %" PRIu16
"",
1639 pdu.surfaceId, pdu.cacheKey, pdu.cacheSlot, pdu.rectSrc.left, pdu.rectSrc.top,
1640 pdu.rectSrc.right, pdu.rectSrc.bottom);
1644 IFCALLRET(context->SurfaceToCache, error, context, &pdu);
1647 WLog_Print(gfx->base.log, WLOG_ERROR,
1648 "context->SurfaceToCache failed with error %" PRIu32
"", error);
1662 WINPR_ASSERT(callback);
1666 RdpgfxClientContext* context = gfx->context;
1667 UINT error = CHANNEL_RC_OK;
1669 if (!Stream_CheckAndLogRequiredLengthWLog(gfx->base.log, s, 6))
1670 return ERROR_INVALID_DATA;
1672 Stream_Read_UINT16(s, pdu.cacheSlot);
1673 Stream_Read_UINT16(s, pdu.surfaceId);
1674 Stream_Read_UINT16(s, pdu.destPtsCount);
1676 if (!Stream_CheckAndLogRequiredLengthOfSizeWLog(gfx->base.log, s, pdu.destPtsCount, 4ull))
1677 return ERROR_INVALID_DATA;
1683 WLog_Print(gfx->base.log, WLOG_ERROR,
"calloc failed!");
1684 return CHANNEL_RC_NO_MEMORY;
1687 for (UINT16 index = 0; index < pdu.destPtsCount; index++)
1691 if ((error = rdpgfx_read_point16(gfx->base.log, s, destPt)))
1693 WLog_Print(gfx->base.log, WLOG_ERROR,
1694 "rdpgfx_read_point16 failed with error %" PRIu32
"", error);
1700 WLog_Print(gfx->base.log, WLOG_TRACE,
1701 "RdpGfxRecvCacheToSurfacePdu: cacheSlot: %" PRIu16
" surfaceId: %" PRIu16
1702 " destPtsCount: %" PRIu16
"",
1703 pdu.cacheSlot, pdu.surfaceId, pdu.destPtsCount);
1707 IFCALLRET(context->CacheToSurface, error, context, &pdu);
1710 WLog_Print(gfx->base.log, WLOG_ERROR,
1711 "context->CacheToSurface failed with error %" PRIu32
"", error);
1726 WINPR_ASSERT(callback);
1730 RdpgfxClientContext* context = gfx->context;
1731 UINT error = CHANNEL_RC_OK;
1733 if (!Stream_CheckAndLogRequiredLengthWLog(gfx->base.log, s, 12))
1734 return ERROR_INVALID_DATA;
1736 Stream_Read_UINT16(s, pdu.surfaceId);
1737 Stream_Read_UINT16(s, pdu.reserved);
1738 Stream_Read_UINT32(s, pdu.outputOriginX);
1739 Stream_Read_UINT32(s, pdu.outputOriginY);
1740 WLog_Print(gfx->base.log, WLOG_DEBUG,
1741 "RecvMapSurfaceToOutputPdu: surfaceId: %" PRIu16
" outputOriginX: %" PRIu32
1742 " outputOriginY: %" PRIu32
"",
1743 pdu.surfaceId, pdu.outputOriginX, pdu.outputOriginY);
1747 IFCALLRET(context->MapSurfaceToOutput, error, context, &pdu);
1750 WLog_Print(gfx->base.log, WLOG_ERROR,
1751 "context->MapSurfaceToOutput failed with error %" PRIu32
"", error);
1761 WINPR_ASSERT(callback);
1765 RdpgfxClientContext* context = gfx->context;
1766 UINT error = CHANNEL_RC_OK;
1768 if (!Stream_CheckAndLogRequiredLengthWLog(gfx->base.log, s, 20))
1769 return ERROR_INVALID_DATA;
1771 Stream_Read_UINT16(s, pdu.surfaceId);
1772 Stream_Read_UINT16(s, pdu.reserved);
1773 Stream_Read_UINT32(s, pdu.outputOriginX);
1774 Stream_Read_UINT32(s, pdu.outputOriginY);
1775 Stream_Read_UINT32(s, pdu.targetWidth);
1776 Stream_Read_UINT32(s, pdu.targetHeight);
1777 WLog_Print(gfx->base.log, WLOG_DEBUG,
1778 "RecvMapSurfaceToScaledOutputPdu: surfaceId: %" PRIu16
" outputOriginX: %" PRIu32
1779 " outputOriginY: %" PRIu32
" targetWidth: %" PRIu32
" targetHeight: %" PRIu32,
1780 pdu.surfaceId, pdu.outputOriginX, pdu.outputOriginY, pdu.targetWidth,
1785 IFCALLRET(context->MapSurfaceToScaledOutput, error, context, &pdu);
1788 WLog_Print(gfx->base.log, WLOG_ERROR,
1789 "context->MapSurfaceToScaledOutput failed with error %" PRIu32
"", error);
1803 WINPR_ASSERT(callback);
1807 RdpgfxClientContext* context = gfx->context;
1808 UINT error = CHANNEL_RC_OK;
1810 if (!Stream_CheckAndLogRequiredLengthWLog(gfx->base.log, s, 18))
1811 return ERROR_INVALID_DATA;
1813 Stream_Read_UINT16(s, pdu.surfaceId);
1814 Stream_Read_UINT64(s, pdu.windowId);
1815 Stream_Read_UINT32(s, pdu.mappedWidth);
1816 Stream_Read_UINT32(s, pdu.mappedHeight);
1817 WLog_Print(gfx->base.log, WLOG_DEBUG,
1818 "RecvMapSurfaceToWindowPdu: surfaceId: %" PRIu16
" windowId: 0x%016" PRIX64
1819 " mappedWidth: %" PRIu32
" mappedHeight: %" PRIu32
"",
1820 pdu.surfaceId, pdu.windowId, pdu.mappedWidth, pdu.mappedHeight);
1822 if (context && context->MapSurfaceToWindow)
1824 IFCALLRET(context->MapSurfaceToWindow, error, context, &pdu);
1827 WLog_Print(gfx->base.log, WLOG_ERROR,
1828 "context->MapSurfaceToWindow failed with error %" PRIu32
"", error);
1838 WINPR_ASSERT(callback);
1841 RdpgfxClientContext* context = gfx->context;
1842 UINT error = CHANNEL_RC_OK;
1844 if (!Stream_CheckAndLogRequiredLengthWLog(gfx->base.log, s, 26))
1845 return ERROR_INVALID_DATA;
1847 Stream_Read_UINT16(s, pdu.surfaceId);
1848 Stream_Read_UINT64(s, pdu.windowId);
1849 Stream_Read_UINT32(s, pdu.mappedWidth);
1850 Stream_Read_UINT32(s, pdu.mappedHeight);
1851 Stream_Read_UINT32(s, pdu.targetWidth);
1852 Stream_Read_UINT32(s, pdu.targetHeight);
1853 WLog_Print(gfx->base.log, WLOG_DEBUG,
1854 "RecvMapSurfaceToScaledWindowPdu: surfaceId: %" PRIu16
" windowId: 0x%016" PRIX64
1855 " mappedWidth: %" PRIu32
" mappedHeight: %" PRIu32
" targetWidth: %" PRIu32
1856 " targetHeight: %" PRIu32
"",
1857 pdu.surfaceId, pdu.windowId, pdu.mappedWidth, pdu.mappedHeight, pdu.targetWidth,
1860 if (context && context->MapSurfaceToScaledWindow)
1862 IFCALLRET(context->MapSurfaceToScaledWindow, error, context, &pdu);
1865 WLog_Print(gfx->base.log, WLOG_ERROR,
1866 "context->MapSurfaceToScaledWindow failed with error %" PRIu32
"", error);
1881 WINPR_ASSERT(callback);
1883 const size_t beg = Stream_GetPosition(s);
1887 UINT error = rdpgfx_read_header(gfx->base.log, s, &header);
1888 if (error != CHANNEL_RC_OK)
1890 WLog_Print(gfx->base.log, WLOG_ERROR,
"rdpgfx_read_header failed with error %" PRIu32
"!",
1895 WLog_Print(gfx->base.log, WLOG_TRACE,
1896 "cmdId: %s (0x%04" PRIX16
") flags: 0x%04" PRIX16
" pduLength: %" PRIu32
"",
1897 rdpgfx_get_cmd_id_string(header.cmdId), header.cmdId, header.flags,
1900 switch (header.cmdId)
1902 case RDPGFX_CMDID_WIRETOSURFACE_1:
1903 if ((error = rdpgfx_recv_wire_to_surface_1_pdu(callback, s)))
1904 WLog_Print(gfx->base.log, WLOG_ERROR,
1905 "rdpgfx_recv_wire_to_surface_1_pdu failed with error %" PRIu32
"!",
1910 case RDPGFX_CMDID_WIRETOSURFACE_2:
1911 if ((error = rdpgfx_recv_wire_to_surface_2_pdu(callback, s)))
1912 WLog_Print(gfx->base.log, WLOG_ERROR,
1913 "rdpgfx_recv_wire_to_surface_2_pdu failed with error %" PRIu32
"!",
1918 case RDPGFX_CMDID_DELETEENCODINGCONTEXT:
1919 if ((error = rdpgfx_recv_delete_encoding_context_pdu(callback, s)))
1920 WLog_Print(gfx->base.log, WLOG_ERROR,
1921 "rdpgfx_recv_delete_encoding_context_pdu failed with error %" PRIu32
"!",
1926 case RDPGFX_CMDID_SOLIDFILL:
1927 if ((error = rdpgfx_recv_solid_fill_pdu(callback, s)))
1928 WLog_Print(gfx->base.log, WLOG_ERROR,
1929 "rdpgfx_recv_solid_fill_pdu failed with error %" PRIu32
"!", error);
1933 case RDPGFX_CMDID_SURFACETOSURFACE:
1934 if ((error = rdpgfx_recv_surface_to_surface_pdu(callback, s)))
1935 WLog_Print(gfx->base.log, WLOG_ERROR,
1936 "rdpgfx_recv_surface_to_surface_pdu failed with error %" PRIu32
"!",
1941 case RDPGFX_CMDID_SURFACETOCACHE:
1942 if ((error = rdpgfx_recv_surface_to_cache_pdu(callback, s)))
1943 WLog_Print(gfx->base.log, WLOG_ERROR,
1944 "rdpgfx_recv_surface_to_cache_pdu failed with error %" PRIu32
"!",
1949 case RDPGFX_CMDID_CACHETOSURFACE:
1950 if ((error = rdpgfx_recv_cache_to_surface_pdu(callback, s)))
1951 WLog_Print(gfx->base.log, WLOG_ERROR,
1952 "rdpgfx_recv_cache_to_surface_pdu failed with error %" PRIu32
"!",
1957 case RDPGFX_CMDID_EVICTCACHEENTRY:
1958 if ((error = rdpgfx_recv_evict_cache_entry_pdu(callback, s)))
1959 WLog_Print(gfx->base.log, WLOG_ERROR,
1960 "rdpgfx_recv_evict_cache_entry_pdu failed with error %" PRIu32
"!",
1965 case RDPGFX_CMDID_CREATESURFACE:
1966 if ((error = rdpgfx_recv_create_surface_pdu(callback, s)))
1967 WLog_Print(gfx->base.log, WLOG_ERROR,
1968 "rdpgfx_recv_create_surface_pdu failed with error %" PRIu32
"!", error);
1972 case RDPGFX_CMDID_DELETESURFACE:
1973 if ((error = rdpgfx_recv_delete_surface_pdu(callback, s)))
1974 WLog_Print(gfx->base.log, WLOG_ERROR,
1975 "rdpgfx_recv_delete_surface_pdu failed with error %" PRIu32
"!", error);
1979 case RDPGFX_CMDID_STARTFRAME:
1980 if ((error = rdpgfx_recv_start_frame_pdu(callback, s)))
1981 WLog_Print(gfx->base.log, WLOG_ERROR,
1982 "rdpgfx_recv_start_frame_pdu failed with error %" PRIu32
"!", error);
1986 case RDPGFX_CMDID_ENDFRAME:
1987 if ((error = rdpgfx_recv_end_frame_pdu(callback, s)))
1988 WLog_Print(gfx->base.log, WLOG_ERROR,
1989 "rdpgfx_recv_end_frame_pdu failed with error %" PRIu32
"!", error);
1993 case RDPGFX_CMDID_RESETGRAPHICS:
1994 if ((error = rdpgfx_recv_reset_graphics_pdu(callback, s)))
1995 WLog_Print(gfx->base.log, WLOG_ERROR,
1996 "rdpgfx_recv_reset_graphics_pdu failed with error %" PRIu32
"!", error);
2000 case RDPGFX_CMDID_MAPSURFACETOOUTPUT:
2001 if ((error = rdpgfx_recv_map_surface_to_output_pdu(callback, s)))
2002 WLog_Print(gfx->base.log, WLOG_ERROR,
2003 "rdpgfx_recv_map_surface_to_output_pdu failed with error %" PRIu32
"!",
2008 case RDPGFX_CMDID_CACHEIMPORTREPLY:
2009 if ((error = rdpgfx_recv_cache_import_reply_pdu(callback, s)))
2010 WLog_Print(gfx->base.log, WLOG_ERROR,
2011 "rdpgfx_recv_cache_import_reply_pdu failed with error %" PRIu32
"!",
2016 case RDPGFX_CMDID_CAPSCONFIRM:
2017 if ((error = rdpgfx_recv_caps_confirm_pdu(callback, s)))
2018 WLog_Print(gfx->base.log, WLOG_ERROR,
2019 "rdpgfx_recv_caps_confirm_pdu failed with error %" PRIu32
"!", error);
2021 if ((error = rdpgfx_send_cache_offer(gfx)))
2022 WLog_Print(gfx->base.log, WLOG_ERROR,
2023 "rdpgfx_send_cache_offer failed with error %" PRIu32
"!", error);
2027 case RDPGFX_CMDID_MAPSURFACETOWINDOW:
2028 if ((error = rdpgfx_recv_map_surface_to_window_pdu(callback, s)))
2029 WLog_Print(gfx->base.log, WLOG_ERROR,
2030 "rdpgfx_recv_map_surface_to_window_pdu failed with error %" PRIu32
"!",
2035 case RDPGFX_CMDID_MAPSURFACETOSCALEDWINDOW:
2036 if ((error = rdpgfx_recv_map_surface_to_scaled_window_pdu(callback, s)))
2037 WLog_Print(gfx->base.log, WLOG_ERROR,
2038 "rdpgfx_recv_map_surface_to_scaled_window_pdu failed with error %" PRIu32
2044 case RDPGFX_CMDID_MAPSURFACETOSCALEDOUTPUT:
2045 if ((error = rdpgfx_recv_map_surface_to_scaled_output_pdu(callback, s)))
2046 WLog_Print(gfx->base.log, WLOG_ERROR,
2047 "rdpgfx_recv_map_surface_to_scaled_output_pdu failed with error %" PRIu32
2054 error = CHANNEL_RC_BAD_PROC;
2060 WLog_Print(gfx->base.log, WLOG_ERROR,
2061 "Error while processing GFX cmdId: %s (0x%04" PRIX16
")",
2062 rdpgfx_get_cmd_id_string(header.cmdId), header.cmdId);
2063 if (!Stream_SetPosition(s, (beg + header.pduLength)))
2064 return ERROR_INVALID_DATA;
2068 const size_t end = Stream_GetPosition(s);
2070 if (end != (beg + header.pduLength))
2072 WLog_Print(gfx->base.log, WLOG_ERROR,
2073 "Unexpected gfx pdu end: Actual: %" PRIuz
", Expected: %" PRIuz, end,
2074 (beg + header.pduLength));
2075 if (!Stream_SetPosition(s, (beg + header.pduLength)))
2076 return ERROR_INVALID_DATA;
2087static UINT rdpgfx_on_data_received(IWTSVirtualChannelCallback* pChannelCallback,
wStream* data)
2090 BYTE* pDstData =
nullptr;
2092 WINPR_ASSERT(callback);
2094 UINT error = CHANNEL_RC_OK;
2097 int status = zgfx_decompress(gfx->zgfx, Stream_ConstPointer(data),
2098 (UINT32)Stream_GetRemainingLength(data), &pDstData, &DstSize, 0);
2102 WLog_Print(gfx->base.log, WLOG_ERROR,
"zgfx_decompress failure! status: %d", status);
2104 return ERROR_INTERNAL_ERROR;
2107 wStream sbuffer = WINPR_C_ARRAY_INIT;
2108 wStream* s = Stream_StaticConstInit(&sbuffer, pDstData, DstSize);
2112 WLog_Print(gfx->base.log, WLOG_ERROR,
"calloc failed!");
2114 return CHANNEL_RC_NO_MEMORY;
2117 while (Stream_GetPosition(s) < Stream_Length(s))
2119 if ((error = rdpgfx_recv_pdu(callback, s)))
2121 WLog_Print(gfx->base.log, WLOG_ERROR,
"rdpgfx_recv_pdu failed with error %" PRIu32
"!",
2136static UINT rdpgfx_on_open(IWTSVirtualChannelCallback* pChannelCallback)
2139 WINPR_ASSERT(callback);
2142 RdpgfxClientContext* context = gfx->context;
2143 UINT error = CHANNEL_RC_OK;
2144 BOOL do_caps_advertise = TRUE;
2146 gfx->sendFrameAcks = TRUE;
2150 IFCALLRET(context->OnOpen, error, context, &do_caps_advertise, &gfx->sendFrameAcks);
2153 WLog_Print(gfx->base.log, WLOG_ERROR,
"context->OnOpen failed with error %" PRIu32
"",
2157 if (do_caps_advertise)
2158 error = rdpgfx_send_supported_caps(callback);
2168static UINT rdpgfx_on_close(IWTSVirtualChannelCallback* pChannelCallback)
2170 UINT error = CHANNEL_RC_OK;
2172 WINPR_ASSERT(callback);
2178 RdpgfxClientContext* context = gfx->context;
2180 WLog_Print(gfx->base.log, WLOG_DEBUG,
"OnClose");
2181 error = rdpgfx_save_persistent_cache(gfx);
2186 WLog_Print(gfx->base.log, WLOG_ERROR,
2187 "rdpgfx_save_persistent_cache failed with error %" PRIu32
"", error);
2190 free_surfaces(context, gfx->SurfaceTable);
2191 error = evict_cache_slots(context, gfx->MaxCacheSlots, gfx->CacheSlots);
2195 WLog_Print(gfx->base.log, WLOG_ERROR,
"evict_cache_slots failed with error %" PRIu32
"",
2200 gfx->UnacknowledgedFrames = 0;
2201 gfx->TotalDecodedFrames = 0;
2205 error = IFCALLRESULT(CHANNEL_RC_OK, context->OnClose, context);
2209 WLog_Print(gfx->base.log, WLOG_ERROR,
"context->OnClose failed with error %" PRIu32
"",
2215 return CHANNEL_RC_OK;
2222 RdpgfxClientContext* context = gfx->context;
2224 WLog_Print(gfx->base.log, WLOG_DEBUG,
"Terminated");
2225 rdpgfx_client_context_free(context);
2233static UINT rdpgfx_set_surface_data(RdpgfxClientContext* context, UINT16 surfaceId,
void* pData)
2235 WINPR_ASSERT(context);
2238 ULONG_PTR key = ((ULONG_PTR)surfaceId) + 1;
2242 if (!HashTable_Insert(gfx->SurfaceTable, (
void*)key, pData))
2243 return ERROR_BAD_ARGUMENTS;
2246 HashTable_Remove(gfx->SurfaceTable, (
void*)key);
2248 return CHANNEL_RC_OK;
2256static UINT rdpgfx_get_surface_ids(RdpgfxClientContext* context, UINT16** ppSurfaceIds,
2259 ULONG_PTR* pKeys =
nullptr;
2260 WINPR_ASSERT(context);
2263 size_t count = HashTable_GetKeys(gfx->SurfaceTable, &pKeys);
2265 WINPR_ASSERT(ppSurfaceIds);
2266 WINPR_ASSERT(count_out);
2270 return CHANNEL_RC_OK;
2273 UINT16* pSurfaceIds = (UINT16*)calloc(count,
sizeof(UINT16));
2277 WLog_Print(gfx->base.log, WLOG_ERROR,
"calloc failed!");
2279 return CHANNEL_RC_NO_MEMORY;
2282 for (
size_t index = 0; index < count; index++)
2284 pSurfaceIds[index] = (UINT16)(pKeys[index] - 1);
2288 *ppSurfaceIds = pSurfaceIds;
2289 *count_out = (UINT16)count;
2290 return CHANNEL_RC_OK;
2293static void* rdpgfx_get_surface_data(RdpgfxClientContext* context, UINT16 surfaceId)
2295 WINPR_ASSERT(context);
2298 ULONG_PTR key = ((ULONG_PTR)surfaceId) + 1;
2299 return HashTable_GetItemValue(gfx->SurfaceTable, (
void*)key);
2307static UINT rdpgfx_set_cache_slot_data(RdpgfxClientContext* context, UINT16 cacheSlot,
void* pData)
2309 WINPR_ASSERT(context);
2314 if (cacheSlot == 0 || cacheSlot > gfx->MaxCacheSlots)
2316 WLog_Print(gfx->base.log, WLOG_ERROR,
2317 "invalid cache slot %" PRIu16
", must be between 1 and %" PRIu16
"", cacheSlot,
2318 gfx->MaxCacheSlots);
2319 return ERROR_INVALID_INDEX;
2322 gfx->CacheSlots[cacheSlot - 1] = pData;
2323 return CHANNEL_RC_OK;
2326static void* rdpgfx_get_cache_slot_data(RdpgfxClientContext* context, UINT16 cacheSlot)
2328 WINPR_ASSERT(context);
2332 if (cacheSlot == 0 || cacheSlot > gfx->MaxCacheSlots)
2334 WLog_Print(gfx->base.log, WLOG_ERROR,
2335 "invalid cache slot %" PRIu16
", must be between 1 and %" PRIu16
"", cacheSlot,
2336 gfx->MaxCacheSlots);
2340 return gfx->CacheSlots[cacheSlot - 1];
2344 WINPR_ATTR_UNUSED rdpSettings* settings)
2349 gfx->rdpcontext = rcontext;
2351 gfx->SurfaceTable = HashTable_New(TRUE);
2352 if (!gfx->SurfaceTable)
2354 WLog_Print(gfx->base.log, WLOG_ERROR,
"HashTable_New for surfaces failed !");
2355 return CHANNEL_RC_NO_MEMORY;
2358 gfx->suspendFrameAcks =
2360 gfx->MaxCacheSlots =
2363 RdpgfxClientContext* context = (RdpgfxClientContext*)calloc(1,
sizeof(RdpgfxClientContext));
2366 WLog_Print(gfx->base.log, WLOG_ERROR,
"context calloc failed!");
2367 HashTable_Free(gfx->SurfaceTable);
2368 gfx->SurfaceTable =
nullptr;
2369 return CHANNEL_RC_NO_MEMORY;
2372 gfx->zgfx = zgfx_context_new(FALSE);
2375 WLog_Print(gfx->base.log, WLOG_ERROR,
"zgfx_context_new failed!");
2376 HashTable_Free(gfx->SurfaceTable);
2377 gfx->SurfaceTable =
nullptr;
2379 return CHANNEL_RC_NO_MEMORY;
2382 context->handle = (
void*)gfx;
2383 context->GetSurfaceIds = rdpgfx_get_surface_ids;
2384 context->SetSurfaceData = rdpgfx_set_surface_data;
2385 context->GetSurfaceData = rdpgfx_get_surface_data;
2386 context->SetCacheSlotData = rdpgfx_set_cache_slot_data;
2387 context->GetCacheSlotData = rdpgfx_get_cache_slot_data;
2388 context->CapsAdvertise = rdpgfx_send_caps_advertise_pdu;
2389 context->FrameAcknowledge = rdpgfx_send_frame_acknowledge_pdu;
2390 context->CacheImportOffer = rdpgfx_send_cache_import_offer_pdu;
2391 context->QoeFrameAcknowledge = rdpgfx_send_qoe_frame_acknowledge_pdu;
2393 gfx->base.iface.pInterface = (
void*)context;
2394 gfx->context = context;
2395 return CHANNEL_RC_OK;
2398void rdpgfx_client_context_free(RdpgfxClientContext* context)
2405 free_surfaces(context, gfx->SurfaceTable);
2406 evict_cache_slots(context, gfx->MaxCacheSlots, gfx->CacheSlots);
2410 zgfx_context_free(gfx->zgfx);
2411 gfx->zgfx =
nullptr;
2414 HashTable_Free(gfx->SurfaceTable);
2418static const IWTSVirtualChannelCallback rdpgfx_callbacks = { rdpgfx_on_data_received,
2419 rdpgfx_on_open, rdpgfx_on_close,
2427FREERDP_ENTRY_POINT(UINT VCAPITYPE rdpgfx_DVCPluginEntry(IDRDYNVC_ENTRY_POINTS* pEntryPoints))
2429 return freerdp_generic_DVCPluginEntry(pEntryPoints, GFXTAG, RDPGFX_DVC_CHANNEL_NAME,
2431 &rdpgfx_callbacks, init_plugin_cb, terminate_plugin_cb);
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 UINT32 freerdp_settings_get_uint32(const rdpSettings *settings, FreeRDP_Settings_Keys_UInt32 id)
Returns a UINT32 settings value.
WINPR_ATTR_NODISCARD FREERDP_API BOOL freerdp_settings_get_bool(const rdpSettings *settings, FreeRDP_Settings_Keys_Bool id)
Returns a boolean settings value.