Use a feature to customize Vulkan Ycbcr emulation

Test: build
Change-Id: I2d0ae638db8acca321faf55f9166aab27ad8a799
diff --git a/stream-servers/FrameBuffer.cpp b/stream-servers/FrameBuffer.cpp
index e18a4ac..5d9c301 100644
--- a/stream-servers/FrameBuffer.cpp
+++ b/stream-servers/FrameBuffer.cpp
@@ -534,6 +534,7 @@
             .useVulkanNativeSwapchain = feature_is_enabled(kFeature_VulkanNativeSwapchain),
             .guestRenderDoc = std::move(renderDocMultipleVkInstances),
             .enableAstcLdrEmulation = feature_is_enabled(kFeature_VulkanAstcLdrEmulation),
+            .enableYcbcrEmulation = feature_is_enabled(kFeature_VulkanYcbcrEmulation),
         });
 
     //
diff --git a/stream-servers/GfxStreamBackend.cpp b/stream-servers/GfxStreamBackend.cpp
index f75b2d9..db0f417 100644
--- a/stream-servers/GfxStreamBackend.cpp
+++ b/stream-servers/GfxStreamBackend.cpp
@@ -437,6 +437,7 @@
            !syncFdDisabledByFlag &&
            (renderer_flags & GFXSTREAM_RENDERER_FLAGS_ASYNC_FENCE_CB));
     feature_set_enabled_override(kFeature_VulkanAstcLdrEmulation, true);
+    feature_set_enabled_override(kFeature_VulkanYcbcrEmulation, false);
 
     android::featurecontrol::productFeatureOverride();
 
diff --git a/stream-servers/vulkan/VkCommonOperations.cpp b/stream-servers/vulkan/VkCommonOperations.cpp
index c93f440..e799249 100644
--- a/stream-servers/vulkan/VkCommonOperations.cpp
+++ b/stream-servers/vulkan/VkCommonOperations.cpp
@@ -1148,11 +1148,13 @@
     INFO("    useVulkanNativeSwapchain: %s", features->useVulkanNativeSwapchain ? "true" : "false");
     INFO("    enable guestRenderDoc: %s", features->guestRenderDoc ? "true" : "false");
     INFO("    enable ASTC LDR emulation: %s", features->enableAstcLdrEmulation ? "true" : "false");
+    INFO("    enable Ycbcr emulation: %s", features->enableYcbcrEmulation ? "true" : "false");
     sVkEmulation->deviceInfo.glInteropSupported = features->glInteropSupported;
     sVkEmulation->useDeferredCommands = features->deferredCommands;
     sVkEmulation->useCreateResourcesWithRequirements = features->createResourceWithRequirements;
     sVkEmulation->guestRenderDoc = std::move(features->guestRenderDoc);
     sVkEmulation->enableAstcLdrEmulation = features->enableAstcLdrEmulation;
+    sVkEmulation->enableYcbcrEmulation = features->enableYcbcrEmulation;
 
     if (features->useVulkanComposition) {
         if (sVkEmulation->compositorVk) {
diff --git a/stream-servers/vulkan/VkCommonOperations.h b/stream-servers/vulkan/VkCommonOperations.h
index 220dcca..59eea36 100644
--- a/stream-servers/vulkan/VkCommonOperations.h
+++ b/stream-servers/vulkan/VkCommonOperations.h
@@ -84,6 +84,11 @@
     // lost on certain device on Windows.
     bool enableAstcLdrEmulation = false;
 
+    // Whether to use Ycbcr emulation. If this feature is turned on, Ycbcr request will always use
+    // the emulation path regardless of whether the host Vulkan driver actually supports Ycbcr
+    // conversion or not.
+    bool enableYcbcrEmulation = false;
+
     // Instance and device for creating the system-wide shareable objects.
     VkInstance instance = VK_NULL_HANDLE;
     VkPhysicalDevice physdev = VK_NULL_HANDLE;
@@ -357,6 +362,7 @@
     bool useVulkanNativeSwapchain = false;
     std::unique_ptr<emugl::RenderDocWithMultipleVkInstances> guestRenderDoc = nullptr;
     bool enableAstcLdrEmulation = false;
+    bool enableYcbcrEmulation = false;
 };
 void initVkEmulationFeatures(std::unique_ptr<VkEmulationFeatures>);
 
diff --git a/stream-servers/vulkan/VkDecoderGlobalState.cpp b/stream-servers/vulkan/VkDecoderGlobalState.cpp
index 161ae3c..8dde8ee 100644
--- a/stream-servers/vulkan/VkDecoderGlobalState.cpp
+++ b/stream-servers/vulkan/VkDecoderGlobalState.cpp
@@ -729,7 +729,7 @@
         VkPhysicalDeviceSamplerYcbcrConversionFeatures* ycbcrFeatures =
             vk_find_struct<VkPhysicalDeviceSamplerYcbcrConversionFeatures>(pFeatures);
         if (ycbcrFeatures != nullptr) {
-            ycbcrFeatures->samplerYcbcrConversion |= kEmulateSamplerYcbcrConversion;
+            ycbcrFeatures->samplerYcbcrConversion |= m_emu->enableYcbcrEmulation;
         }
     }
 
