Merge master@5406228 into git_qt-dev-plus-aosp.

Change-Id: Idfcca6b933d0a42dd818d6ca8e999ffa2527b04e
BUG: 129345239
diff --git a/shared/OpenglCodecCommon/goldfish_address_space.cpp b/shared/OpenglCodecCommon/goldfish_address_space.cpp
index 50ea76b..afa6b85 100644
--- a/shared/OpenglCodecCommon/goldfish_address_space.cpp
+++ b/shared/OpenglCodecCommon/goldfish_address_space.cpp
@@ -1,3 +1,18 @@
+// Copyright (C) 2019 The Android Open Source Project
+// Copyright (C) 2019 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
 #if PLATFORM_SDK_VERSION < 26
 #include <cutils/log.h>
 #else
@@ -7,17 +22,71 @@
 #include "goldfish_address_space.h"
 
 #ifdef HOST_BUILD
-GoldfishAddressSpaceBlock::GoldfishAddressSpaceBlock() : m_guest_ptr(NULL) {}
-GoldfishAddressSpaceBlock::~GoldfishAddressSpaceBlock() {}
+
+#include "android/base/SubAllocator.h"
+#include "android/base/memory/LazyInstance.h"
+
+// AddressSpaceHost is a global class for obtaining physical addresses
+// for the host-side build.
+class AddressSpaceHost {
+public:
+    AddressSpaceHost() : mAlloc(0, 16ULL * 1024ULL * 1048576ULL, 4096) { }
+    uint64_t alloc(size_t size) {
+        return (uint64_t)(uintptr_t)mAlloc.alloc(size);
+    }
+    void free(uint64_t addr) {
+        mAlloc.free((void*)(uintptr_t)addr);
+    }
+private:
+    android::base::SubAllocator mAlloc;
+};
+
+static android::base::LazyInstance<AddressSpaceHost> sAddressSpaceHost =
+    LAZY_INSTANCE_INIT;
+
+// It may seem like there should be one allocator per provider,
+// but to properly reflect the guest behavior where there is only one
+// allocator in the system and multiple providers are possible,
+// we need to have a separate global object (sAddressSpaceHost).
+GoldfishAddressSpaceBlockProvider::GoldfishAddressSpaceBlockProvider()
+    : mAlloc(sAddressSpaceHost.ptr()) {}
+
+GoldfishAddressSpaceBlockProvider::~GoldfishAddressSpaceBlockProvider() { }
+
+uint64_t GoldfishAddressSpaceBlockProvider::allocPhys(size_t size) {
+    AddressSpaceHost* hostAlloc = reinterpret_cast<AddressSpaceHost*>(mAlloc);
+    return hostAlloc->alloc(size);
+}
+
+void GoldfishAddressSpaceBlockProvider::freePhys(uint64_t phys) {
+    AddressSpaceHost* hostAlloc = reinterpret_cast<AddressSpaceHost*>(mAlloc);
+    return hostAlloc->free(phys);
+}
+
+GoldfishAddressSpaceBlock::GoldfishAddressSpaceBlock() :
+    m_alloced(false), m_guest_ptr(NULL), m_phys_addr(0), m_provider(NULL) {}
+GoldfishAddressSpaceBlock::~GoldfishAddressSpaceBlock() { destroy(); }
+
+GoldfishAddressSpaceBlock &GoldfishAddressSpaceBlock::operator=(const GoldfishAddressSpaceBlock &rhs)
+{
+    m_guest_ptr = rhs.m_guest_ptr;
+    m_phys_addr = rhs.m_phys_addr;
+    m_provider = rhs.m_provider;
+    return *this;
+}
 
 bool GoldfishAddressSpaceBlock::allocate(GoldfishAddressSpaceBlockProvider *provider, size_t size)
 {
+    destroy();
+    m_phys_addr = provider->allocPhys(size);
+    m_alloced = true;
+    m_provider = provider;
     return true;
 }
 
 uint64_t GoldfishAddressSpaceBlock::physAddr() const
 {
-    return 42;  // some random number, not used
+    return m_phys_addr;
 }
 
 uint64_t GoldfishAddressSpaceBlock::hostAddr() const
@@ -38,7 +107,13 @@
 
 void GoldfishAddressSpaceBlock::destroy()
 {
-    m_guest_ptr = NULL;
+    if (m_alloced) {
+        m_guest_ptr = NULL;
+        if (m_provider) {
+            m_provider->freePhys(m_phys_addr);
+        }
+        m_alloced = false;
+    }
 }
 
 void GoldfishAddressSpaceBlock::replace(GoldfishAddressSpaceBlock *other)
diff --git a/shared/OpenglCodecCommon/goldfish_address_space.h b/shared/OpenglCodecCommon/goldfish_address_space.h
index 752a723..637e20d 100644
--- a/shared/OpenglCodecCommon/goldfish_address_space.h
+++ b/shared/OpenglCodecCommon/goldfish_address_space.h
@@ -21,7 +21,19 @@
 class GoldfishAddressSpaceBlock;
 
 #ifdef HOST_BUILD
-class GoldfishAddressSpaceBlockProvider {};
+class GoldfishAddressSpaceBlockProvider {
+public:
+    GoldfishAddressSpaceBlockProvider();
+    ~GoldfishAddressSpaceBlockProvider();
+
+    uint64_t allocPhys(size_t size);
+    void freePhys(uint64_t phys);
+
+private:
+   void* mAlloc;
+
+   friend class GoldfishAddressSpaceBlock;
+};
 #else
 class GoldfishAddressSpaceBlockProvider {
 public:
@@ -56,7 +68,10 @@
     GoldfishAddressSpaceBlock &operator=(const GoldfishAddressSpaceBlock &);
 
 #ifdef HOST_BUILD
+    bool        m_alloced;
     void     *m_guest_ptr;
+    uint64_t  m_phys_addr;
+    GoldfishAddressSpaceBlockProvider* m_provider;
 #else
 #ifdef __Fuchsia__
     uint32_t  m_vmo;
diff --git a/shared/OpenglCodecCommon/goldfish_dma.cpp b/shared/OpenglCodecCommon/goldfish_dma.cpp
index 16bf84e..dbb1f8d 100644
--- a/shared/OpenglCodecCommon/goldfish_dma.cpp
+++ b/shared/OpenglCodecCommon/goldfish_dma.cpp
@@ -51,18 +51,6 @@
     uint64_t size;
 };
 
-int goldfish_dma_lock(struct goldfish_dma_context* cxt) {
-    struct goldfish_dma_ioctl_info info;
-
-    return ioctl(cxt->fd, GOLDFISH_DMA_IOC_LOCK, &info);
-}
-
-int goldfish_dma_unlock(struct goldfish_dma_context* cxt) {
-    struct goldfish_dma_ioctl_info info;
-
-    return ioctl(cxt->fd, GOLDFISH_DMA_IOC_UNLOCK, &info);
-}
-
 int goldfish_dma_create_region(uint32_t sz, struct goldfish_dma_context* res) {
 
     res->fd = qemu_pipe_open("opengles");
diff --git a/shared/OpenglCodecCommon/goldfish_dma.h b/shared/OpenglCodecCommon/goldfish_dma.h
index db1e8d6..ee3df59 100644
--- a/shared/OpenglCodecCommon/goldfish_dma.h
+++ b/shared/OpenglCodecCommon/goldfish_dma.h
@@ -24,8 +24,6 @@
 	int32_t fd;
 };
 
-int goldfish_dma_lock(struct goldfish_dma_context* cxt);
-int goldfish_dma_unlock(struct goldfish_dma_context* cxt);
 int goldfish_dma_create_region(uint32_t sz, struct goldfish_dma_context* res);
 
 void* goldfish_dma_map(struct goldfish_dma_context* cxt);
diff --git a/shared/OpenglCodecCommon/goldfish_dma_host.cpp b/shared/OpenglCodecCommon/goldfish_dma_host.cpp
index 93dcfa3..4ca027b 100644
--- a/shared/OpenglCodecCommon/goldfish_dma_host.cpp
+++ b/shared/OpenglCodecCommon/goldfish_dma_host.cpp
@@ -13,14 +13,6 @@
 // limitations under the License.
 #include "goldfish_dma.h"
 
-int goldfish_dma_lock(struct goldfish_dma_context* cxt) {
-    return 0;
-}
-
-int goldfish_dma_unlock(struct goldfish_dma_context* cxt) {
-    return 0;
-}
-
 int goldfish_dma_create_region(uint32_t sz, struct goldfish_dma_context* res) {
     return 0;
 }
