24 #include <freerdp/config.h>
26 #include <winpr/assert.h>
27 #include <winpr/cast.h>
29 #include <winpr/crt.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 TAG CHANNELS_TAG("rdpgfx.client")
49 static BOOL delete_surface(
const void* key,
void* value,
void* arg)
51 const UINT16
id = (UINT16)(uintptr_t)(key);
52 RdpgfxClientContext* context = arg;
56 pdu.surfaceId =
id - 1;
60 UINT error = CHANNEL_RC_OK;
61 IFCALLRET(context->DeleteSurface, error, context, &pdu);
65 WLog_ERR(TAG,
"context->DeleteSurface failed with error %" PRIu32
"", error);
71 static void free_surfaces(RdpgfxClientContext* context, wHashTable* SurfaceTable)
73 HashTable_Foreach(SurfaceTable, delete_surface, context);
76 static void evict_cache_slots(RdpgfxClientContext* context, UINT16 MaxCacheSlots,
void** CacheSlots)
78 WINPR_ASSERT(CacheSlots);
79 for (UINT16 index = 0; index < MaxCacheSlots; index++)
81 if (CacheSlots[index])
84 pdu.cacheSlot = index + 1;
86 if (context && context->EvictCacheEntry)
88 context->EvictCacheEntry(context, &pdu);
91 CacheSlots[index] = NULL;
101 static UINT rdpgfx_send_caps_advertise_pdu(RdpgfxClientContext* context,
104 UINT error = CHANNEL_RC_OK;
111 WINPR_ASSERT(context);
115 if (!gfx || !gfx->base.listener_callback)
116 return ERROR_BAD_ARGUMENTS;
118 callback = gfx->base.listener_callback->channel_callback;
121 header.cmdId = RDPGFX_CMDID_CAPSADVERTISE;
122 header.pduLength = RDPGFX_HEADER_SIZE + 2;
124 for (UINT16 index = 0; index < pdu->capsSetCount; index++)
127 header.pduLength += RDPGFX_CAPSET_BASE_SIZE + capsSet->length;
130 DEBUG_RDPGFX(gfx->log,
"SendCapsAdvertisePdu %" PRIu16
"", pdu->capsSetCount);
131 s = Stream_New(NULL, header.pduLength);
135 WLog_ERR(TAG,
"Stream_New failed!");
136 return CHANNEL_RC_NO_MEMORY;
139 if ((error = rdpgfx_write_header(s, &header)))
143 Stream_Write_UINT16(s, pdu->capsSetCount);
145 for (UINT16 index = 0; index < pdu->capsSetCount; index++)
149 DEBUG_RDPGFX(gfx->log,
"Sending %s [0x%08" PRIx32
"] flags=0x%08" PRIx32,
150 rdpgfx_caps_version_str(capsSet->version), capsSet->version, capsSet->flags);
152 Stream_Write_UINT32(s, capsSet->version);
153 Stream_Write_UINT32(s, capsSet->length);
154 Stream_Write_UINT32(s, capsSet->flags);
155 Stream_Zero(s, capsSet->length - 4);
158 Stream_SealLength(s);
159 error = callback->channel->Write(callback->channel, (UINT32)Stream_Length(s), Stream_Buffer(s),
162 Stream_Free(s, TRUE);
166 static BOOL rdpgfx_is_capability_filtered(
RDPGFX_PLUGIN* gfx, UINT32 caps)
169 const UINT32 filter =
171 const UINT32 capList[] = { RDPGFX_CAPVERSION_8, RDPGFX_CAPVERSION_81,
172 RDPGFX_CAPVERSION_10, RDPGFX_CAPVERSION_101,
173 RDPGFX_CAPVERSION_102, RDPGFX_CAPVERSION_103,
174 RDPGFX_CAPVERSION_104, RDPGFX_CAPVERSION_105,
175 RDPGFX_CAPVERSION_106, RDPGFX_CAPVERSION_106_ERR,
176 RDPGFX_CAPVERSION_107 };
178 for (
size_t x = 0; x < ARRAYSIZE(capList); x++)
180 if (caps == capList[x])
181 return (filter & (1 << x)) != 0;
195 RdpgfxClientContext* context = NULL;
201 return ERROR_BAD_ARGUMENTS;
206 return ERROR_BAD_CONFIGURATION;
208 context = gfx->context;
211 return ERROR_BAD_CONFIGURATION;
213 pdu.capsSetCount = 0;
216 if (!rdpgfx_is_capability_filtered(gfx, RDPGFX_CAPVERSION_8))
218 capsSet = &capsSets[pdu.capsSetCount++];
219 capsSet->version = RDPGFX_CAPVERSION_8;
224 capsSet->flags |= RDPGFX_CAPS_FLAG_THINCLIENT;
231 capsSet->flags |= RDPGFX_CAPS_FLAG_SMALL_CACHE;
234 if (!rdpgfx_is_capability_filtered(gfx, RDPGFX_CAPVERSION_81))
236 capsSet = &capsSets[pdu.capsSetCount++];
237 capsSet->version = RDPGFX_CAPVERSION_81;
242 capsSet->flags |= RDPGFX_CAPS_FLAG_THINCLIENT;
245 capsSet->flags |= RDPGFX_CAPS_FLAG_SMALL_CACHE;
250 capsSet->flags |= RDPGFX_CAPS_FLAG_AVC420_ENABLED;
258 UINT32 caps10Flags = 0;
261 caps10Flags |= RDPGFX_CAPS_FLAG_SMALL_CACHE;
266 caps10Flags |= RDPGFX_CAPS_FLAG_AVC_DISABLED;
269 caps10Flags |= RDPGFX_CAPS_FLAG_AVC_DISABLED;
272 if (!rdpgfx_is_capability_filtered(gfx, RDPGFX_CAPVERSION_10))
274 capsSet = &capsSets[pdu.capsSetCount++];
275 capsSet->version = RDPGFX_CAPVERSION_10;
277 capsSet->flags = caps10Flags;
280 if (!rdpgfx_is_capability_filtered(gfx, RDPGFX_CAPVERSION_101))
282 capsSet = &capsSets[pdu.capsSetCount++];
283 capsSet->version = RDPGFX_CAPVERSION_101;
284 capsSet->length = 0x10;
288 if (!rdpgfx_is_capability_filtered(gfx, RDPGFX_CAPVERSION_102))
290 capsSet = &capsSets[pdu.capsSetCount++];
291 capsSet->version = RDPGFX_CAPVERSION_102;
292 capsSet->length = 0x4;
293 capsSet->flags = caps10Flags;
298 if ((caps10Flags & RDPGFX_CAPS_FLAG_AVC_DISABLED) == 0)
299 caps10Flags |= RDPGFX_CAPS_FLAG_AVC_THINCLIENT;
302 if (!rdpgfx_is_capability_filtered(gfx, RDPGFX_CAPVERSION_103))
304 capsSet = &capsSets[pdu.capsSetCount++];
305 capsSet->version = RDPGFX_CAPVERSION_103;
306 capsSet->length = 0x4;
307 capsSet->flags = caps10Flags & ~RDPGFX_CAPS_FLAG_SMALL_CACHE;
310 if (!rdpgfx_is_capability_filtered(gfx, RDPGFX_CAPVERSION_104))
312 capsSet = &capsSets[pdu.capsSetCount++];
313 capsSet->version = RDPGFX_CAPVERSION_104;
314 capsSet->length = 0x4;
315 capsSet->flags = caps10Flags;
321 #if defined(WITH_CAIRO) || defined(WITH_SWSCALE)
322 if (!rdpgfx_is_capability_filtered(gfx, RDPGFX_CAPVERSION_105))
324 capsSet = &capsSets[pdu.capsSetCount++];
325 capsSet->version = RDPGFX_CAPVERSION_105;
326 capsSet->length = 0x4;
327 capsSet->flags = caps10Flags;
330 if (!rdpgfx_is_capability_filtered(gfx, RDPGFX_CAPVERSION_106))
332 capsSet = &capsSets[pdu.capsSetCount++];
333 capsSet->version = RDPGFX_CAPVERSION_106;
334 capsSet->length = 0x4;
335 capsSet->flags = caps10Flags;
338 if (!rdpgfx_is_capability_filtered(gfx, RDPGFX_CAPVERSION_106_ERR))
340 capsSet = &capsSets[pdu.capsSetCount++];
341 capsSet->version = RDPGFX_CAPVERSION_106_ERR;
342 capsSet->length = 0x4;
343 capsSet->flags = caps10Flags;
347 if (!rdpgfx_is_capability_filtered(gfx, RDPGFX_CAPVERSION_107))
349 capsSet = &capsSets[pdu.capsSetCount++];
350 capsSet->version = RDPGFX_CAPVERSION_107;
351 capsSet->length = 0x4;
352 capsSet->flags = caps10Flags;
353 #if !defined(WITH_CAIRO) && !defined(WITH_SWSCALE)
354 capsSet->flags |= RDPGFX_CAPS_FLAG_SCALEDMAP_DISABLE;
359 return IFCALLRESULT(ERROR_BAD_CONFIGURATION, context->CapsAdvertise, context, &pdu);
371 WINPR_ASSERT(callback);
375 RdpgfxClientContext* context = gfx->context;
377 pdu.capsSet = &capsSet;
379 if (!Stream_CheckAndLogRequiredLength(TAG, s, 12))
380 return ERROR_INVALID_DATA;
382 Stream_Read_UINT32(s, capsSet.version);
383 Stream_Read_UINT32(s, capsSet.length);
384 Stream_Read_UINT32(s, capsSet.flags);
385 gfx->TotalDecodedFrames = 0;
386 gfx->ConnectionCaps = capsSet;
387 DEBUG_RDPGFX(gfx->log,
388 "RecvCapsConfirmPdu: version: %s [0x%08" PRIX32
"] flags: 0x%08" PRIX32
"",
389 rdpgfx_caps_version_str(capsSet.version), capsSet.version, capsSet.flags);
392 return ERROR_BAD_CONFIGURATION;
394 return IFCALLRESULT(CHANNEL_RC_OK, context->CapsConfirm, context, &pdu);
402 static UINT rdpgfx_send_frame_acknowledge_pdu(RdpgfxClientContext* context,
411 if (!context || !pdu)
412 return ERROR_BAD_ARGUMENTS;
416 if (!gfx || !gfx->base.listener_callback)
417 return ERROR_BAD_CONFIGURATION;
419 callback = gfx->base.listener_callback->channel_callback;
422 return ERROR_BAD_CONFIGURATION;
425 header.cmdId = RDPGFX_CMDID_FRAMEACKNOWLEDGE;
426 header.pduLength = RDPGFX_HEADER_SIZE + 12;
427 DEBUG_RDPGFX(gfx->log,
"SendFrameAcknowledgePdu: %" PRIu32
"", pdu->frameId);
428 s = Stream_New(NULL, header.pduLength);
432 WLog_ERR(TAG,
"Stream_New failed!");
433 return CHANNEL_RC_NO_MEMORY;
436 if ((error = rdpgfx_write_header(s, &header)))
440 Stream_Write_UINT32(s, pdu->queueDepth);
441 Stream_Write_UINT32(s, pdu->frameId);
442 Stream_Write_UINT32(s, pdu->totalFramesDecoded);
443 error = callback->channel->Write(callback->channel, (UINT32)Stream_Length(s), Stream_Buffer(s),
446 if (error == CHANNEL_RC_OK)
447 gfx->UnacknowledgedFrames--;
450 Stream_Free(s, TRUE);
454 static UINT rdpgfx_send_qoe_frame_acknowledge_pdu(RdpgfxClientContext* context,
464 header.cmdId = RDPGFX_CMDID_QOEFRAMEACKNOWLEDGE;
465 header.pduLength = RDPGFX_HEADER_SIZE + 12;
467 if (!context || !pdu)
468 return ERROR_BAD_ARGUMENTS;
472 if (!gfx || !gfx->base.listener_callback)
473 return ERROR_BAD_CONFIGURATION;
475 callback = gfx->base.listener_callback->channel_callback;
478 return ERROR_BAD_CONFIGURATION;
480 DEBUG_RDPGFX(gfx->log,
"SendQoeFrameAcknowledgePdu: %" PRIu32
"", pdu->frameId);
481 s = Stream_New(NULL, header.pduLength);
485 WLog_ERR(TAG,
"Stream_New failed!");
486 return CHANNEL_RC_NO_MEMORY;
489 if ((error = rdpgfx_write_header(s, &header)))
493 Stream_Write_UINT32(s, pdu->frameId);
494 Stream_Write_UINT32(s, pdu->timestamp);
495 Stream_Write_UINT16(s, pdu->timeDiffSE);
496 Stream_Write_UINT16(s, pdu->timeDiffEDR);
497 error = callback->channel->Write(callback->channel, (UINT32)Stream_Length(s), Stream_Buffer(s),
500 Stream_Free(s, TRUE);
513 WINPR_ASSERT(callback);
519 RdpgfxClientContext* context = gfx->context;
520 UINT error = CHANNEL_RC_OK;
521 GraphicsResetEventArgs graphicsReset = { 0 };
523 if (!Stream_CheckAndLogRequiredLength(TAG, s, 12))
524 return ERROR_INVALID_DATA;
526 Stream_Read_UINT32(s, pdu.width);
527 Stream_Read_UINT32(s, pdu.height);
528 Stream_Read_UINT32(s, pdu.monitorCount);
530 if (!Stream_CheckAndLogRequiredLengthOfSize(TAG, s, pdu.monitorCount, 20ull))
531 return ERROR_INVALID_DATA;
535 if (!pdu.monitorDefArray)
537 WLog_Print(gfx->log, WLOG_ERROR,
"calloc failed!");
538 return CHANNEL_RC_NO_MEMORY;
541 for (UINT32 index = 0; index < pdu.monitorCount; index++)
543 monitor = &(pdu.monitorDefArray[index]);
544 Stream_Read_INT32(s, monitor->left);
545 Stream_Read_INT32(s, monitor->top);
546 Stream_Read_INT32(s, monitor->right);
547 Stream_Read_INT32(s, monitor->bottom);
548 Stream_Read_UINT32(s, monitor->flags);
551 const size_t size = (RDPGFX_HEADER_SIZE + 12ULL + (pdu.monitorCount * 20ULL));
554 free(pdu.monitorDefArray);
555 return CHANNEL_RC_NULL_DATA;
557 const size_t pad = 340ULL - size;
559 if (!Stream_CheckAndLogRequiredLength(TAG, s, (
size_t)pad))
561 free(pdu.monitorDefArray);
562 return CHANNEL_RC_NO_MEMORY;
566 DEBUG_RDPGFX(gfx->log,
567 "RecvResetGraphicsPdu: width: %" PRIu32
" height: %" PRIu32
" count: %" PRIu32
"",
568 pdu.width, pdu.height, pdu.monitorCount);
570 #if defined(WITH_DEBUG_RDPGFX)
571 for (UINT32 index = 0; index < pdu.monitorCount; index++)
573 monitor = &(pdu.monitorDefArray[index]);
574 DEBUG_RDPGFX(gfx->log,
575 "RecvResetGraphicsPdu: monitor left:%" PRIi32
" top:%" PRIi32
" right:%" PRIi32
576 " bottom:%" PRIi32
" flags:0x%" PRIx32
"",
577 monitor->left, monitor->top, monitor->right, monitor->bottom, monitor->flags);
583 IFCALLRET(context->ResetGraphics, error, context, &pdu);
586 WLog_Print(gfx->log, WLOG_ERROR,
"context->ResetGraphics failed with error %" PRIu32
"",
591 EventArgsInit(&graphicsReset,
"libfreerdp");
592 graphicsReset.width = pdu.width;
593 graphicsReset.height = pdu.height;
594 PubSub_OnGraphicsReset(gfx->rdpcontext->pubSub, gfx->rdpcontext, &graphicsReset);
595 free(pdu.monitorDefArray);
607 WINPR_ASSERT(callback);
610 RdpgfxClientContext* context = gfx->context;
611 UINT error = CHANNEL_RC_OK;
613 if (!Stream_CheckAndLogRequiredLength(TAG, s, 2))
614 return ERROR_INVALID_DATA;
616 Stream_Read_UINT16(s, pdu.cacheSlot);
617 WLog_Print(gfx->log, WLOG_DEBUG,
"RecvEvictCacheEntryPdu: cacheSlot: %" PRIu16
"",
622 IFCALLRET(context->EvictCacheEntry, error, context, &pdu);
625 WLog_Print(gfx->log, WLOG_ERROR,
626 "context->EvictCacheEntry failed with error %" PRIu32
"", error);
640 UINT error = CHANNEL_RC_OK;
642 rdpPersistentCache* persistent = NULL;
644 WINPR_ASSERT(gfx->rdpcontext);
645 rdpSettings* settings = gfx->rdpcontext->settings;
648 WINPR_ASSERT(settings);
650 offer->cacheEntriesCount = 0;
653 return CHANNEL_RC_OK;
655 const char* BitmapCachePersistFile =
657 if (!BitmapCachePersistFile)
658 return CHANNEL_RC_OK;
660 persistent = persistent_cache_new();
663 return CHANNEL_RC_NO_MEMORY;
665 if (persistent_cache_open(persistent, BitmapCachePersistFile, FALSE, 3) < 1)
667 error = CHANNEL_RC_INITIALIZATION_ERROR;
671 if (persistent_cache_get_version(persistent) != 3)
673 error = ERROR_INVALID_DATA;
677 count = persistent_cache_get_count(persistent);
681 error = ERROR_INVALID_DATA;
685 if (count >= RDPGFX_CACHE_ENTRY_MAX_COUNT)
686 count = RDPGFX_CACHE_ENTRY_MAX_COUNT - 1;
688 if (count > gfx->MaxCacheSlots)
689 count = gfx->MaxCacheSlots;
691 offer->cacheEntriesCount = (UINT16)count;
693 for (
int idx = 0; idx < count; idx++)
695 if (persistent_cache_read_entry(persistent, &entry) < 1)
697 error = ERROR_INVALID_DATA;
701 offer->cacheEntries[idx].cacheKey = entry.key64;
702 offer->cacheEntries[idx].bitmapLength = entry.size;
705 persistent_cache_free(persistent);
709 persistent_cache_free(persistent);
720 UINT error = CHANNEL_RC_OK;
722 rdpPersistentCache* persistent = NULL;
724 WINPR_ASSERT(gfx->rdpcontext);
725 rdpSettings* settings = gfx->rdpcontext->settings;
726 RdpgfxClientContext* context = gfx->context;
728 WINPR_ASSERT(context);
729 WINPR_ASSERT(settings);
732 return CHANNEL_RC_OK;
734 const char* BitmapCachePersistFile =
736 if (!BitmapCachePersistFile)
737 return CHANNEL_RC_OK;
739 if (!context->ExportCacheEntry)
740 return CHANNEL_RC_INITIALIZATION_ERROR;
742 persistent = persistent_cache_new();
745 return CHANNEL_RC_NO_MEMORY;
747 if (persistent_cache_open(persistent, BitmapCachePersistFile, TRUE, 3) < 1)
749 error = CHANNEL_RC_INITIALIZATION_ERROR;
753 for (UINT16 idx = 0; idx < gfx->MaxCacheSlots; idx++)
755 if (gfx->CacheSlots[idx])
757 UINT16 cacheSlot = idx;
759 if (context->ExportCacheEntry(context, cacheSlot, &cacheEntry) != CHANNEL_RC_OK)
762 persistent_cache_write_entry(persistent, &cacheEntry);
766 persistent_cache_free(persistent);
770 persistent_cache_free(persistent);
779 static UINT rdpgfx_send_cache_import_offer_pdu(RdpgfxClientContext* context,
782 UINT error = CHANNEL_RC_OK;
787 if (!context || !pdu)
788 return ERROR_BAD_ARGUMENTS;
792 if (!gfx || !gfx->base.listener_callback)
793 return ERROR_BAD_CONFIGURATION;
795 callback = gfx->base.listener_callback->channel_callback;
798 return ERROR_BAD_CONFIGURATION;
801 header.cmdId = RDPGFX_CMDID_CACHEIMPORTOFFER;
802 header.pduLength = RDPGFX_HEADER_SIZE + 2ul + pdu->cacheEntriesCount * 12ul;
803 DEBUG_RDPGFX(gfx->log,
"SendCacheImportOfferPdu: cacheEntriesCount: %" PRIu16
"",
804 pdu->cacheEntriesCount);
805 s = Stream_New(NULL, header.pduLength);
809 WLog_ERR(TAG,
"Stream_New failed!");
810 return CHANNEL_RC_NO_MEMORY;
813 if ((error = rdpgfx_write_header(s, &header)))
816 if (pdu->cacheEntriesCount <= 0)
818 WLog_ERR(TAG,
"Invalid cacheEntriesCount: %" PRIu16
"", pdu->cacheEntriesCount);
819 error = ERROR_INVALID_DATA;
824 Stream_Write_UINT16(s, pdu->cacheEntriesCount);
826 for (UINT16 index = 0; index < pdu->cacheEntriesCount; index++)
829 Stream_Write_UINT64(s, cacheEntry->cacheKey);
830 Stream_Write_UINT32(s, cacheEntry->bitmapLength);
833 error = callback->channel->Write(callback->channel, (UINT32)Stream_Length(s), Stream_Buffer(s),
837 Stream_Free(s, TRUE);
849 UINT error = CHANNEL_RC_OK;
852 rdpPersistentCache* persistent = NULL;
855 WINPR_ASSERT(gfx->rdpcontext);
857 RdpgfxClientContext* context = gfx->context;
858 rdpSettings* settings = gfx->rdpcontext->settings;
861 return CHANNEL_RC_OK;
863 const char* BitmapCachePersistFile =
865 if (!BitmapCachePersistFile)
866 return CHANNEL_RC_OK;
868 persistent = persistent_cache_new();
871 return CHANNEL_RC_NO_MEMORY;
873 if (persistent_cache_open(persistent, BitmapCachePersistFile, FALSE, 3) < 1)
875 error = CHANNEL_RC_INITIALIZATION_ERROR;
879 if (persistent_cache_get_version(persistent) != 3)
881 error = ERROR_INVALID_DATA;
885 count = persistent_cache_get_count(persistent);
888 error = ERROR_INVALID_DATA;
892 if (count >= RDPGFX_CACHE_ENTRY_MAX_COUNT)
893 count = RDPGFX_CACHE_ENTRY_MAX_COUNT - 1;
895 if (count > gfx->MaxCacheSlots)
896 count = gfx->MaxCacheSlots;
901 error = CHANNEL_RC_NO_MEMORY;
905 WINPR_ASSERT(count <= UINT16_MAX);
906 offer->cacheEntriesCount = (UINT16)count;
908 WLog_DBG(TAG,
"Sending Cache Import Offer: %d", count);
910 for (
int idx = 0; idx < count; idx++)
912 if (persistent_cache_read_entry(persistent, &entry) < 1)
914 error = ERROR_INVALID_DATA;
918 offer->cacheEntries[idx].cacheKey = entry.key64;
919 offer->cacheEntries[idx].bitmapLength = entry.size;
922 if (offer->cacheEntriesCount > 0)
924 error = rdpgfx_send_cache_import_offer_pdu(context, offer);
925 if (error != CHANNEL_RC_OK)
927 WLog_Print(gfx->log, WLOG_ERROR,
"Failed to send cache import offer PDU");
933 persistent_cache_free(persistent);
943 static UINT rdpgfx_load_cache_import_reply(
RDPGFX_PLUGIN* gfx,
947 UINT error = CHANNEL_RC_OK;
948 rdpPersistentCache* persistent = NULL;
950 WINPR_ASSERT(gfx->rdpcontext);
951 rdpSettings* settings = gfx->rdpcontext->settings;
952 RdpgfxClientContext* context = gfx->context;
954 WINPR_ASSERT(settings);
957 return CHANNEL_RC_OK;
959 const char* BitmapCachePersistFile =
961 if (!BitmapCachePersistFile)
962 return CHANNEL_RC_OK;
964 persistent = persistent_cache_new();
967 return CHANNEL_RC_NO_MEMORY;
969 if (persistent_cache_open(persistent, BitmapCachePersistFile, FALSE, 3) < 1)
971 error = CHANNEL_RC_INITIALIZATION_ERROR;
975 if (persistent_cache_get_version(persistent) != 3)
977 error = ERROR_INVALID_DATA;
981 count = persistent_cache_get_count(persistent);
983 count = (count < reply->importedEntriesCount) ? count : reply->importedEntriesCount;
985 WLog_DBG(TAG,
"Receiving Cache Import Reply: %d", count);
987 for (
int idx = 0; idx < count; idx++)
990 if (persistent_cache_read_entry(persistent, &entry) < 1)
992 error = ERROR_INVALID_DATA;
996 const UINT16 cacheSlot = reply->cacheSlots[idx];
997 if (context && context->ImportCacheEntry)
998 context->ImportCacheEntry(context, cacheSlot, &entry);
1001 persistent_cache_free(persistent);
1005 persistent_cache_free(persistent);
1017 WINPR_ASSERT(callback);
1020 RdpgfxClientContext* context = gfx->context;
1021 UINT error = CHANNEL_RC_OK;
1023 if (!Stream_CheckAndLogRequiredLength(TAG, s, 2))
1024 return ERROR_INVALID_DATA;
1026 Stream_Read_UINT16(s, pdu.importedEntriesCount);
1028 if (!Stream_CheckAndLogRequiredLengthOfSize(TAG, s, pdu.importedEntriesCount, 2ull))
1029 return ERROR_INVALID_DATA;
1031 if (pdu.importedEntriesCount > RDPGFX_CACHE_ENTRY_MAX_COUNT)
1032 return ERROR_INVALID_DATA;
1034 for (UINT16 idx = 0; idx < pdu.importedEntriesCount; idx++)
1036 Stream_Read_UINT16(s, pdu.cacheSlots[idx]);
1039 DEBUG_RDPGFX(gfx->log,
"RecvCacheImportReplyPdu: importedEntriesCount: %" PRIu16
"",
1040 pdu.importedEntriesCount);
1042 error = rdpgfx_load_cache_import_reply(gfx, &pdu);
1046 WLog_Print(gfx->log, WLOG_ERROR,
1047 "rdpgfx_load_cache_import_reply failed with error %" PRIu32
"", error);
1053 IFCALLRET(context->CacheImportReply, error, context, &pdu);
1056 WLog_Print(gfx->log, WLOG_ERROR,
1057 "context->CacheImportReply failed with error %" PRIu32
"", error);
1071 WINPR_ASSERT(callback);
1074 RdpgfxClientContext* context = gfx->context;
1075 UINT error = CHANNEL_RC_OK;
1077 if (!Stream_CheckAndLogRequiredLength(TAG, s, 7))
1078 return ERROR_INVALID_DATA;
1080 Stream_Read_UINT16(s, pdu.surfaceId);
1081 Stream_Read_UINT16(s, pdu.width);
1082 Stream_Read_UINT16(s, pdu.height);
1083 Stream_Read_UINT8(s, pdu.pixelFormat);
1084 DEBUG_RDPGFX(gfx->log,
1085 "RecvCreateSurfacePdu: surfaceId: %" PRIu16
" width: %" PRIu16
" height: %" PRIu16
1086 " pixelFormat: 0x%02" PRIX8
"",
1087 pdu.surfaceId, pdu.width, pdu.height, pdu.pixelFormat);
1096 IFCALL(context->DeleteSurface, context, &deletePdu);
1098 IFCALLRET(context->CreateSurface, error, context, &pdu);
1101 WLog_Print(gfx->log, WLOG_ERROR,
"context->CreateSurface failed with error %" PRIu32
"",
1116 WINPR_ASSERT(callback);
1119 RdpgfxClientContext* context = gfx->context;
1120 UINT error = CHANNEL_RC_OK;
1122 if (!Stream_CheckAndLogRequiredLength(TAG, s, 2))
1123 return ERROR_INVALID_DATA;
1125 Stream_Read_UINT16(s, pdu.surfaceId);
1126 DEBUG_RDPGFX(gfx->log,
"RecvDeleteSurfacePdu: surfaceId: %" PRIu16
"", pdu.surfaceId);
1130 IFCALLRET(context->DeleteSurface, error, context, &pdu);
1133 WLog_Print(gfx->log, WLOG_ERROR,
"context->DeleteSurface failed with error %" PRIu32
"",
1148 WINPR_ASSERT(callback);
1151 RdpgfxClientContext* context = gfx->context;
1152 UINT error = CHANNEL_RC_OK;
1154 if (!Stream_CheckAndLogRequiredLength(TAG, s, RDPGFX_START_FRAME_PDU_SIZE))
1155 return ERROR_INVALID_DATA;
1157 Stream_Read_UINT32(s, pdu.timestamp);
1158 Stream_Read_UINT32(s, pdu.frameId);
1159 DEBUG_RDPGFX(gfx->log,
"RecvStartFramePdu: frameId: %" PRIu32
" timestamp: 0x%08" PRIX32
"",
1160 pdu.frameId, pdu.timestamp);
1161 gfx->StartDecodingTime = GetTickCount64();
1165 IFCALLRET(context->StartFrame, error, context, &pdu);
1168 WLog_Print(gfx->log, WLOG_ERROR,
"context->StartFrame failed with error %" PRIu32
"",
1172 gfx->UnacknowledgedFrames++;
1185 WINPR_ASSERT(callback);
1188 RdpgfxClientContext* context = gfx->context;
1189 UINT error = CHANNEL_RC_OK;
1191 if (!Stream_CheckAndLogRequiredLength(TAG, s, RDPGFX_END_FRAME_PDU_SIZE))
1192 return ERROR_INVALID_DATA;
1194 Stream_Read_UINT32(s, pdu.frameId);
1195 DEBUG_RDPGFX(gfx->log,
"RecvEndFramePdu: frameId: %" PRIu32
"", pdu.frameId);
1197 const UINT64 start = GetTickCount64();
1200 IFCALLRET(context->EndFrame, error, context, &pdu);
1204 WLog_Print(gfx->log, WLOG_ERROR,
"context->EndFrame failed with error %" PRIu32
"",
1209 const UINT64 end = GetTickCount64();
1210 const UINT64 EndFrameTime = end - start;
1211 gfx->TotalDecodedFrames++;
1213 if (!gfx->sendFrameAcks)
1216 ack.frameId = pdu.frameId;
1217 ack.totalFramesDecoded = gfx->TotalDecodedFrames;
1219 if (gfx->suspendFrameAcks)
1221 ack.queueDepth = SUSPEND_FRAME_ACKNOWLEDGEMENT;
1223 if (gfx->TotalDecodedFrames == 1)
1224 if ((error = rdpgfx_send_frame_acknowledge_pdu(context, &ack)))
1225 WLog_Print(gfx->log, WLOG_ERROR,
1226 "rdpgfx_send_frame_acknowledge_pdu failed with error %" PRIu32
"",
1231 ack.queueDepth = QUEUE_DEPTH_UNAVAILABLE;
1233 if ((error = rdpgfx_send_frame_acknowledge_pdu(context, &ack)))
1234 WLog_Print(gfx->log, WLOG_ERROR,
1235 "rdpgfx_send_frame_acknowledge_pdu failed with error %" PRIu32
"", error);
1238 switch (gfx->ConnectionCaps.version)
1240 case RDPGFX_CAPVERSION_10:
1241 case RDPGFX_CAPVERSION_102:
1242 case RDPGFX_CAPVERSION_103:
1243 case RDPGFX_CAPVERSION_104:
1244 case RDPGFX_CAPVERSION_105:
1245 case RDPGFX_CAPVERSION_106:
1246 case RDPGFX_CAPVERSION_106_ERR:
1247 case RDPGFX_CAPVERSION_107:
1251 UINT64 diff = (GetTickCount64() - gfx->StartDecodingTime);
1256 qoe.frameId = pdu.frameId;
1257 qoe.timestamp = gfx->StartDecodingTime % UINT32_MAX;
1258 qoe.timeDiffSE = WINPR_ASSERTING_INT_CAST(UINT16, diff);
1259 qoe.timeDiffEDR = WINPR_ASSERTING_INT_CAST(UINT16, EndFrameTime);
1261 if ((error = rdpgfx_send_qoe_frame_acknowledge_pdu(context, &qoe)))
1262 WLog_Print(gfx->log, WLOG_ERROR,
1263 "rdpgfx_send_qoe_frame_acknowledge_pdu failed with error %" PRIu32
1286 WINPR_ASSERT(callback);
1291 if (!Stream_CheckAndLogRequiredLength(TAG, s, RDPGFX_WIRE_TO_SURFACE_PDU_1_SIZE))
1292 return ERROR_INVALID_DATA;
1294 Stream_Read_UINT16(s, pdu.surfaceId);
1295 Stream_Read_UINT16(s, pdu.codecId);
1296 Stream_Read_UINT8(s, pdu.pixelFormat);
1298 if ((error = rdpgfx_read_rect16(s, &(pdu.destRect))))
1300 WLog_Print(gfx->log, WLOG_ERROR,
"rdpgfx_read_rect16 failed with error %" PRIu32
"", error);
1304 Stream_Read_UINT32(s, pdu.bitmapDataLength);
1306 if (!Stream_CheckAndLogRequiredLength(TAG, s, pdu.bitmapDataLength))
1307 return ERROR_INVALID_DATA;
1309 pdu.bitmapData = Stream_Pointer(s);
1310 Stream_Seek(s, pdu.bitmapDataLength);
1312 DEBUG_RDPGFX(gfx->log,
1313 "RecvWireToSurface1Pdu: surfaceId: %" PRIu16
" codecId: %s (0x%04" PRIX16
1314 ") pixelFormat: 0x%02" PRIX8
" "
1315 "destRect: left: %" PRIu16
" top: %" PRIu16
" right: %" PRIu16
" bottom: %" PRIu16
1316 " bitmapDataLength: %" PRIu32
"",
1317 pdu.surfaceId, rdpgfx_get_codec_id_string(pdu.codecId), pdu.codecId,
1318 pdu.pixelFormat, pdu.destRect.left, pdu.destRect.top, pdu.destRect.right,
1319 pdu.destRect.bottom, pdu.bitmapDataLength);
1320 cmd.surfaceId = pdu.surfaceId;
1321 cmd.codecId = pdu.codecId;
1324 switch (pdu.pixelFormat)
1326 case GFX_PIXEL_FORMAT_XRGB_8888:
1327 cmd.format = PIXEL_FORMAT_BGRX32;
1330 case GFX_PIXEL_FORMAT_ARGB_8888:
1331 cmd.format = PIXEL_FORMAT_BGRA32;
1335 return ERROR_INVALID_DATA;
1338 cmd.left = pdu.destRect.left;
1339 cmd.top = pdu.destRect.top;
1340 cmd.right = pdu.destRect.right;
1341 cmd.bottom = pdu.destRect.bottom;
1342 cmd.width = cmd.right - cmd.left;
1343 cmd.height = cmd.bottom - cmd.top;
1344 cmd.length = pdu.bitmapDataLength;
1345 cmd.data = pdu.bitmapData;
1348 if (cmd.right < cmd.left)
1350 WLog_Print(gfx->log, WLOG_ERROR,
"RecvWireToSurface1Pdu right=%" PRIu32
" < left=%" PRIu32,
1351 cmd.right, cmd.left);
1352 return ERROR_INVALID_DATA;
1354 if (cmd.bottom < cmd.top)
1356 WLog_Print(gfx->log, WLOG_ERROR,
"RecvWireToSurface1Pdu bottom=%" PRIu32
" < top=%" PRIu32,
1357 cmd.bottom, cmd.top);
1358 return ERROR_INVALID_DATA;
1361 if ((error = rdpgfx_decode(gfx, &cmd)))
1362 WLog_Print(gfx->log, WLOG_ERROR,
"rdpgfx_decode failed with error %" PRIu32
"!", error);
1376 WINPR_ASSERT(callback);
1379 RdpgfxClientContext* context = gfx->context;
1380 UINT error = CHANNEL_RC_OK;
1382 if (!Stream_CheckAndLogRequiredLength(TAG, s, RDPGFX_WIRE_TO_SURFACE_PDU_2_SIZE))
1383 return ERROR_INVALID_DATA;
1385 Stream_Read_UINT16(s, pdu.surfaceId);
1386 Stream_Read_UINT16(s, pdu.codecId);
1387 Stream_Read_UINT32(s, pdu.codecContextId);
1388 Stream_Read_UINT8(s, pdu.pixelFormat);
1389 Stream_Read_UINT32(s, pdu.bitmapDataLength);
1390 pdu.bitmapData = Stream_Pointer(s);
1391 Stream_Seek(s, pdu.bitmapDataLength);
1393 DEBUG_RDPGFX(gfx->log,
1394 "RecvWireToSurface2Pdu: surfaceId: %" PRIu16
" codecId: %s (0x%04" PRIX16
") "
1395 "codecContextId: %" PRIu32
" pixelFormat: 0x%02" PRIX8
1396 " bitmapDataLength: %" PRIu32
"",
1397 pdu.surfaceId, rdpgfx_get_codec_id_string(pdu.codecId), pdu.codecId,
1398 pdu.codecContextId, pdu.pixelFormat, pdu.bitmapDataLength);
1400 cmd.surfaceId = pdu.surfaceId;
1401 cmd.codecId = pdu.codecId;
1402 cmd.contextId = pdu.codecContextId;
1404 switch (pdu.pixelFormat)
1406 case GFX_PIXEL_FORMAT_XRGB_8888:
1407 cmd.format = PIXEL_FORMAT_BGRX32;
1410 case GFX_PIXEL_FORMAT_ARGB_8888:
1411 cmd.format = PIXEL_FORMAT_BGRA32;
1415 return ERROR_INVALID_DATA;
1424 cmd.length = pdu.bitmapDataLength;
1425 cmd.data = pdu.bitmapData;
1430 IFCALLRET(context->SurfaceCommand, error, context, &cmd);
1433 WLog_Print(gfx->log, WLOG_ERROR,
1434 "context->SurfaceCommand failed with error %" PRIu32
"", error);
1448 WINPR_ASSERT(callback);
1451 RdpgfxClientContext* context = gfx->context;
1452 UINT error = CHANNEL_RC_OK;
1454 if (!Stream_CheckAndLogRequiredLength(TAG, s, 6))
1455 return ERROR_INVALID_DATA;
1457 Stream_Read_UINT16(s, pdu.surfaceId);
1458 Stream_Read_UINT32(s, pdu.codecContextId);
1460 DEBUG_RDPGFX(gfx->log,
1461 "RecvDeleteEncodingContextPdu: surfaceId: %" PRIu16
" codecContextId: %" PRIu32
"",
1462 pdu.surfaceId, pdu.codecContextId);
1466 IFCALLRET(context->DeleteEncodingContext, error, context, &pdu);
1469 WLog_Print(gfx->log, WLOG_ERROR,
1470 "context->DeleteEncodingContext failed with error %" PRIu32
"", error);
1485 WINPR_ASSERT(callback);
1488 RdpgfxClientContext* context = gfx->context;
1491 if (!Stream_CheckAndLogRequiredLength(TAG, s, 8))
1492 return ERROR_INVALID_DATA;
1494 Stream_Read_UINT16(s, pdu.surfaceId);
1496 if ((error = rdpgfx_read_color32(s, &(pdu.fillPixel))))
1498 WLog_Print(gfx->log, WLOG_ERROR,
"rdpgfx_read_color32 failed with error %" PRIu32
"!",
1503 Stream_Read_UINT16(s, pdu.fillRectCount);
1505 if (!Stream_CheckAndLogRequiredLengthOfSize(TAG, s, pdu.fillRectCount, 8ull))
1506 return ERROR_INVALID_DATA;
1512 WLog_Print(gfx->log, WLOG_ERROR,
"calloc failed!");
1513 return CHANNEL_RC_NO_MEMORY;
1516 for (UINT16 index = 0; index < pdu.fillRectCount; index++)
1518 fillRect = &(pdu.fillRects[index]);
1520 if ((error = rdpgfx_read_rect16(s, fillRect)))
1522 WLog_Print(gfx->log, WLOG_ERROR,
"rdpgfx_read_rect16 failed with error %" PRIu32
"!",
1524 free(pdu.fillRects);
1528 DEBUG_RDPGFX(gfx->log,
"RecvSolidFillPdu: surfaceId: %" PRIu16
" fillRectCount: %" PRIu16
"",
1529 pdu.surfaceId, pdu.fillRectCount);
1533 IFCALLRET(context->SolidFill, error, context, &pdu);
1536 WLog_Print(gfx->log, WLOG_ERROR,
"context->SolidFill failed with error %" PRIu32
"",
1540 free(pdu.fillRects);
1553 WINPR_ASSERT(callback);
1556 RdpgfxClientContext* context = gfx->context;
1559 if (!Stream_CheckAndLogRequiredLength(TAG, s, 14))
1560 return ERROR_INVALID_DATA;
1562 Stream_Read_UINT16(s, pdu.surfaceIdSrc);
1563 Stream_Read_UINT16(s, pdu.surfaceIdDest);
1565 if ((error = rdpgfx_read_rect16(s, &(pdu.rectSrc))))
1567 WLog_Print(gfx->log, WLOG_ERROR,
"rdpgfx_read_rect16 failed with error %" PRIu32
"!",
1572 Stream_Read_UINT16(s, pdu.destPtsCount);
1574 if (!Stream_CheckAndLogRequiredLengthOfSize(TAG, s, pdu.destPtsCount, 4ull))
1575 return ERROR_INVALID_DATA;
1581 WLog_Print(gfx->log, WLOG_ERROR,
"calloc failed!");
1582 return CHANNEL_RC_NO_MEMORY;
1585 for (UINT16 index = 0; index < pdu.destPtsCount; index++)
1587 destPt = &(pdu.destPts[index]);
1589 if ((error = rdpgfx_read_point16(s, destPt)))
1591 WLog_Print(gfx->log, WLOG_ERROR,
"rdpgfx_read_point16 failed with error %" PRIu32
"!",
1598 DEBUG_RDPGFX(gfx->log,
1599 "RecvSurfaceToSurfacePdu: surfaceIdSrc: %" PRIu16
" surfaceIdDest: %" PRIu16
" "
1600 "left: %" PRIu16
" top: %" PRIu16
" right: %" PRIu16
" bottom: %" PRIu16
1601 " destPtsCount: %" PRIu16
"",
1602 pdu.surfaceIdSrc, pdu.surfaceIdDest, pdu.rectSrc.left, pdu.rectSrc.top,
1603 pdu.rectSrc.right, pdu.rectSrc.bottom, pdu.destPtsCount);
1607 IFCALLRET(context->SurfaceToSurface, error, context, &pdu);
1610 WLog_Print(gfx->log, WLOG_ERROR,
1611 "context->SurfaceToSurface failed with error %" PRIu32
"", error);
1626 WINPR_ASSERT(callback);
1630 RdpgfxClientContext* context = gfx->context;
1633 if (!Stream_CheckAndLogRequiredLength(TAG, s, 20))
1634 return ERROR_INVALID_DATA;
1636 Stream_Read_UINT16(s, pdu.surfaceId);
1637 Stream_Read_UINT64(s, pdu.cacheKey);
1638 Stream_Read_UINT16(s, pdu.cacheSlot);
1640 if ((error = rdpgfx_read_rect16(s, &(pdu.rectSrc))))
1642 WLog_Print(gfx->log, WLOG_ERROR,
"rdpgfx_read_rect16 failed with error %" PRIu32
"!",
1647 DEBUG_RDPGFX(gfx->log,
1648 "RecvSurfaceToCachePdu: surfaceId: %" PRIu16
" cacheKey: 0x%016" PRIX64
1649 " cacheSlot: %" PRIu16
" "
1650 "left: %" PRIu16
" top: %" PRIu16
" right: %" PRIu16
" bottom: %" PRIu16
"",
1651 pdu.surfaceId, pdu.cacheKey, pdu.cacheSlot, pdu.rectSrc.left, pdu.rectSrc.top,
1652 pdu.rectSrc.right, pdu.rectSrc.bottom);
1656 IFCALLRET(context->SurfaceToCache, error, context, &pdu);
1659 WLog_Print(gfx->log, WLOG_ERROR,
1660 "context->SurfaceToCache failed with error %" PRIu32
"", error);
1675 WINPR_ASSERT(callback);
1679 RdpgfxClientContext* context = gfx->context;
1680 UINT error = CHANNEL_RC_OK;
1682 if (!Stream_CheckAndLogRequiredLength(TAG, s, 6))
1683 return ERROR_INVALID_DATA;
1685 Stream_Read_UINT16(s, pdu.cacheSlot);
1686 Stream_Read_UINT16(s, pdu.surfaceId);
1687 Stream_Read_UINT16(s, pdu.destPtsCount);
1689 if (!Stream_CheckAndLogRequiredLengthOfSize(TAG, s, pdu.destPtsCount, 4ull))
1690 return ERROR_INVALID_DATA;
1696 WLog_Print(gfx->log, WLOG_ERROR,
"calloc failed!");
1697 return CHANNEL_RC_NO_MEMORY;
1700 for (UINT16 index = 0; index < pdu.destPtsCount; index++)
1702 destPt = &(pdu.destPts[index]);
1704 if ((error = rdpgfx_read_point16(s, destPt)))
1706 WLog_Print(gfx->log, WLOG_ERROR,
"rdpgfx_read_point16 failed with error %" PRIu32
"",
1713 DEBUG_RDPGFX(gfx->log,
1714 "RdpGfxRecvCacheToSurfacePdu: cacheSlot: %" PRIu16
" surfaceId: %" PRIu16
1715 " destPtsCount: %" PRIu16
"",
1716 pdu.cacheSlot, pdu.surfaceId, pdu.destPtsCount);
1720 IFCALLRET(context->CacheToSurface, error, context, &pdu);
1723 WLog_Print(gfx->log, WLOG_ERROR,
1724 "context->CacheToSurface failed with error %" PRIu32
"", error);
1739 WINPR_ASSERT(callback);
1743 RdpgfxClientContext* context = gfx->context;
1744 UINT error = CHANNEL_RC_OK;
1746 if (!Stream_CheckAndLogRequiredLength(TAG, s, 12))
1747 return ERROR_INVALID_DATA;
1749 Stream_Read_UINT16(s, pdu.surfaceId);
1750 Stream_Read_UINT16(s, pdu.reserved);
1751 Stream_Read_UINT32(s, pdu.outputOriginX);
1752 Stream_Read_UINT32(s, pdu.outputOriginY);
1753 DEBUG_RDPGFX(gfx->log,
1754 "RecvMapSurfaceToOutputPdu: surfaceId: %" PRIu16
" outputOriginX: %" PRIu32
1755 " outputOriginY: %" PRIu32
"",
1756 pdu.surfaceId, pdu.outputOriginX, pdu.outputOriginY);
1760 IFCALLRET(context->MapSurfaceToOutput, error, context, &pdu);
1763 WLog_Print(gfx->log, WLOG_ERROR,
1764 "context->MapSurfaceToOutput failed with error %" PRIu32
"", error);
1774 WINPR_ASSERT(callback);
1778 RdpgfxClientContext* context = gfx->context;
1779 UINT error = CHANNEL_RC_OK;
1781 if (!Stream_CheckAndLogRequiredLength(TAG, s, 20))
1782 return ERROR_INVALID_DATA;
1784 Stream_Read_UINT16(s, pdu.surfaceId);
1785 Stream_Read_UINT16(s, pdu.reserved);
1786 Stream_Read_UINT32(s, pdu.outputOriginX);
1787 Stream_Read_UINT32(s, pdu.outputOriginY);
1788 Stream_Read_UINT32(s, pdu.targetWidth);
1789 Stream_Read_UINT32(s, pdu.targetHeight);
1790 DEBUG_RDPGFX(gfx->log,
1791 "RecvMapSurfaceToScaledOutputPdu: surfaceId: %" PRIu16
" outputOriginX: %" PRIu32
1792 " outputOriginY: %" PRIu32
" targetWidth: %" PRIu32
" targetHeight: %" PRIu32,
1793 pdu.surfaceId, pdu.outputOriginX, pdu.outputOriginY, pdu.targetWidth,
1798 IFCALLRET(context->MapSurfaceToScaledOutput, error, context, &pdu);
1801 WLog_Print(gfx->log, WLOG_ERROR,
1802 "context->MapSurfaceToScaledOutput failed with error %" PRIu32
"", error);
1816 WINPR_ASSERT(callback);
1820 RdpgfxClientContext* context = gfx->context;
1821 UINT error = CHANNEL_RC_OK;
1823 if (!Stream_CheckAndLogRequiredLength(TAG, s, 18))
1824 return ERROR_INVALID_DATA;
1826 Stream_Read_UINT16(s, pdu.surfaceId);
1827 Stream_Read_UINT64(s, pdu.windowId);
1828 Stream_Read_UINT32(s, pdu.mappedWidth);
1829 Stream_Read_UINT32(s, pdu.mappedHeight);
1830 DEBUG_RDPGFX(gfx->log,
1831 "RecvMapSurfaceToWindowPdu: surfaceId: %" PRIu16
" windowId: 0x%016" PRIX64
1832 " mappedWidth: %" PRIu32
" mappedHeight: %" PRIu32
"",
1833 pdu.surfaceId, pdu.windowId, pdu.mappedWidth, pdu.mappedHeight);
1835 if (context && context->MapSurfaceToWindow)
1837 IFCALLRET(context->MapSurfaceToWindow, error, context, &pdu);
1840 WLog_Print(gfx->log, WLOG_ERROR,
1841 "context->MapSurfaceToWindow failed with error %" PRIu32
"", error);
1851 WINPR_ASSERT(callback);
1854 RdpgfxClientContext* context = gfx->context;
1855 UINT error = CHANNEL_RC_OK;
1857 if (!Stream_CheckAndLogRequiredLength(TAG, s, 26))
1858 return ERROR_INVALID_DATA;
1860 Stream_Read_UINT16(s, pdu.surfaceId);
1861 Stream_Read_UINT64(s, pdu.windowId);
1862 Stream_Read_UINT32(s, pdu.mappedWidth);
1863 Stream_Read_UINT32(s, pdu.mappedHeight);
1864 Stream_Read_UINT32(s, pdu.targetWidth);
1865 Stream_Read_UINT32(s, pdu.targetHeight);
1866 DEBUG_RDPGFX(gfx->log,
1867 "RecvMapSurfaceToScaledWindowPdu: surfaceId: %" PRIu16
" windowId: 0x%016" PRIX64
1868 " mappedWidth: %" PRIu32
" mappedHeight: %" PRIu32
" targetWidth: %" PRIu32
1869 " targetHeight: %" PRIu32
"",
1870 pdu.surfaceId, pdu.windowId, pdu.mappedWidth, pdu.mappedHeight, pdu.targetWidth,
1873 if (context && context->MapSurfaceToScaledWindow)
1875 IFCALLRET(context->MapSurfaceToScaledWindow, error, context, &pdu);
1878 WLog_Print(gfx->log, WLOG_ERROR,
1879 "context->MapSurfaceToScaledWindow failed with error %" PRIu32
"", error);
1895 WINPR_ASSERT(callback);
1897 const size_t beg = Stream_GetPosition(s);
1900 if ((error = rdpgfx_read_header(s, &header)))
1902 WLog_Print(gfx->log, WLOG_ERROR,
"rdpgfx_read_header failed with error %" PRIu32
"!",
1908 gfx->log,
"cmdId: %s (0x%04" PRIX16
") flags: 0x%04" PRIX16
" pduLength: %" PRIu32
"",
1909 rdpgfx_get_cmd_id_string(header.cmdId), header.cmdId, header.flags, header.pduLength);
1911 switch (header.cmdId)
1913 case RDPGFX_CMDID_WIRETOSURFACE_1:
1914 if ((error = rdpgfx_recv_wire_to_surface_1_pdu(callback, s)))
1915 WLog_Print(gfx->log, WLOG_ERROR,
1916 "rdpgfx_recv_wire_to_surface_1_pdu failed with error %" PRIu32
"!",
1921 case RDPGFX_CMDID_WIRETOSURFACE_2:
1922 if ((error = rdpgfx_recv_wire_to_surface_2_pdu(callback, s)))
1923 WLog_Print(gfx->log, WLOG_ERROR,
1924 "rdpgfx_recv_wire_to_surface_2_pdu failed with error %" PRIu32
"!",
1929 case RDPGFX_CMDID_DELETEENCODINGCONTEXT:
1930 if ((error = rdpgfx_recv_delete_encoding_context_pdu(callback, s)))
1931 WLog_Print(gfx->log, WLOG_ERROR,
1932 "rdpgfx_recv_delete_encoding_context_pdu failed with error %" PRIu32
"!",
1937 case RDPGFX_CMDID_SOLIDFILL:
1938 if ((error = rdpgfx_recv_solid_fill_pdu(callback, s)))
1939 WLog_Print(gfx->log, WLOG_ERROR,
1940 "rdpgfx_recv_solid_fill_pdu failed with error %" PRIu32
"!", error);
1944 case RDPGFX_CMDID_SURFACETOSURFACE:
1945 if ((error = rdpgfx_recv_surface_to_surface_pdu(callback, s)))
1946 WLog_Print(gfx->log, WLOG_ERROR,
1947 "rdpgfx_recv_surface_to_surface_pdu failed with error %" PRIu32
"!",
1952 case RDPGFX_CMDID_SURFACETOCACHE:
1953 if ((error = rdpgfx_recv_surface_to_cache_pdu(callback, s)))
1954 WLog_Print(gfx->log, WLOG_ERROR,
1955 "rdpgfx_recv_surface_to_cache_pdu failed with error %" PRIu32
"!",
1960 case RDPGFX_CMDID_CACHETOSURFACE:
1961 if ((error = rdpgfx_recv_cache_to_surface_pdu(callback, s)))
1962 WLog_Print(gfx->log, WLOG_ERROR,
1963 "rdpgfx_recv_cache_to_surface_pdu failed with error %" PRIu32
"!",
1968 case RDPGFX_CMDID_EVICTCACHEENTRY:
1969 if ((error = rdpgfx_recv_evict_cache_entry_pdu(callback, s)))
1970 WLog_Print(gfx->log, WLOG_ERROR,
1971 "rdpgfx_recv_evict_cache_entry_pdu failed with error %" PRIu32
"!",
1976 case RDPGFX_CMDID_CREATESURFACE:
1977 if ((error = rdpgfx_recv_create_surface_pdu(callback, s)))
1978 WLog_Print(gfx->log, WLOG_ERROR,
1979 "rdpgfx_recv_create_surface_pdu failed with error %" PRIu32
"!", error);
1983 case RDPGFX_CMDID_DELETESURFACE:
1984 if ((error = rdpgfx_recv_delete_surface_pdu(callback, s)))
1985 WLog_Print(gfx->log, WLOG_ERROR,
1986 "rdpgfx_recv_delete_surface_pdu failed with error %" PRIu32
"!", error);
1990 case RDPGFX_CMDID_STARTFRAME:
1991 if ((error = rdpgfx_recv_start_frame_pdu(callback, s)))
1992 WLog_Print(gfx->log, WLOG_ERROR,
1993 "rdpgfx_recv_start_frame_pdu failed with error %" PRIu32
"!", error);
1997 case RDPGFX_CMDID_ENDFRAME:
1998 if ((error = rdpgfx_recv_end_frame_pdu(callback, s)))
1999 WLog_Print(gfx->log, WLOG_ERROR,
2000 "rdpgfx_recv_end_frame_pdu failed with error %" PRIu32
"!", error);
2004 case RDPGFX_CMDID_RESETGRAPHICS:
2005 if ((error = rdpgfx_recv_reset_graphics_pdu(callback, s)))
2006 WLog_Print(gfx->log, WLOG_ERROR,
2007 "rdpgfx_recv_reset_graphics_pdu failed with error %" PRIu32
"!", error);
2011 case RDPGFX_CMDID_MAPSURFACETOOUTPUT:
2012 if ((error = rdpgfx_recv_map_surface_to_output_pdu(callback, s)))
2013 WLog_Print(gfx->log, WLOG_ERROR,
2014 "rdpgfx_recv_map_surface_to_output_pdu failed with error %" PRIu32
"!",
2019 case RDPGFX_CMDID_CACHEIMPORTREPLY:
2020 if ((error = rdpgfx_recv_cache_import_reply_pdu(callback, s)))
2021 WLog_Print(gfx->log, WLOG_ERROR,
2022 "rdpgfx_recv_cache_import_reply_pdu failed with error %" PRIu32
"!",
2027 case RDPGFX_CMDID_CAPSCONFIRM:
2028 if ((error = rdpgfx_recv_caps_confirm_pdu(callback, s)))
2029 WLog_Print(gfx->log, WLOG_ERROR,
2030 "rdpgfx_recv_caps_confirm_pdu failed with error %" PRIu32
"!", error);
2032 if ((error = rdpgfx_send_cache_offer(gfx)))
2033 WLog_Print(gfx->log, WLOG_ERROR,
2034 "rdpgfx_send_cache_offer failed with error %" PRIu32
"!", error);
2038 case RDPGFX_CMDID_MAPSURFACETOWINDOW:
2039 if ((error = rdpgfx_recv_map_surface_to_window_pdu(callback, s)))
2040 WLog_Print(gfx->log, WLOG_ERROR,
2041 "rdpgfx_recv_map_surface_to_window_pdu failed with error %" PRIu32
"!",
2046 case RDPGFX_CMDID_MAPSURFACETOSCALEDWINDOW:
2047 if ((error = rdpgfx_recv_map_surface_to_scaled_window_pdu(callback, s)))
2048 WLog_Print(gfx->log, WLOG_ERROR,
2049 "rdpgfx_recv_map_surface_to_scaled_window_pdu failed with error %" PRIu32
2055 case RDPGFX_CMDID_MAPSURFACETOSCALEDOUTPUT:
2056 if ((error = rdpgfx_recv_map_surface_to_scaled_output_pdu(callback, s)))
2057 WLog_Print(gfx->log, WLOG_ERROR,
2058 "rdpgfx_recv_map_surface_to_scaled_output_pdu failed with error %" PRIu32
2065 error = CHANNEL_RC_BAD_PROC;
2071 WLog_Print(gfx->log, WLOG_ERROR,
"Error while processing GFX cmdId: %s (0x%04" PRIX16
")",
2072 rdpgfx_get_cmd_id_string(header.cmdId), header.cmdId);
2073 Stream_SetPosition(s, (beg + header.pduLength));
2077 end = Stream_GetPosition(s);
2079 if (end != (beg + header.pduLength))
2081 WLog_Print(gfx->log, WLOG_ERROR,
2082 "Unexpected gfx pdu end: Actual: %" PRIuz
", Expected: %" PRIuz, end,
2083 (beg + header.pduLength));
2084 Stream_SetPosition(s, (beg + header.pduLength));
2095 static UINT rdpgfx_on_data_received(IWTSVirtualChannelCallback* pChannelCallback,
wStream* data)
2099 BYTE* pDstData = NULL;
2101 WINPR_ASSERT(callback);
2103 UINT error = CHANNEL_RC_OK;
2106 status = zgfx_decompress(gfx->zgfx, Stream_ConstPointer(data),
2107 (UINT32)Stream_GetRemainingLength(data), &pDstData, &DstSize, 0);
2111 WLog_Print(gfx->log, WLOG_ERROR,
"zgfx_decompress failure! status: %d", status);
2113 return ERROR_INTERNAL_ERROR;
2117 wStream* s = Stream_StaticConstInit(&sbuffer, pDstData, DstSize);
2121 WLog_Print(gfx->log, WLOG_ERROR,
"calloc failed!");
2123 return CHANNEL_RC_NO_MEMORY;
2126 while (Stream_GetPosition(s) < Stream_Length(s))
2128 if ((error = rdpgfx_recv_pdu(callback, s)))
2130 WLog_Print(gfx->log, WLOG_ERROR,
"rdpgfx_recv_pdu failed with error %" PRIu32
"!",
2145 static UINT rdpgfx_on_open(IWTSVirtualChannelCallback* pChannelCallback)
2148 WINPR_ASSERT(callback);
2151 RdpgfxClientContext* context = gfx->context;
2152 UINT error = CHANNEL_RC_OK;
2153 BOOL do_caps_advertise = TRUE;
2154 gfx->sendFrameAcks = TRUE;
2158 IFCALLRET(context->OnOpen, error, context, &do_caps_advertise, &gfx->sendFrameAcks);
2161 WLog_Print(gfx->log, WLOG_ERROR,
"context->OnOpen failed with error %" PRIu32
"",
2165 if (do_caps_advertise)
2166 error = rdpgfx_send_supported_caps(callback);
2176 static UINT rdpgfx_on_close(IWTSVirtualChannelCallback* pChannelCallback)
2178 UINT error = CHANNEL_RC_OK;
2180 WINPR_ASSERT(callback);
2186 RdpgfxClientContext* context = gfx->context;
2188 DEBUG_RDPGFX(gfx->log,
"OnClose");
2189 error = rdpgfx_save_persistent_cache(gfx);
2194 WLog_Print(gfx->log, WLOG_ERROR,
2195 "rdpgfx_save_persistent_cache failed with error %" PRIu32
"", error);
2198 free_surfaces(context, gfx->SurfaceTable);
2199 evict_cache_slots(context, gfx->MaxCacheSlots, gfx->CacheSlots);
2202 gfx->UnacknowledgedFrames = 0;
2203 gfx->TotalDecodedFrames = 0;
2207 IFCALL(context->OnClose, context);
2211 return CHANNEL_RC_OK;
2218 RdpgfxClientContext* context = gfx->context;
2220 DEBUG_RDPGFX(gfx->log,
"Terminated");
2221 rdpgfx_client_context_free(context);
2229 static UINT rdpgfx_set_surface_data(RdpgfxClientContext* context, UINT16 surfaceId,
void* pData)
2232 WINPR_ASSERT(context);
2235 key = ((ULONG_PTR)surfaceId) + 1;
2239 if (!HashTable_Insert(gfx->SurfaceTable, (
void*)key, pData))
2240 return ERROR_BAD_ARGUMENTS;
2243 HashTable_Remove(gfx->SurfaceTable, (
void*)key);
2245 return CHANNEL_RC_OK;
2253 static UINT rdpgfx_get_surface_ids(RdpgfxClientContext* context, UINT16** ppSurfaceIds,
2257 UINT16* pSurfaceIds = NULL;
2258 ULONG_PTR* pKeys = NULL;
2259 WINPR_ASSERT(context);
2262 count = HashTable_GetKeys(gfx->SurfaceTable, &pKeys);
2264 WINPR_ASSERT(ppSurfaceIds);
2265 WINPR_ASSERT(count_out);
2269 return CHANNEL_RC_OK;
2272 pSurfaceIds = (UINT16*)calloc(count,
sizeof(UINT16));
2276 WLog_Print(gfx->log, WLOG_ERROR,
"calloc failed!");
2278 return CHANNEL_RC_NO_MEMORY;
2281 for (
size_t index = 0; index < count; index++)
2283 pSurfaceIds[index] = (UINT16)(pKeys[index] - 1);
2287 *ppSurfaceIds = pSurfaceIds;
2288 *count_out = (UINT16)count;
2289 return CHANNEL_RC_OK;
2292 static void* rdpgfx_get_surface_data(RdpgfxClientContext* context, UINT16 surfaceId)
2296 WINPR_ASSERT(context);
2299 key = ((ULONG_PTR)surfaceId) + 1;
2300 pData = HashTable_GetItemValue(gfx->SurfaceTable, (
void*)key);
2309 static UINT rdpgfx_set_cache_slot_data(RdpgfxClientContext* context, UINT16 cacheSlot,
void* pData)
2311 WINPR_ASSERT(context);
2316 if (cacheSlot == 0 || cacheSlot > gfx->MaxCacheSlots)
2318 WLog_ERR(TAG,
"invalid cache slot %" PRIu16
", must be between 1 and %" PRIu16
"",
2319 cacheSlot, gfx->MaxCacheSlots);
2320 return ERROR_INVALID_INDEX;
2323 gfx->CacheSlots[cacheSlot - 1] = pData;
2324 return CHANNEL_RC_OK;
2327 static void* rdpgfx_get_cache_slot_data(RdpgfxClientContext* context, UINT16 cacheSlot)
2330 WINPR_ASSERT(context);
2334 if (cacheSlot == 0 || cacheSlot > gfx->MaxCacheSlots)
2336 WLog_ERR(TAG,
"invalid cache slot %" PRIu16
", must be between 1 and %" PRIu16
"",
2337 cacheSlot, gfx->MaxCacheSlots);
2341 pData = gfx->CacheSlots[cacheSlot - 1];
2345 static UINT init_plugin_cb(
GENERIC_DYNVC_PLUGIN* base, rdpContext* rcontext, rdpSettings* settings)
2347 RdpgfxClientContext* context = NULL;
2351 gfx->rdpcontext = rcontext;
2352 gfx->log = WLog_Get(TAG);
2354 gfx->SurfaceTable = HashTable_New(TRUE);
2355 if (!gfx->SurfaceTable)
2357 WLog_ERR(TAG,
"HashTable_New for surfaces failed !");
2358 return CHANNEL_RC_NO_MEMORY;
2361 gfx->suspendFrameAcks =
2363 gfx->MaxCacheSlots =
2366 context = (RdpgfxClientContext*)calloc(1,
sizeof(RdpgfxClientContext));
2369 WLog_ERR(TAG,
"context calloc failed!");
2370 HashTable_Free(gfx->SurfaceTable);
2371 gfx->SurfaceTable = NULL;
2372 return CHANNEL_RC_NO_MEMORY;
2375 gfx->zgfx = zgfx_context_new(FALSE);
2378 WLog_ERR(TAG,
"zgfx_context_new failed!");
2379 HashTable_Free(gfx->SurfaceTable);
2380 gfx->SurfaceTable = NULL;
2382 return CHANNEL_RC_NO_MEMORY;
2385 context->handle = (
void*)gfx;
2386 context->GetSurfaceIds = rdpgfx_get_surface_ids;
2387 context->SetSurfaceData = rdpgfx_set_surface_data;
2388 context->GetSurfaceData = rdpgfx_get_surface_data;
2389 context->SetCacheSlotData = rdpgfx_set_cache_slot_data;
2390 context->GetCacheSlotData = rdpgfx_get_cache_slot_data;
2391 context->CapsAdvertise = rdpgfx_send_caps_advertise_pdu;
2392 context->FrameAcknowledge = rdpgfx_send_frame_acknowledge_pdu;
2393 context->CacheImportOffer = rdpgfx_send_cache_import_offer_pdu;
2394 context->QoeFrameAcknowledge = rdpgfx_send_qoe_frame_acknowledge_pdu;
2396 gfx->base.iface.pInterface = (
void*)context;
2397 gfx->context = context;
2398 return CHANNEL_RC_OK;
2401 void rdpgfx_client_context_free(RdpgfxClientContext* context)
2411 free_surfaces(context, gfx->SurfaceTable);
2412 evict_cache_slots(context, gfx->MaxCacheSlots, gfx->CacheSlots);
2416 zgfx_context_free(gfx->zgfx);
2420 HashTable_Free(gfx->SurfaceTable);
2424 static const IWTSVirtualChannelCallback rdpgfx_callbacks = { rdpgfx_on_data_received,
2425 rdpgfx_on_open, rdpgfx_on_close,
2433 FREERDP_ENTRY_POINT(UINT VCAPITYPE rdpgfx_DVCPluginEntry(IDRDYNVC_ENTRY_POINTS* pEntryPoints))
2435 return freerdp_generic_DVCPluginEntry(pEntryPoints, TAG, RDPGFX_DVC_CHANNEL_NAME,
2437 &rdpgfx_callbacks, init_plugin_cb, terminate_plugin_cb);
FREERDP_API UINT32 freerdp_settings_get_uint32(const rdpSettings *settings, FreeRDP_Settings_Keys_UInt32 id)
Returns a UINT32 settings value.
FREERDP_API BOOL freerdp_settings_get_bool(const rdpSettings *settings, FreeRDP_Settings_Keys_Bool id)
Returns a boolean settings value.
FREERDP_API const char * freerdp_settings_get_string(const rdpSettings *settings, FreeRDP_Settings_Keys_String id)
Returns a immutable string settings value.