Do not create YcbcrConversion for RGB565 passed as external format

Since we don't support external formats (we replace
them to internal ones and cut off VkExternalFormatANDROID
from struct chains), a vkCreateSampler call with
a conversion based on an external format with
another external format provided does not make sence.

This change returns a predefined value
(VK_YCBCR_CONVERSION_DO_NOTHING of type
VkSamplerYcbcrConversion) for CreateSamplerYcbcrConversion
when RGB565 is passed as an external format.

This special value (VK_YCBCR_CONVERSION_DO_NOTHING) is
checked later in vkCreateSampler and the whole
VkSamplerYcbcrConversionInfo is discarded.

Bug: 134771579
Test: CtsGraphicsTestCases android.graphics.cts.BasicVulkanGpuTest
Change-Id: I6c0a085866178391eb330b0005a687914be5e865
Signed-off-by: Roman Kiryanov <rkir@google.com>
diff --git a/system/vulkan/func_table.cpp b/system/vulkan/func_table.cpp
index f0ed982..a5227ec 100644
--- a/system/vulkan/func_table.cpp
+++ b/system/vulkan/func_table.cpp
@@ -812,7 +812,8 @@
     AEMU_SCOPED_TRACE("vkCreateSampler");
     auto vkEnc = HostConnection::get()->vkEncoder();
     VkResult vkCreateSampler_VkResult_return = (VkResult)0;