diff --git a/system/OpenglSystemCommon/HostConnection.h b/system/OpenglSystemCommon/HostConnection.h
index e46c3aa..c58e6d2 100644
--- a/system/OpenglSystemCommon/HostConnection.h
+++ b/system/OpenglSystemCommon/HostConnection.h
@@ -59,17 +59,12 @@
     DmaImpl getDmaVersion() const { return m_featureInfo.dmaImpl; }
     void bindDmaContext(struct goldfish_dma_context* cxt) { m_dmaCxt = cxt; }
     virtual uint64_t lockAndWriteDma(void* data, uint32_t size) {
-        ALOGV("%s: call", __FUNCTION__);
-        if (!m_dmaCxt) {
-            ALOGE("%s: ERROR: No DMA context bound!",
-                  __FUNCTION__);
+        if (m_dmaCxt) {
+            return lockAndWriteGoldfishDma(data, size, m_dmaCxt);
+        } else {
+            ALOGE("%s: ERROR: No DMA context bound!", __func__);
             return 0;
         }
-        goldfish_dma_lock(m_dmaCxt);
-        goldfish_dma_write(m_dmaCxt, data, size);
-        uint64_t paddr = goldfish_dma_guest_paddr(m_dmaCxt);
-        ALOGV("%s: paddr=0x%llx", __FUNCTION__, (unsigned long long)paddr);
-        return paddr;
     }
     void setGLESMaxVersion(GLESMaxVersion ver) { m_featureInfo.glesMaxVersion = ver; }
     GLESMaxVersion getGLESMaxVersion() const { return m_featureInfo.glesMaxVersion; }
@@ -77,6 +72,17 @@
     const EmulatorFeatureInfo* featureInfo_const() const { return &m_featureInfo; }
     EmulatorFeatureInfo* featureInfo() { return &m_featureInfo; }
 private:
+    static uint64_t lockAndWriteGoldfishDma(void* data, uint32_t size,
+                                            struct goldfish_dma_context* dmaCxt) {
+        ALOGV("%s(data=%p, size=%u): call", __func__, data, size);
+
+        goldfish_dma_write(dmaCxt, data, size);
+        uint64_t paddr = goldfish_dma_guest_paddr(dmaCxt);
+
+        ALOGV("%s: paddr=0x%llx", __func__, (unsigned long long)paddr);
+        return paddr;
+    }
+
     EmulatorFeatureInfo m_featureInfo;
     struct goldfish_dma_context* m_dmaCxt;
 };
diff --git a/system/gralloc/gralloc.cpp b/system/gralloc/gralloc.cpp
index 058ea03..2259501 100644
--- a/system/gralloc/gralloc.cpp
+++ b/system/gralloc/gralloc.cpp
@@ -67,9 +67,9 @@
 #define GOLDFISH_OFFSET_UNIT 8
 
 #ifdef GOLDFISH_HIDL_GRALLOC
-static bool isHidlGralloc = true;
+static const bool isHidlGralloc = true;
 #else
-static bool isHidlGralloc = false;
+static const bool isHidlGralloc = false;
 #endif
 
 int32_t* getOpenCountPtr(cb_handle_t* cb) {
@@ -126,7 +126,6 @@
     alloc_device_t  device;
 
     AllocListNode *allocListHead;    // double linked list of allocated buffers
-    MemRegionSet ashmemRegions; // to track allocations of each ashmem region
     pthread_mutex_t lock;
 };
 
@@ -148,13 +147,13 @@
 static gralloc_memregions_t* s_memregions = NULL;
 static gralloc_dmaregion_t* s_grdma = NULL;
 
-void init_gralloc_memregions() {
+static void init_gralloc_memregions() {
     if (s_memregions) return;
     s_memregions = new gralloc_memregions_t;
     pthread_mutex_init(&s_memregions->lock, NULL);
 }
 
-void init_gralloc_dmaregion() {
+static void init_gralloc_dmaregion() {
     D("%s: call\n", __FUNCTION__);
     if (s_grdma) return;
 
@@ -169,7 +168,7 @@
     pthread_mutex_unlock(&s_grdma->lock);
 }
 
-void get_gralloc_dmaregion() {
+static void get_gralloc_dmaregion() {
     if (!s_grdma) return;
     pthread_mutex_lock(&s_grdma->lock);
     s_grdma->refcount++;
@@ -190,7 +189,7 @@
 // max dma size: 2x 4K rgba8888
 #define MAX_DMA_SIZE 66355200
 
-bool put_gralloc_dmaregion(uint32_t sz) {
+static bool put_gralloc_dmaregion(uint32_t sz) {
     if (!s_grdma) return false;
     pthread_mutex_lock(&s_grdma->lock);
     D("%s: call. refcount before: %u\n", __FUNCTION__, s_grdma->refcount);
@@ -210,7 +209,7 @@
     return shouldDelete;
 }
 
-void gralloc_dmaregion_register_ashmem(uint32_t sz) {
+static void gralloc_dmaregion_register_ashmem(uint32_t sz) {
     if (!s_grdma) return;
     pthread_mutex_lock(&s_grdma->lock);
     D("%s: for sz %u, refcount %u", __FUNCTION__, sz, s_grdma->refcount);
@@ -231,7 +230,7 @@
     pthread_mutex_unlock(&s_grdma->lock);
 }
 
-void get_mem_region(void* ashmemBase) {
+static void get_mem_region(void* ashmemBase) {
     init_gralloc_memregions();
     D("%s: call for %p", __FUNCTION__, ashmemBase);
     MemRegionInfo lookup;
@@ -249,7 +248,7 @@
     pthread_mutex_unlock(&s_memregions->lock);
 }
 
-bool put_mem_region(void* ashmemBase) {
+static bool put_mem_region(void* ashmemBase) {
     init_gralloc_memregions();
     D("%s: call for %p", __FUNCTION__, ashmemBase);
     MemRegionInfo lookup;
@@ -271,7 +270,7 @@
     }
 }
 
-void dump_regions() {
+static void dump_regions() {
     init_gralloc_memregions();
     mem_region_handle_t curr = s_memregions->ashmemRegions.begin();
     std::stringstream res;
@@ -760,7 +759,7 @@
                 allocFormat = GL_RGB;
             }
             hostCon->lock();
-            if (s_grdma) {
+            if (rcEnc->getDmaVersion() > 0) {
                 cb->hostHandle = rcEnc->rcCreateColorBufferDMA(rcEnc, w, h, allocFormat, cb->emuFrameworkFormat);
             } else {
                 cb->hostHandle = rcEnc->rcCreateColorBuffer(rcEnc, w, h, allocFormat);
diff --git a/system/vulkan/func_table.cpp b/system/vulkan/func_table.cpp
index d5ebf2d..1c74ac8 100644
--- a/system/vulkan/func_table.cpp
+++ b/system/vulkan/func_table.cpp
@@ -1754,7 +1754,8 @@
 {
     AEMU_SCOPED_TRACE("vkUpdateDescriptorSetWithTemplate");
     auto vkEnc = HostConnection::get()->vkEncoder();
-    vkEnc->vkUpdateDescriptorSetWithTemplate(device, descriptorSet, descriptorUpdateTemplate, pData);
+    auto resources = ResourceTracker::get();
+    resources->on_vkUpdateDescriptorSetWithTemplate(vkEnc, device, descriptorSet, descriptorUpdateTemplate, pData);
 }
 static void entry_vkGetPhysicalDeviceExternalBufferProperties(
     VkPhysicalDevice physicalDevice,
@@ -3704,6 +3705,26 @@
     return vkRegisterBufferColorBufferGOOGLE_VkResult_return;
 }
 #endif
+#ifdef VK_GOOGLE_sized_descriptor_update_template
+static void entry_vkUpdateDescriptorSetWithTemplateSizedGOOGLE(
+    VkDevice device,
+    VkDescriptorSet descriptorSet,
+    VkDescriptorUpdateTemplate descriptorUpdateTemplate,
+    uint32_t imageInfoCount,
+    uint32_t bufferInfoCount,
+    uint32_t bufferViewCount,
+    const uint32_t* pImageInfoEntryIndices,
+    const uint32_t* pBufferInfoEntryIndices,
+    const uint32_t* pBufferViewEntryIndices,
+    const VkDescriptorImageInfo* pImageInfos,
+    const VkDescriptorBufferInfo* pBufferInfos,
+    const VkBufferView* pBufferViews)
+{
+    AEMU_SCOPED_TRACE("vkUpdateDescriptorSetWithTemplateSizedGOOGLE");
+    auto vkEnc = HostConnection::get()->vkEncoder();
+    vkEnc->vkUpdateDescriptorSetWithTemplateSizedGOOGLE(device, descriptorSet, descriptorUpdateTemplate, imageInfoCount, bufferInfoCount, bufferViewCount, pImageInfoEntryIndices, pBufferInfoEntryIndices, pBufferViewEntryIndices, pImageInfos, pBufferInfos, pBufferViews);
+}
+#endif
 void* goldfish_vulkan_get_proc_address(const char* name){
 #ifdef VK_VERSION_1_0
     if (!strcmp(name, "vkCreateInstance"))
@@ -5115,6 +5136,12 @@
         return nullptr;
     }
 #endif
+#ifdef VK_GOOGLE_sized_descriptor_update_template
+    if (!strcmp(name, "vkUpdateDescriptorSetWithTemplateSizedGOOGLE"))
+    {
+        return nullptr;
+    }
+#endif
     return nullptr;
 }
 void* goldfish_vulkan_get_instance_proc_address(VkInstance instance, const char* name){
@@ -6685,6 +6712,13 @@
         return hasExt ? (void*)entry_vkRegisterBufferColorBufferGOOGLE : nullptr;
     }
 #endif
+#ifdef VK_GOOGLE_sized_descriptor_update_template
+    if (!strcmp(name, "vkUpdateDescriptorSetWithTemplateSizedGOOGLE"))
+    {
+        bool hasExt = resources->hasInstanceExtension(instance, "VK_GOOGLE_sized_descriptor_update_template");
+        return hasExt ? (void*)entry_vkUpdateDescriptorSetWithTemplateSizedGOOGLE : nullptr;
+    }
+#endif
     return nullptr;
 }
 void* goldfish_vulkan_get_device_proc_address(VkDevice device, const char* name){
@@ -8255,6 +8289,13 @@
         return hasExt ? (void*)entry_vkRegisterBufferColorBufferGOOGLE : nullptr;
     }
 #endif
+#ifdef VK_GOOGLE_sized_descriptor_update_template
+    if (!strcmp(name, "vkUpdateDescriptorSetWithTemplateSizedGOOGLE"))
+    {
+        bool hasExt = resources->hasDeviceExtension(device, "VK_GOOGLE_sized_descriptor_update_template");
+        return hasExt ? (void*)entry_vkUpdateDescriptorSetWithTemplateSizedGOOGLE : nullptr;
+    }
+#endif
     return nullptr;
 }
 
diff --git a/system/vulkan/func_table.h b/system/vulkan/func_table.h
index 3dbca4c..565b12a 100644
--- a/system/vulkan/func_table.h
+++ b/system/vulkan/func_table.h
@@ -280,6 +280,8 @@
 #endif
 #ifdef VK_GOOGLE_color_buffer
 #endif
+#ifdef VK_GOOGLE_sized_descriptor_update_template
+#endif
 void* goldfish_vulkan_get_proc_address(const char* name);
 void* goldfish_vulkan_get_instance_proc_address(VkInstance instance, const char* name);
 void* goldfish_vulkan_get_device_proc_address(VkDevice device, const char* name);
diff --git a/system/vulkan/goldfish_vulkan.cpp b/system/vulkan/goldfish_vulkan.cpp
index a40fe23..2ba1511 100644
--- a/system/vulkan/goldfish_vulkan.cpp
+++ b/system/vulkan/goldfish_vulkan.cpp
@@ -481,10 +481,13 @@
                 uint32_t r = rcEnc->rcCreateColorBuffer(rcEnc, width, height, format);
                 return r;
             },
+            [](uint32_t id) {
+                VK_HOST_CONNECTION()
+                rcEnc->rcOpenColorBuffer(rcEnc, id);
+            },
             [](uint32_t id){
-                VK_HOST_CONNECTION((uint32_t)0)
+                VK_HOST_CONNECTION()
                 rcEnc->rcCloseColorBuffer(rcEnc, id);
-                return 0u;
             });
 #else
         goldfish_vk::ResourceTracker::get();
diff --git a/system/vulkan_enc/HostVisibleMemoryVirtualization.cpp b/system/vulkan_enc/HostVisibleMemoryVirtualization.cpp
index 8e254d0..2780d2a 100644
--- a/system/vulkan_enc/HostVisibleMemoryVirtualization.cpp
+++ b/system/vulkan_enc/HostVisibleMemoryVirtualization.cpp
@@ -272,7 +272,7 @@
              alloc->nonCoherentAtomSize - 1) /
             alloc->nonCoherentAtomSize);
 
-    ALOGD("%s: alloc size %u mapped size %u ncaSize %u\n", __func__,
+    ALOGV("%s: alloc size %u mapped size %u ncaSize %u\n", __func__,
             (unsigned int)pAllocateInfo->allocationSize,
             (unsigned int)mappedSize,
             (unsigned int)alloc->nonCoherentAtomSize);
@@ -296,4 +296,11 @@
     memset(toFree, 0x0, sizeof(SubAlloc));
 }
 
+bool canSubAlloc(android::base::SubAllocator* subAlloc, VkDeviceSize size) {
+    auto ptr = subAlloc->alloc(size);
+    if (!ptr) return false;
+    subAlloc->free(ptr);
+    return true;
+}
+
 } // namespace goldfish_vk
diff --git a/system/vulkan_enc/HostVisibleMemoryVirtualization.h b/system/vulkan_enc/HostVisibleMemoryVirtualization.h
index 4f8651b..ad25353 100644
--- a/system/vulkan_enc/HostVisibleMemoryVirtualization.h
+++ b/system/vulkan_enc/HostVisibleMemoryVirtualization.h
@@ -117,4 +117,5 @@
 
 void subFreeHostMemory(SubAlloc* toFree);
 
+bool canSubAlloc(android::base::SubAllocator* subAlloc, VkDeviceSize size);
 } // namespace goldfish_vk
diff --git a/system/vulkan_enc/ResourceTracker.cpp b/system/vulkan_enc/ResourceTracker.cpp
index 24a5777..24a46e1 100644
--- a/system/vulkan_enc/ResourceTracker.cpp
+++ b/system/vulkan_enc/ResourceTracker.cpp
@@ -1,4 +1,4 @@
-/// Copyright (C) 2018 The Android Open Source Project
+// Copyright (C) 2018 The Android Open Source Project
 // Copyright (C) 2018 Google Inc.
 //
 // Licensed under the Apache License, Version 2.0 (the "License");
@@ -230,11 +230,16 @@
         std::vector<VkPhysicalDevice> physicalDevices;
     };
 
