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 void evict_cache_slots(RdpgfxClientContext* context, UINT16 MaxCacheSlots,
void** CacheSlots)
78 WINPR_ASSERT(CacheSlots);
79 for (UINT16 index = 0; index < MaxCacheSlots; index++)
81 if (CacheSlots[index])
84 pdu.cacheSlot = index + 1;
86 if (context && context->EvictCacheEntry)
88 context->EvictCacheEntry(context, &pdu);
91 CacheSlots[index] = NULL;
101static UINT rdpgfx_send_caps_advertise_pdu(RdpgfxClientContext* context,
104 UINT error = CHANNEL_RC_OK;
111 WINPR_ASSERT(context);
115 if (!gfx || !gfx->base.listener_callback)
116 return ERROR_BAD_ARGUMENTS;
118 callback = gfx->base.listener_callback->channel_callback;
121 header.cmdId = RDPGFX_CMDID_CAPSADVERTISE;
122 header.pduLength = RDPGFX_HEADER_SIZE + 2;
124 for (UINT16 index = 0; index < pdu->capsSetCount; index++)
127 header.pduLength += RDPGFX_CAPSET_BASE_SIZE + capsSet->length;
130 DEBUG_RDPGFX(gfx->log,
"SendCapsAdvertisePdu %" PRIu16
"", pdu->capsSetCount);
131 s = Stream_New(NULL, header.pduLength);
135 WLog_ERR(TAG,
"Stream_New failed!");
136 return CHANNEL_RC_NO_MEMORY;
139 if ((error = rdpgfx_write_header(s, &header)))
143 Stream_Write_UINT16(s, pdu->capsSetCount);
145 for (UINT16 index = 0; index < pdu->capsSetCount; index++)
149 DEBUG_RDPGFX(gfx->log,
"Sending %s [0x%08" PRIx32
"] flags=0x%08" PRIx32,
150 rdpgfx_caps_version_str(capsSet->version), capsSet->version, capsSet->flags);
152 Stream_Write_UINT32(s, capsSet->version);
153 Stream_Write_UINT32(s, capsSet->length);
154 Stream_Write_UINT32(s, capsSet->flags);
155 Stream_Zero(s, capsSet->length - 4);
158 Stream_SealLength(s);
159 error = callback->channel->Write(callback->channel, (UINT32)Stream_Length(s), Stream_Buffer(s),
162 Stream_Free(s, TRUE);
166static BOOL rdpgfx_is_capability_filtered(
RDPGFX_PLUGIN* gfx, UINT32 caps)
169 const UINT32 filter =
171 const UINT32 capList[] = { RDPGFX_CAPVERSION_8, RDPGFX_CAPVERSION_81,
172 RDPGFX_CAPVERSION_10, RDPGFX_CAPVERSION_101,
173 RDPGFX_CAPVERSION_102, RDPGFX_CAPVERSION_103,
174 RDPGFX_CAPVERSION_104, RDPGFX_CAPVERSION_105,
175 RDPGFX_CAPVERSION_106, RDPGFX_CAPVERSION_106_ERR,
176 RDPGFX_CAPVERSION_107 };
178 for (
size_t x = 0; x < ARRAYSIZE(capList); x++)
180 if (caps == capList[x])
181 return (filter & (1 << x)) != 0;
195 RdpgfxClientContext* context = NULL;
201 return ERROR_BAD_ARGUMENTS;
206 return ERROR_BAD_CONFIGURATION;
208 context = gfx->context;
211 return ERROR_BAD_CONFIGURATION;
213 pdu.capsSetCount = 0;
216 if (!rdpgfx_is_capability_filtered(gfx, RDPGFX_CAPVERSION_8))
218 capsSet = &capsSets[pdu.capsSetCount++];
219 capsSet->version = RDPGFX_CAPVERSION_8;
224 capsSet->flags |= RDPGFX_CAPS_FLAG_THINCLIENT;
231 capsSet->flags |= RDPGFX_CAPS_FLAG_SMALL_CACHE;
234 if (!rdpgfx_is_capability_filtered(gfx, RDPGFX_CAPVERSION_81))
236 capsSet = &capsSets[pdu.capsSetCount++];
237 capsSet->version = RDPGFX_CAPVERSION_81;
242 capsSet->flags |= RDPGFX_CAPS_FLAG_THINCLIENT;
245 capsSet->flags |= RDPGFX_CAPS_FLAG_SMALL_CACHE;
250 capsSet->flags |= RDPGFX_CAPS_FLAG_AVC420_ENABLED;
258 UINT32 caps10Flags = 0;
261 caps10Flags |= RDPGFX_CAPS_FLAG_SMALL_CACHE;
266 caps10Flags |= RDPGFX_CAPS_FLAG_AVC_DISABLED;
269 caps10Flags |= RDPGFX_CAPS_FLAG_AVC_DISABLED;
272 if (!rdpgfx_is_capability_filtered(gfx, RDPGFX_CAPVERSION_10))
274 capsSet = &capsSets[pdu.capsSetCount++];
275 capsSet->version = RDPGFX_CAPVERSION_10;
277 capsSet->flags = caps10Flags;
280 if (!rdpgfx_is_capability_filtered(gfx, RDPGFX_CAPVERSION_101))
282 capsSet = &capsSets[pdu.capsSetCount++];
283 capsSet->version = RDPGFX_CAPVERSION_101;
284 capsSet->length = 0x10;
288 if (!rdpgfx_is_capability_filtered(gfx, RDPGFX_CAPVERSION_102))
290 capsSet = &capsSets[pdu.capsSetCount++];
291 capsSet->version = RDPGFX_CAPVERSION_102;
292 capsSet->length = 0x4;
293 capsSet->flags = caps10Flags;
298 if ((caps10Flags & RDPGFX_CAPS_FLAG_AVC_DISABLED) == 0)
299 caps10Flags |= RDPGFX_CAPS_FLAG_AVC_THINCLIENT;
302 if (!rdpgfx_is_capability_filtered(gfx, RDPGFX_CAPVERSION_103))
304 capsSet = &capsSets[pdu.capsSetCount++];
305 capsSet->version = RDPGFX_CAPVERSION_103;
306 capsSet->length = 0x4;
307 capsSet->flags = caps10Flags & ~RDPGFX_CAPS_FLAG_SMALL_CACHE;
310 if (!rdpgfx_is_capability_filtered(gfx, RDPGFX_CAPVERSION_104))
312 capsSet = &capsSets[pdu.capsSetCount++];
313 capsSet->version = RDPGFX_CAPVERSION_104;
314 capsSet->length = 0x4;
315 capsSet->flags = caps10Flags;
321#if defined(WITH_CAIRO) || defined(WITH_SWSCALE)
322 if (!rdpgfx_is_capability_filtered(gfx, RDPGFX_CAPVERSION_105))
324 capsSet = &capsSets[pdu.capsSetCount++];
325 capsSet->version = RDPGFX_CAPVERSION_105;
326 capsSet->length = 0x4;
327 capsSet->flags = caps10Flags;
330 if (!rdpgfx_is_capability_filtered(gfx, RDPGFX_CAPVERSION_106))
332 capsSet = &capsSets[pdu.capsSetCount++];
333 capsSet->version = RDPGFX_CAPVERSION_106;
334 capsSet->length = 0x4;
335 capsSet->flags = caps10Flags;
338 if (!rdpgfx_is_capability_filtered(gfx, RDPGFX_CAPVERSION_106_ERR))
340 capsSet = &capsSets[pdu.capsSetCount++];
341 capsSet->version = RDPGFX_CAPVERSION_106_ERR;
342 capsSet->length = 0x4;
343 capsSet->flags = caps10Flags;
347 if (!rdpgfx_is_capability_filtered(gfx, RDPGFX_CAPVERSION_107))
349 capsSet = &capsSets[pdu.capsSetCount++];
350 capsSet->version = RDPGFX_CAPVERSION_107;
351 capsSet->length = 0x4;
352 capsSet->flags = caps10Flags;
353#if !defined(WITH_CAIRO) && !defined(WITH_SWSCALE)
354 capsSet->flags |= RDPGFX_CAPS_FLAG_SCALEDMAP_DISABLE;
359 return IFCALLRESULT(ERROR_BAD_CONFIGURATION, context->CapsAdvertise, context, &pdu);
371 WINPR_ASSERT(callback);
375 RdpgfxClientContext* context = gfx->context;
377 pdu.capsSet = &capsSet;
379 if (!Stream_CheckAndLogRequiredLength(TAG, s, 12))
380 return ERROR_INVALID_DATA;
382 Stream_Read_UINT32(s, capsSet.version);
383 Stream_Read_UINT32(s, capsSet.length);
384 Stream_Read_UINT32(s, capsSet.flags);
385 gfx->TotalDecodedFrames = 0;
386 gfx->ConnectionCaps = capsSet;
387 WLog_Print(gfx->log, WLOG_DEBUG,
388 "RecvCapsConfirmPdu: version: %s [0x%08" PRIX32
"] flags: 0x%08" PRIX32
"",
389 rdpgfx_caps_version_str(capsSet.version), capsSet.version, capsSet.flags);
392 return ERROR_BAD_CONFIGURATION;
394 return IFCALLRESULT(CHANNEL_RC_OK, context->CapsConfirm, context, &pdu);
402static UINT rdpgfx_send_frame_acknowledge_pdu(RdpgfxClientContext* context,
411 if (!context || !pdu)
412 return ERROR_BAD_ARGUMENTS;
416 if (!gfx || !gfx->base.listener_callback)
417 return ERROR_BAD_CONFIGURATION;
419 callback = gfx->base.listener_callback->channel_callback;
422 return ERROR_BAD_CONFIGURATION;
425 header.cmdId = RDPGFX_CMDID_FRAMEACKNOWLEDGE;
426 header.pduLength = RDPGFX_HEADER_SIZE + 12;
427 DEBUG_RDPGFX(gfx->log,
"SendFrameAcknowledgePdu: %" PRIu32
"", pdu->frameId);
428 s = Stream_New(NULL, header.pduLength);
432 WLog_ERR(TAG,
"Stream_New failed!");
433 return CHANNEL_RC_NO_MEMORY;
436 if ((error = rdpgfx_write_header(s, &header)))
440 Stream_Write_UINT32(s, pdu->queueDepth);
441 Stream_Write_UINT32(s, pdu->frameId);
442 Stream_Write_UINT32(s, pdu->totalFramesDecoded);
443 error = callback->channel->Write(callback->channel, (UINT32)Stream_Length(s), Stream_Buffer(s),
446 if (error == CHANNEL_RC_OK)
447 gfx->UnacknowledgedFrames--;
450 Stream_Free(s, TRUE);
454static UINT rdpgfx_send_qoe_frame_acknowledge_pdu(RdpgfxClientContext* context,
464 header.cmdId = RDPGFX_CMDID_QOEFRAMEACKNOWLEDGE;
465 header.pduLength = RDPGFX_HEADER_SIZE + 12;
467 if (!context || !pdu)
468 return ERROR_BAD_ARGUMENTS;
472 if (!gfx || !gfx->base.listener_callback)
473 return ERROR_BAD_CONFIGURATION;
475 callback = gfx->base.listener_callback->channel_callback;
478 return ERROR_BAD_CONFIGURATION;
480 DEBUG_RDPGFX(gfx->log,
"SendQoeFrameAcknowledgePdu: %" PRIu32
"", pdu->frameId);
481 s = Stream_New(NULL, header.pduLength);
485 WLog_ERR(TAG,
"Stream_New failed!");
486 return CHANNEL_RC_NO_MEMORY;
489 if ((error = rdpgfx_write_header(s, &header)))
493 Stream_Write_UINT32(s, pdu->frameId);
494 Stream_Write_UINT32(s, pdu->timestamp);
495 Stream_Write_UINT16(s, pdu->timeDiffSE);
496 Stream_Write_UINT16(s, pdu->timeDiffEDR);
497 error = callback->channel->Write(callback->channel, (UINT32)Stream_Length(s), Stream_Buffer(s),
500 Stream_Free(s, TRUE);
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_DEF* 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 WLog_Print(gfx->log, WLOG_DEBUG,
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_DEF* 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);
638 UINT error = CHANNEL_RC_OK;
640 rdpPersistentCache* persistent = NULL;
642 WINPR_ASSERT(gfx->rdpcontext);
643 rdpSettings* settings = gfx->rdpcontext->settings;
644 RdpgfxClientContext* context = gfx->context;
646 WINPR_ASSERT(context);
647 WINPR_ASSERT(settings);
650 return CHANNEL_RC_OK;
652 const char* BitmapCachePersistFile =
654 if (!BitmapCachePersistFile)
655 return CHANNEL_RC_OK;
657 if (!context->ExportCacheEntry)
658 return CHANNEL_RC_INITIALIZATION_ERROR;
660 persistent = persistent_cache_new();
663 return CHANNEL_RC_NO_MEMORY;
665 if (persistent_cache_open(persistent, BitmapCachePersistFile, TRUE, 3) < 1)
667 error = CHANNEL_RC_INITIALIZATION_ERROR;
671 for (UINT16 idx = 0; idx < gfx->MaxCacheSlots; idx++)
673 if (gfx->CacheSlots[idx])
675 UINT16 cacheSlot = idx;
677 if (context->ExportCacheEntry(context, cacheSlot, &cacheEntry) != CHANNEL_RC_OK)
680 persistent_cache_write_entry(persistent, &cacheEntry);
684 persistent_cache_free(persistent);
688 persistent_cache_free(persistent);
697static UINT rdpgfx_send_cache_import_offer_pdu(RdpgfxClientContext* context,
700 UINT error = CHANNEL_RC_OK;
705 if (!context || !pdu)
706 return ERROR_BAD_ARGUMENTS;
710 if (!gfx || !gfx->base.listener_callback)
711 return ERROR_BAD_CONFIGURATION;
713 callback = gfx->base.listener_callback->channel_callback;
716 return ERROR_BAD_CONFIGURATION;
719 header.cmdId = RDPGFX_CMDID_CACHEIMPORTOFFER;
720 header.pduLength = RDPGFX_HEADER_SIZE + 2ul + pdu->cacheEntriesCount * 12ul;
721 WLog_Print(gfx->log, WLOG_DEBUG,
"SendCacheImportOfferPdu: cacheEntriesCount: %" PRIu16
"",
722 pdu->cacheEntriesCount);
723 s = Stream_New(NULL, header.pduLength);
727 WLog_ERR(TAG,
"Stream_New failed!");
728 return CHANNEL_RC_NO_MEMORY;
731 if ((error = rdpgfx_write_header(s, &header)))
734 if (pdu->cacheEntriesCount <= 0)
736 WLog_ERR(TAG,
"Invalid cacheEntriesCount: %" PRIu16
"", pdu->cacheEntriesCount);
737 error = ERROR_INVALID_DATA;
742 Stream_Write_UINT16(s, pdu->cacheEntriesCount);
744 for (UINT16 index = 0; index < pdu->cacheEntriesCount; index++)
747 Stream_Write_UINT64(s, cacheEntry->cacheKey);
748 Stream_Write_UINT32(s, cacheEntry->bitmapLength);
751 error = callback->channel->Write(callback->channel, (UINT32)Stream_Length(s), Stream_Buffer(s),
755 Stream_Free(s, TRUE);
767 UINT error = CHANNEL_RC_OK;
770 rdpPersistentCache* persistent = NULL;
773 WINPR_ASSERT(gfx->rdpcontext);
775 RdpgfxClientContext* context = gfx->context;
776 rdpSettings* settings = gfx->rdpcontext->settings;
779 return CHANNEL_RC_OK;
781 const char* BitmapCachePersistFile =
783 if (!BitmapCachePersistFile)
784 return CHANNEL_RC_OK;
786 persistent = persistent_cache_new();
789 return CHANNEL_RC_NO_MEMORY;
791 if (persistent_cache_open(persistent, BitmapCachePersistFile, FALSE, 3) < 1)
793 error = CHANNEL_RC_INITIALIZATION_ERROR;
797 if (persistent_cache_get_version(persistent) != 3)
799 error = ERROR_INVALID_DATA;
803 count = persistent_cache_get_count(persistent);
806 error = ERROR_INVALID_DATA;
810 if (count >= RDPGFX_CACHE_ENTRY_MAX_COUNT)
811 count = RDPGFX_CACHE_ENTRY_MAX_COUNT - 1;
813 if (count > gfx->MaxCacheSlots)
814 count = gfx->MaxCacheSlots;
819 error = CHANNEL_RC_NO_MEMORY;
823 WINPR_ASSERT(count <= UINT16_MAX);
824 offer->cacheEntriesCount = (UINT16)count;
826 WLog_DBG(TAG,
"Sending Cache Import Offer: %d", count);
828 for (
int idx = 0; idx < count; idx++)
830 if (persistent_cache_read_entry(persistent, &entry) < 1)
832 error = ERROR_INVALID_DATA;
836 offer->cacheEntries[idx].cacheKey = entry.key64;
837 offer->cacheEntries[idx].bitmapLength = entry.size;
840 if (offer->cacheEntriesCount > 0)
842 error = rdpgfx_send_cache_import_offer_pdu(context, offer);
843 if (error != CHANNEL_RC_OK)
845 WLog_Print(gfx->log, WLOG_ERROR,
"Failed to send cache import offer PDU");
851 persistent_cache_free(persistent);
861static UINT rdpgfx_load_cache_import_reply(
RDPGFX_PLUGIN* gfx,
865 UINT error = CHANNEL_RC_OK;
866 rdpPersistentCache* persistent = NULL;
868 WINPR_ASSERT(gfx->rdpcontext);
869 rdpSettings* settings = gfx->rdpcontext->settings;
870 RdpgfxClientContext* context = gfx->context;
872 WINPR_ASSERT(settings);
875 return CHANNEL_RC_OK;
877 const char* BitmapCachePersistFile =
879 if (!BitmapCachePersistFile)
880 return CHANNEL_RC_OK;
882 persistent = persistent_cache_new();
885 return CHANNEL_RC_NO_MEMORY;
887 if (persistent_cache_open(persistent, BitmapCachePersistFile, FALSE, 3) < 1)
889 error = CHANNEL_RC_INITIALIZATION_ERROR;
893 if (persistent_cache_get_version(persistent) != 3)
895 error = ERROR_INVALID_DATA;
899 count = persistent_cache_get_count(persistent);
901 count = (count < reply->importedEntriesCount) ? count : reply->importedEntriesCount;
903 WLog_DBG(TAG,
"Receiving Cache Import Reply: %d", count);
905 for (
int idx = 0; idx < count; idx++)
908 if (persistent_cache_read_entry(persistent, &entry) < 1)
910 error = ERROR_INVALID_DATA;
914 const UINT16 cacheSlot = reply->cacheSlots[idx];
915 if (context && context->ImportCacheEntry)
916 context->ImportCacheEntry(context, cacheSlot, &entry);
919 persistent_cache_free(persistent);
923 persistent_cache_free(persistent);
935 WINPR_ASSERT(callback);
938 RdpgfxClientContext* context = gfx->context;
939 UINT error = CHANNEL_RC_OK;
941 if (!Stream_CheckAndLogRequiredLength(TAG, s, 2))
942 return ERROR_INVALID_DATA;
944 Stream_Read_UINT16(s, pdu.importedEntriesCount);
946 if (!Stream_CheckAndLogRequiredLengthOfSize(TAG, s, pdu.importedEntriesCount, 2ull))
947 return ERROR_INVALID_DATA;
949 if (pdu.importedEntriesCount > RDPGFX_CACHE_ENTRY_MAX_COUNT)
950 return ERROR_INVALID_DATA;
952 for (UINT16 idx = 0; idx < pdu.importedEntriesCount; idx++)
954 Stream_Read_UINT16(s, pdu.cacheSlots[idx]);
957 DEBUG_RDPGFX(gfx->log,
"RecvCacheImportReplyPdu: importedEntriesCount: %" PRIu16
"",
958 pdu.importedEntriesCount);
960 error = rdpgfx_load_cache_import_reply(gfx, &pdu);
964 WLog_Print(gfx->log, WLOG_ERROR,
965 "rdpgfx_load_cache_import_reply failed with error %" PRIu32
"", error);
971 IFCALLRET(context->CacheImportReply, error, context, &pdu);
974 WLog_Print(gfx->log, WLOG_ERROR,
975 "context->CacheImportReply failed with error %" PRIu32
"", error);
989 WINPR_ASSERT(callback);
992 RdpgfxClientContext* context = gfx->context;
993 UINT error = CHANNEL_RC_OK;
995 if (!Stream_CheckAndLogRequiredLength(TAG, s, 7))
996 return ERROR_INVALID_DATA;
998 Stream_Read_UINT16(s, pdu.surfaceId);
999 Stream_Read_UINT16(s, pdu.width);
1000 Stream_Read_UINT16(s, pdu.height);
1001 Stream_Read_UINT8(s, pdu.pixelFormat);
1002 DEBUG_RDPGFX(gfx->log,
1003 "RecvCreateSurfacePdu: surfaceId: %" PRIu16
" width: %" PRIu16
" height: %" PRIu16
1004 " pixelFormat: 0x%02" PRIX8
"",
1005 pdu.surfaceId, pdu.width, pdu.height, pdu.pixelFormat);
1014 IFCALL(context->DeleteSurface, context, &deletePdu);
1016 IFCALLRET(context->CreateSurface, error, context, &pdu);
1019 WLog_Print(gfx->log, WLOG_ERROR,
"context->CreateSurface failed with error %" PRIu32
"",
1034 WINPR_ASSERT(callback);
1037 RdpgfxClientContext* context = gfx->context;
1038 UINT error = CHANNEL_RC_OK;
1040 if (!Stream_CheckAndLogRequiredLength(TAG, s, 2))
1041 return ERROR_INVALID_DATA;
1043 Stream_Read_UINT16(s, pdu.surfaceId);
1044 DEBUG_RDPGFX(gfx->log,
"RecvDeleteSurfacePdu: surfaceId: %" PRIu16
"", pdu.surfaceId);
1048 IFCALLRET(context->DeleteSurface, error, context, &pdu);
1051 WLog_Print(gfx->log, WLOG_ERROR,
"context->DeleteSurface failed with error %" PRIu32
"",
1066 WINPR_ASSERT(callback);
1069 RdpgfxClientContext* context = gfx->context;
1070 UINT error = CHANNEL_RC_OK;
1072 if (!Stream_CheckAndLogRequiredLength(TAG, s, RDPGFX_START_FRAME_PDU_SIZE))
1073 return ERROR_INVALID_DATA;
1075 Stream_Read_UINT32(s, pdu.timestamp);
1076 Stream_Read_UINT32(s, pdu.frameId);
1077 DEBUG_RDPGFX(gfx->log,
"RecvStartFramePdu: frameId: %" PRIu32
" timestamp: 0x%08" PRIX32
"",
1078 pdu.frameId, pdu.timestamp);
1079 gfx->StartDecodingTime = GetTickCount64();
1083 IFCALLRET(context->StartFrame, error, context, &pdu);
1086 WLog_Print(gfx->log, WLOG_ERROR,
"context->StartFrame failed with error %" PRIu32
"",
1090 gfx->UnacknowledgedFrames++;
1103 WINPR_ASSERT(callback);
1106 RdpgfxClientContext* context = gfx->context;
1107 UINT error = CHANNEL_RC_OK;
1109 if (!Stream_CheckAndLogRequiredLength(TAG, s, RDPGFX_END_FRAME_PDU_SIZE))
1110 return ERROR_INVALID_DATA;
1112 Stream_Read_UINT32(s, pdu.frameId);
1113 DEBUG_RDPGFX(gfx->log,
"RecvEndFramePdu: frameId: %" PRIu32
"", pdu.frameId);
1115 const UINT64 start = GetTickCount64();
1118 IFCALLRET(context->EndFrame, error, context, &pdu);
1122 WLog_Print(gfx->log, WLOG_ERROR,
"context->EndFrame failed with error %" PRIu32
"",
1127 const UINT64 end = GetTickCount64();
1128 const UINT64 EndFrameTime = end - start;
1129 gfx->TotalDecodedFrames++;
1131 if (!gfx->sendFrameAcks)
1134 ack.frameId = pdu.frameId;
1135 ack.totalFramesDecoded = gfx->TotalDecodedFrames;
1137 if (gfx->suspendFrameAcks)
1139 ack.queueDepth = SUSPEND_FRAME_ACKNOWLEDGEMENT;
1141 if (gfx->TotalDecodedFrames == 1)
1142 if ((error = rdpgfx_send_frame_acknowledge_pdu(context, &ack)))
1143 WLog_Print(gfx->log, WLOG_ERROR,
1144 "rdpgfx_send_frame_acknowledge_pdu failed with error %" PRIu32
"",
1149 ack.queueDepth = QUEUE_DEPTH_UNAVAILABLE;
1151 if ((error = rdpgfx_send_frame_acknowledge_pdu(context, &ack)))
1152 WLog_Print(gfx->log, WLOG_ERROR,
1153 "rdpgfx_send_frame_acknowledge_pdu failed with error %" PRIu32
"", error);
1156 switch (gfx->ConnectionCaps.version)
1158 case RDPGFX_CAPVERSION_10:
1159 case RDPGFX_CAPVERSION_102:
1160 case RDPGFX_CAPVERSION_103:
1161 case RDPGFX_CAPVERSION_104:
1162 case RDPGFX_CAPVERSION_105:
1163 case RDPGFX_CAPVERSION_106:
1164 case RDPGFX_CAPVERSION_106_ERR:
1165 case RDPGFX_CAPVERSION_107:
1169 UINT64 diff = (GetTickCount64() - gfx->StartDecodingTime);
1174 qoe.frameId = pdu.frameId;
1175 qoe.timestamp = gfx->StartDecodingTime % UINT32_MAX;
1176 qoe.timeDiffSE = WINPR_ASSERTING_INT_CAST(UINT16, diff);
1177 qoe.timeDiffEDR = WINPR_ASSERTING_INT_CAST(UINT16, EndFrameTime);
1179 if ((error = rdpgfx_send_qoe_frame_acknowledge_pdu(context, &qoe)))
1180 WLog_Print(gfx->log, WLOG_ERROR,
1181 "rdpgfx_send_qoe_frame_acknowledge_pdu failed with error %" PRIu32
1204 WINPR_ASSERT(callback);
1209 if (!Stream_CheckAndLogRequiredLength(TAG, s, RDPGFX_WIRE_TO_SURFACE_PDU_1_SIZE))
1210 return ERROR_INVALID_DATA;
1212 Stream_Read_UINT16(s, pdu.surfaceId);
1213 Stream_Read_UINT16(s, pdu.codecId);
1214 Stream_Read_UINT8(s, pdu.pixelFormat);
1216 if ((error = rdpgfx_read_rect16(s, &(pdu.destRect))))
1218 WLog_Print(gfx->log, WLOG_ERROR,
"rdpgfx_read_rect16 failed with error %" PRIu32
"", error);
1222 Stream_Read_UINT32(s, pdu.bitmapDataLength);
1224 if (!Stream_CheckAndLogRequiredLength(TAG, s, pdu.bitmapDataLength))
1225 return ERROR_INVALID_DATA;
1227 pdu.bitmapData = Stream_Pointer(s);
1228 Stream_Seek(s, pdu.bitmapDataLength);
1230 DEBUG_RDPGFX(gfx->log,
1231 "RecvWireToSurface1Pdu: surfaceId: %" PRIu16
" codecId: %s (0x%04" PRIX16
1232 ") pixelFormat: 0x%02" PRIX8
" "
1233 "destRect: left: %" PRIu16
" top: %" PRIu16
" right: %" PRIu16
" bottom: %" PRIu16
1234 " bitmapDataLength: %" PRIu32
"",
1235 pdu.surfaceId, rdpgfx_get_codec_id_string(pdu.codecId), pdu.codecId,
1236 pdu.pixelFormat, pdu.destRect.left, pdu.destRect.top, pdu.destRect.right,
1237 pdu.destRect.bottom, pdu.bitmapDataLength);
1238 cmd.surfaceId = pdu.surfaceId;
1239 cmd.codecId = pdu.codecId;
1242 switch (pdu.pixelFormat)
1244 case GFX_PIXEL_FORMAT_XRGB_8888:
1245 cmd.format = PIXEL_FORMAT_BGRX32;
1248 case GFX_PIXEL_FORMAT_ARGB_8888:
1249 cmd.format = PIXEL_FORMAT_BGRA32;
1253 return ERROR_INVALID_DATA;
1256 cmd.left = pdu.destRect.left;
1257 cmd.top = pdu.destRect.top;
1258 cmd.right = pdu.destRect.right;
1259 cmd.bottom = pdu.destRect.bottom;
1260 cmd.width = cmd.right - cmd.left;
1261 cmd.height = cmd.bottom - cmd.top;
1262 cmd.length = pdu.bitmapDataLength;
1263 cmd.data = pdu.bitmapData;
1266 if (cmd.right < cmd.left)
1268 WLog_Print(gfx->log, WLOG_ERROR,
"RecvWireToSurface1Pdu right=%" PRIu32
" < left=%" PRIu32,
1269 cmd.right, cmd.left);
1270 return ERROR_INVALID_DATA;
1272 if (cmd.bottom < cmd.top)
1274 WLog_Print(gfx->log, WLOG_ERROR,
"RecvWireToSurface1Pdu bottom=%" PRIu32
" < top=%" PRIu32,
1275 cmd.bottom, cmd.top);
1276 return ERROR_INVALID_DATA;
1279 if ((error = rdpgfx_decode(gfx, &cmd)))
1280 WLog_Print(gfx->log, WLOG_ERROR,
"rdpgfx_decode failed with error %" PRIu32
"!", error);
1294 WINPR_ASSERT(callback);
1297 RdpgfxClientContext* context = gfx->context;
1298 UINT error = CHANNEL_RC_OK;
1300 if (!Stream_CheckAndLogRequiredLength(TAG, s, RDPGFX_WIRE_TO_SURFACE_PDU_2_SIZE))
1301 return ERROR_INVALID_DATA;
1303 Stream_Read_UINT16(s, pdu.surfaceId);
1304 Stream_Read_UINT16(s, pdu.codecId);
1305 Stream_Read_UINT32(s, pdu.codecContextId);
1306 Stream_Read_UINT8(s, pdu.pixelFormat);
1307 Stream_Read_UINT32(s, pdu.bitmapDataLength);
1308 pdu.bitmapData = Stream_Pointer(s);
1309 Stream_Seek(s, pdu.bitmapDataLength);
1311 DEBUG_RDPGFX(gfx->log,
1312 "RecvWireToSurface2Pdu: surfaceId: %" PRIu16
" codecId: %s (0x%04" PRIX16
") "
1313 "codecContextId: %" PRIu32
" pixelFormat: 0x%02" PRIX8
1314 " bitmapDataLength: %" PRIu32
"",
1315 pdu.surfaceId, rdpgfx_get_codec_id_string(pdu.codecId), pdu.codecId,
1316 pdu.codecContextId, pdu.pixelFormat, pdu.bitmapDataLength);
1318 cmd.surfaceId = pdu.surfaceId;
1319 cmd.codecId = pdu.codecId;
1320 cmd.contextId = pdu.codecContextId;
1322 switch (pdu.pixelFormat)
1324 case GFX_PIXEL_FORMAT_XRGB_8888:
1325 cmd.format = PIXEL_FORMAT_BGRX32;
1328 case GFX_PIXEL_FORMAT_ARGB_8888:
1329 cmd.format = PIXEL_FORMAT_BGRA32;
1333 return ERROR_INVALID_DATA;
1342 cmd.length = pdu.bitmapDataLength;
1343 cmd.data = pdu.bitmapData;
1348 IFCALLRET(context->SurfaceCommand, error, context, &cmd);
1351 WLog_Print(gfx->log, WLOG_ERROR,
1352 "context->SurfaceCommand failed with error %" PRIu32
"", error);
1366 WINPR_ASSERT(callback);
1369 RdpgfxClientContext* context = gfx->context;
1370 UINT error = CHANNEL_RC_OK;
1372 if (!Stream_CheckAndLogRequiredLength(TAG, s, 6))
1373 return ERROR_INVALID_DATA;
1375 Stream_Read_UINT16(s, pdu.surfaceId);
1376 Stream_Read_UINT32(s, pdu.codecContextId);
1378 DEBUG_RDPGFX(gfx->log,
1379 "RecvDeleteEncodingContextPdu: surfaceId: %" PRIu16
" codecContextId: %" PRIu32
"",
1380 pdu.surfaceId, pdu.codecContextId);
1384 IFCALLRET(context->DeleteEncodingContext, error, context, &pdu);
1387 WLog_Print(gfx->log, WLOG_ERROR,
1388 "context->DeleteEncodingContext failed with error %" PRIu32
"", error);
1403 WINPR_ASSERT(callback);
1406 RdpgfxClientContext* context = gfx->context;
1409 if (!Stream_CheckAndLogRequiredLength(TAG, s, 8))
1410 return ERROR_INVALID_DATA;
1412 Stream_Read_UINT16(s, pdu.surfaceId);
1414 if ((error = rdpgfx_read_color32(s, &(pdu.fillPixel))))
1416 WLog_Print(gfx->log, WLOG_ERROR,
"rdpgfx_read_color32 failed with error %" PRIu32
"!",
1421 Stream_Read_UINT16(s, pdu.fillRectCount);
1423 if (!Stream_CheckAndLogRequiredLengthOfSize(TAG, s, pdu.fillRectCount, 8ull))
1424 return ERROR_INVALID_DATA;
1430 WLog_Print(gfx->log, WLOG_ERROR,
"calloc failed!");
1431 return CHANNEL_RC_NO_MEMORY;
1434 for (UINT16 index = 0; index < pdu.fillRectCount; index++)
1436 fillRect = &(pdu.fillRects[index]);
1438 if ((error = rdpgfx_read_rect16(s, fillRect)))
1440 WLog_Print(gfx->log, WLOG_ERROR,
"rdpgfx_read_rect16 failed with error %" PRIu32
"!",
1442 free(pdu.fillRects);
1446 DEBUG_RDPGFX(gfx->log,
"RecvSolidFillPdu: surfaceId: %" PRIu16
" fillRectCount: %" PRIu16
"",
1447 pdu.surfaceId, pdu.fillRectCount);
1451 IFCALLRET(context->SolidFill, error, context, &pdu);
1454 WLog_Print(gfx->log, WLOG_ERROR,
"context->SolidFill failed with error %" PRIu32
"",
1458 free(pdu.fillRects);
1471 WINPR_ASSERT(callback);
1474 RdpgfxClientContext* context = gfx->context;
1477 if (!Stream_CheckAndLogRequiredLength(TAG, s, 14))
1478 return ERROR_INVALID_DATA;
1480 Stream_Read_UINT16(s, pdu.surfaceIdSrc);
1481 Stream_Read_UINT16(s, pdu.surfaceIdDest);
1483 if ((error = rdpgfx_read_rect16(s, &(pdu.rectSrc))))
1485 WLog_Print(gfx->log, WLOG_ERROR,
"rdpgfx_read_rect16 failed with error %" PRIu32
"!",
1490 Stream_Read_UINT16(s, pdu.destPtsCount);
1492 if (!Stream_CheckAndLogRequiredLengthOfSize(TAG, s, pdu.destPtsCount, 4ull))
1493 return ERROR_INVALID_DATA;
1499 WLog_Print(gfx->log, WLOG_ERROR,
"calloc failed!");
1500 return CHANNEL_RC_NO_MEMORY;
1503 for (UINT16 index = 0; index < pdu.destPtsCount; index++)
1505 destPt = &(pdu.destPts[index]);
1507 if ((error = rdpgfx_read_point16(s, destPt)))
1509 WLog_Print(gfx->log, WLOG_ERROR,
"rdpgfx_read_point16 failed with error %" PRIu32
"!",
1516 DEBUG_RDPGFX(gfx->log,
1517 "RecvSurfaceToSurfacePdu: surfaceIdSrc: %" PRIu16
" surfaceIdDest: %" PRIu16
" "
1518 "left: %" PRIu16
" top: %" PRIu16
" right: %" PRIu16
" bottom: %" PRIu16
1519 " destPtsCount: %" PRIu16
"",
1520 pdu.surfaceIdSrc, pdu.surfaceIdDest, pdu.rectSrc.left, pdu.rectSrc.top,
1521 pdu.rectSrc.right, pdu.rectSrc.bottom, pdu.destPtsCount);
1525 IFCALLRET(context->SurfaceToSurface, error, context, &pdu);
1528 WLog_Print(gfx->log, WLOG_ERROR,
1529 "context->SurfaceToSurface failed with error %" PRIu32
"", error);
1544 WINPR_ASSERT(callback);
1548 RdpgfxClientContext* context = gfx->context;
1551 if (!Stream_CheckAndLogRequiredLength(TAG, s, 20))
1552 return ERROR_INVALID_DATA;
1554 Stream_Read_UINT16(s, pdu.surfaceId);
1555 Stream_Read_UINT64(s, pdu.cacheKey);
1556 Stream_Read_UINT16(s, pdu.cacheSlot);
1558 if ((error = rdpgfx_read_rect16(s, &(pdu.rectSrc))))
1560 WLog_Print(gfx->log, WLOG_ERROR,
"rdpgfx_read_rect16 failed with error %" PRIu32
"!",
1565 DEBUG_RDPGFX(gfx->log,
1566 "RecvSurfaceToCachePdu: surfaceId: %" PRIu16
" cacheKey: 0x%016" PRIX64
1567 " cacheSlot: %" PRIu16
" "
1568 "left: %" PRIu16
" top: %" PRIu16
" right: %" PRIu16
" bottom: %" PRIu16
"",
1569 pdu.surfaceId, pdu.cacheKey, pdu.cacheSlot, pdu.rectSrc.left, pdu.rectSrc.top,
1570 pdu.rectSrc.right, pdu.rectSrc.bottom);
1574 IFCALLRET(context->SurfaceToCache, error, context, &pdu);
1577 WLog_Print(gfx->log, WLOG_ERROR,
1578 "context->SurfaceToCache failed with error %" PRIu32
"", error);
1593 WINPR_ASSERT(callback);
1597 RdpgfxClientContext* context = gfx->context;
1598 UINT error = CHANNEL_RC_OK;
1600 if (!Stream_CheckAndLogRequiredLength(TAG, s, 6))
1601 return ERROR_INVALID_DATA;
1603 Stream_Read_UINT16(s, pdu.cacheSlot);
1604 Stream_Read_UINT16(s, pdu.surfaceId);
1605 Stream_Read_UINT16(s, pdu.destPtsCount);
1607 if (!Stream_CheckAndLogRequiredLengthOfSize(TAG, s, pdu.destPtsCount, 4ull))
1608 return ERROR_INVALID_DATA;
1614 WLog_Print(gfx->log, WLOG_ERROR,
"calloc failed!");
1615 return CHANNEL_RC_NO_MEMORY;
1618 for (UINT16 index = 0; index < pdu.destPtsCount; index++)
1620 destPt = &(pdu.destPts[index]);
1622 if ((error = rdpgfx_read_point16(s, destPt)))
1624 WLog_Print(gfx->log, WLOG_ERROR,
"rdpgfx_read_point16 failed with error %" PRIu32
"",
1631 DEBUG_RDPGFX(gfx->log,
1632 "RdpGfxRecvCacheToSurfacePdu: cacheSlot: %" PRIu16
" surfaceId: %" PRIu16
1633 " destPtsCount: %" PRIu16
"",
1634 pdu.cacheSlot, pdu.surfaceId, pdu.destPtsCount);
1638 IFCALLRET(context->CacheToSurface, error, context, &pdu);
1641 WLog_Print(gfx->log, WLOG_ERROR,
1642 "context->CacheToSurface failed with error %" PRIu32
"", error);
1657 WINPR_ASSERT(callback);
1661 RdpgfxClientContext* context = gfx->context;
1662 UINT error = CHANNEL_RC_OK;
1664 if (!Stream_CheckAndLogRequiredLength(TAG, s, 12))
1665 return ERROR_INVALID_DATA;
1667 Stream_Read_UINT16(s, pdu.surfaceId);
1668 Stream_Read_UINT16(s, pdu.reserved);
1669 Stream_Read_UINT32(s, pdu.outputOriginX);
1670 Stream_Read_UINT32(s, pdu.outputOriginY);
1671 DEBUG_RDPGFX(gfx->log,
1672 "RecvMapSurfaceToOutputPdu: surfaceId: %" PRIu16
" outputOriginX: %" PRIu32
1673 " outputOriginY: %" PRIu32
"",
1674 pdu.surfaceId, pdu.outputOriginX, pdu.outputOriginY);
1678 IFCALLRET(context->MapSurfaceToOutput, error, context, &pdu);
1681 WLog_Print(gfx->log, WLOG_ERROR,
1682 "context->MapSurfaceToOutput failed with error %" PRIu32
"", error);
1692 WINPR_ASSERT(callback);
1696 RdpgfxClientContext* context = gfx->context;
1697 UINT error = CHANNEL_RC_OK;
1699 if (!Stream_CheckAndLogRequiredLength(TAG, s, 20))
1700 return ERROR_INVALID_DATA;
1702 Stream_Read_UINT16(s, pdu.surfaceId);
1703 Stream_Read_UINT16(s, pdu.reserved);
1704 Stream_Read_UINT32(s, pdu.outputOriginX);
1705 Stream_Read_UINT32(s, pdu.outputOriginY);
1706 Stream_Read_UINT32(s, pdu.targetWidth);
1707 Stream_Read_UINT32(s, pdu.targetHeight);
1708 DEBUG_RDPGFX(gfx->log,
1709 "RecvMapSurfaceToScaledOutputPdu: surfaceId: %" PRIu16
" outputOriginX: %" PRIu32
1710 " outputOriginY: %" PRIu32
" targetWidth: %" PRIu32
" targetHeight: %" PRIu32,
1711 pdu.surfaceId, pdu.outputOriginX, pdu.outputOriginY, pdu.targetWidth,
1716 IFCALLRET(context->MapSurfaceToScaledOutput, error, context, &pdu);
1719 WLog_Print(gfx->log, WLOG_ERROR,
1720 "context->MapSurfaceToScaledOutput failed with error %" PRIu32
"", error);
1734 WINPR_ASSERT(callback);
1738 RdpgfxClientContext* context = gfx->context;
1739 UINT error = CHANNEL_RC_OK;
1741 if (!Stream_CheckAndLogRequiredLength(TAG, s, 18))
1742 return ERROR_INVALID_DATA;
1744 Stream_Read_UINT16(s, pdu.surfaceId);
1745 Stream_Read_UINT64(s, pdu.windowId);
1746 Stream_Read_UINT32(s, pdu.mappedWidth);
1747 Stream_Read_UINT32(s, pdu.mappedHeight);
1748 DEBUG_RDPGFX(gfx->log,
1749 "RecvMapSurfaceToWindowPdu: surfaceId: %" PRIu16
" windowId: 0x%016" PRIX64
1750 " mappedWidth: %" PRIu32
" mappedHeight: %" PRIu32
"",
1751 pdu.surfaceId, pdu.windowId, pdu.mappedWidth, pdu.mappedHeight);
1753 if (context && context->MapSurfaceToWindow)
1755 IFCALLRET(context->MapSurfaceToWindow, error, context, &pdu);
1758 WLog_Print(gfx->log, WLOG_ERROR,
1759 "context->MapSurfaceToWindow failed with error %" PRIu32
"", error);
1769 WINPR_ASSERT(callback);
1772 RdpgfxClientContext* context = gfx->context;
1773 UINT error = CHANNEL_RC_OK;
1775 if (!Stream_CheckAndLogRequiredLength(TAG, s, 26))
1776 return ERROR_INVALID_DATA;
1778 Stream_Read_UINT16(s, pdu.surfaceId);
1779 Stream_Read_UINT64(s, pdu.windowId);
1780 Stream_Read_UINT32(s, pdu.mappedWidth);
1781 Stream_Read_UINT32(s, pdu.mappedHeight);
1782 Stream_Read_UINT32(s, pdu.targetWidth);
1783 Stream_Read_UINT32(s, pdu.targetHeight);
1784 DEBUG_RDPGFX(gfx->log,
1785 "RecvMapSurfaceToScaledWindowPdu: surfaceId: %" PRIu16
" windowId: 0x%016" PRIX64
1786 " mappedWidth: %" PRIu32
" mappedHeight: %" PRIu32
" targetWidth: %" PRIu32
1787 " targetHeight: %" PRIu32
"",
1788 pdu.surfaceId, pdu.windowId, pdu.mappedWidth, pdu.mappedHeight, pdu.targetWidth,
1791 if (context && context->MapSurfaceToScaledWindow)
1793 IFCALLRET(context->MapSurfaceToScaledWindow, error, context, &pdu);
1796 WLog_Print(gfx->log, WLOG_ERROR,
1797 "context->MapSurfaceToScaledWindow failed with error %" PRIu32
"", error);
1813 WINPR_ASSERT(callback);
1815 const size_t beg = Stream_GetPosition(s);
1818 if ((error = rdpgfx_read_header(s, &header)))
1820 WLog_Print(gfx->log, WLOG_ERROR,
"rdpgfx_read_header failed with error %" PRIu32
"!",
1826 gfx->log,
"cmdId: %s (0x%04" PRIX16
") flags: 0x%04" PRIX16
" pduLength: %" PRIu32
"",
1827 rdpgfx_get_cmd_id_string(header.cmdId), header.cmdId, header.flags, header.pduLength);
1829 switch (header.cmdId)
1831 case RDPGFX_CMDID_WIRETOSURFACE_1:
1832 if ((error = rdpgfx_recv_wire_to_surface_1_pdu(callback, s)))
1833 WLog_Print(gfx->log, WLOG_ERROR,
1834 "rdpgfx_recv_wire_to_surface_1_pdu failed with error %" PRIu32
"!",
1839 case RDPGFX_CMDID_WIRETOSURFACE_2:
1840 if ((error = rdpgfx_recv_wire_to_surface_2_pdu(callback, s)))
1841 WLog_Print(gfx->log, WLOG_ERROR,
1842 "rdpgfx_recv_wire_to_surface_2_pdu failed with error %" PRIu32
"!",
1847 case RDPGFX_CMDID_DELETEENCODINGCONTEXT:
1848 if ((error = rdpgfx_recv_delete_encoding_context_pdu(callback, s)))
1849 WLog_Print(gfx->log, WLOG_ERROR,
1850 "rdpgfx_recv_delete_encoding_context_pdu failed with error %" PRIu32
"!",
1855 case RDPGFX_CMDID_SOLIDFILL:
1856 if ((error = rdpgfx_recv_solid_fill_pdu(callback, s)))
1857 WLog_Print(gfx->log, WLOG_ERROR,
1858 "rdpgfx_recv_solid_fill_pdu failed with error %" PRIu32
"!", error);
1862 case RDPGFX_CMDID_SURFACETOSURFACE:
1863 if ((error = rdpgfx_recv_surface_to_surface_pdu(callback, s)))
1864 WLog_Print(gfx->log, WLOG_ERROR,
1865 "rdpgfx_recv_surface_to_surface_pdu failed with error %" PRIu32
"!",
1870 case RDPGFX_CMDID_SURFACETOCACHE:
1871 if ((error = rdpgfx_recv_surface_to_cache_pdu(callback, s)))
1872 WLog_Print(gfx->log, WLOG_ERROR,
1873 "rdpgfx_recv_surface_to_cache_pdu failed with error %" PRIu32
"!",
1878 case RDPGFX_CMDID_CACHETOSURFACE:
1879 if ((error = rdpgfx_recv_cache_to_surface_pdu(callback, s)))
1880 WLog_Print(gfx->log, WLOG_ERROR,
1881 "rdpgfx_recv_cache_to_surface_pdu failed with error %" PRIu32
"!",
1886 case RDPGFX_CMDID_EVICTCACHEENTRY:
1887 if ((error = rdpgfx_recv_evict_cache_entry_pdu(callback, s)))
1888 WLog_Print(gfx->log, WLOG_ERROR,
1889 "rdpgfx_recv_evict_cache_entry_pdu failed with error %" PRIu32
"!",
1894 case RDPGFX_CMDID_CREATESURFACE:
1895 if ((error = rdpgfx_recv_create_surface_pdu(callback, s)))
1896 WLog_Print(gfx->log, WLOG_ERROR,
1897 "rdpgfx_recv_create_surface_pdu failed with error %" PRIu32
"!", error);
1901 case RDPGFX_CMDID_DELETESURFACE:
1902 if ((error = rdpgfx_recv_delete_surface_pdu(callback, s)))
1903 WLog_Print(gfx->log, WLOG_ERROR,
1904 "rdpgfx_recv_delete_surface_pdu failed with error %" PRIu32
"!", error);
1908 case RDPGFX_CMDID_STARTFRAME:
1909 if ((error = rdpgfx_recv_start_frame_pdu(callback, s)))
1910 WLog_Print(gfx->log, WLOG_ERROR,
1911 "rdpgfx_recv_start_frame_pdu failed with error %" PRIu32
"!", error);
1915 case RDPGFX_CMDID_ENDFRAME:
1916 if ((error = rdpgfx_recv_end_frame_pdu(callback, s)))
1917 WLog_Print(gfx->log, WLOG_ERROR,
1918 "rdpgfx_recv_end_frame_pdu failed with error %" PRIu32
"!", error);
1922 case RDPGFX_CMDID_RESETGRAPHICS:
1923 if ((error = rdpgfx_recv_reset_graphics_pdu(callback, s)))
1924 WLog_Print(gfx->log, WLOG_ERROR,
1925 "rdpgfx_recv_reset_graphics_pdu failed with error %" PRIu32
"!", error);
1929 case RDPGFX_CMDID_MAPSURFACETOOUTPUT:
1930 if ((error = rdpgfx_recv_map_surface_to_output_pdu(callback, s)))
1931 WLog_Print(gfx->log, WLOG_ERROR,
1932 "rdpgfx_recv_map_surface_to_output_pdu failed with error %" PRIu32
"!",
1937 case RDPGFX_CMDID_CACHEIMPORTREPLY:
1938 if ((error = rdpgfx_recv_cache_import_reply_pdu(callback, s)))
1939 WLog_Print(gfx->log, WLOG_ERROR,
1940 "rdpgfx_recv_cache_import_reply_pdu failed with error %" PRIu32
"!",
1945 case RDPGFX_CMDID_CAPSCONFIRM:
1946 if ((error = rdpgfx_recv_caps_confirm_pdu(callback, s)))
1947 WLog_Print(gfx->log, WLOG_ERROR,
1948 "rdpgfx_recv_caps_confirm_pdu failed with error %" PRIu32
"!", error);
1950 if ((error = rdpgfx_send_cache_offer(gfx)))
1951 WLog_Print(gfx->log, WLOG_ERROR,
1952 "rdpgfx_send_cache_offer failed with error %" PRIu32
"!", error);
1956 case RDPGFX_CMDID_MAPSURFACETOWINDOW:
1957 if ((error = rdpgfx_recv_map_surface_to_window_pdu(callback, s)))
1958 WLog_Print(gfx->log, WLOG_ERROR,
1959 "rdpgfx_recv_map_surface_to_window_pdu failed with error %" PRIu32
"!",
1964 case RDPGFX_CMDID_MAPSURFACETOSCALEDWINDOW:
1965 if ((error = rdpgfx_recv_map_surface_to_scaled_window_pdu(callback, s)))
1966 WLog_Print(gfx->log, WLOG_ERROR,
1967 "rdpgfx_recv_map_surface_to_scaled_window_pdu failed with error %" PRIu32
1973 case RDPGFX_CMDID_MAPSURFACETOSCALEDOUTPUT:
1974 if ((error = rdpgfx_recv_map_surface_to_scaled_output_pdu(callback, s)))
1975 WLog_Print(gfx->log, WLOG_ERROR,
1976 "rdpgfx_recv_map_surface_to_scaled_output_pdu failed with error %" PRIu32
1983 error = CHANNEL_RC_BAD_PROC;
1989 WLog_Print(gfx->log, WLOG_ERROR,
"Error while processing GFX cmdId: %s (0x%04" PRIX16
")",
1990 rdpgfx_get_cmd_id_string(header.cmdId), header.cmdId);
1991 Stream_SetPosition(s, (beg + header.pduLength));
1995 end = Stream_GetPosition(s);
1997 if (end != (beg + header.pduLength))
1999 WLog_Print(gfx->log, WLOG_ERROR,
2000 "Unexpected gfx pdu end: Actual: %" PRIuz
", Expected: %" PRIuz, end,
2001 (beg + header.pduLength));
2002 Stream_SetPosition(s, (beg + header.pduLength));
2013static UINT rdpgfx_on_data_received(IWTSVirtualChannelCallback* pChannelCallback,
wStream* data)
2017 BYTE* pDstData = NULL;
2019 WINPR_ASSERT(callback);
2021 UINT error = CHANNEL_RC_OK;
2024 status = zgfx_decompress(gfx->zgfx, Stream_ConstPointer(data),
2025 (UINT32)Stream_GetRemainingLength(data), &pDstData, &DstSize, 0);
2029 WLog_Print(gfx->log, WLOG_ERROR,
"zgfx_decompress failure! status: %d", status);
2031 return ERROR_INTERNAL_ERROR;
2035 wStream* s = Stream_StaticConstInit(&sbuffer, pDstData, DstSize);
2039 WLog_Print(gfx->log, WLOG_ERROR,
"calloc failed!");
2041 return CHANNEL_RC_NO_MEMORY;
2044 while (Stream_GetPosition(s) < Stream_Length(s))
2046 if ((error = rdpgfx_recv_pdu(callback, s)))
2048 WLog_Print(gfx->log, WLOG_ERROR,
"rdpgfx_recv_pdu failed with error %" PRIu32
"!",
2063static UINT rdpgfx_on_open(IWTSVirtualChannelCallback* pChannelCallback)
2066 WINPR_ASSERT(callback);
2069 RdpgfxClientContext* context = gfx->context;
2070 UINT error = CHANNEL_RC_OK;
2071 BOOL do_caps_advertise = TRUE;
2072 gfx->sendFrameAcks = TRUE;
2076 IFCALLRET(context->OnOpen, error, context, &do_caps_advertise, &gfx->sendFrameAcks);
2079 WLog_Print(gfx->log, WLOG_ERROR,
"context->OnOpen failed with error %" PRIu32
"",
2083 if (do_caps_advertise)
2084 error = rdpgfx_send_supported_caps(callback);
2094static UINT rdpgfx_on_close(IWTSVirtualChannelCallback* pChannelCallback)
2096 UINT error = CHANNEL_RC_OK;
2098 WINPR_ASSERT(callback);
2104 RdpgfxClientContext* context = gfx->context;
2106 DEBUG_RDPGFX(gfx->log,
"OnClose");
2107 error = rdpgfx_save_persistent_cache(gfx);
2112 WLog_Print(gfx->log, WLOG_ERROR,
2113 "rdpgfx_save_persistent_cache failed with error %" PRIu32
"", error);
2116 free_surfaces(context, gfx->SurfaceTable);
2117 evict_cache_slots(context, gfx->MaxCacheSlots, gfx->CacheSlots);
2120 gfx->UnacknowledgedFrames = 0;
2121 gfx->TotalDecodedFrames = 0;
2125 IFCALL(context->OnClose, context);
2129 return CHANNEL_RC_OK;
2136 RdpgfxClientContext* context = gfx->context;
2138 DEBUG_RDPGFX(gfx->log,
"Terminated");
2139 rdpgfx_client_context_free(context);
2147static UINT rdpgfx_set_surface_data(RdpgfxClientContext* context, UINT16 surfaceId,
void* pData)
2150 WINPR_ASSERT(context);
2153 key = ((ULONG_PTR)surfaceId) + 1;
2157 if (!HashTable_Insert(gfx->SurfaceTable, (
void*)key, pData))
2158 return ERROR_BAD_ARGUMENTS;
2161 HashTable_Remove(gfx->SurfaceTable, (
void*)key);
2163 return CHANNEL_RC_OK;
2171static UINT rdpgfx_get_surface_ids(RdpgfxClientContext* context, UINT16** ppSurfaceIds,
2175 UINT16* pSurfaceIds = NULL;
2176 ULONG_PTR* pKeys = NULL;
2177 WINPR_ASSERT(context);
2180 count = HashTable_GetKeys(gfx->SurfaceTable, &pKeys);
2182 WINPR_ASSERT(ppSurfaceIds);
2183 WINPR_ASSERT(count_out);
2187 return CHANNEL_RC_OK;
2190 pSurfaceIds = (UINT16*)calloc(count,
sizeof(UINT16));
2194 WLog_Print(gfx->log, WLOG_ERROR,
"calloc failed!");
2196 return CHANNEL_RC_NO_MEMORY;
2199 for (
size_t index = 0; index < count; index++)
2201 pSurfaceIds[index] = (UINT16)(pKeys[index] - 1);
2205 *ppSurfaceIds = pSurfaceIds;
2206 *count_out = (UINT16)count;
2207 return CHANNEL_RC_OK;
2210static void* rdpgfx_get_surface_data(RdpgfxClientContext* context, UINT16 surfaceId)
2214 WINPR_ASSERT(context);
2217 key = ((ULONG_PTR)surfaceId) + 1;
2218 pData = HashTable_GetItemValue(gfx->SurfaceTable, (
void*)key);
2227static UINT rdpgfx_set_cache_slot_data(RdpgfxClientContext* context, UINT16 cacheSlot,
void* pData)
2229 WINPR_ASSERT(context);
2234 if (cacheSlot == 0 || cacheSlot > gfx->MaxCacheSlots)
2236 WLog_ERR(TAG,
"invalid cache slot %" PRIu16
", must be between 1 and %" PRIu16
"",
2237 cacheSlot, gfx->MaxCacheSlots);
2238 return ERROR_INVALID_INDEX;
2241 gfx->CacheSlots[cacheSlot - 1] = pData;
2242 return CHANNEL_RC_OK;
2245static void* rdpgfx_get_cache_slot_data(RdpgfxClientContext* context, UINT16 cacheSlot)
2248 WINPR_ASSERT(context);
2252 if (cacheSlot == 0 || cacheSlot > gfx->MaxCacheSlots)
2254 WLog_ERR(TAG,
"invalid cache slot %" PRIu16
", must be between 1 and %" PRIu16
"",
2255 cacheSlot, gfx->MaxCacheSlots);
2259 pData = gfx->CacheSlots[cacheSlot - 1];
2264 WINPR_ATTR_UNUSED rdpSettings* settings)
2266 RdpgfxClientContext* context = NULL;
2270 gfx->rdpcontext = rcontext;
2271 gfx->log = WLog_Get(TAG);
2273 gfx->SurfaceTable = HashTable_New(TRUE);
2274 if (!gfx->SurfaceTable)
2276 WLog_ERR(TAG,
"HashTable_New for surfaces failed !");
2277 return CHANNEL_RC_NO_MEMORY;
2280 gfx->suspendFrameAcks =
2282 gfx->MaxCacheSlots =
2285 context = (RdpgfxClientContext*)calloc(1,
sizeof(RdpgfxClientContext));
2288 WLog_ERR(TAG,
"context calloc failed!");
2289 HashTable_Free(gfx->SurfaceTable);
2290 gfx->SurfaceTable = NULL;
2291 return CHANNEL_RC_NO_MEMORY;
2294 gfx->zgfx = zgfx_context_new(FALSE);
2297 WLog_ERR(TAG,
"zgfx_context_new failed!");
2298 HashTable_Free(gfx->SurfaceTable);
2299 gfx->SurfaceTable = NULL;
2301 return CHANNEL_RC_NO_MEMORY;
2304 context->handle = (
void*)gfx;
2305 context->GetSurfaceIds = rdpgfx_get_surface_ids;
2306 context->SetSurfaceData = rdpgfx_set_surface_data;
2307 context->GetSurfaceData = rdpgfx_get_surface_data;
2308 context->SetCacheSlotData = rdpgfx_set_cache_slot_data;
2309 context->GetCacheSlotData = rdpgfx_get_cache_slot_data;
2310 context->CapsAdvertise = rdpgfx_send_caps_advertise_pdu;
2311 context->FrameAcknowledge = rdpgfx_send_frame_acknowledge_pdu;
2312 context->CacheImportOffer = rdpgfx_send_cache_import_offer_pdu;
2313 context->QoeFrameAcknowledge = rdpgfx_send_qoe_frame_acknowledge_pdu;
2315 gfx->base.iface.pInterface = (
void*)context;
2316 gfx->context = context;
2317 return CHANNEL_RC_OK;
2320void rdpgfx_client_context_free(RdpgfxClientContext* context)
2330 free_surfaces(context, gfx->SurfaceTable);
2331 evict_cache_slots(context, gfx->MaxCacheSlots, gfx->CacheSlots);
2335 zgfx_context_free(gfx->zgfx);
2339 HashTable_Free(gfx->SurfaceTable);
2343static const IWTSVirtualChannelCallback rdpgfx_callbacks = { rdpgfx_on_data_received,
2344 rdpgfx_on_open, rdpgfx_on_close,
2352FREERDP_ENTRY_POINT(UINT VCAPITYPE rdpgfx_DVCPluginEntry(IDRDYNVC_ENTRY_POINTS* pEntryPoints))
2354 return freerdp_generic_DVCPluginEntry(pEntryPoints, TAG, RDPGFX_DVC_CHANNEL_NAME,
2356 &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.