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
53 uint64_t cntGfxCodecID[RDPGFX_CODECID_MAX];
54 uint64_t cntGfxCommandID[RDPGFX_CMDID_MAX + 1];
55} RdpgfxClientContextStats;
59 RdpgfxClientContext common;
60 RdpgfxClientContextStats stats;
61} RdpgfxClientContextInt;
63size_t rdpgfx_stats_max_index(
void)
65 return sizeof(RdpgfxClientContextStats) /
sizeof(uint64_t);
68const char* rdpgfx_stats_name_for_index(
size_t index)
70 if (index < RDPGFX_CODECID_MAX)
71 return rdpgfx_get_codec_id_string(WINPR_ASSERTING_INT_CAST(UINT16, index));
73 index -= RDPGFX_CODECID_MAX;
74 if (index < RDPGFX_CMDID_MAX)
75 return rdpgfx_get_cmd_id_string(WINPR_ASSERTING_INT_CAST(UINT16, index));
76 return "RDPGFX_STATS_UNUSED";
79uint64_t rdpgfx_stats_value_for_index(RdpgfxClientContext* context,
size_t index)
81 WINPR_ASSERT(context);
83 RdpgfxClientContextInt* intCtx = (RdpgfxClientContextInt*)context;
85 if (index < RDPGFX_CODECID_MAX)
86 return intCtx->stats.cntGfxCodecID[WINPR_ASSERTING_INT_CAST(UINT16, index)];
88 index -= RDPGFX_CODECID_MAX;
89 if (index < RDPGFX_CMDID_MAX)
90 return intCtx->stats.cntGfxCommandID[WINPR_ASSERTING_INT_CAST(UINT16, index)];
94static void rdpgfx_codecid_event(RdpgfxClientContext* context, uint32_t index)
98 RdpgfxClientContextInt* intCtx = (RdpgfxClientContextInt*)context;
100 if (index < RDPGFX_CODECID_MAX)
101 intCtx->stats.cntGfxCodecID[index]++;
106 WLog_Print(gfx->base.log, WLOG_WARN,
"Invalid event index %" PRIu32, index);
110static void rdpgfx_stats_cmdid_event(RdpgfxClientContext* context, uint32_t index)
114 RdpgfxClientContextInt* intCtx = (RdpgfxClientContextInt*)context;
115 WINPR_ASSERT(intCtx);
117 if (index >= RDPGFX_CMDID_MAX)
121 WLog_Print(gfx->base.log, WLOG_WARN,
"Invalid codecID %" PRIu32, index);
122 index = RDPGFX_CMDID_MAX;
124 intCtx->stats.cntGfxCommandID[index]++;
127static BOOL delete_surface(
const void* key,
void* value,
void* arg)
129 const UINT16
id = (UINT16)(uintptr_t)(key);
133 RdpgfxClientContext* context = arg;
140 UINT error = CHANNEL_RC_OK;
141 IFCALLRET(context->DeleteSurface, error, context, &pdu);
147 WLog_Print(gfx->base.log, WLOG_ERROR,
148 "context->DeleteSurface failed with error %" PRIu32
"", error);
154static void free_surfaces(RdpgfxClientContext* context, wHashTable* SurfaceTable)
156 WINPR_ASSERT(context);
157 if (!HashTable_Foreach(SurfaceTable, delete_surface, context))
161 WLog_Print(gfx->base.log, WLOG_WARN,
"delete_surface failed");
165static UINT evict_cache_slots(RdpgfxClientContext* context, UINT16 MaxCacheSlots,
void** CacheSlots)
167 UINT error = CHANNEL_RC_OK;
169 WINPR_ASSERT(CacheSlots);
170 for (UINT16 index = 0; index < MaxCacheSlots; index++)
172 if (CacheSlots[index])
176 if (context && context->EvictCacheEntry)
178 const UINT rc = context->EvictCacheEntry(context, &pdu);
179 if (rc != CHANNEL_RC_OK)
183 CacheSlots[index] =
nullptr;
194static UINT rdpgfx_send_caps_advertise_pdu(RdpgfxClientContext* context,
197 UINT error = CHANNEL_RC_OK;
200 WINPR_ASSERT(context);
204 if (!gfx || !gfx->base.listener_callback)
205 return ERROR_BAD_ARGUMENTS;
210 .cmdId = RDPGFX_CMDID_CAPSADVERTISE,
211 .pduLength = RDPGFX_HEADER_SIZE + 2 };
213 for (UINT16 index = 0; index < pdu->capsSetCount; index++)
216 header.pduLength += RDPGFX_CAPSET_BASE_SIZE + capsSet->length;
219 WLog_Print(gfx->base.log, WLOG_DEBUG,
"SendCapsAdvertisePdu %" PRIu16
"", pdu->capsSetCount);
220 wStream* s = Stream_New(
nullptr, header.pduLength);
224 WLog_Print(gfx->base.log, WLOG_ERROR,
"Stream_New failed!");
225 return CHANNEL_RC_NO_MEMORY;
228 if ((error = rdpgfx_write_header(s, &header)))
232 Stream_Write_UINT16(s, pdu->capsSetCount);
234 for (UINT16 index = 0; index < pdu->capsSetCount; index++)
238 WLog_Print(gfx->base.log, WLOG_DEBUG,
"Sending %s [0x%08" PRIx32
"] flags=0x%08" PRIx32,
239 rdpgfx_caps_version_str(capsSet->version), capsSet->version, capsSet->flags);
241 Stream_Write_UINT32(s, capsSet->version);
242 Stream_Write_UINT32(s, capsSet->length);
243 Stream_Write_UINT32(s, capsSet->flags);
244 if (capsSet->length < 4)
246 Stream_Zero(s, capsSet->length - 4);
249 Stream_SealLength(s);
250 error = callback->channel->Write(callback->channel, (UINT32)Stream_Length(s), Stream_Buffer(s),
253 Stream_Free(s, TRUE);
257static BOOL rdpgfx_is_capability_filtered(
RDPGFX_PLUGIN* gfx, UINT32 caps)
260 const UINT32 filter =
262 const UINT32 capList[] = {
263#if defined(WITH_GFX_AV1)
264 RDPGFX_CAPVERSION_FRDP_1,
267 RDPGFX_CAPVERSION_81,
268 RDPGFX_CAPVERSION_10,
269 RDPGFX_CAPVERSION_101,
270 RDPGFX_CAPVERSION_102,
271 RDPGFX_CAPVERSION_103,
272 RDPGFX_CAPVERSION_104,
273 RDPGFX_CAPVERSION_105,
274 RDPGFX_CAPVERSION_106,
275 RDPGFX_CAPVERSION_106_ERR,
276 RDPGFX_CAPVERSION_107
277#if defined(WITH_GFX_AZURE)
279 RDPGFX_CAPVERSION_111,
280 RDPGFX_CAPVERSION_112,
281 RDPGFX_CAPVERSION_113
285 for (
size_t x = 0; x < ARRAYSIZE(capList); x++)
287 if (caps == capList[x])
288 return (filter & (1u << x)) != 0;
298 WINPR_ASSERT(pdu->capsSets);
299 WINPR_ASSERT(count > 0);
300 WINPR_ASSERT(pdu->capsSetCount < count);
301 if (pdu->capsSetCount >= count)
303 return &pdu->capsSets[pdu->capsSetCount++];
313 RDPGFX_CAPSET capsSets[RDPGFX_NUMBER_CAPSETS] = WINPR_C_ARRAY_INIT;
316 return ERROR_BAD_ARGUMENTS;
321 return ERROR_BAD_CONFIGURATION;
323 RdpgfxClientContext* context = gfx->context;
326 return ERROR_BAD_CONFIGURATION;
330 if (!rdpgfx_is_capability_filtered(gfx, RDPGFX_CAPVERSION_8))
332 RDPGFX_CAPSET* capsSet = nextCapset(&pdu, ARRAYSIZE(capsSets));
334 return ERROR_BAD_CONFIGURATION;
335 capsSet->version = RDPGFX_CAPVERSION_8;
340 capsSet->flags |= RDPGFX_CAPS_FLAG_THINCLIENT;
347 capsSet->flags |= RDPGFX_CAPS_FLAG_SMALL_CACHE;
350 if (!rdpgfx_is_capability_filtered(gfx, RDPGFX_CAPVERSION_81))
352 RDPGFX_CAPSET* capsSet = nextCapset(&pdu, ARRAYSIZE(capsSets));
354 return ERROR_BAD_CONFIGURATION;
355 capsSet->version = RDPGFX_CAPVERSION_81;
360 capsSet->flags |= RDPGFX_CAPS_FLAG_THINCLIENT;
363 capsSet->flags |= RDPGFX_CAPS_FLAG_SMALL_CACHE;
368 capsSet->flags |= RDPGFX_CAPS_FLAG_AVC420_ENABLED;
373 UINT32 caps10Flags = 0;
378 caps10Flags |= RDPGFX_CAPS_FLAG_SMALL_CACHE;
383 caps10Flags |= RDPGFX_CAPS_FLAG_AVC_DISABLED;
386 caps10Flags |= RDPGFX_CAPS_FLAG_AVC_DISABLED;
389 if (!rdpgfx_is_capability_filtered(gfx, RDPGFX_CAPVERSION_10))
391 RDPGFX_CAPSET* capsSet = nextCapset(&pdu, ARRAYSIZE(capsSets));
393 return ERROR_BAD_CONFIGURATION;
394 capsSet->version = RDPGFX_CAPVERSION_10;
396 capsSet->flags = caps10Flags;
399 if (!rdpgfx_is_capability_filtered(gfx, RDPGFX_CAPVERSION_101))
401 RDPGFX_CAPSET* capsSet = nextCapset(&pdu, ARRAYSIZE(capsSets));
403 return ERROR_BAD_CONFIGURATION;
404 capsSet->version = RDPGFX_CAPVERSION_101;
405 capsSet->length = 0x10;
409 if (!rdpgfx_is_capability_filtered(gfx, RDPGFX_CAPVERSION_102))
411 RDPGFX_CAPSET* capsSet = nextCapset(&pdu, ARRAYSIZE(capsSets));
413 return ERROR_BAD_CONFIGURATION;
414 capsSet->version = RDPGFX_CAPVERSION_102;
415 capsSet->length = 0x4;
416 capsSet->flags = caps10Flags;
421 if ((caps10Flags & RDPGFX_CAPS_FLAG_AVC_DISABLED) == 0)
422 caps10Flags |= RDPGFX_CAPS_FLAG_AVC_THINCLIENT;
425 if (!rdpgfx_is_capability_filtered(gfx, RDPGFX_CAPVERSION_103))
427 RDPGFX_CAPSET* capsSet = nextCapset(&pdu, ARRAYSIZE(capsSets));
429 return ERROR_BAD_CONFIGURATION;
430 capsSet->version = RDPGFX_CAPVERSION_103;
431 capsSet->length = 0x4;
432 capsSet->flags = caps10Flags & ~RDPGFX_CAPS_FLAG_SMALL_CACHE;
435 if (!rdpgfx_is_capability_filtered(gfx, RDPGFX_CAPVERSION_104))
437 RDPGFX_CAPSET* capsSet = nextCapset(&pdu, ARRAYSIZE(capsSets));
439 return ERROR_BAD_CONFIGURATION;
440 capsSet->version = RDPGFX_CAPVERSION_104;
441 capsSet->length = 0x4;
442 capsSet->flags = caps10Flags;
448#if defined(WITH_CAIRO) || defined(WITH_SWSCALE)
449 if (!rdpgfx_is_capability_filtered(gfx, RDPGFX_CAPVERSION_105))
451 RDPGFX_CAPSET* capsSet = nextCapset(&pdu, ARRAYSIZE(capsSets));
453 return ERROR_BAD_CONFIGURATION;
454 capsSet->version = RDPGFX_CAPVERSION_105;
455 capsSet->length = 0x4;
456 capsSet->flags = caps10Flags;
459 if (!rdpgfx_is_capability_filtered(gfx, RDPGFX_CAPVERSION_106))
461 RDPGFX_CAPSET* capsSet = nextCapset(&pdu, ARRAYSIZE(capsSets));
463 return ERROR_BAD_CONFIGURATION;
464 capsSet->version = RDPGFX_CAPVERSION_106;
465 capsSet->length = 0x4;
466 capsSet->flags = caps10Flags;
469 if (!rdpgfx_is_capability_filtered(gfx, RDPGFX_CAPVERSION_106_ERR))
471 RDPGFX_CAPSET* capsSet = nextCapset(&pdu, ARRAYSIZE(capsSets));
473 return ERROR_BAD_CONFIGURATION;
474 capsSet->version = RDPGFX_CAPVERSION_106_ERR;
475 capsSet->length = 0x4;
476 capsSet->flags = caps10Flags;
480 if (!rdpgfx_is_capability_filtered(gfx, RDPGFX_CAPVERSION_107))
482 RDPGFX_CAPSET* capsSet = nextCapset(&pdu, ARRAYSIZE(capsSets));
484 return ERROR_BAD_CONFIGURATION;
485 capsSet->version = RDPGFX_CAPVERSION_107;
486 capsSet->length = 0x4;
487 capsSet->flags = caps10Flags;
488#if !defined(WITH_CAIRO) && !defined(WITH_SWSCALE)
489 capsSet->flags |= RDPGFX_CAPS_FLAG_SCALEDMAP_DISABLE;
493#if defined(WITH_GFX_AZURE)
494 if (!rdpgfx_is_capability_filtered(gfx, RDPGFX_CAPVERSION_111))
496 RDPGFX_CAPSET* capsSet = nextCapset(&pdu, ARRAYSIZE(capsSets));
498 return ERROR_BAD_CONFIGURATION;
499 capsSet->version = RDPGFX_CAPVERSION_111;
500 capsSet->length = 0x4;
501 capsSet->flags = caps10Flags;
502#if !defined(WITH_CAIRO) && !defined(WITH_SWSCALE)
503 capsSet->flags |= RDPGFX_CAPS_FLAG_SCALEDMAP_DISABLE;
507 if (!rdpgfx_is_capability_filtered(gfx, RDPGFX_CAPVERSION_112))
509 RDPGFX_CAPSET* capsSet = nextCapset(&pdu, ARRAYSIZE(capsSets));
511 return ERROR_BAD_CONFIGURATION;
512 capsSet->version = RDPGFX_CAPVERSION_112;
513 capsSet->length = 0x4;
514 capsSet->flags = caps10Flags;
515#if !defined(WITH_CAIRO) && !defined(WITH_SWSCALE)
516 capsSet->flags |= RDPGFX_CAPS_FLAG_SCALEDMAP_DISABLE;
520 if (!rdpgfx_is_capability_filtered(gfx, RDPGFX_CAPVERSION_113))
522 RDPGFX_CAPSET* capsSet = nextCapset(&pdu, ARRAYSIZE(capsSets));
524 return ERROR_BAD_CONFIGURATION;
525 capsSet->version = RDPGFX_CAPVERSION_113;
526 capsSet->length = 0x4;
527 capsSet->flags = caps10Flags;
528#if !defined(WITH_CAIRO) && !defined(WITH_SWSCALE)
529 capsSet->flags |= RDPGFX_CAPS_FLAG_SCALEDMAP_DISABLE;
535#if defined(WITH_GFX_AV1)
538 if (!rdpgfx_is_capability_filtered(gfx, RDPGFX_CAPVERSION_FRDP_1))
540 RDPGFX_CAPSET* capsSet = nextCapset(&pdu, ARRAYSIZE(capsSets));
542 return ERROR_BAD_CONFIGURATION;
543 capsSet->version = RDPGFX_CAPVERSION_FRDP_1;
544 capsSet->length = 0x4;
546 capsSet->flags = caps10Flags | RDPGFX_CAPS_FLAG_AV1_I444_SUPPORTED;
547 const UINT32 profile =
550 capsSet->flags |= RDPGFX_CAPS_FLAG_AV1_I444_DISABLED;
552#if !defined(WITH_CAIRO) && !defined(WITH_SWSCALE)
553 capsSet->flags |= RDPGFX_CAPS_FLAG_SCALEDMAP_DISABLE;
559 return IFCALLRESULT(ERROR_BAD_CONFIGURATION, context->CapsAdvertise, context, &pdu);
569 WINPR_ASSERT(callback);
573 RdpgfxClientContext* context = gfx->context;
578 if (!Stream_CheckAndLogRequiredLengthWLog(gfx->base.log, s, 12))
579 return ERROR_INVALID_DATA;
581 Stream_Read_UINT32(s, capsSet.version);
582 Stream_Read_UINT32(s, capsSet.length);
583 Stream_Read_UINT32(s, capsSet.flags);
584 gfx->TotalDecodedFrames = 0;
585 gfx->ConnectionCaps = capsSet;
586 WLog_Print(gfx->base.log, WLOG_DEBUG,
587 "RecvCapsConfirmPdu: version: %s [0x%08" PRIX32
"] flags: 0x%08" PRIX32
"",
588 rdpgfx_caps_version_str(capsSet.version), capsSet.version, capsSet.flags);
591 return ERROR_BAD_CONFIGURATION;
593 return IFCALLRESULT(CHANNEL_RC_OK, context->CapsConfirm, context, &pdu);
601static UINT rdpgfx_send_frame_acknowledge_pdu(RdpgfxClientContext* context,
606 if (!context || !pdu)
607 return ERROR_BAD_ARGUMENTS;
611 if (!gfx || !gfx->base.listener_callback)
612 return ERROR_BAD_CONFIGURATION;
617 return ERROR_BAD_CONFIGURATION;
620 .cmdId = RDPGFX_CMDID_FRAMEACKNOWLEDGE,
621 .pduLength = RDPGFX_HEADER_SIZE + 12 };
623 WLog_Print(gfx->base.log, WLOG_TRACE,
"SendFrameAcknowledgePdu: %" PRIu32
"", pdu->frameId);
625 wStream* s = Stream_New(
nullptr, header.pduLength);
629 WLog_Print(gfx->base.log, WLOG_ERROR,
"Stream_New failed!");
630 return CHANNEL_RC_NO_MEMORY;
633 if ((error = rdpgfx_write_header(s, &header)))
637 Stream_Write_UINT32(s, pdu->queueDepth);
638 Stream_Write_UINT32(s, pdu->frameId);
639 Stream_Write_UINT32(s, pdu->totalFramesDecoded);
640 error = callback->channel->Write(callback->channel, (UINT32)Stream_Length(s), Stream_Buffer(s),
643 if (error == CHANNEL_RC_OK)
644 gfx->UnacknowledgedFrames--;
647 Stream_Free(s, TRUE);
651static UINT rdpgfx_send_qoe_frame_acknowledge_pdu(RdpgfxClientContext* context,
654 UINT error = CHANNEL_RC_OK;
656 .cmdId = RDPGFX_CMDID_QOEFRAMEACKNOWLEDGE,
657 .pduLength = RDPGFX_HEADER_SIZE + 12 };
659 if (!context || !pdu)
660 return ERROR_BAD_ARGUMENTS;
664 if (!gfx || !gfx->base.listener_callback)
665 return ERROR_BAD_CONFIGURATION;
670 return ERROR_BAD_CONFIGURATION;
672 WLog_Print(gfx->base.log, WLOG_TRACE,
"SendQoeFrameAcknowledgePdu: %" PRIu32
"", pdu->frameId);
673 wStream* s = Stream_New(
nullptr, header.pduLength);
677 WLog_Print(gfx->base.log, WLOG_ERROR,
"Stream_New failed!");
678 return CHANNEL_RC_NO_MEMORY;
681 if ((error = rdpgfx_write_header(s, &header)))
685 Stream_Write_UINT32(s, pdu->frameId);
686 Stream_Write_UINT32(s, pdu->timestamp);
687 Stream_Write_UINT16(s, pdu->timeDiffSE);
688 Stream_Write_UINT16(s, pdu->timeDiffEDR);
689 error = callback->channel->Write(callback->channel, (UINT32)Stream_Length(s), Stream_Buffer(s),
692 Stream_Free(s, TRUE);
704 WINPR_ASSERT(callback);
710 RdpgfxClientContext* context = gfx->context;
711 UINT error = CHANNEL_RC_OK;
712 GraphicsResetEventArgs graphicsReset = WINPR_C_ARRAY_INIT;
714 if (!Stream_CheckAndLogRequiredLengthWLog(gfx->base.log, s, 12))
715 return ERROR_INVALID_DATA;
717 Stream_Read_UINT32(s, pdu.width);
718 Stream_Read_UINT32(s, pdu.height);
719 Stream_Read_UINT32(s, pdu.monitorCount);
721 if (!Stream_CheckAndLogRequiredLengthOfSizeWLog(gfx->base.log, s, pdu.monitorCount, 20ull))
722 return ERROR_INVALID_DATA;
726 if (!pdu.monitorDefArray)
728 WLog_Print(gfx->base.log, WLOG_ERROR,
"calloc failed!");
729 return CHANNEL_RC_NO_MEMORY;
732 for (UINT32 index = 0; index < pdu.monitorCount; index++)
734 MONITOR_DEF* monitor = &(pdu.monitorDefArray[index]);
735 Stream_Read_INT32(s, monitor->left);
736 Stream_Read_INT32(s, monitor->top);
737 Stream_Read_INT32(s, monitor->right);
738 Stream_Read_INT32(s, monitor->bottom);
739 Stream_Read_UINT32(s, monitor->flags);
742 const size_t size = (RDPGFX_HEADER_SIZE + 12ULL + (pdu.monitorCount * 20ULL));
745 free(pdu.monitorDefArray);
746 return CHANNEL_RC_NULL_DATA;
748 const size_t pad = 340ULL - size;
750 if (!Stream_CheckAndLogRequiredLengthWLog(gfx->base.log, s, (
size_t)pad))
752 free(pdu.monitorDefArray);
753 return CHANNEL_RC_NO_MEMORY;
757 WLog_Print(gfx->base.log, WLOG_DEBUG,
758 "RecvResetGraphicsPdu: width: %" PRIu32
" height: %" PRIu32
" count: %" PRIu32
"",
759 pdu.width, pdu.height, pdu.monitorCount);
761 for (UINT32 index = 0; index < pdu.monitorCount; index++)
763 MONITOR_DEF* monitor = &(pdu.monitorDefArray[index]);
764 WLog_Print(gfx->base.log, WLOG_TRACE,
765 "RecvResetGraphicsPdu: monitor left:%" PRIi32
" top:%" PRIi32
" right:%" PRIi32
766 " bottom:%" PRIi32
" flags:0x%" PRIx32
"",
767 monitor->left, monitor->top, monitor->right, monitor->bottom, monitor->flags);
772 IFCALLRET(context->ResetGraphics, error, context, &pdu);
775 WLog_Print(gfx->base.log, WLOG_ERROR,
776 "context->ResetGraphics failed with error %" PRIu32
"", error);
779 free(pdu.monitorDefArray);
782 EventArgsInit(&graphicsReset,
"libfreerdp");
783 graphicsReset.width = pdu.width;
784 graphicsReset.height = pdu.height;
785 if (PubSub_OnGraphicsReset(gfx->rdpcontext->pubSub, gfx->rdpcontext, &graphicsReset) < 0)
786 return ERROR_INTERNAL_ERROR;
798 WINPR_ASSERT(callback);
801 RdpgfxClientContext* context = gfx->context;
802 UINT error = CHANNEL_RC_OK;
804 if (!Stream_CheckAndLogRequiredLengthWLog(gfx->base.log, s, 2))
805 return ERROR_INVALID_DATA;
807 Stream_Read_UINT16(s, pdu.cacheSlot);
808 WLog_Print(gfx->base.log, WLOG_DEBUG,
"RecvEvictCacheEntryPdu: cacheSlot: %" PRIu16
"",
813 IFCALLRET(context->EvictCacheEntry, error, context, &pdu);
816 WLog_Print(gfx->base.log, WLOG_ERROR,
817 "context->EvictCacheEntry failed with error %" PRIu32
"", error);
830 UINT error = CHANNEL_RC_OK;
833 WINPR_ASSERT(gfx->rdpcontext);
834 rdpSettings* settings = gfx->rdpcontext->settings;
835 RdpgfxClientContext* context = gfx->context;
837 WINPR_ASSERT(context);
838 WINPR_ASSERT(settings);
841 return CHANNEL_RC_OK;
843 const char* BitmapCachePersistFile =
845 if (!BitmapCachePersistFile)
846 return CHANNEL_RC_OK;
848 if (!context->ExportCacheEntry)
849 return CHANNEL_RC_INITIALIZATION_ERROR;
851 rdpPersistentCache* persistent = persistent_cache_new();
854 return CHANNEL_RC_NO_MEMORY;
856 if (persistent_cache_open(persistent, BitmapCachePersistFile, TRUE, 3) < 1)
858 error = CHANNEL_RC_INITIALIZATION_ERROR;
862 for (UINT16 idx = 0; idx < gfx->MaxCacheSlots; idx++)
864 if (gfx->CacheSlots[idx])
866 const UINT16 cacheSlot = idx;
869 if (context->ExportCacheEntry(context, cacheSlot, &cacheEntry) != CHANNEL_RC_OK)
872 if (persistent_cache_write_entry(persistent, &cacheEntry) < 0)
877 persistent_cache_free(persistent);
881 persistent_cache_free(persistent);
890static UINT rdpgfx_send_cache_import_offer_pdu(RdpgfxClientContext* context,
893 UINT error = CHANNEL_RC_OK;
895 if (!context || !pdu)
896 return ERROR_BAD_ARGUMENTS;
900 if (!gfx || !gfx->base.listener_callback)
901 return ERROR_BAD_CONFIGURATION;
906 return ERROR_BAD_CONFIGURATION;
909 .cmdId = RDPGFX_CMDID_CACHEIMPORTOFFER,
911 RDPGFX_HEADER_SIZE + 2ul + pdu->cacheEntriesCount * 12ul };
913 WLog_Print(gfx->base.log, WLOG_DEBUG,
"SendCacheImportOfferPdu: cacheEntriesCount: %" PRIu16
"",
914 pdu->cacheEntriesCount);
915 wStream* s = Stream_New(
nullptr, header.pduLength);
919 WLog_Print(gfx->base.log, WLOG_ERROR,
"Stream_New failed!");
920 return CHANNEL_RC_NO_MEMORY;
923 if ((error = rdpgfx_write_header(s, &header)))
926 if (pdu->cacheEntriesCount <= 0)
928 WLog_Print(gfx->base.log, WLOG_ERROR,
"Invalid cacheEntriesCount: %" PRIu16
"",
929 pdu->cacheEntriesCount);
930 error = ERROR_INVALID_DATA;
935 Stream_Write_UINT16(s, pdu->cacheEntriesCount);
937 for (UINT16 index = 0; index < pdu->cacheEntriesCount; index++)
940 Stream_Write_UINT64(s, cacheEntry->cacheKey);
941 Stream_Write_UINT32(s, cacheEntry->bitmapLength);
944 error = callback->channel->Write(callback->channel, (UINT32)Stream_Length(s), Stream_Buffer(s),
948 Stream_Free(s, TRUE);
960 UINT error = CHANNEL_RC_OK;
965 WINPR_ASSERT(gfx->rdpcontext);
967 RdpgfxClientContext* context = gfx->context;
968 rdpSettings* settings = gfx->rdpcontext->settings;
971 return CHANNEL_RC_OK;
973 const char* BitmapCachePersistFile =
975 if (!BitmapCachePersistFile)
976 return CHANNEL_RC_OK;
978 rdpPersistentCache* persistent = persistent_cache_new();
981 return CHANNEL_RC_NO_MEMORY;
983 if (persistent_cache_open(persistent, BitmapCachePersistFile, FALSE, 3) < 1)
985 error = CHANNEL_RC_INITIALIZATION_ERROR;
989 if (persistent_cache_get_version(persistent) != 3)
991 error = ERROR_INVALID_DATA;
995 count = persistent_cache_get_count(persistent);
998 error = ERROR_INVALID_DATA;
1002 if (count >= RDPGFX_CACHE_ENTRY_MAX_COUNT)
1003 count = RDPGFX_CACHE_ENTRY_MAX_COUNT - 1;
1005 if (count > gfx->MaxCacheSlots)
1006 count = gfx->MaxCacheSlots;
1011 error = CHANNEL_RC_NO_MEMORY;
1015 WINPR_ASSERT(count <= UINT16_MAX);
1016 offer->cacheEntriesCount = (UINT16)count;
1018 WLog_Print(gfx->base.log, WLOG_DEBUG,
"Sending Cache Import Offer: %d", count);
1020 for (
int idx = 0; idx < count; idx++)
1022 if (persistent_cache_read_entry(persistent, &entry) < 1)
1024 error = ERROR_INVALID_DATA;
1028 offer->cacheEntries[idx].cacheKey = entry.key64;
1029 offer->cacheEntries[idx].bitmapLength = entry.size;
1032 if (offer->cacheEntriesCount > 0)
1034 error = rdpgfx_send_cache_import_offer_pdu(context, offer);
1035 if (error != CHANNEL_RC_OK)
1037 WLog_Print(gfx->base.log, WLOG_ERROR,
"Failed to send cache import offer PDU");
1043 persistent_cache_free(persistent);
1053static UINT rdpgfx_load_cache_import_reply(
RDPGFX_PLUGIN* gfx,
1056 UINT error = CHANNEL_RC_OK;
1057 rdpPersistentCache* persistent =
nullptr;
1059 WINPR_ASSERT(gfx->rdpcontext);
1060 rdpSettings* settings = gfx->rdpcontext->settings;
1061 RdpgfxClientContext* context = gfx->context;
1063 WINPR_ASSERT(settings);
1064 WINPR_ASSERT(reply);
1066 return CHANNEL_RC_OK;
1068 const char* BitmapCachePersistFile =
1070 if (!BitmapCachePersistFile)
1071 return CHANNEL_RC_OK;
1073 persistent = persistent_cache_new();
1076 return CHANNEL_RC_NO_MEMORY;
1078 if (persistent_cache_open(persistent, BitmapCachePersistFile, FALSE, 3) < 1)
1080 error = CHANNEL_RC_INITIALIZATION_ERROR;
1084 if (persistent_cache_get_version(persistent) != 3)
1086 error = ERROR_INVALID_DATA;
1090 int count = persistent_cache_get_count(persistent);
1092 count = (count < reply->importedEntriesCount) ? count : reply->importedEntriesCount;
1094 WLog_Print(gfx->base.log, WLOG_DEBUG,
"Receiving Cache Import Reply: %d", count);
1096 for (
int idx = 0; idx < count; idx++)
1099 if (persistent_cache_read_entry(persistent, &entry) < 1)
1101 error = ERROR_INVALID_DATA;
1105 const UINT16 cacheSlot = reply->cacheSlots[idx];
1106 if (context && context->ImportCacheEntry)
1108 error = context->ImportCacheEntry(context, cacheSlot, &entry);
1109 if (error != CHANNEL_RC_OK)
1114 persistent_cache_free(persistent);
1118 persistent_cache_free(persistent);
1130 WINPR_ASSERT(callback);
1133 RdpgfxClientContext* context = gfx->context;
1134 UINT error = CHANNEL_RC_OK;
1136 if (!Stream_CheckAndLogRequiredLengthWLog(gfx->base.log, s, 2))
1137 return ERROR_INVALID_DATA;
1139 Stream_Read_UINT16(s, pdu.importedEntriesCount);
1141 if (!Stream_CheckAndLogRequiredLengthOfSizeWLog(gfx->base.log, s, pdu.importedEntriesCount,
1143 return ERROR_INVALID_DATA;
1145 if (pdu.importedEntriesCount > RDPGFX_CACHE_ENTRY_MAX_COUNT)
1146 return ERROR_INVALID_DATA;
1148 for (UINT16 idx = 0; idx < pdu.importedEntriesCount; idx++)
1150 Stream_Read_UINT16(s, pdu.cacheSlots[idx]);
1153 WLog_Print(gfx->base.log, WLOG_TRACE,
1154 "RecvCacheImportReplyPdu: importedEntriesCount: %" PRIu16
"",
1155 pdu.importedEntriesCount);
1157 error = rdpgfx_load_cache_import_reply(gfx, &pdu);
1161 WLog_Print(gfx->base.log, WLOG_ERROR,
1162 "rdpgfx_load_cache_import_reply failed with error %" PRIu32
"", error);
1168 IFCALLRET(context->CacheImportReply, error, context, &pdu);
1171 WLog_Print(gfx->base.log, WLOG_ERROR,
1172 "context->CacheImportReply failed with error %" PRIu32
"", error);
1186 WINPR_ASSERT(callback);
1189 RdpgfxClientContext* context = gfx->context;
1190 UINT error = CHANNEL_RC_OK;
1192 if (!Stream_CheckAndLogRequiredLengthWLog(gfx->base.log, s, 7))
1193 return ERROR_INVALID_DATA;
1195 Stream_Read_UINT16(s, pdu.surfaceId);
1196 Stream_Read_UINT16(s, pdu.width);
1197 Stream_Read_UINT16(s, pdu.height);
1198 Stream_Read_UINT8(s, pdu.pixelFormat);
1199 WLog_Print(gfx->base.log, WLOG_DEBUG,
1200 "RecvCreateSurfacePdu: surfaceId: %" PRIu16
" width: %" PRIu16
" height: %" PRIu16
1201 " pixelFormat: 0x%02" PRIX8
"",
1202 pdu.surfaceId, pdu.width, pdu.height, pdu.pixelFormat);
1211 const UINT drc = IFCALLRESULT(CHANNEL_RC_OK, context->DeleteSurface, context, &deletePdu);
1212 if (drc != CHANNEL_RC_OK)
1213 WLog_Print(gfx->base.log, WLOG_WARN,
1214 "context->DeleteSurface failed with error %" PRIu32
", ignoring", drc);
1216 IFCALLRET(context->CreateSurface, error, context, &pdu);
1219 WLog_Print(gfx->base.log, WLOG_ERROR,
1220 "context->CreateSurface failed with error %" PRIu32
"", error);
1234 WINPR_ASSERT(callback);
1237 RdpgfxClientContext* context = gfx->context;
1238 UINT error = CHANNEL_RC_OK;
1240 if (!Stream_CheckAndLogRequiredLengthWLog(gfx->base.log, s, 2))
1241 return ERROR_INVALID_DATA;
1243 Stream_Read_UINT16(s, pdu.surfaceId);
1244 WLog_Print(gfx->base.log, WLOG_DEBUG,
"RecvDeleteSurfacePdu: surfaceId: %" PRIu16
"",
1249 IFCALLRET(context->DeleteSurface, error, context, &pdu);
1252 WLog_Print(gfx->base.log, WLOG_ERROR,
1253 "context->DeleteSurface failed with error %" PRIu32
"", error);
1267 WINPR_ASSERT(callback);
1270 RdpgfxClientContext* context = gfx->context;
1271 UINT error = CHANNEL_RC_OK;
1273 if (!Stream_CheckAndLogRequiredLengthWLog(gfx->base.log, s, RDPGFX_START_FRAME_PDU_SIZE))
1274 return ERROR_INVALID_DATA;
1276 Stream_Read_UINT32(s, pdu.timestamp);
1277 Stream_Read_UINT32(s, pdu.frameId);
1278 WLog_Print(gfx->base.log, WLOG_TRACE,
1279 "RecvStartFramePdu: frameId: %" PRIu32
" timestamp: 0x%08" PRIX32
"", pdu.frameId,
1281 gfx->StartDecodingTime = GetTickCount64();
1285 IFCALLRET(context->StartFrame, error, context, &pdu);
1288 WLog_Print(gfx->base.log, WLOG_ERROR,
1289 "context->StartFrame failed with error %" PRIu32
"", error);
1292 gfx->UnacknowledgedFrames++;
1305 WINPR_ASSERT(callback);
1308 RdpgfxClientContext* context = gfx->context;
1309 UINT error = CHANNEL_RC_OK;
1311 if (!Stream_CheckAndLogRequiredLengthWLog(gfx->base.log, s, RDPGFX_END_FRAME_PDU_SIZE))
1312 return ERROR_INVALID_DATA;
1314 Stream_Read_UINT32(s, pdu.frameId);
1315 WLog_Print(gfx->base.log, WLOG_TRACE,
"RecvEndFramePdu: frameId: %" PRIu32
"", pdu.frameId);
1317 const UINT64 start = GetTickCount64();
1320 IFCALLRET(context->EndFrame, error, context, &pdu);
1324 WLog_Print(gfx->base.log, WLOG_ERROR,
"context->EndFrame failed with error %" PRIu32
"",
1329 const UINT64 end = GetTickCount64();
1330 const UINT64 EndFrameTime = end - start;
1331 gfx->TotalDecodedFrames++;
1333 if (!gfx->sendFrameAcks)
1336 ack.frameId = pdu.frameId;
1337 ack.totalFramesDecoded = gfx->TotalDecodedFrames;
1339 if (gfx->suspendFrameAcks)
1341 ack.queueDepth = SUSPEND_FRAME_ACKNOWLEDGEMENT;
1343 if (gfx->TotalDecodedFrames == 1)
1344 if ((error = rdpgfx_send_frame_acknowledge_pdu(context, &ack)))
1345 WLog_Print(gfx->base.log, WLOG_ERROR,
1346 "rdpgfx_send_frame_acknowledge_pdu failed with error %" PRIu32
"",
1351 ack.queueDepth = QUEUE_DEPTH_UNAVAILABLE;
1353 if ((error = rdpgfx_send_frame_acknowledge_pdu(context, &ack)))
1354 WLog_Print(gfx->base.log, WLOG_ERROR,
1355 "rdpgfx_send_frame_acknowledge_pdu failed with error %" PRIu32
"", error);
1358 switch (gfx->ConnectionCaps.version)
1360#if defined(WITH_GFX_AV1)
1361 case RDPGFX_CAPVERSION_FRDP_1:
1363 case RDPGFX_CAPVERSION_10:
1364 case RDPGFX_CAPVERSION_102:
1365 case RDPGFX_CAPVERSION_103:
1366 case RDPGFX_CAPVERSION_104:
1367 case RDPGFX_CAPVERSION_105:
1368 case RDPGFX_CAPVERSION_106:
1369 case RDPGFX_CAPVERSION_106_ERR:
1370 case RDPGFX_CAPVERSION_107:
1371#if defined(WITH_GFX_AZURE)
1372 case RDPGFX_CAPVERSION_111:
1373 case RDPGFX_CAPVERSION_112:
1374 case RDPGFX_CAPVERSION_113:
1379 UINT64 diff = (GetTickCount64() - gfx->StartDecodingTime);
1384 qoe.frameId = pdu.frameId;
1385 qoe.timestamp = gfx->StartDecodingTime % UINT32_MAX;
1386 qoe.timeDiffSE = WINPR_ASSERTING_INT_CAST(UINT16, diff);
1387 qoe.timeDiffEDR = WINPR_ASSERTING_INT_CAST(UINT16, EndFrameTime);
1389 if ((error = rdpgfx_send_qoe_frame_acknowledge_pdu(context, &qoe)))
1390 WLog_Print(gfx->base.log, WLOG_ERROR,
1391 "rdpgfx_send_qoe_frame_acknowledge_pdu failed with error %" PRIu32
1414 WINPR_ASSERT(callback);
1419 if (!Stream_CheckAndLogRequiredLengthWLog(gfx->base.log, s, RDPGFX_WIRE_TO_SURFACE_PDU_1_SIZE))
1420 return ERROR_INVALID_DATA;
1422 Stream_Read_UINT16(s, pdu.surfaceId);
1423 Stream_Read_UINT16(s, pdu.codecId);
1424 Stream_Read_UINT8(s, pdu.pixelFormat);
1426 if ((error = rdpgfx_read_rect16(gfx->base.log, s, &(pdu.destRect))))
1428 WLog_Print(gfx->base.log, WLOG_ERROR,
"rdpgfx_read_rect16 failed with error %" PRIu32
"",
1433 Stream_Read_UINT32(s, pdu.bitmapDataLength);
1435 if (!Stream_CheckAndLogRequiredLengthWLog(gfx->base.log, s, pdu.bitmapDataLength))
1436 return ERROR_INVALID_DATA;
1438 pdu.bitmapData = Stream_Pointer(s);
1439 Stream_Seek(s, pdu.bitmapDataLength);
1441 WLog_Print(gfx->base.log, WLOG_TRACE,
1442 "RecvWireToSurface1Pdu: surfaceId: %" PRIu16
" codecId: %s (0x%04" PRIX16
1443 ") pixelFormat: 0x%02" PRIX8
" "
1444 "destRect: left: %" PRIu16
" top: %" PRIu16
" right: %" PRIu16
" bottom: %" PRIu16
1445 " bitmapDataLength: %" PRIu32
"",
1446 pdu.surfaceId, rdpgfx_get_codec_id_string(pdu.codecId), pdu.codecId, pdu.pixelFormat,
1447 pdu.destRect.left, pdu.destRect.top, pdu.destRect.right, pdu.destRect.bottom,
1448 pdu.bitmapDataLength);
1449 cmd.surfaceId = pdu.surfaceId;
1450 cmd.codecId = pdu.codecId;
1453 switch (pdu.pixelFormat)
1455 case GFX_PIXEL_FORMAT_XRGB_8888:
1456 cmd.format = PIXEL_FORMAT_BGRX32;
1459 case GFX_PIXEL_FORMAT_ARGB_8888:
1460 cmd.format = PIXEL_FORMAT_BGRA32;
1464 return ERROR_INVALID_DATA;
1467 cmd.left = pdu.destRect.left;
1468 cmd.top = pdu.destRect.top;
1469 cmd.right = pdu.destRect.right;
1470 cmd.bottom = pdu.destRect.bottom;
1471 cmd.width = cmd.right - cmd.left;
1472 cmd.height = cmd.bottom - cmd.top;
1473 cmd.length = pdu.bitmapDataLength;
1474 cmd.data = pdu.bitmapData;
1475 cmd.extra =
nullptr;
1477 if (cmd.right < cmd.left)
1479 WLog_Print(gfx->base.log, WLOG_ERROR,
1480 "RecvWireToSurface1Pdu right=%" PRIu32
" < left=%" PRIu32, cmd.right, cmd.left);
1481 return ERROR_INVALID_DATA;
1483 if (cmd.bottom < cmd.top)
1485 WLog_Print(gfx->base.log, WLOG_ERROR,
1486 "RecvWireToSurface1Pdu bottom=%" PRIu32
" < top=%" PRIu32, cmd.bottom, cmd.top);
1487 return ERROR_INVALID_DATA;
1490 if ((error = rdpgfx_decode(gfx, &cmd)))
1491 WLog_Print(gfx->base.log, WLOG_ERROR,
"rdpgfx_decode failed with error %" PRIu32
"!",
1500 switch (cmd->codecId)
1502 case RDPGFX_CODECID_UNCOMPRESSED:
1503 case RDPGFX_CODECID_CAVIDEO:
1504 case RDPGFX_CODECID_CLEARCODEC:
1505 case RDPGFX_CODECID_PLANAR:
1506 case RDPGFX_CODECID_AVC420:
1507 case RDPGFX_CODECID_ALPHA:
1508 case RDPGFX_CODECID_AVC444:
1509 case RDPGFX_CODECID_AVC444v2:
1510 case RDPGFX_CODECID_CAPROGRESSIVE:
1511 case RDPGFX_CODECID_CAPROGRESSIVE_V2:
1513#if defined(WITH_GFX_AV1)
1514 case RDPGFX_CODECID_AV1:
1515 if (gfx->ConnectionCaps.version != RDPGFX_CAPVERSION_FRDP_1)
1517 WLog_Print(gfx->base.log, WLOG_ERROR,
1518 "RDPGFX_SURFACE_COMMAND::codecId %" PRIu32
1519 " only supported with %s but connection uses %s [0x%08" PRIx32
"]",
1520 cmd->codecId, rdpgfx_caps_version_str(RDPGFX_CAPVERSION_FRDP_1),
1521 rdpgfx_caps_version_str(gfx->ConnectionCaps.version),
1522 gfx->ConnectionCaps.version);
1528 WLog_Print(gfx->base.log, WLOG_ERROR,
1529 "Unknown RDPGFX_SURFACE_COMMAND::codecId %" PRIu32, cmd->codecId);
1538 WLog_Print(gfx->base.log, WLOG_DEBUG,
"Got GFX %s",
1539 rdpgfx_get_codec_id_string(WINPR_ASSERTING_INT_CAST(UINT16, cmd->codecId)));
1541 RdpgfxClientContext* context = gfx->context;
1543 return CHANNEL_RC_OK;
1545 if (!checkSurfaceCommand(gfx, cmd))
1546 return CHANNEL_RC_NULL_DATA;
1548 const UINT error = IFCALLRESULT(CHANNEL_RC_OK, context->SurfaceCommand, context, cmd);
1551 WLog_Print(gfx->base.log, WLOG_ERROR,
1552 "context->SurfaceCommand failed with error %" PRIu32
"", error);
1554 rdpgfx_codecid_event(context, cmd->codecId);
1568 WINPR_ASSERT(callback);
1572 if (!Stream_CheckAndLogRequiredLengthWLog(gfx->base.log, s, RDPGFX_WIRE_TO_SURFACE_PDU_2_SIZE))
1573 return ERROR_INVALID_DATA;
1575 Stream_Read_UINT16(s, pdu.surfaceId);
1576 Stream_Read_UINT16(s, pdu.codecId);
1577 Stream_Read_UINT32(s, pdu.codecContextId);
1578 Stream_Read_UINT8(s, pdu.pixelFormat);
1579 Stream_Read_UINT32(s, pdu.bitmapDataLength);
1580 pdu.bitmapData = Stream_Pointer(s);
1581 if (!Stream_SafeSeek(s, pdu.bitmapDataLength))
1582 return ERROR_INVALID_DATA;
1584 WLog_Print(gfx->base.log, WLOG_TRACE,
1585 "RecvWireToSurface2Pdu: surfaceId: %" PRIu16
" codecId: %s (0x%04" PRIX16
") "
1586 "codecContextId: %" PRIu32
" pixelFormat: 0x%02" PRIX8
" bitmapDataLength: %" PRIu32
1588 pdu.surfaceId, rdpgfx_get_codec_id_string(pdu.codecId), pdu.codecId,
1589 pdu.codecContextId, pdu.pixelFormat, pdu.bitmapDataLength);
1591 cmd.surfaceId = pdu.surfaceId;
1592 cmd.codecId = pdu.codecId;
1593 cmd.contextId = pdu.codecContextId;
1595 switch (pdu.pixelFormat)
1597 case GFX_PIXEL_FORMAT_XRGB_8888:
1598 cmd.format = PIXEL_FORMAT_BGRX32;
1601 case GFX_PIXEL_FORMAT_ARGB_8888:
1602 cmd.format = PIXEL_FORMAT_BGRA32;
1606 return ERROR_INVALID_DATA;
1609 cmd.length = pdu.bitmapDataLength;
1610 cmd.data = pdu.bitmapData;
1611 cmd.extra =
nullptr;
1613 return logSurfaceCommand(gfx, &cmd);
1624 WINPR_ASSERT(callback);
1627 RdpgfxClientContext* context = gfx->context;
1628 UINT error = CHANNEL_RC_OK;
1630 if (!Stream_CheckAndLogRequiredLengthWLog(gfx->base.log, s, 6))
1631 return ERROR_INVALID_DATA;
1633 Stream_Read_UINT16(s, pdu.surfaceId);
1634 Stream_Read_UINT32(s, pdu.codecContextId);
1636 WLog_Print(gfx->base.log, WLOG_DEBUG,
1637 "RecvDeleteEncodingContextPdu: surfaceId: %" PRIu16
" codecContextId: %" PRIu32
"",
1638 pdu.surfaceId, pdu.codecContextId);
1642 IFCALLRET(context->DeleteEncodingContext, error, context, &pdu);
1645 WLog_Print(gfx->base.log, WLOG_ERROR,
1646 "context->DeleteEncodingContext failed with error %" PRIu32
"", error);
1660 WINPR_ASSERT(callback);
1663 RdpgfxClientContext* context = gfx->context;
1665 if (!Stream_CheckAndLogRequiredLengthWLog(gfx->base.log, s, 8))
1666 return ERROR_INVALID_DATA;
1668 Stream_Read_UINT16(s, pdu.surfaceId);
1670 UINT error = rdpgfx_read_color32(gfx->base.log, s, &(pdu.fillPixel));
1671 if (error != CHANNEL_RC_OK)
1673 WLog_Print(gfx->base.log, WLOG_ERROR,
"rdpgfx_read_color32 failed with error %" PRIu32
"!",
1678 Stream_Read_UINT16(s, pdu.fillRectCount);
1680 if (!Stream_CheckAndLogRequiredLengthOfSizeWLog(gfx->base.log, s, pdu.fillRectCount, 8ull))
1681 return ERROR_INVALID_DATA;
1687 WLog_Print(gfx->base.log, WLOG_ERROR,
"calloc failed!");
1688 return CHANNEL_RC_NO_MEMORY;
1691 for (UINT16 index = 0; index < pdu.fillRectCount; index++)
1695 if ((error = rdpgfx_read_rect16(gfx->base.log, s, fillRect)))
1697 WLog_Print(gfx->base.log, WLOG_ERROR,
1698 "rdpgfx_read_rect16 failed with error %" PRIu32
"!", error);
1699 free(pdu.fillRects);
1703 WLog_Print(gfx->base.log, WLOG_TRACE,
1704 "RecvSolidFillPdu: surfaceId: %" PRIu16
" fillRectCount: %" PRIu16
"", pdu.surfaceId,
1709 IFCALLRET(context->SolidFill, error, context, &pdu);
1712 WLog_Print(gfx->base.log, WLOG_ERROR,
1713 "context->SolidFill failed with error %" PRIu32
"", error);
1716 free(pdu.fillRects);
1728 WINPR_ASSERT(callback);
1731 RdpgfxClientContext* context = gfx->context;
1734 if (!Stream_CheckAndLogRequiredLengthWLog(gfx->base.log, s, 14))
1735 return ERROR_INVALID_DATA;
1737 Stream_Read_UINT16(s, pdu.surfaceIdSrc);
1738 Stream_Read_UINT16(s, pdu.surfaceIdDest);
1740 if ((error = rdpgfx_read_rect16(gfx->base.log, s, &(pdu.rectSrc))))
1742 WLog_Print(gfx->base.log, WLOG_ERROR,
"rdpgfx_read_rect16 failed with error %" PRIu32
"!",
1747 Stream_Read_UINT16(s, pdu.destPtsCount);
1749 if (!Stream_CheckAndLogRequiredLengthOfSizeWLog(gfx->base.log, s, pdu.destPtsCount, 4ull))
1750 return ERROR_INVALID_DATA;
1756 WLog_Print(gfx->base.log, WLOG_ERROR,
"calloc failed!");
1757 return CHANNEL_RC_NO_MEMORY;
1760 for (UINT16 index = 0; index < pdu.destPtsCount; index++)
1764 if ((error = rdpgfx_read_point16(gfx->base.log, s, destPt)))
1766 WLog_Print(gfx->base.log, WLOG_ERROR,
1767 "rdpgfx_read_point16 failed with error %" PRIu32
"!", error);
1773 WLog_Print(gfx->base.log, WLOG_TRACE,
1774 "RecvSurfaceToSurfacePdu: surfaceIdSrc: %" PRIu16
" surfaceIdDest: %" PRIu16
" "
1775 "left: %" PRIu16
" top: %" PRIu16
" right: %" PRIu16
" bottom: %" PRIu16
1776 " destPtsCount: %" PRIu16
"",
1777 pdu.surfaceIdSrc, pdu.surfaceIdDest, pdu.rectSrc.left, pdu.rectSrc.top,
1778 pdu.rectSrc.right, pdu.rectSrc.bottom, pdu.destPtsCount);
1782 IFCALLRET(context->SurfaceToSurface, error, context, &pdu);
1785 WLog_Print(gfx->base.log, WLOG_ERROR,
1786 "context->SurfaceToSurface failed with error %" PRIu32
"", error);
1801 WINPR_ASSERT(callback);
1805 RdpgfxClientContext* context = gfx->context;
1807 if (!Stream_CheckAndLogRequiredLengthWLog(gfx->base.log, s, 20))
1808 return ERROR_INVALID_DATA;
1810 Stream_Read_UINT16(s, pdu.surfaceId);
1811 Stream_Read_UINT64(s, pdu.cacheKey);
1812 Stream_Read_UINT16(s, pdu.cacheSlot);
1814 UINT error = rdpgfx_read_rect16(gfx->base.log, s, &(pdu.rectSrc));
1815 if (error != CHANNEL_RC_OK)
1817 WLog_Print(gfx->base.log, WLOG_ERROR,
"rdpgfx_read_rect16 failed with error %" PRIu32
"!",
1822 WLog_Print(gfx->base.log, WLOG_TRACE,
1823 "RecvSurfaceToCachePdu: surfaceId: %" PRIu16
" cacheKey: 0x%016" PRIX64
1824 " cacheSlot: %" PRIu16
" "
1825 "left: %" PRIu16
" top: %" PRIu16
" right: %" PRIu16
" bottom: %" PRIu16
"",
1826 pdu.surfaceId, pdu.cacheKey, pdu.cacheSlot, pdu.rectSrc.left, pdu.rectSrc.top,
1827 pdu.rectSrc.right, pdu.rectSrc.bottom);
1831 IFCALLRET(context->SurfaceToCache, error, context, &pdu);
1834 WLog_Print(gfx->base.log, WLOG_ERROR,
1835 "context->SurfaceToCache failed with error %" PRIu32
"", error);
1849 WINPR_ASSERT(callback);
1853 RdpgfxClientContext* context = gfx->context;
1854 UINT error = CHANNEL_RC_OK;
1856 if (!Stream_CheckAndLogRequiredLengthWLog(gfx->base.log, s, 6))
1857 return ERROR_INVALID_DATA;
1859 Stream_Read_UINT16(s, pdu.cacheSlot);
1860 Stream_Read_UINT16(s, pdu.surfaceId);
1861 Stream_Read_UINT16(s, pdu.destPtsCount);
1863 if (!Stream_CheckAndLogRequiredLengthOfSizeWLog(gfx->base.log, s, pdu.destPtsCount, 4ull))
1864 return ERROR_INVALID_DATA;
1870 WLog_Print(gfx->base.log, WLOG_ERROR,
"calloc failed!");
1871 return CHANNEL_RC_NO_MEMORY;
1874 for (UINT16 index = 0; index < pdu.destPtsCount; index++)
1878 if ((error = rdpgfx_read_point16(gfx->base.log, s, destPt)))
1880 WLog_Print(gfx->base.log, WLOG_ERROR,
1881 "rdpgfx_read_point16 failed with error %" PRIu32
"", error);
1887 WLog_Print(gfx->base.log, WLOG_TRACE,
1888 "RdpGfxRecvCacheToSurfacePdu: cacheSlot: %" PRIu16
" surfaceId: %" PRIu16
1889 " destPtsCount: %" PRIu16
"",
1890 pdu.cacheSlot, pdu.surfaceId, pdu.destPtsCount);
1894 IFCALLRET(context->CacheToSurface, error, context, &pdu);
1897 WLog_Print(gfx->base.log, WLOG_ERROR,
1898 "context->CacheToSurface failed with error %" PRIu32
"", error);
1913 WINPR_ASSERT(callback);
1917 RdpgfxClientContext* context = gfx->context;
1918 UINT error = CHANNEL_RC_OK;
1920 if (!Stream_CheckAndLogRequiredLengthWLog(gfx->base.log, s, 12))
1921 return ERROR_INVALID_DATA;
1923 Stream_Read_UINT16(s, pdu.surfaceId);
1924 Stream_Read_UINT16(s, pdu.reserved);
1925 Stream_Read_UINT32(s, pdu.outputOriginX);
1926 Stream_Read_UINT32(s, pdu.outputOriginY);
1927 WLog_Print(gfx->base.log, WLOG_DEBUG,
1928 "RecvMapSurfaceToOutputPdu: surfaceId: %" PRIu16
" outputOriginX: %" PRIu32
1929 " outputOriginY: %" PRIu32
"",
1930 pdu.surfaceId, pdu.outputOriginX, pdu.outputOriginY);
1934 IFCALLRET(context->MapSurfaceToOutput, error, context, &pdu);
1937 WLog_Print(gfx->base.log, WLOG_ERROR,
1938 "context->MapSurfaceToOutput failed with error %" PRIu32
"", error);
1948 WINPR_ASSERT(callback);
1952 RdpgfxClientContext* context = gfx->context;
1953 UINT error = CHANNEL_RC_OK;
1955 if (!Stream_CheckAndLogRequiredLengthWLog(gfx->base.log, s, 20))
1956 return ERROR_INVALID_DATA;
1958 Stream_Read_UINT16(s, pdu.surfaceId);
1959 Stream_Read_UINT16(s, pdu.reserved);
1960 Stream_Read_UINT32(s, pdu.outputOriginX);
1961 Stream_Read_UINT32(s, pdu.outputOriginY);
1962 Stream_Read_UINT32(s, pdu.targetWidth);
1963 Stream_Read_UINT32(s, pdu.targetHeight);
1964 WLog_Print(gfx->base.log, WLOG_DEBUG,
1965 "RecvMapSurfaceToScaledOutputPdu: surfaceId: %" PRIu16
" outputOriginX: %" PRIu32
1966 " outputOriginY: %" PRIu32
" targetWidth: %" PRIu32
" targetHeight: %" PRIu32,
1967 pdu.surfaceId, pdu.outputOriginX, pdu.outputOriginY, pdu.targetWidth,
1972 IFCALLRET(context->MapSurfaceToScaledOutput, error, context, &pdu);
1975 WLog_Print(gfx->base.log, WLOG_ERROR,
1976 "context->MapSurfaceToScaledOutput failed with error %" PRIu32
"", error);
1990 WINPR_ASSERT(callback);
1994 RdpgfxClientContext* context = gfx->context;
1995 UINT error = CHANNEL_RC_OK;
1997 if (!Stream_CheckAndLogRequiredLengthWLog(gfx->base.log, s, 18))
1998 return ERROR_INVALID_DATA;
2000 Stream_Read_UINT16(s, pdu.surfaceId);
2001 Stream_Read_UINT64(s, pdu.windowId);
2002 Stream_Read_UINT32(s, pdu.mappedWidth);
2003 Stream_Read_UINT32(s, pdu.mappedHeight);
2004 WLog_Print(gfx->base.log, WLOG_DEBUG,
2005 "RecvMapSurfaceToWindowPdu: surfaceId: %" PRIu16
" windowId: 0x%016" PRIX64
2006 " mappedWidth: %" PRIu32
" mappedHeight: %" PRIu32
"",
2007 pdu.surfaceId, pdu.windowId, pdu.mappedWidth, pdu.mappedHeight);
2009 if (context && context->MapSurfaceToWindow)
2011 IFCALLRET(context->MapSurfaceToWindow, error, context, &pdu);
2014 WLog_Print(gfx->base.log, WLOG_ERROR,
2015 "context->MapSurfaceToWindow failed with error %" PRIu32
"", error);
2025 WINPR_ASSERT(callback);
2028 RdpgfxClientContext* context = gfx->context;
2029 UINT error = CHANNEL_RC_OK;
2031 if (!Stream_CheckAndLogRequiredLengthWLog(gfx->base.log, s, 26))
2032 return ERROR_INVALID_DATA;
2034 Stream_Read_UINT16(s, pdu.surfaceId);
2035 Stream_Read_UINT64(s, pdu.windowId);
2036 Stream_Read_UINT32(s, pdu.mappedWidth);
2037 Stream_Read_UINT32(s, pdu.mappedHeight);
2038 Stream_Read_UINT32(s, pdu.targetWidth);
2039 Stream_Read_UINT32(s, pdu.targetHeight);
2040 WLog_Print(gfx->base.log, WLOG_DEBUG,
2041 "RecvMapSurfaceToScaledWindowPdu: surfaceId: %" PRIu16
" windowId: 0x%016" PRIX64
2042 " mappedWidth: %" PRIu32
" mappedHeight: %" PRIu32
" targetWidth: %" PRIu32
2043 " targetHeight: %" PRIu32
"",
2044 pdu.surfaceId, pdu.windowId, pdu.mappedWidth, pdu.mappedHeight, pdu.targetWidth,
2047 if (context && context->MapSurfaceToScaledWindow)
2049 IFCALLRET(context->MapSurfaceToScaledWindow, error, context, &pdu);
2052 WLog_Print(gfx->base.log, WLOG_ERROR,
2053 "context->MapSurfaceToScaledWindow failed with error %" PRIu32
"", error);
2068 WINPR_ASSERT(callback);
2070 const size_t beg = Stream_GetPosition(s);
2074 size_t packetlen = 0;
2075 UINT error = rdpgfx_read_header(gfx->base.log, s, &header, &packetlen);
2076 if (error != CHANNEL_RC_OK)
2078 WLog_Print(gfx->base.log, WLOG_ERROR,
"rdpgfx_read_header failed with error %" PRIu32
"!",
2083 WLog_Print(gfx->base.log, WLOG_TRACE,
2084 "cmdId: %s (0x%04" PRIX16
") flags: 0x%04" PRIX16
" pduLength: %" PRIu32
"",
2085 rdpgfx_get_cmd_id_string(header.cmdId), header.cmdId, header.flags,
2088 rdpgfx_stats_cmdid_event(gfx->context, header.cmdId);
2089 switch (header.cmdId)
2091 case RDPGFX_CMDID_WIRETOSURFACE_1:
2092 if ((error = rdpgfx_recv_wire_to_surface_1_pdu(callback, s)))
2093 WLog_Print(gfx->base.log, WLOG_ERROR,
2094 "rdpgfx_recv_wire_to_surface_1_pdu failed with error %" PRIu32
"!",
2099 case RDPGFX_CMDID_WIRETOSURFACE_2:
2100 if ((error = rdpgfx_recv_wire_to_surface_2_pdu(callback, s)))
2101 WLog_Print(gfx->base.log, WLOG_ERROR,
2102 "rdpgfx_recv_wire_to_surface_2_pdu failed with error %" PRIu32
"!",
2107 case RDPGFX_CMDID_DELETEENCODINGCONTEXT:
2108 if ((error = rdpgfx_recv_delete_encoding_context_pdu(callback, s)))
2109 WLog_Print(gfx->base.log, WLOG_ERROR,
2110 "rdpgfx_recv_delete_encoding_context_pdu failed with error %" PRIu32
"!",
2115 case RDPGFX_CMDID_SOLIDFILL:
2116 if ((error = rdpgfx_recv_solid_fill_pdu(callback, s)))
2117 WLog_Print(gfx->base.log, WLOG_ERROR,
2118 "rdpgfx_recv_solid_fill_pdu failed with error %" PRIu32
"!", error);
2122 case RDPGFX_CMDID_SURFACETOSURFACE:
2123 if ((error = rdpgfx_recv_surface_to_surface_pdu(callback, s)))
2124 WLog_Print(gfx->base.log, WLOG_ERROR,
2125 "rdpgfx_recv_surface_to_surface_pdu failed with error %" PRIu32
"!",
2130 case RDPGFX_CMDID_SURFACETOCACHE:
2131 if ((error = rdpgfx_recv_surface_to_cache_pdu(callback, s)))
2132 WLog_Print(gfx->base.log, WLOG_ERROR,
2133 "rdpgfx_recv_surface_to_cache_pdu failed with error %" PRIu32
"!",
2138 case RDPGFX_CMDID_CACHETOSURFACE:
2139 if ((error = rdpgfx_recv_cache_to_surface_pdu(callback, s)))
2140 WLog_Print(gfx->base.log, WLOG_ERROR,
2141 "rdpgfx_recv_cache_to_surface_pdu failed with error %" PRIu32
"!",
2146 case RDPGFX_CMDID_EVICTCACHEENTRY:
2147 if ((error = rdpgfx_recv_evict_cache_entry_pdu(callback, s)))
2148 WLog_Print(gfx->base.log, WLOG_ERROR,
2149 "rdpgfx_recv_evict_cache_entry_pdu failed with error %" PRIu32
"!",
2154 case RDPGFX_CMDID_CREATESURFACE:
2155 if ((error = rdpgfx_recv_create_surface_pdu(callback, s)))
2156 WLog_Print(gfx->base.log, WLOG_ERROR,
2157 "rdpgfx_recv_create_surface_pdu failed with error %" PRIu32
"!", error);
2161 case RDPGFX_CMDID_DELETESURFACE:
2162 if ((error = rdpgfx_recv_delete_surface_pdu(callback, s)))
2163 WLog_Print(gfx->base.log, WLOG_ERROR,
2164 "rdpgfx_recv_delete_surface_pdu failed with error %" PRIu32
"!", error);
2168 case RDPGFX_CMDID_STARTFRAME:
2169 if ((error = rdpgfx_recv_start_frame_pdu(callback, s)))
2170 WLog_Print(gfx->base.log, WLOG_ERROR,
2171 "rdpgfx_recv_start_frame_pdu failed with error %" PRIu32
"!", error);
2175 case RDPGFX_CMDID_ENDFRAME:
2176 if ((error = rdpgfx_recv_end_frame_pdu(callback, s)))
2177 WLog_Print(gfx->base.log, WLOG_ERROR,
2178 "rdpgfx_recv_end_frame_pdu failed with error %" PRIu32
"!", error);
2182 case RDPGFX_CMDID_RESETGRAPHICS:
2183 if ((error = rdpgfx_recv_reset_graphics_pdu(callback, s)))
2184 WLog_Print(gfx->base.log, WLOG_ERROR,
2185 "rdpgfx_recv_reset_graphics_pdu failed with error %" PRIu32
"!", error);
2189 case RDPGFX_CMDID_MAPSURFACETOOUTPUT:
2190 if ((error = rdpgfx_recv_map_surface_to_output_pdu(callback, s)))
2191 WLog_Print(gfx->base.log, WLOG_ERROR,
2192 "rdpgfx_recv_map_surface_to_output_pdu failed with error %" PRIu32
"!",
2197 case RDPGFX_CMDID_CACHEIMPORTREPLY:
2198 if ((error = rdpgfx_recv_cache_import_reply_pdu(callback, s)))
2199 WLog_Print(gfx->base.log, WLOG_ERROR,
2200 "rdpgfx_recv_cache_import_reply_pdu failed with error %" PRIu32
"!",
2205 case RDPGFX_CMDID_CAPSCONFIRM:
2206 if ((error = rdpgfx_recv_caps_confirm_pdu(callback, s)))
2207 WLog_Print(gfx->base.log, WLOG_ERROR,
2208 "rdpgfx_recv_caps_confirm_pdu failed with error %" PRIu32
"!", error);
2210 if ((error = rdpgfx_send_cache_offer(gfx)))
2211 WLog_Print(gfx->base.log, WLOG_ERROR,
2212 "rdpgfx_send_cache_offer failed with error %" PRIu32
"!", error);
2216 case RDPGFX_CMDID_MAPSURFACETOWINDOW:
2217 if ((error = rdpgfx_recv_map_surface_to_window_pdu(callback, s)))
2218 WLog_Print(gfx->base.log, WLOG_ERROR,
2219 "rdpgfx_recv_map_surface_to_window_pdu failed with error %" PRIu32
"!",
2224 case RDPGFX_CMDID_MAPSURFACETOSCALEDWINDOW:
2225 if ((error = rdpgfx_recv_map_surface_to_scaled_window_pdu(callback, s)))
2226 WLog_Print(gfx->base.log, WLOG_ERROR,
2227 "rdpgfx_recv_map_surface_to_scaled_window_pdu failed with error %" PRIu32
2233 case RDPGFX_CMDID_MAPSURFACETOSCALEDOUTPUT:
2234 if ((error = rdpgfx_recv_map_surface_to_scaled_output_pdu(callback, s)))
2235 WLog_Print(gfx->base.log, WLOG_ERROR,
2236 "rdpgfx_recv_map_surface_to_scaled_output_pdu failed with error %" PRIu32
2242 case RDPGFX_CMDID_PROTECT_SURFACE:
2243 case RDPGFX_CMDID_WATERMARK:
2244 WLog_Print(gfx->base.log, WLOG_WARN,
2245 "Command %s not implemented, skipping %" PRIu32
" bytes",
2246 rdpgfx_get_cmd_id_string(header.cmdId), header.pduLength);
2247 if (!Stream_SafeSeek(s, packetlen))
2248 error = ERROR_INVALID_DATA;
2251 error = CHANNEL_RC_BAD_PROC;
2257 WLog_Print(gfx->base.log, WLOG_ERROR,
2258 "Error while processing GFX cmdId: %s (0x%04" PRIX16
")",
2259 rdpgfx_get_cmd_id_string(header.cmdId), header.cmdId);
2260 if (!Stream_SetPosition(s, (beg + header.pduLength)))
2261 return ERROR_INVALID_DATA;
2265 const size_t end = Stream_GetPosition(s);
2267 if (end != (beg + header.pduLength))
2269 WLog_Print(gfx->base.log, WLOG_ERROR,
2270 "Unexpected gfx pdu end: Actual: %" PRIuz
", Expected: %" PRIuz, end,
2271 (beg + header.pduLength));
2272 if (!Stream_SetPosition(s, (beg + header.pduLength)))
2273 return ERROR_INVALID_DATA;
2284static UINT rdpgfx_on_data_received(IWTSVirtualChannelCallback* pChannelCallback,
wStream* data)
2287 BYTE* pDstData =
nullptr;
2289 WINPR_ASSERT(callback);
2291 UINT error = CHANNEL_RC_OK;
2294 int status = zgfx_decompress(gfx->zgfx, Stream_ConstPointer(data),
2295 (UINT32)Stream_GetRemainingLength(data), &pDstData, &DstSize, 0);
2299 WLog_Print(gfx->base.log, WLOG_ERROR,
"zgfx_decompress failure! status: %d", status);
2301 return ERROR_INTERNAL_ERROR;
2304 wStream sbuffer = WINPR_C_ARRAY_INIT;
2305 wStream* s = Stream_StaticConstInit(&sbuffer, pDstData, DstSize);
2309 WLog_Print(gfx->base.log, WLOG_ERROR,
"calloc failed!");
2311 return CHANNEL_RC_NO_MEMORY;
2314 while (Stream_GetPosition(s) < Stream_Length(s))
2316 if ((error = rdpgfx_recv_pdu(callback, s)))
2318 WLog_Print(gfx->base.log, WLOG_ERROR,
"rdpgfx_recv_pdu failed with error %" PRIu32
"!",
2333static UINT rdpgfx_on_open(IWTSVirtualChannelCallback* pChannelCallback)
2336 WINPR_ASSERT(callback);
2339 RdpgfxClientContext* context = gfx->context;
2340 UINT error = CHANNEL_RC_OK;
2341 BOOL do_caps_advertise = TRUE;
2343 gfx->sendFrameAcks = TRUE;
2347 IFCALLRET(context->OnOpen, error, context, &do_caps_advertise, &gfx->sendFrameAcks);
2350 WLog_Print(gfx->base.log, WLOG_ERROR,
"context->OnOpen failed with error %" PRIu32
"",
2353 RdpgfxClientContextInt* ctx = (RdpgfxClientContextInt*)context;
2354 const RdpgfxClientContextStats empty = WINPR_C_ARRAY_INIT;
2358 if (do_caps_advertise)
2359 error = rdpgfx_send_supported_caps(callback);
2364static void rdpgfx_dump_stats(RdpgfxClientContext* context)
2366 WINPR_ASSERT(context);
2371 wLog* log = gfx->base.log;
2372 const DWORD level = WLOG_TRACE;
2373 if (!WLog_IsLevelActive(log, level))
2376 WLog_Print(log, level,
"RdpgfxClientContextStats");
2377 for (
size_t x = 0; x < rdpgfx_stats_max_index(); x++)
2379 const char* name = rdpgfx_stats_name_for_index(x);
2380 const uint64_t val = rdpgfx_stats_value_for_index(context, x);
2381 WLog_Print(log, level,
"%s: %" PRIu64, name, val);
2390static UINT rdpgfx_on_close(IWTSVirtualChannelCallback* pChannelCallback)
2392 UINT error = CHANNEL_RC_OK;
2394 WINPR_ASSERT(callback);
2400 RdpgfxClientContext* context = gfx->context;
2402 WLog_Print(gfx->base.log, WLOG_DEBUG,
"OnClose");
2403 error = rdpgfx_save_persistent_cache(gfx);
2408 WLog_Print(gfx->base.log, WLOG_ERROR,
2409 "rdpgfx_save_persistent_cache failed with error %" PRIu32
"", error);
2412 free_surfaces(context, gfx->SurfaceTable);
2413 error = evict_cache_slots(context, gfx->MaxCacheSlots, gfx->CacheSlots);
2417 WLog_Print(gfx->base.log, WLOG_ERROR,
"evict_cache_slots failed with error %" PRIu32
"",
2422 gfx->UnacknowledgedFrames = 0;
2423 gfx->TotalDecodedFrames = 0;
2427 error = IFCALLRESULT(CHANNEL_RC_OK, context->OnClose, context);
2431 WLog_Print(gfx->base.log, WLOG_ERROR,
"context->OnClose failed with error %" PRIu32
"",
2434 rdpgfx_dump_stats(context);
2438 return CHANNEL_RC_OK;
2445 RdpgfxClientContext* context = gfx->context;
2447 WLog_Print(gfx->base.log, WLOG_DEBUG,
"Terminated");
2448 rdpgfx_client_context_free(context);
2456static UINT rdpgfx_set_surface_data(RdpgfxClientContext* context, UINT16 surfaceId,
void* pData)
2458 WINPR_ASSERT(context);
2461 ULONG_PTR key = ((ULONG_PTR)surfaceId) + 1;
2465 if (!HashTable_Insert(gfx->SurfaceTable, (
void*)key, pData))
2466 return ERROR_BAD_ARGUMENTS;
2469 HashTable_Remove(gfx->SurfaceTable, (
void*)key);
2471 return CHANNEL_RC_OK;
2479static UINT rdpgfx_get_surface_ids(RdpgfxClientContext* context, UINT16** ppSurfaceIds,
2482 ULONG_PTR* pKeys =
nullptr;
2483 WINPR_ASSERT(context);
2486 size_t count = HashTable_GetKeys(gfx->SurfaceTable, &pKeys);
2488 WINPR_ASSERT(ppSurfaceIds);
2489 WINPR_ASSERT(count_out);
2493 return CHANNEL_RC_OK;
2496 UINT16* pSurfaceIds = (UINT16*)calloc(count,
sizeof(UINT16));
2500 WLog_Print(gfx->base.log, WLOG_ERROR,
"calloc failed!");
2502 return CHANNEL_RC_NO_MEMORY;
2505 for (
size_t index = 0; index < count; index++)
2507 pSurfaceIds[index] = (UINT16)(pKeys[index] - 1);
2511 *ppSurfaceIds = pSurfaceIds;
2512 *count_out = (UINT16)count;
2513 return CHANNEL_RC_OK;
2516static void* rdpgfx_get_surface_data(RdpgfxClientContext* context, UINT16 surfaceId)
2518 WINPR_ASSERT(context);
2521 ULONG_PTR key = ((ULONG_PTR)surfaceId) + 1;
2522 return HashTable_GetItemValue(gfx->SurfaceTable, (
void*)key);
2530static UINT rdpgfx_set_cache_slot_data(RdpgfxClientContext* context, UINT16 cacheSlot,
void* pData)
2532 WINPR_ASSERT(context);
2537 if (cacheSlot == 0 || cacheSlot > gfx->MaxCacheSlots)
2539 WLog_Print(gfx->base.log, WLOG_ERROR,
2540 "invalid cache slot %" PRIu16
", must be between 1 and %" PRIu16
"", cacheSlot,
2541 gfx->MaxCacheSlots);
2542 return ERROR_INVALID_INDEX;
2545 gfx->CacheSlots[cacheSlot - 1] = pData;
2546 return CHANNEL_RC_OK;
2549static void* rdpgfx_get_cache_slot_data(RdpgfxClientContext* context, UINT16 cacheSlot)
2551 WINPR_ASSERT(context);
2555 if (cacheSlot == 0 || cacheSlot > gfx->MaxCacheSlots)
2557 WLog_Print(gfx->base.log, WLOG_ERROR,
2558 "invalid cache slot %" PRIu16
", must be between 1 and %" PRIu16
"", cacheSlot,
2559 gfx->MaxCacheSlots);
2563 return gfx->CacheSlots[cacheSlot - 1];
2567 WINPR_ATTR_UNUSED rdpSettings* settings)
2572 gfx->rdpcontext = rcontext;
2574 gfx->SurfaceTable = HashTable_New(TRUE);
2575 if (!gfx->SurfaceTable)
2577 WLog_Print(gfx->base.log, WLOG_ERROR,
"HashTable_New for surfaces failed !");
2578 return CHANNEL_RC_NO_MEMORY;
2581 gfx->suspendFrameAcks =
2583 gfx->MaxCacheSlots =
2586 RdpgfxClientContextInt* context =
2587 (RdpgfxClientContextInt*)calloc(1,
sizeof(RdpgfxClientContextInt));
2590 WLog_Print(gfx->base.log, WLOG_ERROR,
"context calloc failed!");
2591 HashTable_Free(gfx->SurfaceTable);
2592 gfx->SurfaceTable =
nullptr;
2593 return CHANNEL_RC_NO_MEMORY;
2596 gfx->zgfx = zgfx_context_new(FALSE);
2599 WLog_Print(gfx->base.log, WLOG_ERROR,
"zgfx_context_new failed!");
2600 HashTable_Free(gfx->SurfaceTable);
2601 gfx->SurfaceTable =
nullptr;
2603 return CHANNEL_RC_NO_MEMORY;
2606 context->common.handle = (
void*)gfx;
2607 context->common.GetSurfaceIds = rdpgfx_get_surface_ids;
2608 context->common.SetSurfaceData = rdpgfx_set_surface_data;
2609 context->common.GetSurfaceData = rdpgfx_get_surface_data;
2610 context->common.SetCacheSlotData = rdpgfx_set_cache_slot_data;
2611 context->common.GetCacheSlotData = rdpgfx_get_cache_slot_data;
2612 context->common.CapsAdvertise = rdpgfx_send_caps_advertise_pdu;
2613 context->common.FrameAcknowledge = rdpgfx_send_frame_acknowledge_pdu;
2614 context->common.CacheImportOffer = rdpgfx_send_cache_import_offer_pdu;
2615 context->common.QoeFrameAcknowledge = rdpgfx_send_qoe_frame_acknowledge_pdu;
2617 gfx->base.iface.pInterface = (
void*)context;
2618 gfx->context = &context->common;
2619 return CHANNEL_RC_OK;
2622void rdpgfx_client_context_free(RdpgfxClientContext* context)
2629 free_surfaces(context, gfx->SurfaceTable);
2630 evict_cache_slots(context, gfx->MaxCacheSlots, gfx->CacheSlots);
2634 zgfx_context_free(gfx->zgfx);
2635 gfx->zgfx =
nullptr;
2638 HashTable_Free(gfx->SurfaceTable);
2642static const IWTSVirtualChannelCallback rdpgfx_callbacks = { rdpgfx_on_data_received,
2643 rdpgfx_on_open, rdpgfx_on_close,
2651FREERDP_ENTRY_POINT(UINT VCAPITYPE rdpgfx_DVCPluginEntry(IDRDYNVC_ENTRY_POINTS* pEntryPoints))
2653 return freerdp_generic_DVCPluginEntry(pEntryPoints, GFXTAG, RDPGFX_DVC_CHANNEL_NAME,
2655 &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.