+    using HostMemBlocks = std::vector<HostMemAlloc>;
+    using HostMemBlockIndex = size_t;
+
+#define INVALID_HOST_MEM_BLOCK (-1)
+
     struct VkDevice_Info {
         VkPhysicalDevice physdev;
         VkPhysicalDeviceProperties props;
         VkPhysicalDeviceMemoryProperties memProps;
-        HostMemAlloc hostMemAllocs[VK_MAX_MEMORY_TYPES] = {};
+        std::vector<HostMemBlocks> hostMemBlocks { VK_MAX_MEMORY_TYPES };
         uint32_t apiVersion;
         std::set<std::string> enabledExtensions;
         VkFence fence = VK_NULL_HANDLE;
@@ -252,6 +257,7 @@
         SubAlloc subAlloc;
         AHardwareBuffer* ahw = nullptr;
         zx_handle_t vmoHandle = ZX_HANDLE_INVALID;
+        uint32_t cbHandle = 0;
     };
 
     // custom guest-side structs for images/buffers because of AHardwareBuffer :((
@@ -282,6 +288,17 @@
         int syncFd = -1;
     };
 
+    struct VkDescriptorUpdateTemplate_Info {
+        std::vector<VkDescriptorUpdateTemplateEntry> templateEntries;
+
+        // Flattened versions
+        std::vector<uint32_t> imageInfoEntryIndices;
+        std::vector<uint32_t> bufferInfoEntryIndices;
+        std::vector<uint32_t> bufferViewEntryIndices;
+        std::vector<VkDescriptorImageInfo> imageInfos;
+        std::vector<VkDescriptorBufferInfo> bufferInfos;
+        std::vector<VkBufferView> bufferViews;
+    };
 
 #define HANDLE_REGISTER_IMPL_IMPL(type) \
     std::unordered_map<type, type##_Info> info_##type; \
@@ -331,6 +348,10 @@
             AHardwareBuffer_release(memInfo.ahw);
         }
 
+        if (memInfo.cbHandle) {
+            (*mCloseColorBuffer)(memInfo.cbHandle);
+        }
+
         if (memInfo.vmoHandle != ZX_HANDLE_INVALID) {
             zx_handle_close(memInfo.vmoHandle);
         }
@@ -388,6 +409,10 @@
         info_VkSemaphore.erase(sem);
     }
 
+    void unregister_VkDescriptorUpdateTemplate(VkDescriptorUpdateTemplate templ) {
+        info_VkDescriptorUpdateTemplate.erase(templ);
+    }
+
     // TODO: Upgrade to 1.1
     static constexpr uint32_t kMaxApiVersion = VK_MAKE_VERSION(1, 1, 0);
     static constexpr uint32_t kMinApiVersion = VK_MAKE_VERSION(1, 0, 0);
@@ -438,7 +463,8 @@
                              uint8_t* ptr,
                              uint32_t memoryTypeIndex,
                              AHardwareBuffer* ahw = nullptr,
-                             zx_handle_t vmoHandle = ZX_HANDLE_INVALID) {
+                             zx_handle_t vmoHandle = ZX_HANDLE_INVALID,
+                             uint32_t cbHandle = 0) {
         AutoLock lock(mLock);
         auto& deviceInfo = info_VkDevice[device];
         auto& info = info_VkDeviceMemory[memory];
@@ -449,6 +475,7 @@
         info.memoryTypeIndex = memoryTypeIndex;
         info.ahw = ahw;
         info.vmoHandle = vmoHandle;
+        info.cbHandle = cbHandle;
     }
 
     void setImageInfo(VkImage image,
@@ -574,8 +601,10 @@
     }
 
     void setColorBufferFunctions(PFN_CreateColorBuffer create,
+                                 PFN_OpenColorBuffer open,
                                  PFN_CloseColorBuffer close) {
         mCreateColorBuffer = create;
+        mOpenColorBuffer = open;
         mCloseColorBuffer = close;
     }
 
@@ -1037,7 +1066,9 @@
         VkEncoder* enc = (VkEncoder*)context;
 
         for (uint32_t i = 0; i < VK_MAX_MEMORY_TYPES; ++i) {
-            destroyHostMemAlloc(enc, device, &info.hostMemAllocs[i]);
+            for (auto& block : info.hostMemBlocks[i]) {
+                destroyHostMemAlloc(enc, device, &block);
+            }
         }
 
         if (info.fence != VK_NULL_HANDLE) {
@@ -1257,6 +1288,8 @@
         buffer_constraints.physically_contiguous_required = false;
         buffer_constraints.secure_required = false;
         buffer_constraints.secure_permitted = false;
+        buffer_constraints.ram_domain_supported = true;
+        buffer_constraints.cpu_domain_supported = false;
         constraints.image_format_constraints_count = 1;
         fuchsia::sysmem::ImageFormatConstraints& image_constraints =
             constraints.image_format_constraints[0];
@@ -1284,6 +1317,121 @@
     }
 #endif
 
