diff --git a/shared/OpenglCodecCommon/gralloc_cb.h b/shared/OpenglCodecCommon/gralloc_cb.h
index f874c12f1a01340b460d98022b56fe120510ef75..927c820f0ea1cb49a580876640cdc111599e30d1 100644
--- a/shared/OpenglCodecCommon/gralloc_cb.h
+++ b/shared/OpenglCodecCommon/gralloc_cb.h
@@ -21,7 +21,6 @@
 #include <hardware/gralloc.h>
 #include <cutils/native_handle.h>
 
-#include "goldfish_dma.h"
 #include "qemu_pipe.h"
 
 #define BUFFER_HANDLE_MAGIC ((int)0xabfabfab)
@@ -64,7 +63,6 @@ struct cb_handle_t : public native_handle {
         hostHandle(0),
         emuFrameworkFormat(p_emuFrameworkFormat)
     {
-        goldfish_dma.fd = -1;
         refcount_pipe_fd = QEMU_PIPE_INVALID_HANDLE;
         version = sizeof(native_handle);
         numFds = 0;
@@ -134,8 +132,6 @@ struct cb_handle_t : public native_handle {
     int lockedHeight;
     uint32_t hostHandle;
 
-    goldfish_dma_context goldfish_dma;
-    uint32_t goldfish_dma_buf_size;
     EmulatorFrameworkFormat emuFrameworkFormat;
 };
 
diff --git a/system/OpenglSystemCommon/EmulatorFeatureInfo.h b/system/OpenglSystemCommon/EmulatorFeatureInfo.h
index ba4111e424a3bea4a1e85f7590e522cf3f6dac50..518273a08d5af206e8e08cf67a1647bbfef54bab 100644
--- a/system/OpenglSystemCommon/EmulatorFeatureInfo.h
+++ b/system/OpenglSystemCommon/EmulatorFeatureInfo.h
@@ -76,6 +76,9 @@ static const char kGLDirectMem[] = "ANDROID_EMU_direct_mem";
 // - Full gralloc interop: External memory, AHB
 static const char kVulkan[] = "ANDROID_EMU_vulkan";
 
+// Deferred Vulkan commands
+static const char kDeferredVulkanCommands[] = "ANDROID_EMU_deferred_vulkan_commands";
+
 // Struct describing available emulator features
 struct EmulatorFeatureInfo {
 
@@ -85,7 +88,8 @@ struct EmulatorFeatureInfo {
         hostComposition(HOST_COMPOSITION_NONE),
         glesMaxVersion(GLES_MAX_VERSION_2),
         hasDirectMem(false),
-        hasVulkan(false) { }
+        hasVulkan(false),
+        hasDeferredVulkanCommands(false) { }
 
     SyncImpl syncImpl;
     DmaImpl dmaImpl;
@@ -93,6 +97,7 @@ struct EmulatorFeatureInfo {
     GLESMaxVersion glesMaxVersion;
     bool hasDirectMem;
     bool hasVulkan;
+    bool hasDeferredVulkanCommands;
 };
 
 #endif // __COMMON_EMULATOR_FEATURE_INFO_H
diff --git a/system/OpenglSystemCommon/HostConnection.cpp b/system/OpenglSystemCommon/HostConnection.cpp
index 5e0507308a623c88cfb094c2856d1808fd769fe3..b6d465cc65a2a8fd0b239601b4a4759c25a676d6 100644
--- a/system/OpenglSystemCommon/HostConnection.cpp
+++ b/system/OpenglSystemCommon/HostConnection.cpp
@@ -440,3 +440,10 @@ void HostConnection::queryAndSetVulkanSupport(ExtendedRCEncoderContext* rcEnc) {
         rcEnc->featureInfo()->hasVulkan = true;
     }
 }
+
+void HostConnection::queryAndSetDeferredVulkanCommandsSupport(ExtendedRCEncoderContext* rcEnc) {
+    std::string glExtensions = queryGLExtensions(rcEnc);
+    if (glExtensions.find(kDeferredVulkanCommands) != std::string::npos) {
+        rcEnc->featureInfo()->hasDeferredVulkanCommands = true;
+    }
+}
diff --git a/system/OpenglSystemCommon/HostConnection.h b/system/OpenglSystemCommon/HostConnection.h
index c58e6d2d1eb2895f02a735eee5812bc111618ee5..922c35c44d6e5d62f12a73a1bc03e207ab252c9b 100644
--- a/system/OpenglSystemCommon/HostConnection.h
+++ b/system/OpenglSystemCommon/HostConnection.h
@@ -165,6 +165,7 @@ private:
     void queryAndSetHostCompositionImpl(ExtendedRCEncoderContext *rcEnc);
     void queryAndSetDirectMemSupport(ExtendedRCEncoderContext *rcEnc);
     void queryAndSetVulkanSupport(ExtendedRCEncoderContext *rcEnc);
+    void queryAndSetDeferredVulkanCommandsSupport(ExtendedRCEncoderContext *rcEnc);
 
 private:
     IOStream *m_stream;
diff --git a/system/gralloc/gralloc.cpp b/system/gralloc/gralloc.cpp
index 6edfc3ad705a9da46f796b8406bfeb2d5874249d..851f3b022655dbb07f3485e9a602c25623d56975 100644
--- a/system/gralloc/gralloc.cpp
+++ b/system/gralloc/gralloc.cpp
@@ -44,6 +44,8 @@
 #include <cutils/properties.h>
 
 #include <set>
+#include <map>
+#include <vector>
 #include <string>
 #include <sstream>
 
@@ -99,43 +101,32 @@ static pthread_once_t     sFallbackOnce = PTHREAD_ONCE_INIT;
 
 static void fallback_init(void);  // forward
 
-typedef struct _alloc_list_node {
-    buffer_handle_t handle;
-    _alloc_list_node *next;
-    _alloc_list_node *prev;
-} AllocListNode;
-
-struct MemRegionInfo {
-    void* ashmemBase;
-    mutable uint32_t refCount;
-};
-
-struct MemRegionInfoCmp {
-    bool operator()(const MemRegionInfo& a, const MemRegionInfo& b) const {
-        return a.ashmemBase < b.ashmemBase;
-    }
-};
-
-typedef std::set<MemRegionInfo, MemRegionInfoCmp> MemRegionSet;
-typedef MemRegionSet::iterator mem_region_handle_t;
-
 //
 // Our gralloc device structure (alloc interface)
 //
 struct gralloc_device_t {
     alloc_device_t  device;
-
-    AllocListNode *allocListHead;    // double linked list of allocated buffers
+    std::set<buffer_handle_t> allocated;
     pthread_mutex_t lock;
 };
 
 struct gralloc_memregions_t {
-    MemRegionSet ashmemRegions;
+    typedef std::map<void*, uint32_t> MemRegionMap;  // base -> refCount
+    typedef MemRegionMap::const_iterator mem_region_handle_t;
+
+    MemRegionMap ashmemRegions;
     pthread_mutex_t lock;
 };
 
 #define INITIAL_DMA_REGION_SIZE 4096
 struct gralloc_dmaregion_t {
+    gralloc_dmaregion_t(ExtendedRCEncoderContext *rcEnc)
+      : sz(0), refcount(0), bigbufCount(0) {
+        pthread_mutex_init(&lock, NULL);
+        sz = INITIAL_DMA_REGION_SIZE;
+        goldfish_dma_create_region(sz, &goldfish_dma);
+    }
+
     goldfish_dma_context goldfish_dma;
     uint32_t sz;
     uint32_t refcount;
@@ -147,161 +138,168 @@ struct gralloc_dmaregion_t {
 static gralloc_memregions_t* s_memregions = NULL;
 static gralloc_dmaregion_t* s_grdma = NULL;
 
-static void init_gralloc_memregions() {
-    if (s_memregions) return;
+static gralloc_memregions_t* init_gralloc_memregions() {
+    if (s_memregions) return s_memregions;
+
     s_memregions = new gralloc_memregions_t;
     pthread_mutex_init(&s_memregions->lock, NULL);
+    return s_memregions;
 }
 
-static void init_gralloc_dmaregion() {
-    D("%s: call\n", __FUNCTION__);
-    if (s_grdma) return;
-
-    s_grdma = new gralloc_dmaregion_t;
-    s_grdma->sz = INITIAL_DMA_REGION_SIZE;
-    s_grdma->refcount = 0;
-    s_grdma->bigbufCount = 0;
-
-    pthread_mutex_init(&s_grdma->lock, NULL);
-    pthread_mutex_lock(&s_grdma->lock);
-    goldfish_dma_create_region(s_grdma->sz, &s_grdma->goldfish_dma);
-    pthread_mutex_unlock(&s_grdma->lock);
+static gralloc_dmaregion_t* init_gralloc_dmaregion(ExtendedRCEncoderContext *rcEnc) {
+    D("%s: call\n", __func__);
+    if (!s_grdma) {
+        s_grdma = new gralloc_dmaregion_t(rcEnc);
+    }
+    return s_grdma;
 }
 
-static void get_gralloc_dmaregion() {
-    if (!s_grdma) return;
-    pthread_mutex_lock(&s_grdma->lock);
-    s_grdma->refcount++;
-    D("%s: call. refcount: %u\n", __FUNCTION__, s_grdma->refcount);
-    pthread_mutex_unlock(&s_grdma->lock);
+static void get_gralloc_region(ExtendedRCEncoderContext *rcEnc) {
+    gralloc_dmaregion_t* grdma = init_gralloc_dmaregion(rcEnc);
+
+    pthread_mutex_lock(&grdma->lock);
+    grdma->refcount++;
+    D("%s: call. refcount: %u\n", __func__, grdma->refcount);
+    pthread_mutex_unlock(&grdma->lock);
 }
 
-static void resize_gralloc_dmaregion_locked(uint32_t new_sz) {
-    if (!s_grdma) return;
-    if (s_grdma->goldfish_dma.mapped_addr) {
-        goldfish_dma_unmap(&s_grdma->goldfish_dma);
+static void resize_gralloc_dmaregion_locked(gralloc_dmaregion_t* grdma, uint32_t new_sz) {
+    if (grdma->goldfish_dma.mapped_addr) {
+        goldfish_dma_unmap(&grdma->goldfish_dma);
     }
-    close(s_grdma->goldfish_dma.fd);
-    goldfish_dma_create_region(new_sz, &s_grdma->goldfish_dma);
-    s_grdma->sz = new_sz;
+    close(grdma->goldfish_dma.fd);
+    goldfish_dma_create_region(new_sz, &grdma->goldfish_dma);
+    grdma->sz = new_sz;
 }
 
 // max dma size: 2x 4K rgba8888
 #define MAX_DMA_SIZE 66355200
 
-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);
-    s_grdma->refcount--;
-    if (sz > MAX_DMA_SIZE &&
-        s_grdma->bigbufCount) {
-        s_grdma->bigbufCount--;
+static bool put_gralloc_region_dma_locked(gralloc_dmaregion_t* grdma, uint32_t sz) {
+    D("%s: call. refcount before: %u\n", __func__, grdma->refcount);
+    grdma->refcount--;
+    if (sz > MAX_DMA_SIZE && grdma->bigbufCount) {
+        grdma->bigbufCount--;
     }
-    bool shouldDelete = !s_grdma->refcount;
+    bool shouldDelete = !grdma->refcount;
     if (shouldDelete) {
-        D("%s: should delete!\n", __FUNCTION__);
-        resize_gralloc_dmaregion_locked(INITIAL_DMA_REGION_SIZE);
-        D("%s: done\n", __FUNCTION__);
+        D("%s: should delete!\n", __func__);
+        resize_gralloc_dmaregion_locked(grdma, INITIAL_DMA_REGION_SIZE);
+        D("%s: done\n", __func__);
     }
-    pthread_mutex_unlock(&s_grdma->lock);
-    D("%s: exit\n", __FUNCTION__);
+    D("%s: exit\n", __func__);
+    return shouldDelete;
+}
+
+static bool put_gralloc_region(ExtendedRCEncoderContext *rcEnc, uint32_t sz) {
+    bool shouldDelete;
+
+    gralloc_dmaregion_t* grdma = init_gralloc_dmaregion(rcEnc);
+    pthread_mutex_lock(&grdma->lock);
+    shouldDelete = put_gralloc_region_dma_locked(grdma, sz);
+    pthread_mutex_unlock(&grdma->lock);
+
     return shouldDelete;
 }
 
-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);
-    uint32_t new_sz = std::max(s_grdma->sz, sz);
-    if (new_sz != s_grdma->sz) {
+static void gralloc_dmaregion_register_ashmem_dma(gralloc_dmaregion_t* grdma, uint32_t new_sz) {
+    if (new_sz != grdma->sz) {
         if (new_sz > MAX_DMA_SIZE)  {
             D("%s: requested sz %u too large (limit %u), set to fallback.",
-              __FUNCTION__, sz, MAX_DMA_SIZE);
-            s_grdma->bigbufCount++;
+              __func__, sz, MAX_DMA_SIZE);
+            grdma->bigbufCount++;
         } else {
-            D("%s: change sz from %u to %u", __FUNCTION__, s_grdma->sz, sz);
-            resize_gralloc_dmaregion_locked(new_sz);
+            D("%s: change sz from %u to %u", __func__, grdma->sz, sz);
+            resize_gralloc_dmaregion_locked(grdma, new_sz);
         }
     }
-    if (!s_grdma->goldfish_dma.mapped_addr) {
-        goldfish_dma_map(&s_grdma->goldfish_dma);
+    if (!grdma->goldfish_dma.mapped_addr) {
+        goldfish_dma_map(&grdma->goldfish_dma);
     }
-    pthread_mutex_unlock(&s_grdma->lock);
+}
+
+static void gralloc_dmaregion_register_ashmem(ExtendedRCEncoderContext *rcEnc, uint32_t sz) {
+    gralloc_dmaregion_t* grdma = init_gralloc_dmaregion(rcEnc);
+
+    pthread_mutex_lock(&grdma->lock);
+    D("%s: for sz %u, refcount %u", __func__, sz, grdma->refcount);
+    const uint32_t new_sz = std::max(grdma->sz, sz);
+    gralloc_dmaregion_register_ashmem_dma(grdma, new_sz);
+    pthread_mutex_unlock(&grdma->lock);
 }
 
 static void get_mem_region(void* ashmemBase) {
-    init_gralloc_memregions();
-    D("%s: call for %p", __FUNCTION__, ashmemBase);
-    MemRegionInfo lookup;
-    lookup.ashmemBase = ashmemBase;
-    pthread_mutex_lock(&s_memregions->lock);
-    mem_region_handle_t handle = s_memregions->ashmemRegions.find(lookup);
-    if (handle == s_memregions->ashmemRegions.end()) {
-        MemRegionInfo newRegion;
-        newRegion.ashmemBase = ashmemBase;
-        newRegion.refCount = 1;
-        s_memregions->ashmemRegions.insert(newRegion);
-    } else {
-        handle->refCount++;
-    }
-    pthread_mutex_unlock(&s_memregions->lock);
+    D("%s: call for %p", __func__, ashmemBase);
+
+    gralloc_memregions_t* memregions = init_gralloc_memregions();
+
+    pthread_mutex_lock(&memregions->lock);
+    ++memregions->ashmemRegions[ashmemBase];
+    pthread_mutex_unlock(&memregions->lock);
 }
 
-static bool put_mem_region(void* ashmemBase) {
-    init_gralloc_memregions();
-    D("%s: call for %p", __FUNCTION__, ashmemBase);
-    MemRegionInfo lookup;
-    lookup.ashmemBase = ashmemBase;
-    pthread_mutex_lock(&s_memregions->lock);
-    mem_region_handle_t handle = s_memregions->ashmemRegions.find(lookup);
-    if (handle == s_memregions->ashmemRegions.end()) {
-        ALOGE("%s: error: tried to put nonexistent mem region!", __FUNCTION__);
-        pthread_mutex_unlock(&s_memregions->lock);
-        return true;
+static bool put_mem_region(ExtendedRCEncoderContext *rcEnc, void* ashmemBase) {
+    D("%s: call for %p", __func__, ashmemBase);
+
+    gralloc_memregions_t* memregions = init_gralloc_memregions();
+    bool shouldRemove;
+
+    pthread_mutex_lock(&memregions->lock);
+    gralloc_memregions_t::MemRegionMap::iterator i = memregions->ashmemRegions.find(ashmemBase);
+    if (i == memregions->ashmemRegions.end()) {
+        shouldRemove = true;
+        ALOGE("%s: error: tried to put a nonexistent mem region (%p)!", __func__, ashmemBase);
     } else {
-        handle->refCount--;
-        bool shouldRemove = !handle->refCount;
+        shouldRemove = --i->second == 0;
         if (shouldRemove) {
-            s_memregions->ashmemRegions.erase(lookup);
+            memregions->ashmemRegions.erase(i);
         }
-        pthread_mutex_unlock(&s_memregions->lock);
-        return shouldRemove;
     }
+    pthread_mutex_unlock(&memregions->lock);
+
+    return shouldRemove;
 }
 
-static void dump_regions() {
-    init_gralloc_memregions();
-    mem_region_handle_t curr = s_memregions->ashmemRegions.begin();
+static void dump_regions(ExtendedRCEncoderContext *rcEnc) {
+    gralloc_memregions_t* memregions = init_gralloc_memregions();
+    gralloc_memregions_t::mem_region_handle_t curr = memregions->ashmemRegions.begin();
     std::stringstream res;
-    for (; curr != s_memregions->ashmemRegions.end(); curr++) {
-        res << "\tashmem base " << curr->ashmemBase << " refcount " << curr->refCount << "\n";
+    for (; curr != memregions->ashmemRegions.end(); ++curr) {
+        res << "\tashmem base " << curr->first << " refcount " << curr->second << "\n";
     }
     ALOGD("ashmem region dump [\n%s]", res.str().c_str());
 }
 
+static void get_ashmem_region(ExtendedRCEncoderContext *rcEnc, cb_handle_t *cb) {
 #if DEBUG
+    dump_regions(rcEnc);
+#endif
 
-#define GET_ASHMEM_REGION(cb) \
-    dump_regions(); \
-    get_mem_region((void*)cb->ashmemBase); \
-    dump_regions(); \
+    get_mem_region((void*)cb->ashmemBase);
 
-#define PUT_ASHMEM_REGION(cb) \
-    dump_regions(); \
-    bool SHOULD_UNMAP = put_mem_region((void*)cb->ashmemBase); \
-    dump_regions(); \
+#if DEBUG
+    dump_regions(rcEnc);
+#endif
 
-#else
+    get_gralloc_region(rcEnc);
+}
 
-#define GET_ASHMEM_REGION(cb) \
-    get_mem_region((void*)cb->ashmemBase); \
+static bool put_ashmem_region(ExtendedRCEncoderContext *rcEnc, cb_handle_t *cb) {
+#if DEBUG
+    dump_regions(rcEnc);
+#endif
 
-#define PUT_ASHMEM_REGION(cb) \
-    bool SHOULD_UNMAP = put_mem_region((void*)cb->ashmemBase); \
+    const bool should_unmap = put_mem_region(rcEnc, (void*)cb->ashmemBase);
 
+#if DEBUG
+    dump_regions(rcEnc);
 #endif
 
+    put_gralloc_region(rcEnc, cb->ashmemSize);
+
+    return should_unmap;
+}
+
 //
 // Our framebuffer device structure
 //
@@ -370,7 +368,10 @@ static void updateHostColorBuffer(cb_handle_t* cb,
                               bool doLocked,
                               char* pixels) {
     D("%s: call. doLocked=%d", __FUNCTION__, doLocked);
+
     DEFINE_HOST_CONNECTION;
+    gralloc_dmaregion_t* grdma = init_gralloc_dmaregion(rcEnc);
+
     int bpp = glUtilsPixelBitSize(cb->glFormat, cb->glType) >> 3;
     int left = doLocked ? cb->lockedLeft : 0;
     int top = doLocked ? cb->lockedTop : 0;
@@ -384,12 +385,11 @@ static void updateHostColorBuffer(cb_handle_t* cb,
         cb->frameworkFormat != HAL_PIXEL_FORMAT_YV12 &&
         cb->frameworkFormat != HAL_PIXEL_FORMAT_YCbCr_420_888;
 
-    char* convertedBuf = NULL;
+    std::vector<char> convertedBuf;
     if ((doLocked && is_rgb_format) ||
-        (!s_grdma &&
-         (doLocked || !is_rgb_format))) {
-        convertedBuf = new char[rgbSz];
-        to_send = convertedBuf;
+        (!grdma && (doLocked || !is_rgb_format))) {
+        convertedBuf.resize(rgbSz);
+        to_send = convertedBuf.data();
         send_buffer_size = rgbSz;
     }
 
@@ -400,12 +400,13 @@ static void updateHostColorBuffer(cb_handle_t* cb,
                 width, height, top, left, bpp);
     }
 
-    if (s_grdma && s_grdma->bigbufCount) {
+    const bool hasDMA = rcEnc->getDmaVersion() > 0;
+    if (hasDMA && grdma->bigbufCount) {
         D("%s: there are big buffers alive, use fallback (count %u)", __FUNCTION__,
-          s_grdma->bigbufCount);
+          grdma->bigbufCount);
     }
 
-    if (s_grdma && !s_grdma->bigbufCount) {
+    if (hasDMA && !grdma->bigbufCount) {
         if (cb->frameworkFormat == HAL_PIXEL_FORMAT_YV12) {
             get_yv12_offsets(width, height, NULL, NULL,
                              &send_buffer_size);
@@ -415,14 +416,15 @@ static void updateHostColorBuffer(cb_handle_t* cb,
                                 &send_buffer_size);
         }
 
-        rcEnc->bindDmaContext(&s_grdma->goldfish_dma);
-        D("%s: call. dma update with sz=%u", __FUNCTION__, send_buffer_size);
-        pthread_mutex_lock(&s_grdma->lock);
+        rcEnc->bindDmaContext(&grdma->goldfish_dma);
+
+        D("%s: call. dma update with sz=%u", __func__, send_buffer_size);
+        pthread_mutex_lock(&grdma->lock);
         rcEnc->rcUpdateColorBufferDMA(rcEnc, cb->hostHandle,
                 left, top, width, height,
                 cb->glFormat, cb->glType,
                 to_send, send_buffer_size);
-        pthread_mutex_unlock(&s_grdma->lock);
+        pthread_mutex_unlock(&grdma->lock);
     } else {
         if (cb->frameworkFormat == HAL_PIXEL_FORMAT_YV12) {
             yv12_to_rgb888(to_send, pixels,
@@ -438,8 +440,6 @@ static void updateHostColorBuffer(cb_handle_t* cb,
                 left, top, width, height,
                 cb->glFormat, cb->glType, to_send);
     }
-
-    if (convertedBuf) delete [] convertedBuf;
 }
 
 #ifndef GL_RGBA16F
@@ -719,7 +719,6 @@ static int gralloc_alloc(alloc_device_t* dev,
                                       glFormat, glType, selectedEmuFrameworkFormat);
 
     if (ashmem_size > 0) {
-
         //
         // map ashmem region if exist
         //
@@ -730,21 +729,7 @@ static int gralloc_alloc(alloc_device_t* dev,
             delete cb;
             return err;
         }
-
         cb->setFd(fd);
-
-        hostCon->lock();
-
-        if (rcEnc->getDmaVersion() > 0) {
-            D("%s: creating goldfish dma region of size %lu (cb fd %d)\n", __FUNCTION__, ashmem_size, cb->fd);
-            init_gralloc_dmaregion();
-            get_gralloc_dmaregion();
-        } else {
-            cb->goldfish_dma.fd = -1;
-        }
-        hostCon->unlock();
-    } else {
-        cb->goldfish_dma.fd = -1;
     }
 
     if (needHostCb) {
@@ -758,8 +743,10 @@ static int gralloc_alloc(alloc_device_t* dev,
             if (HAL_PIXEL_FORMAT_RGBX_8888 == format) {
                 allocFormat = GL_RGB;
             }
+
+            gralloc_dmaregion_t* grdma = init_gralloc_dmaregion(rcEnc);
             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);
@@ -788,15 +775,8 @@ static int gralloc_alloc(alloc_device_t* dev,
     //
     // alloc succeeded - insert the allocated handle to the allocated list
     //
-    AllocListNode *node = new AllocListNode();
     pthread_mutex_lock(&grdev->lock);
-    node->handle = cb;
-    node->next =  grdev->allocListHead;
-    node->prev =  NULL;
-    if (grdev->allocListHead) {
-        grdev->allocListHead->prev = node;
-    }
-    grdev->allocListHead = node;
+    grdev->allocated.insert(cb);
     pthread_mutex_unlock(&grdev->lock);
 
     *pHandle = cb;
@@ -810,12 +790,21 @@ static int gralloc_alloc(alloc_device_t* dev,
         *pStride = stride;
         break;
     }
+
+    hostCon->lock();
+    if (rcEnc->getDmaVersion() > 0) {
+        get_gralloc_region(rcEnc);  // map_buffer(cb, ...) refers here
+    }
+    hostCon->unlock();
+
     return 0;
 }
 
 static int gralloc_free(alloc_device_t* dev,
                         buffer_handle_t handle)
 {
+    DEFINE_AND_VALIDATE_HOST_CONNECTION;
+
     cb_handle_t *cb = (cb_handle_t *)handle;
     if (!cb_handle_t::validate((cb_handle_t*)cb)) {
         ERR("gralloc_free: invalid handle");
@@ -834,7 +823,6 @@ static int gralloc_free(alloc_device_t* dev,
         }
 
         if (*openCountPtr > 0) {
-            DEFINE_AND_VALIDATE_HOST_CONNECTION;
             D("Closing host ColorBuffer 0x%x\n", cb->hostHandle);
             hostCon->lock();
             rcEnc->rcCloseColorBuffer(rcEnc, cb->hostHandle);
@@ -852,7 +840,7 @@ static int gralloc_free(alloc_device_t* dev,
         if (cb->ashmemSize > 0 && cb->ashmemBase) {
             D("%s: unmapped %p", __FUNCTION__, cb->ashmemBase);
             munmap((void *)cb->ashmemBase, cb->ashmemSize);
-            put_gralloc_dmaregion(cb->ashmemSize);
+            put_gralloc_region(rcEnc, cb->ashmemSize);
         }
         close(cb->fd);
     }
@@ -863,25 +851,9 @@ static int gralloc_free(alloc_device_t* dev,
     D("%s: done", __FUNCTION__);
     // remove it from the allocated list
     gralloc_device_t *grdev = (gralloc_device_t *)dev;
+
     pthread_mutex_lock(&grdev->lock);
-    AllocListNode *n = grdev->allocListHead;
-    while( n && n->handle != cb ) {
-        n = n->next;
-    }
-    if (n) {
-       // buffer found on list - remove it from list
-       if (n->next) {
-           n->next->prev = n->prev;
-       }
-       if (n->prev) {
-           n->prev->next = n->next;
-       }
-       else {
-           grdev->allocListHead = n->next;
-       }
-
-       delete n;
-    }
+    grdev->allocated.erase(cb);
     pthread_mutex_unlock(&grdev->lock);
 
     delete cb;
@@ -894,14 +866,12 @@ static int gralloc_device_close(struct hw_device_t *dev)
 {
     gralloc_device_t* d = reinterpret_cast<gralloc_device_t*>(dev);
     if (d) {
-
-        // free still allocated buffers
-        while( d->allocListHead != NULL ) {
-            gralloc_free(&d->device, d->allocListHead->handle);
+        for (std::set<buffer_handle_t>::const_iterator i = d->allocated.begin();
+             i != d->allocated.end(); ++i) {
+            gralloc_free(&d->device, *i);
         }
 
-        // free device
-        free(d);
+        delete d;
     }
     return 0;
 }
@@ -1006,6 +976,7 @@ static int fb_close(struct hw_device_t *dev)
 static int gralloc_register_buffer(gralloc_module_t const* module,
                                    buffer_handle_t handle)
 {
+    DEFINE_AND_VALIDATE_HOST_CONNECTION;
 
     D("%s: start", __FUNCTION__);
     pthread_once(&sFallbackOnce, fallback_init);
@@ -1025,7 +996,6 @@ static int gralloc_register_buffer(gralloc_module_t const* module,
         handle, cb->width, cb->height, cb->format, cb->frameworkFormat);
 
     if (cb->hostHandle != 0 && !cb->hasRefcountPipe()) {
-        DEFINE_AND_VALIDATE_HOST_CONNECTION;
         D("Opening host ColorBuffer 0x%x\n", cb->hostHandle);
         hostCon->lock();
         rcEnc->rcOpenColorBuffer2(rcEnc, cb->hostHandle);
@@ -1050,19 +1020,16 @@ static int gralloc_register_buffer(gralloc_module_t const* module,
             if (!*openCountPtr) *openCountPtr = 1;
         }
 
-        DEFINE_AND_VALIDATE_HOST_CONNECTION;
         hostCon->lock();
         if (rcEnc->getDmaVersion() > 0) {
-            init_gralloc_dmaregion();
-            gralloc_dmaregion_register_ashmem(cb->ashmemSize);
+            gralloc_dmaregion_register_ashmem(rcEnc, cb->ashmemSize);
         }
         hostCon->unlock();
 
     }
 
     if (cb->ashmemSize > 0) {
-        GET_ASHMEM_REGION(cb);
-        get_gralloc_dmaregion();
+        get_ashmem_region(rcEnc, cb);
     }
 
     return 0;
@@ -1071,6 +1038,8 @@ static int gralloc_register_buffer(gralloc_module_t const* module,
 static int gralloc_unregister_buffer(gralloc_module_t const* module,
                                      buffer_handle_t handle)
 {
+    DEFINE_AND_VALIDATE_HOST_CONNECTION;
+
     if (sFallback != NULL) {
         return sFallback->unregisterBuffer(sFallback, handle);
     }
@@ -1086,7 +1055,6 @@ static int gralloc_unregister_buffer(gralloc_module_t const* module,
 
     if (cb->hostHandle && !cb->hasRefcountPipe()) {
         D("Closing host ColorBuffer 0x%x\n", cb->hostHandle);
-        DEFINE_AND_VALIDATE_HOST_CONNECTION;
         hostCon->lock();
         rcEnc->rcCloseColorBuffer(rcEnc, cb->hostHandle);
 
@@ -1110,12 +1078,8 @@ static int gralloc_unregister_buffer(gralloc_module_t const* module,
     // (through register_buffer)
     //
     if (cb->ashmemSize > 0 && cb->mappedPid == getpid()) {
-
-        PUT_ASHMEM_REGION(cb);
-        put_gralloc_dmaregion(cb->ashmemSize);
-
-        if (!SHOULD_UNMAP) goto done;
-
+        const bool should_unmap = put_ashmem_region(rcEnc, cb);
+        if (!should_unmap) goto done;
 
         void *vaddr;
         int err = munmap((void *)cb->ashmemBase, cb->ashmemSize);
@@ -1133,8 +1097,6 @@ done:
     return 0;
 }
 
-
-
 static int gralloc_lock(gralloc_module_t const* module,
                         buffer_handle_t handle, int usage,
                         int l, int t, int w, int h,
@@ -1454,12 +1416,10 @@ static int gralloc_device_open(const hw_module_t* module,
         //
         // Allocate memory for the gralloc device (alloc interface)
         //
-        gralloc_device_t *dev;
-        dev = (gralloc_device_t*)malloc(sizeof(gralloc_device_t));
+        gralloc_device_t *dev = new gralloc_device_t;
         if (NULL == dev) {
             return -ENOMEM;
         }
-        memset(dev, 0, sizeof(gralloc_device_t));
 
         // Initialize our device structure
         //
@@ -1470,7 +1430,6 @@ static int gralloc_device_open(const hw_module_t* module,
 
         dev->device.alloc   = gralloc_alloc;
         dev->device.free    = gralloc_free;
-        dev->allocListHead  = NULL;
         pthread_mutex_init(&dev->lock, NULL);
 
         *device = &dev->device.common;
diff --git a/system/vulkan/func_table.cpp b/system/vulkan/func_table.cpp
index d5ebf2d3303865c40ce196bb97839c266126521a..14c8c323930fa65077df9a967f225108e52eab8f 100644
--- a/system/vulkan/func_table.cpp
+++ b/system/vulkan/func_table.cpp
@@ -1021,7 +1021,8 @@ static VkResult entry_vkBeginCommandBuffer(
     AEMU_SCOPED_TRACE("vkBeginCommandBuffer");
     auto vkEnc = HostConnection::get()->vkEncoder();
     VkResult vkBeginCommandBuffer_VkResult_return = (VkResult)0;
-    vkBeginCommandBuffer_VkResult_return = vkEnc->vkBeginCommandBuffer(commandBuffer, pBeginInfo);
+    auto resources = ResourceTracker::get();
+    vkBeginCommandBuffer_VkResult_return = resources->on_vkBeginCommandBuffer(vkEnc, VK_SUCCESS, commandBuffer, pBeginInfo);
     return vkBeginCommandBuffer_VkResult_return;
 }
 static VkResult entry_vkEndCommandBuffer(
@@ -1030,7 +1031,8 @@ static VkResult entry_vkEndCommandBuffer(
     AEMU_SCOPED_TRACE("vkEndCommandBuffer");
     auto vkEnc = HostConnection::get()->vkEncoder();
     VkResult vkEndCommandBuffer_VkResult_return = (VkResult)0;
-    vkEndCommandBuffer_VkResult_return = vkEnc->vkEndCommandBuffer(commandBuffer);
+    auto resources = ResourceTracker::get();
+    vkEndCommandBuffer_VkResult_return = resources->on_vkEndCommandBuffer(vkEnc, VK_SUCCESS, commandBuffer);
     return vkEndCommandBuffer_VkResult_return;
 }
 static VkResult entry_vkResetCommandBuffer(
@@ -1040,7 +1042,8 @@ static VkResult entry_vkResetCommandBuffer(
     AEMU_SCOPED_TRACE("vkResetCommandBuffer");
     auto vkEnc = HostConnection::get()->vkEncoder();
     VkResult vkResetCommandBuffer_VkResult_return = (VkResult)0;
-    vkResetCommandBuffer_VkResult_return = vkEnc->vkResetCommandBuffer(commandBuffer, flags);
+    auto resources = ResourceTracker::get();
+    vkResetCommandBuffer_VkResult_return = resources->on_vkResetCommandBuffer(vkEnc, VK_SUCCESS, commandBuffer, flags);
     return vkResetCommandBuffer_VkResult_return;
 }
 static void entry_vkCmdBindPipeline(
@@ -1655,7 +1658,8 @@ static VkResult entry_vkGetPhysicalDeviceImageFormatProperties2(
     AEMU_SCOPED_TRACE("vkGetPhysicalDeviceImageFormatProperties2");
     auto vkEnc = HostConnection::get()->vkEncoder();
     VkResult vkGetPhysicalDeviceImageFormatProperties2_VkResult_return = (VkResult)0;
-    vkGetPhysicalDeviceImageFormatProperties2_VkResult_return = vkEnc->vkGetPhysicalDeviceImageFormatProperties2(physicalDevice, pImageFormatInfo, pImageFormatProperties);
+    auto resources = ResourceTracker::get();
+    vkGetPhysicalDeviceImageFormatProperties2_VkResult_return = resources->on_vkGetPhysicalDeviceImageFormatProperties2(vkEnc, VK_SUCCESS, physicalDevice, pImageFormatInfo, pImageFormatProperties);
     return vkGetPhysicalDeviceImageFormatProperties2_VkResult_return;
 }
 static void entry_vkGetPhysicalDeviceQueueFamilyProperties2(
@@ -1754,7 +1758,8 @@ static void entry_vkUpdateDescriptorSetWithTemplate(
 {
     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,
@@ -2232,7 +2237,8 @@ static VkResult entry_vkGetPhysicalDeviceImageFormatProperties2KHR(
     AEMU_SCOPED_TRACE("vkGetPhysicalDeviceImageFormatProperties2KHR");
     auto vkEnc = HostConnection::get()->vkEncoder();
     VkResult vkGetPhysicalDeviceImageFormatProperties2KHR_VkResult_return = (VkResult)0;
-    vkGetPhysicalDeviceImageFormatProperties2KHR_VkResult_return = vkEnc->vkGetPhysicalDeviceImageFormatProperties2KHR(physicalDevice, pImageFormatInfo, pImageFormatProperties);
+    auto resources = ResourceTracker::get();
+    vkGetPhysicalDeviceImageFormatProperties2KHR_VkResult_return = resources->on_vkGetPhysicalDeviceImageFormatProperties2KHR(vkEnc, VK_SUCCESS, physicalDevice, pImageFormatInfo, pImageFormatProperties);
     return vkGetPhysicalDeviceImageFormatProperties2KHR_VkResult_return;
 }
 static void entry_vkGetPhysicalDeviceQueueFamilyProperties2KHR(
@@ -3704,6 +3710,51 @@ static VkResult entry_vkRegisterBufferColorBufferGOOGLE(
     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
+#ifdef VK_GOOGLE_async_command_buffers
+static void entry_vkBeginCommandBufferAsyncGOOGLE(
+    VkCommandBuffer commandBuffer,
+    const VkCommandBufferBeginInfo* pBeginInfo)
+{
+    AEMU_SCOPED_TRACE("vkBeginCommandBufferAsyncGOOGLE");
+    auto vkEnc = HostConnection::get()->vkEncoder();
+    vkEnc->vkBeginCommandBufferAsyncGOOGLE(commandBuffer, pBeginInfo);
+}
+static void entry_vkEndCommandBufferAsyncGOOGLE(
+    VkCommandBuffer commandBuffer)
+{
+    AEMU_SCOPED_TRACE("vkEndCommandBufferAsyncGOOGLE");
+    auto vkEnc = HostConnection::get()->vkEncoder();
+    vkEnc->vkEndCommandBufferAsyncGOOGLE(commandBuffer);
+}
+static void entry_vkResetCommandBufferAsyncGOOGLE(
+    VkCommandBuffer commandBuffer,
+    VkCommandBufferResetFlags flags)
+{
+    AEMU_SCOPED_TRACE("vkResetCommandBufferAsyncGOOGLE");
+    auto vkEnc = HostConnection::get()->vkEncoder();
+    vkEnc->vkResetCommandBufferAsyncGOOGLE(commandBuffer, flags);
+}
+#endif
 void* goldfish_vulkan_get_proc_address(const char* name){
 #ifdef VK_VERSION_1_0
     if (!strcmp(name, "vkCreateInstance"))
@@ -5114,6 +5165,26 @@ void* goldfish_vulkan_get_proc_address(const char* name){
     {
         return nullptr;
     }
+#endif
+#ifdef VK_GOOGLE_sized_descriptor_update_template
+    if (!strcmp(name, "vkUpdateDescriptorSetWithTemplateSizedGOOGLE"))
+    {
+        return nullptr;
+    }
+#endif
+#ifdef VK_GOOGLE_async_command_buffers
+    if (!strcmp(name, "vkBeginCommandBufferAsyncGOOGLE"))
+    {
+        return nullptr;
+    }
+    if (!strcmp(name, "vkEndCommandBufferAsyncGOOGLE"))
+    {
+        return nullptr;
+    }
+    if (!strcmp(name, "vkResetCommandBufferAsyncGOOGLE"))
+    {
+        return nullptr;
+    }
 #endif
     return nullptr;
 }
@@ -6684,6 +6755,30 @@ void* goldfish_vulkan_get_instance_proc_address(VkInstance instance, const char*
         bool hasExt = resources->hasInstanceExtension(instance, "VK_GOOGLE_color_buffer");
         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
+#ifdef VK_GOOGLE_async_command_buffers
+    if (!strcmp(name, "vkBeginCommandBufferAsyncGOOGLE"))
+    {
+        bool hasExt = resources->hasInstanceExtension(instance, "VK_GOOGLE_async_command_buffers");
+        return hasExt ? (void*)entry_vkBeginCommandBufferAsyncGOOGLE : nullptr;
+    }
+    if (!strcmp(name, "vkEndCommandBufferAsyncGOOGLE"))
+    {
+        bool hasExt = resources->hasInstanceExtension(instance, "VK_GOOGLE_async_command_buffers");
+        return hasExt ? (void*)entry_vkEndCommandBufferAsyncGOOGLE : nullptr;
+    }
+    if (!strcmp(name, "vkResetCommandBufferAsyncGOOGLE"))
+    {
+        bool hasExt = resources->hasInstanceExtension(instance, "VK_GOOGLE_async_command_buffers");
+        return hasExt ? (void*)entry_vkResetCommandBufferAsyncGOOGLE : nullptr;
+    }
 #endif
     return nullptr;
 }
@@ -8254,6 +8349,30 @@ void* goldfish_vulkan_get_device_proc_address(VkDevice device, const char* name)
         bool hasExt = resources->hasDeviceExtension(device, "VK_GOOGLE_color_buffer");
         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
+#ifdef VK_GOOGLE_async_command_buffers
+    if (!strcmp(name, "vkBeginCommandBufferAsyncGOOGLE"))
+    {
+        bool hasExt = resources->hasDeviceExtension(device, "VK_GOOGLE_async_command_buffers");
+        return hasExt ? (void*)entry_vkBeginCommandBufferAsyncGOOGLE : nullptr;
+    }
+    if (!strcmp(name, "vkEndCommandBufferAsyncGOOGLE"))
+    {
+        bool hasExt = resources->hasDeviceExtension(device, "VK_GOOGLE_async_command_buffers");
+        return hasExt ? (void*)entry_vkEndCommandBufferAsyncGOOGLE : nullptr;
+    }
+    if (!strcmp(name, "vkResetCommandBufferAsyncGOOGLE"))
+    {
+        bool hasExt = resources->hasDeviceExtension(device, "VK_GOOGLE_async_command_buffers");
+        return hasExt ? (void*)entry_vkResetCommandBufferAsyncGOOGLE : nullptr;
+    }
 #endif
     return nullptr;
 }
diff --git a/system/vulkan/func_table.h b/system/vulkan/func_table.h
index 3dbca4c17efc2b6d54cdcc44d7eecc6c0e319629..4d0e977d880c47cd5953204b69896a6f0766d0b9 100644
--- a/system/vulkan/func_table.h
+++ b/system/vulkan/func_table.h
@@ -280,6 +280,10 @@ namespace goldfish_vk {
 #endif
 #ifdef VK_GOOGLE_color_buffer
 #endif
+#ifdef VK_GOOGLE_sized_descriptor_update_template
+#endif
+#ifdef VK_GOOGLE_async_command_buffers
+#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 2ba151182f13db4311cd7239b541267e7a65efba..18a9424580b0ec4f5c0580063822eef1e49b2b87 100644
--- a/system/vulkan/goldfish_vulkan.cpp
+++ b/system/vulkan/goldfish_vulkan.cpp
@@ -105,24 +105,36 @@ EnumeratePhysicalDeviceGroups(VkInstance /*instance*/,
 
 #ifdef VK_USE_PLATFORM_FUCHSIA
 VkResult
-GetMemoryFuchsiaHandleKHR(VkDevice /*device*/,
-                          const VkMemoryGetFuchsiaHandleInfoKHR* /*pInfo*/,
-                          uint32_t* pHandle) {
+GetMemoryZirconHandleFUCHSIA(VkDevice /*device*/,
+                             const VkMemoryGetZirconHandleInfoFUCHSIA* /*pInfo*/,
+                             uint32_t* pHandle) {
+    AEMU_SCOPED_TRACE("vkstubhal::GetMemoryZirconHandleFUCHSIA");
     *pHandle = 0;
     return VK_SUCCESS;
 }
 
 VkResult
-GetSemaphoreFuchsiaHandleKHR(VkDevice /*device*/,
-                             const VkSemaphoreGetFuchsiaHandleInfoKHR* /*pInfo*/,
-                             uint32_t* pHandle) {
+GetMemoryZirconHandlePropertiesFUCHSIA(VkDevice /*device*/,
+                                       VkExternalMemoryHandleTypeFlagBits /*handleType*/,
+                                       uint32_t /*handle*/,
+                                       VkMemoryZirconHandlePropertiesFUCHSIA* /*pProperties*/) {
+    AEMU_SCOPED_TRACE("vkstubhal::GetMemoryZirconHandlePropertiesFUCHSIA");
+    return VK_SUCCESS;
+}
+
+VkResult
+GetSemaphoreZirconHandleFUCHSIA(VkDevice /*device*/,
+                                const VkSemaphoreGetZirconHandleInfoFUCHSIA* /*pInfo*/,
+                                uint32_t* pHandle) {
+    AEMU_SCOPED_TRACE("vkstubhal::GetSemaphoreZirconHandleFUCHSIA");
     *pHandle = 0;
     return VK_SUCCESS;
 }
 
 VkResult
-ImportSemaphoreFuchsiaHandleKHR(VkDevice /*device*/,
-                                const VkImportSemaphoreFuchsiaHandleInfoKHR* /*pInfo*/) {
+ImportSemaphoreZirconHandleFUCHSIA(VkDevice /*device*/,
+                                   const VkImportSemaphoreZirconHandleInfoFUCHSIA* /*pInfo*/) {
+    AEMU_SCOPED_TRACE("vkstubhal::ImportSemaphoreZirconHandleFUCHSIA");
     return VK_SUCCESS;
 }
 
@@ -131,18 +143,22 @@ CreateBufferCollectionFUCHSIA(VkDevice /*device*/,
                               const VkBufferCollectionCreateInfoFUCHSIA* /*pInfo*/,
                               const VkAllocationCallbacks* /*pAllocator*/,
                               VkBufferCollectionFUCHSIA* /*pCollection*/) {
+    AEMU_SCOPED_TRACE("vkstubhal::CreateBufferCollectionFUCHSIA");
     return VK_SUCCESS;
 }
 
-void DestroyBufferCollectionFUCHSIA(VkDevice /*device*/,
-                                    VkBufferCollectionFUCHSIA /*collection*/,
-                                    const VkAllocationCallbacks* /*pAllocator*/) {
+void
+DestroyBufferCollectionFUCHSIA(VkDevice /*device*/,
+                               VkBufferCollectionFUCHSIA /*collection*/,
+                               const VkAllocationCallbacks* /*pAllocator*/) {
+    AEMU_SCOPED_TRACE("vkstubhal::DestroyBufferCollectionFUCHSIA");
 }
 
 VkResult
 SetBufferCollectionConstraintsFUCHSIA(VkDevice /*device*/,
                                       VkBufferCollectionFUCHSIA /*collection*/,
                                       const VkImageCreateInfo* /*pImageInfo*/) {
+    AEMU_SCOPED_TRACE("vkstubhal::SetBufferCollectionConstraintsFUCHSIA");
     return VK_SUCCESS;
 }
 #endif
@@ -165,12 +181,14 @@ PFN_vkVoidFunction GetInstanceProcAddr(VkInstance instance,
     if (strcmp(name, "vkGetInstanceProcAddr") == 0)
         return reinterpret_cast<PFN_vkVoidFunction>(GetInstanceProcAddr);
 #ifdef VK_USE_PLATFORM_FUCHSIA
-    if (strcmp(name, "vkGetMemoryFuchsiaHandleKHR") == 0)
-        return reinterpret_cast<PFN_vkVoidFunction>(GetMemoryFuchsiaHandleKHR);
-    if (strcmp(name, "vkGetSemaphoreFuchsiaHandleKHR") == 0)
-        return reinterpret_cast<PFN_vkVoidFunction>(GetSemaphoreFuchsiaHandleKHR);
-    if (strcmp(name, "vkImportSemaphoreFuchsiaHandleKHR") == 0)
-        return reinterpret_cast<PFN_vkVoidFunction>(ImportSemaphoreFuchsiaHandleKHR);
+    if (strcmp(name, "vkGetMemoryZirconHandleFUCHSIA") == 0)
+        return reinterpret_cast<PFN_vkVoidFunction>(GetMemoryZirconHandleFUCHSIA);
+    if (strcmp(name, "vkGetMemoryZirconHandlePropertiesFUCHSIA") == 0)
+        return reinterpret_cast<PFN_vkVoidFunction>(GetMemoryZirconHandlePropertiesFUCHSIA);
+    if (strcmp(name, "vkGetSemaphoreZirconHandleFUCHSIA") == 0)
+        return reinterpret_cast<PFN_vkVoidFunction>(GetSemaphoreZirconHandleFUCHSIA);
+    if (strcmp(name, "vkImportSemaphoreZirconHandleFUCHSIA") == 0)
+        return reinterpret_cast<PFN_vkVoidFunction>(ImportSemaphoreZirconHandleFUCHSIA);
     if (strcmp(name, "vkCreateBufferCollectionFUCHSIA") == 0)
         return reinterpret_cast<PFN_vkVoidFunction>(CreateBufferCollectionFUCHSIA);
     if (strcmp(name, "vkDestroyBufferCollectionFUCHSIA") == 0)
@@ -278,20 +296,20 @@ VkResult CreateInstance(const VkInstanceCreateInfo* create_info,
 
 #ifdef VK_USE_PLATFORM_FUCHSIA
 VKAPI_ATTR
-VkResult GetMemoryFuchsiaHandleKHR(
+VkResult GetMemoryZirconHandleFUCHSIA(
     VkDevice device,
-    const VkMemoryGetFuchsiaHandleInfoKHR* pInfo,
+    const VkMemoryGetZirconHandleInfoFUCHSIA* pInfo,
     uint32_t* pHandle) {
-    AEMU_SCOPED_TRACE("goldfish_vulkan::GetMemoryFuchsiaHandleKHR");
+    AEMU_SCOPED_TRACE("goldfish_vulkan::GetMemoryZirconHandleFUCHSIA");
 
     VK_HOST_CONNECTION(VK_ERROR_DEVICE_LOST)
 
     if (!hostSupportsVulkan) {
-        return vkstubhal::GetMemoryFuchsiaHandleKHR(device, pInfo, pHandle);
+        return vkstubhal::GetMemoryZirconHandleFUCHSIA(device, pInfo, pHandle);
     }
 
     VkResult res = goldfish_vk::ResourceTracker::get()->
-        on_vkGetMemoryFuchsiaHandleKHR(
+        on_vkGetMemoryZirconHandleFUCHSIA(
             vkEnc, VK_SUCCESS,
             device, pInfo, pHandle);
 
@@ -299,39 +317,61 @@ VkResult GetMemoryFuchsiaHandleKHR(
 }
 
 VKAPI_ATTR
-VkResult GetSemaphoreFuchsiaHandleKHR(
+VkResult GetMemoryZirconHandlePropertiesFUCHSIA(
+    VkDevice device,
+    VkExternalMemoryHandleTypeFlagBits handleType,
+    uint32_t handle,
+    VkMemoryZirconHandlePropertiesFUCHSIA* pProperties) {
+    AEMU_SCOPED_TRACE("goldfish_vulkan::GetMemoryZirconHandlePropertiesFUCHSIA");
+
+    VK_HOST_CONNECTION(VK_ERROR_DEVICE_LOST)
+
+    if (!hostSupportsVulkan) {
+        return vkstubhal::GetMemoryZirconHandlePropertiesFUCHSIA(
+            device, handleType, handle, pProperties);
+    }
+
+    VkResult res = goldfish_vk::ResourceTracker::get()->
+        on_vkGetMemoryZirconHandlePropertiesFUCHSIA(
+            vkEnc, VK_SUCCESS, device, handleType, handle, pProperties);
+
+    return res;
+}
+
+VKAPI_ATTR
+VkResult GetSemaphoreZirconHandleFUCHSIA(
     VkDevice device,
-    const VkSemaphoreGetFuchsiaHandleInfoKHR* pInfo,
+    const VkSemaphoreGetZirconHandleInfoFUCHSIA* pInfo,
     uint32_t* pHandle) {
-    AEMU_SCOPED_TRACE("goldfish_vulkan::GetSemaphoreFuchsiaHandleKHR");
+    AEMU_SCOPED_TRACE("goldfish_vulkan::GetSemaphoreZirconHandleFUCHSIA");
 
     VK_HOST_CONNECTION(VK_ERROR_DEVICE_LOST)
 
     if (!hostSupportsVulkan) {
-        return vkstubhal::GetSemaphoreFuchsiaHandleKHR(device, pInfo, pHandle);
+        return vkstubhal::GetSemaphoreZirconHandleFUCHSIA(device, pInfo, pHandle);
     }
 
     VkResult res = goldfish_vk::ResourceTracker::get()->
-        on_vkGetSemaphoreFuchsiaHandleKHR(
+        on_vkGetSemaphoreZirconHandleFUCHSIA(
             vkEnc, VK_SUCCESS, device, pInfo, pHandle);
 
     return res;
 }
 
 VKAPI_ATTR
-VkResult ImportSemaphoreFuchsiaHandleKHR(
+VkResult ImportSemaphoreZirconHandleFUCHSIA(
     VkDevice device,
-    const VkImportSemaphoreFuchsiaHandleInfoKHR* pInfo) {
-    AEMU_SCOPED_TRACE("goldfish_vulkan::ImportSemaphoreFuchsiaHandleKHR");
+    const VkImportSemaphoreZirconHandleInfoFUCHSIA* pInfo) {
+    AEMU_SCOPED_TRACE("goldfish_vulkan::ImportSemaphoreZirconHandleFUCHSIA");
 
     VK_HOST_CONNECTION(VK_ERROR_DEVICE_LOST)
 
     if (!hostSupportsVulkan) {
-        return vkstubhal::ImportSemaphoreFuchsiaHandleKHR(device, pInfo);
+        return vkstubhal::ImportSemaphoreZirconHandleFUCHSIA(device, pInfo);
     }
 
     VkResult res = goldfish_vk::ResourceTracker::get()->
-        on_vkImportSemaphoreFuchsiaHandleKHR(
+        on_vkImportSemaphoreZirconHandleFUCHSIA(
             vkEnc, VK_SUCCESS, device, pInfo);
 
     return res;
@@ -408,14 +448,17 @@ static PFN_vkVoidFunction GetDeviceProcAddr(VkDevice device, const char* name) {
     }
 
 #ifdef VK_USE_PLATFORM_FUCHSIA
-    if (!strcmp(name, "vkGetMemoryFuchsiaHandleKHR")) {
-        return (PFN_vkVoidFunction)GetMemoryFuchsiaHandleKHR;
+    if (!strcmp(name, "vkGetMemoryZirconHandleFUCHSIA")) {
+        return (PFN_vkVoidFunction)GetMemoryZirconHandleFUCHSIA;
+    }
+    if (!strcmp(name, "vkGetMemoryZirconHandlePropertiesFUCHSIA")) {
+        return (PFN_vkVoidFunction)GetMemoryZirconHandlePropertiesFUCHSIA;
     }
-    if (!strcmp(name, "vkGetSemaphoreFuchsiaHandleKHR")) {
-        return (PFN_vkVoidFunction)GetSemaphoreFuchsiaHandleKHR;
+    if (!strcmp(name, "vkGetSemaphoreZirconHandleFUCHSIA")) {
+        return (PFN_vkVoidFunction)GetSemaphoreZirconHandleFUCHSIA;
     }
-    if (!strcmp(name, "vkImportSemaphoreFuchsiaHandleKHR")) {
-        return (PFN_vkVoidFunction)ImportSemaphoreFuchsiaHandleKHR;
+    if (!strcmp(name, "vkImportSemaphoreZirconHandleFUCHSIA")) {
+        return (PFN_vkVoidFunction)ImportSemaphoreZirconHandleFUCHSIA;
     }
     if (!strcmp(name, "vkCreateBufferCollectionFUCHSIA")) {
         return (PFN_vkVoidFunction)CreateBufferCollectionFUCHSIA;
diff --git a/system/vulkan_enc/AndroidHardwareBuffer.cpp b/system/vulkan_enc/AndroidHardwareBuffer.cpp
index 620159d74a04417f023ef85f478c1be5566bfce2..a4478306863e15006d8e578f92edce2a8a7cbe59 100644
--- a/system/vulkan_enc/AndroidHardwareBuffer.cpp
+++ b/system/vulkan_enc/AndroidHardwareBuffer.cpp
@@ -24,8 +24,8 @@ namespace goldfish_vk {
 /* Construct ahw usage mask from image usage bits, see
  * 'AHardwareBuffer Usage Equivalence' in Vulkan spec.
  */
-static uint64_t
-goldfish_ahw_usage_from_vk_usage(const VkImageCreateFlags vk_create,
+uint64_t
+getAndroidHardwareBufferUsageFromVkUsage(const VkImageCreateFlags vk_create,
                                  const VkImageUsageFlags vk_usage)
 {
    uint64_t ahw_usage = 0;
@@ -208,7 +208,7 @@ VkResult createAndroidHardwareBuffer(
        h = imageExtent.height;
        layers = imageLayers;
        format = android_format_from_vk(imageFormat);
-       usage = goldfish_ahw_usage_from_vk_usage(imageCreateFlags, imageUsage);
+       usage = getAndroidHardwareBufferUsageFromVkUsage(imageCreateFlags, imageUsage);
     } else if (hasDedicatedBuffer) {
        w = bufferSize;
        format = AHARDWAREBUFFER_FORMAT_BLOB;
@@ -239,4 +239,4 @@ VkResult createAndroidHardwareBuffer(
     return VK_SUCCESS;
 }
 
-} // namespace goldfish_vk
\ No newline at end of file
+} // namespace goldfish_vk
diff --git a/system/vulkan_enc/AndroidHardwareBuffer.h b/system/vulkan_enc/AndroidHardwareBuffer.h
index fc6a27e195e391391e41a686dad1bbb935e90d88..81e8cd9191e5c7b97faffdd5303d777304b4eb96 100644
--- a/system/vulkan_enc/AndroidHardwareBuffer.h
+++ b/system/vulkan_enc/AndroidHardwareBuffer.h
@@ -24,6 +24,11 @@
 
 namespace goldfish_vk {
 
+uint64_t
+getAndroidHardwareBufferUsageFromVkUsage(
+    const VkImageCreateFlags vk_create,
+    const VkImageUsageFlags vk_usage);
+
 VkResult getAndroidHardwareBufferPropertiesANDROID(
     const HostVisibleMemoryVirtualizationInfo* hostMemVirtInfo,
     VkDevice device,
@@ -49,4 +54,4 @@ VkResult createAndroidHardwareBuffer(
     VkDeviceSize allocationInfoAllocSize,
     struct AHardwareBuffer **out);
 
-} // namespace goldfish_vk
\ No newline at end of file
+} // namespace goldfish_vk
diff --git a/system/vulkan_enc/ResourceTracker.cpp b/system/vulkan_enc/ResourceTracker.cpp
index af1db37bdf42f4fb8dd5a7b7ad9ac3e2b77b5929..01ad42b77cd9831a324bef06c3733eedf81ed255 100644
--- a/system/vulkan_enc/ResourceTracker.cpp
+++ b/system/vulkan_enc/ResourceTracker.cpp
@@ -26,18 +26,29 @@ typedef uint32_t zx_handle_t;
 void zx_handle_close(zx_handle_t) { }
 void zx_event_create(int, zx_handle_t*) { }
 
-typedef struct VkImportMemoryFuchsiaHandleInfoKHR {
+typedef struct VkImportMemoryZirconHandleInfoFUCHSIA {
     VkStructureType                       sType;
     const void*                           pNext;
     VkExternalMemoryHandleTypeFlagBits    handleType;
     uint32_t                              handle;
-} VkImportMemoryFuchsiaHandleInfoKHR;
+} VkImportMemoryZirconHandleInfoFUCHSIA;
 
-#define VK_STRUCTURE_TYPE_IMPORT_MEMORY_FUCHSIA_HANDLE_INFO_KHR \
+typedef uint32_t VkBufferCollectionFUCHSIA;
+
+typedef struct VkImportMemoryBufferCollectionFUCHSIA {
+    VkStructureType              sType;
+    const void*                  pNext;
+    VkBufferCollectionFUCHSIA    collection;
+    uint32_t                     index;
+} VkImportMemoryBufferCollectionFUCHSIA;
+
+#define VK_STRUCTURE_TYPE_IMPORT_MEMORY_BUFFER_COLLECTION_FUCHSIA \
     ((VkStructureType)1001000000)
-#define VK_EXTERNAL_MEMORY_HANDLE_TYPE_FUCHSIA_VMO_BIT_KHR \
+#define VK_STRUCTURE_TYPE_TEMP_IMPORT_MEMORY_ZIRCON_HANDLE_INFO_FUCHSIA \
+    ((VkStructureType)1001000000)
+#define VK_EXTERNAL_MEMORY_HANDLE_TYPE_TEMP_ZIRCON_VMO_BIT_FUCHSIA \
     ((VkStructureType)0x00000800)
-#define VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_FUCHSIA_FENCE_BIT_KHR \
+#define VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_TEMP_ZIRCON_EVENT_BIT_FUCHSIA \
     ((VkStructureType)0x00000020)
 
 #include "AndroidHardwareBuffer.h"
@@ -53,7 +64,6 @@ typedef struct VkImportMemoryFuchsiaHandleInfoKHR {
 #include <lib/fdio/fd.h>
 #include <lib/fdio/fdio.h>
 #include <lib/fdio/io.h>
-#include <lib/fzl/fdio.h>
 #include <lib/zx/channel.h>
 #include <zircon/process.h>
 #include <zircon/syscalls.h>
@@ -65,6 +75,12 @@ void AHardwareBuffer_release(AHardwareBuffer*) { }
 
 native_handle_t *AHardwareBuffer_getNativeHandle(AHardwareBuffer*) { return NULL; }
 
+uint64_t getAndroidHardwareBufferUsageFromVkUsage(
+    const VkImageCreateFlags vk_create,
+    const VkImageUsageFlags vk_usage) {
+  return AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE;
+}
+
 VkResult importAndroidHardwareBuffer(
     const VkImportAndroidHardwareBufferInfoANDROID* info,
     struct AHardwareBuffer **importOut) {
@@ -288,6 +304,17 @@ public:
         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; \
@@ -398,6 +425,10 @@ public:
         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);
@@ -563,6 +594,11 @@ public:
         return mHostVisibleMemoryVirtInfo.virtualizationSupported;
     }
 
+    bool supportsDeferredCommands() const {
+        if (!mFeatureInfo) return false;
+        return mFeatureInfo->hasDeferredVulkanCommands;
+    }
+
     int getHostInstanceExtensionIndex(const std::string& extName) const {
         int i = 0;
         for (const auto& prop : mHostInstanceExtensions) {
@@ -847,9 +883,8 @@ public:
 #endif
 #ifdef VK_USE_PLATFORM_FUCHSIA
             { "VK_KHR_external_memory", 1 },
-            { "VK_KHR_external_memory_fuchsia", 1 },
             { "VK_KHR_external_semaphore", 1 },
-            { "VK_KHR_external_semaphore_fuchsia", 1 },
+            { "VK_FUCHSIA_external_semaphore", 1 },
             { "VK_FUCHSIA_buffer_collection", 1 },
 #endif
         };
@@ -879,6 +914,11 @@ public:
             filteredExts.push_back({
                 "VK_ANDROID_external_memory_android_hardware_buffer", 7
             });
+#endif
+#ifdef VK_USE_PLATFORM_FUCHSIA
+            filteredExts.push_back({
+                "VK_FUCHSIA_external_memory", 1
+            });
 #endif
         }
 
@@ -1107,10 +1147,10 @@ public:
     }
 
 #ifdef VK_USE_PLATFORM_FUCHSIA
-    VkResult on_vkGetMemoryFuchsiaHandleKHR(
+    VkResult on_vkGetMemoryZirconHandleFUCHSIA(
         void*, VkResult,
         VkDevice device,
-        const VkMemoryGetFuchsiaHandleInfoKHR* pInfo,
+        const VkMemoryGetZirconHandleInfoFUCHSIA* pInfo,
         uint32_t* pHandle) {
 
         if (!pInfo) return VK_ERROR_INITIALIZATION_FAILED;
@@ -1142,20 +1182,44 @@ public:
         return VK_SUCCESS;
     }
 
-    VkResult on_vkGetMemoryFuchsiaHandlePropertiesKHR(
+    VkResult on_vkGetMemoryZirconHandlePropertiesFUCHSIA(
         void*, VkResult,
         VkDevice device,
-        VkExternalMemoryHandleTypeFlagBitsKHR handleType,
+        VkExternalMemoryHandleTypeFlagBits handleType,
         uint32_t handle,
-        VkMemoryFuchsiaHandlePropertiesKHR* pProperties) {
-        ALOGW("%s", __FUNCTION__);
-        return VK_ERROR_INITIALIZATION_FAILED;
+        VkMemoryZirconHandlePropertiesFUCHSIA* pProperties) {
+        if (handleType != VK_EXTERNAL_MEMORY_HANDLE_TYPE_TEMP_ZIRCON_VMO_BIT_FUCHSIA) {
+            return VK_ERROR_INITIALIZATION_FAILED;
+        }
+        if (pProperties->sType != VK_STRUCTURE_TYPE_TEMP_MEMORY_ZIRCON_HANDLE_PROPERTIES_FUCHSIA) {
+            return VK_ERROR_INITIALIZATION_FAILED;
+        }
+
+        AutoLock lock(mLock);
+
+        auto deviceIt = info_VkDevice.find(device);
+
+        if (deviceIt == info_VkDevice.end()) {
+            return VK_ERROR_INITIALIZATION_FAILED;
+        }
+
+        auto& info = deviceIt->second;
+
+        // Device local memory type supported.
+        pProperties->memoryTypeBits = 0;
+        for (uint32_t i = 0; i < info.memProps.memoryTypeCount; ++i) {
+            if (info.memProps.memoryTypes[i].propertyFlags &
+                VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT) {
+                pProperties->memoryTypeBits = 1ull << i;
+            }
+        }
+        return VK_SUCCESS;
     }
 
-    VkResult on_vkImportSemaphoreFuchsiaHandleKHR(
+    VkResult on_vkImportSemaphoreZirconHandleFUCHSIA(
         void*, VkResult,
         VkDevice device,
-        const VkImportSemaphoreFuchsiaHandleInfoKHR* pInfo) {
+        const VkImportSemaphoreZirconHandleInfoFUCHSIA* pInfo) {
 
         if (!pInfo) return VK_ERROR_INITIALIZATION_FAILED;
         if (!pInfo->semaphore) return VK_ERROR_INITIALIZATION_FAILED;
@@ -1184,10 +1248,10 @@ public:
         return VK_SUCCESS;
     }
 
-    VkResult on_vkGetSemaphoreFuchsiaHandleKHR(
+    VkResult on_vkGetSemaphoreZirconHandleFUCHSIA(
         void*, VkResult,
         VkDevice device,
-        const VkSemaphoreGetFuchsiaHandleInfoKHR* pInfo,
+        const VkSemaphoreGetZirconHandleInfoFUCHSIA* pInfo,
         uint32_t* pHandle) {
 
         if (!pInfo) return VK_ERROR_INITIALIZATION_FAILED;
@@ -1235,7 +1299,7 @@ public:
         }
         auto sysmem_collection = new fuchsia::sysmem::BufferCollectionSyncPtr;
         zx_status_t status = mSysmemAllocator->BindSharedCollection(
-            token, sysmem_collection->NewRequest());
+            std::move(token), sysmem_collection->NewRequest());
         if (status != ZX_OK) {
             ALOGE("BindSharedCollection failed: %d", status);
             return VK_ERROR_INITIALIZATION_FAILED;
@@ -1434,9 +1498,9 @@ public:
         VkImportColorBufferGOOGLE importCbInfo = {
             VK_STRUCTURE_TYPE_IMPORT_COLOR_BUFFER_GOOGLE, 0,
         };
-        VkImportPhysicalAddressGOOGLE importPhysAddrInfo = {
-            VK_STRUCTURE_TYPE_IMPORT_PHYSICAL_ADDRESS_GOOGLE, 0,
-        };
+        // VkImportPhysicalAddressGOOGLE importPhysAddrInfo = {
+        //     VK_STRUCTURE_TYPE_IMPORT_PHYSICAL_ADDRESS_GOOGLE, 0,
+        // };
 
         vk_struct_common* structChain =
         structChain = vk_init_struct_chain(
@@ -1451,9 +1515,13 @@ public:
             (VkImportAndroidHardwareBufferInfoANDROID*)vk_find_struct((vk_struct_common*)pAllocateInfo,
                 VK_STRUCTURE_TYPE_IMPORT_ANDROID_HARDWARE_BUFFER_INFO_ANDROID);
 
-        VkImportMemoryFuchsiaHandleInfoKHR* importPhysAddrInfoPtr =
-            (VkImportMemoryFuchsiaHandleInfoKHR*)vk_find_struct((vk_struct_common*)pAllocateInfo,
-                VK_STRUCTURE_TYPE_IMPORT_MEMORY_FUCHSIA_HANDLE_INFO_KHR);
+        VkImportMemoryBufferCollectionFUCHSIA* importBufferCollectionInfoPtr =
+            (VkImportMemoryBufferCollectionFUCHSIA*)vk_find_struct((vk_struct_common*)pAllocateInfo,
+                VK_STRUCTURE_TYPE_IMPORT_MEMORY_BUFFER_COLLECTION_FUCHSIA);
+
+        VkImportMemoryZirconHandleInfoFUCHSIA* importVmoInfoPtr =
+            (VkImportMemoryZirconHandleInfoFUCHSIA*)vk_find_struct((vk_struct_common*)pAllocateInfo,
+                VK_STRUCTURE_TYPE_TEMP_IMPORT_MEMORY_ZIRCON_HANDLE_INFO_FUCHSIA);
 
         VkMemoryDedicatedAllocateInfo* dedicatedAllocInfoPtr =
             (VkMemoryDedicatedAllocateInfo*)vk_find_struct((vk_struct_common*)pAllocateInfo,
@@ -1462,13 +1530,14 @@ public:
         bool shouldPassThroughDedicatedAllocInfo =
             !exportAllocateInfoPtr &&
             !importAhbInfoPtr &&
-            !importPhysAddrInfoPtr &&
+            !importBufferCollectionInfoPtr &&
+            !importVmoInfoPtr &&
             !isHostVisibleMemoryTypeIndexForGuest(
                 &mHostVisibleMemoryVirtInfo,
                 pAllocateInfo->memoryTypeIndex);
 
         if (!exportAllocateInfoPtr &&
-            (importAhbInfoPtr || importPhysAddrInfoPtr) &&
+            (importAhbInfoPtr || importBufferCollectionInfoPtr || importVmoInfoPtr) &&
             dedicatedAllocInfoPtr &&
             isHostVisibleMemoryTypeIndexForGuest(
                 &mHostVisibleMemoryVirtInfo,
@@ -1490,11 +1559,11 @@ public:
 
         // State needed for import/export.
         bool exportAhb = false;
-        bool exportPhysAddr = false;
+        bool exportVmo = false;
         bool importAhb = false;
-        bool importPhysAddr = false;
-        (void)exportPhysAddr;
-        (void)importPhysAddr;
+        bool importBufferCollection = false;
+        bool importVmo = false;
+        (void)exportVmo;
 
         // Even if we export allocate, the underlying operation
         // for the host is always going to be an import operation.
@@ -1513,13 +1582,15 @@ public:
             exportAhb =
                 exportAllocateInfoPtr->handleTypes &
                 VK_EXTERNAL_MEMORY_HANDLE_TYPE_ANDROID_HARDWARE_BUFFER_BIT_ANDROID;
-            exportPhysAddr =
+            exportVmo =
                 exportAllocateInfoPtr->handleTypes &
-                VK_EXTERNAL_MEMORY_HANDLE_TYPE_FUCHSIA_VMO_BIT_KHR;
+                VK_EXTERNAL_MEMORY_HANDLE_TYPE_TEMP_ZIRCON_VMO_BIT_FUCHSIA;
         } else if (importAhbInfoPtr) {
             importAhb = true;
-        } else if (importPhysAddrInfoPtr) {
-            importPhysAddr = true;
+        } else if (importBufferCollectionInfoPtr) {
+            importBufferCollection = true;
+        } else if (importVmoInfoPtr) {
+            importVmo = true;
         }
 
         if (exportAhb) {
@@ -1600,8 +1671,33 @@ public:
                 vk_append_struct(structChain, (vk_struct_common*)(&importCbInfo));
         }
 
-        if (importPhysAddr) {
-            vmo_handle = importPhysAddrInfoPtr->handle;
+        if (importBufferCollection) {
+
+#ifdef VK_USE_PLATFORM_FUCHSIA
+            auto collection = reinterpret_cast<fuchsia::sysmem::BufferCollectionSyncPtr*>(
+                importBufferCollectionInfoPtr->collection);
+            fuchsia::sysmem::BufferCollectionInfo_2 info;
+            zx_status_t status2;
+            zx_status_t status = (*collection)->WaitForBuffersAllocated(&status2, &info);
+            if (status != ZX_OK || status2 != ZX_OK) {
+                ALOGE("WaitForBuffersAllocated failed: %d %d", status);
+                return VK_ERROR_INITIALIZATION_FAILED;
+            }
+            uint32_t index = importBufferCollectionInfoPtr->index;
+            if (info.buffer_count < index) {
+                ALOGE("Invalid buffer index: %d %d", index);
+                return VK_ERROR_INITIALIZATION_FAILED;
+            }
+            vmo_handle = info.buffers[index].vmo.release();
+#endif
+
+        }
+
+        if (importVmo) {
+            vmo_handle = importVmoInfoPtr->handle;
+        }
+
+        if (vmo_handle != ZX_HANDLE_INVALID) {
             uint64_t cb = 0;
 
 #ifdef VK_USE_PLATFORM_FUCHSIA
@@ -1615,7 +1711,7 @@ public:
             }
         }
 
-        // TODO if (exportPhysAddr) { }
+        // TODO if (exportVmo) { }
 
         if (!isHostVisibleMemoryTypeIndexForGuest(
                 &mHostVisibleMemoryVirtInfo,
@@ -1686,12 +1782,12 @@ public:
 
         // Host visible memory with direct mapping via
         // VkImportPhysicalAddressGOOGLE
-        if (importPhysAddr) {
+        // if (importPhysAddr) {
             // vkAllocateMemory(device, &finalAllocInfo, pAllocator, pMemory);
             //    host maps the host pointer to the guest physical address
             // TODO: the host side page offset of the
             // host pointer needs to be returned somehow.
-        }
+        // }
 
         // Host visible memory with direct mapping
         AutoLock lock(mLock);
@@ -2006,6 +2102,12 @@ public:
         vk_find_struct(
             (vk_struct_common*)pCreateInfo_mut,
             VK_STRUCTURE_TYPE_FUCHSIA_IMAGE_FORMAT_FUCHSIA);
+
+        VkBufferCollectionImageCreateInfoFUCHSIA* extBufferCollectionPtr =
+        (VkBufferCollectionImageCreateInfoFUCHSIA*)
+        vk_find_struct(
+            (vk_struct_common*)pCreateInfo_mut,
+            VK_STRUCTURE_TYPE_BUFFER_COLLECTION_IMAGE_CREATE_INFO_FUCHSIA);
 #endif
 
         vk_struct_common* structChain =
@@ -2058,7 +2160,22 @@ public:
                 abort();
             }
             pCreateInfo_mut->pNext = &native_info;
-            if (extFuchsiaImageFormatPtr) {
+
+            bool is_physically_contiguous = false;
+            if (extBufferCollectionPtr) {
+               auto collection = reinterpret_cast<fuchsia::sysmem::BufferCollectionSyncPtr*>(
+                   extBufferCollectionPtr->collection);
+               fuchsia::sysmem::BufferCollectionInfo_2 info;
+               zx_status_t status2;
+               zx_status_t status = (*collection)->WaitForBuffersAllocated(&status2, &info);
+               if (status == ZX_OK && status2 == ZX_OK) {
+                   is_physically_contiguous =
+                       info.settings.has_image_format_constraints &&
+                       info.settings.buffer_settings.is_physically_contiguous;
+               } else {
+                   ALOGE("WaitForBuffersAllocated failed: %d %d", status, status2);
+               }
+            } else if (extFuchsiaImageFormatPtr) {
                 auto imageFormat = static_cast<const uint8_t*>(
                     extFuchsiaImageFormatPtr->imageFormat);
                 size_t imageFormatSize =
@@ -2081,14 +2198,17 @@ public:
                 fuchsia::sysmem::SingleBufferSettings settings;
                 fuchsia::sysmem::SingleBufferSettings::Decode(
                     &decoder, &settings, 0);
-                if (settings.buffer_settings.is_physically_contiguous) {
-                    // Replace the local image pCreateInfo_mut format
-                    // with the color buffer format if physically contiguous
-                    // and a potential display layer candidate.
-                    // TODO(reveman): Remove this after adding BGRA color
-                    // buffer support.
-                    pCreateInfo_mut->format = VK_FORMAT_R8G8B8A8_UNORM;
-                }
+                is_physically_contiguous =
+                    settings.buffer_settings.is_physically_contiguous;
+            }
+
+            if (is_physically_contiguous) {
+                // Replace the local image pCreateInfo_mut format
+                // with the color buffer format if physically contiguous
+                // and a potential display layer candidate.
+                // TODO(reveman): Remove this after adding BGRA color
+                // buffer support.
+                pCreateInfo_mut->format = VK_FORMAT_R8G8B8A8_UNORM;
             }
         }
 #endif
@@ -2406,19 +2526,13 @@ public:
                 VK_STRUCTURE_TYPE_EXPORT_SEMAPHORE_CREATE_INFO_KHR);
 
 #ifdef VK_USE_PLATFORM_FUCHSIA
-        // vk_init_struct_chain initializes pNext to nullptr
-        vk_struct_common* structChain = vk_init_struct_chain(
-            (vk_struct_common*)(&finalCreateInfo));
-
-        bool exportFence = false;
+        bool exportEvent = exportSemaphoreInfoPtr &&
+            (exportSemaphoreInfoPtr->handleTypes &
+             VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_TEMP_ZIRCON_EVENT_BIT_FUCHSIA);
 
-        if (exportSemaphoreInfoPtr) {
-            exportFence =
-                exportSemaphoreInfoPtr->handleTypes &
-                VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_FUCHSIA_FENCE_BIT_KHR;
-            // TODO: add host side export struct info.
+        if (exportEvent) {
+            finalCreateInfo.pNext = nullptr;
         }
-
 #endif
 
 #ifdef VK_USE_PLATFORM_ANDROID_KHR
@@ -2436,7 +2550,7 @@ public:
         zx_handle_t event_handle = ZX_HANDLE_INVALID;
 
 #ifdef VK_USE_PLATFORM_FUCHSIA
-        if (exportFence) {
+        if (exportEvent) {
             zx_event_create(0, &event_handle);
         }
 #endif
@@ -2788,6 +2902,291 @@ public:
         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());
+    }
+
+    VkResult on_vkGetPhysicalDeviceImageFormatProperties2_common(
+        bool isKhr,
+        void* context, VkResult input_result,
+        VkPhysicalDevice physicalDevice,
+        const VkPhysicalDeviceImageFormatInfo2* pImageFormatInfo,
+        VkImageFormatProperties2* pImageFormatProperties) {
+
+        VkEncoder* enc = (VkEncoder*)context;
+        (void)input_result;
+
+        VkAndroidHardwareBufferUsageANDROID* output_ahw_usage =
+            (VkAndroidHardwareBufferUsageANDROID*)vk_find_struct(
+                (vk_struct_common*)pImageFormatProperties,
+                VK_STRUCTURE_TYPE_ANDROID_HARDWARE_BUFFER_USAGE_ANDROID);
+
+        VkResult hostRes;
+
+        if (isKhr) {
+            hostRes = enc->vkGetPhysicalDeviceImageFormatProperties2KHR(
+                physicalDevice, pImageFormatInfo,
+                pImageFormatProperties);
+        } else {
+            hostRes = enc->vkGetPhysicalDeviceImageFormatProperties2(
+                physicalDevice, pImageFormatInfo,
+                pImageFormatProperties);
+        }
+
+        if (hostRes != VK_SUCCESS) return hostRes;
+
+        if (output_ahw_usage) {
+            output_ahw_usage->androidHardwareBufferUsage =
+                getAndroidHardwareBufferUsageFromVkUsage(
+                    pImageFormatInfo->flags,
+                    pImageFormatInfo->usage);
+        }
+
+        return hostRes;
+    }
+
+    VkResult on_vkGetPhysicalDeviceImageFormatProperties2(
+        void* context, VkResult input_result,
+        VkPhysicalDevice physicalDevice,
+        const VkPhysicalDeviceImageFormatInfo2* pImageFormatInfo,
+        VkImageFormatProperties2* pImageFormatProperties) {
+        return on_vkGetPhysicalDeviceImageFormatProperties2_common(
+            false /* not KHR */, context, input_result,
+            physicalDevice, pImageFormatInfo, pImageFormatProperties);
+    }
+
+    VkResult on_vkGetPhysicalDeviceImageFormatProperties2KHR(
+        void* context, VkResult input_result,
+        VkPhysicalDevice physicalDevice,
+        const VkPhysicalDeviceImageFormatInfo2* pImageFormatInfo,
+        VkImageFormatProperties2* pImageFormatProperties) {
+        return on_vkGetPhysicalDeviceImageFormatProperties2_common(
+            true /* is KHR */, context, input_result,
+            physicalDevice, pImageFormatInfo, pImageFormatProperties);
+    }
+
+    VkResult on_vkBeginCommandBuffer(
+        void* context, VkResult input_result,
+        VkCommandBuffer commandBuffer,
+        const VkCommandBufferBeginInfo* pBeginInfo) {
+
+        VkEncoder* enc = (VkEncoder*)context;
+        (void)input_result;
+
+        if (!supportsDeferredCommands()) {
+            return enc->vkBeginCommandBuffer(commandBuffer, pBeginInfo);
+        }
+
+        enc->vkBeginCommandBufferAsyncGOOGLE(commandBuffer, pBeginInfo);
+        return VK_SUCCESS;
+    }
+
+    VkResult on_vkEndCommandBuffer(
+        void* context, VkResult input_result,
+        VkCommandBuffer commandBuffer) {
+
+        VkEncoder* enc = (VkEncoder*)context;
+        (void)input_result;
+
+        if (!supportsDeferredCommands()) {
+            return enc->vkEndCommandBuffer(commandBuffer);
+        }
+
+        enc->vkEndCommandBufferAsyncGOOGLE(commandBuffer);
+        return VK_SUCCESS;
+    }
+
+    VkResult on_vkResetCommandBuffer(
+        void* context, VkResult input_result,
+        VkCommandBuffer commandBuffer,
+        VkCommandBufferResetFlags flags) {
+
+        VkEncoder* enc = (VkEncoder*)context;
+        (void)input_result;
+
+        if (!supportsDeferredCommands()) {
+            return enc->vkResetCommandBuffer(commandBuffer, flags);
+        }
+
+        enc->vkResetCommandBufferAsyncGOOGLE(commandBuffer, flags);
+        return VK_SUCCESS;
+    }
+
     uint32_t getApiVersionFromInstance(VkInstance instance) const {
         AutoLock lock(mLock);
         uint32_t api = kMinApiVersion;
@@ -3230,39 +3629,39 @@ void ResourceTracker::unwrap_vkAcquireImageANDROID_nativeFenceFd(int fd, int* fd
 }
 
 #ifdef VK_USE_PLATFORM_FUCHSIA
-VkResult ResourceTracker::on_vkGetMemoryFuchsiaHandleKHR(
+VkResult ResourceTracker::on_vkGetMemoryZirconHandleFUCHSIA(
     void* context, VkResult input_result,
     VkDevice device,
-    const VkMemoryGetFuchsiaHandleInfoKHR* pInfo,
+    const VkMemoryGetZirconHandleInfoFUCHSIA* pInfo,
     uint32_t* pHandle) {
-    return mImpl->on_vkGetMemoryFuchsiaHandleKHR(
+    return mImpl->on_vkGetMemoryZirconHandleFUCHSIA(
         context, input_result, device, pInfo, pHandle);
 }
 
-VkResult ResourceTracker::on_vkGetMemoryFuchsiaHandlePropertiesKHR(
+VkResult ResourceTracker::on_vkGetMemoryZirconHandlePropertiesFUCHSIA(
     void* context, VkResult input_result,
     VkDevice device,
-    VkExternalMemoryHandleTypeFlagBitsKHR handleType,
+    VkExternalMemoryHandleTypeFlagBits handleType,
     uint32_t handle,
-    VkMemoryFuchsiaHandlePropertiesKHR* pProperties) {
-    return mImpl->on_vkGetMemoryFuchsiaHandlePropertiesKHR(
+    VkMemoryZirconHandlePropertiesFUCHSIA* pProperties) {
+    return mImpl->on_vkGetMemoryZirconHandlePropertiesFUCHSIA(
         context, input_result, device, handleType, handle, pProperties);
 }
 
-VkResult ResourceTracker::on_vkGetSemaphoreFuchsiaHandleKHR(
+VkResult ResourceTracker::on_vkGetSemaphoreZirconHandleFUCHSIA(
     void* context, VkResult input_result,
     VkDevice device,
-    const VkSemaphoreGetFuchsiaHandleInfoKHR* pInfo,
+    const VkSemaphoreGetZirconHandleInfoFUCHSIA* pInfo,
     uint32_t* pHandle) {
-    return mImpl->on_vkGetSemaphoreFuchsiaHandleKHR(
+    return mImpl->on_vkGetSemaphoreZirconHandleFUCHSIA(
         context, input_result, device, pInfo, pHandle);
 }
 
-VkResult ResourceTracker::on_vkImportSemaphoreFuchsiaHandleKHR(
+VkResult ResourceTracker::on_vkImportSemaphoreZirconHandleFUCHSIA(
     void* context, VkResult input_result,
     VkDevice device,
-    const VkImportSemaphoreFuchsiaHandleInfoKHR* pInfo) {
-    return mImpl->on_vkImportSemaphoreFuchsiaHandleKHR(
+    const VkImportSemaphoreZirconHandleInfoFUCHSIA* pInfo) {
+    return mImpl->on_vkImportSemaphoreZirconHandleFUCHSIA(
         context, input_result, device, pInfo);
 }
 
@@ -3353,6 +3752,82 @@ VkResult ResourceTracker::on_vkMapMemoryIntoAddressSpaceGOOGLE(
         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);
+}
+
+VkResult ResourceTracker::on_vkGetPhysicalDeviceImageFormatProperties2(
+    void* context, VkResult input_result,
+    VkPhysicalDevice physicalDevice,
+    const VkPhysicalDeviceImageFormatInfo2* pImageFormatInfo,
+    VkImageFormatProperties2* pImageFormatProperties) {
+    return mImpl->on_vkGetPhysicalDeviceImageFormatProperties2(
+        context, input_result, physicalDevice, pImageFormatInfo,
+        pImageFormatProperties);
+}
+
+VkResult ResourceTracker::on_vkGetPhysicalDeviceImageFormatProperties2KHR(
+    void* context, VkResult input_result,
+    VkPhysicalDevice physicalDevice,
+    const VkPhysicalDeviceImageFormatInfo2* pImageFormatInfo,
+    VkImageFormatProperties2* pImageFormatProperties) {
+    return mImpl->on_vkGetPhysicalDeviceImageFormatProperties2KHR(
+        context, input_result, physicalDevice, pImageFormatInfo,
+        pImageFormatProperties);
+}
+
+VkResult ResourceTracker::on_vkBeginCommandBuffer(
+    void* context, VkResult input_result,
+    VkCommandBuffer commandBuffer,
+    const VkCommandBufferBeginInfo* pBeginInfo) {
+    return mImpl->on_vkBeginCommandBuffer(
+        context, input_result, commandBuffer, pBeginInfo);
+}
+
+VkResult ResourceTracker::on_vkEndCommandBuffer(
+    void* context, VkResult input_result,
+    VkCommandBuffer commandBuffer) {
+    return mImpl->on_vkEndCommandBuffer(
+        context, input_result, commandBuffer);
+}
+
+VkResult ResourceTracker::on_vkResetCommandBuffer(
+    void* context, VkResult input_result,
+    VkCommandBuffer commandBuffer,
+    VkCommandBufferResetFlags flags) {
+    return mImpl->on_vkResetCommandBuffer(
+        context, input_result, commandBuffer, flags);
+}
+
 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 a26c3a250d9878570dfbfeb1fd8697676fdd634e..200bfb6870dcb756d280eff4dfd080173ff822c8 100644
--- a/system/vulkan_enc/ResourceTracker.h
+++ b/system/vulkan_enc/ResourceTracker.h
@@ -213,26 +213,26 @@ public:
     void unwrap_vkAcquireImageANDROID_nativeFenceFd(int fd, int* fd_out);
 
 #ifdef VK_USE_PLATFORM_FUCHSIA
-    VkResult on_vkGetMemoryFuchsiaHandleKHR(
+    VkResult on_vkGetMemoryZirconHandleFUCHSIA(
         void* context, VkResult input_result,
         VkDevice device,
-        const VkMemoryGetFuchsiaHandleInfoKHR* pInfo,
+        const VkMemoryGetZirconHandleInfoFUCHSIA* pInfo,
         uint32_t* pHandle);
-    VkResult on_vkGetMemoryFuchsiaHandlePropertiesKHR(
+    VkResult on_vkGetMemoryZirconHandlePropertiesFUCHSIA(
         void* context, VkResult input_result,
         VkDevice device,
-        VkExternalMemoryHandleTypeFlagBitsKHR handleType,
+        VkExternalMemoryHandleTypeFlagBits handleType,
         uint32_t handle,
-        VkMemoryFuchsiaHandlePropertiesKHR* pProperties);
-    VkResult on_vkGetSemaphoreFuchsiaHandleKHR(
+        VkMemoryZirconHandlePropertiesFUCHSIA* pProperties);
+    VkResult on_vkGetSemaphoreZirconHandleFUCHSIA(
         void* context, VkResult input_result,
         VkDevice device,
-        const VkSemaphoreGetFuchsiaHandleInfoKHR* pInfo,
+        const VkSemaphoreGetZirconHandleInfoFUCHSIA* pInfo,
         uint32_t* pHandle);
-    VkResult on_vkImportSemaphoreFuchsiaHandleKHR(
+    VkResult on_vkImportSemaphoreZirconHandleFUCHSIA(
         void* context, VkResult input_result,
         VkDevice device,
-        const VkImportSemaphoreFuchsiaHandleInfoKHR* pInfo);
+        const VkImportSemaphoreZirconHandleInfoFUCHSIA* pInfo);
     VkResult on_vkCreateBufferCollectionFUCHSIA(
         void* context, VkResult input_result,
         VkDevice device,
@@ -288,6 +288,51 @@ public:
         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);
+
+    VkResult on_vkGetPhysicalDeviceImageFormatProperties2(
+        void* context, VkResult input_result,
+        VkPhysicalDevice physicalDevice,
+        const VkPhysicalDeviceImageFormatInfo2* pImageFormatInfo,
+        VkImageFormatProperties2* pImageFormatProperties);
+
+    VkResult on_vkGetPhysicalDeviceImageFormatProperties2KHR(
+        void* context, VkResult input_result,
+        VkPhysicalDevice physicalDevice,
+        const VkPhysicalDeviceImageFormatInfo2* pImageFormatInfo,
+        VkImageFormatProperties2* pImageFormatProperties);
+
+    VkResult on_vkBeginCommandBuffer(
+        void* context, VkResult input_result,
+        VkCommandBuffer commandBuffer,
+        const VkCommandBufferBeginInfo* pBeginInfo);
+    VkResult on_vkEndCommandBuffer(
+        void* context, VkResult input_result,
+        VkCommandBuffer commandBuffer);
+    VkResult on_vkResetCommandBuffer(
+        void* context, VkResult input_result,
+        VkCommandBuffer commandBuffer,
+        VkCommandBufferResetFlags flags);
+
     bool isMemoryTypeHostVisible(VkDevice device, uint32_t typeIndex) const;
     uint8_t* getMappedPointer(VkDeviceMemory memory);
     VkDeviceSize getMappedSize(VkDeviceMemory memory);
diff --git a/system/vulkan_enc/VkEncoder.cpp b/system/vulkan_enc/VkEncoder.cpp
index 4261d7179df20b636314d1c13baeece885ab71d3..b97f120e8650c9c3f4a5231c4b3a5654d5ed84bf 100644
--- a/system/vulkan_enc/VkEncoder.cpp
+++ b/system/vulkan_enc/VkEncoder.cpp
@@ -11086,6 +11086,7 @@ VkResult VkEncoder::vkCreateDescriptorUpdateTemplate(
     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 @@ VkResult VkEncoder::vkCreateDescriptorUpdateTemplateKHR(
     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;
 }
@@ -22260,6 +22262,358 @@ VkResult VkEncoder::vkRegisterBufferColorBufferGOOGLE(
     return vkRegisterBufferColorBufferGOOGLE_VkResult_return;
 }
 
+#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
+#ifdef VK_GOOGLE_async_command_buffers
+void VkEncoder::vkBeginCommandBufferAsyncGOOGLE(
+    VkCommandBuffer commandBuffer,
+    const VkCommandBufferBeginInfo* pBeginInfo)
+{
+    AEMU_SCOPED_TRACE("vkBeginCommandBufferAsyncGOOGLE encode");
+    mImpl->log("start vkBeginCommandBufferAsyncGOOGLE");
+    auto stream = mImpl->stream();
+    auto countingStream = mImpl->countingStream();
+    auto resources = mImpl->resources();
+    auto pool = mImpl->pool();
+    stream->setHandleMapping(resources->unwrapMapping());
+    VkCommandBuffer local_commandBuffer;
+    VkCommandBufferBeginInfo* local_pBeginInfo;
+    local_commandBuffer = commandBuffer;
+    local_pBeginInfo = nullptr;
+    if (pBeginInfo)
+    {
+        local_pBeginInfo = (VkCommandBufferBeginInfo*)pool->alloc(sizeof(const VkCommandBufferBeginInfo));
+        deepcopy_VkCommandBufferBeginInfo(pool, pBeginInfo, (VkCommandBufferBeginInfo*)(local_pBeginInfo));
+    }
+    if (local_pBeginInfo)
+    {
+        transform_tohost_VkCommandBufferBeginInfo(mImpl->resources(), (VkCommandBufferBeginInfo*)(local_pBeginInfo));
+    }
+    countingStream->rewind();
+    {
+        uint64_t cgen_var_1508;
+        countingStream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_1508, 1);
+        countingStream->write((uint64_t*)&cgen_var_1508, 1 * 8);
+        marshal_VkCommandBufferBeginInfo(countingStream, (VkCommandBufferBeginInfo*)(local_pBeginInfo));
+    }
+    uint32_t packetSize_vkBeginCommandBufferAsyncGOOGLE = 4 + 4 + (uint32_t)countingStream->bytesWritten();
+    countingStream->rewind();
+    uint32_t opcode_vkBeginCommandBufferAsyncGOOGLE = OP_vkBeginCommandBufferAsyncGOOGLE;
+    stream->write(&opcode_vkBeginCommandBufferAsyncGOOGLE, sizeof(uint32_t));
+    stream->write(&packetSize_vkBeginCommandBufferAsyncGOOGLE, sizeof(uint32_t));
+    uint64_t cgen_var_1509;
+    stream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_1509, 1);
+    stream->write((uint64_t*)&cgen_var_1509, 1 * 8);
+    marshal_VkCommandBufferBeginInfo(stream, (VkCommandBufferBeginInfo*)(local_pBeginInfo));
+    AEMU_SCOPED_TRACE("vkBeginCommandBufferAsyncGOOGLE readParams");
+    AEMU_SCOPED_TRACE("vkBeginCommandBufferAsyncGOOGLE returnUnmarshal");
+    mImpl->log("finish vkBeginCommandBufferAsyncGOOGLE");;
+}
+
+void VkEncoder::vkEndCommandBufferAsyncGOOGLE(
+    VkCommandBuffer commandBuffer)
+{
+    AEMU_SCOPED_TRACE("vkEndCommandBufferAsyncGOOGLE encode");
+    mImpl->log("start vkEndCommandBufferAsyncGOOGLE");
+    auto stream = mImpl->stream();
+    auto countingStream = mImpl->countingStream();
+    auto resources = mImpl->resources();
+    auto pool = mImpl->pool();
+    stream->setHandleMapping(resources->unwrapMapping());
+    VkCommandBuffer local_commandBuffer;
+    local_commandBuffer = commandBuffer;
+    countingStream->rewind();
+    {
+        uint64_t cgen_var_1510;
+        countingStream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_1510, 1);
+        countingStream->write((uint64_t*)&cgen_var_1510, 1 * 8);
+    }
+    uint32_t packetSize_vkEndCommandBufferAsyncGOOGLE = 4 + 4 + (uint32_t)countingStream->bytesWritten();
+    countingStream->rewind();
+    uint32_t opcode_vkEndCommandBufferAsyncGOOGLE = OP_vkEndCommandBufferAsyncGOOGLE;
+    stream->write(&opcode_vkEndCommandBufferAsyncGOOGLE, sizeof(uint32_t));
+    stream->write(&packetSize_vkEndCommandBufferAsyncGOOGLE, sizeof(uint32_t));
+    uint64_t cgen_var_1511;
+    stream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_1511, 1);
+    stream->write((uint64_t*)&cgen_var_1511, 1 * 8);
+    AEMU_SCOPED_TRACE("vkEndCommandBufferAsyncGOOGLE readParams");
+    AEMU_SCOPED_TRACE("vkEndCommandBufferAsyncGOOGLE returnUnmarshal");
+    mImpl->log("finish vkEndCommandBufferAsyncGOOGLE");;
+}
+
+void VkEncoder::vkResetCommandBufferAsyncGOOGLE(
+    VkCommandBuffer commandBuffer,
+    VkCommandBufferResetFlags flags)
+{
+    AEMU_SCOPED_TRACE("vkResetCommandBufferAsyncGOOGLE encode");
+    mImpl->log("start vkResetCommandBufferAsyncGOOGLE");
+    auto stream = mImpl->stream();
+    auto countingStream = mImpl->countingStream();
+    auto resources = mImpl->resources();
+    auto pool = mImpl->pool();
+    stream->setHandleMapping(resources->unwrapMapping());
+    VkCommandBuffer local_commandBuffer;
+    VkCommandBufferResetFlags local_flags;
+    local_commandBuffer = commandBuffer;
+    local_flags = flags;
+    countingStream->rewind();
+    {
+        uint64_t cgen_var_1512;
+        countingStream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_1512, 1);
+        countingStream->write((uint64_t*)&cgen_var_1512, 1 * 8);
+        countingStream->write((VkCommandBufferResetFlags*)&local_flags, sizeof(VkCommandBufferResetFlags));
+    }
+    uint32_t packetSize_vkResetCommandBufferAsyncGOOGLE = 4 + 4 + (uint32_t)countingStream->bytesWritten();
+    countingStream->rewind();
+    uint32_t opcode_vkResetCommandBufferAsyncGOOGLE = OP_vkResetCommandBufferAsyncGOOGLE;
+    stream->write(&opcode_vkResetCommandBufferAsyncGOOGLE, sizeof(uint32_t));
+    stream->write(&packetSize_vkResetCommandBufferAsyncGOOGLE, sizeof(uint32_t));
+    uint64_t cgen_var_1513;
+    stream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_1513, 1);
+    stream->write((uint64_t*)&cgen_var_1513, 1 * 8);
+    stream->write((VkCommandBufferResetFlags*)&local_flags, sizeof(VkCommandBufferResetFlags));
+    AEMU_SCOPED_TRACE("vkResetCommandBufferAsyncGOOGLE readParams");
+    AEMU_SCOPED_TRACE("vkResetCommandBufferAsyncGOOGLE returnUnmarshal");
+    mImpl->log("finish vkResetCommandBufferAsyncGOOGLE");;
+}
+
 #endif
 
 } // namespace goldfish_vk
diff --git a/system/vulkan_enc/VkEncoder.h b/system/vulkan_enc/VkEncoder.h
index 2e72833ce1115669f319ff659f09c7534bde4ac9..16df497f6f881c0a8e609e93f6770cbb1be6b5e7 100644
--- a/system/vulkan_enc/VkEncoder.h
+++ b/system/vulkan_enc/VkEncoder.h
@@ -1757,6 +1757,31 @@ public:
         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
+#ifdef VK_GOOGLE_async_command_buffers
+    void vkBeginCommandBufferAsyncGOOGLE(
+    VkCommandBuffer commandBuffer,
+        const VkCommandBufferBeginInfo* pBeginInfo);
+    void vkEndCommandBufferAsyncGOOGLE(
+    VkCommandBuffer commandBuffer);
+    void vkResetCommandBufferAsyncGOOGLE(
+    VkCommandBuffer commandBuffer,
+        VkCommandBufferResetFlags flags);
+#endif
 
 private:
     class Impl;
diff --git a/system/vulkan_enc/VulkanHandles.h b/system/vulkan_enc/VulkanHandles.h
index 23200729887d5f6336cd9422eb81019a4b5b0608..481e601cc7954668c61935471d19ad62821a8eac 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 0478e91c2bd71187c1934f5e9497afe301211122..5b004c0ae1b8c2f14da7df9d1fec1859a6506bdb 100644
--- a/system/vulkan_enc/goldfish_vk_deepcopy_guest.cpp
+++ b/system/vulkan_enc/goldfish_vk_deepcopy_guest.cpp
@@ -6379,6 +6379,10 @@ void deepcopy_VkImportPhysicalAddressGOOGLE(
     }
 }
 
+#endif
+#ifdef VK_GOOGLE_sized_descriptor_update_template
+#endif
+#ifdef VK_GOOGLE_async_command_buffers
 #endif
 void deepcopy_extension_struct(
     Pool* pool,
diff --git a/system/vulkan_enc/goldfish_vk_deepcopy_guest.h b/system/vulkan_enc/goldfish_vk_deepcopy_guest.h
index 6b73d1f73cf8cd7ee25255df39b9279b7dbca2c1..b367ee04d5e42a6c63b1e85e6e25558f28a0e5d0 100644
--- a/system/vulkan_enc/goldfish_vk_deepcopy_guest.h
+++ b/system/vulkan_enc/goldfish_vk_deepcopy_guest.h
@@ -2022,5 +2022,9 @@ void deepcopy_VkImportPhysicalAddressGOOGLE(
     VkImportPhysicalAddressGOOGLE* to);
 
 #endif
+#ifdef VK_GOOGLE_sized_descriptor_update_template
+#endif
+#ifdef VK_GOOGLE_async_command_buffers
+#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 0457642879d1e391a812c98ca5cd70b4bdc40c9e..c42f6e8b2171ab22c30cd4b3c764bd7ddf1568c5 100644
--- a/system/vulkan_enc/goldfish_vk_extension_structs_guest.cpp
+++ b/system/vulkan_enc/goldfish_vk_extension_structs_guest.cpp
@@ -278,6 +278,10 @@ namespace goldfish_vk {
 #endif
 #ifdef VK_GOOGLE_color_buffer
 #endif
+#ifdef VK_GOOGLE_sized_descriptor_update_template
+#endif
+#ifdef VK_GOOGLE_async_command_buffers
+#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 9d09bb81b950f41ca666eaa77ffcd6436545cbe1..1d671f8c318970cbc73fc34bbc7d323366781b32 100644
--- a/system/vulkan_enc/goldfish_vk_extension_structs_guest.h
+++ b/system/vulkan_enc/goldfish_vk_extension_structs_guest.h
@@ -295,5 +295,9 @@ size_t goldfish_vk_extension_struct_size(
 #endif
 #ifdef VK_GOOGLE_color_buffer
 #endif
+#ifdef VK_GOOGLE_sized_descriptor_update_template
+#endif
+#ifdef VK_GOOGLE_async_command_buffers
+#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 0bc04197ee24330d55911e5a813f5f220e3fd91b..7d16b31b5f4ce217e4e1982e12003aa1fe34ada1 100644
--- a/system/vulkan_enc/goldfish_vk_handlemap_guest.cpp
+++ b/system/vulkan_enc/goldfish_vk_handlemap_guest.cpp
@@ -4743,6 +4743,10 @@ void handlemap_VkImportPhysicalAddressGOOGLE(
     }
 }
 
+#endif
+#ifdef VK_GOOGLE_sized_descriptor_update_template
+#endif
+#ifdef VK_GOOGLE_async_command_buffers
 #endif
 void handlemap_extension_struct(
     VulkanHandleMapping* handlemap,
diff --git a/system/vulkan_enc/goldfish_vk_handlemap_guest.h b/system/vulkan_enc/goldfish_vk_handlemap_guest.h
index c9678d4af730eab939ba856b3de27546fa6ed92c..e973064e566441b5031add1e7256f4f59e584001 100644
--- a/system/vulkan_enc/goldfish_vk_handlemap_guest.h
+++ b/system/vulkan_enc/goldfish_vk_handlemap_guest.h
@@ -1675,5 +1675,9 @@ void handlemap_VkImportPhysicalAddressGOOGLE(
     VkImportPhysicalAddressGOOGLE* toMap);
 
 #endif
+#ifdef VK_GOOGLE_sized_descriptor_update_template
+#endif
+#ifdef VK_GOOGLE_async_command_buffers
+#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 0c12dfbb0dcd9146fc666031cff43db27c8a14bd..a67e9ad683f0802045c500089a15b805d3b814bd 100644
--- a/system/vulkan_enc/goldfish_vk_marshaling_guest.cpp
+++ b/system/vulkan_enc/goldfish_vk_marshaling_guest.cpp
@@ -13328,6 +13328,10 @@ void unmarshal_VkImportPhysicalAddressGOOGLE(
     vkStream->read((uint32_t*)&forUnmarshaling->tilingParameter, sizeof(uint32_t));
 }
 
+#endif
+#ifdef VK_GOOGLE_sized_descriptor_update_template
+#endif
+#ifdef VK_GOOGLE_async_command_buffers
 #endif
 void marshal_extension_struct(
     VulkanStreamGuest* vkStream,
diff --git a/system/vulkan_enc/goldfish_vk_marshaling_guest.h b/system/vulkan_enc/goldfish_vk_marshaling_guest.h
index 5d04b418aff031ce7b1ca6f900529fddaa1253f8..283e0adffbde8c9bdc2f004afb083fe2519b71ea 100644
--- a/system/vulkan_enc/goldfish_vk_marshaling_guest.h
+++ b/system/vulkan_enc/goldfish_vk_marshaling_guest.h
@@ -3381,5 +3381,13 @@ void unmarshal_VkImportPhysicalAddressGOOGLE(
 #define OP_vkRegisterImageColorBufferGOOGLE 20318
 #define OP_vkRegisterBufferColorBufferGOOGLE 20319
 #endif
+#ifdef VK_GOOGLE_sized_descriptor_update_template
+#define OP_vkUpdateDescriptorSetWithTemplateSizedGOOGLE 20320
+#endif
+#ifdef VK_GOOGLE_async_command_buffers
+#define OP_vkBeginCommandBufferAsyncGOOGLE 20321
+#define OP_vkEndCommandBufferAsyncGOOGLE 20322
+#define OP_vkResetCommandBufferAsyncGOOGLE 20323
+#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 9ace1d1195beff26ea68f4422568beda3bbf8b40..3eed2442ed3805998e3dc53e7c1f42bfce6a99bd 100644
--- a/system/vulkan_enc/goldfish_vk_private_defs.h
+++ b/system/vulkan_enc/goldfish_vk_private_defs.h
@@ -400,6 +400,31 @@ typedef struct AHardwareBuffer_Desc {
 
 #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);
+
+#define VK_GOOGLE_async_command_buffers 1
+
+typedef void (VKAPI_PTR *PFN_vkBeginCommandBufferAsyncGOOGLE)(
+    VkCommandBuffer commandBuffer,
+    const VkCommandBufferBeginInfo* pBeginInfo);
+typedef void (VKAPI_PTR *PFN_vkEndCommandBufferAsyncGOOGLE)(
+    VkCommandBuffer commandBuffer);
+typedef void (VKAPI_PTR *PFN_vkResetCommandBufferAsyncGOOGLE)(
+    VkCommandBuffer commandBuffer,
+    VkCommandBufferResetFlags flags);
+
 #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 9ef029b9d66b57637351cd537b049cb625832445..aa42af7d28189978fa5538fe78d568e532710ad0 100644
--- a/system/vulkan_enc/goldfish_vk_transform_guest.cpp
+++ b/system/vulkan_enc/goldfish_vk_transform_guest.cpp
@@ -8940,6 +8940,10 @@ void transform_fromhost_VkImportPhysicalAddressGOOGLE(
     }
 }
 
+#endif
+#ifdef VK_GOOGLE_sized_descriptor_update_template
+#endif
+#ifdef VK_GOOGLE_async_command_buffers
 #endif
 void transform_tohost_extension_struct(
     ResourceTracker* resourceTracker,
diff --git a/system/vulkan_enc/goldfish_vk_transform_guest.h b/system/vulkan_enc/goldfish_vk_transform_guest.h
index c7fb7d0df285bd8827a9409504f1a2f9ffee766e..754c033bb3c4a8cf30e7ac0e80e64d6d50cfe904 100644
--- a/system/vulkan_enc/goldfish_vk_transform_guest.h
+++ b/system/vulkan_enc/goldfish_vk_transform_guest.h
@@ -3063,5 +3063,9 @@ void transform_fromhost_VkImportPhysicalAddressGOOGLE(
     VkImportPhysicalAddressGOOGLE* toTransform);
 
 #endif
+#ifdef VK_GOOGLE_sized_descriptor_update_template
+#endif
+#ifdef VK_GOOGLE_async_command_buffers
+#endif
 
 } // namespace goldfish_vk