rdpgfx/client: Add callbacks for manual caps sending and frame acking

This commit is contained in:
Mati Shabtay 2019-05-05 15:31:18 +03:00
parent f867c90e4c
commit eee234c239
3 changed files with 121 additions and 52 deletions

View File

@ -52,20 +52,75 @@
* *
* @return 0 on success, otherwise a Win32 error code * @return 0 on success, otherwise a Win32 error code
*/ */
static UINT rdpgfx_send_caps_advertise_pdu(RDPGFX_CHANNEL_CALLBACK* callback) static UINT rdpgfx_send_caps_advertise_pdu(RdpgfxClientContext* context,
const RDPGFX_CAPS_ADVERTISE_PDU* pdu)
{ {
UINT error; UINT error = CHANNEL_RC_OK;
UINT32 x;
wStream* s;
UINT16 index; UINT16 index;
RDPGFX_PLUGIN* gfx;
RDPGFX_HEADER header; RDPGFX_HEADER header;
RDPGFX_CAPSET* capsSet; RDPGFX_CAPSET* capsSet;
RDPGFX_PLUGIN* gfx;
RDPGFX_CHANNEL_CALLBACK* callback;
wStream* s;
gfx = (RDPGFX_PLUGIN*) context->handle;
callback = gfx->listener_callback->channel_callback;
header.flags = 0;
header.cmdId = RDPGFX_CMDID_CAPSADVERTISE;
header.pduLength = RDPGFX_HEADER_SIZE + 2;
for (index = 0; index < pdu->capsSetCount; index++)
{
capsSet = &(pdu->capsSets[index]);
header.pduLength += RDPGFX_CAPSET_BASE_SIZE + capsSet->length;
}
WLog_Print(gfx->log, WLOG_DEBUG, "SendCapsAdvertisePdu %"PRIu16"", pdu->capsSetCount);
s = Stream_New(NULL, header.pduLength);
if (!s)
{
WLog_ERR(TAG, "Stream_New failed!");
return CHANNEL_RC_NO_MEMORY;
}
if ((error = rdpgfx_write_header(s, &header)))
goto fail;
/* RDPGFX_CAPS_ADVERTISE_PDU */
Stream_Write_UINT16(s, pdu->capsSetCount); /* capsSetCount (2 bytes) */
for (index = 0; index < pdu->capsSetCount; index++)
{
capsSet = &(pdu->capsSets[index]);
Stream_Write_UINT32(s, capsSet->version); /* version (4 bytes) */
Stream_Write_UINT32(s, capsSet->length); /* capsDataLength (4 bytes) */
Stream_Write_UINT32(s, capsSet->flags); /* capsData (4 bytes) */
Stream_Zero(s, capsSet->length - 4);
}
Stream_SealLength(s);
error = callback->channel->Write(callback->channel, (UINT32) Stream_Length(s),
Stream_Buffer(s), NULL);
fail:
Stream_Free(s, TRUE);
return error;
}
/**
* Function description
*
* @return 0 on success, otherwise a Win32 error code
*/
static UINT rdpgfx_send_supported_caps(RDPGFX_CHANNEL_CALLBACK* callback)
{
UINT error = CHANNEL_RC_OK;
RDPGFX_PLUGIN* gfx;
RdpgfxClientContext* context;
RDPGFX_CAPSET* capsSet;
RDPGFX_CAPSET capsSets[RDPGFX_NUMBER_CAPSETS] = { 0 }; RDPGFX_CAPSET capsSets[RDPGFX_NUMBER_CAPSETS] = { 0 };
RDPGFX_CAPS_ADVERTISE_PDU pdu; RDPGFX_CAPS_ADVERTISE_PDU pdu;
gfx = (RDPGFX_PLUGIN*) callback->plugin; gfx = (RDPGFX_PLUGIN*) callback->plugin;
header.flags = 0; context = (RdpgfxClientContext*) gfx->iface.pInterface;
header.cmdId = RDPGFX_CMDID_CAPSADVERTISE;
pdu.capsSetCount = 0; pdu.capsSetCount = 0;
pdu.capsSets = (RDPGFX_CAPSET*) capsSets; pdu.capsSets = (RDPGFX_CAPSET*) capsSets;
capsSet = &capsSets[pdu.capsSetCount++]; capsSet = &capsSets[pdu.capsSetCount++];
@ -160,40 +215,11 @@ static UINT rdpgfx_send_caps_advertise_pdu(RDPGFX_CHANNEL_CALLBACK* callback)
#endif #endif
} }
header.pduLength = RDPGFX_HEADER_SIZE + 2; if (context)
for (x = 0; x < pdu.capsSetCount; x++)
header.pduLength += RDPGFX_CAPSET_BASE_SIZE + capsSets[x].length;
WLog_Print(gfx->log, WLOG_DEBUG, "SendCapsAdvertisePdu %"PRIu16"", pdu.capsSetCount);
s = Stream_New(NULL, header.pduLength);
if (!s)
{ {
WLog_ERR(TAG, "Stream_New failed!"); IFCALLRET(context->CapsAdvertise, error, context, &pdu);
return CHANNEL_RC_NO_MEMORY;
} }
if ((error = rdpgfx_write_header(s, &header)))
goto fail;
/* RDPGFX_CAPS_ADVERTISE_PDU */
Stream_Write_UINT16(s, pdu.capsSetCount); /* capsSetCount (2 bytes) */
for (index = 0; index < pdu.capsSetCount; index++)
{
capsSet = &(pdu.capsSets[index]);
Stream_Write_UINT32(s, capsSet->version); /* version (4 bytes) */
Stream_Write_UINT32(s, capsSet->length); /* capsDataLength (4 bytes) */
Stream_Write_UINT32(s, capsSet->flags); /* capsData (4 bytes) */
Stream_Zero(s, capsSet->length - 4);
}
Stream_SealLength(s);
error = callback->channel->Write(callback->channel, (UINT32) Stream_Length(s),
Stream_Buffer(s), NULL);
fail:
Stream_Free(s, TRUE);
return error; return error;
} }
@ -209,6 +235,7 @@ static UINT rdpgfx_recv_caps_confirm_pdu(RDPGFX_CHANNEL_CALLBACK* callback,
UINT32 capsDataLength; UINT32 capsDataLength;
RDPGFX_CAPS_CONFIRM_PDU pdu; RDPGFX_CAPS_CONFIRM_PDU pdu;
RDPGFX_PLUGIN* gfx = (RDPGFX_PLUGIN*) callback->plugin; RDPGFX_PLUGIN* gfx = (RDPGFX_PLUGIN*) callback->plugin;
RdpgfxClientContext* context = (RdpgfxClientContext*) gfx->iface.pInterface;
pdu.capsSet = &capsSet; pdu.capsSet = &capsSet;
if (Stream_GetRemainingLength(s) < 12) if (Stream_GetRemainingLength(s) < 12)
@ -223,6 +250,12 @@ static UINT rdpgfx_recv_caps_confirm_pdu(RDPGFX_CHANNEL_CALLBACK* callback,
gfx->ConnectionCaps = capsSet; gfx->ConnectionCaps = capsSet;
WLog_Print(gfx->log, WLOG_DEBUG, "RecvCapsConfirmPdu: version: 0x%08"PRIX32" flags: 0x%08"PRIX32"", WLog_Print(gfx->log, WLOG_DEBUG, "RecvCapsConfirmPdu: version: 0x%08"PRIX32" flags: 0x%08"PRIX32"",
capsSet.version, capsSet.flags); capsSet.version, capsSet.flags);
if (context)
{
IFCALL(context->CapsConfirm, context, &pdu);
}
return CHANNEL_RC_OK; return CHANNEL_RC_OK;
} }
@ -231,13 +264,14 @@ static UINT rdpgfx_recv_caps_confirm_pdu(RDPGFX_CHANNEL_CALLBACK* callback,
* *
* @return 0 on success, otherwise a Win32 error code * @return 0 on success, otherwise a Win32 error code
*/ */
static UINT rdpgfx_send_frame_acknowledge_pdu(RDPGFX_CHANNEL_CALLBACK* callback, static UINT rdpgfx_send_frame_acknowledge_pdu(RdpgfxClientContext* context,
RDPGFX_FRAME_ACKNOWLEDGE_PDU* pdu) RDPGFX_FRAME_ACKNOWLEDGE_PDU* pdu)
{ {
UINT error; UINT error;
wStream* s; wStream* s;
RDPGFX_HEADER header; RDPGFX_HEADER header;
RDPGFX_PLUGIN* gfx = (RDPGFX_PLUGIN*) callback->plugin; RDPGFX_PLUGIN* gfx = (RDPGFX_PLUGIN*) context->handle;
RDPGFX_CHANNEL_CALLBACK* callback = gfx->listener_callback->channel_callback;
header.flags = 0; header.flags = 0;
header.cmdId = RDPGFX_CMDID_FRAMEACKNOWLEDGE; header.cmdId = RDPGFX_CMDID_FRAMEACKNOWLEDGE;
header.pduLength = RDPGFX_HEADER_SIZE + 12; header.pduLength = RDPGFX_HEADER_SIZE + 12;
@ -599,7 +633,6 @@ static UINT rdpgfx_recv_end_frame_pdu(RDPGFX_CHANNEL_CALLBACK* callback,
RDPGFX_PLUGIN* gfx = (RDPGFX_PLUGIN*) callback->plugin; RDPGFX_PLUGIN* gfx = (RDPGFX_PLUGIN*) callback->plugin;
RdpgfxClientContext* context = (RdpgfxClientContext*) gfx->iface.pInterface; RdpgfxClientContext* context = (RdpgfxClientContext*) gfx->iface.pInterface;
UINT error = CHANNEL_RC_OK; UINT error = CHANNEL_RC_OK;
BOOL sendAck = TRUE;
if (Stream_GetRemainingLength(s) < RDPGFX_END_FRAME_PDU_SIZE) if (Stream_GetRemainingLength(s) < RDPGFX_END_FRAME_PDU_SIZE)
{ {
@ -625,16 +658,15 @@ static UINT rdpgfx_recv_end_frame_pdu(RDPGFX_CHANNEL_CALLBACK* callback,
gfx->TotalDecodedFrames++; gfx->TotalDecodedFrames++;
ack.frameId = pdu.frameId; ack.frameId = pdu.frameId;
ack.totalFramesDecoded = gfx->TotalDecodedFrames; ack.totalFramesDecoded = gfx->TotalDecodedFrames;
IFCALLRET(context->PreFrameAck, sendAck, context, &ack);
if (sendAck) if (gfx->sendFrameAcks)
{ {
if (gfx->suspendFrameAcks) if (gfx->suspendFrameAcks)
{ {
ack.queueDepth = SUSPEND_FRAME_ACKNOWLEDGEMENT; ack.queueDepth = SUSPEND_FRAME_ACKNOWLEDGEMENT;
if (gfx->TotalDecodedFrames == 1) if (gfx->TotalDecodedFrames == 1)
if ((error = rdpgfx_send_frame_acknowledge_pdu(callback, &ack))) if ((error = rdpgfx_send_frame_acknowledge_pdu(context, &ack)))
WLog_Print(gfx->log, WLOG_ERROR, "rdpgfx_send_frame_acknowledge_pdu failed with error %"PRIu32"", WLog_Print(gfx->log, WLOG_ERROR, "rdpgfx_send_frame_acknowledge_pdu failed with error %"PRIu32"",
error); error);
} }
@ -642,7 +674,7 @@ static UINT rdpgfx_recv_end_frame_pdu(RDPGFX_CHANNEL_CALLBACK* callback,
{ {
ack.queueDepth = QUEUE_DEPTH_UNAVAILABLE; ack.queueDepth = QUEUE_DEPTH_UNAVAILABLE;
if ((error = rdpgfx_send_frame_acknowledge_pdu(callback, &ack))) if ((error = rdpgfx_send_frame_acknowledge_pdu(context, &ack)))
WLog_Print(gfx->log, WLOG_ERROR, "rdpgfx_send_frame_acknowledge_pdu failed with error %"PRIu32"", WLog_Print(gfx->log, WLOG_ERROR, "rdpgfx_send_frame_acknowledge_pdu failed with error %"PRIu32"",
error); error);
} }
@ -667,7 +699,8 @@ static UINT rdpgfx_recv_end_frame_pdu(RDPGFX_CHANNEL_CALLBACK* callback,
qoe.timeDiffEDR = 1; qoe.timeDiffEDR = 1;
if ((error = rdpgfx_send_qoe_frame_acknowledge_pdu(callback, &qoe))) if ((error = rdpgfx_send_qoe_frame_acknowledge_pdu(callback, &qoe)))
WLog_Print(gfx->log, WLOG_ERROR, "rdpgfx_send_frame_acknowledge_pdu failed with error %"PRIu32"", WLog_Print(gfx->log, WLOG_ERROR,
"rdpgfx_send_qoe_frame_acknowledge_pdu failed with error %"PRIu32"",
error); error);
} }
@ -1518,8 +1551,24 @@ static UINT rdpgfx_on_data_received(IWTSVirtualChannelCallback*
static UINT rdpgfx_on_open(IWTSVirtualChannelCallback* pChannelCallback) static UINT rdpgfx_on_open(IWTSVirtualChannelCallback* pChannelCallback)
{ {
RDPGFX_CHANNEL_CALLBACK* callback = (RDPGFX_CHANNEL_CALLBACK*) pChannelCallback; RDPGFX_CHANNEL_CALLBACK* callback = (RDPGFX_CHANNEL_CALLBACK*) pChannelCallback;
WLog_DBG(TAG, "OnOpen"); RDPGFX_PLUGIN* gfx = (RDPGFX_PLUGIN*) callback->plugin;
return rdpgfx_send_caps_advertise_pdu(callback); RdpgfxClientContext* context = (RdpgfxClientContext*) gfx->iface.pInterface;
UINT error = CHANNEL_RC_OK;
BOOL do_caps_advertise = TRUE;
gfx->sendFrameAcks = TRUE;
if (context)
{
IFCALLRET(context->OnOpen, error, context, &do_caps_advertise, &gfx->sendFrameAcks);
if (error)
WLog_Print(gfx->log, WLOG_ERROR, "context->OnOpen failed with error %"PRIu32"", error);
}
if (do_caps_advertise)
error = rdpgfx_send_supported_caps(callback);
return error;
} }
/** /**
@ -1580,6 +1629,11 @@ static UINT rdpgfx_on_close(IWTSVirtualChannelCallback* pChannelCallback)
} }
} }
if (context)
{
IFCALL(context->OnClose, context);
}
return CHANNEL_RC_OK; return CHANNEL_RC_OK;
} }
@ -1911,6 +1965,8 @@ UINT DVCPluginEntry(IDRDYNVC_ENTRY_POINTS* pEntryPoints)
context->GetSurfaceData = rdpgfx_get_surface_data; context->GetSurfaceData = rdpgfx_get_surface_data;
context->SetCacheSlotData = rdpgfx_set_cache_slot_data; context->SetCacheSlotData = rdpgfx_set_cache_slot_data;
context->GetCacheSlotData = rdpgfx_get_cache_slot_data; context->GetCacheSlotData = rdpgfx_get_cache_slot_data;
context->CapsAdvertise = rdpgfx_send_caps_advertise_pdu;
context->FrameAcknowledge = rdpgfx_send_frame_acknowledge_pdu;
gfx->iface.pInterface = (void*) context; gfx->iface.pInterface = (void*) context;
gfx->zgfx = zgfx_context_new(FALSE); gfx->zgfx = zgfx_context_new(FALSE);

View File

@ -73,6 +73,7 @@ struct _RDPGFX_PLUGIN
UINT32 TotalDecodedFrames; UINT32 TotalDecodedFrames;
UINT32 StartDecodingTime; UINT32 StartDecodingTime;
BOOL suspendFrameAcks; BOOL suspendFrameAcks;
BOOL sendFrameAcks;
wHashTable* SurfaceTable; wHashTable* SurfaceTable;

View File

@ -83,8 +83,15 @@ typedef UINT(*pcRdpgfxUpdateSurfaces)(RdpgfxClientContext* context);
typedef UINT(*pcRdpgfxUpdateSurfaceArea)(RdpgfxClientContext* context, UINT16 surfaceId, typedef UINT(*pcRdpgfxUpdateSurfaceArea)(RdpgfxClientContext* context, UINT16 surfaceId,
UINT32 nrRects, const RECTANGLE_16* rects); UINT32 nrRects, const RECTANGLE_16* rects);
typedef BOOL(*pcRdpgfxPreFrameAck)(RdpgfxClientContext* context, typedef UINT(*pcRdpgfxOnOpen)(RdpgfxClientContext* context, BOOL* do_caps_advertise,
RDPGFX_FRAME_ACKNOWLEDGE_PDU* frameAcknowledge); BOOL* do_frame_acks);
typedef UINT(*pcRdpgfxOnClose)(RdpgfxClientContext* context);
typedef UINT(*pcRdpgfxCapsAdvertise)(RdpgfxClientContext* context,
const RDPGFX_CAPS_ADVERTISE_PDU* capsAdvertise);
typedef UINT(*pcRdpgfxCapsConfirm)(RdpgfxClientContext* context,
const RDPGFX_CAPS_CONFIRM_PDU* capsConfirm);
typedef UINT(*pcRdpgfxFrameAcknowledge)(RdpgfxClientContext* context,
const RDPGFX_FRAME_ACKNOWLEDGE_PDU* frameAcknowledge);
struct _rdpgfx_client_context struct _rdpgfx_client_context
{ {
@ -117,12 +124,17 @@ struct _rdpgfx_client_context
pcRdpgfxSetCacheSlotData SetCacheSlotData; pcRdpgfxSetCacheSlotData SetCacheSlotData;
pcRdpgfxGetCacheSlotData GetCacheSlotData; pcRdpgfxGetCacheSlotData GetCacheSlotData;
/* Proxy callbacks */
pcRdpgfxOnOpen OnOpen;
pcRdpgfxOnClose OnClose;
pcRdpgfxCapsAdvertise CapsAdvertise;
pcRdpgfxCapsConfirm CapsConfirm;
pcRdpgfxFrameAcknowledge FrameAcknowledge;
/* No locking required */ /* No locking required */
pcRdpgfxUpdateSurfaces UpdateSurfaces; pcRdpgfxUpdateSurfaces UpdateSurfaces;
pcRdpgfxUpdateSurfaceArea UpdateSurfaceArea; pcRdpgfxUpdateSurfaceArea UpdateSurfaceArea;
pcRdpgfxPreFrameAck PreFrameAck;
CRITICAL_SECTION mux; CRITICAL_SECTION mux;
PROFILER_DEFINE(SurfaceProfiler) PROFILER_DEFINE(SurfaceProfiler)
}; };