Added gfx capability filter option.

With this new option it is possible to selectively disable certain
GFX capability versions. This way buggy behaviour can be addressed
at runtime.
This commit is contained in:
Armin Novak 2019-05-08 11:43:22 +02:00
parent 3d1cec894c
commit 7b2608a938
4 changed files with 195 additions and 90 deletions

View File

@ -106,6 +106,32 @@ fail:
return error;
}
static BOOL rdpgfx_is_capability_filtered(RDPGFX_PLUGIN* gfx, UINT32 caps)
{
const UINT32 filter = gfx->capsFilter;
const UINT32 capList[] =
{
RDPGFX_CAPVERSION_8,
RDPGFX_CAPVERSION_81,
RDPGFX_CAPVERSION_10,
RDPGFX_CAPVERSION_101,
RDPGFX_CAPVERSION_102,
RDPGFX_CAPVERSION_103,
RDPGFX_CAPVERSION_104,
RDPGFX_CAPVERSION_105,
RDPGFX_CAPVERSION_106
};
UINT32 x;
for (x = 0; x < ARRAYSIZE(capList); x++)
{
if (caps == capList[x])
return (filter & (1 << x)) != 0;
}
return TRUE;
}
/**
* Function description
*
@ -113,54 +139,69 @@ fail:
*/
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_CAPS_ADVERTISE_PDU pdu;
if (!callback)
return ERROR_BAD_ARGUMENTS;
gfx = (RDPGFX_PLUGIN*) callback->plugin;
if (!gfx)
return ERROR_BAD_CONFIGURATION;
context = (RdpgfxClientContext*) gfx->iface.pInterface;
if (!context)
return ERROR_BAD_CONFIGURATION;
pdu.capsSetCount = 0;
pdu.capsSets = (RDPGFX_CAPSET*) capsSets;
capsSet = &capsSets[pdu.capsSetCount++];
capsSet->version = RDPGFX_CAPVERSION_8;
capsSet->length = 4;
capsSet->flags = 0;
if (gfx->ThinClient)
capsSet->flags |= RDPGFX_CAPS_FLAG_THINCLIENT;
if (!rdpgfx_is_capability_filtered(gfx, RDPGFX_CAPVERSION_8))
{
capsSet = &capsSets[pdu.capsSetCount++];
capsSet->version = RDPGFX_CAPVERSION_8;
capsSet->length = 4;
capsSet->flags = 0;
/* in CAPVERSION_8 the spec says that we should not have both
* thinclient and smallcache (and thinclient implies a small cache)
*/
if (gfx->SmallCache && !gfx->ThinClient)
capsSet->flags |= RDPGFX_CAPS_FLAG_SMALL_CACHE;
if (gfx->ThinClient)
capsSet->flags |= RDPGFX_CAPS_FLAG_THINCLIENT;
capsSet = &capsSets[pdu.capsSetCount++];
capsSet->version = RDPGFX_CAPVERSION_81;
capsSet->length = 4;
capsSet->flags = 0;
/* in CAPVERSION_8 the spec says that we should not have both
* thinclient and smallcache (and thinclient implies a small cache)
*/
if (gfx->SmallCache && !gfx->ThinClient)
capsSet->flags |= RDPGFX_CAPS_FLAG_SMALL_CACHE;
}
if (gfx->ThinClient)
capsSet->flags |= RDPGFX_CAPS_FLAG_THINCLIENT;
if (!rdpgfx_is_capability_filtered(gfx, RDPGFX_CAPVERSION_81))
{
capsSet = &capsSets[pdu.capsSetCount++];
capsSet->version = RDPGFX_CAPVERSION_81;
capsSet->length = 4;
capsSet->flags = 0;
if (gfx->SmallCache)
capsSet->flags |= RDPGFX_CAPS_FLAG_SMALL_CACHE;
if (gfx->ThinClient)
capsSet->flags |= RDPGFX_CAPS_FLAG_THINCLIENT;
if (gfx->SmallCache)
capsSet->flags |= RDPGFX_CAPS_FLAG_SMALL_CACHE;
#ifdef WITH_GFX_H264
if (gfx->H264)
capsSet->flags |= RDPGFX_CAPS_FLAG_AVC420_ENABLED;
if (gfx->H264)
capsSet->flags |= RDPGFX_CAPS_FLAG_AVC420_ENABLED;
#endif
}
if (!gfx->H264 || gfx->AVC444)
{
UINT32 caps10Flags = 0;
capsSet = &capsSets[pdu.capsSetCount++];
capsSet->version = RDPGFX_CAPVERSION_10;
capsSet->length = 4;
if (gfx->SmallCache)
caps10Flags |= RDPGFX_CAPS_FLAG_SMALL_CACHE;
@ -173,43 +214,68 @@ static UINT rdpgfx_send_supported_caps(RDPGFX_CHANNEL_CALLBACK* callback)
#else
caps10Flags |= RDPGFX_CAPS_FLAG_AVC_DISABLED;
#endif
capsSet->flags = caps10Flags;
capsSet = &capsSets[pdu.capsSetCount++];
capsSet->version = RDPGFX_CAPVERSION_101;
capsSet->length = 0x10;
capsSet->flags = 0;
capsSet = &capsSets[pdu.capsSetCount++];
capsSet->version = RDPGFX_CAPVERSION_102;
capsSet->length = 0x4;
capsSet->flags = caps10Flags;
if (!rdpgfx_is_capability_filtered(gfx, RDPGFX_CAPVERSION_10))
{
capsSet = &capsSets[pdu.capsSetCount++];
capsSet->version = RDPGFX_CAPVERSION_10;
capsSet->length = 4;
capsSet->flags = caps10Flags;
}
if (!rdpgfx_is_capability_filtered(gfx, RDPGFX_CAPVERSION_101))
{
capsSet = &capsSets[pdu.capsSetCount++];
capsSet->version = RDPGFX_CAPVERSION_101;
capsSet->length = 0x10;
capsSet->flags = 0;
}
if (!rdpgfx_is_capability_filtered(gfx, RDPGFX_CAPVERSION_102))
{
capsSet = &capsSets[pdu.capsSetCount++];
capsSet->version = RDPGFX_CAPVERSION_102;
capsSet->length = 0x4;
capsSet->flags = caps10Flags;
}
if (gfx->ThinClient)
caps10Flags |= RDPGFX_CAPS_FLAG_AVC_THINCLIENT;
capsSet = &capsSets[pdu.capsSetCount++];
capsSet->version = RDPGFX_CAPVERSION_103;
capsSet->length = 0x4;
capsSet->flags = caps10Flags & ~RDPGFX_CAPS_FLAG_SMALL_CACHE;
capsSet = &capsSets[pdu.capsSetCount++];
capsSet->version = RDPGFX_CAPVERSION_104;
capsSet->length = 0x4;
capsSet->flags = caps10Flags;
capsSet = &capsSets[pdu.capsSetCount++];
capsSet->version = RDPGFX_CAPVERSION_105;
capsSet->length = 0x4;
capsSet->flags = caps10Flags;
capsSet = &capsSets[pdu.capsSetCount++];
capsSet->version = RDPGFX_CAPVERSION_106;
capsSet->length = 0x4;
capsSet->flags = caps10Flags;
if (!rdpgfx_is_capability_filtered(gfx, RDPGFX_CAPVERSION_103))
{
capsSet = &capsSets[pdu.capsSetCount++];
capsSet->version = RDPGFX_CAPVERSION_103;
capsSet->length = 0x4;
capsSet->flags = caps10Flags & ~RDPGFX_CAPS_FLAG_SMALL_CACHE;
}
if (!rdpgfx_is_capability_filtered(gfx, RDPGFX_CAPVERSION_104))
{
capsSet = &capsSets[pdu.capsSetCount++];
capsSet->version = RDPGFX_CAPVERSION_104;
capsSet->length = 0x4;
capsSet->flags = caps10Flags;
}
if (!rdpgfx_is_capability_filtered(gfx, RDPGFX_CAPVERSION_105))
{
capsSet = &capsSets[pdu.capsSetCount++];
capsSet->version = RDPGFX_CAPVERSION_105;
capsSet->length = 0x4;
capsSet->flags = caps10Flags;
}
if (!rdpgfx_is_capability_filtered(gfx, RDPGFX_CAPVERSION_106))
{
capsSet = &capsSets[pdu.capsSetCount++];
capsSet->version = RDPGFX_CAPVERSION_106;
capsSet->length = 0x4;
capsSet->flags = caps10Flags;
}
}
if (context)
{
IFCALLRET(context->CapsAdvertise, error, context, &pdu);
}
return error;
return IFCALLRESULT(ERROR_BAD_CONFIGURATION, context->CapsAdvertise, context, &pdu);
}
/**
@ -1949,6 +2015,7 @@ UINT DVCPluginEntry(IDRDYNVC_ENTRY_POINTS* pEntryPoints)
gfx->H264 = gfx->settings->GfxH264;
gfx->AVC444 = gfx->settings->GfxAVC444;
gfx->SendQoeAck = gfx->settings->GfxSendQoeAck;
gfx->capsFilter = gfx->settings->GfxCapsFilter;
if (gfx->H264)
gfx->SmallCache = TRUE;

View File

@ -67,6 +67,7 @@ struct _RDPGFX_PLUGIN
BOOL ProgressiveV2;
BOOL H264;
BOOL AVC444;
UINT32 capsFilter;
ZGFX_CONTEXT* zgfx;
UINT32 UnacknowledgedFrames;

View File

@ -835,6 +835,7 @@ typedef struct _RDPDR_PARALLEL RDPDR_PARALLEL;
#define FreeRDP_GfxAVC444 (3845)
#define FreeRDP_GfxSendQoeAck (3846)
#define FreeRDP_GfxAVC444v2 (3847)
#define FreeRDP_GfxCapsFilter (3848)
#define FreeRDP_BitmapCacheV3CodecId (3904)
#define FreeRDP_DrawNineGridEnabled (3968)
#define FreeRDP_DrawNineGridCacheSize (3969)
@ -1419,7 +1420,8 @@ struct rdp_settings
ALIGN64 BOOL GfxAVC444; /* 3845 */
ALIGN64 BOOL GfxSendQoeAck; /* 3846 */
ALIGN64 BOOL GfxAVC444v2; /* 3847 */
UINT64 padding3904[3904 - 3848]; /* 3848 */
ALIGN64 UINT32 GfxCapsFilter; /* 3848 */
UINT64 padding3904[3904 - 3849]; /* 3849 */
/**
* Caches

View File

@ -613,6 +613,32 @@ static UINT shadow_client_rdpgfx_frame_acknowledge(RdpgfxServerContext* context,
return CHANNEL_RC_OK;
}
static BOOL shadow_are_caps_filtered(const rdpSettings* settings, UINT32 caps)
{
const UINT32 filter = settings->GfxCapsFilter;
const UINT32 capList[] =
{
RDPGFX_CAPVERSION_8,
RDPGFX_CAPVERSION_81,
RDPGFX_CAPVERSION_10,
RDPGFX_CAPVERSION_101,
RDPGFX_CAPVERSION_102,
RDPGFX_CAPVERSION_103,
RDPGFX_CAPVERSION_104,
RDPGFX_CAPVERSION_105,
RDPGFX_CAPVERSION_106
};
UINT32 x;
for (x = 0; x < ARRAYSIZE(capList); x++)
{
if (caps == capList[x])
return (filter & (1 << x)) != 0;
}
return TRUE;
}
static BOOL shadow_client_caps_test_version(RdpgfxServerContext* context,
const RDPGFX_CAPSET* capsSets,
UINT32 capsSetCount,
@ -623,6 +649,9 @@ static BOOL shadow_client_caps_test_version(RdpgfxServerContext* context,
rdpSettings* settings;
settings = context->rdpcontext->settings;
if (shadow_are_caps_filtered(settings, capsVersion))
return FALSE;
for (index = 0; index < capsSetCount; index++)
{
const RDPGFX_CAPSET* currentCaps = &capsSets[index];
@ -697,52 +726,58 @@ static UINT shadow_client_rdpgfx_caps_advertise(RdpgfxServerContext* context,
RDPGFX_CAPVERSION_10, &rc))
return rc;
for (index = 0; index < capsAdvertise->capsSetCount; index++)
if (!shadow_are_caps_filtered(settings, RDPGFX_CAPVERSION_81))
{
const RDPGFX_CAPSET* currentCaps = &capsAdvertise->capsSets[index];
if (currentCaps->version == RDPGFX_CAPVERSION_81)
for (index = 0; index < capsAdvertise->capsSetCount; index++)
{
RDPGFX_CAPSET caps = *currentCaps;
RDPGFX_CAPS_CONFIRM_PDU pdu;
pdu.capsSet = &caps;
const RDPGFX_CAPSET* currentCaps = &capsAdvertise->capsSets[index];
if (settings)
if (currentCaps->version == RDPGFX_CAPVERSION_81)
{
flags = pdu.capsSet->flags;
settings->GfxAVC444v2 = settings->GfxAVC444 = FALSE;
settings->GfxThinClient = (flags & RDPGFX_CAPS_FLAG_THINCLIENT);
settings->GfxSmallCache = (flags & RDPGFX_CAPS_FLAG_SMALL_CACHE);
#ifndef WITH_GFX_H264
settings->GfxH264 = FALSE;
pdu.capsSet->flags &= ~RDPGFX_CAPS_FLAG_AVC420_ENABLED;
#else
settings->GfxH264 = (flags & RDPGFX_CAPS_FLAG_AVC420_ENABLED);
#endif
}
RDPGFX_CAPSET caps = *currentCaps;
RDPGFX_CAPS_CONFIRM_PDU pdu;
pdu.capsSet = &caps;
return context->CapsConfirm(context, &pdu);
if (settings)
{
flags = pdu.capsSet->flags;
settings->GfxAVC444v2 = settings->GfxAVC444 = FALSE;
settings->GfxThinClient = (flags & RDPGFX_CAPS_FLAG_THINCLIENT);
settings->GfxSmallCache = (flags & RDPGFX_CAPS_FLAG_SMALL_CACHE);
#ifndef WITH_GFX_H264
settings->GfxH264 = FALSE;
pdu.capsSet->flags &= ~RDPGFX_CAPS_FLAG_AVC420_ENABLED;
#else
settings->GfxH264 = (flags & RDPGFX_CAPS_FLAG_AVC420_ENABLED);
#endif
}
return context->CapsConfirm(context, &pdu);
}
}
}
for (index = 0; index < capsAdvertise->capsSetCount; index++)
if (!shadow_are_caps_filtered(settings, RDPGFX_CAPVERSION_8))
{
const RDPGFX_CAPSET* currentCaps = &capsAdvertise->capsSets[index];
if (currentCaps->version == RDPGFX_CAPVERSION_8)
for (index = 0; index < capsAdvertise->capsSetCount; index++)
{
RDPGFX_CAPSET caps = *currentCaps;
RDPGFX_CAPS_CONFIRM_PDU pdu;
pdu.capsSet = &caps;
const RDPGFX_CAPSET* currentCaps = &capsAdvertise->capsSets[index];
if (settings)
if (currentCaps->version == RDPGFX_CAPVERSION_8)
{
flags = pdu.capsSet->flags;
settings->GfxThinClient = (flags & RDPGFX_CAPS_FLAG_THINCLIENT);
settings->GfxSmallCache = (flags & RDPGFX_CAPS_FLAG_SMALL_CACHE);
}
RDPGFX_CAPSET caps = *currentCaps;
RDPGFX_CAPS_CONFIRM_PDU pdu;
pdu.capsSet = &caps;
return context->CapsConfirm(context, &pdu);
if (settings)
{
flags = pdu.capsSet->flags;
settings->GfxThinClient = (flags & RDPGFX_CAPS_FLAG_THINCLIENT);
settings->GfxSmallCache = (flags & RDPGFX_CAPS_FLAG_SMALL_CACHE);
}
return context->CapsConfirm(context, &pdu);
}
}
}