vulkan: Properly free guest-side handles for descriptor sets (guest) am: e9e77d5f9b

bug: 145153816

Merged-In: Ic9d8f42b075ef26322252ecb067a5fcc58f3eab0
Change-Id: I4da6b39a3237d0abb0bc09672e51852c439d6759
(cherry picked from commit c0a57f1a032ab5382f362d6b3bd71a5dcb6d9039)
diff --git a/system/vulkan/func_table.cpp b/system/vulkan/func_table.cpp
index 80f586f..4e02b93 100644
--- a/system/vulkan/func_table.cpp
+++ b/system/vulkan/func_table.cpp
@@ -866,7 +866,8 @@
     AEMU_SCOPED_TRACE("vkCreateDescriptorPool");
     auto vkEnc = HostConnection::get()->vkEncoder();
     VkResult vkCreateDescriptorPool_VkResult_return = (VkResult)0;
-    vkCreateDescriptorPool_VkResult_return = vkEnc->vkCreateDescriptorPool(device, pCreateInfo, pAllocator, pDescriptorPool);
+    auto resources = ResourceTracker::get();
+    vkCreateDescriptorPool_VkResult_return = resources->on_vkCreateDescriptorPool(vkEnc, VK_SUCCESS, device, pCreateInfo, pAllocator, pDescriptorPool);
     return vkCreateDescriptorPool_VkResult_return;
 }
 static void entry_vkDestroyDescriptorPool(
@@ -876,7 +877,8 @@
 {
     AEMU_SCOPED_TRACE("vkDestroyDescriptorPool");
     auto vkEnc = HostConnection::get()->vkEncoder();
-    vkEnc->vkDestroyDescriptorPool(device, descriptorPool, pAllocator);
+    auto resources = ResourceTracker::get();
+    resources->on_vkDestroyDescriptorPool(vkEnc, device, descriptorPool, pAllocator);
 }
 static VkResult entry_vkResetDescriptorPool(
     VkDevice device,
@@ -886,7 +888,8 @@
     AEMU_SCOPED_TRACE("vkResetDescriptorPool");
     auto vkEnc = HostConnection::get()->vkEncoder();
     VkResult vkResetDescriptorPool_VkResult_return = (VkResult)0;
-    vkResetDescriptorPool_VkResult_return = vkEnc->vkResetDescriptorPool(device, descriptorPool, flags);
+    auto resources = ResourceTracker::get();
+    vkResetDescriptorPool_VkResult_return = resources->on_vkResetDescriptorPool(vkEnc, VK_SUCCESS, device, descriptorPool, flags);
     return vkResetDescriptorPool_VkResult_return;
 }
 static VkResult entry_vkAllocateDescriptorSets(
@@ -897,7 +900,8 @@
     AEMU_SCOPED_TRACE("vkAllocateDescriptorSets");
     auto vkEnc = HostConnection::get()->vkEncoder();
     VkResult vkAllocateDescriptorSets_VkResult_return = (VkResult)0;
-    vkAllocateDescriptorSets_VkResult_return = vkEnc->vkAllocateDescriptorSets(device, pAllocateInfo, pDescriptorSets);
+    auto resources = ResourceTracker::get();
+    vkAllocateDescriptorSets_VkResult_return = resources->on_vkAllocateDescriptorSets(vkEnc, VK_SUCCESS, device, pAllocateInfo, pDescriptorSets);
     return vkAllocateDescriptorSets_VkResult_return;
 }
 static VkResult entry_vkFreeDescriptorSets(
@@ -909,7 +913,8 @@
     AEMU_SCOPED_TRACE("vkFreeDescriptorSets");
     auto vkEnc = HostConnection::get()->vkEncoder();
     VkResult vkFreeDescriptorSets_VkResult_return = (VkResult)0;
-    vkFreeDescriptorSets_VkResult_return = vkEnc->vkFreeDescriptorSets(device, descriptorPool, descriptorSetCount, pDescriptorSets);
+    auto resources = ResourceTracker::get();
+    vkFreeDescriptorSets_VkResult_return = resources->on_vkFreeDescriptorSets(vkEnc, VK_SUCCESS, device, descriptorPool, descriptorSetCount, pDescriptorSets);
     return vkFreeDescriptorSets_VkResult_return;
 }
 static void entry_vkUpdateDescriptorSets(
diff --git a/system/vulkan_enc/ResourceTracker.cpp b/system/vulkan_enc/ResourceTracker.cpp
index e7ad451..077ea3c 100644
--- a/system/vulkan_enc/ResourceTracker.cpp
+++ b/system/vulkan_enc/ResourceTracker.cpp
@@ -115,9 +115,10 @@
 #include "vk_format_info.h"
 #include "vk_util.h"
 
+#include <set>
 #include <string>
 #include <unordered_map>
-#include <set>
+#include <unordered_set>
 
 #include <vndk/hardware_buffer.h>
 #include <log/log.h>
@@ -327,6 +328,15 @@
 #endif
     };
 
+    struct VkDescriptorPool_Info {
+        std::unordered_set<VkDescriptorSet> allocedSets;
+        VkDescriptorPoolCreateFlags createFlags;
+    };
+
+    struct VkDescriptorSet_Info {
+        VkDescriptorPool pool;
+    };
+
 #define HANDLE_REGISTER_IMPL_IMPL(type) \
     std::unordered_map<type, type##_Info> info_##type; \
     void register_##type(type obj) { \
@@ -468,7 +478,94 @@
         info_VkFence.erase(fence);
     }
 