@@ -1083,7 +1083,7 @@
         auto physicalDevice = unbox_VkPhysicalDevice(boxed_physicalDevice);
         auto vk = dispatch_VkPhysicalDevice(boxed_physicalDevice);
 
-        if (!m_emu->instanceSupportsMoltenVK && !kEmulateSamplerYcbcrConversion) {
+        if (!m_emu->instanceSupportsMoltenVK && !m_emu->enableYcbcrEmulation) {
             return vk->vkEnumerateDeviceExtensionProperties(physicalDevice, pLayerName,
                                                             pPropertyCount, pProperties);
         }
@@ -1106,9 +1106,8 @@
             properties.push_back(mvk_props);
         }
 
-        if (kEmulateSamplerYcbcrConversion &&
-            !hasDeviceExtension(
-                properties, VK_KHR_SAMPLER_YCBCR_CONVERSION_EXTENSION_NAME)) {
+        if (m_emu->enableYcbcrEmulation &&
+            !hasDeviceExtension(properties, VK_KHR_SAMPLER_YCBCR_CONVERSION_EXTENSION_NAME)) {
             VkExtensionProperties ycbcr_props;
             strncpy(ycbcr_props.extensionName, VK_KHR_SAMPLER_YCBCR_CONVERSION_EXTENSION_NAME,
                     sizeof(ycbcr_props.extensionName));
@@ -1182,7 +1181,7 @@
                     }
                     break;
                 case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SAMPLER_YCBCR_CONVERSION_FEATURES:
-                    if (kEmulateSamplerYcbcrConversion &&
+                    if (m_emu->enableYcbcrEmulation &&
                         !m_emu->deviceInfo.supportsSamplerYcbcrConversion) {
                         VkPhysicalDeviceSamplerYcbcrConversionFeatures* features2 =
                             (VkPhysicalDeviceSamplerYcbcrConversionFeatures*)ext;
@@ -4735,7 +4734,7 @@
         android::base::BumpPool*, VkDevice boxed_device,
         const VkSamplerYcbcrConversionCreateInfo* pCreateInfo,
         const VkAllocationCallbacks* pAllocator, VkSamplerYcbcrConversion* pYcbcrConversion) {
-        if (kEmulateSamplerYcbcrConversion && !m_emu->deviceInfo.supportsSamplerYcbcrConversion) {
+        if (m_emu->enableYcbcrEmulation && !m_emu->deviceInfo.supportsSamplerYcbcrConversion) {
             *pYcbcrConversion = new_boxed_non_dispatchable_VkSamplerYcbcrConversion(
                 (VkSamplerYcbcrConversion)((uintptr_t)0xffff0000ull));
             return VK_SUCCESS;
@@ -4754,7 +4753,7 @@
     void on_vkDestroySamplerYcbcrConversion(android::base::BumpPool* pool, VkDevice boxed_device,
                                             VkSamplerYcbcrConversion boxed_ycbcrConversion,
                                             const VkAllocationCallbacks* pAllocator) {
-        if (kEmulateSamplerYcbcrConversion && !m_emu->deviceInfo.supportsSamplerYcbcrConversion) {
+        if (m_emu->enableYcbcrEmulation && !m_emu->deviceInfo.supportsSamplerYcbcrConversion) {
             return;
         }
         auto device = unbox_VkDevice(boxed_device);
@@ -5135,15 +5134,13 @@
     VkDecoderSnapshot* snapshot() { return &mSnapshot; }
 
    private:
-    static const bool kEmulateSamplerYcbcrConversion = false;
-
     bool isEmulatedExtension(const char* name) const {
         for (auto emulatedExt : kEmulatedExtensions) {
             if (!strcmp(emulatedExt, name)) return true;
         }
         if (!strcmp(VK_KHR_SAMPLER_YCBCR_CONVERSION_EXTENSION_NAME, name)) {
             return !m_emu->deviceInfo.hasSamplerYcbcrConversionExtension &&
-                   kEmulateSamplerYcbcrConversion;
+                   m_emu->enableYcbcrEmulation;
         }
         return false;
     }