24 #include <freerdp/config.h>
26 #include <winpr/assert.h>
28 #include <winpr/crt.h>
29 #include <winpr/wlog.h>
30 #include <winpr/print.h>
31 #include <winpr/synch.h>
32 #include <winpr/thread.h>
33 #include <winpr/stream.h>
34 #include <winpr/sysinfo.h>
35 #include <winpr/cmdline.h>
36 #include <winpr/collections.h>
38 #include <freerdp/addin.h>
39 #include <freerdp/channels/log.h>
41 #include "rdpgfx_common.h"
42 #include "rdpgfx_codec.h"
44 #include "rdpgfx_main.h"
46 #define TAG CHANNELS_TAG("rdpgfx.client")
48 static BOOL delete_surface(
const void* key,
void* value,
void* arg)
50 const UINT16
id = (UINT16)(uintptr_t)(key);
51 RdpgfxClientContext* context = arg;
55 pdu.surfaceId =
id - 1;
59 UINT error = CHANNEL_RC_OK;
60 IFCALLRET(context->DeleteSurface, error, context, &pdu);
64 WLog_ERR(TAG,
"context->DeleteSurface failed with error %" PRIu32
"", error);
70 static void free_surfaces(RdpgfxClientContext* context, wHashTable* SurfaceTable)
72 HashTable_Foreach(SurfaceTable, delete_surface, context);
75 static void evict_cache_slots(RdpgfxClientContext* context, UINT16 MaxCacheSlots,
void** CacheSlots)
77 WINPR_ASSERT(CacheSlots);
78 for (UINT16 index = 0; index < MaxCacheSlots; index++)
80 if (CacheSlots[index])
83 pdu.cacheSlot = index + 1;
85 if (context && context->EvictCacheEntry)
87 context->EvictCacheEntry(context, &pdu);
90 CacheSlots[index] = NULL;
100 static UINT rdpgfx_send_caps_advertise_pdu(RdpgfxClientContext* context,
103 UINT error = CHANNEL_RC_OK;
110 WINPR_ASSERT(context);
114 if (!gfx || !gfx->base.listener_callback)
115 return ERROR_BAD_ARGUMENTS;
117 callback = gfx->base.listener_callback->channel_callback;
120 header.cmdId = RDPGFX_CMDID_CAPSADVERTISE;
121 header.pduLength = RDPGFX_HEADER_SIZE + 2;
123 for (UINT16 index = 0; index < pdu->capsSetCount; index++)
126 header.pduLength += RDPGFX_CAPSET_BASE_SIZE + capsSet->length;
129 DEBUG_RDPGFX(gfx->log,
"SendCapsAdvertisePdu %" PRIu16
"", pdu->capsSetCount);
130 s = Stream_New(NULL, header.pduLength);
134 WLog_ERR(TAG,
"Stream_New failed!");
135 return CHANNEL_RC_NO_MEMORY;
138 if ((error = rdpgfx_write_header(s, &header)))
142 Stream_Write_UINT16(s, pdu->capsSetCount);
144 for (UINT16 index = 0; index < pdu->capsSetCount; index++)
148 DEBUG_RDPGFX(gfx->log,
"Sending %s [0x%08" PRIx32
"] flags=0x%08" PRIx32,
149 rdpgfx_caps_version_str(capsSet->version), capsSet->version, capsSet->flags);
151 Stream_Write_UINT32(s, capsSet->version);
152 Stream_Write_UINT32(s, capsSet->length);
153 Stream_Write_UINT32(s, capsSet->flags);
154 Stream_Zero(s, capsSet->length - 4);
157 Stream_SealLength(s);
158 error = callback->channel->Write(callback->channel, (UINT32)Stream_Length(s), Stream_Buffer(s),
161 Stream_Free(s, TRUE);
165 static BOOL rdpgfx_is_capability_filtered(
RDPGFX_PLUGIN* gfx, UINT32 caps)
168 const UINT32 filter =
170 const UINT32 capList[] = { RDPGFX_CAPVERSION_8, RDPGFX_CAPVERSION_81,
171 RDPGFX_CAPVERSION_10, RDPGFX_CAPVERSION_101,
172 RDPGFX_CAPVERSION_102, RDPGFX_CAPVERSION_103,
173 RDPGFX_CAPVERSION_104, RDPGFX_CAPVERSION_105,
174 RDPGFX_CAPVERSION_106, RDPGFX_CAPVERSION_106_ERR,
175 RDPGFX_CAPVERSION_107 };
177 for (
size_t x = 0; x < ARRAYSIZE(capList); x++)
179 if (caps == capList[x])
180 return (filter & (1 << x)) != 0;
194 RdpgfxClientContext* context = NULL;
200 return ERROR_BAD_ARGUMENTS;
205 return ERROR_BAD_CONFIGURATION;
207 context = gfx->context;
210 return ERROR_BAD_CONFIGURATION;
212 pdu.capsSetCount = 0;
215 if (!rdpgfx_is_capability_filtered(gfx, RDPGFX_CAPVERSION_8))
217 capsSet = &capsSets[pdu.capsSetCount++];
218 capsSet->version = RDPGFX_CAPVERSION_8;
223 capsSet->flags |= RDPGFX_CAPS_FLAG_THINCLIENT;
230 capsSet->flags |= RDPGFX_CAPS_FLAG_SMALL_CACHE;
233 if (!rdpgfx_is_capability_filtered(gfx, RDPGFX_CAPVERSION_81))
235 capsSet = &capsSets[pdu.capsSetCount++];
236 capsSet->version = RDPGFX_CAPVERSION_81;
241 capsSet->flags |= RDPGFX_CAPS_FLAG_THINCLIENT;
244 capsSet->flags |= RDPGFX_CAPS_FLAG_SMALL_CACHE;
249 capsSet->flags |= RDPGFX_CAPS_FLAG_AVC420_ENABLED;
257 UINT32 caps10Flags = 0;
260 caps10Flags |= RDPGFX_CAPS_FLAG_SMALL_CACHE;
265 caps10Flags |= RDPGFX_CAPS_FLAG_AVC_DISABLED;
268 caps10Flags |= RDPGFX_CAPS_FLAG_AVC_DISABLED;
271 if (!rdpgfx_is_capability_filtered(gfx, RDPGFX_CAPVERSION_10))
273 capsSet = &capsSets[pdu.capsSetCount++];
274 capsSet->version = RDPGFX_CAPVERSION_10;
276 capsSet->flags = caps10Flags;
279 if (!rdpgfx_is_capability_filtered(gfx, RDPGFX_CAPVERSION_101))
281 capsSet = &capsSets[pdu.capsSetCount++];
282 capsSet->version = RDPGFX_CAPVERSION_101;
283 capsSet->length = 0x10;
287 if (!rdpgfx_is_capability_filtered(gfx, RDPGFX_CAPVERSION_102))
289 capsSet = &capsSets[pdu.capsSetCount++];
290 capsSet->version = RDPGFX_CAPVERSION_102;
291 capsSet->length = 0x4;
292 capsSet->flags = caps10Flags;
297 if ((caps10Flags & RDPGFX_CAPS_FLAG_AVC_DISABLED) == 0)
298 caps10Flags |= RDPGFX_CAPS_FLAG_AVC_THINCLIENT;
301 if (!rdpgfx_is_capability_filtered(gfx, RDPGFX_CAPVERSION_103))
303 capsSet = &capsSets[pdu.capsSetCount++];
304 capsSet->version = RDPGFX_CAPVERSION_103;
305 capsSet->length = 0x4;
306 capsSet->flags = caps10Flags & ~RDPGFX_CAPS_FLAG_SMALL_CACHE;
309 if (!rdpgfx_is_capability_filtered(gfx, RDPGFX_CAPVERSION_104))
311 capsSet = &capsSets[pdu.capsSetCount++];
312 capsSet->version = RDPGFX_CAPVERSION_104;
313 capsSet->length = 0x4;
314 capsSet->flags = caps10Flags;
320 #if defined(WITH_CAIRO) || defined(WITH_SWSCALE)
321 if (!rdpgfx_is_capability_filtered(gfx, RDPGFX_CAPVERSION_105))
323 capsSet = &capsSets[pdu.capsSetCount++];
324 capsSet->version = RDPGFX_CAPVERSION_105;
325 capsSet->length = 0x4;
326 capsSet->flags = caps10Flags;
329 if (!rdpgfx_is_capability_filtered(gfx, RDPGFX_CAPVERSION_106))
331 capsSet = &capsSets[pdu.capsSetCount++];
332 capsSet->version = RDPGFX_CAPVERSION_106;
333 capsSet->length = 0x4;
334 capsSet->flags = caps10Flags;
337 if (!rdpgfx_is_capability_filtered(gfx, RDPGFX_CAPVERSION_106_ERR))
339 capsSet = &capsSets[pdu.capsSetCount++];
340 capsSet->version = RDPGFX_CAPVERSION_106_ERR;
341 capsSet->length = 0x4;
342 capsSet->flags = caps10Flags;
346 if (!rdpgfx_is_capability_filtered(gfx, RDPGFX_CAPVERSION_107))
348 capsSet = &capsSets[pdu.capsSetCount++];
349 capsSet->version = RDPGFX_CAPVERSION_107;
350 capsSet->length = 0x4;
351 capsSet->flags = caps10Flags;
352 #if !defined(WITH_CAIRO) && !defined(WITH_SWSCALE)
353 capsSet->flags |= RDPGFX_CAPS_FLAG_SCALEDMAP_DISABLE;
358 return IFCALLRESULT(ERROR_BAD_CONFIGURATION, context->CapsAdvertise, context, &pdu);
370 WINPR_ASSERT(callback);
374 RdpgfxClientContext* context = gfx->context;
376 pdu.capsSet = &capsSet;
378 if (!Stream_CheckAndLogRequiredLength(TAG, s, 12))
379 return ERROR_INVALID_DATA;
381 Stream_Read_UINT32(s, capsSet.version);
382 Stream_Read_UINT32(s, capsSet.length);
383 Stream_Read_UINT32(s, capsSet.flags);
384 gfx->TotalDecodedFrames = 0;
385 gfx->ConnectionCaps = capsSet;
386 DEBUG_RDPGFX(gfx->log,
387 "RecvCapsConfirmPdu: version: %s [0x%08" PRIX32
"] flags: 0x%08" PRIX32
"",
388 rdpgfx_caps_version_str(capsSet.version), capsSet.version, capsSet.flags);
391 return ERROR_BAD_CONFIGURATION;
393 return IFCALLRESULT(CHANNEL_RC_OK, context->CapsConfirm, context, &pdu);
401 static UINT rdpgfx_send_frame_acknowledge_pdu(RdpgfxClientContext* context,
410 if (!context || !pdu)
411 return ERROR_BAD_ARGUMENTS;
415 if (!gfx || !gfx->base.listener_callback)
416 return ERROR_BAD_CONFIGURATION;
418 callback = gfx->base.listener_callback->channel_callback;
421 return ERROR_BAD_CONFIGURATION;
424 header.cmdId = RDPGFX_CMDID_FRAMEACKNOWLEDGE;
425 header.pduLength = RDPGFX_HEADER_SIZE + 12;
426 DEBUG_RDPGFX(gfx->log,
"SendFrameAcknowledgePdu: %" PRIu32
"", pdu->frameId);
427 s = Stream_New(NULL, header.pduLength);
431 WLog_ERR(TAG,
"Stream_New failed!");
432 return CHANNEL_RC_NO_MEMORY;
435 if ((error = rdpgfx_write_header(s, &header)))
439 Stream_Write_UINT32(s, pdu->queueDepth);
440 Stream_Write_UINT32(s, pdu->frameId);
441 Stream_Write_UINT32(s, pdu->totalFramesDecoded);
442 error = callback->channel->Write(callback->channel, (UINT32)Stream_Length(s), Stream_Buffer(s),
445 if (error == CHANNEL_RC_OK)
446 gfx->UnacknowledgedFrames--;
449 Stream_Free(s, TRUE);
453 static UINT rdpgfx_send_qoe_frame_acknowledge_pdu(RdpgfxClientContext* context,
463 header.cmdId = RDPGFX_CMDID_QOEFRAMEACKNOWLEDGE;
464 header.pduLength = RDPGFX_HEADER_SIZE + 12;
466 if (!context || !pdu)
467 return ERROR_BAD_ARGUMENTS;
471 if (!gfx || !gfx->base.listener_callback)
472 return ERROR_BAD_CONFIGURATION;
474 callback = gfx->base.listener_callback->channel_callback;
477 return ERROR_BAD_CONFIGURATION;
479 DEBUG_RDPGFX(gfx->log,
"SendQoeFrameAcknowledgePdu: %" PRIu32
"", pdu->frameId);
480 s = Stream_New(NULL, header.pduLength);
484 WLog_ERR(TAG,
"Stream_New failed!");
485 return CHANNEL_RC_NO_MEMORY;
488 if ((error = rdpgfx_write_header(s, &header)))
492 Stream_Write_UINT32(s, pdu->frameId);
493 Stream_Write_UINT32(s, pdu->timestamp);
494 Stream_Write_UINT16(s, pdu->timeDiffSE);
495 Stream_Write_UINT16(s, pdu->timeDiffEDR);
496 error = callback->channel->Write(callback->channel, (UINT32)Stream_Length(s), Stream_Buffer(s),
499 Stream_Free(s, TRUE);
512 WINPR_ASSERT(callback);
518 RdpgfxClientContext* context = gfx->context;
519 UINT error = CHANNEL_RC_OK;
520 GraphicsResetEventArgs graphicsReset = { 0 };
522 if (!Stream_CheckAndLogRequiredLength(TAG, s, 12))
523 return ERROR_INVALID_DATA;
525 Stream_Read_UINT32(s, pdu.width);
526 Stream_Read_UINT32(s, pdu.height);
527 Stream_Read_UINT32(s, pdu.monitorCount);
529 if (!Stream_CheckAndLogRequiredLengthOfSize(TAG, s, pdu.monitorCount, 20ull))
530 return ERROR_INVALID_DATA;
534 if (!pdu.monitorDefArray)
536 WLog_Print(gfx->log, WLOG_ERROR,
"calloc failed!");
537 return CHANNEL_RC_NO_MEMORY;
540 for (UINT32 index = 0; index < pdu.monitorCount; index++)
542 monitor = &(pdu.monitorDefArray[index]);
543 Stream_Read_INT32(s, monitor->left);
544 Stream_Read_INT32(s, monitor->top);
545 Stream_Read_INT32(s, monitor->right);
546 Stream_Read_INT32(s, monitor->bottom);
547 Stream_Read_UINT32(s, monitor->flags);
550 const size_t size = (RDPGFX_HEADER_SIZE + 12ULL + (pdu.monitorCount * 20ULL));
553 free(pdu.monitorDefArray);
554 return CHANNEL_RC_NULL_DATA;
556 const size_t pad = 340ULL - size;
558 if (!Stream_CheckAndLogRequiredLength(TAG, s, (
size_t)pad))
560 free(pdu.monitorDefArray);
561 return CHANNEL_RC_NO_MEMORY;
565 DEBUG_RDPGFX(gfx->log,
566 "RecvResetGraphicsPdu: width: %" PRIu32
" height: %" PRIu32
" count: %" PRIu32
"",
567 pdu.width, pdu.height, pdu.monitorCount);
569 #if defined(WITH_DEBUG_RDPGFX)
570 for (UINT32 index = 0; index < pdu.monitorCount; index++)
572 monitor = &(pdu.monitorDefArray[index]);
573 DEBUG_RDPGFX(gfx->log,
574 "RecvResetGraphicsPdu: monitor left:%" PRIi32
" top:%" PRIi32
" right:%" PRIi32
575 " bottom:%" PRIi32
" flags:0x%" PRIx32
"",
576 monitor->left, monitor->top, monitor->right, monitor->bottom, monitor->flags);
582 IFCALLRET(context->ResetGraphics, error, context, &pdu);
585 WLog_Print(gfx->log, WLOG_ERROR,
"context->ResetGraphics failed with error %" PRIu32
"",
590 EventArgsInit(&graphicsReset,
"libfreerdp");
591 graphicsReset.width = pdu.width;
592 graphicsReset.height = pdu.height;
593 PubSub_OnGraphicsReset(gfx->rdpcontext->pubSub, gfx->rdpcontext, &graphicsReset);
594 free(pdu.monitorDefArray);
606 WINPR_ASSERT(callback);
609 RdpgfxClientContext* context = gfx->context;
610 UINT error = CHANNEL_RC_OK;
612 if (!Stream_CheckAndLogRequiredLength(TAG, s, 2))
613 return ERROR_INVALID_DATA;
615 Stream_Read_UINT16(s, pdu.cacheSlot);
616 WLog_Print(gfx->log, WLOG_DEBUG,
"RecvEvictCacheEntryPdu: cacheSlot: %" PRIu16
"",
621 IFCALLRET(context->EvictCacheEntry, error, context, &pdu);
624 WLog_Print(gfx->log, WLOG_ERROR,
625 "context->EvictCacheEntry failed with error %" PRIu32
"", error);
639 UINT error = CHANNEL_RC_OK;
641 rdpPersistentCache* persistent = NULL;
643 WINPR_ASSERT(gfx->rdpcontext);
644 rdpSettings* settings = gfx->rdpcontext->settings;
647 WINPR_ASSERT(settings);
649 offer->cacheEntriesCount = 0;
652 return CHANNEL_RC_OK;
654 const char* BitmapCachePersistFile =
656 if (!BitmapCachePersistFile)
657 return CHANNEL_RC_OK;
659 persistent = persistent_cache_new();
662 return CHANNEL_RC_NO_MEMORY;
664 if (persistent_cache_open(persistent, BitmapCachePersistFile, FALSE, 3) < 1)
666 error = CHANNEL_RC_INITIALIZATION_ERROR;
670 if (persistent_cache_get_version(persistent) != 3)
672 error = ERROR_INVALID_DATA;
676 count = persistent_cache_get_count(persistent);
680 error = ERROR_INVALID_DATA;
684 if (count >= RDPGFX_CACHE_ENTRY_MAX_COUNT)
685 count = RDPGFX_CACHE_ENTRY_MAX_COUNT - 1;
687 if (count > gfx->MaxCacheSlots)
688 count = gfx->MaxCacheSlots;
690 offer->cacheEntriesCount = (UINT16)count;
692 for (
int idx = 0; idx < count; idx++)
694 if (persistent_cache_read_entry(persistent, &entry) < 1)
696 error = ERROR_INVALID_DATA;
700 offer->cacheEntries[idx].cacheKey = entry.key64;
701 offer->cacheEntries[idx].bitmapLength = entry.size;
704 persistent_cache_free(persistent);
708 persistent_cache_free(persistent);
719 UINT error = CHANNEL_RC_OK;
721 rdpPersistentCache* persistent = NULL;
723 WINPR_ASSERT(gfx->rdpcontext);
724 rdpSettings* settings = gfx->rdpcontext->settings;
725 RdpgfxClientContext* context = gfx->context;
727 WINPR_ASSERT(context);
728 WINPR_ASSERT(settings);
731 return CHANNEL_RC_OK;
733 const char* BitmapCachePersistFile =
735 if (!BitmapCachePersistFile)
736 return CHANNEL_RC_OK;
738 if (!context->ExportCacheEntry)
739 return CHANNEL_RC_INITIALIZATION_ERROR;
741 persistent = persistent_cache_new();
744 return CHANNEL_RC_NO_MEMORY;
746 if (persistent_cache_open(persistent, BitmapCachePersistFile, TRUE, 3) < 1)
748 error = CHANNEL_RC_INITIALIZATION_ERROR;
752 for (UINT16 idx = 0; idx < gfx->MaxCacheSlots; idx++)
754 if (gfx->CacheSlots[idx])
756 UINT16 cacheSlot = idx;
758 if (context->ExportCacheEntry(context, cacheSlot, &cacheEntry) != CHANNEL_RC_OK)
761 persistent_cache_write_entry(persistent, &cacheEntry);
765 persistent_cache_free(persistent);
769 persistent_cache_free(persistent);
778 static UINT rdpgfx_send_cache_import_offer_pdu(RdpgfxClientContext* context,
781 UINT error = CHANNEL_RC_OK;
786 if (!context || !pdu)
787 return ERROR_BAD_ARGUMENTS;
791 if (!gfx || !gfx->base.listener_callback)
792 return ERROR_BAD_CONFIGURATION;
794 callback = gfx->base.listener_callback->channel_callback;
797 return ERROR_BAD_CONFIGURATION;
800 header.cmdId = RDPGFX_CMDID_CACHEIMPORTOFFER;
801 header.pduLength = RDPGFX_HEADER_SIZE + 2ul + pdu->cacheEntriesCount * 12ul;
802 DEBUG_RDPGFX(gfx->log,
"SendCacheImportOfferPdu: cacheEntriesCount: %" PRIu16
"",
803 pdu->cacheEntriesCount);
804 s = Stream_New(NULL, header.pduLength);
808 WLog_ERR(TAG,
"Stream_New failed!");
809 return CHANNEL_RC_NO_MEMORY;
812 if ((error = rdpgfx_write_header(s, &header)))
815 if (pdu->cacheEntriesCount <= 0)
817 WLog_ERR(TAG,
"Invalid cacheEntriesCount: %" PRIu16
"", pdu->cacheEntriesCount);
818 error = ERROR_INVALID_DATA;
823 Stream_Write_UINT16(s, pdu->cacheEntriesCount);
825 for (UINT16 index = 0; index < pdu->cacheEntriesCount; index++)
828 Stream_Write_UINT64(s, cacheEntry->cacheKey);
829 Stream_Write_UINT32(s, cacheEntry->bitmapLength);
832 error = callback->channel->Write(callback->channel, (UINT32)Stream_Length(s), Stream_Buffer(s),
836 Stream_Free(s, TRUE);
848 UINT error = CHANNEL_RC_OK;
851 rdpPersistentCache* persistent = NULL;
854 WINPR_ASSERT(gfx->rdpcontext);
856 RdpgfxClientContext* context = gfx->context;
857 rdpSettings* settings = gfx->rdpcontext->settings;
860 return CHANNEL_RC_OK;
862 const char* BitmapCachePersistFile =
864 if (!BitmapCachePersistFile)
865 return CHANNEL_RC_OK;
867 persistent = persistent_cache_new();
870 return CHANNEL_RC_NO_MEMORY;
872 if (persistent_cache_open(persistent, BitmapCachePersistFile, FALSE, 3) < 1)
874 error = CHANNEL_RC_INITIALIZATION_ERROR;
878 if (persistent_cache_get_version(persistent) != 3)
880 error = ERROR_INVALID_DATA;
884 count = persistent_cache_get_count(persistent);
887 error = ERROR_INVALID_DATA;
891 if (count >= RDPGFX_CACHE_ENTRY_MAX_COUNT)
892 count = RDPGFX_CACHE_ENTRY_MAX_COUNT - 1;
894 if (count > gfx->MaxCacheSlots)
895 count = gfx->MaxCacheSlots;
900 error = CHANNEL_RC_NO_MEMORY;
904 WINPR_ASSERT(count <= UINT16_MAX);
905 offer->cacheEntriesCount = (UINT16)count;
907 WLog_DBG(TAG,
"Sending Cache Import Offer: %d", count);
909 for (
int idx = 0; idx < count; idx++)
911 if (persistent_cache_read_entry(persistent, &entry) < 1)
913 error = ERROR_INVALID_DATA;
917 offer->cacheEntries[idx].cacheKey = entry.key64;
918 offer->cacheEntries[idx].bitmapLength = entry.size;
921 if (offer->cacheEntriesCount > 0)
923 error = rdpgfx_send_cache_import_offer_pdu(context, offer);
924 if (error != CHANNEL_RC_OK)
926 WLog_Print(gfx->log, WLOG_ERROR,
"Failed to send cache import offer PDU");
932 persistent_cache_free(persistent);
942 static UINT rdpgfx_load_cache_import_reply(
RDPGFX_PLUGIN* gfx,
946 UINT error = CHANNEL_RC_OK;
947 rdpPersistentCache* persistent = NULL;
949 WINPR_ASSERT(gfx->rdpcontext);
950 rdpSettings* settings = gfx->rdpcontext->settings;
951 RdpgfxClientContext* context = gfx->context;
953 WINPR_ASSERT(settings);
956 return CHANNEL_RC_OK;
958 const char* BitmapCachePersistFile =
960 if (!BitmapCachePersistFile)
961 return CHANNEL_RC_OK;
963 persistent = persistent_cache_new();
966 return CHANNEL_RC_NO_MEMORY;
968 if (persistent_cache_open(persistent, BitmapCachePersistFile, FALSE, 3) < 1)
970 error = CHANNEL_RC_INITIALIZATION_ERROR;
974 if (persistent_cache_get_version(persistent) != 3)
976 error = ERROR_INVALID_DATA;
980 count = persistent_cache_get_count(persistent);
982 count = (count < reply->importedEntriesCount) ? count : reply->importedEntriesCount;
984 WLog_DBG(TAG,
"Receiving Cache Import Reply: %d", count);
986 for (
int idx = 0; idx < count; idx++)
989 if (persistent_cache_read_entry(persistent, &entry) < 1)
991 error = ERROR_INVALID_DATA;
995 const UINT16 cacheSlot = reply->cacheSlots[idx];
996 if (context && context->ImportCacheEntry)
997 context->ImportCacheEntry(context, cacheSlot, &entry);
1000 persistent_cache_free(persistent);
1004 persistent_cache_free(persistent);
1016 WINPR_ASSERT(callback);
1019 RdpgfxClientContext* context = gfx->context;
1020 UINT error = CHANNEL_RC_OK;
1022 if (!Stream_CheckAndLogRequiredLength(TAG, s, 2))
1023 return ERROR_INVALID_DATA;
1025 Stream_Read_UINT16(s, pdu.importedEntriesCount);
1027 if (!Stream_CheckAndLogRequiredLengthOfSize(TAG, s, pdu.importedEntriesCount, 2ull))
1028 return ERROR_INVALID_DATA;
1030 if (pdu.importedEntriesCount > RDPGFX_CACHE_ENTRY_MAX_COUNT)
1031 return ERROR_INVALID_DATA;
1033 for (UINT16 idx = 0; idx < pdu.importedEntriesCount; idx++)
1035 Stream_Read_UINT16(s, pdu.cacheSlots[idx]);
1038 DEBUG_RDPGFX(gfx->log,
"RecvCacheImportReplyPdu: importedEntriesCount: %" PRIu16
"",
1039 pdu.importedEntriesCount);
1041 error = rdpgfx_load_cache_import_reply(gfx, &pdu);
1045 WLog_Print(gfx->log, WLOG_ERROR,
1046 "rdpgfx_load_cache_import_reply failed with error %" PRIu32
"", error);
1052 IFCALLRET(context->CacheImportReply, error, context, &pdu);
1055 WLog_Print(gfx->log, WLOG_ERROR,
1056 "context->CacheImportReply failed with error %" PRIu32
"", error);
1070 WINPR_ASSERT(callback);
1073 RdpgfxClientContext* context = gfx->context;
1074 UINT error = CHANNEL_RC_OK;
1076 if (!Stream_CheckAndLogRequiredLength(TAG, s, 7))
1077 return ERROR_INVALID_DATA;
1079 Stream_Read_UINT16(s, pdu.surfaceId);
1080 Stream_Read_UINT16(s, pdu.width);
1081 Stream_Read_UINT16(s, pdu.height);
1082 Stream_Read_UINT8(s, pdu.pixelFormat);
1083 DEBUG_RDPGFX(gfx->log,
1084 "RecvCreateSurfacePdu: surfaceId: %" PRIu16
" width: %" PRIu16
" height: %" PRIu16
1085 " pixelFormat: 0x%02" PRIX8
"",
1086 pdu.surfaceId, pdu.width, pdu.height, pdu.pixelFormat);
1095 IFCALL(context->DeleteSurface, context, &deletePdu);
1097 IFCALLRET(context->CreateSurface, error, context, &pdu);
1100 WLog_Print(gfx->log, WLOG_ERROR,
"context->CreateSurface failed with error %" PRIu32
"",
1115 WINPR_ASSERT(callback);
1118 RdpgfxClientContext* context = gfx->context;
1119 UINT error = CHANNEL_RC_OK;
1121 if (!Stream_CheckAndLogRequiredLength(TAG, s, 2))
1122 return ERROR_INVALID_DATA;
1124 Stream_Read_UINT16(s, pdu.surfaceId);
1125 DEBUG_RDPGFX(gfx->log,
"RecvDeleteSurfacePdu: surfaceId: %" PRIu16
"", pdu.surfaceId);
1129 IFCALLRET(context->DeleteSurface, error, context, &pdu);
1132 WLog_Print(gfx->log, WLOG_ERROR,
"context->DeleteSurface failed with error %" PRIu32
"",
1147 WINPR_ASSERT(callback);
1150 RdpgfxClientContext* context = gfx->context;
1151 UINT error = CHANNEL_RC_OK;
1153 if (!Stream_CheckAndLogRequiredLength(TAG, s, RDPGFX_START_FRAME_PDU_SIZE))
1154 return ERROR_INVALID_DATA;
1156 Stream_Read_UINT32(s, pdu.timestamp);
1157 Stream_Read_UINT32(s, pdu.frameId);
1158 DEBUG_RDPGFX(gfx->log,
"RecvStartFramePdu: frameId: %" PRIu32
" timestamp: 0x%08" PRIX32
"",
1159 pdu.frameId, pdu.timestamp);
1160 gfx->StartDecodingTime = GetTickCount64();
1164 IFCALLRET(context->StartFrame, error, context, &pdu);
1167 WLog_Print(gfx->log, WLOG_ERROR,
"context->StartFrame failed with error %" PRIu32
"",
1171 gfx->UnacknowledgedFrames++;
1184 WINPR_ASSERT(callback);
1187 RdpgfxClientContext* context = gfx->context;
1188 UINT error = CHANNEL_RC_OK;
1190 if (!Stream_CheckAndLogRequiredLength(TAG, s, RDPGFX_END_FRAME_PDU_SIZE))
1191 return ERROR_INVALID_DATA;
1193 Stream_Read_UINT32(s, pdu.frameId);
1194 DEBUG_RDPGFX(gfx->log,
"RecvEndFramePdu: frameId: %" PRIu32
"", pdu.frameId);
1196 const UINT64 start = GetTickCount64();
1199 IFCALLRET(context->EndFrame, error, context, &pdu);
1203 WLog_Print(gfx->log, WLOG_ERROR,
"context->EndFrame failed with error %" PRIu32
"",
1208 const UINT64 end = GetTickCount64();
1209 const UINT64 EndFrameTime = end - start;
1210 gfx->TotalDecodedFrames++;
1212 if (!gfx->sendFrameAcks)
1215 ack.frameId = pdu.frameId;
1216 ack.totalFramesDecoded = gfx->TotalDecodedFrames;
1218 if (gfx->suspendFrameAcks)
1220 ack.queueDepth = SUSPEND_FRAME_ACKNOWLEDGEMENT;
1222 if (gfx->TotalDecodedFrames == 1)
1223 if ((error = rdpgfx_send_frame_acknowledge_pdu(context, &ack)))
1224 WLog_Print(gfx->log, WLOG_ERROR,
1225 "rdpgfx_send_frame_acknowledge_pdu failed with error %" PRIu32
"",
1230 ack.queueDepth = QUEUE_DEPTH_UNAVAILABLE;
1232 if ((error = rdpgfx_send_frame_acknowledge_pdu(context, &ack)))
1233 WLog_Print(gfx->log, WLOG_ERROR,
1234 "rdpgfx_send_frame_acknowledge_pdu failed with error %" PRIu32
"", error);
1237 switch (gfx->ConnectionCaps.version)
1239 case RDPGFX_CAPVERSION_10:
1240 case RDPGFX_CAPVERSION_102:
1241 case RDPGFX_CAPVERSION_103:
1242 case RDPGFX_CAPVERSION_104:
1243 case RDPGFX_CAPVERSION_105:
1244 case RDPGFX_CAPVERSION_106:
1245 case RDPGFX_CAPVERSION_106_ERR:
1246 case RDPGFX_CAPVERSION_107:
1250 UINT64 diff = (GetTickCount64() - gfx->StartDecodingTime);
1255 qoe.frameId = pdu.frameId;
1256 qoe.timestamp = gfx->StartDecodingTime % UINT32_MAX;
1257 qoe.timeDiffSE = diff;
1258 qoe.timeDiffEDR = EndFrameTime;
1260 if ((error = rdpgfx_send_qoe_frame_acknowledge_pdu(context, &qoe)))
1261 WLog_Print(gfx->log, WLOG_ERROR,
1262 "rdpgfx_send_qoe_frame_acknowledge_pdu failed with error %" PRIu32
1285 WINPR_ASSERT(callback);
1290 if (!Stream_CheckAndLogRequiredLength(TAG, s, RDPGFX_WIRE_TO_SURFACE_PDU_1_SIZE))
1291 return ERROR_INVALID_DATA;
1293 Stream_Read_UINT16(s, pdu.surfaceId);
1294 Stream_Read_UINT16(s, pdu.codecId);
1295 Stream_Read_UINT8(s, pdu.pixelFormat);
1297 if ((error = rdpgfx_read_rect16(s, &(pdu.destRect))))
1299 WLog_Print(gfx->log, WLOG_ERROR,
"rdpgfx_read_rect16 failed with error %" PRIu32
"", error);
1303 Stream_Read_UINT32(s, pdu.bitmapDataLength);
1305 if (!Stream_CheckAndLogRequiredLength(TAG, s, pdu.bitmapDataLength))
1306 return ERROR_INVALID_DATA;
1308 pdu.bitmapData = Stream_Pointer(s);
1309 Stream_Seek(s, pdu.bitmapDataLength);
1311 DEBUG_RDPGFX(gfx->log,
1312 "RecvWireToSurface1Pdu: surfaceId: %" PRIu16
" codecId: %s (0x%04" PRIX16
1313 ") pixelFormat: 0x%02" PRIX8
" "
1314 "destRect: left: %" PRIu16
" top: %" PRIu16
" right: %" PRIu16
" bottom: %" PRIu16
1315 " bitmapDataLength: %" PRIu32
"",
1316 pdu.surfaceId, rdpgfx_get_codec_id_string(pdu.codecId), pdu.codecId,
1317 pdu.pixelFormat, pdu.destRect.left, pdu.destRect.top, pdu.destRect.right,
1318 pdu.destRect.bottom, pdu.bitmapDataLength);
1319 cmd.surfaceId = pdu.surfaceId;
1320 cmd.codecId = pdu.codecId;
1323 switch (pdu.pixelFormat)
1325 case GFX_PIXEL_FORMAT_XRGB_8888:
1326 cmd.format = PIXEL_FORMAT_BGRX32;
1329 case GFX_PIXEL_FORMAT_ARGB_8888:
1330 cmd.format = PIXEL_FORMAT_BGRA32;
1334 return ERROR_INVALID_DATA;
1337 cmd.left = pdu.destRect.left;
1338 cmd.top = pdu.destRect.top;
1339 cmd.right = pdu.destRect.right;
1340 cmd.bottom = pdu.destRect.bottom;
1341 cmd.width = cmd.right - cmd.left;
1342 cmd.height = cmd.bottom - cmd.top;
1343 cmd.length = pdu.bitmapDataLength;
1344 cmd.data = pdu.bitmapData;
1347 if (cmd.right < cmd.left)
1349 WLog_Print(gfx->log, WLOG_ERROR,
"RecvWireToSurface1Pdu right=%" PRIu32
" < left=%" PRIu32,
1350 cmd.right, cmd.left);
1351 return ERROR_INVALID_DATA;
1353 if (cmd.bottom < cmd.top)
1355 WLog_Print(gfx->log, WLOG_ERROR,
"RecvWireToSurface1Pdu bottom=%" PRIu32
" < top=%" PRIu32,
1356 cmd.bottom, cmd.top);
1357 return ERROR_INVALID_DATA;
1360 if ((error = rdpgfx_decode(gfx, &cmd)))
1361 WLog_Print(gfx->log, WLOG_ERROR,
"rdpgfx_decode failed with error %" PRIu32
"!", error);
1375 WINPR_ASSERT(callback);
1378 RdpgfxClientContext* context = gfx->context;
1379 UINT error = CHANNEL_RC_OK;
1381 if (!Stream_CheckAndLogRequiredLength(TAG, s, RDPGFX_WIRE_TO_SURFACE_PDU_2_SIZE))
1382 return ERROR_INVALID_DATA;
1384 Stream_Read_UINT16(s, pdu.surfaceId);
1385 Stream_Read_UINT16(s, pdu.codecId);
1386 Stream_Read_UINT32(s, pdu.codecContextId);
1387 Stream_Read_UINT8(s, pdu.pixelFormat);
1388 Stream_Read_UINT32(s, pdu.bitmapDataLength);
1389 pdu.bitmapData = Stream_Pointer(s);
1390 Stream_Seek(s, pdu.bitmapDataLength);
1392 DEBUG_RDPGFX(gfx->log,
1393 "RecvWireToSurface2Pdu: surfaceId: %" PRIu16
" codecId: %s (0x%04" PRIX16
") "
1394 "codecContextId: %" PRIu32
" pixelFormat: 0x%02" PRIX8
1395 " bitmapDataLength: %" PRIu32
"",
1396 pdu.surfaceId, rdpgfx_get_codec_id_string(pdu.codecId), pdu.codecId,
1397 pdu.codecContextId, pdu.pixelFormat, pdu.bitmapDataLength);
1399 cmd.surfaceId = pdu.surfaceId;
1400 cmd.codecId = pdu.codecId;
1401 cmd.contextId = pdu.codecContextId;
1403 switch (pdu.pixelFormat)
1405 case GFX_PIXEL_FORMAT_XRGB_8888:
1406 cmd.format = PIXEL_FORMAT_BGRX32;
1409 case GFX_PIXEL_FORMAT_ARGB_8888:
1410 cmd.format = PIXEL_FORMAT_BGRA32;
1414 return ERROR_INVALID_DATA;
1423 cmd.length = pdu.bitmapDataLength;
1424 cmd.data = pdu.bitmapData;
1429 IFCALLRET(context->SurfaceCommand, error, context, &cmd);
1432 WLog_Print(gfx->log, WLOG_ERROR,
1433 "context->SurfaceCommand failed with error %" PRIu32
"", error);
1447 WINPR_ASSERT(callback);
1450 RdpgfxClientContext* context = gfx->context;
1451 UINT error = CHANNEL_RC_OK;
1453 if (!Stream_CheckAndLogRequiredLength(TAG, s, 6))
1454 return ERROR_INVALID_DATA;
1456 Stream_Read_UINT16(s, pdu.surfaceId);
1457 Stream_Read_UINT32(s, pdu.codecContextId);
1459 DEBUG_RDPGFX(gfx->log,
1460 "RecvDeleteEncodingContextPdu: surfaceId: %" PRIu16
" codecContextId: %" PRIu32
"",
1461 pdu.surfaceId, pdu.codecContextId);
1465 IFCALLRET(context->DeleteEncodingContext, error, context, &pdu);
1468 WLog_Print(gfx->log, WLOG_ERROR,
1469 "context->DeleteEncodingContext failed with error %" PRIu32
"", error);
1484 WINPR_ASSERT(callback);
1487 RdpgfxClientContext* context = gfx->context;
1490 if (!Stream_CheckAndLogRequiredLength(TAG, s, 8))
1491 return ERROR_INVALID_DATA;
1493 Stream_Read_UINT16(s, pdu.surfaceId);
1495 if ((error = rdpgfx_read_color32(s, &(pdu.fillPixel))))
1497 WLog_Print(gfx->log, WLOG_ERROR,
"rdpgfx_read_color32 failed with error %" PRIu32
"!",
1502 Stream_Read_UINT16(s, pdu.fillRectCount);
1504 if (!Stream_CheckAndLogRequiredLengthOfSize(TAG, s, pdu.fillRectCount, 8ull))
1505 return ERROR_INVALID_DATA;
1511 WLog_Print(gfx->log, WLOG_ERROR,
"calloc failed!");
1512 return CHANNEL_RC_NO_MEMORY;
1515 for (UINT16 index = 0; index < pdu.fillRectCount; index++)
1517 fillRect = &(pdu.fillRects[index]);
1519 if ((error = rdpgfx_read_rect16(s, fillRect)))
1521 WLog_Print(gfx->log, WLOG_ERROR,
"rdpgfx_read_rect16 failed with error %" PRIu32
"!",
1523 free(pdu.fillRects);
1527 DEBUG_RDPGFX(gfx->log,
"RecvSolidFillPdu: surfaceId: %" PRIu16
" fillRectCount: %" PRIu16
"",
1528 pdu.surfaceId, pdu.fillRectCount);
1532 IFCALLRET(context->SolidFill, error, context, &pdu);
1535 WLog_Print(gfx->log, WLOG_ERROR,
"context->SolidFill failed with error %" PRIu32
"",
1539 free(pdu.fillRects);
1552 WINPR_ASSERT(callback);
1555 RdpgfxClientContext* context = gfx->context;
1558 if (!Stream_CheckAndLogRequiredLength(TAG, s, 14))
1559 return ERROR_INVALID_DATA;
1561 Stream_Read_UINT16(s, pdu.surfaceIdSrc);
1562 Stream_Read_UINT16(s, pdu.surfaceIdDest);
1564 if ((error = rdpgfx_read_rect16(s, &(pdu.rectSrc))))
1566 WLog_Print(gfx->log, WLOG_ERROR,
"rdpgfx_read_rect16 failed with error %" PRIu32
"!",
1571 Stream_Read_UINT16(s, pdu.destPtsCount);
1573 if (!Stream_CheckAndLogRequiredLengthOfSize(TAG, s, pdu.destPtsCount, 4ull))
1574 return ERROR_INVALID_DATA;
1580 WLog_Print(gfx->log, WLOG_ERROR,
"calloc failed!");
1581 return CHANNEL_RC_NO_MEMORY;
1584 for (UINT16 index = 0; index < pdu.destPtsCount; index++)
1586 destPt = &(pdu.destPts[index]);
1588 if ((error = rdpgfx_read_point16(s, destPt)))
1590 WLog_Print(gfx->log, WLOG_ERROR,
"rdpgfx_read_point16 failed with error %" PRIu32
"!",
1597 DEBUG_RDPGFX(gfx->log,
1598 "RecvSurfaceToSurfacePdu: surfaceIdSrc: %" PRIu16
" surfaceIdDest: %" PRIu16
" "
1599 "left: %" PRIu16
" top: %" PRIu16
" right: %" PRIu16
" bottom: %" PRIu16
1600 " destPtsCount: %" PRIu16
"",
1601 pdu.surfaceIdSrc, pdu.surfaceIdDest, pdu.rectSrc.left, pdu.rectSrc.top,
1602 pdu.rectSrc.right, pdu.rectSrc.bottom, pdu.destPtsCount);
1606 IFCALLRET(context->SurfaceToSurface, error, context, &pdu);
1609 WLog_Print(gfx->log, WLOG_ERROR,
1610 "context->SurfaceToSurface failed with error %" PRIu32
"", error);
1625 WINPR_ASSERT(callback);
1629 RdpgfxClientContext* context = gfx->context;
1632 if (!Stream_CheckAndLogRequiredLength(TAG, s, 20))
1633 return ERROR_INVALID_DATA;
1635 Stream_Read_UINT16(s, pdu.surfaceId);
1636 Stream_Read_UINT64(s, pdu.cacheKey);
1637 Stream_Read_UINT16(s, pdu.cacheSlot);
1639 if ((error = rdpgfx_read_rect16(s, &(pdu.rectSrc))))
1641 WLog_Print(gfx->log, WLOG_ERROR,
"rdpgfx_read_rect16 failed with error %" PRIu32
"!",
1646 DEBUG_RDPGFX(gfx->log,
1647 "RecvSurfaceToCachePdu: surfaceId: %" PRIu16
" cacheKey: 0x%016" PRIX64
1648 " cacheSlot: %" PRIu16
" "
1649 "left: %" PRIu16
" top: %" PRIu16
" right: %" PRIu16
" bottom: %" PRIu16
"",
1650 pdu.surfaceId, pdu.cacheKey, pdu.cacheSlot, pdu.rectSrc.left, pdu.rectSrc.top,
1651 pdu.rectSrc.right, pdu.rectSrc.bottom);
1655 IFCALLRET(context->SurfaceToCache, error, context, &pdu);
1658 WLog_Print(gfx->log, WLOG_ERROR,
1659 "context->SurfaceToCache failed with error %" PRIu32
"", error);
1674 WINPR_ASSERT(callback);
1678 RdpgfxClientContext* context = gfx->context;
1679 UINT error = CHANNEL_RC_OK;
1681 if (!Stream_CheckAndLogRequiredLength(TAG, s, 6))
1682 return ERROR_INVALID_DATA;
1684 Stream_Read_UINT16(s, pdu.cacheSlot);
1685 Stream_Read_UINT16(s, pdu.surfaceId);
1686 Stream_Read_UINT16(s, pdu.destPtsCount);
1688 if (!Stream_CheckAndLogRequiredLengthOfSize(TAG, s, pdu.destPtsCount, 4ull))
1689 return ERROR_INVALID_DATA;
1695 WLog_Print(gfx->log, WLOG_ERROR,
"calloc failed!");
1696 return CHANNEL_RC_NO_MEMORY;
1699 for (UINT16 index = 0; index < pdu.destPtsCount; index++)
1701 destPt = &(pdu.destPts[index]);
1703 if ((error = rdpgfx_read_point16(s, destPt)))
1705 WLog_Print(gfx->log, WLOG_ERROR,
"rdpgfx_read_point16 failed with error %" PRIu32
"",
1712 DEBUG_RDPGFX(gfx->log,
1713 "RdpGfxRecvCacheToSurfacePdu: cacheSlot: %" PRIu16
" surfaceId: %" PRIu16
1714 " destPtsCount: %" PRIu16
"",
1715 pdu.cacheSlot, pdu.surfaceId, pdu.destPtsCount);
1719 IFCALLRET(context->CacheToSurface, error, context, &pdu);
1722 WLog_Print(gfx->log, WLOG_ERROR,
1723 "context->CacheToSurface failed with error %" PRIu32
"", error);
1738 WINPR_ASSERT(callback);
1742 RdpgfxClientContext* context = gfx->context;
1743 UINT error = CHANNEL_RC_OK;
1745 if (!Stream_CheckAndLogRequiredLength(TAG, s, 12))
1746 return ERROR_INVALID_DATA;
1748 Stream_Read_UINT16(s, pdu.surfaceId);
1749 Stream_Read_UINT16(s, pdu.reserved);
1750 Stream_Read_UINT32(s, pdu.outputOriginX);
1751 Stream_Read_UINT32(s, pdu.outputOriginY);
1752 DEBUG_RDPGFX(gfx->log,
1753 "RecvMapSurfaceToOutputPdu: surfaceId: %" PRIu16
" outputOriginX: %" PRIu32
1754 " outputOriginY: %" PRIu32
"",
1755 pdu.surfaceId, pdu.outputOriginX, pdu.outputOriginY);
1759 IFCALLRET(context->MapSurfaceToOutput, error, context, &pdu);
1762 WLog_Print(gfx->log, WLOG_ERROR,
1763 "context->MapSurfaceToOutput failed with error %" PRIu32
"", error);
1773 WINPR_ASSERT(callback);
1777 RdpgfxClientContext* context = gfx->context;
1778 UINT error = CHANNEL_RC_OK;
1780 if (!Stream_CheckAndLogRequiredLength(TAG, s, 20))
1781 return ERROR_INVALID_DATA;
1783 Stream_Read_UINT16(s, pdu.surfaceId);
1784 Stream_Read_UINT16(s, pdu.reserved);
1785 Stream_Read_UINT32(s, pdu.outputOriginX);
1786 Stream_Read_UINT32(s, pdu.outputOriginY);
1787 Stream_Read_UINT32(s, pdu.targetWidth);
1788 Stream_Read_UINT32(s, pdu.targetHeight);
1789 DEBUG_RDPGFX(gfx->log,
1790 "RecvMapSurfaceToScaledOutputPdu: surfaceId: %" PRIu16
" outputOriginX: %" PRIu32
1791 " outputOriginY: %" PRIu32
" targetWidth: %" PRIu32
" targetHeight: %" PRIu32,
1792 pdu.surfaceId, pdu.outputOriginX, pdu.outputOriginY, pdu.targetWidth,
1797 IFCALLRET(context->MapSurfaceToScaledOutput, error, context, &pdu);
1800 WLog_Print(gfx->log, WLOG_ERROR,
1801 "context->MapSurfaceToScaledOutput failed with error %" PRIu32
"", error);
1815 WINPR_ASSERT(callback);
1819 RdpgfxClientContext* context = gfx->context;
1820 UINT error = CHANNEL_RC_OK;
1822 if (!Stream_CheckAndLogRequiredLength(TAG, s, 18))
1823 return ERROR_INVALID_DATA;
1825 Stream_Read_UINT16(s, pdu.surfaceId);
1826 Stream_Read_UINT64(s, pdu.windowId);
1827 Stream_Read_UINT32(s, pdu.mappedWidth);
1828 Stream_Read_UINT32(s, pdu.mappedHeight);
1829 DEBUG_RDPGFX(gfx->log,
1830 "RecvMapSurfaceToWindowPdu: surfaceId: %" PRIu16
" windowId: 0x%016" PRIX64
1831 " mappedWidth: %" PRIu32
" mappedHeight: %" PRIu32
"",
1832 pdu.surfaceId, pdu.windowId, pdu.mappedWidth, pdu.mappedHeight);
1834 if (context && context->MapSurfaceToWindow)
1836 IFCALLRET(context->MapSurfaceToWindow, error, context, &pdu);
1839 WLog_Print(gfx->log, WLOG_ERROR,
1840 "context->MapSurfaceToWindow failed with error %" PRIu32
"", error);
1850 WINPR_ASSERT(callback);
1853 RdpgfxClientContext* context = gfx->context;
1854 UINT error = CHANNEL_RC_OK;
1856 if (!Stream_CheckAndLogRequiredLength(TAG, s, 26))
1857 return ERROR_INVALID_DATA;
1859 Stream_Read_UINT16(s, pdu.surfaceId);
1860 Stream_Read_UINT64(s, pdu.windowId);
1861 Stream_Read_UINT32(s, pdu.mappedWidth);
1862 Stream_Read_UINT32(s, pdu.mappedHeight);
1863 Stream_Read_UINT32(s, pdu.targetWidth);
1864 Stream_Read_UINT32(s, pdu.targetHeight);
1865 DEBUG_RDPGFX(gfx->log,
1866 "RecvMapSurfaceToScaledWindowPdu: surfaceId: %" PRIu16
" windowId: 0x%016" PRIX64
1867 " mappedWidth: %" PRIu32
" mappedHeight: %" PRIu32
" targetWidth: %" PRIu32
1868 " targetHeight: %" PRIu32
"",
1869 pdu.surfaceId, pdu.windowId, pdu.mappedWidth, pdu.mappedHeight, pdu.targetWidth,
1872 if (context && context->MapSurfaceToScaledWindow)
1874 IFCALLRET(context->MapSurfaceToScaledWindow, error, context, &pdu);
1877 WLog_Print(gfx->log, WLOG_ERROR,
1878 "context->MapSurfaceToScaledWindow failed with error %" PRIu32
"", error);
1894 WINPR_ASSERT(callback);
1896 const size_t beg = Stream_GetPosition(s);
1899 if ((error = rdpgfx_read_header(s, &header)))
1901 WLog_Print(gfx->log, WLOG_ERROR,
"rdpgfx_read_header failed with error %" PRIu32
"!",
1907 gfx->log,
"cmdId: %s (0x%04" PRIX16
") flags: 0x%04" PRIX16
" pduLength: %" PRIu32
"",
1908 rdpgfx_get_cmd_id_string(header.cmdId), header.cmdId, header.flags, header.pduLength);
1910 switch (header.cmdId)
1912 case RDPGFX_CMDID_WIRETOSURFACE_1:
1913 if ((error = rdpgfx_recv_wire_to_surface_1_pdu(callback, s)))
1914 WLog_Print(gfx->log, WLOG_ERROR,
1915 "rdpgfx_recv_wire_to_surface_1_pdu failed with error %" PRIu32
"!",
1920 case RDPGFX_CMDID_WIRETOSURFACE_2:
1921 if ((error = rdpgfx_recv_wire_to_surface_2_pdu(callback, s)))
1922 WLog_Print(gfx->log, WLOG_ERROR,
1923 "rdpgfx_recv_wire_to_surface_2_pdu failed with error %" PRIu32
"!",
1928 case RDPGFX_CMDID_DELETEENCODINGCONTEXT:
1929 if ((error = rdpgfx_recv_delete_encoding_context_pdu(callback, s)))
1930 WLog_Print(gfx->log, WLOG_ERROR,
1931 "rdpgfx_recv_delete_encoding_context_pdu failed with error %" PRIu32
"!",
1936 case RDPGFX_CMDID_SOLIDFILL:
1937 if ((error = rdpgfx_recv_solid_fill_pdu(callback, s)))
1938 WLog_Print(gfx->log, WLOG_ERROR,
1939 "rdpgfx_recv_solid_fill_pdu failed with error %" PRIu32
"!", error);
1943 case RDPGFX_CMDID_SURFACETOSURFACE:
1944 if ((error = rdpgfx_recv_surface_to_surface_pdu(callback, s)))
1945 WLog_Print(gfx->log, WLOG_ERROR,
1946 "rdpgfx_recv_surface_to_surface_pdu failed with error %" PRIu32
"!",
1951 case RDPGFX_CMDID_SURFACETOCACHE:
1952 if ((error = rdpgfx_recv_surface_to_cache_pdu(callback, s)))
1953 WLog_Print(gfx->log, WLOG_ERROR,
1954 "rdpgfx_recv_surface_to_cache_pdu failed with error %" PRIu32
"!",
1959 case RDPGFX_CMDID_CACHETOSURFACE:
1960 if ((error = rdpgfx_recv_cache_to_surface_pdu(callback, s)))
1961 WLog_Print(gfx->log, WLOG_ERROR,
1962 "rdpgfx_recv_cache_to_surface_pdu failed with error %" PRIu32
"!",
1967 case RDPGFX_CMDID_EVICTCACHEENTRY:
1968 if ((error = rdpgfx_recv_evict_cache_entry_pdu(callback, s)))
1969 WLog_Print(gfx->log, WLOG_ERROR,
1970 "rdpgfx_recv_evict_cache_entry_pdu failed with error %" PRIu32
"!",
1975 case RDPGFX_CMDID_CREATESURFACE:
1976 if ((error = rdpgfx_recv_create_surface_pdu(callback, s)))
1977 WLog_Print(gfx->log, WLOG_ERROR,
1978 "rdpgfx_recv_create_surface_pdu failed with error %" PRIu32
"!", error);
1982 case RDPGFX_CMDID_DELETESURFACE:
1983 if ((error = rdpgfx_recv_delete_surface_pdu(callback, s)))
1984 WLog_Print(gfx->log, WLOG_ERROR,
1985 "rdpgfx_recv_delete_surface_pdu failed with error %" PRIu32
"!", error);
1989 case RDPGFX_CMDID_STARTFRAME:
1990 if ((error = rdpgfx_recv_start_frame_pdu(callback, s)))
1991 WLog_Print(gfx->log, WLOG_ERROR,
1992 "rdpgfx_recv_start_frame_pdu failed with error %" PRIu32
"!", error);
1996 case RDPGFX_CMDID_ENDFRAME:
1997 if ((error = rdpgfx_recv_end_frame_pdu(callback, s)))
1998 WLog_Print(gfx->log, WLOG_ERROR,
1999 "rdpgfx_recv_end_frame_pdu failed with error %" PRIu32
"!", error);
2003 case RDPGFX_CMDID_RESETGRAPHICS:
2004 if ((error = rdpgfx_recv_reset_graphics_pdu(callback, s)))
2005 WLog_Print(gfx->log, WLOG_ERROR,
2006 "rdpgfx_recv_reset_graphics_pdu failed with error %" PRIu32
"!", error);
2010 case RDPGFX_CMDID_MAPSURFACETOOUTPUT:
2011 if ((error = rdpgfx_recv_map_surface_to_output_pdu(callback, s)))
2012 WLog_Print(gfx->log, WLOG_ERROR,
2013 "rdpgfx_recv_map_surface_to_output_pdu failed with error %" PRIu32
"!",
2018 case RDPGFX_CMDID_CACHEIMPORTREPLY:
2019 if ((error = rdpgfx_recv_cache_import_reply_pdu(callback, s)))
2020 WLog_Print(gfx->log, WLOG_ERROR,
2021 "rdpgfx_recv_cache_import_reply_pdu failed with error %" PRIu32
"!",
2026 case RDPGFX_CMDID_CAPSCONFIRM:
2027 if ((error = rdpgfx_recv_caps_confirm_pdu(callback, s)))
2028 WLog_Print(gfx->log, WLOG_ERROR,
2029 "rdpgfx_recv_caps_confirm_pdu failed with error %" PRIu32
"!", error);
2031 if ((error = rdpgfx_send_cache_offer(gfx)))
2032 WLog_Print(gfx->log, WLOG_ERROR,
2033 "rdpgfx_send_cache_offer failed with error %" PRIu32
"!", error);
2037 case RDPGFX_CMDID_MAPSURFACETOWINDOW:
2038 if ((error = rdpgfx_recv_map_surface_to_window_pdu(callback, s)))
2039 WLog_Print(gfx->log, WLOG_ERROR,
2040 "rdpgfx_recv_map_surface_to_window_pdu failed with error %" PRIu32
"!",
2045 case RDPGFX_CMDID_MAPSURFACETOSCALEDWINDOW:
2046 if ((error = rdpgfx_recv_map_surface_to_scaled_window_pdu(callback, s)))
2047 WLog_Print(gfx->log, WLOG_ERROR,
2048 "rdpgfx_recv_map_surface_to_scaled_window_pdu failed with error %" PRIu32
2054 case RDPGFX_CMDID_MAPSURFACETOSCALEDOUTPUT:
2055 if ((error = rdpgfx_recv_map_surface_to_scaled_output_pdu(callback, s)))
2056 WLog_Print(gfx->log, WLOG_ERROR,
2057 "rdpgfx_recv_map_surface_to_scaled_output_pdu failed with error %" PRIu32
2064 error = CHANNEL_RC_BAD_PROC;
2070 WLog_Print(gfx->log, WLOG_ERROR,
"Error while processing GFX cmdId: %s (0x%04" PRIX16
")",
2071 rdpgfx_get_cmd_id_string(header.cmdId), header.cmdId);
2072 Stream_SetPosition(s, (beg + header.pduLength));
2076 end = Stream_GetPosition(s);
2078 if (end != (beg + header.pduLength))
2080 WLog_Print(gfx->log, WLOG_ERROR,
2081 "Unexpected gfx pdu end: Actual: %" PRIuz
", Expected: %" PRIuz, end,
2082 (beg + header.pduLength));
2083 Stream_SetPosition(s, (beg + header.pduLength));
2094 static UINT rdpgfx_on_data_received(IWTSVirtualChannelCallback* pChannelCallback,
wStream* data)
2098 BYTE* pDstData = NULL;
2100 WINPR_ASSERT(callback);
2102 UINT error = CHANNEL_RC_OK;
2105 status = zgfx_decompress(gfx->zgfx, Stream_ConstPointer(data),
2106 (UINT32)Stream_GetRemainingLength(data), &pDstData, &DstSize, 0);
2110 WLog_Print(gfx->log, WLOG_ERROR,
"zgfx_decompress failure! status: %d", status);
2112 return ERROR_INTERNAL_ERROR;
2116 wStream* s = Stream_StaticConstInit(&sbuffer, pDstData, DstSize);
2120 WLog_Print(gfx->log, WLOG_ERROR,
"calloc failed!");
2122 return CHANNEL_RC_NO_MEMORY;
2125 while (Stream_GetPosition(s) < Stream_Length(s))
2127 if ((error = rdpgfx_recv_pdu(callback, s)))
2129 WLog_Print(gfx->log, WLOG_ERROR,
"rdpgfx_recv_pdu failed with error %" PRIu32
"!",
2144 static UINT rdpgfx_on_open(IWTSVirtualChannelCallback* pChannelCallback)
2147 WINPR_ASSERT(callback);
2150 RdpgfxClientContext* context = gfx->context;
2151 UINT error = CHANNEL_RC_OK;
2152 BOOL do_caps_advertise = TRUE;
2153 gfx->sendFrameAcks = TRUE;
2157 IFCALLRET(context->OnOpen, error, context, &do_caps_advertise, &gfx->sendFrameAcks);
2160 WLog_Print(gfx->log, WLOG_ERROR,
"context->OnOpen failed with error %" PRIu32
"",
2164 if (do_caps_advertise)
2165 error = rdpgfx_send_supported_caps(callback);
2175 static UINT rdpgfx_on_close(IWTSVirtualChannelCallback* pChannelCallback)
2177 UINT error = CHANNEL_RC_OK;
2179 WINPR_ASSERT(callback);
2185 RdpgfxClientContext* context = gfx->context;
2187 DEBUG_RDPGFX(gfx->log,
"OnClose");
2188 error = rdpgfx_save_persistent_cache(gfx);
2193 WLog_Print(gfx->log, WLOG_ERROR,
2194 "rdpgfx_save_persistent_cache failed with error %" PRIu32
"", error);
2197 free_surfaces(context, gfx->SurfaceTable);
2198 evict_cache_slots(context, gfx->MaxCacheSlots, gfx->CacheSlots);
2201 gfx->UnacknowledgedFrames = 0;
2202 gfx->TotalDecodedFrames = 0;
2206 IFCALL(context->OnClose, context);
2210 return CHANNEL_RC_OK;
2217 RdpgfxClientContext* context = gfx->context;
2219 DEBUG_RDPGFX(gfx->log,
"Terminated");
2220 rdpgfx_client_context_free(context);
2228 static UINT rdpgfx_set_surface_data(RdpgfxClientContext* context, UINT16 surfaceId,
void* pData)
2231 WINPR_ASSERT(context);
2234 key = ((ULONG_PTR)surfaceId) + 1;
2238 if (!HashTable_Insert(gfx->SurfaceTable, (
void*)key, pData))
2239 return ERROR_BAD_ARGUMENTS;
2242 HashTable_Remove(gfx->SurfaceTable, (
void*)key);
2244 return CHANNEL_RC_OK;
2252 static UINT rdpgfx_get_surface_ids(RdpgfxClientContext* context, UINT16** ppSurfaceIds,
2256 UINT16* pSurfaceIds = NULL;
2257 ULONG_PTR* pKeys = NULL;
2258 WINPR_ASSERT(context);
2261 count = HashTable_GetKeys(gfx->SurfaceTable, &pKeys);
2263 WINPR_ASSERT(ppSurfaceIds);
2264 WINPR_ASSERT(count_out);
2268 return CHANNEL_RC_OK;
2271 pSurfaceIds = (UINT16*)calloc(count,
sizeof(UINT16));
2275 WLog_Print(gfx->log, WLOG_ERROR,
"calloc failed!");
2277 return CHANNEL_RC_NO_MEMORY;
2280 for (
size_t index = 0; index < count; index++)
2282 pSurfaceIds[index] = (UINT16)(pKeys[index] - 1);
2286 *ppSurfaceIds = pSurfaceIds;
2287 *count_out = (UINT16)count;
2288 return CHANNEL_RC_OK;
2291 static void* rdpgfx_get_surface_data(RdpgfxClientContext* context, UINT16 surfaceId)
2295 WINPR_ASSERT(context);
2298 key = ((ULONG_PTR)surfaceId) + 1;
2299 pData = HashTable_GetItemValue(gfx->SurfaceTable, (
void*)key);
2308 static UINT rdpgfx_set_cache_slot_data(RdpgfxClientContext* context, UINT16 cacheSlot,
void* pData)
2310 WINPR_ASSERT(context);
2315 if (cacheSlot == 0 || cacheSlot > gfx->MaxCacheSlots)
2317 WLog_ERR(TAG,
"invalid cache slot %" PRIu16
", must be between 1 and %" PRIu16
"",
2318 cacheSlot, gfx->MaxCacheSlots);
2319 return ERROR_INVALID_INDEX;
2322 gfx->CacheSlots[cacheSlot - 1] = pData;
2323 return CHANNEL_RC_OK;
2326 static void* rdpgfx_get_cache_slot_data(RdpgfxClientContext* context, UINT16 cacheSlot)
2329 WINPR_ASSERT(context);
2333 if (cacheSlot == 0 || cacheSlot > gfx->MaxCacheSlots)
2335 WLog_ERR(TAG,
"invalid cache slot %" PRIu16
", must be between 1 and %" PRIu16
"",
2336 cacheSlot, gfx->MaxCacheSlots);
2340 pData = gfx->CacheSlots[cacheSlot - 1];
2344 static UINT init_plugin_cb(
GENERIC_DYNVC_PLUGIN* base, rdpContext* rcontext, rdpSettings* settings)
2346 RdpgfxClientContext* context = NULL;
2350 gfx->rdpcontext = rcontext;
2351 gfx->log = WLog_Get(TAG);
2353 gfx->SurfaceTable = HashTable_New(TRUE);
2354 if (!gfx->SurfaceTable)
2356 WLog_ERR(TAG,
"HashTable_New for surfaces failed !");
2357 return CHANNEL_RC_NO_MEMORY;
2360 gfx->suspendFrameAcks =
2362 gfx->MaxCacheSlots =
2365 context = (RdpgfxClientContext*)calloc(1,
sizeof(RdpgfxClientContext));
2368 WLog_ERR(TAG,
"context calloc failed!");
2369 HashTable_Free(gfx->SurfaceTable);
2370 gfx->SurfaceTable = NULL;
2371 return CHANNEL_RC_NO_MEMORY;
2374 gfx->zgfx = zgfx_context_new(FALSE);
2377 WLog_ERR(TAG,
"zgfx_context_new failed!");
2378 HashTable_Free(gfx->SurfaceTable);
2379 gfx->SurfaceTable = NULL;
2381 return CHANNEL_RC_NO_MEMORY;
2384 context->handle = (
void*)gfx;
2385 context->GetSurfaceIds = rdpgfx_get_surface_ids;
2386 context->SetSurfaceData = rdpgfx_set_surface_data;
2387 context->GetSurfaceData = rdpgfx_get_surface_data;
2388 context->SetCacheSlotData = rdpgfx_set_cache_slot_data;
2389 context->GetCacheSlotData = rdpgfx_get_cache_slot_data;
2390 context->CapsAdvertise = rdpgfx_send_caps_advertise_pdu;
2391 context->FrameAcknowledge = rdpgfx_send_frame_acknowledge_pdu;
2392 context->CacheImportOffer = rdpgfx_send_cache_import_offer_pdu;
2393 context->QoeFrameAcknowledge = rdpgfx_send_qoe_frame_acknowledge_pdu;
2395 gfx->base.iface.pInterface = (
void*)context;
2396 gfx->context = context;
2397 return CHANNEL_RC_OK;
2400 void rdpgfx_client_context_free(RdpgfxClientContext* context)
2410 free_surfaces(context, gfx->SurfaceTable);
2411 evict_cache_slots(context, gfx->MaxCacheSlots, gfx->CacheSlots);
2415 zgfx_context_free(gfx->zgfx);
2419 HashTable_Free(gfx->SurfaceTable);
2423 static const IWTSVirtualChannelCallback rdpgfx_callbacks = { rdpgfx_on_data_received,
2424 rdpgfx_on_open, rdpgfx_on_close,
2432 FREERDP_ENTRY_POINT(UINT VCAPITYPE rdpgfx_DVCPluginEntry(IDRDYNVC_ENTRY_POINTS* pEntryPoints))
2434 return freerdp_generic_DVCPluginEntry(pEntryPoints, TAG, RDPGFX_DVC_CHANNEL_NAME,
2436 &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.