-    // TODO: Upgrade to 1.1
+    void unregister_VkDescriptorSet_locked(VkDescriptorSet set) {
+        auto it = info_VkDescriptorSet.find(set);
+        if (it == info_VkDescriptorSet.end()) return;
+
+        const auto& setInfo = it->second;
+
+        auto poolIt = info_VkDescriptorPool.find(setInfo.pool);
+
+        info_VkDescriptorSet.erase(set);
+
+        if (poolIt == info_VkDescriptorPool.end()) return;
+
+        auto& poolInfo = poolIt->second;
+        poolInfo.allocedSets.erase(set);
+    }
+
+    void unregister_VkDescriptorSet(VkDescriptorSet set) {
+        AutoLock lock(mLock);
+        unregister_VkDescriptorSet_locked(set);
+    }
+
+    void addAllocedDescriptorSetsToPoolLocked(const VkDescriptorSetAllocateInfo* ci, const VkDescriptorSet* sets) {
+        auto it = info_VkDescriptorPool.find(ci->descriptorPool);
+        if (it == info_VkDescriptorPool.end()) return;
+
+        auto& info = it->second;
+        for (uint32_t i = 0; i < ci->descriptorSetCount; ++i) {
+            info.allocedSets.insert(sets[i]);
+
+            auto setIt = info_VkDescriptorSet.find(sets[i]);
+            if (setIt == info_VkDescriptorSet.end()) continue;
+
+            auto& setInfo = setIt->second;
+            setInfo.pool = ci->descriptorPool;
+        }
+    }
+
+    // Also unregisters underlying descriptor sets
+    // and deletes their guest-side wrapped handles.
+    void clearDescriptorPoolLocked(VkDescriptorPool pool) {
+        auto it = info_VkDescriptorPool.find(pool);
+        if (it == info_VkDescriptorPool.end()) return;
+
+        std::vector<VkDescriptorSet> toClear;
+        for (auto set : it->second.allocedSets) {
+            toClear.push_back(set);
+        }
+
+        for (auto set : toClear) {
+            unregister_VkDescriptorSet_locked(set);
+            delete_goldfish_VkDescriptorSet(set);
+        }
+    }
+
+    void unregister_VkDescriptorPool(VkDescriptorPool pool) {
+        AutoLock lock(mLock);
+        clearDescriptorPoolLocked(pool);
+        info_VkDescriptorPool.erase(pool);
+    }
+
+    bool descriptorPoolSupportsIndividualFreeLocked(VkDescriptorPool pool) {
+        auto it = info_VkDescriptorPool.find(pool);
+        if (it == info_VkDescriptorPool.end()) return false;
+
+        const auto& info = it->second;
+
+        return VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT &
+            info.createFlags;
+    }
+
+    bool descriptorSetReallyAllocedFromPoolLocked(VkDescriptorSet set, VkDescriptorPool pool) {
+        auto it = info_VkDescriptorSet.find(set);
+        if (it == info_VkDescriptorSet.end()) return false;
+
+        const auto& info = it->second;
+
+        if (pool != info.pool) return false;
+
+        auto poolIt = info_VkDescriptorPool.find(info.pool);
+        if (poolIt == info_VkDescriptorPool.end()) return false;
+
+        const auto& poolInfo = poolIt->second;
+
+        if (poolInfo.allocedSets.find(set) == poolInfo.allocedSets.end()) return false;
+
+        return true;
+    }
+
     static constexpr uint32_t kMaxApiVersion = VK_MAKE_VERSION(1, 1, 0);
     static constexpr uint32_t kMinApiVersion = VK_MAKE_VERSION(1, 0, 0);
 
