Added gfx capability filter option.
authorArmin Novak <armin.novak@thincast.com>
Wed, 8 May 2019 09:43:22 +0000 (11:43 +0200)
committerArmin Novak <armin.novak@thincast.com>
Wed, 8 May 2019 09:43:22 +0000 (11:43 +0200)
With this new option it is possible to selectively disable certain
GFX capability versions. This way buggy behaviour can be addressed
at runtime.

channels/rdpgfx/client/rdpgfx_main.c
channels/rdpgfx/client/rdpgfx_main.h
include/freerdp/settings.h
server/shadow/shadow_client.c

index dcf6cbe..2a448bd 100644 (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 (context)
-       {
-               IFCALLRET(context->CapsAdvertise, error, context, &pdu);
+               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;
+               }
        }
 
-       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;
index bf7be0d..aada843 100644 (file)
@@ -67,6 +67,7 @@ struct _RDPGFX_PLUGIN
        BOOL ProgressiveV2;
        BOOL H264;
        BOOL AVC444;
+       UINT32 capsFilter;
 
        ZGFX_CONTEXT* zgfx;
        UINT32 UnacknowledgedFrames;
index 5a4e4c6..d6eef5c 100644 (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
index 18fc8e3..b414081 100644 (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);
+                               RDPGFX_CAPSET caps = *currentCaps;
+                               RDPGFX_CAPS_CONFIRM_PDU pdu;
+                               pdu.capsSet = &caps;
+
+                               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;
+                                       settings->GfxH264 = FALSE;
+                                       pdu.capsSet->flags &= ~RDPGFX_CAPS_FLAG_AVC420_ENABLED;
 #else
-                               settings->GfxH264 = (flags & RDPGFX_CAPS_FLAG_AVC420_ENABLED);
+                                       settings->GfxH264 = (flags & RDPGFX_CAPS_FLAG_AVC420_ENABLED);
 #endif
-                       }
+                               }
 
-                       return context->CapsConfirm(context, &pdu);
+                               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);
+                       }
                }
        }