vulkan: filter nonexistent samplers

Bug: 186021150

Test: dEQP-VK.binding_model.descriptor_update.samplerless*

Change-Id: Ie80e5465460efaad3144ec2be63f42e8bfbc94bc
diff --git a/system/vulkan_enc/ResourceTracker.cpp b/system/vulkan_enc/ResourceTracker.cpp
index 814a8dc..1b8563c 100644
--- a/system/vulkan_enc/ResourceTracker.cpp
+++ b/system/vulkan_enc/ResourceTracker.cpp
@@ -419,6 +419,10 @@
         uint32_t unused;
     };
 
+    struct VkSampler_Info {
+        uint32_t unused;
+    };
+
     struct VkBufferCollectionFUCHSIA_Info {
 #ifdef VK_USE_PLATFORM_FUCHSIA
         android::base::Optional<
@@ -478,6 +482,13 @@
         info_VkCommandPool.erase(pool);
     }
 
+    void unregister_VkSampler(VkSampler sampler) {
+        if (!sampler) return;
+
+        AutoLock lock(mLock);
+        info_VkSampler.erase(sampler);
+    }
+
     void unregister_VkCommandBuffer(VkCommandBuffer commandBuffer) {
         resetCommandBufferStagingInfo(commandBuffer, true /* also reset primaries */, true /* also clear pending descriptor sets */);
 
@@ -709,34 +720,32 @@
         return res;
     }
 