+    HostMemBlockIndex getOrAllocateHostMemBlockLocked(
+        HostMemBlocks& blocks,
+        const VkMemoryAllocateInfo* pAllocateInfo,
+        VkEncoder* enc,
+        VkDevice device,
+        const VkDevice_Info& deviceInfo) {
+
+        HostMemBlockIndex res = 0;
+        bool found = false;
+
+        while (!found) {
+            for (HostMemBlockIndex i = 0; i < blocks.size(); ++i) {
+                if (blocks[i].initialized &&
+                    blocks[i].initResult == VK_SUCCESS &&
+                    canSubAlloc(
+                        blocks[i].subAlloc,
+                        pAllocateInfo->allocationSize)) {
+                    res = i;
+                    found = true;
+                    return res;
+                }
+            }
+
+            blocks.push_back({});
+
+            auto& hostMemAlloc = blocks.back();
+
+            // Uninitialized block; allocate on host.
+            static constexpr VkDeviceSize oneMb = 1048576;
+            static constexpr VkDeviceSize kDefaultHostMemBlockSize =
+                16 * oneMb; // 16 mb
+            VkDeviceSize roundedUpAllocSize =
+                oneMb * ((pAllocateInfo->allocationSize + oneMb - 1) / oneMb);
+
+            VkDeviceSize virtualHeapSize = VIRTUAL_HOST_VISIBLE_HEAP_SIZE;
+
+            VkDeviceSize blockSizeNeeded =
+                std::max(roundedUpAllocSize,
+                    std::min(virtualHeapSize,
+                             kDefaultHostMemBlockSize));
+
+            VkMemoryAllocateInfo allocInfoForHost = *pAllocateInfo;
+
+            allocInfoForHost.allocationSize = blockSizeNeeded;
+
+            // TODO: Support dedicated/external host visible allocation
+            allocInfoForHost.pNext = nullptr;
+
+            mLock.unlock();
+            VkResult host_res =
+                enc->vkAllocateMemory(
+                    device,
+                    &allocInfoForHost,
+                    nullptr,
+                    &hostMemAlloc.memory);
+            mLock.lock();
+
+            if (host_res != VK_SUCCESS) {
+                ALOGE("Could not allocate backing for virtual host visible memory: %d",
+                      host_res);
+                hostMemAlloc.initialized = true;
+                hostMemAlloc.initResult = host_res;
+                return INVALID_HOST_MEM_BLOCK;
+            }
+
+            auto& hostMemInfo = info_VkDeviceMemory[hostMemAlloc.memory];
+            hostMemInfo.allocationSize = allocInfoForHost.allocationSize;
+            VkDeviceSize nonCoherentAtomSize =
+                deviceInfo.props.limits.nonCoherentAtomSize;
+            hostMemInfo.mappedSize = hostMemInfo.allocationSize;
+            hostMemInfo.memoryTypeIndex =
+                pAllocateInfo->memoryTypeIndex;
+            hostMemAlloc.nonCoherentAtomSize = nonCoherentAtomSize;
+
+            uint64_t directMappedAddr = 0;
+
+            mLock.unlock();
+            VkResult directMapResult =
+                enc->vkMapMemoryIntoAddressSpaceGOOGLE(
+                    device, hostMemAlloc.memory, &directMappedAddr);
+            mLock.lock();
+
+            if (directMapResult != VK_SUCCESS) {
+                hostMemAlloc.initialized = true;
+                hostMemAlloc.initResult = directMapResult;
+                mLock.unlock();
+                enc->vkFreeMemory(device, hostMemAlloc.memory, nullptr);
+                mLock.lock();
+                return INVALID_HOST_MEM_BLOCK;
+            }
+
+            hostMemInfo.mappedPtr =
+                (uint8_t*)(uintptr_t)directMappedAddr;
+            hostMemInfo.virtualHostVisibleBacking = true;
+
+            VkResult hostMemAllocRes =
+                finishHostMemAllocInit(
+                    enc,
+                    device,
+                    pAllocateInfo->memoryTypeIndex,
+                    nonCoherentAtomSize,
+                    hostMemInfo.allocationSize,
+                    hostMemInfo.mappedSize,
+                    hostMemInfo.mappedPtr,
+                    &hostMemAlloc);
+
+            if (hostMemAllocRes != VK_SUCCESS) {
+                return INVALID_HOST_MEM_BLOCK;
+            }
+        }
+
+        // unreacheable, but we need to make Werror happy
+        return INVALID_HOST_MEM_BLOCK;
+    }
+
     VkResult on_vkAllocateMemory(
         void* context,
         VkResult input_result,
@@ -1374,6 +1522,7 @@
         // to the AHardwareBuffer on the host via an "import" operation.
         AHardwareBuffer* ahw = nullptr;
         zx_handle_t vmo_handle = ZX_HANDLE_INVALID;
+        uint32_t cbHandle = 0;
 
         if (exportAllocateInfoPtr) {
             exportAhb =
@@ -1456,7 +1605,7 @@
         }
 
         if (ahw) {
-            ALOGD("%s: AHBIMPORT", __func__);
+            ALOGD("%s: Import AHardwareBulffer", __func__);
             const native_handle_t *handle =
                 AHardwareBuffer_getNativeHandle(ahw);
             const cb_handle_t* cb_handle =
@@ -1475,7 +1624,7 @@
 #endif
 
             if (cb) {
-                importCbInfo.colorBuffer = cb;
+                cbHandle = importCbInfo.colorBuffer = cb;
                 structChain =
                     vk_append_struct(structChain, (vk_struct_common*)(&importCbInfo));
             }
@@ -1486,7 +1635,9 @@
         if (!isHostVisibleMemoryTypeIndexForGuest(
                 &mHostVisibleMemoryVirtInfo,
                 finalAllocInfo.memoryTypeIndex)) {
-
+            if (cbHandle) {
+                (*mOpenColorBuffer)(cbHandle);
+            }
             input_result =
                 enc->vkAllocateMemory(
                     device, &finalAllocInfo, pAllocator, pMemory);
@@ -1500,7 +1651,8 @@
                 0, nullptr,
                 finalAllocInfo.memoryTypeIndex,
                 ahw,
-                vmo_handle);
+                vmo_handle,
+                cbHandle);
 
             return VK_SUCCESS;
         }
@@ -1563,78 +1715,25 @@
         if (it == info_VkDevice.end()) return VK_ERROR_DEVICE_LOST;
         auto& deviceInfo = it->second;
 
-        HostMemAlloc* hostMemAlloc =
-            &deviceInfo.hostMemAllocs[finalAllocInfo.memoryTypeIndex];
+        auto& hostMemBlocksForTypeIndex =
+            deviceInfo.hostMemBlocks[finalAllocInfo.memoryTypeIndex];
 
-        if (!hostMemAlloc->initialized) {
-            VkMemoryAllocateInfo allocInfoForHost = finalAllocInfo;
-            allocInfoForHost.allocationSize = VIRTUAL_HOST_VISIBLE_HEAP_SIZE;
-            // TODO: Support dedicated allocation
-            allocInfoForHost.pNext = nullptr;
+        HostMemBlockIndex blockIndex =
+            getOrAllocateHostMemBlockLocked(
+                hostMemBlocksForTypeIndex,
+                &finalAllocInfo,
+                enc,
+                device,
+                deviceInfo);
 
-            lock.unlock();
-            VkResult host_res =
-                enc->vkAllocateMemory(
-                    device,
-                    &allocInfoForHost,
-                    nullptr,
-                    &hostMemAlloc->memory);
-            lock.lock();
-
-            if (host_res != VK_SUCCESS) {
-                ALOGE("Could not allocate backing for virtual host visible memory: %d",
-                      host_res);
-                hostMemAlloc->initialized = true;
-                hostMemAlloc->initResult = host_res;
-                return host_res;
-            }
-
-            auto& hostMemInfo = info_VkDeviceMemory[hostMemAlloc->memory];
-            hostMemInfo.allocationSize = allocInfoForHost.allocationSize;
-            VkDeviceSize nonCoherentAtomSize =
-                deviceInfo.props.limits.nonCoherentAtomSize;
-            hostMemInfo.mappedSize = hostMemInfo.allocationSize;
-            hostMemInfo.memoryTypeIndex =
-                finalAllocInfo.memoryTypeIndex;
-            hostMemAlloc->nonCoherentAtomSize = nonCoherentAtomSize;
-
-            uint64_t directMappedAddr = 0;
-            lock.unlock();
-            VkResult directMapResult =
-                enc->vkMapMemoryIntoAddressSpaceGOOGLE(
-                    device, hostMemAlloc->memory, &directMappedAddr);
-            lock.lock();
-
-            if (directMapResult != VK_SUCCESS) {
-                hostMemAlloc->initialized = true;
-                hostMemAlloc->initResult = directMapResult;
-                return directMapResult;
-            }
-
-            hostMemInfo.mappedPtr =
-                (uint8_t*)(uintptr_t)directMappedAddr;
-            hostMemInfo.virtualHostVisibleBacking = true;
-
-            VkResult hostMemAllocRes =
-                finishHostMemAllocInit(
-                    enc,
-                    device,
-                    finalAllocInfo.memoryTypeIndex,
-                    nonCoherentAtomSize,
-                    hostMemInfo.allocationSize,
-                    hostMemInfo.mappedSize,
-                    hostMemInfo.mappedPtr,
-                    hostMemAlloc);
-
-            if (hostMemAllocRes != VK_SUCCESS) {
-                return hostMemAllocRes;
-            }
+        if (blockIndex == (HostMemBlockIndex) INVALID_HOST_MEM_BLOCK) {
+            return VK_ERROR_OUT_OF_HOST_MEMORY;
         }
 
         VkDeviceMemory_Info virtualMemInfo;
 
         subAllocHostMemory(
-            hostMemAlloc,
+            &hostMemBlocksForTypeIndex[blockIndex],
             &finalAllocInfo,
             &virtualMemInfo.subAlloc);
 
@@ -2704,6 +2803,185 @@
         return input_result;
     }
 
