20#include <freerdp/config.h>
22#include <winpr/assert.h>
27#include <winpr/cast.h>
29#include <winpr/synch.h>
30#include <winpr/thread.h>
31#include <winpr/stream.h>
33#include <freerdp/freerdp.h>
34#include <freerdp/codec/color.h>
36#include <freerdp/channels/wtsvc.h>
37#include <freerdp/channels/log.h>
39#include "rdpgfx_common.h"
40#include "rdpgfx_main.h"
42#define TAG CHANNELS_TAG("rdpgfx.server")
44static BOOL rdpgfx_server_close(RdpgfxServerContext* context);
46#define checkCapsAreExchanged(context) \
47 checkCapsAreExchangedInt(context, __FILE__, __func__, __LINE__)
48WINPR_ATTR_NODISCARD
static BOOL checkCapsAreExchangedInt(RdpgfxServerContext* context,
49 const char* file,
const char* fkt,
52 WINPR_ASSERT(context);
53 WINPR_ASSERT(context->priv);
55 const DWORD level = WLOG_TRACE;
56 if (WLog_IsLevelActive(context->priv->log, level))
58 WLog_PrintTextMessage(context->priv->log, level, line, file, fkt,
59 "activeCapSet{Version=0x%08" PRIx32
", flags=0x%08" PRIx32
"}",
60 context->priv->activeCapSet.version,
61 context->priv->activeCapSet.flags);
63 return context->priv->activeCapSet.version > 0;
75WINPR_ATTR_NODISCARD
static inline size_t rdpgfx_pdu_length(
size_t dataLen)
77 return RDPGFX_HEADER_SIZE + dataLen;
80WINPR_ATTR_NODISCARD
static inline UINT rdpgfx_server_packet_init_header(
wStream* s, UINT16 cmdId,
85 .pduLength = WINPR_ASSERTING_INT_CAST(UINT32, pduLength) };
88 return rdpgfx_write_header(s, &header);
98WINPR_ATTR_NODISCARD
static inline BOOL rdpgfx_server_packet_complete_header(
wStream* s,
101 const size_t current = Stream_GetPosition(s);
102 const size_t cap = Stream_Capacity(s);
103 if (cap < start + RDPGFX_HEADER_SIZE)
105 if ((start > UINT32_MAX) || (current < start))
108 if (!Stream_SetPosition(s, start + RDPGFX_HEADER_SIZE -
sizeof(UINT32)))
110 Stream_Write_UINT32(s, (UINT32)(current - start));
111 return Stream_SetPosition(s, current);
121WINPR_ATTR_NODISCARD
static UINT rdpgfx_server_packet_send(RdpgfxServerContext* context,
wStream* s)
126 BYTE* pSrcData = Stream_Buffer(s);
127 const size_t SrcSize = Stream_GetPosition(s);
128 if (SrcSize > UINT32_MAX)
129 return ERROR_INTERNAL_ERROR;
131 WINPR_ASSERT(context);
132 WINPR_ASSERT(context->priv);
137 wStream* fs = Stream_New(
nullptr, SrcSize + 7 + (SrcSize / ZGFX_SEGMENTED_MAXSIZE + 1) * 4);
141 WLog_Print(context->priv->log, WLOG_ERROR,
"Stream_New failed!");
142 error = CHANNEL_RC_NO_MEMORY;
146 if (zgfx_compress_to_stream(context->priv->zgfx, fs, pSrcData, (UINT32)SrcSize, &flags) < 0)
148 WLog_Print(context->priv->log, WLOG_ERROR,
"zgfx_compress_to_stream failed!");
149 error = ERROR_INTERNAL_ERROR;
154 const size_t pos = Stream_GetPosition(fs);
155 WINPR_ASSERT(pos <= UINT32_MAX);
156 if (!WTSVirtualChannelWrite(context->priv->rdpgfx_channel, Stream_BufferAs(fs,
char),
157 (UINT32)pos, &written))
159 WLog_Print(context->priv->log, WLOG_ERROR,
"WTSVirtualChannelWrite failed!");
160 error = ERROR_INTERNAL_ERROR;
165 if (written < Stream_GetPosition(fs))
167 WLog_Print(context->priv->log, WLOG_WARN,
168 "Unexpected bytes written: %" PRIu32
"/%" PRIuz
"", written,
169 Stream_GetPosition(fs));
172 error = CHANNEL_RC_OK;
174 Stream_Free(fs, TRUE);
175 Stream_Free(s, TRUE);
191WINPR_ATTR_MALLOC(Stream_Free, 1)
192static
wStream* rdpgfx_server_single_packet_new(wLog* log, UINT16 cmdId,
size_t dataLen)
195 const size_t pduLength = rdpgfx_pdu_length(dataLen);
196 wStream* s = Stream_New(
nullptr, pduLength);
200 WLog_Print(log, WLOG_ERROR,
"Stream_New failed!");
204 if ((error = rdpgfx_server_packet_init_header(s, cmdId, pduLength)))
206 WLog_Print(log, WLOG_ERROR,
"Failed to init header with error %" PRIu32
"!", error);
212 Stream_Free(s, TRUE);
224WINPR_ATTR_NODISCARD
static inline UINT
225rdpgfx_server_single_packet_send(RdpgfxServerContext* context,
wStream* s)
228 if (!rdpgfx_server_packet_complete_header(s, 0))
229 return ERROR_INTERNAL_ERROR;
230 return rdpgfx_server_packet_send(context, s);
238WINPR_ATTR_NODISCARD
static UINT
239rdpgfx_send_caps_confirm_pdu(RdpgfxServerContext* context,
242 WINPR_ASSERT(context);
243 WINPR_ASSERT(context->priv);
244 WINPR_ASSERT(capsConfirm);
247 WINPR_ASSERT(capsSet);
249 wStream* s = rdpgfx_server_single_packet_new(context->priv->log, RDPGFX_CMDID_CAPSCONFIRM,
250 RDPGFX_CAPSET_BASE_SIZE + capsSet->length);
254 WLog_Print(context->priv->log, WLOG_ERROR,
"rdpgfx_server_single_packet_new failed!");
255 return CHANNEL_RC_NO_MEMORY;
258 WLog_Print(context->priv->log, WLOG_DEBUG,
259 "CAPS version=0x%04" PRIx32
", flags=0x%04" PRIx32
", length=%" PRIu32,
260 capsSet->version, capsSet->flags, capsSet->length);
261 Stream_Write_UINT32(s, capsSet->version);
262 Stream_Write_UINT32(s, capsSet->length);
264 if (capsSet->length >= 4)
266 Stream_Write_UINT32(s, capsSet->flags);
267 Stream_Zero(s, capsSet->length - 4);
270 Stream_Zero(s, capsSet->length);
272 context->priv->activeCapSet = *capsSet;
273 return rdpgfx_server_single_packet_send(context, s);
281WINPR_ATTR_NODISCARD
static UINT
284 const size_t RDPGFX_RESET_GRAPHICS_PDU_SIZE = 340;
286 if (!checkCapsAreExchanged(context))
287 return CHANNEL_RC_NOT_INITIALIZED;
290 WINPR_ASSERT(context->priv);
293 if (pdu->monitorCount >= 16)
295 WLog_Print(context->priv->log, WLOG_ERROR,
296 "Monitor count MUST be less than or equal to 16: %" PRIu32
"",
298 return ERROR_INVALID_DATA;
302 rdpgfx_server_single_packet_new(context->priv->log, RDPGFX_CMDID_RESETGRAPHICS,
303 RDPGFX_RESET_GRAPHICS_PDU_SIZE - RDPGFX_HEADER_SIZE);
307 WLog_Print(context->priv->log, WLOG_ERROR,
"rdpgfx_server_single_packet_new failed!");
308 return CHANNEL_RC_NO_MEMORY;
311 Stream_Write_UINT32(s, pdu->width);
312 Stream_Write_UINT32(s, pdu->height);
313 Stream_Write_UINT32(s, pdu->monitorCount);
315 for (UINT32 index = 0; index < pdu->monitorCount; index++)
317 const MONITOR_DEF* monitor = &(pdu->monitorDefArray[index]);
318 Stream_Write_INT32(s, monitor->left);
319 Stream_Write_INT32(s, monitor->top);
320 Stream_Write_INT32(s, monitor->right);
321 Stream_Write_INT32(s, monitor->bottom);
322 Stream_Write_UINT32(s, monitor->flags);
326 const size_t pos = Stream_GetPosition(s);
327 if (pos > RDPGFX_RESET_GRAPHICS_PDU_SIZE)
329 Stream_Free(s, TRUE);
330 return ERROR_INVALID_DATA;
332 if (!Stream_SafeZero(s, RDPGFX_RESET_GRAPHICS_PDU_SIZE - pos))
334 Stream_Free(s, TRUE);
335 return ERROR_INVALID_DATA;
337 return rdpgfx_server_single_packet_send(context, s);
345WINPR_ATTR_NODISCARD
static UINT
346rdpgfx_send_evict_cache_entry_pdu(RdpgfxServerContext* context,
349 if (!checkCapsAreExchanged(context))
350 return CHANNEL_RC_NOT_INITIALIZED;
353 WINPR_ASSERT(context->priv);
355 rdpgfx_server_single_packet_new(context->priv->log, RDPGFX_CMDID_EVICTCACHEENTRY, 2);
359 WLog_Print(context->priv->log, WLOG_ERROR,
"rdpgfx_server_single_packet_new failed!");
360 return CHANNEL_RC_NO_MEMORY;
363 Stream_Write_UINT16(s, pdu->cacheSlot);
364 return rdpgfx_server_single_packet_send(context, s);
372WINPR_ATTR_NODISCARD
static UINT
373rdpgfx_send_cache_import_reply_pdu(RdpgfxServerContext* context,
376 if (!checkCapsAreExchanged(context))
377 return CHANNEL_RC_NOT_INITIALIZED;
378 WINPR_ASSERT(context);
379 WINPR_ASSERT(context->priv);
382 WLog_Print(context->priv->log, WLOG_DEBUG,
"reply with %" PRIu16
" entries",
383 pdu->importedEntriesCount);
384 wStream* s = rdpgfx_server_single_packet_new(context->priv->log, RDPGFX_CMDID_CACHEIMPORTREPLY,
385 2 + 2 * pdu->importedEntriesCount);
389 WLog_Print(context->priv->log, WLOG_ERROR,
"rdpgfx_server_single_packet_new failed!");
390 return CHANNEL_RC_NO_MEMORY;
394 Stream_Write_UINT16(s, pdu->importedEntriesCount);
396 for (UINT16 index = 0; index < pdu->importedEntriesCount; index++)
398 Stream_Write_UINT16(s, pdu->cacheSlots[index]);
401 return rdpgfx_server_single_packet_send(context, s);
404WINPR_ATTR_NODISCARD
static UINT
405rdpgfx_process_cache_import_offer_pdu(RdpgfxServerContext* context,
408 if (!checkCapsAreExchanged(context))
409 return CHANNEL_RC_NOT_INITIALIZED;
410 WINPR_ASSERT(context);
411 WINPR_ASSERT(context->priv);
412 WINPR_ASSERT(cacheImportOffer);
415 WLog_Print(context->priv->log, WLOG_DEBUG,
416 "received %" PRIu16
" entries, reply with %" PRIu16
" entries",
417 cacheImportOffer->cacheEntriesCount, reply.importedEntriesCount);
418 return IFCALLRESULT(CHANNEL_RC_OK, context->CacheImportReply, context, &reply);
426WINPR_ATTR_NODISCARD
static UINT
429 if (!checkCapsAreExchanged(context))
430 return CHANNEL_RC_NOT_INITIALIZED;
432 WINPR_ASSERT(context->priv);
433 wStream* s = rdpgfx_server_single_packet_new(context->priv->log, RDPGFX_CMDID_CREATESURFACE, 7);
435 WINPR_ASSERT(context);
437 WINPR_ASSERT((pdu->pixelFormat == GFX_PIXEL_FORMAT_XRGB_8888) ||
438 (pdu->pixelFormat == GFX_PIXEL_FORMAT_ARGB_8888));
442 WLog_Print(context->priv->log, WLOG_ERROR,
"rdpgfx_server_single_packet_new failed!");
443 return CHANNEL_RC_NO_MEMORY;
446 Stream_Write_UINT16(s, pdu->surfaceId);
447 Stream_Write_UINT16(s, pdu->width);
448 Stream_Write_UINT16(s, pdu->height);
449 Stream_Write_UINT8(s, pdu->pixelFormat);
450 return rdpgfx_server_single_packet_send(context, s);
458WINPR_ATTR_NODISCARD
static UINT
461 if (!checkCapsAreExchanged(context))
462 return CHANNEL_RC_NOT_INITIALIZED;
465 WINPR_ASSERT(context->priv);
466 wStream* s = rdpgfx_server_single_packet_new(context->priv->log, RDPGFX_CMDID_DELETESURFACE, 2);
470 WLog_Print(context->priv->log, WLOG_ERROR,
"rdpgfx_server_single_packet_new failed!");
471 return CHANNEL_RC_NO_MEMORY;
474 Stream_Write_UINT16(s, pdu->surfaceId);
475 return rdpgfx_server_single_packet_send(context, s);
478WINPR_ATTR_NODISCARD
static inline BOOL
481 if (!Stream_EnsureRemainingCapacity(s, 8))
485 Stream_Write_UINT32(s, pdu->timestamp);
486 Stream_Write_UINT32(s, pdu->frameId);
490WINPR_ATTR_NODISCARD
static inline BOOL rdpgfx_write_end_frame_pdu(
wStream* s,
493 if (!Stream_EnsureRemainingCapacity(s, 4))
496 Stream_Write_UINT32(s, pdu->frameId);
505WINPR_ATTR_NODISCARD
static UINT rdpgfx_send_start_frame_pdu(RdpgfxServerContext* context,
508 if (!checkCapsAreExchanged(context))
509 return CHANNEL_RC_NOT_INITIALIZED;
512 WINPR_ASSERT(context->priv);
513 wStream* s = rdpgfx_server_single_packet_new(context->priv->log, RDPGFX_CMDID_STARTFRAME,
514 RDPGFX_START_FRAME_PDU_SIZE);
518 WLog_Print(context->priv->log, WLOG_ERROR,
"rdpgfx_server_single_packet_new failed!");
519 return CHANNEL_RC_NO_MEMORY;
522 if (!rdpgfx_write_start_frame_pdu(s, pdu))
524 Stream_Free(s, TRUE);
525 return ERROR_INTERNAL_ERROR;
527 return rdpgfx_server_single_packet_send(context, s);
535WINPR_ATTR_NODISCARD
static UINT rdpgfx_send_end_frame_pdu(RdpgfxServerContext* context,
538 if (!checkCapsAreExchanged(context))
539 return CHANNEL_RC_NOT_INITIALIZED;
542 WINPR_ASSERT(context->priv);
543 wStream* s = rdpgfx_server_single_packet_new(context->priv->log, RDPGFX_CMDID_ENDFRAME,
544 RDPGFX_END_FRAME_PDU_SIZE);
548 WLog_Print(context->priv->log, WLOG_ERROR,
"rdpgfx_server_single_packet_new failed!");
549 return CHANNEL_RC_NO_MEMORY;
552 if (!rdpgfx_write_end_frame_pdu(s, pdu))
554 Stream_Free(s, TRUE);
555 return ERROR_INTERNAL_ERROR;
557 return rdpgfx_server_single_packet_send(context, s);
566WINPR_ATTR_NODISCARD
static inline UINT32
569 WINPR_ASSERT(havc420);
571 return sizeof(UINT32)
573 * havc420->meta.numRegionRects +
577#if defined(WITH_GFX_AZURE)
578WINPR_ATTR_NODISCARD
static inline UINT32
583 UINT32 len =
sizeof(UINT32)
585 * hevc->meta.numRegionRects +
587 hevc->cbNalSizes + hevc->length;
588 if (hevc->frameAttributes >= 0)
600WINPR_ATTR_NODISCARD
static inline UINT32
610 switch (cmd->codecId)
612 case RDPGFX_CODECID_CAPROGRESSIVE:
613 case RDPGFX_CODECID_CAPROGRESSIVE_V2:
614 return RDPGFX_WIRE_TO_SURFACE_PDU_2_SIZE + cmd->length;
616#if defined(WITH_GFX_AZURE)
617 case RDPGFX_CODECID_HEVC420:
618 case RDPGFX_CODECID_HEVC444:
621 const UINT32 hevcSize = rdpgfx_estimate_hevc(hevc);
622 return RDPGFX_WIRE_TO_SURFACE_PDU_1_SIZE + hevcSize;
626#if defined(WITH_GFX_AV1) || defined(WITH_GFX_AV2)
627 case RDPGFX_CODECID_AV1:
629 case RDPGFX_CODECID_AVC420:
631 h264Size = rdpgfx_estimate_h264_avc420(havc420);
632 return RDPGFX_WIRE_TO_SURFACE_PDU_1_SIZE + h264Size;
634 case RDPGFX_CODECID_AVC444:
636 h264Size =
sizeof(UINT32);
638 havc420 = &(havc444->bitstream[0]);
639 h264Size += rdpgfx_estimate_h264_avc420(havc420);
642 if (havc444->LC == 0)
644 havc420 = &(havc444->bitstream[1]);
645 h264Size += rdpgfx_estimate_h264_avc420(havc420);
648 return RDPGFX_WIRE_TO_SURFACE_PDU_1_SIZE + h264Size;
651 return RDPGFX_WIRE_TO_SURFACE_PDU_1_SIZE + cmd->length;
662WINPR_ATTR_NODISCARD
static inline UINT16
667 if (cmd->codecId == RDPGFX_CODECID_CAPROGRESSIVE ||
668 cmd->codecId == RDPGFX_CODECID_CAPROGRESSIVE_V2)
670 return RDPGFX_CMDID_WIRETOSURFACE_2;
673 return RDPGFX_CMDID_WIRETOSURFACE_1;
681WINPR_ATTR_NODISCARD
static UINT rdpgfx_write_h264_metablock(wLog* log,
wStream* s,
686 UINT error = CHANNEL_RC_OK;
689 if (!Stream_EnsureRemainingCapacity(s, 4ull + meta->numRegionRects * 10ull))
690 return ERROR_OUTOFMEMORY;
692 Stream_Write_UINT32(s, meta->numRegionRects);
694 for (UINT32 index = 0; index < meta->numRegionRects; index++)
696 regionRect = &(meta->regionRects[index]);
698 if ((error = rdpgfx_write_rect16(s, regionRect)))
700 WLog_Print(log, WLOG_ERROR,
"rdpgfx_write_rect16 failed with error %" PRIu32
"!",
706 for (UINT32 index = 0; index < meta->numRegionRects; index++)
708 quantQualityVal = &(meta->quantQualityVals[index]);
709 Stream_Write_UINT8(s, WINPR_ASSERTING_INT_CAST(
710 uint8_t, quantQualityVal->qp | (quantQualityVal->r << 6) |
711 (quantQualityVal->p << 7)));
713 Stream_Write_UINT8(s, quantQualityVal->qualityVal);
725WINPR_ATTR_NODISCARD
static inline UINT
728 WINPR_ASSERT(havc420);
729 const UINT error = rdpgfx_write_h264_metablock(log, s, &(havc420->meta));
731 if (error != CHANNEL_RC_OK)
733 WLog_Print(log, WLOG_ERROR,
"rdpgfx_write_h264_metablock failed with error %" PRIu32
"!",
738 if (!Stream_EnsureRemainingCapacity(s, havc420->length))
739 return ERROR_OUTOFMEMORY;
741 Stream_Write(s, havc420->data, havc420->length);
745#if defined(WITH_GFX_AZURE)
746WINPR_ATTR_NODISCARD
static inline UINT rdpgfx_write_hevc(wLog* log,
wStream* s,
750 const UINT error = rdpgfx_write_h264_metablock(log, s, &(hevc->meta));
752 if (error != CHANNEL_RC_OK)
754 WLog_Print(log, WLOG_ERROR,
"rdpgfx_write_h264_metablock failed with error %" PRIu32
"!",
759 if (!Stream_EnsureRemainingCapacity(s,
sizeof(UINT32)))
760 return ERROR_OUTOFMEMORY;
761 Stream_Write_UINT32(s, hevc->cbNalSizes);
763 if (!Stream_EnsureRemainingCapacity(s, hevc->cbNalSizes))
764 return ERROR_OUTOFMEMORY;
766 for (
size_t x = 0; x < hevc->cbNalSizes / 4; x++)
767 Stream_Write_UINT32(s, hevc->nalSize[x]);
769 if (hevc->frameAttributes >= 0)
771 if (!Stream_EnsureRemainingCapacity(s, 1))
772 return ERROR_OUTOFMEMORY;
774 Stream_Write_UINT8(s, hevc->frameAttributes & 0xff);
777 if (!Stream_EnsureRemainingCapacity(s, hevc->length))
778 return ERROR_OUTOFMEMORY;
780 Stream_Write(s, hevc->data, hevc->length);
792WINPR_ATTR_NODISCARD
static UINT rdpgfx_write_surface_command(wLog* log,
wStream* s,
795 UINT error = CHANNEL_RC_OK;
798 UINT8 pixelFormat = 0;
803 case PIXEL_FORMAT_BGRX32:
804 pixelFormat = GFX_PIXEL_FORMAT_XRGB_8888;
807 case PIXEL_FORMAT_BGRA32:
808 pixelFormat = GFX_PIXEL_FORMAT_ARGB_8888;
812 WLog_Print(log, WLOG_ERROR,
"Format %s not supported!",
813 FreeRDPGetColorFormatName(cmd->format));
814 return ERROR_INVALID_DATA;
817 if (cmd->codecId == RDPGFX_CODECID_CAPROGRESSIVE ||
818 cmd->codecId == RDPGFX_CODECID_CAPROGRESSIVE_V2)
820 if (!Stream_EnsureRemainingCapacity(s, 13ull + cmd->length))
821 return ERROR_INTERNAL_ERROR;
824 s, WINPR_ASSERTING_INT_CAST(uint16_t, cmd->surfaceId));
826 s, WINPR_ASSERTING_INT_CAST(uint16_t, cmd->codecId));
827 Stream_Write_UINT32(s, cmd->contextId);
828 Stream_Write_UINT8(s, pixelFormat);
829 Stream_Write_UINT32(s, cmd->length);
830 Stream_Write(s, cmd->data, cmd->length);
835 if (!Stream_EnsureRemainingCapacity(s, 17))
836 return ERROR_INTERNAL_ERROR;
838 s, WINPR_ASSERTING_INT_CAST(uint16_t, cmd->surfaceId));
840 s, WINPR_ASSERTING_INT_CAST(uint16_t, cmd->codecId));
841 Stream_Write_UINT8(s, pixelFormat);
842 Stream_Write_UINT16(s, WINPR_ASSERTING_INT_CAST(uint16_t, cmd->left));
843 Stream_Write_UINT16(s, WINPR_ASSERTING_INT_CAST(uint16_t, cmd->top));
844 Stream_Write_UINT16(s,
845 WINPR_ASSERTING_INT_CAST(uint16_t, cmd->right));
846 Stream_Write_UINT16(s,
847 WINPR_ASSERTING_INT_CAST(uint16_t, cmd->bottom));
848 Stream_Write_UINT32(s, cmd->length);
849 const size_t bitmapDataStart = Stream_GetPosition(s);
851 switch (cmd->codecId)
853#if defined(WITH_GFX_AV1) || defined(WITH_GFX_AV2)
854 case RDPGFX_CODECID_AV1:
856#if defined(WITH_GFX_AZURE)
857 case RDPGFX_CODECID_HEVC420:
858 case RDPGFX_CODECID_HEVC444:
861 error = rdpgfx_write_hevc(log, s, hevc);
863 if (error != CHANNEL_RC_OK)
865 WLog_Print(log, WLOG_ERROR,
"rdpgfx_write_h264_avc420 failed!");
871 case RDPGFX_CODECID_AVC420:
874 error = rdpgfx_write_h264_avc420(log, s, havc420);
876 if (error != CHANNEL_RC_OK)
878 WLog_Print(log, WLOG_ERROR,
"rdpgfx_write_h264_avc420 failed!");
884 case RDPGFX_CODECID_AVC444:
885 case RDPGFX_CODECID_AVC444v2:
888 havc420 = &(havc444->bitstream[0]);
889 if (!Stream_EnsureRemainingCapacity(s, 4))
890 return ERROR_INTERNAL_ERROR;
891 Stream_Write_UINT32(s, havc444->cbAvc420EncodedBitstream1 |
892 ((uint32_t)havc444->LC << 30UL));
894 error = rdpgfx_write_h264_avc420(log, s, havc420);
896 if (error != CHANNEL_RC_OK)
898 WLog_Print(log, WLOG_ERROR,
"rdpgfx_write_h264_avc420 failed!");
903 if (havc444->LC == 0)
905 havc420 = &(havc444->bitstream[1]);
906 error = rdpgfx_write_h264_avc420(log, s, havc420);
908 if (error != CHANNEL_RC_OK)
910 WLog_Print(log, WLOG_ERROR,
"rdpgfx_write_h264_avc420 failed!");
917 if (!Stream_EnsureRemainingCapacity(s, cmd->length))
918 return ERROR_INTERNAL_ERROR;
919 Stream_Write(s, cmd->data, cmd->length);
924 const size_t bitmapDataLength = Stream_GetPosition(s) - bitmapDataStart;
925 if (bitmapDataLength > UINT32_MAX)
926 return ERROR_INTERNAL_ERROR;
928 if (!Stream_SetPosition(s, bitmapDataStart -
sizeof(UINT32)))
929 return ERROR_INVALID_DATA;
930 if (!Stream_EnsureRemainingCapacity(s, 4))
931 return ERROR_INTERNAL_ERROR;
932 Stream_Write_UINT32(s, (UINT32)bitmapDataLength);
933 if (!Stream_SafeSeek(s, bitmapDataLength))
934 return ERROR_INTERNAL_ERROR;
947WINPR_ATTR_NODISCARD
static UINT rdpgfx_send_surface_command(RdpgfxServerContext* context,
950 if (!checkCapsAreExchanged(context))
951 return CHANNEL_RC_NOT_INITIALIZED;
952 UINT error = CHANNEL_RC_OK;
954 WINPR_ASSERT(context);
955 WINPR_ASSERT(context->priv);
959 rdpgfx_server_single_packet_new(context->priv->log, rdpgfx_surface_command_cmdid(cmd),
960 rdpgfx_estimate_surface_command(cmd));
964 WLog_Print(context->priv->log, WLOG_ERROR,
"rdpgfx_server_single_packet_new failed!");
965 return CHANNEL_RC_NO_MEMORY;
968 error = rdpgfx_write_surface_command(context->priv->log, s, cmd);
970 if (error != CHANNEL_RC_OK)
972 WLog_Print(context->priv->log, WLOG_ERROR,
"rdpgfx_write_surface_command failed!");
976 return rdpgfx_server_single_packet_send(context, s);
978 Stream_Free(s, TRUE);
990WINPR_ATTR_NODISCARD
static UINT
996 if (!checkCapsAreExchanged(context))
997 return CHANNEL_RC_NOT_INITIALIZED;
999 WINPR_ASSERT(context->priv);
1001 WINPR_ASSERT(startFrame);
1002 WINPR_ASSERT(endFrame);
1004 UINT error = CHANNEL_RC_OK;
1005 size_t size = rdpgfx_pdu_length(rdpgfx_estimate_surface_command(cmd));
1009 size += rdpgfx_pdu_length(RDPGFX_START_FRAME_PDU_SIZE);
1014 size += rdpgfx_pdu_length(RDPGFX_END_FRAME_PDU_SIZE);
1017 wStream* s = Stream_New(
nullptr, size);
1021 WLog_Print(context->priv->log, WLOG_ERROR,
"Stream_New failed!");
1022 return CHANNEL_RC_NO_MEMORY;
1028 const size_t position = Stream_GetPosition(s);
1029 error = rdpgfx_server_packet_init_header(s, RDPGFX_CMDID_STARTFRAME, 0);
1031 if (error != CHANNEL_RC_OK)
1033 WLog_Print(context->priv->log, WLOG_ERROR,
1034 "Failed to init header with error %" PRIu32
"!", error);
1038 if (!rdpgfx_write_start_frame_pdu(s, startFrame) ||
1039 !rdpgfx_server_packet_complete_header(s, position))
1041 error = ERROR_INTERNAL_ERROR;
1048 const size_t pos = Stream_GetPosition(s);
1049 error = rdpgfx_server_packet_init_header(s, rdpgfx_surface_command_cmdid(cmd),
1052 if (error != CHANNEL_RC_OK)
1054 WLog_Print(context->priv->log, WLOG_ERROR,
1055 "Failed to init header with error %" PRIu32
"!", error);
1059 error = rdpgfx_write_surface_command(context->priv->log, s, cmd);
1061 if (error != CHANNEL_RC_OK)
1063 WLog_Print(context->priv->log, WLOG_ERROR,
"rdpgfx_write_surface_command failed!");
1067 if (!rdpgfx_server_packet_complete_header(s, pos))
1069 error = ERROR_INTERNAL_ERROR;
1077 const size_t position = Stream_GetPosition(s);
1078 error = rdpgfx_server_packet_init_header(s, RDPGFX_CMDID_ENDFRAME, 0);
1080 if (error != CHANNEL_RC_OK)
1082 WLog_Print(context->priv->log, WLOG_ERROR,
1083 "Failed to init header with error %" PRIu32
"!", error);
1087 if (!rdpgfx_write_end_frame_pdu(s, endFrame) ||
1088 !rdpgfx_server_packet_complete_header(s, position))
1090 error = ERROR_INTERNAL_ERROR;
1095 return rdpgfx_server_packet_send(context, s);
1097 Stream_Free(s, TRUE);
1106WINPR_ATTR_NODISCARD
static UINT
1107rdpgfx_send_delete_encoding_context_pdu(RdpgfxServerContext* context,
1110 if (!checkCapsAreExchanged(context))
1111 return CHANNEL_RC_NOT_INITIALIZED;
1113 WINPR_ASSERT(context->priv);
1116 rdpgfx_server_single_packet_new(context->priv->log, RDPGFX_CMDID_DELETEENCODINGCONTEXT, 6);
1120 WLog_Print(context->priv->log, WLOG_ERROR,
"rdpgfx_server_single_packet_new failed!");
1121 return CHANNEL_RC_NO_MEMORY;
1124 Stream_Write_UINT16(s, pdu->surfaceId);
1125 Stream_Write_UINT32(s, pdu->codecContextId);
1126 return rdpgfx_server_single_packet_send(context, s);
1134WINPR_ATTR_NODISCARD
static UINT rdpgfx_send_solid_fill_pdu(RdpgfxServerContext* context,
1137 if (!checkCapsAreExchanged(context))
1138 return CHANNEL_RC_NOT_INITIALIZED;
1140 WINPR_ASSERT(context->priv);
1143 UINT error = CHANNEL_RC_OK;
1145 wStream* s = rdpgfx_server_single_packet_new(context->priv->log, RDPGFX_CMDID_SOLIDFILL,
1146 8 + 8 * pdu->fillRectCount);
1150 WLog_Print(context->priv->log, WLOG_ERROR,
"rdpgfx_server_single_packet_new failed!");
1151 return CHANNEL_RC_NO_MEMORY;
1154 Stream_Write_UINT16(s, pdu->surfaceId);
1157 if ((error = rdpgfx_write_color32(s, &(pdu->fillPixel))))
1159 WLog_Print(context->priv->log, WLOG_ERROR,
1160 "rdpgfx_write_color32 failed with error %" PRIu32
"!", error);
1164 Stream_Write_UINT16(s, pdu->fillRectCount);
1166 for (UINT16 index = 0; index < pdu->fillRectCount; index++)
1168 fillRect = &(pdu->fillRects[index]);
1170 if ((error = rdpgfx_write_rect16(s, fillRect)))
1172 WLog_Print(context->priv->log, WLOG_ERROR,
1173 "rdpgfx_write_rect16 failed with error %" PRIu32
"!", error);
1178 return rdpgfx_server_single_packet_send(context, s);
1180 Stream_Free(s, TRUE);
1189WINPR_ATTR_NODISCARD
static UINT
1190rdpgfx_send_surface_to_surface_pdu(RdpgfxServerContext* context,
1193 if (!checkCapsAreExchanged(context))
1194 return CHANNEL_RC_NOT_INITIALIZED;
1197 WINPR_ASSERT(context->priv);
1199 UINT error = CHANNEL_RC_OK;
1201 wStream* s = rdpgfx_server_single_packet_new(context->priv->log, RDPGFX_CMDID_SURFACETOSURFACE,
1202 14 + 4 * pdu->destPtsCount);
1206 WLog_Print(context->priv->log, WLOG_ERROR,
"rdpgfx_server_single_packet_new failed!");
1207 return CHANNEL_RC_NO_MEMORY;
1210 Stream_Write_UINT16(s, pdu->surfaceIdSrc);
1211 Stream_Write_UINT16(s, pdu->surfaceIdDest);
1214 if ((error = rdpgfx_write_rect16(s, &(pdu->rectSrc))))
1216 WLog_Print(context->priv->log, WLOG_ERROR,
1217 "rdpgfx_write_rect16 failed with error %" PRIu32
"!", error);
1221 Stream_Write_UINT16(s, pdu->destPtsCount);
1223 for (UINT16 index = 0; index < pdu->destPtsCount; index++)
1225 destPt = &(pdu->destPts[index]);
1227 if ((error = rdpgfx_write_point16(s, destPt)))
1229 WLog_Print(context->priv->log, WLOG_ERROR,
1230 "rdpgfx_write_point16 failed with error %" PRIu32
"!", error);
1235 return rdpgfx_server_single_packet_send(context, s);
1237 Stream_Free(s, TRUE);
1246WINPR_ATTR_NODISCARD
static UINT
1247rdpgfx_send_surface_to_cache_pdu(RdpgfxServerContext* context,
1250 if (!checkCapsAreExchanged(context))
1251 return CHANNEL_RC_NOT_INITIALIZED;
1254 WINPR_ASSERT(context->priv);
1256 UINT error = CHANNEL_RC_OK;
1258 rdpgfx_server_single_packet_new(context->priv->log, RDPGFX_CMDID_SURFACETOCACHE, 20);
1262 WLog_Print(context->priv->log, WLOG_ERROR,
"rdpgfx_server_single_packet_new failed!");
1263 return CHANNEL_RC_NO_MEMORY;
1266 Stream_Write_UINT16(s, pdu->surfaceId);
1267 Stream_Write_UINT64(s, pdu->cacheKey);
1268 Stream_Write_UINT16(s, pdu->cacheSlot);
1271 if ((error = rdpgfx_write_rect16(s, &(pdu->rectSrc))))
1273 WLog_Print(context->priv->log, WLOG_ERROR,
1274 "rdpgfx_write_rect16 failed with error %" PRIu32
"!", error);
1278 return rdpgfx_server_single_packet_send(context, s);
1280 Stream_Free(s, TRUE);
1289WINPR_ATTR_NODISCARD
static UINT
1290rdpgfx_send_cache_to_surface_pdu(RdpgfxServerContext* context,
1293 if (!checkCapsAreExchanged(context))
1294 return CHANNEL_RC_NOT_INITIALIZED;
1297 WINPR_ASSERT(context->priv);
1299 UINT error = CHANNEL_RC_OK;
1301 wStream* s = rdpgfx_server_single_packet_new(context->priv->log, RDPGFX_CMDID_CACHETOSURFACE,
1302 6 + 4 * pdu->destPtsCount);
1306 WLog_Print(context->priv->log, WLOG_ERROR,
"rdpgfx_server_single_packet_new failed!");
1307 return CHANNEL_RC_NO_MEMORY;
1310 Stream_Write_UINT16(s, pdu->cacheSlot);
1311 Stream_Write_UINT16(s, pdu->surfaceId);
1312 Stream_Write_UINT16(s, pdu->destPtsCount);
1314 for (UINT16 index = 0; index < pdu->destPtsCount; index++)
1316 destPt = &(pdu->destPts[index]);
1318 if ((error = rdpgfx_write_point16(s, destPt)))
1320 WLog_Print(context->priv->log, WLOG_ERROR,
1321 "rdpgfx_write_point16 failed with error %" PRIu32
"", error);
1326 return rdpgfx_server_single_packet_send(context, s);
1328 Stream_Free(s, TRUE);
1337WINPR_ATTR_NODISCARD
static UINT
1338rdpgfx_send_map_surface_to_output_pdu(RdpgfxServerContext* context,
1341 if (!checkCapsAreExchanged(context))
1342 return CHANNEL_RC_NOT_INITIALIZED;
1345 WINPR_ASSERT(context->priv);
1347 rdpgfx_server_single_packet_new(context->priv->log, RDPGFX_CMDID_MAPSURFACETOOUTPUT, 12);
1351 WLog_Print(context->priv->log, WLOG_ERROR,
"rdpgfx_server_single_packet_new failed!");
1352 return CHANNEL_RC_NO_MEMORY;
1355 Stream_Write_UINT16(s, pdu->surfaceId);
1356 Stream_Write_UINT16(s, 0);
1357 Stream_Write_UINT32(s, pdu->outputOriginX);
1358 Stream_Write_UINT32(s, pdu->outputOriginY);
1359 return rdpgfx_server_single_packet_send(context, s);
1367WINPR_ATTR_NODISCARD
static UINT
1368rdpgfx_send_map_surface_to_window_pdu(RdpgfxServerContext* context,
1371 if (!checkCapsAreExchanged(context))
1372 return CHANNEL_RC_NOT_INITIALIZED;
1375 WINPR_ASSERT(context->priv);
1378 rdpgfx_server_single_packet_new(context->priv->log, RDPGFX_CMDID_MAPSURFACETOWINDOW, 18);
1382 WLog_Print(context->priv->log, WLOG_ERROR,
"rdpgfx_server_single_packet_new failed!");
1383 return CHANNEL_RC_NO_MEMORY;
1386 Stream_Write_UINT16(s, pdu->surfaceId);
1387 Stream_Write_UINT64(s, pdu->windowId);
1388 Stream_Write_UINT32(s, pdu->mappedWidth);
1389 Stream_Write_UINT32(s, pdu->mappedHeight);
1390 return rdpgfx_server_single_packet_send(context, s);
1393WINPR_ATTR_NODISCARD
static UINT
1394rdpgfx_send_map_surface_to_scaled_window_pdu(RdpgfxServerContext* context,
1397 if (!checkCapsAreExchanged(context))
1398 return CHANNEL_RC_NOT_INITIALIZED;
1401 WINPR_ASSERT(context->priv);
1402 wStream* s = rdpgfx_server_single_packet_new(context->priv->log,
1403 RDPGFX_CMDID_MAPSURFACETOSCALEDWINDOW, 26);
1407 WLog_Print(context->priv->log, WLOG_ERROR,
"rdpgfx_server_single_packet_new failed!");
1408 return CHANNEL_RC_NO_MEMORY;
1411 Stream_Write_UINT16(s, pdu->surfaceId);
1412 Stream_Write_UINT64(s, pdu->windowId);
1413 Stream_Write_UINT32(s, pdu->mappedWidth);
1414 Stream_Write_UINT32(s, pdu->mappedHeight);
1415 Stream_Write_UINT32(s, pdu->targetWidth);
1416 Stream_Write_UINT32(s, pdu->targetHeight);
1417 return rdpgfx_server_single_packet_send(context, s);
1425WINPR_ATTR_NODISCARD
static UINT rdpgfx_recv_frame_acknowledge_pdu(RdpgfxServerContext* context,
1428 WINPR_ASSERT(context);
1430 if (!checkCapsAreExchanged(context))
1431 return CHANNEL_RC_NOT_INITIALIZED;
1433 WINPR_ASSERT(context->priv);
1436 UINT error = CHANNEL_RC_OK;
1438 if (!Stream_CheckAndLogRequiredLengthWLog(context->priv->log, s, 12))
1439 return ERROR_INVALID_DATA;
1441 Stream_Read_UINT32(s, pdu.queueDepth);
1442 Stream_Read_UINT32(s, pdu.frameId);
1443 Stream_Read_UINT32(s, pdu.totalFramesDecoded);
1445 IFCALLRET(context->FrameAcknowledge, error, context, &pdu);
1448 WLog_Print(context->priv->log, WLOG_ERROR,
1449 "context->FrameAcknowledge failed with error %" PRIu32
"", error);
1459WINPR_ATTR_NODISCARD
static UINT rdpgfx_recv_cache_import_offer_pdu(RdpgfxServerContext* context,
1462 WINPR_ASSERT(context);
1463 if (!checkCapsAreExchanged(context))
1464 return CHANNEL_RC_NOT_INITIALIZED;
1466 WINPR_ASSERT(context->priv);
1470 UINT error = CHANNEL_RC_OK;
1472 if (!Stream_CheckAndLogRequiredLengthWLog(context->priv->log, s, 2))
1473 return ERROR_INVALID_DATA;
1476 Stream_Read_UINT16(s, pdu.cacheEntriesCount);
1479 if (pdu.cacheEntriesCount >= 5462)
1481 WLog_Print(context->priv->log, WLOG_ERROR,
"Invalid cacheEntriesCount: %" PRIu16
"",
1482 pdu.cacheEntriesCount);
1483 return ERROR_INVALID_DATA;
1486 if (!Stream_CheckAndLogRequiredLengthOfSizeWLog(context->priv->log, s, pdu.cacheEntriesCount,
1488 return ERROR_INVALID_DATA;
1490 for (UINT16 index = 0; index < pdu.cacheEntriesCount; index++)
1492 cacheEntry = &(pdu.cacheEntries[index]);
1493 Stream_Read_UINT64(s, cacheEntry->cacheKey);
1494 Stream_Read_UINT32(s, cacheEntry->bitmapLength);
1497 IFCALLRET(context->CacheImportOffer, error, context, &pdu);
1500 WLog_Print(context->priv->log, WLOG_ERROR,
1501 "context->CacheImportOffer failed with error %" PRIu32
"", error);
1511WINPR_ATTR_NODISCARD
static UINT rdpgfx_recv_caps_advertise_pdu(RdpgfxServerContext* context,
1516 UINT error = ERROR_INVALID_DATA;
1519 return ERROR_BAD_ARGUMENTS;
1521 WINPR_ASSERT(context->priv);
1522 if (!Stream_CheckAndLogRequiredLengthWLog(context->priv->log, s, 2))
1523 return ERROR_INVALID_DATA;
1525 Stream_Read_UINT16(s, pdu.capsSetCount);
1526 if (pdu.capsSetCount > 0)
1528 capsSets = calloc(pdu.capsSetCount, (RDPGFX_CAPSET_BASE_SIZE + 4));
1530 return ERROR_OUTOFMEMORY;
1533 pdu.capsSets = capsSets;
1535 for (UINT16 index = 0; index < pdu.capsSetCount; index++)
1539 if (!Stream_CheckAndLogRequiredLengthWLog(context->priv->log, s, 8))
1542 Stream_Read_UINT32(s, capsSet->version);
1543 Stream_Read_UINT32(s, capsSet->length);
1545 if (capsSet->length >= 4)
1547 if (!Stream_CheckAndLogRequiredLengthWLog(context->priv->log, s, 4))
1550 Stream_Peek_UINT32(s, capsSet->flags);
1553 if (!Stream_SafeSeek(s, capsSet->length))
1557 error = ERROR_BAD_CONFIGURATION;
1558 IFCALLRET(context->CapsAdvertise, error, context, &pdu);
1561 WLog_Print(context->priv->log, WLOG_ERROR,
1562 "context->CapsAdvertise failed with error %" PRIu32
"", error);
1574WINPR_ATTR_NODISCARD
static UINT rdpgfx_recv_qoe_frame_acknowledge_pdu(RdpgfxServerContext* context,
1577 WINPR_ASSERT(context);
1579 if (!checkCapsAreExchanged(context))
1580 return CHANNEL_RC_NOT_INITIALIZED;
1583 UINT error = CHANNEL_RC_OK;
1585 WINPR_ASSERT(context->priv);
1587 if (!Stream_CheckAndLogRequiredLengthWLog(context->priv->log, s, 12))
1588 return ERROR_INVALID_DATA;
1590 Stream_Read_UINT32(s, pdu.frameId);
1591 Stream_Read_UINT32(s, pdu.timestamp);
1592 Stream_Read_UINT16(s, pdu.timeDiffSE);
1593 Stream_Read_UINT16(s, pdu.timeDiffEDR);
1595 IFCALLRET(context->QoeFrameAcknowledge, error, context, &pdu);
1598 WLog_Print(context->priv->log, WLOG_ERROR,
1599 "context->QoeFrameAcknowledge failed with error %" PRIu32
"", error);
1604WINPR_ATTR_NODISCARD
static UINT
1605rdpgfx_send_map_surface_to_scaled_output_pdu(RdpgfxServerContext* context,
1608 if (!checkCapsAreExchanged(context))
1609 return CHANNEL_RC_NOT_INITIALIZED;
1612 WINPR_ASSERT(context->priv);
1613 wStream* s = rdpgfx_server_single_packet_new(context->priv->log,
1614 RDPGFX_CMDID_MAPSURFACETOSCALEDOUTPUT, 20);
1618 WLog_Print(context->priv->log, WLOG_ERROR,
"rdpgfx_server_single_packet_new failed!");
1619 return CHANNEL_RC_NO_MEMORY;
1622 Stream_Write_UINT16(s, pdu->surfaceId);
1623 Stream_Write_UINT16(s, 0);
1624 Stream_Write_UINT32(s, pdu->outputOriginX);
1625 Stream_Write_UINT32(s, pdu->outputOriginY);
1626 Stream_Write_UINT32(s, pdu->targetWidth);
1627 Stream_Write_UINT32(s, pdu->targetHeight);
1628 return rdpgfx_server_single_packet_send(context, s);
1636WINPR_ATTR_NODISCARD
static UINT rdpgfx_server_receive_pdu(RdpgfxServerContext* context,
1639 size_t packetlen = 0;
1640 wStream sbuffer = WINPR_C_ARRAY_INIT;
1642 UINT error = CHANNEL_RC_OK;
1644 WINPR_ASSERT(context);
1645 WINPR_ASSERT(context->priv);
1647 if ((error = rdpgfx_read_header(context->priv->log, data, &header, &packetlen)))
1649 WLog_Print(context->priv->log, WLOG_ERROR,
1650 "rdpgfx_read_header failed with error %" PRIu32
"!", error);
1655 wStream* s = Stream_StaticConstInit(&sbuffer, Stream_ConstPointer(data), packetlen);
1656 Stream_Seek(data, packetlen);
1658 WLog_Print(context->priv->log, WLOG_TRACE,
1659 "cmdId: %s (0x%04" PRIX16
") flags: 0x%04" PRIX16
" pduLength: %" PRIu32
"",
1660 rdpgfx_get_cmd_id_string(header.cmdId), header.cmdId, header.flags,
1663 switch (header.cmdId)
1665 case RDPGFX_CMDID_FRAMEACKNOWLEDGE:
1666 if ((error = rdpgfx_recv_frame_acknowledge_pdu(context, s)))
1667 WLog_Print(context->priv->log, WLOG_ERROR,
1668 "rdpgfx_recv_frame_acknowledge_pdu "
1669 "failed with error %" PRIu32
"!",
1674 case RDPGFX_CMDID_CACHEIMPORTOFFER:
1675 if ((error = rdpgfx_recv_cache_import_offer_pdu(context, s)))
1676 WLog_Print(context->priv->log, WLOG_ERROR,
1677 "rdpgfx_recv_cache_import_offer_pdu "
1678 "failed with error %" PRIu32
"!",
1683 case RDPGFX_CMDID_CAPSADVERTISE:
1684 if ((error = rdpgfx_recv_caps_advertise_pdu(context, s)))
1685 WLog_Print(context->priv->log, WLOG_ERROR,
1686 "rdpgfx_recv_caps_advertise_pdu "
1687 "failed with error %" PRIu32
"!",
1692 case RDPGFX_CMDID_QOEFRAMEACKNOWLEDGE:
1693 if ((error = rdpgfx_recv_qoe_frame_acknowledge_pdu(context, s)))
1694 WLog_Print(context->priv->log, WLOG_ERROR,
1695 "rdpgfx_recv_qoe_frame_acknowledge_pdu "
1696 "failed with error %" PRIu32
"!",
1702 error = CHANNEL_RC_BAD_PROC;
1708 WLog_Print(context->priv->log, WLOG_ERROR,
1709 "Error while parsing GFX cmdId: %s (0x%04" PRIX16
")",
1710 rdpgfx_get_cmd_id_string(header.cmdId), header.cmdId);
1714 const size_t end = Stream_GetPosition(s);
1716 if (end != packetlen)
1718 WLog_Print(context->priv->log, WLOG_ERROR,
1719 "Unexpected gfx pdu end: Actual: %" PRIuz
", Expected: %" PRIuz
"", end,
1726WINPR_ATTR_NODISCARD
static DWORD WINAPI rdpgfx_server_thread_func(LPVOID arg)
1728 RdpgfxServerContext* context = (RdpgfxServerContext*)arg;
1729 WINPR_ASSERT(context);
1731 RdpgfxServerPrivate* priv = context->priv;
1734 HANDLE events[8] = WINPR_C_ARRAY_INIT;
1735 UINT error = CHANNEL_RC_OK;
1739 if (priv->ownThread)
1741 WINPR_ASSERT(priv->stopEvent);
1742 events[nCount++] = priv->stopEvent;
1745 WINPR_ASSERT(priv->channelEvent);
1746 events[nCount++] = priv->channelEvent;
1751 status = WaitForMultipleObjects(nCount, events, FALSE, INFINITE);
1753 if (status == WAIT_FAILED)
1755 error = GetLastError();
1756 WLog_Print(context->priv->log, WLOG_ERROR,
1757 "WaitForMultipleObjects failed with error %" PRIu32
"", error);
1762 if (status == WAIT_OBJECT_0)
1765 if ((error = rdpgfx_server_handle_messages(context)))
1767 WLog_Print(context->priv->log, WLOG_ERROR,
1768 "rdpgfx_server_handle_messages failed with error %" PRIu32
"", error);
1773 if (error && context->rdpcontext)
1774 setChannelError(context->rdpcontext, error,
"rdpgfx_server_thread_func reported an error");
1780WINPR_ATTR_NODISCARD
static BOOL rdpgfx_server_open(RdpgfxServerContext* context)
1782 WINPR_ASSERT(context);
1783 RdpgfxServerPrivate* priv = context->priv;
1784 void* buffer =
nullptr;
1788 if (!priv->isOpened)
1790 PULONG pSessionId =
nullptr;
1791 DWORD BytesReturned = 0;
1792 priv->SessionId = WTS_CURRENT_SESSION;
1793 UINT32 channelId = 0;
1796 if (WTSQuerySessionInformationA(context->vcm, WTS_CURRENT_SESSION, WTSSessionId,
1797 (LPSTR*)&pSessionId, &BytesReturned) == FALSE)
1799 WLog_Print(context->priv->log, WLOG_ERROR,
"WTSQuerySessionInformationA failed!");
1803 priv->SessionId = (DWORD)*pSessionId;
1804 WTSFreeMemory(pSessionId);
1805 priv->rdpgfx_channel = WTSVirtualChannelOpenEx(priv->SessionId, RDPGFX_DVC_CHANNEL_NAME,
1806 WTS_CHANNEL_OPTION_DYNAMIC);
1808 if (!priv->rdpgfx_channel)
1810 WLog_Print(context->priv->log, WLOG_ERROR,
"WTSVirtualChannelOpenEx failed!");
1814 channelId = WTSChannelGetIdByHandle(priv->rdpgfx_channel);
1816 IFCALLRET(context->ChannelIdAssigned, status, context, channelId);
1819 WLog_Print(context->priv->log, WLOG_ERROR,
"context->ChannelIdAssigned failed!");
1824 if (!WTSVirtualChannelQuery(priv->rdpgfx_channel, WTSVirtualEventHandle, &buffer,
1826 (BytesReturned !=
sizeof(HANDLE)))
1828 WLog_Print(context->priv->log, WLOG_ERROR,
1829 "WTSVirtualChannelQuery failed "
1830 "or invalid returned size(%" PRIu32
")",
1834 WTSFreeMemory(buffer);
1839 priv->channelEvent = *(HANDLE*)buffer;
1840 WTSFreeMemory(buffer);
1842 if (!(priv->zgfx = zgfx_context_new(TRUE)))
1844 WLog_Print(context->priv->log, WLOG_ERROR,
"Create zgfx context failed!");
1848 priv->isReady = FALSE;
1850 priv->activeCapSet = empty;
1851 if (priv->ownThread)
1853 if (!(priv->stopEvent = CreateEvent(
nullptr, TRUE, FALSE,
nullptr)))
1855 WLog_Print(context->priv->log, WLOG_ERROR,
"CreateEvent failed!");
1859 if (!(priv->thread = CreateThread(
nullptr, 0, rdpgfx_server_thread_func, (
void*)context,
1862 WLog_Print(context->priv->log, WLOG_ERROR,
"CreateThread failed!");
1867 priv->isOpened = TRUE;
1871 WLog_Print(context->priv->log, WLOG_ERROR,
"RDPGFX channel is already opened!");
1874 (void)rdpgfx_server_close(context);
1878BOOL rdpgfx_server_close(RdpgfxServerContext* context)
1880 WINPR_ASSERT(context);
1882 RdpgfxServerPrivate* priv = context->priv;
1885 if (priv->ownThread && priv->thread)
1887 (void)SetEvent(priv->stopEvent);
1889 if (WaitForSingleObject(priv->thread, INFINITE) == WAIT_FAILED)
1891 WLog_Print(context->priv->log, WLOG_ERROR,
1892 "WaitForSingleObject failed with error %" PRIu32
"", GetLastError());
1896 (void)CloseHandle(priv->thread);
1897 (void)CloseHandle(priv->stopEvent);
1898 priv->thread =
nullptr;
1899 priv->stopEvent =
nullptr;
1902 zgfx_context_free(priv->zgfx);
1903 priv->zgfx =
nullptr;
1905 if (priv->rdpgfx_channel)
1907 (void)WTSVirtualChannelClose(priv->rdpgfx_channel);
1908 priv->rdpgfx_channel =
nullptr;
1911 priv->channelEvent =
nullptr;
1912 priv->isOpened = FALSE;
1913 priv->isReady = FALSE;
1915 priv->activeCapSet = empty;
1919WINPR_ATTR_NODISCARD
static BOOL rdpgfx_server_initialize(RdpgfxServerContext* context,
1920 BOOL externalThread)
1922 WINPR_ASSERT(context);
1923 WINPR_ASSERT(context->priv);
1925 if (context->priv->isOpened)
1927 WLog_Print(context->priv->log, WLOG_WARN,
1928 "Application error: RDPEGFX channel already initialized, "
1929 "calling in this state is not possible!");
1933 context->priv->ownThread = !externalThread;
1937RdpgfxServerContext* rdpgfx_server_context_new(HANDLE vcm)
1939 RdpgfxServerContext* context = (RdpgfxServerContext*)calloc(1,
sizeof(RdpgfxServerContext));
1945 context->Initialize = rdpgfx_server_initialize;
1946 context->Open = rdpgfx_server_open;
1947 context->Close = rdpgfx_server_close;
1948 context->ResetGraphics = rdpgfx_send_reset_graphics_pdu;
1949 context->StartFrame = rdpgfx_send_start_frame_pdu;
1950 context->EndFrame = rdpgfx_send_end_frame_pdu;
1951 context->SurfaceCommand = rdpgfx_send_surface_command;
1952 context->SurfaceFrameCommand = rdpgfx_send_surface_frame_command;
1953 context->DeleteEncodingContext = rdpgfx_send_delete_encoding_context_pdu;
1954 context->CreateSurface = rdpgfx_send_create_surface_pdu;
1955 context->DeleteSurface = rdpgfx_send_delete_surface_pdu;
1956 context->SolidFill = rdpgfx_send_solid_fill_pdu;
1957 context->SurfaceToSurface = rdpgfx_send_surface_to_surface_pdu;
1958 context->SurfaceToCache = rdpgfx_send_surface_to_cache_pdu;
1959 context->CacheToSurface = rdpgfx_send_cache_to_surface_pdu;
1960 context->CacheImportOffer = rdpgfx_process_cache_import_offer_pdu;
1961 context->CacheImportReply = rdpgfx_send_cache_import_reply_pdu;
1962 context->EvictCacheEntry = rdpgfx_send_evict_cache_entry_pdu;
1963 context->MapSurfaceToOutput = rdpgfx_send_map_surface_to_output_pdu;
1964 context->MapSurfaceToWindow = rdpgfx_send_map_surface_to_window_pdu;
1965 context->MapSurfaceToScaledOutput = rdpgfx_send_map_surface_to_scaled_output_pdu;
1966 context->MapSurfaceToScaledWindow = rdpgfx_send_map_surface_to_scaled_window_pdu;
1967 context->CapsAdvertise =
nullptr;
1968 context->CapsConfirm = rdpgfx_send_caps_confirm_pdu;
1969 context->FrameAcknowledge =
nullptr;
1970 context->QoeFrameAcknowledge =
nullptr;
1971 RdpgfxServerPrivate* priv = context->priv =
1972 (RdpgfxServerPrivate*)calloc(1,
sizeof(RdpgfxServerPrivate));
1977 priv->log = WLog_Get(TAG);
1982 priv->input_stream = Stream_New(
nullptr, 4);
1984 if (!priv->input_stream)
1986 WLog_Print(context->priv->log, WLOG_ERROR,
"Stream_New failed!");
1990 priv->isOpened = FALSE;
1991 priv->isReady = FALSE;
1992 priv->ownThread = TRUE;
1996 priv->activeCapSet = empty;
2001 WINPR_PRAGMA_DIAG_PUSH
2002 WINPR_PRAGMA_DIAG_IGNORED_MISMATCHED_DEALLOC
2003 rdpgfx_server_context_free(context);
2004 WINPR_PRAGMA_DIAG_POP
2008void rdpgfx_server_context_free(RdpgfxServerContext* context)
2013 (void)rdpgfx_server_close(context);
2016 Stream_Free(context->priv->input_stream, TRUE);
2018 free(context->priv);
2022HANDLE rdpgfx_server_get_event_handle(RdpgfxServerContext* context)
2028 return context->priv->channelEvent;
2040UINT rdpgfx_server_handle_messages(RdpgfxServerContext* context)
2042 DWORD BytesReturned = 0;
2043 void* buffer =
nullptr;
2044 UINT ret = CHANNEL_RC_OK;
2046 WINPR_ASSERT(context);
2047 WINPR_ASSERT(context->priv);
2049 RdpgfxServerPrivate* priv = context->priv;
2050 wStream* s = priv->input_stream;
2055 if (WTSVirtualChannelQuery(priv->rdpgfx_channel, WTSVirtualChannelReady, &buffer,
2056 &BytesReturned) == FALSE)
2058 if (GetLastError() == ERROR_NO_DATA)
2059 return ERROR_NO_DATA;
2061 WLog_Print(context->priv->log, WLOG_ERROR,
"WTSVirtualChannelQuery failed");
2062 return ERROR_INTERNAL_ERROR;
2065 priv->isReady = *((BOOL*)buffer);
2066 WTSFreeMemory(buffer);
2072 Stream_ResetPosition(s);
2074 if (!WTSVirtualChannelRead(priv->rdpgfx_channel, 0,
nullptr, 0, &BytesReturned))
2076 if (GetLastError() == ERROR_NO_DATA)
2077 return ERROR_NO_DATA;
2079 WLog_Print(context->priv->log, WLOG_ERROR,
"WTSVirtualChannelRead failed!");
2080 return ERROR_INTERNAL_ERROR;
2083 if (BytesReturned < 1)
2084 return CHANNEL_RC_OK;
2086 if (!Stream_EnsureRemainingCapacity(s, BytesReturned))
2088 WLog_Print(context->priv->log, WLOG_ERROR,
"Stream_EnsureRemainingCapacity failed!");
2089 return CHANNEL_RC_NO_MEMORY;
2092 const size_t len = Stream_Capacity(s);
2093 if (len > UINT32_MAX)
2094 return ERROR_INTERNAL_ERROR;
2095 if (WTSVirtualChannelRead(priv->rdpgfx_channel, 0, Stream_BufferAs(s,
char), (UINT32)len,
2096 &BytesReturned) == FALSE)
2098 WLog_Print(context->priv->log, WLOG_ERROR,
"WTSVirtualChannelRead failed!");
2099 return ERROR_INTERNAL_ERROR;
2102 if (!Stream_SetLength(s, BytesReturned))
2103 return ERROR_INTERNAL_ERROR;
2105 Stream_ResetPosition(s);
2107 while (Stream_GetPosition(s) < Stream_Length(s))
2109 if ((ret = rdpgfx_server_receive_pdu(context, s)))
2111 WLog_Print(context->priv->log, WLOG_ERROR,
2112 "rdpgfx_server_receive_pdu "
2113 "failed with error %" PRIu32
"!",