-    VkWriteDescriptorSet
-    createImmutableSamplersFilteredWriteDescriptorSetLocked(
-        const VkWriteDescriptorSet* descriptorWrite,
-        std::vector<VkDescriptorImageInfo>* imageInfoArray) {
+    bool descriptorBindingIsImmutableSampler(
+        VkDescriptorSet dstSet,
+        uint32_t dstBinding) {
 
-        VkWriteDescriptorSet res = *descriptorWrite;
+        return as_goldfish_VkDescriptorSet(dstSet)->reified->bindingIsImmutableSampler[dstBinding];
+    }
 
-        if  (descriptorWrite->descriptorCount == 0) return res;
+    VkDescriptorImageInfo
+    filterNonexistentSampler(
+        const VkDescriptorImageInfo& inputInfo) {
 
-        if  (descriptorWrite->descriptorType != VK_DESCRIPTOR_TYPE_SAMPLER &&
-             descriptorWrite->descriptorType != VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER) return res;
+        VkSampler sampler =
+            inputInfo.sampler;
 
-        bool immutableSampler =
-            as_goldfish_VkDescriptorSet(descriptorWrite->dstSet)->reified->bindingIsImmutableSampler[descriptorWrite->dstBinding];
+        VkDescriptorImageInfo res = inputInfo;
 
-        if (!immutableSampler) return res;
-
-        for (uint32_t i = 0; i < descriptorWrite->descriptorCount; ++i) {
-            VkDescriptorImageInfo imageInfo = descriptorWrite->pImageInfo[i];
-            imageInfo.sampler = 0;
-            imageInfoArray->push_back(imageInfo);
+        if (sampler) {
+            auto it = info_VkSampler.find(sampler);
+            bool samplerExists = it != info_VkSampler.end();
+            if (!samplerExists) res.sampler = 0;
         }
 
-        res.pImageInfo = imageInfoArray->data();
-
         return res;
     }
 
+
     void freeDescriptorSetsIfHostAllocated(VkEncoder* enc, VkDevice device, uint32_t descriptorSetCount, const VkDescriptorSet* sets) {
         for (uint32_t i = 0; i < descriptorSetCount; ++i) {
             struct goldfish_VkDescriptorSet* ds = as_goldfish_VkDescriptorSet(sets[i]);
@@ -4782,25 +4791,62 @@
 
         VkEncoder* enc = (VkEncoder*)context;
 
-        std::vector<std::vector<VkDescriptorImageInfo>> imageInfosPerWrite(
-                descriptorWriteCount);
+        std::vector<VkDescriptorImageInfo> transformedImageInfos;
+        std::vector<VkWriteDescriptorSet> transformedWrites(descriptorWriteCount);
 
-        std::vector<VkWriteDescriptorSet> writesWithSuppressedSamplers;
+        memcpy(transformedWrites.data(), pDescriptorWrites, sizeof(VkWriteDescriptorSet) * descriptorWriteCount);
+
+        size_t imageInfosNeeded = 0;
+        for (uint32_t i = 0; i < descriptorWriteCount; ++i) {
+            if (!isDescriptorTypeImageInfo(transformedWrites[i].descriptorType)) continue;
+            if (!transformedWrites[i].pImageInfo) continue;
+
+            imageInfosNeeded += transformedWrites[i].descriptorCount;
+        }
+
+        transformedImageInfos.resize(imageInfosNeeded);
+
+        size_t imageInfoIndex = 0;
+        for (uint32_t i = 0; i < descriptorWriteCount; ++i) {
+            if (!isDescriptorTypeImageInfo(transformedWrites[i].descriptorType)) continue;
+            if (!transformedWrites[i].pImageInfo) continue;
+
+            for (uint32_t j = 0; j < transformedWrites[i].descriptorCount; ++j) {
+                transformedImageInfos[imageInfoIndex] = transformedWrites[i].pImageInfo[j];
+                ++imageInfoIndex;
+            }
+            transformedWrites[i].pImageInfo = &transformedImageInfos[imageInfoIndex - transformedWrites[i].descriptorCount];
+        }
 
         {
+            // Validate and filter samplers
             AutoLock lock(mLock);
+            size_t imageInfoIndex = 0;
             for (uint32_t i = 0; i < descriptorWriteCount; ++i) {
-                writesWithSuppressedSamplers.push_back(
-                        createImmutableSamplersFilteredWriteDescriptorSetLocked(
-                            pDescriptorWrites + i,
-                            imageInfosPerWrite.data() + i));
+
+                if (!isDescriptorTypeImageInfo(transformedWrites[i].descriptorType)) continue;
+                if (!transformedWrites[i].pImageInfo) continue;
+
+                bool isImmutableSampler =
+                    descriptorBindingIsImmutableSampler(
+                        transformedWrites[i].dstSet,
+                        transformedWrites[i].dstBinding);
+
+                for (uint32_t j = 0; j < transformedWrites[i].descriptorCount; ++j) {
+                    if (isImmutableSampler) {
+                        transformedImageInfos[imageInfoIndex].sampler = 0;
+                    }
+                    transformedImageInfos[imageInfoIndex] =
+                        filterNonexistentSampler(transformedImageInfos[imageInfoIndex]);
+                    ++imageInfoIndex;
+                }
             }
         }
 
         if (mFeatureInfo->hasVulkanBatchedDescriptorSetUpdate) {
             for (uint32_t i = 0; i < descriptorWriteCount; ++i) {
-                VkDescriptorSet set = writesWithSuppressedSamplers[i].dstSet;
-                doEmulatedDescriptorWrite(&writesWithSuppressedSamplers[i],
+                VkDescriptorSet set = transformedWrites[i].dstSet;
+                doEmulatedDescriptorWrite(&transformedWrites[i],
                         as_goldfish_VkDescriptorSet(set)->reified);
             }
 
@@ -4811,7 +4857,7 @@
             }
         } else {
             enc->vkUpdateDescriptorSets(
-                    device, descriptorWriteCount, writesWithSuppressedSamplers.data(),
+                    device, descriptorWriteCount, transformedWrites.data(),
                     descriptorCopyCount, pDescriptorCopies, true /* do lock */);
         }
     }
diff --git a/system/vulkan_enc/VulkanHandles.h b/system/vulkan_enc/VulkanHandles.h
index f12a753..b0f4f6c 100644
--- a/system/vulkan_enc/VulkanHandles.h
+++ b/system/vulkan_enc/VulkanHandles.h
@@ -86,7 +86,6 @@
     f(VkBufferView) \
     f(VkImageView) \
     f(VkShaderModule) \
-    f(VkSampler) \
     f(VkPipeline) \
     f(VkPipelineCache) \
     f(VkPipelineLayout) \
@@ -118,6 +117,7 @@
     f(VkDescriptorSet) \
     f(VkDescriptorSetLayout) \
     f(VkCommandPool) \
+    f(VkSampler) \
     __GOLDFISH_VK_LIST_NON_DISPATCHABLE_HANDLE_TYPES_FUCHSIA(f) \
     GOLDFISH_VK_LIST_TRIVIAL_NON_DISPATCHABLE_HANDLE_TYPES(f) \
 
@@ -143,6 +143,7 @@
     f(VkFence) \
     f(VkDescriptorUpdateTemplate) \
     f(VkCommandPool) \
+    f(VkSampler) \
     __GOLDFISH_VK_LIST_NON_DISPATCHABLE_HANDLE_TYPES_FUCHSIA(f) \
     GOLDFISH_VK_LIST_TRIVIAL_NON_DISPATCHABLE_HANDLE_TYPES(f) \