+    bool isDescriptorTypeImageInfo(VkDescriptorType descType) {
+        return (descType == VK_DESCRIPTOR_TYPE_SAMPLER) ||
+               (descType == VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER) ||
+               (descType == VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE) ||
+               (descType == VK_DESCRIPTOR_TYPE_STORAGE_IMAGE) ||
+               (descType == VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT);
+    }
+
+    bool isDescriptorTypeBufferInfo(VkDescriptorType descType) {
+        return (descType == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER) ||
+               (descType == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC) ||
+               (descType == VK_DESCRIPTOR_TYPE_STORAGE_BUFFER) ||
+               (descType == VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC);
+    }
+
+    bool isDescriptorTypeBufferView(VkDescriptorType descType) {
+        return (descType == VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER) ||
+               (descType == VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER);
+    }
+
+    VkResult initDescriptorUpdateTemplateBuffers(
+        const VkDescriptorUpdateTemplateCreateInfo* pCreateInfo,
+        VkDescriptorUpdateTemplate descriptorUpdateTemplate) {
+
+        AutoLock lock(mLock);
+
+        auto it = info_VkDescriptorUpdateTemplate.find(descriptorUpdateTemplate);
+        if (it == info_VkDescriptorUpdateTemplate.end()) {
+            return VK_ERROR_INITIALIZATION_FAILED;
+        }
+
+        auto& info = it->second;
+
+        size_t imageInfosNeeded = 0;
+        size_t bufferInfosNeeded = 0;
+        size_t bufferViewsNeeded = 0;
+
+        for (uint32_t i = 0; i < pCreateInfo->descriptorUpdateEntryCount; ++i) {
+            const auto& entry = pCreateInfo->pDescriptorUpdateEntries[i];
+            uint32_t descCount = entry.descriptorCount;
+            VkDescriptorType descType = entry.descriptorType;
+
+            info.templateEntries.push_back(entry);
+
+            for (uint32_t j = 0; j < descCount; ++j) {
+                if (isDescriptorTypeImageInfo(descType)) {
+                    ++imageInfosNeeded;
+                    info.imageInfoEntryIndices.push_back(i);
+                } else if (isDescriptorTypeBufferInfo(descType)) {
+                    ++bufferInfosNeeded;
+                    info.bufferInfoEntryIndices.push_back(i);
+                } else if (isDescriptorTypeBufferView(descType)) {
+                    ++bufferViewsNeeded;
+                    info.bufferViewEntryIndices.push_back(i);
+                } else {
+                    ALOGE("%s: FATAL: Unknown descriptor type %d\n", __func__, descType);
+                    abort();
+                }
+            }
+        }
+
+        // To be filled in later (our flat structure)
+        info.imageInfos.resize(imageInfosNeeded);
+        info.bufferInfos.resize(bufferInfosNeeded);
+        info.bufferViews.resize(bufferViewsNeeded);
+
+        return VK_SUCCESS;
+    }
+
+    VkResult on_vkCreateDescriptorUpdateTemplate(
+        void* context, VkResult input_result,
+        VkDevice device,
+        const VkDescriptorUpdateTemplateCreateInfo* pCreateInfo,
+        const VkAllocationCallbacks* pAllocator,
+        VkDescriptorUpdateTemplate* pDescriptorUpdateTemplate) {
+
+        (void)context;
+        (void)device;
+        (void)pAllocator;
+
+        if (input_result != VK_SUCCESS) return input_result;
+
+        return initDescriptorUpdateTemplateBuffers(pCreateInfo, *pDescriptorUpdateTemplate);
+    }
+
+    VkResult on_vkCreateDescriptorUpdateTemplateKHR(
+        void* context, VkResult input_result,
+        VkDevice device,
+        const VkDescriptorUpdateTemplateCreateInfo* pCreateInfo,
+        const VkAllocationCallbacks* pAllocator,
+        VkDescriptorUpdateTemplate* pDescriptorUpdateTemplate) {
+
+        (void)context;
+        (void)device;
+        (void)pAllocator;
+
+        if (input_result != VK_SUCCESS) return input_result;
+
+        return initDescriptorUpdateTemplateBuffers(pCreateInfo, *pDescriptorUpdateTemplate);
+    }
+
+    void on_vkUpdateDescriptorSetWithTemplate(
+        void* context,
+        VkDevice device,
+        VkDescriptorSet descriptorSet,
+        VkDescriptorUpdateTemplate descriptorUpdateTemplate,
+        const void* pData) {
+
+        VkEncoder* enc = (VkEncoder*)context;
+
+        uint8_t* userBuffer = (uint8_t*)pData;
+        if (!userBuffer) return;
+
+        AutoLock lock(mLock);
+
+        auto it = info_VkDescriptorUpdateTemplate.find(descriptorUpdateTemplate);
+        if (it == info_VkDescriptorUpdateTemplate.end()) {
+            return;
+        }
+
+        auto& info = it->second;
+
+        size_t currImageInfoOffset = 0;
+        size_t currBufferInfoOffset = 0;
+        size_t currBufferViewOffset = 0;
+
+        for (const auto& entry : info.templateEntries) {
+            VkDescriptorType descType = entry.descriptorType;
+
+            auto offset = entry.offset;
+            auto stride = entry.stride;
+
+            uint32_t descCount = entry.descriptorCount;
+
+            if (isDescriptorTypeImageInfo(descType)) {
+                if (!stride) stride = sizeof(VkDescriptorImageInfo);
+                for (uint32_t j = 0; j < descCount; ++j) {
+                    memcpy(((uint8_t*)info.imageInfos.data()) + currImageInfoOffset,
+                           userBuffer + offset + j * stride,
+                           sizeof(VkDescriptorImageInfo));
+                    currImageInfoOffset += sizeof(VkDescriptorImageInfo);
+                }
+            } else if (isDescriptorTypeBufferInfo(descType)) {
+                if (!stride) stride = sizeof(VkDescriptorBufferInfo);
+                for (uint32_t j = 0; j < descCount; ++j) {
+                    memcpy(((uint8_t*)info.bufferInfos.data()) + currBufferInfoOffset,
+                           userBuffer + offset + j * stride,
+                           sizeof(VkDescriptorBufferInfo));
+                    currBufferInfoOffset += sizeof(VkDescriptorBufferInfo);
+                }
+            } else if (isDescriptorTypeBufferView(descType)) {
+                if (!stride) stride = sizeof(VkBufferView);
+                for (uint32_t j = 0; j < descCount; ++j) {
+                    memcpy(((uint8_t*)info.bufferViews.data()) + currBufferViewOffset,
+                           userBuffer + offset + j * stride,
+                           sizeof(VkBufferView));
+                    currBufferViewOffset += sizeof(VkBufferView);
+                }
+            } else {
+                ALOGE("%s: FATAL: Unknown descriptor type %d\n", __func__, descType);
+                abort();
+            }
+        }
+
+        enc->vkUpdateDescriptorSetWithTemplateSizedGOOGLE(
+            device,
+            descriptorSet,
+            descriptorUpdateTemplate,
+            (uint32_t)info.imageInfos.size(),
+            (uint32_t)info.bufferInfos.size(),
+            (uint32_t)info.bufferViews.size(),
+            info.imageInfoEntryIndices.data(),
+            info.bufferInfoEntryIndices.data(),
+            info.bufferViewEntryIndices.data(),
+            info.imageInfos.data(),
+            info.bufferInfos.data(),
+            info.bufferViews.data());
+    }
+
     uint32_t getApiVersionFromInstance(VkInstance instance) const {
         AutoLock lock(mLock);
         uint32_t api = kMinApiVersion;
@@ -2755,6 +3033,7 @@
     std::unique_ptr<EmulatorFeatureInfo> mFeatureInfo;
     std::unique_ptr<GoldfishAddressSpaceBlockProvider> mGoldfishAddressSpaceBlockProvider;
     PFN_CreateColorBuffer mCreateColorBuffer;
+    PFN_OpenColorBuffer mOpenColorBuffer;
     PFN_CloseColorBuffer mCloseColorBuffer;
 
     std::vector<VkExtensionProperties> mHostInstanceExtensions;
@@ -2849,8 +3128,10 @@
 }
 
 void ResourceTracker::setColorBufferFunctions(
-    PFN_CreateColorBuffer create, PFN_CloseColorBuffer close) {
-    mImpl->setColorBufferFunctions(create, close);
+    PFN_CreateColorBuffer create,
+    PFN_OpenColorBuffer open,
+    PFN_CloseColorBuffer close) {
+    mImpl->setColorBufferFunctions(create, open, close);
 }
 
 VkResult ResourceTracker::on_vkEnumerateInstanceExtensionProperties(
@@ -3266,6 +3547,39 @@
         context, input_result, device, memory, pAddress);
 }
 
