24#include <freerdp/config.h>
26#include <winpr/assert.h>
27#include <winpr/cast.h>
30#include <winpr/wlog.h>
31#include <winpr/print.h>
32#include <winpr/synch.h>
33#include <winpr/thread.h>
34#include <winpr/stream.h>
35#include <winpr/sysinfo.h>
36#include <winpr/cmdline.h>
37#include <winpr/collections.h>
39#include <freerdp/addin.h>
40#include <freerdp/channels/log.h>
42#include "rdpgfx_common.h"
43#include "rdpgfx_codec.h"
45#include "rdpgfx_main.h"
47#define TAG CHANNELS_TAG("rdpgfx.client")
49static 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);
71static void free_surfaces(RdpgfxClientContext* context, wHashTable* SurfaceTable)
73 HashTable_Foreach(SurfaceTable, delete_surface, context);
76static UINT evict_cache_slots(RdpgfxClientContext* context, UINT16 MaxCacheSlots,
void** CacheSlots)
78 UINT error = CHANNEL_RC_OK;
80 WINPR_ASSERT(CacheSlots);
81 for (UINT16 index = 0; index < MaxCacheSlots; index++)
83 if (CacheSlots[index])
86 pdu.cacheSlot = index + 1;
88 if (context && context->EvictCacheEntry)
90 const UINT rc = context->EvictCacheEntry(context, &pdu);
91 if (rc != CHANNEL_RC_OK)
95 CacheSlots[index] = NULL;
106static UINT rdpgfx_send_caps_advertise_pdu(RdpgfxClientContext* context,
109 UINT error = CHANNEL_RC_OK;
116 WINPR_ASSERT(context);
120 if (!gfx || !gfx->base.listener_callback)
121 return ERROR_BAD_ARGUMENTS;
123 callback = gfx->base.listener_callback->channel_callback;
126 header.cmdId = RDPGFX_CMDID_CAPSADVERTISE;
127 header.pduLength = RDPGFX_HEADER_SIZE + 2;
129 for (UINT16 index = 0; index < pdu->capsSetCount; index++)
132 header.pduLength += RDPGFX_CAPSET_BASE_SIZE + capsSet->length;
135 DEBUG_RDPGFX(gfx->log,
"SendCapsAdvertisePdu %" PRIu16
"", pdu->capsSetCount);
136 s = Stream_New(NULL, header.pduLength);
140 WLog_ERR(TAG,
"Stream_New failed!");
141 return CHANNEL_RC_NO_MEMORY;
144 if ((error = rdpgfx_write_header(s, &header)))
148 Stream_Write_UINT16(s, pdu->capsSetCount);
150 for (UINT16 index = 0; index < pdu->capsSetCount; index++)
154 DEBUG_RDPGFX(gfx->log,
"Sending %s [0x%08" PRIx32
"] flags=0x%08" PRIx32,
155 rdpgfx_caps_version_str(capsSet->version), capsSet->version, capsSet->flags);
157 Stream_Write_UINT32(s, capsSet->version);
158 Stream_Write_UINT32(s, capsSet->length);
159 Stream_Write_UINT32(s, capsSet->flags);
160 Stream_Zero(s, capsSet->length - 4);
163 Stream_SealLength(s);
164 error = callback->channel->Write(callback->channel, (UINT32)Stream_Length(s), Stream_Buffer(s),
167 Stream_Free(s, TRUE);
171static BOOL rdpgfx_is_capability_filtered(
RDPGFX_PLUGIN* gfx, UINT32 caps)
174 const UINT32 filter =
176 const UINT32 capList[] = { RDPGFX_CAPVERSION_8, RDPGFX_CAPVERSION_81,
177 RDPGFX_CAPVERSION_10, RDPGFX_CAPVERSION_101,
178 RDPGFX_CAPVERSION_102, RDPGFX_CAPVERSION_103,
179 RDPGFX_CAPVERSION_104, RDPGFX_CAPVERSION_105,
180 RDPGFX_CAPVERSION_106, RDPGFX_CAPVERSION_106_ERR,
181 RDPGFX_CAPVERSION_107 };
183 for (
size_t x = 0; x < ARRAYSIZE(capList); x++)
185 if (caps == capList[x])
186 return (filter & (1 << x)) != 0;
200 RdpgfxClientContext* context = NULL;
206 return ERROR_BAD_ARGUMENTS;
211 return ERROR_BAD_CONFIGURATION;
213 context = gfx->context;
216 return ERROR_BAD_CONFIGURATION;
218 pdu.capsSetCount = 0;
221 if (!rdpgfx_is_capability_filtered(gfx, RDPGFX_CAPVERSION_8))
223 capsSet = &capsSets[pdu.capsSetCount++];
224 capsSet->version = RDPGFX_CAPVERSION_8;
229 capsSet->flags |= RDPGFX_CAPS_FLAG_THINCLIENT;
236 capsSet->flags |= RDPGFX_CAPS_FLAG_SMALL_CACHE;
239 if (!rdpgfx_is_capability_filtered(gfx, RDPGFX_CAPVERSION_81))
241 capsSet = &capsSets[pdu.capsSetCount++];
242 capsSet->version = RDPGFX_CAPVERSION_81;
247 capsSet->flags |= RDPGFX_CAPS_FLAG_THINCLIENT;
250 capsSet->flags |= RDPGFX_CAPS_FLAG_SMALL_CACHE;
255 capsSet->flags |= RDPGFX_CAPS_FLAG_AVC420_ENABLED;
263 UINT32 caps10Flags = 0;
266 caps10Flags |= RDPGFX_CAPS_FLAG_SMALL_CACHE;
271 caps10Flags |= RDPGFX_CAPS_FLAG_AVC_DISABLED;
274 caps10Flags |= RDPGFX_CAPS_FLAG_AVC_DISABLED;
277 if (!rdpgfx_is_capability_filtered(gfx, RDPGFX_CAPVERSION_10))
279 capsSet = &capsSets[pdu.capsSetCount++];
280 capsSet->version = RDPGFX_CAPVERSION_10;
282 capsSet->flags = caps10Flags;
285 if (!rdpgfx_is_capability_filtered(gfx, RDPGFX_CAPVERSION_101))
287 capsSet = &capsSets[pdu.capsSetCount++];
288 capsSet->version = RDPGFX_CAPVERSION_101;
289 capsSet->length = 0x10;
293 if (!rdpgfx_is_capability_filtered(gfx, RDPGFX_CAPVERSION_102))
295 capsSet = &capsSets[pdu.capsSetCount++];
296 capsSet->version = RDPGFX_CAPVERSION_102;
297 capsSet->length = 0x4;
298 capsSet->flags = caps10Flags;
303 if ((caps10Flags & RDPGFX_CAPS_FLAG_AVC_DISABLED) == 0)
304 caps10Flags |= RDPGFX_CAPS_FLAG_AVC_THINCLIENT;
307 if (!rdpgfx_is_capability_filtered(gfx, RDPGFX_CAPVERSION_103))
309 capsSet = &capsSets[pdu.capsSetCount++];
310 capsSet->version = RDPGFX_CAPVERSION_103;
311 capsSet->length = 0x4;
312 capsSet->flags = caps10Flags & ~RDPGFX_CAPS_FLAG_SMALL_CACHE;
315 if (!rdpgfx_is_capability_filtered(gfx, RDPGFX_CAPVERSION_104))
317 capsSet = &capsSets[pdu.capsSetCount++];
318 capsSet->version = RDPGFX_CAPVERSION_104;
319 capsSet->length = 0x4;
320 capsSet->flags = caps10Flags;
326#if defined(WITH_CAIRO) || defined(WITH_SWSCALE)
327 if (!rdpgfx_is_capability_filtered(gfx, RDPGFX_CAPVERSION_105))
329 capsSet = &capsSets[pdu.capsSetCount++];
330 capsSet->version = RDPGFX_CAPVERSION_105;
331 capsSet->length = 0x4;
332 capsSet->flags = caps10Flags;
335 if (!rdpgfx_is_capability_filtered(gfx, RDPGFX_CAPVERSION_106))
337 capsSet = &capsSets[pdu.capsSetCount++];
338 capsSet->version = RDPGFX_CAPVERSION_106;
339 capsSet->length = 0x4;
340 capsSet->flags = caps10Flags;
343 if (!rdpgfx_is_capability_filtered(gfx, RDPGFX_CAPVERSION_106_ERR))
345 capsSet = &capsSets[pdu.capsSetCount++];
346 capsSet->version = RDPGFX_CAPVERSION_106_ERR;
347 capsSet->length = 0x4;
348 capsSet->flags = caps10Flags;
352 if (!rdpgfx_is_capability_filtered(gfx, RDPGFX_CAPVERSION_107))
354 capsSet = &capsSets[pdu.capsSetCount++];
355 capsSet->version = RDPGFX_CAPVERSION_107;
356 capsSet->length = 0x4;
357 capsSet->flags = caps10Flags;
358#if !defined(WITH_CAIRO) && !defined(WITH_SWSCALE)
359 capsSet->flags |= RDPGFX_CAPS_FLAG_SCALEDMAP_DISABLE;
364 return IFCALLRESULT(ERROR_BAD_CONFIGURATION, context->CapsAdvertise, context, &pdu);
376 WINPR_ASSERT(callback);
380 RdpgfxClientContext* context = gfx->context;
382 pdu.capsSet = &capsSet;
384 if (!Stream_CheckAndLogRequiredLength(TAG, s, 12))
385 return ERROR_INVALID_DATA;
387 Stream_Read_UINT32(s, capsSet.version);
388 Stream_Read_UINT32(s, capsSet.length);
389 Stream_Read_UINT32(s, capsSet.flags);
390 gfx->TotalDecodedFrames = 0;
391 gfx->ConnectionCaps = capsSet;
392 WLog_Print(gfx->log, WLOG_DEBUG,
393 "RecvCapsConfirmPdu: version: %s [0x%08" PRIX32
"] flags: 0x%08" PRIX32
"",
394 rdpgfx_caps_version_str(capsSet.version), capsSet.version, capsSet.flags);
397 return ERROR_BAD_CONFIGURATION;
399 return IFCALLRESULT(CHANNEL_RC_OK, context->CapsConfirm, context, &pdu);
407static UINT rdpgfx_send_frame_acknowledge_pdu(RdpgfxClientContext* context,
416 if (!context || !pdu)
417 return ERROR_BAD_ARGUMENTS;
421 if (!gfx || !gfx->base.listener_callback)
422 return ERROR_BAD_CONFIGURATION;
424 callback = gfx->base.listener_callback->channel_callback;
427 return ERROR_BAD_CONFIGURATION;
430 header.cmdId = RDPGFX_CMDID_FRAMEACKNOWLEDGE;
431 header.pduLength = RDPGFX_HEADER_SIZE + 12;
432 DEBUG_RDPGFX(gfx->log,
"SendFrameAcknowledgePdu: %" PRIu32
"", pdu->frameId);
433 s = Stream_New(NULL, header.pduLength);
437 WLog_ERR(TAG,
"Stream_New failed!");
438 return CHANNEL_RC_NO_MEMORY;
441 if ((error = rdpgfx_write_header(s, &header)))
445 Stream_Write_UINT32(s, pdu->queueDepth);
446 Stream_Write_UINT32(s, pdu->frameId);
447 Stream_Write_UINT32(s, pdu->totalFramesDecoded);
448 error = callback->channel->Write(callback->channel, (UINT32)Stream_Length(s), Stream_Buffer(s),
451 if (error == CHANNEL_RC_OK)
452 gfx->UnacknowledgedFrames--;
455 Stream_Free(s, TRUE);
459static UINT rdpgfx_send_qoe_frame_acknowledge_pdu(RdpgfxClientContext* context,
469 header.cmdId = RDPGFX_CMDID_QOEFRAMEACKNOWLEDGE;
470 header.pduLength = RDPGFX_HEADER_SIZE + 12;
472 if (!context || !pdu)
473 return ERROR_BAD_ARGUMENTS;
477 if (!gfx || !gfx->base.listener_callback)
478 return ERROR_BAD_CONFIGURATION;
480 callback = gfx->base.listener_callback->channel_callback;
483 return ERROR_BAD_CONFIGURATION;
485 DEBUG_RDPGFX(gfx->log,
"SendQoeFrameAcknowledgePdu: %" PRIu32
"", pdu->frameId);
486 s = Stream_New(NULL, header.pduLength);
490 WLog_ERR(TAG,
"Stream_New failed!");
491 return CHANNEL_RC_NO_MEMORY;
494 if ((error = rdpgfx_write_header(s, &header)))
498 Stream_Write_UINT32(s, pdu->frameId);
499 Stream_Write_UINT32(s, pdu->timestamp);
500 Stream_Write_UINT16(s, pdu->timeDiffSE);
501 Stream_Write_UINT16(s, pdu->timeDiffEDR);
502 error = callback->channel->Write(callback->channel, (UINT32)Stream_Length(s), Stream_Buffer(s),
505 Stream_Free(s, TRUE);
517 WINPR_ASSERT(callback);
523 RdpgfxClientContext* context = gfx->context;
524 UINT error = CHANNEL_RC_OK;
525 GraphicsResetEventArgs graphicsReset = { 0 };
527 if (!Stream_CheckAndLogRequiredLength(TAG, s, 12))
528 return ERROR_INVALID_DATA;
530 Stream_Read_UINT32(s, pdu.width);
531 Stream_Read_UINT32(s, pdu.height);
532 Stream_Read_UINT32(s, pdu.monitorCount);
534 if (!Stream_CheckAndLogRequiredLengthOfSize(TAG, s, pdu.monitorCount, 20ull))
535 return ERROR_INVALID_DATA;
539 if (!pdu.monitorDefArray)
541 WLog_Print(gfx->log, WLOG_ERROR,
"calloc failed!");
542 return CHANNEL_RC_NO_MEMORY;
545 for (UINT32 index = 0; index < pdu.monitorCount; index++)
547 MONITOR_DEF* monitor = &(pdu.monitorDefArray[index]);
548 Stream_Read_INT32(s, monitor->left);
549 Stream_Read_INT32(s, monitor->top);
550 Stream_Read_INT32(s, monitor->right);
551 Stream_Read_INT32(s, monitor->bottom);
552 Stream_Read_UINT32(s, monitor->flags);
555 const size_t size = (RDPGFX_HEADER_SIZE + 12ULL + (pdu.monitorCount * 20ULL));
558 free(pdu.monitorDefArray);
559 return CHANNEL_RC_NULL_DATA;
561 const size_t pad = 340ULL - size;
563 if (!Stream_CheckAndLogRequiredLength(TAG, s, (
size_t)pad))
565 free(pdu.monitorDefArray);
566 return CHANNEL_RC_NO_MEMORY;
570 WLog_Print(gfx->log, WLOG_DEBUG,
571 "RecvResetGraphicsPdu: width: %" PRIu32
" height: %" PRIu32
" count: %" PRIu32
"",
572 pdu.width, pdu.height, pdu.monitorCount);
574#if defined(WITH_DEBUG_RDPGFX)
575 for (UINT32 index = 0; index < pdu.monitorCount; index++)
577 MONITOR_DEF* monitor = &(pdu.monitorDefArray[index]);
578 DEBUG_RDPGFX(gfx->log,
579 "RecvResetGraphicsPdu: monitor left:%" PRIi32
" top:%" PRIi32
" right:%" PRIi32
580 " bottom:%" PRIi32
" flags:0x%" PRIx32
"",
581 monitor->left, monitor->top, monitor->right, monitor->bottom, monitor->flags);
587 IFCALLRET(context->ResetGraphics, error, context, &pdu);
590 WLog_Print(gfx->log, WLOG_ERROR,
"context->ResetGraphics failed with error %" PRIu32
"",
595 EventArgsInit(&graphicsReset,
"libfreerdp");
596 graphicsReset.width = pdu.width;
597 graphicsReset.height = pdu.height;
598 PubSub_OnGraphicsReset(gfx->rdpcontext->pubSub, gfx->rdpcontext, &graphicsReset);
599 free(pdu.monitorDefArray);
611 WINPR_ASSERT(callback);
614 RdpgfxClientContext* context = gfx->context;
615 UINT error = CHANNEL_RC_OK;
617 if (!Stream_CheckAndLogRequiredLength(TAG, s, 2))
618 return ERROR_INVALID_DATA;
620 Stream_Read_UINT16(s, pdu.cacheSlot);
621 WLog_Print(gfx->log, WLOG_DEBUG,
"RecvEvictCacheEntryPdu: cacheSlot: %" PRIu16
"",
626 IFCALLRET(context->EvictCacheEntry, error, context, &pdu);
629 WLog_Print(gfx->log, WLOG_ERROR,
630 "context->EvictCacheEntry failed with error %" PRIu32
"", error);
643 UINT error = CHANNEL_RC_OK;
645 rdpPersistentCache* persistent = NULL;
647 WINPR_ASSERT(gfx->rdpcontext);
648 rdpSettings* settings = gfx->rdpcontext->settings;
649 RdpgfxClientContext* context = gfx->context;
651 WINPR_ASSERT(context);
652 WINPR_ASSERT(settings);
655 return CHANNEL_RC_OK;
657 const char* BitmapCachePersistFile =
659 if (!BitmapCachePersistFile)
660 return CHANNEL_RC_OK;
662 if (!context->ExportCacheEntry)
663 return CHANNEL_RC_INITIALIZATION_ERROR;
665 persistent = persistent_cache_new();
668 return CHANNEL_RC_NO_MEMORY;
670 if (persistent_cache_open(persistent, BitmapCachePersistFile, TRUE, 3) < 1)
672 error = CHANNEL_RC_INITIALIZATION_ERROR;
676 for (UINT16 idx = 0; idx < gfx->MaxCacheSlots; idx++)
678 if (gfx->CacheSlots[idx])
680 UINT16 cacheSlot = idx;
682 if (context->ExportCacheEntry(context, cacheSlot, &cacheEntry) != CHANNEL_RC_OK)
685 if (persistent_cache_write_entry(persistent, &cacheEntry) < 0)
690 persistent_cache_free(persistent);
694 persistent_cache_free(persistent);
703static UINT rdpgfx_send_cache_import_offer_pdu(RdpgfxClientContext* context,
706 UINT error = CHANNEL_RC_OK;
711 if (!context || !pdu)
712 return ERROR_BAD_ARGUMENTS;
716 if (!gfx || !gfx->base.listener_callback)
717 return ERROR_BAD_CONFIGURATION;
719 callback = gfx->base.listener_callback->channel_callback;
722 return ERROR_BAD_CONFIGURATION;
725 header.cmdId = RDPGFX_CMDID_CACHEIMPORTOFFER;
726 header.pduLength = RDPGFX_HEADER_SIZE + 2ul + pdu->cacheEntriesCount * 12ul;
727 WLog_Print(gfx->log, WLOG_DEBUG,
"SendCacheImportOfferPdu: cacheEntriesCount: %" PRIu16
"",
728 pdu->cacheEntriesCount);
729 s = Stream_New(NULL, header.pduLength);
733 WLog_ERR(TAG,
"Stream_New failed!");
734 return CHANNEL_RC_NO_MEMORY;
737 if ((error = rdpgfx_write_header(s, &header)))
740 if (pdu->cacheEntriesCount <= 0)
742 WLog_ERR(TAG,
"Invalid cacheEntriesCount: %" PRIu16
"", pdu->cacheEntriesCount);
743 error = ERROR_INVALID_DATA;
748 Stream_Write_UINT16(s, pdu->cacheEntriesCount);
750 for (UINT16 index = 0; index < pdu->cacheEntriesCount; index++)
753 Stream_Write_UINT64(s, cacheEntry->cacheKey);
754 Stream_Write_UINT32(s, cacheEntry->bitmapLength);
757 error = callback->channel->Write(callback->channel, (UINT32)Stream_Length(s), Stream_Buffer(s),
761 Stream_Free(s, TRUE);
773 UINT error = CHANNEL_RC_OK;
776 rdpPersistentCache* persistent = NULL;
779 WINPR_ASSERT(gfx->rdpcontext);
781 RdpgfxClientContext* context = gfx->context;
782 rdpSettings* settings = gfx->rdpcontext->settings;
785 return CHANNEL_RC_OK;
787 const char* BitmapCachePersistFile =
789 if (!BitmapCachePersistFile)
790 return CHANNEL_RC_OK;
792 persistent = persistent_cache_new();
795 return CHANNEL_RC_NO_MEMORY;
797 if (persistent_cache_open(persistent, BitmapCachePersistFile, FALSE, 3) < 1)
799 error = CHANNEL_RC_INITIALIZATION_ERROR;
803 if (persistent_cache_get_version(persistent) != 3)
805 error = ERROR_INVALID_DATA;
809 count = persistent_cache_get_count(persistent);
812 error = ERROR_INVALID_DATA;
816 if (count >= RDPGFX_CACHE_ENTRY_MAX_COUNT)
817 count = RDPGFX_CACHE_ENTRY_MAX_COUNT - 1;
819 if (count > gfx->MaxCacheSlots)
820 count = gfx->MaxCacheSlots;
825 error = CHANNEL_RC_NO_MEMORY;
829 WINPR_ASSERT(count <= UINT16_MAX);
830 offer->cacheEntriesCount = (UINT16)count;
832 WLog_DBG(TAG,
"Sending Cache Import Offer: %d", count);
834 for (
int idx = 0; idx < count; idx++)
836 if (persistent_cache_read_entry(persistent, &entry) < 1)
838 error = ERROR_INVALID_DATA;
842 offer->cacheEntries[idx].cacheKey = entry.key64;
843 offer->cacheEntries[idx].bitmapLength = entry.size;
846 if (offer->cacheEntriesCount > 0)
848 error = rdpgfx_send_cache_import_offer_pdu(context, offer);
849 if (error != CHANNEL_RC_OK)
851 WLog_Print(gfx->log, WLOG_ERROR,
"Failed to send cache import offer PDU");
857 persistent_cache_free(persistent);
867static UINT rdpgfx_load_cache_import_reply(
RDPGFX_PLUGIN* gfx,
870 UINT error = CHANNEL_RC_OK;
871 rdpPersistentCache* persistent = NULL;
873 WINPR_ASSERT(gfx->rdpcontext);
874 rdpSettings* settings = gfx->rdpcontext->settings;
875 RdpgfxClientContext* context = gfx->context;
877 WINPR_ASSERT(settings);
880 return CHANNEL_RC_OK;
882 const char* BitmapCachePersistFile =
884 if (!BitmapCachePersistFile)
885 return CHANNEL_RC_OK;
887 persistent = persistent_cache_new();
890 return CHANNEL_RC_NO_MEMORY;
892 if (persistent_cache_open(persistent, BitmapCachePersistFile, FALSE, 3) < 1)
894 error = CHANNEL_RC_INITIALIZATION_ERROR;
898 if (persistent_cache_get_version(persistent) != 3)
900 error = ERROR_INVALID_DATA;
904 int count = persistent_cache_get_count(persistent);
906 count = (count < reply->importedEntriesCount) ? count : reply->importedEntriesCount;
908 WLog_DBG(TAG,
"Receiving Cache Import Reply: %d", count);
910 for (
int idx = 0; idx < count; idx++)
913 if (persistent_cache_read_entry(persistent, &entry) < 1)
915 error = ERROR_INVALID_DATA;
919 const UINT16 cacheSlot = reply->cacheSlots[idx];
920 if (context && context->ImportCacheEntry)
922 error = context->ImportCacheEntry(context, cacheSlot, &entry);
923 if (error != CHANNEL_RC_OK)
928 persistent_cache_free(persistent);
932 persistent_cache_free(persistent);
944 WINPR_ASSERT(callback);
947 RdpgfxClientContext* context = gfx->context;
948 UINT error = CHANNEL_RC_OK;
950 if (!Stream_CheckAndLogRequiredLength(TAG, s, 2))
951 return ERROR_INVALID_DATA;
953 Stream_Read_UINT16(s, pdu.importedEntriesCount);
955 if (!Stream_CheckAndLogRequiredLengthOfSize(TAG, s, pdu.importedEntriesCount, 2ull))
956 return ERROR_INVALID_DATA;
958 if (pdu.importedEntriesCount > RDPGFX_CACHE_ENTRY_MAX_COUNT)
959 return ERROR_INVALID_DATA;
961 for (UINT16 idx = 0; idx < pdu.importedEntriesCount; idx++)
963 Stream_Read_UINT16(s, pdu.cacheSlots[idx]);
966 DEBUG_RDPGFX(gfx->log,
"RecvCacheImportReplyPdu: importedEntriesCount: %" PRIu16
"",
967 pdu.importedEntriesCount);
969 error = rdpgfx_load_cache_import_reply(gfx, &pdu);
973 WLog_Print(gfx->log, WLOG_ERROR,
974 "rdpgfx_load_cache_import_reply failed with error %" PRIu32
"", error);
980 IFCALLRET(context->CacheImportReply, error, context, &pdu);
983 WLog_Print(gfx->log, WLOG_ERROR,
984 "context->CacheImportReply failed with error %" PRIu32
"", error);
998 WINPR_ASSERT(callback);
1001 RdpgfxClientContext* context = gfx->context;
1002 UINT error = CHANNEL_RC_OK;
1004 if (!Stream_CheckAndLogRequiredLength(TAG, s, 7))
1005 return ERROR_INVALID_DATA;
1007 Stream_Read_UINT16(s, pdu.surfaceId);
1008 Stream_Read_UINT16(s, pdu.width);
1009 Stream_Read_UINT16(s, pdu.height);
1010 Stream_Read_UINT8(s, pdu.pixelFormat);
1011 DEBUG_RDPGFX(gfx->log,
1012 "RecvCreateSurfacePdu: surfaceId: %" PRIu16
" width: %" PRIu16
" height: %" PRIu16
1013 " pixelFormat: 0x%02" PRIX8
"",
1014 pdu.surfaceId, pdu.width, pdu.height, pdu.pixelFormat);
1023 const UINT drc = IFCALLRESULT(CHANNEL_RC_OK, context->DeleteSurface, context, &deletePdu);
1024 if (drc != CHANNEL_RC_OK)
1025 WLog_Print(gfx->log, WLOG_WARN,
1026 "context->DeleteSurface failed with error %" PRIu32
", ignoring", error);
1028 IFCALLRET(context->CreateSurface, error, context, &pdu);
1031 WLog_Print(gfx->log, WLOG_ERROR,
"context->CreateSurface failed with error %" PRIu32
"",
1046 WINPR_ASSERT(callback);
1049 RdpgfxClientContext* context = gfx->context;
1050 UINT error = CHANNEL_RC_OK;
1052 if (!Stream_CheckAndLogRequiredLength(TAG, s, 2))
1053 return ERROR_INVALID_DATA;
1055 Stream_Read_UINT16(s, pdu.surfaceId);
1056 DEBUG_RDPGFX(gfx->log,
"RecvDeleteSurfacePdu: surfaceId: %" PRIu16
"", pdu.surfaceId);
1060 IFCALLRET(context->DeleteSurface, error, context, &pdu);
1063 WLog_Print(gfx->log, WLOG_ERROR,
"context->DeleteSurface failed with error %" PRIu32
"",
1078 WINPR_ASSERT(callback);
1081 RdpgfxClientContext* context = gfx->context;
1082 UINT error = CHANNEL_RC_OK;
1084 if (!Stream_CheckAndLogRequiredLength(TAG, s, RDPGFX_START_FRAME_PDU_SIZE))
1085 return ERROR_INVALID_DATA;
1087 Stream_Read_UINT32(s, pdu.timestamp);
1088 Stream_Read_UINT32(s, pdu.frameId);
1089 DEBUG_RDPGFX(gfx->log,
"RecvStartFramePdu: frameId: %" PRIu32
" timestamp: 0x%08" PRIX32
"",
1090 pdu.frameId, pdu.timestamp);
1091 gfx->StartDecodingTime = GetTickCount64();
1095 IFCALLRET(context->StartFrame, error, context, &pdu);
1098 WLog_Print(gfx->log, WLOG_ERROR,
"context->StartFrame failed with error %" PRIu32
"",
1102 gfx->UnacknowledgedFrames++;
1115 WINPR_ASSERT(callback);
1118 RdpgfxClientContext* context = gfx->context;
1119 UINT error = CHANNEL_RC_OK;
1121 if (!Stream_CheckAndLogRequiredLength(TAG, s, RDPGFX_END_FRAME_PDU_SIZE))
1122 return ERROR_INVALID_DATA;
1124 Stream_Read_UINT32(s, pdu.frameId);
1125 DEBUG_RDPGFX(gfx->log,
"RecvEndFramePdu: frameId: %" PRIu32
"", pdu.frameId);
1127 const UINT64 start = GetTickCount64();
1130 IFCALLRET(context->EndFrame, error, context, &pdu);
1134 WLog_Print(gfx->log, WLOG_ERROR,
"context->EndFrame failed with error %" PRIu32
"",
1139 const UINT64 end = GetTickCount64();
1140 const UINT64 EndFrameTime = end - start;
1141 gfx->TotalDecodedFrames++;
1143 if (!gfx->sendFrameAcks)
1146 ack.frameId = pdu.frameId;
1147 ack.totalFramesDecoded = gfx->TotalDecodedFrames;
1149 if (gfx->suspendFrameAcks)
1151 ack.queueDepth = SUSPEND_FRAME_ACKNOWLEDGEMENT;
1153 if (gfx->TotalDecodedFrames == 1)
1154 if ((error = rdpgfx_send_frame_acknowledge_pdu(context, &ack)))
1155 WLog_Print(gfx->log, WLOG_ERROR,
1156 "rdpgfx_send_frame_acknowledge_pdu failed with error %" PRIu32
"",
1161 ack.queueDepth = QUEUE_DEPTH_UNAVAILABLE;
1163 if ((error = rdpgfx_send_frame_acknowledge_pdu(context, &ack)))
1164 WLog_Print(gfx->log, WLOG_ERROR,
1165 "rdpgfx_send_frame_acknowledge_pdu failed with error %" PRIu32
"", error);
1168 switch (gfx->ConnectionCaps.version)
1170 case RDPGFX_CAPVERSION_10:
1171 case RDPGFX_CAPVERSION_102:
1172 case RDPGFX_CAPVERSION_103:
1173 case RDPGFX_CAPVERSION_104:
1174 case RDPGFX_CAPVERSION_105:
1175 case RDPGFX_CAPVERSION_106:
1176 case RDPGFX_CAPVERSION_106_ERR:
1177 case RDPGFX_CAPVERSION_107:
1181 UINT64 diff = (GetTickCount64() - gfx->StartDecodingTime);
1186 qoe.frameId = pdu.frameId;
1187 qoe.timestamp = gfx->StartDecodingTime % UINT32_MAX;
1188 qoe.timeDiffSE = WINPR_ASSERTING_INT_CAST(UINT16, diff);
1189 qoe.timeDiffEDR = WINPR_ASSERTING_INT_CAST(UINT16, EndFrameTime);
1191 if ((error = rdpgfx_send_qoe_frame_acknowledge_pdu(context, &qoe)))
1192 WLog_Print(gfx->log, WLOG_ERROR,
1193 "rdpgfx_send_qoe_frame_acknowledge_pdu failed with error %" PRIu32
1216 WINPR_ASSERT(callback);
1221 if (!Stream_CheckAndLogRequiredLength(TAG, s, RDPGFX_WIRE_TO_SURFACE_PDU_1_SIZE))
1222 return ERROR_INVALID_DATA;
1224 Stream_Read_UINT16(s, pdu.surfaceId);
1225 Stream_Read_UINT16(s, pdu.codecId);
1226 Stream_Read_UINT8(s, pdu.pixelFormat);
1228 if ((error = rdpgfx_read_rect16(s, &(pdu.destRect))))
1230 WLog_Print(gfx->log, WLOG_ERROR,
"rdpgfx_read_rect16 failed with error %" PRIu32
"", error);
1234 Stream_Read_UINT32(s, pdu.bitmapDataLength);
1236 if (!Stream_CheckAndLogRequiredLength(TAG, s, pdu.bitmapDataLength))
1237 return ERROR_INVALID_DATA;
1239 pdu.bitmapData = Stream_Pointer(s);
1240 Stream_Seek(s, pdu.bitmapDataLength);
1242 DEBUG_RDPGFX(gfx->log,
1243 "RecvWireToSurface1Pdu: surfaceId: %" PRIu16
" codecId: %s (0x%04" PRIX16
1244 ") pixelFormat: 0x%02" PRIX8
" "
1245 "destRect: left: %" PRIu16
" top: %" PRIu16
" right: %" PRIu16
" bottom: %" PRIu16
1246 " bitmapDataLength: %" PRIu32
"",
1247 pdu.surfaceId, rdpgfx_get_codec_id_string(pdu.codecId), pdu.codecId,
1248 pdu.pixelFormat, pdu.destRect.left, pdu.destRect.top, pdu.destRect.right,
1249 pdu.destRect.bottom, pdu.bitmapDataLength);
1250 cmd.surfaceId = pdu.surfaceId;
1251 cmd.codecId = pdu.codecId;
1254 switch (pdu.pixelFormat)
1256 case GFX_PIXEL_FORMAT_XRGB_8888:
1257 cmd.format = PIXEL_FORMAT_BGRX32;
1260 case GFX_PIXEL_FORMAT_ARGB_8888:
1261 cmd.format = PIXEL_FORMAT_BGRA32;
1265 return ERROR_INVALID_DATA;
1268 cmd.left = pdu.destRect.left;
1269 cmd.top = pdu.destRect.top;
1270 cmd.right = pdu.destRect.right;
1271 cmd.bottom = pdu.destRect.bottom;
1272 cmd.width = cmd.right - cmd.left;
1273 cmd.height = cmd.bottom - cmd.top;
1274 cmd.length = pdu.bitmapDataLength;
1275 cmd.data = pdu.bitmapData;
1278 if (cmd.right < cmd.left)
1280 WLog_Print(gfx->log, WLOG_ERROR,
"RecvWireToSurface1Pdu right=%" PRIu32
" < left=%" PRIu32,
1281 cmd.right, cmd.left);
1282 return ERROR_INVALID_DATA;
1284 if (cmd.bottom < cmd.top)
1286 WLog_Print(gfx->log, WLOG_ERROR,
"RecvWireToSurface1Pdu bottom=%" PRIu32
" < top=%" PRIu32,
1287 cmd.bottom, cmd.top);
1288 return ERROR_INVALID_DATA;
1291 if ((error = rdpgfx_decode(gfx, &cmd)))
1292 WLog_Print(gfx->log, WLOG_ERROR,
"rdpgfx_decode failed with error %" PRIu32
"!", error);
1306 WINPR_ASSERT(callback);
1309 RdpgfxClientContext* context = gfx->context;
1310 UINT error = CHANNEL_RC_OK;
1312 if (!Stream_CheckAndLogRequiredLength(TAG, s, RDPGFX_WIRE_TO_SURFACE_PDU_2_SIZE))
1313 return ERROR_INVALID_DATA;
1315 Stream_Read_UINT16(s, pdu.surfaceId);
1316 Stream_Read_UINT16(s, pdu.codecId);
1317 Stream_Read_UINT32(s, pdu.codecContextId);
1318 Stream_Read_UINT8(s, pdu.pixelFormat);
1319 Stream_Read_UINT32(s, pdu.bitmapDataLength);
1320 pdu.bitmapData = Stream_Pointer(s);
1321 if (!Stream_SafeSeek(s, pdu.bitmapDataLength))
1322 return ERROR_INVALID_DATA;
1324 DEBUG_RDPGFX(gfx->log,
1325 "RecvWireToSurface2Pdu: surfaceId: %" PRIu16
" codecId: %s (0x%04" PRIX16
") "
1326 "codecContextId: %" PRIu32
" pixelFormat: 0x%02" PRIX8
1327 " bitmapDataLength: %" PRIu32
"",
1328 pdu.surfaceId, rdpgfx_get_codec_id_string(pdu.codecId), pdu.codecId,
1329 pdu.codecContextId, pdu.pixelFormat, pdu.bitmapDataLength);
1331 cmd.surfaceId = pdu.surfaceId;
1332 cmd.codecId = pdu.codecId;
1333 cmd.contextId = pdu.codecContextId;
1335 switch (pdu.pixelFormat)
1337 case GFX_PIXEL_FORMAT_XRGB_8888:
1338 cmd.format = PIXEL_FORMAT_BGRX32;
1341 case GFX_PIXEL_FORMAT_ARGB_8888:
1342 cmd.format = PIXEL_FORMAT_BGRA32;
1346 return ERROR_INVALID_DATA;
1355 cmd.length = pdu.bitmapDataLength;
1356 cmd.data = pdu.bitmapData;
1361 IFCALLRET(context->SurfaceCommand, error, context, &cmd);
1364 WLog_Print(gfx->log, WLOG_ERROR,
1365 "context->SurfaceCommand failed with error %" PRIu32
"", error);
1379 WINPR_ASSERT(callback);
1382 RdpgfxClientContext* context = gfx->context;
1383 UINT error = CHANNEL_RC_OK;
1385 if (!Stream_CheckAndLogRequiredLength(TAG, s, 6))
1386 return ERROR_INVALID_DATA;
1388 Stream_Read_UINT16(s, pdu.surfaceId);
1389 Stream_Read_UINT32(s, pdu.codecContextId);
1391 DEBUG_RDPGFX(gfx->log,
1392 "RecvDeleteEncodingContextPdu: surfaceId: %" PRIu16
" codecContextId: %" PRIu32
"",
1393 pdu.surfaceId, pdu.codecContextId);
1397 IFCALLRET(context->DeleteEncodingContext, error, context, &pdu);
1400 WLog_Print(gfx->log, WLOG_ERROR,
1401 "context->DeleteEncodingContext failed with error %" PRIu32
"", error);
1416 WINPR_ASSERT(callback);
1419 RdpgfxClientContext* context = gfx->context;
1422 if (!Stream_CheckAndLogRequiredLength(TAG, s, 8))
1423 return ERROR_INVALID_DATA;
1425 Stream_Read_UINT16(s, pdu.surfaceId);
1427 if ((error = rdpgfx_read_color32(s, &(pdu.fillPixel))))
1429 WLog_Print(gfx->log, WLOG_ERROR,
"rdpgfx_read_color32 failed with error %" PRIu32
"!",
1434 Stream_Read_UINT16(s, pdu.fillRectCount);
1436 if (!Stream_CheckAndLogRequiredLengthOfSize(TAG, s, pdu.fillRectCount, 8ull))
1437 return ERROR_INVALID_DATA;
1443 WLog_Print(gfx->log, WLOG_ERROR,
"calloc failed!");
1444 return CHANNEL_RC_NO_MEMORY;
1447 for (UINT16 index = 0; index < pdu.fillRectCount; index++)
1449 fillRect = &(pdu.fillRects[index]);
1451 if ((error = rdpgfx_read_rect16(s, fillRect)))
1453 WLog_Print(gfx->log, WLOG_ERROR,
"rdpgfx_read_rect16 failed with error %" PRIu32
"!",
1455 free(pdu.fillRects);
1459 DEBUG_RDPGFX(gfx->log,
"RecvSolidFillPdu: surfaceId: %" PRIu16
" fillRectCount: %" PRIu16
"",
1460 pdu.surfaceId, pdu.fillRectCount);
1464 IFCALLRET(context->SolidFill, error, context, &pdu);
1467 WLog_Print(gfx->log, WLOG_ERROR,
"context->SolidFill failed with error %" PRIu32
"",
1471 free(pdu.fillRects);
1484 WINPR_ASSERT(callback);
1487 RdpgfxClientContext* context = gfx->context;
1490 if (!Stream_CheckAndLogRequiredLength(TAG, s, 14))
1491 return ERROR_INVALID_DATA;
1493 Stream_Read_UINT16(s, pdu.surfaceIdSrc);
1494 Stream_Read_UINT16(s, pdu.surfaceIdDest);
1496 if ((error = rdpgfx_read_rect16(s, &(pdu.rectSrc))))
1498 WLog_Print(gfx->log, WLOG_ERROR,
"rdpgfx_read_rect16 failed with error %" PRIu32
"!",
1503 Stream_Read_UINT16(s, pdu.destPtsCount);
1505 if (!Stream_CheckAndLogRequiredLengthOfSize(TAG, s, pdu.destPtsCount, 4ull))
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.destPtsCount; index++)
1518 destPt = &(pdu.destPts[index]);
1520 if ((error = rdpgfx_read_point16(s, destPt)))
1522 WLog_Print(gfx->log, WLOG_ERROR,
"rdpgfx_read_point16 failed with error %" PRIu32
"!",
1529 DEBUG_RDPGFX(gfx->log,
1530 "RecvSurfaceToSurfacePdu: surfaceIdSrc: %" PRIu16
" surfaceIdDest: %" PRIu16
" "
1531 "left: %" PRIu16
" top: %" PRIu16
" right: %" PRIu16
" bottom: %" PRIu16
1532 " destPtsCount: %" PRIu16
"",
1533 pdu.surfaceIdSrc, pdu.surfaceIdDest, pdu.rectSrc.left, pdu.rectSrc.top,
1534 pdu.rectSrc.right, pdu.rectSrc.bottom, pdu.destPtsCount);
1538 IFCALLRET(context->SurfaceToSurface, error, context, &pdu);
1541 WLog_Print(gfx->log, WLOG_ERROR,
1542 "context->SurfaceToSurface failed with error %" PRIu32
"", error);
1557 WINPR_ASSERT(callback);
1561 RdpgfxClientContext* context = gfx->context;
1564 if (!Stream_CheckAndLogRequiredLength(TAG, s, 20))
1565 return ERROR_INVALID_DATA;
1567 Stream_Read_UINT16(s, pdu.surfaceId);
1568 Stream_Read_UINT64(s, pdu.cacheKey);
1569 Stream_Read_UINT16(s, pdu.cacheSlot);
1571 if ((error = rdpgfx_read_rect16(s, &(pdu.rectSrc))))
1573 WLog_Print(gfx->log, WLOG_ERROR,
"rdpgfx_read_rect16 failed with error %" PRIu32
"!",
1578 DEBUG_RDPGFX(gfx->log,
1579 "RecvSurfaceToCachePdu: surfaceId: %" PRIu16
" cacheKey: 0x%016" PRIX64
1580 " cacheSlot: %" PRIu16
" "
1581 "left: %" PRIu16
" top: %" PRIu16
" right: %" PRIu16
" bottom: %" PRIu16
"",
1582 pdu.surfaceId, pdu.cacheKey, pdu.cacheSlot, pdu.rectSrc.left, pdu.rectSrc.top,
1583 pdu.rectSrc.right, pdu.rectSrc.bottom);
1587 IFCALLRET(context->SurfaceToCache, error, context, &pdu);
1590 WLog_Print(gfx->log, WLOG_ERROR,
1591 "context->SurfaceToCache failed with error %" PRIu32
"", error);
1606 WINPR_ASSERT(callback);
1610 RdpgfxClientContext* context = gfx->context;
1611 UINT error = CHANNEL_RC_OK;
1613 if (!Stream_CheckAndLogRequiredLength(TAG, s, 6))
1614 return ERROR_INVALID_DATA;
1616 Stream_Read_UINT16(s, pdu.cacheSlot);
1617 Stream_Read_UINT16(s, pdu.surfaceId);
1618 Stream_Read_UINT16(s, pdu.destPtsCount);
1620 if (!Stream_CheckAndLogRequiredLengthOfSize(TAG, s, pdu.destPtsCount, 4ull))
1621 return ERROR_INVALID_DATA;
1627 WLog_Print(gfx->log, WLOG_ERROR,
"calloc failed!");
1628 return CHANNEL_RC_NO_MEMORY;
1631 for (UINT16 index = 0; index < pdu.destPtsCount; index++)
1633 destPt = &(pdu.destPts[index]);
1635 if ((error = rdpgfx_read_point16(s, destPt)))
1637 WLog_Print(gfx->log, WLOG_ERROR,
"rdpgfx_read_point16 failed with error %" PRIu32
"",
1644 DEBUG_RDPGFX(gfx->log,
1645 "RdpGfxRecvCacheToSurfacePdu: cacheSlot: %" PRIu16
" surfaceId: %" PRIu16
1646 " destPtsCount: %" PRIu16
"",
1647 pdu.cacheSlot, pdu.surfaceId, pdu.destPtsCount);
1651 IFCALLRET(context->CacheToSurface, error, context, &pdu);
1654 WLog_Print(gfx->log, WLOG_ERROR,
1655 "context->CacheToSurface failed with error %" PRIu32
"", error);
1670 WINPR_ASSERT(callback);
1674 RdpgfxClientContext* context = gfx->context;
1675 UINT error = CHANNEL_RC_OK;
1677 if (!Stream_CheckAndLogRequiredLength(TAG, s, 12))
1678 return ERROR_INVALID_DATA;
1680 Stream_Read_UINT16(s, pdu.surfaceId);
1681 Stream_Read_UINT16(s, pdu.reserved);
1682 Stream_Read_UINT32(s, pdu.outputOriginX);
1683 Stream_Read_UINT32(s, pdu.outputOriginY);
1684 DEBUG_RDPGFX(gfx->log,
1685 "RecvMapSurfaceToOutputPdu: surfaceId: %" PRIu16
" outputOriginX: %" PRIu32
1686 " outputOriginY: %" PRIu32
"",
1687 pdu.surfaceId, pdu.outputOriginX, pdu.outputOriginY);
1691 IFCALLRET(context->MapSurfaceToOutput, error, context, &pdu);
1694 WLog_Print(gfx->log, WLOG_ERROR,
1695 "context->MapSurfaceToOutput failed with error %" PRIu32
"", error);
1705 WINPR_ASSERT(callback);
1709 RdpgfxClientContext* context = gfx->context;
1710 UINT error = CHANNEL_RC_OK;
1712 if (!Stream_CheckAndLogRequiredLength(TAG, s, 20))
1713 return ERROR_INVALID_DATA;
1715 Stream_Read_UINT16(s, pdu.surfaceId);
1716 Stream_Read_UINT16(s, pdu.reserved);
1717 Stream_Read_UINT32(s, pdu.outputOriginX);
1718 Stream_Read_UINT32(s, pdu.outputOriginY);
1719 Stream_Read_UINT32(s, pdu.targetWidth);
1720 Stream_Read_UINT32(s, pdu.targetHeight);
1721 DEBUG_RDPGFX(gfx->log,
1722 "RecvMapSurfaceToScaledOutputPdu: surfaceId: %" PRIu16
" outputOriginX: %" PRIu32
1723 " outputOriginY: %" PRIu32
" targetWidth: %" PRIu32
" targetHeight: %" PRIu32,
1724 pdu.surfaceId, pdu.outputOriginX, pdu.outputOriginY, pdu.targetWidth,
1729 IFCALLRET(context->MapSurfaceToScaledOutput, error, context, &pdu);
1732 WLog_Print(gfx->log, WLOG_ERROR,
1733 "context->MapSurfaceToScaledOutput failed with error %" PRIu32
"", error);
1747 WINPR_ASSERT(callback);
1751 RdpgfxClientContext* context = gfx->context;
1752 UINT error = CHANNEL_RC_OK;
1754 if (!Stream_CheckAndLogRequiredLength(TAG, s, 18))
1755 return ERROR_INVALID_DATA;
1757 Stream_Read_UINT16(s, pdu.surfaceId);
1758 Stream_Read_UINT64(s, pdu.windowId);
1759 Stream_Read_UINT32(s, pdu.mappedWidth);
1760 Stream_Read_UINT32(s, pdu.mappedHeight);
1761 DEBUG_RDPGFX(gfx->log,
1762 "RecvMapSurfaceToWindowPdu: surfaceId: %" PRIu16
" windowId: 0x%016" PRIX64
1763 " mappedWidth: %" PRIu32
" mappedHeight: %" PRIu32
"",
1764 pdu.surfaceId, pdu.windowId, pdu.mappedWidth, pdu.mappedHeight);
1766 if (context && context->MapSurfaceToWindow)
1768 IFCALLRET(context->MapSurfaceToWindow, error, context, &pdu);
1771 WLog_Print(gfx->log, WLOG_ERROR,
1772 "context->MapSurfaceToWindow failed with error %" PRIu32
"", error);
1782 WINPR_ASSERT(callback);
1785 RdpgfxClientContext* context = gfx->context;
1786 UINT error = CHANNEL_RC_OK;
1788 if (!Stream_CheckAndLogRequiredLength(TAG, s, 26))
1789 return ERROR_INVALID_DATA;
1791 Stream_Read_UINT16(s, pdu.surfaceId);
1792 Stream_Read_UINT64(s, pdu.windowId);
1793 Stream_Read_UINT32(s, pdu.mappedWidth);
1794 Stream_Read_UINT32(s, pdu.mappedHeight);
1795 Stream_Read_UINT32(s, pdu.targetWidth);
1796 Stream_Read_UINT32(s, pdu.targetHeight);
1797 DEBUG_RDPGFX(gfx->log,
1798 "RecvMapSurfaceToScaledWindowPdu: surfaceId: %" PRIu16
" windowId: 0x%016" PRIX64
1799 " mappedWidth: %" PRIu32
" mappedHeight: %" PRIu32
" targetWidth: %" PRIu32
1800 " targetHeight: %" PRIu32
"",
1801 pdu.surfaceId, pdu.windowId, pdu.mappedWidth, pdu.mappedHeight, pdu.targetWidth,
1804 if (context && context->MapSurfaceToScaledWindow)
1806 IFCALLRET(context->MapSurfaceToScaledWindow, error, context, &pdu);
1809 WLog_Print(gfx->log, WLOG_ERROR,
1810 "context->MapSurfaceToScaledWindow failed with error %" PRIu32
"", error);
1826 WINPR_ASSERT(callback);
1828 const size_t beg = Stream_GetPosition(s);
1831 if ((error = rdpgfx_read_header(s, &header)))
1833 WLog_Print(gfx->log, WLOG_ERROR,
"rdpgfx_read_header failed with error %" PRIu32
"!",
1839 gfx->log,
"cmdId: %s (0x%04" PRIX16
") flags: 0x%04" PRIX16
" pduLength: %" PRIu32
"",
1840 rdpgfx_get_cmd_id_string(header.cmdId), header.cmdId, header.flags, header.pduLength);
1842 switch (header.cmdId)
1844 case RDPGFX_CMDID_WIRETOSURFACE_1:
1845 if ((error = rdpgfx_recv_wire_to_surface_1_pdu(callback, s)))
1846 WLog_Print(gfx->log, WLOG_ERROR,
1847 "rdpgfx_recv_wire_to_surface_1_pdu failed with error %" PRIu32
"!",
1852 case RDPGFX_CMDID_WIRETOSURFACE_2:
1853 if ((error = rdpgfx_recv_wire_to_surface_2_pdu(callback, s)))
1854 WLog_Print(gfx->log, WLOG_ERROR,
1855 "rdpgfx_recv_wire_to_surface_2_pdu failed with error %" PRIu32
"!",
1860 case RDPGFX_CMDID_DELETEENCODINGCONTEXT:
1861 if ((error = rdpgfx_recv_delete_encoding_context_pdu(callback, s)))
1862 WLog_Print(gfx->log, WLOG_ERROR,
1863 "rdpgfx_recv_delete_encoding_context_pdu failed with error %" PRIu32
"!",
1868 case RDPGFX_CMDID_SOLIDFILL:
1869 if ((error = rdpgfx_recv_solid_fill_pdu(callback, s)))
1870 WLog_Print(gfx->log, WLOG_ERROR,
1871 "rdpgfx_recv_solid_fill_pdu failed with error %" PRIu32
"!", error);
1875 case RDPGFX_CMDID_SURFACETOSURFACE:
1876 if ((error = rdpgfx_recv_surface_to_surface_pdu(callback, s)))
1877 WLog_Print(gfx->log, WLOG_ERROR,
1878 "rdpgfx_recv_surface_to_surface_pdu failed with error %" PRIu32
"!",
1883 case RDPGFX_CMDID_SURFACETOCACHE:
1884 if ((error = rdpgfx_recv_surface_to_cache_pdu(callback, s)))
1885 WLog_Print(gfx->log, WLOG_ERROR,
1886 "rdpgfx_recv_surface_to_cache_pdu failed with error %" PRIu32
"!",
1891 case RDPGFX_CMDID_CACHETOSURFACE:
1892 if ((error = rdpgfx_recv_cache_to_surface_pdu(callback, s)))
1893 WLog_Print(gfx->log, WLOG_ERROR,
1894 "rdpgfx_recv_cache_to_surface_pdu failed with error %" PRIu32
"!",
1899 case RDPGFX_CMDID_EVICTCACHEENTRY:
1900 if ((error = rdpgfx_recv_evict_cache_entry_pdu(callback, s)))
1901 WLog_Print(gfx->log, WLOG_ERROR,
1902 "rdpgfx_recv_evict_cache_entry_pdu failed with error %" PRIu32
"!",
1907 case RDPGFX_CMDID_CREATESURFACE:
1908 if ((error = rdpgfx_recv_create_surface_pdu(callback, s)))
1909 WLog_Print(gfx->log, WLOG_ERROR,
1910 "rdpgfx_recv_create_surface_pdu failed with error %" PRIu32
"!", error);
1914 case RDPGFX_CMDID_DELETESURFACE:
1915 if ((error = rdpgfx_recv_delete_surface_pdu(callback, s)))
1916 WLog_Print(gfx->log, WLOG_ERROR,
1917 "rdpgfx_recv_delete_surface_pdu failed with error %" PRIu32
"!", error);
1921 case RDPGFX_CMDID_STARTFRAME:
1922 if ((error = rdpgfx_recv_start_frame_pdu(callback, s)))
1923 WLog_Print(gfx->log, WLOG_ERROR,
1924 "rdpgfx_recv_start_frame_pdu failed with error %" PRIu32
"!", error);
1928 case RDPGFX_CMDID_ENDFRAME:
1929 if ((error = rdpgfx_recv_end_frame_pdu(callback, s)))
1930 WLog_Print(gfx->log, WLOG_ERROR,
1931 "rdpgfx_recv_end_frame_pdu failed with error %" PRIu32
"!", error);
1935 case RDPGFX_CMDID_RESETGRAPHICS:
1936 if ((error = rdpgfx_recv_reset_graphics_pdu(callback, s)))
1937 WLog_Print(gfx->log, WLOG_ERROR,
1938 "rdpgfx_recv_reset_graphics_pdu failed with error %" PRIu32
"!", error);
1942 case RDPGFX_CMDID_MAPSURFACETOOUTPUT:
1943 if ((error = rdpgfx_recv_map_surface_to_output_pdu(callback, s)))
1944 WLog_Print(gfx->log, WLOG_ERROR,
1945 "rdpgfx_recv_map_surface_to_output_pdu failed with error %" PRIu32
"!",
1950 case RDPGFX_CMDID_CACHEIMPORTREPLY:
1951 if ((error = rdpgfx_recv_cache_import_reply_pdu(callback, s)))
1952 WLog_Print(gfx->log, WLOG_ERROR,
1953 "rdpgfx_recv_cache_import_reply_pdu failed with error %" PRIu32
"!",
1958 case RDPGFX_CMDID_CAPSCONFIRM:
1959 if ((error = rdpgfx_recv_caps_confirm_pdu(callback, s)))
1960 WLog_Print(gfx->log, WLOG_ERROR,
1961 "rdpgfx_recv_caps_confirm_pdu failed with error %" PRIu32
"!", error);
1963 if ((error = rdpgfx_send_cache_offer(gfx)))
1964 WLog_Print(gfx->log, WLOG_ERROR,
1965 "rdpgfx_send_cache_offer failed with error %" PRIu32
"!", error);
1969 case RDPGFX_CMDID_MAPSURFACETOWINDOW:
1970 if ((error = rdpgfx_recv_map_surface_to_window_pdu(callback, s)))
1971 WLog_Print(gfx->log, WLOG_ERROR,
1972 "rdpgfx_recv_map_surface_to_window_pdu failed with error %" PRIu32
"!",
1977 case RDPGFX_CMDID_MAPSURFACETOSCALEDWINDOW:
1978 if ((error = rdpgfx_recv_map_surface_to_scaled_window_pdu(callback, s)))
1979 WLog_Print(gfx->log, WLOG_ERROR,
1980 "rdpgfx_recv_map_surface_to_scaled_window_pdu failed with error %" PRIu32
1986 case RDPGFX_CMDID_MAPSURFACETOSCALEDOUTPUT:
1987 if ((error = rdpgfx_recv_map_surface_to_scaled_output_pdu(callback, s)))
1988 WLog_Print(gfx->log, WLOG_ERROR,
1989 "rdpgfx_recv_map_surface_to_scaled_output_pdu failed with error %" PRIu32
1996 error = CHANNEL_RC_BAD_PROC;
2002 WLog_Print(gfx->log, WLOG_ERROR,
"Error while processing GFX cmdId: %s (0x%04" PRIX16
")",
2003 rdpgfx_get_cmd_id_string(header.cmdId), header.cmdId);
2004 Stream_SetPosition(s, (beg + header.pduLength));
2008 end = Stream_GetPosition(s);
2010 if (end != (beg + header.pduLength))
2012 WLog_Print(gfx->log, WLOG_ERROR,
2013 "Unexpected gfx pdu end: Actual: %" PRIuz
", Expected: %" PRIuz, end,
2014 (beg + header.pduLength));
2015 Stream_SetPosition(s, (beg + header.pduLength));
2026static UINT rdpgfx_on_data_received(IWTSVirtualChannelCallback* pChannelCallback,
wStream* data)
2030 BYTE* pDstData = NULL;
2032 WINPR_ASSERT(callback);
2034 UINT error = CHANNEL_RC_OK;
2037 status = zgfx_decompress(gfx->zgfx, Stream_ConstPointer(data),
2038 (UINT32)Stream_GetRemainingLength(data), &pDstData, &DstSize, 0);
2042 WLog_Print(gfx->log, WLOG_ERROR,
"zgfx_decompress failure! status: %d", status);
2044 return ERROR_INTERNAL_ERROR;
2048 wStream* s = Stream_StaticConstInit(&sbuffer, pDstData, DstSize);
2052 WLog_Print(gfx->log, WLOG_ERROR,
"calloc failed!");
2054 return CHANNEL_RC_NO_MEMORY;
2057 while (Stream_GetPosition(s) < Stream_Length(s))
2059 if ((error = rdpgfx_recv_pdu(callback, s)))
2061 WLog_Print(gfx->log, WLOG_ERROR,
"rdpgfx_recv_pdu failed with error %" PRIu32
"!",
2076static UINT rdpgfx_on_open(IWTSVirtualChannelCallback* pChannelCallback)
2079 WINPR_ASSERT(callback);
2082 RdpgfxClientContext* context = gfx->context;
2083 UINT error = CHANNEL_RC_OK;
2084 BOOL do_caps_advertise = TRUE;
2085 gfx->sendFrameAcks = TRUE;
2089 IFCALLRET(context->OnOpen, error, context, &do_caps_advertise, &gfx->sendFrameAcks);
2092 WLog_Print(gfx->log, WLOG_ERROR,
"context->OnOpen failed with error %" PRIu32
"",
2096 if (do_caps_advertise)
2097 error = rdpgfx_send_supported_caps(callback);
2107static UINT rdpgfx_on_close(IWTSVirtualChannelCallback* pChannelCallback)
2109 UINT error = CHANNEL_RC_OK;
2111 WINPR_ASSERT(callback);
2118 RdpgfxClientContext* context = gfx->context;
2120 DEBUG_RDPGFX(gfx->log,
"OnClose");
2121 error = rdpgfx_save_persistent_cache(gfx);
2126 WLog_Print(gfx->log, WLOG_ERROR,
2127 "rdpgfx_save_persistent_cache failed with error %" PRIu32
"", error);
2130 free_surfaces(context, gfx->SurfaceTable);
2131 error = evict_cache_slots(context, gfx->MaxCacheSlots, gfx->CacheSlots);
2135 WLog_Print(gfx->log, WLOG_ERROR,
"evict_cache_slots failed with error %" PRIu32
"",
2140 gfx->UnacknowledgedFrames = 0;
2141 gfx->TotalDecodedFrames = 0;
2145 error = IFCALLRESULT(CHANNEL_RC_OK, context->OnClose, context);
2149 WLog_Print(gfx->log, WLOG_ERROR,
"context->OnClose failed with error %" PRIu32
"",
2156 return CHANNEL_RC_OK;
2163 RdpgfxClientContext* context = gfx->context;
2165 DEBUG_RDPGFX(gfx->log,
"Terminated");
2166 rdpgfx_client_context_free(context);
2174static UINT rdpgfx_set_surface_data(RdpgfxClientContext* context, UINT16 surfaceId,
void* pData)
2177 WINPR_ASSERT(context);
2180 key = ((ULONG_PTR)surfaceId) + 1;
2184 if (!HashTable_Insert(gfx->SurfaceTable, (
void*)key, pData))
2185 return ERROR_BAD_ARGUMENTS;
2188 HashTable_Remove(gfx->SurfaceTable, (
void*)key);
2190 return CHANNEL_RC_OK;
2198static UINT rdpgfx_get_surface_ids(RdpgfxClientContext* context, UINT16** ppSurfaceIds,
2202 UINT16* pSurfaceIds = NULL;
2203 ULONG_PTR* pKeys = NULL;
2204 WINPR_ASSERT(context);
2207 count = HashTable_GetKeys(gfx->SurfaceTable, &pKeys);
2209 WINPR_ASSERT(ppSurfaceIds);
2210 WINPR_ASSERT(count_out);
2214 return CHANNEL_RC_OK;
2217 pSurfaceIds = (UINT16*)calloc(count,
sizeof(UINT16));
2221 WLog_Print(gfx->log, WLOG_ERROR,
"calloc failed!");
2223 return CHANNEL_RC_NO_MEMORY;
2226 for (
size_t index = 0; index < count; index++)
2228 pSurfaceIds[index] = (UINT16)(pKeys[index] - 1);
2232 *ppSurfaceIds = pSurfaceIds;
2233 *count_out = (UINT16)count;
2234 return CHANNEL_RC_OK;
2237static void* rdpgfx_get_surface_data(RdpgfxClientContext* context, UINT16 surfaceId)
2241 WINPR_ASSERT(context);
2244 key = ((ULONG_PTR)surfaceId) + 1;
2245 pData = HashTable_GetItemValue(gfx->SurfaceTable, (
void*)key);
2254static UINT rdpgfx_set_cache_slot_data(RdpgfxClientContext* context, UINT16 cacheSlot,
void* pData)
2256 WINPR_ASSERT(context);
2261 if (cacheSlot == 0 || cacheSlot > gfx->MaxCacheSlots)
2263 WLog_ERR(TAG,
"invalid cache slot %" PRIu16
", must be between 1 and %" PRIu16
"",
2264 cacheSlot, gfx->MaxCacheSlots);
2265 return ERROR_INVALID_INDEX;
2268 gfx->CacheSlots[cacheSlot - 1] = pData;
2269 return CHANNEL_RC_OK;
2272static void* rdpgfx_get_cache_slot_data(RdpgfxClientContext* context, UINT16 cacheSlot)
2275 WINPR_ASSERT(context);
2279 if (cacheSlot == 0 || cacheSlot > gfx->MaxCacheSlots)
2281 WLog_ERR(TAG,
"invalid cache slot %" PRIu16
", must be between 1 and %" PRIu16
"",
2282 cacheSlot, gfx->MaxCacheSlots);
2286 pData = gfx->CacheSlots[cacheSlot - 1];
2291 WINPR_ATTR_UNUSED rdpSettings* settings)
2293 RdpgfxClientContext* context = NULL;
2297 gfx->rdpcontext = rcontext;
2298 gfx->log = WLog_Get(TAG);
2300 gfx->SurfaceTable = HashTable_New(TRUE);
2301 if (!gfx->SurfaceTable)
2303 WLog_ERR(TAG,
"HashTable_New for surfaces failed !");
2304 return CHANNEL_RC_NO_MEMORY;
2307 gfx->suspendFrameAcks =
2309 gfx->MaxCacheSlots =
2312 context = (RdpgfxClientContext*)calloc(1,
sizeof(RdpgfxClientContext));
2315 WLog_ERR(TAG,
"context calloc failed!");
2316 HashTable_Free(gfx->SurfaceTable);
2317 gfx->SurfaceTable = NULL;
2318 return CHANNEL_RC_NO_MEMORY;
2321 gfx->zgfx = zgfx_context_new(FALSE);
2324 WLog_ERR(TAG,
"zgfx_context_new failed!");
2325 HashTable_Free(gfx->SurfaceTable);
2326 gfx->SurfaceTable = NULL;
2328 return CHANNEL_RC_NO_MEMORY;
2331 context->handle = (
void*)gfx;
2332 context->GetSurfaceIds = rdpgfx_get_surface_ids;
2333 context->SetSurfaceData = rdpgfx_set_surface_data;
2334 context->GetSurfaceData = rdpgfx_get_surface_data;
2335 context->SetCacheSlotData = rdpgfx_set_cache_slot_data;
2336 context->GetCacheSlotData = rdpgfx_get_cache_slot_data;
2337 context->CapsAdvertise = rdpgfx_send_caps_advertise_pdu;
2338 context->FrameAcknowledge = rdpgfx_send_frame_acknowledge_pdu;
2339 context->CacheImportOffer = rdpgfx_send_cache_import_offer_pdu;
2340 context->QoeFrameAcknowledge = rdpgfx_send_qoe_frame_acknowledge_pdu;
2342 gfx->base.iface.pInterface = (
void*)context;
2343 gfx->context = context;
2344 return CHANNEL_RC_OK;
2347void rdpgfx_client_context_free(RdpgfxClientContext* context)
2357 free_surfaces(context, gfx->SurfaceTable);
2358 evict_cache_slots(context, gfx->MaxCacheSlots, gfx->CacheSlots);
2362 zgfx_context_free(gfx->zgfx);
2366 HashTable_Free(gfx->SurfaceTable);
2370static const IWTSVirtualChannelCallback rdpgfx_callbacks = { rdpgfx_on_data_received,
2371 rdpgfx_on_open, rdpgfx_on_close,
2379FREERDP_ENTRY_POINT(UINT VCAPITYPE rdpgfx_DVCPluginEntry(IDRDYNVC_ENTRY_POINTS* pEntryPoints))
2381 return freerdp_generic_DVCPluginEntry(pEntryPoints, TAG, RDPGFX_DVC_CHANNEL_NAME,
2383 &rdpgfx_callbacks, init_plugin_cb, terminate_plugin_cb);
WINPR_ATTR_NODISCARD FREERDP_API const char * freerdp_settings_get_string(const rdpSettings *settings, FreeRDP_Settings_Keys_String id)
Returns a immutable string settings value.
WINPR_ATTR_NODISCARD FREERDP_API UINT32 freerdp_settings_get_uint32(const rdpSettings *settings, FreeRDP_Settings_Keys_UInt32 id)
Returns a UINT32 settings value.
WINPR_ATTR_NODISCARD FREERDP_API BOOL freerdp_settings_get_bool(const rdpSettings *settings, FreeRDP_Settings_Keys_Bool id)
Returns a boolean settings value.