-    vkCreateSampler_VkResult_return = vkEnc->vkCreateSampler(device, pCreateInfo, pAllocator, pSampler);
+    auto resources = ResourceTracker::get();
+    vkCreateSampler_VkResult_return = resources->on_vkCreateSampler(vkEnc, VK_SUCCESS, device, pCreateInfo, pAllocator, pSampler);
     return vkCreateSampler_VkResult_return;
 }
 static void entry_vkDestroySampler(
@@ -1777,7 +1778,8 @@
 {
     AEMU_SCOPED_TRACE("vkDestroySamplerYcbcrConversion");
     auto vkEnc = HostConnection::get()->vkEncoder();
-    vkEnc->vkDestroySamplerYcbcrConversion(device, ycbcrConversion, pAllocator);
+    auto resources = ResourceTracker::get();
+    resources->on_vkDestroySamplerYcbcrConversion(vkEnc, device, ycbcrConversion, pAllocator);
 }
 static VkResult entry_vkCreateDescriptorUpdateTemplate(
     VkDevice device,
@@ -2822,7 +2824,8 @@
 {
     AEMU_SCOPED_TRACE("vkDestroySamplerYcbcrConversionKHR");
     auto vkEnc = HostConnection::get()->vkEncoder();
-    vkEnc->vkDestroySamplerYcbcrConversionKHR(device, ycbcrConversion, pAllocator);
+    auto resources = ResourceTracker::get();
+    resources->on_vkDestroySamplerYcbcrConversionKHR(vkEnc, device, ycbcrConversion, pAllocator);
 }
 #endif
 #ifdef VK_KHR_bind_memory2
diff --git a/system/vulkan_enc/ResourceTracker.cpp b/system/vulkan_enc/ResourceTracker.cpp
index 9cd8a79..e03e143 100644
--- a/system/vulkan_enc/ResourceTracker.cpp
+++ b/system/vulkan_enc/ResourceTracker.cpp
@@ -2274,7 +2274,15 @@
         const VkExternalFormatANDROID* extFormatAndroidPtr =
             vk_find_struct<VkExternalFormatANDROID>(pCreateInfo);
         if (extFormatAndroidPtr) {
-            if (extFormatAndroidPtr->externalFormat) {
+            if (extFormatAndroidPtr->externalFormat == AHARDWAREBUFFER_FORMAT_R5G6B5_UNORM) {
+                // We don't support external formats on host and it causes RGB565
+                // to fail in CtsGraphicsTestCases android.graphics.cts.BasicVulkanGpuTest
+                // when passed as an external format.
+                // We may consider doing this for all external formats.
+                // See b/134771579.
+                *pYcbcrConversion = VK_YCBCR_CONVERSION_DO_NOTHING;
+                return VK_SUCCESS;
+            } else if (extFormatAndroidPtr->externalFormat) {
                 localCreateInfo.format =
                     vk_format_from_android(extFormatAndroidPtr->externalFormat);
             }
@@ -2282,8 +2290,25 @@
 #endif
 
         VkEncoder* enc = (VkEncoder*)context;
-        return enc->vkCreateSamplerYcbcrConversion(
+        VkResult res = enc->vkCreateSamplerYcbcrConversion(
             device, &localCreateInfo, pAllocator, pYcbcrConversion);
+
+        if (*pYcbcrConversion == VK_YCBCR_CONVERSION_DO_NOTHING) {
+            ALOGE("FATAL: vkCreateSamplerYcbcrConversion returned a reserved value (VK_YCBCR_CONVERSION_DO_NOTHING)");
+            abort();
+        }
+        return res;
+    }
+
+    void on_vkDestroySamplerYcbcrConversion(
+        void* context,
+        VkDevice device,
+        VkSamplerYcbcrConversion ycbcrConversion,
+        const VkAllocationCallbacks* pAllocator) {
+        VkEncoder* enc = (VkEncoder*)context;
+        if (ycbcrConversion != VK_YCBCR_CONVERSION_DO_NOTHING) {
+            enc->vkDestroySamplerYcbcrConversion(device, ycbcrConversion, pAllocator);
+        }
     }
 
     VkResult on_vkCreateSamplerYcbcrConversionKHR(
@@ -2299,7 +2324,15 @@
         const VkExternalFormatANDROID* extFormatAndroidPtr =
             vk_find_struct<VkExternalFormatANDROID>(pCreateInfo);
         if (extFormatAndroidPtr) {
-            if (extFormatAndroidPtr->externalFormat) {
+            if (extFormatAndroidPtr->externalFormat == AHARDWAREBUFFER_FORMAT_R5G6B5_UNORM) {
+                // We don't support external formats on host and it causes RGB565
+                // to fail in CtsGraphicsTestCases android.graphics.cts.BasicVulkanGpuTest
+                // when passed as an external format.
+                // We may consider doing this for all external formats.
+                // See b/134771579.
+                *pYcbcrConversion = VK_YCBCR_CONVERSION_DO_NOTHING;
+                return VK_SUCCESS;
+            } else if (extFormatAndroidPtr->externalFormat) {
                 localCreateInfo.format =
                     vk_format_from_android(extFormatAndroidPtr->externalFormat);
             }
@@ -2307,8 +2340,51 @@
 #endif
 
         VkEncoder* enc = (VkEncoder*)context;
-        return enc->vkCreateSamplerYcbcrConversionKHR(
+        VkResult res = enc->vkCreateSamplerYcbcrConversionKHR(
             device, &localCreateInfo, pAllocator, pYcbcrConversion);
+
+        if (*pYcbcrConversion == VK_YCBCR_CONVERSION_DO_NOTHING) {
+            ALOGE("FATAL: vkCreateSamplerYcbcrConversionKHR returned a reserved value (VK_YCBCR_CONVERSION_DO_NOTHING)");
+            abort();
+        }
+        return res;
+    }
+
+    void on_vkDestroySamplerYcbcrConversionKHR(
+        void* context,
+        VkDevice device,
+        VkSamplerYcbcrConversion ycbcrConversion,
+        const VkAllocationCallbacks* pAllocator) {
+        VkEncoder* enc = (VkEncoder*)context;
+        if (ycbcrConversion != VK_YCBCR_CONVERSION_DO_NOTHING) {
+            enc->vkDestroySamplerYcbcrConversion(device, ycbcrConversion, pAllocator);
+        }
+    }
+
+    VkResult on_vkCreateSampler(
+        void* context, VkResult,
+        VkDevice device,
+        const VkSamplerCreateInfo* pCreateInfo,
+        const VkAllocationCallbacks* pAllocator,
+        VkSampler* pSampler) {
+
+        VkSamplerCreateInfo localCreateInfo = vk_make_orphan_copy(*pCreateInfo);
+        vk_struct_chain_iterator structChainIter = vk_make_chain_iterator(&localCreateInfo);
+
+#ifdef VK_USE_PLATFORM_ANDROID_KHR
+        VkSamplerYcbcrConversionInfo localVkSamplerYcbcrConversionInfo;
+        const VkSamplerYcbcrConversionInfo* samplerYcbcrConversionInfo =
+            vk_find_struct<VkSamplerYcbcrConversionInfo>(pCreateInfo);
+        if (samplerYcbcrConversionInfo) {
+            if (samplerYcbcrConversionInfo->conversion != VK_YCBCR_CONVERSION_DO_NOTHING) {
+                localVkSamplerYcbcrConversionInfo = vk_make_orphan_copy(*samplerYcbcrConversionInfo);
+                vk_append_struct(&structChainIter, &localVkSamplerYcbcrConversionInfo);
+            }
+        }
+#endif
+
+        VkEncoder* enc = (VkEncoder*)context;
+        return enc->vkCreateSampler(device, &localCreateInfo, pAllocator, pSampler);
     }
 
     void on_vkDestroyImage(
@@ -3738,6 +3814,15 @@
         context, input_result, device, pCreateInfo, pAllocator, pYcbcrConversion);
 }
 
+void ResourceTracker::on_vkDestroySamplerYcbcrConversion(
+    void* context,
+    VkDevice device,
+    VkSamplerYcbcrConversion ycbcrConversion,
+    const VkAllocationCallbacks* pAllocator) {
+    mImpl->on_vkDestroySamplerYcbcrConversion(
+        context, device, ycbcrConversion, pAllocator);
+}
+
 VkResult ResourceTracker::on_vkCreateSamplerYcbcrConversionKHR(
     void* context, VkResult input_result,
     VkDevice device,
@@ -3748,6 +3833,25 @@
         context, input_result, device, pCreateInfo, pAllocator, pYcbcrConversion);
 }
 
+void ResourceTracker::on_vkDestroySamplerYcbcrConversionKHR(
+    void* context,
+    VkDevice device,
+    VkSamplerYcbcrConversion ycbcrConversion,
+    const VkAllocationCallbacks* pAllocator) {
+    mImpl->on_vkDestroySamplerYcbcrConversionKHR(
+        context, device, ycbcrConversion, pAllocator);
+}
+
+VkResult ResourceTracker::on_vkCreateSampler(
+    void* context, VkResult input_result,
+    VkDevice device,
+    const VkSamplerCreateInfo* pCreateInfo,
+    const VkAllocationCallbacks* pAllocator,
+    VkSampler* pSampler) {
+    return mImpl->on_vkCreateSampler(
+        context, input_result, device, pCreateInfo, pAllocator, pSampler);
+}
+
 VkResult ResourceTracker::on_vkMapMemoryIntoAddressSpaceGOOGLE_pre(
     void* context,
     VkResult input_result,
diff --git a/system/vulkan_enc/ResourceTracker.h b/system/vulkan_enc/ResourceTracker.h
index 8daf979..f8e3270 100644
--- a/system/vulkan_enc/ResourceTracker.h
+++ b/system/vulkan_enc/ResourceTracker.h
@@ -271,12 +271,29 @@
         const VkSamplerYcbcrConversionCreateInfo* pCreateInfo,
         const VkAllocationCallbacks* pAllocator,
         VkSamplerYcbcrConversion* pYcbcrConversion);
+    void on_vkDestroySamplerYcbcrConversion(
+        void* context,
+        VkDevice device,
+        VkSamplerYcbcrConversion ycbcrConversion,
+        const VkAllocationCallbacks* pAllocator);
     VkResult on_vkCreateSamplerYcbcrConversionKHR(
         void* context, VkResult input_result,
         VkDevice device,
         const VkSamplerYcbcrConversionCreateInfo* pCreateInfo,
         const VkAllocationCallbacks* pAllocator,
         VkSamplerYcbcrConversion* pYcbcrConversion);
+    void on_vkDestroySamplerYcbcrConversionKHR(
+        void* context,
+        VkDevice device,
+        VkSamplerYcbcrConversion ycbcrConversion,
+        const VkAllocationCallbacks* pAllocator);
+
+    VkResult on_vkCreateSampler(
+        void* context, VkResult input_result,
+        VkDevice device,
+        const VkSamplerCreateInfo* pCreateInfo,
+        const VkAllocationCallbacks* pAllocator,
+        VkSampler* pSampler);
 
     VkResult on_vkMapMemoryIntoAddressSpaceGOOGLE_pre(
         void* context,
diff --git a/system/vulkan_enc/goldfish_vk_private_defs.h b/system/vulkan_enc/goldfish_vk_private_defs.h
index 662b8f0..8c08a44 100644
--- a/system/vulkan_enc/goldfish_vk_private_defs.h
+++ b/system/vulkan_enc/goldfish_vk_private_defs.h
@@ -530,6 +530,8 @@
 // VulkanStream features
 #define VULKAN_STREAM_FEATURE_NULL_OPTIONAL_STRINGS_BIT (1 << 0)
 
+#define VK_YCBCR_CONVERSION_DO_NOTHING ((VkSamplerYcbcrConversion)0x1111111111111111)
+
 #ifdef __cplusplus
 } // extern "C"
 #endif
diff --git a/system/vulkan_enc/vk_struct_id.h b/system/vulkan_enc/vk_struct_id.h
index 561b430..9721900 100644
--- a/system/vulkan_enc/vk_struct_id.h
+++ b/system/vulkan_enc/vk_struct_id.h
@@ -46,5 +46,7 @@
 REGISTER_VK_STRUCT_ID(VkImportMemoryBufferCollectionFUCHSIA, VK_STRUCTURE_TYPE_IMPORT_MEMORY_BUFFER_COLLECTION_FUCHSIA);
 REGISTER_VK_STRUCT_ID(VkImportMemoryZirconHandleInfoFUCHSIA, VK_STRUCTURE_TYPE_TEMP_IMPORT_MEMORY_ZIRCON_HANDLE_INFO_FUCHSIA);
 REGISTER_VK_STRUCT_ID(VkBufferCollectionImageCreateInfoFUCHSIA, VK_STRUCTURE_TYPE_BUFFER_COLLECTION_IMAGE_CREATE_INFO_FUCHSIA);
+REGISTER_VK_STRUCT_ID(VkSamplerCreateInfo, VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO);
+REGISTER_VK_STRUCT_ID(VkSamplerYcbcrConversionInfo, VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_INFO);
 
 #undef REGISTER_VK_STRUCT_ID