@@ -2985,6 +3082,115 @@
 #endif
     }
 
+    VkResult on_vkCreateDescriptorPool(
+        void* context,
+        VkResult,
+        VkDevice device,
+        const VkDescriptorPoolCreateInfo* pCreateInfo,
+        const VkAllocationCallbacks* pAllocator,
+        VkDescriptorPool* pDescriptorPool) {
+
+        VkEncoder* enc = (VkEncoder*)context;
+
+        VkResult res = enc->vkCreateDescriptorPool(
+            device, pCreateInfo, pAllocator, pDescriptorPool);
+
+        if (res != VK_SUCCESS) return res;
+
+        AutoLock lock(mLock);
+        auto it = info_VkDescriptorPool.find(*pDescriptorPool);
+        if (it == info_VkDescriptorPool.end()) return res;
+
+        auto &info = it->second;
+        info.createFlags = pCreateInfo->flags;
+
+        return res;
+    }
+
+    void on_vkDestroyDescriptorPool(
+        void* context,
+        VkDevice device,
+        VkDescriptorPool descriptorPool,
+        const VkAllocationCallbacks* pAllocator) {
+
+        VkEncoder* enc = (VkEncoder*)context;
+
+        enc->vkDestroyDescriptorPool(device, descriptorPool, pAllocator);
+    }
+
+    VkResult on_vkResetDescriptorPool(
+        void* context,
+        VkResult,
+        VkDevice device,
+        VkDescriptorPool descriptorPool,
+        VkDescriptorPoolResetFlags flags) {
+
+        VkEncoder* enc = (VkEncoder*)context;
+
+        VkResult res = enc->vkResetDescriptorPool(device, descriptorPool, flags);
+
+        if (res != VK_SUCCESS) return res;
+
+        AutoLock lock(mLock);
+        clearDescriptorPoolLocked(descriptorPool);
+        return res;
+    }
+
+    VkResult on_vkAllocateDescriptorSets(
+        void* context,
+        VkResult,
+        VkDevice                                    device,
+        const VkDescriptorSetAllocateInfo*          pAllocateInfo,
+        VkDescriptorSet*                            pDescriptorSets) {
+
+        VkEncoder* enc = (VkEncoder*)context;
+
+        VkResult res = enc->vkAllocateDescriptorSets(device, pAllocateInfo, pDescriptorSets);
+
+        if (res != VK_SUCCESS) return res;
+
+        AutoLock lock(mLock);
+        addAllocedDescriptorSetsToPoolLocked(pAllocateInfo, pDescriptorSets);
+        return res;
+    }
+
+    VkResult on_vkFreeDescriptorSets(
+        void* context,
+        VkResult,
+        VkDevice                                    device,
+        VkDescriptorPool                            descriptorPool,
+        uint32_t                                    descriptorSetCount,
+        const VkDescriptorSet*                      pDescriptorSets) {
+
+        VkEncoder* enc = (VkEncoder*)context;
+
+        // Bit of robustness so that we can double free descriptor sets
+        // and do other invalid usages
+        // https://github.com/KhronosGroup/Vulkan-Docs/issues/1070
+        // (people expect VK_SUCCESS to always be returned by vkFreeDescriptorSets)
+        std::vector<VkDescriptorSet> toActuallyFree;
+        {
+            AutoLock lock(mLock);
+
+            if (!descriptorPoolSupportsIndividualFreeLocked(descriptorPool))
+                return VK_SUCCESS;
+
+            for (uint32_t i = 0; i < descriptorSetCount; ++i) {
+                if (descriptorSetReallyAllocedFromPoolLocked(
+                        pDescriptorSets[i], descriptorPool)) {
+                    toActuallyFree.push_back(pDescriptorSets[i]);
+                }
+            }
+
+            if (toActuallyFree.empty()) return VK_SUCCESS;
+        }
+
+        return enc->vkFreeDescriptorSets(
+            device, descriptorPool,
+            (uint32_t)toActuallyFree.size(),
+            toActuallyFree.data());
+    }
+
     void on_vkDestroyImage(
         void* context,
         VkDevice device, VkImage image, const VkAllocationCallbacks *pAllocator) {
@@ -4721,6 +4927,56 @@
         context, input_result, device, fenceCount, pFences, waitAll, timeout);
 }
 