+VkResult ResourceTracker::on_vkCreateDescriptorUpdateTemplate(
+    void* context, VkResult input_result,
+    VkDevice device,
+    const VkDescriptorUpdateTemplateCreateInfo* pCreateInfo,
+    const VkAllocationCallbacks* pAllocator,
+    VkDescriptorUpdateTemplate* pDescriptorUpdateTemplate) {
+    return mImpl->on_vkCreateDescriptorUpdateTemplate(
+        context, input_result,
+        device, pCreateInfo, pAllocator, pDescriptorUpdateTemplate);
+}
+
+VkResult ResourceTracker::on_vkCreateDescriptorUpdateTemplateKHR(
+    void* context, VkResult input_result,
+    VkDevice device,
+    const VkDescriptorUpdateTemplateCreateInfo* pCreateInfo,
+    const VkAllocationCallbacks* pAllocator,
+    VkDescriptorUpdateTemplate* pDescriptorUpdateTemplate) {
+    return mImpl->on_vkCreateDescriptorUpdateTemplateKHR(
+        context, input_result,
+        device, pCreateInfo, pAllocator, pDescriptorUpdateTemplate);
+}
+
+void ResourceTracker::on_vkUpdateDescriptorSetWithTemplate(
+    void* context,
+    VkDevice device,
+    VkDescriptorSet descriptorSet,
+    VkDescriptorUpdateTemplate descriptorUpdateTemplate,
+    const void* pData) {
+    mImpl->on_vkUpdateDescriptorSetWithTemplate(
+        context, device, descriptorSet,
+        descriptorUpdateTemplate, pData);
+}
+
 void ResourceTracker::deviceMemoryTransform_tohost(
     VkDeviceMemory* memory, uint32_t memoryCount,
     VkDeviceSize* offset, uint32_t offsetCount,
diff --git a/system/vulkan_enc/ResourceTracker.h b/system/vulkan_enc/ResourceTracker.h
index 57eadda..830537f 100644
--- a/system/vulkan_enc/ResourceTracker.h
+++ b/system/vulkan_enc/ResourceTracker.h
@@ -29,7 +29,8 @@
 namespace goldfish_vk {
 
 typedef uint32_t (*PFN_CreateColorBuffer)(uint32_t width, uint32_t height, uint32_t format);
-typedef uint32_t (*PFN_CloseColorBuffer)(uint32_t id);
+typedef void (*PFN_OpenColorBuffer)(uint32_t id);
+typedef void (*PFN_CloseColorBuffer)(uint32_t id);
 
 class ResourceTracker {
 public:
@@ -287,6 +288,27 @@
         VkDeviceMemory memory,
         uint64_t* pAddress);
 
+    VkResult on_vkCreateDescriptorUpdateTemplate(
+        void* context, VkResult input_result,
+        VkDevice device,
+        const VkDescriptorUpdateTemplateCreateInfo* pCreateInfo,
+        const VkAllocationCallbacks* pAllocator,
+        VkDescriptorUpdateTemplate* pDescriptorUpdateTemplate);
+
+    VkResult on_vkCreateDescriptorUpdateTemplateKHR(
+        void* context, VkResult input_result,
+        VkDevice device,
+        const VkDescriptorUpdateTemplateCreateInfo* pCreateInfo,
+        const VkAllocationCallbacks* pAllocator,
+        VkDescriptorUpdateTemplate* pDescriptorUpdateTemplate);
+
+    void on_vkUpdateDescriptorSetWithTemplate(
+        void* context,
+        VkDevice device,
+        VkDescriptorSet descriptorSet,
+        VkDescriptorUpdateTemplate descriptorUpdateTemplate,
+        const void* pData);
+
     bool isMemoryTypeHostVisible(VkDevice device, uint32_t typeIndex) const;
     uint8_t* getMappedPointer(VkDeviceMemory memory);
     VkDeviceSize getMappedSize(VkDeviceMemory memory);
@@ -299,7 +321,9 @@
     uint32_t getApiVersionFromDevice(VkDevice device) const;
     bool hasInstanceExtension(VkInstance instance, const std::string& name) const;
     bool hasDeviceExtension(VkDevice instance, const std::string& name) const;
-    void setColorBufferFunctions(PFN_CreateColorBuffer create, PFN_CloseColorBuffer close);
+    void setColorBufferFunctions(PFN_CreateColorBuffer create,
+                                 PFN_OpenColorBuffer open,
+                                 PFN_CloseColorBuffer close);
 
     // Transforms
     void deviceMemoryTransform_tohost(
diff --git a/system/vulkan_enc/VkEncoder.cpp b/system/vulkan_enc/VkEncoder.cpp
index 4261d71..8f38e54 100644
--- a/system/vulkan_enc/VkEncoder.cpp
+++ b/system/vulkan_enc/VkEncoder.cpp
@@ -11086,6 +11086,7 @@
     countingStream->clearPool();
     stream->clearPool();
     pool->freeAll();
+    mImpl->resources()->on_vkCreateDescriptorUpdateTemplate(this, vkCreateDescriptorUpdateTemplate_VkResult_return, device, pCreateInfo, pAllocator, pDescriptorUpdateTemplate);
     mImpl->log("finish vkCreateDescriptorUpdateTemplate");;
     return vkCreateDescriptorUpdateTemplate_VkResult_return;
 }
@@ -15676,6 +15677,7 @@
     countingStream->clearPool();
     stream->clearPool();
     pool->freeAll();
+    mImpl->resources()->on_vkCreateDescriptorUpdateTemplateKHR(this, vkCreateDescriptorUpdateTemplateKHR_VkResult_return, device, pCreateInfo, pAllocator, pDescriptorUpdateTemplate);
     mImpl->log("finish vkCreateDescriptorUpdateTemplateKHR");;
     return vkCreateDescriptorUpdateTemplateKHR_VkResult_return;
 }
@@ -22261,5 +22263,243 @@
 }
 
 #endif