+VkResult ResourceTracker::on_vkCreateDescriptorPool(
+    void* context,
+    VkResult input_result,
+    VkDevice device,
+    const VkDescriptorPoolCreateInfo* pCreateInfo,
+    const VkAllocationCallbacks* pAllocator,
+    VkDescriptorPool* pDescriptorPool) {
+    return mImpl->on_vkCreateDescriptorPool(
+        context, input_result, device, pCreateInfo, pAllocator, pDescriptorPool);
+}
+
+void ResourceTracker::on_vkDestroyDescriptorPool(
+    void* context,
+    VkDevice device,
+    VkDescriptorPool descriptorPool,
+    const VkAllocationCallbacks* pAllocator) {
+    mImpl->on_vkDestroyDescriptorPool(context, device, descriptorPool, pAllocator);
+}
+
+VkResult ResourceTracker::on_vkResetDescriptorPool(
+    void* context,
+    VkResult input_result,
+    VkDevice device,
+    VkDescriptorPool descriptorPool,
+    VkDescriptorPoolResetFlags flags) {
+    return mImpl->on_vkResetDescriptorPool(
+        context, input_result, device, descriptorPool, flags);
+}
+
+VkResult ResourceTracker::on_vkAllocateDescriptorSets(
+    void* context,
+    VkResult input_result,
+    VkDevice                                    device,
+    const VkDescriptorSetAllocateInfo*          pAllocateInfo,
+    VkDescriptorSet*                            pDescriptorSets) {
+    return mImpl->on_vkAllocateDescriptorSets(
+        context, input_result, device, pAllocateInfo, pDescriptorSets);
+}
+
+VkResult ResourceTracker::on_vkFreeDescriptorSets(
+    void* context,
+    VkResult input_result,
+    VkDevice                                    device,
+    VkDescriptorPool                            descriptorPool,
+    uint32_t                                    descriptorSetCount,
+    const VkDescriptorSet*                      pDescriptorSets) {
+    return mImpl->on_vkFreeDescriptorSets(
+        context, input_result, device, descriptorPool, descriptorSetCount, pDescriptorSets);
+}
+
 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 791a2b2..97abb0f 100644
--- a/system/vulkan_enc/ResourceTracker.h
+++ b/system/vulkan_enc/ResourceTracker.h
@@ -363,6 +363,42 @@
         VkBool32 waitAll,
         uint64_t timeout);
 
+    VkResult on_vkCreateDescriptorPool(
+        void* context,
+        VkResult input_result,
+        VkDevice device,
+        const VkDescriptorPoolCreateInfo* pCreateInfo,
+        const VkAllocationCallbacks* pAllocator,
+        VkDescriptorPool* pDescriptorPool);
+
+    void on_vkDestroyDescriptorPool(
+        void* context,
+        VkDevice device,
+        VkDescriptorPool descriptorPool,
+        const VkAllocationCallbacks* pAllocator);
+
+    VkResult on_vkResetDescriptorPool(
+        void* context,
+        VkResult input_result,
+        VkDevice device,
+        VkDescriptorPool descriptorPool,
+        VkDescriptorPoolResetFlags flags);
+
+    VkResult on_vkAllocateDescriptorSets(
+        void* context,
+        VkResult input_result,
+        VkDevice                                    device,
+        const VkDescriptorSetAllocateInfo*          pAllocateInfo,
+        VkDescriptorSet*                            pDescriptorSets);
+
+    VkResult on_vkFreeDescriptorSets(
+        void* context,
+        VkResult input_result,
+        VkDevice                                    device,
+        VkDescriptorPool                            descriptorPool,
+        uint32_t                                    descriptorSetCount,
+        const VkDescriptorSet*                      pDescriptorSets);
+
     VkResult on_vkMapMemoryIntoAddressSpaceGOOGLE_pre(
         void* context,
         VkResult input_result,
diff --git a/system/vulkan_enc/VulkanHandles.h b/system/vulkan_enc/VulkanHandles.h
index b8bd801..3a0f4eb 100644
--- a/system/vulkan_enc/VulkanHandles.h
+++ b/system/vulkan_enc/VulkanHandles.h
@@ -30,9 +30,7 @@
     f(VkBufferView) \
     f(VkImageView) \
     f(VkShaderModule) \
-    f(VkDescriptorPool) \
     f(VkDescriptorSetLayout) \
-    f(VkDescriptorSet) \
     f(VkSampler) \
     f(VkPipeline) \
     f(VkPipelineCache) \
@@ -60,6 +58,8 @@
     f(VkSemaphore) \
     f(VkDescriptorUpdateTemplate) \
     f(VkFence) \
+    f(VkDescriptorPool) \
+    f(VkDescriptorSet) \
     GOLDFISH_VK_LIST_TRIVIAL_NON_DISPATCHABLE_HANDLE_TYPES(f) \
 
 #define GOLDFISH_VK_LIST_HANDLE_TYPES(f) \