+#ifdef VK_GOOGLE_sized_descriptor_update_template
+void VkEncoder::vkUpdateDescriptorSetWithTemplateSizedGOOGLE(
+    VkDevice device,
+    VkDescriptorSet descriptorSet,
+    VkDescriptorUpdateTemplate descriptorUpdateTemplate,
+    uint32_t imageInfoCount,
+    uint32_t bufferInfoCount,
+    uint32_t bufferViewCount,
+    const uint32_t* pImageInfoEntryIndices,
+    const uint32_t* pBufferInfoEntryIndices,
+    const uint32_t* pBufferViewEntryIndices,
+    const VkDescriptorImageInfo* pImageInfos,
+    const VkDescriptorBufferInfo* pBufferInfos,
+    const VkBufferView* pBufferViews)
+{
+    AEMU_SCOPED_TRACE("vkUpdateDescriptorSetWithTemplateSizedGOOGLE encode");
+    mImpl->log("start vkUpdateDescriptorSetWithTemplateSizedGOOGLE");
+    auto stream = mImpl->stream();
+    auto countingStream = mImpl->countingStream();
+    auto resources = mImpl->resources();
+    auto pool = mImpl->pool();
+    stream->setHandleMapping(resources->unwrapMapping());
+    VkDevice local_device;
+    VkDescriptorSet local_descriptorSet;
+    VkDescriptorUpdateTemplate local_descriptorUpdateTemplate;
+    uint32_t local_imageInfoCount;
+    uint32_t local_bufferInfoCount;
+    uint32_t local_bufferViewCount;
+    uint32_t* local_pImageInfoEntryIndices;
+    uint32_t* local_pBufferInfoEntryIndices;
+    uint32_t* local_pBufferViewEntryIndices;
+    VkDescriptorImageInfo* local_pImageInfos;
+    VkDescriptorBufferInfo* local_pBufferInfos;
+    VkBufferView* local_pBufferViews;
+    local_device = device;
+    local_descriptorSet = descriptorSet;
+    local_descriptorUpdateTemplate = descriptorUpdateTemplate;
+    local_imageInfoCount = imageInfoCount;
+    local_bufferInfoCount = bufferInfoCount;
+    local_bufferViewCount = bufferViewCount;
+    local_pImageInfoEntryIndices = nullptr;
+    if (pImageInfoEntryIndices)
+    {
+        local_pImageInfoEntryIndices = (uint32_t*)pool->dupArray(pImageInfoEntryIndices, ((imageInfoCount)) * sizeof(const uint32_t));
+    }
+    local_pBufferInfoEntryIndices = nullptr;
+    if (pBufferInfoEntryIndices)
+    {
+        local_pBufferInfoEntryIndices = (uint32_t*)pool->dupArray(pBufferInfoEntryIndices, ((bufferInfoCount)) * sizeof(const uint32_t));
+    }
+    local_pBufferViewEntryIndices = nullptr;
+    if (pBufferViewEntryIndices)
+    {
+        local_pBufferViewEntryIndices = (uint32_t*)pool->dupArray(pBufferViewEntryIndices, ((bufferViewCount)) * sizeof(const uint32_t));
+    }
+    local_pImageInfos = nullptr;
+    if (pImageInfos)
+    {
+        local_pImageInfos = (VkDescriptorImageInfo*)pool->alloc(((imageInfoCount)) * sizeof(const VkDescriptorImageInfo));
+        for (uint32_t i = 0; i < (uint32_t)((imageInfoCount)); ++i)
+        {
+            deepcopy_VkDescriptorImageInfo(pool, pImageInfos + i, (VkDescriptorImageInfo*)(local_pImageInfos + i));
+        }
+    }
+    local_pBufferInfos = nullptr;
+    if (pBufferInfos)
+    {
+        local_pBufferInfos = (VkDescriptorBufferInfo*)pool->alloc(((bufferInfoCount)) * sizeof(const VkDescriptorBufferInfo));
+        for (uint32_t i = 0; i < (uint32_t)((bufferInfoCount)); ++i)
+        {
+            deepcopy_VkDescriptorBufferInfo(pool, pBufferInfos + i, (VkDescriptorBufferInfo*)(local_pBufferInfos + i));
+        }
+    }
+    local_pBufferViews = nullptr;
+    if (pBufferViews)
+    {
+        local_pBufferViews = (VkBufferView*)pool->dupArray(pBufferViews, ((bufferViewCount)) * sizeof(const VkBufferView));
+    }
+    if (local_pImageInfos)
+    {
+        for (uint32_t i = 0; i < (uint32_t)((imageInfoCount)); ++i)
+        {
+            transform_tohost_VkDescriptorImageInfo(mImpl->resources(), (VkDescriptorImageInfo*)(local_pImageInfos + i));
+        }
+    }
+    if (local_pBufferInfos)
+    {
+        for (uint32_t i = 0; i < (uint32_t)((bufferInfoCount)); ++i)
+        {
+            transform_tohost_VkDescriptorBufferInfo(mImpl->resources(), (VkDescriptorBufferInfo*)(local_pBufferInfos + i));
+        }
+    }
+    countingStream->rewind();
+    {
+        uint64_t cgen_var_1488;
+        countingStream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_1488, 1);
+        countingStream->write((uint64_t*)&cgen_var_1488, 1 * 8);
+        uint64_t cgen_var_1489;
+        countingStream->handleMapping()->mapHandles_VkDescriptorSet_u64(&local_descriptorSet, &cgen_var_1489, 1);
+        countingStream->write((uint64_t*)&cgen_var_1489, 1 * 8);
+        uint64_t cgen_var_1490;
+        countingStream->handleMapping()->mapHandles_VkDescriptorUpdateTemplate_u64(&local_descriptorUpdateTemplate, &cgen_var_1490, 1);
+        countingStream->write((uint64_t*)&cgen_var_1490, 1 * 8);
+        countingStream->write((uint32_t*)&local_imageInfoCount, sizeof(uint32_t));
+        countingStream->write((uint32_t*)&local_bufferInfoCount, sizeof(uint32_t));
+        countingStream->write((uint32_t*)&local_bufferViewCount, sizeof(uint32_t));
+        // WARNING PTR CHECK
+        uint64_t cgen_var_1491 = (uint64_t)(uintptr_t)local_pImageInfoEntryIndices;
+        countingStream->putBe64(cgen_var_1491);
+        if (local_pImageInfoEntryIndices)
+        {
+            countingStream->write((uint32_t*)local_pImageInfoEntryIndices, ((imageInfoCount)) * sizeof(uint32_t));
+        }
+        // WARNING PTR CHECK
+        uint64_t cgen_var_1492 = (uint64_t)(uintptr_t)local_pBufferInfoEntryIndices;
+        countingStream->putBe64(cgen_var_1492);
+        if (local_pBufferInfoEntryIndices)
+        {
+            countingStream->write((uint32_t*)local_pBufferInfoEntryIndices, ((bufferInfoCount)) * sizeof(uint32_t));
+        }
+        // WARNING PTR CHECK
+        uint64_t cgen_var_1493 = (uint64_t)(uintptr_t)local_pBufferViewEntryIndices;
+        countingStream->putBe64(cgen_var_1493);
+        if (local_pBufferViewEntryIndices)
+        {
+            countingStream->write((uint32_t*)local_pBufferViewEntryIndices, ((bufferViewCount)) * sizeof(uint32_t));
+        }
+        // WARNING PTR CHECK
+        uint64_t cgen_var_1494 = (uint64_t)(uintptr_t)local_pImageInfos;
+        countingStream->putBe64(cgen_var_1494);
+        if (local_pImageInfos)
+        {
+            for (uint32_t i = 0; i < (uint32_t)((imageInfoCount)); ++i)
+            {
+                marshal_VkDescriptorImageInfo(countingStream, (VkDescriptorImageInfo*)(local_pImageInfos + i));
+            }
+        }
+        // WARNING PTR CHECK
+        uint64_t cgen_var_1495 = (uint64_t)(uintptr_t)local_pBufferInfos;
+        countingStream->putBe64(cgen_var_1495);
+        if (local_pBufferInfos)
+        {
+            for (uint32_t i = 0; i < (uint32_t)((bufferInfoCount)); ++i)
+            {
+                marshal_VkDescriptorBufferInfo(countingStream, (VkDescriptorBufferInfo*)(local_pBufferInfos + i));
+            }
+        }
+        // WARNING PTR CHECK
+        uint64_t cgen_var_1496 = (uint64_t)(uintptr_t)local_pBufferViews;
+        countingStream->putBe64(cgen_var_1496);
+        if (local_pBufferViews)
+        {
+            if (((bufferViewCount)))
+            {
+                uint64_t* cgen_var_1497;
+                countingStream->alloc((void**)&cgen_var_1497, ((bufferViewCount)) * 8);
+                countingStream->handleMapping()->mapHandles_VkBufferView_u64(local_pBufferViews, cgen_var_1497, ((bufferViewCount)));
+                countingStream->write((uint64_t*)cgen_var_1497, ((bufferViewCount)) * 8);
+            }
+        }
+    }
+    uint32_t packetSize_vkUpdateDescriptorSetWithTemplateSizedGOOGLE = 4 + 4 + (uint32_t)countingStream->bytesWritten();
+    countingStream->rewind();
+    uint32_t opcode_vkUpdateDescriptorSetWithTemplateSizedGOOGLE = OP_vkUpdateDescriptorSetWithTemplateSizedGOOGLE;
+    stream->write(&opcode_vkUpdateDescriptorSetWithTemplateSizedGOOGLE, sizeof(uint32_t));
+    stream->write(&packetSize_vkUpdateDescriptorSetWithTemplateSizedGOOGLE, sizeof(uint32_t));
+    uint64_t cgen_var_1498;
+    stream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_1498, 1);
+    stream->write((uint64_t*)&cgen_var_1498, 1 * 8);
+    uint64_t cgen_var_1499;
+    stream->handleMapping()->mapHandles_VkDescriptorSet_u64(&local_descriptorSet, &cgen_var_1499, 1);
+    stream->write((uint64_t*)&cgen_var_1499, 1 * 8);
+    uint64_t cgen_var_1500;
+    stream->handleMapping()->mapHandles_VkDescriptorUpdateTemplate_u64(&local_descriptorUpdateTemplate, &cgen_var_1500, 1);
+    stream->write((uint64_t*)&cgen_var_1500, 1 * 8);
+    stream->write((uint32_t*)&local_imageInfoCount, sizeof(uint32_t));
+    stream->write((uint32_t*)&local_bufferInfoCount, sizeof(uint32_t));
+    stream->write((uint32_t*)&local_bufferViewCount, sizeof(uint32_t));
+    // WARNING PTR CHECK
+    uint64_t cgen_var_1501 = (uint64_t)(uintptr_t)local_pImageInfoEntryIndices;
+    stream->putBe64(cgen_var_1501);
+    if (local_pImageInfoEntryIndices)
+    {
+        stream->write((uint32_t*)local_pImageInfoEntryIndices, ((imageInfoCount)) * sizeof(uint32_t));
+    }
+    // WARNING PTR CHECK
+    uint64_t cgen_var_1502 = (uint64_t)(uintptr_t)local_pBufferInfoEntryIndices;
+    stream->putBe64(cgen_var_1502);
+    if (local_pBufferInfoEntryIndices)
+    {
+        stream->write((uint32_t*)local_pBufferInfoEntryIndices, ((bufferInfoCount)) * sizeof(uint32_t));
+    }
+    // WARNING PTR CHECK
+    uint64_t cgen_var_1503 = (uint64_t)(uintptr_t)local_pBufferViewEntryIndices;
+    stream->putBe64(cgen_var_1503);
+    if (local_pBufferViewEntryIndices)
+    {
+        stream->write((uint32_t*)local_pBufferViewEntryIndices, ((bufferViewCount)) * sizeof(uint32_t));
+    }
+    // WARNING PTR CHECK
+    uint64_t cgen_var_1504 = (uint64_t)(uintptr_t)local_pImageInfos;
+    stream->putBe64(cgen_var_1504);
+    if (local_pImageInfos)
+    {
+        for (uint32_t i = 0; i < (uint32_t)((imageInfoCount)); ++i)
+        {
+            marshal_VkDescriptorImageInfo(stream, (VkDescriptorImageInfo*)(local_pImageInfos + i));
+        }
+    }
+    // WARNING PTR CHECK
+    uint64_t cgen_var_1505 = (uint64_t)(uintptr_t)local_pBufferInfos;
+    stream->putBe64(cgen_var_1505);
+    if (local_pBufferInfos)
+    {
+        for (uint32_t i = 0; i < (uint32_t)((bufferInfoCount)); ++i)
+        {
+            marshal_VkDescriptorBufferInfo(stream, (VkDescriptorBufferInfo*)(local_pBufferInfos + i));
+        }
+    }
+    // WARNING PTR CHECK
+    uint64_t cgen_var_1506 = (uint64_t)(uintptr_t)local_pBufferViews;
+    stream->putBe64(cgen_var_1506);
+    if (local_pBufferViews)
+    {
+        if (((bufferViewCount)))
+        {
+            uint64_t* cgen_var_1507;
+            stream->alloc((void**)&cgen_var_1507, ((bufferViewCount)) * 8);
+            stream->handleMapping()->mapHandles_VkBufferView_u64(local_pBufferViews, cgen_var_1507, ((bufferViewCount)));
+            stream->write((uint64_t*)cgen_var_1507, ((bufferViewCount)) * 8);
+        }
+    }
+    AEMU_SCOPED_TRACE("vkUpdateDescriptorSetWithTemplateSizedGOOGLE readParams");
+    AEMU_SCOPED_TRACE("vkUpdateDescriptorSetWithTemplateSizedGOOGLE returnUnmarshal");
+    mImpl->log("finish vkUpdateDescriptorSetWithTemplateSizedGOOGLE");;
+}
+
+#endif
 
 } // namespace goldfish_vk
diff --git a/system/vulkan_enc/VkEncoder.h b/system/vulkan_enc/VkEncoder.h
index 2e72833..36b768c 100644
--- a/system/vulkan_enc/VkEncoder.h
+++ b/system/vulkan_enc/VkEncoder.h
@@ -1757,6 +1757,21 @@
         VkBuffer buffer,
         uint32_t colorBuffer);
 #endif
+#ifdef VK_GOOGLE_sized_descriptor_update_template
+    void vkUpdateDescriptorSetWithTemplateSizedGOOGLE(
+    VkDevice device,
+        VkDescriptorSet descriptorSet,
+        VkDescriptorUpdateTemplate descriptorUpdateTemplate,
+        uint32_t imageInfoCount,
+        uint32_t bufferInfoCount,
+        uint32_t bufferViewCount,
+        const uint32_t* pImageInfoEntryIndices,
+        const uint32_t* pBufferInfoEntryIndices,
+        const uint32_t* pBufferViewEntryIndices,
+        const VkDescriptorImageInfo* pImageInfos,
+        const VkDescriptorBufferInfo* pBufferInfos,
+        const VkBufferView* pBufferViews);
+#endif
 
 private:
     class Impl;
diff --git a/system/vulkan_enc/VulkanHandles.h b/system/vulkan_enc/VulkanHandles.h
index 2320072..481e601 100644
--- a/system/vulkan_enc/VulkanHandles.h
+++ b/system/vulkan_enc/VulkanHandles.h
@@ -44,7 +44,6 @@
     f(VkEvent) \
     f(VkQueryPool) \
     f(VkSamplerYcbcrConversion) \
-    f(VkDescriptorUpdateTemplate) \
     f(VkSurfaceKHR) \
     f(VkSwapchainKHR) \
     f(VkDisplayKHR) \
@@ -60,6 +59,7 @@
     f(VkBuffer) \
     f(VkImage) \
     f(VkSemaphore) \
+    f(VkDescriptorUpdateTemplate) \
     GOLDFISH_VK_LIST_TRIVIAL_NON_DISPATCHABLE_HANDLE_TYPES(f) \
 
 #define GOLDFISH_VK_LIST_HANDLE_TYPES(f) \
diff --git a/system/vulkan_enc/goldfish_vk_deepcopy_guest.cpp b/system/vulkan_enc/goldfish_vk_deepcopy_guest.cpp
index 0478e91..962a6be 100644
--- a/system/vulkan_enc/goldfish_vk_deepcopy_guest.cpp
+++ b/system/vulkan_enc/goldfish_vk_deepcopy_guest.cpp
@@ -6380,6 +6380,8 @@
 }
 
 #endif
+#ifdef VK_GOOGLE_sized_descriptor_update_template
+#endif
 void deepcopy_extension_struct(
     Pool* pool,
     const void* structExtension,
diff --git a/system/vulkan_enc/goldfish_vk_deepcopy_guest.h b/system/vulkan_enc/goldfish_vk_deepcopy_guest.h
index 6b73d1f..fbddca8 100644
--- a/system/vulkan_enc/goldfish_vk_deepcopy_guest.h
+++ b/system/vulkan_enc/goldfish_vk_deepcopy_guest.h
@@ -2022,5 +2022,7 @@
     VkImportPhysicalAddressGOOGLE* to);
 
 #endif
+#ifdef VK_GOOGLE_sized_descriptor_update_template
+#endif
 
 } // namespace goldfish_vk
diff --git a/system/vulkan_enc/goldfish_vk_extension_structs_guest.cpp b/system/vulkan_enc/goldfish_vk_extension_structs_guest.cpp
index 0457642..ffe1af5 100644
--- a/system/vulkan_enc/goldfish_vk_extension_structs_guest.cpp
+++ b/system/vulkan_enc/goldfish_vk_extension_structs_guest.cpp
@@ -278,6 +278,8 @@
 #endif
 #ifdef VK_GOOGLE_color_buffer
 #endif
+#ifdef VK_GOOGLE_sized_descriptor_update_template
+#endif
 uint32_t goldfish_vk_struct_type(
     const void* structExtension)
 {
diff --git a/system/vulkan_enc/goldfish_vk_extension_structs_guest.h b/system/vulkan_enc/goldfish_vk_extension_structs_guest.h
index 9d09bb8..1d9c327 100644
--- a/system/vulkan_enc/goldfish_vk_extension_structs_guest.h
+++ b/system/vulkan_enc/goldfish_vk_extension_structs_guest.h
@@ -295,5 +295,7 @@
 #endif
 #ifdef VK_GOOGLE_color_buffer
 #endif
+#ifdef VK_GOOGLE_sized_descriptor_update_template
+#endif
 
 } // namespace goldfish_vk
diff --git a/system/vulkan_enc/goldfish_vk_handlemap_guest.cpp b/system/vulkan_enc/goldfish_vk_handlemap_guest.cpp
index 0bc0419..3110cb5 100644
--- a/system/vulkan_enc/goldfish_vk_handlemap_guest.cpp
+++ b/system/vulkan_enc/goldfish_vk_handlemap_guest.cpp
@@ -4744,6 +4744,8 @@
 }
 
 #endif
+#ifdef VK_GOOGLE_sized_descriptor_update_template
+#endif
 void handlemap_extension_struct(
     VulkanHandleMapping* handlemap,
     void* structExtension_out)
diff --git a/system/vulkan_enc/goldfish_vk_handlemap_guest.h b/system/vulkan_enc/goldfish_vk_handlemap_guest.h
index c9678d4..8fc6584 100644
--- a/system/vulkan_enc/goldfish_vk_handlemap_guest.h
+++ b/system/vulkan_enc/goldfish_vk_handlemap_guest.h
@@ -1675,5 +1675,7 @@
     VkImportPhysicalAddressGOOGLE* toMap);
 
 #endif
+#ifdef VK_GOOGLE_sized_descriptor_update_template
+#endif
 
 } // namespace goldfish_vk
diff --git a/system/vulkan_enc/goldfish_vk_marshaling_guest.cpp b/system/vulkan_enc/goldfish_vk_marshaling_guest.cpp
index 0c12dfb..77d3be3 100644
--- a/system/vulkan_enc/goldfish_vk_marshaling_guest.cpp
+++ b/system/vulkan_enc/goldfish_vk_marshaling_guest.cpp
@@ -13329,6 +13329,8 @@
 }
 
 #endif
+#ifdef VK_GOOGLE_sized_descriptor_update_template
+#endif
 void marshal_extension_struct(
     VulkanStreamGuest* vkStream,
     const void* structExtension)
diff --git a/system/vulkan_enc/goldfish_vk_marshaling_guest.h b/system/vulkan_enc/goldfish_vk_marshaling_guest.h
index 5d04b41..0a908d9 100644
--- a/system/vulkan_enc/goldfish_vk_marshaling_guest.h
+++ b/system/vulkan_enc/goldfish_vk_marshaling_guest.h
@@ -3381,5 +3381,8 @@
 #define OP_vkRegisterImageColorBufferGOOGLE 20318
 #define OP_vkRegisterBufferColorBufferGOOGLE 20319
 #endif
+#ifdef VK_GOOGLE_sized_descriptor_update_template
+#define OP_vkUpdateDescriptorSetWithTemplateSizedGOOGLE 20320
+#endif
 
 } // namespace goldfish_vk
diff --git a/system/vulkan_enc/goldfish_vk_private_defs.h b/system/vulkan_enc/goldfish_vk_private_defs.h
index 9ace1d1..89a355e 100644
--- a/system/vulkan_enc/goldfish_vk_private_defs.h
+++ b/system/vulkan_enc/goldfish_vk_private_defs.h
@@ -400,6 +400,20 @@
 
 #endif // __Fuchsia__
 
+#define VK_GOOGLE_sized_descriptor_update_template 1
+
+typedef void (VKAPI_PTR *PFN_vkUpdateDescriptorSetWithTemplateSizedGOOGLE)(
+    VkDevice device, VkDescriptorSet descriptorSet, VkDescriptorUpdateTemplate descriptorUpdateTemplate,
+    uint32_t imageInfoCount,
+    uint32_t bufferInfoCount,
+    uint32_t bufferViewCount,
+    const uint32_t* pImageInfoEntryIndices,
+    const uint32_t* pBufferInfoEntryIndices,
+    const uint32_t* pBufferViewEntryIndices,
+    const VkDescriptorImageInfo* pImageInfos,
+    const VkDescriptorBufferInfo* pBufferInfos,
+    const VkBufferView* pBufferViews);
+
 #ifdef __cplusplus
 } // extern "C"
 #endif
diff --git a/system/vulkan_enc/goldfish_vk_transform_guest.cpp b/system/vulkan_enc/goldfish_vk_transform_guest.cpp
index 9ef029b..2c651db 100644
--- a/system/vulkan_enc/goldfish_vk_transform_guest.cpp
+++ b/system/vulkan_enc/goldfish_vk_transform_guest.cpp
@@ -8941,6 +8941,8 @@
 }
 
 #endif
+#ifdef VK_GOOGLE_sized_descriptor_update_template
+#endif
 void transform_tohost_extension_struct(
     ResourceTracker* resourceTracker,
     void* structExtension_out)
diff --git a/system/vulkan_enc/goldfish_vk_transform_guest.h b/system/vulkan_enc/goldfish_vk_transform_guest.h
index c7fb7d0..0f7aea5 100644
--- a/system/vulkan_enc/goldfish_vk_transform_guest.h
+++ b/system/vulkan_enc/goldfish_vk_transform_guest.h
@@ -3063,5 +3063,7 @@
     VkImportPhysicalAddressGOOGLE* toTransform);
 
 #endif
+#ifdef VK_GOOGLE_sized_descriptor_update_template
+#endif
 
 } // namespace goldfish_vk