Merge branch 'master' into android10-gsi

bug: 146066070
Change-Id: I27d905d0c5ba84c36867bd3c054285fee860eac7
diff --git a/Android.mk b/Android.mk
index 6cf4651..7afa40a 100644
--- a/Android.mk
+++ b/Android.mk
@@ -150,6 +150,12 @@
 
 include $(GOLDFISH_OPENGL_PATH)/system/gralloc/Android.mk
 
+ifneq (true,$(GOLDFISH_OPENGL_BUILD_FOR_HOST))
+include $(GOLDFISH_OPENGL_PATH)/system/hals/Android.mk
+endif
+
+include $(GOLDFISH_OPENGL_PATH)/system/cbmanager/Android.mk
+
 include $(GOLDFISH_OPENGL_PATH)/system/egl/Android.mk
 
 ifeq (true,$(BUILD_EMULATOR_VULKAN)) # Vulkan libs
@@ -159,6 +165,11 @@
 ifeq ($(shell test $(PLATFORM_SDK_VERSION) -gt 28 -o $(IS_AT_LEAST_QPR1) = true && echo isApi29OrHigher),isApi29OrHigher)
     # HWC2 enabled after P
     include $(GOLDFISH_OPENGL_PATH)/system/hwc2/Android.mk
+    # hardware codecs enabled after P
+    include $(GOLDFISH_OPENGL_PATH)/system/codecs/omx/common/Android.mk
+    include $(GOLDFISH_OPENGL_PATH)/system/codecs/omx/plugin/Android.mk
+    include $(GOLDFISH_OPENGL_PATH)/system/codecs/omx/avcdec/Android.mk
+    include $(GOLDFISH_OPENGL_PATH)/system/codecs/omx/vpxdec/Android.mk
 endif
 
 endif
diff --git a/BUILD.gn b/BUILD.gn
index 348ab87..0e2fea1 100644
--- a/BUILD.gn
+++ b/BUILD.gn
@@ -1,17 +1,31 @@
-shared_library("vulkan_goldfish") {
+shared_library("libvulkan_goldfish") {
   sources = [
     "android-emu/android/base/AlignedBuf.cpp",
     "android-emu/android/base/AlignedBuf.h",
     "android-emu/android/base/Pool.cpp",
     "android-emu/android/base/Pool.h",
-    "android-emu/android/base/SubAllocator.cpp",
-    "android-emu/android/base/SubAllocator.h",
+    "android-emu/android/base/ring_buffer.c",
+    "android-emu/android/base/AndroidSubAllocator.cpp",
+    "android-emu/android/base/AndroidSubAllocator.h",
     "android-emu/android/base/files/MemStream.cpp",
     "android-emu/android/base/files/MemStream.h",
     "android-emu/android/base/files/Stream.cpp",
     "android-emu/android/base/files/Stream.h",
     "android-emu/android/base/files/StreamSerializing.cpp",
     "android-emu/android/base/files/StreamSerializing.h",
+    "android-emu/android/base/synchronization/AndroidConditionVariable.h",
+    "android-emu/android/base/synchronization/AndroidLock.h",
+    "android-emu/android/base/synchronization/AndroidMessageChannel.h",
+    "android-emu/android/base/synchronization/AndroidMessageChannel.cpp",
+    "android-emu/android/base/threads/AndroidFunctorThread.h",
+    "android-emu/android/base/threads/AndroidThread.h",
+    "android-emu/android/base/threads/AndroidThreadStore.h",
+    "android-emu/android/base/threads/AndroidThreadTypes.h",
+    "android-emu/android/base/threads/AndroidWorkPool.h",
+    "android-emu/android/base/threads/AndroidFunctorThread.cpp",
+    "android-emu/android/base/threads/AndroidThreadStore.h",
+    "android-emu/android/base/threads/AndroidThread_pthread.cpp",
+    "android-emu/android/base/threads/AndroidWorkPool.cpp",
     "android-emu/android/base/Tracing.cpp",
     "android-emu/android/base/Tracing.h",
     "shared/OpenglCodecCommon/ChecksumCalculator.cpp",
@@ -22,6 +36,7 @@
     "shared/OpenglCodecCommon/goldfish_address_space.h",
     "shared/OpenglCodecCommon/goldfish_dma.cpp",
     "shared/OpenglCodecCommon/goldfish_dma.h",
+    "system/OpenglSystemCommon/AddressSpaceStream.cpp",
     "system/OpenglSystemCommon/HostConnection.cpp",
     "system/OpenglSystemCommon/HostConnection.h",
     "system/OpenglSystemCommon/ProcessPipe.cpp",
@@ -78,10 +93,20 @@
     "PAGE_SIZE=4096",
   ]
 
-  cflags_cc = [
-    "-Wno-unused-function",
-    "-Wno-unused-variable",
+  cflags_c = [
     "-Wno-missing-field-initializers",
+    "-Wno-newline-eof",
+    "-Wno-unused-function",
+    "-Wno-unused-value",
+    "-Wno-unused-variable",
+  ]
+
+  cflags_cc = [
+    "-Wno-missing-field-initializers",
+    "-Wno-newline-eof",
+    "-Wno-unused-function",
+    "-Wno-unused-value",
+    "-Wno-unused-variable",
   ]
 
   ldflags = [ "-static-libstdc++" ]
@@ -89,13 +114,15 @@
   if (target_os == "fuchsia") {
     sources -= [ "system/OpenglSystemCommon/QemuPipeStream.cpp" ]
     sources += [
+      "fuchsia/fuchsia_stdio.cc",
       "fuchsia/port.cc",
+      "fuchsia/service_connector.cc",
       "system/OpenglSystemCommon/QemuPipeStreamFuchsia.cpp",
     ]
 
     include_dirs += [
-      "//third_party/vulkan_loader_and_validation_layers/include",
       "fuchsia/include",
+      "//third_party/Vulkan-Headers/include"
     ]
 
     libs = [
@@ -103,12 +130,13 @@
     ]
 
     deps = [
-      "//zircon/public/fidl/fuchsia-hardware-goldfish-address-space:fuchsia-hardware-goldfish-address-space_c",
-      "//zircon/public/fidl/fuchsia-hardware-goldfish-control:fuchsia-hardware-goldfish-control_c",
-      "//zircon/public/fidl/fuchsia-hardware-goldfish-pipe:fuchsia-hardware-goldfish-pipe_c",
-      "//zircon/public/fidl/fuchsia-sysmem",
-      "//zircon/public/lib/fdio",
-      "//zircon/public/lib/trace",
+      "//sdk/fidl/fuchsia.hardware.goldfish",
+      "//zircon/system/fidl/fuchsia-sysmem",
+      "//zircon/public/lib/trace-with-static-engine",
+      "//zircon/public/lib/syslog-static",
+      "//zircon/public/lib/zx",
+      "//zircon/public/lib/zxio",
+      "//zircon/system/fidl/fuchsia-logger:llcpp",
     ]
 
     defines += [
diff --git a/CMakeLists.txt b/CMakeLists.txt
index ac15aad..9c58ad1 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -2,7 +2,7 @@
 # instead run make from .../device/generic/goldfish-opengl
 # which will re-generate this file.
 set(GOLDFISH_DEVICE_ROOT ${CMAKE_CURRENT_SOURCE_DIR})
-android_validate_sha256("${GOLDFISH_DEVICE_ROOT}/./Android.mk" "8a354859d6be293140931db80edcbaf2c4db30118482356373f9ed2c92059806")
+android_validate_sha256("${GOLDFISH_DEVICE_ROOT}/./Android.mk" "c8e5536771d09cd120c3e396beac994a1e2d2880f37b4e3bd1844be4cfc31555")
 add_subdirectory(shared/OpenglCodecCommon)
 add_subdirectory(system/GLESv1_enc)
 add_subdirectory(system/GLESv2_enc)
diff --git a/android-emu/Android.mk b/android-emu/Android.mk
index 5bc64dd..4be199b 100644
--- a/android-emu/Android.mk
+++ b/android-emu/Android.mk
@@ -1,6 +1,6 @@
 LOCAL_PATH := $(call my-dir)
 
-$(call emugl-begin-static-library,libandroidemu)
+$(call emugl-begin-shared-library,libandroidemu)
 $(call emugl-export,C_INCLUDES,$(LOCAL_PATH))
 $(call emugl-export,SHARED_LIBRARIES,libcutils libutils liblog)
 
@@ -16,8 +16,14 @@
     android/base/files/Stream.cpp \
     android/base/files/StreamSerializing.cpp \
     android/base/Pool.cpp \
+    android/base/ring_buffer.c \
     android/base/StringFormat.cpp \
-    android/base/SubAllocator.cpp \
+    android/base/AndroidSubAllocator.cpp \
+    android/base/synchronization/AndroidMessageChannel.cpp \
+    android/base/threads/AndroidFunctorThread.cpp \
+    android/base/threads/AndroidThreadStore.cpp \
+    android/base/threads/AndroidThread_pthread.cpp \
+    android/base/threads/AndroidWorkPool.cpp \
     android/base/Tracing.cpp \
     android/utils/debug.c \
 
diff --git a/android-emu/CMakeLists.txt b/android-emu/CMakeLists.txt
index 2691b00..f490697 100644
--- a/android-emu/CMakeLists.txt
+++ b/android-emu/CMakeLists.txt
@@ -1,10 +1,10 @@
 # This is an autogenerated file! Do not edit!
 # instead run make from .../device/generic/goldfish-opengl
 # which will re-generate this file.
-android_validate_sha256("${GOLDFISH_DEVICE_ROOT}/android-emu/Android.mk" "7bcf3be99b2f95203390d08a2710b7bdc2bd6248403850b1f713a39869b2dfd1")
-set(androidemu_src android/base/AlignedBuf.cpp android/base/files/MemStream.cpp android/base/files/Stream.cpp android/base/files/StreamSerializing.cpp android/base/Pool.cpp android/base/StringFormat.cpp android/base/SubAllocator.cpp android/base/Tracing.cpp android/utils/debug.c)
-android_add_library(androidemu)
+android_validate_sha256("${GOLDFISH_DEVICE_ROOT}/android-emu/Android.mk" "e7c9acc2277e7c651d6e722f96705a1fd445441b5ab6bb5b6d5b4c46dddfc702")
+set(androidemu_src android/base/AlignedBuf.cpp android/base/files/MemStream.cpp android/base/files/Stream.cpp android/base/files/StreamSerializing.cpp android/base/Pool.cpp android/base/ring_buffer.c android/base/StringFormat.cpp android/base/AndroidSubAllocator.cpp android/base/synchronization/AndroidMessageChannel.cpp android/base/threads/AndroidFunctorThread.cpp android/base/threads/AndroidThreadStore.cpp android/base/threads/AndroidThread_pthread.cpp android/base/threads/AndroidWorkPool.cpp android/base/Tracing.cpp android/utils/debug.c)
+android_add_library(TARGET androidemu SHARED LICENSE Apache-2.0 SRC android/base/AlignedBuf.cpp android/base/files/MemStream.cpp android/base/files/Stream.cpp android/base/files/StreamSerializing.cpp android/base/Pool.cpp android/base/ring_buffer.c android/base/StringFormat.cpp android/base/AndroidSubAllocator.cpp android/base/synchronization/AndroidMessageChannel.cpp android/base/threads/AndroidFunctorThread.cpp android/base/threads/AndroidThreadStore.cpp android/base/threads/AndroidThread_pthread.cpp android/base/threads/AndroidWorkPool.cpp android/base/Tracing.cpp android/utils/debug.c)
 target_include_directories(androidemu PRIVATE ${GOLDFISH_DEVICE_ROOT}/android-emu ${GOLDFISH_DEVICE_ROOT}/./host/include/libOpenglRender ${GOLDFISH_DEVICE_ROOT}/./system/include ${GOLDFISH_DEVICE_ROOT}/./../../../external/qemu/android/android-emugl/guest)
 target_compile_definitions(androidemu PRIVATE "-DWITH_GLES2" "-DPLATFORM_SDK_VERSION=29" "-DGOLDFISH_HIDL_GRALLOC" "-DEMULATOR_OPENGL_POST_O=1" "-DHOST_BUILD" "-DANDROID" "-DGL_GLEXT_PROTOTYPES" "-DPAGE_SIZE=4096" "-DGOLDFISH_VULKAN" "-DLOG_TAG=\"androidemu\"")
-target_compile_options(androidemu PRIVATE "-fvisibility=default" "-Wno-missing-field-initializers" "-fstrict-aliasing")
+target_compile_options(androidemu PRIVATE "-fvisibility=default" "-Wno-unused-parameter" "-Wno-missing-field-initializers" "-fstrict-aliasing")
 target_link_libraries(androidemu PRIVATE cutils utils log OpenglCodecCommon_host android-emu-shared)
\ No newline at end of file
diff --git a/android-emu/android/base/AndroidSubAllocator.cpp b/android-emu/android/base/AndroidSubAllocator.cpp
new file mode 100644
index 0000000..0b17a8a
--- /dev/null
+++ b/android-emu/android/base/AndroidSubAllocator.cpp
@@ -0,0 +1,240 @@
+// Copyright 2018 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+#include "android/base/AndroidSubAllocator.h"
+
+#include "android/base/address_space.h"
+#include "android/base/files/Stream.h"
+
+#include <iomanip>
+#include <sstream>
+#include <string>
+
+#include <log/log.h>
+
+namespace android {
+namespace base {
+namespace guest {
+
+class SubAllocator::Impl {
+public:
+    Impl(
+        void* _buffer,
+        uint64_t _totalSize,
+        uint64_t _pageSize) :
+        buffer(_buffer),
+        totalSize(_totalSize),
+        pageSize(_pageSize),
+        startAddr((uintptr_t)buffer),
+        endAddr(startAddr + totalSize) {
+
+        address_space_allocator_init(
+            &addr_alloc,
+            totalSize,
+            32);
+    }
+
+    ~Impl() {
+        address_space_allocator_destroy_nocleanup(&addr_alloc);
+    }
+
+    void clear() {
+        address_space_allocator_destroy_nocleanup(&addr_alloc);
+        address_space_allocator_init(
+            &addr_alloc,
+            totalSize,
+            32);
+    }
+
+    bool save(Stream* stream) {
+        address_space_allocator_iter_func_t allocatorSaver =
+            [](void* context, struct address_space_allocator* allocator) {
+                Stream* stream = reinterpret_cast<Stream*>(context);
+                stream->putBe32(allocator->size);
+                stream->putBe32(allocator->capacity);
+                stream->putBe64(allocator->total_bytes);
+            };
+        address_block_iter_func_t allocatorBlockSaver =
+            [](void* context, struct address_block* block) {
+                Stream* stream = reinterpret_cast<Stream*>(context);
+                stream->putBe64(block->offset);
+                stream->putBe64(block->size_available);
+            };
+        address_space_allocator_run(
+            &addr_alloc,
+            (void*)stream,
+            allocatorSaver,
+            allocatorBlockSaver);
+
+        stream->putBe64(pageSize);
+        stream->putBe64(totalSize);
+        stream->putBe32(allocCount);
+
+        return true;
+    }
+
+    bool load(Stream* stream) {
+        clear();
+        address_space_allocator_iter_func_t allocatorLoader =
+            [](void* context, struct address_space_allocator* allocator) {
+                Stream* stream = reinterpret_cast<Stream*>(context);
+                allocator->size = stream->getBe32();
+                allocator->capacity = stream->getBe32();
+                allocator->total_bytes = stream->getBe64();
+            };
+        address_block_iter_func_t allocatorBlockLoader =
+            [](void* context, struct address_block* block) {
+                Stream* stream = reinterpret_cast<Stream*>(context);
+                block->offset = stream->getBe64();
+                block->size_available = stream->getBe64();
+            };
+        address_space_allocator_run(
+            &addr_alloc,
+            (void*)stream,
+            allocatorLoader,
+            allocatorBlockLoader);
+
+        pageSize = stream->getBe64();
+        totalSize = stream->getBe64();
+        allocCount = stream->getBe32();
+
+        return true;
+    }
+
+    bool postLoad(void* postLoadBuffer) {
+        buffer = postLoadBuffer;
+        startAddr =
+            (uint64_t)(uintptr_t)postLoadBuffer;
+        return true;
+    }
+
+    void rangeCheck(const char* task, void* ptr) {
+        uint64_t addr = (uintptr_t)ptr;
+        if (addr < startAddr ||
+            addr > endAddr) {
+            std::stringstream ss;
+            ss << "SubAllocator " << task << ": ";
+            ss << "Out of range: " << std::hex << addr << " ";
+            ss << "Range: " <<
+                std::hex << startAddr << " " <<
+                std::hex << endAddr;
+            std::string msg = ss.str();
+            ALOGE("Fatal: %s\n", msg.c_str());
+        }
+    }
+
+    uint64_t getOffset(void* checkedPtr) {
+        uint64_t addr = (uintptr_t)checkedPtr;
+        return addr - startAddr;
+    }
+
+    bool free(void* ptr) {
+        if (!ptr) return false;
+
+        rangeCheck("free", ptr);
+        if (EINVAL == address_space_allocator_deallocate(
+            &addr_alloc, getOffset(ptr))) {
+            return false;
+        }
+
+        --allocCount;
+        return true;
+    }
+
+    void freeAll() {
+        address_space_allocator_reset(&addr_alloc);
+        allocCount = 0;
+    }
+
+    void* alloc(size_t wantedSize) {
+        if (wantedSize == 0) return nullptr;
+
+        uint64_t wantedSize64 =
+            (uint64_t)wantedSize;
+
+        size_t toPageSize =
+            pageSize *
+            ((wantedSize + pageSize - 1) / pageSize);
+
+        uint64_t offset =
+            address_space_allocator_allocate(
+                &addr_alloc, toPageSize);
+
+        if (offset == ANDROID_EMU_ADDRESS_SPACE_BAD_OFFSET) {
+            return nullptr;
+        }
+
+        ++allocCount;
+        return (void*)(uintptr_t)(startAddr + offset);
+    }
+
+    bool empty() const {
+        return allocCount == 0;
+    }
+
+    void* buffer;
+    uint64_t totalSize;
+    uint64_t pageSize;
+    uint64_t startAddr;
+    uint64_t endAddr;
+    struct address_space_allocator addr_alloc;
+    uint32_t allocCount = 0;
+};
+
+SubAllocator::SubAllocator(
+    void* buffer,
+    uint64_t totalSize,
+    uint64_t pageSize) :
+    mImpl(
+        new SubAllocator::Impl(buffer, totalSize, pageSize)) { }
+
+SubAllocator::~SubAllocator() {
+    delete mImpl;
+}
+
+// Snapshotting
+bool SubAllocator::save(Stream* stream) {
+    return mImpl->save(stream);
+}
+
+bool SubAllocator::load(Stream* stream) {
+    return mImpl->load(stream);
+}
+
+bool SubAllocator::postLoad(void* postLoadBuffer) {
+    return mImpl->postLoad(postLoadBuffer);
+}
+
+void* SubAllocator::alloc(size_t wantedSize) {
+    return mImpl->alloc(wantedSize);
+}
+
+bool SubAllocator::free(void* ptr) {
+    return mImpl->free(ptr);
+}
+
+void SubAllocator::freeAll() {
+    mImpl->freeAll();
+}
+
+uint64_t SubAllocator::getOffset(void* ptr) {
+    return mImpl->getOffset(ptr);
+}
+
+bool SubAllocator::empty() const {
+    return mImpl->empty();
+}
+
+} // namespace guest
+} // namespace base
+} // namespace android
diff --git a/android-emu/android/base/SubAllocator.h b/android-emu/android/base/AndroidSubAllocator.h
similarity index 86%
rename from android-emu/android/base/SubAllocator.h
rename to android-emu/android/base/AndroidSubAllocator.h
index b2363bd..8442137 100644
--- a/android-emu/android/base/SubAllocator.h
+++ b/android-emu/android/base/AndroidSubAllocator.h
@@ -20,6 +20,16 @@
 namespace android {
 namespace base {
 
+class Stream;
+
+} // namespace base
+} // namespace android
+
+namespace android {
+namespace base {
+namespace guest {
+
+
 // Class to create sub-allocations in an existing buffer. Similar interface to
 // Pool, but underlying mechanism is different as it's difficult to combine
 // same-size heaps in Pool with a preallocated buffer.
@@ -36,12 +46,20 @@
     // SubAllocator, but the prealloced buffer is not freed.
     ~SubAllocator();
 
+    // Snapshotting
+    bool save(Stream* stream);
+    bool load(Stream* stream);
+    bool postLoad(void* postLoadBuffer);
+
     // returns null if the allocation cannot be satisfied.
     void* alloc(size_t wantedSize);
-    void free(void* ptr);
+    // returns true if |ptr| came from alloc(), false otherwise
+    bool free(void* ptr);
     void freeAll();
     uint64_t getOffset(void* ptr);
 
+    bool empty() const;
+
     // Convenience function to allocate an array
     // of objects of type T.
     template <class T>
@@ -80,5 +98,6 @@
     Impl* mImpl = nullptr;
 };
 
+} // namespace guest
 } // namespace base
 } // namespace android
diff --git a/android-emu/android/base/EnumFlags.h b/android-emu/android/base/EnumFlags.h
new file mode 100644
index 0000000..fec56b9
--- /dev/null
+++ b/android-emu/android/base/EnumFlags.h
@@ -0,0 +1,117 @@
+// Copyright 2015 The Android Open Source Project
+//
+// This software is licensed under the terms of the GNU General Public
+// License version 2, as published by the Free Software Foundation, and
+// may be copied, distributed, and modified under those terms.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+#pragma once
+
+#include <type_traits>
+
+// This header defines some utitily methods to manipulate scoped enums as flags
+// C++11 scoped enums by default don't support flag operations (e.g. if (a & b))
+// We need to define bitwise operations for them to be able to have strongly
+// typed flags in our code.
+//
+// To enable the flag operators for your enum, most probably you just need to
+// include this file. The only exception is if your enum is located in some
+// namespace other than android, android::base or global. In that case you also
+// need to add the following using to bring in the operators:
+//
+// using namespace ::android::base::EnumFlags;
+
+namespace android {
+namespace base {
+namespace EnumFlags {
+
+// A predicate which checks if template agument is a scoped enum
+template<class E>
+using is_scoped_enum = std::integral_constant<
+        bool,
+        std::is_enum<E>::value && !std::is_convertible<E, int>::value>;
+
+template <class E>
+using underlying_enum_type = typename std::underlying_type<E>::type;
+
+template <class E, class Res = E>
+using enable_if_scoped_enum =
+    typename std::enable_if<is_scoped_enum<E>::value, Res>::type;
+
+template <class E>
+enable_if_scoped_enum<E> operator|(E l, E r) {
+    return static_cast<E>(static_cast<underlying_enum_type<E>>(l)
+                          | static_cast<underlying_enum_type<E>>(r));
+}
+
+template <class E>
+enable_if_scoped_enum<E> operator&(E l, E r) {
+    return static_cast<E>(static_cast<underlying_enum_type<E>>(l)
+                          & static_cast<underlying_enum_type<E>>(r));
+}
+
+template <class E>
+enable_if_scoped_enum<E> operator~(E e) {
+    return static_cast<E>(~static_cast<underlying_enum_type<E>>(e));
+}
+
+template <class E>
+enable_if_scoped_enum<E> operator|=(E& l, E r) {
+    return l = (l | r);
+}
+
+template <class E>
+enable_if_scoped_enum<E> operator&=(E& l, E r) {
+    return l = (l & r);
+}
+
+template <class E>
+enable_if_scoped_enum<E, bool> operator!(E e) {
+    return !static_cast<underlying_enum_type<E>>(e);
+}
+
+template <class E>
+enable_if_scoped_enum<E, bool> operator!=(E e, int val) {
+    return static_cast<underlying_enum_type<E>>(e) !=
+            static_cast<underlying_enum_type<E>>(val);
+}
+
+template <class E>
+enable_if_scoped_enum<E, bool> operator!=(int val, E e) {
+    return e != val;
+}
+
+template <class E>
+enable_if_scoped_enum<E, bool> operator==(E e, int val) {
+    return static_cast<underlying_enum_type<E>>(e) ==
+            static_cast<underlying_enum_type<E>>(val);
+}
+
+template <class E>
+enable_if_scoped_enum<E, bool> operator==(int val, E e) {
+    return e == val;
+}
+
+template <class E>
+enable_if_scoped_enum<E, bool> nonzero(E e) {
+    return static_cast<underlying_enum_type<E>>(e) != 0;
+}
+
+}  // namespace EnumFlags
+
+// For the ADL to kick in let's make sure we bring all the operators into our
+// main AndroidEmu namespaces...
+using namespace ::android::base::EnumFlags;
+
+}  // namespace base
+
+using namespace ::android::base::EnumFlags;
+
+}  // namespace android
+
+// ... and into the global one, where most of the client functions are
+using namespace ::android::base::EnumFlags;
diff --git a/android-emu/android/base/SubAllocator.cpp b/android-emu/android/base/SubAllocator.cpp
deleted file mode 100644
index 0d835d6..0000000
--- a/android-emu/android/base/SubAllocator.cpp
+++ /dev/null
@@ -1,139 +0,0 @@
-// Copyright 2018 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-#include "android/base/SubAllocator.h"
-
-#include "android/base/address_space.h"
-
-#include <log/log.h>
-
-#include <iomanip>
-#include <sstream>
-#include <string>
-
-namespace android {
-namespace base {
-
-class SubAllocator::Impl {
-public:
-    Impl(
-        void* _buffer,
-        uint64_t _totalSize,
-        uint64_t _pageSize) :
-        buffer(_buffer),
-        totalSize(_totalSize),
-        pageSize(_pageSize),
-        startAddr((uintptr_t)buffer),
-        endAddr(startAddr + totalSize) {
-
-        address_space_allocator_init(
-            &addr_alloc,
-            totalSize,
-            32);
-    }
-
-    ~Impl() {
-        address_space_allocator_destroy(&addr_alloc);
-    }
-
-    void rangeCheck(const char* task, void* ptr) {
-        uint64_t addr = (uintptr_t)ptr;
-        if (addr < startAddr ||
-            addr > endAddr) {
-            std::stringstream ss;
-            ss << "SubAllocator " << task << ": ";
-            ss << "Out of range: " << std::hex << addr << " ";
-            ss << "Range: " <<
-                std::hex << startAddr << " " <<
-                std::hex << endAddr;
-            std::string msg = ss.str();
-            ALOGE("%s", msg.c_str());
-            abort();
-        }
-    }
-
-    uint64_t getOffset(void* checkedPtr) {
-        uint64_t addr = (uintptr_t)checkedPtr;
-        return addr - startAddr;
-    }
-
-    void free(void* ptr) {
-        if (!ptr) return;
-
-        rangeCheck("free", ptr);
-        address_space_allocator_deallocate(
-            &addr_alloc, getOffset(ptr));
-    }
-
-    void freeAll() {
-        address_space_allocator_reset(&addr_alloc);
-    }
-
-    void* alloc(size_t wantedSize) {
-        if (wantedSize == 0) return nullptr;
-
-        uint64_t wantedSize64 =
-            (uint64_t)wantedSize;
-
-        size_t toPageSize =
-            pageSize *
-            ((wantedSize + pageSize - 1) / pageSize);
-
-        uint64_t offset =
-            address_space_allocator_allocate(
-                &addr_alloc, toPageSize);
-
-        if (offset == ANDROID_EMU_ADDRESS_SPACE_BAD_OFFSET) {
-            return nullptr;
-        }
-
-        return (void*)(uintptr_t)(startAddr + offset);
-    }
-
-    void* buffer;
-    uint64_t totalSize;
-    uint64_t pageSize;
-    uint64_t startAddr;
-    uint64_t endAddr;
-    struct address_space_allocator addr_alloc;
-};
-
-SubAllocator::SubAllocator(
-    void* buffer,
-    uint64_t totalSize,
-    uint64_t pageSize) :
-    mImpl(
-        new SubAllocator::Impl(buffer, totalSize, pageSize)) { }
-
-SubAllocator::~SubAllocator() {
-    delete mImpl;
-}
-
-void* SubAllocator::alloc(size_t wantedSize) {
-    return mImpl->alloc(wantedSize);
-}
-
-void SubAllocator::free(void* ptr) {
-    mImpl->free(ptr);
-}
-
-void SubAllocator::freeAll() {
-    mImpl->freeAll();
-}
-
-uint64_t SubAllocator::getOffset(void* ptr) {
-    return mImpl->getOffset(ptr);
-}
-
-} // namespace base
-} // namespace android
diff --git a/android-emu/android/base/Tracing.cpp b/android-emu/android/base/Tracing.cpp
index 8b254d2..ff72093 100644
--- a/android-emu/android/base/Tracing.cpp
+++ b/android-emu/android/base/Tracing.cpp
@@ -36,7 +36,9 @@
 
 #elif __Fuchsia__
 
+#ifndef FUCHSIA_NO_TRACE
 #include <trace/event.h>
+#endif
 
 #define VK_TRACE_TAG "gfx"
 
@@ -44,11 +46,15 @@
 namespace base {
 
 void ScopedTrace::beginTraceImpl(const char* name) {
+#ifndef FUCHSIA_NO_TRACE
     TRACE_DURATION_BEGIN(VK_TRACE_TAG, name);
+#endif
 }
 
 void ScopedTrace::endTraceImpl(const char* name) {
+#ifndef FUCHSIA_NO_TRACE
     TRACE_DURATION_END(VK_TRACE_TAG, name);
+#endif
 }
 
 } // namespace base
diff --git a/android-emu/android/base/address_space.h b/android-emu/android/base/address_space.h
index 6f454a7..e7b43fd 100644
--- a/android-emu/android/base/address_space.h
+++ b/android-emu/android/base/address_space.h
@@ -18,10 +18,15 @@
 #include <errno.h>
 #include <inttypes.h>
 #include <stdlib.h>
+#include <stdio.h>
 #include <string.h>
 
 ANDROID_BEGIN_HEADER
 
+#ifdef ADDRESS_SPACE_NAMESPACE
+namespace ADDRESS_SPACE_NAMESPACE {
+#endif
+
 // This is ported from goldfish_address_space, allowing it to be used for
 // general sub-allocations of any buffer range.
 // It is also a pure header library, so there are no compiler tricks needed
@@ -33,8 +38,13 @@
  */
 struct address_block {
     uint64_t offset;
-    uint64_t size : 63;
-    uint64_t available : 1;
+    union {
+        uint64_t size_available; /* VMSTATE_x does not support bit fields */
+        struct {
+            uint64_t size : 63;
+            uint64_t available : 1;
+        };
+    };
 };
 
 /* A dynamic array of address blocks, with the following invariant:
@@ -60,7 +70,7 @@
 #endif
 }
 
-void* address_space_malloc0(size_t size) {
+static void* address_space_malloc0(size_t size) {
 #ifdef ANDROID_EMU_ADDRESS_SPACE_MALLOC0_FUNC
     return ANDROID_EMU_ADDRESS_SPACE_MALLOC0_FUNC(size);
 #else
@@ -70,7 +80,7 @@
 #endif
 }
 
-void* address_space_realloc(void* ptr, size_t size) {
+static void* address_space_realloc(void* ptr, size_t size) {
 #ifdef ANDROID_EMU_ADDRESS_SPACE_REALLOC_FUNC
     return ANDROID_EMU_ADDRESS_SPACE_REALLOC_FUNC(ptr, size);
 #else
@@ -79,7 +89,7 @@
 #endif
 }
 
-void address_space_free(void* ptr) {
+static void address_space_free(void* ptr) {
 #ifdef ANDROID_EMU_ADDRESS_SPACE_FREE_FUNC
     return ANDROID_EMU_ADDRESS_SPACE_FREE_FUNC(ptr);
 #else
@@ -301,7 +311,8 @@
 
     allocator->blocks =
         (struct address_block*)
-        address_space_malloc0(sizeof(struct address_block) * initial_capacity);
+        malloc(sizeof(struct address_block) * initial_capacity);
+    memset(allocator->blocks, 0, sizeof(struct address_block) * initial_capacity);
     address_space_assert(allocator->blocks);
 
     struct address_block *block = allocator->blocks;
@@ -327,6 +338,15 @@
     address_space_free(allocator->blocks);
 }
 
+/* Destroy function if we don't care what was previoulsy allocated.
+ * have been merged into one block.
+ */
+static void address_space_allocator_destroy_nocleanup(
+    struct address_space_allocator *allocator)
+{
+    address_space_free(allocator->blocks);
+}
+
 /* Resets the state of the allocator to the initial state without
  * performing any dynamic memory management. */
 static void address_space_allocator_reset(
@@ -342,4 +362,33 @@
     block->available = 1;
 }
 
+typedef void (*address_block_iter_func_t)(void* context, struct address_block*);
+typedef void (*address_space_allocator_iter_func_t)(void* context, struct address_space_allocator*);
+
+static void address_space_allocator_run(
+    struct address_space_allocator *allocator,
+    void* context,
+    address_space_allocator_iter_func_t allocator_func,
+    address_block_iter_func_t block_func)
+{
+    struct address_block *block = 0;
+    int size;
+    int i;
+
+    allocator_func(context, allocator);
+
+    block = allocator->blocks;
+    size = allocator->size;
+
+    address_space_assert(size >= 1);
+
+    for (i = 0; i < size; ++i, ++block) {
+        block_func(context, block);
+    }
+}
+
+#ifdef ADDRESS_SPACE_NAMESPACE
+}
+#endif
+
 ANDROID_END_HEADER
diff --git a/android-emu/android/base/ring_buffer.c b/android-emu/android/base/ring_buffer.c
new file mode 100644
index 0000000..1ad122e
--- /dev/null
+++ b/android-emu/android/base/ring_buffer.c
@@ -0,0 +1,636 @@
+// Copyright 2018 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+#include "android/base/ring_buffer.h"
+
+#include <errno.h>
+#include <string.h>
+#ifdef _MSC_VER
+#include "msvc-posix.h"
+#else
+#include <sys/time.h>
+#endif
+
+#if (defined(__i386__) || defined(__x86_64__))
+#define RING_BUFFER_X86 1
+#else
+#define RING_BUFFER_X86 0
+#endif
+
+#if RING_BUFFER_X86
+#include <emmintrin.h>
+#endif
+
+#ifdef _WIN32
+#include <windows.h>
+#else
+#include <sched.h>
+#include <unistd.h>
+#endif
+
+#define RING_BUFFER_MASK (RING_BUFFER_SIZE - 1)
+
+#define RING_BUFFER_VERSION 1
+
+static inline void ring_buffer_pause() {
+#if RING_BUFFER_X86
+    _mm_pause();
+#else
+    // TODO(lfy) analog of pause on ARM
+#endif
+}
+
+void ring_buffer_init(struct ring_buffer* r) {
+    r->guest_version = 1;
+    r->write_pos = 0;
+    r->read_pos = 0;
+
+    r->read_live_count = 0;
+    r->read_yield_count = 0;
+    r->read_sleep_us_count = 0;
+
+    r->state = 0;
+}
+
+static uint32_t get_ring_pos(uint32_t index) {
+    return index & RING_BUFFER_MASK;
+}
+
+bool ring_buffer_can_write(const struct ring_buffer* r, uint32_t bytes) {
+    uint32_t read_view;
+    __atomic_load(&r->read_pos, &read_view, __ATOMIC_SEQ_CST);
+    return get_ring_pos(read_view - r->write_pos - 1) >= bytes;
+}
+
+bool ring_buffer_can_read(const struct ring_buffer* r, uint32_t bytes) {
+    uint32_t write_view;
+    __atomic_load(&r->write_pos, &write_view, __ATOMIC_SEQ_CST);
+    return get_ring_pos(write_view - r->read_pos) >= bytes;
+}
+
+long ring_buffer_write(
+    struct ring_buffer* r, const void* data, uint32_t step_size, uint32_t steps) {
+    const uint8_t* data_bytes = (const uint8_t*)data;
+    uint32_t i;
+
+    for (i = 0; i < steps; ++i) {
+        if (!ring_buffer_can_write(r, step_size)) {
+            errno = -EAGAIN;
+            return (long)i;
+        }
+
+        // Needs to be split up into 2 writes for the edge case.
+        uint32_t available_at_end =
+            RING_BUFFER_SIZE - get_ring_pos(r->write_pos);
+
+        if (step_size > available_at_end) {
+            uint32_t remaining = step_size - available_at_end;
+            memcpy(
+                &r->buf[get_ring_pos(r->write_pos)],
+                data_bytes + i * step_size,
+                available_at_end);
+            memcpy(
+                &r->buf[get_ring_pos(r->write_pos + available_at_end)],
+                data_bytes + i * step_size + available_at_end,
+                remaining);
+        } else {
+            memcpy(
+                &r->buf[get_ring_pos(r->write_pos)],
+                data_bytes + i * step_size,
+                step_size);
+        }
+
+        __atomic_add_fetch(&r->write_pos, step_size, __ATOMIC_SEQ_CST);
+    }
+
+    errno = 0;
+    return (long)steps;
+}
+
+long ring_buffer_read(
+    struct ring_buffer* r, void* data, uint32_t step_size, uint32_t steps) {
+    uint8_t* data_bytes = (uint8_t*)data;
+    uint32_t i;
+
+    for (i = 0; i < steps; ++i) {
+        if (!ring_buffer_can_read(r, step_size)) {
+            errno = -EAGAIN;
+            return (long)i;
+        }
+
+        // Needs to be split up into 2 reads for the edge case.
+        uint32_t available_at_end =
+            RING_BUFFER_SIZE - get_ring_pos(r->read_pos);
+
+        if (step_size > available_at_end) {
+            uint32_t remaining = step_size - available_at_end;
+            memcpy(
+                data_bytes + i * step_size,
+                &r->buf[get_ring_pos(r->read_pos)],
+                available_at_end);
+            memcpy(
+                data_bytes + i * step_size + available_at_end,
+                &r->buf[get_ring_pos(r->read_pos + available_at_end)],
+                remaining);
+        } else {
+            memcpy(
+                data_bytes + i * step_size,
+                &r->buf[get_ring_pos(r->read_pos)],
+                step_size);
+        }
+
+        __atomic_add_fetch(&r->read_pos, step_size, __ATOMIC_SEQ_CST);
+    }
+
+    errno = 0;
+    return (long)steps;
+}
+
+long ring_buffer_advance_write(
+    struct ring_buffer* r, uint32_t step_size, uint32_t steps) {
+    uint32_t i;
+
+    for (i = 0; i < steps; ++i) {
+        if (!ring_buffer_can_write(r, step_size)) {
+            errno = -EAGAIN;
+            return (long)i;
+        }
+
+        __atomic_add_fetch(&r->write_pos, step_size, __ATOMIC_SEQ_CST);
+    }
+
+    errno = 0;
+    return (long)steps;
+}
+
+long ring_buffer_advance_read(
+    struct ring_buffer* r, uint32_t step_size, uint32_t steps) {
+    uint32_t i;
+
+    for (i = 0; i < steps; ++i) {
+        if (!ring_buffer_can_read(r, step_size)) {
+            errno = -EAGAIN;
+            return (long)i;
+        }
+
+        __atomic_add_fetch(&r->read_pos, step_size, __ATOMIC_SEQ_CST);
+    }
+
+    errno = 0;
+    return (long)steps;
+}
+
+uint32_t ring_buffer_calc_shift(uint32_t size) {
+    uint32_t shift = 0;
+    while ((1 << shift) < size) {
+        ++shift;
+    }
+
+    // if size is not a power of 2,
+    if ((1 << shift) > size) {
+        --shift;
+    }
+    return shift;
+}
+
+void ring_buffer_view_init(
+    struct ring_buffer* r,
+    struct ring_buffer_view* v,
+    uint8_t* buf,
+    uint32_t size) {
+
+    uint32_t shift = ring_buffer_calc_shift(size);
+
+    ring_buffer_init(r);
+
+    v->buf = buf;
+    v->size = (1 << shift);
+    v->mask = (1 << shift) - 1;
+}
+
+void ring_buffer_init_view_only(
+    struct ring_buffer_view* v,
+    uint8_t* buf,
+    uint32_t size) {
+
+    uint32_t shift = ring_buffer_calc_shift(size);
+
+    v->buf = buf;
+    v->size = (1 << shift);
+    v->mask = (1 << shift) - 1;
+}
+
+uint32_t ring_buffer_view_get_ring_pos(
+    const struct ring_buffer_view* v,
+    uint32_t index) {
+    return index & v->mask;
+}
+
+bool ring_buffer_view_can_write(
+    const struct ring_buffer* r,
+    const struct ring_buffer_view* v,
+    uint32_t bytes) {
+    uint32_t read_view;
+    __atomic_load(&r->read_pos, &read_view, __ATOMIC_SEQ_CST);
+    return ring_buffer_view_get_ring_pos(
+            v, read_view - r->write_pos - 1) >= bytes;
+}
+
+bool ring_buffer_view_can_read(
+    const struct ring_buffer* r,
+    const struct ring_buffer_view* v,
+    uint32_t bytes) {
+    uint32_t write_view;
+    __atomic_load(&r->write_pos, &write_view, __ATOMIC_SEQ_CST);
+    return ring_buffer_view_get_ring_pos(
+            v, write_view - r->read_pos) >= bytes;
+}
+
+uint32_t ring_buffer_available_read(
+    const struct ring_buffer* r,
+    const struct ring_buffer_view* v) {
+    uint32_t write_view;
+    __atomic_load(&r->write_pos, &write_view, __ATOMIC_SEQ_CST);
+    if (v) {
+        return ring_buffer_view_get_ring_pos(
+                v, write_view - r->read_pos);
+    } else {
+        return get_ring_pos(write_view - r->read_pos);
+    }
+}
+
+int ring_buffer_copy_contents(
+    const struct ring_buffer* r,
+    const struct ring_buffer_view* v,
+    uint32_t wanted_bytes,
+    uint8_t* res) {
+
+    uint32_t total_available =
+        ring_buffer_available_read(r, v);
+    uint32_t available_at_end = 0;
+
+    if (v) {
+        available_at_end =
+            v->size - ring_buffer_view_get_ring_pos(v, r->read_pos);
+    } else {
+        available_at_end =
+            RING_BUFFER_SIZE - get_ring_pos(r->write_pos);
+    }
+
+    if (total_available < wanted_bytes) {
+        return -1;
+    }
+
+    if (v) {
+        if (wanted_bytes > available_at_end) {
+            uint32_t remaining = wanted_bytes - available_at_end;
+            memcpy(res,
+                   &v->buf[ring_buffer_view_get_ring_pos(v, r->read_pos)],
+                   available_at_end);
+            memcpy(res + available_at_end,
+                   &v->buf[ring_buffer_view_get_ring_pos(v, r->read_pos + available_at_end)],
+                   remaining);
+        } else {
+            memcpy(res,
+                   &v->buf[ring_buffer_view_get_ring_pos(v, r->read_pos)],
+                   wanted_bytes);
+        }
+    } else {
+        if (wanted_bytes > available_at_end) {
+            uint32_t remaining = wanted_bytes - available_at_end;
+            memcpy(res,
+                   &r->buf[get_ring_pos(r->read_pos)],
+                   available_at_end);
+            memcpy(res + available_at_end,
+                   &r->buf[get_ring_pos(r->read_pos + available_at_end)],
+                   remaining);
+        } else {
+            memcpy(res,
+                   &r->buf[get_ring_pos(r->read_pos)],
+                   wanted_bytes);
+        }
+    }
+    return 0;
+}
+
+long ring_buffer_view_write(
+    struct ring_buffer* r,
+    struct ring_buffer_view* v,
+    const void* data, uint32_t step_size, uint32_t steps) {
+
+    uint8_t* data_bytes = (uint8_t*)data;
+    uint32_t i;
+
+    for (i = 0; i < steps; ++i) {
+        if (!ring_buffer_view_can_write(r, v, step_size)) {
+            errno = -EAGAIN;
+            return (long)i;
+        }
+
+        // Needs to be split up into 2 writes for the edge case.
+        uint32_t available_at_end =
+            v->size - ring_buffer_view_get_ring_pos(v, r->write_pos);
+
+        if (step_size > available_at_end) {
+            uint32_t remaining = step_size - available_at_end;
+            memcpy(
+                &v->buf[ring_buffer_view_get_ring_pos(v, r->write_pos)],
+                data_bytes + i * step_size,
+                available_at_end);
+            memcpy(
+                &v->buf[ring_buffer_view_get_ring_pos(v, r->write_pos + available_at_end)],
+                data_bytes + i * step_size + available_at_end,
+                remaining);
+        } else {
+            memcpy(
+                &v->buf[ring_buffer_view_get_ring_pos(v, r->write_pos)],
+                data_bytes + i * step_size,
+                step_size);
+        }
+
+        __atomic_add_fetch(&r->write_pos, step_size, __ATOMIC_SEQ_CST);
+    }
+
+    errno = 0;
+    return (long)steps;
+
+}
+
+long ring_buffer_view_read(
+    struct ring_buffer* r,
+    struct ring_buffer_view* v,
+    void* data, uint32_t step_size, uint32_t steps) {
+    uint8_t* data_bytes = (uint8_t*)data;
+    uint32_t i;
+
+    for (i = 0; i < steps; ++i) {
+        if (!ring_buffer_view_can_read(r, v, step_size)) {
+            errno = -EAGAIN;
+            return (long)i;
+        }
+
+        // Needs to be split up into 2 reads for the edge case.
+        uint32_t available_at_end =
+            v->size - ring_buffer_view_get_ring_pos(v, r->read_pos);
+
+        if (step_size > available_at_end) {
+            uint32_t remaining = step_size - available_at_end;
+            memcpy(
+                data_bytes + i * step_size,
+                &v->buf[ring_buffer_view_get_ring_pos(v, r->read_pos)],
+                available_at_end);
+            memcpy(
+                data_bytes + i * step_size + available_at_end,
+                &v->buf[ring_buffer_view_get_ring_pos(v, r->read_pos + available_at_end)],
+                remaining);
+        } else {
+            memcpy(data_bytes + i * step_size,
+                   &v->buf[ring_buffer_view_get_ring_pos(v, r->read_pos)],
+                   step_size);
+        }
+        __atomic_add_fetch(&r->read_pos, step_size, __ATOMIC_SEQ_CST);
+    }
+
+    errno = 0;
+    return (long)steps;
+}
+
+void ring_buffer_yield() { }
+
+static void ring_buffer_sleep() {
+#ifdef _WIN32
+    Sleep(2);
+#else
+    usleep(2000);
+#endif
+}
+
+static uint64_t ring_buffer_curr_us() {
+    uint64_t res;
+    struct timeval tv;
+    gettimeofday(&tv, NULL);
+    res = tv.tv_sec * 1000000ULL + tv.tv_usec;
+    return res;
+}
+
+static const uint32_t yield_backoff_us = 1000;
+static const uint32_t sleep_backoff_us = 2000;
+
+bool ring_buffer_wait_write(
+    const struct ring_buffer* r,
+    const struct ring_buffer_view* v,
+    uint32_t bytes,
+    uint64_t timeout_us) {
+
+    uint64_t start_us = ring_buffer_curr_us();
+    uint64_t curr_wait_us;
+
+    bool can_write =
+        v ? ring_buffer_view_can_write(r, v, bytes) :
+            ring_buffer_can_write(r, bytes);
+
+    while (!can_write) {
+        ring_buffer_yield();
+        can_write =
+            v ? ring_buffer_view_can_write(r, v, bytes) :
+                ring_buffer_can_write(r, bytes);
+    }
+
+    return true;
+}
+
+bool ring_buffer_wait_read(
+    const struct ring_buffer* r,
+    const struct ring_buffer_view* v,
+    uint32_t bytes,
+    uint64_t timeout_us) {
+
+    bool can_read =
+        v ? ring_buffer_view_can_read(r, v, bytes) :
+            ring_buffer_can_read(r, bytes);
+
+    while (!can_read) {
+        ring_buffer_yield();
+        can_read =
+            v ? ring_buffer_view_can_read(r, v, bytes) :
+                ring_buffer_can_read(r, bytes);
+    }
+
+    ((struct ring_buffer*)r)->read_live_count++;
+    return true;
+}
+
+static uint32_t get_step_size(
+    struct ring_buffer* r,
+    struct ring_buffer_view* v,
+    uint32_t bytes) {
+
+    uint32_t step_shift = 0;
+    uint32_t available = v ? (v->size >> 1) : (RING_BUFFER_SIZE >> 1);
+    uint32_t res = available < bytes ? available : bytes;
+
+    return res;
+}
+
+void ring_buffer_write_fully(
+    struct ring_buffer* r,
+    struct ring_buffer_view* v,
+    const void* data,
+    uint32_t bytes) {
+    ring_buffer_write_fully_with_abort(r, v, data, bytes, 0, 0);
+}
+
+void ring_buffer_read_fully(
+    struct ring_buffer* r,
+    struct ring_buffer_view* v,
+    void* data,
+    uint32_t bytes) {
+    ring_buffer_read_fully_with_abort(r, v, data, bytes, 0, 0);
+}
+
+uint32_t ring_buffer_write_fully_with_abort(
+    struct ring_buffer* r,
+    struct ring_buffer_view* v,
+    const void* data,
+    uint32_t bytes,
+    uint32_t abort_value,
+    const volatile uint32_t* abort_ptr) {
+
+    uint32_t candidate_step = get_step_size(r, v, bytes);
+    uint32_t processed = 0;
+
+    uint8_t* dst = (uint8_t*)data;
+
+    while (processed < bytes) {
+        if (bytes - processed < candidate_step) {
+            candidate_step = bytes - processed;
+        }
+
+        long processed_here = 0;
+        ring_buffer_wait_write(r, v, candidate_step, (uint64_t)(-1));
+
+        if (v) {
+            processed_here = ring_buffer_view_write(r, v, dst + processed, candidate_step, 1);
+        } else {
+            processed_here = ring_buffer_write(r, dst + processed, candidate_step, 1);
+        }
+
+        processed += processed_here ? candidate_step : 0;
+
+        if (abort_ptr && (abort_value == *abort_ptr)) {
+            return processed;
+        }
+    }
+
+    return processed;
+}
+
+uint32_t ring_buffer_read_fully_with_abort(
+    struct ring_buffer* r,
+    struct ring_buffer_view* v,
+    void* data,
+    uint32_t bytes,
+    uint32_t abort_value,
+    const volatile uint32_t* abort_ptr) {
+
+    uint32_t candidate_step = get_step_size(r, v, bytes);
+    uint32_t processed = 0;
+
+    uint8_t* dst = (uint8_t*)data;
+
+    while (processed < bytes) {
+        ring_buffer_pause();
+        if (bytes - processed < candidate_step) {
+            candidate_step = bytes - processed;
+        }
+
+        long processed_here = 0;
+        ring_buffer_wait_read(r, v, candidate_step, (uint64_t)(-1));
+
+        if (v) {
+            processed_here = ring_buffer_view_read(r, v, dst + processed, candidate_step, 1);
+        } else {
+            processed_here = ring_buffer_read(r, dst + processed, candidate_step, 1);
+        }
+
+        processed += processed_here ? candidate_step : 0;
+
+        if (abort_ptr && (abort_value == *abort_ptr)) {
+            return processed;
+        }
+    }
+
+    return processed;
+}
+
+void ring_buffer_sync_init(struct ring_buffer* r) {
+    __atomic_store_n(&r->state, RING_BUFFER_SYNC_PRODUCER_IDLE, __ATOMIC_SEQ_CST);
+}
+
+bool ring_buffer_producer_acquire(struct ring_buffer* r) {
+    uint32_t expected_idle = RING_BUFFER_SYNC_PRODUCER_IDLE;
+    bool success = __atomic_compare_exchange_n(
+        &r->state,
+        &expected_idle,
+        RING_BUFFER_SYNC_PRODUCER_ACTIVE,
+        false /* strong */,
+        __ATOMIC_SEQ_CST,
+        __ATOMIC_SEQ_CST);
+    return success;
+}
+
+bool ring_buffer_producer_acquire_from_hangup(struct ring_buffer* r) {
+    uint32_t expected_hangup = RING_BUFFER_SYNC_CONSUMER_HUNG_UP;
+    bool success = __atomic_compare_exchange_n(
+        &r->state,
+        &expected_hangup,
+        RING_BUFFER_SYNC_PRODUCER_ACTIVE,
+        false /* strong */,
+        __ATOMIC_SEQ_CST,
+        __ATOMIC_SEQ_CST);
+    return success;
+}
+
+void ring_buffer_producer_wait_hangup(struct ring_buffer* r) {
+    while (__atomic_load_n(&r->state, __ATOMIC_SEQ_CST) !=
+           RING_BUFFER_SYNC_CONSUMER_HUNG_UP) {
+        ring_buffer_yield();
+    }
+}
+
+void ring_buffer_producer_idle(struct ring_buffer* r) {
+    __atomic_store_n(&r->state, RING_BUFFER_SYNC_PRODUCER_IDLE, __ATOMIC_SEQ_CST);
+}
+
+bool ring_buffer_consumer_hangup(struct ring_buffer* r) {
+    uint32_t expected_idle = RING_BUFFER_SYNC_PRODUCER_IDLE;
+    bool success = __atomic_compare_exchange_n(
+        &r->state,
+        &expected_idle,
+        RING_BUFFER_SYNC_CONSUMER_HANGING_UP,
+        false /* strong */,
+        __ATOMIC_SEQ_CST,
+        __ATOMIC_SEQ_CST);
+    return success;
+}
+
+void ring_buffer_consumer_wait_producer_idle(struct ring_buffer* r) {
+    while (__atomic_load_n(&r->state, __ATOMIC_SEQ_CST) !=
+           RING_BUFFER_SYNC_PRODUCER_IDLE) {
+        ring_buffer_yield();
+    }
+}
+
+void ring_buffer_consumer_hung_up(struct ring_buffer* r) {
+    __atomic_store_n(&r->state, RING_BUFFER_SYNC_CONSUMER_HUNG_UP, __ATOMIC_SEQ_CST);
+}
diff --git a/android-emu/android/base/ring_buffer.h b/android-emu/android/base/ring_buffer.h
new file mode 100644
index 0000000..390a758
--- /dev/null
+++ b/android-emu/android/base/ring_buffer.h
@@ -0,0 +1,232 @@
+// Copyright 2018 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+#pragma once
+
+#include "android/utils/compiler.h"
+
+ANDROID_BEGIN_HEADER
+
+#include <stdbool.h>
+#include <stdint.h>
+
+#define RING_BUFFER_SHIFT 11
+#define RING_BUFFER_SIZE (1 << RING_BUFFER_SHIFT)
+#define NUM_CONFIG_FIELDS 32
+
+// Single producer/consumer ring buffer struct that can be shared
+// between host and guest as-is.
+struct ring_buffer {
+    uint32_t host_version;
+    uint32_t guest_version;
+    uint32_t write_pos; // Atomically updated for the consumer
+    uint32_t unused0[13]; // Separate cache line
+    uint32_t read_pos; // Atomically updated for the producer
+    uint32_t read_live_count;
+    uint32_t read_yield_count;
+    uint32_t read_sleep_us_count;
+    uint32_t unused1[12]; // Separate cache line
+    uint8_t buf[RING_BUFFER_SIZE];
+    uint32_t state; // An atomically updated variable from both
+                    // producer and consumer for other forms of
+                    // coordination.
+    // Configuration fields
+    uint32_t config[NUM_CONFIG_FIELDS];
+};
+
+void ring_buffer_init(struct ring_buffer* r);
+
+// Writes or reads step_size at a time. Sets errno=EAGAIN if full or empty.
+// Returns the number of step_size steps read.
+long ring_buffer_write(
+    struct ring_buffer* r, const void* data, uint32_t step_size, uint32_t steps);
+long ring_buffer_read(
+    struct ring_buffer* r, void* data, uint32_t step_size, uint32_t steps);
+// Like ring_buffer_write / ring_buffer_read, but merely advances the counters
+// without reading or writing anything. Returns the number of step_size steps
+// advanced.
+long ring_buffer_advance_write(
+    struct ring_buffer* r, uint32_t step_size, uint32_t steps);
+long ring_buffer_advance_read(
+    struct ring_buffer* r, uint32_t step_size, uint32_t steps);
+
+// If we want to work with dynamically allocated buffers, a separate struct is
+// needed; the host and guest are in different address spaces and thus have
+// different views of the same memory, with the host and guest having different
+// copies of this struct.
+struct ring_buffer_view {
+    uint8_t* buf;
+    uint32_t size;
+    uint32_t mask;
+};
+
+// Convenience struct that holds a pointer to a ring along with a view.  It's a
+// common pattern for the ring and the buffer of the view to be shared between
+// two entities (in this case, usually guest and host).
+struct ring_buffer_with_view {
+    struct ring_buffer* ring;
+    struct ring_buffer_view view;
+};
+
+// Calculates the highest power of 2 so that
+// (1 << shift) <= size.
+uint32_t ring_buffer_calc_shift(uint32_t size);
+
+// Initializes ring buffer with view using |buf|. If |size| is not a power of
+// two, then the buffer will assume a size equal to the greater power of two
+// less than |size|.
+void ring_buffer_view_init(
+    struct ring_buffer* r,
+    struct ring_buffer_view* v,
+    uint8_t* buf,
+    uint32_t size);
+
+void ring_buffer_init_view_only(
+    struct ring_buffer_view* v,
+    uint8_t* buf,
+    uint32_t size);
+
+// Read/write functions with the view.
+long ring_buffer_view_write(
+    struct ring_buffer* r,
+    struct ring_buffer_view* v,
+    const void* data, uint32_t step_size, uint32_t steps);
+long ring_buffer_view_read(
+    struct ring_buffer* r,
+    struct ring_buffer_view* v,
+    void* data, uint32_t step_size, uint32_t steps);
+
+// Usage of ring_buffer as a waitable object.
+// These functions will back off if spinning too long.
+//
+// if |v| is null, it is assumed that the statically allocated ring buffer is
+// used.
+//
+// Returns true if ring buffer became available, false if timed out.
+bool ring_buffer_wait_write(
+    const struct ring_buffer* r,
+    const struct ring_buffer_view* v,
+    uint32_t bytes,
+    uint64_t timeout_us);
+bool ring_buffer_wait_read(
+    const struct ring_buffer* r,
+    const struct ring_buffer_view* v,
+    uint32_t bytes,
+    uint64_t timeout_us);
+
+// read/write fully, blocking if there is nothing to read/write.
+void ring_buffer_write_fully(
+    struct ring_buffer* r,
+    struct ring_buffer_view* v,
+    const void* data,
+    uint32_t bytes);
+void ring_buffer_read_fully(
+    struct ring_buffer* r,
+    struct ring_buffer_view* v,
+    void* data,
+    uint32_t bytes);
+
+// Like read/write fully, but with an abort value. The value is read from
+// |abortPtr| each time. If |abortPtr| is null, then behaves the same
+// as ring_buffer_(read|write)_fully.
+// Returns the actual number of bytes sent or received.
+uint32_t ring_buffer_write_fully_with_abort(
+    struct ring_buffer* r,
+    struct ring_buffer_view* v,
+    const void* data,
+    uint32_t bytes,
+    uint32_t abort_value,
+    const volatile uint32_t* abort_ptr);
+uint32_t ring_buffer_read_fully_with_abort(
+    struct ring_buffer* r,
+    struct ring_buffer_view* v,
+    void* data,
+    uint32_t bytes,
+    uint32_t abort_value,
+    const volatile uint32_t* abort_ptr);
+
+uint32_t ring_buffer_view_get_ring_pos(
+    const struct ring_buffer_view* v,
+    uint32_t index);
+
+bool ring_buffer_can_write(
+    const struct ring_buffer* r, uint32_t bytes);
+bool ring_buffer_can_read(
+    const struct ring_buffer* r, uint32_t bytes);
+bool ring_buffer_view_can_write(
+    const struct ring_buffer* r,
+    const struct ring_buffer_view* v,
+    uint32_t bytes);
+bool ring_buffer_view_can_read(
+    const struct ring_buffer* r,
+    const struct ring_buffer_view* v,
+    uint32_t bytes);
+uint32_t ring_buffer_available_read(
+    const struct ring_buffer* r,
+    const struct ring_buffer_view* v);
+// Copies out contents from the consumer side of
+// ring buffer/view |r,v|.
+// If there is less available read than |wanted_bytes|,
+// returns -1.
+// On success, returns 0.
+int ring_buffer_copy_contents(
+    const struct ring_buffer* r,
+    const struct ring_buffer_view* v,
+    uint32_t wanted_bytes,
+    uint8_t* res);
+
+// Lockless synchronization where the consumer is allowed to hang up and go to
+// sleep. This can be considered a sort of asymmetric lock for two threads,
+// where the consumer can be more sleepy. It captures the pattern we usually use
+// for emulator devices; the guest asks the host for something, and some host
+// thread services the request and goes back to sleep.
+enum ring_buffer_sync_state {
+    RING_BUFFER_SYNC_PRODUCER_IDLE = 0,
+    RING_BUFFER_SYNC_PRODUCER_ACTIVE = 1,
+    RING_BUFFER_SYNC_CONSUMER_HANGING_UP = 2,
+    RING_BUFFER_SYNC_CONSUMER_HUNG_UP = 3,
+};
+
+// Sync state is RING_BUFFER_SYNC_PRODUCER_IDLE.
+void ring_buffer_sync_init(struct ring_buffer* r);
+
+// Tries to acquire the channel for sending.
+// Returns false if the consumer was in the middle of hanging up,
+// true if the producer successfully acquired the channel
+// (put it in the RING_BUFFER_SYNC_PRODUCER_ACTIVE state).
+bool ring_buffer_producer_acquire(struct ring_buffer* r);
+// Same as above, but acquires from RING_BUFFER_SYNC_CONSUMER_HUNG_UP.
+bool ring_buffer_producer_acquire_from_hangup(struct ring_buffer* r);
+// Waits until the consumer hangs up.
+void ring_buffer_producer_wait_hangup(struct ring_buffer* r);
+// Sets the state back to RING_BUFFER_SYNC_PRODUCER_IDLE.
+void ring_buffer_producer_idle(struct ring_buffer* r);
+
+// There is no symmetric consumer acquire because the consumer can consume with
+// the ring buffer being in any state (albeit with long waiting if the producer
+// does not send anything)
+
+// Tries to acquire the channel on the consumer side for
+// hanging up. Returns false if the producer is in the middle of sending,
+// true if the consumer successfully hung up the channel
+// (put it in the RING_BUFFER_SYNC_CONSUMER_HUNG_UP state).
+bool ring_buffer_consumer_hangup(struct ring_buffer* r);
+// Waits until the producer has set the state to
+// RING_BUFFER_SYNC_PRODUCER_IDLE.
+void ring_buffer_consumer_wait_producer_idle(struct ring_buffer* r);
+// Sets the state to hung up.
+void ring_buffer_consumer_hung_up(struct ring_buffer* r);
+
+// Convenient function to reschedule thread
+void ring_buffer_yield();
+ANDROID_END_HEADER
diff --git a/android-emu/android/base/synchronization/AndroidConditionVariable.h b/android-emu/android/base/synchronization/AndroidConditionVariable.h
new file mode 100644
index 0000000..21cbdc0
--- /dev/null
+++ b/android-emu/android/base/synchronization/AndroidConditionVariable.h
@@ -0,0 +1,212 @@
+// Copyright (C) 2014 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#pragma once
+
+#include "android/base/Compiler.h"
+#include "android/base/synchronization/AndroidLock.h"
+
+#ifdef _WIN32
+#include <windows.h>
+#else
+#include <pthread.h>
+#endif
+
+#include <assert.h>
+
+namespace android {
+namespace base {
+namespace guest {
+
+// A class that implements a condition variable, which can be used in
+// association with a Lock to blocking-wait for specific conditions.
+// Useful to implement various synchronization data structures.
+class ConditionVariable {
+public:
+    // A set of functions to efficiently unlock the lock used with
+    // the current condition variable and signal or broadcast it.
+    //
+    // The functions are needed because on some platforms (Posix) it's more
+    // efficient to signal the variable before unlocking mutex, while on others
+    // (Windows) it's exactly the opposite. Functions implement the best way
+    // for each platform and abstract it out from the user.
+    void signalAndUnlock(StaticLock* lock);
+    void signalAndUnlock(AutoLock* lock);
+
+    void broadcastAndUnlock(StaticLock* lock);
+    void broadcastAndUnlock(AutoLock* lock);
+
+    void wait(AutoLock* userLock) {
+        assert(userLock->mLocked);
+        wait(&userLock->mLock);
+    }
+
+    //
+    // Convenience functions to get rid of the loop in condition variable usage
+    // Instead of hand-writing a loop, e.g.
+    //
+    //      while (mRefCount < 3) {
+    //          mCv.wait(&mLock);
+    //      }
+    //
+    // use the following two wait() overloads:
+    //
+    //      mCv.wait(&mLock, [this]() { return mRefCount >= 3; });
+    //
+    // Parameters:
+    // |lock| - a Lock or AutoLock pointer used with the condition variable.
+    // |pred| - a functor predicate that's compatible with "bool pred()"
+    //          signature and returns a condition when one should stop waiting.
+    //
+
+    template <class Predicate>
+    void wait(StaticLock* lock, Predicate pred) {
+        while (!pred()) {
+            this->wait(lock);
+        }
+    }
+
+    template <class Predicate>
+    void wait(AutoLock* lock, Predicate pred) {
+        this->wait(&lock->mLock, pred);
+    }
+
+#ifdef _WIN32
+
+    ConditionVariable() {
+        ::InitializeConditionVariable(&mCond);
+    }
+
+    // There's no special function to destroy CONDITION_VARIABLE in Windows.
+    ~ConditionVariable() = default;
+
+    // Wait until the condition variable is signaled. Note that spurious
+    // wakeups are always a possibility, so always check the condition
+    // in a loop, i.e. do:
+    //
+    //    while (!condition) { condVar.wait(&lock); }
+    //
+    // instead of:
+    //
+    //    if (!condition) { condVar.wait(&lock); }
+    //
+    void wait(StaticLock* userLock) {
+        ::SleepConditionVariableSRW(&mCond, &userLock->mLock, INFINITE, 0);
+    }
+
+    bool timedWait(StaticLock *userLock, System::Duration waitUntilUs) {
+        const auto now = System::get()->getUnixTimeUs();
+        const auto timeout =
+                std::max<System::Duration>(0, waitUntilUs  - now) / 1000;
+        return ::SleepConditionVariableSRW(
+                    &mCond, &userLock->mLock, timeout, 0) != 0;
+    }
+
+    // Signal that a condition was reached. This will wake at least (and
+    // preferrably) one waiting thread that is blocked on wait().
+    void signal() {
+        ::WakeConditionVariable(&mCond);
+    }
+
+    // Like signal(), but wakes all of the waiting threads.
+    void broadcast() {
+        ::WakeAllConditionVariable(&mCond);
+    }
+
+private:
+    CONDITION_VARIABLE mCond;
+
+#else  // !_WIN32
+
+    // Note: on Posix systems, make it a naive wrapper around pthread_cond_t.
+
+    ConditionVariable() {
+        pthread_cond_init(&mCond, NULL);
+    }
+
+    ~ConditionVariable() {
+        pthread_cond_destroy(&mCond);
+    }
+
+    void wait(StaticLock* userLock) {
+        pthread_cond_wait(&mCond, &userLock->mLock);
+    }
+
+    bool timedWait(StaticLock* userLock, uint64_t waitUntilUs) {
+        timespec abstime;
+        abstime.tv_sec = waitUntilUs / 1000000LL;
+        abstime.tv_nsec = (waitUntilUs % 1000000LL) * 1000;
+        return timedWait(userLock, abstime);
+    }
+
+    bool timedWait(StaticLock* userLock, const timespec& abstime) {
+        return pthread_cond_timedwait(&mCond, &userLock->mLock, &abstime) == 0;
+    }
+
+    void signal() {
+        pthread_cond_signal(&mCond);
+    }
+
+    void broadcast() {
+        pthread_cond_broadcast(&mCond);
+    }
+
+private:
+    pthread_cond_t mCond;
+
+#endif  // !_WIN32
+
+    DISALLOW_COPY_ASSIGN_AND_MOVE(ConditionVariable);
+};
+
+#ifdef _WIN32
+inline void ConditionVariable::signalAndUnlock(StaticLock* lock) {
+    lock->unlock();
+    signal();
+}
+inline void ConditionVariable::signalAndUnlock(AutoLock* lock) {
+    lock->unlock();
+    signal();
+}
+
+inline void ConditionVariable::broadcastAndUnlock(StaticLock* lock) {
+    lock->unlock();
+    broadcast();
+}
+inline void ConditionVariable::broadcastAndUnlock(AutoLock* lock) {
+    lock->unlock();
+    broadcast();
+}
+#else  // !_WIN32
+inline void ConditionVariable::signalAndUnlock(StaticLock* lock) {
+    signal();
+    lock->unlock();
+}
+inline void ConditionVariable::signalAndUnlock(AutoLock* lock) {
+    signal();
+    lock->unlock();
+}
+inline void ConditionVariable::broadcastAndUnlock(StaticLock* lock) {
+    broadcast();
+    lock->unlock();
+}
+inline void ConditionVariable::broadcastAndUnlock(AutoLock* lock) {
+    broadcast();
+    lock->unlock();
+}
+#endif  // !_WIN32
+
+}  // namespace guest
+}  // namespace base
+}  // namespace android
diff --git a/android-emu/android/base/synchronization/AndroidMessageChannel.cpp b/android-emu/android/base/synchronization/AndroidMessageChannel.cpp
new file mode 100644
index 0000000..7ba0263
--- /dev/null
+++ b/android-emu/android/base/synchronization/AndroidMessageChannel.cpp
@@ -0,0 +1,122 @@
+// Copyright 2014 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "android/base/synchronization/AndroidMessageChannel.h"
+
+namespace android {
+namespace base {
+namespace guest {
+
+MessageChannelBase::MessageChannelBase(size_t capacity) : mCapacity(capacity) {}
+
+size_t MessageChannelBase::size() const {
+    AutoLock lock(mLock);
+    return mCount;
+}
+
+void MessageChannelBase::stop() {
+    android::base::guest::AutoLock lock(mLock);
+    mStopped = true;
+    mCount = 0;
+    mCanRead.broadcast();
+    mCanWrite.broadcastAndUnlock(&lock);
+}
+
+bool MessageChannelBase::isStopped() const {
+    AutoLock lock(mLock);
+    return isStoppedLocked();
+}
+
+void MessageChannelBase::waitForEmpty() {
+    AutoLock lock(mLock);
+    while (mCount > 0) {
+        mCanWrite.wait(&lock);
+    }
+}
+
+size_t MessageChannelBase::beforeWrite() {
+    mLock.lock();
+    while (mCount >= mCapacity && !mStopped) {
+        mCanWrite.wait(&mLock);
+    }
+    // Return value is undefined if stopped, so let's save a branch and skip the
+    // check for it.
+    size_t result = mPos + mCount;
+    if (result >= mCapacity) {
+        result -= mCapacity;
+    }
+    return result;
+}
+
+Optional<size_t> MessageChannelBase::beforeTryWrite() {
+    mLock.lock();
+
+    if (mCount >= mCapacity || mStopped) {
+        return {};
+    }
+    size_t result = mPos + mCount;
+    if (result >= mCapacity) {
+        result -= mCapacity;
+    }
+    return result;
+}
+
+void MessageChannelBase::afterWrite(bool success) {
+    if (success) {
+        ++mCount;
+    }
+    mCanRead.signalAndUnlock(&mLock);
+}
+
+size_t MessageChannelBase::beforeRead() {
+    mLock.lock();
+    while (mCount == 0 && !mStopped) {
+        mCanRead.wait(&mLock);
+    }
+    return mPos; // return value is undefined if stopped, so let's save a branch
+}
+
+Optional<size_t> MessageChannelBase::beforeTryRead() {
+    mLock.lock();
+
+    if (mCount == 0 || mStopped) {
+        return {};
+    }
+    return mPos;
+}
+
+Optional<size_t> MessageChannelBase::beforeTimedRead(uint64_t wallTimeUs) {
+    mLock.lock();
+
+    while (mCount == 0 && !mStopped) {
+        if (!mCanRead.timedWait(&mLock, wallTimeUs)) {
+            return {};
+        }
+    }
+    return mPos;
+}
+
+void MessageChannelBase::afterRead(bool success) {
+    if (success) {
+        if (++mPos == mCapacity) {
+            mPos = 0U;
+        }
+        --mCount;
+    }
+    mCanWrite.signalAndUnlock(&mLock);
+}
+
+}  // namespace guest
+}  // namespace base
+}  // namespace android
diff --git a/android-emu/android/base/synchronization/AndroidMessageChannel.h b/android-emu/android/base/synchronization/AndroidMessageChannel.h
new file mode 100644
index 0000000..1d5d2de
--- /dev/null
+++ b/android-emu/android/base/synchronization/AndroidMessageChannel.h
@@ -0,0 +1,210 @@
+// Copyright 2014 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#pragma once
+
+#include "android/base/Optional.h"
+#include "android/base/synchronization/AndroidConditionVariable.h"
+#include "android/base/synchronization/AndroidLock.h"
+
+#include <utility>
+#include <stddef.h>
+
+namespace android {
+namespace base {
+namespace guest {
+
+// Base non-templated class used to reduce the amount of template
+// specialization.
+class MessageChannelBase {
+public:
+    // Get the current channel size
+    size_t size() const;
+
+    // Abort the currently pending operations and don't allow any other ones
+    void stop();
+
+    // Check if the channel is stopped.
+    bool isStopped() const;
+
+    // Block until the channel has no pending messages.
+    void waitForEmpty();
+
+protected:
+    // Constructor. |capacity| is the buffer capacity in messages.
+    MessageChannelBase(size_t capacity);
+
+    // Destructor.
+    ~MessageChannelBase() = default;
+
+    // Call this method in the sender thread before writing a new message.
+    // This returns the position of the available slot in the message array
+    // where to copy the new fixed-size message. After the copy, call
+    // afterWrite().
+    // If the channel is stopped, return value is undefined.
+    size_t beforeWrite();
+
+    // Same as beforeWrite(), but returns an empty optional if there was
+    // no room to write to instead of waiting for it.
+    // One still needs to call afterWrite() anyway.
+    Optional<size_t> beforeTryWrite();
+
+    // To be called after trying to write a new fixed-size message (which should
+    // happen after beforeWrite() or beforeTryWrite()).
+    // |success| must be true to indicate that a new item was added to the
+    // channel, or false otherwise (i.e. if the channel is stopped, or if
+    // beforeTryWrite() returned an empty optional).
+    void afterWrite(bool success);
+
+    // Call this method in the receiver thread before reading a new message.
+    // This returns the position in the message array where the new message
+    // can be read. Caller must process the message, then call afterRead().
+    // If the channel is stopped, return value is undefined.
+    size_t beforeRead();
+
+    // Same as beforeRead(), but returns an empty optional if there was
+    // no data to read instead of waiting for it.
+    // One still needs to call afterWrite() anyway.
+    Optional<size_t> beforeTryRead();
+
+    // Same as beforeRead(), but returns an empty optional if no data arrived
+    // by the |wallTimeUs| absolute time. One still needs to call
+    // afterWrite() anyway.
+    Optional<size_t> beforeTimedRead(uint64_t wallTimeUs);
+
+    // To be called after reading a fixed-size message from the channel (which
+    // must happen after beforeRead() or beforeTryRead()).
+    // |success| must be true to indicate that a message was read, or false
+    // otherwise (i.e. if the channel is stopped or if beforeTryRead() returned
+    // an empty optional).
+    void afterRead(bool success);
+
+    // A version of isStopped() that doesn't lock the channel but expects it
+    // to be locked by the caller.
+    bool isStoppedLocked() const { return mStopped; }
+
+private:
+    size_t mPos = 0;
+    size_t mCapacity;
+    size_t mCount = 0;
+    bool mStopped = false;
+    mutable Lock mLock;     // Mutable to allow const members to lock it.
+    ConditionVariable mCanRead;
+    ConditionVariable mCanWrite;
+};
+
+// Helper class used to implement an uni-directional IPC channel between
+// two threads. The channel can be used to send fixed-size messages of type
+// |T|, with an internal buffer size of |CAPACITY| items. All calls are
+// blocking.
+//
+// Usage is pretty straightforward:
+//
+//   - From the sender thread, call send(msg);
+//   - From the receiver thread, call receive(&msg);
+//   - If you want to stop the IPC, call stop();
+template <typename T, size_t CAPACITY>
+class MessageChannel : public MessageChannelBase {
+public:
+    MessageChannel() : MessageChannelBase(CAPACITY) {}
+
+    bool send(const T& msg) {
+        const size_t pos = beforeWrite();
+        const bool res = !isStoppedLocked();
+        if (res) {
+            mItems[pos] = msg;
+        }
+        afterWrite(res);
+        return res;
+    }
+
+    bool send(T&& msg) {
+        const size_t pos = beforeWrite();
+        const bool res = !isStoppedLocked();
+        if (res) {
+            mItems[pos] = std::move(msg);
+        }
+        afterWrite(res);
+        return res;
+    }
+
+    bool trySend(const T& msg) {
+        const auto pos = beforeTryWrite();
+        if (pos) {
+            mItems[*pos] = msg;
+        }
+        afterWrite(pos);
+        return pos;
+    }
+
+    bool trySend(T&& msg) {
+        const auto pos = beforeTryWrite();
+        if (pos) {
+            mItems[*pos] = std::move(msg);
+        }
+        afterWrite(pos);
+        return pos;
+    }
+
+    bool receive(T* msg) {
+        const size_t pos = beforeRead();
+        const bool res = !isStoppedLocked();
+        if (res) {
+            *msg = std::move(mItems[pos]);
+        }
+        afterRead(res);
+        return res;
+    }
+
+    Optional<T> receive() {
+        const size_t pos = beforeRead();
+        if (!isStoppedLocked()) {
+            Optional<T> msg(std::move(mItems[pos]));
+            afterRead(true);
+            return msg;
+        } else {
+            afterRead(false);
+            return {};
+        }
+    }
+
+    bool tryReceive(T* msg) {
+        const auto pos = beforeTryRead();
+        if (pos) {
+            *msg = std::move(mItems[*pos]);
+        }
+        afterRead(pos);
+        return pos;
+    }
+
+    Optional<T> timedReceive(uint64_t wallTimeUs) {
+        const auto pos = beforeTimedRead(wallTimeUs);
+        if (pos && !isStoppedLocked()) {
+            Optional<T> res(std::move(mItems[*pos]));
+            afterRead(true);
+            return res;
+        }
+        afterRead(false);
+        return {};
+    }
+
+    constexpr size_t capacity() const { return CAPACITY; }
+
+private:
+    T mItems[CAPACITY];
+};
+
+}  // namespace guest
+}  // namespace base
+}  // namespace android
diff --git a/android-emu/android/base/threads/AndroidFunctorThread.cpp b/android-emu/android/base/threads/AndroidFunctorThread.cpp
new file mode 100644
index 0000000..025f0d8
--- /dev/null
+++ b/android-emu/android/base/threads/AndroidFunctorThread.cpp
@@ -0,0 +1,35 @@
+// Copyright (C) 2015 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "android/base/threads/AndroidFunctorThread.h"
+
+#include <assert.h>
+
+namespace android {
+namespace base {
+namespace guest {
+
+FunctorThread::FunctorThread(Functor&& func, ThreadFlags flags)
+    : Thread(flags)
+    , mThreadFunc(std::move(func)) {
+    assert(mThreadFunc);
+}
+
+intptr_t FunctorThread::main() {
+    return mThreadFunc();
+}
+
+}  // namespace guest
+}  // namespace base
+}  // namespace android
diff --git a/android-emu/android/base/threads/AndroidFunctorThread.h b/android-emu/android/base/threads/AndroidFunctorThread.h
new file mode 100644
index 0000000..5b88cb4
--- /dev/null
+++ b/android-emu/android/base/threads/AndroidFunctorThread.h
@@ -0,0 +1,60 @@
+// Copyright (C) 2015 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#pragma once
+
+#include "android/base/TypeTraits.h"
+#include "android/base/threads/AndroidThread.h"
+#include "android/base/threads/AndroidThreadTypes.h"
+
+#include <utility>
+
+// FunctorThread class is an implementation of base Thread interface that
+// allows one to run a function object in separate thread. It's mostly a
+// convenience class so one doesn't need to create a separate class if the only
+// needed thing is to run a specific existing function in a thread.
+
+namespace android {
+namespace base {
+namespace guest {
+
+class FunctorThread : public android::base::guest::Thread {
+public:
+    using Functor = android::base::guest::ThreadFunctor;
+
+    explicit FunctorThread(const Functor& func,
+                           ThreadFlags flags = ThreadFlags::MaskSignals)
+        : FunctorThread(Functor(func), flags) {}
+
+    explicit FunctorThread(Functor&& func,
+                           ThreadFlags flags = ThreadFlags::MaskSignals);
+
+    // A constructor from a void function in case when result isn't important.
+    template <class Func, class = enable_if<is_callable_as<Func, void()>>>
+    explicit FunctorThread(Func&& func,
+                           ThreadFlags flags = ThreadFlags::MaskSignals)
+        : Thread(flags), mThreadFunc([func = std::move(func)]() {
+              func();
+              return intptr_t();
+          }) {}
+
+private:
+    intptr_t main() override;
+
+    Functor mThreadFunc;
+};
+
+}  // namespace guest
+}  // namespace base
+}  // namespace android
diff --git a/android-emu/android/base/threads/AndroidThread.h b/android-emu/android/base/threads/AndroidThread.h
new file mode 100644
index 0000000..1916378
--- /dev/null
+++ b/android-emu/android/base/threads/AndroidThread.h
@@ -0,0 +1,150 @@
+// Copyright (C) 2014 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#pragma once
+
+#include "android/base/Compiler.h"
+#include "android/base/threads/AndroidThreadTypes.h"
+#include "android/base/synchronization/AndroidLock.h"
+
+#ifdef _WIN32
+#include <windows.h>
+#else
+#include <pthread.h>
+#endif
+
+#include <inttypes.h>
+
+namespace android {
+namespace base {
+namespace guest {
+
+// Wrapper class for platform-specific threads.
+// To create your own thread, define a sub-class of emugl::Thread
+// and override its main() method.
+//
+// For example:
+//
+//    class MyThread : public emugl::Thread {
+//    public:
+//        MyThread() : Thread() {}
+//
+//        virtual intptr_t main() {
+//            ... main thread loop implementation
+//            return 0;
+//        }
+//    };
+//
+//    ...
+//
+//    // Create new instance, but does not start it.
+//    MyThread* thread = new MyThread();
+//
+//    // Start the thread.
+//    thread->start();
+//
+//    // Wait for thread completion, and gets result into |exitStatus|.
+//    int exitStatus;
+//    thread->wait(&exitStatus);
+//
+class Thread {
+    DISALLOW_COPY_ASSIGN_AND_MOVE(Thread);
+
+public:
+    // Public constructor.
+    Thread(ThreadFlags flags = ThreadFlags::MaskSignals, int stackSize = 0);
+
+    // Virtual destructor.
+    virtual ~Thread();
+
+    // Override this method in your own thread sub-classes. This will
+    // be called when start() is invoked on the Thread instance.
+    virtual intptr_t main() = 0;
+
+    // Override this if you need to execute some code after thread has
+    // exited main() and is guaranteed not to access any of its members.
+    // E.g. if you need to delete a thread object from the same thread
+    // it has created
+    virtual void onExit() {}
+
+    // Start a thread instance. Return true on success, false otherwise
+    // (e.g. if the thread was already started or terminated).
+    bool start();
+
+    // Wait for thread termination and retrieve exist status into
+    // |*exitStatus|. Return true on success, false otherwise.
+    // NOTE: |exitStatus| can be NULL.
+    virtual bool  wait(intptr_t *exitStatus = nullptr);
+
+    // Check whether a thread has terminated. On success, return true
+    // and sets |*exitStatus|. On failure, return false.
+    // NOTE: |exitStatus| can be NULL.
+    bool tryWait(intptr_t *exitStatus);
+
+    // Mask all signals for the current thread
+    // This is needed for the qemu guest to run properly
+    // NB: noop for Win32
+    static void maskAllSignals();
+
+    // Sleep for |n| milliseconds
+    static void sleepMs(unsigned n);
+
+    // Sleep for |n| microseconds
+    static void sleepUs(unsigned n);
+
+    // Yield the remaining part of current thread's CPU time slice to another
+    // thread that's ready to run.
+    static void yield();
+
+private:
+#ifdef _WIN32
+    static DWORD WINAPI thread_main(void* arg);
+
+    HANDLE mThread = nullptr;
+#else // !WIN32
+    static void* thread_main(void* arg);
+
+    pthread_t mThread;
+#endif
+    Lock mLock;
+    // Access guarded by |mLock|.
+    intptr_t mExitStatus = 0;
+    int mStackSize;
+    const ThreadFlags mFlags;
+    bool mStarted = false;
+    // Access guarded by |mLock|.
+    bool mFinished = false;
+#ifndef _WIN32
+    // Posix-only, remember if we've joined our non-detached thread already.
+    bool mJoined = false;
+#endif
+};
+
+// Helper function to obtain a printable id for the current thread.
+unsigned long getCurrentThreadId();
+
+// Subclass of Thread covering interruptible threads.
+class InterruptibleThread : public Thread {
+    DISALLOW_COPY_ASSIGN_AND_MOVE(InterruptibleThread);
+public:
+    // Public constructor.
+    InterruptibleThread(ThreadFlags flags = ThreadFlags::MaskSignals, int stackSize = 0) :
+        Thread(flags, stackSize) { }
+
+    virtual void interrupt() = 0;
+};
+
+}  // namespace guest
+}  // namespace base
+}  // namespace android
diff --git a/android-emu/android/base/threads/AndroidThreadStore.cpp b/android-emu/android/base/threads/AndroidThreadStore.cpp
new file mode 100644
index 0000000..f5278db
--- /dev/null
+++ b/android-emu/android/base/threads/AndroidThreadStore.cpp
@@ -0,0 +1,248 @@
+// Copyright (C) 2014 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "android/base/threads/AndroidThreadStore.h"
+
+#ifdef _WIN32
+#include "android/base/memory/LazyInstance.h"
+#endif
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+// Set to 1 to print debug messages.
+#define DEBUG_THREAD_STORE  0
+
+#if DEBUG_THREAD_STORE
+#  define D(...)   do { printf("%s:%d: ", __FUNCTION__, __LINE__); printf(__VA_ARGS__); fflush(stdout); } while (0)
+#else
+#  define D(...)   ((void)0)
+#endif
+
+namespace android {
+namespace base {
+namespace guest {
+
+#ifdef _WIN32
+
+namespace {
+
+// The ThreadStore implementation on Windows is very tricky, because
+// TlsAlloc() doesn't allow one to provide a destructor function. As
+// such threads are expected to destroy all TLS values explicitely.
+//
+// To solve this issue, this source file provides a static method called
+// ThreadStore::OnThreadExit() that must be called when a thread exits,
+// which will cleanup all values for the current thread.
+//
+// But this forces us to track thread-specific values ourselves.
+
+// Maximum amount of thread-specific slots supported by this implementation.
+enum {
+    kMaxTlsSlots = 64
+};
+
+// TlsSlotArray is a thread-specific array of values. Instances will
+// be stored in a Win32 TLS value controlled by a single master TLS
+// key.
+//
+typedef void* TlsSlotArray[kMaxTlsSlots];
+
+// Global state shared by all threads
+class GlobalState {
+public:
+    GlobalState() {
+        D("Entering\n");
+        mMasterTls = TlsAlloc();
+        D("Master TLS = %d\n", (int)mMasterTls);
+        InitializeCriticalSection(&mSection);
+        mLastIndex = 0;
+        ::memset(mDestructors, 0, sizeof(mDestructors));
+        D("Exiting\n");
+    }
+
+    // Register a new TLS key, or return -1 on error (too many keys).
+    // |destroy| is the destructor function for the key.
+    int registerKey(ThreadStoreBase::Destructor* destroy) {
+        D("Entering destroy=%p\n", destroy);
+        int ret = -1;
+        EnterCriticalSection(&mSection);
+        if (mLastIndex < kMaxTlsSlots) {
+            ret = mLastIndex++;
+            mDestructors[ret] = destroy;
+        }
+        LeaveCriticalSection(&mSection);
+        D("Exiting newKey=%d\n", ret);
+        return ret;
+    }
+
+    void unregisterKey(int key) {
+        D("key=%d\n", key);
+        if (key < 0 || key >= kMaxTlsSlots) {
+            D("Invalid key\n");
+            return;
+        }
+
+        // Note: keys are not reusable, but remove the destructor to avoid
+        // crashes in leaveCurrentThread() when it points to a function that
+        // is going to be unloaded from the process' address space.
+        EnterCriticalSection(&mSection);
+        mDestructors[key] = NULL;
+        LeaveCriticalSection(&mSection);
+        D("Exiting\n");
+    }
+
+    // Get the current thread-local value for a given |key|.
+    void* getValue(int key) const {
+        D("Entering key=%d\n", key);
+        if (key < 0 || key >= kMaxTlsSlots) {
+            D("Invalid key, result=NULL\n");
+            return NULL;
+        }
+
+        TlsSlotArray* array = getArray();
+        void* ret = (*array)[key];
+        D("Exiting keyValue=%p\n", ret);
+        return ret;
+    }
+
+    // Set the current thread-local |value| for a given |key|.
+    void setValue(int key, void* value) {
+        D("Entering key=%d\n",key);
+        if (key < 0 || key >= kMaxTlsSlots) {
+            D("Invalid key, returning\n");
+            return;
+        }
+
+        TlsSlotArray* array = getArray();
+        (*array)[key] = value;
+        D("Exiting\n");
+    }
+
+    // Call this when a thread exits to destroy all its thread-local values.
+    void leaveCurrentThread() {
+        D("Entering\n");
+        TlsSlotArray* array =
+                reinterpret_cast<TlsSlotArray*>(TlsGetValue(mMasterTls));
+        if (!array) {
+            D("Exiting, no thread-local data in this thread\n");
+            return;
+        }
+
+        for (size_t n = 0; n < kMaxTlsSlots; ++n) {
+            void* value = (*array)[n];
+            if (!value) {
+                continue;
+            }
+            (*array)[n] = NULL;
+
+            // NOTE: In theory, a destructor could reset the slot to
+            // a new value, and we would have to loop in this function
+            // in interesting ways. In practice, ignore the issue.
+            EnterCriticalSection(&mSection);
+            ThreadStoreBase::Destructor* destroy = mDestructors[n];
+            LeaveCriticalSection(&mSection);
+            if (destroy) {
+                D("Calling destructor %p for key=%d, with value=%p\n",
+                    destroy, (int)n, value);
+                (*destroy)(value);
+            }
+        }
+        TlsSetValue(mMasterTls, NULL);
+        ::free(array);
+        D("Exiting\n");
+    }
+
+private:
+    // Return the thread-local array of TLS slots for the current thread.
+    // Cannot return NULL.
+    TlsSlotArray* getArray() const {
+        D("Entering\n");
+        TlsSlotArray* array =
+                reinterpret_cast<TlsSlotArray*>(TlsGetValue(mMasterTls));
+        if (!array) {
+            array = reinterpret_cast<TlsSlotArray*>(
+                    ::calloc(sizeof(*array), 1));
+            TlsSetValue(mMasterTls, array);
+            D("Allocated new array at %p\n", array);
+        } else {
+            D("Retrieved array at %p\n", array);
+        }
+        return array;
+    }
+
+    DWORD mMasterTls;
+    CRITICAL_SECTION mSection;
+    int mLastIndex;
+    ThreadStoreBase::Destructor* mDestructors[kMaxTlsSlots];
+};
+
+LazyInstance<GlobalState> gGlobalState = LAZY_INSTANCE_INIT;
+
+}  // namespace
+
+ThreadStoreBase::ThreadStoreBase(Destructor* destroy) {
+    D("Entering this=%p destroy=%p\n", this, destroy);
+    mKey = gGlobalState->registerKey(destroy);
+    D("Exiting this=%p key=%d\n", this, mKey);
+}
+
+ThreadStoreBase::~ThreadStoreBase() {
+    D("Entering this=%p\n", this);
+    GlobalState* state = gGlobalState.ptr();
+    state->unregisterKey(mKey);
+    D("Exiting this=%p\n", this);
+}
+
+void* ThreadStoreBase::get() const {
+    D("Entering this=%p\n", this);
+    void* ret = gGlobalState->getValue(mKey);
+    D("Exiting this=%p value=%p\n", this, ret);
+    return ret;
+}
+
+void ThreadStoreBase::set(void* value) {
+    D("Entering this=%p value=%p\n", this, value);
+    gGlobalState->setValue(mKey, value);
+    D("Exiting this=%p\n", this);
+}
+
+// static
+void ThreadStoreBase::OnThreadExit() {
+    gGlobalState->leaveCurrentThread();
+}
+
+#else  // !_WIN32
+
+ThreadStoreBase::ThreadStoreBase(Destructor* destroy) {
+    int ret = pthread_key_create(&mKey, destroy);
+    if (ret != 0) {
+        fprintf(stderr,
+                "Could not create thread store key: %s\n",
+                strerror(ret));
+        exit(1);
+    }
+}
+
+ThreadStoreBase::~ThreadStoreBase() {
+    pthread_key_delete(mKey);
+}
+
+#endif  // !_WIN32
+
+}  // namespace guest
+}  // namespace base
+}  // namespace android
diff --git a/android-emu/android/base/threads/AndroidThreadStore.h b/android-emu/android/base/threads/AndroidThreadStore.h
new file mode 100644
index 0000000..9636aee
--- /dev/null
+++ b/android-emu/android/base/threads/AndroidThreadStore.h
@@ -0,0 +1,156 @@
+// Copyright (C) 2014 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#pragma once
+
+#include "android/base/Compiler.h"
+
+#ifdef _WIN32
+#  define WIN32_LEAN_AND_MEAN 1
+#  include <windows.h>
+#else
+#  include <pthread.h>
+#endif
+
+namespace android {
+namespace base {
+namespace guest {
+
+// A class to model storage of thread-specific values, that can be
+// destroyed on thread exit.
+//
+// Note that on Windows, a thread must call OnThreadExit() explicitly
+// here to ensure that the values are probably discarded. This is an
+// unfortunate requirement of the Win32 API, which doesn't support
+// destructors at all.
+//
+// There are various hacks on the web to try to achieve this automatically
+// (e.g. [1]) but they rely on using the Microsoft build tools,
+// which doesn't work for us.
+//
+// Note another important issue with ThreadStore instances: if you create
+// one instance in a shared library, you need to make sure that it is
+// always destroyed before the library is unloaded. Otherwise, future
+// thread exit will likely crash, due to calling a destructor function
+// that is no longer in the process' address space.
+//
+// Finally, destroying an instance does _not_ free the corresponding values,
+// because doing so properly requires coordinating all participating threads,
+// which is impossible to achieve in the most general case. Thus, consider
+// that thread-local values are always leaked on library unload, or on
+// program exit.
+//
+// [1] http://stackoverflow.com/questions/14538159/about-tls-callback-in-windows
+
+// ThreadStoreBase is the base class used by all ThreadStore template
+// instances, used to reduce bloat.
+class ThreadStoreBase {
+public:
+    // Type of a function used to destroy a thread-specific value that
+    // was previously assigned by calling set().
+    typedef void (Destructor)(void* value);
+
+    // Initialize instance so that is hold keys that must be destroyed
+    // on thread exit by calling |destroy|.
+    explicit ThreadStoreBase(Destructor* destroy);
+
+    // NOTE: Destructor don't free the thread-local values, but are required
+    // to avoid crashes (see note above).
+    ~ThreadStoreBase();
+
+    // Retrieve current thread-specific value from store.
+#ifdef _WIN32
+    void* get() const;
+#else
+    inline void* get() const {
+        return pthread_getspecific(mKey);
+    }
+#endif
+
+    // Set the new thread-specific value.
+#ifdef _WIN32
+    void set(void* value);
+#else
+    inline void set(void* value) {
+        pthread_setspecific(mKey, value);
+    }
+#endif
+
+    inline void* swap(void* value) {
+        void* old = get();
+        set(value);
+        return old;
+    }
+
+#ifdef _WIN32
+    // Each thread should call this function on exit to ensure that
+    // all corresponding TLS values are properly freed.
+    static void OnThreadExit();
+#else
+    // Nothing to do on Posix.
+    static inline void OnThreadExit() {}
+#endif
+
+private:
+    // Ensure you can't create an empty ThreadStore instance.
+    ThreadStoreBase();
+
+    DISALLOW_COPY_AND_ASSIGN(ThreadStoreBase);
+
+#ifdef _WIN32
+    int mKey;
+#else
+    pthread_key_t mKey;
+#endif
+};
+
+// ThreadStore is a template class used to implement a thread-local store
+// of objects of type |T|. Note that the store owns the objects, and these
+// are destroyed when an android::base::Thread exits.
+template <typename T>
+class ThreadStore : public ThreadStoreBase {
+public:
+    // Create a new ThreadStore instance.
+    ThreadStore() : ThreadStoreBase(myDestructor) {}
+
+    // Retrieve the thread-specific object instance, or NULL if set()
+    // was never called before in the current thread.
+    T* get() {
+        return static_cast<T*>(ThreadStoreBase::get());
+    }
+
+    // Set the current thread-specific objet instance for this thread.
+    // |t| is the new object instance.
+    // NOTE: Any previous object instance is deleted.
+    void set(T* t) {
+        T* old = static_cast<T*>(swap(t));
+        delete old;
+    }
+
+    // Swap the current thread-specific object for this thread.
+    // |t| is the new object instance.
+    // Return the previous one. Transfers ownership to the caller.
+    T* swap(T* t) {
+        return static_cast<T*>(ThreadStoreBase::swap(t));
+    }
+
+private:
+    static void myDestructor(void* opaque) {
+        delete static_cast<T*>(opaque);
+    }
+};
+
+}  // namespace guest
+}  // namespace base
+}  // namespace android
diff --git a/android-emu/android/base/threads/AndroidThreadTypes.h b/android-emu/android/base/threads/AndroidThreadTypes.h
new file mode 100644
index 0000000..26dcf25
--- /dev/null
+++ b/android-emu/android/base/threads/AndroidThreadTypes.h
@@ -0,0 +1,41 @@
+// Copyright (C) 2015 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#pragma once
+
+#include "android/base/EnumFlags.h"
+
+#include <functional>
+#include <stdint.h>
+
+namespace android {
+namespace base {
+namespace guest {
+
+// a functor which can run in a separate thread
+using ThreadFunctor = std::function<intptr_t()>;
+
+enum class ThreadFlags : unsigned char {
+    NoFlags = 0,
+    MaskSignals = 1,
+    // A Detach-ed thread is a launch-and-forget thread.
+    // wait() and tryWait() on a Detach-ed thread always fails.
+    // OTOH, if you don't wait() on a non Detach-ed thread it would do it
+    // in dtor anyway.
+    Detach = 1 << 1
+};
+
+}  // namespace guest
+}  // namespace base
+}  // namespace android
diff --git a/android-emu/android/base/threads/AndroidThread_pthread.cpp b/android-emu/android/base/threads/AndroidThread_pthread.cpp
new file mode 100644
index 0000000..cfef69f
--- /dev/null
+++ b/android-emu/android/base/threads/AndroidThread_pthread.cpp
@@ -0,0 +1,192 @@
+// Copyright (C) 2014 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "android/base/threads/AndroidThread.h"
+
+#include "android/base/threads/AndroidThreadStore.h"
+
+#include <log/log.h>
+#include <assert.h>
+#include <errno.h>
+#include <signal.h>
+#include <stdio.h>
+#ifndef _MSC_VER
+#include <unistd.h>
+#endif
+
+namespace android {
+namespace base {
+namespace guest {
+
+Thread::Thread(ThreadFlags flags, int stackSize)
+    : mThread((pthread_t)NULL), mStackSize(stackSize), mFlags(flags) {}
+
+Thread::~Thread() {
+    assert(!mStarted || mFinished);
+    if ((mFlags & ThreadFlags::Detach) == ThreadFlags::NoFlags && mStarted &&
+        !mJoined) {
+        // Make sure we reclaim the OS resources.
+        pthread_join(mThread, nullptr);
+    }
+}
+
+bool Thread::start() {
+    if (mStarted) {
+        return false;
+    }
+
+    bool ret = true;
+    mStarted = true;
+
+    const auto useAttributes = mStackSize != 0;
+
+    pthread_attr_t attr;
+    if (useAttributes) {
+        pthread_attr_init(&attr);
+        pthread_attr_setstacksize(&attr, mStackSize);
+    }
+
+    if (pthread_create(&mThread, mStackSize ? &attr : nullptr, thread_main,
+                       this)) {
+        ALOGE("Thread: failed to create a thread, errno %d\n", errno);
+        ret = false;
+        // We _do not_ need to guard this access to |mFinished| because we're
+        // sure that the launched thread failed, so there can't be parallel
+        // access.
+        mFinished = true;
+        mExitStatus = -errno;
+        // Nothing to join, so technically it's joined.
+        mJoined = true;
+    }
+
+    if (useAttributes) {
+        pthread_attr_destroy(&attr);
+    }
+
+    return ret;
+}
+
+bool Thread::wait(intptr_t* exitStatus) {
+    if (!mStarted || (mFlags & ThreadFlags::Detach) != ThreadFlags::NoFlags) {
+        return false;
+    }
+
+    // NOTE: Do not hold the lock when waiting for the thread to ensure
+    // it can update mFinished and mExitStatus properly in thread_main
+    // without blocking.
+    if (!mJoined && pthread_join(mThread, NULL)) {
+        return false;
+    }
+    mJoined = true;
+
+    if (exitStatus) {
+        *exitStatus = mExitStatus;
+    }
+    return true;
+}
+
+bool Thread::tryWait(intptr_t* exitStatus) {
+    if (!mStarted || (mFlags & ThreadFlags::Detach) != ThreadFlags::NoFlags) {
+        return false;
+    }
+
+    {
+        AutoLock locker(mLock);
+        if (!mFinished) {
+            return false;
+        }
+    }
+
+    if (!mJoined) {
+        if (pthread_join(mThread, NULL)) {
+            ALOGW("Thread: failed to join a finished thread, errno %d\n", errno);
+        }
+        mJoined = true;
+    }
+
+    if (exitStatus) {
+        *exitStatus = mExitStatus;
+    }
+    return true;
+}
+
+// static
+void* Thread::thread_main(void* arg) {
+    intptr_t ret;
+
+    {
+        Thread* self = reinterpret_cast<Thread*>(arg);
+        if ((self->mFlags & ThreadFlags::MaskSignals) != ThreadFlags::NoFlags) {
+            Thread::maskAllSignals();
+        }
+
+        if ((self->mFlags & ThreadFlags::Detach) != ThreadFlags::NoFlags) {
+            if (pthread_detach(pthread_self())) {
+                // This only means a slow memory leak, so use VERBOSE.
+                ALOGV("Failed to set thread to detach mode\n");
+            }
+        }
+
+        ret = self->main();
+
+        {
+            AutoLock lock(self->mLock);
+            self->mFinished = true;
+            self->mExitStatus = ret;
+        }
+
+        self->onExit();
+        // |self| is not valid beyond this point
+    }
+
+    ::android::base::guest::ThreadStoreBase::OnThreadExit();
+
+    // This return value is ignored.
+    return NULL;
+}
+
+// static
+void Thread::maskAllSignals() {
+    sigset_t set;
+    sigfillset(&set);
+    pthread_sigmask(SIG_SETMASK, &set, nullptr);
+}
+
+// static
+void Thread::sleepMs(unsigned n) {
+    usleep(n * 1000);
+}
+
+// static
+void Thread::sleepUs(unsigned n) {
+    usleep(n);
+}
+
+// static
+void Thread::yield() {
+    sched_yield();
+}
+
+unsigned long getCurrentThreadId() {
+    pthread_t tid = pthread_self();
+    // POSIX doesn't require pthread_t to be a numeric type.
+    // Instead, just pick up the first sizeof(long) bytes as the "id".
+    static_assert(sizeof(tid) >= sizeof(long),
+                  "Expected pthread_t to be at least sizeof(long) wide");
+    return *reinterpret_cast<unsigned long*>(&tid);
+}
+
+}  // namespace guest
+}  // namespace base
+}  // namespace android
diff --git a/android-emu/android/base/threads/AndroidWorkPool.cpp b/android-emu/android/base/threads/AndroidWorkPool.cpp
new file mode 100644
index 0000000..ff9c82e
--- /dev/null
+++ b/android-emu/android/base/threads/AndroidWorkPool.cpp
@@ -0,0 +1,465 @@
+// Copyright (C) 2019 The Android Open Source Project
+// Copyright (C) 2019 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+#include "android/base/threads/AndroidWorkPool.h"
+
+#include "android/base/threads/AndroidFunctorThread.h"
+#include "android/base/synchronization/AndroidLock.h"
+#include "android/base/synchronization/AndroidConditionVariable.h"
+#include "android/base/synchronization/AndroidMessageChannel.h"
+
+#include <atomic>
+#include <memory>
+#include <unordered_map>
+#include <sys/time.h>
+
+using android::base::guest::AutoLock;
+using android::base::guest::ConditionVariable;
+using android::base::guest::FunctorThread;
+using android::base::guest::Lock;
+using android::base::guest::MessageChannel;
+
+namespace android {
+namespace base {
+namespace guest {
+
+class WaitGroup { // intrusive refcounted
+public:
+
+    WaitGroup(int numTasksRemaining) :
+        mNumTasksInitial(numTasksRemaining),
+        mNumTasksRemaining(numTasksRemaining) { }
+
+    ~WaitGroup() = default;
+
+    android::base::guest::Lock& getLock() { return mLock; }
+
+    void acquire() {
+        if (0 == mRefCount.fetch_add(1, std::memory_order_seq_cst)) {
+            ALOGE("%s: goofed, refcount0 acquire\n", __func__);
+            abort();
+        }
+    }
+
+    bool release() {
+        if (0 == mRefCount) {
+            ALOGE("%s: goofed, refcount0 release\n", __func__);
+            abort();
+        }
+        if (1 == mRefCount.fetch_sub(1, std::memory_order_seq_cst)) {
+            std::atomic_thread_fence(std::memory_order_acquire);
+            delete this;
+            return true;
+        }
+        return false;
+    }
+
+    // wait on all of or any of the associated tasks to complete.
+    bool waitAllLocked(WorkPool::TimeoutUs timeout) {
+        return conditionalTimeoutLocked(
+            [this] { return mNumTasksRemaining > 0; },
+            timeout);
+    }
+
+    bool waitAnyLocked(WorkPool::TimeoutUs timeout) {
+        return conditionalTimeoutLocked(
+            [this] { return mNumTasksRemaining == mNumTasksInitial; },
+            timeout);
+    }
+
+    // broadcasts to all waiters that there has been a new job that has completed
+    bool decrementBroadcast() {
+        AutoLock lock(mLock);
+        bool done =
+            (1 == mNumTasksRemaining.fetch_sub(1, std::memory_order_seq_cst));
+        std::atomic_thread_fence(std::memory_order_acquire);
+        mCv.broadcast();
+        return done;
+    }
+
+private:
+
+    bool doWait(WorkPool::TimeoutUs timeout) {
+        if (timeout == ~0ULL) {
+            ALOGV("%s: uncond wait\n", __func__);
+            mCv.wait(&mLock);
+            return true;
+        } else {
+            return mCv.timedWait(&mLock, getDeadline(timeout));
+        }
+    }
+
+    struct timespec getDeadline(WorkPool::TimeoutUs relative) {
+        struct timeval deadlineUs;
+        struct timespec deadlineNs;
+        gettimeofday(&deadlineUs, 0);
+
+        auto prevDeadlineUs = deadlineUs.tv_usec;
+
+        deadlineUs.tv_usec += relative;
+
+        // Wrap around
+        if (prevDeadlineUs > deadlineUs.tv_usec) {
+            ++deadlineUs.tv_sec;
+        }
+
+        deadlineNs.tv_sec = deadlineUs.tv_sec;
+        deadlineNs.tv_nsec = deadlineUs.tv_usec * 1000LL;
+        return deadlineNs;
+    }
+
+    uint64_t currTimeUs() {
+        struct timeval tv;
+        gettimeofday(&tv, 0);
+        return (uint64_t)(tv.tv_sec * 1000000LL + tv.tv_usec);
+    }
+
+    bool conditionalTimeoutLocked(std::function<bool()> conditionFunc, WorkPool::TimeoutUs timeout) {
+        uint64_t currTime = currTimeUs();
+        WorkPool::TimeoutUs currTimeout = timeout;
+
+        while (conditionFunc()) {
+            doWait(currTimeout);
+            if (!conditionFunc()) {
+                // Decrement timeout for wakeups
+                uint64_t nextTime = currTimeUs();
+                WorkPool::TimeoutUs waited = 
+                    nextTime - currTime;
+                currTime = nextTime;
+
+                if (currTimeout > waited) {
+                    currTimeout -= waited;
+                } else {
+                    return conditionFunc();
+                }
+            }
+        }
+
+        return true;
+    }
+
+    std::atomic<int> mRefCount = { 1 };
+    int mNumTasksInitial;
+    std::atomic<int> mNumTasksRemaining;
+
+    Lock mLock;
+    ConditionVariable mCv;
+};
+
+class WorkPoolThread {
+public:
+    // State diagram for each work pool thread
+    //
+    // Unacquired: (Start state) When no one else has claimed the thread.
+    // Acquired: When the thread has been claimed for work,
+    // but work has not been issued to it yet.
+    // Scheduled: When the thread is running tasks from the acquirer.
+    // Exiting: cleanup
+    //
+    // Messages:
+    //
+    // Acquire
+    // Run
+    // Exit
+    //
+    // Transitions:
+    //
+    // Note: While task is being run, messages will come back with a failure value.
+    //
+    // Unacquired:
+    //     message Acquire -> Acquired. effect: return success value
+    //     message Run -> Unacquired. effect: return failure value
+    //     message Exit -> Exiting. effect: return success value
+    //
+    // Acquired:
+    //     message Acquire -> Acquired. effect: return failure value
+    //     message Run -> Scheduled. effect: run the task, return success
+    //     message Exit -> Exiting. effect: return success value
+    //
+    // Scheduled:
+    //     implicit effect: after task is run, transition back to Unacquired.
+    //     message Acquire -> Scheduled. effect: return failure value
+    //     message Run -> Scheduled. effect: return failure value
+    //     message Exit -> queue up exit message, then transition to Exiting after that is done.
+    //         effect: return success value
+    //
+    enum State {
+        Unacquired = 0,
+        Acquired = 1,
+        Scheduled = 2,
+        Exiting = 3,
+    };
+
+    WorkPoolThread() : mThread([this] { threadFunc(); }) {
+        mThread.start();
+    }
+
+    ~WorkPoolThread() {
+        exit();
+        mThread.wait();
+    }
+
+    bool acquire() {
+        AutoLock lock(mLock);
+        switch (mState) {
+            case State::Unacquired:
+                mState = State::Acquired;
+                return true;
+            case State::Acquired:
+            case State::Scheduled:
+            case State::Exiting:
+                return false;
+        }
+    }
+
+    bool run(WorkPool::WaitGroupHandle waitGroupHandle, WaitGroup* waitGroup, WorkPool::Task task) {
+        AutoLock lock(mLock);
+        switch (mState) {
+            case State::Unacquired:
+                return false;
+            case State::Acquired: {
+                mState = State::Scheduled;
+                mToCleanupWaitGroupHandle = waitGroupHandle;
+                waitGroup->acquire();
+                mToCleanupWaitGroup = waitGroup;
+                mShouldCleanupWaitGroup = false;
+                TaskInfo msg = {
+                    Command::Run,
+                    waitGroup, task,
+                };
+                mRunMessages.send(msg);
+                return true;
+            }
+            case State::Scheduled:
+            case State::Exiting:
+                return false;
+        }
+    }
+
+    bool shouldCleanupWaitGroup(WorkPool::WaitGroupHandle* waitGroupHandle, WaitGroup** waitGroup) {
+        AutoLock lock(mLock);
+        bool res = mShouldCleanupWaitGroup;
+        *waitGroupHandle = mToCleanupWaitGroupHandle;
+        *waitGroup = mToCleanupWaitGroup;
+        mShouldCleanupWaitGroup = false;
+        return res;
+    }
+
+private:
+    enum Command {
+        Run = 0,
+        Exit = 1,
+    };
+
+    struct TaskInfo {
+        Command cmd;
+        WaitGroup* waitGroup = nullptr;
+        WorkPool::Task task = {};
+    };
+
+    bool exit() {
+        AutoLock lock(mLock);
+        TaskInfo msg { Command::Exit, };
+        mRunMessages.send(msg);
+        return true;
+    }
+
+    void threadFunc() {
+        TaskInfo taskInfo;
+        bool done = false;
+
+        while (!done) {
+            mRunMessages.receive(&taskInfo);
+            switch (taskInfo.cmd) {
+                case Command::Run:
+                    doRun(taskInfo);
+                    break;
+                case Command::Exit: {
+                    AutoLock lock(mLock);
+                    mState = State::Exiting;
+                    break;
+                }
+            }
+            AutoLock lock(mLock);
+            done = mState == State::Exiting;
+        }
+    }
+
+    // Assumption: the wait group refcount is >= 1 when entering
+    // this function (before decrement)..
+    // at least it doesn't get to 0
+    void doRun(TaskInfo& msg) {
+        WaitGroup* waitGroup = msg.waitGroup;
+
+        if (msg.task) msg.task();
+
+        bool lastTask =
+            waitGroup->decrementBroadcast();
+
+        AutoLock lock(mLock);
+        mState = State::Unacquired;
+
+        if (lastTask) {
+            mShouldCleanupWaitGroup = true;
+        }
+
+        waitGroup->release();
+    }
+
+    FunctorThread mThread;
+    Lock mLock;
+    State mState = State::Unacquired;
+    MessageChannel<TaskInfo, 4> mRunMessages;
+    WorkPool::WaitGroupHandle mToCleanupWaitGroupHandle = 0;
+    WaitGroup* mToCleanupWaitGroup = nullptr;
+    bool mShouldCleanupWaitGroup = false;
+};
+
+class WorkPool::Impl {
+public:
+    Impl(int numInitialThreads) : mThreads(numInitialThreads) {
+        for (size_t i = 0; i < mThreads.size(); ++i) {
+            mThreads[i].reset(new WorkPoolThread);
+        }
+    }
+
+    ~Impl() = default;
+
+    WorkPool::WaitGroupHandle schedule(const std::vector<WorkPool::Task>& tasks) {
+
+        if (tasks.empty()) abort();
+
+        AutoLock lock(mLock);
+
+        // Sweep old wait groups
+        for (size_t i = 0; i < mThreads.size(); ++i) {
+            WaitGroupHandle handle;
+            WaitGroup* waitGroup;
+            bool cleanup = mThreads[i]->shouldCleanupWaitGroup(&handle, &waitGroup);
+            if (cleanup) {
+                mWaitGroups.erase(handle);
+                waitGroup->release();
+            }
+        }
+
+        WorkPool::WaitGroupHandle resHandle = genWaitGroupHandleLocked();
+        WaitGroup* waitGroup =
+            new WaitGroup(tasks.size());
+
+        mWaitGroups[resHandle] = waitGroup;
+
+        std::vector<size_t> threadIndices;
+
+        while (threadIndices.size() < tasks.size()) {
+            for (size_t i = 0; i < mThreads.size(); ++i) {
+                if (!mThreads[i]->acquire()) continue;
+                threadIndices.push_back(i);
+                if (threadIndices.size() == tasks.size()) break;
+            }
+            if (threadIndices.size() < tasks.size()) {
+                mThreads.resize(mThreads.size() + 1);
+                mThreads[mThreads.size() - 1].reset(new WorkPoolThread);
+            }
+        }
+
+        // every thread here is acquired
+        for (size_t i = 0; i < threadIndices.size(); ++i) {
+            mThreads[threadIndices[i]]->run(resHandle, waitGroup, tasks[i]);
+        }
+
+        return resHandle;
+    }
+
+    bool waitAny(WorkPool::WaitGroupHandle waitGroupHandle, WorkPool::TimeoutUs timeout) {
+        AutoLock lock(mLock);
+        auto it = mWaitGroups.find(waitGroupHandle);
+        if (it == mWaitGroups.end()) return true;
+
+        auto waitGroup = it->second;
+        waitGroup->acquire();
+        lock.unlock();
+
+        bool waitRes = false;
+
+        {
+            AutoLock waitGroupLock(waitGroup->getLock());
+            waitRes = waitGroup->waitAnyLocked(timeout);
+        }
+
+        waitGroup->release();
+
+        return waitRes;
+    }
+
+    bool waitAll(WorkPool::WaitGroupHandle waitGroupHandle, WorkPool::TimeoutUs timeout) {
+        auto waitGroup = acquireWaitGroupFromHandle(waitGroupHandle);
+        if (!waitGroup) return true;
+
+        bool waitRes = false;
+
+        {
+            AutoLock waitGroupLock(waitGroup->getLock());
+            waitRes = waitGroup->waitAllLocked(timeout);
+        }
+
+        waitGroup->release();
+
+        return waitRes;
+    }
+
+private:
+    // Increments wait group refcount by 1.
+    WaitGroup* acquireWaitGroupFromHandle(WorkPool::WaitGroupHandle waitGroupHandle) {
+        AutoLock lock(mLock);
+        auto it = mWaitGroups.find(waitGroupHandle);
+        if (it == mWaitGroups.end()) return nullptr;
+
+        auto waitGroup = it->second;
+        waitGroup->acquire();
+
+        return waitGroup;
+    }
+
+    using WaitGroupStore = std::unordered_map<WorkPool::WaitGroupHandle, WaitGroup*>;
+
+    WorkPool::WaitGroupHandle genWaitGroupHandleLocked() {
+        WorkPool::WaitGroupHandle res = mNextWaitGroupHandle;
+        ++mNextWaitGroupHandle;
+        return res;
+    }
+
+    Lock mLock;
+    uint64_t mNextWaitGroupHandle = 0;
+    WaitGroupStore mWaitGroups;
+    std::vector<std::unique_ptr<WorkPoolThread>> mThreads;
+};
+
+WorkPool::WorkPool(int numInitialThreads) : mImpl(new WorkPool::Impl(numInitialThreads)) { }
+WorkPool::~WorkPool() = default;
+
+WorkPool::WaitGroupHandle WorkPool::schedule(const std::vector<WorkPool::Task>& tasks) {
+    return mImpl->schedule(tasks);
+}
+
+bool WorkPool::waitAny(WorkPool::WaitGroupHandle waitGroup, WorkPool::TimeoutUs timeout) {
+    return mImpl->waitAny(waitGroup, timeout);
+}
+
+bool WorkPool::waitAll(WorkPool::WaitGroupHandle waitGroup, WorkPool::TimeoutUs timeout) {
+    return mImpl->waitAll(waitGroup, timeout);
+}
+
+} // namespace guest
+} // namespace base
+} // namespace android
diff --git a/android-emu/android/base/threads/AndroidWorkPool.h b/android-emu/android/base/threads/AndroidWorkPool.h
new file mode 100644
index 0000000..5ffaecb
--- /dev/null
+++ b/android-emu/android/base/threads/AndroidWorkPool.h
@@ -0,0 +1,51 @@
+
+// Copyright (C) 2019 The Android Open Source Project
+// Copyright (C) 2019 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+#pragma once
+
+#include <functional>
+#include <memory>
+#include <vector>
+
+namespace android {
+namespace base {
+namespace guest {
+
+// WorkPool provides a way to queue several different + arbitrary wait / signal
+// operations.  There is no specific imposed order to the operations; all
+// ordering is derived from dependencies among the queued tasks.  The number of
+// threads used is the number of concurrent tasks in flight.  Tasks are sent in
+// groups, representing a collection that can be waited on (a wait group). 
+class WorkPool {
+public:
+    using Task = std::function<void()>;
+    using WaitGroupHandle = uint64_t;
+    using TimeoutUs = uint64_t;
+
+    WorkPool(int numInitialThreads = 4);
+    ~WorkPool();
+
+    WaitGroupHandle schedule(const std::vector<Task>& tasks);
+
+    bool waitAny(WaitGroupHandle waitGroup, TimeoutUs timeout = -1);
+    bool waitAll(WaitGroupHandle waitGroup, TimeoutUs timeout = -1);
+private:
+    class Impl;
+    std::unique_ptr<Impl> mImpl;
+};
+
+} // namespace android
+} // namespace base
+} // namespace guest
diff --git a/cmake_transform.py b/cmake_transform.py
index 3e8d9c5..3583ec8 100644
--- a/cmake_transform.py
+++ b/cmake_transform.py
@@ -88,9 +88,9 @@
         'android_validate_sha256("${GOLDFISH_DEVICE_ROOT}/%s" "%s")' % (mkfile, sha256))
     make.append('set(%s_src %s)' % (name, ' '.join(module['src'])))
     if module['type'] == 'SHARED_LIBRARY':
-        make.append('android_add_shared_library(%s)' % name)
+        make.append('android_add_library(TARGET {} SHARED LICENSE Apache-2.0 SRC {})'.format(name, ' '.join(module['src'])))
     elif module['type'] == 'STATIC_LIBRARY':
-        make.append('android_add_library(%s)' % name)
+        make.append('android_add_library(TARGET {} LICENSE Apache-2.0 SRC {})'.format(name, ' '.join(module['src'])))
     else:
         raise ValueError('Unexpected module type: %s' % module['type'])
 
diff --git a/fuchsia/fuchsia_stdio.cc b/fuchsia/fuchsia_stdio.cc
new file mode 100644
index 0000000..9f33454
--- /dev/null
+++ b/fuchsia/fuchsia_stdio.cc
@@ -0,0 +1,89 @@
+// Copyright 2019 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <assert.h>
+#include <lib/syslog/global.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+void __assert_fail(const char *expr, const char *file, int line, const char *func)
+{
+  FX_LOGF(ERROR, "goldfish", "Assertion failed: %s (%s: %s: %d)", expr, file, func, line);
+  abort();
+}
+
+int puts(const char *s)
+{
+  return fputs(s, stdout);
+}
+
+int printf(const char *format, ...)
+{
+  va_list args;
+  va_start(args, format);
+  vfprintf(stdout, format, args);
+  va_end(args);
+  return 0;
+}
+
+int vprintf(const char *format, va_list ap)
+{
+  return vfprintf(stdout, format, ap);
+}
+
+int fprintf(FILE *stream, const char *format, ...)
+{
+  assert(stream == stdout || stream == stderr);
+  if (stream == stdout || stream == stderr)
+  {
+    va_list args;
+    va_start(args, format);
+    vfprintf(stream, format, args);
+    va_end(args);
+  }
+  return 0;
+}
+
+static inline fx_log_severity_t severity(FILE *stream)
+{
+  return stream == stdout ? FX_LOG_INFO : FX_LOG_ERROR;
+}
+
+int fputs(const char *s, FILE *stream)
+{
+  assert(stream == stdout || stream == stderr);
+  if (stream == stdout || stream == stderr)
+  {
+    _FX_LOG(severity(stream), "goldfish", s);
+  }
+  return 0;
+}
+
+int vfprintf(FILE *stream, const char *format, va_list ap)
+{
+  assert(stream == stdout || stream == stderr);
+  if (stream == stdout || stream == stderr)
+  {
+    _FX_LOGVF(severity(stream), "goldfish", format, ap);
+  }
+  return 0;
+}
+
+size_t fwrite(const void *ptr, size_t size, size_t nitems, FILE *stream)
+{
+  assert(stream == stdout || stream == stderr);
+  char buffer[512];
+  size_t offset = 0;
+  size_t count = 0;
+  for (; count < nitems; count++)
+  {
+    snprintf(buffer + offset, sizeof(buffer) - offset, reinterpret_cast<const char *>(ptr) + offset, size);
+    offset += size;
+    if (offset > sizeof(buffer))
+      break;
+  }
+  buffer[sizeof(buffer) - 1] = 0;
+  fputs(buffer, stream);
+  return count;
+}
diff --git a/fuchsia/include/cutils/log.h b/fuchsia/include/cutils/log.h
index 19ef6ca..a2ddde8 100644
--- a/fuchsia/include/cutils/log.h
+++ b/fuchsia/include/cutils/log.h
@@ -17,18 +17,17 @@
   ANDROID_LOG_SILENT,
 };
 
-#define android_printLog(prio, tag, ...) \
-  __android_log_print(prio, tag, __VA_ARGS__)
+#define android_printLog(prio, tag, format, ...) \
+  __android_log_print(prio, tag, "[prio %d] " format, prio, ##__VA_ARGS__)
 
 #define LOG_PRI(priority, tag, ...) android_printLog(priority, tag, __VA_ARGS__)
 #define ALOG(priority, tag, ...) LOG_PRI(ANDROID_##priority, tag, __VA_ARGS__)
 
 #define __android_second(dummy, second, ...) second
 #define __android_rest(first, ...) , ##__VA_ARGS__
-#define android_printAssert(condition, tag, ...)                \
-  __android_log_assert(condition, tag,                          \
-                       __android_second(0, ##__VA_ARGS__, NULL) \
-                           __android_rest(__VA_ARGS__))
+
+#define android_printAssert(condition, tag, format, ...)                \
+  __android_log_assert(condition, tag, "assert: condition: %s " format, condition, ##__VA_ARGS__)
 
 #define LOG_ALWAYS_FATAL_IF(condition, ...)                              \
   ((condition)                                                           \
diff --git a/fuchsia/include/services/service_connector.h b/fuchsia/include/services/service_connector.h
new file mode 100644
index 0000000..1320401
--- /dev/null
+++ b/fuchsia/include/services/service_connector.h
@@ -0,0 +1,29 @@
+// Copyright (C) 2019 The Android Open Source Project
+// Copyright (C) 2019 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef FUCHSIA_INCLUDE_SERVICES_SERVICE_CONNECTOR_H_
+#define FUCHSIA_INCLUDE_SERVICES_SERVICE_CONNECTOR_H_
+
+#include <cstdint>
+#include <zircon/types.h>
+
+// Takes the name of a service (e.g. /svc/fuchsia.sysmem.Allocator) and returns
+// a handle to a connection to it.
+typedef zx_handle_t (*PFN_ConnectToServiceAddr)(const char *pName);
+
+void SetConnectToServiceFunction(PFN_ConnectToServiceAddr func);
+PFN_ConnectToServiceAddr GetConnectToServiceFunction();
+
+#endif // FUCHSIA_INCLUDE_SERVICES_SERVICE_CONNECTOR_H_
diff --git a/fuchsia/port.cc b/fuchsia/port.cc
index dd00eb6..37c7694 100644
--- a/fuchsia/port.cc
+++ b/fuchsia/port.cc
@@ -11,6 +11,8 @@
 #include <cstdio>
 #include <thread>
 
+#include <lib/syslog/global.h>
+
 #include "cutils/log.h"
 #include "cutils/properties.h"
 #include "cutils/threads.h"
@@ -30,12 +32,21 @@
   if (!local_tag) {
     local_tag = "<NO_TAG>";
   }
-  printf("%d %s ", priority, local_tag);
   va_list ap;
   va_start(ap, format);
-  vprintf(format, ap);
-  va_end(ap);
-  printf("\n");
+  switch (priority) {
+    case ANDROID_LOG_WARN:
+      FX_LOGVF(WARNING, local_tag, format, ap);
+      break;
+    case ANDROID_LOG_ERROR:
+    case ANDROID_LOG_FATAL:
+      FX_LOGVF(ERROR, local_tag, format, ap);
+      break;
+    case ANDROID_LOG_INFO:
+    default:
+      FX_LOGVF(INFO, local_tag, format, ap);
+      break;
+  }
   return 1;
 }
 
@@ -45,17 +56,12 @@
   if (!local_tag) {
     local_tag = "<NO_TAG>";
   }
-  printf("__android_log_assert: condition: %s tag: %s ", condition, local_tag);
-  if (format) {
-    va_list ap;
-    va_start(ap, format);
-    vprintf(format, ap);
-    va_end(ap);
-  }
-  printf("\n");
+  va_list ap;
+  va_start(ap, format);
+  FX_LOGVF(ERROR, local_tag, format, ap);
+  va_end(ap);
 
-  assert(0);
-  exit(-1);
+  abort();
 }
 
 int sync_wait(int fd, int timeout) {
diff --git a/fuchsia/releasepackage.py b/fuchsia/releasepackage.py
new file mode 100644
index 0000000..dda9432
--- /dev/null
+++ b/fuchsia/releasepackage.py
@@ -0,0 +1,114 @@
+# Copyright 2019 The Fuchsia Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import os
+import sys
+import shutil
+import subprocess
+import argparse
+import re
+
+parser = argparse.ArgumentParser(description="Upload goldfish libvulkan to CIPD")
+
+parser.add_argument("--release-dir")
+parser.add_argument("--arch")
+parser.add_argument("--dry-run", action="store_true")
+parser.add_argument("--ignore-branch", action="store_true")
+parser.add_argument("--ignore-rebuild", action="store_true")
+parser.add_argument("--ignore-buildtype", action="store_true")
+
+args = parser.parse_args()
+
+dir_path = os.path.dirname(os.path.realpath(__file__))
+
+os.chdir(dir_path)
+
+fuchsia_root = os.path.abspath(os.path.join(dir_path, "../../../"))
+fx_path = os.path.join(fuchsia_root, "scripts/fx")
+
+if args.release_dir:
+  release_dir = os.path.abspath(args.release_dir)
+else:
+  release_dir = os.path.join(fuchsia_root, "out/default")
+
+if not os.path.exists(release_dir):
+  print "Release dir: %s doesn't exist" % release_dir
+  sys.exit(1)
+
+if args.arch:
+  arch = args.arch
+else:
+  arch = "x64"
+
+target_name = "%s-shared/lib.unstripped/libvulkan_goldfish.so" % arch
+git_repo_location = "%s/third_party/goldfish-opengl" % fuchsia_root
+package_dir = "libvulkan_goldfish/%s" % arch
+package_name = "fuchsia/lib/libvulkan/%s" % package_dir
+
+repo_name = "goldfish-opengl"
+git_branch = subprocess.check_output([
+    "git", "-C", git_repo_location, "rev-parse", "--abbrev-ref", "HEAD"
+]).strip()
+if git_branch != "master":
+  print("Git repo %s on incorrect branch %s (should be master)" %
+        (repo_name, git_branch))
+  if args.ignore_branch:
+    print("Ignoring")
+  else:
+    print("Use --ignore-branch flag to upload anyway")
+    sys.exit(1)
+
+# Force ninja dry-run
+ninja_output = subprocess.check_output([
+    fx_path, "ninja", "-C", release_dir, "-v", "-n", target_name
+])
+
+if "ninja: no work to do." not in ninja_output:
+  print("Ninja reported work needed to be done for %s" % target_name)
+  if args.ignore_rebuild:
+    print("Ignoring")
+  else:
+    print("Use --ignore-rebuild flag to upload anyway")
+    sys.exit(1)
+
+gn_output = subprocess.check_output([
+    fx_path, "gn", "args", release_dir, "--list=is_debug", "--short"
+]).strip()
+if gn_output != "is_debug = false":
+  print("GN argument \"%s\" unexpected" % gn_output)
+  if args.ignore_buildtype:
+    print("Ignoring")
+  else:
+    print("Use --ignore-buildtype flag to upload anyway")
+    sys.exit(1)
+
+file_name = "libvulkan_goldfish.so"
+full_name = os.path.join(package_dir, file_name)
+
+source_file_name = os.path.join(release_dir, target_name)
+try:
+  os.remove(full_name)
+except:
+  pass
+try:
+  os.makedirs(package_dir)
+except:
+  pass
+shutil.copyfile(source_file_name, full_name)
+
+git_rev = subprocess.check_output(
+    ["git", "-C", git_repo_location, "rev-parse", "HEAD"]).strip()
+
+cipd_command = ("%s cipd create -in %s -name %s -ref latest"
+                " -install-mode copy -tag git_revision:%s") % (
+                    fx_path, package_dir, package_name, git_rev)
+print cipd_command
+if not args.dry_run:
+  subprocess.check_call(cipd_command.split(" "))
+
+print ("""
+  <package name="%s"
+           version="git_revision:%s"
+           path="prebuild/third_party/%s"/>
+""" % (package_name, git_rev, package_dir))[1:-1]
diff --git a/fuchsia/service_connector.cc b/fuchsia/service_connector.cc
new file mode 100644
index 0000000..409ef63
--- /dev/null
+++ b/fuchsia/service_connector.cc
@@ -0,0 +1,28 @@
+// Copyright (C) 2019 The Android Open Source Project
+// Copyright (C) 2019 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "services/service_connector.h"
+
+namespace {
+PFN_ConnectToServiceAddr g_connection_function;
+}
+
+void SetConnectToServiceFunction(PFN_ConnectToServiceAddr func) {
+  g_connection_function = func;
+}
+
+PFN_ConnectToServiceAddr GetConnectToServiceFunction() {
+  return g_connection_function;
+}
diff --git a/host/include/libOpenglRender/IOStream.h b/host/include/libOpenglRender/IOStream.h
index d06440e..2f699bc 100644
--- a/host/include/libOpenglRender/IOStream.h
+++ b/host/include/libOpenglRender/IOStream.h
@@ -25,35 +25,40 @@
 public:
 
     IOStream(size_t bufSize) {
-        m_buf = NULL;
+        m_iostreamBuf = NULL;
         m_bufsize = bufSize;
         m_free = 0;
     }
 
+    virtual size_t idealAllocSize(size_t len) {
+        return m_bufsize < len ? len : m_bufsize;
+    }
+
     virtual void *allocBuffer(size_t minSize) = 0;
     virtual int commitBuffer(size_t size) = 0;
     virtual const unsigned char *readFully( void *buf, size_t len) = 0;
+    virtual const unsigned char *commitBufferAndReadFully(size_t size, void *buf, size_t len) = 0;
     virtual const unsigned char *read( void *buf, size_t *inout_len) = 0;
     virtual int writeFully(const void* buf, size_t len) = 0;
 
     virtual ~IOStream() {
 
-        // NOTE: m_buf is 'owned' by the child class thus we expect it to be released by it
+        // NOTE: m_iostreamBuf is 'owned' by the child class thus we expect it to be released by it
     }
 
     virtual unsigned char *alloc(size_t len) {
 
-        if (m_buf && len > m_free) {
+        if (m_iostreamBuf && len > m_free) {
             if (flush() < 0) {
                 ERR("Failed to flush in alloc\n");
                 return NULL; // we failed to flush so something is wrong
             }
         }
 
-        if (!m_buf || len > m_bufsize) {
-            int allocLen = m_bufsize < len ? len : m_bufsize;
-            m_buf = (unsigned char *)allocBuffer(allocLen);
-            if (!m_buf) {
+        if (!m_iostreamBuf || len > m_bufsize) {
+            int allocLen = this->idealAllocSize(len);
+            m_iostreamBuf = (unsigned char *)allocBuffer(allocLen);
+            if (!m_iostreamBuf) {
                 ERR("Alloc (%u bytes) failed\n", allocLen);
                 return NULL;
             }
@@ -62,7 +67,7 @@
 
         unsigned char *ptr;
 
-        ptr = m_buf + (m_bufsize - m_free);
+        ptr = m_iostreamBuf + (m_bufsize - m_free);
         m_free -= len;
 
         return ptr;
@@ -70,16 +75,21 @@
 
     virtual int flush() {
 
-        if (!m_buf || m_free == m_bufsize) return 0;
+        if (!m_iostreamBuf || m_free == m_bufsize) return 0;
 
         int stat = commitBuffer(m_bufsize - m_free);
-        m_buf = NULL;
+        m_iostreamBuf = NULL;
         m_free = 0;
         return stat;
     }
 
     const unsigned char *readback(void *buf, size_t len) {
-        flush();
+        if (m_iostreamBuf && m_free != m_bufsize) {
+            size_t size = m_bufsize - m_free;
+            m_iostreamBuf = NULL;
+            m_free = 0;
+            return commitBufferAndReadFully(size, buf, len);
+        }
         return readFully(buf, len);
     }
 
@@ -87,7 +97,7 @@
 
 
 private:
-    unsigned char *m_buf;
+    unsigned char *m_iostreamBuf;
     size_t m_bufsize;
     size_t m_free;
 };
diff --git a/shared/OpenglCodecCommon/Android.bp b/shared/OpenglCodecCommon/Android.bp
new file mode 100644
index 0000000..e56dfcd
--- /dev/null
+++ b/shared/OpenglCodecCommon/Android.bp
@@ -0,0 +1,5 @@
+cc_library_headers {
+    name: "goldfish_pipe_headers",
+    vendor_available: true,
+    export_include_dirs: ["."],
+}
diff --git a/shared/OpenglCodecCommon/Android.mk b/shared/OpenglCodecCommon/Android.mk
index 5ca0a08..af7c65d 100644
--- a/shared/OpenglCodecCommon/Android.mk
+++ b/shared/OpenglCodecCommon/Android.mk
@@ -34,6 +34,7 @@
 LOCAL_SRC_FILES := $(commonSources)
 
 LOCAL_CFLAGS += -DLOG_TAG=\"eglCodecCommon\"
+LOCAL_CFLAGS += -Wno-unused-private-field
 
 $(call emugl-export,SHARED_LIBRARIES,libcutils libutils liblog)
 
diff --git a/shared/OpenglCodecCommon/CMakeLists.txt b/shared/OpenglCodecCommon/CMakeLists.txt
index 5d5ee8d..4528e13 100644
--- a/shared/OpenglCodecCommon/CMakeLists.txt
+++ b/shared/OpenglCodecCommon/CMakeLists.txt
@@ -1,10 +1,10 @@
 # This is an autogenerated file! Do not edit!
 # instead run make from .../device/generic/goldfish-opengl
 # which will re-generate this file.
-android_validate_sha256("${GOLDFISH_DEVICE_ROOT}/shared/OpenglCodecCommon/Android.mk" "8aaff0a6f86ae81d01d6e87b9477d200a774b95a3f15267921e4e1f9cbb9848e")
+android_validate_sha256("${GOLDFISH_DEVICE_ROOT}/shared/OpenglCodecCommon/Android.mk" "b93e7098601bba92b0e1b4d4a94cee25d2181a9842c7902d5f339c405c862cea")
 set(OpenglCodecCommon_host_src GLClientState.cpp GLESTextureUtils.cpp ChecksumCalculator.cpp GLSharedGroup.cpp glUtils.cpp IndexRangeCache.cpp SocketStream.cpp TcpStream.cpp auto_goldfish_dma_context.cpp goldfish_address_space.cpp goldfish_dma_host.cpp qemu_pipe_host.cpp)
-android_add_shared_library(OpenglCodecCommon_host)
+android_add_library(TARGET OpenglCodecCommon_host SHARED LICENSE Apache-2.0 SRC GLClientState.cpp GLESTextureUtils.cpp ChecksumCalculator.cpp GLSharedGroup.cpp glUtils.cpp IndexRangeCache.cpp SocketStream.cpp TcpStream.cpp auto_goldfish_dma_context.cpp goldfish_address_space.cpp goldfish_dma_host.cpp qemu_pipe_host.cpp)
 target_include_directories(OpenglCodecCommon_host PRIVATE ${GOLDFISH_DEVICE_ROOT}/shared/OpenglCodecCommon ${GOLDFISH_DEVICE_ROOT}/./host/include/libOpenglRender ${GOLDFISH_DEVICE_ROOT}/./system/include ${GOLDFISH_DEVICE_ROOT}/./../../../external/qemu/android/android-emugl/guest)
 target_compile_definitions(OpenglCodecCommon_host PRIVATE "-DWITH_GLES2" "-DPLATFORM_SDK_VERSION=29" "-DGOLDFISH_HIDL_GRALLOC" "-DEMULATOR_OPENGL_POST_O=1" "-DHOST_BUILD" "-DANDROID" "-DGL_GLEXT_PROTOTYPES" "-DPAGE_SIZE=4096" "-DGOLDFISH_VULKAN" "-DLOG_TAG=\"eglCodecCommon\"")
-target_compile_options(OpenglCodecCommon_host PRIVATE "-fvisibility=default")
+target_compile_options(OpenglCodecCommon_host PRIVATE "-fvisibility=default" "-Wno-unused-parameter" "-Wno-unused-private-field")
 target_link_libraries(OpenglCodecCommon_host PRIVATE android-emu-shared cutils utils log)
\ No newline at end of file
diff --git a/shared/OpenglCodecCommon/ChecksumCalculator.cpp b/shared/OpenglCodecCommon/ChecksumCalculator.cpp
index 8983524..123cec7 100644
--- a/shared/OpenglCodecCommon/ChecksumCalculator.cpp
+++ b/shared/OpenglCodecCommon/ChecksumCalculator.cpp
@@ -82,7 +82,7 @@
 {
 }
 
-void ChecksumCalculator::addBuffer(const void* buf, size_t packetLen) {
+void ChecksumCalculator::addBuffer(const void*, size_t packetLen) {
     m_isEncodingChecksum = true;
     switch (m_version) {
         case 1:
diff --git a/shared/OpenglCodecCommon/GLClientState.cpp b/shared/OpenglCodecCommon/GLClientState.cpp
index 50d4d65..c6140db 100644
--- a/shared/OpenglCodecCommon/GLClientState.cpp
+++ b/shared/OpenglCodecCommon/GLClientState.cpp
@@ -41,6 +41,13 @@
 
     m_arrayBuffer = 0;
     m_arrayBuffer_lastEncode = 0;
+
+    m_attribEnableCache = 0;
+    m_vaoAttribBindingCacheInvalid = 0xffff;
+    m_vaoAttribBindingHasClientArrayCache = 0;
+    m_vaoAttribBindingHasVboCache = 0;
+    m_noClientArraysCache = 0;
+
     m_max_vertex_attrib_bindings = m_nLocations;
     addVertexArrayObject(0);
     setVertexArrayObject(0);
@@ -130,6 +137,12 @@
 {
     m_currVaoState[location].enableDirty |= (state != m_currVaoState[location].enabled);
     m_currVaoState[location].enabled = state;
+    if (state) {
+        m_attribEnableCache |= (1 << location);
+        m_noClientArraysCache = 0;
+    } else {
+        m_attribEnableCache &= ~(1 << location);
+    }
 }
 
 void GLClientState::setVertexAttribState(int location, int size, GLenum type, GLboolean normalized, GLsizei stride, const void *data, bool isInt)
@@ -163,6 +176,9 @@
 
 void GLClientState::setVertexAttribBinding(int attribindex, int bindingindex) {
     m_currVaoState[attribindex].bindingindex = bindingindex;
+    m_currVaoState.bufferBinding(bindingindex).vertexAttribLoc = attribindex;
+    m_vaoAttribBindingCacheInvalid |= (1 << attribindex);
+    m_noClientArraysCache = 0;
 }
 
 void GLClientState::setVertexAttribFormat(int location, int size, GLenum type, GLboolean normalized, GLuint reloffset, bool isInt) {
@@ -261,19 +277,74 @@
 
     m_currVaoState =
         VAOStateRef(m_vaoMap.find(name));
-    ALOGD("%s: set vao to %u (%u) %u %u", __FUNCTION__,
-            name,
-            m_currVaoState.vaoId(),
-            m_arrayBuffer,
-            m_currVaoState.iboId());
 }
 
 bool GLClientState::isVertexArrayObject(GLuint vao) const {
     return m_vaoMap.find(vao) != m_vaoMap.end();
 }
 
-const GLClientState::VertexAttribState& GLClientState::getState(int location)
-{
+void GLClientState::getVBOUsage(bool* hasClientArrays, bool* hasVBOs) {
+    uint8_t todo_count = 0;
+    uint8_t todo[CODEC_MAX_VERTEX_ATTRIBUTES];
+
+    if (m_noClientArraysCache) {
+        *hasClientArrays = false;
+        *hasVBOs = true;
+        return;
+    }
+
+    for (int i = 0; i < CODEC_MAX_VERTEX_ATTRIBUTES; i++) {
+        if ((1 << i) & (m_attribEnableCache)) {
+            if (!((1 << i) & m_vaoAttribBindingCacheInvalid)) {
+                if ((1 << i) & m_vaoAttribBindingHasClientArrayCache) {
+                    *hasClientArrays = true;
+                }
+                if ((1 << i) & m_vaoAttribBindingHasVboCache) {
+                    *hasVBOs = true;
+                }
+                if (*hasClientArrays && *hasVBOs) return;
+            } else {
+                todo[todo_count] = i;
+                ++todo_count;
+            }
+        }
+    }
+
+    if (todo_count == 0 &&
+        !(*hasClientArrays) &&
+        *hasVBOs) {
+        m_noClientArraysCache = 1;
+    }
+
+    for (int k = 0; k < todo_count; ++k) {
+        int i = todo[k];
+        const GLClientState::BufferBinding& curr_binding =
+            m_currVaoState.bufferBindings_const()[
+                m_currVaoState[i].bindingindex];
+        GLuint bufferObject = curr_binding.buffer;
+        if (bufferObject == 0 && curr_binding.offset && hasClientArrays) {
+            *hasClientArrays = true;
+            m_vaoAttribBindingHasClientArrayCache |= (1 << i);
+        } else {
+            m_vaoAttribBindingHasClientArrayCache &= ~(1 << i);
+        }
+        if (bufferObject != 0 && hasVBOs) {
+            *hasVBOs = true;
+            m_vaoAttribBindingHasVboCache |= (1 << i);
+        } else {
+            m_vaoAttribBindingHasVboCache &= ~(1 << i);
+        }
+        m_vaoAttribBindingCacheInvalid &= ~(1 << i);
+        if (*hasClientArrays && *hasVBOs) return;
+    }
+
+    if (!(*hasClientArrays) &&
+        *hasVBOs) {
+        m_noClientArraysCache = 1;
+    }
+}
+
+const GLClientState::VertexAttribState& GLClientState::getState(int location) {
     return m_currVaoState[location];
 }
 
@@ -399,6 +470,8 @@
     sClearIndexedBufferBinding(id, m_indexedAtomicCounterBuffers);
     sClearIndexedBufferBinding(id, m_indexedShaderStorageBuffers);
     sClearIndexedBufferBinding(id, m_currVaoState.bufferBindings());
+    m_vaoAttribBindingCacheInvalid = 0xffff;
+    m_noClientArraysCache = 0;
 }
 
 int GLClientState::bindBuffer(GLenum target, GLuint id)
@@ -479,6 +552,7 @@
         m_currVaoState.bufferBinding(index).size = size;
         m_currVaoState.bufferBinding(index).stride = stride;
         m_currVaoState.bufferBinding(index).effectiveStride = effectiveStride;
+        m_vaoAttribBindingCacheInvalid |= (1 << m_currVaoState.bufferBinding(index).vertexAttribLoc);
         return;
     }
 }
@@ -659,7 +733,7 @@
         }
     }
     if (which_state != -1)
-        *params = getState(which_state).data;
+        *params = m_currVaoState[which_state].data;
 }
 
 int GLClientState::setPixelStore(GLenum param, GLint value)
@@ -956,6 +1030,8 @@
 }
 
 void GLClientState::setBoundEGLImage(GLenum target, GLeglImageOES image) {
+    (void)image;
+
     GLuint texture = getBoundTexture(target);
     TextureRec* texrec = getTextureRec(texture);
     if (!texrec) return;
diff --git a/shared/OpenglCodecCommon/GLClientState.h b/shared/OpenglCodecCommon/GLClientState.h
index 49a63b6..5180338 100644
--- a/shared/OpenglCodecCommon/GLClientState.h
+++ b/shared/OpenglCodecCommon/GLClientState.h
@@ -139,6 +139,7 @@
         GLsizeiptr size;
         GLuint buffer;
         GLuint divisor;
+        GLint vertexAttribLoc;
     };
 
     typedef std::vector<VertexAttribState> VertexAttribStateVector;
@@ -221,6 +222,7 @@
     const BufferBinding& getCurrAttributeBindingInfo(int attribindex);
     void setVertexAttribBinding(int attribindex, int bindingindex);
     void setVertexAttribFormat(int location, int size, GLenum type, GLboolean normalized, GLuint reloffset, bool isInt = false);
+    void getVBOUsage(bool* hasClientArrays, bool* hasVBOs);
     const VertexAttribState& getState(int location);
     const VertexAttribState& getStateAndEnableDirty(int location, bool *enableChanged);
     void updateEnableDirtyArrayForDraw();
@@ -450,6 +452,12 @@
     VAOStateMap m_vaoMap;
     VAOStateRef m_currVaoState;
 
+    uint16_t m_attribEnableCache;
+    uint16_t m_vaoAttribBindingCacheInvalid;
+    uint16_t m_vaoAttribBindingHasClientArrayCache;
+    uint16_t m_vaoAttribBindingHasVboCache;
+    uint8_t m_noClientArraysCache;
+
     // Other buffer id's, other targets
     GLuint m_copyReadBuffer;
     GLuint m_copyWriteBuffer;
diff --git a/shared/OpenglCodecCommon/GLSharedGroup.cpp b/shared/OpenglCodecCommon/GLSharedGroup.cpp
index e4bc889..46d94a9 100755
--- a/shared/OpenglCodecCommon/GLSharedGroup.cpp
+++ b/shared/OpenglCodecCommon/GLSharedGroup.cpp
@@ -34,8 +34,7 @@
 
 /**** ProgramData ****/
 ProgramData::ProgramData() : m_numIndexes(0),
-                             m_initialized(false),
-                             m_locShiftWAR(false) {
+                             m_initialized(false) {
     m_Indexes = NULL;
 }
 
@@ -46,7 +45,6 @@
     delete [] m_Indexes;
 
     m_Indexes = new IndexInfo[numIndexes];
-    m_locShiftWAR = false;
 }
 
 bool ProgramData::isInitialized() {
@@ -68,14 +66,6 @@
     m_Indexes[index].base = base;
     m_Indexes[index].size = size;
     m_Indexes[index].type = type;
-
-    if (index > 0) {
-        m_Indexes[index].appBase = m_Indexes[index-1].appBase +
-                                   m_Indexes[index-1].size;
-    } else {
-        m_Indexes[index].appBase = 0;
-    }
-
     m_Indexes[index].hostLocsPerElement = 1;
     m_Indexes[index].flags = 0;
     m_Indexes[index].samplerValue = 0;
@@ -112,52 +102,6 @@
     return 0;
 }
 
-void ProgramData::setupLocationShiftWAR() {
-    m_locShiftWAR = false;
-    for (GLuint  i= 0; i < m_numIndexes; i++) {
-        if (0 != (m_Indexes[i].base & 0xffff)) {
-            return;
-        }
-    }
-
-    // if we have one uniform at location 0, we do not need the WAR.
-    if (m_numIndexes > 1) m_locShiftWAR = true;
-}
-
-GLint ProgramData::locationWARHostToApp(GLint hostLoc, GLint arrIndex) {
-
-    if (!m_locShiftWAR) return hostLoc;
-
-    GLuint index = getIndexForLocation(hostLoc);
-
-    if (index < m_numIndexes) {
-        if (arrIndex > 0) {
-            m_Indexes[index].hostLocsPerElement =
-                (hostLoc - m_Indexes[index].base) / arrIndex;
-        }
-        return m_Indexes[index].appBase + arrIndex;
-    }
-
-    return -1;
-}
-
-GLint ProgramData::locationWARAppToHost(GLint appLoc) {
-
-    if (!m_locShiftWAR) return appLoc;
-
-    for (GLuint i = 0; i < m_numIndexes; i++) {
-        GLint elemIndex =
-            appLoc - m_Indexes[i].appBase;
-
-        if (elemIndex >= 0 && elemIndex < m_Indexes[i].size) {
-            return m_Indexes[i].base +
-                   elemIndex * m_Indexes[i].hostLocsPerElement;
-        }
-    }
-
-    return -1;
-}
-
 GLint ProgramData::getNextSamplerUniform(
     GLint index, GLint* val, GLenum* target) {
 
@@ -187,7 +131,7 @@
 
     for (GLuint i = 0; i < m_numIndexes; i++) {
 
-        GLint elemIndex = appLoc - m_Indexes[i].appBase;
+        GLint elemIndex = appLoc - m_Indexes[i].base;
 
         if (elemIndex >= 0 && elemIndex < m_Indexes[i].size) {
             if (m_Indexes[i].type == GL_SAMPLER_2D) {
@@ -520,77 +464,6 @@
     return false;
 }
 
-void GLSharedGroup::setupLocationShiftWAR(GLuint program) {
-
-    android::AutoMutex _lock(m_lock);
-
-    ProgramData* pData =
-        findObjectOrDefault(m_programs, program);
-
-    if (pData) pData->setupLocationShiftWAR();
-}
-
-GLint GLSharedGroup::locationWARHostToApp(
-    GLuint program, GLint hostLoc, GLint arrIndex) {
-
-    android::AutoMutex _lock(m_lock);
-
-    ProgramData* pData = findObjectOrDefault(m_programs, program);
-
-    if (pData) return pData->locationWARHostToApp(hostLoc, arrIndex);
-
-    if (m_shaderProgramIdMap.find(program) ==
-        m_shaderProgramIdMap.end()) return hostLoc;
-
-    ShaderProgramData* spData =
-        findObjectOrDefault(m_shaderPrograms, m_shaderProgramIdMap[program]);
-
-    if (spData) return spData->programData.locationWARHostToApp(hostLoc, arrIndex);
-
-    return hostLoc;
-}
-
-GLint GLSharedGroup::locationWARAppToHost(GLuint program, GLint appLoc) {
-
-    android::AutoMutex _lock(m_lock);
-
-    ProgramData* pData =
-        findObjectOrDefault(m_programs, program);
-
-    if (pData) return pData->locationWARAppToHost(appLoc);
-
-    if (m_shaderProgramIdMap.find(program) ==
-        m_shaderProgramIdMap.end()) return appLoc;
-
-    ShaderProgramData* spData =
-        findObjectOrDefault(
-            m_shaderPrograms, m_shaderProgramIdMap[program]);
-
-    if (spData) return spData->programData.locationWARAppToHost(appLoc);
-
-    return appLoc;
-}
-
-bool GLSharedGroup::needUniformLocationWAR(GLuint program) {
-
-    android::AutoMutex _lock(m_lock);
-
-    ProgramData* pData =
-        findObjectOrDefault(m_programs, program);
-
-    if (pData) return pData->needUniformLocationWAR();
-
-    if (m_shaderProgramIdMap.find(program) ==
-        m_shaderProgramIdMap.end()) return false;
-
-    ShaderProgramData* spData =
-        findObjectOrDefault(m_shaderPrograms, m_shaderProgramIdMap[program]);
-
-    if (spData) return spData->programData.needUniformLocationWAR();
-
-    return false;
-}
-
 GLint GLSharedGroup::getNextSamplerUniform(
     GLuint program, GLint index, GLint* val, GLenum* target) const {
 
@@ -787,8 +660,3 @@
         }
     }
 }
-
-void GLSharedGroup::setupShaderProgramLocationShiftWAR(GLuint shaderProgram) {
-    ShaderProgramData* spData = getShaderProgramData(shaderProgram);
-    spData->programData.setupLocationShiftWAR();
-}
diff --git a/shared/OpenglCodecCommon/GLSharedGroup.h b/shared/OpenglCodecCommon/GLSharedGroup.h
index 9ef92ea..d471795 100755
--- a/shared/OpenglCodecCommon/GLSharedGroup.h
+++ b/shared/OpenglCodecCommon/GLSharedGroup.h
@@ -71,7 +71,6 @@
         GLint base;
         GLint size;
         GLenum type;
-        GLint appBase;
         GLint hostLocsPerElement;
         GLuint flags;
         GLint samplerValue; // only set for sampler uniforms
@@ -80,7 +79,6 @@
     GLuint m_numIndexes;
     IndexInfo* m_Indexes;
     bool m_initialized;
-    bool m_locShiftWAR;
 
     std::vector<GLuint> m_shaders;
 
@@ -98,11 +96,6 @@
     GLuint getIndexForLocation(GLint location);
     GLenum getTypeForLocation(GLint location);
 
-    bool needUniformLocationWAR() const { return m_locShiftWAR; }
-    void setupLocationShiftWAR();
-    GLint locationWARHostToApp(GLint hostLoc, GLint arrIndex);
-    GLint locationWARAppToHost(GLint appLoc);
-
     GLint getNextSamplerUniform(GLint index, GLint* val, GLenum* target);
     bool setSamplerUniform(GLint appLoc, GLint val, GLenum* target);
 
@@ -165,10 +158,6 @@
     void    deleteProgramData(GLuint program);
     void    setProgramIndexInfo(GLuint program, GLuint index, GLint base, GLint size, GLenum type, const char* name);
     GLenum  getProgramUniformType(GLuint program, GLint location);
-    void    setupLocationShiftWAR(GLuint program);
-    GLint   locationWARHostToApp(GLuint program, GLint hostLoc, GLint arrIndex);
-    GLint   locationWARAppToHost(GLuint program, GLint appLoc);
-    bool    needUniformLocationWAR(GLuint program);
     GLint   getNextSamplerUniform(GLuint program, GLint index, GLint* val, GLenum* target) const;
     bool    setSamplerUniform(GLuint program, GLint appLoc, GLint val, GLenum* target);
 
@@ -187,7 +176,6 @@
     void deleteShaderProgramData(GLuint shaderProgramName);
     void initShaderProgramData(GLuint shaderProgram, GLuint numIndices);
     void setShaderProgramIndexInfo(GLuint shaderProgram, GLuint index, GLint base, GLint size, GLenum type, const char* name);
-    void setupShaderProgramLocationShiftWAR(GLuint shaderProgram);
 };
 
 typedef SmartPtr<GLSharedGroup> GLSharedGroupPtr; 
diff --git a/shared/OpenglCodecCommon/SocketStream.cpp b/shared/OpenglCodecCommon/SocketStream.cpp
index e813142..d6d31c0 100644
--- a/shared/OpenglCodecCommon/SocketStream.cpp
+++ b/shared/OpenglCodecCommon/SocketStream.cpp
@@ -130,6 +130,11 @@
     return (const unsigned char *)buf;
 }
 
+const unsigned char *SocketStream::commitBufferAndReadFully(size_t size, void *buf, size_t len)
+{
+    return commitBuffer(size) ? NULL : readFully(buf, len);
+}
+
 const unsigned char *SocketStream::read( void *buf, size_t *inout_len)
 {
     if (!valid()) return NULL;
diff --git a/shared/OpenglCodecCommon/SocketStream.h b/shared/OpenglCodecCommon/SocketStream.h
index 3a501b4..3d8f5f5 100644
--- a/shared/OpenglCodecCommon/SocketStream.h
+++ b/shared/OpenglCodecCommon/SocketStream.h
@@ -33,6 +33,7 @@
     virtual void *allocBuffer(size_t minSize);
     virtual int commitBuffer(size_t size);
     virtual const unsigned char *readFully(void *buf, size_t len);
+    virtual const unsigned char *commitBufferAndReadFully(size_t size, void *buf, size_t len);
     virtual const unsigned char *read(void *buf, size_t *inout_len);
 
     bool valid() { return m_sock >= 0; }
diff --git a/shared/OpenglCodecCommon/goldfish_address_space.cpp b/shared/OpenglCodecCommon/goldfish_address_space.cpp
index bbc59c6..7bb628c 100644
--- a/shared/OpenglCodecCommon/goldfish_address_space.cpp
+++ b/shared/OpenglCodecCommon/goldfish_address_space.cpp
@@ -13,271 +13,14 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-#if PLATFORM_SDK_VERSION < 26
-#include <cutils/log.h>
+#if defined(HOST_BUILD)
+#include "goldfish_address_space_host.impl"
+#elif defined(__Fuchsia__)
+#include "goldfish_address_space_fuchsia.impl"
 #else
-#include <log/log.h>
+#include "goldfish_address_space_android.impl"
 #endif
 
-#include "goldfish_address_space.h"
-
-#ifdef HOST_BUILD
-
-#include "android/base/SubAllocator.h"
-#include "android/base/memory/LazyInstance.h"
-
-// AddressSpaceHost is a global class for obtaining physical addresses
-// for the host-side build.
-class AddressSpaceHost {
-public:
-    AddressSpaceHost() : mAlloc(0, 16ULL * 1024ULL * 1048576ULL, 4096) { }
-    uint64_t alloc(size_t size) {
-        return (uint64_t)(uintptr_t)mAlloc.alloc(size);
-    }
-    void free(uint64_t addr) {
-        mAlloc.free((void*)(uintptr_t)addr);
-    }
-private:
-    android::base::SubAllocator mAlloc;
-};
-
-static android::base::LazyInstance<AddressSpaceHost> sAddressSpaceHost =
-    LAZY_INSTANCE_INIT;
-
-// It may seem like there should be one allocator per provider,
-// but to properly reflect the guest behavior where there is only one
-// allocator in the system and multiple providers are possible,
-// we need to have a separate global object (sAddressSpaceHost).
-GoldfishAddressSpaceBlockProvider::GoldfishAddressSpaceBlockProvider()
-    : mAlloc(sAddressSpaceHost.ptr()) {}
-
-GoldfishAddressSpaceBlockProvider::~GoldfishAddressSpaceBlockProvider() { }
-
-uint64_t GoldfishAddressSpaceBlockProvider::allocPhys(size_t size) {
-    AddressSpaceHost* hostAlloc = reinterpret_cast<AddressSpaceHost*>(mAlloc);
-    return hostAlloc->alloc(size);
-}
-
-void GoldfishAddressSpaceBlockProvider::freePhys(uint64_t phys) {
-    AddressSpaceHost* hostAlloc = reinterpret_cast<AddressSpaceHost*>(mAlloc);
-    return hostAlloc->free(phys);
-}
-
-GoldfishAddressSpaceBlock::GoldfishAddressSpaceBlock() :
-    m_alloced(false), m_guest_ptr(NULL), m_phys_addr(0), m_provider(NULL) {}
-GoldfishAddressSpaceBlock::~GoldfishAddressSpaceBlock() { destroy(); }
-
-GoldfishAddressSpaceBlock &GoldfishAddressSpaceBlock::operator=(const GoldfishAddressSpaceBlock &rhs)
-{
-    m_guest_ptr = rhs.m_guest_ptr;
-    m_phys_addr = rhs.m_phys_addr;
-    m_provider = rhs.m_provider;
-    return *this;
-}
-
-bool GoldfishAddressSpaceBlock::allocate(GoldfishAddressSpaceBlockProvider *provider, size_t size)
-{
-    destroy();
-    m_phys_addr = provider->allocPhys(size);
-    m_alloced = true;
-    m_provider = provider;
-    return true;
-}
-
-uint64_t GoldfishAddressSpaceBlock::physAddr() const
-{
-    return m_phys_addr;
-}
-
-uint64_t GoldfishAddressSpaceBlock::hostAddr() const
-{
-    return 42;  // some random number, not used
-}
-
-void *GoldfishAddressSpaceBlock::mmap(uint64_t opaque)
-{
-    m_guest_ptr = reinterpret_cast<void *>(opaque);
-    return m_guest_ptr;
-}
-
-void *GoldfishAddressSpaceBlock::guestPtr() const
-{
-    return m_guest_ptr;
-}
-
-void GoldfishAddressSpaceBlock::destroy()
-{
-    if (m_alloced) {
-        m_guest_ptr = NULL;
-        if (m_provider) {
-            m_provider->freePhys(m_phys_addr);
-        }
-        m_alloced = false;
-    }
-}
-
-void GoldfishAddressSpaceBlock::replace(GoldfishAddressSpaceBlock *other)
-{
-    if (other) {
-        this->m_guest_ptr = other->m_guest_ptr;
-        other->m_guest_ptr = NULL;
-    } else {
-        this->m_guest_ptr = NULL;
-    }
-}
-#elif __Fuchsia__
-#include <fcntl.h>
-#include <fuchsia/hardware/goldfish/address/space/c/fidl.h>
-#include <lib/fdio/fdio.h>
-#include <stdlib.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <unistd.h>
-#include <zircon/process.h>
-#include <zircon/syscalls.h>
-#include <zircon/syscalls/object.h>
-
-GoldfishAddressSpaceBlockProvider::GoldfishAddressSpaceBlockProvider() {
-    fdio_get_service_handle(::open(GOLDFISH_ADDRESS_SPACE_DEVICE_NAME, O_RDWR), &m_channel);
-}
-
-GoldfishAddressSpaceBlockProvider::~GoldfishAddressSpaceBlockProvider()
-{
-    zx_handle_close(m_channel);
-}
-
-GoldfishAddressSpaceBlock::GoldfishAddressSpaceBlock()
-    : m_vmo(ZX_HANDLE_INVALID)
-    , m_channel(ZX_HANDLE_INVALID)
-    , m_mmaped_ptr(NULL)
-    , m_phys_addr(0)
-    , m_host_addr(0)
-    , m_offset(0)
-    , m_size(0) {}
-
-GoldfishAddressSpaceBlock::~GoldfishAddressSpaceBlock()
-{
-    destroy();
-}
-
-GoldfishAddressSpaceBlock &GoldfishAddressSpaceBlock::operator=(const GoldfishAddressSpaceBlock &rhs)
-{
-    m_vmo = rhs.m_vmo;
-    m_mmaped_ptr = rhs.m_mmaped_ptr;
-    m_phys_addr = rhs.m_phys_addr;
-    m_host_addr = rhs.m_host_addr;
-    m_offset = rhs.m_offset;
-    m_size = rhs.m_size;
-    m_channel = rhs.m_channel;
-
-    return *this;
-}
-
-bool GoldfishAddressSpaceBlock::allocate(GoldfishAddressSpaceBlockProvider *provider, size_t size)
-{
-    ALOGD("%s: Ask for block of size 0x%llx\n", __func__,
-         (unsigned long long)size);
-
-    destroy();
-
-    if (!provider->is_opened()) {
-        return false;
-    }
-
-    int32_t res = ZX_OK;
-    zx_status_t status =
-        fuchsia_hardware_goldfish_address_space_DeviceAllocateBlock(
-            provider->m_channel, size, &res, &m_phys_addr, &m_vmo);
-    if (status != ZX_OK || res != ZX_OK) {
-        ALOGE("%s: allocate block failed: %d:%d", __func__, status, res);
-        return false;
-    }
-
-    m_offset = 0;
-    m_size = size;
-
-    ALOGD("%s: allocate returned offset 0x%llx size 0x%llx\n", __func__,
-          (unsigned long long)m_offset,
-          (unsigned long long)m_size);
-
-    m_channel = provider->m_channel;
-    return true;
-}
-
-uint64_t GoldfishAddressSpaceBlock::physAddr() const
-{
-    return m_phys_addr;
-}
-
-uint64_t GoldfishAddressSpaceBlock::hostAddr() const
-{
-    return m_host_addr;
-}
-
-void *GoldfishAddressSpaceBlock::mmap(uint64_t host_addr)
-{
-    if (m_size == 0) {
-        ALOGE("%s: called with zero size\n", __func__);
-        return NULL;
-    }
-    if (m_mmaped_ptr) {
-        ALOGE("'mmap' called for an already mmaped address block");
-        ::abort();
-    }
-
-    zx_vaddr_t ptr = 0;
-    zx_status_t status = zx_vmar_map(zx_vmar_root_self(),
-                                     ZX_VM_PERM_READ | ZX_VM_PERM_WRITE,
-                                     0, m_vmo,
-                                     m_offset,
-                                     m_size,
-                                     &ptr);
-    if (status != ZX_OK) {
-        ALOGE("%s: host memory map failed with size 0x%llx "
-              "off 0x%llx status %d\n",
-              __func__,
-              (unsigned long long)m_size,
-              (unsigned long long)m_offset, status);
-        return NULL;
-    } else {
-        m_mmaped_ptr = (void*)ptr;
-        m_host_addr = host_addr;
-        return guestPtr();
-    }
-}
-
-void *GoldfishAddressSpaceBlock::guestPtr() const
-{
-    return reinterpret_cast<char *>(m_mmaped_ptr) + (m_host_addr & (PAGE_SIZE - 1));
-}
-
-void GoldfishAddressSpaceBlock::destroy()
-{
-    if (m_mmaped_ptr && m_size) {
-        zx_vmar_unmap(zx_vmar_root_self(),
-                      (zx_vaddr_t)m_mmaped_ptr,
-                      m_size);
-        m_mmaped_ptr = NULL;
-    }
-
-    if (m_size) {
-        zx_handle_close(m_vmo);
-        m_vmo = ZX_HANDLE_INVALID;
-        int32_t res = ZX_OK;
-        zx_status_t status =
-            fuchsia_hardware_goldfish_address_space_DeviceDeallocateBlock(
-                m_channel, m_phys_addr, &res);
-        if (status != ZX_OK || res != ZX_OK) {
-            ALOGE("%s: deallocate block failed: %d:%d", __func__, status, res);
-        }
-        m_channel = ZX_HANDLE_INVALID;
-        m_phys_addr = 0;
-        m_host_addr = 0;
-        m_offset = 0;
-        m_size = 0;
-    }
-}
-
 void GoldfishAddressSpaceBlock::replace(GoldfishAddressSpaceBlock *other)
 {
     destroy();
@@ -287,172 +30,3 @@
         *other = GoldfishAddressSpaceBlock();
     }
 }
-
-bool GoldfishAddressSpaceBlockProvider::is_opened()
-{
-    return m_channel != ZX_HANDLE_INVALID;
-}
-#else
-#include <linux/types.h>
-#include <linux/ioctl.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <sys/mman.h>
-#include <sys/ioctl.h>
-#include <fcntl.h>
-#include <unistd.h>
-#include <cstdlib>
-#include <errno.h>
-
-struct goldfish_address_space_allocate_block {
-    __u64 size;
-    __u64 offset;
-    __u64 phys_addr;
-};
-
-#define GOLDFISH_ADDRESS_SPACE_IOCTL_MAGIC		'G'
-#define GOLDFISH_ADDRESS_SPACE_IOCTL_OP(OP, T)		_IOWR(GOLDFISH_ADDRESS_SPACE_IOCTL_MAGIC, OP, T)
-#define GOLDFISH_ADDRESS_SPACE_IOCTL_ALLOCATE_BLOCK	GOLDFISH_ADDRESS_SPACE_IOCTL_OP(10, struct goldfish_address_space_allocate_block)
-#define GOLDFISH_ADDRESS_SPACE_IOCTL_DEALLOCATE_BLOCK	GOLDFISH_ADDRESS_SPACE_IOCTL_OP(11, __u64)
-
-const char GOLDFISH_ADDRESS_SPACE_DEVICE_NAME[] = "/dev/goldfish_address_space";
-
-GoldfishAddressSpaceBlockProvider::GoldfishAddressSpaceBlockProvider()
-    : m_fd(::open(GOLDFISH_ADDRESS_SPACE_DEVICE_NAME, O_RDWR)) {}
-
-GoldfishAddressSpaceBlockProvider::~GoldfishAddressSpaceBlockProvider()
-{
-    ::close(m_fd);
-}
-
-GoldfishAddressSpaceBlock::GoldfishAddressSpaceBlock()
-    : m_mmaped_ptr(NULL)
-    , m_phys_addr(0)
-    , m_host_addr(0)
-    , m_offset(0)
-    , m_size(0)
-    , m_fd(-1) {}
-
-GoldfishAddressSpaceBlock::~GoldfishAddressSpaceBlock()
-{
-    destroy();
-}
-
-GoldfishAddressSpaceBlock &GoldfishAddressSpaceBlock::operator=(const GoldfishAddressSpaceBlock &rhs)
-{
-    m_mmaped_ptr = rhs.m_mmaped_ptr;
-    m_phys_addr = rhs.m_phys_addr;
-    m_host_addr = rhs.m_host_addr;
-    m_offset = rhs.m_offset;
-    m_size = rhs.m_size;
-    m_fd = rhs.m_fd;
-
-    return *this;
-}
-
-bool GoldfishAddressSpaceBlock::allocate(GoldfishAddressSpaceBlockProvider *provider, size_t size)
-{
-
-    ALOGD("%s: Ask for block of size 0x%llx\n", __func__,
-         (unsigned long long)size);
-
-    destroy();
-
-    if (!provider->is_opened()) {
-        return false;
-    }
-
-    struct goldfish_address_space_allocate_block request;
-    long res;
-
-    request.size = size;
-    res = ::ioctl(provider->m_fd, GOLDFISH_ADDRESS_SPACE_IOCTL_ALLOCATE_BLOCK, &request);
-    if (res) {
-        return false;
-    } else {
-        m_phys_addr = request.phys_addr;
-
-        m_offset = request.offset;
-        m_size = request.size;
-
-        ALOGD("%s: ioctl allocate returned offset 0x%llx size 0x%llx\n", __func__,
-                (unsigned long long)m_offset,
-                (unsigned long long)m_size);
-
-        m_fd = provider->m_fd;
-        return true;
-    }
-}
-
-uint64_t GoldfishAddressSpaceBlock::physAddr() const
-{
-    return m_phys_addr;
-}
-
-uint64_t GoldfishAddressSpaceBlock::hostAddr() const
-{
-    return m_host_addr;
-}
-
-void *GoldfishAddressSpaceBlock::mmap(uint64_t host_addr)
-{
-    if (m_size == 0) {
-        ALOGE("%s: called with zero size\n", __func__);
-        return NULL;
-    }
-    if (m_mmaped_ptr) {
-        ALOGE("'mmap' called for an already mmaped address block");
-        ::abort();
-    }
-
-    void *result = ::mmap64(NULL, m_size, PROT_WRITE, MAP_SHARED, m_fd, m_offset);
-    if (result == MAP_FAILED) {
-        ALOGE("%s: host memory map failed with size 0x%llx "
-              "off 0x%llx errno %d\n",
-              __func__,
-              (unsigned long long)m_size,
-              (unsigned long long)m_offset, errno);
-        return NULL;
-    } else {
-        m_mmaped_ptr = result;
-        m_host_addr = host_addr;
-        return guestPtr();
-    }
-}
-
-void *GoldfishAddressSpaceBlock::guestPtr() const
-{
-    return reinterpret_cast<char *>(m_mmaped_ptr) + (m_host_addr & (PAGE_SIZE - 1));
-}
-
-void GoldfishAddressSpaceBlock::destroy()
-{
-    if (m_mmaped_ptr && m_size) {
-        ::munmap(m_mmaped_ptr, m_size);
-        m_mmaped_ptr = NULL;
-    }
-
-    if (m_size) {
-        ::ioctl(m_fd, GOLDFISH_ADDRESS_SPACE_IOCTL_DEALLOCATE_BLOCK, &m_offset);
-        m_phys_addr = 0;
-        m_host_addr = 0;
-        m_offset = 0;
-        m_size = 0;
-    }
-}
-
-void GoldfishAddressSpaceBlock::replace(GoldfishAddressSpaceBlock *other)
-{
-    destroy();
-
-    if (other) {
-        *this = *other;
-        *other = GoldfishAddressSpaceBlock();
-    }
-}
-
-bool GoldfishAddressSpaceBlockProvider::is_opened()
-{
-    return m_fd >= 0;
-}
-#endif
diff --git a/shared/OpenglCodecCommon/goldfish_address_space.h b/shared/OpenglCodecCommon/goldfish_address_space.h
index 7ebb451..064f601 100644
--- a/shared/OpenglCodecCommon/goldfish_address_space.h
+++ b/shared/OpenglCodecCommon/goldfish_address_space.h
@@ -18,42 +18,62 @@
 #include <inttypes.h>
 #include <stddef.h>
 
+#ifdef __Fuchsia__
+#include <fuchsia/hardware/goldfish/cpp/fidl.h>
+#endif
+
 class GoldfishAddressSpaceBlock;
+class GoldfishAddressSpaceHostMemoryAllocator;
 
 #ifdef HOST_BUILD
-class GoldfishAddressSpaceBlockProvider {
-public:
-    GoldfishAddressSpaceBlockProvider();
-    ~GoldfishAddressSpaceBlockProvider();
 
-    uint64_t allocPhys(size_t size);
-    void freePhys(uint64_t phys);
+namespace android {
 
-private:
-   void* mAlloc;
+class HostAddressSpaceDevice;
 
-   friend class GoldfishAddressSpaceBlock;
-};
+} // namespace android
+
+#endif
+
+#if defined(__Fuchsia__)
+    typedef void* address_space_handle_t;
+#elif defined(HOST_BUILD)
+    typedef uint32_t address_space_handle_t;
 #else
+    typedef int address_space_handle_t;
+#endif
+
+enum GoldfishAddressSpaceSubdeviceType {
+    NoSubdevice = -1,
+    Graphics = 0,
+    Media = 1,
+    HostMemoryAllocator = 5,
+};
+
 class GoldfishAddressSpaceBlockProvider {
 public:
-    GoldfishAddressSpaceBlockProvider();
+    GoldfishAddressSpaceBlockProvider(GoldfishAddressSpaceSubdeviceType subdevice);
     ~GoldfishAddressSpaceBlockProvider();
 
 private:
-   GoldfishAddressSpaceBlockProvider(const GoldfishAddressSpaceBlockProvider &rhs);
-   GoldfishAddressSpaceBlockProvider &operator=(const GoldfishAddressSpaceBlockProvider &rhs);
+    GoldfishAddressSpaceBlockProvider(const GoldfishAddressSpaceBlockProvider &rhs);
+    GoldfishAddressSpaceBlockProvider &operator=(const GoldfishAddressSpaceBlockProvider &rhs);
 
-   bool is_opened();
+    bool is_opened() const;
+    void close();
+    address_space_handle_t release();
+    static void closeHandle(address_space_handle_t handle);
+
 #ifdef __Fuchsia__
-   uint32_t m_channel;
-#else
-   int m_fd;
-#endif
+    fuchsia::hardware::goldfish::AddressSpaceDeviceSyncPtr m_device;
+    fuchsia::hardware::goldfish::AddressSpaceChildDriverSyncPtr m_child_driver;
+#else // __Fuchsia__
+    address_space_handle_t m_handle;
+#endif // !__Fuchsia__
 
-   friend class GoldfishAddressSpaceBlock;
+    friend class GoldfishAddressSpaceBlock;
+    friend class GoldfishAddressSpaceHostMemoryAllocator;
 };
-#endif
 
 class GoldfishAddressSpaceBlock {
 public:
@@ -61,34 +81,87 @@
     ~GoldfishAddressSpaceBlock();
 
     bool allocate(GoldfishAddressSpaceBlockProvider *provider, size_t size);
+    bool claimShared(GoldfishAddressSpaceBlockProvider *provider, uint64_t offset, uint64_t size);
     uint64_t physAddr() const;
     uint64_t hostAddr() const;
+    uint64_t offset() const { return m_offset; }
+    size_t size() const { return m_size; }
     void *mmap(uint64_t opaque);
     void *guestPtr() const;
-    void replace(GoldfishAddressSpaceBlock *x);
+    void replace(GoldfishAddressSpaceBlock *other);
+    void release();
+    static int memoryMap(void *addr, size_t len, address_space_handle_t fd, uint64_t off, void** dst);
+    static void memoryUnmap(void *ptr, size_t size);
 
 private:
     void destroy();
     GoldfishAddressSpaceBlock &operator=(const GoldfishAddressSpaceBlock &);
 
-#ifdef HOST_BUILD
-    bool        m_alloced;
-    void     *m_guest_ptr;
-    uint64_t  m_phys_addr;
-    GoldfishAddressSpaceBlockProvider* m_provider;
-#else
 #ifdef __Fuchsia__
+    fuchsia::hardware::goldfish::AddressSpaceChildDriverSyncPtr* m_driver;
     uint32_t  m_vmo;
-    uint32_t  m_channel;
-#else
-    int       m_fd;
-#endif
+#else // __Fuchsia__
+    address_space_handle_t m_handle;
+#endif // !__Fuchsia__
+
     void     *m_mmaped_ptr;
     uint64_t  m_phys_addr;
     uint64_t  m_host_addr;
     uint64_t  m_offset;
-    size_t    m_size;
-#endif
+    uint64_t  m_size;
+    bool      m_is_shared_mapping;
 };
 
-#endif
+class GoldfishAddressSpaceHostMemoryAllocator {
+public:
+    GoldfishAddressSpaceHostMemoryAllocator();
+
+    long hostMalloc(GoldfishAddressSpaceBlock *block, size_t size);
+    void hostFree(GoldfishAddressSpaceBlock *block);
+
+    bool is_opened() const;
+    address_space_handle_t release() { return m_provider.release(); }
+    static void closeHandle(address_space_handle_t handle) { GoldfishAddressSpaceBlockProvider::closeHandle(handle); }
+
+private:
+    GoldfishAddressSpaceBlockProvider m_provider;
+};
+
+// Convenience functions that run address space driver api without wrapping in
+// a class. Useful for when a client wants to manage the driver handle directly
+// (e.g., mmaping() more than one region associated with a single handle will
+// require different lifetime expectations versus GoldfishAddressSpaceBlock).
+
+// We also expose the ping info struct that is shared between host and guest.
+struct goldfish_address_space_ping {
+    uint64_t offset;
+    uint64_t size;
+    uint64_t metadata;
+    uint32_t version;
+    uint32_t wait_fd;
+    uint32_t wait_flags;
+    uint32_t direction;
+};
+
+address_space_handle_t goldfish_address_space_open();
+void goldfish_address_space_close(address_space_handle_t);
+
+bool goldfish_address_space_allocate(
+    address_space_handle_t, size_t size, uint64_t* phys_addr, uint64_t* offset);
+bool goldfish_address_space_free(
+    address_space_handle_t, uint64_t offset);
+
+bool goldfish_address_space_claim_shared(
+    address_space_handle_t, uint64_t offset, uint64_t size);
+bool goldfish_address_space_unclaim_shared(
+    address_space_handle_t, uint64_t offset);
+
+// pgoff is the offset into the page to return in the result
+void* goldfish_address_space_map(
+    address_space_handle_t, uint64_t offset, uint64_t size, uint64_t pgoff = 0);
+void goldfish_address_space_unmap(void* ptr, uint64_t size);
+
+bool goldfish_address_space_set_subdevice_type(address_space_handle_t, GoldfishAddressSpaceSubdeviceType type, address_space_handle_t*);
+bool goldfish_address_space_ping(address_space_handle_t, struct goldfish_address_space_ping*);
+
+#endif  // #ifndef ANDROID_INCLUDE_HARDWARE_GOLDFISH_ADDRESS_SPACE_H
diff --git a/shared/OpenglCodecCommon/goldfish_address_space_android.impl b/shared/OpenglCodecCommon/goldfish_address_space_android.impl
new file mode 100644
index 0000000..646695f
--- /dev/null
+++ b/shared/OpenglCodecCommon/goldfish_address_space_android.impl
@@ -0,0 +1,511 @@
+// Copyright (C) 2019 The Android Open Source Project
+// Copyright (C) 2019 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include <linux/types.h>
+#include <linux/ioctl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/mman.h>
+#include <sys/ioctl.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <cstdlib>
+#include <errno.h>
+#include <memory>
+
+#if PLATFORM_SDK_VERSION < 26
+#include <cutils/log.h>
+#else
+#include <log/log.h>
+#endif
+
+#include "goldfish_address_space.h"
+
+namespace {
+
+struct goldfish_address_space_allocate_block {
+    __u64 size;
+    __u64 offset;
+    __u64 phys_addr;
+};
+
+struct goldfish_address_space_claim_shared {
+    __u64 offset;
+    __u64 size;
+};
+
+#define GOLDFISH_ADDRESS_SPACE_IOCTL_MAGIC		'G'
+#define GOLDFISH_ADDRESS_SPACE_IOCTL_OP(OP, T)		_IOWR(GOLDFISH_ADDRESS_SPACE_IOCTL_MAGIC, OP, T)
+#define GOLDFISH_ADDRESS_SPACE_IOCTL_ALLOCATE_BLOCK	GOLDFISH_ADDRESS_SPACE_IOCTL_OP(10, struct goldfish_address_space_allocate_block)
+#define GOLDFISH_ADDRESS_SPACE_IOCTL_DEALLOCATE_BLOCK	GOLDFISH_ADDRESS_SPACE_IOCTL_OP(11, __u64)
+#define GOLDFISH_ADDRESS_SPACE_IOCTL_PING		GOLDFISH_ADDRESS_SPACE_IOCTL_OP(12, struct goldfish_address_space_ping)
+#define GOLDFISH_ADDRESS_SPACE_IOCTL_CLAIM_SHARED		GOLDFISH_ADDRESS_SPACE_IOCTL_OP(13, struct goldfish_address_space_claim_shared)
+#define GOLDFISH_ADDRESS_SPACE_IOCTL_UNCLAIM_SHARED		GOLDFISH_ADDRESS_SPACE_IOCTL_OP(14, __u64)
+
+const char GOLDFISH_ADDRESS_SPACE_DEVICE_NAME[] = "/dev/goldfish_address_space";
+
+const int HOST_MEMORY_ALLOCATOR_COMMAND_ALLOCATE_ID = 1;
+const int HOST_MEMORY_ALLOCATOR_COMMAND_UNALLOCATE_ID = 2;
+
+int create_address_space_fd()
+{
+    return ::open(GOLDFISH_ADDRESS_SPACE_DEVICE_NAME, O_RDWR);
+}
+
+long ioctl_allocate(int fd, struct goldfish_address_space_allocate_block *request)
+{
+    return ::ioctl(fd, GOLDFISH_ADDRESS_SPACE_IOCTL_ALLOCATE_BLOCK, request);
+}
+
+long ioctl_deallocate(int fd, uint64_t offset)
+{
+    return ::ioctl(fd, GOLDFISH_ADDRESS_SPACE_IOCTL_DEALLOCATE_BLOCK, &offset);
+}
+
+long ioctl_ping(int fd, struct goldfish_address_space_ping *request)
+{
+    return ::ioctl(fd, GOLDFISH_ADDRESS_SPACE_IOCTL_PING, request);
+}
+
+long set_address_space_subdevice_type(int fd, uint64_t type)
+{
+    struct goldfish_address_space_ping request;
+    ::memset(&request, 0, sizeof(request));
+    request.version = sizeof(request);
+    request.metadata = type;
+
+    return ioctl_ping(fd, &request);
+}
+
+long ioctl_claim_shared(int fd, struct goldfish_address_space_claim_shared *request)
+{
+    return ::ioctl(fd, GOLDFISH_ADDRESS_SPACE_IOCTL_CLAIM_SHARED, request);
+}
+
+long ioctl_unclaim_shared(int fd, uint64_t offset)
+{
+    return ::ioctl(fd, GOLDFISH_ADDRESS_SPACE_IOCTL_UNCLAIM_SHARED, &offset);
+}
+
+}  // namespace
+
+GoldfishAddressSpaceBlockProvider::GoldfishAddressSpaceBlockProvider(GoldfishAddressSpaceSubdeviceType subdevice)
+  : m_handle(create_address_space_fd())
+{
+    if ((subdevice != GoldfishAddressSpaceSubdeviceType::NoSubdevice) && is_opened()) {
+        const long ret = set_address_space_subdevice_type(m_handle, subdevice);
+        if (ret) {
+            ALOGE("%s: set_address_space_subdevice_type failed for device_type=%lu, ret=%ld",
+                  __func__, static_cast<unsigned long>(subdevice), ret);
+            close();
+        }
+    }
+}
+
+GoldfishAddressSpaceBlockProvider::~GoldfishAddressSpaceBlockProvider()
+{
+    if (is_opened()) {
+        ::close(m_handle);
+    }
+}
+
+bool GoldfishAddressSpaceBlockProvider::is_opened() const
+{
+    return m_handle >= 0;
+}
+
+void GoldfishAddressSpaceBlockProvider::close()
+{
+    if (is_opened()) {
+        ::close(m_handle);
+        m_handle = -1;
+    }
+}
+
+address_space_handle_t GoldfishAddressSpaceBlockProvider::release()
+{
+    address_space_handle_t handle = m_handle;
+    m_handle = -1;
+    return handle;
+}
+
+void GoldfishAddressSpaceBlockProvider::closeHandle(address_space_handle_t handle)
+{
+    ::close(handle);
+}
+
+GoldfishAddressSpaceBlock::GoldfishAddressSpaceBlock()
+    : m_handle(-1)
+    , m_mmaped_ptr(NULL)
+    , m_phys_addr(0)
+    , m_host_addr(0)
+    , m_offset(0)
+    , m_size(0) {}
+
+GoldfishAddressSpaceBlock::~GoldfishAddressSpaceBlock()
+{
+    destroy();
+}
+
+GoldfishAddressSpaceBlock &GoldfishAddressSpaceBlock::operator=(const GoldfishAddressSpaceBlock &rhs)
+{
+    m_mmaped_ptr = rhs.m_mmaped_ptr;
+    m_phys_addr = rhs.m_phys_addr;
+    m_host_addr = rhs.m_host_addr;
+    m_offset = rhs.m_offset;
+    m_size = rhs.m_size;
+    m_handle = rhs.m_handle;
+
+    return *this;
+}
+
+bool GoldfishAddressSpaceBlock::allocate(GoldfishAddressSpaceBlockProvider *provider, size_t size)
+{
+    ALOGD("%s: Ask for block of size 0x%llx\n", __func__,
+         (unsigned long long)size);
+
+    destroy();
+
+    if (!provider->is_opened()) {
+        return false;
+    }
+
+    struct goldfish_address_space_allocate_block request;
+    ::memset(&request, 0, sizeof(request));
+    request.size = size;
+
+    long res = ioctl_allocate(provider->m_handle, &request);
+    if (res) {
+        return false;
+    } else {
+        m_phys_addr = request.phys_addr;
+        m_offset = request.offset;
+        m_size = request.size;
+        m_handle = provider->m_handle;
+        m_is_shared_mapping = false;
+
+        ALOGD("%s: ioctl allocate returned offset 0x%llx size 0x%llx\n", __func__,
+                (unsigned long long)m_offset,
+                (unsigned long long)m_size);
+
+        return true;
+    }
+}
+
+bool GoldfishAddressSpaceBlock::claimShared(GoldfishAddressSpaceBlockProvider *provider, uint64_t offset, uint64_t size)
+{
+    ALOGD("%s: Ask to claim region [0x%llx 0x%llx]\n", __func__,
+         (unsigned long long)offset,
+         (unsigned long long)offset + size);
+
+    destroy();
+
+    if (!provider->is_opened()) {
+        return false;
+    }
+
+    struct goldfish_address_space_claim_shared request;
+    request.offset = offset;
+    request.size = size;
+    long res = ioctl_claim_shared(provider->m_handle, &request);
+
+    if (res) {
+        return false;
+    }
+
+    m_offset = offset;
+    m_size = size;
+    m_handle = provider->m_handle;
+    m_is_shared_mapping = true;
+
+    return true;
+}
+
+uint64_t GoldfishAddressSpaceBlock::physAddr() const
+{
+    return m_phys_addr;
+}
+
+uint64_t GoldfishAddressSpaceBlock::hostAddr() const
+{
+    return m_host_addr;
+}
+
+void *GoldfishAddressSpaceBlock::mmap(uint64_t host_addr)
+{
+    if (m_size == 0) {
+        ALOGE("%s: called with zero size\n", __func__);
+        return NULL;
+    }
+    if (m_mmaped_ptr) {
+        ALOGE("'mmap' called for an already mmaped address block");
+        ::abort();
+    }
+
+    void *result;
+    const int res = memoryMap(NULL, m_size, m_handle, m_offset, &result);
+    if (res) {
+        ALOGE("%s: host memory map failed with size 0x%llx "
+              "off 0x%llx errno %d\n",
+              __func__,
+              (unsigned long long)m_size,
+              (unsigned long long)m_offset, res);
+        return NULL;
+    } else {
+        m_mmaped_ptr = result;
+        m_host_addr = host_addr;
+        return guestPtr();
+    }
+}
+
+void *GoldfishAddressSpaceBlock::guestPtr() const
+{
+    return reinterpret_cast<char *>(m_mmaped_ptr) + (m_host_addr & (PAGE_SIZE - 1));
+}
+
+void GoldfishAddressSpaceBlock::destroy()
+{
+    if (m_mmaped_ptr && m_size) {
+        memoryUnmap(m_mmaped_ptr, m_size);
+        m_mmaped_ptr = NULL;
+    }
+
+    if (m_size) {
+        long res = -EINVAL;
+
+        if (m_is_shared_mapping) {
+            res = ioctl_unclaim_shared(m_handle, m_offset);
+            if (res) {
+                ALOGE("ioctl_unclaim_shared failed, res=%ld", res);
+                ::abort();
+            }
+        } else {
+            res = ioctl_deallocate(m_handle, m_offset);
+            if (res) {
+                ALOGE("ioctl_deallocate failed, res=%ld", res);
+                ::abort();
+            }
+        }
+
+        m_is_shared_mapping = false;
+
+        m_phys_addr = 0;
+        m_host_addr = 0;
+        m_offset = 0;
+        m_size = 0;
+    }
+}
+
+void GoldfishAddressSpaceBlock::release()
+{
+    m_handle = -1;
+    m_mmaped_ptr = NULL;
+    m_phys_addr = 0;
+    m_host_addr = 0;
+    m_offset = 0;
+    m_size = 0;
+}
+
+int GoldfishAddressSpaceBlock::memoryMap(void *addr,
+                                         size_t len,
+                                         address_space_handle_t fd,
+                                         uint64_t off,
+                                         void** dst) {
+    void* ptr = ::mmap64(addr, len, PROT_WRITE, MAP_SHARED, fd, off);
+    if (MAP_FAILED == ptr) {
+        return errno;
+    } else {
+        *dst = ptr;
+        return 0;
+    }
+}
+
+void GoldfishAddressSpaceBlock::memoryUnmap(void *ptr, size_t size)
+{
+    ::munmap(ptr, size);
+}
+
+GoldfishAddressSpaceHostMemoryAllocator::GoldfishAddressSpaceHostMemoryAllocator()
+  : m_provider(GoldfishAddressSpaceSubdeviceType::HostMemoryAllocator) {}
+
+bool GoldfishAddressSpaceHostMemoryAllocator::is_opened() const { return m_provider.is_opened(); }
+
+long GoldfishAddressSpaceHostMemoryAllocator::hostMalloc(GoldfishAddressSpaceBlock *block, size_t size)
+{
+    if (size == 0) {
+        return -EINVAL;
+    }
+    if (block->size() > 0) {
+        return -EINVAL;
+    }
+    if (!m_provider.is_opened()) {
+        return -ENODEV;
+    }
+    if (!block->allocate(&m_provider, size)) {
+        return -ENOMEM;
+    }
+
+    struct goldfish_address_space_ping request;
+    ::memset(&request, 0, sizeof(request));
+    request.version = sizeof(request);
+    request.offset = block->offset();
+    request.size = block->size();
+    request.metadata = HOST_MEMORY_ALLOCATOR_COMMAND_ALLOCATE_ID;
+
+    long ret = ioctl_ping(m_provider.m_handle, &request);
+    if (ret) {
+        return ret;
+    }
+    ret = static_cast<long>(request.metadata);
+    if (ret) {
+        return ret;
+    }
+
+    block->mmap(0);
+    return 0;
+}
+
+void GoldfishAddressSpaceHostMemoryAllocator::hostFree(GoldfishAddressSpaceBlock *block)
+{
+    if (block->size() == 0) {
+        return;
+    }
+
+    if (!m_provider.is_opened()) {
+        ALOGE("%s: device is not available", __func__);
+        ::abort();
+    }
+
+    if (block->guestPtr()) {
+        struct goldfish_address_space_ping request;
+        ::memset(&request, 0, sizeof(request));
+        request.version = sizeof(request);
+        request.offset = block->offset();
+        request.metadata = HOST_MEMORY_ALLOCATOR_COMMAND_UNALLOCATE_ID;
+
+        const long ret = ioctl_ping(m_provider.m_handle, &request);
+        if (ret) {
+            ALOGE("%s: ioctl_ping failed, ret=%ld", __func__, ret);
+            ::abort();
+        }
+    }
+
+    block->replace(NULL);
+}
+
+address_space_handle_t goldfish_address_space_open() {
+    return ::open(GOLDFISH_ADDRESS_SPACE_DEVICE_NAME, O_RDWR);
+}
+
+void goldfish_address_space_close(address_space_handle_t handle) {
+    ::close(handle);
+}
+
+bool goldfish_address_space_allocate(
+    address_space_handle_t handle,
+    size_t size, uint64_t* phys_addr, uint64_t* offset) {
+
+    struct goldfish_address_space_allocate_block request;
+    ::memset(&request, 0, sizeof(request));
+    request.size = size;
+
+    long res = ioctl_allocate(handle, &request);
+
+    if (res) return false;
+
+    *phys_addr = request.phys_addr;
+    *offset = request.offset;
+    return true;
+}
+
+bool goldfish_address_space_free(
+    address_space_handle_t handle, uint64_t offset) {
+
+    long res = ioctl_deallocate(handle, offset);
+
+    if (res) {
+        ALOGE("ioctl_deallocate failed, res=%ld", res);
+        ::abort();
+    }
+
+    return true;
+}
+
+bool goldfish_address_space_claim_shared(
+    address_space_handle_t handle, uint64_t offset, uint64_t size) {
+
+    struct goldfish_address_space_claim_shared request;
+    request.offset = offset;
+    request.size = size;
+    long res = ioctl_claim_shared(handle, &request);
+
+    if (res) return false;
+
+    return true;
+}
+
+bool goldfish_address_space_unclaim_shared(
+        address_space_handle_t handle, uint64_t offset) {
+    long res = ioctl_unclaim_shared(handle, offset);
+    if (res) {
+        ALOGE("ioctl_unclaim_shared failed, res=%ld", res);
+        ::abort();
+    }
+
+    return true;
+}
+
+// pgoff is the offset into the page to return in the result
+void* goldfish_address_space_map(
+    address_space_handle_t handle,
+    uint64_t offset, uint64_t size,
+    uint64_t pgoff) {
+
+    void* res = ::mmap64(0, size, PROT_WRITE, MAP_SHARED, handle, offset);
+
+    if (res == MAP_FAILED) {
+        ALOGE("%s: failed to map. errno: %d\n", __func__, errno);
+        return 0;
+    }
+
+    return (void*)(((char*)res) + (uintptr_t)(pgoff & (PAGE_SIZE - 1)));
+}
+
+void goldfish_address_space_unmap(void* ptr, uint64_t size) {
+    void* pagePtr = (void*)(((uintptr_t)ptr) & ~(PAGE_SIZE - 1));
+    ::munmap(pagePtr, size);
+}
+
+bool goldfish_address_space_set_subdevice_type(
+    address_space_handle_t handle, GoldfishAddressSpaceSubdeviceType type,
+    address_space_handle_t* handle_out) {
+    struct goldfish_address_space_ping request;
+    request.metadata = (uint64_t)type;
+    *handle_out = handle;
+    return goldfish_address_space_ping(handle, &request);
+}
+
+bool goldfish_address_space_ping(
+    address_space_handle_t handle,
+    struct goldfish_address_space_ping* ping) {
+    long res = ioctl_ping(handle, ping);
+
+    if (res) {
+        ALOGE("%s: ping failed: errno: %d\n", __func__, errno);
+        return false;
+    }
+
+    return true;
+}
diff --git a/shared/OpenglCodecCommon/goldfish_address_space_fuchsia.impl b/shared/OpenglCodecCommon/goldfish_address_space_fuchsia.impl
new file mode 100644
index 0000000..4d54eed
--- /dev/null
+++ b/shared/OpenglCodecCommon/goldfish_address_space_fuchsia.impl
@@ -0,0 +1,459 @@
+// Copyright (C) 2019 The Android Open Source Project
+// Copyright (C) 2019 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include <memory>
+#include <fcntl.h>
+#include <lib/zx/channel.h>
+#include <lib/zx/vmo.h>
+#include <log/log.h>
+#include <stdlib.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <zircon/process.h>
+#include <zircon/syscalls.h>
+#include <zircon/syscalls/object.h>
+
+#include "goldfish_address_space.h"
+#include "android/base/synchronization/AndroidLock.h"
+#include "services/service_connector.h"
+
+#include <unordered_map>
+
+using android::base::guest::AutoLock;
+using android::base::guest::Lock;
+
+using fuchsia::hardware::goldfish::AddressSpaceDeviceSyncPtr;
+using fuchsia::hardware::goldfish::AddressSpaceChildDriverSyncPtr;
+using fuchsia::hardware::goldfish::AddressSpaceChildDriverType;
+using fuchsia::hardware::goldfish::AddressSpaceChildDriverPingMessage;
+
+GoldfishAddressSpaceBlockProvider::GoldfishAddressSpaceBlockProvider(GoldfishAddressSpaceSubdeviceType subdevice) {
+
+    if (subdevice != GoldfishAddressSpaceSubdeviceType::NoSubdevice) {
+        ALOGE("%s: Tried to use a nontrivial subdevice when support has not been added\n", __func__);
+        abort();
+    }
+
+    zx::channel channel(GetConnectToServiceFunction()(GOLDFISH_ADDRESS_SPACE_DEVICE_NAME));
+    if (!channel) {
+        ALOGE("%s: failed to get service handle for " GOLDFISH_ADDRESS_SPACE_DEVICE_NAME,
+              __FUNCTION__);
+        return;
+    }
+    m_device.Bind(std::move(channel));
+
+    zx_status_t status = (*m_device).OpenChildDriver(
+        static_cast<fuchsia::hardware::goldfish::AddressSpaceChildDriverType>(0 /* graphics */),
+        m_child_driver.NewRequest());
+
+    if (status != ZX_OK) {
+        ALOGE("%s: failed to open child driver: %d",
+              __FUNCTION__, status);
+        return;
+    }
+}
+
+GoldfishAddressSpaceBlockProvider::~GoldfishAddressSpaceBlockProvider()
+{
+}
+
+bool GoldfishAddressSpaceBlockProvider::is_opened() const
+{
+    return m_device.is_bound();
+}
+
+// void GoldfishAddressSpaceBlockProvider::close() - not implemented
+// address_space_handle_t GoldfishAddressSpaceBlockProvider::release() - not imeplemented
+
+GoldfishAddressSpaceBlock::GoldfishAddressSpaceBlock()
+    : m_driver(NULL)
+    , m_vmo(ZX_HANDLE_INVALID)
+    , m_mmaped_ptr(NULL)
+    , m_phys_addr(0)
+    , m_host_addr(0)
+    , m_offset(0)
+    , m_size(0) {}
+
+GoldfishAddressSpaceBlock::~GoldfishAddressSpaceBlock()
+{
+    destroy();
+}
+
+GoldfishAddressSpaceBlock &GoldfishAddressSpaceBlock::operator=(const GoldfishAddressSpaceBlock &rhs)
+{
+    m_vmo = rhs.m_vmo;
+    m_mmaped_ptr = rhs.m_mmaped_ptr;
+    m_phys_addr = rhs.m_phys_addr;
+    m_host_addr = rhs.m_host_addr;
+    m_offset = rhs.m_offset;
+    m_size = rhs.m_size;
+    m_driver = rhs.m_driver;
+
+    return *this;
+}
+
+bool GoldfishAddressSpaceBlock::allocate(GoldfishAddressSpaceBlockProvider *provider, size_t size)
+{
+    ALOGD("%s: Ask for block of size 0x%llx\n", __func__,
+         (unsigned long long)size);
+
+    destroy();
+
+    if (!provider->is_opened()) {
+        return false;
+    }
+
+    fuchsia::hardware::goldfish::AddressSpaceChildDriverSyncPtr* driver = &provider->m_child_driver;
+
+    int32_t res = ZX_OK;
+    zx::vmo vmo;
+    zx_status_t status = (*driver)->AllocateBlock(size, &res, &m_phys_addr, &vmo);
+    if (status != ZX_OK || res != ZX_OK) {
+        ALOGE("%s: allocate block failed: %d:%d", __func__, status, res);
+        return false;
+    }
+
+    m_size = size;
+    m_vmo = vmo.release();
+    m_offset = 0;
+    m_is_shared_mapping = false;
+
+    ALOGD("%s: allocate returned offset 0x%llx size 0x%llx\n", __func__,
+          (unsigned long long)m_offset,
+          (unsigned long long)m_size);
+
+    m_driver = driver;
+    return true;
+}
+
+bool GoldfishAddressSpaceBlock::claimShared(GoldfishAddressSpaceBlockProvider *provider, uint64_t offset, uint64_t size)
+{
+    ALOGE("%s: FATAL: not supported\n", __func__);
+    abort();
+}
+
+uint64_t GoldfishAddressSpaceBlock::physAddr() const
+{
+    return m_phys_addr;
+}
+
+uint64_t GoldfishAddressSpaceBlock::hostAddr() const
+{
+    return m_host_addr;
+}
+
+void *GoldfishAddressSpaceBlock::mmap(uint64_t host_addr)
+{
+    if (m_size == 0) {
+        ALOGE("%s: called with zero size\n", __func__);
+        return NULL;
+    }
+    if (m_mmaped_ptr) {
+        ALOGE("'mmap' called for an already mmaped address block");
+        ::abort();
+    }
+
+    zx_vaddr_t ptr = 0;
+    zx_status_t status = zx_vmar_map(zx_vmar_root_self(),
+                                     ZX_VM_PERM_READ | ZX_VM_PERM_WRITE,
+                                     0, m_vmo,
+                                     m_offset,
+                                     m_size,
+                                     &ptr);
+    if (status != ZX_OK) {
+        ALOGE("%s: host memory map failed with size 0x%llx "
+              "off 0x%llx status %d\n",
+              __func__,
+              (unsigned long long)m_size,
+              (unsigned long long)m_offset, status);
+        return NULL;
+    } else {
+        m_mmaped_ptr = (void*)ptr;
+        m_host_addr = host_addr;
+        return guestPtr();
+    }
+}
+
+void *GoldfishAddressSpaceBlock::guestPtr() const
+{
+    return reinterpret_cast<char *>(m_mmaped_ptr) + (m_host_addr & (PAGE_SIZE - 1));
+}
+
+void GoldfishAddressSpaceBlock::destroy()
+{
+    if (m_mmaped_ptr && m_size) {
+        zx_vmar_unmap(zx_vmar_root_self(),
+                      (zx_vaddr_t)m_mmaped_ptr,
+                      m_size);
+        m_mmaped_ptr = NULL;
+    }
+
+    if (m_size) {
+        zx_handle_close(m_vmo);
+        m_vmo = ZX_HANDLE_INVALID;
+        if (m_is_shared_mapping) {
+            // TODO
+            ALOGE("%s: unsupported: GoldfishAddressSpaceBlock destroy() for shared regions\n", __func__);
+            abort();
+            // int32_t res = ZX_OK;
+            // zx_status_t status = (*m_driver)->UnclaimShared(m_offset, &res);
+            // if (status != ZX_OK || res != ZX_OK) {
+            //     ALOGE("%s: unclaim shared block failed: %d:%d", __func__, status, res);
+            // }
+        } else {
+            int32_t res = ZX_OK;
+            zx_status_t status = (*m_driver)->DeallocateBlock(m_phys_addr, &res);
+            if (status != ZX_OK || res != ZX_OK) {
+                ALOGE("%s: deallocate block failed: %d:%d", __func__, status, res);
+            }
+        }
+        m_driver = NULL;
+        m_phys_addr = 0;
+        m_host_addr = 0;
+        m_offset = 0;
+        m_size = 0;
+    }
+}
+
+GoldfishAddressSpaceHostMemoryAllocator::GoldfishAddressSpaceHostMemoryAllocator()
+  : m_provider(GoldfishAddressSpaceSubdeviceType::HostMemoryAllocator) { }
+
+long GoldfishAddressSpaceHostMemoryAllocator::hostMalloc(GoldfishAddressSpaceBlock *block, size_t size)
+{
+    return 0;
+}
+
+void GoldfishAddressSpaceHostMemoryAllocator::hostFree(GoldfishAddressSpaceBlock *block)
+{
+}
+
+class VmoStore {
+public:
+    struct Info {
+        zx_handle_t vmo = ZX_HANDLE_INVALID;
+        uint64_t phys_addr = 0;
+    };
+
+    void add(uint64_t offset, const Info& info) {
+        AutoLock lock(mLock);
+        mInfo[offset] = info;
+    }
+
+    void remove(uint64_t offset) {
+        AutoLock lock(mLock);
+        mInfo.erase(offset);
+    }
+
+    Info get(uint64_t offset) {
+        Info res;
+        AutoLock lock(mLock);
+        auto it = mInfo.find(offset);
+        if (it == mInfo.end()) {
+            ALOGE("VmoStore::%s cannot find info on offset 0x%llx\n", __func__,
+                  (unsigned long long)offset);
+            return res;
+        }
+        res = it->second;
+        return res;
+    }
+
+private:
+    Lock mLock;
+    std::unordered_map<uint64_t, Info> mInfo;
+};
+
+static Lock sVmoStoreInitLock;
+static VmoStore* sVmoStore = nullptr;
+
+static VmoStore* getVmoStore() {
+    AutoLock lock(sVmoStoreInitLock);
+    if (!sVmoStore) sVmoStore = new VmoStore;
+    return sVmoStore;
+}
+
+address_space_handle_t goldfish_address_space_open() {
+    zx::channel channel(GetConnectToServiceFunction()(GOLDFISH_ADDRESS_SPACE_DEVICE_NAME));
+    if (!channel) {
+        ALOGE("%s: failed to get service handle for " GOLDFISH_ADDRESS_SPACE_DEVICE_NAME,
+              __FUNCTION__);
+        return 0;
+    }
+    fuchsia::hardware::goldfish::AddressSpaceDeviceSyncPtr*
+        deviceSync = new fuchsia::hardware::goldfish::AddressSpaceDeviceSyncPtr;
+    deviceSync->Bind(std::move(channel));
+    return (address_space_handle_t)deviceSync;
+}
+
+void goldfish_address_space_close(address_space_handle_t handle) {
+    fuchsia::hardware::goldfish::AddressSpaceDeviceSyncPtr* deviceSync =
+        reinterpret_cast<
+            fuchsia::hardware::goldfish::AddressSpaceDeviceSyncPtr*>(handle);
+    delete deviceSync;
+}
+
+bool goldfish_address_space_set_subdevice_type(
+    address_space_handle_t handle, GoldfishAddressSpaceSubdeviceType type,
+    address_space_handle_t* handle_out) {
+
+    fuchsia::hardware::goldfish::AddressSpaceDeviceSyncPtr* deviceSync =
+        reinterpret_cast<
+            fuchsia::hardware::goldfish::AddressSpaceDeviceSyncPtr*>(handle);
+
+    fuchsia::hardware::goldfish::AddressSpaceChildDriverSyncPtr*
+        childSync = new fuchsia::hardware::goldfish::AddressSpaceChildDriverSyncPtr;
+
+    zx_status_t res = (*(*deviceSync)).OpenChildDriver(
+        static_cast<fuchsia::hardware::goldfish::AddressSpaceChildDriverType>(type),
+        (*childSync).NewRequest());
+
+    // On creating a subdevice, in our use cases we wont be needing the
+    // original device sync anymore, so get rid of it.
+    delete deviceSync;
+
+    *handle_out = (void*)childSync;
+
+    return true;
+}
+
+bool goldfish_address_space_allocate(
+    address_space_handle_t handle,
+    size_t size, uint64_t* phys_addr, uint64_t* offset) {
+    fuchsia::hardware::goldfish::AddressSpaceChildDriverSyncPtr* deviceSync =
+        reinterpret_cast<
+            fuchsia::hardware::goldfish::AddressSpaceChildDriverSyncPtr*>(handle);
+
+    int32_t res = ZX_OK;
+    zx::vmo vmo;
+    zx_status_t status = (*(*deviceSync)).AllocateBlock(size, &res, phys_addr, &vmo);
+    if (status != ZX_OK || res != ZX_OK) {
+        ALOGE("%s: allocate block failed: %d:%d", __func__, status, res);
+        return false;
+    }
+
+    *offset = 0;
+
+    VmoStore::Info info = {
+        vmo.release(),
+        *phys_addr,
+    };
+
+    getVmoStore()->add(*offset, info);
+    return true;
+}
+
+bool goldfish_address_space_free(
+    address_space_handle_t handle, uint64_t offset) {
+    auto info = getVmoStore()->get(offset);
+    if (info.vmo == ZX_HANDLE_INVALID) return false;
+    zx_handle_close(info.vmo);
+
+    fuchsia::hardware::goldfish::AddressSpaceChildDriverSyncPtr* deviceSync =
+        reinterpret_cast<
+            fuchsia::hardware::goldfish::AddressSpaceChildDriverSyncPtr*>(handle);
+
+    int32_t res = ZX_OK;
+    zx_status_t status = (*(*deviceSync)).DeallocateBlock(info.phys_addr, &res);
+    if (status != ZX_OK || res != ZX_OK) {
+        ALOGE("%s: deallocate block failed: %d:%d", __func__, status, res);
+        return false;
+    }
+
+    return true;
+}
+
+bool goldfish_address_space_claim_shared(
+    address_space_handle_t handle, uint64_t offset, uint64_t size) {
+
+    fuchsia::hardware::goldfish::AddressSpaceChildDriverSyncPtr* deviceSync =
+        reinterpret_cast<
+            fuchsia::hardware::goldfish::AddressSpaceChildDriverSyncPtr*>(handle);
+    zx::vmo vmo;
+    zx_status_t res;
+    zx_status_t status = (*(*deviceSync)).ClaimSharedBlock(offset, size, &res, &vmo);
+
+    VmoStore::Info info = {
+        vmo.release(),
+    };
+
+    getVmoStore()->add(offset, info);
+
+    if (status != ZX_OK) return false;
+
+    return true;
+}
+
+bool goldfish_address_space_unclaim_shared(
+    address_space_handle_t handle, uint64_t offset) {
+    fuchsia::hardware::goldfish::AddressSpaceChildDriverSyncPtr* deviceSync =
+        reinterpret_cast<
+            fuchsia::hardware::goldfish::AddressSpaceChildDriverSyncPtr*>(handle);
+    zx::vmo vmo;
+    zx_status_t res;
+    zx_status_t status = (*(*deviceSync)).UnclaimSharedBlock(offset, &res);
+
+    if (status != ZX_OK) return false;
+
+    getVmoStore()->remove(offset);
+    return true;
+}
+
+// pgoff is the offset into the page to return in the result
+void* goldfish_address_space_map(
+    address_space_handle_t handle,
+    uint64_t offset, uint64_t size,
+    uint64_t pgoff) {
+
+    auto info = getVmoStore()->get(offset);
+    if (info.vmo == ZX_HANDLE_INVALID) return nullptr;
+
+    zx_vaddr_t ptr = 0;
+    zx_status_t status =
+        zx_vmar_map(zx_vmar_root_self(),
+                    ZX_VM_PERM_READ | ZX_VM_PERM_WRITE,
+                    0, info.vmo,
+                    0, size,
+                    &ptr);
+    return (void*)(((char*)ptr) + (uintptr_t)(pgoff & (PAGE_SIZE - 1)));
+}
+
+void goldfish_address_space_unmap(void* ptr, uint64_t size) {
+    zx_vmar_unmap(zx_vmar_root_self(),
+                  (zx_vaddr_t)(((uintptr_t)ptr) & (uintptr_t)(~(PAGE_SIZE - 1))),
+                  size);
+}
+
+bool goldfish_address_space_ping(
+    address_space_handle_t handle,
+    struct goldfish_address_space_ping* ping) {
+
+    AddressSpaceChildDriverPingMessage fuchsiaPing =
+        *(AddressSpaceChildDriverPingMessage*)ping;
+
+    AddressSpaceChildDriverSyncPtr* deviceSync =
+        reinterpret_cast<
+            AddressSpaceChildDriverSyncPtr*>(handle);
+
+    AddressSpaceChildDriverPingMessage res;
+    zx_status_t pingStatus;
+    zx_status_t status = (*(*deviceSync)).Ping(fuchsiaPing, &pingStatus, &res);
+
+    if (pingStatus != ZX_OK) {
+        return false;
+    }
+
+    *ping = *(struct goldfish_address_space_ping*)(&res);
+    return true;
+}
diff --git a/shared/OpenglCodecCommon/goldfish_address_space_host.impl b/shared/OpenglCodecCommon/goldfish_address_space_host.impl
new file mode 100644
index 0000000..6630ed7
--- /dev/null
+++ b/shared/OpenglCodecCommon/goldfish_address_space_host.impl
@@ -0,0 +1,378 @@
+// Copyright (C) 2019 The Android Open Source Project
+// Copyright (C) 2019 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "android/emulation/hostdevices/HostAddressSpace.h"
+
+#include <memory>
+
+#if PLATFORM_SDK_VERSION < 26
+#include <cutils/log.h>
+#else
+#include <log/log.h>
+#endif
+
+#include <errno.h>
+#include "goldfish_address_space.h"
+
+namespace {
+
+const int HOST_MEMORY_ALLOCATOR_COMMAND_ALLOCATE_ID = 1;
+const int HOST_MEMORY_ALLOCATOR_COMMAND_UNALLOCATE_ID = 2;
+
+}  // namsepace
+
+using android::HostAddressSpaceDevice;
+using android::emulation::AddressSpaceDevicePingInfo;
+
+GoldfishAddressSpaceBlockProvider::GoldfishAddressSpaceBlockProvider(GoldfishAddressSpaceSubdeviceType subdevice)
+    : m_handle(HostAddressSpaceDevice::get()->open())
+{
+    if ((subdevice != GoldfishAddressSpaceSubdeviceType::NoSubdevice) && is_opened()) {
+        AddressSpaceDevicePingInfo request;
+        ::memset(&request, 0, sizeof(request));
+        request.metadata = subdevice;
+
+        HostAddressSpaceDevice::get()->ping(m_handle, &request);
+    }
+}
+
+GoldfishAddressSpaceBlockProvider::~GoldfishAddressSpaceBlockProvider()
+{
+    if (is_opened()) {
+        HostAddressSpaceDevice::get()->close(m_handle);
+    }
+}
+
+bool GoldfishAddressSpaceBlockProvider::is_opened() const
+{
+    return m_handle > 0;
+}
+
+void GoldfishAddressSpaceBlockProvider::close()
+{
+    if (is_opened()) {
+        HostAddressSpaceDevice::get()->close(m_handle);
+        m_handle = 0;
+    }
+}
+
+address_space_handle_t GoldfishAddressSpaceBlockProvider::release()
+{
+    address_space_handle_t handle = m_handle;
+    m_handle = 0;
+    return handle;
+}
+
+void GoldfishAddressSpaceBlockProvider::closeHandle(address_space_handle_t handle)
+{
+    HostAddressSpaceDevice::get()->close(handle);
+}
+
+GoldfishAddressSpaceBlock::GoldfishAddressSpaceBlock()
+    : m_handle(0)
+    , m_mmaped_ptr(NULL)
+    , m_phys_addr(0)
+    , m_host_addr(0)
+    , m_offset(0)
+    , m_size(0)
+    , m_is_shared_mapping(false) {}
+
+GoldfishAddressSpaceBlock::~GoldfishAddressSpaceBlock()
+{
+    destroy();
+}
+
+GoldfishAddressSpaceBlock &GoldfishAddressSpaceBlock::operator=(const GoldfishAddressSpaceBlock &rhs)
+{
+    m_mmaped_ptr = rhs.m_mmaped_ptr;
+    m_phys_addr = rhs.m_phys_addr;
+    m_host_addr = rhs.m_host_addr;
+    m_offset = rhs.m_offset;
+    m_size = rhs.m_size;
+    m_is_shared_mapping = rhs.m_is_shared_mapping;
+    m_handle = rhs.m_handle;
+    return *this;
+}
+
+bool GoldfishAddressSpaceBlock::allocate(GoldfishAddressSpaceBlockProvider *provider, size_t size)
+{
+    ALOGD("%s: Ask for block of size 0x%llx\n", __func__,
+         (unsigned long long)size);
+
+    destroy();
+
+    if (!provider->is_opened()) {
+        return false;
+    }
+
+    m_size = size;
+    m_offset =
+        HostAddressSpaceDevice::get()->allocBlock(
+            provider->m_handle, size, &m_phys_addr);
+    m_handle = provider->m_handle;
+    m_is_shared_mapping = false;
+
+    return true;
+}
+
+bool GoldfishAddressSpaceBlock::claimShared(GoldfishAddressSpaceBlockProvider *provider, uint64_t offset, uint64_t size)
+{
+    ALOGD("%s: Ask to claim region [0x%llx 0x%llx]\n", __func__,
+         (unsigned long long)offset,
+         (unsigned long long)offset + size);
+
+    destroy();
+
+    if (!provider->is_opened()) {
+        return false;
+    }
+
+    int claimRes = HostAddressSpaceDevice::get()->claimShared(
+            provider->m_handle, offset, size);
+
+    if (claimRes) {
+        ALOGE("%s: failed to claim shared region. Error: %d\n", __func__, claimRes);
+        return false;
+    }
+
+    m_size = size;
+    m_offset = offset;
+    m_handle = provider->m_handle;
+    m_is_shared_mapping = true;
+    m_phys_addr = HostAddressSpaceDevice::get()->offsetToPhysAddr(m_offset);
+
+    return true;
+}
+
+uint64_t GoldfishAddressSpaceBlock::physAddr() const
+{
+    return m_phys_addr;
+}
+
+uint64_t GoldfishAddressSpaceBlock::hostAddr() const
+{
+    return m_host_addr;
+}
+
+// In the host implementation:
+// mmap: is done by interpreting |host_addr| as the actual host address.
+void *GoldfishAddressSpaceBlock::mmap(uint64_t host_addr)
+{
+    if (m_size == 0) {
+        ALOGE("%s: called with zero size\n", __func__);
+        return NULL;
+    }
+
+    if (m_mmaped_ptr != nullptr) {
+        ALOGE("'mmap' called for an already mmaped address block 0x%llx %d", (unsigned long long)m_mmaped_ptr, nullptr == m_mmaped_ptr);
+        ::abort();
+    }
+
+    m_mmaped_ptr = (void*)(uintptr_t)(host_addr & (~(PAGE_SIZE - 1)));
+    m_host_addr = host_addr;
+
+    return guestPtr();
+}
+
+void *GoldfishAddressSpaceBlock::guestPtr() const
+{
+    return reinterpret_cast<char *>(m_mmaped_ptr) + (m_host_addr & (PAGE_SIZE - 1));
+}
+
+void GoldfishAddressSpaceBlock::destroy()
+{
+    if (m_mmaped_ptr && m_size) {
+        m_mmaped_ptr = NULL;
+    }
+
+    if (m_size) {
+        if (m_is_shared_mapping) {
+            HostAddressSpaceDevice::get()->unclaimShared(m_handle, m_offset);
+        } else {
+            HostAddressSpaceDevice::get()->freeBlock(m_handle, m_offset);
+        }
+        m_phys_addr = 0;
+        m_host_addr = 0;
+        m_offset = 0;
+        m_size = 0;
+    }
+}
+
+void GoldfishAddressSpaceBlock::release()
+{
+    m_handle = 0;
+    m_mmaped_ptr = NULL;
+    m_phys_addr = 0;
+    m_host_addr = 0;
+    m_offset = 0;
+    m_size = 0;
+}
+
+int GoldfishAddressSpaceBlock::memoryMap(void *addr,
+                                         size_t,
+                                         address_space_handle_t,
+                                         uint64_t,
+                                         void** dst) {
+    *dst = addr;
+    return 0;
+}
+
+void GoldfishAddressSpaceBlock::memoryUnmap(void *ptr, size_t size) {}
+
+GoldfishAddressSpaceHostMemoryAllocator::GoldfishAddressSpaceHostMemoryAllocator()
+  : m_provider(GoldfishAddressSpaceSubdeviceType::HostMemoryAllocator) {}
+
+bool GoldfishAddressSpaceHostMemoryAllocator::is_opened() const { return m_provider.is_opened(); }
+
+long GoldfishAddressSpaceHostMemoryAllocator::hostMalloc(GoldfishAddressSpaceBlock *block, size_t size)
+{
+    if (size == 0) {
+        return -EINVAL;
+    }
+    if (block->size() > 0) {
+        return -EINVAL;
+    }
+    if (!m_provider.is_opened()) {
+        return -ENODEV;
+    }
+    if (!block->allocate(&m_provider, size)) {
+        return -ENOMEM;
+    }
+
+    AddressSpaceDevicePingInfo request;
+    ::memset(&request, 0, sizeof(request));
+    request.phys_addr = block->physAddr();
+    request.size = block->size();
+    request.metadata = HOST_MEMORY_ALLOCATOR_COMMAND_ALLOCATE_ID;
+
+    HostAddressSpaceDevice::get()->ping(m_provider.m_handle, &request);
+
+    void *hostPtr = HostAddressSpaceDevice::get()->getHostAddr(block->physAddr());
+    block->mmap(static_cast<uint64_t>(reinterpret_cast<uintptr_t>(hostPtr)));
+
+    return 0;
+}
+
+void GoldfishAddressSpaceHostMemoryAllocator::hostFree(GoldfishAddressSpaceBlock *block)
+{
+    if (block->size() == 0) {
+        return;
+    }
+
+    if (!m_provider.is_opened()) {
+        ALOGE("%s: device is not available", __func__);
+        ::abort();
+    }
+
+    if (block->guestPtr()) {
+        AddressSpaceDevicePingInfo request;
+        ::memset(&request, 0, sizeof(request));
+        request.phys_addr = block->physAddr();
+        request.metadata = HOST_MEMORY_ALLOCATOR_COMMAND_UNALLOCATE_ID;
+
+        HostAddressSpaceDevice::get()->ping(m_provider.m_handle, &request);
+    }
+
+    block->replace(NULL);
+}
+
+address_space_handle_t goldfish_address_space_open() {
+    return HostAddressSpaceDevice::get()->open();
+}
+
+void goldfish_address_space_close(address_space_handle_t handle) {
+    HostAddressSpaceDevice::get()->close(handle);
+}
+
+bool goldfish_address_space_allocate(
+    address_space_handle_t handle,
+    size_t size, uint64_t* phys_addr, uint64_t* offset) {
+
+    *offset =
+        HostAddressSpaceDevice::get()->allocBlock(
+            handle, size, phys_addr);
+
+    return true;
+}
+
+bool goldfish_address_space_free(
+    address_space_handle_t handle, uint64_t offset) {
+    HostAddressSpaceDevice::get()->freeBlock(handle, offset);
+    return true;
+}
+
+bool goldfish_address_space_claim_shared(
+    address_space_handle_t handle, uint64_t offset, uint64_t size) {
+
+    int claimRes = HostAddressSpaceDevice::get()->claimShared(
+        handle, offset, size);
+
+    if (claimRes) {
+        ALOGE("%s: failed to claim shared region. Error: %d\n", __func__, claimRes);
+        return false;
+    }
+
+    return true;
+}
+
+bool goldfish_address_space_unclaim_shared(
+        address_space_handle_t handle, uint64_t offset) {
+    HostAddressSpaceDevice::get()->unclaimShared(handle, offset);
+    return true;
+}
+
+// pgoff is the offset into the page to return in the result
+void* goldfish_address_space_map(
+    address_space_handle_t handle,
+    uint64_t offset, uint64_t size,
+    uint64_t pgoff) {
+
+    (void)size;
+
+    void* res = HostAddressSpaceDevice::get()->
+        getHostAddr(
+            HostAddressSpaceDevice::get()->offsetToPhysAddr(offset));
+
+    if (!res) {
+        ALOGE("%s: failed to map. errno: %d\n", __func__, errno);
+        return nullptr;
+    }
+
+    return (void*)(((char*)res) + (uintptr_t)(pgoff & (PAGE_SIZE - 1)));
+}
+
+// same address space
+void goldfish_address_space_unmap(void*, uint64_t) { }
+
+bool goldfish_address_space_set_subdevice_type(
+    address_space_handle_t handle, GoldfishAddressSpaceSubdeviceType type,
+    address_space_handle_t* handle_out) {
+    struct goldfish_address_space_ping request;
+    request.metadata = (uint64_t)type;
+    *handle_out = handle;
+    return goldfish_address_space_ping(handle, &request);
+}
+
+bool goldfish_address_space_ping(
+    address_space_handle_t handle,
+    struct goldfish_address_space_ping* ping) {
+
+    AddressSpaceDevicePingInfo* asHostPingInfo =
+        reinterpret_cast<AddressSpaceDevicePingInfo*>(ping);
+
+    HostAddressSpaceDevice::get()->ping(handle, asHostPingInfo);
+
+    return true;
+}
diff --git a/shared/OpenglCodecCommon/gralloc_cb.h b/shared/OpenglCodecCommon/gralloc_cb.h
index bff33f3..26d6026 100644
--- a/shared/OpenglCodecCommon/gralloc_cb.h
+++ b/shared/OpenglCodecCommon/gralloc_cb.h
@@ -17,123 +17,112 @@
 #ifndef __GRALLOC_CB_H__
 #define __GRALLOC_CB_H__
 
-#include <hardware/hardware.h>
-#include <hardware/gralloc.h>
 #include <cutils/native_handle.h>
-
 #include "qemu_pipe.h"
 
-#define BUFFER_HANDLE_MAGIC ((int)0xabfabfab)
-#define CB_HANDLE_NUM_INTS(nfds) (int)((sizeof(cb_handle_t) - (nfds)*sizeof(int)) / sizeof(int))
+const uint32_t CB_HANDLE_MAGIC_MASK = 0xFFFFFFF0;
+const uint32_t CB_HANDLE_MAGIC_BASE = 0xABFABFA0;
 
-// Tell the emulator which gralloc formats
-// need special handling.
-enum EmulatorFrameworkFormat {
-    FRAMEWORK_FORMAT_GL_COMPATIBLE = 0,
-    FRAMEWORK_FORMAT_YV12 = 1,
-    FRAMEWORK_FORMAT_YUV_420_888 = 2,              // (Y+)(U+)(V+)
-};
+#define CB_HANDLE_NUM_INTS(nfd) \
+    ((sizeof(*this)-sizeof(native_handle_t)-nfd*sizeof(int32_t))/sizeof(int32_t))
 
-//
-// Our buffer handle structure
-//
-struct cb_handle_t : public native_handle {
-
-    cb_handle_t(int p_fd, int p_ashmemSize, int p_usage,
-                int p_width, int p_height, int p_frameworkFormat,
-                int p_format, int p_glFormat, int p_glType,
-                EmulatorFrameworkFormat p_emuFrameworkFormat) :
-        fd(p_fd),
-        magic(BUFFER_HANDLE_MAGIC),
-        usage(p_usage),
-        width(p_width),
-        height(p_height),
-        frameworkFormat(p_frameworkFormat),
-        format(p_format),
-        glFormat(p_glFormat),
-        glType(p_glType),
-        ashmemSize(p_ashmemSize),
-        ashmemBase(0),
-        ashmemBasePid(0),
-        mappedPid(0),
-        lockedLeft(0),
-        lockedTop(0),
-        lockedWidth(0),
-        lockedHeight(0),
-        hostHandle(0),
-        emuFrameworkFormat(p_emuFrameworkFormat)
-    {
-        refcount_pipe_fd = QEMU_PIPE_INVALID_HANDLE;
+struct cb_handle_t : public native_handle_t {
+    cb_handle_t(int32_t p_bufferFd,
+                QEMU_PIPE_HANDLE p_hostHandleRefCountFd,
+                uint32_t p_magic,
+                uint32_t p_hostHandle,
+                int32_t p_usage,
+                int32_t p_width,
+                int32_t p_height,
+                int32_t p_format,
+                int32_t p_glFormat,
+                int32_t p_glType,
+                uint32_t p_bufSize,
+                void* p_bufPtr,
+                uint64_t p_mmapedOffset)
+        : bufferFd(p_bufferFd),
+          hostHandleRefCountFd(p_hostHandleRefCountFd),
+          magic(p_magic),
+          hostHandle(p_hostHandle),
+          usage(p_usage),
+          width(p_width),
+          height(p_height),
+          format(p_format),
+          glFormat(p_glFormat),
+          glType(p_glType),
+          bufferSize(p_bufSize),
+          mmapedOffsetLo(static_cast<uint32_t>(p_mmapedOffset)),
+          mmapedOffsetHi(static_cast<uint32_t>(p_mmapedOffset >> 32)),
+          lockedLeft(0),
+          lockedTop(0),
+          lockedWidth(0),
+          lockedHeight(0) {
         version = sizeof(native_handle);
-        numFds = 0;
-        numInts = CB_HANDLE_NUM_INTS(numFds);
+        numFds = ((bufferFd >= 0) ? 1 : 0) + (qemu_pipe_valid(hostHandleRefCountFd) ? 1 : 0);
+        numInts = 0; // has to be overwritten in children classes
+        setBufferPtr(p_bufPtr);
     }
 
-    ~cb_handle_t() {
-        magic = 0;
+    void* getBufferPtr() const {
+        const uint64_t addr = (uint64_t(bufferPtrHi) << 32) | bufferPtrLo;
+        return reinterpret_cast<void*>(static_cast<uintptr_t>(addr));
     }
 
-    void setFd(int p_fd) {
-        if (p_fd >= 0) {
-            numFds++;
-        }
-        fd = p_fd;
-        numInts = CB_HANDLE_NUM_INTS(numFds);
+    void setBufferPtr(void* ptr) {
+        const uint64_t addr = static_cast<uint64_t>(reinterpret_cast<uintptr_t>(ptr));
+        bufferPtrLo = uint32_t(addr);
+        bufferPtrHi = uint32_t(addr >> 32);
     }
 
-    bool hasRefcountPipe() {
-        return qemu_pipe_valid(refcount_pipe_fd);
+    uint64_t getMmapedOffset() const {
+        return (uint64_t(mmapedOffsetHi) << 32) | mmapedOffsetLo;
     }
 
-    void setRefcountPipeFd(QEMU_PIPE_HANDLE fd) {
-        if (qemu_pipe_valid(fd)) {
-            numFds++;
-        }
-        refcount_pipe_fd = fd;
-        numInts = CB_HANDLE_NUM_INTS(numFds);
+    uint32_t allocatedSize() const {
+        return getBufferPtr() ? bufferSize : 0;
     }
 
-    static bool validate(const cb_handle_t* hnd) {
-        return (hnd &&
-                hnd->version == sizeof(native_handle) &&
-                hnd->magic == BUFFER_HANDLE_MAGIC &&
-                hnd->numInts == CB_HANDLE_NUM_INTS(hnd->numFds));
+    bool isValid() const {
+        return (version == sizeof(native_handle))
+               && (magic & CB_HANDLE_MAGIC_MASK) == CB_HANDLE_MAGIC_BASE;
     }
 
-    bool canBePosted() {
-        return (0 != (usage & GRALLOC_USAGE_HW_FB));
+    static cb_handle_t* from(void* p) {
+        if (!p) { return NULL; }
+        cb_handle_t* cb = static_cast<cb_handle_t*>(p);
+        return cb->isValid() ? cb : NULL;
     }
 
-    // file-descriptors
-    int fd;  // ashmem fd (-1 of ashmem region did not allocated, i.e. no SW access needed)
-    QEMU_PIPE_HANDLE refcount_pipe_fd; // goldfish pipe service for gralloc refcounting fd.
+    static const cb_handle_t* from(const void* p) {
+        return from(const_cast<void*>(p));
+    }
+
+    static cb_handle_t* from_unconst(const void* p) {
+        return from(const_cast<void*>(p));
+    }
+
+    // fds
+    int32_t bufferFd;       // underlying buffer file handle
+    QEMU_PIPE_HANDLE hostHandleRefCountFd; // guest side refcounter to hostHandle
 
     // ints
-    int magic;              // magic number in order to validate a pointer to be a cb_handle_t
-    int usage;              // usage bits the buffer was created with
-    int width;              // buffer width
-    int height;             // buffer height
-    int frameworkFormat;    // format requested by the Android framework
-    int format;             // real internal pixel format format
-    int glFormat;           // OpenGL format enum used for host h/w color buffer
-    int glType;             // OpenGL type enum used when uploading to host
-    int ashmemSize;         // ashmem region size for the buffer (0 unless is HW_FB buffer or
-                            //                                    s/w access is needed)
-    union {
-        intptr_t ashmemBase;    // CPU address of the mapped ashmem region
-        uint64_t padding;       // enforce same size on 32-bit/64-bit
-    } __attribute__((aligned(8)));
-
-    int ashmemBasePid;      // process id which mapped the ashmem region
-    int mappedPid;          // process id which succeeded gralloc_register call
-    int lockedLeft;         // region of buffer locked for s/w write
-    int lockedTop;
-    int lockedWidth;
-    int lockedHeight;
-    uint32_t hostHandle;
-
-    EmulatorFrameworkFormat emuFrameworkFormat;
+    uint32_t magic;         // magic number in order to validate a pointer
+    uint32_t hostHandle;    // the host reference to this buffer
+    int32_t  usage;         // usage bits the buffer was created with
+    int32_t  width;         // buffer width
+    int32_t  height;        // buffer height
+    int32_t  format;        // real internal pixel format format
+    int32_t  glFormat;      // OpenGL format enum used for host h/w color buffer
+    int32_t  glType;        // OpenGL type enum used when uploading to host
+    uint32_t bufferSize;    // buffer size and location
+    uint32_t bufferPtrLo;
+    uint32_t bufferPtrHi;
+    uint32_t mmapedOffsetLo;
+    uint32_t mmapedOffsetHi;
+    int32_t  lockedLeft;    // region of buffer locked for s/w write
+    int32_t  lockedTop;
+    int32_t  lockedWidth;
+    int32_t  lockedHeight;
 };
 
-
 #endif //__GRALLOC_CB_H__
diff --git a/shared/OpenglCodecCommon/qemu_pipe.h b/shared/OpenglCodecCommon/qemu_pipe.h
index 429b3fe..55ebb74 100644
--- a/shared/OpenglCodecCommon/qemu_pipe.h
+++ b/shared/OpenglCodecCommon/qemu_pipe.h
@@ -16,9 +16,15 @@
 #ifndef ANDROID_INCLUDE_HARDWARE_QEMU_PIPE_H
 #define ANDROID_INCLUDE_HARDWARE_QEMU_PIPE_H
 
+#include <sys/types.h>
+#include <stdint.h>
+#include <errno.h>
+
 #ifdef HOST_BUILD
 
-#include <sys/types.h>
+#ifndef QEMU_PIPE_RETRY
+#define QEMU_PIPE_RETRY TEMP_FAILURE_RETRY
+#endif
 
 typedef void* QEMU_PIPE_HANDLE;
 
@@ -41,18 +47,18 @@
 
 #define QEMU_PIPE_INVALID_HANDLE (-1)
 
-#ifndef QEMU_PIPE_PATH
-#define QEMU_PIPE_PATH "/dev/qemu_pipe"
+#ifndef QEMU_PIPE_RETRY
+#define QEMU_PIPE_RETRY(exp) ({ \
+    __typeof__(exp) _rc; \
+    do { \
+        _rc = (exp); \
+    } while (_rc == -1 && (errno == EINTR || errno == EAGAIN)); \
+    _rc; }) \
+
 #endif
 
-#ifndef TEMP_FAILURE_RETRY
-#define TEMP_FAILURE_RETRY(exp) ({         \
-    __typeof__(exp) _rc;                   \
-    do {                                   \
-        _rc = (exp);                       \
-    } while (_rc == -1 && errno == EINTR); \
-    _rc; })
-#include <stdint.h>
+#ifndef QEMU_PIPE_PATH
+#define QEMU_PIPE_PATH "/dev/qemu_pipe"
 #endif
 
 #if PLATFORM_SDK_VERSION < 26
@@ -70,24 +76,11 @@
 #include <stdlib.h>
 #include <stdio.h>
 #include <string.h>
-#include <errno.h>
 
 #ifndef D
 #  define  D(...)   do{}while(0)
 #endif
 
-static bool WriteFully(QEMU_PIPE_HANDLE fd, const void* data, size_t byte_count) {
-  const uint8_t* p = (const uint8_t*)(data);
-  size_t remaining = byte_count;
-  while (remaining > 0) {
-    ssize_t n = TEMP_FAILURE_RETRY(write(fd, p, remaining));
-    if (n == -1) return false;
-    p += n;
-    remaining -= n;
-  }
-  return true;
-}
-
 /* Try to open a new Qemu fast-pipe. This function returns a file descriptor
  * that can be used to communicate with a named service managed by the
  * emulator.
@@ -110,8 +103,12 @@
  * except for a few special cases (e.g. GSM modem), where EBUSY will be
  * returned if more than one client tries to connect to it.
  */
+
+static __inline__ ssize_t
+qemu_pipe_write_fully(QEMU_PIPE_HANDLE pipe, const void* buffer, ssize_t len);
+
 static __inline__ QEMU_PIPE_HANDLE
-qemu_pipe_open(const char* pipeName) {
+qemu_pipe_open_ns(const char* ns, const char* pipeName, int flags) {
     char  buff[256];
     int   buffLen;
     QEMU_PIPE_HANDLE   fd;
@@ -121,20 +118,23 @@
         return -1;
     }
 
-    snprintf(buff, sizeof buff, "pipe:%s", pipeName);
+    if (ns) {
+        buffLen = snprintf(buff, sizeof(buff), "pipe:%s:%s", ns, pipeName);
+    } else {
+        buffLen = snprintf(buff, sizeof(buff), "pipe:%s", pipeName);
+    }
 
-    fd = TEMP_FAILURE_RETRY(open(QEMU_PIPE_PATH, O_RDWR));
-    if (fd < 0 && errno == ENOENT)
-        fd = TEMP_FAILURE_RETRY(open("/dev/goldfish_pipe", O_RDWR));
+    fd = QEMU_PIPE_RETRY(open(QEMU_PIPE_PATH, flags));
+    if (fd < 0 && errno == ENOENT) {
+        fd = QEMU_PIPE_RETRY(open("/dev/goldfish_pipe", flags));
+    }
     if (fd < 0) {
         D("%s: Could not open " QEMU_PIPE_PATH ": %s", __FUNCTION__, strerror(errno));
         //errno = ENOSYS;
         return -1;
     }
 
-    buffLen = strlen(buff);
-
-    if (!WriteFully(fd, buff, buffLen + 1)) {
+    if (qemu_pipe_write_fully(fd, buff, buffLen + 1)) {
         D("%s: Could not connect to %s pipe service: %s", __FUNCTION__, pipeName, strerror(errno));
         return -1;
     }
@@ -142,6 +142,11 @@
     return fd;
 }
 
+static __inline__ QEMU_PIPE_HANDLE
+qemu_pipe_open(const char* pipeName) {
+    return qemu_pipe_open_ns(NULL, pipeName, O_RDWR | O_NONBLOCK);
+}
+
 static __inline__ void
 qemu_pipe_close(QEMU_PIPE_HANDLE pipe) {
     close(pipe);
@@ -159,7 +164,7 @@
 
 static __inline__ bool
 qemu_pipe_try_again() {
-    return errno == EINTR;
+    return errno == EINTR || errno == EAGAIN;
 }
 
 static __inline__ bool
@@ -172,6 +177,46 @@
     ALOGE("pipe error: fd %d errno %d", pipe, errno);
 }
 
+
 #endif // !HOST_BUILD
 
+#ifndef TEMP_FAILURE_RETRY
+#define TEMP_FAILURE_RETRY(exp) ({         \
+    __typeof__(exp) _rc;                   \
+    do {                                   \
+        _rc = (exp);                       \
+    } while (_rc == -1 && errno == EINTR); \
+    _rc; })
+#endif
+
+static __inline__ ssize_t
+qemu_pipe_read_fully(QEMU_PIPE_HANDLE pipe, void* buffer, ssize_t len) {
+    char* p = (char*)buffer;
+
+    while (len > 0) {
+      ssize_t n = QEMU_PIPE_RETRY(qemu_pipe_read(pipe, p, len));
+      if (n < 0) return n;
+
+      p += n;
+      len -= n;
+    }
+
+    return 0;
+}
+
+static __inline__ ssize_t
+qemu_pipe_write_fully(QEMU_PIPE_HANDLE pipe, const void* buffer, ssize_t len) {
+    const char* p = (const char*)buffer;
+
+    while (len > 0) {
+      ssize_t n = QEMU_PIPE_RETRY(qemu_pipe_write(pipe, p, len));
+      if (n < 0) return n;
+
+      p += n;
+      len -= n;
+    }
+
+    return 0;
+}
+
 #endif /* ANDROID_INCLUDE_HARDWARE_QEMU_PIPE_H */
diff --git a/shared/OpenglCodecCommon/qemu_pipe_host.cpp b/shared/OpenglCodecCommon/qemu_pipe_host.cpp
index e1a3b45..c53a8eb 100644
--- a/shared/OpenglCodecCommon/qemu_pipe_host.cpp
+++ b/shared/OpenglCodecCommon/qemu_pipe_host.cpp
@@ -13,7 +13,7 @@
 // limitations under the License.
 #include "qemu_pipe.h"
 
-#include "android/emulation/hostpipe/HostGoldfishPipe.h"
+#include "android/emulation/hostdevices/HostGoldfishPipe.h"
 
 #if PLATFORM_SDK_VERSION < 26
 #include <cutils/log.h>
@@ -21,6 +21,8 @@
 #include <log/log.h>
 #endif
 
+#include <errno.h>
+
 using android::HostGoldfishPipeDevice;
 
 QEMU_PIPE_HANDLE qemu_pipe_open(const char* pipeName) {
diff --git a/system/GLESv1/CMakeLists.txt b/system/GLESv1/CMakeLists.txt
index 9642bb2..a8dc669 100644
--- a/system/GLESv1/CMakeLists.txt
+++ b/system/GLESv1/CMakeLists.txt
@@ -3,8 +3,8 @@
 # which will re-generate this file.
 android_validate_sha256("${GOLDFISH_DEVICE_ROOT}/system/GLESv1/Android.mk" "e095cb082e3791719749cfc80b90560afd7348eb0d7895449d2509aa129bea75")
 set(GLESv1_CM_emulation_src gl.cpp)
-android_add_shared_library(GLESv1_CM_emulation)
-target_include_directories(GLESv1_CM_emulation PRIVATE ${GOLDFISH_DEVICE_ROOT}/system/OpenglSystemCommon ${GOLDFISH_DEVICE_ROOT}/bionic/libc/private ${GOLDFISH_DEVICE_ROOT}/system/vulkan_enc ${GOLDFISH_DEVICE_ROOT}/android-emu ${GOLDFISH_DEVICE_ROOT}/system/renderControl_enc ${GOLDFISH_DEVICE_ROOT}/system/GLESv2_enc ${GOLDFISH_DEVICE_ROOT}/system/GLESv1_enc ${GOLDFISH_DEVICE_ROOT}/shared/OpenglCodecCommon ${GOLDFISH_DEVICE_ROOT}/./host/include/libOpenglRender ${GOLDFISH_DEVICE_ROOT}/./system/include ${GOLDFISH_DEVICE_ROOT}/./../../../external/qemu/android/android-emugl/guest)
+android_add_library(TARGET GLESv1_CM_emulation SHARED LICENSE Apache-2.0 SRC gl.cpp)
+target_include_directories(GLESv1_CM_emulation PRIVATE ${GOLDFISH_DEVICE_ROOT}/system/OpenglSystemCommon/bionic-include ${GOLDFISH_DEVICE_ROOT}/system/OpenglSystemCommon ${GOLDFISH_DEVICE_ROOT}/bionic/libc/private ${GOLDFISH_DEVICE_ROOT}/bionic/libc/platform ${GOLDFISH_DEVICE_ROOT}/system/vulkan_enc ${GOLDFISH_DEVICE_ROOT}/android-emu ${GOLDFISH_DEVICE_ROOT}/system/renderControl_enc ${GOLDFISH_DEVICE_ROOT}/system/GLESv2_enc ${GOLDFISH_DEVICE_ROOT}/system/GLESv1_enc ${GOLDFISH_DEVICE_ROOT}/shared/OpenglCodecCommon ${GOLDFISH_DEVICE_ROOT}/./host/include/libOpenglRender ${GOLDFISH_DEVICE_ROOT}/./system/include ${GOLDFISH_DEVICE_ROOT}/./../../../external/qemu/android/android-emugl/guest)
 target_compile_definitions(GLESv1_CM_emulation PRIVATE "-DWITH_GLES2" "-DPLATFORM_SDK_VERSION=29" "-DGOLDFISH_HIDL_GRALLOC" "-DEMULATOR_OPENGL_POST_O=1" "-DHOST_BUILD" "-DANDROID" "-DGL_GLEXT_PROTOTYPES" "-DPAGE_SIZE=4096" "-DGOLDFISH_VULKAN" "-DLOG_TAG=\"GLES_emulation\"")
-target_compile_options(GLESv1_CM_emulation PRIVATE "-fvisibility=default")
-target_link_libraries(GLESv1_CM_emulation PRIVATE OpenglSystemCommon android-emu-shared vulkan_enc gui cutils utils log _renderControl_enc GLESv2_enc GLESv1_enc OpenglCodecCommon_host)
\ No newline at end of file
+target_compile_options(GLESv1_CM_emulation PRIVATE "-fvisibility=default" "-Wno-unused-parameter")
+target_link_libraries(GLESv1_CM_emulation PRIVATE OpenglSystemCommon android-emu-shared vulkan_enc gui androidemu cutils utils log _renderControl_enc GLESv2_enc GLESv1_enc OpenglCodecCommon_host)
\ No newline at end of file
diff --git a/system/GLESv1_enc/CMakeLists.txt b/system/GLESv1_enc/CMakeLists.txt
index 1b86cdb..8acc4ff 100644
--- a/system/GLESv1_enc/CMakeLists.txt
+++ b/system/GLESv1_enc/CMakeLists.txt
@@ -3,8 +3,8 @@
 # which will re-generate this file.
 android_validate_sha256("${GOLDFISH_DEVICE_ROOT}/system/GLESv1_enc/Android.mk" "953e6b7371d10eed63a4be555f8f1fb6f347338484a78102fa8f55dff96f5d3b")
 set(GLESv1_enc_src GLEncoder.cpp GLEncoderUtils.cpp gl_client_context.cpp gl_enc.cpp gl_entry.cpp)
-android_add_shared_library(GLESv1_enc)
+android_add_library(TARGET GLESv1_enc SHARED LICENSE Apache-2.0 SRC GLEncoder.cpp GLEncoderUtils.cpp gl_client_context.cpp gl_enc.cpp gl_entry.cpp)
 target_include_directories(GLESv1_enc PRIVATE ${GOLDFISH_DEVICE_ROOT}/system/GLESv1_enc ${GOLDFISH_DEVICE_ROOT}/shared/OpenglCodecCommon ${GOLDFISH_DEVICE_ROOT}/./host/include/libOpenglRender ${GOLDFISH_DEVICE_ROOT}/./system/include ${GOLDFISH_DEVICE_ROOT}/./../../../external/qemu/android/android-emugl/guest)
 target_compile_definitions(GLESv1_enc PRIVATE "-DWITH_GLES2" "-DPLATFORM_SDK_VERSION=29" "-DGOLDFISH_HIDL_GRALLOC" "-DEMULATOR_OPENGL_POST_O=1" "-DHOST_BUILD" "-DANDROID" "-DGL_GLEXT_PROTOTYPES" "-DPAGE_SIZE=4096" "-DGOLDFISH_VULKAN" "-DLOG_TAG=\"emuglGLESv1_enc\"")
-target_compile_options(GLESv1_enc PRIVATE "-fvisibility=default")
+target_compile_options(GLESv1_enc PRIVATE "-fvisibility=default" "-Wno-unused-parameter")
 target_link_libraries(GLESv1_enc PRIVATE OpenglCodecCommon_host cutils utils log android-emu-shared)
\ No newline at end of file
diff --git a/system/GLESv1_enc/gl_enc.h b/system/GLESv1_enc/gl_enc.h
index 030bd66..d71964f 100644
--- a/system/GLESv1_enc/gl_enc.h
+++ b/system/GLESv1_enc/gl_enc.h
@@ -18,7 +18,7 @@
 	ChecksumCalculator *m_checksumCalculator;
 
 	gl_encoder_context_t(IOStream *stream, ChecksumCalculator *checksumCalculator);
-	virtual uint64_t lockAndWriteDma(void* data, uint32_t sz) { return 0; }
+	virtual uint64_t lockAndWriteDma(void*, uint32_t) { return 0; }
 };
 
 #endif  // GUARD_gl_encoder_context_t
diff --git a/system/GLESv2/CMakeLists.txt b/system/GLESv2/CMakeLists.txt
index 7738bcd..e2f5f4e 100644
--- a/system/GLESv2/CMakeLists.txt
+++ b/system/GLESv2/CMakeLists.txt
@@ -3,8 +3,8 @@
 # which will re-generate this file.
 android_validate_sha256("${GOLDFISH_DEVICE_ROOT}/system/GLESv2/Android.mk" "d8f9dda69ec57ad8b7a65f02c3335b16a4724f612dec1d1a2cd793c28c0a10f9")
 set(GLESv2_emulation_src gl2.cpp)
-android_add_shared_library(GLESv2_emulation)
-target_include_directories(GLESv2_emulation PRIVATE ${GOLDFISH_DEVICE_ROOT}/system/OpenglSystemCommon ${GOLDFISH_DEVICE_ROOT}/bionic/libc/private ${GOLDFISH_DEVICE_ROOT}/system/vulkan_enc ${GOLDFISH_DEVICE_ROOT}/android-emu ${GOLDFISH_DEVICE_ROOT}/system/renderControl_enc ${GOLDFISH_DEVICE_ROOT}/system/GLESv2_enc ${GOLDFISH_DEVICE_ROOT}/system/GLESv1_enc ${GOLDFISH_DEVICE_ROOT}/shared/OpenglCodecCommon ${GOLDFISH_DEVICE_ROOT}/./host/include/libOpenglRender ${GOLDFISH_DEVICE_ROOT}/./system/include ${GOLDFISH_DEVICE_ROOT}/./../../../external/qemu/android/android-emugl/guest)
+android_add_library(TARGET GLESv2_emulation SHARED LICENSE Apache-2.0 SRC gl2.cpp)
+target_include_directories(GLESv2_emulation PRIVATE ${GOLDFISH_DEVICE_ROOT}/system/OpenglSystemCommon/bionic-include ${GOLDFISH_DEVICE_ROOT}/system/OpenglSystemCommon ${GOLDFISH_DEVICE_ROOT}/bionic/libc/private ${GOLDFISH_DEVICE_ROOT}/bionic/libc/platform ${GOLDFISH_DEVICE_ROOT}/system/vulkan_enc ${GOLDFISH_DEVICE_ROOT}/android-emu ${GOLDFISH_DEVICE_ROOT}/system/renderControl_enc ${GOLDFISH_DEVICE_ROOT}/system/GLESv2_enc ${GOLDFISH_DEVICE_ROOT}/system/GLESv1_enc ${GOLDFISH_DEVICE_ROOT}/shared/OpenglCodecCommon ${GOLDFISH_DEVICE_ROOT}/./host/include/libOpenglRender ${GOLDFISH_DEVICE_ROOT}/./system/include ${GOLDFISH_DEVICE_ROOT}/./../../../external/qemu/android/android-emugl/guest)
 target_compile_definitions(GLESv2_emulation PRIVATE "-DWITH_GLES2" "-DPLATFORM_SDK_VERSION=29" "-DGOLDFISH_HIDL_GRALLOC" "-DEMULATOR_OPENGL_POST_O=1" "-DHOST_BUILD" "-DANDROID" "-DGL_GLEXT_PROTOTYPES" "-DPAGE_SIZE=4096" "-DGOLDFISH_VULKAN" "-DLOG_TAG=\"GLESv2_emulation\"")
-target_compile_options(GLESv2_emulation PRIVATE "-fvisibility=default")
-target_link_libraries(GLESv2_emulation PRIVATE OpenglSystemCommon android-emu-shared vulkan_enc gui cutils utils log _renderControl_enc GLESv2_enc GLESv1_enc OpenglCodecCommon_host)
\ No newline at end of file
+target_compile_options(GLESv2_emulation PRIVATE "-fvisibility=default" "-Wno-unused-parameter")
+target_link_libraries(GLESv2_emulation PRIVATE OpenglSystemCommon android-emu-shared vulkan_enc gui androidemu cutils utils log _renderControl_enc GLESv2_enc GLESv1_enc OpenglCodecCommon_host)
\ No newline at end of file
diff --git a/system/GLESv2_enc/Android.mk b/system/GLESv2_enc/Android.mk
index 12bb013..af95736 100644
--- a/system/GLESv2_enc/Android.mk
+++ b/system/GLESv2_enc/Android.mk
@@ -13,6 +13,8 @@
     ../enc_common/IOStream_common.cpp \
 
 LOCAL_CFLAGS += -DLOG_TAG=\"emuglGLESv2_enc\"
+LOCAL_CFLAGS += -Wno-unused-private-field
+
 
 $(call emugl-export,C_INCLUDES,$(LOCAL_PATH))
 $(call emugl-import,libOpenglCodecCommon$(GOLDFISH_OPENGL_LIB_SUFFIX))
diff --git a/system/GLESv2_enc/CMakeLists.txt b/system/GLESv2_enc/CMakeLists.txt
index 87534fc..72afa76 100644
--- a/system/GLESv2_enc/CMakeLists.txt
+++ b/system/GLESv2_enc/CMakeLists.txt
@@ -1,10 +1,10 @@
 # This is an autogenerated file! Do not edit!
 # instead run make from .../device/generic/goldfish-opengl
 # which will re-generate this file.
-android_validate_sha256("${GOLDFISH_DEVICE_ROOT}/system/GLESv2_enc/Android.mk" "61772afe3e393d4ff6add7929ed232da8e614e44bf903018a91c774bc5b54a18")
+android_validate_sha256("${GOLDFISH_DEVICE_ROOT}/system/GLESv2_enc/Android.mk" "d4fc971ccdbafbf971253b27bbc2168682b2994476079f4f81fb7a33c27070e0")
 set(GLESv2_enc_src GL2EncoderUtils.cpp GL2Encoder.cpp GLESv2Validation.cpp gl2_client_context.cpp gl2_enc.cpp gl2_entry.cpp ../enc_common/IOStream_common.cpp)
-android_add_shared_library(GLESv2_enc)
+android_add_library(TARGET GLESv2_enc SHARED LICENSE Apache-2.0 SRC GL2EncoderUtils.cpp GL2Encoder.cpp GLESv2Validation.cpp gl2_client_context.cpp gl2_enc.cpp gl2_entry.cpp ../enc_common/IOStream_common.cpp)
 target_include_directories(GLESv2_enc PRIVATE ${GOLDFISH_DEVICE_ROOT}/shared/OpenglCodecCommon ${GOLDFISH_DEVICE_ROOT}/system/GLESv2_enc ${GOLDFISH_DEVICE_ROOT}/./host/include/libOpenglRender ${GOLDFISH_DEVICE_ROOT}/./system/include ${GOLDFISH_DEVICE_ROOT}/./../../../external/qemu/android/android-emugl/guest)
 target_compile_definitions(GLESv2_enc PRIVATE "-DWITH_GLES2" "-DPLATFORM_SDK_VERSION=29" "-DGOLDFISH_HIDL_GRALLOC" "-DEMULATOR_OPENGL_POST_O=1" "-DHOST_BUILD" "-DANDROID" "-DGL_GLEXT_PROTOTYPES" "-DPAGE_SIZE=4096" "-DGOLDFISH_VULKAN" "-DLOG_TAG=\"emuglGLESv2_enc\"")
-target_compile_options(GLESv2_enc PRIVATE "-fvisibility=default")
+target_compile_options(GLESv2_enc PRIVATE "-fvisibility=default" "-Wno-unused-parameter" "-Wno-unused-private-field")
 target_link_libraries(GLESv2_enc PRIVATE OpenglCodecCommon_host cutils utils log android-emu-shared)
\ No newline at end of file
diff --git a/system/GLESv2_enc/GL2Encoder.cpp b/system/GLESv2_enc/GL2Encoder.cpp
index 44264d9..cc009a9 100755
--- a/system/GLESv2_enc/GL2Encoder.cpp
+++ b/system/GLESv2_enc/GL2Encoder.cpp
@@ -72,6 +72,7 @@
 {
     m_currMajorVersion = 2;
     m_currMinorVersion = 0;
+    m_hasAsyncUnmapBuffer = false;
     m_initialized = false;
     m_noHostError = false;
     m_state = NULL;
@@ -101,6 +102,7 @@
     m_ssbo_offset_align = 0;
     m_ubo_offset_align = 0;
 
+    m_drawCallFlushInterval = 800;
     m_drawCallFlushCount = 0;
     m_primitiveRestartEnabled = false;
     m_primitiveRestartIndex = 0;
@@ -1184,19 +1186,7 @@
     if (hasClientArrays) *hasClientArrays = false;
     if (hasVBOs) *hasVBOs = false;
 
-    for (int i = 0; i < m_state->nLocations(); i++) {
-        const GLClientState::VertexAttribState& state = m_state->getState(i);
-        if (state.enabled) {
-            const GLClientState::BufferBinding& curr_binding = m_state->getCurrAttributeBindingInfo(i);
-            GLuint bufferObject = curr_binding.buffer;
-            if (bufferObject == 0 && curr_binding.offset && hasClientArrays) {
-                *hasClientArrays = true;
-            }
-            if (bufferObject != 0 && hasVBOs) {
-                *hasVBOs = true;
-            }
-        }
-    }
+    m_state->getVBOUsage(hasClientArrays, hasVBOs);
 }
 
 void GL2Encoder::sendVertexAttributes(GLint first, GLsizei count, bool hasClientArrays, GLsizei primcount)
@@ -1205,7 +1195,6 @@
 
     m_state->updateEnableDirtyArrayForDraw();
 
-    GLuint currentVao = m_state->currentVertexArrayObject();
     GLuint lastBoundVbo = m_state->currentArrayVbo();
     const GLClientState::VAOState& vaoState = m_state->currentVaoState();
 
@@ -1303,11 +1292,7 @@
 }
 
 void GL2Encoder::flushDrawCall() {
-    // This used to be every other draw call, but
-    // now that we are using real GPU buffers on host,
-    // set this to every 200 draw calls
-    // (tuned on z840 linux NVIDIA Quadro K2200)
-    if (m_drawCallFlushCount % 200 == 0) {
+    if (m_drawCallFlushCount % m_drawCallFlushInterval == 0) {
         m_stream->flush();
     }
     m_drawCallFlushCount++;
@@ -1347,7 +1332,6 @@
         ctx->sendVertexAttributes(first, count, true);
         ctx->m_glDrawArrays_enc(ctx, mode, 0, count);
     } else {
-        ctx->sendVertexAttributes(0, count, false);
         ctx->m_glDrawArrays_enc(ctx, mode, first, count);
     }
 }
@@ -1365,7 +1349,6 @@
 
     bool has_client_vertex_arrays = false;
     bool has_indirect_arrays = false;
-    int nLocations = ctx->m_state->nLocations();
     GLintptr offset = 0;
 
     ctx->getVBOUsage(&has_client_vertex_arrays, &has_indirect_arrays);
@@ -1412,13 +1395,11 @@
     bool adjustIndices = true;
     if (ctx->m_state->currentIndexVbo() != 0) {
         if (!has_client_vertex_arrays) {
-            ctx->sendVertexAttributes(0, maxIndex + 1, false);
             ctx->doBindBufferEncodeCached(GL_ELEMENT_ARRAY_BUFFER, ctx->m_state->currentIndexVbo());
             ctx->glDrawElementsOffset(ctx, mode, count, type, offset);
             ctx->flushDrawCall();
             adjustIndices = false;
         } else {
-            BufferData * buf = ctx->m_shared->getBufferData(ctx->m_state->currentIndexVbo());
             ctx->doBindBufferEncodeCached(GL_ELEMENT_ARRAY_BUFFER, 0);
         }
     }
@@ -1463,9 +1444,9 @@
         ctx->sendVertexAttributes(first, count, true);
         ctx->m_glDrawArraysNullAEMU_enc(ctx, mode, 0, count);
     } else {
-        ctx->sendVertexAttributes(0, count, false);
         ctx->m_glDrawArraysNullAEMU_enc(ctx, mode, first, count);
     }
+    ctx->flushDrawCall();
 }
 
 void GL2Encoder::s_glDrawElementsNullAEMU(void *self, GLenum mode, GLsizei count, GLenum type, const void *indices)
@@ -1480,8 +1461,7 @@
 
     bool has_client_vertex_arrays = false;
     bool has_indirect_arrays = false;
-    int nLocations = ctx->m_state->nLocations();
-    GLintptr offset = 0;
+    GLintptr offset = (GLintptr)indices;
 
     ctx->getVBOUsage(&has_client_vertex_arrays, &has_indirect_arrays);
 
@@ -1501,15 +1481,19 @@
     // can more quickly get min/max vertex index by
     // caching previous results.
     if (ctx->m_state->currentIndexVbo() != 0) {
-        buf = ctx->m_shared->getBufferData(ctx->m_state->currentIndexVbo());
-        offset = (GLintptr)indices;
-        indices = (void*)((GLintptr)buf->m_fixedBuffer.ptr() + (GLintptr)indices);
-        ctx->getBufferIndexRange(buf,
-                                 indices,
-                                 type,
-                                 (size_t)count,
-                                 (size_t)offset,
-                                 &minIndex, &maxIndex);
+        if (!has_client_vertex_arrays && has_indirect_arrays) {
+            // Don't do anything
+        } else {
+            buf = ctx->m_shared->getBufferData(ctx->m_state->currentIndexVbo());
+            offset = (GLintptr)indices;
+            indices = (void*)((GLintptr)buf->m_fixedBuffer.ptr() + (GLintptr)indices);
+            ctx->getBufferIndexRange(buf,
+                                     indices,
+                                     type,
+                                     (size_t)count,
+                                     (size_t)offset,
+                                     &minIndex, &maxIndex);
+        }
     } else {
         // In this case, the |indices| field holds a real
         // array, so calculate the indices now. They will
@@ -1527,13 +1511,11 @@
     bool adjustIndices = true;
     if (ctx->m_state->currentIndexVbo() != 0) {
         if (!has_client_vertex_arrays) {
-            ctx->sendVertexAttributes(0, maxIndex + 1, false);
-            ctx->m_glBindBuffer_enc(self, GL_ELEMENT_ARRAY_BUFFER, ctx->m_state->currentIndexVbo());
+            ctx->doBindBufferEncodeCached(GL_ELEMENT_ARRAY_BUFFER, ctx->m_state->currentIndexVbo());
             ctx->glDrawElementsOffsetNullAEMU(ctx, mode, count, type, offset);
             ctx->flushDrawCall();
             adjustIndices = false;
         } else {
-            BufferData * buf = ctx->m_shared->getBufferData(ctx->m_state->currentIndexVbo());
             ctx->m_glBindBuffer_enc(self, GL_ELEMENT_ARRAY_BUFFER, 0);
         }
     }
@@ -1744,10 +1726,10 @@
     return true;
 }
 
-void GL2Encoder::s_glShaderBinary(void *self, GLsizei n, const GLuint *shaders, GLenum binaryformat, const void* binary, GLsizei length)
+void GL2Encoder::s_glShaderBinary(void *self, GLsizei, const GLuint *, GLenum, const void*, GLsizei)
 {
-    GL2Encoder* ctx = (GL2Encoder*)self;
     // Although it is not supported, need to set proper error code.
+    GL2Encoder* ctx = (GL2Encoder*)self;
     SET_ERROR_IF(1, GL_INVALID_ENUM);
 }
 
@@ -1761,8 +1743,22 @@
 
     // Track original sources---they may be translated in the backend
     std::vector<std::string> orig_sources;
-    for (int i = 0; i < count; i++) {
-        orig_sources.push_back(std::string((const char*)(string[i])));
+    if (length) {
+        for (int i = 0; i < count; i++) {
+            // Each element in the length array may contain the length of the corresponding
+            // string (the null character is not counted as part of the string length) or a
+            // value less than 0 to indicate that the string is null terminated.
+            if (length[i] >= 0) {
+                orig_sources.push_back(std::string((const char*)(string[i]),
+                                                   (const char*)(string[i]) + length[i]));
+            } else {
+                orig_sources.push_back(std::string((const char*)(string[i])));
+            }
+        }
+    } else {
+        for (int i = 0; i < count; i++) {
+            orig_sources.push_back(std::string((const char*)(string[i])));
+        }
     }
     shaderData->sources = orig_sources;
 
@@ -1823,7 +1819,6 @@
         location = ctx->m_glGetUniformLocation_enc(self, program, name);
         ctx->m_shared->setProgramIndexInfo(program, i, location, size, type, name);
     }
-    ctx->m_shared->setupLocationShiftWAR(program);
 
     delete[] name;
 }
@@ -1842,7 +1837,7 @@
     SET_ERROR_IF(!ctx->m_shared->isShaderOrProgramObject(program), GL_INVALID_VALUE);
     SET_ERROR_IF(!ctx->m_shared->isProgram(program), GL_INVALID_OPERATION);
     SET_ERROR_IF(!ctx->m_shared->isProgramInitialized(program), GL_INVALID_OPERATION);
-    GLint hostLoc = ctx->m_shared->locationWARAppToHost(program, location);
+    GLint hostLoc = location;
     SET_ERROR_IF(ctx->m_shared->getProgramUniformType(program,hostLoc)==0, GL_INVALID_OPERATION);
     ctx->m_glGetUniformiv_enc(self, program, hostLoc, params);
 }
@@ -1852,7 +1847,7 @@
     SET_ERROR_IF(!ctx->m_shared->isShaderOrProgramObject(program), GL_INVALID_VALUE);
     SET_ERROR_IF(!ctx->m_shared->isProgram(program), GL_INVALID_OPERATION);
     SET_ERROR_IF(!ctx->m_shared->isProgramInitialized(program), GL_INVALID_OPERATION);
-    GLint hostLoc = ctx->m_shared->locationWARAppToHost(program,location);
+    GLint hostLoc = location;
     SET_ERROR_IF(ctx->m_shared->getProgramUniformType(program,hostLoc)==0, GL_INVALID_OPERATION);
     ctx->m_glGetUniformfv_enc(self, program, hostLoc, params);
 }
@@ -1963,24 +1958,8 @@
 int GL2Encoder::s_glGetUniformLocation(void *self, GLuint program, const GLchar *name)
 {
     if (!name) return -1;
-
     GL2Encoder *ctx = (GL2Encoder*)self;
-
-    // if we need the uniform location WAR
-    // parse array index from the end of the name string
-    int arrIndex = 0;
-    bool needLocationWAR = ctx->m_shared->needUniformLocationWAR(program);
-    if (needLocationWAR) {
-        int err;
-        arrIndex = sArrIndexOfUniformExpr(name, &err);
-        if (err) return -1;
-    }
-
-    int hostLoc = ctx->m_glGetUniformLocation_enc(self, program, name);
-    if (hostLoc >= 0 && needLocationWAR) {
-        return ctx->m_shared->locationWARHostToApp(program, hostLoc, arrIndex);
-    }
-    return hostLoc;
+    return ctx->m_glGetUniformLocation_enc(self, program, name);
 }
 
 bool GL2Encoder::updateHostTexture2DBinding(GLenum texUnit, GLenum newTarget)
@@ -2051,14 +2030,14 @@
 void GL2Encoder::s_glUniform1f(void *self , GLint location, GLfloat x)
 {
     GL2Encoder *ctx = (GL2Encoder*)self;
-    GLint hostLoc = ctx->m_shared->locationWARAppToHost(ctx->m_state->currentShaderProgram(),location);
+    GLint hostLoc = location;
     ctx->m_glUniform1f_enc(self, hostLoc, x);
 }
 
 void GL2Encoder::s_glUniform1fv(void *self , GLint location, GLsizei count, const GLfloat* v)
 {
     GL2Encoder *ctx = (GL2Encoder*)self;
-    GLint hostLoc = ctx->m_shared->locationWARAppToHost(ctx->m_state->currentShaderProgram(),location);
+    GLint hostLoc = location;
     ctx->m_glUniform1fv_enc(self, hostLoc, count, v);
 }
 
@@ -2068,7 +2047,7 @@
     GLClientState* state = ctx->m_state;
     GLSharedGroupPtr shared = ctx->m_shared;
 
-    GLint hostLoc = ctx->m_shared->locationWARAppToHost(ctx->m_state->currentShaderProgram(),location);
+    GLint hostLoc = location;
     ctx->m_glUniform1i_enc(self, hostLoc, x);
 
     GLenum target;
@@ -2084,112 +2063,112 @@
 void GL2Encoder::s_glUniform1iv(void *self , GLint location, GLsizei count, const GLint* v)
 {
     GL2Encoder *ctx = (GL2Encoder*)self;
-    GLint hostLoc = ctx->m_shared->locationWARAppToHost(ctx->m_state->currentShaderProgram(),location);
+    GLint hostLoc = location;
     ctx->m_glUniform1iv_enc(self, hostLoc, count, v);
 }
 
 void GL2Encoder::s_glUniform2f(void *self , GLint location, GLfloat x, GLfloat y)
 {
     GL2Encoder *ctx = (GL2Encoder*)self;
-    GLint hostLoc = ctx->m_shared->locationWARAppToHost(ctx->m_state->currentShaderProgram(),location);
+    GLint hostLoc = location;
     ctx->m_glUniform2f_enc(self, hostLoc, x, y);
 }
 
 void GL2Encoder::s_glUniform2fv(void *self , GLint location, GLsizei count, const GLfloat* v)
 {
     GL2Encoder *ctx = (GL2Encoder*)self;
-    GLint hostLoc = ctx->m_shared->locationWARAppToHost(ctx->m_state->currentShaderProgram(),location);
+    GLint hostLoc = location;
     ctx->m_glUniform2fv_enc(self, hostLoc, count, v);
 }
 
 void GL2Encoder::s_glUniform2i(void *self , GLint location, GLint x, GLint y)
 {
     GL2Encoder *ctx = (GL2Encoder*)self;
-    GLint hostLoc = ctx->m_shared->locationWARAppToHost(ctx->m_state->currentShaderProgram(),location);
+    GLint hostLoc = location;
     ctx->m_glUniform2i_enc(self, hostLoc, x, y);
 }
 
 void GL2Encoder::s_glUniform2iv(void *self , GLint location, GLsizei count, const GLint* v)
 {
     GL2Encoder *ctx = (GL2Encoder*)self;
-    GLint hostLoc = ctx->m_shared->locationWARAppToHost(ctx->m_state->currentShaderProgram(),location);
+    GLint hostLoc = location;
     ctx->m_glUniform2iv_enc(self, hostLoc, count, v);
 }
 
 void GL2Encoder::s_glUniform3f(void *self , GLint location, GLfloat x, GLfloat y, GLfloat z)
 {
     GL2Encoder *ctx = (GL2Encoder*)self;
-    GLint hostLoc = ctx->m_shared->locationWARAppToHost(ctx->m_state->currentShaderProgram(),location);
+    GLint hostLoc = location;
     ctx->m_glUniform3f_enc(self, hostLoc, x, y, z);
 }
 
 void GL2Encoder::s_glUniform3fv(void *self , GLint location, GLsizei count, const GLfloat* v)
 {
     GL2Encoder *ctx = (GL2Encoder*)self;
-    GLint hostLoc = ctx->m_shared->locationWARAppToHost(ctx->m_state->currentShaderProgram(),location);
+    GLint hostLoc = location;
     ctx->m_glUniform3fv_enc(self, hostLoc, count, v);
 }
 
 void GL2Encoder::s_glUniform3i(void *self , GLint location, GLint x, GLint y, GLint z)
 {
     GL2Encoder *ctx = (GL2Encoder*)self;
-    GLint hostLoc = ctx->m_shared->locationWARAppToHost(ctx->m_state->currentShaderProgram(),location);
+    GLint hostLoc = location;
     ctx->m_glUniform3i_enc(self, hostLoc, x, y, z);
 }
 
 void GL2Encoder::s_glUniform3iv(void *self , GLint location, GLsizei count, const GLint* v)
 {
     GL2Encoder *ctx = (GL2Encoder*)self;
-    GLint hostLoc = ctx->m_shared->locationWARAppToHost(ctx->m_state->currentShaderProgram(),location);
+    GLint hostLoc = location;
     ctx->m_glUniform3iv_enc(self, hostLoc, count, v);
 }
 
 void GL2Encoder::s_glUniform4f(void *self , GLint location, GLfloat x, GLfloat y, GLfloat z, GLfloat w)
 {
     GL2Encoder *ctx = (GL2Encoder*)self;
-    GLint hostLoc = ctx->m_shared->locationWARAppToHost(ctx->m_state->currentShaderProgram(),location);
+    GLint hostLoc = location;
     ctx->m_glUniform4f_enc(self, hostLoc, x, y, z, w);
 }
 
 void GL2Encoder::s_glUniform4fv(void *self , GLint location, GLsizei count, const GLfloat* v)
 {
     GL2Encoder *ctx = (GL2Encoder*)self;
-    GLint hostLoc = ctx->m_shared->locationWARAppToHost(ctx->m_state->currentShaderProgram(),location);
+    GLint hostLoc = location;
     ctx->m_glUniform4fv_enc(self, hostLoc, count, v);
 }
 
 void GL2Encoder::s_glUniform4i(void *self , GLint location, GLint x, GLint y, GLint z, GLint w)
 {
     GL2Encoder *ctx = (GL2Encoder*)self;
-    GLint hostLoc = ctx->m_shared->locationWARAppToHost(ctx->m_state->currentShaderProgram(),location);
+    GLint hostLoc = location;
     ctx->m_glUniform4i_enc(self, hostLoc, x, y, z, w);
 }
 
 void GL2Encoder::s_glUniform4iv(void *self , GLint location, GLsizei count, const GLint* v)
 {
     GL2Encoder *ctx = (GL2Encoder*)self;
-    GLint hostLoc = ctx->m_shared->locationWARAppToHost(ctx->m_state->currentShaderProgram(),location);
+    GLint hostLoc = location;
     ctx->m_glUniform4iv_enc(self, hostLoc, count, v);
 }
 
 void GL2Encoder::s_glUniformMatrix2fv(void *self , GLint location, GLsizei count, GLboolean transpose, const GLfloat* value)
 {
     GL2Encoder *ctx = (GL2Encoder*)self;
-    GLint hostLoc = ctx->m_shared->locationWARAppToHost(ctx->m_state->currentShaderProgram(),location);
+    GLint hostLoc = location;
     ctx->m_glUniformMatrix2fv_enc(self, hostLoc, count, transpose, value);
 }
 
 void GL2Encoder::s_glUniformMatrix3fv(void *self , GLint location, GLsizei count, GLboolean transpose, const GLfloat* value)
 {
     GL2Encoder *ctx = (GL2Encoder*)self;
-    GLint hostLoc = ctx->m_shared->locationWARAppToHost(ctx->m_state->currentShaderProgram(),location);
+    GLint hostLoc = location;
     ctx->m_glUniformMatrix3fv_enc(self, hostLoc, count, transpose, value);
 }
 
 void GL2Encoder::s_glUniformMatrix4fv(void *self , GLint location, GLsizei count, GLboolean transpose, const GLfloat* value)
 {
     GL2Encoder *ctx = (GL2Encoder*)self;
-    GLint hostLoc = ctx->m_shared->locationWARAppToHost(ctx->m_state->currentShaderProgram(),location);
+    GLint hostLoc = location;
     ctx->m_glUniformMatrix4fv_enc(self, hostLoc, count, transpose, value);
 }
 
@@ -2254,7 +2233,6 @@
         GLenum target, GLenum pname, GLfloat* params)
 {
     GL2Encoder* ctx = (GL2Encoder*)self;
-    const GLClientState* state = ctx->m_state;
 
     if (target == GL_TEXTURE_2D || target == GL_TEXTURE_EXTERNAL_OES) {
         ctx->override2DTextureTarget(target);
@@ -2269,7 +2247,6 @@
         GLenum target, GLenum pname, GLint* params)
 {
     GL2Encoder* ctx = (GL2Encoder*)self;
-    const GLClientState* state = ctx->m_state;
 
     switch (pname) {
     case GL_REQUIRED_TEXTURE_IMAGE_UNITS_OES:
@@ -2308,7 +2285,6 @@
         GLenum target, GLenum pname, GLfloat param)
 {
     GL2Encoder* ctx = (GL2Encoder*)self;
-    const GLClientState* state = ctx->m_state;
 
     SET_ERROR_IF((target == GL_TEXTURE_EXTERNAL_OES &&
             !isValidTextureExternalParam(pname, (GLenum)param)),
@@ -2327,7 +2303,6 @@
         GLenum target, GLenum pname, const GLfloat* params)
 {
     GL2Encoder* ctx = (GL2Encoder*)self;
-    const GLClientState* state = ctx->m_state;
 
     SET_ERROR_IF((target == GL_TEXTURE_EXTERNAL_OES &&
             !isValidTextureExternalParam(pname, (GLenum)params[0])),
@@ -2346,7 +2321,6 @@
         GLenum target, GLenum pname, GLint param)
 {
     GL2Encoder* ctx = (GL2Encoder*)self;
-    const GLClientState* state = ctx->m_state;
 
     SET_ERROR_IF((target == GL_TEXTURE_EXTERNAL_OES &&
             !isValidTextureExternalParam(pname, (GLenum)param)),
@@ -2549,7 +2523,6 @@
         GLenum target, GLenum pname, const GLint* params)
 {
     GL2Encoder* ctx = (GL2Encoder*)self;
-    const GLClientState* state = ctx->m_state;
 
     SET_ERROR_IF((target == GL_TEXTURE_EXTERNAL_OES &&
             !isValidTextureExternalParam(pname, (GLenum)params[0])),
@@ -2966,18 +2939,22 @@
                                              GLbitfield access, BufferData* buf) {
     char* bits = (char*)buf->m_fixedBuffer.ptr() + offset;
 
-    ctx->glMapBufferRangeAEMU(
-            ctx, target,
-            offset, length,
-            access,
-            bits);
+    if ((access & GL_MAP_READ_BIT) ||
+        ((access & GL_MAP_WRITE_BIT) &&
+        (!(access & GL_MAP_INVALIDATE_RANGE_BIT) &&
+         !(access & GL_MAP_INVALIDATE_BUFFER_BIT)))) {
+        ctx->glMapBufferRangeAEMU(
+                ctx, target,
+                offset, length,
+                access,
+                bits);
+    }
 
     return bits;
 }
 
 void* GL2Encoder::s_glMapBufferRange(void* self, GLenum target, GLintptr offset, GLsizeiptr length, GLbitfield access) {
     GL2Encoder* ctx = (GL2Encoder*)self;
-    GLClientState* state = ctx->m_state;
 
     // begin validation (lots)
 
@@ -3048,7 +3025,6 @@
 
 GLboolean GL2Encoder::s_glUnmapBuffer(void* self, GLenum target) {
     GL2Encoder* ctx = (GL2Encoder*)self;
-    GLClientState* state = ctx->m_state;
 
     RET_AND_SET_ERROR_IF(!GLESv2Validation::bufferTarget(ctx, target), GL_INVALID_ENUM, GL_FALSE);
 
@@ -3084,13 +3060,25 @@
             goldfish_dma_guest_paddr(&buf->dma_buffer.get()),
             &host_res);
     } else {
-        ctx->glUnmapBufferAEMU(
-                ctx, target,
-                buf->m_mappedOffset,
-                buf->m_mappedLength,
-                buf->m_mappedAccess,
-                (void*)((char*)buf->m_fixedBuffer.ptr() + buf->m_mappedOffset),
-                &host_res);
+        if (ctx->m_hasAsyncUnmapBuffer) {
+            ctx->glUnmapBufferAsyncAEMU(
+                    ctx, target,
+                    buf->m_mappedOffset,
+                    buf->m_mappedLength,
+                    buf->m_mappedAccess,
+                    (void*)((char*)buf->m_fixedBuffer.ptr() + buf->m_mappedOffset),
+                    &host_res);
+        } else {
+            if (buf->m_mappedAccess & GL_MAP_WRITE_BIT) {
+                ctx->glUnmapBufferAEMU(
+                        ctx, target,
+                        buf->m_mappedOffset,
+                        buf->m_mappedLength,
+                        buf->m_mappedAccess,
+                        (void*)((char*)buf->m_fixedBuffer.ptr() + buf->m_mappedOffset),
+                        &host_res);
+            }
+        }
     }
 
     buf->m_mapped = false;
@@ -3103,7 +3091,6 @@
 
 void GL2Encoder::s_glFlushMappedBufferRange(void* self, GLenum target, GLintptr offset, GLsizeiptr length) {
     GL2Encoder* ctx = (GL2Encoder*)self;
-    GLClientState* state = ctx->m_state;
 
     SET_ERROR_IF(!GLESv2Validation::bufferTarget(ctx, target), GL_INVALID_ENUM);
 
@@ -3123,12 +3110,21 @@
 
     buf->m_indexRangeCache.invalidateRange(totalOffset, length);
 
-    ctx->glFlushMappedBufferRangeAEMU(
-            ctx, target,
-            totalOffset,
-            length,
-            buf->m_mappedAccess,
-            (void*)((char*)buf->m_fixedBuffer.ptr() + totalOffset));
+    if (ctx->m_hasAsyncUnmapBuffer) {
+        ctx->glFlushMappedBufferRangeAEMU2(
+                ctx, target,
+                totalOffset,
+                length,
+                buf->m_mappedAccess,
+                (void*)((char*)buf->m_fixedBuffer.ptr() + totalOffset));
+    } else {
+        ctx->glFlushMappedBufferRangeAEMU(
+                ctx, target,
+                totalOffset,
+                length,
+                buf->m_mappedAccess,
+                (void*)((char*)buf->m_fixedBuffer.ptr() + totalOffset));
+    }
 }
 
 void GL2Encoder::s_glCompressedTexImage2D(void* self, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const GLvoid* data) {
@@ -3195,7 +3191,6 @@
 
 void GL2Encoder::s_glCompressedTexSubImage2D(void* self, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const GLvoid* data) {
     GL2Encoder* ctx = (GL2Encoder*)self;
-    GLClientState* state = ctx->m_state;
 
     SET_ERROR_IF(!GLESv2Validation::textureTarget(ctx, target), GL_INVALID_ENUM);
     // If unpack buffer is nonzero, verify unmapped state.
@@ -3332,7 +3327,6 @@
 
 void GL2Encoder::s_glCopyBufferSubData(void *self , GLenum readtarget, GLenum writetarget, GLintptr readoffset, GLintptr writeoffset, GLsizeiptr size) {
     GL2Encoder* ctx = (GL2Encoder*)self;
-    GLClientState* state = ctx->m_state;
 
     SET_ERROR_IF(!GLESv2Validation::bufferTarget(ctx, readtarget), GL_INVALID_ENUM);
     SET_ERROR_IF(!GLESv2Validation::bufferTarget(ctx, writetarget), GL_INVALID_ENUM);
@@ -3527,7 +3521,6 @@
     std::string packed = packVarNames(uniformCount, (const char**)uniformNames, &err);
     SET_ERROR_IF(err != GL_NO_ERROR, GL_INVALID_OPERATION);
 
-    bool needLocationWAR = ctx->m_shared->needUniformLocationWAR(program);
     std::vector<int> arrIndices;
     for (size_t i = 0; i < uniformCount; i++) {
         int err;
@@ -3539,13 +3532,6 @@
     }
 
     ctx->glGetUniformIndicesAEMU(ctx, program, uniformCount, (const GLchar*)&packed[0], packed.size() + 1, uniformIndices);
-
-    for (int i = 0; i < uniformCount; i++) {
-        if (uniformIndices[i] >= 0 && needLocationWAR) {
-            uniformIndices[i] =
-                ctx->m_shared->locationWARHostToApp(program, uniformIndices[i], arrIndices[i]);
-        }
-    }
 }
 
 void GL2Encoder::s_glUniform1ui(void* self, GLint location, GLuint v0) {
@@ -3553,7 +3539,7 @@
     GLClientState* state = ctx->m_state;
     GLSharedGroupPtr shared = ctx->m_shared;
 
-    GLint hostLoc = ctx->m_shared->locationWARAppToHost(ctx->m_state->currentShaderProgram(),location);
+    GLint hostLoc = location;
     ctx->m_glUniform1ui_enc(self, hostLoc, v0);
 
     GLenum target;
@@ -3568,79 +3554,79 @@
 
 void GL2Encoder::s_glUniform2ui(void* self, GLint location, GLuint v0, GLuint v1) {
     GL2Encoder *ctx = (GL2Encoder*)self;
-    GLint hostLoc = ctx->m_shared->locationWARAppToHost(ctx->m_state->currentShaderProgram(),location);
+    GLint hostLoc = location;
     ctx->m_glUniform2ui_enc(self, hostLoc, v0, v1);
 }
 
 void GL2Encoder::s_glUniform3ui(void* self, GLint location, GLuint v0, GLuint v1, GLuint v2) {
     GL2Encoder *ctx = (GL2Encoder*)self;
-    GLint hostLoc = ctx->m_shared->locationWARAppToHost(ctx->m_state->currentShaderProgram(),location);
+    GLint hostLoc = location;
     ctx->m_glUniform3ui_enc(self, hostLoc, v0, v1, v2);
 }
 
 void GL2Encoder::s_glUniform4ui(void* self, GLint location, GLint v0, GLuint v1, GLuint v2, GLuint v3) {
     GL2Encoder *ctx = (GL2Encoder*)self;
-    GLint hostLoc = ctx->m_shared->locationWARAppToHost(ctx->m_state->currentShaderProgram(),location);
+    GLint hostLoc = location;
     ctx->m_glUniform4ui_enc(self, hostLoc, v0, v1, v2, v3);
 }
 
 void GL2Encoder::s_glUniform1uiv(void* self, GLint location, GLsizei count, const GLuint *value) {
     GL2Encoder *ctx = (GL2Encoder*)self;
-    GLint hostLoc = ctx->m_shared->locationWARAppToHost(ctx->m_state->currentShaderProgram(),location);
+    GLint hostLoc = location;
     ctx->m_glUniform1uiv_enc(self, hostLoc, count, value);
 }
 
 void GL2Encoder::s_glUniform2uiv(void* self, GLint location, GLsizei count, const GLuint *value) {
     GL2Encoder *ctx = (GL2Encoder*)self;
-    GLint hostLoc = ctx->m_shared->locationWARAppToHost(ctx->m_state->currentShaderProgram(),location);
+    GLint hostLoc = location;
     ctx->m_glUniform2uiv_enc(self, hostLoc, count, value);
 }
 
 void GL2Encoder::s_glUniform3uiv(void* self, GLint location, GLsizei count, const GLuint *value) {
     GL2Encoder *ctx = (GL2Encoder*)self;
-    GLint hostLoc = ctx->m_shared->locationWARAppToHost(ctx->m_state->currentShaderProgram(),location);
+    GLint hostLoc = location;
     ctx->m_glUniform3uiv_enc(self, hostLoc, count, value);
 }
 
 void GL2Encoder::s_glUniform4uiv(void* self, GLint location, GLsizei count, const GLuint *value) {
     GL2Encoder *ctx = (GL2Encoder*)self;
-    GLint hostLoc = ctx->m_shared->locationWARAppToHost(ctx->m_state->currentShaderProgram(),location);
+    GLint hostLoc = location;
     ctx->m_glUniform4uiv_enc(self, hostLoc, count, value);
 }
 
 void GL2Encoder::s_glUniformMatrix2x3fv(void* self, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) {
     GL2Encoder *ctx = (GL2Encoder*)self;
-    GLint hostLoc = ctx->m_shared->locationWARAppToHost(ctx->m_state->currentShaderProgram(),location);
+    GLint hostLoc = location;
     ctx->m_glUniformMatrix2x3fv_enc(self, hostLoc, count, transpose, value);
 }
 
 void GL2Encoder::s_glUniformMatrix3x2fv(void* self, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) {
     GL2Encoder *ctx = (GL2Encoder*)self;
-    GLint hostLoc = ctx->m_shared->locationWARAppToHost(ctx->m_state->currentShaderProgram(),location);
+    GLint hostLoc = location;
     ctx->m_glUniformMatrix3x2fv_enc(self, hostLoc, count, transpose, value);
 }
 
 void GL2Encoder::s_glUniformMatrix2x4fv(void* self, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) {
     GL2Encoder *ctx = (GL2Encoder*)self;
-    GLint hostLoc = ctx->m_shared->locationWARAppToHost(ctx->m_state->currentShaderProgram(),location);
+    GLint hostLoc = location;
     ctx->m_glUniformMatrix2x4fv_enc(self, hostLoc, count, transpose, value);
 }
 
 void GL2Encoder::s_glUniformMatrix4x2fv(void* self, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) {
     GL2Encoder *ctx = (GL2Encoder*)self;
-    GLint hostLoc = ctx->m_shared->locationWARAppToHost(ctx->m_state->currentShaderProgram(),location);
+    GLint hostLoc = location;
     ctx->m_glUniformMatrix4x2fv_enc(self, hostLoc, count, transpose, value);
 }
 
 void GL2Encoder::s_glUniformMatrix3x4fv(void* self, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) {
     GL2Encoder *ctx = (GL2Encoder*)self;
-    GLint hostLoc = ctx->m_shared->locationWARAppToHost(ctx->m_state->currentShaderProgram(),location);
+    GLint hostLoc = location;
     ctx->m_glUniformMatrix3x4fv_enc(self, hostLoc, count, transpose, value);
 }
 
 void GL2Encoder::s_glUniformMatrix4x3fv(void* self, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) {
     GL2Encoder *ctx = (GL2Encoder*)self;
-    GLint hostLoc = ctx->m_shared->locationWARAppToHost(ctx->m_state->currentShaderProgram(),location);
+    GLint hostLoc = location;
     ctx->m_glUniformMatrix4x3fv_enc(self, hostLoc, count, transpose, value);
 }
 
@@ -3649,14 +3635,13 @@
     SET_ERROR_IF(!ctx->m_shared->isShaderOrProgramObject(program), GL_INVALID_VALUE);
     SET_ERROR_IF(!ctx->m_shared->isProgram(program), GL_INVALID_OPERATION);
     SET_ERROR_IF(!ctx->m_shared->isProgramInitialized(program), GL_INVALID_OPERATION);
-    GLint hostLoc = ctx->m_shared->locationWARAppToHost(program, location);
+    GLint hostLoc = location;
     SET_ERROR_IF(ctx->m_shared->getProgramUniformType(program,hostLoc)==0, GL_INVALID_OPERATION);
     ctx->m_glGetUniformuiv_enc(self, program, hostLoc, params);
 }
 
 void GL2Encoder::s_glGetActiveUniformBlockiv(void* self, GLuint program, GLuint uniformBlockIndex, GLenum pname, GLint* params) {
     GL2Encoder* ctx = (GL2Encoder*)self;
-    GLClientState* state = ctx->m_state;
 
     // refresh client state's # active uniforms in this block
     if (pname == GL_UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES) {
@@ -3949,12 +3934,12 @@
     SET_ERROR_IF(level > ilog2(max_3d_texture_size), GL_INVALID_VALUE);
 
     SET_ERROR_IF(width < 0 || height < 0 || depth < 0, GL_INVALID_VALUE);
-    SET_ERROR_IF(width > GL_MAX_TEXTURE_SIZE, GL_INVALID_VALUE);
-    SET_ERROR_IF(height > GL_MAX_TEXTURE_SIZE, GL_INVALID_VALUE);
-    SET_ERROR_IF(depth > GL_MAX_TEXTURE_SIZE, GL_INVALID_VALUE);
-    SET_ERROR_IF(width > GL_MAX_3D_TEXTURE_SIZE, GL_INVALID_VALUE);
-    SET_ERROR_IF(height > GL_MAX_3D_TEXTURE_SIZE, GL_INVALID_VALUE);
-    SET_ERROR_IF(depth > GL_MAX_3D_TEXTURE_SIZE, GL_INVALID_VALUE);
+    SET_ERROR_IF(width > max_texture_size, GL_INVALID_VALUE);
+    SET_ERROR_IF(height > max_texture_size, GL_INVALID_VALUE);
+    SET_ERROR_IF(depth > max_texture_size, GL_INVALID_VALUE);
+    SET_ERROR_IF(width > max_3d_texture_size, GL_INVALID_VALUE);
+    SET_ERROR_IF(height > max_3d_texture_size, GL_INVALID_VALUE);
+    SET_ERROR_IF(depth > max_3d_texture_size, GL_INVALID_VALUE);
     SET_ERROR_IF(border != 0, GL_INVALID_VALUE);
     // If unpack buffer is nonzero, verify buffer data fits and is evenly divisible by the type.
     SET_ERROR_IF(ctx->boundBuffer(GL_PIXEL_UNPACK_BUFFER) &&
@@ -4082,7 +4067,6 @@
 
 void GL2Encoder::s_glCompressedTexSubImage3D(void* self, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const GLvoid* data) {
     GL2Encoder* ctx = (GL2Encoder*)self;
-    GLClientState* state = ctx->m_state;
 
     SET_ERROR_IF(!GLESv2Validation::textureTarget(ctx, target), GL_INVALID_ENUM);
     // If unpack buffer is nonzero, verify unmapped state.
@@ -4168,7 +4152,6 @@
 
     bool has_client_vertex_arrays = false;
     bool has_indirect_arrays = false;
-    int nLocations = ctx->m_state->nLocations();
     GLintptr offset = 0;
 
     ctx->getVBOUsage(&has_client_vertex_arrays, &has_indirect_arrays);
@@ -4221,7 +4204,6 @@
             ctx->flushDrawCall();
             adjustIndices = false;
         } else {
-            BufferData * buf = ctx->m_shared->getBufferData(ctx->m_state->currentIndexVbo());
             ctx->doBindBufferEncodeCached(GL_ELEMENT_ARRAY_BUFFER, 0);
         }
     }
@@ -4261,7 +4243,6 @@
 
     bool has_client_vertex_arrays = false;
     bool has_indirect_arrays = false;
-    int nLocations = ctx->m_state->nLocations();
     GLintptr offset = 0;
 
     ctx->getVBOUsage(&has_client_vertex_arrays, &has_indirect_arrays);
@@ -4320,7 +4301,6 @@
             ctx->flushDrawCall();
             adjustIndices = false;
         } else {
-            BufferData * buf = ctx->m_shared->getBufferData(ctx->m_state->currentIndexVbo());
             ctx->doBindBufferEncodeCached(GL_ELEMENT_ARRAY_BUFFER, 0);
         }
     }
@@ -4503,9 +4483,9 @@
     GL2Encoder *ctx = (GL2Encoder *)self;
     GLClientState* state = ctx->m_state;
 
-    bool validateColor = mask | GL_COLOR_BUFFER_BIT;
-    bool validateDepth = mask | GL_DEPTH_BUFFER_BIT;
-    bool validateStencil = mask | GL_STENCIL_BUFFER_BIT;
+    bool validateColor = mask & GL_COLOR_BUFFER_BIT;
+    bool validateDepth = mask & GL_DEPTH_BUFFER_BIT;
+    bool validateStencil = mask & GL_STENCIL_BUFFER_BIT;
 
     FboFormatInfo read_fbo_format_info;
     FboFormatInfo draw_fbo_format_info;
@@ -4635,7 +4615,6 @@
 
     GLuint tex = state->getBoundTexture(target);
     GLenum internalformat = state->queryTexInternalFormat(tex);
-    GLenum format = state->queryTexFormat(tex);
 
     SET_ERROR_IF(tex && GLESv2Validation::isCompressedFormat(internalformat),
                  GL_INVALID_OPERATION);
@@ -4909,8 +4888,6 @@
         ctx->m_shared->setShaderProgramIndexInfo(res, i, location, size, uniformType, name);
     }
 
-    ctx->m_shared->setupShaderProgramLocationShiftWAR(res);
-
     delete [] name;
 
     return res;
@@ -4919,21 +4896,21 @@
 void GL2Encoder::s_glProgramUniform1f(void* self, GLuint program, GLint location, GLfloat v0)
 {
     GL2Encoder *ctx = (GL2Encoder*)self;
-    GLint hostLoc = ctx->m_shared->locationWARAppToHost(program, location);
+    GLint hostLoc = location;
     ctx->m_glProgramUniform1f_enc(self, program, hostLoc, v0);
 }
 
 void GL2Encoder::s_glProgramUniform1fv(void* self, GLuint program, GLint location, GLsizei count, const GLfloat *value)
 {
     GL2Encoder *ctx = (GL2Encoder*)self;
-    GLint hostLoc = ctx->m_shared->locationWARAppToHost(program, location);
+    GLint hostLoc = location;
     ctx->m_glProgramUniform1fv_enc(self, program, hostLoc, count, value);
 }
 
 void GL2Encoder::s_glProgramUniform1i(void* self, GLuint program, GLint location, GLint v0)
 {
     GL2Encoder *ctx = (GL2Encoder*)self;
-    GLint hostLoc = ctx->m_shared->locationWARAppToHost(program, location);
+    GLint hostLoc = location;
     ctx->m_glProgramUniform1i_enc(self, program, hostLoc, v0);
 
     GLClientState* state = ctx->m_state;
@@ -4952,14 +4929,14 @@
 void GL2Encoder::s_glProgramUniform1iv(void* self, GLuint program, GLint location, GLsizei count, const GLint *value)
 {
     GL2Encoder *ctx = (GL2Encoder*)self;
-    GLint hostLoc = ctx->m_shared->locationWARAppToHost(program, location);
+    GLint hostLoc = location;
     ctx->m_glProgramUniform1iv_enc(self, program, hostLoc, count, value);
 }
 
 void GL2Encoder::s_glProgramUniform1ui(void* self, GLuint program, GLint location, GLuint v0)
 {
     GL2Encoder *ctx = (GL2Encoder*)self;
-    GLint hostLoc = ctx->m_shared->locationWARAppToHost(program, location);
+    GLint hostLoc = location;
     ctx->m_glProgramUniform1ui_enc(self, program, hostLoc, v0);
 
     GLClientState* state = ctx->m_state;
@@ -4978,196 +4955,196 @@
 void GL2Encoder::s_glProgramUniform1uiv(void* self, GLuint program, GLint location, GLsizei count, const GLuint *value)
 {
     GL2Encoder *ctx = (GL2Encoder*)self;
-    GLint hostLoc = ctx->m_shared->locationWARAppToHost(program, location);
+    GLint hostLoc = location;
     ctx->m_glProgramUniform1uiv_enc(self, program, hostLoc, count, value);
 }
 
 void GL2Encoder::s_glProgramUniform2f(void* self, GLuint program, GLint location, GLfloat v0, GLfloat v1)
 {
     GL2Encoder *ctx = (GL2Encoder*)self;
-    GLint hostLoc = ctx->m_shared->locationWARAppToHost(program, location);
+    GLint hostLoc = location;
     ctx->m_glProgramUniform2f_enc(self, program, hostLoc, v0, v1);
 }
 
 void GL2Encoder::s_glProgramUniform2fv(void* self, GLuint program, GLint location, GLsizei count, const GLfloat *value)
 {
     GL2Encoder *ctx = (GL2Encoder*)self;
-    GLint hostLoc = ctx->m_shared->locationWARAppToHost(program, location);
+    GLint hostLoc = location;
     ctx->m_glProgramUniform2fv_enc(self, program, hostLoc, count, value);
 }
 
 void GL2Encoder::s_glProgramUniform2i(void* self, GLuint program, GLint location, GLint v0, GLint v1)
 {
     GL2Encoder *ctx = (GL2Encoder*)self;
-    GLint hostLoc = ctx->m_shared->locationWARAppToHost(program, location);
+    GLint hostLoc = location;
     ctx->m_glProgramUniform2i_enc(self, program, hostLoc, v0, v1);
 }
 
 void GL2Encoder::s_glProgramUniform2iv(void* self, GLuint program, GLint location, GLsizei count, const GLint *value)
 {
     GL2Encoder *ctx = (GL2Encoder*)self;
-    GLint hostLoc = ctx->m_shared->locationWARAppToHost(program, location);
+    GLint hostLoc = location;
     ctx->m_glProgramUniform2iv_enc(self, program, hostLoc, count, value);
 }
 
 void GL2Encoder::s_glProgramUniform2ui(void* self, GLuint program, GLint location, GLint v0, GLuint v1)
 {
     GL2Encoder *ctx = (GL2Encoder*)self;
-    GLint hostLoc = ctx->m_shared->locationWARAppToHost(program, location);
+    GLint hostLoc = location;
     ctx->m_glProgramUniform2ui_enc(self, program, hostLoc, v0, v1);
 }
 
 void GL2Encoder::s_glProgramUniform2uiv(void* self, GLuint program, GLint location, GLsizei count, const GLuint *value)
 {
     GL2Encoder *ctx = (GL2Encoder*)self;
-    GLint hostLoc = ctx->m_shared->locationWARAppToHost(program, location);
+    GLint hostLoc = location;
     ctx->m_glProgramUniform2uiv_enc(self, program, hostLoc, count, value);
 }
 
 void GL2Encoder::s_glProgramUniform3f(void* self, GLuint program, GLint location, GLfloat v0, GLfloat v1, GLfloat v2)
 {
     GL2Encoder *ctx = (GL2Encoder*)self;
-    GLint hostLoc = ctx->m_shared->locationWARAppToHost(program, location);
+    GLint hostLoc = location;
     ctx->m_glProgramUniform3f_enc(self, program, hostLoc, v0, v1, v2);
 }
 
 void GL2Encoder::s_glProgramUniform3fv(void* self, GLuint program, GLint location, GLsizei count, const GLfloat *value)
 {
     GL2Encoder *ctx = (GL2Encoder*)self;
-    GLint hostLoc = ctx->m_shared->locationWARAppToHost(program, location);
+    GLint hostLoc = location;
     ctx->m_glProgramUniform3fv_enc(self, program, hostLoc, count, value);
 }
 
 void GL2Encoder::s_glProgramUniform3i(void* self, GLuint program, GLint location, GLint v0, GLint v1, GLint v2)
 {
     GL2Encoder *ctx = (GL2Encoder*)self;
-    GLint hostLoc = ctx->m_shared->locationWARAppToHost(program, location);
+    GLint hostLoc = location;
     ctx->m_glProgramUniform3i_enc(self, program, hostLoc, v0, v1, v2);
 }
 
 void GL2Encoder::s_glProgramUniform3iv(void* self, GLuint program, GLint location, GLsizei count, const GLint *value)
 {
     GL2Encoder *ctx = (GL2Encoder*)self;
-    GLint hostLoc = ctx->m_shared->locationWARAppToHost(program, location);
+    GLint hostLoc = location;
     ctx->m_glProgramUniform3iv_enc(self, program, hostLoc, count, value);
 }
 
 void GL2Encoder::s_glProgramUniform3ui(void* self, GLuint program, GLint location, GLint v0, GLint v1, GLuint v2)
 {
     GL2Encoder *ctx = (GL2Encoder*)self;
-    GLint hostLoc = ctx->m_shared->locationWARAppToHost(program, location);
+    GLint hostLoc = location;
     ctx->m_glProgramUniform3ui_enc(self, program, hostLoc, v0, v1, v2);
 }
 
 void GL2Encoder::s_glProgramUniform3uiv(void* self, GLuint program, GLint location, GLsizei count, const GLuint *value)
 {
     GL2Encoder *ctx = (GL2Encoder*)self;
-    GLint hostLoc = ctx->m_shared->locationWARAppToHost(program, location);
+    GLint hostLoc = location;
     ctx->m_glProgramUniform3uiv_enc(self, program, hostLoc, count, value);
 }
 
 void GL2Encoder::s_glProgramUniform4f(void* self, GLuint program, GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3)
 {
     GL2Encoder *ctx = (GL2Encoder*)self;
-    GLint hostLoc = ctx->m_shared->locationWARAppToHost(program, location);
+    GLint hostLoc = location;
     ctx->m_glProgramUniform4f_enc(self, program, hostLoc, v0, v1, v2, v3);
 }
 
 void GL2Encoder::s_glProgramUniform4fv(void* self, GLuint program, GLint location, GLsizei count, const GLfloat *value)
 {
     GL2Encoder *ctx = (GL2Encoder*)self;
-    GLint hostLoc = ctx->m_shared->locationWARAppToHost(program, location);
+    GLint hostLoc = location;
     ctx->m_glProgramUniform4fv_enc(self, program, hostLoc, count, value);
 }
 
 void GL2Encoder::s_glProgramUniform4i(void* self, GLuint program, GLint location, GLint v0, GLint v1, GLint v2, GLint v3)
 {
     GL2Encoder *ctx = (GL2Encoder*)self;
-    GLint hostLoc = ctx->m_shared->locationWARAppToHost(program, location);
+    GLint hostLoc = location;
     ctx->m_glProgramUniform4i_enc(self, program, hostLoc, v0, v1, v2, v3);
 }
 
 void GL2Encoder::s_glProgramUniform4iv(void* self, GLuint program, GLint location, GLsizei count, const GLint *value)
 {
     GL2Encoder *ctx = (GL2Encoder*)self;
-    GLint hostLoc = ctx->m_shared->locationWARAppToHost(program, location);
+    GLint hostLoc = location;
     ctx->m_glProgramUniform4iv_enc(self, program, hostLoc, count, value);
 }
 
 void GL2Encoder::s_glProgramUniform4ui(void* self, GLuint program, GLint location, GLint v0, GLint v1, GLint v2, GLuint v3)
 {
     GL2Encoder *ctx = (GL2Encoder*)self;
-    GLint hostLoc = ctx->m_shared->locationWARAppToHost(program, location);
+    GLint hostLoc = location;
     ctx->m_glProgramUniform4ui_enc(self, program, hostLoc, v0, v1, v2, v3);
 }
 
 void GL2Encoder::s_glProgramUniform4uiv(void* self, GLuint program, GLint location, GLsizei count, const GLuint *value)
 {
     GL2Encoder *ctx = (GL2Encoder*)self;
-    GLint hostLoc = ctx->m_shared->locationWARAppToHost(program, location);
+    GLint hostLoc = location;
     ctx->m_glProgramUniform4uiv_enc(self, program, hostLoc, count, value);
 }
 
 void GL2Encoder::s_glProgramUniformMatrix2fv(void* self, GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
 {
     GL2Encoder *ctx = (GL2Encoder*)self;
-    GLint hostLoc = ctx->m_shared->locationWARAppToHost(program, location);
+    GLint hostLoc = location;
     ctx->m_glProgramUniformMatrix2fv_enc(self, program, hostLoc, count, transpose, value);
 }
 
 void GL2Encoder::s_glProgramUniformMatrix2x3fv(void* self, GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
 {
     GL2Encoder *ctx = (GL2Encoder*)self;
-    GLint hostLoc = ctx->m_shared->locationWARAppToHost(program, location);
+    GLint hostLoc = location;
     ctx->m_glProgramUniformMatrix2x3fv_enc(self, program, hostLoc, count, transpose, value);
 }
 
 void GL2Encoder::s_glProgramUniformMatrix2x4fv(void* self, GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
 {
     GL2Encoder *ctx = (GL2Encoder*)self;
-    GLint hostLoc = ctx->m_shared->locationWARAppToHost(program, location);
+    GLint hostLoc = location;
     ctx->m_glProgramUniformMatrix2x4fv_enc(self, program, hostLoc, count, transpose, value);
 }
 
 void GL2Encoder::s_glProgramUniformMatrix3fv(void* self, GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
 {
     GL2Encoder *ctx = (GL2Encoder*)self;
-    GLint hostLoc = ctx->m_shared->locationWARAppToHost(program, location);
+    GLint hostLoc = location;
     ctx->m_glProgramUniformMatrix3fv_enc(self, program, hostLoc, count, transpose, value);
 }
 
 void GL2Encoder::s_glProgramUniformMatrix3x2fv(void* self, GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
 {
     GL2Encoder *ctx = (GL2Encoder*)self;
-    GLint hostLoc = ctx->m_shared->locationWARAppToHost(program, location);
+    GLint hostLoc = location;
     ctx->m_glProgramUniformMatrix3x2fv_enc(self, program, hostLoc, count, transpose, value);
 }
 
 void GL2Encoder::s_glProgramUniformMatrix3x4fv(void* self, GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
 {
     GL2Encoder *ctx = (GL2Encoder*)self;
-    GLint hostLoc = ctx->m_shared->locationWARAppToHost(program, location);
+    GLint hostLoc = location;
     ctx->m_glProgramUniformMatrix3x4fv_enc(self, program, hostLoc, count, transpose, value);
 }
 
 void GL2Encoder::s_glProgramUniformMatrix4fv(void* self, GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
 {
     GL2Encoder *ctx = (GL2Encoder*)self;
-    GLint hostLoc = ctx->m_shared->locationWARAppToHost(program, location);
+    GLint hostLoc = location;
     ctx->m_glProgramUniformMatrix4fv_enc(self, program, hostLoc, count, transpose, value);
 }
 
 void GL2Encoder::s_glProgramUniformMatrix4x2fv(void* self, GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
 {
     GL2Encoder *ctx = (GL2Encoder*)self;
-    GLint hostLoc = ctx->m_shared->locationWARAppToHost(program, location);
+    GLint hostLoc = location;
     ctx->m_glProgramUniformMatrix4x2fv_enc(self, program, hostLoc, count, transpose, value);
 }
 
 void GL2Encoder::s_glProgramUniformMatrix4x3fv(void* self, GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
 {
     GL2Encoder *ctx = (GL2Encoder*)self;
-    GLint hostLoc = ctx->m_shared->locationWARAppToHost(program, location);
+    GLint hostLoc = location;
     ctx->m_glProgramUniformMatrix4x3fv_enc(self, program, hostLoc, count, transpose, value);
 }
 
@@ -5357,7 +5334,8 @@
     GLClientState* state = ctx->m_state;
 
     bool hasClientArrays = false;
-    ctx->getVBOUsage(&hasClientArrays, NULL);
+    bool hasVBOs = false;
+    ctx->getVBOUsage(&hasClientArrays, &hasVBOs);
 
     SET_ERROR_IF(hasClientArrays, GL_INVALID_OPERATION);
     SET_ERROR_IF(!state->currentVertexArrayObject(), GL_INVALID_OPERATION);
@@ -5383,7 +5361,8 @@
     GLClientState* state = ctx->m_state;
 
     bool hasClientArrays = false;
-    ctx->getVBOUsage(&hasClientArrays, NULL);
+    bool hasVBOs = false;
+    ctx->getVBOUsage(&hasClientArrays, &hasVBOs);
 
     SET_ERROR_IF(hasClientArrays, GL_INVALID_OPERATION);
     SET_ERROR_IF(!state->currentVertexArrayObject(), GL_INVALID_OPERATION);
diff --git a/system/GLESv2_enc/GL2Encoder.h b/system/GLESv2_enc/GL2Encoder.h
index c617a36..d016898 100644
--- a/system/GLESv2_enc/GL2Encoder.h
+++ b/system/GLESv2_enc/GL2Encoder.h
@@ -28,6 +28,12 @@
 public:
     GL2Encoder(IOStream *stream, ChecksumCalculator* protocol);
     virtual ~GL2Encoder();
+    void setDrawCallFlushInterval(uint32_t interval) {
+        m_drawCallFlushInterval = interval;
+    }
+    void setHasAsyncUnmapBuffer(int version) {
+        m_hasAsyncUnmapBuffer = version;
+    }
     void setNoHostError(bool noHostError) {
         m_noHostError = noHostError;
     }
@@ -98,6 +104,7 @@
     std::string m_currExtensions;
     std::vector<std::string> m_currExtensionsArray;
 
+    bool    m_hasAsyncUnmapBuffer;
     bool    m_initialized;
     bool    m_noHostError;
     GLClientState *m_state;
@@ -131,7 +138,8 @@
 
     FixedBuffer m_fixedBuffer;
 
-    int m_drawCallFlushCount;
+    uint32_t m_drawCallFlushInterval;
+    uint32_t m_drawCallFlushCount;
 
     bool m_primitiveRestartEnabled;
     GLuint m_primitiveRestartIndex;
diff --git a/system/GLESv2_enc/GLESv2Validation.cpp b/system/GLESv2_enc/GLESv2Validation.cpp
index 098091f..9f72853 100644
--- a/system/GLESv2_enc/GLESv2Validation.cpp
+++ b/system/GLESv2_enc/GLESv2Validation.cpp
@@ -731,6 +731,7 @@
     return false;
 }
 #define LIST_VALID_TEX_INTERNALFORMATS(f) \
+    f(GL_BGRA8_EXT) \
     f(GL_R8) \
     f(GL_R8_SNORM) \
     f(GL_R16F) \
diff --git a/system/GLESv2_enc/gl2_client_context.cpp b/system/GLESv2_enc/gl2_client_context.cpp
index c811b66..aaa0325 100644
--- a/system/GLESv2_enc/gl2_client_context.cpp
+++ b/system/GLESv2_enc/gl2_client_context.cpp
@@ -434,6 +434,8 @@
 	glDrawElementsNullAEMU = (glDrawElementsNullAEMU_client_proc_t) getProc("glDrawElementsNullAEMU", userData);
 	glDrawElementsOffsetNullAEMU = (glDrawElementsOffsetNullAEMU_client_proc_t) getProc("glDrawElementsOffsetNullAEMU", userData);
 	glDrawElementsDataNullAEMU = (glDrawElementsDataNullAEMU_client_proc_t) getProc("glDrawElementsDataNullAEMU", userData);
+	glUnmapBufferAsyncAEMU = (glUnmapBufferAsyncAEMU_client_proc_t) getProc("glUnmapBufferAsyncAEMU", userData);
+	glFlushMappedBufferRangeAEMU2 = (glFlushMappedBufferRangeAEMU2_client_proc_t) getProc("glFlushMappedBufferRangeAEMU2", userData);
 	return 0;
 }
 
diff --git a/system/GLESv2_enc/gl2_client_context.h b/system/GLESv2_enc/gl2_client_context.h
index ce0cf47..575395a 100644
--- a/system/GLESv2_enc/gl2_client_context.h
+++ b/system/GLESv2_enc/gl2_client_context.h
@@ -434,6 +434,8 @@
 	glDrawElementsNullAEMU_client_proc_t glDrawElementsNullAEMU;
 	glDrawElementsOffsetNullAEMU_client_proc_t glDrawElementsOffsetNullAEMU;
 	glDrawElementsDataNullAEMU_client_proc_t glDrawElementsDataNullAEMU;
+	glUnmapBufferAsyncAEMU_client_proc_t glUnmapBufferAsyncAEMU;
+	glFlushMappedBufferRangeAEMU2_client_proc_t glFlushMappedBufferRangeAEMU2;
 	virtual ~gl2_client_context_t() {}
 
 	typedef gl2_client_context_t *CONTEXT_ACCESSOR_TYPE(void);
diff --git a/system/GLESv2_enc/gl2_client_proc.h b/system/GLESv2_enc/gl2_client_proc.h
index dea6d12..615b123 100644
--- a/system/GLESv2_enc/gl2_client_proc.h
+++ b/system/GLESv2_enc/gl2_client_proc.h
@@ -436,6 +436,8 @@
 typedef void (gl2_APIENTRY *glDrawElementsNullAEMU_client_proc_t) (void * ctx, GLenum, GLsizei, GLenum, const GLvoid*);
 typedef void (gl2_APIENTRY *glDrawElementsOffsetNullAEMU_client_proc_t) (void * ctx, GLenum, GLsizei, GLenum, GLuint);
 typedef void (gl2_APIENTRY *glDrawElementsDataNullAEMU_client_proc_t) (void * ctx, GLenum, GLsizei, GLenum, void*, GLuint);
+typedef void (gl2_APIENTRY *glUnmapBufferAsyncAEMU_client_proc_t) (void * ctx, GLenum, GLintptr, GLsizeiptr, GLbitfield, void*, GLboolean*);
+typedef void (gl2_APIENTRY *glFlushMappedBufferRangeAEMU2_client_proc_t) (void * ctx, GLenum, GLintptr, GLsizeiptr, GLbitfield, void*);
 
 
 #endif
diff --git a/system/GLESv2_enc/gl2_enc.cpp b/system/GLESv2_enc/gl2_enc.cpp
index 17b3cba..0df93f8 100644
--- a/system/GLESv2_enc/gl2_enc.cpp
+++ b/system/GLESv2_enc/gl2_enc.cpp
@@ -11482,6 +11482,87 @@
 
 }
 
+void glUnmapBufferAsyncAEMU_enc(void *self , GLenum target, GLintptr offset, GLsizeiptr length, GLbitfield access, void* guest_buffer, GLboolean* out_res)
+{
+
+	gl2_encoder_context_t *ctx = (gl2_encoder_context_t *)self;
+	IOStream *stream = ctx->m_stream;
+	ChecksumCalculator *checksumCalculator = ctx->m_checksumCalculator;
+	bool useChecksum = checksumCalculator->getVersion() > 0;
+
+	const unsigned int __size_guest_buffer = ((guest_buffer != NULL) ?  length : 0);
+	const unsigned int __size_out_res =  (sizeof(GLboolean));
+	 unsigned char *ptr;
+	 unsigned char *buf;
+	 const size_t sizeWithoutChecksum = 8 + 4 + 4 + 4 + 4 + __size_guest_buffer + __size_out_res + 2*4;
+	 const size_t checksumSize = checksumCalculator->checksumByteSize();
+	 const size_t totalSize = sizeWithoutChecksum + checksumSize;
+	buf = stream->alloc(8 + 4 + 4 + 4 + 4);
+	ptr = buf;
+	int tmp = OP_glUnmapBufferAsyncAEMU;memcpy(ptr, &tmp, 4); ptr += 4;
+	memcpy(ptr, &totalSize, 4);  ptr += 4;
+
+		memcpy(ptr, &target, 4); ptr += 4;
+		memcpy(ptr, &offset, 4); ptr += 4;
+		memcpy(ptr, &length, 4); ptr += 4;
+		memcpy(ptr, &access, 4); ptr += 4;
+
+	if (useChecksum) checksumCalculator->addBuffer(buf, ptr-buf);
+	stream->flush();
+	stream->writeFully(&__size_guest_buffer,4);
+	if (useChecksum) checksumCalculator->addBuffer(&__size_guest_buffer,4);
+	if (guest_buffer != NULL) {
+		stream->writeFully(guest_buffer, __size_guest_buffer);
+		if (useChecksum) checksumCalculator->addBuffer(guest_buffer, __size_guest_buffer);
+	}
+	buf = stream->alloc(__size_out_res + 1*4);
+	ptr = buf;
+	*(unsigned int *)(ptr) = __size_out_res; ptr += 4;
+	memcpy(ptr, out_res, __size_out_res);ptr += __size_out_res;
+
+	if (useChecksum) checksumCalculator->addBuffer(buf, ptr-buf);
+	buf = stream->alloc(checksumSize);
+	if (useChecksum) checksumCalculator->writeChecksum(buf, checksumSize);
+
+}
+
+void glFlushMappedBufferRangeAEMU2_enc(void *self , GLenum target, GLintptr offset, GLsizeiptr length, GLbitfield access, void* guest_buffer)
+{
+
+	gl2_encoder_context_t *ctx = (gl2_encoder_context_t *)self;
+	IOStream *stream = ctx->m_stream;
+	ChecksumCalculator *checksumCalculator = ctx->m_checksumCalculator;
+	bool useChecksum = checksumCalculator->getVersion() > 0;
+
+	const unsigned int __size_guest_buffer = ((guest_buffer != NULL) ?  length : 0);
+	 unsigned char *ptr;
+	 unsigned char *buf;
+	 const size_t sizeWithoutChecksum = 8 + 4 + 4 + 4 + 4 + __size_guest_buffer + 1*4;
+	 const size_t checksumSize = checksumCalculator->checksumByteSize();
+	 const size_t totalSize = sizeWithoutChecksum + checksumSize;
+	buf = stream->alloc(8 + 4 + 4 + 4 + 4);
+	ptr = buf;
+	int tmp = OP_glFlushMappedBufferRangeAEMU2;memcpy(ptr, &tmp, 4); ptr += 4;
+	memcpy(ptr, &totalSize, 4);  ptr += 4;
+
+		memcpy(ptr, &target, 4); ptr += 4;
+		memcpy(ptr, &offset, 4); ptr += 4;
+		memcpy(ptr, &length, 4); ptr += 4;
+		memcpy(ptr, &access, 4); ptr += 4;
+
+	if (useChecksum) checksumCalculator->addBuffer(buf, ptr-buf);
+	stream->flush();
+	stream->writeFully(&__size_guest_buffer,4);
+	if (useChecksum) checksumCalculator->addBuffer(&__size_guest_buffer,4);
+	if (guest_buffer != NULL) {
+		stream->writeFully(guest_buffer, __size_guest_buffer);
+		if (useChecksum) checksumCalculator->addBuffer(guest_buffer, __size_guest_buffer);
+	}
+	buf = stream->alloc(checksumSize);
+	if (useChecksum) checksumCalculator->writeChecksum(buf, checksumSize);
+
+}
+
 }  // namespace
 
 gl2_encoder_context_t::gl2_encoder_context_t(IOStream *stream, ChecksumCalculator *checksumCalculator)
@@ -11913,5 +11994,7 @@
 	this->glDrawElementsNullAEMU = (glDrawElementsNullAEMU_client_proc_t) &enc_unsupported;
 	this->glDrawElementsOffsetNullAEMU = &glDrawElementsOffsetNullAEMU_enc;
 	this->glDrawElementsDataNullAEMU = &glDrawElementsDataNullAEMU_enc;
+	this->glUnmapBufferAsyncAEMU = &glUnmapBufferAsyncAEMU_enc;
+	this->glFlushMappedBufferRangeAEMU2 = &glFlushMappedBufferRangeAEMU2_enc;
 }
 
diff --git a/system/GLESv2_enc/gl2_enc.h b/system/GLESv2_enc/gl2_enc.h
index 4129b9d..3b175cd 100644
--- a/system/GLESv2_enc/gl2_enc.h
+++ b/system/GLESv2_enc/gl2_enc.h
@@ -19,7 +19,7 @@
 	ChecksumCalculator *m_checksumCalculator;
 
 	gl2_encoder_context_t(IOStream *stream, ChecksumCalculator *checksumCalculator);
-	virtual uint64_t lockAndWriteDma(void* data, uint32_t sz) { return 0; }
+	virtual uint64_t lockAndWriteDma(void*, uint32_t) { return 0; }
 };
 
 #endif  // GUARD_gl2_encoder_context_t
diff --git a/system/GLESv2_enc/gl2_entry.cpp b/system/GLESv2_enc/gl2_entry.cpp
index 69ce39d..a5d6c87 100644
--- a/system/GLESv2_enc/gl2_entry.cpp
+++ b/system/GLESv2_enc/gl2_entry.cpp
@@ -429,6 +429,8 @@
 	void glDrawElementsNullAEMU(GLenum mode, GLsizei count, GLenum type, const GLvoid* indices);
 	void glDrawElementsOffsetNullAEMU(GLenum mode, GLsizei count, GLenum type, GLuint offset);
 	void glDrawElementsDataNullAEMU(GLenum mode, GLsizei count, GLenum type, void* data, GLuint datalen);
+	void glUnmapBufferAsyncAEMU(GLenum target, GLintptr offset, GLsizeiptr length, GLbitfield access, void* guest_buffer, GLboolean* out_res);
+	void glFlushMappedBufferRangeAEMU2(GLenum target, GLintptr offset, GLsizeiptr length, GLbitfield access, void* guest_buffer);
 };
 
 #ifndef GET_CONTEXT
@@ -3018,3 +3020,15 @@
 	ctx->glDrawElementsDataNullAEMU(ctx, mode, count, type, data, datalen);
 }
 
+void glUnmapBufferAsyncAEMU(GLenum target, GLintptr offset, GLsizeiptr length, GLbitfield access, void* guest_buffer, GLboolean* out_res)
+{
+	GET_CONTEXT;
+	ctx->glUnmapBufferAsyncAEMU(ctx, target, offset, length, access, guest_buffer, out_res);
+}
+
+void glFlushMappedBufferRangeAEMU2(GLenum target, GLintptr offset, GLsizeiptr length, GLbitfield access, void* guest_buffer)
+{
+	GET_CONTEXT;
+	ctx->glFlushMappedBufferRangeAEMU2(ctx, target, offset, length, access, guest_buffer);
+}
+
diff --git a/system/GLESv2_enc/gl2_opcodes.h b/system/GLESv2_enc/gl2_opcodes.h
index 7628a2e..9c619e1 100644
--- a/system/GLESv2_enc/gl2_opcodes.h
+++ b/system/GLESv2_enc/gl2_opcodes.h
@@ -427,7 +427,9 @@
 #define OP_glDrawElementsNullAEMU 					2469
 #define OP_glDrawElementsOffsetNullAEMU 					2470
 #define OP_glDrawElementsDataNullAEMU 					2471
-#define OP_last 					2472
+#define OP_glUnmapBufferAsyncAEMU 					2472
+#define OP_glFlushMappedBufferRangeAEMU2 					2473
+#define OP_last 					2474
 
 
 #endif
diff --git a/system/OpenglSystemCommon/AddressSpaceStream.cpp b/system/OpenglSystemCommon/AddressSpaceStream.cpp
new file mode 100644
index 0000000..ce7c720
--- /dev/null
+++ b/system/OpenglSystemCommon/AddressSpaceStream.cpp
@@ -0,0 +1,550 @@
+/*
+* Copyright (C) 2011 The Android Open Source Project
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+#include "AddressSpaceStream.h"
+
+#if PLATFORM_SDK_VERSION < 26
+#include <cutils/log.h>
+#else
+#include <log/log.h>
+#endif
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+
+static const size_t kReadSize = 512 * 1024;
+static const size_t kWriteOffset = kReadSize;
+
+AddressSpaceStream* createAddressSpaceStream(size_t ignored_bufSize) {
+    // Ignore incoming ignored_bufSize
+    (void)ignored_bufSize;
+
+    auto handle = goldfish_address_space_open();
+    address_space_handle_t child_device_handle;
+
+    if (!goldfish_address_space_set_subdevice_type(handle, GoldfishAddressSpaceSubdeviceType::Graphics, &child_device_handle)) {
+        ALOGE("AddressSpaceStream::create failed (initial device create)\n");
+        goldfish_address_space_close(handle);
+        return nullptr;
+    }
+
+    struct goldfish_address_space_ping request;
+    request.metadata = ASG_GET_RING;
+    if (!goldfish_address_space_ping(child_device_handle, &request)) {
+        ALOGE("AddressSpaceStream::create failed (get ring)\n");
+        goldfish_address_space_close(child_device_handle);
+        return nullptr;
+    }
+
+    uint64_t ringOffset = request.metadata;
+
+    request.metadata = ASG_GET_BUFFER;
+    if (!goldfish_address_space_ping(child_device_handle, &request)) {
+        ALOGE("AddressSpaceStream::create failed (get buffer)\n");
+        goldfish_address_space_close(child_device_handle);
+        return nullptr;
+    }
+
+    uint64_t bufferOffset = request.metadata;
+    uint64_t bufferSize = request.size;
+
+    if (!goldfish_address_space_claim_shared(
+        child_device_handle, ringOffset, sizeof(asg_ring_storage))) {
+        ALOGE("AddressSpaceStream::create failed (claim ring storage)\n");
+        goldfish_address_space_close(child_device_handle);
+        return nullptr;
+    }
+
+    if (!goldfish_address_space_claim_shared(
+        child_device_handle, bufferOffset, bufferSize)) {
+        ALOGE("AddressSpaceStream::create failed (claim buffer storage)\n");
+        goldfish_address_space_unclaim_shared(child_device_handle, ringOffset);
+        goldfish_address_space_close(child_device_handle);
+        return nullptr;
+    }
+
+    char* ringPtr = (char*)goldfish_address_space_map(
+        child_device_handle, ringOffset, sizeof(struct asg_ring_storage));
+
+    if (!ringPtr) {
+        ALOGE("AddressSpaceStream::create failed (map ring storage)\n");
+        goldfish_address_space_unclaim_shared(child_device_handle, bufferOffset);
+        goldfish_address_space_unclaim_shared(child_device_handle, ringOffset);
+        goldfish_address_space_close(child_device_handle);
+        return nullptr;
+    }
+
+    char* bufferPtr = (char*)goldfish_address_space_map(
+        child_device_handle, bufferOffset, bufferSize);
+
+    if (!bufferPtr) {
+        ALOGE("AddressSpaceStream::create failed (map buffer storage)\n");
+        goldfish_address_space_unmap(ringPtr, sizeof(struct asg_ring_storage));
+        goldfish_address_space_unclaim_shared(child_device_handle, bufferOffset);
+        goldfish_address_space_unclaim_shared(child_device_handle, ringOffset);
+        goldfish_address_space_close(child_device_handle);
+        return nullptr;
+    }
+
+    struct asg_context context =
+        asg_context_create(
+            ringPtr, bufferPtr, bufferSize);
+
+    request.metadata = ASG_SET_VERSION;
+    request.size = 1; // version 1
+
+    if (!goldfish_address_space_ping(child_device_handle, &request)) {
+        ALOGE("AddressSpaceStream::create failed (get buffer)\n");
+        goldfish_address_space_unmap(bufferPtr, bufferSize);
+        goldfish_address_space_unmap(ringPtr, sizeof(struct asg_ring_storage));
+        goldfish_address_space_unclaim_shared(child_device_handle, bufferOffset);
+        goldfish_address_space_unclaim_shared(child_device_handle, ringOffset);
+        goldfish_address_space_close(child_device_handle);
+        return nullptr;
+    }
+
+    uint32_t version = request.size;
+
+    context.ring_config->transfer_mode = 1;
+    context.ring_config->host_consumed_pos = 0;
+    context.ring_config->guest_write_pos = 0;
+
+    AddressSpaceStream* res =
+        new AddressSpaceStream(
+            child_device_handle, version, context,
+            ringOffset, bufferOffset);
+
+    return res;
+}
+
+AddressSpaceStream::AddressSpaceStream(
+    address_space_handle_t handle,
+    uint32_t version,
+    struct asg_context context,
+    uint64_t ringOffset,
+    uint64_t writeBufferOffset) :
+    IOStream(context.ring_config->flush_interval),
+    m_tmpBuf(0),
+    m_tmpBufSize(0),
+    m_tmpBufXferSize(0),
+    m_usingTmpBuf(0),
+    m_readBuf(0),
+    m_read(0),
+    m_readLeft(0),
+    m_handle(handle),
+    m_version(version),
+    m_context(context),
+    m_ringOffset(ringOffset),
+    m_writeBufferOffset(writeBufferOffset),
+    m_writeBufferSize(context.ring_config->buffer_size),
+    m_writeBufferMask(m_writeBufferSize - 1),
+    m_buf((unsigned char*)context.buffer),
+    m_writeStart(m_buf),
+    m_writeStep(context.ring_config->flush_interval),
+    m_notifs(0),
+    m_written(0) {
+    // We'll use this in the future, but at the moment,
+    // it's a potential compile Werror.
+    (void)m_version;
+}
+
+AddressSpaceStream::~AddressSpaceStream() {
+    goldfish_address_space_unmap(m_context.to_host, sizeof(struct asg_ring_storage));
+    goldfish_address_space_unmap(m_context.buffer, m_writeBufferSize);
+    goldfish_address_space_unclaim_shared(m_handle, m_ringOffset);
+    goldfish_address_space_unclaim_shared(m_handle, m_writeBufferOffset);
+    goldfish_address_space_close(m_handle);
+    if (m_readBuf) free(m_readBuf);
+    if (m_tmpBuf) free(m_tmpBuf);
+}
+
+size_t AddressSpaceStream::idealAllocSize(size_t len) {
+    if (len > m_writeStep) return len;
+    return m_writeStep;
+}
+
+void *AddressSpaceStream::allocBuffer(size_t minSize) {
+    if (!m_readBuf) {
+        m_readBuf = (unsigned char*)malloc(kReadSize);
+    }
+
+    size_t allocSize =
+        (m_writeStep < minSize ? minSize : m_writeStep);
+
+    if (m_writeStep < allocSize) {
+        if (!m_tmpBuf) {
+            m_tmpBufSize = allocSize * 2;
+            m_tmpBuf = (unsigned char*)malloc(m_tmpBufSize);
+        }
+
+        if (m_tmpBufSize < allocSize) {
+            m_tmpBufSize = allocSize * 2;
+            m_tmpBuf = (unsigned char*)realloc(m_tmpBuf, m_tmpBufSize);
+        }
+
+        if (!m_usingTmpBuf) {
+            flush();
+        }
+
+        m_usingTmpBuf = true;
+        m_tmpBufXferSize = allocSize;
+        return m_tmpBuf;
+    } else {
+        if (m_usingTmpBuf) {
+            writeFully(m_tmpBuf, m_tmpBufXferSize);
+            m_usingTmpBuf = false;
+            m_tmpBufXferSize = 0;
+        }
+
+        return m_writeStart;
+    }
+};
+
+int AddressSpaceStream::commitBuffer(size_t size)
+{
+    if (size == 0) return 0;
+
+    if (m_usingTmpBuf) {
+        writeFully(m_tmpBuf, size);
+        m_tmpBufXferSize = 0;
+        m_usingTmpBuf = false;
+        return 0;
+    } else {
+        int res = type1Write(m_writeStart - m_buf, size);
+        advanceWrite();
+        return res;
+    }
+}
+
+const unsigned char *AddressSpaceStream::readFully(void *ptr, size_t totalReadSize)
+{
+
+    unsigned char* userReadBuf = static_cast<unsigned char*>(ptr);
+
+    if (!userReadBuf) {
+        if (totalReadSize > 0) {
+            ALOGE("AddressSpaceStream::commitBufferAndReadFully failed, userReadBuf=NULL, totalReadSize %zu, lethal"
+                    " error, exiting.", totalReadSize);
+            abort();
+        }
+        return nullptr;
+    }
+
+    // Advance buffered read if not yet consumed.
+    size_t remaining = totalReadSize;
+    size_t bufferedReadSize =
+        m_readLeft < remaining ? m_readLeft : remaining;
+
+    if (bufferedReadSize) {
+        memcpy(userReadBuf,
+               m_readBuf + (m_read - m_readLeft),
+               bufferedReadSize);
+        remaining -= bufferedReadSize;
+        m_readLeft -= bufferedReadSize;
+    }
+
+    if (!remaining) return userReadBuf;
+
+    // Read up to kReadSize bytes if all buffered read has been consumed.
+    size_t maxRead = m_readLeft ? 0 : kReadSize;
+    ssize_t actual = 0;
+
+    if (maxRead) {
+        actual = speculativeRead(m_readBuf, maxRead);
+
+        // Updated buffered read size.
+        if (actual > 0) {
+            m_read = m_readLeft = actual;
+        }
+
+        if (actual == 0) {
+            ALOGD("%s: end of pipe", __FUNCTION__);
+            return NULL;
+        }
+    }
+
+    // Consume buffered read and read more if necessary.
+    while (remaining) {
+        bufferedReadSize = m_readLeft < remaining ? m_readLeft : remaining;
+        if (bufferedReadSize) {
+            memcpy(userReadBuf + (totalReadSize - remaining),
+                   m_readBuf + (m_read - m_readLeft),
+                   bufferedReadSize);
+            remaining -= bufferedReadSize;
+            m_readLeft -= bufferedReadSize;
+            continue;
+        }
+
+        actual = speculativeRead(m_readBuf, kReadSize);
+
+        if (actual == 0) {
+            ALOGD("%s: Failed reading from pipe: %d", __FUNCTION__,  errno);
+            return NULL;
+        }
+
+        if (actual > 0) {
+            m_read = m_readLeft = actual;
+            continue;
+        }
+    }
+
+    return userReadBuf;
+}
+
+const unsigned char *AddressSpaceStream::read(void *buf, size_t *inout_len) {
+    unsigned char* dst = (unsigned char*)buf;
+    size_t wanted = *inout_len;
+    ssize_t actual = speculativeRead(dst, wanted);
+
+    if (actual >= 0) {
+        *inout_len = actual;
+    } else {
+        return nullptr;
+    }
+
+    return (const unsigned char*)dst;
+}
+
+int AddressSpaceStream::writeFully(const void *buf, size_t size)
+{
+    ensureConsumerFinishing();
+    ensureType3Finished();
+    ensureType1Finished();
+
+    m_context.ring_config->transfer_size = size;
+    m_context.ring_config->transfer_mode = 3;
+
+    size_t sent = 0;
+    size_t quarterRingSize = m_writeBufferSize / 4;
+    size_t chunkSize = size < quarterRingSize ? size : quarterRingSize;
+    const uint8_t* bufferBytes = (const uint8_t*)buf;
+
+    while (sent < size) {
+        size_t remaining = size - sent;
+        size_t sendThisTime = remaining < chunkSize ? remaining : chunkSize;
+
+        long sentChunks =
+            ring_buffer_view_write(
+                m_context.to_host_large_xfer.ring,
+                &m_context.to_host_large_xfer.view,
+                bufferBytes + sent, sendThisTime, 1);
+
+        if (*(m_context.host_state) != ASG_HOST_STATE_CAN_CONSUME) {
+            notifyAvailable();
+        }
+
+        if (sentChunks == 0) {
+            ring_buffer_yield();
+        }
+
+        sent += sentChunks * sendThisTime;
+
+        if (isInError()) {
+            return -1;
+        }
+    }
+
+    ensureType3Finished();
+    m_context.ring_config->transfer_mode = 1;
+    m_written += size;
+    return 0;
+}
+
+const unsigned char *AddressSpaceStream::commitBufferAndReadFully(
+    size_t writeSize, void *userReadBufPtr, size_t totalReadSize) {
+
+    if (m_usingTmpBuf) {
+        writeFully(m_tmpBuf, writeSize);
+        m_usingTmpBuf = false;
+        m_tmpBufXferSize = 0;
+        return readFully(userReadBufPtr, totalReadSize);
+    } else {
+        commitBuffer(writeSize);
+        return readFully(userReadBufPtr, totalReadSize);
+    }
+}
+
+bool AddressSpaceStream::isInError() const {
+    return 1 == m_context.ring_config->in_error;
+}
+
+ssize_t AddressSpaceStream::speculativeRead(unsigned char* readBuffer, size_t trySize) {
+    ensureConsumerFinishing();
+    ensureType3Finished();
+    ensureType1Finished();
+
+    size_t actuallyRead = 0;
+    while (!actuallyRead) {
+        uint32_t readAvail =
+            ring_buffer_available_read(
+                m_context.from_host_large_xfer.ring,
+                &m_context.from_host_large_xfer.view);
+
+        if (!readAvail) {
+            ring_buffer_yield();
+            continue;
+        }
+
+        uint32_t toRead = readAvail > trySize ?  trySize : readAvail;
+
+        long stepsRead = ring_buffer_view_read(
+            m_context.from_host_large_xfer.ring,
+            &m_context.from_host_large_xfer.view,
+            readBuffer, toRead, 1);
+
+        actuallyRead += stepsRead * toRead;
+
+        if (isInError()) {
+            return -1;
+        }
+    }
+
+    return actuallyRead;
+}
+
+void AddressSpaceStream::notifyAvailable() {
+    struct goldfish_address_space_ping request;
+    request.metadata = ASG_NOTIFY_AVAILABLE;
+    goldfish_address_space_ping(m_handle, &request);
+    ++m_notifs;
+}
+
+uint32_t AddressSpaceStream::getRelativeBufferPos(uint32_t pos) {
+    return pos & m_writeBufferMask;
+}
+
+void AddressSpaceStream::advanceWrite() {
+    m_writeStart += m_context.ring_config->flush_interval;
+
+    if (m_writeStart == m_buf + m_context.ring_config->buffer_size) {
+        m_writeStart = m_buf;
+    }
+}
+
+void AddressSpaceStream::ensureConsumerFinishing() {
+    uint32_t currAvailRead = ring_buffer_available_read(m_context.to_host, 0);
+
+    while (currAvailRead) {
+        ring_buffer_yield();
+        uint32_t nextAvailRead = ring_buffer_available_read(m_context.to_host, 0);
+
+        if (nextAvailRead != currAvailRead) {
+            break;
+        }
+
+        if (*(m_context.host_state) != ASG_HOST_STATE_CAN_CONSUME) {
+            notifyAvailable();
+            break;
+        }
+    }
+}
+
+void AddressSpaceStream::ensureType1Finished() {
+    ensureConsumerFinishing();
+
+    uint32_t currAvailRead =
+        ring_buffer_available_read(m_context.to_host, 0);
+
+    while (currAvailRead) {
+        ring_buffer_yield();
+        currAvailRead = ring_buffer_available_read(m_context.to_host, 0);
+        if (isInError()) {
+            return;
+        }
+    }
+}
+
+void AddressSpaceStream::ensureType3Finished() {
+    uint32_t availReadLarge =
+        ring_buffer_available_read(
+            m_context.to_host_large_xfer.ring,
+            &m_context.to_host_large_xfer.view);
+    while (availReadLarge) {
+        ring_buffer_yield();
+        availReadLarge =
+            ring_buffer_available_read(
+                m_context.to_host_large_xfer.ring,
+                &m_context.to_host_large_xfer.view);
+        if (*(m_context.host_state) != ASG_HOST_STATE_CAN_CONSUME) {
+            notifyAvailable();
+        }
+        if (isInError()) {
+            return;
+        }
+    }
+}
+
+int AddressSpaceStream::type1Write(uint32_t bufferOffset, size_t size) {
+    size_t sent = 0;
+    size_t sizeForRing = sizeof(struct asg_type1_xfer);
+
+    struct asg_type1_xfer xfer = {
+        bufferOffset,
+        (uint32_t)size,
+    };
+
+    uint8_t* writeBufferBytes = (uint8_t*)(&xfer);
+
+    uint32_t maxOutstanding = 1;
+    uint32_t maxSteps = m_context.ring_config->buffer_size /
+            m_context.ring_config->flush_interval;
+
+    if (maxSteps > 1) maxOutstanding = maxSteps >> 1;
+
+    uint32_t ringAvailReadNow = ring_buffer_available_read(m_context.to_host, 0);
+
+    while (ringAvailReadNow >= maxOutstanding) {
+        ensureConsumerFinishing();
+        ring_buffer_yield();
+        ringAvailReadNow = ring_buffer_available_read(m_context.to_host, 0);
+    }
+
+    while (sent < sizeForRing) {
+
+        long sentChunks = ring_buffer_write(
+            m_context.to_host,
+            writeBufferBytes + sent,
+            sizeForRing - sent, 1);
+
+        if (*(m_context.host_state) != ASG_HOST_STATE_CAN_CONSUME) {
+            notifyAvailable();
+        }
+
+        if (sentChunks == 0) {
+            ring_buffer_yield();
+        }
+
+        sent += sentChunks * (sizeForRing - sent);
+
+        if (isInError()) {
+            return -1;
+        }
+    }
+
+    ensureConsumerFinishing();
+    m_written += size;
+
+    float mb = (float)m_written / 1048576.0f;
+    if (mb > 100.0f) {
+        ALOGD("%s: %f mb in %d notifs. %f mb/notif\n", __func__,
+              mb, m_notifs, m_notifs ? mb / (float)m_notifs : 0.0f);
+        m_notifs = 0;
+        m_written = 0;
+    }
+
+    return 0;
+}
diff --git a/system/OpenglSystemCommon/AddressSpaceStream.h b/system/OpenglSystemCommon/AddressSpaceStream.h
new file mode 100644
index 0000000..a4db5aa
--- /dev/null
+++ b/system/OpenglSystemCommon/AddressSpaceStream.h
@@ -0,0 +1,83 @@
+/*
+* Copyright (C) 2011 The Android Open Source Project
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+#ifndef __ADDRESS_SPACE_STREAM_H
+#define __ADDRESS_SPACE_STREAM_H
+
+#include "IOStream.h"
+
+#include "address_space_graphics_types.h"
+#include "goldfish_address_space.h"
+
+class AddressSpaceStream;
+
+AddressSpaceStream* createAddressSpaceStream(size_t bufSize);
+
+class AddressSpaceStream : public IOStream {
+public:
+    explicit AddressSpaceStream(
+        address_space_handle_t handle,
+        uint32_t version,
+        struct asg_context context,
+        uint64_t ringOffset,
+        uint64_t writeBufferOffset);
+    ~AddressSpaceStream();
+
+    virtual size_t idealAllocSize(size_t len);
+    virtual void *allocBuffer(size_t minSize);
+    virtual int commitBuffer(size_t size);
+    virtual const unsigned char *readFully( void *buf, size_t len);
+    virtual const unsigned char *read( void *buf, size_t *inout_len);
+    virtual int writeFully(const void *buf, size_t len);
+    virtual const unsigned char *commitBufferAndReadFully(size_t size, void *buf, size_t len);
+
+private:
+    bool isInError() const;
+    ssize_t speculativeRead(unsigned char* readBuffer, size_t trySize);
+    void notifyAvailable();
+    uint32_t getRelativeBufferPos(uint32_t pos);
+    void advanceWrite();
+    void ensureConsumerFinishing();
+    void ensureType1Finished();
+    void ensureType3Finished();
+    int type1Write(uint32_t offset, size_t size);
+
+    unsigned char* m_tmpBuf;
+    size_t m_tmpBufSize;
+    size_t m_tmpBufXferSize;
+    bool m_usingTmpBuf;
+
+    unsigned char* m_readBuf;
+    size_t m_read;
+    size_t m_readLeft;
+
+    address_space_handle_t m_handle;
+    uint32_t m_version;
+    struct asg_context m_context;
+
+    uint64_t m_ringOffset;
+    uint64_t m_writeBufferOffset;
+
+    uint32_t m_writeBufferSize;
+    uint32_t m_writeBufferMask;
+    unsigned char* m_buf;
+    unsigned char* m_writeStart;
+    uint32_t m_writeStep;
+
+    uint32_t m_notifs;
+    uint32_t m_written;
+};
+
+#endif
diff --git a/system/OpenglSystemCommon/Android.mk b/system/OpenglSystemCommon/Android.mk
index f29901e..bb9e14f 100644
--- a/system/OpenglSystemCommon/Android.mk
+++ b/system/OpenglSystemCommon/Android.mk
@@ -3,16 +3,19 @@
 $(call emugl-begin-shared-library,libOpenglSystemCommon)
 $(call emugl-import,libGLESv1_enc libGLESv2_enc lib_renderControl_enc)
 
-ifeq (true,$(BUILD_EMULATOR_VULKAN))
-$(call emugl-import,libvulkan_enc)
-endif
-
 LOCAL_SRC_FILES := \
     FormatConversions.cpp \
     HostConnection.cpp \
     QemuPipeStream.cpp \
     ProcessPipe.cpp    \
 
+ifeq (true,$(BUILD_EMULATOR_VULKAN))
+$(call emugl-import,libvulkan_enc)
+
+LOCAL_SRC_FILES += AddressSpaceStream.cpp
+
+endif
+
 LOCAL_CFLAGS += -Wno-unused-variable -Wno-unused-parameter
 
 ifeq (true,$(GOLDFISH_OPENGL_BUILD_FOR_HOST))
@@ -26,6 +29,14 @@
 
 LOCAL_HEADER_LIBRARIES += vulkan_headers
 
+LOCAL_CFLAGS += -DVIRTIO_GPU
+LOCAL_SRC_FILES += \
+    VirtioGpuStream.cpp \
+    VirtioGpuPipeStream.cpp \
+
+LOCAL_C_INCLUDES += external/libdrm external/minigbm/cros_gralloc
+LOCAL_SHARED_LIBRARIES += libdrm
+
 endif
 
 LOCAL_SRC_FILES += \
@@ -33,13 +44,6 @@
 
 endif
 
-ifneq ($(filter virgl, $(BOARD_GPU_DRIVERS)),)
-LOCAL_CFLAGS += -DVIRTIO_GPU
-LOCAL_SRC_FILES += VirtioGpuStream.cpp
-LOCAL_C_INCLUDES += external/libdrm external/minigbm/cros_gralloc
-LOCAL_SHARED_LIBRARIES += libdrm
-endif
-
 ifdef IS_AT_LEAST_OPD1
 LOCAL_HEADER_LIBRARIES += libnativebase_headers
 
@@ -51,7 +55,9 @@
 $(call emugl-export,HEADER_LIBRARIES,libhardware_headers)
 endif
 
+$(call emugl-export,C_INCLUDES,$(LOCAL_PATH)/bionic-include)
 $(call emugl-export,C_INCLUDES,$(LOCAL_PATH) bionic/libc/private)
+$(call emugl-export,C_INCLUDES,$(LOCAL_PATH) bionic/libc/platform)
 
 ifeq (true,$(GOLDFISH_OPENGL_BUILD_FOR_HOST))
 $(call emugl-export,SHARED_LIBRARIES,android-emu-shared)
diff --git a/system/OpenglSystemCommon/CMakeLists.txt b/system/OpenglSystemCommon/CMakeLists.txt
index 28e4075..7feb903 100644
--- a/system/OpenglSystemCommon/CMakeLists.txt
+++ b/system/OpenglSystemCommon/CMakeLists.txt
@@ -1,10 +1,10 @@
 # This is an autogenerated file! Do not edit!
 # instead run make from .../device/generic/goldfish-opengl
 # which will re-generate this file.
-android_validate_sha256("${GOLDFISH_DEVICE_ROOT}/system/OpenglSystemCommon/Android.mk" "5ee7d71d6652a9dae3d1de93b9ff1ac36a26a40193aa8d2604965c766d2ed8ab")
-set(OpenglSystemCommon_src FormatConversions.cpp HostConnection.cpp QemuPipeStream.cpp ProcessPipe.cpp ThreadInfo_host.cpp)
-android_add_shared_library(OpenglSystemCommon)
-target_include_directories(OpenglSystemCommon PRIVATE ${GOLDFISH_DEVICE_ROOT}/system/OpenglSystemCommon ${GOLDFISH_DEVICE_ROOT}/bionic/libc/private ${GOLDFISH_DEVICE_ROOT}/system/vulkan_enc ${GOLDFISH_DEVICE_ROOT}/android-emu ${GOLDFISH_DEVICE_ROOT}/system/renderControl_enc ${GOLDFISH_DEVICE_ROOT}/system/GLESv2_enc ${GOLDFISH_DEVICE_ROOT}/system/GLESv1_enc ${GOLDFISH_DEVICE_ROOT}/shared/OpenglCodecCommon ${GOLDFISH_DEVICE_ROOT}/./host/include/libOpenglRender ${GOLDFISH_DEVICE_ROOT}/./system/include ${GOLDFISH_DEVICE_ROOT}/./../../../external/qemu/android/android-emugl/guest)
+android_validate_sha256("${GOLDFISH_DEVICE_ROOT}/system/OpenglSystemCommon/Android.mk" "6fedb15afaabb2c4e6cd24123f711639d6574b47356b2fa626a668bb497b8977")
+set(OpenglSystemCommon_src FormatConversions.cpp HostConnection.cpp QemuPipeStream.cpp ProcessPipe.cpp AddressSpaceStream.cpp ThreadInfo_host.cpp)
+android_add_library(TARGET OpenglSystemCommon SHARED LICENSE Apache-2.0 SRC FormatConversions.cpp HostConnection.cpp QemuPipeStream.cpp ProcessPipe.cpp AddressSpaceStream.cpp ThreadInfo_host.cpp)
+target_include_directories(OpenglSystemCommon PRIVATE ${GOLDFISH_DEVICE_ROOT}/system/OpenglSystemCommon ${GOLDFISH_DEVICE_ROOT}/bionic/libc/platform ${GOLDFISH_DEVICE_ROOT}/bionic/libc/private ${GOLDFISH_DEVICE_ROOT}/system/OpenglSystemCommon/bionic-include ${GOLDFISH_DEVICE_ROOT}/system/vulkan_enc ${GOLDFISH_DEVICE_ROOT}/android-emu ${GOLDFISH_DEVICE_ROOT}/system/renderControl_enc ${GOLDFISH_DEVICE_ROOT}/system/GLESv2_enc ${GOLDFISH_DEVICE_ROOT}/system/GLESv1_enc ${GOLDFISH_DEVICE_ROOT}/shared/OpenglCodecCommon ${GOLDFISH_DEVICE_ROOT}/./host/include/libOpenglRender ${GOLDFISH_DEVICE_ROOT}/./system/include ${GOLDFISH_DEVICE_ROOT}/./../../../external/qemu/android/android-emugl/guest)
 target_compile_definitions(OpenglSystemCommon PRIVATE "-DWITH_GLES2" "-DPLATFORM_SDK_VERSION=29" "-DGOLDFISH_HIDL_GRALLOC" "-DEMULATOR_OPENGL_POST_O=1" "-DHOST_BUILD" "-DANDROID" "-DGL_GLEXT_PROTOTYPES" "-DPAGE_SIZE=4096" "-DGOLDFISH_VULKAN")
-target_compile_options(OpenglSystemCommon PRIVATE "-fvisibility=default")
-target_link_libraries(OpenglSystemCommon PRIVATE android-emu-shared vulkan_enc gui cutils utils log _renderControl_enc GLESv2_enc GLESv1_enc OpenglCodecCommon_host)
\ No newline at end of file
+target_compile_options(OpenglSystemCommon PRIVATE "-fvisibility=default" "-Wno-unused-parameter" "-Wno-unused-variable")
+target_link_libraries(OpenglSystemCommon PRIVATE android-emu-shared vulkan_enc gui androidemu cutils utils log _renderControl_enc GLESv2_enc GLESv1_enc OpenglCodecCommon_host)
\ No newline at end of file
diff --git a/system/OpenglSystemCommon/EmulatorFeatureInfo.h b/system/OpenglSystemCommon/EmulatorFeatureInfo.h
index 518273a..4edf1fd 100644
--- a/system/OpenglSystemCommon/EmulatorFeatureInfo.h
+++ b/system/OpenglSystemCommon/EmulatorFeatureInfo.h
@@ -26,15 +26,16 @@
 // capability, and we will use a fence fd to synchronize buffer swaps.
 enum SyncImpl {
     SYNC_IMPL_NONE = 0,
-    SYNC_IMPL_NATIVE_SYNC_V2 = 1,
-    SYNC_IMPL_NATIVE_SYNC_V3 = 2,
+    SYNC_IMPL_NATIVE_SYNC_V2 = 1, // ANDROID_native_fence_sync
+    SYNC_IMPL_NATIVE_SYNC_V3 = 2, // KHR_wait_sync
+    SYNC_IMPL_NATIVE_SYNC_V4 = 3, // Correct eglGetSyncAttribKHR
 };
 
-// Interface:
-// Use the highest of v2 or v3 that show up, making us
-// SYNC_IMPL_NATIVE_SYNC_V2 or SYNC_IMPL_NATIVE_SYNC_V3.
+// Interface for native sync:
+// Use the highest that shows up
 static const char kRCNativeSyncV2[] = "ANDROID_EMU_native_sync_v2";
 static const char kRCNativeSyncV3[] = "ANDROID_EMU_native_sync_v3";
+static const char kRCNativeSyncV4[] = "ANDROID_EMU_native_sync_v4";
 
 // DMA for OpenGL
 enum DmaImpl {
@@ -60,9 +61,11 @@
 enum HostComposition {
     HOST_COMPOSITION_NONE = 0,
     HOST_COMPOSITION_V1,
+    HOST_COMPOSITION_V2,
 };
 
 static const char kHostCompositionV1[] = "ANDROID_EMU_host_composition_v1";
+static const char kHostCompositionV2[] = "ANDROID_EMU_host_composition_v2";
 
 // No querying errors from host extension
 static const char kGLESNoHostError[] = "ANDROID_EMU_gles_no_host_error";
@@ -79,6 +82,24 @@
 // Deferred Vulkan commands
 static const char kDeferredVulkanCommands[] = "ANDROID_EMU_deferred_vulkan_commands";
 
+// Vulkan null optional strings
+static const char kVulkanNullOptionalStrings[] = "ANDROID_EMU_vulkan_null_optional_strings";
+
+// Vulkan create resources with requirements
+static const char kVulkanCreateResourcesWithRequirements[] = "ANDROID_EMU_vulkan_create_resources_with_requirements";
+
+// Vulkan ignored handles
+static const char kVulkanIgnoredHandles[] = "ANDROID_EMU_vulkan_ignored_handles";
+
+// YUV host cache
+static const char kYUVCache[] = "ANDROID_EMU_YUV_Cache";
+
+// GL protocol v2
+static const char kAsyncUnmapBuffer[] = "ANDROID_EMU_async_unmap_buffer";
+
+// virtio-gpu-next
+static const char kVirtioGpuNext[] = "ANDROID_EMU_virtio_gpu_next";
+
 // Struct describing available emulator features
 struct EmulatorFeatureInfo {
 
@@ -89,7 +110,13 @@
         glesMaxVersion(GLES_MAX_VERSION_2),
         hasDirectMem(false),
         hasVulkan(false),
-        hasDeferredVulkanCommands(false) { }
+        hasDeferredVulkanCommands(false),
+        hasVulkanNullOptionalStrings(false),
+        hasVulkanCreateResourcesWithRequirements(false),
+        hasVulkanIgnoredHandles(false),
+        hasYUVCache (false),
+        hasAsyncUnmapBuffer (false),
+        hasVirtioGpuNext (false) { }
 
     SyncImpl syncImpl;
     DmaImpl dmaImpl;
@@ -98,6 +125,26 @@
     bool hasDirectMem;
     bool hasVulkan;
     bool hasDeferredVulkanCommands;
+    bool hasVulkanNullOptionalStrings;
+    bool hasVulkanCreateResourcesWithRequirements;
+    bool hasVulkanIgnoredHandles;
+    bool hasYUVCache;
+    bool hasAsyncUnmapBuffer;
+    bool hasVirtioGpuNext;
+};
+
+enum HostConnectionType {
+    HOST_CONNECTION_TCP = 0,
+    HOST_CONNECTION_QEMU_PIPE = 1,
+    HOST_CONNECTION_VIRTIO_GPU = 2,
+    HOST_CONNECTION_ADDRESS_SPACE = 3,
+    HOST_CONNECTION_VIRTIO_GPU_PIPE = 4,
+};
+
+enum GrallocType {
+    GRALLOC_TYPE_RANCHU = 0,
+    GRALLOC_TYPE_MINIGBM = 1,
+    GRALLOC_TYPE_DYN_ALLOC_MINIGBM = 2,
 };
 
 #endif // __COMMON_EMULATOR_FEATURE_INFO_H
diff --git a/system/OpenglSystemCommon/FormatConversions.cpp b/system/OpenglSystemCommon/FormatConversions.cpp
index 53f0e83..ca4286c 100644
--- a/system/OpenglSystemCommon/FormatConversions.cpp
+++ b/system/OpenglSystemCommon/FormatConversions.cpp
@@ -12,6 +12,7 @@
  *
  */
 
+#include <hardware/gralloc.h>
 #include "FormatConversions.h"
 
 #if PLATFORM_SDK_VERSION < 26
@@ -20,6 +21,7 @@
 #include <log/log.h>
 #endif
 #include <string.h>
+#include <stdio.h>
 
 #define DEBUG 0
 
@@ -33,6 +35,18 @@
     return row * width * rgbStride;
 }
 
+bool gralloc_is_yuv_format(const int format) {
+    switch (format) {
+    case HAL_PIXEL_FORMAT_YV12:
+    case HAL_PIXEL_FORMAT_YCbCr_420_888:
+    case HAL_PIXEL_FORMAT_YCrCb_420_SP:
+        return true;
+
+    default:
+        return false;
+    }
+}
+
 void get_yv12_offsets(int width, int height,
                              uint32_t* yStride_out,
                              uint32_t* cStride_out,
@@ -79,7 +93,6 @@
     int align = 16;
     int yStride = (width + (align -1)) & ~(align-1);
     int cStride = (yStride / 2 + (align - 1)) & ~(align-1);
-    int yOffset = 0;
     int cSize = cStride * height/2;
 
     uint16_t *rgb_ptr0 = (uint16_t *)src;
@@ -90,7 +103,7 @@
         uint8_t *yv12_y = yv12_y0 + j * yStride;
         uint8_t *yv12_v = yv12_v0 + (j/2) * cStride;
         uint8_t *yv12_u = yv12_v + cSize;
-        uint16_t *rgb_ptr = rgb_ptr0 + get_rgb_offset(j, width, rgb_stride);
+        uint16_t *rgb_ptr = rgb_ptr0 + get_rgb_offset(j, width, rgb_stride) / 2;
         bool jeven = (j & 1) == 0;
         for (int i = left; i <= right; ++i) {
             uint8_t r = ((rgb_ptr[i]) >> 11) & 0x01f;
@@ -121,18 +134,31 @@
     int align = 16;
     int yStride = (width + (align -1)) & ~(align-1);
     int cStride = (yStride / 2 + (align - 1)) & ~(align-1);
-    int yOffset = 0;
     int cSize = cStride * height/2;
 
 
     uint8_t *rgb_ptr0 = (uint8_t *)src;
     uint8_t *yv12_y0 = (uint8_t *)dest;
+    uint8_t *yv12_u0 = yv12_y0 + yStride * height + cSize;
     uint8_t *yv12_v0 = yv12_y0 + yStride * height;
 
+#if DEBUG
+    char mybuf[1024];
+    snprintf(mybuf, sizeof(mybuf), "/sdcard/raw_%d_%d_rgb.ppm", width, height);
+    FILE *myfp = fopen(mybuf, "wb"); /* b - binary mode */
+    (void) fprintf(myfp, "P6\n%d %d\n255\n", width, height);
+
+    if (myfp == NULL) {
+        DD("failed to open /sdcard/raw_rgb888.ppm");
+    } else {
+        fwrite(rgb_ptr0, width * height * rgb_stride, 1, myfp);
+        fclose(myfp);
+    }
+#endif
+
+    int uvcount = 0;
     for (int j = top; j <= bottom; ++j) {
         uint8_t *yv12_y = yv12_y0 + j * yStride;
-        uint8_t *yv12_v = yv12_v0 + (j/2) * cStride;
-        uint8_t *yv12_u = yv12_v + cSize;
         uint8_t *rgb_ptr = rgb_ptr0 + get_rgb_offset(j, width, rgb_stride);
         bool jeven = (j & 1) == 0;
         for (int i = left; i <= right; ++i) {
@@ -140,15 +166,32 @@
             uint8_t G = rgb_ptr[i*rgb_stride+1];
             uint8_t B = rgb_ptr[i*rgb_stride+2];
             // convert to YV12
-            // frameworks/base/core/jni/android_hardware_camera2_legacy_LegacyCameraDevice.cpp
-            yv12_y[i] = clamp_rgb((77 * R + 150 * G +  29 * B) >> 8);
+            // https://en.wikipedia.org/wiki/YCbCr#ITU-R_BT.601_conversion
+            // but scale up U by 1/0.96
+            yv12_y[i] = clamp_rgb(1.0 * ((0.25678823529411765 * R) + (0.5041294117647058 * G) + (0.09790588235294118 * B)) + 16);
             bool ieven = (i & 1) == 0;
             if (jeven && ieven) {
-                yv12_u[i] = clamp_rgb((( -43 * R - 85 * G + 128 * B) >> 8) + 128);
-                yv12_v[i] = clamp_rgb((( 128 * R - 107 * G - 21 * B) >> 8) + 128);
+                yv12_u0[uvcount] = clamp_rgb((1/0.96) * (-(0.1482235294117647 * R) - (0.2909921568627451 * G) + (0.4392156862745098 * B)) + 128);
+                yv12_v0[uvcount] = clamp_rgb((1.0)* ((0.4392156862745098 * R) - (0.36778823529411764 * G) - (0.07142745098039215 * B)) + 128);
+                uvcount ++;
             }
         }
+        if (jeven) {
+            yv12_u0 += cStride;
+            yv12_v0 += cStride;
+            uvcount = 0;
+        }
     }
+
+#if DEBUG
+    snprintf(mybuf, sizeof(mybuf), "/sdcard/raw_%d_%d_yv12.yuv", width, height);
+    FILE *yuvfp = fopen(mybuf, "wb"); /* b - binary mode */
+    if (yuvfp != NULL) {
+        fwrite(yv12_y0, yStride * height + 2 * cSize, 1, yuvfp);
+        fclose(yuvfp);
+    }
+#endif
+
 }
 
 void rgb888_to_yuv420p(char* dest, char* src, int width, int height,
@@ -158,7 +201,6 @@
     DD("%s convert %d by %d", __func__, width, height);
     int yStride = width;
     int cStride = yStride / 2;
-    int yOffset = 0;
     int cSize = cStride * height/2;
 
     uint8_t *rgb_ptr0 = (uint8_t *)src;
@@ -186,6 +228,7 @@
         }
     }
 }
+
 // YV12 is aka YUV420Planar, or YUV420p; the only difference is that YV12 has
 // certain stride requirements for Y and UV respectively.
 void yv12_to_rgb565(char* dest, char* src, int width, int height,
@@ -196,7 +239,6 @@
     int align = 16;
     int yStride = (width + (align -1)) & ~(align-1);
     int cStride = (yStride / 2 + (align - 1)) & ~(align-1);
-    int yOffset = 0;
     int cSize = cStride * height/2;
 
     uint16_t *rgb_ptr0 = (uint16_t *)dest;
@@ -242,7 +284,6 @@
     int align = 16;
     int yStride = (width + (align -1)) & ~(align-1);
     int cStride = (yStride / 2 + (align - 1)) & ~(align-1);
-    int yOffset = 0;
     int cSize = cStride * height/2;
 
     uint8_t *rgb_ptr0 = (uint8_t *)dest;
@@ -256,20 +297,15 @@
         uint8_t *rgb_ptr = rgb_ptr0 + get_rgb_offset(j - top, right - left + 1, rgb_stride);
         for (int i = left; i <= right; ++i) {
             // convert to rgb
-            // frameworks/av/media/libstagefright/colorconversion/ColorConverter.cpp
+            // https://en.wikipedia.org/wiki/YCbCr#ITU-R_BT.601_conversion
+            // but scale down U by 0.96 to mitigate rgb over/under flow
             signed y1 = (signed)yv12_y[i] - 16;
             signed u = (signed)yv12_u[i / 2] - 128;
             signed v = (signed)yv12_v[i / 2] - 128;
 
-            signed u_b = u * 517;
-            signed u_g = -u * 100;
-            signed v_g = -v * 208;
-            signed v_r = v * 409;
-
-            signed tmp1 = y1 * 298;
-            signed b1 = clamp_rgb((tmp1 + u_b) / 256);
-            signed g1 = clamp_rgb((tmp1 + v_g + u_g) / 256);
-            signed r1 = clamp_rgb((tmp1 + v_r) / 256);
+            signed r1 = clamp_rgb(1 * (1.1643835616438356 * y1 + 1.5960267857142856 * v));
+            signed g1 = clamp_rgb(1 * (1.1643835616438356 * y1 - 0.39176229009491365 * u * 0.97  - 0.8129676472377708 * v));
+            signed b1 = clamp_rgb(1 * (1.1643835616438356 * y1 + 2.017232142857143 * u * 0.97));
 
             rgb_ptr[(i-left)*rgb_stride] = r1;
             rgb_ptr[(i-left)*rgb_stride+1] = g1;
@@ -287,7 +323,6 @@
     DD("%s convert %d by %d", __func__, width, height);
     int yStride = width;
     int cStride = yStride / 2;
-    int yOffset = 0;
     int cSize = cStride * height/2;
 
     uint8_t *rgb_ptr0 = (uint8_t *)dest;
@@ -324,14 +359,13 @@
 }
 
 void copy_rgb_buffer_from_unlocked(
-        char* _dst, char* raw_data,
+        char* dst, const char* raw_data,
         int unlockedWidth,
         int width, int height, int top, int left,
         int bpp) {
-    char* dst = _dst;
     int dst_line_len = width * bpp;
     int src_line_len = unlockedWidth * bpp;
-    char *src = (char *)raw_data + top*src_line_len + left*bpp;
+    const char *src = raw_data + top*src_line_len + left*bpp;
     for (int y = 0; y < height; y++) {
         memcpy(dst, src, dst_line_len);
         src += src_line_len;
diff --git a/system/OpenglSystemCommon/FormatConversions.h b/system/OpenglSystemCommon/FormatConversions.h
index 6e15f36..f9d7806 100644
--- a/system/OpenglSystemCommon/FormatConversions.h
+++ b/system/OpenglSystemCommon/FormatConversions.h
@@ -18,6 +18,8 @@
 #include <inttypes.h>
 
 // format conversions and helper functions
+bool gralloc_is_yuv_format(int format); // e.g. HAL_PIXEL_FORMAT_YCbCr_420_888
+
 void get_yv12_offsets(int width, int height,
                       uint32_t* yStride_out,
                       uint32_t* cStride_out,
@@ -39,7 +41,7 @@
                     int left, int top, int right, int bottom);
 void yuv420p_to_rgb888(char* dest, char* src, int width, int height,
                        int left, int top, int right, int bottom);
-void copy_rgb_buffer_from_unlocked(char* _dst, char* raw_data,
+void copy_rgb_buffer_from_unlocked(char* _dst, const char* raw_data,
                                    int unlockedWidth,
                                    int width, int height, int top, int left,
                                    int bpp);
diff --git a/system/OpenglSystemCommon/HostConnection.cpp b/system/OpenglSystemCommon/HostConnection.cpp
index b6d465c..bbe2857 100644
--- a/system/OpenglSystemCommon/HostConnection.cpp
+++ b/system/OpenglSystemCommon/HostConnection.cpp
@@ -15,6 +15,8 @@
 */
 #include "HostConnection.h"
 
+#include "cutils/properties.h"
+
 #ifdef GOLDFISH_NO_GL
 struct gl_client_context_t {
     int placeholder;
@@ -32,6 +34,8 @@
     GL2Encoder(IOStream*, ChecksumCalculator*) { }
     void setContextAccessor(gl2_client_context_t *()) { }
     void setNoHostError(bool) { }
+    void setDrawCallFlushInterval(uint32_t) { }
+    void setHasAsyncUnmapBuffer(int) { }
 };
 #else
 #include "GLEncoder.h"
@@ -40,6 +44,7 @@
 
 #ifdef GOLDFISH_VULKAN
 #include "VkEncoder.h"
+#include "AddressSpaceStream.h"
 #else
 namespace goldfish_vk {
 struct VkEncoder {
@@ -47,6 +52,12 @@
     int placeholder;
 };
 } // namespace goldfish_vk
+class QemuPipeStream;
+typedef QemuPipeStream AddressSpaceStream;
+AddressSpaceStream* createAddressSpaceStream(size_t bufSize) {
+    ALOGE("%s: FATAL: Trying to create ASG stream in unsupported build\n", __func__);
+    abort();
+}
 #endif
 
 using goldfish_vk::VkEncoder;
@@ -59,9 +70,18 @@
 #include "gralloc_cb.h"
 
 #ifdef VIRTIO_GPU
+
 #include "VirtioGpuStream.h"
+#include "VirtioGpuPipeStream.h"
+
+#include <cros_gralloc_handle.h>
+#include <drm/virtgpu_drm.h>
+#include <xf86drm.h>
+
 #endif
 
+#undef LOG_TAG
+#define LOG_TAG "HostConnection"
 #if PLATFORM_SDK_VERSION < 26
 #include <cutils/log.h>
 #else
@@ -71,32 +91,255 @@
 #define STREAM_BUFFER_SIZE  (4*1024*1024)
 #define STREAM_PORT_NUM     22468
 
-enum HostConnectionType {
-    HOST_CONNECTION_TCP = 0,
-    HOST_CONNECTION_QEMU_PIPE = 1,
-    HOST_CONNECTION_VIRTIO_GPU = 2,
-};
+static HostConnectionType getConnectionTypeFromProperty() {
+#ifdef __Fuchsia__
+    return HOST_CONNECTION_ADDRESS_SPACE;
+#else
+    char transportValue[PROPERTY_VALUE_MAX] = "";
+    property_get("ro.kernel.qemu.gltransport", transportValue, "");
+
+    bool isValid = transportValue[0] != '\0';
+
+    if (!isValid) {
+        property_get("ro.boot.hardware.gltransport", transportValue, "");
+        isValid = transportValue[0] != '\0';
+    }
+
+    if (!isValid) return HOST_CONNECTION_QEMU_PIPE;
+
+    if (!strcmp("tcp", transportValue)) return HOST_CONNECTION_TCP;
+    if (!strcmp("pipe", transportValue)) return HOST_CONNECTION_QEMU_PIPE;
+    if (!strcmp("virtio-gpu", transportValue)) return HOST_CONNECTION_VIRTIO_GPU;
+    if (!strcmp("asg", transportValue)) return HOST_CONNECTION_ADDRESS_SPACE;
+    if (!strcmp("virtio-gpu-pipe", transportValue)) return HOST_CONNECTION_VIRTIO_GPU_PIPE;
+
+    return HOST_CONNECTION_QEMU_PIPE;
+#endif
+}
+
+static uint32_t getDrawCallFlushIntervalFromProperty() {
+    char flushValue[PROPERTY_VALUE_MAX] = "";
+    property_get("ro.kernel.qemu.gltransport.drawFlushInterval", flushValue, "");
+
+    bool isValid = flushValue[0] != '\0';
+    if (!isValid) return 800;
+
+    long interval = strtol(flushValue, 0, 10);
+
+    if (!interval) return 800;
+
+    return (uint32_t)interval;
+}
+
+static GrallocType getGrallocTypeFromProperty() {
+    char prop[PROPERTY_VALUE_MAX] = "";
+    property_get("ro.hardware.gralloc", prop, "");
+
+    bool isValid = prop[0] != '\0';
+
+    if (!isValid) return GRALLOC_TYPE_RANCHU;
+
+    if (!strcmp("ranchu", prop)) return GRALLOC_TYPE_RANCHU;
+    if (!strcmp("minigbm", prop)) return GRALLOC_TYPE_MINIGBM;
+    return GRALLOC_TYPE_RANCHU;
+}
 
 class GoldfishGralloc : public Gralloc
 {
 public:
-    uint32_t getHostHandle(native_handle_t const* handle)
-    {
-        return ((cb_handle_t *)handle)->hostHandle;
+    virtual uint32_t createColorBuffer(
+        ExtendedRCEncoderContext* rcEnc,
+        int width, int height, uint32_t glformat) {
+        return rcEnc->rcCreateColorBuffer(
+            rcEnc, width, height, glformat);
     }
 
-    int getFormat(native_handle_t const* handle)
+    virtual uint32_t getHostHandle(native_handle_t const* handle)
     {
-        return ((cb_handle_t *)handle)->format;
+        return cb_handle_t::from(handle)->hostHandle;
+    }
+
+    virtual int getFormat(native_handle_t const* handle)
+    {
+        return cb_handle_t::from(handle)->format;
+    }
+
+    virtual size_t getAllocatedSize(native_handle_t const* handle)
+    {
+        return static_cast<size_t>(cb_handle_t::from(handle)->allocatedSize());
     }
 };
 
+static inline uint32_t align_up(uint32_t n, uint32_t a) {
+    return ((n + a - 1) / a) * a;
+}
+
+#ifdef VIRTIO_GPU
+
+class MinigbmGralloc : public Gralloc {
+public:
+    virtual uint32_t createColorBuffer(
+        ExtendedRCEncoderContext*,
+        int width, int height, uint32_t glformat) {
+
+        // Only supported format for pbuffers in gfxstream
+        // should be RGBA8
+        const uint32_t kGlRGB = 0x1907;
+        const uint32_t kGlRGBA = 0x1908;
+        const uint32_t kVirglFormatRGBA = 67; // VIRGL_FORMAT_R8G8B8A8_UNORM;
+        uint32_t virtgpu_format = 0;
+        uint32_t bpp = 0;
+        switch (glformat) {
+            case kGlRGB:
+                ALOGD("Note: egl wanted GL_RGB, still using RGBA");
+                virtgpu_format = kVirglFormatRGBA;
+                bpp = 4;
+                break;
+            case kGlRGBA:
+                virtgpu_format = kVirglFormatRGBA;
+                bpp = 4;
+                break;
+            default:
+                ALOGD("Note: egl wanted 0x%x, still using RGBA", glformat);
+                virtgpu_format = kVirglFormatRGBA;
+                bpp = 4;
+                break;
+        }
+        const uint32_t kPipeTexture2D = 2; // PIPE_TEXTURE_2D
+        const uint32_t kBindRenderTarget = 1 << 1; // VIRGL_BIND_RENDER_TARGET
+        struct drm_virtgpu_resource_create res_create;
+        memset(&res_create, 0, sizeof(res_create));
+        res_create.target = kPipeTexture2D;
+        res_create.format = virtgpu_format;
+        res_create.bind = kBindRenderTarget;
+        res_create.width = width;
+        res_create.height = height;
+        res_create.depth = 1;
+        res_create.array_size = 1;
+        res_create.last_level = 0;
+        res_create.nr_samples = 0;
+        res_create.stride = bpp * width;
+        res_create.size = align_up(bpp * width * height, PAGE_SIZE);
+
+        int ret = drmIoctl(m_fd, DRM_IOCTL_VIRTGPU_RESOURCE_CREATE, &res_create);
+        if (ret) {
+            ALOGE("%s: DRM_IOCTL_VIRTGPU_RESOURCE_CREATE failed with %s (%d)\n", __func__,
+                  strerror(errno), errno);
+            abort();
+        }
+
+        return res_create.res_handle;
+    }
+
+    virtual uint32_t getHostHandle(native_handle_t const* handle) {
+        struct drm_virtgpu_resource_info info;
+        if (!getResInfo(handle, &info)) {
+            ALOGE("%s: failed to get resource info\n", __func__);
+            return 0;
+        }
+
+        return info.res_handle;
+    }
+
+    virtual int getFormat(native_handle_t const* handle) {
+        return ((cros_gralloc_handle *)handle)->droid_format;
+    }
+
+    virtual size_t getAllocatedSize(native_handle_t const* handle) {
+        struct drm_virtgpu_resource_info info;
+        if (!getResInfo(handle, &info)) {
+            ALOGE("%s: failed to get resource info\n", __func__);
+            return 0;
+        }
+
+        return info.size;
+    }
+
+    void setFd(int fd) { m_fd = fd; }
+
+private:
+
+    bool getResInfo(native_handle_t const* handle,
+                    struct drm_virtgpu_resource_info* info) {
+        memset(info, 0x0, sizeof(*info));
+        if (m_fd < 0) {
+            ALOGE("%s: Error, rendernode fd missing\n", __func__);
+            return false;
+        }
+
+        struct drm_gem_close gem_close;
+        memset(&gem_close, 0x0, sizeof(gem_close));
+
+        cros_gralloc_handle const* cros_handle =
+            reinterpret_cast<cros_gralloc_handle const*>(handle);
+
+        uint32_t prime_handle;
+        int ret = drmPrimeFDToHandle(m_fd, cros_handle->fds[0], &prime_handle);
+        if (ret) {
+            ALOGE("%s: DRM_IOCTL_PRIME_FD_TO_HANDLE failed: %s (errno %d)\n",
+                  __func__, strerror(errno), errno);
+            return false;
+        }
+
+        info->bo_handle = prime_handle;
+        gem_close.handle = prime_handle;
+
+        ret = drmIoctl(m_fd, DRM_IOCTL_VIRTGPU_RESOURCE_INFO, info);
+        if (ret) {
+            ALOGE("%s: DRM_IOCTL_VIRTGPU_RESOURCE_INFO failed: %s (errno %d)\n",
+                  __func__, strerror(errno), errno);
+            drmIoctl(m_fd, DRM_IOCTL_GEM_CLOSE, &gem_close);
+            return false;
+        }
+
+        drmIoctl(m_fd, DRM_IOCTL_GEM_CLOSE, &gem_close);
+        return true;
+    }
+
+    int m_fd = -1;
+};
+
+#else
+
+class MinigbmGralloc : public Gralloc {
+public:
+    virtual uint32_t createColorBuffer(
+        ExtendedRCEncoderContext*,
+        int width, int height, uint32_t glformat) {
+        ALOGE("%s: Error: using minigbm without -DVIRTIO_GPU\n", __func__);
+        return 0;
+    }
+
+    virtual uint32_t getHostHandle(native_handle_t const* handle) {
+        ALOGE("%s: Error: using minigbm without -DVIRTIO_GPU\n", __func__);
+        return 0;
+    }
+
+    virtual int getFormat(native_handle_t const* handle) {
+        ALOGE("%s: Error: using minigbm without -DVIRTIO_GPU\n", __func__);
+        return 0;
+    }
+
+    virtual size_t getAllocatedSize(native_handle_t const* handle) {
+        ALOGE("%s: Error: using minigbm without -DVIRTIO_GPU\n", __func__);
+        return 0;
+    }
+
+    void setFd(int fd) { m_fd = fd; }
+
+private:
+
+    int m_fd = -1;
+};
+
+#endif
+
 class GoldfishProcessPipe : public ProcessPipe
 {
 public:
-    bool processPipeInit(renderControl_encoder_context_t *rcEnc)
+    bool processPipeInit(HostConnectionType connType, renderControl_encoder_context_t *rcEnc)
     {
-        return ::processPipeInit(rcEnc);
+        return ::processPipeInit(connType, rcEnc);
     }
 };
 
@@ -112,12 +355,18 @@
     m_checksumHelper(),
     m_glExtensions(),
     m_grallocOnly(true),
-    m_noHostError(false)
-{
-}
+    m_noHostError(false) { }
 
 HostConnection::~HostConnection()
 {
+    // round-trip to ensure that queued commands have been processed
+    // before process pipe closure is detected.
+    if (m_rcEnc) {
+        (void) m_rcEnc->rcGetRendererVersion(m_rcEnc);
+    }
+    if (m_grallocType == GRALLOC_TYPE_MINIGBM) {
+        delete m_grallocHelper;
+    }
     delete m_stream;
     delete m_glEnc;
     delete m_gl2Enc;
@@ -128,10 +377,24 @@
 HostConnection* HostConnection::connect(HostConnection* con) {
     if (!con) return con;
 
-    const enum HostConnectionType connType = HOST_CONNECTION_VIRTIO_GPU;
+    const enum HostConnectionType connType = getConnectionTypeFromProperty();
+    // const enum HostConnectionType connType = HOST_CONNECTION_VIRTIO_GPU;
 
     switch (connType) {
-        default:
+        case HOST_CONNECTION_ADDRESS_SPACE: {
+            AddressSpaceStream *stream = createAddressSpaceStream(STREAM_BUFFER_SIZE);
+            if (!stream) {
+                ALOGE("Failed to create AddressSpaceStream for host connection!!!\n");
+                delete con;
+                return NULL;
+            }
+            con->m_connectionType = HOST_CONNECTION_ADDRESS_SPACE;
+            con->m_grallocType = GRALLOC_TYPE_RANCHU;
+            con->m_stream = stream;
+            con->m_grallocHelper = &m_goldfishGralloc;
+            con->m_processPipe = &m_goldfishProcessPipe;
+            break;
+        }
         case HOST_CONNECTION_QEMU_PIPE: {
             QemuPipeStream *stream = new QemuPipeStream(STREAM_BUFFER_SIZE);
             if (!stream) {
@@ -145,12 +408,20 @@
                 delete con;
                 return NULL;
             }
+            con->m_connectionType = HOST_CONNECTION_QEMU_PIPE;
+            con->m_grallocType = GRALLOC_TYPE_RANCHU;
             con->m_stream = stream;
             con->m_grallocHelper = &m_goldfishGralloc;
             con->m_processPipe = &m_goldfishProcessPipe;
             break;
         }
         case HOST_CONNECTION_TCP: {
+#ifdef __Fuchsia__
+            ALOGE("Fuchsia doesn't support HOST_CONNECTION_TCP!!!\n");
+            delete con;
+            return NULL;
+            break;
+#else
             TcpStream *stream = new TcpStream(STREAM_BUFFER_SIZE);
             if (!stream) {
                 ALOGE("Failed to create TcpStream for host connection!!!\n");
@@ -164,10 +435,13 @@
                 delete con;
                 return NULL;
             }
+            con->m_connectionType = HOST_CONNECTION_TCP;
+            con->m_grallocType = GRALLOC_TYPE_RANCHU;
             con->m_stream = stream;
             con->m_grallocHelper = &m_goldfishGralloc;
             con->m_processPipe = &m_goldfishProcessPipe;
             break;
+#endif
         }
 #ifdef VIRTIO_GPU
         case HOST_CONNECTION_VIRTIO_GPU: {
@@ -183,11 +457,51 @@
                 delete con;
                 return NULL;
             }
+            con->m_connectionType = HOST_CONNECTION_VIRTIO_GPU;
+            con->m_grallocType = GRALLOC_TYPE_MINIGBM;
             con->m_stream = stream;
-            con->m_grallocHelper = stream->getGralloc();
+            MinigbmGralloc* m = new MinigbmGralloc;
+            m->setFd(stream->getRendernodeFd());
+            con->m_grallocHelper = m;
             con->m_processPipe = stream->getProcessPipe();
             break;
         }
+        case HOST_CONNECTION_VIRTIO_GPU_PIPE: {
+            VirtioGpuPipeStream *stream = new VirtioGpuPipeStream(STREAM_BUFFER_SIZE);
+            if (!stream) {
+                ALOGE("Failed to create VirtioGpu for host connection!!!\n");
+                delete con;
+                return NULL;
+            }
+            if (stream->connect() < 0) {
+                ALOGE("Failed to connect to host (VirtioGpu)!!!\n");
+                delete stream;
+                delete con;
+                return NULL;
+            }
+            con->m_connectionType = HOST_CONNECTION_VIRTIO_GPU_PIPE;
+            con->m_grallocType = getGrallocTypeFromProperty();
+            con->m_stream = stream;
+            switch (con->m_grallocType) {
+                case GRALLOC_TYPE_RANCHU:
+                    con->m_grallocHelper = &m_goldfishGralloc;
+                    break;
+                case GRALLOC_TYPE_MINIGBM: {
+                    MinigbmGralloc* m = new MinigbmGralloc;
+                    m->setFd(stream->getRendernodeFd());
+                    con->m_grallocHelper = m;
+                    break;
+                }
+                default:
+                    ALOGE("Fatal: Unknown gralloc type 0x%x\n", con->m_grallocType);
+                    abort();
+            }
+            con->m_processPipe = &m_goldfishProcessPipe;
+            break;
+        }
+#else
+        default:
+            break;
 #endif
     }
 
@@ -199,6 +513,8 @@
 
     ALOGD("HostConnection::get() New Host Connection established %p, tid %d\n",
           con, getCurrentThreadId());
+
+    // ALOGD("Address space echo latency check done\n");
     return con;
 }
 
@@ -207,10 +523,6 @@
 }
 
 HostConnection *HostConnection::getWithThreadInfo(EGLThreadInfo* tinfo) {
-
-    /* TODO: Make this configurable with a system property */
-    const enum HostConnectionType connType = HOST_CONNECTION_VIRTIO_GPU;
-
     // Get thread info
     if (!tinfo) {
         return NULL;
@@ -238,7 +550,7 @@
     }
 }
 
-// static 
+// static
 HostConnection *HostConnection::createUnique() {
     ALOGD("%s: call\n", __func__);
     return connect(new HostConnection());
@@ -268,6 +580,9 @@
             m_gl2Enc, getCurrentThreadId());
         m_gl2Enc->setContextAccessor(s_getGL2Context);
         m_gl2Enc->setNoHostError(m_noHostError);
+        m_gl2Enc->setDrawCallFlushInterval(
+            getDrawCallFlushIntervalFromProperty());
+        m_gl2Enc->setHasAsyncUnmapBuffer(m_rcEnc->hasAsyncUnmapBuffer());
     }
     return m_gl2Enc;
 }
@@ -292,8 +607,15 @@
         queryAndSetHostCompositionImpl(m_rcEnc);
         queryAndSetDirectMemSupport(m_rcEnc);
         queryAndSetVulkanSupport(m_rcEnc);
+        queryAndSetDeferredVulkanCommandsSupport(m_rcEnc);
+        queryAndSetVulkanNullOptionalStringsSupport(m_rcEnc);
+        queryAndSetVulkanCreateResourcesWithRequirementsSupport(m_rcEnc);
+        queryAndSetVulkanIgnoredHandles(m_rcEnc);
+        queryAndSetYUVCache(m_rcEnc);
+        queryAndSetAsyncUnmapBuffer(m_rcEnc);
+        queryAndSetVirtioGpuNext(m_rcEnc);
         if (m_processPipe) {
-            m_processPipe->processPipeInit(m_rcEnc);
+            m_processPipe->processPipeInit(m_connectionType, m_rcEnc);
         }
     }
     return m_rcEnc;
@@ -348,7 +670,11 @@
 void HostConnection::queryAndSetHostCompositionImpl(ExtendedRCEncoderContext *rcEnc) {
     const std::string& glExtensions = queryGLExtensions(rcEnc);
     ALOGD("HostComposition ext %s", glExtensions.c_str());
-    if (glExtensions.find(kHostCompositionV1) != std::string::npos) {
+    // make sure V2 is checked first before V1, as host may declare supporting both
+    if (glExtensions.find(kHostCompositionV2) != std::string::npos) {
+        rcEnc->setHostComposition(HOST_COMPOSITION_V2);
+    }
+    else if (glExtensions.find(kHostCompositionV1) != std::string::npos) {
         rcEnc->setHostComposition(HOST_COMPOSITION_V1);
     }
     else {
@@ -380,7 +706,9 @@
 #if PLATFORM_SDK_VERSION <= 16 || (!defined(__i386__) && !defined(__x86_64__))
     rcEnc->setSyncImpl(SYNC_IMPL_NONE);
 #else
-    if (glExtensions.find(kRCNativeSyncV3) != std::string::npos) {
+    if (glExtensions.find(kRCNativeSyncV4) != std::string::npos) {
+        rcEnc->setSyncImpl(SYNC_IMPL_NATIVE_SYNC_V4);
+    } else if (glExtensions.find(kRCNativeSyncV3) != std::string::npos) {
         rcEnc->setSyncImpl(SYNC_IMPL_NATIVE_SYNC_V3);
     } else if (glExtensions.find(kRCNativeSyncV2) != std::string::npos) {
         rcEnc->setSyncImpl(SYNC_IMPL_NATIVE_SYNC_V2);
@@ -447,3 +775,45 @@
         rcEnc->featureInfo()->hasDeferredVulkanCommands = true;
     }
 }
+
+void HostConnection::queryAndSetVulkanNullOptionalStringsSupport(ExtendedRCEncoderContext* rcEnc) {
+    std::string glExtensions = queryGLExtensions(rcEnc);
+    if (glExtensions.find(kVulkanNullOptionalStrings) != std::string::npos) {
+        rcEnc->featureInfo()->hasVulkanNullOptionalStrings = true;
+    }
+}
+
+void HostConnection::queryAndSetVulkanCreateResourcesWithRequirementsSupport(ExtendedRCEncoderContext* rcEnc) {
+    std::string glExtensions = queryGLExtensions(rcEnc);
+    if (glExtensions.find(kVulkanCreateResourcesWithRequirements) != std::string::npos) {
+        rcEnc->featureInfo()->hasVulkanCreateResourcesWithRequirements = true;
+    }
+}
+
+void HostConnection::queryAndSetVulkanIgnoredHandles(ExtendedRCEncoderContext* rcEnc) {
+    std::string glExtensions = queryGLExtensions(rcEnc);
+    if (glExtensions.find(kVulkanIgnoredHandles) != std::string::npos) {
+        rcEnc->featureInfo()->hasVulkanIgnoredHandles = true;
+    }
+}
+
+void HostConnection::queryAndSetYUVCache(ExtendedRCEncoderContext* rcEnc) {
+    std::string glExtensions = queryGLExtensions(rcEnc);
+    if (glExtensions.find(kYUVCache) != std::string::npos) {
+        rcEnc->featureInfo()->hasYUVCache = true;
+    }
+}
+
+void HostConnection::queryAndSetAsyncUnmapBuffer(ExtendedRCEncoderContext* rcEnc) {
+    std::string glExtensions = queryGLExtensions(rcEnc);
+    if (glExtensions.find(kAsyncUnmapBuffer) != std::string::npos) {
+        rcEnc->featureInfo()->hasAsyncUnmapBuffer = true;
+    }
+}
+
+void HostConnection::queryAndSetVirtioGpuNext(ExtendedRCEncoderContext* rcEnc) {
+    std::string glExtensions = queryGLExtensions(rcEnc);
+    if (glExtensions.find(kVirtioGpuNext) != std::string::npos) {
+        rcEnc->featureInfo()->hasVirtioGpuNext = true;
+    }
+}
diff --git a/system/OpenglSystemCommon/HostConnection.h b/system/OpenglSystemCommon/HostConnection.h
index 922c35c..c91af0b 100644
--- a/system/OpenglSystemCommon/HostConnection.h
+++ b/system/OpenglSystemCommon/HostConnection.h
@@ -47,20 +47,34 @@
 public:
     ExtendedRCEncoderContext(IOStream *stream, ChecksumCalculator *checksumCalculator)
         : renderControl_encoder_context_t(stream, checksumCalculator),
-          m_dmaCxt(NULL) { }
+          m_dmaCxt(NULL), m_dmaPtr(NULL), m_dmaPhysAddr(0) { }
     void setSyncImpl(SyncImpl syncImpl) { m_featureInfo.syncImpl = syncImpl; }
     void setDmaImpl(DmaImpl dmaImpl) { m_featureInfo.dmaImpl = dmaImpl; }
     void setHostComposition(HostComposition hostComposition) {
         m_featureInfo.hostComposition = hostComposition; }
     bool hasNativeSync() const { return m_featureInfo.syncImpl >= SYNC_IMPL_NATIVE_SYNC_V2; }
     bool hasNativeSyncV3() const { return m_featureInfo.syncImpl >= SYNC_IMPL_NATIVE_SYNC_V3; }
+    bool hasNativeSyncV4() const { return m_featureInfo.syncImpl >= SYNC_IMPL_NATIVE_SYNC_V4; }
     bool hasHostCompositionV1() const {
         return m_featureInfo.hostComposition == HOST_COMPOSITION_V1; }
+    bool hasHostCompositionV2() const {
+        return m_featureInfo.hostComposition == HOST_COMPOSITION_V2; }
+    bool hasYUVCache() const {
+        return m_featureInfo.hasYUVCache; }
+    bool hasAsyncUnmapBuffer() const {
+        return m_featureInfo.hasAsyncUnmapBuffer; }
     DmaImpl getDmaVersion() const { return m_featureInfo.dmaImpl; }
     void bindDmaContext(struct goldfish_dma_context* cxt) { m_dmaCxt = cxt; }
+    void bindDmaDirectly(void* dmaPtr, uint64_t dmaPhysAddr) {
+        m_dmaPtr = dmaPtr;
+        m_dmaPhysAddr = dmaPhysAddr;
+    }
     virtual uint64_t lockAndWriteDma(void* data, uint32_t size) {
-        if (m_dmaCxt) {
-            return lockAndWriteGoldfishDma(data, size, m_dmaCxt);
+        if (m_dmaPtr && m_dmaPhysAddr) {
+            memcpy(m_dmaPtr, data, size);
+            return m_dmaPhysAddr;
+        } else if (m_dmaCxt) {
+            return writeGoldfishDma(data, size, m_dmaCxt);
         } else {
             ALOGE("%s: ERROR: No DMA context bound!", __func__);
             return 0;
@@ -68,12 +82,20 @@
     }
     void setGLESMaxVersion(GLESMaxVersion ver) { m_featureInfo.glesMaxVersion = ver; }
     GLESMaxVersion getGLESMaxVersion() const { return m_featureInfo.glesMaxVersion; }
+    bool hasDirectMem() const {
+#ifdef HOST_BUILD
+        // unit tests do not support restoring "guest" ram because there is no VM
+        return false;
+#else
+        return m_featureInfo.hasDirectMem;
+#endif
+    }
 
     const EmulatorFeatureInfo* featureInfo_const() const { return &m_featureInfo; }
     EmulatorFeatureInfo* featureInfo() { return &m_featureInfo; }
 private:
-    static uint64_t lockAndWriteGoldfishDma(void* data, uint32_t size,
-                                            struct goldfish_dma_context* dmaCxt) {
+    static uint64_t writeGoldfishDma(void* data, uint32_t size,
+                                     struct goldfish_dma_context* dmaCxt) {
         ALOGV("%s(data=%p, size=%u): call", __func__, data, size);
 
         goldfish_dma_write(dmaCxt, data, size);
@@ -85,25 +107,31 @@
 
     EmulatorFeatureInfo m_featureInfo;
     struct goldfish_dma_context* m_dmaCxt;
+    void* m_dmaPtr;
+    uint64_t m_dmaPhysAddr;
 };
 
 // Abstraction for gralloc handle conversion
 class Gralloc {
 public:
+    virtual uint32_t createColorBuffer(
+        ExtendedRCEncoderContext* rcEnc, int width, int height, uint32_t glformat);
     virtual uint32_t getHostHandle(native_handle_t const* handle) = 0;
     virtual int getFormat(native_handle_t const* handle) = 0;
+    virtual size_t getAllocatedSize(native_handle_t const* handle) = 0;
     virtual ~Gralloc() {}
 };
 
 // Abstraction for process pipe helper
 class ProcessPipe {
 public:
-    virtual bool processPipeInit(renderControl_encoder_context_t *rcEnc) = 0;
+    virtual bool processPipeInit(HostConnectionType connType, renderControl_encoder_context_t *rcEnc) = 0;
     virtual ~ProcessPipe() {}
 };
 
 struct EGLThreadInfo;
 
+
 class HostConnection
 {
 public:
@@ -116,6 +144,10 @@
 
     ~HostConnection();
 
+    HostConnectionType connectionType() const {
+        return m_connectionType;
+    }
+
     GLEncoder *glEncoder();
     GL2Encoder *gl2Encoder();
     goldfish_vk::VkEncoder *vkEncoder();
@@ -166,8 +198,16 @@
     void queryAndSetDirectMemSupport(ExtendedRCEncoderContext *rcEnc);
     void queryAndSetVulkanSupport(ExtendedRCEncoderContext *rcEnc);
     void queryAndSetDeferredVulkanCommandsSupport(ExtendedRCEncoderContext *rcEnc);
+    void queryAndSetVulkanNullOptionalStringsSupport(ExtendedRCEncoderContext *rcEnc);
+    void queryAndSetVulkanCreateResourcesWithRequirementsSupport(ExtendedRCEncoderContext *rcEnc);
+    void queryAndSetVulkanIgnoredHandles(ExtendedRCEncoderContext *rcEnc);
+    void queryAndSetYUVCache(ExtendedRCEncoderContext *mrcEnc);
+    void queryAndSetAsyncUnmapBuffer(ExtendedRCEncoderContext *rcEnc);
+    void queryAndSetVirtioGpuNext(ExtendedRCEncoderContext *rcEnc);
 
 private:
+    HostConnectionType m_connectionType;
+    GrallocType m_grallocType;
     IOStream *m_stream;
     GLEncoder   *m_glEnc;
     GL2Encoder  *m_gl2Enc;
diff --git a/system/OpenglSystemCommon/ProcessPipe.cpp b/system/OpenglSystemCommon/ProcessPipe.cpp
index ad0527a..40cb298 100644
--- a/system/OpenglSystemCommon/ProcessPipe.cpp
+++ b/system/OpenglSystemCommon/ProcessPipe.cpp
@@ -14,6 +14,7 @@
 * limitations under the License.
 */
 
+#include "ProcessPipe.h"
 #include "renderControl_enc.h"
 #include "qemu_pipe.h"
 
@@ -25,11 +26,26 @@
 #include <pthread.h>
 #include <errno.h>
 
+#ifdef __Fuchsia__
+#include <fuchsia/hardware/goldfish/cpp/fidl.h>
+#include <lib/zx/vmo.h>
+
+#include "services/service_connector.h"
+
+static QEMU_PIPE_HANDLE   sProcDevice = 0;
+#else // __Fuchsia__
+
+#include "VirtioGpuPipeStream.h"
+static VirtioGpuPipeStream* sVirtioGpuPipeStream = 0;
+
+#endif // !__Fuchsia__
+
 static QEMU_PIPE_HANDLE   sProcPipe = 0;
 static pthread_once_t     sProcPipeOnce = PTHREAD_ONCE_INIT;
 // sProcUID is a unique ID per process assigned by the host.
 // It is different from getpid().
 static uint64_t           sProcUID = 0;
+static volatile HostConnectionType sConnType = HOST_CONNECTION_VIRTIO_GPU_PIPE;
 
 // processPipeInitOnce is used to generate a process unique ID (puid).
 // processPipeInitOnce will only be called at most once per process.
@@ -38,7 +54,67 @@
 // It will fallback to the default path if the host does not support it.
 // Processes are identified by acquiring a per-process 64bit unique ID from the
 // host.
+#ifdef __Fuchsia__
 static void processPipeInitOnce() {
+    zx::channel channel(GetConnectToServiceFunction()(QEMU_PIPE_PATH));
+    if (!channel) {
+        ALOGE("%s: failed to open " QEMU_PIPE_PATH,
+              __FUNCTION__);
+        return;
+    }
+
+    fuchsia::hardware::goldfish::PipeDeviceSyncPtr device;
+    device.Bind(std::move(channel));
+
+    fuchsia::hardware::goldfish::PipeSyncPtr pipe;
+    device->OpenPipe(pipe.NewRequest());
+
+    zx_status_t status, status2 = ZX_OK;
+    zx::vmo vmo;
+    status = pipe->GetBuffer(&status2, &vmo);
+    if (status != ZX_OK || status2 != ZX_OK) {
+        ALOGE("%s: failed to get buffer: %d:%d", __FUNCTION__, status, status2);
+        return;
+    }
+
+    size_t len = strlen("pipe:GLProcessPipe");
+    status = vmo.write("pipe:GLProcessPipe", 0, len + 1);
+    if (status != ZX_OK) {
+        ALOGE("%s: failed write pipe name", __FUNCTION__);
+        return;
+    }
+    uint64_t actual;
+    status = pipe->Write(len + 1, 0, &status2, &actual);
+    if (status != ZX_OK || status2 != ZX_OK) {
+        ALOGD("%s: connecting to pipe service failed: %d:%d", __FUNCTION__,
+              status, status2);
+        return;
+    }
+
+    // Send a confirmation int to the host and get per-process unique ID back
+    int32_t confirmInt = 100;
+    status = vmo.write(&confirmInt, 0, sizeof(confirmInt));
+    if (status != ZX_OK) {
+        ALOGE("%s: failed write confirm int", __FUNCTION__);
+        return;
+    }
+    status = pipe->Call(sizeof(confirmInt), 0, sizeof(sProcUID), 0, &status2, &actual);
+    if (status != ZX_OK || status2 != ZX_OK) {
+        ALOGD("%s: failed to get per-process ID: %d:%d", __FUNCTION__,
+              status, status2);
+        return;
+    }
+    status = vmo.read(&sProcUID, 0, sizeof(sProcUID));
+    if (status != ZX_OK) {
+        ALOGE("%s: failed read per-process ID: %d", __FUNCTION__, status);
+        return;
+    }
+    sProcDevice = device.Unbind().TakeChannel().release();
+    sProcPipe = pipe.Unbind().TakeChannel().release();
+}
+#else // __Fuchsia__
+
+static void sQemuPipeInit() {
     sProcPipe = qemu_pipe_open("GLProcessPipe");
     if (!qemu_pipe_valid(sProcPipe)) {
         sProcPipe = 0;
@@ -66,7 +142,7 @@
         stat =
             qemu_pipe_read(sProcPipe, (char*)&sProcUID,
                 sizeof(sProcUID));
-    } while (stat < 0 && errno == EINTR);
+    } while (stat < 0 && (errno == EINTR || errno == EAGAIN));
 
     if (stat != sizeof(sProcUID)) {
         qemu_pipe_close(sProcPipe);
@@ -77,9 +153,36 @@
     }
 }
 
-bool processPipeInit(renderControl_encoder_context_t *rcEnc) {
+static void processPipeInitOnce() {
+#if defined(HOST_BUILD) || !defined(GOLDFISH_VULKAN)
+    sQemuPipeInit();
+#else // HOST_BUILD
+    switch (sConnType) {
+        // TODO: Move those over too
+        case HOST_CONNECTION_QEMU_PIPE:
+        case HOST_CONNECTION_ADDRESS_SPACE:
+        case HOST_CONNECTION_TCP:
+        case HOST_CONNECTION_VIRTIO_GPU:
+            sQemuPipeInit();
+            break;
+        case HOST_CONNECTION_VIRTIO_GPU_PIPE: {
+            sVirtioGpuPipeStream = new VirtioGpuPipeStream(4096);
+            sProcUID = sVirtioGpuPipeStream->initProcessPipe();
+            break;
+        }
+    }
+#endif // !HOST_BUILD
+}
+#endif // !__Fuchsia__
+
+bool processPipeInit(HostConnectionType connType, renderControl_encoder_context_t *rcEnc) {
+    sConnType = connType;
     pthread_once(&sProcPipeOnce, processPipeInitOnce);
-    if (!sProcPipe) return false;
+    bool pipeHandleInvalid = !sProcPipe;
+#ifndef __Fuchsia__
+    pipeHandleInvalid = pipeHandleInvalid && !sVirtioGpuPipeStream;
+#endif // !__Fuchsia__
+    if (pipeHandleInvalid) return false;
     rcEnc->rcSetPuid(rcEnc, sProcUID);
     return true;
 }
diff --git a/system/OpenglSystemCommon/ProcessPipe.h b/system/OpenglSystemCommon/ProcessPipe.h
index 66744b1..dea2a3f 100644
--- a/system/OpenglSystemCommon/ProcessPipe.h
+++ b/system/OpenglSystemCommon/ProcessPipe.h
@@ -13,9 +13,10 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 //
-
 #pragma once
 
+#include "EmulatorFeatureInfo.h"
+
 #include <stdint.h>
 
 // The process pipe is used to notify the host about process exits,
@@ -30,6 +31,6 @@
 //
 // This is called when creating rcEncoder.
 
-struct renderControl_client_context_t;
+struct renderControl_encoder_context_t;
 
-extern bool processPipeInit(renderControl_encoder_context_t *rcEnc);
+extern bool processPipeInit(HostConnectionType connType, renderControl_encoder_context_t *rcEnc);
diff --git a/system/OpenglSystemCommon/QemuPipeStream.cpp b/system/OpenglSystemCommon/QemuPipeStream.cpp
index fb515c9..57b60d1 100644
--- a/system/OpenglSystemCommon/QemuPipeStream.cpp
+++ b/system/OpenglSystemCommon/QemuPipeStream.cpp
@@ -26,11 +26,16 @@
 #include <unistd.h>
 #include <string.h>
 
+static const size_t kReadSize = 512 * 1024;
+static const size_t kWriteOffset = kReadSize;
+
 QemuPipeStream::QemuPipeStream(size_t bufSize) :
     IOStream(bufSize),
     m_sock((QEMU_PIPE_HANDLE)(-1)),
     m_bufsize(bufSize),
-    m_buf(NULL)
+    m_buf(NULL),
+    m_read(0),
+    m_readLeft(0)
 {
 }
 
@@ -38,7 +43,9 @@
     IOStream(bufSize),
     m_sock(sock),
     m_bufsize(bufSize),
-    m_buf(NULL)
+    m_buf(NULL),
+    m_read(0),
+    m_readLeft(0)
 {
 }
 
@@ -67,6 +74,9 @@
 
 void *QemuPipeStream::allocBuffer(size_t minSize)
 {
+    // Add dedicated read buffer space at the front of the buffer.
+    minSize += kReadSize;
+
     size_t allocSize = (m_bufsize < minSize ? minSize : m_bufsize);
     if (!m_buf) {
         m_buf = (unsigned char *)malloc(allocSize);
@@ -84,13 +94,13 @@
         }
     }
 
-    return m_buf;
+    return m_buf + kWriteOffset;
 };
 
 int QemuPipeStream::commitBuffer(size_t size)
 {
     if (size == 0) return 0;
-    return writeFully(m_buf, size);
+    return writeFully(m_buf + kWriteOffset, size);
 }
 
 int QemuPipeStream::writeFully(const void *buf, size_t len)
@@ -140,39 +150,96 @@
 
 const unsigned char *QemuPipeStream::readFully(void *buf, size_t len)
 {
-    //DBG(">> QemuPipeStream::readFully %d\n", len);
+    return commitBufferAndReadFully(0, buf, len);
+}
+
+const unsigned char *QemuPipeStream::commitBufferAndReadFully(size_t writeSize, void *userReadBufPtr, size_t totalReadSize) {
+
+    unsigned char* userReadBuf = static_cast<unsigned char*>(userReadBufPtr);
+
     if (!valid()) return NULL;
-    if (!buf) {
-        if (len > 0) {
-            // If len is non-zero, buf must not be NULL. Otherwise the pipe would be
-            // in a corrupted state, which is lethal for the emulator.
-            ERR("QemuPipeStream::readFully failed, buf=NULL, len %zu, lethal"
-                    " error, exiting.", len);
+
+    if (!userReadBuf) {
+        if (totalReadSize > 0) {
+            ALOGE("QemuPipeStream::commitBufferAndReadFully failed, userReadBuf=NULL, totalReadSize %zu, lethal"
+                    " error, exiting.", totalReadSize);
             abort();
         }
-        return NULL;  // do not allow NULL buf in that implementation
-    }
-    size_t res = len;
-    while (res > 0) {
-        ssize_t stat = qemu_pipe_read(m_sock, (char *)(buf) + len - res, res);
-        if (stat == 0) {
-            // client shutdown;
+        if (!writeSize) {
             return NULL;
-        } else if (stat < 0) {
-            if (qemu_pipe_try_again()) {
-                continue;
-            } else {
-                ERR("QemuPipeStream::readFully failed (buf %p, len %zu"
-                    ", res %zu): %s, lethal error, exiting.", buf, len, res,
-                    strerror(errno));
-                abort();
-            }
-        } else {
-            res -= stat;
         }
     }
-    //DBG("<< QemuPipeStream::readFully %d\n", len);
-    return (const unsigned char *)buf;
+
+    // Advance buffered read if not yet consumed.
+    size_t remaining = totalReadSize;
+    size_t bufferedReadSize = m_readLeft < remaining ? m_readLeft : remaining;
+    if (bufferedReadSize) {
+        memcpy(userReadBuf, m_buf + (m_read - m_readLeft), bufferedReadSize);
+        remaining -= bufferedReadSize;
+        m_readLeft -= bufferedReadSize;
+    }
+
+    // Early out if nothing left to do.
+    if (!writeSize && !remaining) {
+        return userReadBuf;
+    }
+
+    writeFully(m_buf + kWriteOffset, writeSize);
+
+    // Now done writing. Early out if no reading left to do.
+    if (!remaining) {
+        return userReadBuf;
+    }
+
+    // Read up to kReadSize bytes if all buffered read has been consumed.
+    size_t maxRead = m_readLeft ? 0 : kReadSize;
+
+    ssize_t actual = 0;
+
+    if (maxRead) {
+        actual = qemu_pipe_read(m_sock, m_buf, maxRead);
+        // Updated buffered read size.
+        if (actual > 0) {
+            m_read = m_readLeft = actual;
+        }
+
+        if (actual == 0) {
+            ALOGD("%s: end of pipe", __FUNCTION__);
+            return NULL;
+        }
+    }
+
+    // Consume buffered read and read more if necessary.
+    while (remaining) {
+        bufferedReadSize = m_readLeft < remaining ? m_readLeft : remaining;
+        if (bufferedReadSize) {
+            memcpy(userReadBuf + (totalReadSize - remaining),
+                   m_buf + (m_read - m_readLeft),
+                   bufferedReadSize);
+            remaining -= bufferedReadSize;
+            m_readLeft -= bufferedReadSize;
+            continue;
+        }
+
+        actual = qemu_pipe_read(m_sock, m_buf, kReadSize);
+
+        if (actual == 0) {
+            ALOGD("%s: Failed reading from pipe: %d", __FUNCTION__,  errno);
+            return NULL;
+        }
+
+        if (actual > 0) {
+            m_read = m_readLeft = actual;
+            continue;
+        }
+
+        if (!qemu_pipe_try_again()) {
+            ALOGD("%s: Error reading from pipe: %d", __FUNCTION__, errno);
+            return NULL;
+        }
+    }
+
+    return userReadBuf;
 }
 
 const unsigned char *QemuPipeStream::read( void *buf, size_t *inout_len)
@@ -211,8 +278,9 @@
         if (res == 0) { /* EOF */
              break;
         }
-        if (qemu_pipe_try_again())
+        if (qemu_pipe_try_again()) {
             continue;
+        }
 
         /* A real error */
         if (ret == 0)
diff --git a/system/OpenglSystemCommon/QemuPipeStream.h b/system/OpenglSystemCommon/QemuPipeStream.h
index 8d64ab8..87638af 100644
--- a/system/OpenglSystemCommon/QemuPipeStream.h
+++ b/system/OpenglSystemCommon/QemuPipeStream.h
@@ -26,7 +26,7 @@
 #include "qemu_pipe.h"
 
 #ifdef __Fuchsia__
-#include <lib/zx/channel.h>
+#include <fuchsia/hardware/goldfish/cpp/fidl.h>
 #include <lib/zx/event.h>
 #include <lib/zx/vmo.h>
 #endif
@@ -42,6 +42,7 @@
     virtual void *allocBuffer(size_t minSize);
     virtual int commitBuffer(size_t size);
     virtual const unsigned char *readFully( void *buf, size_t len);
+    virtual const unsigned char *commitBufferAndReadFully(size_t size, void *buf, size_t len);
     virtual const unsigned char *read( void *buf, size_t *inout_len);
 
     bool valid() { return qemu_pipe_valid(m_sock); }
@@ -54,8 +55,11 @@
     QEMU_PIPE_HANDLE m_sock;
     size_t m_bufsize;
     unsigned char *m_buf;
+    size_t m_read;
+    size_t m_readLeft;
 #ifdef __Fuchsia__
-    zx::channel m_channel;
+    fuchsia::hardware::goldfish::PipeDeviceSyncPtr m_device;
+    fuchsia::hardware::goldfish::PipeSyncPtr m_pipe;
     zx::event m_event;
     zx::vmo m_vmo;
 #endif
diff --git a/system/OpenglSystemCommon/QemuPipeStreamFuchsia.cpp b/system/OpenglSystemCommon/QemuPipeStreamFuchsia.cpp
index f4ee61c..66dec13 100644
--- a/system/OpenglSystemCommon/QemuPipeStreamFuchsia.cpp
+++ b/system/OpenglSystemCommon/QemuPipeStreamFuchsia.cpp
@@ -17,8 +17,7 @@
 
 #include <cutils/log.h>
 #include <errno.h>
-#include <fuchsia/hardware/goldfish/pipe/c/fidl.h>
-#include <lib/fdio/fdio.h>
+#include <lib/zx/channel.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
@@ -27,11 +26,18 @@
 
 #include <utility>
 
+#include "services/service_connector.h"
+
+constexpr size_t kReadSize = 512 * 1024;
+constexpr size_t kWriteOffset = kReadSize;
+
 QemuPipeStream::QemuPipeStream(size_t bufSize) :
     IOStream(bufSize),
     m_sock(-1),
     m_bufsize(bufSize),
-    m_buf(nullptr)
+    m_buf(nullptr),
+    m_read(0),
+    m_readLeft(0)
 {
 }
 
@@ -39,13 +45,15 @@
     IOStream(bufSize),
     m_sock(sock),
     m_bufsize(bufSize),
-    m_buf(nullptr)
+    m_buf(nullptr),
+    m_read(0),
+    m_readLeft(0)
 {
 }
 
 QemuPipeStream::~QemuPipeStream()
 {
-    if (m_channel.is_valid()) {
+    if (m_device.is_bound()) {
         flush();
     }
     if (m_buf) {
@@ -61,25 +69,18 @@
 
 int QemuPipeStream::connect(void)
 {
-    int fd = TEMP_FAILURE_RETRY(open(QEMU_PIPE_PATH, O_RDWR));
-    if (fd < 0) {
-        ALOGE("%s: failed to open " QEMU_PIPE_PATH ": %s",
-              __FUNCTION__, strerror(errno));
+    zx::channel channel(GetConnectToServiceFunction()(QEMU_PIPE_PATH));
+    if (!channel) {
+        ALOGE("%s: failed to get service handle for " QEMU_PIPE_PATH,
+              __FUNCTION__);
         return -1;
     }
 
-    zx::channel channel;
-    zx_status_t status = fdio_get_service_handle(
-        fd, channel.reset_and_get_address());
-    if (status != ZX_OK) {
-        ALOGE("%s: failed to get service handle for " QEMU_PIPE_PATH ": %d",
-              __FUNCTION__, status);
-        close(fd);
-        return -1;
-    }
+    m_device.Bind(std::move(channel));
+    m_device->OpenPipe(m_pipe.NewRequest());
 
     zx::event event;
-    status = zx::event::create(0, &event);
+    zx_status_t status = zx::event::create(0, &event);
     if (status != ZX_OK) {
         ALOGE("%s: failed to create event: %d", __FUNCTION__, status);
         return -1;
@@ -91,50 +92,46 @@
         return -1;
     }
 
-    status = fuchsia_hardware_goldfish_pipe_DeviceSetEvent(
-        channel.get(), event_copy.release());
+    status = m_pipe->SetEvent(std::move(event_copy));
     if (status != ZX_OK) {
         ALOGE("%s: failed to set event: %d:%d", __FUNCTION__, status);
         return -1;
     }
 
-    zx_status_t status2 = ZX_OK;
-    zx::vmo vmo;
-    status = fuchsia_hardware_goldfish_pipe_DeviceGetBuffer(
-        channel.get(), &status2, vmo.reset_and_get_address());
-    if (status != ZX_OK || status2 != ZX_OK) {
-        ALOGE("%s: failed to get buffer: %d:%d", __FUNCTION__, status, status2);
+    if (!allocBuffer(m_bufsize)) {
+        ALOGE("%s: failed allocate initial buffer", __FUNCTION__);
         return -1;
     }
 
     size_t len = strlen("pipe:opengles");
-    status = vmo.write("pipe:opengles", 0, len + 1);
+    status = m_vmo.write("pipe:opengles", 0, len + 1);
     if (status != ZX_OK) {
         ALOGE("%s: failed write pipe name", __FUNCTION__);
         return -1;
     }
 
     uint64_t actual;
-    status = fuchsia_hardware_goldfish_pipe_DeviceWrite(
-        channel.get(), len + 1, 0, &status2, &actual);
+    zx_status_t status2 = ZX_OK;
+    status = m_pipe->Write(len + 1, 0, &status2, &actual);
     if (status != ZX_OK || status2 != ZX_OK) {
         ALOGD("%s: connecting to pipe service failed: %d:%d", __FUNCTION__,
               status, status2);
         return -1;
     }
 
-    m_channel = std::move(channel);
     m_event = std::move(event);
-    m_vmo = std::move(vmo);
     return 0;
 }
 
 void *QemuPipeStream::allocBuffer(size_t minSize)
 {
+    // Add dedicated read buffer space at the front of buffer.
+    minSize += kReadSize;
+
     zx_status_t status;
     if (m_buf) {
         if (minSize <= m_bufsize) {
-            return m_buf;
+            return m_buf + kWriteOffset;
         }
         status = zx_vmar_unmap(zx_vmar_root_self(),
                                reinterpret_cast<zx_vaddr_t>(m_buf),
@@ -149,16 +146,14 @@
     size_t allocSize = m_bufsize < minSize ? minSize : m_bufsize;
 
     zx_status_t status2 = ZX_OK;
-    status = fuchsia_hardware_goldfish_pipe_DeviceSetBufferSize(
-        m_channel.get(), allocSize, &status2);
+    status = m_pipe->SetBufferSize(allocSize, &status2);
     if (status != ZX_OK || status2 != ZX_OK) {
         ALOGE("%s: failed to get buffer: %d:%d", __FUNCTION__, status, status2);
         return nullptr;
     }
 
     zx::vmo vmo;
-    status = fuchsia_hardware_goldfish_pipe_DeviceGetBuffer(
-        m_channel.get(), &status2, vmo.reset_and_get_address());
+    status = m_pipe->GetBuffer(&status2, &vmo);
     if (status != ZX_OK || status2 != ZX_OK) {
         ALOGE("%s: failed to get buffer: %d:%d", __FUNCTION__, status, status2);
         return nullptr;
@@ -176,44 +171,19 @@
     m_buf = reinterpret_cast<unsigned char*>(mapped_addr);
     m_bufsize = allocSize;
     m_vmo = std::move(vmo);
-    return m_buf;
+    return m_buf + kWriteOffset;
 }
 
 int QemuPipeStream::commitBuffer(size_t size)
 {
     if (size == 0) return 0;
 
-    size_t remaining = size;
-    while (remaining) {
-        zx_status_t status2 = ZX_OK;
-        uint64_t actual = 0;
-        zx_status_t status = fuchsia_hardware_goldfish_pipe_DeviceWrite(
-            m_channel.get(), remaining, size - remaining, &status2, &actual);
-        if (status != ZX_OK) {
-            ALOGD("%s: Failed writing to pipe: %d", __FUNCTION__, status);
-            return -1;
-        }
-        if (actual) {
-            remaining -= actual;
-            continue;
-        }
-        if (status2 != ZX_ERR_SHOULD_WAIT) {
-            ALOGD("%s: Error writing to pipe: %d", __FUNCTION__, status2);
-            return -1;
-        }
-        zx_signals_t observed = ZX_SIGNAL_NONE;
-        status = m_event.wait_one(
-            fuchsia_hardware_goldfish_pipe_SIGNAL_WRITABLE |
-            fuchsia_hardware_goldfish_pipe_SIGNAL_HANGUP,
-            zx::time::infinite(), &observed);
-        if (status != ZX_OK) {
-            ALOGD("%s: wait_one failed: %d", __FUNCTION__, status);
-            return -1;
-        }
-        if (observed & fuchsia_hardware_goldfish_pipe_SIGNAL_HANGUP) {
-            ALOGD("%s: Remote end hungup", __FUNCTION__);
-            return -1;
-        }
+    uint64_t actual = 0;
+    zx_status_t status2 = ZX_OK;
+    zx_status_t status = m_pipe->Call(size, kWriteOffset, 0, 0, &status2, &actual);
+    if (status != ZX_OK || status2 != ZX_OK) {
+        ALOGD("%s: Pipe call failed: %d:%d", __FUNCTION__, status, status2);
+        return -1;
     }
 
     return 0;
@@ -232,31 +202,74 @@
 
 const unsigned char *QemuPipeStream::readFully(void *buf, size_t len)
 {
-    if (!m_channel.is_valid()) return nullptr;
+    return commitBufferAndReadFully(0, buf, len);
+}
+
+const unsigned char *QemuPipeStream::commitBufferAndReadFully(size_t size, void *buf, size_t len)
+{
+    if (!m_device.is_bound()) return nullptr;
 
     if (!buf) {
         if (len > 0) {
-            ALOGE("QemuPipeStream::readFully failed, buf=NULL, len %zu, lethal"
+            ALOGE("QemuPipeStream::commitBufferAndReadFully failed, buf=NULL, len %zu, lethal"
                     " error, exiting.", len);
             abort();
         }
+        if (!size) {
+            return nullptr;
+        }
+    }
+
+    // Advance buffered read if not yet consumed.
+    size_t remaining = len;
+    size_t readSize = m_readLeft < remaining ? m_readLeft : remaining;
+    if (readSize) {
+        memcpy(static_cast<char*>(buf), m_buf + (m_read - m_readLeft), readSize);
+        remaining -= readSize;
+        m_readLeft -= readSize;
+    }
+
+    // Early out if nothing left to do.
+    if (!size && !remaining) {
+        return static_cast<const unsigned char *>(buf);
+    }
+
+    // Read up to kReadSize bytes if all buffered read has been consumed.
+    size_t maxRead = (m_readLeft || !remaining) ? 0 : kReadSize;
+    uint64_t actual = 0;
+    zx_status_t status2 = ZX_OK;
+    zx_status_t status = m_pipe->Call(size, kWriteOffset, maxRead, 0, &status2, &actual);
+    if (status != ZX_OK) {
+        ALOGD("%s: Pipe call failed: %d", __FUNCTION__, status);
         return nullptr;
     }
 
-    size_t remaining = len;
+    // Updated buffered read size.
+    if (actual) {
+        m_read = m_readLeft = actual;
+    }
+
+    // Consume buffered read and read more if neccessary.
     while (remaining) {
-        size_t readSize = m_bufsize < remaining ? m_bufsize : remaining;
-        zx_status_t status2 = ZX_OK;
-        uint64_t actual = 0;
-        zx_status_t status = fuchsia_hardware_goldfish_pipe_DeviceRead(
-            m_channel.get(), readSize, 0, &status2, &actual);
+        readSize = m_readLeft < remaining ? m_readLeft : remaining;
+        if (readSize) {
+            memcpy(static_cast<char*>(buf) + (len - remaining),
+                   m_buf + (m_read - m_readLeft),
+                   readSize);
+            remaining -= readSize;
+            m_readLeft -= readSize;
+            continue;
+        }
+
+        status2 = ZX_OK;
+        actual = 0;
+        status = m_pipe->Read(kReadSize, 0, &status2, &actual);
         if (status != ZX_OK) {
             ALOGD("%s: Failed reading from pipe: %d", __FUNCTION__, status);
             return nullptr;
         }
         if (actual) {
-            m_vmo.read(static_cast<char *>(buf) + (len - remaining), 0, actual);
-            remaining -= actual;
+            m_read = m_readLeft = actual;
             continue;
         }
         if (status2 != ZX_ERR_SHOULD_WAIT) {
@@ -265,14 +278,14 @@
         }
         zx_signals_t observed = ZX_SIGNAL_NONE;
         status = m_event.wait_one(
-            fuchsia_hardware_goldfish_pipe_SIGNAL_READABLE |
-            fuchsia_hardware_goldfish_pipe_SIGNAL_HANGUP,
+            fuchsia::hardware::goldfish::SIGNAL_READABLE |
+            fuchsia::hardware::goldfish::SIGNAL_HANGUP,
             zx::time::infinite(), &observed);
         if (status != ZX_OK) {
             ALOGD("%s: wait_one failed: %d", __FUNCTION__, status);
             return nullptr;
         }
-        if (observed & fuchsia_hardware_goldfish_pipe_SIGNAL_HANGUP) {
+        if (observed & fuchsia::hardware::goldfish::SIGNAL_HANGUP) {
             ALOGD("%s: Remote end hungup", __FUNCTION__);
             return nullptr;
         }
diff --git a/system/OpenglSystemCommon/ThreadInfo.cpp b/system/OpenglSystemCommon/ThreadInfo.cpp
index c432cea..fea6cb7 100644
--- a/system/OpenglSystemCommon/ThreadInfo.cpp
+++ b/system/OpenglSystemCommon/ThreadInfo.cpp
@@ -16,9 +16,17 @@
 #include "ThreadInfo.h"
 #include "cutils/threads.h"
 
+#ifdef __BIONIC__
+#include <bionic/tls.h>
+#endif
+
 #ifdef __ANDROID__
+// Are we missing an actual set of TLS defs?
+#ifdef GOLDFISH_OPENGL_NO_PLATFORM_BIONIC_INCLUDES
 #include <bionic_tls.h>
 #endif
+#endif
+
 #include <pthread.h>
 
 thread_store_t s_tls = THREAD_STORE_INITIALIZER;
diff --git a/system/OpenglSystemCommon/VirtioGpuPipeStream.cpp b/system/OpenglSystemCommon/VirtioGpuPipeStream.cpp
new file mode 100644
index 0000000..d3618f3
--- /dev/null
+++ b/system/OpenglSystemCommon/VirtioGpuPipeStream.cpp
@@ -0,0 +1,420 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "VirtioGpuPipeStream.h"
+
+#include <drm/virtgpu_drm.h>
+#include <xf86drm.h>
+
+#include <sys/types.h>
+#include <sys/mman.h>
+
+#include <errno.h>
+#include <unistd.h>
+
+// In a virtual machine, there should only be one GPU
+#define RENDERNODE_MINOR 128
+
+// Attributes use to allocate our response buffer
+// Similar to virgl's fence objects
+#define PIPE_BUFFER             0
+#define VIRGL_FORMAT_R8_UNORM   64
+#define VIRGL_BIND_CUSTOM       (1 << 17)
+
+static const size_t kTransferBufferSize = (1048576);
+
+static const size_t kReadSize = 512 * 1024;
+static const size_t kWriteOffset = kReadSize;
+
+VirtioGpuPipeStream::VirtioGpuPipeStream(size_t bufSize) :
+    IOStream(bufSize),
+    m_fd(-1),
+    m_virtio_rh(~0U),
+    m_virtio_bo(0),
+    m_virtio_mapped(nullptr),
+    m_bufsize(bufSize),
+    m_buf(nullptr),
+    m_read(0),
+    m_readLeft(0),
+    m_writtenPos(0) { }
+
+VirtioGpuPipeStream::~VirtioGpuPipeStream()
+{
+    if (m_virtio_mapped) {
+        munmap(m_virtio_mapped, kTransferBufferSize);
+    }
+
+    if (m_virtio_bo > 0U) {
+        drm_gem_close gem_close = {
+            .handle = m_virtio_bo,
+        };
+        drmIoctl(m_fd, DRM_IOCTL_GEM_CLOSE, &gem_close);
+    }
+
+    if (m_fd >= 0) {
+        close(m_fd);
+    }
+
+    free(m_buf);
+}
+
+int VirtioGpuPipeStream::connect(const char* serviceName)
+{
+    if (m_fd < 0) {
+        m_fd = drmOpenRender(RENDERNODE_MINOR);
+        if (m_fd < 0) {
+            ERR("%s: failed with fd %d (%s)", __func__, m_fd, strerror(errno));
+            return -1;
+        }
+    }
+
+    if (!m_virtio_bo) {
+        drm_virtgpu_resource_create create = {
+            .target     = PIPE_BUFFER,
+            .format     = VIRGL_FORMAT_R8_UNORM,
+            .bind       = VIRGL_BIND_CUSTOM,
+            .width      = kTransferBufferSize,
+            .height     = 1U,
+            .depth      = 1U,
+            .array_size = 0U,
+            .size       = kTransferBufferSize,
+            .stride     = kTransferBufferSize,
+        };
+
+        int ret = drmIoctl(m_fd, DRM_IOCTL_VIRTGPU_RESOURCE_CREATE, &create);
+        if (ret) {
+            ERR("%s: failed with %d allocating command buffer (%s)",
+                __func__, ret, strerror(errno));
+            return -1;
+        }
+
+        m_virtio_bo = create.bo_handle;
+        if (!m_virtio_bo) {
+            ERR("%s: no handle when allocating command buffer",
+                __func__);
+            return -1;
+        }
+
+        m_virtio_rh = create.res_handle;
+
+        if (create.size != kTransferBufferSize) {
+            ERR("%s: command buffer wrongly sized, create.size=%zu "
+                "!= %zu", __func__,
+                static_cast<size_t>(create.size),
+                static_cast<size_t>(kTransferBufferSize));
+            abort();
+        }
+    }
+
+    if (!m_virtio_mapped) {
+        drm_virtgpu_map map = {
+            .handle = m_virtio_bo,
+        };
+
+        int ret = drmIoctl(m_fd, DRM_IOCTL_VIRTGPU_MAP, &map);
+        if (ret) {
+            ERR("%s: failed with %d mapping command response buffer (%s)",
+                __func__, ret, strerror(errno));
+            return -1;
+        }
+
+        m_virtio_mapped = static_cast<unsigned char*>(
+            mmap64(nullptr, kTransferBufferSize, PROT_WRITE,
+                   MAP_SHARED, m_fd, map.offset));
+
+        if (m_virtio_mapped == MAP_FAILED) {
+            ERR("%s: failed with %d mmap'ing command response buffer (%s)",
+                __func__, ret, strerror(errno));
+            return -1;
+        }
+    }
+
+    wait();
+
+    if (serviceName) {
+        writeFully(serviceName, strlen(serviceName) + 1);
+    } else {
+        static const char kPipeString[] = "pipe:opengles";
+        std::string pipeStr(kPipeString);
+        writeFully(kPipeString, sizeof(kPipeString));
+    }
+    return 0;
+}
+
+uint64_t VirtioGpuPipeStream::initProcessPipe() {
+    connect("pipe:GLProcessPipe");
+    int32_t confirmInt = 100;
+    writeFully(&confirmInt, sizeof(confirmInt));
+    uint64_t res;
+    readFully(&res, sizeof(res));
+    return res;
+}
+
+void *VirtioGpuPipeStream::allocBuffer(size_t minSize) {
+    size_t allocSize = (m_bufsize < minSize ? minSize : m_bufsize);
+    if (!m_buf) {
+        m_buf = (unsigned char *)malloc(allocSize);
+    }
+    else if (m_bufsize < allocSize) {
+        unsigned char *p = (unsigned char *)realloc(m_buf, allocSize);
+        if (p != NULL) {
+            m_buf = p;
+            m_bufsize = allocSize;
+        } else {
+            ERR("realloc (%zu) failed\n", allocSize);
+            free(m_buf);
+            m_buf = NULL;
+            m_bufsize = 0;
+        }
+    }
+
+    return m_buf;
+}
+
+int VirtioGpuPipeStream::commitBuffer(size_t size) {
+    if (size == 0) return 0;
+    return writeFully(m_buf, size);
+}
+
+int VirtioGpuPipeStream::writeFully(const void *buf, size_t len)
+{
+    //DBG(">> VirtioGpuPipeStream::writeFully %d\n", len);
+    if (!valid()) return -1;
+    if (!buf) {
+       if (len>0) {
+            // If len is non-zero, buf must not be NULL. Otherwise the pipe would be
+            // in a corrupted state, which is lethal for the emulator.
+           ERR("VirtioGpuPipeStream::writeFully failed, buf=NULL, len %zu,"
+                   " lethal error, exiting", len);
+           abort();
+       }
+       return 0;
+    }
+
+    size_t res = len;
+    int retval = 0;
+
+    while (res > 0) {
+        ssize_t stat = transferToHost((const char *)(buf) + (len - res), res);
+        if (stat > 0) {
+            res -= stat;
+            continue;
+        }
+        if (stat == 0) { /* EOF */
+            ERR("VirtioGpuPipeStream::writeFully failed: premature EOF\n");
+            retval = -1;
+            break;
+        }
+        if (errno == EAGAIN) {
+            continue;
+        }
+        retval =  stat;
+        ERR("VirtioGpuPipeStream::writeFully failed: %s, lethal error, exiting.\n",
+                strerror(errno));
+        abort();
+    }
+    //DBG("<< VirtioGpuPipeStream::writeFully %d\n", len );
+    return retval;
+}
+
+const unsigned char *VirtioGpuPipeStream::readFully(void *buf, size_t len)
+{
+    flush();
+
+    if (!valid()) return NULL;
+    if (!buf) {
+        if (len > 0) {
+            // If len is non-zero, buf must not be NULL. Otherwise the pipe would be
+            // in a corrupted state, which is lethal for the emulator.
+            ERR("VirtioGpuPipeStream::readFully failed, buf=NULL, len %zu, lethal"
+                    " error, exiting.", len);
+            abort();
+        }
+    }
+
+    size_t res = len;
+    while (res > 0) {
+        ssize_t stat = transferFromHost((char *)(buf) + len - res, res);
+        if (stat == 0) {
+            // client shutdown;
+            return NULL;
+        } else if (stat < 0) {
+            if (errno == EAGAIN) {
+                continue;
+            } else {
+                ERR("VirtioGpuPipeStream::readFully failed (buf %p, len %zu"
+                    ", res %zu): %s, lethal error, exiting.", buf, len, res,
+                    strerror(errno));
+                abort();
+            }
+        } else {
+            res -= stat;
+        }
+    }
+    //DBG("<< VirtioGpuPipeStream::readFully %d\n", len);
+    return (const unsigned char *)buf;
+}
+
+const unsigned char *VirtioGpuPipeStream::commitBufferAndReadFully(
+    size_t writeSize, void *userReadBufPtr, size_t totalReadSize)
+{
+    return commitBuffer(writeSize) ? nullptr : readFully(userReadBufPtr, totalReadSize);
+}
+
+const unsigned char *VirtioGpuPipeStream::read( void *buf, size_t *inout_len)
+{
+    //DBG(">> VirtioGpuPipeStream::read %d\n", *inout_len);
+    if (!valid()) return NULL;
+    if (!buf) {
+      ERR("VirtioGpuPipeStream::read failed, buf=NULL");
+      return NULL;  // do not allow NULL buf in that implementation
+    }
+
+    int n = recv(buf, *inout_len);
+
+    if (n > 0) {
+        *inout_len = n;
+        return (const unsigned char *)buf;
+    }
+
+    //DBG("<< VirtioGpuPipeStream::read %d\n", *inout_len);
+    return NULL;
+}
+
+int VirtioGpuPipeStream::recv(void *buf, size_t len)
+{
+    if (!valid()) return int(ERR_INVALID_SOCKET);
+    char* p = (char *)buf;
+    int ret = 0;
+    while(len > 0) {
+        int res = transferFromHost(p, len);
+        if (res > 0) {
+            p += res;
+            ret += res;
+            len -= res;
+            continue;
+        }
+        if (res == 0) { /* EOF */
+             break;
+        }
+        if (errno != EAGAIN) {
+            continue;
+        }
+
+        /* A real error */
+        if (ret == 0)
+            ret = -1;
+        break;
+    }
+    return ret;
+}
+
+void VirtioGpuPipeStream::wait() {
+    struct drm_virtgpu_3d_wait waitcmd;
+    memset(&waitcmd, 0, sizeof(waitcmd));
+    waitcmd.handle = m_virtio_bo;
+    int ret = drmIoctl(m_fd, DRM_IOCTL_VIRTGPU_WAIT, &waitcmd);
+    if (ret) {
+        ERR("VirtioGpuPipeStream: DRM_IOCTL_VIRTGPU_WAIT failed with %d (%s)\n", errno, strerror(errno));
+    }
+    m_writtenPos = 0;
+}
+
+ssize_t VirtioGpuPipeStream::transferToHost(const void* buffer, size_t len) {
+    size_t todo = len;
+    size_t done = 0;
+    int ret = EAGAIN;
+    struct drm_virtgpu_3d_transfer_to_host xfer;
+
+    unsigned char* virtioPtr = m_virtio_mapped;
+
+    const unsigned char* readPtr = reinterpret_cast<const unsigned char*>(buffer);
+
+    while (done < len) {
+        size_t toXfer = todo > kTransferBufferSize ? kTransferBufferSize : todo;
+
+        if (toXfer > (kTransferBufferSize - m_writtenPos)) {
+            wait();
+        }
+
+        memcpy(virtioPtr + m_writtenPos, readPtr, toXfer);
+
+        memset(&xfer, 0, sizeof(xfer));
+        xfer.bo_handle = m_virtio_bo;
+        xfer.box.x = m_writtenPos;
+        xfer.box.y = 0;
+        xfer.box.w = toXfer;
+        xfer.box.h = 1;
+        xfer.box.d = 1;
+
+        ret = drmIoctl(m_fd, DRM_IOCTL_VIRTGPU_TRANSFER_TO_HOST, &xfer);
+
+        if (ret) {
+            ERR("VirtioGpuPipeStream: failed with errno %d (%s)\n", errno, strerror(errno));
+            return (ssize_t)ret;
+        }
+
+        done += toXfer;
+        readPtr += toXfer;
+		todo -= toXfer;
+        m_writtenPos += toXfer;
+    }
+
+    return len;
+}
+
+ssize_t VirtioGpuPipeStream::transferFromHost(void* buffer, size_t len) {
+    size_t todo = len;
+    size_t done = 0;
+    int ret = EAGAIN;
+    struct drm_virtgpu_3d_transfer_from_host xfer;
+
+    const unsigned char* virtioPtr = m_virtio_mapped;
+    unsigned char* readPtr = reinterpret_cast<unsigned char*>(buffer);
+
+    if (m_writtenPos) {
+        wait();
+    }
+
+    while (done < len) {
+        size_t toXfer = todo > kTransferBufferSize ? kTransferBufferSize : todo;
+
+        memset(&xfer, 0, sizeof(xfer));
+        xfer.bo_handle = m_virtio_bo;
+        xfer.box.x = 0;
+        xfer.box.y = 0;
+        xfer.box.w = toXfer;
+        xfer.box.h = 1;
+        xfer.box.d = 1;
+
+        ret = drmIoctl(m_fd, DRM_IOCTL_VIRTGPU_TRANSFER_FROM_HOST, &xfer);
+
+        if (ret) {
+            ERR("VirtioGpuPipeStream: failed with errno %d (%s)\n", errno, strerror(errno));
+            return (ssize_t)ret;
+        }
+
+        wait();
+
+        memcpy(readPtr, virtioPtr, toXfer);
+
+        done += toXfer;
+        readPtr += toXfer;
+	    todo -= toXfer;
+    }
+
+    return len;
+}
diff --git a/system/OpenglSystemCommon/VirtioGpuPipeStream.h b/system/OpenglSystemCommon/VirtioGpuPipeStream.h
new file mode 100644
index 0000000..3f3c537
--- /dev/null
+++ b/system/OpenglSystemCommon/VirtioGpuPipeStream.h
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include "HostConnection.h"
+#include "IOStream.h"
+
+#include <stdlib.h>
+
+/* This file implements an IOStream that uses VIRTGPU TRANSFER* ioctls on a
+ * virtio-gpu DRM rendernode device to communicate with a goldfish-pipe
+ * service on the host side.
+ */
+
+class VirtioGpuPipeStream : public IOStream {
+public:
+    typedef enum { ERR_INVALID_SOCKET = -1000 } QemuPipeStreamError;
+
+    explicit VirtioGpuPipeStream(size_t bufsize = 10000);
+    ~VirtioGpuPipeStream();
+    int connect(const char* serviceName = 0);
+    uint64_t initProcessPipe();
+
+    virtual void *allocBuffer(size_t minSize);
+    virtual int commitBuffer(size_t size);
+    virtual const unsigned char *readFully( void *buf, size_t len);
+    virtual const unsigned char *commitBufferAndReadFully(
+        size_t size, void *buf, size_t len);
+    virtual const unsigned char *read( void *buf, size_t *inout_len);
+
+    bool valid() { return m_fd >= 0; }
+    int getRendernodeFd() { return m_fd; }
+    int recv(void *buf, size_t len);
+
+    virtual int writeFully(const void *buf, size_t len);
+
+    int getSocket() const;
+private:
+    // sync. Also resets the write position.
+    void wait();
+
+    // transfer to/from host ops
+    ssize_t transferToHost(const void* buffer, size_t len);
+    ssize_t transferFromHost(void* buffer, size_t len);
+
+    int m_fd; // rendernode fd
+
+    uint32_t m_virtio_rh; // transfer buffer res handle
+    uint32_t m_virtio_bo; // transfer bo handle
+    unsigned char* m_virtio_mapped; // user mapping of bo
+
+    // intermediate buffer
+    size_t m_bufsize;
+    unsigned char *m_buf;
+    size_t m_read;
+    size_t m_readLeft;
+
+    size_t m_writtenPos;
+
+    VirtioGpuPipeStream(int sock, size_t bufSize);
+};
diff --git a/system/OpenglSystemCommon/VirtioGpuStream.cpp b/system/OpenglSystemCommon/VirtioGpuStream.cpp
index f6d04d8..a0876dc 100644
--- a/system/OpenglSystemCommon/VirtioGpuStream.cpp
+++ b/system/OpenglSystemCommon/VirtioGpuStream.cpp
@@ -52,25 +52,7 @@
     unsigned char buf[0];
 } __attribute__((packed));
 
-uint32_t CrosGralloc::getHostHandle(native_handle_t const* handle_)
-{
-    uint32_t id = 0;
-
-    if (m_fd >= 0) {
-        cros_gralloc_handle const* handle =
-          reinterpret_cast<cros_gralloc_handle const*>(handle_);
-        drmPrimeFDToHandle(m_fd, handle->fds[0], &id);
-    }
-
-    return id;
-}
-
-int CrosGralloc::getFormat(native_handle_t const* handle)
-{
-    return ((cros_gralloc_handle *)handle)->droid_format;
-}
-
-bool VirtioGpuProcessPipe::processPipeInit(renderControl_encoder_context_t *rcEnc)
+bool VirtioGpuProcessPipe::processPipeInit(HostConnectionType, renderControl_encoder_context_t *rcEnc)
 {
   union {
       uint64_t proto;
@@ -187,7 +169,6 @@
         }
     }
 
-    m_gralloc.setFd(m_fd);
     return 0;
 }
 
diff --git a/system/OpenglSystemCommon/VirtioGpuStream.h b/system/OpenglSystemCommon/VirtioGpuStream.h
index 9d6faa5..1c7a496 100644
--- a/system/OpenglSystemCommon/VirtioGpuStream.h
+++ b/system/OpenglSystemCommon/VirtioGpuStream.h
@@ -27,23 +27,10 @@
 
 struct VirtioGpuCmd;
 
-class CrosGralloc : public Gralloc
-{
-    friend class VirtioGpuStream;
-
-public:
-    virtual uint32_t getHostHandle(native_handle_t const* handle);
-    virtual int getFormat(native_handle_t const* handle);
-
-private:
-    inline void setFd(int fd) { m_fd = fd; }
-    int m_fd = -1;
-};
-
 class VirtioGpuProcessPipe : public ProcessPipe
 {
 public:
-    virtual bool processPipeInit(renderControl_encoder_context_t *rcEnc);
+    virtual bool processPipeInit(HostConnectionType connType, renderControl_encoder_context_t *rcEnc);
 };
 
 class VirtioGpuStream : public IOStream
@@ -53,7 +40,6 @@
     ~VirtioGpuStream();
 
     int connect();
-    Gralloc *getGralloc() { return &m_gralloc; }
     ProcessPipe *getProcessPipe() { return &m_processPipe; }
 
     // override IOStream so we can see non-rounded allocation sizes
@@ -69,6 +55,10 @@
     virtual int writeFully(const void *buf, size_t len);
     virtual const unsigned char *readFully(void *buf, size_t len);
     virtual int commitBuffer(size_t size);
+    virtual const unsigned char* commitBufferAndReadFully(size_t size, void *buf, size_t len)
+    {
+        return commitBuffer(size) ? nullptr : readFully(buf, len);
+    }
     virtual const unsigned char *read(void *buf, size_t *inout_len) final
     {
         return readFully(buf, *inout_len);
@@ -79,6 +69,8 @@
         return m_fd >= 0 && m_cmdResp_bo > 0 && m_cmdResp;
     }
 
+    int getRendernodeFd() { return m_fd; }
+
 private:
     // rendernode fd
     int m_fd;
@@ -111,9 +103,6 @@
     // bytes of an alloc flushed through flush() API
     size_t m_allocFlushSize;
 
-    // CrOS gralloc interface
-    CrosGralloc m_gralloc;
-
     // Fake process pipe implementation
     VirtioGpuProcessPipe m_processPipe;
 
diff --git a/system/OpenglSystemCommon/address_space_graphics_types.h b/system/OpenglSystemCommon/address_space_graphics_types.h
new file mode 100644
index 0000000..1ebad34
--- /dev/null
+++ b/system/OpenglSystemCommon/address_space_graphics_types.h
@@ -0,0 +1,354 @@
+// Copyright 2019 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+#pragma once
+
+#include "android/base/ring_buffer.h"
+
+#include <functional>
+
+// This file defines common types for address space graphics and provides
+// documentation.
+
+// Address space graphics======================================================
+//
+// Basic idea
+//
+// Address space graphics (ASG) is a subdevice of the address space device that
+// provides a way to run graphics commands and data with fewer VM exits by
+// leveraging shared memory ring buffers.
+//
+// Each GL/Vk thread in the guest is associated with a context (asg_context).
+// asg_context consists of pointers into the shared memory that view it as a
+// collection of ring buffers and a common write buffer.
+//
+// Consumer concept
+//
+// ASG does not assume a particular rendering backend (though we will use
+// RenderThread's). This is for ease of coding/testing and flexibility; the
+// implementation is not coupled to emugl/libOpenglRender.
+//
+// Instead, there is the concept of a "Consumer" of ASG that will do something
+// with the data arriving from the shared memory region, and possibly reply
+// back to the guest. We register functions to construct and deconstruct
+// Consumers as part of emulator init (setConsumer).
+//
+// Guest workflow
+//
+// 1. Open address space device
+//
+// 2. Create the graphics context as the subdevice
+//
+// 3. ping(ASG_GET_RING) to get the offset/size of the ring buffer admin. info
+//
+// 4. ping(ASG_GET_BUFFER) to get the offset/size of the shared transfer buffer.
+//
+// 5. ioctl(CLAIM_SHARED) and mmap on those two offset/size pairs to get a
+// guest-side mapping.
+//
+// 6. call asg_context_create on the ring and buffer pointers to create the asg_context.
+//
+// 7. Now the guest and host share asg_context pts and can communicate.
+//
+// 8. But usually the guest will sometimes need to ping(ASG_NOTIFY_AVAILABLE)
+// so that the host side (which is usually a separate thread that we don't want
+// to spin too much) wakes up and processes data.
+
+namespace android {
+namespace base {
+
+class Stream;
+
+} // namespace base
+} // namespace android
+
+#define ADDRESS_SPACE_GRAPHICS_DEVICE_ID 0
+#define ADDRESS_SPACE_GRAPHICS_PAGE_SIZE 4096
+#define ADDRESS_SPACE_GRAPHICS_BLOCK_SIZE (16ULL * 1048576ULL)
+
+// AddressSpaceGraphicsContext shares memory with
+// the guest via the following layout:
+extern "C" {
+
+struct asg_ring_storage { // directly shared with guest
+    char to_host[ADDRESS_SPACE_GRAPHICS_PAGE_SIZE];
+    char to_host_large_xfer[ADDRESS_SPACE_GRAPHICS_PAGE_SIZE];
+    char from_host_large_xfer[ADDRESS_SPACE_GRAPHICS_PAGE_SIZE];
+};
+
+// Set by the address space graphics device to notify the guest that the host
+// has slept or is able to consume something, or we are exiting, or there is an
+// error.
+enum asg_host_state {
+    // The host renderthread is asleep and needs to be woken up.
+    ASG_HOST_STATE_NEED_NOTIFY = 0,
+
+    // The host renderthread is active and can consume new data
+    // without notification.
+    ASG_HOST_STATE_CAN_CONSUME = 1,
+
+    // Normal exit
+    ASG_HOST_STATE_EXIT = 2,
+
+    // Error: Something weird happened and we need to exit.
+    ASG_HOST_STATE_ERROR = 3,
+};
+
+struct asg_ring_config;
+
+// Each context has a pair of ring buffers for communication
+// to and from the host. There is another ring buffer for large xfers
+// to the host (all xfers from the host are already considered "large").
+//
+// Each context also comes with _one_ auxiliary buffer to hold both its own
+// commands and to perform private DMA transfers.
+struct asg_context { // ptrs into RingStorage
+    struct ring_buffer* to_host;
+    char* buffer;
+    asg_host_state* host_state;
+    asg_ring_config* ring_config;
+    struct ring_buffer_with_view to_host_large_xfer;
+    struct ring_buffer_with_view from_host_large_xfer;
+};
+
+// Helper function that will be common between guest and host:
+// Given ring storage and a write buffer, returns asg_context that
+// is the correct view into it.
+static struct asg_context asg_context_create(
+    char* ring_storage,
+    char* buffer,
+    uint32_t buffer_size) {
+
+    struct asg_context res;
+
+    res.to_host =
+        reinterpret_cast<struct ring_buffer*>(
+            ring_storage +
+            offsetof(struct asg_ring_storage, to_host));
+    res.to_host_large_xfer.ring =
+        reinterpret_cast<struct ring_buffer*>(
+            ring_storage +
+            offsetof(struct asg_ring_storage, to_host_large_xfer));
+    res.from_host_large_xfer.ring =
+        reinterpret_cast<struct ring_buffer*>(
+            ring_storage +
+            offsetof(struct asg_ring_storage, from_host_large_xfer));
+
+    ring_buffer_init(res.to_host);
+
+    res.buffer = buffer;
+    res.host_state =
+        reinterpret_cast<asg_host_state*>(
+            &res.to_host->state);
+    res.ring_config =
+        reinterpret_cast<asg_ring_config*>(
+            res.to_host->config);
+
+    ring_buffer_view_init(
+        res.to_host_large_xfer.ring,
+        &res.to_host_large_xfer.view,
+        (uint8_t*)res.buffer, buffer_size);
+
+    ring_buffer_view_init(
+        res.from_host_large_xfer.ring,
+        &res.from_host_large_xfer.view,
+        (uint8_t*)res.buffer, buffer_size);
+
+    return res;
+}
+
+// During operation, the guest sends commands and data over the auxiliary
+// buffer while using the |to_host| ring to communicate what parts of the auxiliary
+// buffer is outstanding traffic needing to be consumed by the host.
+// After a transfer completes to the host, the host may write back data.
+// The guest then reads the results on the same auxiliary buffer
+// while being notified of which parts to read via the |from_host| ring.
+//
+// The size of the auxiliary buffer and flush interval is defined by
+// the following config.ini android_hw setting:
+//
+// 1) android_hw->hw_gltransport_asg_writeBufferSize
+// 2) android_hw->hw_gltransport_asg_writeStepSize
+//
+// 1) the size for the auxiliary buffer
+// 2) the step size over which commands are flushed to the host
+//
+// When transferring commands, command data is built up in writeStepSize
+// chunks and flushed to the host when either writeStepSize is reached or
+// the guest flushes explicitly.
+//
+// Command vs. Data Modes
+//
+// For command data larger than writeStepSize or when transferring data, we
+// fall back to using a different mode where the entire auxiliary buffer is
+// used to perform the transfer, |asg_writeBufferSize| steps at a time. The
+// host is also notified of the total transport size.
+//
+// When writing back to the guest, it is assumed that the write buffer will
+// be completely empty as the guest has already flushed and the host has
+// already consumed all commands/data, and is writing back. In this case,
+// the full auxiliary buffer is used at the same time for writing back to
+// the guest.
+//
+// Larger / Shared transfers
+//
+// Each of |to_host| and |from_host| can contain elements of type 1, 2, or 3:
+// Type 1: 8 bytes: 4 bytes offset, 4 bytes size. Relative to write buffer.
+struct __attribute__((__packed__)) asg_type1_xfer {
+    uint32_t offset;
+    uint32_t size;
+};
+// Type 2: 16 bytes: 16 bytes offset into address space PCI space, 8 bytes
+// size.
+struct __attribute__((__packed__)) asg_type2_xfer {
+    uint64_t physAddr;
+    uint64_t size;
+};
+// Type 3: There is a large transfer of known size and the entire write buffer
+// will be used to send it over.
+//
+// For type 1 transfers, we get the corresponding host virtual address by
+// adding the offset to the beginning of the write buffer.  For type 2
+// transfers, we need to calculate the guest physical address and then call
+// addressspacecontrolops.gethostptr, which is slower since it goes through
+// a data structure map of existing mappings.
+//
+// The rings never contain a mix of type 1 and 2 elements. For to_host,
+// the guest initiates changes between type 1 and 2.
+//
+// The config fields:
+//
+struct asg_ring_config {
+    // config[0]: size of the auxiliary buffer
+    uint32_t buffer_size;
+
+    // config[1]: flush interval for the auxiliary buffer
+    uint32_t flush_interval;
+
+    // the position of the interval in the auxiliary buffer
+    // that the host has read so far
+    uint32_t host_consumed_pos;
+
+    // the start of the places the guest might write to next
+    uint32_t guest_write_pos;
+
+    // 1 if transfers are of type 1, 2 if transfers of type 2,
+    // 3 if the overall transfer size is known and we are sending something large.
+    uint32_t transfer_mode;
+
+    // the size of the transfer, used if transfer size is known.
+    // Set before setting config[2] to 3.
+    uint32_t transfer_size;
+
+    // error state
+    uint32_t in_error;
+};
+
+// State/config changes may only occur if the ring is empty, or the state
+// is transitioning to Error. That way, the host and guest have a chance to
+// synchronize on the same state.
+//
+// Thus far we've established how commands and data are transferred
+// to and from the host. Next, let's discuss how AddressSpaceGraphicsContext
+// talks to the code that actually does something with the commands
+// and sends data back.
+
+} // extern "C"
+
+namespace android {
+namespace emulation {
+namespace asg {
+
+// Consumer Concept
+//
+// AddressSpaceGraphicsContext's are each associated with a consumer that
+// takes data off the auxiliary buffer and to_host, while sending back data
+// over the auxiliary buffer / from_host.
+//
+// will read the commands and write back data.
+//
+// The consumer type is fixed at startup. The interface is as follows:
+
+// Called by the consumer, implemented in AddressSpaceGraphicsContext:
+//
+// Called when the consumer doesn't find anything to
+// read in to_host. Will make the consumer sleep
+// until another Ping(NotifyAvailable).
+using OnUnavailableReadCallback =
+    std::function<int()>;
+
+// Unpacks a type 2 transfer into host pointer and size.
+using GetPtrCallback =
+    std::function<char*(uint64_t)>;
+
+struct ConsumerCallbacks {
+    OnUnavailableReadCallback onUnavailableRead;
+    GetPtrCallback getPtr;
+};
+
+using ConsumerCreateCallback =
+    std::function<void* (struct asg_context, ConsumerCallbacks)>;
+using ConsumerDestroyCallback =
+    std::function<void(void*)>;
+using ConsumerSaveCallback =
+    std::function<void(void*, base::Stream*)>;
+using ConsumerLoadCallback =
+    std::function<void(void*, base::Stream*)>;
+
+struct ConsumerInterface {
+    ConsumerCreateCallback create;
+    ConsumerDestroyCallback destroy;
+    ConsumerSaveCallback save;
+    ConsumerLoadCallback load;
+};
+
+} // namespace asg
+} // namespace emulation
+} // namespace android
+
+// The interface for the guest:
+
+extern "C" {
+// Handled outside in address_space_device.cpp:
+//
+// Ping(device id): Create the device. On the host, the two rings and
+// auxiliary buffer are allocated. The two rings are allocated up front.
+// Both the auxiliary buffers and the rings are allocated from blocks of
+// rings and auxiliary buffers. New blocks are created if we run out either
+// way.
+enum asg_command {
+    // Ping(get_ring): Returns, in the fields:
+    // metadata: offset to give to claimShared and mmap() in the guest
+    // size: size to give to claimShared and mmap() in the guest
+    ASG_GET_RING = 0,
+
+    // Ping(get_buffer): Returns, in the fields:
+    // metadata: offset to give to claimShared and mmap() in the guest
+    // size: size to give to claimShared and mmap() in the guest
+    ASG_GET_BUFFER = 1,
+
+    // Ping(set_version): Run after the guest reads and negotiates its
+    // version of the device with the host. The host now knows the guest's
+    // version and can proceed with a protocol that works for both.
+    // size (in): the version of the guest
+    // size (out): the version of the host
+    // After this command runs, the consumer is
+    // implicitly created.
+    ASG_SET_VERSION = 2,
+
+    // Ping(notiy_available): Wakes up the consumer from sleep so it
+    // can read data via toHost
+    ASG_NOTIFY_AVAILABLE = 3,
+};
+
+} // extern "C"
diff --git a/system/OpenglSystemCommon/bionic-include/bionic/tls.h b/system/OpenglSystemCommon/bionic-include/bionic/tls.h
new file mode 100644
index 0000000..659d75f
--- /dev/null
+++ b/system/OpenglSystemCommon/bionic-include/bionic/tls.h
@@ -0,0 +1,16 @@
+// Copyright (C) 2018 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+#pragma once
+
+#define GOLDFISH_OPENGL_NO_PLATFORM_BIONIC_INCLUDES
diff --git a/system/cbmanager/Android.mk b/system/cbmanager/Android.mk
new file mode 100644
index 0000000..753f00a
--- /dev/null
+++ b/system/cbmanager/Android.mk
@@ -0,0 +1,53 @@
+#
+# Copyright 2015 The Android Open-Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_CFLAGS += \
+    -DLOG_TAG=\"cbmanager\" \
+    -Werror \
+
+ifeq (true,$(GOLDFISH_OPENGL_BUILD_FOR_HOST))
+LOCAL_CFLAGS += \
+    -DHOST_BUILD \
+
+LOCAL_SRC_FILES := host.cpp
+else
+LOCAL_SHARED_LIBRARIES += \
+    liblog \
+    libcutils \
+    libutils \
+    libhidlbase \
+    android.hardware.graphics.mapper@2.0 \
+    android.hardware.graphics.mapper@3.0 \
+    android.hardware.graphics.allocator@2.0 \
+    android.hardware.graphics.allocator@3.0 \
+
+LOCAL_CFLAGS += \
+    -DPLATFORM_SDK_VERSION=$(PLATFORM_SDK_VERSION) \
+
+LOCAL_SRC_FILES := hidl.cpp
+
+endif
+
+LOCAL_C_INCLUDES += \
+    device/generic/goldfish-opengl/system/include \
+    device/generic/goldfish-opengl/shared/OpenglCodecCommon \
+
+LOCAL_MODULE := libcbmanager
+LOCAL_VENDOR_MODULE := true
+
+include $(BUILD_SHARED_LIBRARY)
diff --git a/system/cbmanager/debug.h b/system/cbmanager/debug.h
new file mode 100644
index 0000000..23899bd
--- /dev/null
+++ b/system/cbmanager/debug.h
@@ -0,0 +1,51 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_GOLDFISH_OPENGL_SYSTEM_CBMANAGER_DEBUG_H
+#define ANDROID_GOLDFISH_OPENGL_SYSTEM_CBMANAGER_DEBUG_H
+
+#include <log/log.h>
+
+#define CRASH(MSG) \
+    do { \
+        ALOGE("%s:%d crashed with '%s'", __func__, __LINE__, MSG); \
+        ::abort(); \
+    } while (false)
+
+#define CRASH_IF(COND, MSG) \
+    do { \
+        if ((COND)) { \
+            ALOGE("%s:%d crashed on '%s' with '%s'", __func__, __LINE__, #COND, MSG); \
+            ::abort(); \
+        } \
+    } while (false)
+
+#define RETURN_ERROR_CODE(X) \
+    do { \
+        ALOGE("%s:%d failed with '%s' (%d)", \
+              __func__, __LINE__, strerror(-(X)), -(X)); \
+        return (X); \
+    } while (false)
+
+#define RETURN_ERROR(X) \
+    do { \
+        ALOGE("%s:%d failed with '%s'", __func__, __LINE__, #X); \
+        return (X); \
+    } while (false)
+
+#define RETURN(X) return (X)
+
+#endif  // ANDROID_GOLDFISH_OPENGL_SYSTEM_CBMANAGER_DEBUG_H
diff --git a/system/cbmanager/hidl.cpp b/system/cbmanager/hidl.cpp
new file mode 100644
index 0000000..46b6b1b
--- /dev/null
+++ b/system/cbmanager/hidl.cpp
@@ -0,0 +1,387 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <cutils/native_handle.h>
+#include <android/hardware/graphics/allocator/2.0/IAllocator.h>
+#include <android/hardware/graphics/allocator/3.0/IAllocator.h>
+#include <android/hardware/graphics/mapper/2.0/IMapper.h>
+#include <android/hardware/graphics/mapper/3.0/IMapper.h>
+#include <log/log.h>
+
+#include "cbmanager.h"
+#include "debug.h"
+
+namespace android {
+namespace {
+using hardware::hidl_handle;
+using hardware::hidl_vec;
+
+namespace IMapper2ns = hardware::graphics::mapper::V2_0;
+namespace IMapper3ns = hardware::graphics::mapper::V3_0;
+namespace IAllocator2ns = hardware::graphics::allocator::V2_0;
+namespace IAllocator3ns = hardware::graphics::allocator::V3_0;
+
+class CbManagerHidlV3Impl : public CbManager::CbManagerImpl {
+public:
+    typedef CbManager::BufferUsage BufferUsage;
+    typedef CbManager::PixelFormat PixelFormat;
+    typedef CbManager::YCbCrLayout YCbCrLayout;
+    typedef hardware::hidl_bitfield<BufferUsage> BufferUsageBits;
+
+    CbManagerHidlV3Impl(sp<IMapper3ns::IMapper> mapper,
+                        sp<IAllocator3ns::IAllocator> allocator)
+      : mMapper(mapper), mAllocator(allocator) {}
+
+    native_handle_t* allocateBuffer(int width, int height,
+                                    PixelFormat format, BufferUsageBits usage) {
+        using IMapper3ns::Error;
+        using IMapper3ns::BufferDescriptor;
+
+        IMapper3ns::IMapper::BufferDescriptorInfo descriptor_info;
+        descriptor_info.width = width;
+        descriptor_info.height = height;
+        descriptor_info.layerCount = 1;
+        descriptor_info.format =
+            static_cast<hardware::graphics::common::V1_2::PixelFormat>(format);
+        descriptor_info.usage = usage;
+        Error hidl_err = Error::NONE;
+
+        BufferDescriptor descriptor;
+        mMapper->createDescriptor(descriptor_info,
+                                  [&](const Error &_error,
+                                      const BufferDescriptor &_descriptor) {
+            hidl_err = _error;
+            descriptor = _descriptor;
+        });
+        if (hidl_err != Error::NONE) {
+            RETURN_ERROR(nullptr);
+        }
+
+        hidl_handle raw_handle = nullptr;
+        mAllocator->allocate(descriptor, 1,
+                             [&](const Error &_error,
+                                 uint32_t _stride,
+                                 const hidl_vec<hidl_handle> &_buffers) {
+            hidl_err = _error;
+            (void)_stride;
+            raw_handle = _buffers[0];
+        });
+        if (hidl_err != Error::NONE) {
+            RETURN_ERROR(nullptr);
+        }
+
+        native_handle_t *buf = nullptr;
+        mMapper->importBuffer(raw_handle, [&](const Error &_error,
+                                              void *_buf) {
+            hidl_err = _error;
+            buf = static_cast<native_handle_t*>(_buf);
+        });
+        if (hidl_err != Error::NONE) {
+            RETURN_ERROR(nullptr);
+        }
+
+        RETURN(buf);
+    }
+
+    void freeBuffer(const native_handle_t* _h) {
+        using IMapper2ns::Error;
+
+        native_handle_t* h = const_cast<native_handle_t*>(_h);
+
+        mMapper->freeBuffer(h);
+        native_handle_close(h);
+        native_handle_delete(h);
+    }
+
+    int lockBuffer(native_handle_t& handle,
+                   BufferUsageBits usage,
+                   int left, int top, int width, int height,
+                   void** vaddr) {
+        using IMapper3ns::Error;
+
+        Error hidl_err = Error::NONE;
+        mMapper->lock(
+            &handle,
+            usage,
+            { left, top, width, height },  // rect
+            hidl_handle(),  // fence
+            [&hidl_err, vaddr](const Error &_error,
+                               void* _ptr,
+                               int32_t /*bytesPerPixel*/,
+                               int32_t /*bytesPerStride*/) {
+                hidl_err = _error;
+                if (_error == Error::NONE) {
+                    *vaddr = _ptr;
+                }
+            });
+
+        if (hidl_err == Error::NONE) {
+            RETURN(0);
+        } else {
+            RETURN_ERROR(-1);
+        }
+    }
+
+    int lockYCbCrBuffer(native_handle_t& handle,
+                        BufferUsageBits usage,
+                        int left, int top, int width, int height,
+                        YCbCrLayout* ycbcr) {
+        using IMapper3ns::Error;
+        typedef IMapper3ns::YCbCrLayout YCbCrLayout3;
+
+        Error hidl_err = Error::NONE;
+        mMapper->lockYCbCr(
+            &handle,
+            usage,
+            { left, top, width, height },  // rect
+            hidl_handle(),  // fence
+            [&hidl_err, ycbcr](const Error &_error,
+                               const YCbCrLayout3 &_ycbcr) {
+                hidl_err = _error;
+                if (_error == Error::NONE) {
+                    ycbcr->y = _ycbcr.y;
+                    ycbcr->cb = _ycbcr.cb;
+                    ycbcr->cr = _ycbcr.cr;
+                    ycbcr->yStride = _ycbcr.yStride;
+                    ycbcr->cStride = _ycbcr.cStride;
+                    ycbcr->chromaStep = _ycbcr.chromaStep;
+                }
+            });
+
+        if (hidl_err == Error::NONE) {
+            RETURN(0);
+        } else {
+            RETURN_ERROR(-1);
+        }
+    }
+
+    int unlockBuffer(native_handle_t& handle) {
+        using IMapper3ns::Error;
+
+        Error hidl_err = Error::NONE;
+        int fence = -1;
+        mMapper->unlock(
+            &handle,
+            [&hidl_err, &fence](const Error &_error,
+                                const hidl_handle &_fence) {
+                hidl_err = _error;
+                (void)_fence;
+            });
+
+        if (hidl_err == Error::NONE) {
+            RETURN(0);
+        } else {
+            RETURN_ERROR(-1);
+        }
+    }
+
+private:
+    const sp<IMapper3ns::IMapper> mMapper;
+    const sp<IAllocator3ns::IAllocator> mAllocator;
+};
+
+class CbManagerHidlV2Impl : public CbManager::CbManagerImpl {
+public:
+    typedef CbManager::BufferUsage BufferUsage;
+    typedef CbManager::PixelFormat PixelFormat;
+    typedef CbManager::YCbCrLayout YCbCrLayout;
+    typedef hardware::hidl_bitfield<BufferUsage> BufferUsageBits;
+
+    CbManagerHidlV2Impl(sp<IMapper2ns::IMapper> mapper,
+                        sp<IAllocator2ns::IAllocator> allocator)
+      : mMapper(mapper), mAllocator(allocator) {}
+
+    native_handle_t* allocateBuffer(int width, int height,
+                                    PixelFormat format, BufferUsageBits usage) {
+        using IMapper2ns::Error;
+        using IMapper2ns::BufferDescriptor;
+
+        IMapper2ns::IMapper::BufferDescriptorInfo descriptor_info;
+        descriptor_info.width = width;
+        descriptor_info.height = height;
+        descriptor_info.layerCount = 1;
+        descriptor_info.format = format;
+        descriptor_info.usage = usage;
+        Error hidl_err = Error::NONE;
+
+        BufferDescriptor descriptor;
+        mMapper->createDescriptor(descriptor_info,
+                                  [&](const Error &_error,
+                                      const BufferDescriptor &_descriptor) {
+            hidl_err = _error;
+            descriptor = _descriptor;
+        });
+        if (hidl_err != Error::NONE) {
+            RETURN_ERROR(nullptr);
+        }
+
+        hidl_handle raw_handle = nullptr;
+        mAllocator->allocate(descriptor, 1,
+                             [&](const Error &_error,
+                                 uint32_t _stride,
+                                 const hidl_vec<hidl_handle> &_buffers) {
+            hidl_err = _error;
+            (void)_stride;
+            raw_handle = _buffers[0];
+        });
+        if (hidl_err != Error::NONE) {
+            RETURN_ERROR(nullptr);
+        }
+
+        native_handle_t *buf = nullptr;
+        mMapper->importBuffer(raw_handle, [&](const Error &_error,
+                                              void *_buf) {
+            hidl_err = _error;
+            buf = static_cast<native_handle_t*>(_buf);
+        });
+        if (hidl_err != Error::NONE) {
+            RETURN_ERROR(nullptr);
+        }
+
+        RETURN(buf);
+    }
+
+    void freeBuffer(const native_handle_t* _h) {
+        using IMapper2ns::Error;
+
+        native_handle_t* h = const_cast<native_handle_t*>(_h);
+
+        mMapper->freeBuffer(h);
+        native_handle_close(h);
+        native_handle_delete(h);
+    }
+
+    int lockBuffer(native_handle_t& handle,
+                   BufferUsageBits usage,
+                   int left, int top, int width, int height,
+                   void** vaddr) {
+        using IMapper2ns::Error;
+
+        Error hidl_err = Error::NONE;
+        mMapper->lock(
+            &handle,
+            usage,
+            { left, top, width, height },  // rect
+            hidl_handle(),  // fence
+            [&hidl_err, vaddr](const Error &_error,
+                               void* _ptr) {
+                hidl_err = _error;
+                if (_error == Error::NONE) {
+                    *vaddr = _ptr;
+                }
+            });
+
+        if (hidl_err == Error::NONE) {
+            RETURN(0);
+        } else {
+            RETURN_ERROR(-1);
+        }
+    }
+
+    int lockYCbCrBuffer(native_handle_t& handle,
+                        BufferUsageBits usage,
+                        int left, int top, int width, int height,
+                        YCbCrLayout* ycbcr) {
+        using IMapper2ns::Error;
+
+        Error hidl_err = Error::NONE;
+        mMapper->lockYCbCr(
+            &handle,
+            usage,
+            { left, top, width, height },  // rect
+            hidl_handle(),  // fence
+            [&hidl_err, ycbcr](const Error &_error,
+                               const YCbCrLayout &_ycbcr) {
+                hidl_err = _error;
+                if (_error == Error::NONE) {
+                    *ycbcr = _ycbcr;
+                }
+            });
+
+        if (hidl_err == Error::NONE) {
+            RETURN(0);
+        } else {
+            RETURN_ERROR(-1);
+        }
+    }
+
+    int unlockBuffer(native_handle_t& handle) {
+        using IMapper2ns::Error;
+
+        Error hidl_err = Error::NONE;
+        int fence = -1;
+        mMapper->unlock(
+            &handle,
+            [&hidl_err, &fence](const Error &_error,
+                                const hidl_handle &_fence) {
+                hidl_err = _error;
+                (void)_fence;
+            });
+
+        if (hidl_err == Error::NONE) {
+            RETURN(0);
+        } else {
+            RETURN_ERROR(-1);
+        }
+    }
+
+private:
+    const sp<IMapper2ns::IMapper> mMapper;
+    const sp<IAllocator2ns::IAllocator> mAllocator;
+};
+
+std::unique_ptr<CbManager::CbManagerImpl> buildHidlImpl() {
+    {
+        sp<IMapper3ns::IMapper> mapper =
+            IMapper3ns::IMapper::getService();
+        if (!mapper) {
+           ALOGW("%s:%d: no IMapper@3.0 implementation found", __func__, __LINE__);
+        }
+
+        sp<IAllocator3ns::IAllocator> allocator =
+            IAllocator3ns::IAllocator::getService();
+        if (!allocator) {
+            ALOGW("%s:%d: no IAllocator@3.0 implementation found", __func__, __LINE__);
+        }
+
+        if (mapper && allocator) {
+            return std::make_unique<CbManagerHidlV3Impl>(mapper, allocator);
+        }
+    }
+    {
+        sp<IMapper2ns::IMapper> mapper =
+            IMapper2ns::IMapper::getService();
+        if (!mapper) {
+            ALOGW("%s:%d: no IMapper@2.0 implementation found", __func__, __LINE__);
+        }
+
+        sp<IAllocator2ns::IAllocator> allocator =
+            IAllocator2ns::IAllocator::getService();
+        if (!allocator) {
+            ALOGW("%s:%d: no IAllocator@2.0 implementation found", __func__, __LINE__);
+        }
+
+        return std::make_unique<CbManagerHidlV2Impl>(mapper, allocator);
+    }
+
+    return nullptr;
+}
+
+}  // namespace
+
+CbManager::CbManager() : mImpl(buildHidlImpl()) {}
+
+}  // namespace android
diff --git a/system/cbmanager/host.cpp b/system/cbmanager/host.cpp
new file mode 100644
index 0000000..c1a46af
--- /dev/null
+++ b/system/cbmanager/host.cpp
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <hardware/gralloc.h>
+#include "cbmanager.h"
+
+namespace android {
+namespace {
+
+class CbManagerHostImpl : public CbManager::CbManagerImpl {
+public:
+    CbManagerHostImpl() {}
+
+    ~CbManagerHostImpl() {}
+
+    const cb_handle_t* allocateBuffer(int width, int height, int format) {
+        return nullptr;
+    }
+
+    void freeBuffer(const cb_handle_t* h) {
+    }
+
+private:
+};
+
+std::unique_ptr<CbManager::CbManagerImpl> buildHostImpl() {
+    return std::make_unique<CbManagerHostImpl>();
+}
+}  // namespace
+
+CbManager::CbManager() : mImpl(buildHostImpl()) {}
+
+}  // namespace android
diff --git a/system/codecs/Android.mk b/system/codecs/Android.mk
new file mode 100644
index 0000000..5053e7d
--- /dev/null
+++ b/system/codecs/Android.mk
@@ -0,0 +1 @@
+include $(call all-subdir-makefiles)
diff --git a/system/codecs/omx/Android.mk b/system/codecs/omx/Android.mk
new file mode 100644
index 0000000..c307f8e
--- /dev/null
+++ b/system/codecs/omx/Android.mk
@@ -0,0 +1,16 @@
+#
+# Copyright 2018 The Android Open-Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+include $(call all-subdir-makefiles)
diff --git a/system/codecs/omx/avcdec/Android.mk b/system/codecs/omx/avcdec/Android.mk
new file mode 100644
index 0000000..798255f
--- /dev/null
+++ b/system/codecs/omx/avcdec/Android.mk
@@ -0,0 +1,55 @@
+#
+# Copyright 2019 The Android Open-Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+LOCAL_PATH := $(call my-dir)
+
+commonSources := \
+        GoldfishAVCDec.cpp  \
+        MediaH264Decoder.cpp
+
+$(call emugl-begin-shared-library,libstagefright_goldfish_avcdec$(GOLDFISH_OPENGL_LIB_SUFFIX))
+
+LOCAL_SRC_FILES := $(commonSources)
+
+LOCAL_CFLAGS += -DLOG_TAG=\"goldfish_avcdec\"
+LOCAL_CFLAGS += -Wno-unused-private-field
+
+$(call emugl-export,SHARED_LIBRARIES,libcutils libutils liblog)
+
+LOCAL_HEADER_LIBRARIES := media_plugin_headers \
+                          libmedia_headers \
+                          libbinder_headers \
+                          libhidlbase_impl_internal \
+                          libbase
+LOCAL_HEADER_LIBRARIES += libui_headers \
+                          libnativewindow_headers \
+                          libhardware_headers \
+                          libarect_headers \
+                          libarect_headers_for_ndk
+LOCAL_SHARED_LIBRARIES :=       \
+        libbinder               \
+        libutils                \
+        liblog                  \
+        libcutils               \
+        libui \
+        android.hardware.media.omx@1.0 \
+	    android.hardware.graphics.allocator@3.0 \
+		android.hardware.graphics.mapper@3.0 \
+        libstagefright_foundation
+
+$(call emugl-export,C_INCLUDES,$(LOCAL_PATH))
+$(call emugl-import,libgoldfish_codecs_common)
+$(call emugl-import,libstagefrighthw)
+$(call emugl-end-module)
diff --git a/system/codecs/omx/avcdec/GoldfishAVCDec.cpp b/system/codecs/omx/avcdec/GoldfishAVCDec.cpp
new file mode 100644
index 0000000..027524e
--- /dev/null
+++ b/system/codecs/omx/avcdec/GoldfishAVCDec.cpp
@@ -0,0 +1,638 @@
+/*
+ * Copyright 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+#include <utils/Log.h>
+
+#define DEBUG  0
+#if DEBUG
+#  define  DDD(...)    ALOGD(__VA_ARGS__)
+#else
+#  define  DDD(...)    ((void)0)
+#endif
+
+#include "GoldfishAVCDec.h"
+
+#include <media/stagefright/foundation/ADebug.h>
+#include <media/stagefright/MediaDefs.h>
+#include <OMX_VideoExt.h>
+#include <inttypes.h>
+
+#include <nativebase/nativebase.h>
+
+#include <android/hardware/graphics/allocator/3.0/IAllocator.h>
+#include <android/hardware/graphics/mapper/3.0/IMapper.h>
+#include <hidl/LegacySupport.h>
+
+using ::android::hardware::graphics::common::V1_2::PixelFormat;
+using ::android::hardware::graphics::common::V1_0::BufferUsage;
+
+namespace android {
+
+#define componentName                   "video_decoder.avc"
+#define codingType                      OMX_VIDEO_CodingAVC
+#define CODEC_MIME_TYPE                 MEDIA_MIMETYPE_VIDEO_AVC
+
+/** Function and structure definitions to keep code similar for each codec */
+#define ivdec_api_function              ih264d_api_function
+#define ivdext_create_ip_t              ih264d_create_ip_t
+#define ivdext_create_op_t              ih264d_create_op_t
+#define ivdext_delete_ip_t              ih264d_delete_ip_t
+#define ivdext_delete_op_t              ih264d_delete_op_t
+#define ivdext_ctl_set_num_cores_ip_t   ih264d_ctl_set_num_cores_ip_t
+#define ivdext_ctl_set_num_cores_op_t   ih264d_ctl_set_num_cores_op_t
+
+#define IVDEXT_CMD_CTL_SET_NUM_CORES    \
+        (IVD_CONTROL_API_COMMAND_TYPE_T)IH264D_CMD_CTL_SET_NUM_CORES
+
+static const CodecProfileLevel kProfileLevels[] = {
+    { OMX_VIDEO_AVCProfileConstrainedBaseline, OMX_VIDEO_AVCLevel52 },
+
+    { OMX_VIDEO_AVCProfileBaseline, OMX_VIDEO_AVCLevel52 },
+
+    { OMX_VIDEO_AVCProfileMain,     OMX_VIDEO_AVCLevel52 },
+
+    { OMX_VIDEO_AVCProfileConstrainedHigh,     OMX_VIDEO_AVCLevel52 },
+
+    { OMX_VIDEO_AVCProfileHigh,     OMX_VIDEO_AVCLevel52 },
+};
+
+GoldfishAVCDec::GoldfishAVCDec(
+        const char *name,
+        const OMX_CALLBACKTYPE *callbacks,
+        OMX_PTR appData,
+        OMX_COMPONENTTYPE **component, RenderMode renderMode)
+    : GoldfishVideoDecoderOMXComponent(
+            name, componentName, codingType,
+            kProfileLevels, ARRAY_SIZE(kProfileLevels),
+            320 /* width */, 240 /* height */, callbacks,
+            appData, component),
+      mOmxColorFormat(OMX_COLOR_FormatYUV420Planar),
+      mChangingResolution(false),
+      mSignalledError(false),
+      mInputOffset(0), mRenderMode(renderMode){
+    initPorts(
+            1 /* numMinInputBuffers */, kNumBuffers, INPUT_BUF_SIZE,
+            1 /* numMinOutputBuffers */, kNumBuffers, CODEC_MIME_TYPE);
+
+    mTimeStart = mTimeEnd = systemTime();
+
+    // If input dump is enabled, then open create an empty file
+    GENERATE_FILE_NAMES();
+    CREATE_DUMP_FILE(mInFile);
+    ALOGI("created %s %d object %p", __func__, __LINE__, this);
+}
+
+GoldfishAVCDec::~GoldfishAVCDec() {
+    CHECK_EQ(deInitDecoder(), (status_t)OK);
+    DDD("destroyed %s %d object %p", __func__, __LINE__, this);
+}
+
+void GoldfishAVCDec::logVersion() {
+    // TODO: get emulation decoder implementation version from the host.
+    ALOGI("GoldfishAVC decoder version 1.0");
+}
+
+status_t GoldfishAVCDec::resetPlugin() {
+    mIsInFlush = false;
+    mReceivedEOS = false;
+
+    /* Initialize both start and end times */
+    mTimeStart = mTimeEnd = systemTime();
+
+    return OK;
+}
+
+status_t GoldfishAVCDec::resetDecoder() {
+    if (mContext) {
+    // The resolution may have changed, so our safest bet is to just destroy the
+    // current context and recreate another one, with the new width and height.
+    mContext->destroyH264Context();
+    mContext.reset(nullptr);
+
+    }
+    return OK;
+}
+
+status_t GoldfishAVCDec::setFlushMode() {
+    /* Set the decoder in Flush mode, subsequent decode() calls will flush */
+    mIsInFlush = true;
+    mContext->flush();
+    return OK;
+}
+
+status_t GoldfishAVCDec::initDecoder() {
+    /* Initialize the decoder */
+    mContext.reset(new MediaH264Decoder(mRenderMode));
+    mContext->initH264Context(mWidth,
+                              mHeight,
+                              mWidth,
+                              mHeight,
+                              MediaH264Decoder::PixelFormat::YUV420P);
+
+    /* Reset the plugin state */
+    resetPlugin();
+
+    /* Get codec version */
+    logVersion();
+
+    return OK;
+}
+
+status_t GoldfishAVCDec::deInitDecoder() {
+    if (mContext) {
+        mContext->destroyH264Context();
+        mContext.reset();
+    }
+
+    mChangingResolution = false;
+
+    return OK;
+}
+
+void GoldfishAVCDec::onReset() {
+    GoldfishVideoDecoderOMXComponent::onReset();
+
+    mSignalledError = false;
+    mInputOffset = 0;
+    resetDecoder();
+    resetPlugin();
+}
+
+bool GoldfishAVCDec::getVUIParams(h264_image_t& img) {
+    int32_t primaries = img.color_primaries;
+    bool fullRange = img.color_range == 2 ? true : false;
+    int32_t transfer = img.color_trc;
+    int32_t coeffs = img.colorspace;
+
+    ColorAspects colorAspects;
+    ColorUtils::convertIsoColorAspectsToCodecAspects(
+            primaries, transfer, coeffs, fullRange, colorAspects);
+
+    DDD("img pts %lld, primaries %d, range %d transfer %d colorspace %d", (long long)img.pts,
+            (int)img.color_primaries, (int)img.color_range, (int)img.color_trc, (int)img.colorspace);
+
+    // Update color aspects if necessary.
+    if (colorAspectsDiffer(colorAspects, mBitstreamColorAspects)) {
+        mBitstreamColorAspects = colorAspects;
+        status_t err = handleColorAspectsChange();
+        CHECK(err == OK);
+    }
+    return true;
+}
+
+bool GoldfishAVCDec::setDecodeArgs(
+        OMX_BUFFERHEADERTYPE *inHeader,
+        OMX_BUFFERHEADERTYPE *outHeader) {
+    size_t sizeY = outputBufferWidth() * outputBufferHeight();
+    size_t sizeUV = sizeY / 4;
+
+    /* When in flush and after EOS with zero byte input,
+     * inHeader is set to zero. Hence check for non-null */
+    if (inHeader) {
+        mConsumedBytes = inHeader->nFilledLen - mInputOffset;
+        mInPBuffer = inHeader->pBuffer + inHeader->nOffset + mInputOffset;
+        DDD("got input timestamp %lld in-addr-base %p real-data-offset %d inputoffset %d", (long long)(inHeader->nTimeStamp),
+                inHeader->pBuffer, (int)(inHeader->nOffset + mInputOffset), (int)mInputOffset);
+    } else {
+        mConsumedBytes = 0;
+        mInPBuffer = nullptr;
+    }
+
+    if (outHeader) {
+        if (outHeader->nAllocLen < sizeY + (sizeUV * 2)) {
+            ALOGE("outHeader->nAllocLen %d < needed size %d", outHeader->nAllocLen, (int)(sizeY + sizeUV * 2));
+            android_errorWriteLog(0x534e4554, "27833616");
+            return false;
+        }
+        mOutHeaderBuf = outHeader->pBuffer;
+    } else {
+        // We flush out on the host side
+        mOutHeaderBuf = nullptr;
+    }
+
+    return true;
+}
+
+void GoldfishAVCDec::readAndDiscardAllHostBuffers() {
+    while (mContext) {
+        h264_image_t img = mContext->getImage();
+        if (img.data != nullptr) {
+            DDD("img pts %lld is discarded", (long long)img.pts);
+        } else {
+            return;
+        }
+    }
+}
+
+void GoldfishAVCDec::onPortFlushCompleted(OMX_U32 portIndex) {
+    /* Once the output buffers are flushed, ignore any buffers that are held in decoder */
+    if (kOutputPortIndex == portIndex) {
+        setFlushMode();
+        DDD("%s %d", __func__, __LINE__);
+        readAndDiscardAllHostBuffers();
+        mContext->resetH264Context(mWidth, mHeight, mWidth, mHeight, MediaH264Decoder::PixelFormat::YUV420P);
+        if (!mCsd0.empty() && !mCsd1.empty()) {
+            mContext->decodeFrame(&(mCsd0[0]), mCsd0.size(), 0);
+            mContext->getImage();
+            mContext->decodeFrame(&(mCsd1[0]), mCsd1.size(), 0);
+            mContext->getImage();
+        }
+        resetPlugin();
+    } else {
+        mInputOffset = 0;
+    }
+}
+
+void GoldfishAVCDec::copyImageData( OMX_BUFFERHEADERTYPE *outHeader, h264_image_t & img) {
+    int myStride = outputBufferWidth();
+    for (int i=0; i < mHeight; ++i) {
+        memcpy(outHeader->pBuffer + i * myStride, img.data + i * mWidth, mWidth);
+    }
+    int Y = myStride * outputBufferHeight();
+    for (int i=0; i < mHeight/2; ++i) {
+        memcpy(outHeader->pBuffer + Y + i * myStride / 2 , img.data + mWidth * mHeight + i * mWidth/2, mWidth/2);
+    }
+    int UV = Y/4;
+    for (int i=0; i < mHeight/2; ++i) {
+        memcpy(outHeader->pBuffer + Y + UV + i * myStride / 2 , img.data + mWidth * mHeight * 5/4 + i * mWidth/2, mWidth/2);
+    }
+}
+
+int GoldfishAVCDec::getHostColorBufferId(void* header) {
+  if (mNWBuffers.find(header) == mNWBuffers.end()) {
+      DDD("cannot find color buffer for header %p", header);
+    return -1;
+  }
+  sp<ANativeWindowBuffer> nBuf = mNWBuffers[header];
+  cb_handle_t *handle = (cb_handle_t*)nBuf->handle;
+  DDD("found color buffer for header %p --> %d", header, handle->hostHandle);
+  return handle->hostHandle;
+}
+
+void GoldfishAVCDec::onQueueFilled(OMX_U32 portIndex) {
+    static int count1=0;
+    DDD("calling %s count %d object %p", __func__, ++count1, this);
+    UNUSED(portIndex);
+    OMX_BUFFERHEADERTYPE *inHeader = NULL;
+    BufferInfo *inInfo = NULL;
+
+    if (mSignalledError) {
+        return;
+    }
+    if (mOutputPortSettingsChange != NONE) {
+        return;
+    }
+
+    if (mContext == nullptr) {
+        if (OK != initDecoder()) {
+            ALOGE("Failed to initialize decoder");
+            notify(OMX_EventError, OMX_ErrorUnsupportedSetting, 0, NULL);
+            mSignalledError = true;
+            return;
+        }
+    }
+
+    List<BufferInfo *> &inQueue = getPortQueue(kInputPortIndex);
+    List<BufferInfo *> &outQueue = getPortQueue(kOutputPortIndex);
+
+    int count2=0;
+    while (!outQueue.empty()) {
+        DDD("calling %s in while loop count %d", __func__, ++count2);
+        BufferInfo *outInfo;
+        OMX_BUFFERHEADERTYPE *outHeader;
+
+        if (!mIsInFlush && (NULL == inHeader)) {
+            if (!inQueue.empty()) {
+                inInfo = *inQueue.begin();
+                inHeader = inInfo->mHeader;
+                if (inHeader == NULL) {
+                    inQueue.erase(inQueue.begin());
+                    inInfo->mOwnedByUs = false;
+                    continue;
+                }
+            } else {
+                break;
+            }
+        }
+
+        outInfo = *outQueue.begin();
+        outHeader = outInfo->mHeader;
+        outHeader->nFlags = 0;
+        outHeader->nTimeStamp = 0;
+        outHeader->nOffset = 0;
+
+        if (inHeader != NULL) {
+            if (inHeader->nFilledLen == 0) {
+                // An empty buffer can be end of stream (EOS) buffer, so
+                // we'll set the decoder in flush mode if so. If it's not EOS,
+                // then just release the buffer.
+                inQueue.erase(inQueue.begin());
+                inInfo->mOwnedByUs = false;
+                notifyEmptyBufferDone(inHeader);
+
+                if (!(inHeader->nFlags & OMX_BUFFERFLAG_EOS)) {
+                    return;
+                }
+
+                mReceivedEOS = true;
+                inHeader = NULL;
+                setFlushMode();
+            } else if (inHeader->nFlags & OMX_BUFFERFLAG_EOS) {
+                mReceivedEOS = true;
+            }
+        }
+
+        {
+            nsecs_t timeDelay, timeTaken;
+
+            if (!setDecodeArgs(inHeader, outHeader)) {
+                ALOGE("Decoder arg setup failed");
+                notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL);
+                mSignalledError = true;
+                return;
+            }
+
+            mTimeStart = systemTime();
+            /* Compute time elapsed between end of previous decode()
+             * to start of current decode() */
+            timeDelay = mTimeStart - mTimeEnd;
+
+            // TODO: We also need to send the timestamp
+            h264_result_t h264Res = {(int)MediaH264Decoder::Err::NoErr, 0};
+            if (inHeader != nullptr) {
+                if (inHeader->nFlags & OMX_BUFFERFLAG_CODECCONFIG) { 
+                    unsigned long mysize = (inHeader->nFilledLen - mInputOffset);
+                    uint8_t* mydata = mInPBuffer;
+                    if (mCsd0.empty()) {
+                        mCsd0.assign(mydata, mydata + mysize);
+                    } else if (mCsd1.empty()) {
+                        mCsd1.assign(mydata, mydata + mysize);
+                    }
+                }
+                DDD("Decoding frame(sz=%lu)", (unsigned long)(inHeader->nFilledLen - mInputOffset));
+                h264Res = mContext->decodeFrame(mInPBuffer,
+                                                inHeader->nFilledLen - mInputOffset,
+                                                inHeader->nTimeStamp);
+                mConsumedBytes = h264Res.bytesProcessed;
+                if (h264Res.ret == (int)MediaH264Decoder::Err::DecoderRestarted) {
+                    mChangingResolution = true;
+                }
+            } else {
+                DDD("No more input data. Attempting to get a decoded frame, if any.");
+            }
+            h264_image_t img = {};
+
+            bool readBackPixels = true;
+            if (mRenderMode == RenderMode::RENDER_BY_GUEST_CPU) {
+              img = mContext->getImage();
+            } else {
+                int hostColorBufferId = getHostColorBufferId(outHeader);
+                if (hostColorBufferId >= 0) {
+                    img = mContext->renderOnHostAndReturnImageMetadata(getHostColorBufferId(outHeader));
+                    readBackPixels = false;
+                } else {
+                    img = mContext->getImage();
+                }
+            }
+
+
+            if (img.data != nullptr) {
+                getVUIParams(img);
+            }
+
+            mTimeEnd = systemTime();
+            /* Compute time taken for decode() */
+            timeTaken = mTimeEnd - mTimeStart;
+
+
+            if (inHeader) {
+                DDD("input time stamp %lld flag %d", inHeader->nTimeStamp, (int)(inHeader->nFlags));
+            }
+
+            // If the decoder is in the changing resolution mode and there is no output present,
+            // that means the switching is done and it's ready to reset the decoder and the plugin.
+            if (mChangingResolution && img.data == nullptr) {
+                mChangingResolution = false;
+                DDD("re-create decoder because resolution changed");
+                bool portWillReset = false;
+                handlePortSettingsChange(&portWillReset, img.width, img.height);
+                {
+                    DDD("handling port reset");
+                    DDD("port resetting (img.width=%u, img.height=%u, mWidth=%u, mHeight=%u)",
+                          img.width, img.height, mWidth, mHeight);
+                    //resetDecoder();
+                    resetPlugin();
+
+                //mContext->destroyH264Context();
+                //mContext.reset(new MediaH264Decoder());
+                mContext->resetH264Context(mWidth,
+                              mHeight,
+                              mWidth,
+                              mHeight,
+                              MediaH264Decoder::PixelFormat::YUV420P);
+                //mInputOffset += mConsumedBytes;
+                return;
+                }
+            }
+
+            if (img.data != nullptr) {
+                int myWidth = img.width;
+                int myHeight = img.height;
+                if (myWidth != mWidth || myHeight != mHeight) {
+                    bool portWillReset = false;
+                    handlePortSettingsChange(&portWillReset, myWidth, myHeight);
+                    resetPlugin();
+                    mWidth = myWidth;
+                    mHeight = myHeight;
+                    if (portWillReset) {
+                        DDD("port will reset return now");
+                        return;
+                    } else {
+                        DDD("port will NOT reset keep going now");
+                    }
+                }
+                outHeader->nFilledLen =  (outputBufferWidth() * outputBufferHeight() * 3) / 2;
+                if (readBackPixels) {
+                  if (outputBufferWidth() == mWidth && outputBufferHeight() == mHeight) {
+                    memcpy(outHeader->pBuffer, img.data, outHeader->nFilledLen);
+                  } else {
+                    copyImageData(outHeader, img);
+                  }
+                }
+
+                outHeader->nTimeStamp = img.pts;
+                DDD("got output timestamp %lld", (long long)(img.pts));
+
+                outInfo->mOwnedByUs = false;
+                outQueue.erase(outQueue.begin());
+                outInfo = NULL;
+                notifyFillBufferDone(outHeader);
+                outHeader = NULL;
+            } else if (mIsInFlush) {
+                DDD("not img.data and it is in flush mode");
+                /* If in flush mode and no output is returned by the codec,
+                 * then come out of flush mode */
+                mIsInFlush = false;
+
+                /* If EOS was recieved on input port and there is no output
+                 * from the codec, then signal EOS on output port */
+                if (mReceivedEOS) {
+                    ALOGI("received EOS, re-create host context");
+                    outHeader->nFilledLen = 0;
+                    outHeader->nFlags |= OMX_BUFFERFLAG_EOS;
+
+                    outInfo->mOwnedByUs = false;
+                    outQueue.erase(outQueue.begin());
+                    outInfo = NULL;
+                    notifyFillBufferDone(outHeader);
+                    outHeader = NULL;
+                    resetPlugin();
+
+                    //mContext->destroyH264Context();
+                //mContext.reset(new MediaH264Decoder());
+                    mContext->resetH264Context(mWidth,
+                              mHeight,
+                              mWidth,
+                              mHeight,
+                              MediaH264Decoder::PixelFormat::YUV420P);
+
+                }
+            }
+            mInputOffset += mConsumedBytes;
+        }
+
+        // If more than 4 bytes are remaining in input, then do not release it
+        if (inHeader != NULL && ((inHeader->nFilledLen - mInputOffset) <= 4)) {
+            inInfo->mOwnedByUs = false;
+            inQueue.erase(inQueue.begin());
+            inInfo = NULL;
+            notifyEmptyBufferDone(inHeader);
+            inHeader = NULL;
+            mInputOffset = 0;
+
+            /* If input EOS is seen and decoder is not in flush mode,
+             * set the decoder in flush mode.
+             * There can be a case where EOS is sent along with last picture data
+             * In that case, only after decoding that input data, decoder has to be
+             * put in flush. This case is handled here  */
+
+            if (mReceivedEOS && !mIsInFlush) {
+                setFlushMode();
+            }
+        }
+    }
+}
+
+OMX_ERRORTYPE GoldfishAVCDec::internalGetParameter(
+        OMX_INDEXTYPE index, OMX_PTR params) {
+    const int32_t indexFull = index;
+    switch (indexFull) {
+        case kGetAndroidNativeBufferUsageIndex:
+        {
+            DDD("calling kGetAndroidNativeBufferUsageIndex");
+            GetAndroidNativeBufferUsageParams* nativeBuffersUsage = (GetAndroidNativeBufferUsageParams *) params;
+            nativeBuffersUsage->nUsage = (unsigned int)(BufferUsage::GPU_DATA_BUFFER);
+            return OMX_ErrorNone;
+        }
+
+        default:
+            return GoldfishVideoDecoderOMXComponent::internalGetParameter(index, params);
+    }
+}
+
+OMX_ERRORTYPE GoldfishAVCDec::internalSetParameter(
+        OMX_INDEXTYPE index, const OMX_PTR params) {
+    // Include extension index OMX_INDEXEXTTYPE.
+    const int32_t indexFull = index;
+
+    switch (indexFull) {
+        case kEnableAndroidNativeBuffersIndex:
+        {
+            DDD("calling kEnableAndroidNativeBuffersIndex");
+            EnableAndroidNativeBuffersParams* enableNativeBuffers = (EnableAndroidNativeBuffersParams *) params;
+            if (enableNativeBuffers) {
+                mEnableAndroidNativeBuffers = enableNativeBuffers->enable;
+                if (mEnableAndroidNativeBuffers == false) {
+                    mNWBuffers.clear();
+                    DDD("disabled kEnableAndroidNativeBuffersIndex");
+                } else {
+                    DDD("enabled kEnableAndroidNativeBuffersIndex");
+                }
+            }
+            return OMX_ErrorNone;
+        }
+
+        case kUseAndroidNativeBufferIndex:
+        {
+            if (mEnableAndroidNativeBuffers == false) {
+                ALOGE("Error: not enabled Android Native Buffers");
+                return OMX_ErrorBadParameter;
+            }
+            UseAndroidNativeBufferParams *use_buffer_params = (UseAndroidNativeBufferParams *)params;
+            if (use_buffer_params) {
+                sp<ANativeWindowBuffer> nBuf = use_buffer_params->nativeBuffer;
+                cb_handle_t *handle = (cb_handle_t*)nBuf->handle;
+                void* dst = NULL;
+                DDD("kUseAndroidNativeBufferIndex with handle %p host color handle %d calling usebuffer", handle,
+                      handle->hostHandle);
+                useBufferCallerLockedAlready(use_buffer_params->bufferHeader,use_buffer_params->nPortIndex,
+                        use_buffer_params->pAppPrivate,handle->allocatedSize(), (OMX_U8*)dst);
+                mNWBuffers[*(use_buffer_params->bufferHeader)] = use_buffer_params->nativeBuffer;;
+            }
+            return OMX_ErrorNone;
+        }
+
+        default:
+            return GoldfishVideoDecoderOMXComponent::internalSetParameter(index, params);
+    }
+}
+
+OMX_ERRORTYPE GoldfishAVCDec::getExtensionIndex(
+        const char *name, OMX_INDEXTYPE *index) {
+
+    if (mRenderMode == RenderMode::RENDER_BY_HOST_GPU) {
+        if (!strcmp(name, "OMX.google.android.index.enableAndroidNativeBuffers")) {
+            DDD("calling getExtensionIndex for enable ANB");
+            *(int32_t*)index = kEnableAndroidNativeBuffersIndex;
+            return OMX_ErrorNone;
+        } else if (!strcmp(name, "OMX.google.android.index.useAndroidNativeBuffer")) {
+            *(int32_t*)index = kUseAndroidNativeBufferIndex;
+            return OMX_ErrorNone;
+        } else if (!strcmp(name, "OMX.google.android.index.getAndroidNativeBufferUsage")) {
+            *(int32_t*)index = kGetAndroidNativeBufferUsageIndex;
+            return OMX_ErrorNone;
+        }
+    }
+    return GoldfishVideoDecoderOMXComponent::getExtensionIndex(name, index);
+}
+
+int GoldfishAVCDec::getColorAspectPreference() {
+    return kPreferBitstream;
+}
+
+}  // namespace android
+
+android::GoldfishOMXComponent *createGoldfishOMXComponent(
+        const char *name, const OMX_CALLBACKTYPE *callbacks, OMX_PTR appData,
+        OMX_COMPONENTTYPE **component) {
+    if (!strncmp("OMX.android.goldfish", name, 20)) {
+      return new android::GoldfishAVCDec(name, callbacks, appData, component, RenderMode::RENDER_BY_HOST_GPU);
+    } else {
+      return new android::GoldfishAVCDec(name, callbacks, appData, component, RenderMode::RENDER_BY_GUEST_CPU);
+    }
+}
+
diff --git a/system/codecs/omx/avcdec/GoldfishAVCDec.h b/system/codecs/omx/avcdec/GoldfishAVCDec.h
new file mode 100644
index 0000000..dc9dc96
--- /dev/null
+++ b/system/codecs/omx/avcdec/GoldfishAVCDec.h
@@ -0,0 +1,184 @@
+/*
+ * Copyright 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef GOLDFISH_H264_DEC_H_
+
+#define GOLDFISH_H264_DEC_H_
+
+#include "GoldfishVideoDecoderOMXComponent.h"
+#include "MediaH264Decoder.h"
+#include <sys/time.h>
+
+#include <vector>
+#include <map>
+
+#include "gralloc_cb.h"
+#include <utils/RefBase.h>
+#include <utils/threads.h>
+#include <utils/Vector.h>
+#include <utils/List.h>
+#include <ui/GraphicBuffer.h>
+
+
+namespace android {
+
+/** Number of entries in the time-stamp array */
+#define MAX_TIME_STAMPS 64
+
+/** Maximum number of cores supported by the codec */
+#define CODEC_MAX_NUM_CORES 4
+
+#define CODEC_MAX_WIDTH     1920
+
+#define CODEC_MAX_HEIGHT    1088
+
+/** Input buffer size */
+#define INPUT_BUF_SIZE (1024 * 1024)
+
+#define MIN(a, b) ((a) < (b)) ? (a) : (b)
+
+/** Used to remove warnings about unused parameters */
+#define UNUSED(x) ((void)(x))
+
+struct GoldfishAVCDec : public GoldfishVideoDecoderOMXComponent {
+    GoldfishAVCDec(const char *name, const OMX_CALLBACKTYPE *callbacks,
+            OMX_PTR appData, OMX_COMPONENTTYPE **component, RenderMode renderMode);
+
+protected:
+    virtual ~GoldfishAVCDec();
+
+    virtual void onQueueFilled(OMX_U32 portIndex);
+    virtual void onPortFlushCompleted(OMX_U32 portIndex);
+    virtual void onReset();
+    virtual int getColorAspectPreference();
+
+    virtual OMX_ERRORTYPE internalGetParameter(OMX_INDEXTYPE index, OMX_PTR params);
+
+    virtual OMX_ERRORTYPE internalSetParameter(OMX_INDEXTYPE index, const OMX_PTR params);
+
+    virtual OMX_ERRORTYPE getExtensionIndex(const char *name, OMX_INDEXTYPE *index);
+
+private:
+    // Number of input and output buffers
+    enum {
+        kNumBuffers = 8
+    };
+
+    RenderMode  mRenderMode = RenderMode::RENDER_BY_GUEST_CPU;
+    bool mEnableAndroidNativeBuffers = false;
+    std::map<void*, sp<ANativeWindowBuffer>> mNWBuffers;
+
+    int getHostColorBufferId(void* header);
+
+    size_t mNumCores;            // Number of cores to be uesd by the codec
+
+    nsecs_t mTimeStart;   // Time at the start of decode()
+    nsecs_t mTimeEnd;     // Time at the end of decode()
+
+#ifdef FILE_DUMP_ENABLE
+    char mInFile[200];
+#endif /* FILE_DUMP_ENABLE */
+
+    OMX_COLOR_FORMATTYPE mOmxColorFormat;    // OMX Color format
+
+    bool mIsInFlush;        // codec is flush mode
+    bool mReceivedEOS;      // EOS is receieved on input port
+
+    // The input stream has changed to a different resolution, which is still supported by the
+    // codec. So the codec is switching to decode the new resolution.
+    bool mChangingResolution;
+    bool mSignalledError;
+    size_t mInputOffset;
+
+    status_t initDecoder();
+    status_t deInitDecoder();
+    status_t setFlushMode();
+    status_t setParams(size_t stride);
+    void logVersion();
+    status_t setNumCores();
+    status_t resetDecoder();
+    status_t resetPlugin();
+
+
+    void readAndDiscardAllHostBuffers();
+
+    bool setDecodeArgs(
+            OMX_BUFFERHEADERTYPE *inHeader,
+            OMX_BUFFERHEADERTYPE *outHeader);
+
+    bool getVUIParams(h264_image_t& img);
+
+    void copyImageData( OMX_BUFFERHEADERTYPE *outHeader, h264_image_t & img);
+
+    std::unique_ptr<MediaH264Decoder> mContext;
+    std::vector<uint8_t> mCsd0;
+    std::vector<uint8_t> mCsd1;
+    uint64_t mConsumedBytes = 0;
+    uint8_t* mInPBuffer = nullptr;
+    uint8_t* mOutHeaderBuf = nullptr;
+    DISALLOW_EVIL_CONSTRUCTORS(GoldfishAVCDec);
+};
+#ifdef FILE_DUMP_ENABLE
+
+#define INPUT_DUMP_PATH     "/sdcard/media/avcd_input"
+#define INPUT_DUMP_EXT      "h264"
+
+#define GENERATE_FILE_NAMES() {                         \
+    strcpy(mInFile, "");                                \
+    sprintf(mInFile, "%s_%lld.%s", INPUT_DUMP_PATH,     \
+            (long long) mTimeStart,                     \
+            INPUT_DUMP_EXT);                            \
+}
+
+#define CREATE_DUMP_FILE(m_filename) {                  \
+    FILE *fp = fopen(m_filename, "wb");                 \
+    if (fp != NULL) {                                   \
+        fclose(fp);                                     \
+    } else {                                            \
+        ALOGD("Could not open file %s", m_filename);    \
+    }                                                   \
+}
+#define DUMP_TO_FILE(m_filename, m_buf, m_size, m_offset)\
+{                                                       \
+    FILE *fp = fopen(m_filename, "ab");                 \
+    if (fp != NULL && m_buf != NULL && m_offset == 0) { \
+        int i;                                          \
+        i = fwrite(m_buf, 1, m_size, fp);               \
+        ALOGD("fwrite ret %d to write %d", i, m_size);  \
+        if (i != (int) m_size) {                        \
+            ALOGD("Error in fwrite, returned %d", i);   \
+            perror("Error in write to file");           \
+        }                                               \
+    } else if (fp == NULL) {                            \
+        ALOGD("Could not write to file %s", m_filename);\
+    }                                                   \
+    if (fp) {                                           \
+        fclose(fp);                                     \
+    }                                                   \
+}
+#else /* FILE_DUMP_ENABLE */
+#define INPUT_DUMP_PATH
+#define INPUT_DUMP_EXT
+#define OUTPUT_DUMP_PATH
+#define OUTPUT_DUMP_EXT
+#define GENERATE_FILE_NAMES()
+#define CREATE_DUMP_FILE(m_filename)
+#define DUMP_TO_FILE(m_filename, m_buf, m_size, m_offset)
+#endif /* FILE_DUMP_ENABLE */
+
+} // namespace android
+
+#endif  // GOLDFISH_H264_DEC_H_
diff --git a/system/codecs/omx/avcdec/MediaH264Decoder.cpp b/system/codecs/omx/avcdec/MediaH264Decoder.cpp
new file mode 100644
index 0000000..ac285a2
--- /dev/null
+++ b/system/codecs/omx/avcdec/MediaH264Decoder.cpp
@@ -0,0 +1,208 @@
+/*
+ * Copyright 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <utils/Log.h>
+
+#define DEBUG  0
+#if DEBUG
+#  define  DDD(...)    ALOGD(__VA_ARGS__)
+#else
+#  define  DDD(...)    ((void)0)
+#endif
+
+#include "MediaH264Decoder.h"
+#include "goldfish_media_utils.h"
+#include <string.h>
+
+MediaH264Decoder::MediaH264Decoder(RenderMode renderMode) :mRenderMode(renderMode) {
+  if (renderMode == RenderMode::RENDER_BY_HOST_GPU) {
+      mVersion = 200;
+  } else if (renderMode == RenderMode::RENDER_BY_GUEST_CPU) {
+      mVersion = 100;
+  }
+}
+
+void MediaH264Decoder::initH264Context(unsigned int width,
+                                       unsigned int height,
+                                       unsigned int outWidth,
+                                       unsigned int outHeight,
+                                       PixelFormat pixFmt) {
+    auto transport = GoldfishMediaTransport::getInstance();
+    if (!mHasAddressSpaceMemory) {
+        int slot = transport->getMemorySlot();
+        if (slot < 0) {
+            ALOGE("ERROR: Failed to initH264Context: cannot get memory slot");
+            return;
+        }
+        mAddressOffSet = static_cast<unsigned int>(slot) * 8 * (1 << 20);
+        DDD("got memory lot %d addrr %x", slot, mAddressOffSet);
+        mHasAddressSpaceMemory = true;
+    }
+    transport->writeParam(mVersion, 0, mAddressOffSet);
+    transport->writeParam(width, 1, mAddressOffSet);
+    transport->writeParam(height, 2, mAddressOffSet);
+    transport->writeParam(outWidth, 3, mAddressOffSet);
+    transport->writeParam(outHeight, 4, mAddressOffSet);
+    transport->writeParam(static_cast<uint64_t>(pixFmt), 5, mAddressOffSet);
+    transport->sendOperation(MediaCodecType::H264Codec,
+                             MediaOperation::InitContext, mAddressOffSet);
+    auto* retptr = transport->getReturnAddr(mAddressOffSet);
+    mHostHandle = *(uint64_t*)(retptr);
+    DDD("initH264Context: got handle to host %lld", mHostHandle);
+}
+
+
+void MediaH264Decoder::resetH264Context(unsigned int width,
+                                       unsigned int height,
+                                       unsigned int outWidth,
+                                       unsigned int outHeight,
+                                       PixelFormat pixFmt) {
+    auto transport = GoldfishMediaTransport::getInstance();
+    if (!mHasAddressSpaceMemory) {
+        ALOGE("%s no address space memory", __func__);
+        return;
+    }
+    transport->writeParam((uint64_t)mHostHandle, 0, mAddressOffSet);
+    transport->writeParam(width, 1, mAddressOffSet);
+    transport->writeParam(height, 2, mAddressOffSet);
+    transport->writeParam(outWidth, 3, mAddressOffSet);
+    transport->writeParam(outHeight, 4, mAddressOffSet);
+    transport->writeParam(static_cast<uint64_t>(pixFmt), 5, mAddressOffSet);
+    transport->sendOperation(MediaCodecType::H264Codec,
+                             MediaOperation::Reset, mAddressOffSet);
+    DDD("resetH264Context: done");
+}
+
+
+void MediaH264Decoder::destroyH264Context() {
+
+    DDD("return memory lot %d addrr %x", (int)(mAddressOffSet >> 23), mAddressOffSet);
+    auto transport = GoldfishMediaTransport::getInstance();
+    transport->writeParam((uint64_t)mHostHandle, 0, mAddressOffSet);
+    transport->sendOperation(MediaCodecType::H264Codec,
+                             MediaOperation::DestroyContext, mAddressOffSet);
+    transport->returnMemorySlot(mAddressOffSet >> 23);
+    mHasAddressSpaceMemory = false;
+}
+
+h264_result_t MediaH264Decoder::decodeFrame(uint8_t* img, size_t szBytes, uint64_t pts) {
+    DDD("decode frame: use handle to host %lld", mHostHandle);
+    h264_result_t res = {0, 0};
+    if (!mHasAddressSpaceMemory) {
+        ALOGE("%s no address space memory", __func__);
+        return res;
+    }
+    auto transport = GoldfishMediaTransport::getInstance();
+    uint8_t* hostSrc = transport->getInputAddr(mAddressOffSet);
+    if (img != nullptr && szBytes > 0) {
+        memcpy(hostSrc, img, szBytes);
+    }
+    transport->writeParam((uint64_t)mHostHandle, 0, mAddressOffSet);
+    transport->writeParam(transport->offsetOf((uint64_t)(hostSrc)) - mAddressOffSet, 1, mAddressOffSet);
+    transport->writeParam((uint64_t)szBytes, 2, mAddressOffSet);
+    transport->writeParam((uint64_t)pts, 3, mAddressOffSet);
+    transport->sendOperation(MediaCodecType::H264Codec,
+                             MediaOperation::DecodeImage, mAddressOffSet);
+
+
+    auto* retptr = transport->getReturnAddr(mAddressOffSet);
+    res.bytesProcessed = *(uint64_t*)(retptr);
+    res.ret = *(int*)(retptr + 8);
+
+    return res;
+}
+
+void MediaH264Decoder::flush() {
+    if (!mHasAddressSpaceMemory) {
+        ALOGE("%s no address space memory", __func__);
+        return;
+    }
+    DDD("flush: use handle to host %lld", mHostHandle);
+    auto transport = GoldfishMediaTransport::getInstance();
+    transport->writeParam((uint64_t)mHostHandle, 0, mAddressOffSet);
+    transport->sendOperation(MediaCodecType::H264Codec,
+                             MediaOperation::Flush, mAddressOffSet);
+}
+
+h264_image_t MediaH264Decoder::getImage() {
+    DDD("getImage: use handle to host %lld", mHostHandle);
+    h264_image_t res { };
+    if (!mHasAddressSpaceMemory) {
+        ALOGE("%s no address space memory", __func__);
+        return res;
+    }
+    auto transport = GoldfishMediaTransport::getInstance();
+    uint8_t* dst = transport->getInputAddr(mAddressOffSet); // Note: reuse the same addr for input and output
+    transport->writeParam((uint64_t)mHostHandle, 0, mAddressOffSet);
+    transport->writeParam(transport->offsetOf((uint64_t)(dst)) - mAddressOffSet, 1, mAddressOffSet);
+    transport->writeParam(-1, 2, mAddressOffSet);
+    transport->sendOperation(MediaCodecType::H264Codec,
+                             MediaOperation::GetImage, mAddressOffSet);
+    auto* retptr = transport->getReturnAddr(mAddressOffSet);
+    res.ret = *(int*)(retptr);
+    if (res.ret >= 0) {
+        res.data = dst;
+        res.width = *(uint32_t*)(retptr + 8);
+        res.height = *(uint32_t*)(retptr + 16);
+        res.pts = *(uint32_t*)(retptr + 24);
+        res.color_primaries = *(uint32_t*)(retptr + 32);
+        res.color_range = *(uint32_t*)(retptr + 40);
+        res.color_trc = *(uint32_t*)(retptr + 48);
+        res.colorspace = *(uint32_t*)(retptr + 56);
+    } else if (res.ret == (int)(Err::DecoderRestarted)) {
+        res.width = *(uint32_t*)(retptr + 8);
+        res.height = *(uint32_t*)(retptr + 16);
+    }
+    return res;
+}
+
+
+h264_image_t MediaH264Decoder::renderOnHostAndReturnImageMetadata(int hostColorBufferId) {
+    DDD("%s: use handle to host %lld", __func__, mHostHandle);
+    h264_image_t res { };
+    if (hostColorBufferId < 0) {
+      ALOGE("%s negative color buffer id %d", __func__, hostColorBufferId);
+      return res;
+    }
+    DDD("%s send color buffer id %d", __func__, hostColorBufferId);
+    if (!mHasAddressSpaceMemory) {
+        ALOGE("%s no address space memory", __func__);
+        return res;
+    }
+    auto transport = GoldfishMediaTransport::getInstance();
+    uint8_t* dst = transport->getInputAddr(mAddressOffSet); // Note: reuse the same addr for input and output
+    transport->writeParam((uint64_t)mHostHandle, 0, mAddressOffSet);
+    transport->writeParam(transport->offsetOf((uint64_t)(dst)) - mAddressOffSet, 1, mAddressOffSet);
+    transport->writeParam((uint64_t)hostColorBufferId, 2, mAddressOffSet);
+    transport->sendOperation(MediaCodecType::H264Codec,
+                             MediaOperation::GetImage, mAddressOffSet);
+    auto* retptr = transport->getReturnAddr(mAddressOffSet);
+    res.ret = *(int*)(retptr);
+    if (res.ret >= 0) {
+        res.data = dst; // note: the data could be junk
+        res.width = *(uint32_t*)(retptr + 8);
+        res.height = *(uint32_t*)(retptr + 16);
+        res.pts = *(uint32_t*)(retptr + 24);
+        res.color_primaries = *(uint32_t*)(retptr + 32);
+        res.color_range = *(uint32_t*)(retptr + 40);
+        res.color_trc = *(uint32_t*)(retptr + 48);
+        res.colorspace = *(uint32_t*)(retptr + 56);
+    } else if (res.ret == (int)(Err::DecoderRestarted)) {
+        res.width = *(uint32_t*)(retptr + 8);
+        res.height = *(uint32_t*)(retptr + 16);
+    }
+    return res;
+}
diff --git a/system/codecs/omx/avcdec/MediaH264Decoder.h b/system/codecs/omx/avcdec/MediaH264Decoder.h
new file mode 100644
index 0000000..8264d3c
--- /dev/null
+++ b/system/codecs/omx/avcdec/MediaH264Decoder.h
@@ -0,0 +1,96 @@
+/*
+ * Copyright 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef GOLDFISH_MEDIA_H264_DEC_H_
+#define GOLDFISH_MEDIA_H264_DEC_H_
+
+struct h264_init_result_t {
+    uint64_t host_handle;
+    int ret;
+};
+
+struct h264_result_t {
+    int ret;
+    uint64_t bytesProcessed;
+};
+
+struct h264_image_t {
+    const uint8_t* data;
+    uint32_t width;
+    uint32_t height;
+    uint64_t pts; // presentation time stamp
+    uint64_t color_primaries;
+    uint64_t color_range;
+    uint64_t color_trc;
+    uint64_t colorspace;
+    // on success, |ret| will indicate the size of |data|.
+    // If failed, |ret| will contain some negative error code.
+    int ret;
+};
+
+enum class RenderMode {
+  RENDER_BY_HOST_GPU = 1,
+  RENDER_BY_GUEST_CPU = 2,
+};
+
+class MediaH264Decoder {
+    uint64_t mHostHandle = 0;
+    uint32_t mVersion = 100;
+    RenderMode  mRenderMode = RenderMode::RENDER_BY_GUEST_CPU;
+
+    bool mHasAddressSpaceMemory = false;
+    uint64_t mAddressOffSet = 0;
+
+public:
+    MediaH264Decoder(RenderMode renderMode);
+    virtual ~MediaH264Decoder() = default;
+
+    enum class PixelFormat : uint8_t {
+        YUV420P = 0,
+        UYVY422 = 1,
+        BGRA8888 = 2,
+    };
+
+    enum class Err : int {
+        NoErr = 0,
+        NoDecodedFrame = -1,
+        InitContextFailed = -2,
+        DecoderRestarted = -3,
+        NALUIgnored = -4,
+    };
+
+    bool getAddressSpaceMemory();
+    void initH264Context(unsigned int width,
+                         unsigned int height,
+                         unsigned int outWidth,
+                         unsigned int outHeight,
+                         PixelFormat pixFmt);
+    void resetH264Context(unsigned int width,
+                         unsigned int height,
+                         unsigned int outWidth,
+                         unsigned int outHeight,
+                         PixelFormat pixFmt);
+    void destroyH264Context();
+    h264_result_t decodeFrame(uint8_t* img, size_t szBytes, uint64_t pts);
+    void flush();
+    // ask host to copy image data back to guest, with image metadata
+    // to guest as well
+    h264_image_t getImage();
+    // ask host to render to hostColorBufferId, return only image metadata back to
+    // guest
+    h264_image_t renderOnHostAndReturnImageMetadata(int hostColorBufferId);
+};
+#endif
diff --git a/system/codecs/omx/avcdec/exports.lds b/system/codecs/omx/avcdec/exports.lds
new file mode 100644
index 0000000..e6674f2
--- /dev/null
+++ b/system/codecs/omx/avcdec/exports.lds
@@ -0,0 +1,5 @@
+{
+    global:
+        _Z26createGoldfishOMXComponentPKcPK16OMX_CALLBACKTYPEPvPP17OMX_COMPONENTTYPE;
+    local: *;
+};
diff --git a/system/codecs/omx/common/Android.mk b/system/codecs/omx/common/Android.mk
new file mode 100644
index 0000000..50ce286
--- /dev/null
+++ b/system/codecs/omx/common/Android.mk
@@ -0,0 +1,32 @@
+#
+# Copyright 2019 The Android Open-Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+LOCAL_PATH := $(call my-dir)
+
+commonSources := \
+        goldfish_media_utils.cpp
+
+$(call emugl-begin-shared-library,libgoldfish_codecs_common$(GOLDFISH_OPENGL_LIB_SUFFIX))
+
+LOCAL_SRC_FILES := $(commonSources)
+
+LOCAL_CFLAGS += -DLOG_TAG=\"goldfish_codecs_common\"
+LOCAL_CFLAGS += -Wno-unused-private-field
+
+$(call emugl-export,SHARED_LIBRARIES,libcutils libutils liblog)
+
+$(call emugl-export,C_INCLUDES,$(LOCAL_PATH))
+$(call emugl-import,libOpenglSystemCommon)
+$(call emugl-end-module)
diff --git a/system/codecs/omx/common/goldfish_media_utils.cpp b/system/codecs/omx/common/goldfish_media_utils.cpp
new file mode 100644
index 0000000..9cd5063
--- /dev/null
+++ b/system/codecs/omx/common/goldfish_media_utils.cpp
@@ -0,0 +1,200 @@
+/*
+ * Copyright (C) 2018 Google, Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include "goldfish_media_utils.h"
+
+#include "goldfish_address_space.h"
+
+#include <log/log.h>
+
+#define DEBUG  0
+#if DEBUG
+#  define  DDD(...)    ALOGD(__VA_ARGS__)
+#else
+#  define  DDD(...)    ((void)0)
+#endif
+
+#include <memory>
+#include <vector>
+#include <mutex>
+
+
+
+std::mutex sSingletonMutex;
+std::unique_ptr<GoldfishMediaTransport> sTransport;
+
+class GoldfishMediaTransportImpl : public GoldfishMediaTransport {
+public:
+    GoldfishMediaTransportImpl();
+    ~GoldfishMediaTransportImpl();
+
+    virtual void writeParam(__u64 val, unsigned int num, unsigned int offSetToStartAddr = 0) override;
+    virtual bool sendOperation(MediaCodecType type, MediaOperation op, unsigned int offSetToStartAddr = 0) override;
+    virtual uint8_t* getBaseAddr() const override;
+    virtual uint8_t* getInputAddr(unsigned int offSet = 0) const override;
+    virtual uint8_t* getOutputAddr() const override;
+    virtual uint8_t* getReturnAddr(unsigned int offSet = 0) const override;
+    virtual __u64 offsetOf(uint64_t addr) const override;
+
+public:
+    // each lot has 8 M
+    virtual int getMemorySlot() override {
+        std::lock_guard<std::mutex> g{mMemoryMutex};
+        for (int i = mMemoryLotsAvailable.size() - 1; i >=0 ; --i) {
+            if (mMemoryLotsAvailable[i]) {
+                mMemoryLotsAvailable[i] = false;
+                return i;
+            }
+        }
+        return -1;
+    }
+    virtual void returnMemorySlot(int lot) override {
+        if (lot < 0 || lot >= mMemoryLotsAvailable.size()) {
+            return;
+        }
+        std::lock_guard<std::mutex> g{mMemoryMutex};
+        if (mMemoryLotsAvailable[lot] == false) {
+            mMemoryLotsAvailable[lot] = true;
+        } else {
+            ALOGE("Error, cannot twice");
+        }
+    }
+private:
+    std::mutex mMemoryMutex;
+    std::vector<bool> mMemoryLotsAvailable = {true, true, true, true};
+
+    address_space_handle_t mHandle;
+    uint64_t  mOffset;
+    uint64_t  mPhysAddr;
+    uint64_t  mSize;
+    void* mStartPtr = nullptr;
+
+    // MediaCodecType will be or'd together with the metadata, so the highest 8-bits
+    // will have the type.
+    static __u64 makeMetadata(MediaCodecType type,
+                              MediaOperation op, uint64_t offset);
+
+    // Chunk size for parameters/return data
+    static constexpr size_t kParamSizeBytes = 4096; // 4K
+    // Chunk size for input
+    static constexpr size_t kInputSizeBytes = 4096 * 4096; // 16M
+    // Chunk size for output
+    static constexpr size_t kOutputSizeBytes = 4096 * 4096; // 16M
+    // Maximum number of parameters that can be passed
+    static constexpr size_t kMaxParams = 32;
+    // Offset from the memory region for return data (8 is size of
+    // a parameter in bytes)
+    static constexpr size_t kReturnOffset = 8 * kMaxParams;
+};
+
+GoldfishMediaTransportImpl::~GoldfishMediaTransportImpl() {
+  if(mHandle >= 0) {
+    goldfish_address_space_close(mHandle);
+    mHandle = -1;
+  }
+}
+
+GoldfishMediaTransportImpl::GoldfishMediaTransportImpl() {
+    // Allocate host memory; the contiguous memory region will be laid out as
+    // follows:
+    // ========================================================
+    // | kParamSizeBytes | kInputSizeBytes | kOutputSizeBytes |
+    // ========================================================
+    mHandle = goldfish_address_space_open();
+    if (mHandle < 0) {
+        ALOGE("Failed to ping host to allocate memory");
+        abort();
+    }
+    mSize = kParamSizeBytes + kInputSizeBytes + kOutputSizeBytes;
+    bool success = goldfish_address_space_allocate(mHandle, mSize, &mPhysAddr, &mOffset);
+    if (success) {
+        ALOGI("successfully allocated %d bytes in goldfish_address_block", (int)mSize);
+        mStartPtr = goldfish_address_space_map(mHandle, mOffset, mSize);
+        ALOGI("guest address is %p", mStartPtr);
+
+        struct goldfish_address_space_ping pingInfo;
+        pingInfo.metadata = GoldfishAddressSpaceSubdeviceType::Media;
+        pingInfo.offset = mOffset;
+        if (goldfish_address_space_ping(mHandle, &pingInfo) == false) {
+            ALOGE("Failed to ping host to allocate memory");
+            abort();
+            return;
+        } else {
+            ALOGI("successfully pinged host to allocate memory");
+        }
+    } else {
+        ALOGE("failed to allocate %d bytes in goldfish_address_block", (int)mSize);
+        abort();
+    }
+}
+
+// static
+GoldfishMediaTransport* GoldfishMediaTransport::getInstance() {
+    std::lock_guard<std::mutex> g{sSingletonMutex};
+    if (sTransport == nullptr) {
+        sTransport.reset(new GoldfishMediaTransportImpl());
+    }
+    return sTransport.get();
+}
+
+// static
+__u64 GoldfishMediaTransportImpl::makeMetadata(MediaCodecType type,
+                                               MediaOperation op, uint64_t offset) {
+    // Shift |type| into the highest 8-bits, leaving the lower bits for other
+    // metadata.
+    offset = offset >> 20;
+    return ((__u64)type << (64 - 8)) | (offset << 8) | static_cast<uint8_t>(op);
+}
+
+uint8_t* GoldfishMediaTransportImpl::getInputAddr(unsigned int offSet) const {
+    return (uint8_t*)mStartPtr + kParamSizeBytes + offSet;
+}
+
+uint8_t* GoldfishMediaTransportImpl::getOutputAddr() const {
+    return getInputAddr() + kInputSizeBytes;
+}
+
+uint8_t* GoldfishMediaTransportImpl::getBaseAddr() const {
+    return (uint8_t*)mStartPtr;
+}
+
+uint8_t* GoldfishMediaTransportImpl::getReturnAddr(unsigned int offSet) const {
+    return (uint8_t*)mStartPtr + kReturnOffset + offSet;
+}
+
+__u64 GoldfishMediaTransportImpl::offsetOf(uint64_t addr) const {
+    return addr - (uint64_t)mStartPtr;
+}
+
+void GoldfishMediaTransportImpl::writeParam(__u64 val, unsigned int num, unsigned int offSetToStartAddr) {
+    uint8_t* p = (uint8_t*)mStartPtr + (offSetToStartAddr);
+    uint64_t* pint = (uint64_t*)(p + 8 * num);
+    *pint = val;
+}
+
+bool GoldfishMediaTransportImpl::sendOperation(MediaCodecType type,
+                                               MediaOperation op, unsigned int offSetToStartAddr) {
+    struct goldfish_address_space_ping pingInfo;
+    pingInfo.metadata = makeMetadata(type, op, offSetToStartAddr);
+    pingInfo.offset = mOffset; // + (offSetToStartAddr);
+    if (goldfish_address_space_ping(mHandle, &pingInfo) == false) {
+        ALOGE("failed to ping host");
+        abort();
+        return false;
+    } else {
+        DDD("successfully pinged host for operation type=%d, op=%d", (int)type, (int)op);
+    }
+
+    return true;
+}
diff --git a/system/codecs/omx/common/goldfish_media_utils.h b/system/codecs/omx/common/goldfish_media_utils.h
new file mode 100644
index 0000000..da57689
--- /dev/null
+++ b/system/codecs/omx/common/goldfish_media_utils.h
@@ -0,0 +1,100 @@
+/*
+ * Copyright (C) 2018 Google, Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/types.h>
+#include <stdint.h>
+
+#ifndef GOLDFISH_COMMON_GOLDFISH_DEFS_H
+#define GOLDFISH_COMMON_GOLDFISH_DEFS_H
+
+enum class MediaCodecType : __u8 {
+    VP8Codec = 0,
+    VP9Codec = 1,
+    H264Codec = 2,
+    Max = 3,
+};
+
+enum class MediaOperation : __u8 {
+    InitContext = 0,
+    DestroyContext = 1,
+    DecodeImage = 2,
+    GetImage = 3,
+    Flush = 4,
+    Reset = 5,
+    Max = 6,
+};
+
+// This class will abstract away the knowledge required to send media codec data
+// to the host. The implementation should only need the following information to
+// properly send the data:
+//   1) Which codec to use (MediaCodecType)
+//   2) What operation to perform (MediaOperation)
+//
+// Example:
+//   auto transport = GoldfishMediaTransport::getInstance();
+//
+class GoldfishMediaTransport {
+protected:
+    GoldfishMediaTransport() {}
+
+public:
+    virtual ~GoldfishMediaTransport() {}
+
+    // Writes a parameter to send to the host. Each parameter will take up
+    // 64-bits. |val| is the value of the parameter, and |num| is the parameter
+    // number, starting from 0. If |val| is an address, wrap it around
+    // offsetOf(), e.g., writeParam(offsetOf((uint64_t)ptr), 2);
+    virtual void writeParam(__u64 val, unsigned int num, unsigned int offSetToStartAddr = 0) = 0;
+    // Send the operation to perform to the host. At the time of this call, any
+    // parameters that the host needs should have already been passed using
+    // writeParam().
+    virtual bool sendOperation(MediaCodecType codec, MediaOperation op, unsigned int offSetToStartAddr = 0) = 0;
+    // Get the address for input. This is usually given the the codec context to
+    // write data into for the host to process.
+    virtual uint8_t* getInputAddr(unsigned int offSet = 0) const = 0;
+    // Get the address for base pointer
+    virtual uint8_t* getBaseAddr() const = 0;
+    // Get the address for output. This is usually given to the codec context to
+    // read data written there by the host.
+    virtual uint8_t* getOutputAddr() const = 0;
+    // Get the address for return data from the host. The guest codec
+    // implementation will have knowledge of how the return data is laid out.
+    virtual uint8_t* getReturnAddr(unsigned int offSet = 0) const = 0;
+    // Get the offset of an address relative to the starting address of the
+    // allocated memory region. Use this for passing pointers from the guest to
+    // the host, as the guest address will be translated, thus the offset is the
+    // only value of significance.
+    virtual __u64 offsetOf(uint64_t addr) const = 0;
+
+    // Get a slot of memory (8 M per slot) for use by a decoder instance.
+    // returns -1 for failure; or a slot >=0 on success.
+    // as of now, there are only 4 slots for use, each has 8 M, it is up
+    // to client on how to use it.
+    // 0th slot: [base, base+8M)
+    // ...
+    // ith slot: [base+8M*i, base+8M*(i+1))
+    virtual int getMemorySlot() = 0;
+
+    // Return a slot back to pool. the slot should be valid >=0 and less
+    // than the total size of slots. If nobody returns slot timely, the
+    // new client could get -1 from getMemorySlot()
+    virtual void returnMemorySlot(int slot) = 0;
+
+    static GoldfishMediaTransport* getInstance();
+};
+
+__u64 goldfish_create_media_metadata(MediaCodecType codecType,
+                                     __u64 metadata);
+
+#endif
diff --git a/system/codecs/omx/plugin/Android.mk b/system/codecs/omx/plugin/Android.mk
new file mode 100644
index 0000000..77a2091
--- /dev/null
+++ b/system/codecs/omx/plugin/Android.mk
@@ -0,0 +1,56 @@
+#
+# Copyright 2018 The Android Open-Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+LOCAL_PATH := $(call my-dir)
+
+commonSources := \
+    GoldfishOMXComponent.cpp \
+    GoldfishOMXPlugin.cpp \
+    GoldfishVideoDecoderOMXComponent.cpp \
+    SimpleGoldfishOMXComponent.cpp \
+
+$(call emugl-begin-shared-library,libstagefrighthw$(GOLDFISH_OPENGL_LIB_SUFFIX))
+
+LOCAL_SRC_FILES := $(commonSources)
+
+LOCAL_CFLAGS += $(PV_CFLAGS_MINUS_VISIBILITY) -Werror
+LOCAL_CFLAGS += -Wno-unused-private-field
+
+LOCAL_C_INCLUDES += \
+        $(call include-path-for, frameworks-native)/media/hardware \
+        $(call include-path-for, frameworks-native)/media/openmax \
+
+$(call emugl-export,SHARED_LIBRARIES,libcutils libutils liblog)
+$(call emugl-export,C_INCLUDES,$(LOCAL_PATH))
+
+
+
+LOCAL_HEADER_LIBRARIES := media_plugin_headers \
+	                      libmedia_headers \
+	                      libbinder_headers \
+	                      libhidlbase_impl_internal \
+	                      libbase
+
+LOCAL_SHARED_LIBRARIES :=       \
+        libbinder               \
+        libutils                \
+        liblog                  \
+        libcutils               \
+        android.hardware.media.omx@1.0 \
+        libstagefright_foundation
+
+LOCAL_VENDOR_MODULE := true
+
+$(call emugl-end-module)
diff --git a/system/codecs/omx/plugin/GoldfishOMXComponent.cpp b/system/codecs/omx/plugin/GoldfishOMXComponent.cpp
new file mode 100644
index 0000000..021a99b
--- /dev/null
+++ b/system/codecs/omx/plugin/GoldfishOMXComponent.cpp
@@ -0,0 +1,330 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "GoldfishOMXComponent"
+#include "GoldfishOMXComponent.h"
+
+#include <log/log.h>
+
+#include <media/stagefright/foundation/ADebug.h>
+
+namespace android {
+
+GoldfishOMXComponent::GoldfishOMXComponent(
+        const char *name,
+        const OMX_CALLBACKTYPE *callbacks,
+        OMX_PTR appData,
+        OMX_COMPONENTTYPE **component)
+    : mName(name),
+      mCallbacks(callbacks),
+      mComponent(new OMX_COMPONENTTYPE),
+      mLibHandle(NULL) {
+    mComponent->nSize = sizeof(*mComponent);
+    mComponent->nVersion.s.nVersionMajor = 1;
+    mComponent->nVersion.s.nVersionMinor = 0;
+    mComponent->nVersion.s.nRevision = 0;
+    mComponent->nVersion.s.nStep = 0;
+    mComponent->pComponentPrivate = this;
+    mComponent->pApplicationPrivate = appData;
+
+    mComponent->GetComponentVersion = NULL;
+    mComponent->SendCommand = SendCommandWrapper;
+    mComponent->GetParameter = GetParameterWrapper;
+    mComponent->SetParameter = SetParameterWrapper;
+    mComponent->GetConfig = GetConfigWrapper;
+    mComponent->SetConfig = SetConfigWrapper;
+    mComponent->GetExtensionIndex = GetExtensionIndexWrapper;
+    mComponent->GetState = GetStateWrapper;
+    mComponent->ComponentTunnelRequest = NULL;
+    mComponent->UseBuffer = UseBufferWrapper;
+    mComponent->AllocateBuffer = AllocateBufferWrapper;
+    mComponent->FreeBuffer = FreeBufferWrapper;
+    mComponent->EmptyThisBuffer = EmptyThisBufferWrapper;
+    mComponent->FillThisBuffer = FillThisBufferWrapper;
+    mComponent->SetCallbacks = NULL;
+    mComponent->ComponentDeInit = NULL;
+    mComponent->UseEGLImage = NULL;
+    mComponent->ComponentRoleEnum = NULL;
+
+    *component = mComponent;
+}
+
+GoldfishOMXComponent::~GoldfishOMXComponent() {
+    delete mComponent;
+    mComponent = NULL;
+}
+
+void GoldfishOMXComponent::setLibHandle(void *libHandle) {
+    CHECK(libHandle != NULL);
+    mLibHandle = libHandle;
+}
+
+void *GoldfishOMXComponent::libHandle() const {
+    return mLibHandle;
+}
+
+OMX_ERRORTYPE GoldfishOMXComponent::initCheck() {
+    return OMX_ErrorNone;
+}
+
+void
+GoldfishOMXComponent::prepareForDestruction() {
+}
+
+const char *GoldfishOMXComponent::name() const {
+    return mName.c_str();
+}
+
+void GoldfishOMXComponent::notify(
+        OMX_EVENTTYPE event,
+        OMX_U32 data1, OMX_U32 data2, OMX_PTR data) {
+    (*mCallbacks->EventHandler)(
+            mComponent,
+            mComponent->pApplicationPrivate,
+            event,
+            data1,
+            data2,
+            data);
+}
+
+void GoldfishOMXComponent::notifyEmptyBufferDone(OMX_BUFFERHEADERTYPE *header) {
+    (*mCallbacks->EmptyBufferDone)(
+            mComponent, mComponent->pApplicationPrivate, header);
+}
+
+void GoldfishOMXComponent::notifyFillBufferDone(OMX_BUFFERHEADERTYPE *header) {
+    (*mCallbacks->FillBufferDone)(
+            mComponent, mComponent->pApplicationPrivate, header);
+}
+
+// static
+OMX_ERRORTYPE GoldfishOMXComponent::SendCommandWrapper(
+        OMX_HANDLETYPE component,
+        OMX_COMMANDTYPE cmd,
+        OMX_U32 param,
+        OMX_PTR data) {
+    GoldfishOMXComponent *me =
+        (GoldfishOMXComponent *)
+            ((OMX_COMPONENTTYPE *)component)->pComponentPrivate;
+
+    return me->sendCommand(cmd, param, data);
+}
+
+// static
+OMX_ERRORTYPE GoldfishOMXComponent::GetParameterWrapper(
+        OMX_HANDLETYPE component,
+        OMX_INDEXTYPE index,
+        OMX_PTR params) {
+    GoldfishOMXComponent *me =
+        (GoldfishOMXComponent *)
+            ((OMX_COMPONENTTYPE *)component)->pComponentPrivate;
+
+    return me->getParameter(index, params);
+}
+
+// static
+OMX_ERRORTYPE GoldfishOMXComponent::SetParameterWrapper(
+        OMX_HANDLETYPE component,
+        OMX_INDEXTYPE index,
+        OMX_PTR params) {
+    GoldfishOMXComponent *me =
+        (GoldfishOMXComponent *)
+            ((OMX_COMPONENTTYPE *)component)->pComponentPrivate;
+
+    return me->setParameter(index, params);
+}
+
+// static
+OMX_ERRORTYPE GoldfishOMXComponent::GetConfigWrapper(
+        OMX_HANDLETYPE component,
+        OMX_INDEXTYPE index,
+        OMX_PTR params) {
+    GoldfishOMXComponent *me =
+        (GoldfishOMXComponent *)
+            ((OMX_COMPONENTTYPE *)component)->pComponentPrivate;
+
+    return me->getConfig(index, params);
+}
+
+// static
+OMX_ERRORTYPE GoldfishOMXComponent::SetConfigWrapper(
+        OMX_HANDLETYPE component,
+        OMX_INDEXTYPE index,
+        OMX_PTR params) {
+    GoldfishOMXComponent *me =
+        (GoldfishOMXComponent *)
+            ((OMX_COMPONENTTYPE *)component)->pComponentPrivate;
+
+    return me->setConfig(index, params);
+}
+
+// static
+OMX_ERRORTYPE GoldfishOMXComponent::GetExtensionIndexWrapper(
+        OMX_HANDLETYPE component,
+        OMX_STRING name,
+        OMX_INDEXTYPE *index) {
+    GoldfishOMXComponent *me =
+        (GoldfishOMXComponent *)
+            ((OMX_COMPONENTTYPE *)component)->pComponentPrivate;
+
+    return me->getExtensionIndex(name, index);
+}
+
+// static
+OMX_ERRORTYPE GoldfishOMXComponent::UseBufferWrapper(
+        OMX_HANDLETYPE component,
+        OMX_BUFFERHEADERTYPE **buffer,
+        OMX_U32 portIndex,
+        OMX_PTR appPrivate,
+        OMX_U32 size,
+        OMX_U8 *ptr) {
+    GoldfishOMXComponent *me =
+        (GoldfishOMXComponent *)
+            ((OMX_COMPONENTTYPE *)component)->pComponentPrivate;
+
+    return me->useBuffer(buffer, portIndex, appPrivate, size, ptr);
+}
+
+// static
+OMX_ERRORTYPE GoldfishOMXComponent::AllocateBufferWrapper(
+        OMX_HANDLETYPE component,
+        OMX_BUFFERHEADERTYPE **buffer,
+        OMX_U32 portIndex,
+        OMX_PTR appPrivate,
+        OMX_U32 size) {
+    GoldfishOMXComponent *me =
+        (GoldfishOMXComponent *)
+            ((OMX_COMPONENTTYPE *)component)->pComponentPrivate;
+
+    return me->allocateBuffer(buffer, portIndex, appPrivate, size);
+}
+
+// static
+OMX_ERRORTYPE GoldfishOMXComponent::FreeBufferWrapper(
+        OMX_HANDLETYPE component,
+        OMX_U32 portIndex,
+        OMX_BUFFERHEADERTYPE *buffer) {
+    GoldfishOMXComponent *me =
+        (GoldfishOMXComponent *)
+            ((OMX_COMPONENTTYPE *)component)->pComponentPrivate;
+
+    return me->freeBuffer(portIndex, buffer);
+}
+
+// static
+OMX_ERRORTYPE GoldfishOMXComponent::EmptyThisBufferWrapper(
+        OMX_HANDLETYPE component,
+        OMX_BUFFERHEADERTYPE *buffer) {
+    GoldfishOMXComponent *me =
+        (GoldfishOMXComponent *)
+            ((OMX_COMPONENTTYPE *)component)->pComponentPrivate;
+
+    return me->emptyThisBuffer(buffer);
+}
+
+// static
+OMX_ERRORTYPE GoldfishOMXComponent::FillThisBufferWrapper(
+        OMX_HANDLETYPE component,
+        OMX_BUFFERHEADERTYPE *buffer) {
+    GoldfishOMXComponent *me =
+        (GoldfishOMXComponent *)
+            ((OMX_COMPONENTTYPE *)component)->pComponentPrivate;
+
+    return me->fillThisBuffer(buffer);
+}
+
+// static
+OMX_ERRORTYPE GoldfishOMXComponent::GetStateWrapper(
+        OMX_HANDLETYPE component,
+        OMX_STATETYPE *state) {
+    GoldfishOMXComponent *me =
+        (GoldfishOMXComponent *)
+            ((OMX_COMPONENTTYPE *)component)->pComponentPrivate;
+
+    return me->getState(state);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+OMX_ERRORTYPE GoldfishOMXComponent::sendCommand(
+        OMX_COMMANDTYPE /* cmd */, OMX_U32 /* param */, OMX_PTR /* data */) {
+    return OMX_ErrorUndefined;
+}
+
+OMX_ERRORTYPE GoldfishOMXComponent::getParameter(
+        OMX_INDEXTYPE /* index */, OMX_PTR /* params */) {
+    return OMX_ErrorUndefined;
+}
+
+OMX_ERRORTYPE GoldfishOMXComponent::setParameter(
+        OMX_INDEXTYPE /* index */, const OMX_PTR /* params */) {
+    return OMX_ErrorUndefined;
+}
+
+OMX_ERRORTYPE GoldfishOMXComponent::getConfig(
+        OMX_INDEXTYPE /* index */, OMX_PTR /* params */) {
+    return OMX_ErrorUndefined;
+}
+
+OMX_ERRORTYPE GoldfishOMXComponent::setConfig(
+        OMX_INDEXTYPE /* index */, const OMX_PTR /* params */) {
+    return OMX_ErrorUndefined;
+}
+
+OMX_ERRORTYPE GoldfishOMXComponent::getExtensionIndex(
+        const char * /* name */, OMX_INDEXTYPE * /* index */) {
+    return OMX_ErrorUnsupportedIndex;
+}
+
+OMX_ERRORTYPE GoldfishOMXComponent::useBuffer(
+        OMX_BUFFERHEADERTYPE ** /* buffer */,
+        OMX_U32 /* portIndex */,
+        OMX_PTR /* appPrivate */,
+        OMX_U32 /* size */,
+        OMX_U8 * /* ptr */) {
+    return OMX_ErrorUndefined;
+}
+
+OMX_ERRORTYPE GoldfishOMXComponent::allocateBuffer(
+        OMX_BUFFERHEADERTYPE ** /* buffer */,
+        OMX_U32 /* portIndex */,
+        OMX_PTR /* appPrivate */,
+        OMX_U32 /* size */) {
+    return OMX_ErrorUndefined;
+}
+
+OMX_ERRORTYPE GoldfishOMXComponent::freeBuffer(
+        OMX_U32 /* portIndex */,
+        OMX_BUFFERHEADERTYPE * /* buffer */) {
+    return OMX_ErrorUndefined;
+}
+
+OMX_ERRORTYPE GoldfishOMXComponent::emptyThisBuffer(
+        OMX_BUFFERHEADERTYPE * /* buffer */) {
+    return OMX_ErrorUndefined;
+}
+
+OMX_ERRORTYPE GoldfishOMXComponent::fillThisBuffer(
+        OMX_BUFFERHEADERTYPE * /* buffer */) {
+    return OMX_ErrorUndefined;
+}
+
+OMX_ERRORTYPE GoldfishOMXComponent::getState(OMX_STATETYPE * /* state */) {
+    return OMX_ErrorUndefined;
+}
+
+}  // namespace android
diff --git a/system/codecs/omx/plugin/GoldfishOMXComponent.h b/system/codecs/omx/plugin/GoldfishOMXComponent.h
new file mode 100644
index 0000000..87a65ae
--- /dev/null
+++ b/system/codecs/omx/plugin/GoldfishOMXComponent.h
@@ -0,0 +1,189 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef GOLDFISH_OMX_COMPONENT_H_
+
+#define GOLDFISH_OMX_COMPONENT_H_
+
+#include <media/stagefright/foundation/ABase.h>
+#include <media/stagefright/foundation/AString.h>
+#include <utils/RefBase.h>
+
+#include <OMX_Component.h>
+
+namespace android {
+
+struct GoldfishOMXComponent : public RefBase {
+    GoldfishOMXComponent(
+            const char *name,
+            const OMX_CALLBACKTYPE *callbacks,
+            OMX_PTR appData,
+            OMX_COMPONENTTYPE **component);
+
+    virtual OMX_ERRORTYPE initCheck();
+
+    void setLibHandle(void *libHandle);
+    void *libHandle() const;
+
+    virtual void prepareForDestruction();
+
+protected:
+    virtual ~GoldfishOMXComponent();
+
+    const char *name() const;
+
+    void notify(
+            OMX_EVENTTYPE event,
+            OMX_U32 data1, OMX_U32 data2, OMX_PTR data);
+
+    void notifyEmptyBufferDone(OMX_BUFFERHEADERTYPE *header);
+    void notifyFillBufferDone(OMX_BUFFERHEADERTYPE *header);
+
+    virtual OMX_ERRORTYPE sendCommand(
+            OMX_COMMANDTYPE cmd, OMX_U32 param, OMX_PTR data);
+
+    virtual OMX_ERRORTYPE getParameter(
+            OMX_INDEXTYPE index, OMX_PTR params);
+
+    virtual OMX_ERRORTYPE setParameter(
+            OMX_INDEXTYPE index, const OMX_PTR params);
+
+    virtual OMX_ERRORTYPE getConfig(
+            OMX_INDEXTYPE index, OMX_PTR params);
+
+    virtual OMX_ERRORTYPE setConfig(
+            OMX_INDEXTYPE index, const OMX_PTR params);
+
+    virtual OMX_ERRORTYPE getExtensionIndex(
+            const char *name, OMX_INDEXTYPE *index);
+
+    virtual OMX_ERRORTYPE useBuffer(
+            OMX_BUFFERHEADERTYPE **buffer,
+            OMX_U32 portIndex,
+            OMX_PTR appPrivate,
+            OMX_U32 size,
+            OMX_U8 *ptr);
+
+    virtual OMX_ERRORTYPE allocateBuffer(
+            OMX_BUFFERHEADERTYPE **buffer,
+            OMX_U32 portIndex,
+            OMX_PTR appPrivate,
+            OMX_U32 size);
+
+    virtual OMX_ERRORTYPE freeBuffer(
+            OMX_U32 portIndex,
+            OMX_BUFFERHEADERTYPE *buffer);
+
+    virtual OMX_ERRORTYPE emptyThisBuffer(
+            OMX_BUFFERHEADERTYPE *buffer);
+
+    virtual OMX_ERRORTYPE fillThisBuffer(
+            OMX_BUFFERHEADERTYPE *buffer);
+
+    virtual OMX_ERRORTYPE getState(OMX_STATETYPE *state);
+
+private:
+    AString mName;
+    const OMX_CALLBACKTYPE *mCallbacks;
+    OMX_COMPONENTTYPE *mComponent;
+
+    void *mLibHandle;
+
+    static OMX_ERRORTYPE SendCommandWrapper(
+            OMX_HANDLETYPE component,
+            OMX_COMMANDTYPE cmd,
+            OMX_U32 param,
+            OMX_PTR data);
+
+    static OMX_ERRORTYPE GetParameterWrapper(
+            OMX_HANDLETYPE component,
+            OMX_INDEXTYPE index,
+            OMX_PTR params);
+
+    static OMX_ERRORTYPE SetParameterWrapper(
+            OMX_HANDLETYPE component,
+            OMX_INDEXTYPE index,
+            OMX_PTR params);
+
+    static OMX_ERRORTYPE GetConfigWrapper(
+            OMX_HANDLETYPE component,
+            OMX_INDEXTYPE index,
+            OMX_PTR params);
+
+    static OMX_ERRORTYPE SetConfigWrapper(
+            OMX_HANDLETYPE component,
+            OMX_INDEXTYPE index,
+            OMX_PTR params);
+
+    static OMX_ERRORTYPE GetExtensionIndexWrapper(
+            OMX_HANDLETYPE component,
+            OMX_STRING name,
+            OMX_INDEXTYPE *index);
+
+    static OMX_ERRORTYPE UseBufferWrapper(
+            OMX_HANDLETYPE component,
+            OMX_BUFFERHEADERTYPE **buffer,
+            OMX_U32 portIndex,
+            OMX_PTR appPrivate,
+            OMX_U32 size,
+            OMX_U8 *ptr);
+
+    static OMX_ERRORTYPE AllocateBufferWrapper(
+            OMX_HANDLETYPE component,
+            OMX_BUFFERHEADERTYPE **buffer,
+            OMX_U32 portIndex,
+            OMX_PTR appPrivate,
+            OMX_U32 size);
+
+    static OMX_ERRORTYPE FreeBufferWrapper(
+            OMX_HANDLETYPE component,
+            OMX_U32 portIndex,
+            OMX_BUFFERHEADERTYPE *buffer);
+
+    static OMX_ERRORTYPE EmptyThisBufferWrapper(
+            OMX_HANDLETYPE component,
+            OMX_BUFFERHEADERTYPE *buffer);
+
+    static OMX_ERRORTYPE FillThisBufferWrapper(
+            OMX_HANDLETYPE component,
+            OMX_BUFFERHEADERTYPE *buffer);
+
+    static OMX_ERRORTYPE GetStateWrapper(
+            OMX_HANDLETYPE component,
+            OMX_STATETYPE *state);
+
+    DISALLOW_EVIL_CONSTRUCTORS(GoldfishOMXComponent);
+};
+
+template<typename T>
+bool isValidOMXParam(T *a) {
+  static_assert(offsetof(typeof(*a), nSize) == 0, "nSize not at offset 0");
+  static_assert(std::is_same< decltype(a->nSize), OMX_U32>::value, "nSize has wrong type");
+  static_assert(offsetof(typeof(*a), nVersion) == 4, "nVersion not at offset 4");
+  static_assert(std::is_same< decltype(a->nVersion), OMX_VERSIONTYPE>::value,
+          "nVersion has wrong type");
+
+  if (a->nSize < sizeof(*a)) {
+      ALOGE("b/27207275: need %zu, got %u", sizeof(*a), a->nSize);
+      //android_errorWriteLog(0x534e4554, "27207275");
+      return false;
+  }
+  return true;
+}
+
+}  // namespace android
+
+#endif  // GOLDFISH_OMX_COMPONENT_H_
diff --git a/system/codecs/omx/plugin/GoldfishOMXPlugin.cpp b/system/codecs/omx/plugin/GoldfishOMXPlugin.cpp
new file mode 100644
index 0000000..47c22a3
--- /dev/null
+++ b/system/codecs/omx/plugin/GoldfishOMXPlugin.cpp
@@ -0,0 +1,224 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "GoldfishOMXPlugin"
+#include "GoldfishOMXPlugin.h"
+
+//#define LOG_NDEBUG 0
+#include <vector>
+
+#include <cutils/properties.h>
+#include <log/log.h>
+
+#include "GoldfishOMXComponent.h"
+
+#include <media/stagefright/foundation/ADebug.h>
+#include <media/stagefright/foundation/AString.h>
+
+#include <dlfcn.h>
+
+namespace android {
+
+OMXPluginBase *createOMXPlugin() {
+    ALOGD("called createOMXPlugin for Goldfish");
+    return new GoldfishOMXPlugin;
+}
+
+// Each component's name should have it's own feature flag in order to toggle
+// individual codecs
+struct GoldfishComponent {
+    const char *mName;
+    const char *mLibNameSuffix;
+    const char *mRole;
+};
+
+static bool useGoogleGoldfishComponentInstance(const char* libname) {
+    // We have a property set indicating whether to use the host side codec
+    // or not (ro.kernel.qemu.hwcodec.<mLibNameSuffix>).
+    char propValue[PROP_VALUE_MAX];
+    AString prop = "ro.kernel.qemu.hwcodec.";
+    prop.append(libname);
+
+    bool myret = property_get(prop.c_str(), propValue, "") > 0 &&
+           strcmp("1", propValue) == 0;
+    if (myret) {
+        ALOGD("%s %d found prop %s val %s", __func__, __LINE__, prop.c_str(), propValue);
+    }
+    return myret;
+}
+
+static bool useAndroidGoldfishComponentInstance(const char* libname) {
+    // We have a property set indicating whether to use the host side codec
+    // or not (ro.kernel.qemu.hwcodec.<mLibNameSuffix>).
+    char propValue[PROP_VALUE_MAX];
+    AString prop = "ro.kernel.qemu.hwcodec.";
+    prop.append(libname);
+
+    bool myret = property_get(prop.c_str(), propValue, "") > 0 &&
+           strcmp("2", propValue) == 0;
+    if (myret) {
+        ALOGD("%s %d found prop %s val %s", __func__, __LINE__, prop.c_str(), propValue);
+    }
+    return myret;
+}
+
+static const GoldfishComponent kComponents[] = {
+    { "OMX.google.goldfish.vp8.decoder", "vpxdec", "video_decoder.vp8" },
+    { "OMX.google.goldfish.vp9.decoder", "vpxdec", "video_decoder.vp9" },
+    { "OMX.google.goldfish.h264.decoder", "avcdec", "video_decoder.avc" },
+    { "OMX.android.goldfish.h264.decoder", "avcdec", "video_decoder.avc" },
+};
+
+static std::vector<GoldfishComponent> kActiveComponents;
+
+static const size_t kNumComponents =
+    sizeof(kComponents) / sizeof(kComponents[0]);
+
+GoldfishOMXPlugin::GoldfishOMXPlugin() {
+    for (int i = 0; i < kNumComponents; ++i) {
+        if ( !strncmp("OMX.google", kComponents[i].mName, 10) &&
+             useGoogleGoldfishComponentInstance(kComponents[i].mLibNameSuffix)) {
+            ALOGD("found and use kComponents[i].name %s", kComponents[i].mName);
+            kActiveComponents.push_back(kComponents[i]);
+        } else if (!strncmp("OMX.android", kComponents[i].mName, 11) &&
+                   useAndroidGoldfishComponentInstance(kComponents[i].mLibNameSuffix)) {
+            ALOGD("found and use kComponents[i].name %s", kComponents[i].mName);
+            kActiveComponents.push_back(kComponents[i]);
+        }
+    }
+}
+
+OMX_ERRORTYPE GoldfishOMXPlugin::makeComponentInstance(
+        const char *name,
+        const OMX_CALLBACKTYPE *callbacks,
+        OMX_PTR appData,
+        OMX_COMPONENTTYPE **component) {
+    ALOGI("makeComponentInstance '%s'", name);
+
+    for (size_t i = 0; i < kActiveComponents.size(); ++i) {
+        if (strcmp(name, kActiveComponents[i].mName)) {
+            continue;
+        }
+
+        AString libName;
+        AString ldsExport;
+        libName = "libstagefright_goldfish_";
+        ldsExport = "_Z26createGoldfishOMXComponentPKcPK16OMX_CALLBACKTYPEPvPP17OMX_COMPONENTTYPE";
+        ALOGI("Using goldfish codec for '%s'", kActiveComponents[i].mLibNameSuffix);
+
+        libName.append(kActiveComponents[i].mLibNameSuffix);
+        libName.append(".so");
+
+        void *libHandle = dlopen(libName.c_str(), RTLD_NOW|RTLD_NODELETE);
+
+        if (libHandle == NULL) {
+            ALOGE("unable to dlopen %s: %s", libName.c_str(), dlerror());
+
+            return OMX_ErrorComponentNotFound;
+        }
+
+        typedef GoldfishOMXComponent *(*CreateGoldfishOMXComponentFunc)(
+                const char *, const OMX_CALLBACKTYPE *,
+                OMX_PTR, OMX_COMPONENTTYPE **);
+
+        CreateGoldfishOMXComponentFunc createGoldfishOMXComponent =
+            (CreateGoldfishOMXComponentFunc)dlsym(
+                    libHandle,
+                    ldsExport.c_str()
+                    );
+
+        if (createGoldfishOMXComponent == NULL) {
+            ALOGE("unable to create component for %s", libName.c_str());
+            dlclose(libHandle);
+            libHandle = NULL;
+
+            return OMX_ErrorComponentNotFound;
+        }
+
+        sp<GoldfishOMXComponent> codec =
+            (*createGoldfishOMXComponent)(name, callbacks, appData, component);
+
+        if (codec == NULL) {
+            dlclose(libHandle);
+            libHandle = NULL;
+
+            return OMX_ErrorInsufficientResources;
+        }
+
+        OMX_ERRORTYPE err = codec->initCheck();
+        if (err != OMX_ErrorNone) {
+            dlclose(libHandle);
+            libHandle = NULL;
+
+            return err;
+        }
+
+        codec->incStrong(this);
+        codec->setLibHandle(libHandle);
+
+        return OMX_ErrorNone;
+    }
+
+    return OMX_ErrorInvalidComponentName;
+}
+
+OMX_ERRORTYPE GoldfishOMXPlugin::destroyComponentInstance(
+        OMX_COMPONENTTYPE *component) {
+    GoldfishOMXComponent *me =
+        (GoldfishOMXComponent *)
+            ((OMX_COMPONENTTYPE *)component)->pComponentPrivate;
+
+    me->prepareForDestruction();
+
+    CHECK_EQ(me->getStrongCount(), 1);
+    me->decStrong(this);
+    me = NULL;
+
+    return OMX_ErrorNone;
+}
+
+OMX_ERRORTYPE GoldfishOMXPlugin::enumerateComponents(
+        OMX_STRING name,
+        size_t /* size */,
+        OMX_U32 index) {
+    if (index >= kActiveComponents.size()) {
+        return OMX_ErrorNoMore;
+    }
+
+    ALOGD("enumerate %s component", kActiveComponents[index].mName);
+    strcpy(name, kActiveComponents[index].mName);
+
+    return OMX_ErrorNone;
+}
+
+OMX_ERRORTYPE GoldfishOMXPlugin::getRolesOfComponent(
+        const char *name,
+        Vector<String8> *roles) {
+    for (size_t i = 0; i < kActiveComponents.size(); ++i) {
+        if (strcmp(name, kActiveComponents[i].mName)) {
+            continue;
+        }
+
+        roles->clear();
+        roles->push(String8(kActiveComponents[i].mRole));
+
+        return OMX_ErrorNone;
+    }
+
+    return OMX_ErrorInvalidComponentName;
+}
+
+}  // namespace android
diff --git a/system/codecs/omx/plugin/GoldfishOMXPlugin.h b/system/codecs/omx/plugin/GoldfishOMXPlugin.h
new file mode 100644
index 0000000..26cee76
--- /dev/null
+++ b/system/codecs/omx/plugin/GoldfishOMXPlugin.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef GOLDFISH_OMX_PLUGIN_H_
+
+#define GOLDFISH_OMX_PLUGIN_H_
+
+#include <media/stagefright/foundation/ABase.h>
+#include <media/hardware/OMXPluginBase.h>
+
+namespace android {
+
+struct GoldfishOMXPlugin : public OMXPluginBase {
+    GoldfishOMXPlugin();
+
+    virtual OMX_ERRORTYPE makeComponentInstance(
+            const char *name,
+            const OMX_CALLBACKTYPE *callbacks,
+            OMX_PTR appData,
+            OMX_COMPONENTTYPE **component);
+
+    virtual OMX_ERRORTYPE destroyComponentInstance(
+            OMX_COMPONENTTYPE *component);
+
+    virtual OMX_ERRORTYPE enumerateComponents(
+            OMX_STRING name,
+            size_t size,
+            OMX_U32 index);
+
+    virtual OMX_ERRORTYPE getRolesOfComponent(
+            const char *name,
+            Vector<String8> *roles);
+
+private:
+    DISALLOW_EVIL_CONSTRUCTORS(GoldfishOMXPlugin);
+};
+
+}  // namespace android
+
+#endif  // GOLDFISH_OMX_PLUGIN_H_
diff --git a/system/codecs/omx/plugin/GoldfishVideoDecoderOMXComponent.cpp b/system/codecs/omx/plugin/GoldfishVideoDecoderOMXComponent.cpp
new file mode 100644
index 0000000..f98adab
--- /dev/null
+++ b/system/codecs/omx/plugin/GoldfishVideoDecoderOMXComponent.cpp
@@ -0,0 +1,806 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <inttypes.h>
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "GoldfishVideoDecoderOMXComponent"
+#include <utils/Log.h>
+
+#include "GoldfishVideoDecoderOMXComponent.h"
+
+#include <media/stagefright/foundation/ADebug.h>
+#include <media/stagefright/foundation/ALooper.h>
+#include <media/stagefright/foundation/AMessage.h>
+#include <media/stagefright/foundation/AUtils.h>
+#include <media/stagefright/foundation/MediaDefs.h>
+#include <media/hardware/HardwareAPI.h>
+
+namespace android {
+
+template<class T>
+static void InitOMXParams(T *params) {
+    params->nSize = sizeof(T);
+    params->nVersion.s.nVersionMajor = 1;
+    params->nVersion.s.nVersionMinor = 0;
+    params->nVersion.s.nRevision = 0;
+    params->nVersion.s.nStep = 0;
+}
+
+GoldfishVideoDecoderOMXComponent::GoldfishVideoDecoderOMXComponent(
+        const char *name,
+        const char *componentRole,
+        OMX_VIDEO_CODINGTYPE codingType,
+        const CodecProfileLevel *profileLevels,
+        size_t numProfileLevels,
+        int32_t width,
+        int32_t height,
+        const OMX_CALLBACKTYPE *callbacks,
+        OMX_PTR appData,
+        OMX_COMPONENTTYPE **component)
+        : SimpleGoldfishOMXComponent(name, callbacks, appData, component),
+        mIsAdaptive(false),
+        mAdaptiveMaxWidth(0),
+        mAdaptiveMaxHeight(0),
+        mWidth(width),
+        mHeight(height),
+        mCropLeft(0),
+        mCropTop(0),
+        mCropWidth(width),
+        mCropHeight(height),
+        mOutputFormat(OMX_COLOR_FormatYUV420Planar),
+        mOutputPortSettingsChange(NONE),
+        mUpdateColorAspects(false),
+        mMinInputBufferSize(384), // arbitrary, using one uncompressed macroblock
+        mMinCompressionRatio(1),  // max input size is normally the output size
+        mComponentRole(componentRole),
+        mCodingType(codingType),
+        mProfileLevels(profileLevels),
+        mNumProfileLevels(numProfileLevels) {
+
+    // init all the color aspects to be Unspecified.
+    memset(&mDefaultColorAspects, 0, sizeof(ColorAspects));
+    memset(&mBitstreamColorAspects, 0, sizeof(ColorAspects));
+    memset(&mFinalColorAspects, 0, sizeof(ColorAspects));
+    memset(&mHdrStaticInfo, 0, sizeof(HDRStaticInfo));
+}
+
+void GoldfishVideoDecoderOMXComponent::initPorts(
+        OMX_U32 numInputBuffers,
+        OMX_U32 inputBufferSize,
+        OMX_U32 numOutputBuffers,
+        const char *mimeType,
+        OMX_U32 minCompressionRatio) {
+    initPorts(numInputBuffers, numInputBuffers, inputBufferSize,
+            numOutputBuffers, numOutputBuffers, mimeType, minCompressionRatio);
+}
+
+void GoldfishVideoDecoderOMXComponent::initPorts(
+        OMX_U32 numMinInputBuffers,
+        OMX_U32 numInputBuffers,
+        OMX_U32 inputBufferSize,
+        OMX_U32 numMinOutputBuffers,
+        OMX_U32 numOutputBuffers,
+        const char *mimeType,
+        OMX_U32 minCompressionRatio) {
+    mMinInputBufferSize = inputBufferSize;
+    mMinCompressionRatio = minCompressionRatio;
+
+    OMX_PARAM_PORTDEFINITIONTYPE def;
+    InitOMXParams(&def);
+
+    def.nPortIndex = kInputPortIndex;
+    def.eDir = OMX_DirInput;
+    def.nBufferCountMin = numMinInputBuffers;
+    def.nBufferCountActual = numInputBuffers;
+    def.nBufferSize = inputBufferSize;
+    def.bEnabled = OMX_TRUE;
+    def.bPopulated = OMX_FALSE;
+    def.eDomain = OMX_PortDomainVideo;
+    def.bBuffersContiguous = OMX_FALSE;
+    def.nBufferAlignment = 1;
+
+    def.format.video.cMIMEType = const_cast<char *>(mimeType);
+    def.format.video.pNativeRender = NULL;
+    /* size is initialized in updatePortDefinitions() */
+    def.format.video.nBitrate = 0;
+    def.format.video.xFramerate = 0;
+    def.format.video.bFlagErrorConcealment = OMX_FALSE;
+    def.format.video.eCompressionFormat = mCodingType;
+    def.format.video.eColorFormat = OMX_COLOR_FormatUnused;
+    def.format.video.pNativeWindow = NULL;
+
+    addPort(def);
+
+    def.nPortIndex = kOutputPortIndex;
+    def.eDir = OMX_DirOutput;
+    def.nBufferCountMin = numMinOutputBuffers;
+    def.nBufferCountActual = numOutputBuffers;
+    def.bEnabled = OMX_TRUE;
+    def.bPopulated = OMX_FALSE;
+    def.eDomain = OMX_PortDomainVideo;
+    def.bBuffersContiguous = OMX_FALSE;
+    def.nBufferAlignment = 2;
+
+    def.format.video.cMIMEType = const_cast<char *>("video/raw");
+    def.format.video.pNativeRender = NULL;
+    /* size is initialized in updatePortDefinitions() */
+    def.format.video.nBitrate = 0;
+    def.format.video.xFramerate = 0;
+    def.format.video.bFlagErrorConcealment = OMX_FALSE;
+    def.format.video.eCompressionFormat = OMX_VIDEO_CodingUnused;
+    def.format.video.pNativeWindow = NULL;
+
+    addPort(def);
+
+    updatePortDefinitions(true /* updateCrop */, true /* updateInputSize */);
+}
+
+void GoldfishVideoDecoderOMXComponent::updatePortDefinitions(bool updateCrop, bool updateInputSize) {
+    OMX_PARAM_PORTDEFINITIONTYPE *outDef = &editPortInfo(kOutputPortIndex)->mDef;
+    outDef->format.video.nFrameWidth = outputBufferWidth();
+    outDef->format.video.nFrameHeight = outputBufferHeight();
+    outDef->format.video.eColorFormat = mOutputFormat;
+    outDef->format.video.nSliceHeight = outDef->format.video.nFrameHeight;
+
+    int32_t bpp = (mOutputFormat == OMX_COLOR_FormatYUV420Planar16) ? 2 : 1;
+    outDef->format.video.nStride = outDef->format.video.nFrameWidth * bpp;
+    outDef->nBufferSize =
+            (outDef->format.video.nStride * outDef->format.video.nSliceHeight * 3) / 2;
+
+    OMX_PARAM_PORTDEFINITIONTYPE *inDef = &editPortInfo(kInputPortIndex)->mDef;
+    inDef->format.video.nFrameWidth = mWidth;
+    inDef->format.video.nFrameHeight = mHeight;
+    // input port is compressed, hence it has no stride
+    inDef->format.video.nStride = 0;
+    inDef->format.video.nSliceHeight = 0;
+
+    // when output format changes, input buffer size does not actually change
+    if (updateInputSize) {
+        inDef->nBufferSize = max(
+                outDef->nBufferSize / mMinCompressionRatio,
+                max(mMinInputBufferSize, inDef->nBufferSize));
+    }
+
+    if (updateCrop) {
+        mCropLeft = 0;
+        mCropTop = 0;
+        mCropWidth = mWidth;
+        mCropHeight = mHeight;
+    }
+}
+
+
+uint32_t GoldfishVideoDecoderOMXComponent::outputBufferWidth() {
+    return max(mIsAdaptive ? mAdaptiveMaxWidth : 0, mWidth);
+}
+
+uint32_t GoldfishVideoDecoderOMXComponent::outputBufferHeight() {
+    return max(mIsAdaptive ? mAdaptiveMaxHeight : 0, mHeight);
+}
+
+void GoldfishVideoDecoderOMXComponent::handlePortSettingsChange(
+        bool *portWillReset, uint32_t width, uint32_t height,
+        OMX_COLOR_FORMATTYPE outputFormat,
+        CropSettingsMode cropSettingsMode, bool fakeStride) {
+    *portWillReset = false;
+    bool sizeChanged = (width != mWidth || height != mHeight);
+    bool formatChanged = (outputFormat != mOutputFormat);
+    bool updateCrop = (cropSettingsMode == kCropUnSet);
+    bool cropChanged = (cropSettingsMode == kCropChanged);
+    bool strideChanged = false;
+    if (fakeStride) {
+        OMX_PARAM_PORTDEFINITIONTYPE *def = &editPortInfo(kOutputPortIndex)->mDef;
+        if (def->format.video.nStride != (OMX_S32)width
+                || def->format.video.nSliceHeight != (OMX_U32)height) {
+            strideChanged = true;
+        }
+    }
+
+    if (formatChanged || sizeChanged || cropChanged || strideChanged) {
+        if (formatChanged) {
+            ALOGD("formatChanged: 0x%08x -> 0x%08x", mOutputFormat, outputFormat);
+        }
+        mOutputFormat = outputFormat;
+        mWidth = width;
+        mHeight = height;
+
+        if ((sizeChanged && !mIsAdaptive)
+            || width > mAdaptiveMaxWidth
+            || height > mAdaptiveMaxHeight
+            || formatChanged) {
+            if (mIsAdaptive) {
+                if (width > mAdaptiveMaxWidth) {
+                    mAdaptiveMaxWidth = width;
+                }
+                if (height > mAdaptiveMaxHeight) {
+                    mAdaptiveMaxHeight = height;
+                }
+            }
+            updatePortDefinitions(updateCrop);
+            notify(OMX_EventPortSettingsChanged, kOutputPortIndex, 0, NULL);
+            mOutputPortSettingsChange = AWAITING_DISABLED;
+            *portWillReset = true;
+        } else {
+            updatePortDefinitions(updateCrop);
+
+            if (fakeStride) {
+                // MAJOR HACK that is not pretty, it's just to fool the renderer to read the correct
+                // data.
+                // Some software decoders (e.g. SoftMPEG4) fill decoded frame directly to output
+                // buffer without considering the output buffer stride and slice height. So this is
+                // used to signal how the buffer is arranged.  The alternative is to re-arrange the
+                // output buffer in SoftMPEG4, but that results in memcopies.
+                OMX_PARAM_PORTDEFINITIONTYPE *def = &editPortInfo(kOutputPortIndex)->mDef;
+                def->format.video.nStride = mWidth;
+                def->format.video.nSliceHeight = mHeight;
+            }
+
+            notify(OMX_EventPortSettingsChanged, kOutputPortIndex,
+                   OMX_IndexConfigCommonOutputCrop, NULL);
+        }
+    } else if (mUpdateColorAspects) {
+        notify(OMX_EventPortSettingsChanged, kOutputPortIndex,
+                kDescribeColorAspectsIndex, NULL);
+        mUpdateColorAspects = false;
+    }
+}
+
+void GoldfishVideoDecoderOMXComponent::dumpColorAspects(const ColorAspects &colorAspects) {
+    ALOGD("dumpColorAspects: (R:%d(%s), P:%d(%s), M:%d(%s), T:%d(%s)) ",
+            colorAspects.mRange, asString(colorAspects.mRange),
+            colorAspects.mPrimaries, asString(colorAspects.mPrimaries),
+            colorAspects.mMatrixCoeffs, asString(colorAspects.mMatrixCoeffs),
+            colorAspects.mTransfer, asString(colorAspects.mTransfer));
+}
+
+bool GoldfishVideoDecoderOMXComponent::colorAspectsDiffer(
+        const ColorAspects &a, const ColorAspects &b) {
+    if (a.mRange != b.mRange
+        || a.mPrimaries != b.mPrimaries
+        || a.mTransfer != b.mTransfer
+        || a.mMatrixCoeffs != b.mMatrixCoeffs) {
+        return true;
+    }
+    return false;
+}
+
+void GoldfishVideoDecoderOMXComponent::updateFinalColorAspects(
+        const ColorAspects &otherAspects, const ColorAspects &preferredAspects) {
+    Mutex::Autolock autoLock(mColorAspectsLock);
+    ColorAspects newAspects;
+    newAspects.mRange = preferredAspects.mRange != ColorAspects::RangeUnspecified ?
+        preferredAspects.mRange : otherAspects.mRange;
+    newAspects.mPrimaries = preferredAspects.mPrimaries != ColorAspects::PrimariesUnspecified ?
+        preferredAspects.mPrimaries : otherAspects.mPrimaries;
+    newAspects.mTransfer = preferredAspects.mTransfer != ColorAspects::TransferUnspecified ?
+        preferredAspects.mTransfer : otherAspects.mTransfer;
+    newAspects.mMatrixCoeffs = preferredAspects.mMatrixCoeffs != ColorAspects::MatrixUnspecified ?
+        preferredAspects.mMatrixCoeffs : otherAspects.mMatrixCoeffs;
+
+    // Check to see if need update mFinalColorAspects.
+    if (colorAspectsDiffer(mFinalColorAspects, newAspects)) {
+        mFinalColorAspects = newAspects;
+        mUpdateColorAspects = true;
+    }
+}
+
+status_t GoldfishVideoDecoderOMXComponent::handleColorAspectsChange() {
+    int perference = getColorAspectPreference();
+    ALOGD("Color Aspects preference: %d ", perference);
+
+    if (perference == kPreferBitstream) {
+        updateFinalColorAspects(mDefaultColorAspects, mBitstreamColorAspects);
+    } else if (perference == kPreferContainer) {
+        updateFinalColorAspects(mBitstreamColorAspects, mDefaultColorAspects);
+    } else {
+        return OMX_ErrorUnsupportedSetting;
+    }
+    return OK;
+}
+
+void GoldfishVideoDecoderOMXComponent::copyYV12FrameToOutputBuffer(
+        uint8_t *dst, const uint8_t *srcY, const uint8_t *srcU, const uint8_t *srcV,
+        size_t srcYStride, size_t srcUStride, size_t srcVStride) {
+    OMX_PARAM_PORTDEFINITIONTYPE *outDef = &editPortInfo(kOutputPortIndex)->mDef;
+    int32_t bpp = (outDef->format.video.eColorFormat == OMX_COLOR_FormatYUV420Planar16) ? 2 : 1;
+
+    size_t dstYStride = outputBufferWidth() * bpp;
+    size_t dstUVStride = dstYStride / 2;
+    size_t dstHeight = outputBufferHeight();
+    uint8_t *dstStart = dst;
+
+    for (size_t i = 0; i < mHeight; ++i) {
+         memcpy(dst, srcY, mWidth * bpp);
+         srcY += srcYStride;
+         dst += dstYStride;
+    }
+
+    dst = dstStart + dstYStride * dstHeight;
+    for (size_t i = 0; i < mHeight / 2; ++i) {
+         memcpy(dst, srcU, mWidth / 2 * bpp);
+         srcU += srcUStride;
+         dst += dstUVStride;
+    }
+
+    dst = dstStart + (5 * dstYStride * dstHeight) / 4;
+    for (size_t i = 0; i < mHeight / 2; ++i) {
+         memcpy(dst, srcV, mWidth / 2 * bpp);
+         srcV += srcVStride;
+         dst += dstUVStride;
+    }
+}
+
+OMX_ERRORTYPE GoldfishVideoDecoderOMXComponent::internalGetParameter(
+        OMX_INDEXTYPE index, OMX_PTR params) {
+    switch (index) {
+        case OMX_IndexParamVideoPortFormat:
+        {
+            OMX_VIDEO_PARAM_PORTFORMATTYPE *formatParams =
+                (OMX_VIDEO_PARAM_PORTFORMATTYPE *)params;
+
+            if (!isValidOMXParam(formatParams)) {
+                return OMX_ErrorBadParameter;
+            }
+
+            if (formatParams->nPortIndex > kMaxPortIndex) {
+                return OMX_ErrorBadPortIndex;
+            }
+
+            if (formatParams->nIndex != 0) {
+                return OMX_ErrorNoMore;
+            }
+
+            if (formatParams->nPortIndex == kInputPortIndex) {
+                formatParams->eCompressionFormat = mCodingType;
+                formatParams->eColorFormat = OMX_COLOR_FormatUnused;
+                formatParams->xFramerate = 0;
+            } else {
+                CHECK_EQ(formatParams->nPortIndex, 1u);
+
+                formatParams->eCompressionFormat = OMX_VIDEO_CodingUnused;
+                formatParams->eColorFormat = OMX_COLOR_FormatYUV420Planar;
+                formatParams->xFramerate = 0;
+            }
+
+            return OMX_ErrorNone;
+        }
+
+        case OMX_IndexParamVideoProfileLevelQuerySupported:
+        {
+            OMX_VIDEO_PARAM_PROFILELEVELTYPE *profileLevel =
+                  (OMX_VIDEO_PARAM_PROFILELEVELTYPE *) params;
+
+            if (!isValidOMXParam(profileLevel)) {
+                return OMX_ErrorBadParameter;
+            }
+
+            if (profileLevel->nPortIndex != kInputPortIndex) {
+                ALOGE("Invalid port index: %" PRIu32, profileLevel->nPortIndex);
+                return OMX_ErrorUnsupportedIndex;
+            }
+
+            if (profileLevel->nProfileIndex >= mNumProfileLevels) {
+                return OMX_ErrorNoMore;
+            }
+
+            profileLevel->eProfile = mProfileLevels[profileLevel->nProfileIndex].mProfile;
+            profileLevel->eLevel   = mProfileLevels[profileLevel->nProfileIndex].mLevel;
+            return OMX_ErrorNone;
+        }
+
+        default:
+            return SimpleGoldfishOMXComponent::internalGetParameter(index, params);
+    }
+}
+
+OMX_ERRORTYPE GoldfishVideoDecoderOMXComponent::internalSetParameter(
+        OMX_INDEXTYPE index, const OMX_PTR params) {
+    // Include extension index OMX_INDEXEXTTYPE.
+    const int32_t indexFull = index;
+
+    switch (indexFull) {
+        case OMX_IndexParamStandardComponentRole:
+        {
+            const OMX_PARAM_COMPONENTROLETYPE *roleParams =
+                (const OMX_PARAM_COMPONENTROLETYPE *)params;
+
+            if (!isValidOMXParam(roleParams)) {
+                return OMX_ErrorBadParameter;
+            }
+
+            if (strncmp((const char *)roleParams->cRole,
+                        mComponentRole,
+                        OMX_MAX_STRINGNAME_SIZE - 1)) {
+                return OMX_ErrorUndefined;
+            }
+
+            return OMX_ErrorNone;
+        }
+
+        case OMX_IndexParamVideoPortFormat:
+        {
+            OMX_VIDEO_PARAM_PORTFORMATTYPE *formatParams =
+                (OMX_VIDEO_PARAM_PORTFORMATTYPE *)params;
+
+            if (!isValidOMXParam(formatParams)) {
+                return OMX_ErrorBadParameter;
+            }
+
+            if (formatParams->nPortIndex > kMaxPortIndex) {
+                return OMX_ErrorBadPortIndex;
+            }
+
+            if (formatParams->nPortIndex == kInputPortIndex) {
+                if (formatParams->eCompressionFormat != mCodingType
+                        || formatParams->eColorFormat != OMX_COLOR_FormatUnused) {
+                    return OMX_ErrorUnsupportedSetting;
+                }
+            } else {
+                if (formatParams->eCompressionFormat != OMX_VIDEO_CodingUnused
+                        || formatParams->eColorFormat != OMX_COLOR_FormatYUV420Planar) {
+                    return OMX_ErrorUnsupportedSetting;
+                }
+            }
+
+            return OMX_ErrorNone;
+        }
+
+        case kPrepareForAdaptivePlaybackIndex:
+        {
+            const PrepareForAdaptivePlaybackParams* adaptivePlaybackParams =
+                    (const PrepareForAdaptivePlaybackParams *)params;
+
+            if (!isValidOMXParam(adaptivePlaybackParams)) {
+                return OMX_ErrorBadParameter;
+            }
+
+            mIsAdaptive = adaptivePlaybackParams->bEnable;
+            if (mIsAdaptive) {
+                mAdaptiveMaxWidth = adaptivePlaybackParams->nMaxFrameWidth;
+                mAdaptiveMaxHeight = adaptivePlaybackParams->nMaxFrameHeight;
+                mWidth = mAdaptiveMaxWidth;
+                mHeight = mAdaptiveMaxHeight;
+            } else {
+                mAdaptiveMaxWidth = 0;
+                mAdaptiveMaxHeight = 0;
+            }
+            updatePortDefinitions(true /* updateCrop */, true /* updateInputSize */);
+            return OMX_ErrorNone;
+        }
+
+        case OMX_IndexParamPortDefinition:
+        {
+            OMX_PARAM_PORTDEFINITIONTYPE *newParams =
+                (OMX_PARAM_PORTDEFINITIONTYPE *)params;
+
+            if (!isValidOMXParam(newParams)) {
+                return OMX_ErrorBadParameter;
+            }
+
+            OMX_VIDEO_PORTDEFINITIONTYPE *video_def = &newParams->format.video;
+            OMX_PARAM_PORTDEFINITIONTYPE *def = &editPortInfo(newParams->nPortIndex)->mDef;
+
+            uint32_t oldWidth = def->format.video.nFrameWidth;
+            uint32_t oldHeight = def->format.video.nFrameHeight;
+            uint32_t newWidth = video_def->nFrameWidth;
+            uint32_t newHeight = video_def->nFrameHeight;
+            // We need width, height, stride and slice-height to be non-zero and sensible.
+            // These values were chosen to prevent integer overflows further down the line, and do
+            // not indicate support for 32kx32k video.
+            if (newWidth > 32768 || newHeight > 32768
+                    || video_def->nStride > 32768 || video_def->nStride < -32768
+                    || video_def->nSliceHeight > 32768) {
+                ALOGE("b/22885421");
+                return OMX_ErrorBadParameter;
+            }
+            if (newWidth != oldWidth || newHeight != oldHeight) {
+                bool outputPort = (newParams->nPortIndex == kOutputPortIndex);
+                if (outputPort) {
+                    // only update (essentially crop) if size changes
+                    mWidth = newWidth;
+                    mHeight = newHeight;
+
+                    updatePortDefinitions(true /* updateCrop */, true /* updateInputSize */);
+                    // reset buffer size based on frame size
+                    newParams->nBufferSize = def->nBufferSize;
+                } else {
+                    // For input port, we only set nFrameWidth and nFrameHeight. Buffer size
+                    // is updated when configuring the output port using the max-frame-size,
+                    // though client can still request a larger size.
+                    def->format.video.nFrameWidth = newWidth;
+                    def->format.video.nFrameHeight = newHeight;
+                }
+            }
+            return SimpleGoldfishOMXComponent::internalSetParameter(index, params);
+        }
+
+        default:
+            return SimpleGoldfishOMXComponent::internalSetParameter(index, params);
+    }
+}
+
+OMX_ERRORTYPE GoldfishVideoDecoderOMXComponent::getConfig(
+        OMX_INDEXTYPE index, OMX_PTR params) {
+    switch ((int)index) {
+        case OMX_IndexConfigCommonOutputCrop:
+        {
+            OMX_CONFIG_RECTTYPE *rectParams = (OMX_CONFIG_RECTTYPE *)params;
+
+            if (!isValidOMXParam(rectParams)) {
+                return OMX_ErrorBadParameter;
+            }
+
+            if (rectParams->nPortIndex != kOutputPortIndex) {
+                return OMX_ErrorUndefined;
+            }
+
+            rectParams->nLeft = mCropLeft;
+            rectParams->nTop = mCropTop;
+            rectParams->nWidth = mCropWidth;
+            rectParams->nHeight = mCropHeight;
+
+            return OMX_ErrorNone;
+        }
+        case kDescribeColorAspectsIndex:
+        {
+            if (!supportsDescribeColorAspects()) {
+                return OMX_ErrorUnsupportedIndex;
+            }
+
+            DescribeColorAspectsParams* colorAspectsParams =
+                    (DescribeColorAspectsParams *)params;
+
+            if (!isValidOMXParam(colorAspectsParams)) {
+                return OMX_ErrorBadParameter;
+            }
+
+            if (colorAspectsParams->nPortIndex != kOutputPortIndex) {
+                return OMX_ErrorBadParameter;
+            }
+
+            colorAspectsParams->sAspects = mFinalColorAspects;
+            if (colorAspectsParams->bRequestingDataSpace || colorAspectsParams->bDataSpaceChanged) {
+                return OMX_ErrorUnsupportedSetting;
+            }
+
+            return OMX_ErrorNone;
+        }
+
+        case kDescribeHdrStaticInfoIndex:
+        {
+            if (!supportDescribeHdrStaticInfo()) {
+                return OMX_ErrorUnsupportedIndex;
+            }
+
+            DescribeHDRStaticInfoParams* hdrStaticInfoParams =
+                    (DescribeHDRStaticInfoParams *)params;
+
+            if (!isValidOMXParam(hdrStaticInfoParams)) {
+                return OMX_ErrorBadParameter;
+            }
+
+            if (hdrStaticInfoParams->nPortIndex != kOutputPortIndex) {
+                return OMX_ErrorBadPortIndex;
+            }
+
+            hdrStaticInfoParams->sInfo = mHdrStaticInfo;
+
+            return OMX_ErrorNone;
+        }
+
+        case kDescribeHdr10PlusInfoIndex:
+        {
+            if (!supportDescribeHdr10PlusInfo()) {
+                return OMX_ErrorUnsupportedIndex;
+            }
+
+            if (mHdr10PlusOutputs.size() > 0) {
+                auto it = mHdr10PlusOutputs.begin();
+
+                auto info = (*it).get();
+
+                DescribeHDR10PlusInfoParams* outParams =
+                        (DescribeHDR10PlusInfoParams *)params;
+
+                outParams->nParamSizeUsed = info->size();
+
+                // If the buffer provided by the client does not have enough
+                // storage, return the size only and do not remove the param yet.
+                if (outParams->nParamSize >= info->size()) {
+                    memcpy(outParams->nValue, info->data(), info->size());
+                    mHdr10PlusOutputs.erase(it);
+                }
+                return OMX_ErrorNone;
+            }
+            return OMX_ErrorUnderflow;
+        }
+
+        default:
+            return OMX_ErrorUnsupportedIndex;
+    }
+}
+
+OMX_ERRORTYPE GoldfishVideoDecoderOMXComponent::internalSetConfig(
+        OMX_INDEXTYPE index, const OMX_PTR params, bool *frameConfig){
+    switch ((int)index) {
+        case kDescribeColorAspectsIndex:
+        {
+            if (!supportsDescribeColorAspects()) {
+                return OMX_ErrorUnsupportedIndex;
+            }
+            const DescribeColorAspectsParams* colorAspectsParams =
+                    (const DescribeColorAspectsParams *)params;
+
+            if (!isValidOMXParam(colorAspectsParams)) {
+                return OMX_ErrorBadParameter;
+            }
+
+            if (colorAspectsParams->nPortIndex != kOutputPortIndex) {
+                return OMX_ErrorBadParameter;
+            }
+
+            // Update color aspects if necessary.
+            if (colorAspectsDiffer(colorAspectsParams->sAspects, mDefaultColorAspects)) {
+                mDefaultColorAspects = colorAspectsParams->sAspects;
+                status_t err = handleColorAspectsChange();
+                CHECK(err == OK);
+            }
+            return OMX_ErrorNone;
+        }
+
+        case kDescribeHdrStaticInfoIndex:
+        {
+            if (!supportDescribeHdrStaticInfo()) {
+                return OMX_ErrorUnsupportedIndex;
+            }
+
+            const DescribeHDRStaticInfoParams* hdrStaticInfoParams =
+                    (DescribeHDRStaticInfoParams *)params;
+
+            if (!isValidOMXParam(hdrStaticInfoParams)) {
+                return OMX_ErrorBadParameter;
+            }
+
+            if (hdrStaticInfoParams->nPortIndex != kOutputPortIndex) {
+                return OMX_ErrorBadPortIndex;
+            }
+
+            mHdrStaticInfo = hdrStaticInfoParams->sInfo;
+            updatePortDefinitions(false);
+
+            return OMX_ErrorNone;
+        }
+
+        case kDescribeHdr10PlusInfoIndex:
+        {
+            if (!supportDescribeHdr10PlusInfo()) {
+                return OMX_ErrorUnsupportedIndex;
+            }
+
+            const DescribeHDR10PlusInfoParams* inParams =
+                    (DescribeHDR10PlusInfoParams *)params;
+
+            if (*frameConfig) {
+                // This is a request to append to the current frame config set.
+                // For now, we only support kDescribeHdr10PlusInfoIndex, which
+                // we simply replace with the last set value.
+                if (mHdr10PlusInputs.size() > 0) {
+                    *(--mHdr10PlusInputs.end()) = ABuffer::CreateAsCopy(
+                            inParams->nValue, inParams->nParamSizeUsed);
+                } else {
+                    ALOGW("Ignoring kDescribeHdr10PlusInfoIndex: append to "
+                            "frame config while no frame config is present");
+                }
+            } else {
+                // This is a frame config, setting *frameConfig to true so that
+                // the client marks the next queued input frame to apply it.
+                *frameConfig = true;
+                mHdr10PlusInputs.push_back(ABuffer::CreateAsCopy(
+                        inParams->nValue, inParams->nParamSizeUsed));
+            }
+            return OMX_ErrorNone;
+        }
+
+        default:
+            return OMX_ErrorUnsupportedIndex;
+    }
+}
+
+sp<ABuffer> GoldfishVideoDecoderOMXComponent::dequeueInputFrameConfig() {
+    auto it = mHdr10PlusInputs.begin();
+    sp<ABuffer> info = *it;
+    mHdr10PlusInputs.erase(it);
+    return info;
+}
+
+void GoldfishVideoDecoderOMXComponent::queueOutputFrameConfig(const sp<ABuffer> &info) {
+    mHdr10PlusOutputs.push_back(info);
+    notify(OMX_EventConfigUpdate,
+           kOutputPortIndex,
+           kDescribeHdr10PlusInfoIndex,
+           NULL);
+}
+
+OMX_ERRORTYPE GoldfishVideoDecoderOMXComponent::getExtensionIndex(
+        const char *name, OMX_INDEXTYPE *index) {
+    if (!strcmp(name, "OMX.google.android.index.prepareForAdaptivePlayback")) {
+        *(int32_t*)index = kPrepareForAdaptivePlaybackIndex;
+        return OMX_ErrorNone;
+    } else if (!strcmp(name, "OMX.google.android.index.describeColorAspects")
+                && supportsDescribeColorAspects()) {
+        *(int32_t*)index = kDescribeColorAspectsIndex;
+        return OMX_ErrorNone;
+    } else if (!strcmp(name, "OMX.google.android.index.describeHDRStaticInfo")
+            && supportDescribeHdrStaticInfo()) {
+        *(int32_t*)index = kDescribeHdrStaticInfoIndex;
+        return OMX_ErrorNone;
+    } else if (!strcmp(name, "OMX.google.android.index.describeHDR10PlusInfo")
+            && supportDescribeHdr10PlusInfo()) {
+        *(int32_t*)index = kDescribeHdr10PlusInfoIndex;
+        return OMX_ErrorNone;
+    }
+
+    return SimpleGoldfishOMXComponent::getExtensionIndex(name, index);
+}
+
+bool GoldfishVideoDecoderOMXComponent::supportsDescribeColorAspects() {
+    return getColorAspectPreference() != kNotSupported;
+}
+
+int GoldfishVideoDecoderOMXComponent::getColorAspectPreference() {
+    return kNotSupported;
+}
+
+bool GoldfishVideoDecoderOMXComponent::supportDescribeHdrStaticInfo() {
+    return false;
+}
+
+bool GoldfishVideoDecoderOMXComponent::supportDescribeHdr10PlusInfo() {
+    return false;
+}
+
+void GoldfishVideoDecoderOMXComponent::onReset() {
+    mOutputPortSettingsChange = NONE;
+}
+
+void GoldfishVideoDecoderOMXComponent::onPortEnableCompleted(OMX_U32 portIndex, bool enabled) {
+    if (portIndex != kOutputPortIndex) {
+        return;
+    }
+
+    switch (mOutputPortSettingsChange) {
+        case NONE:
+            break;
+
+        case AWAITING_DISABLED:
+        {
+            CHECK(!enabled);
+            mOutputPortSettingsChange = AWAITING_ENABLED;
+            break;
+        }
+
+        default:
+        {
+            CHECK_EQ((int)mOutputPortSettingsChange, (int)AWAITING_ENABLED);
+            CHECK(enabled);
+            mOutputPortSettingsChange = NONE;
+            break;
+        }
+    }
+}
+
+}  // namespace android
diff --git a/system/codecs/omx/plugin/GoldfishVideoDecoderOMXComponent.h b/system/codecs/omx/plugin/GoldfishVideoDecoderOMXComponent.h
new file mode 100644
index 0000000..bf60f61
--- /dev/null
+++ b/system/codecs/omx/plugin/GoldfishVideoDecoderOMXComponent.h
@@ -0,0 +1,197 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef GOLDFISH_VIDEO_DECODER_OMX_COMPONENT_H_
+
+#define GOLDFISH_VIDEO_DECODER_OMX_COMPONENT_H_
+
+#include "SimpleGoldfishOMXComponent.h"
+
+#include <media/stagefright/foundation/ABuffer.h>
+#include <media/stagefright/foundation/AHandlerReflector.h>
+#include <media/stagefright/foundation/ColorUtils.h>
+#include <media/IOMX.h>
+#include <media/hardware/HardwareAPI.h>
+
+#include <utils/RefBase.h>
+#include <utils/threads.h>
+#include <utils/Vector.h>
+#include <utils/List.h>
+
+namespace android {
+
+struct GoldfishVideoDecoderOMXComponent : public SimpleGoldfishOMXComponent {
+    GoldfishVideoDecoderOMXComponent(
+            const char *name,
+            const char *componentRole,
+            OMX_VIDEO_CODINGTYPE codingType,
+            const CodecProfileLevel *profileLevels,
+            size_t numProfileLevels,
+            int32_t width,
+            int32_t height,
+            const OMX_CALLBACKTYPE *callbacks,
+            OMX_PTR appData,
+            OMX_COMPONENTTYPE **component);
+
+protected:
+    enum {
+        kDescribeColorAspectsIndex = kPrepareForAdaptivePlaybackIndex + 1,
+        kDescribeHdrStaticInfoIndex = kPrepareForAdaptivePlaybackIndex + 2,
+        kDescribeHdr10PlusInfoIndex = kPrepareForAdaptivePlaybackIndex + 3,
+        kEnableAndroidNativeBuffersIndex = kPrepareForAdaptivePlaybackIndex + 4,
+        kUseAndroidNativeBufferIndex = kPrepareForAdaptivePlaybackIndex + 5,
+        kGetAndroidNativeBufferUsageIndex = kPrepareForAdaptivePlaybackIndex + 6,
+    };
+
+    enum {
+        kNotSupported,
+        kPreferBitstream,
+        kPreferContainer,
+    };
+
+    virtual void onPortEnableCompleted(OMX_U32 portIndex, bool enabled);
+    virtual void onReset();
+
+    virtual OMX_ERRORTYPE internalGetParameter(
+            OMX_INDEXTYPE index, OMX_PTR params);
+
+    virtual OMX_ERRORTYPE internalSetParameter(
+            OMX_INDEXTYPE index, const OMX_PTR params);
+
+    virtual OMX_ERRORTYPE getConfig(
+            OMX_INDEXTYPE index, OMX_PTR params);
+
+    virtual OMX_ERRORTYPE internalSetConfig(
+            OMX_INDEXTYPE index, const OMX_PTR params, bool *frameConfig);
+
+    virtual OMX_ERRORTYPE getExtensionIndex(
+            const char *name, OMX_INDEXTYPE *index);
+
+    virtual bool supportsDescribeColorAspects();
+
+    virtual int getColorAspectPreference();
+
+    virtual bool supportDescribeHdrStaticInfo();
+
+    virtual bool supportDescribeHdr10PlusInfo();
+
+    // This function sets both minimum buffer count and actual buffer count of
+    // input port to be |numInputBuffers|. It will also set both minimum buffer
+    // count and actual buffer count of output port to be |numOutputBuffers|.
+    void initPorts(OMX_U32 numInputBuffers,
+            OMX_U32 inputBufferSize,
+            OMX_U32 numOutputBuffers,
+            const char *mimeType,
+            OMX_U32 minCompressionRatio = 1u);
+
+    // This function sets input port's minimum buffer count to |numMinInputBuffers|,
+    // sets input port's actual buffer count to |numInputBuffers|, sets output port's
+    // minimum buffer count to |numMinOutputBuffers| and sets output port's actual buffer
+    // count to be |numOutputBuffers|.
+    void initPorts(OMX_U32 numMinInputBuffers,
+            OMX_U32 numInputBuffers,
+            OMX_U32 inputBufferSize,
+            OMX_U32 numMinOutputBuffers,
+            OMX_U32 numOutputBuffers,
+            const char *mimeType,
+            OMX_U32 minCompressionRatio = 1u);
+
+    virtual void updatePortDefinitions(bool updateCrop = true, bool updateInputSize = false);
+
+    uint32_t outputBufferWidth();
+    uint32_t outputBufferHeight();
+
+    enum CropSettingsMode {
+        kCropUnSet = 0,
+        kCropSet,
+        kCropChanged,
+    };
+
+    // This function will handle several port change events which include
+    // size changed, crop changed, stride changed and coloraspects changed.
+    // It will trigger OMX_EventPortSettingsChanged event if necessary.
+    void handlePortSettingsChange(
+            bool *portWillReset, uint32_t width, uint32_t height,
+            OMX_COLOR_FORMATTYPE outputFormat = OMX_COLOR_FormatYUV420Planar,
+            CropSettingsMode cropSettingsMode = kCropUnSet,
+            bool fakeStride = false);
+
+    void copyYV12FrameToOutputBuffer(
+            uint8_t *dst, const uint8_t *srcY, const uint8_t *srcU, const uint8_t *srcV,
+            size_t srcYStride, size_t srcUStride, size_t srcVStride);
+
+    enum {
+        kInputPortIndex  = 0,
+        kOutputPortIndex = 1,
+        kMaxPortIndex = 1,
+    };
+
+    bool mIsAdaptive;
+    uint32_t mAdaptiveMaxWidth, mAdaptiveMaxHeight;
+    uint32_t mWidth, mHeight;
+    uint32_t mCropLeft, mCropTop, mCropWidth, mCropHeight;
+    OMX_COLOR_FORMATTYPE mOutputFormat;
+    HDRStaticInfo mHdrStaticInfo;
+    enum {
+        NONE,
+        AWAITING_DISABLED,
+        AWAITING_ENABLED
+    } mOutputPortSettingsChange;
+
+    bool mUpdateColorAspects;
+
+    Mutex mColorAspectsLock;
+    // color aspects passed from the framework.
+    ColorAspects mDefaultColorAspects;
+    // color aspects parsed from the bitstream.
+    ColorAspects mBitstreamColorAspects;
+    // final color aspects after combining the above two aspects.
+    ColorAspects mFinalColorAspects;
+
+    bool colorAspectsDiffer(const ColorAspects &a, const ColorAspects &b);
+
+    // This functions takes two color aspects and updates the mFinalColorAspects
+    // based on |preferredAspects|.
+    void updateFinalColorAspects(
+            const ColorAspects &otherAspects, const ColorAspects &preferredAspects);
+
+    // This function will update the mFinalColorAspects based on codec preference.
+    status_t handleColorAspectsChange();
+
+    // Helper function to dump the ColorAspects.
+    void dumpColorAspects(const ColorAspects &colorAspects);
+
+    sp<ABuffer> dequeueInputFrameConfig();
+    void queueOutputFrameConfig(const sp<ABuffer> &info);
+
+private:
+    uint32_t mMinInputBufferSize;
+    uint32_t mMinCompressionRatio;
+
+    const char *mComponentRole;
+    OMX_VIDEO_CODINGTYPE mCodingType;
+    const CodecProfileLevel *mProfileLevels;
+    size_t mNumProfileLevels;
+    typedef List<sp<ABuffer> > Hdr10PlusInfoList;
+    Hdr10PlusInfoList mHdr10PlusInputs;
+    Hdr10PlusInfoList mHdr10PlusOutputs;
+
+    DISALLOW_EVIL_CONSTRUCTORS(GoldfishVideoDecoderOMXComponent);
+};
+
+}  // namespace android
+
+#endif  // GOLDFISH_VIDEO_DECODER_OMX_COMPONENT_H_
diff --git a/system/codecs/omx/plugin/SimpleGoldfishOMXComponent.cpp b/system/codecs/omx/plugin/SimpleGoldfishOMXComponent.cpp
new file mode 100644
index 0000000..41f71c4
--- /dev/null
+++ b/system/codecs/omx/plugin/SimpleGoldfishOMXComponent.cpp
@@ -0,0 +1,750 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "SimpleGoldfishOMXComponent"
+#include <utils/Log.h>
+
+#include "SimpleGoldfishOMXComponent.h"
+#include <media/stagefright/foundation/ADebug.h>
+#include <media/stagefright/foundation/ALooper.h>
+#include <media/stagefright/foundation/AMessage.h>
+
+namespace android {
+
+SimpleGoldfishOMXComponent::SimpleGoldfishOMXComponent(
+        const char *name,
+        const OMX_CALLBACKTYPE *callbacks,
+        OMX_PTR appData,
+        OMX_COMPONENTTYPE **component)
+    : GoldfishOMXComponent(name, callbacks, appData, component),
+      mLooper(new ALooper),
+      mHandler(new AHandlerReflector<SimpleGoldfishOMXComponent>(this)),
+      mState(OMX_StateLoaded),
+      mTargetState(OMX_StateLoaded),
+      mFrameConfig(false) {
+    mLooper->setName(name);
+    mLooper->registerHandler(mHandler);
+
+    mLooper->start(
+            false, // runOnCallingThread
+            false, // canCallJava
+            ANDROID_PRIORITY_VIDEO);
+}
+
+void SimpleGoldfishOMXComponent::prepareForDestruction() {
+    // The looper's queue may still contain messages referencing this
+    // object. Make sure those are flushed before returning so that
+    // a subsequent dlunload() does not pull out the rug from under us.
+
+    mLooper->unregisterHandler(mHandler->id());
+    mLooper->stop();
+}
+
+OMX_ERRORTYPE SimpleGoldfishOMXComponent::sendCommand(
+        OMX_COMMANDTYPE cmd, OMX_U32 param, OMX_PTR data) {
+    CHECK(data == NULL);
+
+    sp<AMessage> msg = new AMessage(kWhatSendCommand, mHandler);
+    msg->setInt32("cmd", cmd);
+    msg->setInt32("param", param);
+    msg->post();
+
+    return OMX_ErrorNone;
+}
+
+bool SimpleGoldfishOMXComponent::isSetParameterAllowed(
+        OMX_INDEXTYPE index, const OMX_PTR params) const {
+    if (mState == OMX_StateLoaded) {
+        return true;
+    }
+
+    OMX_U32 portIndex;
+
+    switch (index) {
+        case OMX_IndexParamPortDefinition:
+        {
+            const OMX_PARAM_PORTDEFINITIONTYPE *portDefs =
+                    (const OMX_PARAM_PORTDEFINITIONTYPE *) params;
+            if (!isValidOMXParam(portDefs)) {
+                return false;
+            }
+            portIndex = portDefs->nPortIndex;
+            break;
+        }
+
+        case OMX_IndexParamAudioPcm:
+        {
+            const OMX_AUDIO_PARAM_PCMMODETYPE *pcmMode =
+                    (const OMX_AUDIO_PARAM_PCMMODETYPE *) params;
+            if (!isValidOMXParam(pcmMode)) {
+                return false;
+            }
+            portIndex = pcmMode->nPortIndex;
+            break;
+        }
+
+        case OMX_IndexParamAudioAac:
+        {
+            const OMX_AUDIO_PARAM_AACPROFILETYPE *aacMode =
+                    (const OMX_AUDIO_PARAM_AACPROFILETYPE *) params;
+            if (!isValidOMXParam(aacMode)) {
+                return false;
+            }
+            portIndex = aacMode->nPortIndex;
+            break;
+        }
+
+        default:
+            return false;
+    }
+
+    CHECK(portIndex < mPorts.size());
+
+    return !mPorts.itemAt(portIndex).mDef.bEnabled;
+}
+
+OMX_ERRORTYPE SimpleGoldfishOMXComponent::getParameter(
+        OMX_INDEXTYPE index, OMX_PTR params) {
+    Mutex::Autolock autoLock(mLock);
+    return internalGetParameter(index, params);
+}
+
+OMX_ERRORTYPE SimpleGoldfishOMXComponent::setParameter(
+        OMX_INDEXTYPE index, const OMX_PTR params) {
+    Mutex::Autolock autoLock(mLock);
+
+    //CHECK(isSetParameterAllowed(index, params));
+
+    return internalSetParameter(index, params);
+}
+
+OMX_ERRORTYPE SimpleGoldfishOMXComponent::internalGetParameter(
+        OMX_INDEXTYPE index, OMX_PTR params) {
+    switch (index) {
+        case OMX_IndexParamPortDefinition:
+        {
+            OMX_PARAM_PORTDEFINITIONTYPE *defParams =
+                (OMX_PARAM_PORTDEFINITIONTYPE *)params;
+
+            if (!isValidOMXParam(defParams)) {
+                return OMX_ErrorBadParameter;
+            }
+
+            if (defParams->nPortIndex >= mPorts.size()
+                    || defParams->nSize
+                            != sizeof(OMX_PARAM_PORTDEFINITIONTYPE)) {
+                return OMX_ErrorUndefined;
+            }
+
+            const PortInfo *port =
+                &mPorts.itemAt(defParams->nPortIndex);
+
+            memcpy(defParams, &port->mDef, sizeof(port->mDef));
+
+            return OMX_ErrorNone;
+        }
+
+        default:
+            return OMX_ErrorUnsupportedIndex;
+    }
+}
+
+OMX_ERRORTYPE SimpleGoldfishOMXComponent::internalSetParameter(
+        OMX_INDEXTYPE index, const OMX_PTR params) {
+    switch (index) {
+        case OMX_IndexParamPortDefinition:
+        {
+            OMX_PARAM_PORTDEFINITIONTYPE *defParams =
+                (OMX_PARAM_PORTDEFINITIONTYPE *)params;
+
+            if (!isValidOMXParam(defParams)) {
+                return OMX_ErrorBadParameter;
+            }
+
+            if (defParams->nPortIndex >= mPorts.size()) {
+                return OMX_ErrorBadPortIndex;
+            }
+            if (defParams->nSize != sizeof(OMX_PARAM_PORTDEFINITIONTYPE)) {
+                return OMX_ErrorUnsupportedSetting;
+            }
+
+            PortInfo *port =
+                &mPorts.editItemAt(defParams->nPortIndex);
+
+            // default behavior is that we only allow buffer size to increase
+            if (defParams->nBufferSize > port->mDef.nBufferSize) {
+                port->mDef.nBufferSize = defParams->nBufferSize;
+            }
+
+            if (defParams->nBufferCountActual < port->mDef.nBufferCountMin) {
+                ALOGW("component requires at least %u buffers (%u requested)",
+                        port->mDef.nBufferCountMin, defParams->nBufferCountActual);
+                return OMX_ErrorUnsupportedSetting;
+            }
+
+            port->mDef.nBufferCountActual = defParams->nBufferCountActual;
+            return OMX_ErrorNone;
+        }
+
+        default:
+            return OMX_ErrorUnsupportedIndex;
+    }
+}
+
+OMX_ERRORTYPE SimpleGoldfishOMXComponent::internalSetConfig(
+        OMX_INDEXTYPE index __unused, const OMX_PTR params __unused, bool *frameConfig __unused) {
+    return OMX_ErrorUndefined;
+}
+
+OMX_ERRORTYPE SimpleGoldfishOMXComponent::setConfig(
+        OMX_INDEXTYPE index, const OMX_PTR params) {
+    bool frameConfig = mFrameConfig;
+    OMX_ERRORTYPE err = internalSetConfig(index, params, &frameConfig);
+    if (err == OMX_ErrorNone) {
+        mFrameConfig = frameConfig;
+    }
+    return err;
+}
+
+OMX_ERRORTYPE SimpleGoldfishOMXComponent::useBuffer(
+        OMX_BUFFERHEADERTYPE **header,
+        OMX_U32 portIndex,
+        OMX_PTR appPrivate,
+        OMX_U32 size,
+        OMX_U8 *ptr) {
+    Mutex::Autolock autoLock(mLock);
+    return useBufferCallerLockedAlready(header, portIndex, appPrivate, size, ptr);
+}
+
+OMX_ERRORTYPE SimpleGoldfishOMXComponent::useBufferCallerLockedAlready(
+        OMX_BUFFERHEADERTYPE **header,
+        OMX_U32 portIndex,
+        OMX_PTR appPrivate,
+        OMX_U32 size,
+        OMX_U8 *ptr) {
+    CHECK_LT(portIndex, mPorts.size());
+    CHECK_LT(portIndex, mPorts.size());
+
+    PortInfo *port = &mPorts.editItemAt(portIndex);
+    if (size < port->mDef.nBufferSize) {
+        ALOGE("b/63522430, Buffer size is too small.");
+        android_errorWriteLog(0x534e4554, "63522430");
+        return OMX_ErrorBadParameter;
+    }
+
+    *header = new OMX_BUFFERHEADERTYPE;
+    (*header)->nSize = sizeof(OMX_BUFFERHEADERTYPE);
+    (*header)->nVersion.s.nVersionMajor = 1;
+    (*header)->nVersion.s.nVersionMinor = 0;
+    (*header)->nVersion.s.nRevision = 0;
+    (*header)->nVersion.s.nStep = 0;
+    (*header)->pBuffer = ptr;
+    (*header)->nAllocLen = size;
+    (*header)->nFilledLen = 0;
+    (*header)->nOffset = 0;
+    (*header)->pAppPrivate = appPrivate;
+    (*header)->pPlatformPrivate = NULL;
+    (*header)->pInputPortPrivate = NULL;
+    (*header)->pOutputPortPrivate = NULL;
+    (*header)->hMarkTargetComponent = NULL;
+    (*header)->pMarkData = NULL;
+    (*header)->nTickCount = 0;
+    (*header)->nTimeStamp = 0;
+    (*header)->nFlags = 0;
+    (*header)->nOutputPortIndex = portIndex;
+    (*header)->nInputPortIndex = portIndex;
+
+    CHECK(mState == OMX_StateLoaded || port->mDef.bEnabled == OMX_FALSE);
+
+    CHECK_LT(port->mBuffers.size(), port->mDef.nBufferCountActual);
+
+    port->mBuffers.push();
+
+    BufferInfo *buffer =
+        &port->mBuffers.editItemAt(port->mBuffers.size() - 1);
+
+    buffer->mHeader = *header;
+    buffer->mOwnedByUs = false;
+
+    if (port->mBuffers.size() == port->mDef.nBufferCountActual) {
+        port->mDef.bPopulated = OMX_TRUE;
+        checkTransitions();
+    }
+
+    return OMX_ErrorNone;
+}
+
+OMX_ERRORTYPE SimpleGoldfishOMXComponent::allocateBuffer(
+        OMX_BUFFERHEADERTYPE **header,
+        OMX_U32 portIndex,
+        OMX_PTR appPrivate,
+        OMX_U32 size) {
+    OMX_U8 *ptr = new OMX_U8[size];
+
+    OMX_ERRORTYPE err =
+        useBuffer(header, portIndex, appPrivate, size, ptr);
+
+    if (err != OMX_ErrorNone) {
+        delete[] ptr;
+        ptr = NULL;
+
+        return err;
+    }
+
+    CHECK((*header)->pPlatformPrivate == NULL);
+    (*header)->pPlatformPrivate = ptr;
+
+    return OMX_ErrorNone;
+}
+
+OMX_ERRORTYPE SimpleGoldfishOMXComponent::freeBuffer(
+        OMX_U32 portIndex,
+        OMX_BUFFERHEADERTYPE *header) {
+    Mutex::Autolock autoLock(mLock);
+
+    CHECK_LT(portIndex, mPorts.size());
+
+    PortInfo *port = &mPorts.editItemAt(portIndex);
+
+#if 0 // XXX
+    CHECK((mState == OMX_StateIdle && mTargetState == OMX_StateLoaded)
+            || port->mDef.bEnabled == OMX_FALSE);
+#endif
+
+    bool found = false;
+    for (size_t i = 0; i < port->mBuffers.size(); ++i) {
+        BufferInfo *buffer = &port->mBuffers.editItemAt(i);
+
+        if (buffer->mHeader == header) {
+            CHECK(!buffer->mOwnedByUs);
+
+            if (header->pPlatformPrivate != NULL) {
+                // This buffer's data was allocated by us.
+                CHECK(header->pPlatformPrivate == header->pBuffer);
+
+                delete[] header->pBuffer;
+                header->pBuffer = NULL;
+            }
+
+            delete header;
+            header = NULL;
+
+            port->mBuffers.removeAt(i);
+            port->mDef.bPopulated = OMX_FALSE;
+
+            checkTransitions();
+
+            found = true;
+            break;
+        }
+    }
+
+    CHECK(found);
+
+    return OMX_ErrorNone;
+}
+
+OMX_ERRORTYPE SimpleGoldfishOMXComponent::emptyThisBuffer(
+        OMX_BUFFERHEADERTYPE *buffer) {
+    sp<AMessage> msg = new AMessage(kWhatEmptyThisBuffer, mHandler);
+    msg->setPointer("header", buffer);
+    if (mFrameConfig) {
+        msg->setInt32("frame-config", mFrameConfig);
+        mFrameConfig = false;
+    }
+    msg->post();
+
+    return OMX_ErrorNone;
+}
+
+OMX_ERRORTYPE SimpleGoldfishOMXComponent::fillThisBuffer(
+        OMX_BUFFERHEADERTYPE *buffer) {
+    sp<AMessage> msg = new AMessage(kWhatFillThisBuffer, mHandler);
+    msg->setPointer("header", buffer);
+    msg->post();
+
+    return OMX_ErrorNone;
+}
+
+OMX_ERRORTYPE SimpleGoldfishOMXComponent::getState(OMX_STATETYPE *state) {
+    Mutex::Autolock autoLock(mLock);
+
+    *state = mState;
+
+    return OMX_ErrorNone;
+}
+
+void SimpleGoldfishOMXComponent::onMessageReceived(const sp<AMessage> &msg) {
+    Mutex::Autolock autoLock(mLock);
+    uint32_t msgType = msg->what();
+    ALOGV("msgType = %d", msgType);
+    switch (msgType) {
+        case kWhatSendCommand:
+        {
+            int32_t cmd, param;
+            CHECK(msg->findInt32("cmd", &cmd));
+            CHECK(msg->findInt32("param", &param));
+
+            onSendCommand((OMX_COMMANDTYPE)cmd, (OMX_U32)param);
+            break;
+        }
+
+        case kWhatEmptyThisBuffer:
+        case kWhatFillThisBuffer:
+        {
+            OMX_BUFFERHEADERTYPE *header;
+            CHECK(msg->findPointer("header", (void **)&header));
+            int32_t frameConfig;
+            if (!msg->findInt32("frame-config", &frameConfig)) {
+                frameConfig = 0;
+            }
+
+            CHECK(mState == OMX_StateExecuting && mTargetState == mState);
+
+            bool found = false;
+            size_t portIndex = (kWhatEmptyThisBuffer == msgType)?
+                    header->nInputPortIndex: header->nOutputPortIndex;
+            PortInfo *port = &mPorts.editItemAt(portIndex);
+
+            for (size_t j = 0; j < port->mBuffers.size(); ++j) {
+                BufferInfo *buffer = &port->mBuffers.editItemAt(j);
+
+                if (buffer->mHeader == header) {
+                    CHECK(!buffer->mOwnedByUs);
+
+                    buffer->mOwnedByUs = true;
+                    buffer->mFrameConfig = (bool)frameConfig;
+
+                    CHECK((msgType == kWhatEmptyThisBuffer
+                            && port->mDef.eDir == OMX_DirInput)
+                            || (port->mDef.eDir == OMX_DirOutput));
+
+                    port->mQueue.push_back(buffer);
+                    onQueueFilled(portIndex);
+
+                    found = true;
+                    break;
+                }
+            }
+
+            CHECK(found);
+            break;
+        }
+
+        default:
+            TRESPASS();
+            break;
+    }
+}
+
+void SimpleGoldfishOMXComponent::onSendCommand(
+        OMX_COMMANDTYPE cmd, OMX_U32 param) {
+    switch (cmd) {
+        case OMX_CommandStateSet:
+        {
+            onChangeState((OMX_STATETYPE)param);
+            break;
+        }
+
+        case OMX_CommandPortEnable:
+        case OMX_CommandPortDisable:
+        {
+            onPortEnable(param, cmd == OMX_CommandPortEnable);
+            break;
+        }
+
+        case OMX_CommandFlush:
+        {
+            onPortFlush(param, true /* sendFlushComplete */);
+            break;
+        }
+
+        default:
+            TRESPASS();
+            break;
+    }
+}
+
+void SimpleGoldfishOMXComponent::onChangeState(OMX_STATETYPE state) {
+    ALOGV("%p requesting change from %d to %d", this, mState, state);
+    // We shouldn't be in a state transition already.
+
+    if (mState == OMX_StateLoaded
+            && mTargetState == OMX_StateIdle
+            && state == OMX_StateLoaded) {
+        // OMX specifically allows "canceling" a state transition from loaded
+        // to idle. Pretend we made it to idle, and go back to loaded
+        ALOGV("load->idle canceled");
+        mState = mTargetState = OMX_StateIdle;
+        state = OMX_StateLoaded;
+    }
+
+    if (mState != mTargetState) {
+        ALOGE("State change to state %d requested while still transitioning from state %d to %d",
+                state, mState, mTargetState);
+        notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL);
+        return;
+    }
+
+    switch (mState) {
+        case OMX_StateLoaded:
+            CHECK_EQ((int)state, (int)OMX_StateIdle);
+            break;
+        case OMX_StateIdle:
+            CHECK(state == OMX_StateLoaded || state == OMX_StateExecuting);
+            break;
+        case OMX_StateExecuting:
+        {
+            CHECK_EQ((int)state, (int)OMX_StateIdle);
+
+            for (size_t i = 0; i < mPorts.size(); ++i) {
+                onPortFlush(i, false /* sendFlushComplete */);
+            }
+
+            mState = OMX_StateIdle;
+            notify(OMX_EventCmdComplete, OMX_CommandStateSet, state, NULL);
+            break;
+        }
+
+        default:
+            TRESPASS();
+    }
+
+    mTargetState = state;
+
+    checkTransitions();
+}
+
+void SimpleGoldfishOMXComponent::onReset() {
+    // no-op
+}
+
+void SimpleGoldfishOMXComponent::onPortEnable(OMX_U32 portIndex, bool enable) {
+    CHECK_LT(portIndex, mPorts.size());
+
+    PortInfo *port = &mPorts.editItemAt(portIndex);
+    CHECK_EQ((int)port->mTransition, (int)PortInfo::NONE);
+    CHECK(port->mDef.bEnabled == !enable);
+
+    if (port->mDef.eDir != OMX_DirOutput) {
+        ALOGE("Port enable/disable allowed only on output ports.");
+        notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL);
+        android_errorWriteLog(0x534e4554, "29421804");
+        return;
+    }
+
+    if (!enable) {
+        port->mDef.bEnabled = OMX_FALSE;
+        port->mTransition = PortInfo::DISABLING;
+
+        for (size_t i = 0; i < port->mBuffers.size(); ++i) {
+            BufferInfo *buffer = &port->mBuffers.editItemAt(i);
+
+            if (buffer->mOwnedByUs) {
+                buffer->mOwnedByUs = false;
+
+                if (port->mDef.eDir == OMX_DirInput) {
+                    notifyEmptyBufferDone(buffer->mHeader);
+                } else {
+                    CHECK_EQ(port->mDef.eDir, OMX_DirOutput);
+                    notifyFillBufferDone(buffer->mHeader);
+                }
+            }
+        }
+
+        port->mQueue.clear();
+    } else {
+        port->mTransition = PortInfo::ENABLING;
+    }
+
+    checkTransitions();
+}
+
+void SimpleGoldfishOMXComponent::onPortFlush(
+        OMX_U32 portIndex, bool sendFlushComplete) {
+    if (portIndex == OMX_ALL) {
+        for (size_t i = 0; i < mPorts.size(); ++i) {
+            onPortFlush(i, sendFlushComplete);
+        }
+
+        if (sendFlushComplete) {
+            notify(OMX_EventCmdComplete, OMX_CommandFlush, OMX_ALL, NULL);
+        }
+
+        return;
+    }
+
+    CHECK_LT(portIndex, mPorts.size());
+
+    PortInfo *port = &mPorts.editItemAt(portIndex);
+    // Ideally, the port should not in transitioning state when flushing.
+    // However, in error handling case, e.g., the client can't allocate buffers
+    // when it tries to re-enable the port, the port will be stuck in ENABLING.
+    // The client will then transition the component from Executing to Idle,
+    // which leads to flushing ports. At this time, it should be ok to notify
+    // the client of the error and still clear all buffers on the port.
+    if (port->mTransition != PortInfo::NONE) {
+        notify(OMX_EventError, OMX_ErrorUndefined, 0, 0);
+    }
+
+    for (size_t i = 0; i < port->mBuffers.size(); ++i) {
+        BufferInfo *buffer = &port->mBuffers.editItemAt(i);
+
+        if (!buffer->mOwnedByUs) {
+            continue;
+        }
+
+        buffer->mHeader->nFilledLen = 0;
+        buffer->mHeader->nOffset = 0;
+        buffer->mHeader->nFlags = 0;
+
+        buffer->mOwnedByUs = false;
+
+        if (port->mDef.eDir == OMX_DirInput) {
+            notifyEmptyBufferDone(buffer->mHeader);
+        } else {
+            CHECK_EQ(port->mDef.eDir, OMX_DirOutput);
+
+            notifyFillBufferDone(buffer->mHeader);
+        }
+    }
+
+    port->mQueue.clear();
+
+    if (sendFlushComplete) {
+        notify(OMX_EventCmdComplete, OMX_CommandFlush, portIndex, NULL);
+
+        onPortFlushCompleted(portIndex);
+    }
+}
+
+void SimpleGoldfishOMXComponent::checkTransitions() {
+    if (mState != mTargetState) {
+        bool transitionComplete = true;
+
+        if (mState == OMX_StateLoaded) {
+            CHECK_EQ((int)mTargetState, (int)OMX_StateIdle);
+
+            for (size_t i = 0; i < mPorts.size(); ++i) {
+                const PortInfo &port = mPorts.itemAt(i);
+                if (port.mDef.bEnabled == OMX_FALSE) {
+                    continue;
+                }
+
+                if (port.mDef.bPopulated == OMX_FALSE) {
+                    transitionComplete = false;
+                    break;
+                }
+            }
+        } else if (mTargetState == OMX_StateLoaded) {
+            CHECK_EQ((int)mState, (int)OMX_StateIdle);
+
+            for (size_t i = 0; i < mPorts.size(); ++i) {
+                const PortInfo &port = mPorts.itemAt(i);
+                if (port.mDef.bEnabled == OMX_FALSE) {
+                    continue;
+                }
+
+                size_t n = port.mBuffers.size();
+
+                if (n > 0) {
+                    CHECK_LE(n, port.mDef.nBufferCountActual);
+
+                    if (n == port.mDef.nBufferCountActual) {
+                        CHECK_EQ((int)port.mDef.bPopulated, (int)OMX_TRUE);
+                    } else {
+                        CHECK_EQ((int)port.mDef.bPopulated, (int)OMX_FALSE);
+                    }
+
+                    transitionComplete = false;
+                    break;
+                }
+            }
+        }
+
+        if (transitionComplete) {
+            ALOGV("state transition from %d to %d complete", mState, mTargetState);
+            mState = mTargetState;
+
+            if (mState == OMX_StateLoaded) {
+                onReset();
+            }
+
+            notify(OMX_EventCmdComplete, OMX_CommandStateSet, mState, NULL);
+        } else {
+            ALOGV("state transition from %d to %d not yet complete", mState, mTargetState);
+        }
+    }
+
+    for (size_t i = 0; i < mPorts.size(); ++i) {
+        PortInfo *port = &mPorts.editItemAt(i);
+
+        if (port->mTransition == PortInfo::DISABLING) {
+            if (port->mBuffers.empty()) {
+                ALOGV("Port %zu now disabled.", i);
+
+                port->mTransition = PortInfo::NONE;
+                notify(OMX_EventCmdComplete, OMX_CommandPortDisable, i, NULL);
+
+                onPortEnableCompleted(i, false /* enabled */);
+            }
+        } else if (port->mTransition == PortInfo::ENABLING) {
+            if (port->mDef.bPopulated == OMX_TRUE) {
+                ALOGV("Port %zu now enabled.", i);
+
+                port->mTransition = PortInfo::NONE;
+                port->mDef.bEnabled = OMX_TRUE;
+                notify(OMX_EventCmdComplete, OMX_CommandPortEnable, i, NULL);
+
+                onPortEnableCompleted(i, true /* enabled */);
+            }
+        }
+    }
+}
+
+void SimpleGoldfishOMXComponent::addPort(const OMX_PARAM_PORTDEFINITIONTYPE &def) {
+    CHECK_EQ(def.nPortIndex, mPorts.size());
+
+    mPorts.push();
+    PortInfo *info = &mPorts.editItemAt(mPorts.size() - 1);
+    info->mDef = def;
+    info->mTransition = PortInfo::NONE;
+}
+
+void SimpleGoldfishOMXComponent::onQueueFilled(OMX_U32 portIndex __unused) {
+}
+
+void SimpleGoldfishOMXComponent::onPortFlushCompleted(OMX_U32 portIndex __unused) {
+}
+
+void SimpleGoldfishOMXComponent::onPortEnableCompleted(
+        OMX_U32 portIndex __unused, bool enabled __unused) {
+}
+
+List<SimpleGoldfishOMXComponent::BufferInfo *> &
+SimpleGoldfishOMXComponent::getPortQueue(OMX_U32 portIndex) {
+    CHECK_LT(portIndex, mPorts.size());
+    return mPorts.editItemAt(portIndex).mQueue;
+}
+
+SimpleGoldfishOMXComponent::PortInfo *SimpleGoldfishOMXComponent::editPortInfo(
+        OMX_U32 portIndex) {
+    CHECK_LT(portIndex, mPorts.size());
+    return &mPorts.editItemAt(portIndex);
+}
+
+}  // namespace android
diff --git a/system/codecs/omx/plugin/SimpleGoldfishOMXComponent.h b/system/codecs/omx/plugin/SimpleGoldfishOMXComponent.h
new file mode 100644
index 0000000..d2a3bf5
--- /dev/null
+++ b/system/codecs/omx/plugin/SimpleGoldfishOMXComponent.h
@@ -0,0 +1,171 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef SIMPLE_GOLDFISH_OMX_COMPONENT_H_
+
+#define SIMPLE_GOLDFISH_OMX_COMPONENT_H_
+
+#include "GoldfishOMXComponent.h"
+
+#include <atomic>
+#include <media/stagefright/foundation/AHandlerReflector.h>
+#include <utils/RefBase.h>
+#include <utils/threads.h>
+#include <utils/Vector.h>
+
+namespace android {
+
+struct ALooper;
+struct ABuffer;
+
+struct CodecProfileLevel {
+    OMX_U32 mProfile;
+    OMX_U32 mLevel;
+};
+
+struct SimpleGoldfishOMXComponent : public GoldfishOMXComponent {
+    SimpleGoldfishOMXComponent(
+            const char *name,
+            const OMX_CALLBACKTYPE *callbacks,
+            OMX_PTR appData,
+            OMX_COMPONENTTYPE **component);
+
+    virtual void prepareForDestruction();
+
+    void onMessageReceived(const sp<AMessage> &msg);
+
+protected:
+    struct BufferInfo {
+        OMX_BUFFERHEADERTYPE *mHeader;
+        bool mOwnedByUs;
+        bool mFrameConfig;
+    };
+
+    struct PortInfo {
+        OMX_PARAM_PORTDEFINITIONTYPE mDef;
+        Vector<BufferInfo> mBuffers;
+        List<BufferInfo *> mQueue;
+
+        enum {
+            NONE,
+            DISABLING,
+            ENABLING,
+        } mTransition;
+    };
+
+    enum {
+        kStoreMetaDataExtensionIndex = OMX_IndexVendorStartUnused + 1,
+        kPrepareForAdaptivePlaybackIndex,
+    };
+
+    void addPort(const OMX_PARAM_PORTDEFINITIONTYPE &def);
+
+    virtual OMX_ERRORTYPE internalGetParameter(
+            OMX_INDEXTYPE index, OMX_PTR params);
+
+    virtual OMX_ERRORTYPE internalSetParameter(
+            OMX_INDEXTYPE index, const OMX_PTR params);
+
+    virtual OMX_ERRORTYPE internalSetConfig(
+            OMX_INDEXTYPE index, const OMX_PTR params, bool *frameConfig);
+
+    virtual void onQueueFilled(OMX_U32 portIndex);
+    List<BufferInfo *> &getPortQueue(OMX_U32 portIndex);
+
+    virtual void onPortFlushCompleted(OMX_U32 portIndex);
+    virtual void onPortEnableCompleted(OMX_U32 portIndex, bool enabled);
+    virtual void onReset();
+
+    PortInfo *editPortInfo(OMX_U32 portIndex);
+
+protected:
+    enum {
+        kWhatSendCommand,
+        kWhatEmptyThisBuffer,
+        kWhatFillThisBuffer,
+    };
+
+    Mutex mLock;
+
+    sp<ALooper> mLooper;
+    sp<AHandlerReflector<SimpleGoldfishOMXComponent> > mHandler;
+
+    OMX_STATETYPE mState;
+    OMX_STATETYPE mTargetState;
+
+    Vector<PortInfo> mPorts;
+    std::atomic_bool mFrameConfig;
+
+    bool isSetParameterAllowed(
+            OMX_INDEXTYPE index, const OMX_PTR params) const;
+
+    virtual OMX_ERRORTYPE sendCommand(
+            OMX_COMMANDTYPE cmd, OMX_U32 param, OMX_PTR data);
+
+    virtual OMX_ERRORTYPE getParameter(
+            OMX_INDEXTYPE index, OMX_PTR params);
+
+    virtual OMX_ERRORTYPE setParameter(
+            OMX_INDEXTYPE index, const OMX_PTR params);
+
+    virtual OMX_ERRORTYPE setConfig(
+            OMX_INDEXTYPE index, const OMX_PTR params);
+
+    virtual OMX_ERRORTYPE useBuffer(
+            OMX_BUFFERHEADERTYPE **buffer,
+            OMX_U32 portIndex,
+            OMX_PTR appPrivate,
+            OMX_U32 size,
+            OMX_U8 *ptr);
+
+    OMX_ERRORTYPE useBufferCallerLockedAlready(
+            OMX_BUFFERHEADERTYPE **buffer,
+            OMX_U32 portIndex,
+            OMX_PTR appPrivate,
+            OMX_U32 size,
+            OMX_U8 *ptr);
+
+    virtual OMX_ERRORTYPE allocateBuffer(
+            OMX_BUFFERHEADERTYPE **buffer,
+            OMX_U32 portIndex,
+            OMX_PTR appPrivate,
+            OMX_U32 size);
+
+    virtual OMX_ERRORTYPE freeBuffer(
+            OMX_U32 portIndex,
+            OMX_BUFFERHEADERTYPE *buffer);
+
+    virtual OMX_ERRORTYPE emptyThisBuffer(
+            OMX_BUFFERHEADERTYPE *buffer);
+
+    virtual OMX_ERRORTYPE fillThisBuffer(
+            OMX_BUFFERHEADERTYPE *buffer);
+
+    virtual OMX_ERRORTYPE getState(OMX_STATETYPE *state);
+
+    void onSendCommand(OMX_COMMANDTYPE cmd, OMX_U32 param);
+    void onChangeState(OMX_STATETYPE state);
+    void onPortEnable(OMX_U32 portIndex, bool enable);
+    void onPortFlush(OMX_U32 portIndex, bool sendFlushComplete);
+
+    void checkTransitions();
+
+    DISALLOW_EVIL_CONSTRUCTORS(SimpleGoldfishOMXComponent);
+};
+
+}  // namespace android
+
+#endif  // SIMPLE_GOLDFISH_OMX_COMPONENT_H_
diff --git a/system/codecs/omx/vpxdec/Android.mk b/system/codecs/omx/vpxdec/Android.mk
new file mode 100644
index 0000000..6374ac3
--- /dev/null
+++ b/system/codecs/omx/vpxdec/Android.mk
@@ -0,0 +1,48 @@
+#
+# Copyright 2019 The Android Open-Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+LOCAL_PATH := $(call my-dir)
+
+commonSources := \
+        GoldfishVPX.cpp  \
+        goldfish_vpx_impl.cpp
+
+$(call emugl-begin-shared-library,libstagefright_goldfish_vpxdec$(GOLDFISH_OPENGL_LIB_SUFFIX))
+
+LOCAL_SRC_FILES := $(commonSources)
+
+LOCAL_CFLAGS += -DLOG_TAG=\"goldfish_vpxdec\"
+LOCAL_CFLAGS += -Wno-unused-private-field
+
+$(call emugl-export,SHARED_LIBRARIES,libcutils libutils liblog)
+
+LOCAL_HEADER_LIBRARIES := media_plugin_headers \
+	                      libmedia_headers \
+	                      libbinder_headers \
+	                      libhidlbase_impl_internal \
+	                      libbase
+
+LOCAL_SHARED_LIBRARIES :=       \
+        libbinder               \
+        libutils                \
+        liblog                  \
+        libcutils               \
+        android.hardware.media.omx@1.0 \
+        libstagefright_foundation
+
+$(call emugl-export,C_INCLUDES,$(LOCAL_PATH))
+$(call emugl-import,libgoldfish_codecs_common)
+$(call emugl-import,libstagefrighthw)
+$(call emugl-end-module)
diff --git a/system/codecs/omx/vpxdec/GoldfishVPX.cpp b/system/codecs/omx/vpxdec/GoldfishVPX.cpp
new file mode 100644
index 0000000..5b9fb2d
--- /dev/null
+++ b/system/codecs/omx/vpxdec/GoldfishVPX.cpp
@@ -0,0 +1,356 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//#define LOG_NDEBUG 0
+#include <utils/Log.h>
+#include <utils/misc.h>
+//#include "OMX_VideoExt.h"
+
+#include "GoldfishVPX.h"
+
+#include <media/stagefright/foundation/ADebug.h>
+#include <media/stagefright/MediaDefs.h>
+
+
+namespace android {
+
+// Only need to declare the highest supported profile and level here.
+static const CodecProfileLevel kVP9ProfileLevels[] = {
+    { OMX_VIDEO_VP9Profile0, OMX_VIDEO_VP9Level5 },
+    { OMX_VIDEO_VP9Profile2, OMX_VIDEO_VP9Level5 },
+    { OMX_VIDEO_VP9Profile2HDR, OMX_VIDEO_VP9Level5 },
+    { OMX_VIDEO_VP9Profile2HDR10Plus, OMX_VIDEO_VP9Level5 },
+};
+
+GoldfishVPX::GoldfishVPX(
+        const char *name,
+        const char *componentRole,
+        OMX_VIDEO_CODINGTYPE codingType,
+        const OMX_CALLBACKTYPE *callbacks,
+        OMX_PTR appData,
+        OMX_COMPONENTTYPE **component)
+    : GoldfishVideoDecoderOMXComponent(
+            name, componentRole, codingType,
+            codingType == OMX_VIDEO_CodingVP8 ? NULL : kVP9ProfileLevels,
+            codingType == OMX_VIDEO_CodingVP8 ?  0 : NELEM(kVP9ProfileLevels),
+            320 /* width */, 240 /* height */, callbacks, appData, component),
+      mMode(codingType == OMX_VIDEO_CodingVP8 ? MODE_VP8 : MODE_VP9),
+      mEOSStatus(INPUT_DATA_AVAILABLE),
+      mCtx(NULL),
+      mFrameParallelMode(false),
+      mTimeStampIdx(0),
+      mImg(NULL) {
+    // arbitrary from avc/hevc as vpx does not specify a min compression ratio
+    const size_t kMinCompressionRatio = mMode == MODE_VP8 ? 2 : 4;
+    const char *mime = mMode == MODE_VP8 ? MEDIA_MIMETYPE_VIDEO_VP8 : MEDIA_MIMETYPE_VIDEO_VP9;
+    const size_t kMaxOutputBufferSize = 2560 * 2560 * 3 / 2;
+    initPorts(
+            kNumBuffers, kMaxOutputBufferSize / kMinCompressionRatio /* inputBufferSize */,
+            kNumBuffers, mime, kMinCompressionRatio);
+    ALOGE("calling constructor of GoldfishVPX");
+    CHECK_EQ(initDecoder(), (status_t)OK);
+}
+
+GoldfishVPX::~GoldfishVPX() {
+    ALOGE("calling destructor of GoldfishVPX");
+    destroyDecoder();
+}
+
+bool GoldfishVPX::supportDescribeHdrStaticInfo() {
+    return true;
+}
+
+bool GoldfishVPX::supportDescribeHdr10PlusInfo() {
+    return true;
+}
+
+status_t GoldfishVPX::initDecoder() {
+    mCtx = new vpx_codec_ctx_t;
+    mCtx->vpversion = mMode == MODE_VP8 ? 8 : 9;
+
+    int vpx_err = 0;
+    if ((vpx_err = vpx_codec_dec_init(mCtx))) {
+        ALOGE("vpx decoder failed to initialize. (%d)", vpx_err);
+        return UNKNOWN_ERROR;
+    }
+
+    return OK;
+}
+
+status_t GoldfishVPX::destroyDecoder() {
+    vpx_codec_destroy(mCtx);
+    delete mCtx;
+    mCtx = NULL;
+    return OK;
+}
+
+void GoldfishVPX::setup_ctx_parameters(vpx_codec_ctx_t* ctx) {
+    ctx->width = mWidth;
+    ctx->height = mHeight;
+    ctx->outputBufferWidth = outputBufferWidth();
+    ctx->outputBufferHeight = outputBufferHeight();
+    OMX_PARAM_PORTDEFINITIONTYPE *outDef = &editPortInfo(kOutputPortIndex)->mDef;
+    int32_t bpp = (outDef->format.video.eColorFormat == OMX_COLOR_FormatYUV420Planar16) ? 2 : 1;
+    ctx->bpp =  bpp;
+}
+
+bool GoldfishVPX::outputBuffers(bool flushDecoder, bool display, bool eos, bool *portWillReset) {
+    List<BufferInfo *> &outQueue = getPortQueue(1);
+    BufferInfo *outInfo = NULL;
+    OMX_BUFFERHEADERTYPE *outHeader = NULL;
+
+    if (flushDecoder && mFrameParallelMode) {
+        // Flush decoder by passing NULL data ptr and 0 size.
+        // Ideally, this should never fail.
+        if (vpx_codec_flush(mCtx)) {
+            ALOGE("Failed to flush on2 decoder.");
+            return false;
+        }
+    }
+
+    if (!display) {
+        if (!flushDecoder) {
+            ALOGE("Invalid operation.");
+            return false;
+        }
+        // Drop all the decoded frames in decoder.
+        // TODO: move this to host, with something like
+        // vpx_codec_drop_all_frames(mCtx);
+        setup_ctx_parameters(mCtx);
+        while ((mImg = vpx_codec_get_frame(mCtx))) {
+        }
+        return true;
+    }
+
+    while (!outQueue.empty()) {
+        if (mImg == NULL) {
+            setup_ctx_parameters(mCtx);
+            mImg = vpx_codec_get_frame(mCtx);
+            if (mImg == NULL) {
+                break;
+            }
+        }
+        uint32_t width = mImg->d_w;
+        uint32_t height = mImg->d_h;
+        outInfo = *outQueue.begin();
+        outHeader = outInfo->mHeader;
+        CHECK(mImg->fmt == VPX_IMG_FMT_I420 || mImg->fmt == VPX_IMG_FMT_I42016);
+        OMX_COLOR_FORMATTYPE outputColorFormat = OMX_COLOR_FormatYUV420Planar;
+        int32_t bpp = 1;
+        if (mImg->fmt == VPX_IMG_FMT_I42016) {
+            outputColorFormat = OMX_COLOR_FormatYUV420Planar16;
+            bpp = 2;
+        }
+        handlePortSettingsChange(portWillReset, width, height, outputColorFormat);
+        if (*portWillReset) {
+            return true;
+        }
+
+        outHeader->nOffset = 0;
+        outHeader->nFlags = 0;
+        outHeader->nFilledLen = (outputBufferWidth() * outputBufferHeight() * bpp * 3) / 2;
+        PrivInfo *privInfo = (PrivInfo *)mImg->user_priv;
+        outHeader->nTimeStamp = privInfo->mTimeStamp;
+        if (privInfo->mHdr10PlusInfo != nullptr) {
+            queueOutputFrameConfig(privInfo->mHdr10PlusInfo);
+        }
+
+        if (outputBufferSafe(outHeader)) {
+            uint8_t *dst = outHeader->pBuffer;
+            memcpy(dst, mCtx->dst, outHeader->nFilledLen);
+        } else {
+            outHeader->nFilledLen = 0;
+        }
+
+        mImg = NULL;
+        outInfo->mOwnedByUs = false;
+        outQueue.erase(outQueue.begin());
+        outInfo = NULL;
+        notifyFillBufferDone(outHeader);
+        outHeader = NULL;
+    }
+
+    if (!eos) {
+        return true;
+    }
+
+    if (!outQueue.empty()) {
+        outInfo = *outQueue.begin();
+        outQueue.erase(outQueue.begin());
+        outHeader = outInfo->mHeader;
+        outHeader->nTimeStamp = 0;
+        outHeader->nFilledLen = 0;
+        outHeader->nFlags = OMX_BUFFERFLAG_EOS;
+        outInfo->mOwnedByUs = false;
+        notifyFillBufferDone(outHeader);
+        mEOSStatus = OUTPUT_FRAMES_FLUSHED;
+    }
+    return true;
+}
+
+bool GoldfishVPX::outputBufferSafe(OMX_BUFFERHEADERTYPE *outHeader) {
+    uint32_t width = outputBufferWidth();
+    uint32_t height = outputBufferHeight();
+    uint64_t nFilledLen = width;
+    nFilledLen *= height;
+    if (nFilledLen > UINT32_MAX / 3) {
+        ALOGE("b/29421675, nFilledLen overflow %llu w %u h %u",
+                (unsigned long long)nFilledLen, width, height);
+        android_errorWriteLog(0x534e4554, "29421675");
+        return false;
+    } else if (outHeader->nAllocLen < outHeader->nFilledLen) {
+        ALOGE("b/27597103, buffer too small");
+        android_errorWriteLog(0x534e4554, "27597103");
+        return false;
+    }
+
+    return true;
+}
+
+void GoldfishVPX::onQueueFilled(OMX_U32 /* portIndex */) {
+    if (mOutputPortSettingsChange != NONE || mEOSStatus == OUTPUT_FRAMES_FLUSHED) {
+        return;
+    }
+
+    List<BufferInfo *> &inQueue = getPortQueue(0);
+    List<BufferInfo *> &outQueue = getPortQueue(1);
+    bool EOSseen = false;
+    bool portWillReset = false;
+
+    while ((mEOSStatus == INPUT_EOS_SEEN || !inQueue.empty())
+            && !outQueue.empty()) {
+        // Output the pending frames that left from last port reset or decoder flush.
+        if (mEOSStatus == INPUT_EOS_SEEN || mImg != NULL) {
+            if (!outputBuffers(
+                     mEOSStatus == INPUT_EOS_SEEN, true /* display */,
+                     mEOSStatus == INPUT_EOS_SEEN, &portWillReset)) {
+                ALOGE("on2 decoder failed to output frame.");
+                notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL);
+                return;
+            }
+            if (portWillReset || mEOSStatus == OUTPUT_FRAMES_FLUSHED ||
+                    mEOSStatus == INPUT_EOS_SEEN) {
+                return;
+            }
+            // Continue as outQueue may be empty now.
+            continue;
+        }
+
+        BufferInfo *inInfo = *inQueue.begin();
+        OMX_BUFFERHEADERTYPE *inHeader = inInfo->mHeader;
+
+        // Software VP9 Decoder does not need the Codec Specific Data (CSD)
+        // (specified in http://www.webmproject.org/vp9/profiles/). Ignore it if
+        // it was passed.
+        if (inHeader->nFlags & OMX_BUFFERFLAG_CODECCONFIG) {
+            // Only ignore CSD buffer for VP9.
+            if (mMode == MODE_VP9) {
+                inQueue.erase(inQueue.begin());
+                inInfo->mOwnedByUs = false;
+                notifyEmptyBufferDone(inHeader);
+                continue;
+            } else {
+                // Tolerate the CSD buffer for VP8. This is a workaround
+                // for b/28689536.
+                ALOGW("WARNING: Got CSD buffer for VP8.");
+            }
+        }
+
+        mPrivInfo[mTimeStampIdx].mTimeStamp = inHeader->nTimeStamp;
+
+        if (inInfo->mFrameConfig) {
+            mPrivInfo[mTimeStampIdx].mHdr10PlusInfo = dequeueInputFrameConfig();
+        } else {
+            mPrivInfo[mTimeStampIdx].mHdr10PlusInfo.clear();
+        }
+
+        if (inHeader->nFlags & OMX_BUFFERFLAG_EOS) {
+            mEOSStatus = INPUT_EOS_SEEN;
+            EOSseen = true;
+        }
+
+        if (inHeader->nFilledLen > 0) {
+            int err = vpx_codec_decode(mCtx, inHeader->pBuffer + inHeader->nOffset,
+                    inHeader->nFilledLen, &mPrivInfo[mTimeStampIdx], 0);
+            if (err == VPX_CODEC_OK) {
+                inInfo->mOwnedByUs = false;
+                inQueue.erase(inQueue.begin());
+                inInfo = NULL;
+                notifyEmptyBufferDone(inHeader);
+                inHeader = NULL;
+            } else {
+                ALOGE("on2 decoder failed to decode frame. err: %d", err);
+                notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL);
+                return;
+            }
+        }
+
+        mTimeStampIdx = (mTimeStampIdx + 1) % kNumBuffers;
+
+        if (!outputBuffers(
+                 EOSseen /* flushDecoder */, true /* display */, EOSseen, &portWillReset)) {
+            ALOGE("on2 decoder failed to output frame.");
+            notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL);
+            return;
+        }
+        if (portWillReset) {
+            return;
+        }
+    }
+}
+
+void GoldfishVPX::onPortFlushCompleted(OMX_U32 portIndex) {
+    if (portIndex == kInputPortIndex) {
+        bool portWillReset = false;
+        if (!outputBuffers(
+                 true /* flushDecoder */, false /* display */, false /* eos */, &portWillReset)) {
+            ALOGE("Failed to flush decoder.");
+            notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL);
+            return;
+        }
+        mEOSStatus = INPUT_DATA_AVAILABLE;
+    }
+}
+
+void GoldfishVPX::onReset() {
+    bool portWillReset = false;
+    if (!outputBuffers(
+             true /* flushDecoder */, false /* display */, false /* eos */, &portWillReset)) {
+        ALOGW("Failed to flush decoder. Try to hard reset decoder");
+        destroyDecoder();
+        initDecoder();
+    }
+    mEOSStatus = INPUT_DATA_AVAILABLE;
+}
+
+}  // namespace android
+
+android::GoldfishOMXComponent *createGoldfishOMXComponent(
+        const char *name, const OMX_CALLBACKTYPE *callbacks,
+        OMX_PTR appData, OMX_COMPONENTTYPE **component) {
+    if (!strcmp(name, "OMX.google.goldfish.vp8.decoder")) {
+        return new android::GoldfishVPX(
+                name, "video_decoder.vp8", OMX_VIDEO_CodingVP8,
+                callbacks, appData, component);
+    } else if (!strcmp(name, "OMX.google.goldfish.vp9.decoder")) {
+        return new android::GoldfishVPX(
+                name, "video_decoder.vp9", OMX_VIDEO_CodingVP9,
+                callbacks, appData, component);
+    } else {
+        CHECK(!"Unknown component");
+    }
+    return NULL;
+}
diff --git a/system/codecs/omx/vpxdec/GoldfishVPX.h b/system/codecs/omx/vpxdec/GoldfishVPX.h
new file mode 100644
index 0000000..2ba8beb
--- /dev/null
+++ b/system/codecs/omx/vpxdec/GoldfishVPX.h
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef GOLDFISH_VPX_H_
+
+#define GOLDFISH_VPX_H_
+
+#include "GoldfishVideoDecoderOMXComponent.h"
+#include "goldfish_vpx_defs.h"
+
+namespace android {
+
+struct ABuffer;
+
+struct GoldfishVPX : public GoldfishVideoDecoderOMXComponent {
+    GoldfishVPX(const char *name,
+            const char *componentRole,
+            OMX_VIDEO_CODINGTYPE codingType,
+            const OMX_CALLBACKTYPE *callbacks,
+            OMX_PTR appData,
+            OMX_COMPONENTTYPE **component);
+
+protected:
+    virtual ~GoldfishVPX();
+
+    virtual void onQueueFilled(OMX_U32 portIndex);
+    virtual void onPortFlushCompleted(OMX_U32 portIndex);
+    virtual void onReset();
+    virtual bool supportDescribeHdrStaticInfo();
+    virtual bool supportDescribeHdr10PlusInfo();
+
+private:
+    enum {
+        kNumBuffers = 10
+    };
+
+    enum {
+        MODE_VP8,
+        MODE_VP9
+    } mMode;
+
+    enum {
+        INPUT_DATA_AVAILABLE,  // VPX component is ready to decode data.
+        INPUT_EOS_SEEN,        // VPX component saw EOS and is flushing On2 decoder.
+        OUTPUT_FRAMES_FLUSHED  // VPX component finished flushing On2 decoder.
+    } mEOSStatus;
+
+    vpx_codec_ctx_t *mCtx;
+    bool mFrameParallelMode;  // Frame parallel is only supported by VP9 decoder.
+    struct PrivInfo {
+        OMX_TICKS mTimeStamp;
+        sp<ABuffer> mHdr10PlusInfo;
+    };
+    PrivInfo mPrivInfo[kNumBuffers];
+    uint8_t mTimeStampIdx;
+    vpx_image_t *mImg;
+
+    status_t initDecoder();
+    status_t destroyDecoder();
+    bool outputBuffers(bool flushDecoder, bool display, bool eos, bool *portWillReset);
+    bool outputBufferSafe(OMX_BUFFERHEADERTYPE *outHeader);
+
+    void setup_ctx_parameters(vpx_codec_ctx_t*);
+
+    DISALLOW_EVIL_CONSTRUCTORS(GoldfishVPX);
+};
+
+}  // namespace android
+
+#endif  // GOLDFISH_VPX_H_
diff --git a/system/codecs/omx/vpxdec/exports.lds b/system/codecs/omx/vpxdec/exports.lds
new file mode 100644
index 0000000..e6674f2
--- /dev/null
+++ b/system/codecs/omx/vpxdec/exports.lds
@@ -0,0 +1,5 @@
+{
+    global:
+        _Z26createGoldfishOMXComponentPKcPK16OMX_CALLBACKTYPEPvPP17OMX_COMPONENTTYPE;
+    local: *;
+};
diff --git a/system/codecs/omx/vpxdec/goldfish_vpx_defs.h b/system/codecs/omx/vpxdec/goldfish_vpx_defs.h
new file mode 100644
index 0000000..1b1358c
--- /dev/null
+++ b/system/codecs/omx/vpxdec/goldfish_vpx_defs.h
@@ -0,0 +1,54 @@
+#ifndef MY_VPX_DEFS_H_
+#define MY_VPX_DEFS_H_
+
+
+#define VPX_IMG_FMT_PLANAR 0x100       /**< Image is a planar format. */
+#define VPX_IMG_FMT_UV_FLIP 0x200      /**< V plane precedes U in memory. */
+#define VPX_IMG_FMT_HAS_ALPHA 0x400    /**< Image has an alpha channel. */
+#define VPX_IMG_FMT_HIGHBITDEPTH 0x800 /**< Image uses 16bit framebuffer. */
+
+typedef unsigned char uint8_t;
+
+enum vpx_img_fmt_t {
+  VPX_IMG_FMT_NONE,
+  VPX_IMG_FMT_YV12 =
+      VPX_IMG_FMT_PLANAR | VPX_IMG_FMT_UV_FLIP | 1, /**< planar YVU */
+  VPX_IMG_FMT_I420 = VPX_IMG_FMT_PLANAR | 2,
+  VPX_IMG_FMT_I422 = VPX_IMG_FMT_PLANAR | 5,
+  VPX_IMG_FMT_I444 = VPX_IMG_FMT_PLANAR | 6,
+  VPX_IMG_FMT_I440 = VPX_IMG_FMT_PLANAR | 7,
+  VPX_IMG_FMT_I42016 = VPX_IMG_FMT_I420 | VPX_IMG_FMT_HIGHBITDEPTH,
+  VPX_IMG_FMT_I42216 = VPX_IMG_FMT_I422 | VPX_IMG_FMT_HIGHBITDEPTH,
+  VPX_IMG_FMT_I44416 = VPX_IMG_FMT_I444 | VPX_IMG_FMT_HIGHBITDEPTH,
+  VPX_IMG_FMT_I44016 = VPX_IMG_FMT_I440 | VPX_IMG_FMT_HIGHBITDEPTH
+};
+    
+struct vpx_image_t {
+    vpx_img_fmt_t fmt;       /**< Image Format */
+    unsigned int d_w; /**< Displayed image width */
+    unsigned int d_h; /**< Displayed image height */
+    void *user_priv;
+};
+
+#define VPX_CODEC_OK 0
+
+struct vpx_codec_ctx_t {
+    int vpversion; //8: vp8 or 9: vp9
+    size_t outputBufferWidth;
+    size_t outputBufferHeight;
+    size_t width;
+    size_t height;
+    size_t bpp;
+    uint8_t *data;
+    uint8_t *dst;
+};
+
+int vpx_codec_destroy(vpx_codec_ctx_t*);
+int vpx_codec_dec_init(vpx_codec_ctx_t*);
+vpx_image_t *vpx_codec_get_frame(vpx_codec_ctx_t*);
+int vpx_codec_flush(vpx_codec_ctx_t *ctx);
+int vpx_codec_decode(vpx_codec_ctx_t *ctx, const uint8_t *data,
+                                 unsigned int data_sz, void *user_priv,
+                                 long deadline);
+
+#endif  // MY_VPX_DEFS_H_
diff --git a/system/codecs/omx/vpxdec/goldfish_vpx_impl.cpp b/system/codecs/omx/vpxdec/goldfish_vpx_impl.cpp
new file mode 100644
index 0000000..0771176
--- /dev/null
+++ b/system/codecs/omx/vpxdec/goldfish_vpx_impl.cpp
@@ -0,0 +1,98 @@
+#include <log/log.h>
+
+#include <linux/types.h>
+#include <linux/ioctl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/mman.h>
+#include <sys/ioctl.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <cstdlib>
+#include <string>
+#include <errno.h>
+#include "goldfish_vpx_defs.h"
+#include "goldfish_media_utils.h"
+
+static vpx_image_t myImg;
+
+static void sendVpxOperation(vpx_codec_ctx_t* ctx, MediaOperation op) {
+    auto transport = GoldfishMediaTransport::getInstance();
+    transport->sendOperation(
+            ctx->vpversion == 8 ?
+                MediaCodecType::VP8Codec :
+                MediaCodecType::VP9Codec,
+            op);
+}
+
+int vpx_codec_destroy(vpx_codec_ctx_t* ctx) {
+    sendVpxOperation(ctx, MediaOperation::DestroyContext);
+    return 0;
+}
+
+int vpx_codec_dec_init(vpx_codec_ctx_t* ctx) {
+    auto transport = GoldfishMediaTransport::getInstance();
+    // data and dst are on the host side actually
+    ctx->data = transport->getInputAddr();
+    ctx->dst = transport->getOutputAddr();
+    sendVpxOperation(ctx, MediaOperation::InitContext);
+    return 0;
+}
+
+static int getReturnCode(uint8_t* ptr) {
+    int* pint = (int*)(ptr);
+    return *pint;
+}
+
+static void getVpxFrame(uint8_t* ptr) {
+    uint8_t* imgptr = (ptr + 8);
+    myImg.fmt = *(vpx_img_fmt_t*)imgptr;
+    imgptr += 8;
+    myImg.d_w = *(unsigned int *)imgptr;
+    imgptr += 8;
+    myImg.d_h = *(unsigned int *)imgptr;
+    imgptr += 8;
+    myImg.user_priv = (void*)(*(uint64_t*)imgptr);
+}
+
+//TODO: we might not need to do the putting all the time
+vpx_image_t* vpx_codec_get_frame(vpx_codec_ctx_t* ctx) {
+    auto transport = GoldfishMediaTransport::getInstance();
+
+    transport->writeParam(ctx->outputBufferWidth, 0);
+    transport->writeParam(ctx->outputBufferHeight, 1);
+    transport->writeParam(ctx->width, 2);
+    transport->writeParam(ctx->height, 3);
+    transport->writeParam(ctx->bpp, 4);
+    transport->writeParam(transport->offsetOf((uint64_t)(ctx->dst)), 5);
+
+    sendVpxOperation(ctx, MediaOperation::GetImage);
+
+    auto* retptr = transport->getReturnAddr();
+    int ret = getReturnCode(retptr);
+    if (ret) {
+        return nullptr;
+    }
+    getVpxFrame(retptr);
+    return &myImg;
+}
+
+int vpx_codec_flush(vpx_codec_ctx_t* ctx) {
+    sendVpxOperation(ctx, MediaOperation::Flush);
+    return 0;
+}
+
+int vpx_codec_decode(vpx_codec_ctx_t *ctx,
+                     const uint8_t* data,
+                     unsigned int data_sz,
+                     void* user_priv,
+                     long deadline) {
+    auto transport = GoldfishMediaTransport::getInstance();
+    memcpy(ctx->data, data, data_sz);
+
+    transport->writeParam(transport->offsetOf((uint64_t)(ctx->data)), 0);
+    transport->writeParam((__u64)data_sz, 1);
+    transport->writeParam((__u64)user_priv, 2);
+    sendVpxOperation(ctx, MediaOperation::DecodeImage);
+    return 0;
+}
diff --git a/system/egl/Android.mk b/system/egl/Android.mk
index 80778bd..58663e5 100644
--- a/system/egl/Android.mk
+++ b/system/egl/Android.mk
@@ -7,6 +7,7 @@
 $(call emugl-set-shared-library-subpath,egl)
 
 LOCAL_CFLAGS += -DLOG_TAG=\"EGL_emulation\" -DEGL_EGLEXT_PROTOTYPES -DWITH_GLES2
+LOCAL_CFLAGS += -Wno-gnu-designator
 
 LOCAL_SRC_FILES := \
     eglDisplay.cpp \
@@ -29,9 +30,6 @@
 LOCAL_SHARED_LIBRARIES += libnativewindow
 endif
 
-# Used to access the Bionic private OpenGL TLS slot
-LOCAL_C_INCLUDES += bionic/libc/private
-
 endif # !GOLDFISH_OPENGL_BUILD_FOR_HOST
 
 $(call emugl-end-module)
diff --git a/system/egl/CMakeLists.txt b/system/egl/CMakeLists.txt
index 56f92cd..25b4cdd 100644
--- a/system/egl/CMakeLists.txt
+++ b/system/egl/CMakeLists.txt
@@ -1,10 +1,10 @@
 # This is an autogenerated file! Do not edit!
 # instead run make from .../device/generic/goldfish-opengl
 # which will re-generate this file.
-android_validate_sha256("${GOLDFISH_DEVICE_ROOT}/system/egl/Android.mk" "4a6be27a2b501a86cad12c5876d0e766966574b11376ff8614fd92ffe94eb4b3")
+android_validate_sha256("${GOLDFISH_DEVICE_ROOT}/system/egl/Android.mk" "53f944775eac93c4fff6cb2b10ec932462422eb0e4ae0fb616f2f16bb0baf4af")
 set(EGL_emulation_src eglDisplay.cpp egl.cpp ClientAPIExts.cpp)
-android_add_shared_library(EGL_emulation)
-target_include_directories(EGL_emulation PRIVATE ${GOLDFISH_DEVICE_ROOT}/system/OpenglSystemCommon ${GOLDFISH_DEVICE_ROOT}/bionic/libc/private ${GOLDFISH_DEVICE_ROOT}/system/vulkan_enc ${GOLDFISH_DEVICE_ROOT}/android-emu ${GOLDFISH_DEVICE_ROOT}/system/renderControl_enc ${GOLDFISH_DEVICE_ROOT}/system/GLESv2_enc ${GOLDFISH_DEVICE_ROOT}/system/GLESv1_enc ${GOLDFISH_DEVICE_ROOT}/shared/OpenglCodecCommon ${GOLDFISH_DEVICE_ROOT}/./host/include/libOpenglRender ${GOLDFISH_DEVICE_ROOT}/./system/include ${GOLDFISH_DEVICE_ROOT}/./../../../external/qemu/android/android-emugl/guest)
+android_add_library(TARGET EGL_emulation SHARED LICENSE Apache-2.0 SRC eglDisplay.cpp egl.cpp ClientAPIExts.cpp)
+target_include_directories(EGL_emulation PRIVATE ${GOLDFISH_DEVICE_ROOT}/system/OpenglSystemCommon/bionic-include ${GOLDFISH_DEVICE_ROOT}/system/OpenglSystemCommon ${GOLDFISH_DEVICE_ROOT}/bionic/libc/private ${GOLDFISH_DEVICE_ROOT}/bionic/libc/platform ${GOLDFISH_DEVICE_ROOT}/system/vulkan_enc ${GOLDFISH_DEVICE_ROOT}/android-emu ${GOLDFISH_DEVICE_ROOT}/system/renderControl_enc ${GOLDFISH_DEVICE_ROOT}/system/GLESv2_enc ${GOLDFISH_DEVICE_ROOT}/system/GLESv1_enc ${GOLDFISH_DEVICE_ROOT}/shared/OpenglCodecCommon ${GOLDFISH_DEVICE_ROOT}/./host/include/libOpenglRender ${GOLDFISH_DEVICE_ROOT}/./system/include ${GOLDFISH_DEVICE_ROOT}/./../../../external/qemu/android/android-emugl/guest)
 target_compile_definitions(EGL_emulation PRIVATE "-DWITH_GLES2" "-DPLATFORM_SDK_VERSION=29" "-DGOLDFISH_HIDL_GRALLOC" "-DEMULATOR_OPENGL_POST_O=1" "-DHOST_BUILD" "-DANDROID" "-DGL_GLEXT_PROTOTYPES" "-DPAGE_SIZE=4096" "-DGOLDFISH_VULKAN" "-DLOG_TAG=\"EGL_emulation\"" "-DEGL_EGLEXT_PROTOTYPES")
-target_compile_options(EGL_emulation PRIVATE "-fvisibility=default")
-target_link_libraries(EGL_emulation PRIVATE OpenglSystemCommon android-emu-shared vulkan_enc gui cutils utils log _renderControl_enc GLESv2_enc GLESv1_enc OpenglCodecCommon_host)
\ No newline at end of file
+target_compile_options(EGL_emulation PRIVATE "-fvisibility=default" "-Wno-unused-parameter" "-Wno-gnu-designator")
+target_link_libraries(EGL_emulation PRIVATE OpenglSystemCommon android-emu-shared vulkan_enc gui androidemu cutils utils log _renderControl_enc GLESv2_enc GLESv1_enc OpenglCodecCommon_host)
\ No newline at end of file
diff --git a/system/egl/egl.cpp b/system/egl/egl.cpp
index 60d17e5..5940b79 100644
--- a/system/egl/egl.cpp
+++ b/system/egl/egl.cpp
@@ -675,7 +675,7 @@
         return EGL_FALSE;
     }
 
-    rcColorBuffer = rcEnc->rcCreateColorBuffer(rcEnc, getWidth(), getHeight(), pixelFormat);
+    rcColorBuffer = grallocHelper->createColorBuffer(rcEnc, getWidth(), getHeight(), pixelFormat);
     if (!rcColorBuffer) {
         ALOGE("rcCreateColorBuffer returned 0");
         return EGL_FALSE;
@@ -2258,9 +2258,22 @@
     case EGL_SYNC_TYPE_KHR:
         *value = sync->type;
         return EGL_TRUE;
-    case EGL_SYNC_STATUS_KHR:
-        *value = sync->status;
-        return EGL_TRUE;
+    case EGL_SYNC_STATUS_KHR: {
+        if (sync->status == EGL_SIGNALED_KHR) {
+            *value = sync->status;
+            return EGL_TRUE;
+        } else {
+            // ask the host again
+            DEFINE_HOST_CONNECTION;
+            if (rcEnc->hasNativeSyncV4()) {
+                if (rcEnc->rcIsSyncSignaled(rcEnc, sync->handle)) {
+                    sync->status = EGL_SIGNALED_KHR;
+                }
+            }
+            *value = sync->status;
+            return EGL_TRUE;
+        }
+    }
     case EGL_SYNC_CONDITION_KHR:
         *value = EGL_SYNC_PRIOR_COMMANDS_COMPLETE_KHR;
         return EGL_TRUE;
diff --git a/system/egl/eglDisplay.cpp b/system/egl/eglDisplay.cpp
index 70ee096..2e18e11 100644
--- a/system/egl/eglDisplay.cpp
+++ b/system/egl/eglDisplay.cpp
@@ -331,23 +331,6 @@
     return NULL;
 }
 
-static bool findExtInList(const char* token, int tokenlen, const char* list)
-{
-    const char* p = list;
-    while (*p != '\0') {
-        const char* q = strchr(p, ' ');
-        if (q == NULL) {
-            /* should not happen, list must be space-terminated */
-            break;
-        }
-        if (tokenlen == (q - p) && !memcmp(token, p, tokenlen)) {
-            return true;  /* found it */
-        }
-        p = q+1;
-    }
-    return false;  /* not found */
-}
-
 static char *buildExtensionString()
 {
     //Query host extension string
diff --git a/system/gralloc/Android.mk b/system/gralloc/Android.mk
index 88dd193..8a12378 100644
--- a/system/gralloc/Android.mk
+++ b/system/gralloc/Android.mk
@@ -9,12 +9,15 @@
 
 LOCAL_CFLAGS += -DLOG_TAG=\"gralloc_$(1)\"
 LOCAL_CFLAGS += -Wno-missing-field-initializers
+LOCAL_CFLAGS += -Wno-gnu-designator
 
-LOCAL_SRC_FILES := gralloc.cpp
+ifeq ($(shell test $(PLATFORM_SDK_VERSION) -ge 30; echo $$?), 0)
+LOCAL_SRC_FILES := gralloc_30.cpp
+else
+LOCAL_SRC_FILES := gralloc_old.cpp
+endif
 
 ifneq (true,$(GOLDFISH_OPENGL_BUILD_FOR_HOST))
-# Need to access the special OPENGL TLS Slot
-LOCAL_C_INCLUDES += bionic/libc/private
 LOCAL_SHARED_LIBRARIES += libdl
 endif
 
diff --git a/system/gralloc/CMakeLists.txt b/system/gralloc/CMakeLists.txt
index 22318ae..cf65352 100644
--- a/system/gralloc/CMakeLists.txt
+++ b/system/gralloc/CMakeLists.txt
@@ -1,20 +1,20 @@
 # This is an autogenerated file! Do not edit!
 # instead run make from .../device/generic/goldfish-opengl
 # which will re-generate this file.
-android_validate_sha256("${GOLDFISH_DEVICE_ROOT}/system/gralloc/Android.mk" "3898852aade0f86cf9db2d73e90a5294e04aebb513e4757bf5f9ceaaeab528bb")
-set(gralloc.goldfish_src gralloc.cpp)
-android_add_shared_library(gralloc.goldfish)
-target_include_directories(gralloc.goldfish PRIVATE ${GOLDFISH_DEVICE_ROOT}/system/OpenglSystemCommon ${GOLDFISH_DEVICE_ROOT}/bionic/libc/private ${GOLDFISH_DEVICE_ROOT}/system/vulkan_enc ${GOLDFISH_DEVICE_ROOT}/android-emu ${GOLDFISH_DEVICE_ROOT}/system/GLESv2_enc ${GOLDFISH_DEVICE_ROOT}/system/renderControl_enc ${GOLDFISH_DEVICE_ROOT}/system/GLESv1_enc ${GOLDFISH_DEVICE_ROOT}/shared/OpenglCodecCommon ${GOLDFISH_DEVICE_ROOT}/./host/include/libOpenglRender ${GOLDFISH_DEVICE_ROOT}/./system/include ${GOLDFISH_DEVICE_ROOT}/./../../../external/qemu/android/android-emugl/guest)
+android_validate_sha256("${GOLDFISH_DEVICE_ROOT}/system/gralloc/Android.mk" "09618d9293855148fb310e67065028da8c7f6dcf936b02b5695292c82ed4724e")
+set(gralloc.goldfish_src gralloc_old.cpp)
+android_add_library(TARGET gralloc.goldfish SHARED LICENSE Apache-2.0 SRC gralloc_old.cpp)
+target_include_directories(gralloc.goldfish PRIVATE ${GOLDFISH_DEVICE_ROOT}/system/OpenglSystemCommon/bionic-include ${GOLDFISH_DEVICE_ROOT}/system/OpenglSystemCommon ${GOLDFISH_DEVICE_ROOT}/bionic/libc/private ${GOLDFISH_DEVICE_ROOT}/bionic/libc/platform ${GOLDFISH_DEVICE_ROOT}/system/vulkan_enc ${GOLDFISH_DEVICE_ROOT}/android-emu ${GOLDFISH_DEVICE_ROOT}/system/GLESv2_enc ${GOLDFISH_DEVICE_ROOT}/system/renderControl_enc ${GOLDFISH_DEVICE_ROOT}/system/GLESv1_enc ${GOLDFISH_DEVICE_ROOT}/shared/OpenglCodecCommon ${GOLDFISH_DEVICE_ROOT}/./host/include/libOpenglRender ${GOLDFISH_DEVICE_ROOT}/./system/include ${GOLDFISH_DEVICE_ROOT}/./../../../external/qemu/android/android-emugl/guest)
 target_compile_definitions(gralloc.goldfish PRIVATE "-DWITH_GLES2" "-DPLATFORM_SDK_VERSION=29" "-DGOLDFISH_HIDL_GRALLOC" "-DEMULATOR_OPENGL_POST_O=1" "-DHOST_BUILD" "-DANDROID" "-DGL_GLEXT_PROTOTYPES" "-DPAGE_SIZE=4096" "-DGOLDFISH_VULKAN" "-DLOG_TAG=\"gralloc_goldfish\"")
-target_compile_options(gralloc.goldfish PRIVATE "-fvisibility=default" "-Wno-missing-field-initializers")
-target_link_libraries(gralloc.goldfish PRIVATE OpenglSystemCommon android-emu-shared vulkan_enc gui cutils utils log GLESv2_enc _renderControl_enc GLESv1_enc OpenglCodecCommon_host)
+target_compile_options(gralloc.goldfish PRIVATE "-fvisibility=default" "-Wno-unused-parameter" "-Wno-missing-field-initializers" "-Wno-gnu-designator")
+target_link_libraries(gralloc.goldfish PRIVATE OpenglSystemCommon android-emu-shared vulkan_enc gui androidemu cutils utils log GLESv2_enc _renderControl_enc GLESv1_enc OpenglCodecCommon_host)
 # This is an autogenerated file! Do not edit!
 # instead run make from .../device/generic/goldfish-opengl
 # which will re-generate this file.
-android_validate_sha256("${GOLDFISH_DEVICE_ROOT}/system/gralloc/Android.mk" "3898852aade0f86cf9db2d73e90a5294e04aebb513e4757bf5f9ceaaeab528bb")
-set(gralloc.ranchu_src gralloc.cpp)
-android_add_shared_library(gralloc.ranchu)
-target_include_directories(gralloc.ranchu PRIVATE ${GOLDFISH_DEVICE_ROOT}/system/OpenglSystemCommon ${GOLDFISH_DEVICE_ROOT}/bionic/libc/private ${GOLDFISH_DEVICE_ROOT}/system/vulkan_enc ${GOLDFISH_DEVICE_ROOT}/android-emu ${GOLDFISH_DEVICE_ROOT}/system/GLESv2_enc ${GOLDFISH_DEVICE_ROOT}/system/renderControl_enc ${GOLDFISH_DEVICE_ROOT}/system/GLESv1_enc ${GOLDFISH_DEVICE_ROOT}/shared/OpenglCodecCommon ${GOLDFISH_DEVICE_ROOT}/./host/include/libOpenglRender ${GOLDFISH_DEVICE_ROOT}/./system/include ${GOLDFISH_DEVICE_ROOT}/./../../../external/qemu/android/android-emugl/guest)
+android_validate_sha256("${GOLDFISH_DEVICE_ROOT}/system/gralloc/Android.mk" "09618d9293855148fb310e67065028da8c7f6dcf936b02b5695292c82ed4724e")
+set(gralloc.ranchu_src gralloc_old.cpp)
+android_add_library(TARGET gralloc.ranchu SHARED LICENSE Apache-2.0 SRC gralloc_old.cpp)
+target_include_directories(gralloc.ranchu PRIVATE ${GOLDFISH_DEVICE_ROOT}/system/OpenglSystemCommon/bionic-include ${GOLDFISH_DEVICE_ROOT}/system/OpenglSystemCommon ${GOLDFISH_DEVICE_ROOT}/bionic/libc/private ${GOLDFISH_DEVICE_ROOT}/bionic/libc/platform ${GOLDFISH_DEVICE_ROOT}/system/vulkan_enc ${GOLDFISH_DEVICE_ROOT}/android-emu ${GOLDFISH_DEVICE_ROOT}/system/GLESv2_enc ${GOLDFISH_DEVICE_ROOT}/system/renderControl_enc ${GOLDFISH_DEVICE_ROOT}/system/GLESv1_enc ${GOLDFISH_DEVICE_ROOT}/shared/OpenglCodecCommon ${GOLDFISH_DEVICE_ROOT}/./host/include/libOpenglRender ${GOLDFISH_DEVICE_ROOT}/./system/include ${GOLDFISH_DEVICE_ROOT}/./../../../external/qemu/android/android-emugl/guest)
 target_compile_definitions(gralloc.ranchu PRIVATE "-DWITH_GLES2" "-DPLATFORM_SDK_VERSION=29" "-DGOLDFISH_HIDL_GRALLOC" "-DEMULATOR_OPENGL_POST_O=1" "-DHOST_BUILD" "-DANDROID" "-DGL_GLEXT_PROTOTYPES" "-DPAGE_SIZE=4096" "-DGOLDFISH_VULKAN" "-DLOG_TAG=\"gralloc_ranchu\"")
-target_compile_options(gralloc.ranchu PRIVATE "-fvisibility=default" "-Wno-missing-field-initializers")
-target_link_libraries(gralloc.ranchu PRIVATE OpenglSystemCommon android-emu-shared vulkan_enc gui cutils utils log GLESv2_enc _renderControl_enc GLESv1_enc OpenglCodecCommon_host)
\ No newline at end of file
+target_compile_options(gralloc.ranchu PRIVATE "-fvisibility=default" "-Wno-unused-parameter" "-Wno-missing-field-initializers" "-Wno-gnu-designator")
+target_link_libraries(gralloc.ranchu PRIVATE OpenglSystemCommon android-emu-shared vulkan_enc gui androidemu cutils utils log GLESv2_enc _renderControl_enc GLESv1_enc OpenglCodecCommon_host)
\ No newline at end of file
diff --git a/system/gralloc/gralloc_30.cpp b/system/gralloc/gralloc_30.cpp
new file mode 100644
index 0000000..09f421c
--- /dev/null
+++ b/system/gralloc/gralloc_30.cpp
@@ -0,0 +1,1086 @@
+/*
+* Copyright (C) 2019 The Android Open Source Project
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+#include <string.h>
+#include <pthread.h>
+#include <limits.h>
+#include <unistd.h>
+#include <errno.h>
+
+#include <set>
+#include <map>
+#include <vector>
+#include <string>
+#include <algorithm>
+
+#include <log/log.h>
+#include <sys/mman.h>
+
+#include <hardware/hardware.h>
+#include <hardware/gralloc.h>
+
+#include "../../shared/OpenglCodecCommon/gralloc_cb.h"
+#include "gralloc_common.h"
+#include "goldfish_address_space.h"
+#include "HostConnection.h"
+#include "FormatConversions.h"
+#include "qemu_pipe.h"
+
+#define CRASH(MSG) \
+    do { \
+        ALOGE("%s:%d crashed with '%s'", __func__, __LINE__, MSG); \
+        ::abort(); \
+    } while (false)
+
+#define CRASH_IF(COND, MSG) \
+    do { \
+        if ((COND)) { \
+            ALOGE("%s:%d crashed on '%s' with '%s'", __func__, __LINE__, #COND, MSG); \
+            ::abort(); \
+        } \
+    } while (false)
+
+#define RETURN_ERROR_CODE(X) \
+    do { \
+        ALOGE("%s:%d failed with '%s' (%d)", \
+              __func__, __LINE__, strerror(-(X)), -(X)); \
+        return (X); \
+    } while (false)
+
+#define RETURN_ERROR(X) \
+    do { \
+        ALOGE("%s:%d failed with '%s'", __func__, __LINE__, #X); \
+        return (X); \
+    } while (false)
+
+#define OMX_COLOR_FormatYUV420Planar 19
+
+namespace {
+
+const char GOLDFISH_GRALLOC_MODULE_NAME[] = "Graphics Memory Allocator Module";
+
+hw_device_t make_hw_device(hw_module_t* module, int (*close)(hw_device_t*)) {
+    hw_device_t result = {};
+
+    result.tag = HARDWARE_DEVICE_TAG;
+    result.version = 0;
+    result.module = module;
+    result.close = close;
+
+    return result;
+}
+
+size_t align(const size_t v, const size_t a) { return (v + a - 1) & ~(a - 1); }
+
+class HostConnectionSession {
+public:
+    explicit HostConnectionSession(HostConnection* hc) : conn(hc) {
+        hc->lock();
+    }
+
+    ~HostConnectionSession() {
+        if (conn) {
+            conn->unlock();
+        }
+     }
+
+    HostConnectionSession(HostConnectionSession&& rhs) : conn(rhs.conn) {
+        rhs.conn = nullptr;
+    }
+
+    HostConnectionSession& operator=(HostConnectionSession&& rhs) {
+        if (this != &rhs) {
+            std::swap(conn, rhs.conn);
+        }
+        return *this;
+    }
+
+    HostConnectionSession(const HostConnectionSession&) = delete;
+    HostConnectionSession& operator=(const HostConnectionSession&) = delete;
+
+    ExtendedRCEncoderContext* getRcEncoder() const {
+        return conn->rcEncoder();
+    }
+
+private:
+    HostConnection* conn;
+};
+
+class goldfish_gralloc30_module_t;
+class goldfish_gralloc30_device_t;
+class goldfish_fb30_device_t;
+
+class buffer_manager_t {
+public:
+    buffer_manager_t() = default;
+    buffer_manager_t(const buffer_manager_t&) = delete;
+    buffer_manager_t& operator=(const buffer_manager_t&) = delete;
+    buffer_manager_t(buffer_manager_t&&) = delete;
+    buffer_manager_t& operator=(buffer_manager_t&&) = delete;
+    virtual ~buffer_manager_t() {}
+
+    virtual uint64_t getMmapedPhysAddr(uint64_t offset) const = 0;
+
+    virtual int alloc_buffer(int usage,
+                             int width, int height, int format,
+                             EmulatorFrameworkFormat emulatorFrameworkFormat,
+                             int glFormat, int glType,
+                             size_t bufferSize,
+                             buffer_handle_t* pHandle) = 0;
+    virtual int free_buffer(buffer_handle_t h) = 0;
+    virtual int register_buffer(buffer_handle_t h) = 0;
+    virtual int unregister_buffer(buffer_handle_t h) = 0;
+};
+
+std::unique_ptr<buffer_manager_t> create_buffer_manager(goldfish_gralloc30_module_t*);
+
+class goldfish_gralloc30_module_t {
+public:
+    goldfish_gralloc30_module_t(): m_hostConn(HostConnection::createUnique()) {
+        CRASH_IF(!m_hostConn, "m_hostConn cannot be nullptr");
+        m_bufferManager = create_buffer_manager(this);
+        CRASH_IF(!m_bufferManager, "m_bufferManager cannot be nullptr");
+    }
+
+    HostConnectionSession getHostConnectionSession() const {
+        return HostConnectionSession(m_hostConn /*.get()*/);
+    }
+
+    int alloc_buffer(int usage,
+                     int width, int height, int format,
+                     EmulatorFrameworkFormat emulatorFrameworkFormat,
+                     int glFormat, int glType,
+                     size_t bufferSize,
+                     buffer_handle_t* pHandle) {
+        return m_bufferManager->alloc_buffer(usage,
+                                             width, height, format,
+                                             emulatorFrameworkFormat,
+                                             glFormat, glType,
+                                             bufferSize,
+                                             pHandle);
+    }
+
+    int free_buffer(buffer_handle_t h) {
+        return m_bufferManager->free_buffer(h);
+    }
+
+    int register_buffer(buffer_handle_t h) {
+        return m_bufferManager->register_buffer(h);
+    }
+
+    int unregister_buffer(buffer_handle_t h) {
+        return m_bufferManager->unregister_buffer(h);
+    }
+
+    int lock(cb_handle_t& handle,
+             const int usage,
+             const int left, const int top, const int width, const int height,
+             void** vaddr) {
+        if (!handle.bufferSize) { RETURN_ERROR_CODE(-EINVAL); }
+        char* const bufferBits = static_cast<char*>(handle.getBufferPtr());
+        if (!bufferBits) { RETURN_ERROR_CODE(-EINVAL); }
+
+        if (handle.hostHandle) {
+            const int res = lock_impl(handle,
+                                      usage,
+                                      left, top, width, height,
+                                      bufferBits);
+            if (res) { return res; }
+        }
+
+        *vaddr = bufferBits;
+        return 0;
+    }
+
+    int unlock(cb_handle_t& handle) {
+        if (!handle.bufferSize) { RETURN_ERROR_CODE(-EINVAL); }
+
+        char* const bufferBits = static_cast<char*>(handle.getBufferPtr());
+        if (!bufferBits) { RETURN_ERROR_CODE(-EINVAL); }
+
+        if (handle.hostHandle) {
+            unlock_impl(handle, bufferBits);
+        }
+
+        return 0;
+    }
+
+    int lock_ycbcr(cb_handle_t& handle,
+                   const int usage,
+                   const int left, const int top, const int width, const int height,
+                   android_ycbcr* ycbcr) {
+        if (!ycbcr) { RETURN_ERROR_CODE(-EINVAL); }
+        if (!handle.bufferSize) { RETURN_ERROR_CODE(-EINVAL); }
+        char* const bufferBits = static_cast<char*>(handle.getBufferPtr());
+        if (!bufferBits) { RETURN_ERROR_CODE(-EINVAL); }
+
+        size_t uOffset;
+        size_t vOffset;
+        size_t yStride;
+        size_t cStride;
+        size_t cStep;
+
+        switch (handle.format) {
+        case HAL_PIXEL_FORMAT_YCrCb_420_SP:
+            yStride = handle.width;
+            cStride = yStride;
+            vOffset = yStride * handle.height;
+            uOffset = vOffset + 1;
+            cStep = 2;
+            break;
+
+        case HAL_PIXEL_FORMAT_YV12:
+            // https://developer.android.com/reference/android/graphics/ImageFormat.html#YV12
+            yStride = align(handle.width, 16);
+            cStride = align(yStride / 2, 16);
+            vOffset = yStride * handle.height;
+            uOffset = vOffset + (cStride * handle.height / 2);
+            cStep = 1;
+            break;
+
+        case HAL_PIXEL_FORMAT_YCbCr_420_888:
+            yStride = handle.width;
+            cStride = yStride / 2;
+            uOffset = handle.height * yStride;
+            vOffset = uOffset + cStride * handle.height / 2;
+            cStep = 1;
+            break;
+
+        default:
+            ALOGE("%s:%d unexpected format (%d)", __func__, __LINE__, handle.format);
+            RETURN_ERROR_CODE(-EINVAL);
+        }
+
+        if (handle.hostHandle) {
+            const int res = lock_impl(handle,
+                                      usage,
+                                      left, top, width, height,
+                                      bufferBits);
+            if (res) { return res; }
+        }
+
+        memset(ycbcr->reserved, 0, sizeof(ycbcr->reserved));
+        char* const vaddr1 = static_cast<char*>(bufferBits);
+        ycbcr->y = vaddr1;
+        ycbcr->cb = vaddr1 + uOffset;
+        ycbcr->cr = vaddr1 + vOffset;
+        ycbcr->ystride = yStride;
+        ycbcr->cstride = cStride;
+        ycbcr->chroma_step = cStep;
+        return 0;
+    }
+
+private:
+    int lock_impl(cb_handle_t& handle,
+                  const int usage,
+                  const int left, const int top, const int width, const int height,
+                  char* const bufferBits) {
+        const bool usageSwRead = usage & GRALLOC_USAGE_SW_READ_MASK;
+        const bool usageSwWrite = usage & GRALLOC_USAGE_SW_WRITE_MASK;
+        const bool usageHwCamera = usage & GRALLOC_USAGE_HW_CAMERA_MASK;
+        const bool usageHwCameraWrite = usage & GRALLOC_USAGE_HW_CAMERA_WRITE;
+
+        const HostConnectionSession conn = getHostConnectionSession();
+        ExtendedRCEncoderContext *const rcEnc = conn.getRcEncoder();
+
+        const int res = rcEnc->rcColorBufferCacheFlush(
+            rcEnc, handle.hostHandle, 0, usageSwRead);
+        if (res < 0) {
+            RETURN_ERROR_CODE(-EBUSY);
+        }
+
+        // camera delivers bits to the buffer directly and does not require
+        // an explicit read.
+        if (usageSwRead && !usageHwCamera) {
+            if (gralloc_is_yuv_format(handle.format)) {
+                if (rcEnc->hasYUVCache()) {
+                    uint32_t bufferSize;
+
+                    switch (handle.format) {
+                    case HAL_PIXEL_FORMAT_YV12:
+                        get_yv12_offsets(handle.width, handle.height,
+                                         nullptr, nullptr, &bufferSize);
+                        break;
+                    case HAL_PIXEL_FORMAT_YCbCr_420_888:
+                        get_yuv420p_offsets(handle.width, handle.height,
+                                            nullptr, nullptr, &bufferSize);
+                        break;
+                    default:
+                        CRASH("Unexpected format, switch is out of sync with gralloc_is_yuv_format");
+                        break;
+                    }
+
+                    rcEnc->rcReadColorBufferYUV(rcEnc, handle.hostHandle,
+                        0, 0, handle.width, handle.height,
+                        bufferBits, bufferSize);
+                } else {
+                    // We are using RGB888
+                    std::vector<char> tmpBuf(handle.width * handle.height * 3);
+                    rcEnc->rcReadColorBuffer(rcEnc, handle.hostHandle,
+                                             0, 0, handle.width, handle.height,
+                                             handle.glFormat, handle.glType,
+                                             tmpBuf.data());
+
+                    switch (handle.format) {
+                    case HAL_PIXEL_FORMAT_YV12:
+                        rgb888_to_yv12(bufferBits, tmpBuf.data(),
+                                       handle.width, handle.height,
+                                       left, top,
+                                       left + width - 1, top + height - 1);
+                        break;
+                    case HAL_PIXEL_FORMAT_YCbCr_420_888:
+                        rgb888_to_yuv420p(bufferBits, tmpBuf.data(),
+                                          handle.width, handle.height,
+                                          left, top,
+                                          left + width - 1, top + height - 1);
+                        break;
+                    default:
+                        CRASH("Unexpected format, switch is out of sync with gralloc_is_yuv_format");
+                        break;
+                    }
+                }
+            } else {
+                rcEnc->rcReadColorBuffer(rcEnc,
+                                         handle.hostHandle,
+                                         0, 0, handle.width, handle.height,
+                                         handle.glFormat, handle.glType,
+                                         bufferBits);
+            }
+        }
+
+        if (usageSwWrite || usageHwCameraWrite) {
+            handle.lockedLeft = left;
+            handle.lockedTop = top;
+            handle.lockedWidth = width;
+            handle.lockedHeight = height;
+        } else {
+            handle.lockedLeft = 0;
+            handle.lockedTop = 0;
+            handle.lockedWidth = handle.width;
+            handle.lockedHeight = handle.height;
+        }
+
+        return 0;
+    }
+
+    void unlock_impl(cb_handle_t& handle, char* const bufferBits) {
+        const int bpp = glUtilsPixelBitSize(handle.glFormat, handle.glType) >> 3;
+        const int left = handle.lockedLeft;
+        const int top = handle.lockedTop;
+        const int width = handle.lockedWidth;
+        const int height = handle.lockedHeight;
+        const uint32_t rgbSize = width * height * bpp;
+
+        std::vector<char> convertedBuf;
+        const char* bitsToSend;
+        uint32_t sizeToSend;
+        if (gralloc_is_yuv_format(handle.format)) {
+            bitsToSend = bufferBits;
+            switch (handle.format) {
+            case HAL_PIXEL_FORMAT_YV12:
+                get_yv12_offsets(width, height, nullptr, nullptr, &sizeToSend);
+                break;
+
+            case HAL_PIXEL_FORMAT_YCbCr_420_888:
+                get_yuv420p_offsets(width, height, nullptr, nullptr, &sizeToSend);
+                break;
+
+            default:
+                CRASH("Unexpected format, switch is out of sync with gralloc_is_yuv_format");
+                break;
+            }
+        } else {
+            convertedBuf.resize(rgbSize);
+            copy_rgb_buffer_from_unlocked(
+                convertedBuf.data(), bufferBits,
+                handle.width,
+                width, height, top, left, bpp);
+            bitsToSend = convertedBuf.data();
+            sizeToSend = rgbSize;
+        }
+
+        {
+            const HostConnectionSession conn = getHostConnectionSession();
+            ExtendedRCEncoderContext *const rcEnc = conn.getRcEncoder();
+
+            rcEnc->bindDmaDirectly(bufferBits,
+                                   m_bufferManager->getMmapedPhysAddr(handle.getMmapedOffset()));
+            rcEnc->rcUpdateColorBufferDMA(rcEnc, handle.hostHandle,
+                    left, top, width, height,
+                    handle.glFormat, handle.glType,
+                    const_cast<char*>(bitsToSend), sizeToSend);
+        }
+
+        handle.lockedLeft = 0;
+        handle.lockedTop = 0;
+        handle.lockedWidth = 0;
+        handle.lockedHeight = 0;
+    }
+
+    //std::unique_ptr<HostConnection> m_hostConn;  // b/142677230
+    HostConnection* m_hostConn;
+    std::unique_ptr<buffer_manager_t> m_bufferManager;
+};
+
+// no ctor/dctor here
+struct private_module_t {
+    goldfish_gralloc30_module_t* impl() {
+        return &gralloc30;
+    }
+
+    hw_module_t* to_hw_module() { return &base.common; }
+
+    static private_module_t* from_hw_module(const hw_module_t* m) {
+        if (!m) {
+            RETURN_ERROR(nullptr);
+        }
+
+        if ((m->id == GRALLOC_HARDWARE_MODULE_ID) && (m->name == GOLDFISH_GRALLOC_MODULE_NAME)) {
+            return reinterpret_cast<private_module_t*>(const_cast<hw_module_t*>(m));
+        } else {
+            RETURN_ERROR(nullptr);
+        }
+    }
+
+    static private_module_t* from_gralloc_module(const gralloc_module_t* m) {
+        if (!m) {
+            RETURN_ERROR(nullptr);
+        }
+
+        return from_hw_module(&m->common);
+    }
+
+    gralloc_module_t base;
+    goldfish_gralloc30_module_t gralloc30;
+};
+
+class goldfish_gralloc30_device_t {
+    alloc_device_t device;
+    goldfish_gralloc30_module_t* gralloc_module;
+
+public:
+    goldfish_gralloc30_device_t(private_module_t* module)
+            : gralloc_module(module->impl()) {
+        memset(&device, 0, sizeof(device));
+        device.common = make_hw_device(module->to_hw_module(),
+                                       &s_goldfish_gralloc30_device_close);
+        device.alloc = &s_gralloc_alloc;
+        device.free  = &s_gralloc_free;
+    }
+
+    hw_device_t* get_hw_device_ptr() { return &device.common; }
+
+private:
+    static int get_buffer_format(const int frameworkFormat, const int usage) {
+        if (frameworkFormat == HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED) {
+            if (usage & GRALLOC_USAGE_HW_CAMERA_WRITE) {
+                if (usage & GRALLOC_USAGE_HW_TEXTURE) {
+                    // Camera-to-display is RGBA
+                    return HAL_PIXEL_FORMAT_RGBA_8888;
+                } else if (usage & GRALLOC_USAGE_HW_VIDEO_ENCODER) {
+                    // Camera-to-encoder is NV21
+                    return HAL_PIXEL_FORMAT_YCrCb_420_SP;
+                }
+            }
+
+            RETURN_ERROR_CODE(-EINVAL);
+        } else if (frameworkFormat == OMX_COLOR_FormatYUV420Planar &&
+               (usage & GOLDFISH_GRALLOC_USAGE_GPU_DATA_BUFFER)) {
+            ALOGW("gralloc_alloc: Requested OMX_COLOR_FormatYUV420Planar, given "
+              "YCbCr_420_888, taking experimental path. "
+              "usage=%x", usage);
+            return HAL_PIXEL_FORMAT_YCbCr_420_888;
+        }
+        else  {
+            return frameworkFormat;
+        }
+    }
+
+    int gralloc_alloc(const int width, const int height,
+                      const int frameworkFormat,
+                      const int usage,
+                      buffer_handle_t* pHandle,
+                      int* pStride) {
+        const bool usageSwWrite = usage & GRALLOC_USAGE_SW_WRITE_MASK;
+        const bool usageSwRead = usage & GRALLOC_USAGE_SW_READ_MASK;
+        const bool usageHwTexture = usage & GRALLOC_USAGE_HW_TEXTURE;
+        const bool usageHwRender = usage & GRALLOC_USAGE_HW_RENDER;
+        const bool usageHw2d = usage & GRALLOC_USAGE_HW_2D;
+        const bool usageHwComposer = usage & GRALLOC_USAGE_HW_COMPOSER;
+        const bool usageHwFb = usage & GRALLOC_USAGE_HW_FB;
+        const bool usageHwCamWrite = usage & GRALLOC_USAGE_HW_CAMERA_WRITE;
+        const bool usageHwCamRead = usage & GRALLOC_USAGE_HW_CAMERA_READ;
+        const bool usageRGB888Unsupported = usageHwTexture
+            || usageHwRender ||usageHw2d || usageHwComposer || usageHwFb;
+
+        int bpp = 1;
+        int glFormat = 0;
+        int glType = 0;
+        int align = 1;
+        bool yuv_format = false;
+        EmulatorFrameworkFormat emulatorFrameworkFormat = FRAMEWORK_FORMAT_GL_COMPATIBLE;
+
+        const int format = get_buffer_format(frameworkFormat, usage);
+        if (format < 0) {
+            ALOGE("%s:%d Unsupported format: frameworkFormat=%d, usage=%x",
+                  __func__, __LINE__, frameworkFormat, usage);
+            return format;
+        }
+
+        switch (format) {
+        case HAL_PIXEL_FORMAT_RGBA_8888:
+        case HAL_PIXEL_FORMAT_RGBX_8888:
+        case HAL_PIXEL_FORMAT_BGRA_8888:
+            bpp = 4;
+            glFormat = GL_RGBA;
+            glType = GL_UNSIGNED_BYTE;
+            break;
+
+        case HAL_PIXEL_FORMAT_RGB_888:
+            if (usageRGB888Unsupported) {
+                RETURN_ERROR_CODE(-EINVAL);  // we dont support RGB_888 for HW usage
+            } else {
+                bpp = 3;
+                glFormat = GL_RGB;
+                glType = GL_UNSIGNED_BYTE;
+            }
+            break;
+
+        case HAL_PIXEL_FORMAT_RGB_565:
+            bpp = 2;
+            glFormat = GL_RGB565;
+            glType = GL_UNSIGNED_SHORT_5_6_5;
+            break;
+
+        case HAL_PIXEL_FORMAT_RGBA_FP16:
+            bpp = 8;
+            glFormat = GL_RGBA16F;
+            glType = GL_HALF_FLOAT;
+            break;
+
+        case HAL_PIXEL_FORMAT_RGBA_1010102:
+            bpp = 4;
+            glFormat = GL_RGB10_A2;
+            glType = GL_UNSIGNED_INT_2_10_10_10_REV;
+            break;
+
+        case HAL_PIXEL_FORMAT_RAW16:
+        case HAL_PIXEL_FORMAT_Y16:
+            bpp = 2;
+            align = 16 * bpp;
+            if (!((usageSwRead || usageHwCamRead) && (usageSwWrite || usageHwCamWrite))) {
+                // Raw sensor data or Y16 only goes between camera and CPU
+                RETURN_ERROR_CODE(-EINVAL);
+            }
+            // Not expecting to actually create any GL surfaces for this
+            glFormat = GL_LUMINANCE;
+            glType = GL_UNSIGNED_SHORT;
+            break;
+
+        case HAL_PIXEL_FORMAT_BLOB:
+            if (!usageSwRead) {
+                // Blob data cannot be used by HW other than camera emulator
+                // But there is a CTS test trying to have access to it
+                // BUG: https://buganizer.corp.google.com/issues/37719518
+                RETURN_ERROR_CODE(-EINVAL);
+            }
+            // Not expecting to actually create any GL surfaces for this
+            glFormat = GL_LUMINANCE;
+            glType = GL_UNSIGNED_BYTE;
+            break;
+
+        case HAL_PIXEL_FORMAT_YCrCb_420_SP:
+            yuv_format = true;
+            // Not expecting to actually create any GL surfaces for this
+            break;
+
+        case HAL_PIXEL_FORMAT_YV12:
+            align = 16;
+            yuv_format = true;
+            // We are going to use RGB8888 on the host for Vulkan
+            glFormat = GL_RGBA;
+            glType = GL_UNSIGNED_BYTE;
+            emulatorFrameworkFormat = FRAMEWORK_FORMAT_YV12;
+            break;
+
+        case HAL_PIXEL_FORMAT_YCbCr_420_888:
+            yuv_format = true;
+            // We are going to use RGB888 on the host
+            glFormat = GL_RGB;
+            glType = GL_UNSIGNED_BYTE;
+            emulatorFrameworkFormat = FRAMEWORK_FORMAT_YUV_420_888;
+            break;
+
+        default:
+            ALOGE("%s:%d Unsupported format: format=%d, frameworkFormat=%d, usage=%x",
+                  __func__, __LINE__, format, frameworkFormat, usage);
+            RETURN_ERROR_CODE(-EINVAL);
+        }
+
+        const size_t align1 = align - 1;
+        int stride;
+        size_t bufferSize;
+
+        if (yuv_format) {
+            const size_t yStride = (width * bpp + align1) & ~align1;
+            const size_t uvStride = (yStride / 2 + align1) & ~align1;
+            const size_t uvHeight = height / 2;
+            bufferSize = yStride * height + 2 * (uvHeight * uvStride);
+            stride = yStride / bpp;
+        } else {
+            const size_t bpr = (width * bpp + align1) & ~align1;
+            bufferSize = bpr * height;
+            stride = bpr / bpp;
+        }
+
+        const int res = gralloc_module->alloc_buffer(
+            usage,
+            width, height, format,
+            emulatorFrameworkFormat,
+            glFormat, glType,
+            bufferSize,
+            pHandle);
+        if (res) {
+            return res;
+        }
+
+        *pStride = stride;
+        return 0;
+    }
+
+    int gralloc_free(buffer_handle_t h) {
+        return gralloc_module->free_buffer(h);
+    }
+
+    static int s_goldfish_gralloc30_device_close(hw_device_t* d) {
+        goldfish_gralloc30_device_t* gd = from_hw_device(d);
+        if (!gd) {
+            RETURN_ERROR_CODE(-EINVAL);
+        }
+
+        std::unique_ptr<goldfish_gralloc30_device_t> deleter(gd);
+        return 0;
+    }
+
+    static int s_gralloc_alloc(alloc_device_t* ad,
+                         int w, int h, int format, int usage,
+                         buffer_handle_t* pHandle, int* pStride) {
+        goldfish_gralloc30_device_t* gd = from_alloc_device(ad);
+        if (!gd) {
+            RETURN_ERROR_CODE(-EINVAL);
+        }
+
+        return gd->gralloc_alloc(w, h, format, usage, pHandle, pStride);
+    }
+
+    static int s_gralloc_free(alloc_device_t* ad, buffer_handle_t h) {
+        goldfish_gralloc30_device_t* gd = from_alloc_device(ad);
+        if (!gd) {
+            RETURN_ERROR_CODE(-EINVAL);
+        }
+
+        return gd->gralloc_free(h);
+    }
+
+    static goldfish_gralloc30_device_t* from_hw_device(hw_device_t* d) {
+        if (!d) {
+            RETURN_ERROR(nullptr);
+        }
+
+        if (d->close == &s_goldfish_gralloc30_device_close) {
+            return reinterpret_cast<goldfish_gralloc30_device_t*>(d);
+        } else {
+            RETURN_ERROR(nullptr);
+        }
+    }
+
+    static goldfish_gralloc30_device_t* from_alloc_device(alloc_device_t* d) {
+        if (!d) {
+            RETURN_ERROR(nullptr);
+        }
+
+        return from_hw_device(&d->common);
+    }
+};
+
+template <class T> T& unconst(const T& x) { return const_cast<T&>(x); }
+
+const uint32_t CB_HANDLE_MAGIC_30 = CB_HANDLE_MAGIC_BASE | 0x2;
+
+struct cb_handle_30_t : public cb_handle_t {
+    cb_handle_30_t(address_space_handle_t p_bufferFd,
+                   QEMU_PIPE_HANDLE p_hostHandleRefCountFd,
+                   uint32_t p_hostHandle,
+                   int32_t p_usage,
+                   int32_t p_width,
+                   int32_t p_height,
+                   int32_t p_format,
+                   int32_t p_glFormat,
+                   int32_t p_glType,
+                   uint32_t p_bufSize,
+                   void* p_bufPtr,
+                   int32_t p_bufferPtrPid,
+                   uint32_t p_mmapedSize,
+                   uint64_t p_mmapedOffset)
+            : cb_handle_t(p_bufferFd,
+                          p_hostHandleRefCountFd,
+                          CB_HANDLE_MAGIC_30,
+                          p_hostHandle,
+                          p_usage,
+                          p_width,
+                          p_height,
+                          p_format,
+                          p_glFormat,
+                          p_glType,
+                          p_bufSize,
+                          p_bufPtr,
+                          p_mmapedOffset),
+              bufferFdAsInt(p_bufferFd),
+              bufferPtrPid(p_bufferPtrPid),
+              mmapedSize(p_mmapedSize) {
+        numInts = CB_HANDLE_NUM_INTS(numFds);
+    }
+
+    bool isValid() const { return (version == sizeof(native_handle_t)) && (magic == CB_HANDLE_MAGIC_30); }
+
+    static cb_handle_30_t* from(void* p) {
+        if (!p) { return nullptr; }
+        cb_handle_30_t* cb = static_cast<cb_handle_30_t*>(p);
+        return cb->isValid() ? cb : nullptr;
+    }
+
+    static const cb_handle_30_t* from(const void* p) {
+        return from(const_cast<void*>(p));
+    }
+
+    static cb_handle_30_t* from_unconst(const void* p) {
+        return from(const_cast<void*>(p));
+    }
+
+    int32_t  bufferFdAsInt;         // int copy of bufferFd, to check if fd was duped
+    int32_t  bufferPtrPid;          // pid where bufferPtr belongs to
+    uint32_t mmapedSize;            // real allocation side
+};
+
+// goldfish_address_space_host_malloc_handle_manager_t uses
+// GoldfishAddressSpaceHostMemoryAllocator and GoldfishAddressSpaceBlock
+// to allocate buffers on the host.
+// It keeps track of usage of host handles allocated by rcCreateColorBufferDMA
+// on the guest by qemu_pipe_open("refcount").
+class goldfish_address_space_host_malloc_buffer_manager_t : public buffer_manager_t {
+public:
+    goldfish_address_space_host_malloc_buffer_manager_t(goldfish_gralloc30_module_t* gr): m_gr(gr) {
+        GoldfishAddressSpaceHostMemoryAllocator host_memory_allocator;
+        CRASH_IF(!host_memory_allocator.is_opened(),
+                 "GoldfishAddressSpaceHostMemoryAllocator failed to open");
+
+        GoldfishAddressSpaceBlock bufferBits;
+        CRASH_IF(host_memory_allocator.hostMalloc(&bufferBits, 256),
+                 "hostMalloc failed");
+
+        m_physAddrToOffset = bufferBits.physAddr() - bufferBits.offset();
+    }
+
+    uint64_t getMmapedPhysAddr(uint64_t offset) const override {
+        return m_physAddrToOffset + offset;
+    }
+
+    int alloc_buffer(int usage,
+                     int width, int height, int format,
+                     EmulatorFrameworkFormat emulatorFrameworkFormat,
+                     int glFormat, int glType,
+                     size_t bufferSize,
+                     buffer_handle_t* pHandle) override {
+        GoldfishAddressSpaceHostMemoryAllocator host_memory_allocator;
+        if (!host_memory_allocator.is_opened()) { RETURN_ERROR_CODE(-EIO); }
+
+        GoldfishAddressSpaceBlock bufferBits;
+        if (host_memory_allocator.hostMalloc(&bufferBits, bufferSize)) { RETURN_ERROR_CODE(-EIO); }
+
+        uint32_t hostHandle = 0;
+        QEMU_PIPE_HANDLE hostHandleRefCountFd = QEMU_PIPE_INVALID_HANDLE;
+        if (need_host_cb(usage, format)) {
+            hostHandleRefCountFd = qemu_pipe_open("refcount");
+            if (!qemu_pipe_valid(hostHandleRefCountFd)) { RETURN_ERROR_CODE(-EIO); }
+
+            const GLenum allocFormat =
+                (HAL_PIXEL_FORMAT_RGBX_8888 == format) ? GL_RGB : glFormat;
+
+            const HostConnectionSession conn = m_gr->getHostConnectionSession();
+            ExtendedRCEncoderContext *const rcEnc = conn.getRcEncoder();
+
+            hostHandle = rcEnc->rcCreateColorBufferDMA(
+                rcEnc,
+                width, height,
+                allocFormat, emulatorFrameworkFormat);
+            if (!hostHandle) {
+                qemu_pipe_close(hostHandleRefCountFd);
+                RETURN_ERROR_CODE(-EIO);
+            }
+            if (qemu_pipe_write(hostHandleRefCountFd, &hostHandle, sizeof(hostHandle)) != sizeof(hostHandle)) {
+                rcEnc->rcCloseColorBuffer(rcEnc, hostHandle);
+                qemu_pipe_close(hostHandleRefCountFd);
+                RETURN_ERROR_CODE(-EIO);
+            }
+        }
+
+        std::unique_ptr<cb_handle_30_t> handle =
+            std::make_unique<cb_handle_30_t>(
+                host_memory_allocator.release(), hostHandleRefCountFd,
+                hostHandle,
+                usage, width, height,
+                format, glFormat, glType,
+                bufferSize, bufferBits.guestPtr(), getpid(),
+                bufferBits.size(), bufferBits.offset());
+        bufferBits.release();
+
+        *pHandle = handle.release();
+        return 0;
+    }
+
+    int free_buffer(buffer_handle_t h) override {
+        std::unique_ptr<cb_handle_30_t> handle(cb_handle_30_t::from_unconst(h));
+        if (!handle) {
+            RETURN_ERROR_CODE(-EINVAL);
+        }
+
+        if (handle->bufferPtrPid != getpid()) { RETURN_ERROR_CODE(-EACCES); }
+        if (handle->bufferFd != handle->bufferFdAsInt) { RETURN_ERROR_CODE(-EACCES); }
+
+        if (qemu_pipe_valid(handle->hostHandleRefCountFd)) {
+            qemu_pipe_close(handle->hostHandleRefCountFd);
+        }
+        // We can't recycle the address block and host resources because this
+        // fd could be duped. The kernel will take care of it when the last fd
+        // will be closed.
+        if (handle->mmapedSize > 0) {
+            GoldfishAddressSpaceBlock::memoryUnmap(handle->getBufferPtr(), handle->mmapedSize);
+        }
+        GoldfishAddressSpaceHostMemoryAllocator::closeHandle(handle->bufferFd);
+
+        return 0;
+    }
+
+    int register_buffer(buffer_handle_t h) override {
+#ifndef HOST_BUILD
+        cb_handle_30_t *handle = cb_handle_30_t::from_unconst(h);
+        if (!handle) { RETURN_ERROR_CODE(-EINVAL); }
+
+        if (handle->mmapedSize > 0) {
+            void* ptr;
+            const int res = GoldfishAddressSpaceBlock::memoryMap(
+                handle->getBufferPtr(),
+                handle->mmapedSize,
+                handle->bufferFd,
+                handle->getMmapedOffset(),
+                &ptr);
+            if (res) {
+                RETURN_ERROR_CODE(-res);
+            }
+
+            handle->setBufferPtr(ptr);
+        }
+        if (handle->hostHandle) {
+            const HostConnectionSession conn = m_gr->getHostConnectionSession();
+            ExtendedRCEncoderContext *const rcEnc = conn.getRcEncoder();
+            rcEnc->rcOpenColorBuffer2(rcEnc, handle->hostHandle);
+        }
+
+        handle->bufferFdAsInt = handle->bufferFd;
+        handle->bufferPtrPid = getpid();
+#endif  // HOST_BUILD
+
+        return 0;
+    }
+
+    int unregister_buffer(buffer_handle_t h) override {
+#ifndef HOST_BUILD
+        cb_handle_30_t *handle = cb_handle_30_t::from_unconst(h);
+        if (!handle) { RETURN_ERROR_CODE(-EINVAL); }
+
+        if (handle->bufferPtrPid != getpid()) { RETURN_ERROR_CODE(-EACCES); }
+        if (handle->bufferFd != handle->bufferFdAsInt) { RETURN_ERROR_CODE(-EACCES); }
+
+        if (handle->hostHandle) {
+            const HostConnectionSession conn = m_gr->getHostConnectionSession();
+            ExtendedRCEncoderContext *const rcEnc = conn.getRcEncoder();
+            rcEnc->rcCloseColorBuffer(rcEnc, handle->hostHandle);
+        }
+        if (handle->mmapedSize > 0) {
+            GoldfishAddressSpaceBlock::memoryUnmap(handle->getBufferPtr(), handle->mmapedSize);
+        }
+
+        handle->bufferFdAsInt = -1;
+        handle->bufferPtrPid = -1;
+#endif  // HOST_BUILD
+        return 0;
+    }
+
+    static bool need_host_cb(const int usage, const int format) {
+        return ((usage & GOLDFISH_GRALLOC_USAGE_GPU_DATA_BUFFER)
+                   || (format != HAL_PIXEL_FORMAT_BLOB &&
+                       format != HAL_PIXEL_FORMAT_RAW16 &&
+                       format != HAL_PIXEL_FORMAT_Y16))
+               && (usage & (GRALLOC_USAGE_HW_TEXTURE
+                            | GRALLOC_USAGE_HW_RENDER
+                            | GRALLOC_USAGE_HW_2D
+                            | GRALLOC_USAGE_HW_COMPOSER
+                            | GRALLOC_USAGE_HW_VIDEO_ENCODER
+                            | GRALLOC_USAGE_HW_FB
+                            | GRALLOC_USAGE_SW_READ_MASK));
+    }
+
+private:
+    goldfish_gralloc30_module_t* m_gr;
+    uint64_t m_physAddrToOffset;
+};
+
+std::unique_ptr<buffer_manager_t> create_buffer_manager(goldfish_gralloc30_module_t* gr) {
+    if (!gr) {
+        RETURN_ERROR(nullptr);
+    }
+
+    // TODO: negotiate with the host the best way to allocate memory.
+
+    return std::make_unique<goldfish_address_space_host_malloc_buffer_manager_t>(gr);
+}
+
+int gralloc_register_buffer(const gralloc_module_t* gralloc_module, buffer_handle_t h) {
+    private_module_t* module = private_module_t::from_gralloc_module(gralloc_module);
+    if (!module) {
+        RETURN_ERROR_CODE(-EINVAL);
+    }
+
+    return module->impl()->register_buffer(h);
+}
+
+int gralloc_unregister_buffer(const gralloc_module_t* gralloc_module, buffer_handle_t h) {
+    private_module_t* module = private_module_t::from_gralloc_module(gralloc_module);
+    if (!module) {
+        RETURN_ERROR_CODE(-EINVAL);
+    }
+
+   return module->impl()->unregister_buffer(h);
+}
+
+int gralloc_lock(const gralloc_module_t* gralloc_module,
+                 buffer_handle_t bh, int usage,
+                 int l, int t, int w, int h,
+                 void** vaddr) {
+    private_module_t* module = private_module_t::from_gralloc_module(gralloc_module);
+    if (!module) {
+        RETURN_ERROR_CODE(-EINVAL);
+    }
+
+    cb_handle_t* handle = cb_handle_t::from_unconst(bh);
+    if (!handle) {
+        RETURN_ERROR_CODE(-EINVAL);
+    }
+
+    return module->impl()->lock(*handle, usage, l, t, w, h, vaddr);
+}
+
+int gralloc_unlock(const gralloc_module_t* gralloc_module, buffer_handle_t bh) {
+    private_module_t* module = private_module_t::from_gralloc_module(gralloc_module);
+    if (!module) {
+        RETURN_ERROR_CODE(-EINVAL);
+    }
+
+    cb_handle_t* handle = cb_handle_t::from_unconst(bh);
+    if (!handle) {
+        RETURN_ERROR_CODE(-EINVAL);
+    }
+
+    return module->impl()->unlock(*handle);
+}
+
+int gralloc_lock_ycbcr(const gralloc_module_t* gralloc_module,
+                       buffer_handle_t bh, int usage,
+                       int l, int t, int w, int h,
+                       android_ycbcr *ycbcr) {
+    private_module_t* module = private_module_t::from_gralloc_module(gralloc_module);
+    if (!module) {
+        RETURN_ERROR_CODE(-EINVAL);
+    }
+
+    cb_handle_t* handle = cb_handle_t::from_unconst(bh);
+    if (!handle) {
+        RETURN_ERROR_CODE(-EINVAL);
+    }
+
+    return module->impl()->lock_ycbcr(*handle, usage, l, t, w, h, ycbcr);
+}
+
+int gralloc_device_open_gpu0(private_module_t* module, hw_device_t** device) {
+    std::unique_ptr<goldfish_gralloc30_device_t> gralloc_device =
+        std::make_unique<goldfish_gralloc30_device_t>(module);
+    if (!gralloc_device) {
+        RETURN_ERROR_CODE(-ENOMEM);
+    }
+
+    *device = gralloc_device->get_hw_device_ptr();
+    gralloc_device.release();
+    return 0;
+}
+
+int gralloc_device_open(const hw_module_t* hw_module,
+                        const char* name,
+                        hw_device_t** device) {
+    private_module_t* module = private_module_t::from_hw_module(hw_module);
+    if (!module) {
+        RETURN_ERROR_CODE(-EINVAL);
+    }
+    if (!name) {
+        RETURN_ERROR_CODE(-EINVAL);
+    }
+    if (!device) {
+        RETURN_ERROR_CODE(-EINVAL);
+    }
+
+    if (!strcmp(name, GRALLOC_HARDWARE_GPU0)) {
+        return gralloc_device_open_gpu0(module, device);
+    }
+
+    RETURN_ERROR_CODE(-EINVAL);
+}
+
+struct hw_module_methods_t gralloc_module_methods = {
+    .open = &gralloc_device_open
+};
+}  // namespace
+
+extern "C" __attribute__((visibility("default")))
+struct private_module_t HAL_MODULE_INFO_SYM = {
+    .base = {
+        .common = {
+            .tag = HARDWARE_MODULE_TAG,
+            .module_api_version = GRALLOC_MODULE_API_VERSION_0_2,
+            .hal_api_version = 0,
+            .id = GRALLOC_HARDWARE_MODULE_ID,
+            .name = GOLDFISH_GRALLOC_MODULE_NAME,
+            .author = "The Android Open Source Project",
+            .methods = &gralloc_module_methods,
+            .dso = nullptr,
+            .reserved = {0}
+        },
+        .registerBuffer   = &gralloc_register_buffer,
+        .unregisterBuffer = &gralloc_unregister_buffer,
+        .lock             = &gralloc_lock,
+        .unlock           = &gralloc_unlock,
+        .perform          = nullptr,  /* reserved for future use */
+        .lock_ycbcr       = &gralloc_lock_ycbcr,
+    },
+};
diff --git a/system/gralloc/gralloc_common.h b/system/gralloc/gralloc_common.h
new file mode 100644
index 0000000..6dba9cd
--- /dev/null
+++ b/system/gralloc/gralloc_common.h
@@ -0,0 +1,49 @@
+/*
+* Copyright 2019 The Android Open Source Project
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+#ifndef __GRALLOC_COMMON_H__
+#define __GRALLOC_COMMON_H__
+
+// Tell the emulator which gralloc formats
+// need special handling.
+enum EmulatorFrameworkFormat {
+    FRAMEWORK_FORMAT_GL_COMPATIBLE = 0,
+    FRAMEWORK_FORMAT_YV12 = 1,
+    FRAMEWORK_FORMAT_YUV_420_888 = 2,              // (Y+)(U+)(V+)
+};
+
+#ifndef GL_RGBA16F
+#define GL_RGBA16F                        0x881A
+#endif // GL_RGBA16F
+
+#ifndef GL_HALF_FLOAT
+#define GL_HALF_FLOAT                     0x140B
+#endif // GL_HALF_FLOAT
+
+#ifndef GL_RGB10_A2
+#define GL_RGB10_A2                       0x8059
+#endif // GL_RGB10_A2
+
+#ifndef GL_UNSIGNED_INT_2_10_10_10_REV
+#define GL_UNSIGNED_INT_2_10_10_10_REV    0x8368
+#endif // GL_UNSIGNED_INT_2_10_10_10_REV
+
+// defined in hardware/interfaces/graphics/common/1.0/types.hal
+#ifndef GOLDFISH_GRALLOC_USAGE_GPU_DATA_BUFFER
+#define GOLDFISH_GRALLOC_USAGE_GPU_DATA_BUFFER (1ULL << 24)
+#endif // GOLDFISH_GRALLOC_USAGE_GPU_DATA_BUFFER
+
+#endif //__GRALLOC_COMMON_H__
diff --git a/system/gralloc/gralloc.cpp b/system/gralloc/gralloc_old.cpp
similarity index 73%
rename from system/gralloc/gralloc.cpp
rename to system/gralloc/gralloc_old.cpp
index e9140be..56e6c26 100644
--- a/system/gralloc/gralloc.cpp
+++ b/system/gralloc/gralloc_old.cpp
@@ -21,6 +21,7 @@
 #include <errno.h>
 #include <dlfcn.h>
 #include <sys/mman.h>
+#include <hardware/gralloc.h>
 
 #if PLATFORM_SDK_VERSION < 28
 #include "gralloc_cb.h"
@@ -28,7 +29,10 @@
 #include "../../shared/OpenglCodecCommon/gralloc_cb.h"
 #endif
 
+#include "gralloc_common.h"
+
 #include "goldfish_dma.h"
+#include "goldfish_address_space.h"
 #include "FormatConversions.h"
 #include "HostConnection.h"
 #include "ProcessPipe.h"
@@ -52,12 +56,16 @@
 /* Set to 1 or 2 to enable debug traces */
 #define DEBUG  0
 
+#ifndef D
+
 #if DEBUG >= 1
 #  define D(...)   ALOGD(__VA_ARGS__)
 #else
 #  define D(...)   ((void)0)
 #endif
 
+#endif
+
 #if DEBUG >= 2
 #  define DD(...)  ALOGD(__VA_ARGS__)
 #else
@@ -68,17 +76,81 @@
 
 #define GOLDFISH_OFFSET_UNIT 8
 
+#define OMX_COLOR_FormatYUV420Planar 19
+
 #ifdef GOLDFISH_HIDL_GRALLOC
 static const bool isHidlGralloc = true;
 #else
 static const bool isHidlGralloc = false;
 #endif
 
-int32_t* getOpenCountPtr(cb_handle_t* cb) {
-    return ((int32_t*)cb->ashmemBase) + 1;
+const uint32_t CB_HANDLE_MAGIC_OLD = CB_HANDLE_MAGIC_BASE | 0x1;
+
+struct cb_handle_old_t : public cb_handle_t {
+    cb_handle_old_t(int p_fd, int p_ashmemSize, int p_usage,
+                    int p_width, int p_height,
+                    int p_format, int p_glFormat, int p_glType)
+            : cb_handle_t(p_fd,
+                          QEMU_PIPE_INVALID_HANDLE,
+                          CB_HANDLE_MAGIC_OLD,
+                          0,
+                          p_usage,
+                          p_width,
+                          p_height,
+                          p_format,
+                          p_glFormat,
+                          p_glType,
+                          p_ashmemSize,
+                          NULL,
+                          ~uint64_t(0)),
+              ashmemBasePid(0),
+              mappedPid(0) {
+        numInts = CB_HANDLE_NUM_INTS(numFds);
+    }
+
+    bool hasRefcountPipe() const {
+        return qemu_pipe_valid(hostHandleRefCountFd);
+    }
+
+    void setRefcountPipeFd(QEMU_PIPE_HANDLE fd) {
+        if (qemu_pipe_valid(fd)) {
+            numFds++;
+        }
+        hostHandleRefCountFd = fd;
+        numInts = CB_HANDLE_NUM_INTS(numFds);
+    }
+
+    bool canBePosted() const {
+        return (0 != (usage & GRALLOC_USAGE_HW_FB));
+    }
+
+    bool isValid() const {
+        return (version == sizeof(native_handle)) && (magic == CB_HANDLE_MAGIC_OLD);
+    }
+
+    static cb_handle_old_t* from(void* p) {
+        if (!p) { return NULL; }
+        cb_handle_old_t* cb = static_cast<cb_handle_old_t*>(p);
+        return cb->isValid() ? cb : NULL;
+    }
+
+    static const cb_handle_old_t* from(const void* p) {
+        return from(const_cast<void*>(p));
+    }
+
+    static cb_handle_old_t* from_unconst(const void* p) {
+        return from(const_cast<void*>(p));
+    }
+
+    int32_t ashmemBasePid;      // process id which mapped the ashmem region
+    int32_t mappedPid;          // process id which succeeded gralloc_register call
+};
+
+int32_t* getOpenCountPtr(const cb_handle_old_t* cb) {
+    return ((int32_t*)cb->getBufferPtr()) + 1;
 }
 
-uint32_t getAshmemColorOffset(cb_handle_t* cb) {
+uint32_t getAshmemColorOffset(cb_handle_old_t* cb) {
     uint32_t res = 0;
     if (cb->canBePosted()) res = GOLDFISH_OFFSET_UNIT;
     if (isHidlGralloc) res = GOLDFISH_OFFSET_UNIT * 2;
@@ -114,6 +186,10 @@
     typedef std::map<void*, uint32_t> MemRegionMap;  // base -> refCount
     typedef MemRegionMap::const_iterator mem_region_handle_t;
 
+    gralloc_memregions_t() {
+        pthread_mutex_init(&lock, NULL);
+    }
+
     MemRegionMap ashmemRegions;
     pthread_mutex_t lock;
 };
@@ -121,13 +197,20 @@
 #define INITIAL_DMA_REGION_SIZE 4096
 struct gralloc_dmaregion_t {
     gralloc_dmaregion_t(ExtendedRCEncoderContext *rcEnc)
-      : sz(0), refcount(0), bigbufCount(0) {
+      : sz(INITIAL_DMA_REGION_SIZE), refcount(0), bigbufCount(0) {
+        memset(&goldfish_dma, 0, sizeof(goldfish_dma));
         pthread_mutex_init(&lock, NULL);
-        sz = INITIAL_DMA_REGION_SIZE;
-        goldfish_dma_create_region(sz, &goldfish_dma);
+
+        if (rcEnc->hasDirectMem()) {
+            host_memory_allocator.hostMalloc(&address_space_block, sz);
+        } else if (rcEnc->getDmaVersion() > 0) {
+            goldfish_dma_create_region(sz, &goldfish_dma);
+        }
     }
 
     goldfish_dma_context goldfish_dma;
+    GoldfishAddressSpaceHostMemoryAllocator host_memory_allocator;
+    GoldfishAddressSpaceBlock address_space_block;
     uint32_t sz;
     uint32_t refcount;
     pthread_mutex_t lock;
@@ -139,13 +222,16 @@
 static gralloc_dmaregion_t* s_grdma = NULL;
 
 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);
+    if (!s_memregions) {
+        s_memregions = new gralloc_memregions_t;
+    }
     return s_memregions;
 }
 
+static bool has_DMA_support(const ExtendedRCEncoderContext *rcEnc) {
+    return rcEnc->getDmaVersion() > 0 || rcEnc->hasDirectMem();
+}
+
 static gralloc_dmaregion_t* init_gralloc_dmaregion(ExtendedRCEncoderContext *rcEnc) {
     D("%s: call\n", __func__);
     if (!s_grdma) {
@@ -175,6 +261,15 @@
 // max dma size: 2x 4K rgba8888
 #define MAX_DMA_SIZE 66355200
 
+static bool put_gralloc_region_direct_mem_locked(gralloc_dmaregion_t* grdma, uint32_t /* sz, unused */) {
+    const bool shouldDelete = !grdma->refcount;
+    if (shouldDelete) {
+        grdma->host_memory_allocator.hostFree(&grdma->address_space_block);
+    }
+
+    return shouldDelete;
+}
+
 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--;
@@ -196,20 +291,36 @@
 
     gralloc_dmaregion_t* grdma = init_gralloc_dmaregion(rcEnc);
     pthread_mutex_lock(&grdma->lock);
-    shouldDelete = put_gralloc_region_dma_locked(grdma, sz);
+    if (rcEnc->hasDirectMem()) {
+        shouldDelete = put_gralloc_region_direct_mem_locked(grdma, sz);
+    } else if (rcEnc->getDmaVersion() > 0) {
+        shouldDelete = put_gralloc_region_dma_locked(grdma, sz);
+    } else {
+        shouldDelete = false;
+    }
     pthread_mutex_unlock(&grdma->lock);
 
     return shouldDelete;
 }
 
-static void gralloc_dmaregion_register_ashmem_dma(gralloc_dmaregion_t* grdma, uint32_t new_sz) {
+static void gralloc_dmaregion_register_ashmem_direct_mem_locked(gralloc_dmaregion_t* grdma, uint32_t new_sz) {
+    if (new_sz == grdma->sz) return;
+
+    GoldfishAddressSpaceHostMemoryAllocator* allocator = &grdma->host_memory_allocator;
+    GoldfishAddressSpaceBlock* block = &grdma->address_space_block;
+    allocator->hostFree(block);
+    allocator->hostMalloc(block, new_sz);
+    grdma->sz = new_sz;
+}
+
+static void gralloc_dmaregion_register_ashmem_dma_locked(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.",
-              __func__, sz, MAX_DMA_SIZE);
+              __func__, new_sz, MAX_DMA_SIZE);
             grdma->bigbufCount++;
         } else {
-            D("%s: change sz from %u to %u", __func__, grdma->sz, sz);
+            D("%s: change sz from %u to %u", __func__, grdma->sz, new_sz);
             resize_gralloc_dmaregion_locked(grdma, new_sz);
         }
     }
@@ -224,7 +335,15 @@
     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);
+
+    if (rcEnc->hasDirectMem()) {
+        gralloc_dmaregion_register_ashmem_direct_mem_locked(grdma, new_sz);
+    } else if (rcEnc->getDmaVersion() > 0) {
+        gralloc_dmaregion_register_ashmem_dma_locked(grdma, new_sz);
+    } else {
+        ALOGE("%s: unexpected DMA type", __func__);
+    }
+
     pthread_mutex_unlock(&grdma->lock);
 }
 
@@ -238,7 +357,7 @@
     pthread_mutex_unlock(&memregions->lock);
 }
 
-static bool put_mem_region(ExtendedRCEncoderContext *rcEnc, void* ashmemBase) {
+static bool put_mem_region(ExtendedRCEncoderContext *, void* ashmemBase) {
     D("%s: call for %p", __func__, ashmemBase);
 
     gralloc_memregions_t* memregions = init_gralloc_memregions();
@@ -260,7 +379,8 @@
     return shouldRemove;
 }
 
-static void dump_regions(ExtendedRCEncoderContext *rcEnc) {
+#if DEBUG
+static void dump_regions(ExtendedRCEncoderContext *) {
     gralloc_memregions_t* memregions = init_gralloc_memregions();
     gralloc_memregions_t::mem_region_handle_t curr = memregions->ashmemRegions.begin();
     std::stringstream res;
@@ -269,13 +389,14 @@
     }
     ALOGD("ashmem region dump [\n%s]", res.str().c_str());
 }
+#endif
 
-static void get_ashmem_region(ExtendedRCEncoderContext *rcEnc, cb_handle_t *cb) {
+static void get_ashmem_region(ExtendedRCEncoderContext *rcEnc, cb_handle_old_t *cb) {
 #if DEBUG
     dump_regions(rcEnc);
 #endif
 
-    get_mem_region((void*)cb->ashmemBase);
+    get_mem_region(cb->getBufferPtr());
 
 #if DEBUG
     dump_regions(rcEnc);
@@ -284,49 +405,39 @@
     get_gralloc_region(rcEnc);
 }
 
-static bool put_ashmem_region(ExtendedRCEncoderContext *rcEnc, cb_handle_t *cb) {
+static bool put_ashmem_region(ExtendedRCEncoderContext *rcEnc, cb_handle_old_t *cb) {
 #if DEBUG
     dump_regions(rcEnc);
 #endif
 
-    const bool should_unmap = put_mem_region(rcEnc, (void*)cb->ashmemBase);
+    const bool should_unmap = put_mem_region(rcEnc, cb->getBufferPtr());
 
 #if DEBUG
     dump_regions(rcEnc);
 #endif
 
-    put_gralloc_region(rcEnc, cb->ashmemSize);
+    put_gralloc_region(rcEnc, cb->bufferSize);
 
     return should_unmap;
 }
 
-//
-// Our framebuffer device structure
-//
-struct fb_device_t {
-    framebuffer_device_t  device;
-};
-
-static int map_buffer(cb_handle_t *cb, void **vaddr)
+static int map_buffer(cb_handle_old_t *cb, void **vaddr)
 {
-    if (cb->fd < 0 || cb->ashmemSize <= 0) {
+    if (cb->bufferFd < 0) {
         return -EINVAL;
     }
 
-    int map_flags = MAP_SHARED;
-    if (isHidlGralloc) map_flags |= MAP_ANONYMOUS;
-
-    void *addr = mmap(0, cb->ashmemSize, PROT_READ | PROT_WRITE,
-                      MAP_SHARED, cb->fd, 0);
+    void *addr = mmap(0, cb->bufferSize, PROT_READ | PROT_WRITE,
+                      MAP_SHARED, cb->bufferFd, 0);
     if (addr == MAP_FAILED) {
         ALOGE("%s: failed to map ashmem region!", __FUNCTION__);
         return -errno;
     }
 
-    cb->ashmemBase = intptr_t(addr);
+    cb->setBufferPtr(addr);
     cb->ashmemBasePid = getpid();
     D("%s: %p mapped ashmem base %p size %d\n", __FUNCTION__,
-      cb, cb->ashmemBase, cb->ashmemSize);
+      cb, addr, cb->bufferSize);
 
     *vaddr = addr;
     return 0;
@@ -344,7 +455,7 @@
 #define DEFINE_HOST_CONNECTION \
     HostConnection *hostCon = createOrGetHostConnection(); \
     ExtendedRCEncoderContext *rcEnc = (hostCon ? hostCon->rcEncoder() : NULL); \
-    bool hasVulkan = rcEnc->featureInfo_const()->hasVulkan; \
+    bool hasVulkan = rcEnc->featureInfo_const()->hasVulkan; (void)hasVulkan; \
 
 #define DEFINE_AND_VALIDATE_HOST_CONNECTION \
     HostConnection *hostCon = createOrGetHostConnection(); \
@@ -357,14 +468,14 @@
         ALOGE("gralloc: Failed to get renderControl encoder context\n"); \
         return -EIO; \
     } \
-    bool hasVulkan = rcEnc->featureInfo_const()->hasVulkan; \
+    bool hasVulkan = rcEnc->featureInfo_const()->hasVulkan; (void)hasVulkan;\
 
 #if PLATFORM_SDK_VERSION < 18
 // On older APIs, just define it as a value no one is going to use.
 #define HAL_PIXEL_FORMAT_YCbCr_420_888 0xFFFFFFFF
 #endif
 
-static void updateHostColorBuffer(cb_handle_t* cb,
+static void updateHostColorBuffer(cb_handle_old_t* cb,
                               bool doLocked,
                               char* pixels) {
     D("%s: call. doLocked=%d", __FUNCTION__, doLocked);
@@ -382,41 +493,45 @@
     uint32_t rgbSz = width * height * bpp;
     uint32_t send_buffer_size = rgbSz;
     bool is_rgb_format =
-        cb->frameworkFormat != HAL_PIXEL_FORMAT_YV12 &&
-        cb->frameworkFormat != HAL_PIXEL_FORMAT_YCbCr_420_888;
+        cb->format != HAL_PIXEL_FORMAT_YV12 &&
+        cb->format != HAL_PIXEL_FORMAT_YCbCr_420_888;
 
     std::vector<char> convertedBuf;
-    if ((doLocked && is_rgb_format) ||
-        (!grdma && (doLocked || !is_rgb_format))) {
-        convertedBuf.resize(rgbSz);
-        to_send = &convertedBuf.front();
-        send_buffer_size = rgbSz;
-    }
 
     if (doLocked && is_rgb_format) {
+        convertedBuf.resize(rgbSz);
+        to_send = &convertedBuf.front();
         copy_rgb_buffer_from_unlocked(
                 to_send, pixels,
                 cb->width,
                 width, height, top, left, bpp);
     }
 
-    const bool hasDMA = rcEnc->getDmaVersion() > 0;
+    const bool hasDMA = has_DMA_support(rcEnc);
     if (hasDMA && grdma->bigbufCount) {
         D("%s: there are big buffers alive, use fallback (count %u)", __FUNCTION__,
           grdma->bigbufCount);
     }
 
     if (hasDMA && !grdma->bigbufCount) {
-        if (cb->frameworkFormat == HAL_PIXEL_FORMAT_YV12) {
-            get_yv12_offsets(width, height, NULL, NULL,
-                             &send_buffer_size);
-        }
-        if (cb->frameworkFormat == HAL_PIXEL_FORMAT_YCbCr_420_888) {
-            get_yuv420p_offsets(width, height, NULL, NULL,
-                                &send_buffer_size);
+        switch (cb->format) {
+        case HAL_PIXEL_FORMAT_YV12:
+            get_yv12_offsets(width, height, NULL, NULL, &send_buffer_size);
+            break;
+
+        case HAL_PIXEL_FORMAT_YCbCr_420_888:
+            get_yuv420p_offsets(width, height, NULL, NULL, &send_buffer_size);
+            break;
         }
 
-        rcEnc->bindDmaContext(&grdma->goldfish_dma);
+        if (grdma->address_space_block.guestPtr()) {
+            rcEnc->bindDmaDirectly(grdma->address_space_block.guestPtr(),
+                                   grdma->address_space_block.physAddr());
+        } else if (grdma->goldfish_dma.mapped_addr) {
+            rcEnc->bindDmaContext(&grdma->goldfish_dma);
+        } else {
+            ALOGE("%s: Unexpected DMA", __func__);
+        }
 
         D("%s: call. dma update with sz=%u", __func__, send_buffer_size);
         pthread_mutex_lock(&grdma->lock);
@@ -426,44 +541,75 @@
                 to_send, send_buffer_size);
         pthread_mutex_unlock(&grdma->lock);
     } else {
-        if (cb->frameworkFormat == HAL_PIXEL_FORMAT_YV12) {
+        switch (cb->format) {
+        case HAL_PIXEL_FORMAT_YV12:
+            convertedBuf.resize(rgbSz);
+            to_send = &convertedBuf.front();
+            D("convert yv12 to rgb888 here");
             yv12_to_rgb888(to_send, pixels,
                            width, height, left, top,
                            left + width - 1, top + height - 1);
-        }
-        if (cb->frameworkFormat == HAL_PIXEL_FORMAT_YCbCr_420_888) {
+            break;
+
+        case HAL_PIXEL_FORMAT_YCbCr_420_888:
+            convertedBuf.resize(rgbSz);
+            to_send = &convertedBuf.front();
             yuv420p_to_rgb888(to_send, pixels,
                               width, height, left, top,
                               left + width - 1, top + height - 1);
+            break;
         }
+
         rcEnc->rcUpdateColorBuffer(rcEnc, cb->hostHandle,
                 left, top, width, height,
                 cb->glFormat, cb->glType, to_send);
     }
 }
 
-#ifndef GL_RGBA16F
-#define GL_RGBA16F                        0x881A
-#endif // GL_RGBA16F
-#ifndef GL_HALF_FLOAT
-#define GL_HALF_FLOAT                     0x140B
-#endif // GL_HALF_FLOAT
-#ifndef GL_RGB10_A2
-#define GL_RGB10_A2                       0x8059
-#endif // GL_RGB10_A2
-#ifndef GL_UNSIGNED_INT_2_10_10_10_REV
-#define GL_UNSIGNED_INT_2_10_10_10_REV    0x8368
-#endif // GL_UNSIGNED_INT_2_10_10_10_REV
 //
 // gralloc device functions (alloc interface)
 //
 static void gralloc_dump(struct alloc_device_t* /*dev*/, char* /*buff*/, int /*buff_len*/) {}
 
+static int gralloc_get_buffer_format(const int frameworkFormat, const int usage) {
+    // Pick the right concrete pixel format given the endpoints as encoded in
+    // the usage bits.  Every end-point pair needs explicit listing here.
+#if PLATFORM_SDK_VERSION >= 17
+    if (frameworkFormat == HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED) {
+        // Camera as producer
+        if (usage & GRALLOC_USAGE_HW_CAMERA_WRITE) {
+            if (usage & GRALLOC_USAGE_HW_TEXTURE) {
+                // Camera-to-display is RGBA
+                return HAL_PIXEL_FORMAT_RGBA_8888;
+            } else if (usage & GRALLOC_USAGE_HW_VIDEO_ENCODER) {
+                // Camera-to-encoder is NV21
+                return HAL_PIXEL_FORMAT_YCrCb_420_SP;
+            }
+        }
+
+        ALOGE("gralloc_alloc: Requested auto format selection, "
+              "but no known format for this usage=%x", usage);
+        return -EINVAL;
+    } else if (frameworkFormat == HAL_PIXEL_FORMAT_YCbCr_420_888) {
+        ALOGW("gralloc_alloc: Requested YCbCr_420_888, taking experimental path. "
+              "usage=%x", usage);
+    } else if (frameworkFormat == OMX_COLOR_FormatYUV420Planar &&
+               (usage & GOLDFISH_GRALLOC_USAGE_GPU_DATA_BUFFER)) {
+        ALOGW("gralloc_alloc: Requested OMX_COLOR_FormatYUV420Planar, given "
+              "YCbCr_420_888, taking experimental path. "
+              "usage=%x", usage);
+        return HAL_PIXEL_FORMAT_YCbCr_420_888;
+    }
+#endif // PLATFORM_SDK_VERSION >= 17
+
+    return frameworkFormat;
+}
+
 static int gralloc_alloc(alloc_device_t* dev,
-                         int w, int h, int format, int usage,
+                         int w, int h, const int frameworkFormat, int usage,
                          buffer_handle_t* pHandle, int* pStride)
 {
-    D("gralloc_alloc w=%d h=%d usage=0x%x format=0x%x\n", w, h, usage, format);
+    D("gralloc_alloc w=%d h=%d usage=0x%x frameworkFormat=0x%x\n", w, h, usage, frameworkFormat);
 
     gralloc_device_t *grdev = (gralloc_device_t *)dev;
     if (!grdev || !pHandle || !pStride) {
@@ -472,14 +618,25 @@
         return -EINVAL;
     }
 
+    const int format = gralloc_get_buffer_format(frameworkFormat, usage);
+    if (format < 0) {
+        return format;
+    }
+
     //
     // Note: in screen capture mode, both sw_write and hw_write will be on
     // and this is a valid usage
     //
     bool sw_write = (0 != (usage & GRALLOC_USAGE_SW_WRITE_MASK));
-    bool hw_write = (usage & GRALLOC_USAGE_HW_RENDER);
+    bool hw_write = (usage & GRALLOC_USAGE_HW_RENDER); (void)hw_write;
     bool sw_read = (0 != (usage & GRALLOC_USAGE_SW_READ_MASK));
     const bool hw_texture = usage & GRALLOC_USAGE_HW_TEXTURE;
+    const bool hw_render = usage & GRALLOC_USAGE_HW_RENDER;
+    const bool hw_2d = usage & GRALLOC_USAGE_HW_2D;
+    const bool hw_composer = usage & GRALLOC_USAGE_HW_COMPOSER;
+    const bool hw_fb = usage & GRALLOC_USAGE_HW_FB;
+    const bool rgb888_unsupported_usage =
+        hw_texture || hw_render || hw_2d || hw_composer || hw_fb;
 #if PLATFORM_SDK_VERSION >= 17
     bool hw_cam_write = (usage & GRALLOC_USAGE_HW_CAMERA_WRITE);
     bool hw_cam_read = (usage & GRALLOC_USAGE_HW_CAMERA_READ);
@@ -493,38 +650,8 @@
     bool hw_vid_enc_read = false;
 #endif // PLATFORM_SDK_VERSION
 
-    // Keep around original requested format for later validation
-    int frameworkFormat = format;
-    // Pick the right concrete pixel format given the endpoints as encoded in
-    // the usage bits.  Every end-point pair needs explicit listing here.
-#if PLATFORM_SDK_VERSION >= 17
-    if (format == HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED) {
-        // Camera as producer
-        if (usage & GRALLOC_USAGE_HW_CAMERA_WRITE) {
-            if (usage & GRALLOC_USAGE_HW_TEXTURE) {
-                // Camera-to-display is RGBA
-                format = HAL_PIXEL_FORMAT_RGBA_8888;
-            } else if (usage & GRALLOC_USAGE_HW_VIDEO_ENCODER) {
-                // Camera-to-encoder is NV21
-                format = HAL_PIXEL_FORMAT_YCrCb_420_SP;
-            }
-        }
-
-        if (format == HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED) {
-            ALOGE("gralloc_alloc: Requested auto format selection, "
-                    "but no known format for this usage: %d x %d, usage %x",
-                    w, h, usage);
-            return -EINVAL;
-        }
-    }
-    else if (format == HAL_PIXEL_FORMAT_YCbCr_420_888) {
-        ALOGW("gralloc_alloc: Requested YCbCr_420_888, taking experimental path. "
-                "usage: %d x %d, usage %x",
-                w, h, usage);
-    }
-#endif // PLATFORM_SDK_VERSION >= 17
     bool yuv_format = false;
-
+    bool raw_format = false;
     int ashmem_size = 0;
     int stride = w;
 
@@ -543,8 +670,8 @@
             glType = GL_UNSIGNED_BYTE;
             break;
         case HAL_PIXEL_FORMAT_RGB_888:
-            if (hw_texture) {
-                return -EINVAL;  // we dont support RGB_888 for HW textures
+            if (rgb888_unsupported_usage) {
+                return -EINVAL;  // we dont support RGB_888 for HW usage
             } else {
                 bpp = 3;
                 glFormat = GL_RGB;
@@ -586,6 +713,7 @@
             // Not expecting to actually create any GL surfaces for this
             glFormat = GL_LUMINANCE;
             glType = GL_UNSIGNED_SHORT;
+            raw_format = true;
             break;
 #if PLATFORM_SDK_VERSION >= 17
         case HAL_PIXEL_FORMAT_BLOB:
@@ -611,8 +739,8 @@
             align = 16;
             bpp = 1; // per-channel bpp
             yuv_format = true;
-            // We are going to use RGB888 on the host
-            glFormat = GL_RGB;
+            // We are going to use RGB8888 on the host for Vulkan
+            glFormat = GL_RGBA;
             glType = GL_UNSIGNED_BYTE;
             selectedEmuFrameworkFormat = FRAMEWORK_FORMAT_YV12;
             break;
@@ -639,19 +767,14 @@
     //
     DEFINE_AND_VALIDATE_HOST_CONNECTION;
 #if PLATFORM_SDK_VERSION >= 17
-
-#ifdef GOLDFISH_VULKAN
-
-    bool needHostCb = (((!yuv_format) && (hasVulkan || (frameworkFormat != HAL_PIXEL_FORMAT_BLOB))) ||
-#else
     bool needHostCb = ((!yuv_format && frameworkFormat != HAL_PIXEL_FORMAT_BLOB) ||
-#endif // !GOLDFISH_VULKAN
-
+                      usage & GOLDFISH_GRALLOC_USAGE_GPU_DATA_BUFFER ||
 #else
     bool needHostCb = (!yuv_format ||
 #endif // !(PLATFORM_SDK_VERSION >= 17)
                        frameworkFormat == HAL_PIXEL_FORMAT_YV12 ||
                        frameworkFormat == HAL_PIXEL_FORMAT_YCbCr_420_888) &&
+                       !raw_format &&
 #if PLATFORM_SDK_VERSION >= 15
                       (usage & (GRALLOC_USAGE_HW_TEXTURE | GRALLOC_USAGE_HW_RENDER |
                                 GRALLOC_USAGE_HW_2D | GRALLOC_USAGE_HW_COMPOSER |
@@ -717,9 +840,9 @@
         }
     }
 
-    cb_handle_t *cb = new cb_handle_t(fd, ashmem_size, usage,
-                                      w, h, frameworkFormat, format,
-                                      glFormat, glType, selectedEmuFrameworkFormat);
+    cb_handle_old_t *cb = new cb_handle_old_t(fd, ashmem_size, usage,
+                                              w, h, format,
+                                              glFormat, glType);
 
     if (ashmem_size > 0) {
         //
@@ -732,9 +855,10 @@
             delete cb;
             return err;
         }
-        cb->setFd(fd);
     }
 
+    const bool hasDMA = has_DMA_support(rcEnc);
+
     if (needHostCb) {
         if (hostCon && rcEnc) {
             GLenum allocFormat = glFormat;
@@ -747,10 +871,9 @@
                 allocFormat = GL_RGB;
             }
 
-            gralloc_dmaregion_t* grdma = init_gralloc_dmaregion(rcEnc);
             hostCon->lock();
-            if (rcEnc->getDmaVersion() > 0) {
-                cb->hostHandle = rcEnc->rcCreateColorBufferDMA(rcEnc, w, h, allocFormat, cb->emuFrameworkFormat);
+            if (hasDMA) {
+                cb->hostHandle = rcEnc->rcCreateColorBufferDMA(rcEnc, w, h, allocFormat, selectedEmuFrameworkFormat);
             } else {
                 cb->hostHandle = rcEnc->rcCreateColorBuffer(rcEnc, w, h, allocFormat);
             }
@@ -761,7 +884,7 @@
             // Could not create colorbuffer on host !!!
             close(fd);
             delete cb;
-            ALOGD("%s: failed to create host cb! -EIO", __FUNCTION__);
+            ALOGE("%s: failed to create host cb! -EIO", __FUNCTION__);
             return -EIO;
         } else {
             QEMU_PIPE_HANDLE refcountPipeFd = qemu_pipe_open("refcount");
@@ -795,7 +918,7 @@
     }
 
     hostCon->lock();
-    if (rcEnc->getDmaVersion() > 0) {
+    if (hasDMA) {
         get_gralloc_region(rcEnc);  // map_buffer(cb, ...) refers here
     }
     hostCon->unlock();
@@ -808,20 +931,20 @@
 {
     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");
+    const cb_handle_old_t *cb = cb_handle_old_t::from(handle);
+    if (!cb) {
+        ERR("gralloc_free: invalid handle %p", handle);
         return -EINVAL;
     }
 
     D("%s: for buf %p ptr %p size %d\n",
-      __FUNCTION__, handle, cb->ashmemBase, cb->ashmemSize);
+      __FUNCTION__, handle, cb->getBufferPtr(), cb->bufferSize);
 
     if (cb->hostHandle && !cb->hasRefcountPipe()) {
         int32_t openCount = 1;
         int32_t* openCountPtr = &openCount;
 
-        if (isHidlGralloc && cb->ashmemBase) {
+        if (isHidlGralloc && cb->getBufferPtr()) {
             openCountPtr = getOpenCountPtr(cb);
         }
 
@@ -839,17 +962,17 @@
     //
     // detach and unmap ashmem area if present
     //
-    if (cb->fd > 0) {
-        if (cb->ashmemSize > 0 && cb->ashmemBase) {
-            D("%s: unmapped %p", __FUNCTION__, cb->ashmemBase);
-            munmap((void *)cb->ashmemBase, cb->ashmemSize);
-            put_gralloc_region(rcEnc, cb->ashmemSize);
+    if (cb->bufferFd > 0) {
+        if (cb->bufferSize > 0 && cb->getBufferPtr()) {
+            D("%s: unmapped %p", __FUNCTION__, cb->getBufferPtr());
+            munmap(cb->getBufferPtr(), cb->bufferSize);
+            put_gralloc_region(rcEnc, cb->bufferSize);
         }
-        close(cb->fd);
+        close(cb->bufferFd);
     }
 
-    if(qemu_pipe_valid(cb->refcount_pipe_fd)) {
-        qemu_pipe_close(cb->refcount_pipe_fd);
+    if(qemu_pipe_valid(cb->hostHandleRefCountFd)) {
+        qemu_pipe_close(cb->hostHandleRefCountFd);
     }
     D("%s: done", __FUNCTION__);
     // remove it from the allocated list
@@ -879,100 +1002,6 @@
     return 0;
 }
 
-static int fb_compositionComplete(struct framebuffer_device_t* dev)
-{
-    (void)dev;
-
-    return 0;
-}
-
-//
-// Framebuffer device functions
-//
-static int fb_post(struct framebuffer_device_t* dev, buffer_handle_t buffer)
-{
-    fb_device_t *fbdev = (fb_device_t *)dev;
-    cb_handle_t *cb = (cb_handle_t *)buffer;
-
-    if (!fbdev || !cb_handle_t::validate(cb) || !cb->canBePosted()) {
-        return -EINVAL;
-    }
-
-    // Make sure we have host connection
-    DEFINE_AND_VALIDATE_HOST_CONNECTION;
-
-    // increment the post count of the buffer
-    intptr_t *postCountPtr = (intptr_t *)cb->ashmemBase;
-    if (!postCountPtr) {
-        // This should not happen
-        return -EINVAL;
-    }
-    (*postCountPtr)++;
-
-    // send post request to host
-    hostCon->lock();
-    rcEnc->rcFBPost(rcEnc, cb->hostHandle);
-    hostCon->flush();
-    hostCon->unlock();
-
-    return 0;
-}
-
-static int fb_setUpdateRect(struct framebuffer_device_t* dev,
-        int l, int t, int w, int h)
-{
-    fb_device_t *fbdev = (fb_device_t *)dev;
-
-    (void)l;
-    (void)t;
-    (void)w;
-    (void)h;
-
-    if (!fbdev) {
-        return -EINVAL;
-    }
-
-    // Make sure we have host connection
-    DEFINE_AND_VALIDATE_HOST_CONNECTION;
-
-    // send request to host
-    // TODO: XXX - should be implemented
-    //rcEnc->rc_XXX
-
-    return 0;
-}
-
-static int fb_setSwapInterval(struct framebuffer_device_t* dev,
-            int interval)
-{
-    fb_device_t *fbdev = (fb_device_t *)dev;
-
-    if (!fbdev) {
-        return -EINVAL;
-    }
-
-    // Make sure we have host connection
-    DEFINE_AND_VALIDATE_HOST_CONNECTION;
-
-    // send request to host
-    hostCon->lock();
-    rcEnc->rcFBSetSwapInterval(rcEnc, interval);
-    hostCon->flush();
-    hostCon->unlock();
-
-    return 0;
-}
-
-static int fb_close(struct hw_device_t *dev)
-{
-    fb_device_t *fbdev = (fb_device_t *)dev;
-
-    free(fbdev);
-
-    return 0;
-}
-
-
 //
 // gralloc module functions - refcount + locking interface
 //
@@ -988,15 +1017,18 @@
     }
 
     private_module_t *gr = (private_module_t *)module;
-    cb_handle_t *cb = (cb_handle_t *)handle;
+    if (!gr) {
+        return -EINVAL;
+    }
 
-    if (!gr || !cb_handle_t::validate(cb)) {
+    cb_handle_old_t *cb = cb_handle_old_t::from_unconst(handle);
+    if (!cb) {
         ERR("gralloc_register_buffer(%p): invalid buffer", cb);
         return -EINVAL;
     }
 
-    D("gralloc_register_buffer(%p) w %d h %d format 0x%x framworkFormat 0x%x",
-        handle, cb->width, cb->height, cb->format, cb->frameworkFormat);
+    D("gralloc_register_buffer(%p) w %d h %d format 0x%x",
+        handle, cb->width, cb->height, cb->format);
 
     if (cb->hostHandle != 0 && !cb->hasRefcountPipe()) {
         D("Opening host ColorBuffer 0x%x\n", cb->hostHandle);
@@ -1009,7 +1041,7 @@
     // if the color buffer has ashmem region and it is not mapped in this
     // process map it now.
     //
-    if (cb->ashmemSize > 0 && cb->mappedPid != getpid()) {
+    if (cb->bufferSize > 0 && cb->mappedPid != getpid()) {
         void *vaddr;
         int err = map_buffer(cb, &vaddr);
         if (err) {
@@ -1022,16 +1054,9 @@
             int32_t* openCountPtr = getOpenCountPtr(cb);
             if (!*openCountPtr) *openCountPtr = 1;
         }
-
-        hostCon->lock();
-        if (rcEnc->getDmaVersion() > 0) {
-            gralloc_dmaregion_register_ashmem(rcEnc, cb->ashmemSize);
-        }
-        hostCon->unlock();
-
     }
 
-    if (cb->ashmemSize > 0) {
+    if (cb->bufferSize > 0) {
         get_ashmem_region(rcEnc, cb);
     }
 
@@ -1048,9 +1073,12 @@
     }
 
     private_module_t *gr = (private_module_t *)module;
-    cb_handle_t *cb = (cb_handle_t *)handle;
+    if (!gr) {
+        return -EINVAL;
+    }
 
-    if (!gr || !cb_handle_t::validate(cb)) {
+    cb_handle_old_t *cb = cb_handle_old_t::from_unconst(handle);
+    if (!cb) {
         ERR("gralloc_unregister_buffer(%p): invalid buffer", cb);
         return -EINVAL;
     }
@@ -1064,7 +1092,7 @@
         if (isHidlGralloc) {
             // Queue up another rcCloseColorBuffer if applicable.
             // invariant: have ashmem.
-            if (cb->ashmemSize > 0 && cb->mappedPid == getpid()) {
+            if (cb->bufferSize > 0 && cb->mappedPid == getpid()) {
                 int32_t* openCountPtr = getOpenCountPtr(cb);
                 if (*openCountPtr == -1) {
                     D("%s: revenge of the rcCloseColorBuffer!", __func__);
@@ -1080,17 +1108,16 @@
     // unmap ashmem region if it was previously mapped in this process
     // (through register_buffer)
     //
-    if (cb->ashmemSize > 0 && cb->mappedPid == getpid()) {
+    if (cb->bufferSize > 0 && cb->mappedPid == getpid()) {
         const bool should_unmap = put_ashmem_region(rcEnc, cb);
         if (!should_unmap) goto done;
 
-        void *vaddr;
-        int err = munmap((void *)cb->ashmemBase, cb->ashmemSize);
+        int err = munmap(cb->getBufferPtr(), cb->bufferSize);
         if (err) {
             ERR("gralloc_unregister_buffer(%p): unmap failed", cb);
             return -EINVAL;
         }
-        cb->ashmemBase = 0;
+        cb->bufferSize = 0;
         cb->mappedPid = 0;
         D("%s: Unregister buffer previous mapped to pid %d", __FUNCTION__, getpid());
     }
@@ -1110,9 +1137,12 @@
     }
 
     private_module_t *gr = (private_module_t *)module;
-    cb_handle_t *cb = (cb_handle_t *)handle;
+    if (!gr) {
+        return -EINVAL;
+    }
 
-    if (!gr || !cb_handle_t::validate(cb)) {
+    cb_handle_old_t *cb = cb_handle_old_t::from_unconst(handle);
+    if (!cb) {
         ALOGE("gralloc_lock bad handle\n");
         return -EINVAL;
     }
@@ -1164,7 +1194,6 @@
         //return -EINVAL;
     }
 
-    intptr_t postCount = 0;
     void *cpu_addr = NULL;
 
     //
@@ -1173,11 +1202,11 @@
     if (cb->canBePosted() || sw_read || sw_write ||
             hw_cam_write || hw_cam_read ||
             hw_vid_enc_read) {
-        if (cb->ashmemBasePid != getpid() || !cb->ashmemBase) {
+        if (cb->ashmemBasePid != getpid() || !cb->getBufferPtr()) {
             return -EACCES;
         }
 
-        cpu_addr = (void *)(cb->ashmemBase + getAshmemColorOffset(cb));
+        cpu_addr = (void *)((char*)cb->getBufferPtr() + getAshmemColorOffset(cb));
     }
 
     if (cb->hostHandle) {
@@ -1189,40 +1218,60 @@
         // flush color buffer write cache on host and get its sync status.
         //
         int hostSyncStatus = rcEnc->rcColorBufferCacheFlush(rcEnc, cb->hostHandle,
-                                                            postCount,
+                                                            0,
                                                             sw_read);
         if (hostSyncStatus < 0) {
             // host failed the color buffer sync - probably since it was already
             // locked for write access. fail the lock.
-            ALOGE("gralloc_lock cacheFlush failed postCount=%d sw_read=%d\n",
-                 (int)postCount, sw_read);
+            ALOGE("gralloc_lock cacheFlush failed sw_read=%d\n", sw_read);
             return -EBUSY;
         }
 
         // camera delivers bits to the buffer directly and does not require
-        // an explicit read, it also writes in YUV_420 (interleaved)
+        // an explicit read.
         if (sw_read & !(usage & GRALLOC_USAGE_HW_CAMERA_MASK)) {
-            void* rgb_addr = cpu_addr;
-            char* tmpBuf = 0;
-            if (cb->frameworkFormat == HAL_PIXEL_FORMAT_YV12 ||
-                cb->frameworkFormat == HAL_PIXEL_FORMAT_YCbCr_420_888) {
-                // We are using RGB888
-                tmpBuf = new char[cb->width * cb->height * 3];
-                rgb_addr = tmpBuf;
-            }
             D("gralloc_lock read back color buffer %d %d ashmem base %p sz %d\n",
               cb->width, cb->height, cb->ashmemBase, cb->ashmemSize);
-            rcEnc->rcReadColorBuffer(rcEnc, cb->hostHandle,
-                    0, 0, cb->width, cb->height, cb->glFormat, cb->glType, rgb_addr);
-            if (tmpBuf) {
-                if (cb->frameworkFormat == HAL_PIXEL_FORMAT_YV12) {
-                    rgb888_to_yv12((char*)cpu_addr, tmpBuf, cb->width, cb->height, l, t, l+w-1, t+h-1);
-                } else if (cb->frameworkFormat == HAL_PIXEL_FORMAT_YCbCr_420_888) {
-                    rgb888_to_yuv420p((char*)cpu_addr, tmpBuf, cb->width, cb->height, l, t, l+w-1, t+h-1);
+            void* rgb_addr = cpu_addr;
+            char* tmpBuf = 0;
+            if (cb->format == HAL_PIXEL_FORMAT_YV12 ||
+                cb->format == HAL_PIXEL_FORMAT_YCbCr_420_888) {
+                if (rcEnc->hasYUVCache()) {
+                    uint32_t buffer_size;
+                    if (cb->format == HAL_PIXEL_FORMAT_YV12) {
+                       get_yv12_offsets(cb->width, cb->height, NULL, NULL,
+                                        &buffer_size);
+                    } else {
+                       get_yuv420p_offsets(cb->width, cb->height, NULL, NULL,
+                                           &buffer_size);
+                    }
+                    D("read YUV copy from host");
+                    rcEnc->rcReadColorBufferYUV(rcEnc, cb->hostHandle,
+                                            0, 0, cb->width, cb->height,
+                                            rgb_addr, buffer_size);
+                } else {
+                    // We are using RGB888
+                    tmpBuf = new char[cb->width * cb->height * 3];
+                    rcEnc->rcReadColorBuffer(rcEnc, cb->hostHandle,
+                                              0, 0, cb->width, cb->height, cb->glFormat, cb->glType, tmpBuf);
+                    if (cb->format == HAL_PIXEL_FORMAT_YV12) {
+                        D("convert rgb888 to yv12 here");
+                        rgb888_to_yv12((char*)cpu_addr, tmpBuf, cb->width, cb->height, l, t, l+w-1, t+h-1);
+                    } else if (cb->format == HAL_PIXEL_FORMAT_YCbCr_420_888) {
+                        D("convert rgb888 to yuv420p here");
+                        rgb888_to_yuv420p((char*)cpu_addr, tmpBuf, cb->width, cb->height, l, t, l+w-1, t+h-1);
+                    }
+                    delete [] tmpBuf;
                 }
-                delete [] tmpBuf;
+            } else {
+                rcEnc->rcReadColorBuffer(rcEnc, cb->hostHandle,
+                        0, 0, cb->width, cb->height, cb->glFormat, cb->glType, rgb_addr);
             }
         }
+
+        if (has_DMA_support(rcEnc)) {
+            gralloc_dmaregion_register_ashmem(rcEnc, cb->bufferSize);
+        }
         hostCon->unlock();
     }
 
@@ -1257,10 +1306,13 @@
     }
 
     private_module_t *gr = (private_module_t *)module;
-    cb_handle_t *cb = (cb_handle_t *)handle;
+    if (!gr) {
+        return -EINVAL;
+    }
 
-    if (!gr || !cb_handle_t::validate(cb)) {
-        ALOGD("%s: invalid gr or cb handle. -EINVAL", __FUNCTION__);
+    cb_handle_old_t *cb = cb_handle_old_t::from_unconst(handle);
+    if (!cb) {
+        ALOGD("%s: invalid cb handle. -EINVAL", __FUNCTION__);
         return -EINVAL;
     }
 
@@ -1274,14 +1326,13 @@
         DEFINE_AND_VALIDATE_HOST_CONNECTION;
         hostCon->lock();
 
-        void *cpu_addr = (void *)(cb->ashmemBase + getAshmemColorOffset(cb));
+        char *cpu_addr = (char*)cb->getBufferPtr() + getAshmemColorOffset(cb);
 
-        char* rgb_addr = (char *)cpu_addr;
         if (cb->lockedWidth < cb->width || cb->lockedHeight < cb->height) {
-            updateHostColorBuffer(cb, true, rgb_addr);
+            updateHostColorBuffer(cb, true, cpu_addr);
         }
         else {
-            updateHostColorBuffer(cb, false, rgb_addr);
+            updateHostColorBuffer(cb, false, cpu_addr);
         }
 
         hostCon->unlock();
@@ -1310,18 +1361,22 @@
     }
 
     private_module_t *gr = (private_module_t *)module;
-    cb_handle_t *cb = (cb_handle_t *)handle;
-    if (!gr || !cb_handle_t::validate(cb)) {
+    if (!gr) {
+        return -EINVAL;
+    }
+
+    cb_handle_old_t *cb = cb_handle_old_t::from_unconst(handle);
+    if (!cb) {
         ALOGE("%s: bad colorbuffer handle. -EINVAL", __FUNCTION__);
         return -EINVAL;
     }
 
-    if (cb->frameworkFormat != HAL_PIXEL_FORMAT_YV12 &&
-        cb->frameworkFormat != HAL_PIXEL_FORMAT_YCbCr_420_888) {
+    if (cb->format != HAL_PIXEL_FORMAT_YV12 &&
+        cb->format != HAL_PIXEL_FORMAT_YCbCr_420_888) {
         ALOGE("gralloc_lock_ycbcr can only be used with "
                 "HAL_PIXEL_FORMAT_YCbCr_420_888 or HAL_PIXEL_FORMAT_YV12, got %x instead. "
                 "-EINVAL",
-                cb->frameworkFormat);
+                cb->format);
         return -EINVAL;
     }
 
@@ -1365,21 +1420,12 @@
             cStep = 1;
             break;
         case HAL_PIXEL_FORMAT_YCbCr_420_888:
-            if (usage & GRALLOC_USAGE_HW_CAMERA_MASK) {
-                yStride = cb->width;
-                cStride = cb->width;
-                yOffset = 0;
-                vOffset = yStride * cb->height;
-                uOffset = vOffset + 1;
-                cStep = 2;
-            } else {
-                yStride = cb->width;
-                cStride = yStride / 2;
-                yOffset = 0;
-                uOffset = cb->height * yStride;
-                vOffset = uOffset + cStride * cb->height / 2;
-                cStep = 1;
-            }
+            yStride = cb->width;
+            cStride = yStride / 2;
+            yOffset = 0;
+            uOffset = cb->height * yStride;
+            vOffset = uOffset + cStride * cb->height / 2;
+            cStep = 1;
             break;
         default:
             ALOGE("gralloc_lock_ycbcr unexpected internal format %x",
@@ -1452,67 +1498,6 @@
         *device = &dev->device.common;
         status = 0;
     }
-    else if (!strcmp(name, GRALLOC_HARDWARE_FB0)) {
-
-        // return error if connection with host can not be established
-        DEFINE_AND_VALIDATE_HOST_CONNECTION;
-        hostCon->lock();
-
-        //
-        // Query the host for Framebuffer attributes
-        //
-        D("gralloc: query Frabuffer attribs\n");
-        EGLint width = rcEnc->rcGetFBParam(rcEnc, FB_WIDTH);
-        D("gralloc: width=%d\n", width);
-        EGLint height = rcEnc->rcGetFBParam(rcEnc, FB_HEIGHT);
-        D("gralloc: height=%d\n", height);
-        EGLint xdpi = rcEnc->rcGetFBParam(rcEnc, FB_XDPI);
-        D("gralloc: xdpi=%d\n", xdpi);
-        EGLint ydpi = rcEnc->rcGetFBParam(rcEnc, FB_YDPI);
-        D("gralloc: ydpi=%d\n", ydpi);
-        EGLint fps = rcEnc->rcGetFBParam(rcEnc, FB_FPS);
-        D("gralloc: fps=%d\n", fps);
-        EGLint min_si = rcEnc->rcGetFBParam(rcEnc, FB_MIN_SWAP_INTERVAL);
-        D("gralloc: min_swap=%d\n", min_si);
-        EGLint max_si = rcEnc->rcGetFBParam(rcEnc, FB_MAX_SWAP_INTERVAL);
-        D("gralloc: max_swap=%d\n", max_si);
-        hostCon->unlock();
-
-        //
-        // Allocate memory for the framebuffer device
-        //
-        fb_device_t *dev;
-        dev = (fb_device_t*)malloc(sizeof(fb_device_t));
-        if (NULL == dev) {
-            return -ENOMEM;
-        }
-        memset(dev, 0, sizeof(fb_device_t));
-
-        // Initialize our device structure
-        //
-        dev->device.common.tag = HARDWARE_DEVICE_TAG;
-        dev->device.common.version = 0;
-        dev->device.common.module = const_cast<hw_module_t*>(module);
-        dev->device.common.close = fb_close;
-        dev->device.setSwapInterval = fb_setSwapInterval;
-        dev->device.post            = fb_post;
-        dev->device.setUpdateRect   = 0; //fb_setUpdateRect;
-        dev->device.compositionComplete = fb_compositionComplete; //XXX: this is a dummy
-
-        const_cast<uint32_t&>(dev->device.flags) = 0;
-        const_cast<uint32_t&>(dev->device.width) = width;
-        const_cast<uint32_t&>(dev->device.height) = height;
-        const_cast<int&>(dev->device.stride) = width;
-        const_cast<int&>(dev->device.format) = HAL_PIXEL_FORMAT_RGBA_8888;
-        const_cast<float&>(dev->device.xdpi) = xdpi;
-        const_cast<float&>(dev->device.ydpi) = ydpi;
-        const_cast<float&>(dev->device.fps) = fps;
-        const_cast<int&>(dev->device.minSwapInterval) = min_si;
-        const_cast<int&>(dev->device.maxSwapInterval) = max_si;
-        *device = &dev->device.common;
-
-        status = 0;
-    }
 
     return status;
 }
@@ -1521,7 +1506,7 @@
 // define the HMI symbol - our module interface
 //
 static struct hw_module_methods_t gralloc_module_methods = {
-        open: gralloc_device_open
+    .open = gralloc_device_open,
 };
 
 struct private_module_t HAL_MODULE_INFO_SYM = {
@@ -1550,13 +1535,13 @@
         lock: gralloc_lock,
         unlock: gralloc_unlock,
         perform: NULL,
-#if PLATFORM_SDK_VERSION >= 28 // In Q, we want to specify these, but SDK version is not 29 yet. do not merge this to P
-        validateBufferSize: NULL,
-        getTransportSize: NULL,
-#endif // PLATFORM_VERSION > 28
 #if PLATFORM_SDK_VERSION >= 18
         lock_ycbcr: gralloc_lock_ycbcr,
 #endif // PLATFORM_SDK_VERSION >= 18
+#if PLATFORM_SDK_VERSION >= 29 // For Q and later
+        getTransportSize: NULL,
+        validateBufferSize: NULL,
+#endif // PLATFORM_SDK_VERSION >= 29
     }
 };
 
@@ -1585,13 +1570,39 @@
     char  prop[PROPERTY_VALUE_MAX];
     void* module;
 
+    // cuttlefish case: no fallback (if we use sw rendering,
+    // we are not using this lib anyway (would use minigbm))
+    property_get("ro.boot.hardware", prop, "");
+
+    bool isValid = prop[0] != '\0';
+
+    if (isValid && !strcmp(prop, "cutf_cvm")) {
+        return;
+    }
+
     // qemu.gles=0 -> no GLES 2.x support (only 1.x through software).
     // qemu.gles=1 -> host-side GPU emulation through EmuGL
     // qemu.gles=2 -> guest-side GPU emulation.
-    property_get("ro.kernel.qemu.gles", prop, "0");
-    if (atoi(prop) == 1) {
-        return;
+    property_get("ro.kernel.qemu.gles", prop, "999");
+
+    bool useFallback = false;
+    switch (atoi(prop)) {
+        case 0:
+            useFallback = true;
+            break;
+        case 1:
+            useFallback = false;
+            break;
+        case 2:
+            useFallback = true;
+            break;
+        default:
+            useFallback = false;
+            break;
     }
+
+    if (!useFallback) return;
+
     ALOGD("Emulator without host-side GPU emulation detected. "
           "Loading gralloc.default.so from %s...",
           kGrallocDefaultVendorPath);
diff --git a/system/hals/Android.mk b/system/hals/Android.mk
new file mode 100644
index 0000000..b762a78
--- /dev/null
+++ b/system/hals/Android.mk
@@ -0,0 +1,74 @@
+#
+# Copyright 2015 The Android Open-Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := android.hardware.graphics.allocator@3.0-service
+LOCAL_MODULE_RELATIVE_PATH := hw
+LOCAL_VENDOR_MODULE := true
+LOCAL_SRC_FILES := allocator3.cpp
+LOCAL_INIT_RC := android.hardware.graphics.allocator@3.0-service.rc
+
+LOCAL_SHARED_LIBRARIES += \
+    android.hardware.graphics.allocator@3.0 \
+    android.hardware.graphics.mapper@3.0 \
+    libOpenglSystemCommon \
+    libOpenglCodecCommon$(GOLDFISH_OPENGL_LIB_SUFFIX) \
+    libbase \
+    libcutils \
+    libhidlbase \
+    liblog \
+    libutils
+
+LOCAL_C_INCLUDES += \
+    device/generic/goldfish-opengl/system/include \
+    device/generic/goldfish-opengl/system/OpenglSystemCommon \
+    device/generic/goldfish-opengl/shared/OpenglCodecCommon \
+    device/generic/goldfish-opengl/host/include/libOpenglRender \
+    device/generic/goldfish-opengl/system/renderControl_enc \
+
+include $(BUILD_EXECUTABLE)
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := android.hardware.graphics.mapper@3.0-impl-ranchu
+LOCAL_MODULE_RELATIVE_PATH := hw
+LOCAL_VENDOR_MODULE := true
+LOCAL_SRC_FILES := mapper3.cpp
+
+#     android.hardware.graphics.allocator@3.0 \
+
+LOCAL_SHARED_LIBRARIES += \
+    android.hardware.graphics.mapper@3.0 \
+    libOpenglSystemCommon \
+    libOpenglCodecCommon$(GOLDFISH_OPENGL_LIB_SUFFIX) \
+    libbase \
+    libcutils \
+    libhidlbase \
+    liblog \
+    libutils \
+    libsync
+
+LOCAL_C_INCLUDES += \
+    device/generic/goldfish-opengl/system/include \
+    device/generic/goldfish-opengl/system/OpenglSystemCommon \
+    device/generic/goldfish-opengl/shared/OpenglCodecCommon \
+    device/generic/goldfish-opengl/host/include/libOpenglRender \
+    device/generic/goldfish-opengl/system/renderControl_enc \
+
+include $(BUILD_SHARED_LIBRARY)
+
diff --git a/system/hals/allocator3.cpp b/system/hals/allocator3.cpp
new file mode 100644
index 0000000..63d79ef
--- /dev/null
+++ b/system/hals/allocator3.cpp
@@ -0,0 +1,433 @@
+/*
+* Copyright (C) 2020 The Android Open Source Project
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+#include <android/hardware/graphics/allocator/3.0/IAllocator.h>
+#include <android/hardware/graphics/mapper/3.0/IMapper.h>
+#include <hidl/LegacySupport.h>
+
+#include "glUtils.h"
+#include "cb_handle_30.h"
+#include "host_connection_session.h"
+#include "types.h"
+#include "debug.h"
+
+#define OMX_COLOR_FormatYUV420Planar 19
+
+using ::android::hardware::hidl_handle;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::hidl_bitfield;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+
+using ::android::hardware::graphics::common::V1_2::PixelFormat;
+using ::android::hardware::graphics::common::V1_0::BufferUsage;
+
+namespace AllocatorV3 = ::android::hardware::graphics::allocator::V3_0;
+namespace MapperV3 = ::android::hardware::graphics::mapper::V3_0;
+
+using IAllocator3 = AllocatorV3::IAllocator;
+using IMapper3 = MapperV3::IMapper;
+using Error3 = MapperV3::Error;
+using BufferDescriptorInfo = IMapper3::BufferDescriptorInfo;
+
+class GoldfishAllocator : public IAllocator3 {
+public:
+    GoldfishAllocator() : m_hostConn(HostConnection::createUnique()) {}
+
+    Return<void> dumpDebugInfo(dumpDebugInfo_cb hidl_cb) {
+        hidl_cb("GoldfishAllocator::dumpDebugInfo is not implemented");
+        return {};
+    }
+
+    Return<void> allocate(const hidl_vec<uint32_t>& rawDescriptor,
+                          uint32_t count,
+                          allocate_cb hidl_cb) {
+        uint32_t stride = 0;
+        std::vector<cb_handle_30_t*> cbs;
+        cbs.reserve(count);
+
+        const Error3 e = allocateImpl(rawDescriptor, count, &stride, &cbs);
+        if (e == Error3::NONE) {
+            hidl_vec<hidl_handle> handles(cbs.cbegin(), cbs.cend());
+            hidl_cb(Error3::NONE, stride, handles);
+        } else {
+            hidl_cb(e, 0, {});
+        }
+
+        for (cb_handle_30_t* cb : cbs) {
+            freeCb(std::unique_ptr<cb_handle_30_t>(cb));
+        }
+
+        return {};
+    }
+
+private:
+    // this function should be in sync with GoldfishMapper::isSupportedImpl
+    Error3 allocateImpl(const hidl_vec<uint32_t>& rawDescriptor,
+                        uint32_t count,
+                        uint32_t* pStride,
+                        std::vector<cb_handle_30_t*>* cbs) {
+        BufferDescriptorInfo descriptor;
+        if (!decodeBufferDescriptorInfo(rawDescriptor, &descriptor)) {
+            RETURN_ERROR(Error3::BAD_DESCRIPTOR);
+        }
+
+        if (!descriptor.width) { RETURN_ERROR(Error3::UNSUPPORTED); }
+        if (!descriptor.height) { RETURN_ERROR(Error3::UNSUPPORTED); }
+        if (descriptor.layerCount != 1) { RETURN_ERROR(Error3::UNSUPPORTED); }
+
+        const uint32_t usage = descriptor.usage;
+        const bool usageSwWrite = usage & BufferUsage::CPU_WRITE_MASK;
+        const bool usageSwRead = usage & BufferUsage::CPU_READ_MASK;
+        const bool usageHwCamWrite = usage & BufferUsage::CAMERA_OUTPUT;
+        const bool usageHwCamRead = usage & BufferUsage::CAMERA_INPUT;
+
+        int bpp = 1;
+        int glFormat = 0;
+        int glType = 0;
+        int align = 1;
+        bool yuv_format = false;
+        EmulatorFrameworkFormat emulatorFrameworkFormat =
+            EmulatorFrameworkFormat::GL_COMPATIBLE;
+
+        PixelFormat format;
+        Error3 e = getBufferFormat(descriptor.format, usage, &format);
+        if (e != Error3::NONE) {
+            ALOGE("%s:%d Unsupported format: frameworkFormat=%d, usage=%x",
+                  __func__, __LINE__, descriptor.format, usage);
+            return e;
+        }
+
+        switch (format) {
+        case PixelFormat::RGBA_8888:
+        case PixelFormat::RGBX_8888:
+        case PixelFormat::BGRA_8888:
+            bpp = 4;
+            glFormat = GL_RGBA;
+            glType = GL_UNSIGNED_BYTE;
+            break;
+
+        case PixelFormat::RGB_888:
+            if (usage & (BufferUsage::GPU_TEXTURE |
+                         BufferUsage::GPU_RENDER_TARGET |
+                         BufferUsage::COMPOSER_OVERLAY |
+                         BufferUsage::COMPOSER_CLIENT_TARGET)) {
+                RETURN_ERROR(Error3::UNSUPPORTED);
+            } else {
+                bpp = 3;
+                glFormat = GL_RGB;
+                glType = GL_UNSIGNED_BYTE;
+            }
+            break;
+
+        case PixelFormat::RGB_565:
+            bpp = 2;
+            glFormat = GL_RGB565;
+            glType = GL_UNSIGNED_SHORT_5_6_5;
+            break;
+
+        case PixelFormat::RGBA_FP16:
+            bpp = 8;
+            glFormat = GL_RGBA16F;
+            glType = GL_HALF_FLOAT;
+            break;
+
+        case PixelFormat::RGBA_1010102:
+            bpp = 4;
+            glFormat = GL_RGB10_A2;
+            glType = GL_UNSIGNED_INT_2_10_10_10_REV;
+            break;
+
+        case PixelFormat::RAW16:
+        case PixelFormat::Y16:
+            bpp = 2;
+            align = 16 * bpp;
+            if (!((usageSwRead || usageHwCamRead) && (usageSwWrite || usageHwCamWrite))) {
+                // Raw sensor data or Y16 only goes between camera and CPU
+                RETURN_ERROR(Error3::UNSUPPORTED);
+            }
+            // Not expecting to actually create any GL surfaces for this
+            glFormat = GL_LUMINANCE;
+            glType = GL_UNSIGNED_SHORT;
+            break;
+
+        case PixelFormat::BLOB:
+            if (!usageSwRead) {
+                // Blob data cannot be used by HW other than camera emulator
+                // But there is a CTS test trying to have access to it
+                // BUG: https://buganizer.corp.google.com/issues/37719518
+                RETURN_ERROR(Error3::UNSUPPORTED);
+            }
+            // Not expecting to actually create any GL surfaces for this
+            glFormat = GL_LUMINANCE;
+            glType = GL_UNSIGNED_BYTE;
+            break;
+
+        case PixelFormat::YCRCB_420_SP:
+            yuv_format = true;
+            // Not expecting to actually create any GL surfaces for this
+            break;
+
+        case PixelFormat::YV12:
+            align = 16;
+            yuv_format = true;
+            // We are going to use RGB8888 on the host for Vulkan
+            glFormat = GL_RGBA;
+            glType = GL_UNSIGNED_BYTE;
+            emulatorFrameworkFormat = EmulatorFrameworkFormat::YV12;
+            break;
+
+        case PixelFormat::YCBCR_420_888:
+            yuv_format = true;
+            // We are going to use RGBA 8888 on the host
+            glFormat = GL_RGBA;
+            glType = GL_UNSIGNED_BYTE;
+            emulatorFrameworkFormat = EmulatorFrameworkFormat::YUV_420_888;
+            break;
+
+        default:
+            ALOGE("%s:%d Unsupported format: format=%d, frameworkFormat=%d, usage=%x",
+                  __func__, __LINE__, format, descriptor.format, usage);
+            RETURN_ERROR(Error3::UNSUPPORTED);
+        }
+
+        const size_t align1 = align - 1;
+        const uint32_t width = descriptor.width;
+        const uint32_t height = descriptor.height;
+        uint32_t stride;
+        size_t bufferSize;
+
+        if (yuv_format) {
+            const size_t yStride = (width * bpp + align1) & ~align1;
+            const size_t uvStride = (yStride / 2 + align1) & ~align1;
+            const size_t uvHeight = height / 2;
+            bufferSize = yStride * height + 2 * (uvHeight * uvStride);
+            stride = yStride / bpp;
+        } else {
+            const size_t bpr = (width * bpp + align1) & ~align1;
+            bufferSize = bpr * height;
+            stride = bpr / bpp;
+        }
+
+        *pStride = stride;
+
+        return allocateImpl2(usage,
+                             width, height,
+                             format, emulatorFrameworkFormat,
+                             glFormat, glType,
+                             bufferSize,
+                             bpp, stride,
+                             count, cbs);
+    }
+
+    Error3 allocateImpl2(const uint32_t usage,
+                         const uint32_t width, const uint32_t height,
+                         const PixelFormat format,
+                         const EmulatorFrameworkFormat emulatorFrameworkFormat,
+                         const int glFormat, const int glType,
+                         const size_t bufferSize,
+                         const uint32_t bytesPerPixel,
+                         const uint32_t stride,
+                         const uint32_t count,
+                         std::vector<cb_handle_30_t*>* cbs) {
+        for (uint32_t i = 0; i < count; ++i) {
+            cb_handle_30_t* cb;
+            Error3 e = allocateCb(usage,
+                                  width, height,
+                                  format, emulatorFrameworkFormat,
+                                  glFormat, glType,
+                                  bufferSize,
+                                  bytesPerPixel, stride,
+                                  &cb);
+            if (e == Error3::NONE) {
+                cbs->push_back(cb);
+            } else {
+                return e;
+            }
+        }
+
+        RETURN(Error3::NONE);
+    }
+
+    // see GoldfishMapper::encodeBufferDescriptorInfo
+    static bool decodeBufferDescriptorInfo(const hidl_vec<uint32_t>& raw,
+                                           BufferDescriptorInfo* d) {
+        if (raw.size() == 5) {
+            d->width = raw[0];
+            d->height = raw[1];
+            d->layerCount = raw[2];
+            d->format = static_cast<PixelFormat>(raw[3]);
+            d->usage = raw[4];
+
+            RETURN(true);
+        } else {
+            RETURN_ERROR(false);
+        }
+    }
+
+    static Error3 getBufferFormat(const PixelFormat frameworkFormat,
+                                  const uint32_t usage,
+                                  PixelFormat* format) {
+        if (frameworkFormat == PixelFormat::IMPLEMENTATION_DEFINED) {
+            if (usage & BufferUsage::CAMERA_OUTPUT) {
+                if (usage & BufferUsage::GPU_TEXTURE) {
+                    // Camera-to-display is RGBA
+                    *format = PixelFormat::RGBA_8888;
+                    RETURN(Error3::NONE);
+                } else if (usage & BufferUsage::VIDEO_ENCODER) {
+                    // Camera-to-encoder is NV21
+                    *format = PixelFormat::YCRCB_420_SP;
+                    RETURN(Error3::NONE);
+                }
+            }
+            RETURN_ERROR(Error3::UNSUPPORTED);
+        } else if ((int)frameworkFormat == OMX_COLOR_FormatYUV420Planar &&
+               (usage & BufferUsage::GPU_DATA_BUFFER)) {
+            ALOGW("gralloc_alloc: Requested OMX_COLOR_FormatYUV420Planar, given "
+              "YCbCr_420_888, taking experimental path. "
+              "usage=%x", usage);
+            *format = PixelFormat::YCBCR_420_888;
+            RETURN(Error3::NONE);
+        } else  {
+            *format = frameworkFormat;
+            RETURN(Error3::NONE);
+        }
+    }
+
+    static bool needHostCb(const uint32_t usage, const PixelFormat format) {
+        return ((usage & BufferUsage::GPU_DATA_BUFFER)
+                   || (format != PixelFormat::BLOB &&
+                       format != PixelFormat::RAW16 &&
+                       format != PixelFormat::Y16))
+               && (usage & (BufferUsage::GPU_TEXTURE
+                            | BufferUsage::GPU_RENDER_TARGET
+                            | BufferUsage::COMPOSER_OVERLAY
+                            | BufferUsage::VIDEO_ENCODER
+                            | BufferUsage::COMPOSER_CLIENT_TARGET
+                            | BufferUsage::CPU_READ_MASK));
+    }
+
+    Error3 allocateCb(const uint32_t usage,
+                      const uint32_t width, const uint32_t height,
+                      const PixelFormat format,
+                      const EmulatorFrameworkFormat emulatorFrameworkFormat,
+                      const int glFormat, const int glType,
+                      const size_t bufferSize,
+                      const int32_t bytesPerPixel,
+                      const int32_t stride,
+                      cb_handle_30_t** cb) {
+        GoldfishAddressSpaceHostMemoryAllocator host_memory_allocator;
+        if (!host_memory_allocator.is_opened()) {
+            RETURN_ERROR(Error3::NO_RESOURCES);
+        }
+
+        GoldfishAddressSpaceBlock bufferBits;
+        if (host_memory_allocator.hostMalloc(&bufferBits, bufferSize)) {
+            RETURN_ERROR(Error3::NO_RESOURCES);
+        }
+
+        uint32_t hostHandle = 0;
+        QEMU_PIPE_HANDLE hostHandleRefCountFd = QEMU_PIPE_INVALID_HANDLE;
+        if (needHostCb(usage, format)) {
+            hostHandleRefCountFd = qemu_pipe_open("refcount");
+            if (!qemu_pipe_valid(hostHandleRefCountFd)) {
+                RETURN_ERROR(Error3::NO_RESOURCES);
+            }
+
+            const GLenum allocFormat =
+                (PixelFormat::RGBX_8888 == format) ? GL_RGB : glFormat;
+
+            const HostConnectionSession conn = getHostConnectionSession();
+            ExtendedRCEncoderContext *const rcEnc = conn.getRcEncoder();
+            CRASH_IF(!rcEnc, "conn.getRcEncoder() failed");
+
+            hostHandle = rcEnc->rcCreateColorBufferDMA(
+                rcEnc,
+                width, height,
+                allocFormat, static_cast<int>(emulatorFrameworkFormat));
+
+            if (!hostHandle) {
+                qemu_pipe_close(hostHandleRefCountFd);
+                RETURN_ERROR(Error3::NO_RESOURCES);
+            }
+
+            if (qemu_pipe_write(hostHandleRefCountFd,
+                                &hostHandle,
+                                sizeof(hostHandle)) != sizeof(hostHandle)) {
+                rcEnc->rcCloseColorBuffer(rcEnc, hostHandle);
+                qemu_pipe_close(hostHandleRefCountFd);
+                RETURN_ERROR(Error3::NO_RESOURCES);
+            }
+        }
+
+        std::unique_ptr<cb_handle_30_t> handle =
+            std::make_unique<cb_handle_30_t>(
+                host_memory_allocator.release(),
+                hostHandleRefCountFd,
+                hostHandle,
+                usage,
+                width,
+                height,
+                static_cast<int>(format),
+                glFormat,
+                glType,
+                bufferSize,
+                bufferBits.guestPtr(),
+                bufferBits.size(),
+                bufferBits.offset(),
+                bytesPerPixel,
+                stride);
+
+        bufferBits.release();
+        *cb = handle.release();
+        RETURN(Error3::NONE);
+    }
+
+    void freeCb(std::unique_ptr<cb_handle_30_t> cb) {
+        // no need to undo .hostMalloc: the kernel will take care of it once the
+        // last bufferFd (duped) is closed.
+
+        if (qemu_pipe_valid(cb->hostHandleRefCountFd)) {
+            qemu_pipe_close(cb->hostHandleRefCountFd);
+        }
+        GoldfishAddressSpaceBlock::memoryUnmap(cb->getBufferPtr(), cb->mmapedSize);
+        GoldfishAddressSpaceHostMemoryAllocator::closeHandle(cb->bufferFd);
+    }
+
+    HostConnectionSession getHostConnectionSession() const {
+        return HostConnectionSession(m_hostConn.get());
+    }
+
+    std::unique_ptr<HostConnection> m_hostConn;
+};
+
+int main(int, char**) {
+    using ::android::sp;
+
+    ::android::hardware::configureRpcThreadpool(4, true /* callerWillJoin */);
+
+    sp<IAllocator3> allocator(new GoldfishAllocator());
+    if (allocator->registerAsService() != ::android::NO_ERROR) {
+        ALOGE("failed to register graphics IAllocator@3.0 service");
+        return -EINVAL;
+    }
+
+    ALOGI("graphics IAllocator@3.0 service is initialized");
+    ::android::hardware::joinRpcThreadpool();
+
+    ALOGI("graphics IAllocator@3.0 service is terminating");
+    return 0;
+}
diff --git a/system/hals/android.hardware.graphics.allocator@3.0-service.rc b/system/hals/android.hardware.graphics.allocator@3.0-service.rc
new file mode 100644
index 0000000..8b9e13a
--- /dev/null
+++ b/system/hals/android.hardware.graphics.allocator@3.0-service.rc
@@ -0,0 +1,8 @@
+service vendor.gralloc-3-0 /vendor/bin/hw/android.hardware.graphics.allocator@3.0-service
+    interface android.hardware.graphics.allocator@3.0::IAllocator default
+    class hal animation
+    interface android.hardware.graphics.allocator@3.0::IAllocator default
+    user system
+    group graphics drmrpc
+    capabilities SYS_NICE
+    onrestart restart surfaceflinger
diff --git a/system/hals/cb_handle_30.h b/system/hals/cb_handle_30.h
new file mode 100644
index 0000000..11ce322
--- /dev/null
+++ b/system/hals/cb_handle_30.h
@@ -0,0 +1,81 @@
+/*
+* Copyright 2011 The Android Open Source Project
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+#ifndef SYSTEM_HALS_CB_HANDLE_30_H
+#define SYSTEM_HALS_CB_HANDLE_30_H
+
+#include "gralloc_cb.h"
+#include "goldfish_address_space.h"
+
+const uint32_t CB_HANDLE_MAGIC_30 = CB_HANDLE_MAGIC_BASE | 0x2;
+
+struct cb_handle_30_t : public cb_handle_t {
+    cb_handle_30_t(address_space_handle_t p_bufferFd,
+                   QEMU_PIPE_HANDLE p_hostHandleRefCountFd,
+                   uint32_t p_hostHandle,
+                   int32_t p_usage,
+                   int32_t p_width,
+                   int32_t p_height,
+                   int32_t p_format,
+                   int32_t p_glFormat,
+                   int32_t p_glType,
+                   uint32_t p_bufSize,
+                   void* p_bufPtr,
+                   uint32_t p_mmapedSize,
+                   uint64_t p_mmapedOffset,
+                   uint32_t p_bytesPerPixel,
+                   uint32_t p_stride)
+            : cb_handle_t(p_bufferFd,
+                          p_hostHandleRefCountFd,
+                          CB_HANDLE_MAGIC_30,
+                          p_hostHandle,
+                          p_usage,
+                          p_width,
+                          p_height,
+                          p_format,
+                          p_glFormat,
+                          p_glType,
+                          p_bufSize,
+                          p_bufPtr,
+                          p_mmapedOffset),
+              mmapedSize(p_mmapedSize),
+              bytesPerPixel(p_bytesPerPixel),
+              stride(p_stride) {
+        numInts = CB_HANDLE_NUM_INTS(numFds);
+    }
+
+    bool isValid() const { return (version == sizeof(native_handle_t)) && (magic == CB_HANDLE_MAGIC_30); }
+
+    static cb_handle_30_t* from(void* p) {
+        if (!p) { return nullptr; }
+        cb_handle_30_t* cb = static_cast<cb_handle_30_t*>(p);
+        return cb->isValid() ? cb : nullptr;
+    }
+
+    static const cb_handle_30_t* from(const void* p) {
+        return from(const_cast<void*>(p));
+    }
+
+    static cb_handle_30_t* from_unconst(const void* p) {
+        return from(const_cast<void*>(p));
+    }
+
+    uint32_t mmapedSize;            // real allocation side
+    uint32_t bytesPerPixel;
+    uint32_t stride;
+};
+
+#endif // SYSTEM_HALS_CB_HANDLE_30_H
diff --git a/system/hals/debug.h b/system/hals/debug.h
new file mode 100644
index 0000000..f8e41b4
--- /dev/null
+++ b/system/hals/debug.h
@@ -0,0 +1,44 @@
+/*
+* Copyright (C) 2020 The Android Open Source Project
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+#ifndef GOLDFISH_OPENGL_SYSTEM_HALS_DEBUG_H_INCLUDED
+#define GOLDFISH_OPENGL_SYSTEM_HALS_DEBUG_H_INCLUDED
+
+#include <log/log.h>
+
+#define RETURN(X) return (X)
+
+#define RETURN_ERROR(X) \
+    do { \
+        ALOGE("%s:%d failed with '%s'", __func__, __LINE__, #X); \
+        return (X); \
+    } while (false)
+
+#define CRASH(MSG) \
+    do { \
+        ALOGE("%s:%d crashed with '%s'", __func__, __LINE__, MSG); \
+        ::abort(); \
+    } while (false)
+
+#define CRASH_IF(COND, MSG) \
+    do { \
+        if ((COND)) { \
+            ALOGE("%s:%d crashed on '%s' with '%s'", __func__, __LINE__, #COND, MSG); \
+            ::abort(); \
+        } \
+    } while (false)
+
+#endif  // GOLDFISH_OPENGL_SYSTEM_HALS_DEBUG_H_INCLUDED
diff --git a/system/hals/host_connection_session.h b/system/hals/host_connection_session.h
new file mode 100644
index 0000000..12d3b76
--- /dev/null
+++ b/system/hals/host_connection_session.h
@@ -0,0 +1,56 @@
+/*
+* Copyright (C) 2020 The Android Open Source Project
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+#ifndef GOLDFISH_OPENGL_SYSTEM_HALS_HOST_CONNECTION_SESSION_H_INCLUDED
+#define GOLDFISH_OPENGL_SYSTEM_HALS_HOST_CONNECTION_SESSION_H_INCLUDED
+
+#include "HostConnection.h"
+
+class HostConnectionSession {
+public:
+    explicit HostConnectionSession(HostConnection* hc) : conn(hc) {
+        hc->lock();
+    }
+
+    ~HostConnectionSession() {
+        if (conn) {
+            conn->unlock();
+        }
+     }
+
+    HostConnectionSession(HostConnectionSession&& rhs) : conn(rhs.conn) {
+        rhs.conn = nullptr;
+    }
+
+    HostConnectionSession& operator=(HostConnectionSession&& rhs) {
+        if (this != &rhs) {
+            std::swap(conn, rhs.conn);
+        }
+        return *this;
+    }
+
+    HostConnectionSession(const HostConnectionSession&) = delete;
+    HostConnectionSession& operator=(const HostConnectionSession&) = delete;
+
+    ExtendedRCEncoderContext* getRcEncoder() const {
+        return conn->rcEncoder();
+    }
+
+private:
+    HostConnection* conn;
+};
+
+#endif  // GOLDFISH_OPENGL_SYSTEM_HALS_HOST_CONNECTION_SESSION_H_INCLUDED
diff --git a/system/hals/mapper3.cpp b/system/hals/mapper3.cpp
new file mode 100644
index 0000000..b48e497
--- /dev/null
+++ b/system/hals/mapper3.cpp
@@ -0,0 +1,614 @@
+/*
+* Copyright (C) 2020 The Android Open Source Project
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+#include <android/hardware/graphics/mapper/3.0/IMapper.h>
+#include <cutils/native_handle.h>
+#include <sync/sync.h>
+
+#include "cb_handle_30.h"
+#include "host_connection_session.h"
+#include "FormatConversions.h"
+#include "debug.h"
+
+using ::android::hardware::hidl_handle;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+
+using ::android::hardware::graphics::common::V1_2::PixelFormat;
+using ::android::hardware::graphics::common::V1_0::BufferUsage;
+
+namespace MapperV3 = ::android::hardware::graphics::mapper::V3_0;
+
+using IMapper3 = MapperV3::IMapper;
+using Error3 = MapperV3::Error;
+using YCbCrLayout3 = MapperV3::YCbCrLayout;
+
+namespace {
+size_t align(const size_t v, const size_t a) { return (v + a - 1) & ~(a - 1); }
+
+static int waitFenceFd(const int fd, const char* logname) {
+    const int warningTimeout = 5000;
+    if (sync_wait(fd, warningTimeout) < 0) {
+        if (errno == ETIME) {
+            ALOGW("%s: fence %d didn't signal in %d ms", logname, fd, warningTimeout);
+            if (sync_wait(fd, -1) < 0) {
+                RETURN_ERROR(errno);
+            } else {
+                RETURN(0);
+            }
+        } else {
+            RETURN_ERROR(errno);
+        }
+    } else {
+        RETURN(0);
+    }
+}
+
+int waitHidlFence(const hidl_handle& hidlHandle, const char* logname) {
+    const native_handle_t* nativeHandle = hidlHandle.getNativeHandle();
+
+    if (!nativeHandle) {
+        RETURN(0);
+    }
+    if (nativeHandle->numFds > 1) {
+        RETURN_ERROR(-EINVAL);
+    }
+    if (nativeHandle->numInts != 0) {
+        RETURN_ERROR(-EINVAL);
+    }
+
+    return waitFenceFd(nativeHandle->data[0], logname);
+}
+
+class GoldfishMapper : public IMapper3 {
+public:
+    GoldfishMapper() : m_hostConn(HostConnection::createUnique()) {
+        GoldfishAddressSpaceHostMemoryAllocator host_memory_allocator;
+        CRASH_IF(!host_memory_allocator.is_opened(),
+                 "GoldfishAddressSpaceHostMemoryAllocator failed to open");
+
+        GoldfishAddressSpaceBlock bufferBits;
+        CRASH_IF(host_memory_allocator.hostMalloc(&bufferBits, 256),
+                 "hostMalloc failed");
+
+        m_physAddrToOffset = bufferBits.physAddr() - bufferBits.offset();
+    }
+
+    Return<void> importBuffer(const hidl_handle& hh,
+                              importBuffer_cb hidl_cb) {
+        native_handle_t* imported = nullptr;
+        const Error3 e = importBufferImpl(hh.getNativeHandle(), &imported);
+        if (e == Error3::NONE) {
+            hidl_cb(Error3::NONE, imported);
+        } else {
+            hidl_cb(e, nullptr);
+        }
+        return {};
+    }
+
+    Return<Error3> freeBuffer(void* raw) {
+        if (!raw) {
+            RETURN_ERROR(Error3::BAD_BUFFER);
+        }
+        cb_handle_30_t* cb = cb_handle_30_t::from(raw);
+        if (!cb) {
+            RETURN_ERROR(Error3::BAD_BUFFER);
+        }
+
+        if (cb->hostHandle) {
+            const HostConnectionSession conn = getHostConnectionSession();
+            ExtendedRCEncoderContext *const rcEnc = conn.getRcEncoder();
+            rcEnc->rcCloseColorBuffer(rcEnc, cb->hostHandle);
+        }
+
+        if (cb->mmapedSize > 0) {
+            GoldfishAddressSpaceBlock::memoryUnmap(cb->getBufferPtr(), cb->mmapedSize);
+        }
+
+        native_handle_close(cb);
+        native_handle_delete(cb);
+
+        RETURN(Error3::NONE);
+    }
+
+    Return<void> lock(void* raw,
+                      uint64_t cpuUsage,
+                      const Rect& accessRegion,
+                      const hidl_handle& acquireFence,
+                      lock_cb hidl_cb) {
+        void* ptr = nullptr;
+        int32_t bytesPerPixel = 0;
+        int32_t bytesPerStride = 0;
+
+        const Error3 e = lockImpl(raw, cpuUsage, accessRegion, acquireFence,
+                                  &ptr, &bytesPerPixel, &bytesPerStride);
+        if (e == Error3::NONE) {
+            hidl_cb(Error3::NONE, ptr, bytesPerPixel, bytesPerStride);
+        } else {
+            hidl_cb(e, nullptr, 0, 0);
+        }
+        return {};
+    }
+
+    Return<void> lockYCbCr(void* raw,
+                           uint64_t cpuUsage,
+                           const Rect& accessRegion,
+                           const hidl_handle& acquireFence,
+                           lockYCbCr_cb hidl_cb) {
+        YCbCrLayout3 ycbcr = {};
+        const Error3 e = lockYCbCrImpl(raw, cpuUsage, accessRegion, acquireFence,
+                                       &ycbcr);
+        if (e == Error3::NONE) {
+            hidl_cb(Error3::NONE, ycbcr);
+        } else {
+            hidl_cb(e, {});
+        }
+        return {};
+    }
+
+    Return<void> unlock(void* raw, unlock_cb hidl_cb) {
+        hidl_cb(unlockImpl(raw), {});
+        return {};
+
+    }
+
+    Return<void> createDescriptor(const BufferDescriptorInfo& description,
+                                  createDescriptor_cb hidl_cb) {
+        hidl_vec<uint32_t> raw;
+        encodeBufferDescriptorInfo(description, &raw);
+        hidl_cb(Error3::NONE, raw);
+        return {};
+    }
+
+    Return<void> isSupported(const IMapper::BufferDescriptorInfo& description,
+                             isSupported_cb hidl_cb) {
+        hidl_cb(Error3::NONE, isSupportedImpl(description));
+        return {};
+    }
+
+    Return<Error3> validateBufferSize(void* buffer,
+                                      const BufferDescriptorInfo& descriptor,
+                                      uint32_t stride) {
+        const cb_handle_30_t* cb = cb_handle_30_t::from(buffer);
+        if (cb) {
+            return validateBufferSizeImpl(*cb, descriptor, stride);
+        } else {
+            RETURN_ERROR(Error3::BAD_BUFFER);
+        }
+    }
+
+    Return<void> getTransportSize(void* buffer,
+                                  getTransportSize_cb hidl_cb) {
+        const cb_handle_30_t* cb = cb_handle_30_t::from(buffer);
+        if (cb) {
+            hidl_cb(Error3::NONE, cb->numFds, cb->numInts);
+        } else {
+            hidl_cb(Error3::BAD_BUFFER, 0, 0);
+        }
+
+        return {};
+    }
+
+private:  // **** impl ****
+    Error3 importBufferImpl(const native_handle_t* nh, native_handle_t** phandle) {
+        if (!nh) {
+            RETURN_ERROR(Error3::BAD_BUFFER);
+        }
+        native_handle_t* imported = native_handle_clone(nh);
+        if (!imported) {
+            RETURN_ERROR(Error3::BAD_BUFFER);
+        }
+        cb_handle_30_t* cb = cb_handle_30_t::from(imported);
+        if (!cb) {
+            native_handle_close(imported);
+            native_handle_delete(imported);
+            RETURN_ERROR(Error3::BAD_BUFFER);
+        }
+
+        if (cb->mmapedSize > 0) {
+            void* ptr;
+            const int res = GoldfishAddressSpaceBlock::memoryMap(
+                cb->getBufferPtr(),
+                cb->mmapedSize,
+                cb->bufferFd,
+                cb->getMmapedOffset(),
+                &ptr);
+            if (res) {
+                native_handle_close(imported);
+                native_handle_delete(imported);
+                RETURN_ERROR(Error3::NO_RESOURCES);
+            }
+            cb->setBufferPtr(ptr);
+        }
+
+        if (cb->hostHandle) {
+            const HostConnectionSession conn = getHostConnectionSession();
+            ExtendedRCEncoderContext *const rcEnc = conn.getRcEncoder();
+            rcEnc->rcOpenColorBuffer2(rcEnc, cb->hostHandle);
+        }
+
+        *phandle = imported;
+        RETURN(Error3::NONE);
+    }
+
+    Error3 lockImpl(void* raw,
+                    uint64_t cpuUsage,
+                    const Rect& accessRegion,
+                    const hidl_handle& acquireFence,
+                    void** pptr,
+                    int32_t* pBytesPerPixel,
+                    int32_t* pBytesPerStride) {
+        if (!raw) {
+            RETURN_ERROR(Error3::BAD_BUFFER);
+        }
+        cb_handle_30_t* cb = cb_handle_30_t::from(raw);
+        if (!cb) {
+            RETURN_ERROR(Error3::BAD_BUFFER);
+        }
+        if (!cb->bufferSize) {
+            RETURN_ERROR(Error3::BAD_BUFFER);
+        }
+        char* const bufferBits = static_cast<char*>(cb->getBufferPtr());
+        if (!bufferBits) {
+            RETURN_ERROR(Error3::BAD_BUFFER);
+        }
+        if (waitHidlFence(acquireFence, __func__)) {
+            RETURN_ERROR(Error3::BAD_VALUE);
+        }
+
+        if (cb->hostHandle) {
+            const Error3 e = lockHostImpl(*cb, cpuUsage, accessRegion, bufferBits);
+            if (e != Error3::NONE) {
+                return e;
+            }
+        }
+
+        *pptr = bufferBits;
+        *pBytesPerPixel = cb->bytesPerPixel;
+        *pBytesPerStride = cb->bytesPerPixel * cb->stride;
+        RETURN(Error3::NONE);
+    }
+
+    Error3 lockYCbCrImpl(void* raw,
+                         uint64_t cpuUsage,
+                         const Rect& accessRegion,
+                         const hidl_handle& acquireFence,
+                         YCbCrLayout3* pYcbcr) {
+        if (!raw) {
+            RETURN_ERROR(Error3::BAD_BUFFER);
+        }
+        cb_handle_30_t* cb = cb_handle_30_t::from(raw);
+        if (!cb) {
+            RETURN_ERROR(Error3::BAD_BUFFER);
+        }
+        if (!cb->bufferSize) {
+            RETURN_ERROR(Error3::BAD_BUFFER);
+        }
+        char* const bufferBits = static_cast<char*>(cb->getBufferPtr());
+        if (!bufferBits) {
+            RETURN_ERROR(Error3::BAD_BUFFER);
+        }
+        if (waitHidlFence(acquireFence, __func__)) {
+            RETURN_ERROR(Error3::BAD_VALUE);
+        }
+
+        size_t uOffset;
+        size_t vOffset;
+        size_t yStride;
+        size_t cStride;
+        size_t cStep;
+        switch (static_cast<PixelFormat>(cb->format)) {
+        case PixelFormat::YCRCB_420_SP:
+            yStride = cb->width;
+            cStride = yStride;
+            vOffset = yStride * cb->height;
+            uOffset = vOffset + 1;
+            cStep = 2;
+            break;
+
+        case PixelFormat::YV12:
+            // https://developer.android.com/reference/android/graphics/ImageFormat.html#YV12
+            yStride = align(cb->width, 16);
+            cStride = align(yStride / 2, 16);
+            vOffset = yStride * cb->height;
+            uOffset = vOffset + (cStride * cb->height / 2);
+            cStep = 1;
+            break;
+
+        case PixelFormat::YCBCR_420_888:
+            yStride = cb->width;
+            cStride = yStride / 2;
+            uOffset = cb->height * yStride;
+            vOffset = uOffset + cStride * cb->height / 2;
+            cStep = 1;
+            break;
+
+        default:
+            ALOGE("%s:%d unexpected format (%d)", __func__, __LINE__, cb->format);
+            RETURN_ERROR(Error3::BAD_BUFFER);
+        }
+
+        if (cb->hostHandle) {
+            const Error3 e = lockHostImpl(*cb, cpuUsage, accessRegion, bufferBits);
+            if (e != Error3::NONE) {
+                return e;
+            }
+        }
+
+        pYcbcr->y = bufferBits;
+        pYcbcr->cb = bufferBits + uOffset;
+        pYcbcr->cr = bufferBits + vOffset;
+        pYcbcr->yStride = yStride;
+        pYcbcr->cStride = cStride;
+        pYcbcr->chromaStep = cStep;
+
+        RETURN(Error3::NONE);
+    }
+
+    Error3 lockHostImpl(cb_handle_30_t& cb,
+                        const uint32_t usage,
+                        const Rect& accessRegion,
+                        char* const bufferBits) {
+        const bool usageSwRead = usage & BufferUsage::CPU_READ_MASK;
+        const bool usageSwWrite = usage & BufferUsage::CPU_WRITE_MASK;
+        const bool usageHwCamera = usage & (BufferUsage::CAMERA_INPUT | BufferUsage::CAMERA_OUTPUT);
+        const bool usageHwCameraWrite = usage & BufferUsage::CAMERA_OUTPUT;
+
+        const HostConnectionSession conn = getHostConnectionSession();
+        ExtendedRCEncoderContext *const rcEnc = conn.getRcEncoder();
+
+        const int res = rcEnc->rcColorBufferCacheFlush(
+            rcEnc, cb.hostHandle, 0, usageSwRead);
+        if (res < 0) {
+            RETURN_ERROR(Error3::NO_RESOURCES);
+        }
+
+        // camera delivers bits to the buffer directly and does not require
+        // an explicit read.
+        if (usageSwRead && !usageHwCamera) {
+            if (gralloc_is_yuv_format(cb.format)) {
+                if (rcEnc->hasYUVCache()) {
+                    uint32_t bufferSize;
+                    switch (static_cast<PixelFormat>(cb.format)) {
+                    case PixelFormat::YV12:
+                        get_yv12_offsets(cb.width, cb.height,
+                                         nullptr, nullptr, &bufferSize);
+                        break;
+                    case PixelFormat::YCBCR_420_888:
+                        get_yuv420p_offsets(cb.width, cb.height,
+                                            nullptr, nullptr, &bufferSize);
+                        break;
+                    default:
+                        CRASH("Unexpected format, switch is out of sync with gralloc_is_yuv_format");
+                        break;
+                    }
+
+                    rcEnc->rcReadColorBufferYUV(rcEnc, cb.hostHandle,
+                        0, 0, cb.width, cb.height,
+                        bufferBits, bufferSize);
+                } else {
+                    // We are using RGB888
+                    std::vector<char> tmpBuf(cb.width * cb.height * 3);
+                    rcEnc->rcReadColorBuffer(rcEnc, cb.hostHandle,
+                                             0, 0, cb.width, cb.height,
+                                             cb.glFormat, cb.glType,
+                                             tmpBuf.data());
+                    switch (static_cast<PixelFormat>(cb.format)) {
+                    case PixelFormat::YV12:
+                        rgb888_to_yv12(bufferBits, tmpBuf.data(),
+                                       cb.width, cb.height,
+                                       accessRegion.left,
+                                       accessRegion.top,
+                                       accessRegion.left + accessRegion.width - 1,
+                                       accessRegion.top + accessRegion.height - 1);
+                        break;
+                    case PixelFormat::YCBCR_420_888:
+                        rgb888_to_yuv420p(bufferBits, tmpBuf.data(),
+                                          cb.width, cb.height,
+                                          accessRegion.left,
+                                          accessRegion.top,
+                                          accessRegion.left + accessRegion.width - 1,
+                                          accessRegion.top + accessRegion.height - 1);
+                        break;
+                    default:
+                        CRASH("Unexpected format, switch is out of sync with gralloc_is_yuv_format");
+                        break;
+                    }
+                }
+            } else {
+                rcEnc->rcReadColorBuffer(rcEnc,
+                                         cb.hostHandle,
+                                         0, 0, cb.width, cb.height,
+                                         cb.glFormat, cb.glType,
+                                         bufferBits);
+            }
+        }
+
+        if (usageSwWrite || usageHwCameraWrite) {
+            cb.lockedLeft = accessRegion.left;
+            cb.lockedTop = accessRegion.top;
+            cb.lockedWidth = accessRegion.width;
+            cb.lockedHeight = accessRegion.height;
+        } else {
+            cb.lockedLeft = 0;
+            cb.lockedTop = 0;
+            cb.lockedWidth = cb.width;
+            cb.lockedHeight = cb.height;
+        }
+
+        RETURN(Error3::NONE);
+    }
+
+    Error3 unlockImpl(void* raw) {
+        if (!raw) {
+            RETURN_ERROR(Error3::BAD_BUFFER);
+        }
+        cb_handle_30_t* cb = cb_handle_30_t::from(raw);
+        if (!cb) {
+            RETURN_ERROR(Error3::BAD_BUFFER);
+        }
+        if (!cb->bufferSize) {
+            RETURN_ERROR(Error3::BAD_BUFFER);
+        }
+        char* const bufferBits = static_cast<char*>(cb->getBufferPtr());
+        if (!bufferBits) {
+            RETURN_ERROR(Error3::BAD_BUFFER);
+        }
+
+        if (cb->hostHandle) {
+            unlockHostImpl(*cb, bufferBits);
+        }
+
+        RETURN(Error3::NONE);
+    }
+
+    void unlockHostImpl(cb_handle_30_t& cb, char* const bufferBits) {
+        const int bpp = glUtilsPixelBitSize(cb.glFormat, cb.glType) >> 3;
+        const int left = cb.lockedLeft;
+        const int top = cb.lockedTop;
+        const int width = cb.lockedWidth;
+        const int height = cb.lockedHeight;
+        const uint32_t rgbSize = width * height * bpp;
+        std::vector<char> convertedBuf;
+        const char* bitsToSend;
+        uint32_t sizeToSend;
+
+        if (gralloc_is_yuv_format(cb.format)) {
+            bitsToSend = bufferBits;
+            switch (static_cast<PixelFormat>(cb.format)) {
+            case PixelFormat::YV12:
+                get_yv12_offsets(width, height, nullptr, nullptr, &sizeToSend);
+                break;
+            case PixelFormat::YCBCR_420_888:
+                get_yuv420p_offsets(width, height, nullptr, nullptr, &sizeToSend);
+                break;
+            default:
+                CRASH("Unexpected format, switch is out of sync with gralloc_is_yuv_format");
+                break;
+            }
+        } else {
+            convertedBuf.resize(rgbSize);
+            copy_rgb_buffer_from_unlocked(
+                convertedBuf.data(), bufferBits,
+                cb.width,
+                width, height, top, left, bpp);
+            bitsToSend = convertedBuf.data();
+            sizeToSend = rgbSize;
+        }
+
+        {
+            const HostConnectionSession conn = getHostConnectionSession();
+            ExtendedRCEncoderContext *const rcEnc = conn.getRcEncoder();
+            rcEnc->bindDmaDirectly(bufferBits,
+                                   getMmapedPhysAddr(cb.getMmapedOffset()));
+            rcEnc->rcUpdateColorBufferDMA(rcEnc, cb.hostHandle,
+                    left, top, width, height,
+                    cb.glFormat, cb.glType,
+                    const_cast<char*>(bitsToSend), sizeToSend);
+        }
+
+        cb.lockedLeft = 0;
+        cb.lockedTop = 0;
+        cb.lockedWidth = 0;
+        cb.lockedHeight = 0;
+    }
+
+    bool isSupportedImpl(const IMapper::BufferDescriptorInfo& descriptor) const {
+        if (!descriptor.width) { RETURN(false); }
+        if (!descriptor.height) { RETURN(false); }
+        if (descriptor.layerCount != 1) { RETURN(false); }
+
+        const uint32_t usage = descriptor.usage;
+        const bool usageSwWrite = usage & BufferUsage::CPU_WRITE_MASK;
+        const bool usageSwRead = usage & BufferUsage::CPU_READ_MASK;
+        const bool usageHwCamWrite = usage & BufferUsage::CAMERA_OUTPUT;
+        const bool usageHwCamRead = usage & BufferUsage::CAMERA_INPUT;
+
+        switch (descriptor.format) {
+        case PixelFormat::RGBA_8888:
+        case PixelFormat::RGBX_8888:
+        case PixelFormat::BGRA_8888:
+        case PixelFormat::RGB_565:
+        case PixelFormat::RGBA_FP16:
+        case PixelFormat::RGBA_1010102:
+        case PixelFormat::YCRCB_420_SP:
+        case PixelFormat::YV12:
+        case PixelFormat::YCBCR_420_888:
+            RETURN(true);
+
+        case PixelFormat::IMPLEMENTATION_DEFINED:
+            if (usage & BufferUsage::CAMERA_OUTPUT) {
+                if (usage & BufferUsage::GPU_TEXTURE) {
+                    RETURN(true);
+                } else if (usage & BufferUsage::VIDEO_ENCODER) {
+                    RETURN(true);
+                }
+            }
+            RETURN(false);
+
+        case PixelFormat::RGB_888:
+            RETURN(0 == (usage & (BufferUsage::GPU_TEXTURE |
+                                  BufferUsage::GPU_RENDER_TARGET |
+                                  BufferUsage::COMPOSER_OVERLAY |
+                                  BufferUsage::COMPOSER_CLIENT_TARGET)));
+
+        case PixelFormat::RAW16:
+        case PixelFormat::Y16:
+            RETURN((usageSwRead || usageHwCamRead) &&
+                   (usageSwWrite || usageHwCamWrite));
+
+        case PixelFormat::BLOB:
+            RETURN(usageSwRead);
+
+        default:
+            RETURN(false);
+        }
+    }
+
+    Error3 validateBufferSizeImpl(const cb_handle_t& /*cb*/,
+                                  const BufferDescriptorInfo& /*descriptor*/,
+                                  uint32_t /*stride*/) {
+        RETURN(Error3::NONE);
+    }
+
+    HostConnectionSession getHostConnectionSession() const {
+        return HostConnectionSession(m_hostConn.get());
+    }
+
+    static void encodeBufferDescriptorInfo(const BufferDescriptorInfo& d,
+                                           hidl_vec<uint32_t>* raw) {
+        raw->resize(5);
+
+        (*raw)[0] = d.width;
+        (*raw)[1] = d.height;
+        (*raw)[2] = d.layerCount;
+        (*raw)[3] = static_cast<uint32_t>(d.format);
+        (*raw)[4] = d.usage & UINT32_MAX;
+    }
+
+    uint64_t getMmapedPhysAddr(uint64_t offset) const {
+        return m_physAddrToOffset + offset;
+    }
+
+    std::unique_ptr<HostConnection> m_hostConn;
+    uint64_t m_physAddrToOffset;
+};
+}  // namespace
+
+extern "C" IMapper3* HIDL_FETCH_IMapper(const char* /*name*/) {
+    return new GoldfishMapper;
+}
diff --git a/system/hals/types.h b/system/hals/types.h
new file mode 100644
index 0000000..c7d2646
--- /dev/null
+++ b/system/hals/types.h
@@ -0,0 +1,43 @@
+/*
+* Copyright (C) 2020 The Android Open Source Project
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+#ifndef GOLDFISH_OPENGL_SYSTEM_HALS_TYPES_H_INCLUDED
+#define GOLDFISH_OPENGL_SYSTEM_HALS_TYPES_H_INCLUDED
+
+/* Tell the emulator which formats need special handling. */
+enum class EmulatorFrameworkFormat {
+    GL_COMPATIBLE = 0,
+    YV12 = 1,
+    YUV_420_888 = 2, // (Y+)(U+)(V+)
+};
+
+#ifndef GL_RGBA16F
+#define GL_RGBA16F                        0x881A
+#endif // GL_RGBA16F
+
+#ifndef GL_HALF_FLOAT
+#define GL_HALF_FLOAT                     0x140B
+#endif // GL_HALF_FLOAT
+
+#ifndef GL_RGB10_A2
+#define GL_RGB10_A2                       0x8059
+#endif // GL_RGB10_A2
+
+#ifndef GL_UNSIGNED_INT_2_10_10_10_REV
+#define GL_UNSIGNED_INT_2_10_10_10_REV    0x8368
+#endif // GL_UNSIGNED_INT_2_10_10_10_REV
+
+#endif  // GOLDFISH_OPENGL_SYSTEM_HALS_TYPES_H_INCLUDED
diff --git a/system/hwc2/Android.mk b/system/hwc2/Android.mk
index a3bf20f..698de73 100644
--- a/system/hwc2/Android.mk
+++ b/system/hwc2/Android.mk
@@ -27,9 +27,11 @@
     libhardware \
     libsync \
     libui \
+    android.hardware.graphics.mapper@2.0 \
 
 emulator_hwcomposer_cflags += \
-    -DLOG_TAG=\"hwc2\"
+    -DLOG_TAG=\"hwc2\" \
+    -DPLATFORM_SDK_VERSION=$(PLATFORM_SDK_VERSION) \
 
 emulator_hwcomposer_c_includes += \
     system/core/libsync \
@@ -51,6 +53,7 @@
 LOCAL_VENDOR_MODULE := true
 LOCAL_SHARED_LIBRARIES := $(emulator_hwcomposer_shared_libraries)
 LOCAL_SHARED_LIBRARIES += libOpenglSystemCommon lib_renderControl_enc
+LOCAL_SHARED_LIBRARIES += libcbmanager
 LOCAL_SRC_FILES := $(emulator_hwcomposer2_src_files)
 LOCAL_C_INCLUDES := $(emulator_hwcomposer_c_includes)
 LOCAL_MODULE_RELATIVE_PATH := $(emulator_hwcomposer_relative_path)
diff --git a/system/hwc2/EmuHWC2.cpp b/system/hwc2/EmuHWC2.cpp
index 84fd7b6..14bb545 100644
--- a/system/hwc2/EmuHWC2.cpp
+++ b/system/hwc2/EmuHWC2.cpp
@@ -21,6 +21,7 @@
 #define LOG_TAG "EmuHWC2"
 
 #include <errno.h>
+#include <cutils/properties.h>
 #include <log/log.h>
 #include <sync/sync.h>
 
@@ -65,7 +66,6 @@
         return Error::NoResources; \
     }
 
-
 using namespace HWC2;
 
 namespace android {
@@ -79,6 +79,21 @@
     getCapabilities = getCapabilitiesHook;
     getFunction = getFunctionHook;
     populateCapabilities();
+    initDisplayParameters();
+}
+
+Error EmuHWC2::initDisplayParameters() {
+    DEFINE_AND_VALIDATE_HOST_CONNECTION
+    hostCon->lock();
+
+    mDisplayWidth = rcEnc->rcGetFBParam(rcEnc, FB_WIDTH);
+    mDisplayHeight = rcEnc->rcGetFBParam(rcEnc, FB_HEIGHT);
+    mDisplayDpiX = rcEnc->rcGetFBParam(rcEnc, FB_XDPI);
+    mDisplayDpiY = rcEnc->rcGetFBParam(rcEnc, FB_YDPI);
+
+    hostCon->unlock();
+
+    return HWC2::Error::None;
 }
 
 void EmuHWC2::doGetCapabilities(uint32_t* outCount, int32_t* outCapabilities) {
@@ -218,6 +233,23 @@
                     displayHook<decltype(&Display::getClientTargetSupport),
                     &Display::getClientTargetSupport, uint32_t, uint32_t,
                                                       int32_t, int32_t>);
+        // 2.3 required functions
+        case FunctionDescriptor::GetDisplayIdentificationData:
+            return asFP<HWC2_PFN_GET_DISPLAY_IDENTIFICATION_DATA>(
+                    displayHook<decltype(&Display::getDisplayIdentificationData),
+                    &Display::getDisplayIdentificationData, uint8_t*, uint32_t*, uint8_t*>);
+        case FunctionDescriptor::GetDisplayCapabilities:
+            return asFP<HWC2_PFN_GET_DISPLAY_CAPABILITIES>(
+                    displayHook<decltype(&Display::getDisplayCapabilities),
+                    &Display::getDisplayCapabilities, uint32_t*, uint32_t*>);
+        case FunctionDescriptor::GetDisplayBrightnessSupport:
+            return asFP<HWC2_PFN_GET_DISPLAY_BRIGHTNESS_SUPPORT>(
+                    displayHook<decltype(&Display::getDisplayBrightnessSupport),
+                    &Display::getDisplayBrightnessSupport, bool*>);
+        case FunctionDescriptor::SetDisplayBrightness:
+            return asFP<HWC2_PFN_SET_DISPLAY_BRIGHTNESS>(
+                    displayHook<decltype(&Display::setDisplayBrightness),
+                    &Display::setDisplayBrightness, float>);
         // Layer functions
         case FunctionDescriptor::SetCursorPosition:
             return asFP<HWC2_PFN_SET_CURSOR_POSITION>(
@@ -349,61 +381,59 @@
     if (descriptor == Callback::Hotplug) {
         lock.unlock();
         auto hotplug = reinterpret_cast<HWC2_PFN_VSYNC>(pointer);
-        hotplug(callbackData, 0, static_cast<int32_t>(Connection::Connected));
+        for (const auto& iter : mDisplays) {
+            hotplug(callbackData, iter.first, static_cast<int32_t>(Connection::Connected));
+        }
     }
 
     return Error::None;
 }
 
-//Gralloc Functions
-EmuHWC2::GrallocModule::GrallocModule() {
-    int ret;
+const native_handle_t* EmuHWC2::allocateDisplayColorBuffer() {
+    typedef CbManager::BufferUsage BufferUsage;
 
-    ret = hw_get_module(GRALLOC_HARDWARE_MODULE_ID, &mHw);
-    assert(ret == 0 && "Gralloc moudle not found");
-    mGralloc = reinterpret_cast<const gralloc_module_t*>(mHw);
-
-    ret = framebuffer_open(mHw, &mFbDev);
-    assert(ret == 0 && "Fail to open FrameBuffer device");
+    return mCbManager.allocateBuffer(
+        mDisplayWidth,
+        mDisplayHeight,
+        CbManager::PixelFormat::RGBA_8888,
+        (BufferUsage::COMPOSER_OVERLAY | BufferUsage::GPU_RENDER_TARGET));
 }
 
-EmuHWC2::GrallocModule::~GrallocModule() {
-    if (mHandle != nullptr) {
-        mGralloc->unregisterBuffer(mGralloc, mHandle);
-        mAllocDev->free(mAllocDev, mHandle);
-        ALOGI("free targetCb %d", ((cb_handle_t*)(mHandle))->hostHandle);
-    }
-}
-
-uint32_t EmuHWC2::GrallocModule::getTargetCb() {
-    if (mHandle == nullptr) {
-        int ret, stride;
-        ret = gralloc_open(mHw, &mAllocDev);
-        assert(ret == 0 && "Fail to open GPU device");
-        ret = mAllocDev->alloc(mAllocDev,
-                               mFbDev->width, mFbDev->height, mFbDev->format,
-                               GRALLOC_USAGE_HW_COMPOSER|GRALLOC_USAGE_HW_RENDER,
-                               &mHandle, &stride);
-        assert(ret == 0 && "Fail to allocate target ColorBuffer");
-        mGralloc->registerBuffer(mGralloc, mHandle);
-        ALOGI("targetCb %d", reinterpret_cast<const cb_handle_t*>(mHandle)
-              ->hostHandle);
-    }
-    return reinterpret_cast<const cb_handle_t*>(mHandle)->hostHandle;
+void EmuHWC2::freeDisplayColorBuffer(const native_handle_t* h) {
+    mCbManager.freeBuffer(h);
 }
 
 // Display functions
 
+#define VSYNC_PERIOD_PROP "ro.kernel.qemu.vsync"
+
+static int getVsyncPeriodFromProperty() {
+    char displaysValue[PROPERTY_VALUE_MAX] = "";
+    property_get(VSYNC_PERIOD_PROP, displaysValue, "");
+    bool isValid = displaysValue[0] != '\0';
+
+    if (!isValid) return 60;
+
+    long vsyncPeriodParsed = strtol(displaysValue, 0, 10);
+
+    // On failure, strtol returns 0. Also, there's no reason to have 0
+    // as the vsync period.
+    if (!vsyncPeriodParsed) return 60;
+
+    return static_cast<int>(vsyncPeriodParsed);
+}
+
 std::atomic<hwc2_display_t> EmuHWC2::Display::sNextId(0);
 
 EmuHWC2::Display::Display(EmuHWC2& device, DisplayType type)
   : mDevice(device),
     mId(sNextId++),
+    mHostDisplayId(0),
     mName(),
     mType(type),
     mPowerMode(PowerMode::Off),
     mVsyncEnabled(Vsync::Invalid),
-    mVsyncPeriod(1000*1000*1000/60), // vsync is 60 hz
+    mVsyncPeriod(1000*1000*1000/getVsyncPeriodFromProperty()), // vsync is 60 hz
     mVsyncThread(*this),
     mClientTarget(),
     mChanges(),
@@ -414,10 +444,14 @@
     mActiveConfig(nullptr),
     mColorModes(),
     mSetColorTransform(false),
-    mStateMutex()
-    {
-        mVsyncThread.run("", HAL_PRIORITY_URGENT_DISPLAY);
-    }
+    mStateMutex() {
+        mVsyncThread.run("", -19 /* ANDROID_PRIORITY_URGENT_AUDIO */);
+        mTargetCb = device.allocateDisplayColorBuffer();
+}
+
+EmuHWC2::Display::~Display() {
+    mDevice.freeDisplayColorBuffer(mTargetCb);
+}
 
 Error EmuHWC2::Display::acceptChanges() {
     ALOGVV("%s: displayId %u", __FUNCTION__, (uint32_t)mId);
@@ -696,9 +730,15 @@
     DEFINE_AND_VALIDATE_HOST_CONNECTION
     hostCon->lock();
     bool hostCompositionV1 = rcEnc->hasHostCompositionV1();
+    bool hostCompositionV2 = rcEnc->hasHostCompositionV2();
     hostCon->unlock();
 
-    if (hostCompositionV1) {
+    // if we supports v2, then discard v1
+    if (hostCompositionV2) {
+        hostCompositionV1 = false;
+    }
+
+    if (hostCompositionV2 || hostCompositionV1) {
         uint32_t numLayer = 0;
         for (auto layer: mLayers) {
             if (layer->getCompositionType() == Composition::Device ||
@@ -714,19 +754,36 @@
         mReleaseFences.clear();
 
         if (numLayer == 0) {
-            ALOGVV("No layers, exit");
-            mGralloc->getFb()->post(mGralloc->getFb(), mClientTarget.getBuffer());
-            *outRetireFence = mClientTarget.getFence();
+            ALOGW("No layers, exit, buffer %p", mClientTarget.getBuffer());
+            if (mClientTarget.getBuffer()) {
+                post(hostCon, rcEnc, mClientTarget.getBuffer());
+                *outRetireFence = mClientTarget.getFence();
+            }
             return Error::None;
         }
 
-        if (mComposeMsg == nullptr || mComposeMsg->getLayerCnt() < numLayer) {
-            mComposeMsg.reset(new ComposeMsg(numLayer));
+        if (hostCompositionV1) {
+            if (mComposeMsg == nullptr || mComposeMsg->getLayerCnt() < numLayer) {
+                mComposeMsg.reset(new ComposeMsg(numLayer));
+            }
+        } else {
+            if (mComposeMsg_v2 == nullptr || mComposeMsg_v2->getLayerCnt() < numLayer) {
+                mComposeMsg_v2.reset(new ComposeMsg_v2(numLayer));
+            }
         }
 
         // Handle the composition
-        ComposeDevice* p = mComposeMsg->get();
-        ComposeLayer* l = p->layer;
+        ComposeDevice* p;
+        ComposeDevice_v2* p2;
+        ComposeLayer* l;
+
+        if (hostCompositionV1) {
+            p = mComposeMsg->get();
+            l = p->layer;
+        } else {
+            p2 = mComposeMsg_v2->get();
+            l = p2->layer;
+        }
 
         for (auto layer: mLayers) {
             if (layer->getCompositionType() != Composition::Device &&
@@ -752,10 +809,10 @@
                     ALOGV("%s: acquire fence not set for layer %u",
                           __FUNCTION__, (uint32_t)layer->getId());
                 }
-                cb_handle_t *cb =
-                    (cb_handle_t *)layer->getLayerBuffer().getBuffer();
+                const native_handle_t *cb =
+                    layer->getLayerBuffer().getBuffer();
                 if (cb != nullptr) {
-                    l->cbHandle = cb->hostHandle;
+                    l->cbHandle = hostCon->grallocHelper()->getHostHandle(cb);
                 }
                 else {
                     ALOGE("%s null buffer for layer %d", __FUNCTION__,
@@ -781,14 +838,28 @@
                   layer->getZ(), l->composeMode, l->transform);
             l++;
         }
-        p->version = 1;
-        p->targetHandle = mGralloc->getTargetCb();
-        p->numLayers = numLayer;
+        if (hostCompositionV1) {
+            p->version = 1;
+            p->targetHandle = hostCon->grallocHelper()->getHostHandle(mTargetCb);
+            p->numLayers = numLayer;
+        } else {
+            p2->version = 2;
+            p2->displayId = mHostDisplayId;
+            p2->targetHandle = hostCon->grallocHelper()->getHostHandle(mTargetCb);
+            p2->numLayers = numLayer;
+        }
 
         hostCon->lock();
-        rcEnc->rcCompose(rcEnc,
-                         sizeof(ComposeDevice) + numLayer * sizeof(ComposeLayer),
-                         (void *)p);
+        if (hostCompositionV1) {
+            rcEnc->rcCompose(rcEnc,
+                             sizeof(ComposeDevice) + numLayer * sizeof(ComposeLayer),
+                             (void *)p);
+        } else {
+            rcEnc->rcCompose(rcEnc,
+                             sizeof(ComposeDevice_v2) + numLayer * sizeof(ComposeLayer),
+                             (void *)p2);
+        }
+
         hostCon->unlock();
 
         // Send a retire fence and use it as the release fence for all layers,
@@ -818,7 +889,7 @@
         hostCon->unlock();
     } else {
         // we set all layers Composition::Client, so do nothing.
-        mGralloc->getFb()->post(mGralloc->getFb(), mClientTarget.getBuffer());
+        post(hostCon, rcEnc, mClientTarget.getBuffer());
         *outRetireFence = mClientTarget.getFence();
         ALOGV("%s fallback to post, returns outRetireFence %d",
               __FUNCTION__, *outRetireFence);
@@ -849,10 +920,6 @@
         int32_t acquireFence, int32_t /*dataspace*/, hwc_region_t /*damage*/) {
     ALOGVV("%s", __FUNCTION__);
 
-    cb_handle_t *cb =
-            (cb_handle_t *)target;
-    ALOGV("%s: display(%u) buffer handle %p cb %d, acquireFence %d", __FUNCTION__,
-          (uint32_t)mId, target, cb->hostHandle, acquireFence);
     std::unique_lock<std::mutex> lock(mStateMutex);
     mClientTarget.setBuffer(target);
     mClientTarget.setFence(acquireFence);
@@ -960,9 +1027,10 @@
         DEFINE_AND_VALIDATE_HOST_CONNECTION
         hostCon->lock();
         bool hostCompositionV1 = rcEnc->hasHostCompositionV1();
+        bool hostCompositionV2 = rcEnc->hasHostCompositionV2();
         hostCon->unlock();
 
-        if (hostCompositionV1) {
+        if (hostCompositionV1 || hostCompositionV2) {
             // Support Device and SolidColor, otherwise, fallback all layers
             // to Client
             bool fallBack = false;
@@ -1073,19 +1141,150 @@
     return Error::None;
 }
 
+// thess EDIDs are carefully generated according to the EDID spec version 1.3, more info
+// can be found from the following file:
+//   frameworks/native/services/surfaceflinger/DisplayHardware/DisplayIdentification.cpp
+// approved pnp ids can be found here: https://uefi.org/pnp_id_list
+// pnp id: GGL, name: EMU_display_0, last byte is checksum
+// display id is local:8141603649153536
+static const uint8_t sEDID0[] = {
+    0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x1c, 0xec, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00,
+    0x1b, 0x10, 0x01, 0x03, 0x80, 0x50, 0x2d, 0x78, 0x0a, 0x0d, 0xc9, 0xa0, 0x57, 0x47, 0x98, 0x27,
+    0x12, 0x48, 0x4c, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+    0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x3a, 0x80, 0x18, 0x71, 0x38, 0x2d, 0x40, 0x58, 0x2c,
+    0x45, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc,
+    0x00, 0x45, 0x4d, 0x55, 0x5f, 0x64, 0x69, 0x73, 0x70, 0x6c, 0x61, 0x79, 0x5f, 0x30, 0x00, 0x4b
+};
 
-int EmuHWC2::Display::populatePrimaryConfigs() {
+// pnp id: GGL, name: EMU_display_1
+// display id is local:8140900251843329
+static const uint8_t sEDID1[] = {
+    0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x1c, 0xec, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00,
+    0x1b, 0x10, 0x01, 0x03, 0x80, 0x50, 0x2d, 0x78, 0x0a, 0x0d, 0xc9, 0xa0, 0x57, 0x47, 0x98, 0x27,
+    0x12, 0x48, 0x4c, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+    0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x3a, 0x80, 0x18, 0x71, 0x38, 0x2d, 0x40, 0x58, 0x2c,
+    0x54, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc,
+    0x00, 0x45, 0x4d, 0x55, 0x5f, 0x64, 0x69, 0x73, 0x70, 0x6c, 0x61, 0x79, 0x5f, 0x31, 0x00, 0x3b
+};
+
+// pnp id: GGL, name: EMU_display_2
+// display id is local:8140940453066754
+static const uint8_t sEDID2[] = {
+    0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x1c, 0xec, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00,
+    0x1b, 0x10, 0x01, 0x03, 0x80, 0x50, 0x2d, 0x78, 0x0a, 0x0d, 0xc9, 0xa0, 0x57, 0x47, 0x98, 0x27,
+    0x12, 0x48, 0x4c, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+    0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x3a, 0x80, 0x18, 0x71, 0x38, 0x2d, 0x40, 0x58, 0x2c,
+    0x45, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc,
+    0x00, 0x45, 0x4d, 0x55, 0x5f, 0x64, 0x69, 0x73, 0x70, 0x6c, 0x61, 0x79, 0x5f, 0x32, 0x00, 0x49
+};
+
+#define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0]))
+
+Error EmuHWC2::Display::getDisplayIdentificationData(uint8_t* outPort,
+        uint32_t* outDataSize, uint8_t* outData) {
+    ALOGVV("%s DisplayId %u", __FUNCTION__, (uint32_t)mId);
+    if (outPort == nullptr || outDataSize == nullptr)
+        return Error::BadParameter;
+
+    uint32_t len = std::min(*outDataSize, (uint32_t)ARRAY_SIZE(sEDID0));
+    if (outData != nullptr && len < (uint32_t)ARRAY_SIZE(sEDID0)) {
+        ALOGW("%s DisplayId %u, small buffer size: %u is specified",
+                __FUNCTION__, (uint32_t)mId, len);
+    }
+    *outDataSize = ARRAY_SIZE(sEDID0);
+    switch (mId) {
+        case 0:
+            *outPort = 0;
+            if (outData)
+                memcpy(outData, sEDID0, len);
+            break;
+
+        case 1:
+            *outPort = 1;
+            if (outData)
+                memcpy(outData, sEDID1, len);
+            break;
+
+        case 2:
+            *outPort = 2;
+            if (outData)
+                memcpy(outData, sEDID2, len);
+            break;
+
+        default:
+            *outPort = (uint8_t)mId;
+            if (outData) {
+                memcpy(outData, sEDID2, len);
+                uint32_t size = ARRAY_SIZE(sEDID0);
+                // change the name to EMU_display_<mID>
+                // note the 3rd char from back is the number, _0, _1, _2, etc.
+                if (len >= size - 2)
+                    outData[size-3] = '0' + (uint8_t)mId;
+                if (len >= size) {
+                    // update the last byte, which is checksum byte
+                    uint8_t checksum = -(uint8_t)std::accumulate(
+                            outData, outData + size - 1, static_cast<uint8_t>(0));
+                    outData[size - 1] = checksum;
+                }
+            }
+            break;
+    }
+
+    return Error::None;
+}
+
+Error EmuHWC2::Display::getDisplayCapabilities(uint32_t* outNumCapabilities,
+        uint32_t* outCapabilities) {
+    if (outNumCapabilities == nullptr) {
+        return Error::None;
+    }
+
+    bool brightness_support = true;
+    bool doze_support = true;
+
+    uint32_t count = 1  + static_cast<uint32_t>(doze_support) + (brightness_support ? 1 : 0);
+    int index = 0;
+    if (outCapabilities != nullptr && (*outNumCapabilities >= count)) {
+        outCapabilities[index++] = HWC2_DISPLAY_CAPABILITY_SKIP_CLIENT_COLOR_TRANSFORM;
+        if (doze_support) {
+            outCapabilities[index++] = HWC2_DISPLAY_CAPABILITY_DOZE;
+        }
+        if (brightness_support) {
+            outCapabilities[index++] = HWC2_DISPLAY_CAPABILITY_BRIGHTNESS;
+       }
+    }
+
+    *outNumCapabilities = count;
+    return Error::None;
+}
+
+Error EmuHWC2::Display::getDisplayBrightnessSupport(bool *out_support) {
+    *out_support = false;
+    return Error::None;
+}
+
+Error EmuHWC2::Display::setDisplayBrightness(float brightness) {
+    ALOGW("TODO: setDisplayBrightness() is not implemented yet: brightness=%f", brightness);
+    return Error::None;
+}
+
+int EmuHWC2::Display::populatePrimaryConfigs(int width, int height, int dpiX, int dpiY) {
     ALOGVV("%s DisplayId %u", __FUNCTION__, (uint32_t)mId);
     std::unique_lock<std::mutex> lock(mStateMutex);
 
-    mGralloc.reset(new GrallocModule());
     auto newConfig = std::make_shared<Config>(*this);
     // vsync is 60 hz;
     newConfig->setAttribute(Attribute::VsyncPeriod, mVsyncPeriod);
-    newConfig->setAttribute(Attribute::Width, mGralloc->getFb()->width);
-    newConfig->setAttribute(Attribute::Height, mGralloc->getFb()->height);
-    newConfig->setAttribute(Attribute::DpiX, mGralloc->getFb()->xdpi*1000);
-    newConfig->setAttribute(Attribute::DpiY, mGralloc->getFb()->ydpi*1000);
+    newConfig->setAttribute(Attribute::Width, width);
+    newConfig->setAttribute(Attribute::Height, height);
+    newConfig->setAttribute(Attribute::DpiX, dpiX * 1000);
+    newConfig->setAttribute(Attribute::DpiY, dpiY * 1000);
 
     newConfig->setId(static_cast<hwc2_config_t>(mConfigs.size()));
     ALOGV("Found new config %d: %s", (uint32_t)newConfig->getId(),
@@ -1102,6 +1301,55 @@
     return 0;
 }
 
+void EmuHWC2::Display::post(HostConnection *hostCon,
+                            ExtendedRCEncoderContext *rcEnc,
+                            buffer_handle_t h) {
+    assert(cb && "native_handle_t::from(h) failed");
+
+    hostCon->lock();
+    rcEnc->rcFBPost(rcEnc, hostCon->grallocHelper()->getHostHandle(h));
+    hostCon->flush();
+    hostCon->unlock();
+}
+
+HWC2::Error EmuHWC2::Display::populateSecondaryConfigs(uint32_t width, uint32_t height,
+        uint32_t dpi) {
+    ALOGVV("%s DisplayId %u, width %u, height %u, dpi %u",
+            __FUNCTION__, (uint32_t)mId, width, height, dpi);
+    std::unique_lock<std::mutex> lock(mStateMutex);
+
+    auto newConfig = std::make_shared<Config>(*this);
+    // vsync is 60 hz;
+    newConfig->setAttribute(Attribute::VsyncPeriod, mVsyncPeriod);
+    newConfig->setAttribute(Attribute::Width, width);
+    newConfig->setAttribute(Attribute::Height, height);
+    newConfig->setAttribute(Attribute::DpiX, dpi*1000);
+    newConfig->setAttribute(Attribute::DpiY, dpi*1000);
+
+    newConfig->setId(static_cast<hwc2_config_t>(mConfigs.size()));
+    ALOGV("Found new secondary config %d: %s", (uint32_t)newConfig->getId(),
+            newConfig->toString().c_str());
+    mConfigs.emplace_back(std::move(newConfig));
+
+    // we need to reset these values after populatePrimaryConfigs()
+    mActiveConfig = mConfigs[0];
+    mActiveColorMode = HAL_COLOR_MODE_NATIVE;
+    mColorModes.emplace((android_color_mode_t)HAL_COLOR_MODE_NATIVE);
+
+    uint32_t displayId = 0;
+    DEFINE_AND_VALIDATE_HOST_CONNECTION
+
+    hostCon->lock();
+    rcEnc->rcCreateDisplay(rcEnc, &displayId);
+    rcEnc->rcSetDisplayPose(rcEnc, displayId, -1, -1, width, height);
+    hostCon->unlock();
+
+    mHostDisplayId = displayId;
+    ALOGVV("%s: mHostDisplayId=%d", __FUNCTION__, mHostDisplayId);
+
+    return HWC2::Error::None;
+}
+
 
 // Config functions
 
@@ -1147,7 +1395,6 @@
     return output;
 }
 
-
 // VsyncThread function
 bool EmuHWC2::Display::VsyncThread::threadLoop() {
     struct timespec rt;
@@ -1161,19 +1408,38 @@
     int sent = 0;
     int lastSent = 0;
     bool vsyncEnabled = false;
+
     struct timespec wait_time;
     wait_time.tv_sec = 0;
     wait_time.tv_nsec = mDisplay.mVsyncPeriod;
+    const int64_t kOneRefreshNs = mDisplay.mVsyncPeriod;
+    const int64_t kOneSecondNs = 1000ULL * 1000ULL * 1000ULL;
+    int64_t lastTimeNs = -1;
+    int64_t phasedWaitNs = 0;
+    int64_t currentNs = 0;
 
     while (true) {
-        int err = nanosleep(&wait_time, NULL);
-        if (err == -1) {
-            if (errno == EINTR) {
-                break;
-            }
-            ALOGE("%s: error in vsync thread: %s", __FUNCTION__, strerror(errno));
+        clock_gettime(CLOCK_MONOTONIC, &rt);
+        currentNs = rt.tv_nsec + rt.tv_sec * kOneSecondNs;
+
+        if (lastTimeNs < 0) {
+            phasedWaitNs = currentNs + kOneRefreshNs;
+        } else {
+            phasedWaitNs = kOneRefreshNs *
+                (( currentNs - lastTimeNs) / kOneRefreshNs + 1) +
+                lastTimeNs;
         }
 
+        wait_time.tv_sec = phasedWaitNs / kOneSecondNs;
+        wait_time.tv_nsec = phasedWaitNs - wait_time.tv_sec * kOneSecondNs;
+
+        int ret;
+        do {
+            ret = clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, &wait_time, NULL);
+        } while (ret == -1 && errno == EINTR);
+
+        lastTimeNs = phasedWaitNs;
+
         std::unique_lock<std::mutex> lock(mDisplay.mStateMutex);
         vsyncEnabled = (mDisplay.mVsyncEnabled == Vsync::Enable);
         lock.unlock();
@@ -1182,20 +1448,13 @@
             continue;
         }
 
-        if (clock_gettime(CLOCK_MONOTONIC, &rt) == -1) {
-            ALOGE("%s: error in vsync thread clock_gettime: %s",
-                 __FUNCTION__, strerror(errno));
-        }
-
-        int64_t timestamp = int64_t(rt.tv_sec) * 1e9 + rt.tv_nsec;
-
         lock.lock();
         const auto& callbackInfo = mDisplay.mDevice.mCallbacks[Callback::Vsync];
         auto vsync = reinterpret_cast<HWC2_PFN_VSYNC>(callbackInfo.pointer);
         lock.unlock();
 
         if (vsync) {
-            vsync(callbackInfo.data, mDisplay.mId, timestamp);
+            vsync(callbackInfo.data, mDisplay.mId, lastTimeNs);
         }
 
         if (rt.tv_sec - lastLogged >= logInterval) {
@@ -1353,7 +1612,8 @@
 int EmuHWC2::populatePrimary() {
     int ret = 0;
     auto display = std::make_shared<Display>(*this, HWC2::DisplayType::Physical);
-    ret = display->populatePrimaryConfigs();
+    ret = display->populatePrimaryConfigs(mDisplayWidth, mDisplayHeight,
+                                          mDisplayDpiX, mDisplayDpiY);
     if (ret != 0) {
         return ret;
     }
@@ -1361,9 +1621,74 @@
     return ret;
 }
 
+// Note "hwservicemanager." is used to avoid selinux issue
+#define EXTERANL_DISPLAY_PROP "hwservicemanager.external.displays"
+
+// return 0 for successful, 1 if no external displays are specified
+// return < 0 if failed
+int EmuHWC2::populateSecondaryDisplays() {
+    // this guest property, hwservicemanager.external.displays,
+    // specifies multi-display info, with comma (,) as separator
+    // each display has the following info:
+    //   physicalId,width,height,dpi,flags
+    // serveral displays can be provided, e.g., following has 2 displays:
+    // setprop hwservicemanager.external.displays 1,1200,800,120,0,2,1200,800,120,0
+    std::vector<uint64_t> values;
+    char displaysValue[PROPERTY_VALUE_MAX] = "";
+    property_get(EXTERANL_DISPLAY_PROP, displaysValue, "");
+    bool isValid = displaysValue[0] != '\0';
+    if (isValid) {
+        char *p = displaysValue;
+        while (*p) {
+            if (!isdigit(*p) && *p != ',' && *p != ' ') {
+                isValid = false;
+                break;
+            }
+            p ++;
+        }
+        if (!isValid) {
+            ALOGE("Invalid syntax for the value of system prop: %s", EXTERANL_DISPLAY_PROP);
+        }
+    }
+    if (!isValid) {
+        // no external displays are specified
+        return 1;
+    }
+    // parse all int values to a vector
+    std::istringstream stream(displaysValue);
+    for (uint64_t id; stream >> id;) {
+        values.push_back(id);
+        if (stream.peek() == ',')
+            stream.ignore();
+    }
+    // each display has 5 values
+    if ((values.size() % 5) != 0) {
+        ALOGE("%s: invalid value for system property: %s", __FUNCTION__, EXTERANL_DISPLAY_PROP);
+        return -1;
+    }
+    while (!values.empty()) {
+        // uint64_t physicalId = values[0];
+        uint32_t width = values[1];
+        uint32_t height = values[2];
+        uint32_t dpi = values[3];
+        // uint32_t flags = values[4];
+        values.erase(values.begin(), values.begin() + 5);
+
+        Error ret = Error::None;
+        auto display = std::make_shared<Display>(*this, HWC2::DisplayType::Physical);
+        ret = display->populateSecondaryConfigs(width, height, dpi);
+        if (ret != Error::None) {
+            return -2;
+        }
+        mDisplays.emplace(display->getId(), std::move(display));
+    }
+    return 0;
+}
+
 EmuHWC2::Display* EmuHWC2::getDisplay(hwc2_display_t id) {
     auto display = mDisplays.find(id);
     if (display == mDisplays.end()) {
+        ALOGE("Failed to get display for id=%d", (uint32_t)id);
         return nullptr;
     }
     return display->second.get();
@@ -1411,6 +1736,12 @@
         return ret;
     }
 
+    ret = ctx->populateSecondaryDisplays();
+    if (ret < 0) {
+        ALOGE("Failed to populate secondary displays");
+        return ret;
+    }
+
     ctx->common.module = const_cast<hw_module_t *>(module);
     *dev = &ctx->common;
     return 0;
diff --git a/system/hwc2/EmuHWC2.h b/system/hwc2/EmuHWC2.h
index 14e7cec..8cb71c1 100644
--- a/system/hwc2/EmuHWC2.h
+++ b/system/hwc2/EmuHWC2.h
@@ -27,12 +27,16 @@
 #include <atomic>
 #include <map>
 #include <mutex>
+#include <numeric>
+#include <sstream>
 #include <vector>
 #include <unordered_set>
 #include <unordered_map>
 #include <set>
 
-#include "gralloc_cb.h"
+#include <cutils/native_handle.h>
+
+#include "cbmanager.h"
 #include "MiniFence.h"
 #include "HostConnection.h"
 
@@ -42,6 +46,7 @@
 public:
     EmuHWC2();
     int populatePrimary();
+    int populateSecondaryDisplays();
 
 private:
     static inline EmuHWC2* getHWC2(hwc2_device_t* device) {
@@ -134,20 +139,6 @@
             sp<MiniFence> mFence;
     };
 
-    class GrallocModule {
-    public:
-        GrallocModule();
-        ~GrallocModule();
-        framebuffer_device_t* getFb() { return mFbDev; }
-        uint32_t getTargetCb();
-    private:
-        const hw_module_t* mHw = nullptr;
-        const gralloc_module_t* mGralloc = nullptr;
-        alloc_device_t* mAllocDev = nullptr;
-        framebuffer_device_t* mFbDev = nullptr;
-        buffer_handle_t mHandle = nullptr;
-    };
-
     typedef struct compose_layer {
         uint32_t cbHandle;
         hwc2_composition_t composeMode;
@@ -164,6 +155,13 @@
         uint32_t numLayers;
         struct compose_layer layer[0];
     } ComposeDevice;
+    typedef struct compose_device_v2 {
+        uint32_t version;
+        uint32_t displayId;
+        uint32_t targetHandle;
+        uint32_t numLayers;
+        struct compose_layer layer[0];
+    } ComposeDevice_v2;
 
     class ComposeMsg {
     public:
@@ -184,9 +182,29 @@
         ComposeDevice* mComposeDevice;
     };
 
+    class ComposeMsg_v2 {
+    public:
+        ComposeMsg_v2(uint32_t layerCnt = 0) :
+          mData(sizeof(ComposeDevice_v2) + layerCnt * sizeof(ComposeLayer))
+        {
+            mComposeDevice = reinterpret_cast<ComposeDevice_v2*>(mData.data());
+            mLayerCnt = layerCnt;
+        }
+
+        ComposeDevice_v2* get() { return mComposeDevice; }
+
+        uint32_t getLayerCnt() { return mLayerCnt; }
+
+    private:
+        std::vector<uint8_t> mData;
+        uint32_t mLayerCnt;
+        ComposeDevice_v2* mComposeDevice;
+    };
+
     class Display {
     public:
         Display(EmuHWC2& device, HWC2::DisplayType type);
+        ~Display();
         hwc2_display_t getId() const {return mId;}
 
         // HWC2 Display functions
@@ -229,11 +247,23 @@
         HWC2::Error updateLayerZ(hwc2_layer_t layerId, uint32_t z);
         HWC2::Error getClientTargetSupport(uint32_t width, uint32_t height,
                  int32_t format, int32_t dataspace);
+        // 2.3 required functions
+        HWC2::Error getDisplayIdentificationData(uint8_t* outPort,
+                 uint32_t* outDataSize, uint8_t* outData);
+        HWC2::Error getDisplayCapabilities(uint32_t* outNumCapabilities,
+                 uint32_t* outCapabilities);
+        HWC2::Error getDisplayBrightnessSupport(bool *out_support);
+        HWC2::Error setDisplayBrightness(float brightness);
 
         // Read configs from PRIMARY Display
-        int populatePrimaryConfigs();
+        int populatePrimaryConfigs(int width, int height, int dpiX, int dpiY);
+        HWC2::Error populateSecondaryConfigs(uint32_t width, uint32_t height,
+                 uint32_t dpi);
 
     private:
+        void post(HostConnection *hostCon, ExtendedRCEncoderContext *rcEnc,
+                  buffer_handle_t h);
+
         class Config {
         public:
             Config(Display& display)
@@ -315,6 +345,8 @@
         // Display ID generator.
         static std::atomic<hwc2_display_t> sNextId;
         const hwc2_display_t mId;
+        // emulator side displayId
+        uint32_t mHostDisplayId;
         std::string mName;
         HWC2::DisplayType mType;
         HWC2::PowerMode mPowerMode;
@@ -339,11 +371,11 @@
         // called. To prevent a bad state from crashing us during a dump
         // call, all public calls into Display must acquire this mutex.
         mutable std::mutex mStateMutex;
-        std::unique_ptr<GrallocModule> mGralloc;
         std::unique_ptr<ComposeMsg> mComposeMsg;
+        std::unique_ptr<ComposeMsg_v2> mComposeMsg_v2;
         int mSyncDeviceFd;
-
-   };
+        const native_handle_t* mTargetCb;
+    };
 
     template<typename MF, MF memFunc, typename ...Args>
     static int32_t displayHook(hwc2_device_t* device, hwc2_display_t displayId,
@@ -431,6 +463,11 @@
     std::tuple<Layer*, HWC2::Error> getLayer(hwc2_display_t displayId,
             hwc2_layer_t layerId);
 
+    HWC2::Error initDisplayParameters();
+    const native_handle_t* allocateDisplayColorBuffer();
+    void freeDisplayColorBuffer(const native_handle_t* h);
+
+    CbManager mCbManager;
     std::unordered_set<HWC2::Capability> mCapabilities;
 
     // These are potentially accessed from multiple threads, and are protected
@@ -443,9 +480,14 @@
     };
     std::unordered_map<HWC2::Callback, CallbackInfo> mCallbacks;
 
-    std::unordered_map<hwc2_display_t, std::shared_ptr<Display>> mDisplays;
+    // use map so displays can be pluged in by order of ID, 0, 1, 2, 3, etc.
+    std::map<hwc2_display_t, std::shared_ptr<Display>> mDisplays;
     std::unordered_map<hwc2_layer_t, std::shared_ptr<Layer>> mLayers;
 
+    int mDisplayWidth;
+    int mDisplayHeight;
+    int mDisplayDpiX;
+    int mDisplayDpiY;
 };
 
 }
diff --git a/system/include/cbmanager.h b/system/include/cbmanager.h
new file mode 100644
index 0000000..4bddedb
--- /dev/null
+++ b/system/include/cbmanager.h
@@ -0,0 +1,143 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_GOLDFISH_OPENGL_SYSTEM_CBMANAGER_CBMANAGER_H
+#define ANDROID_GOLDFISH_OPENGL_SYSTEM_CBMANAGER_CBMANAGER_H
+
+#include <cutils/native_handle.h>
+#include <log/log.h>
+
+#include <memory>
+#include <android/hardware/graphics/common/1.0/types.h>
+#include <android/hardware/graphics/mapper/2.0/IMapper.h>
+
+#include "gralloc_cb.h"
+
+namespace android {
+
+class CbManager {
+public:
+    typedef hardware::graphics::common::V1_0::BufferUsage BufferUsage;
+    typedef hardware::graphics::common::V1_0::PixelFormat PixelFormat;
+    typedef hardware::graphics::mapper::V2_0::YCbCrLayout YCbCrLayout;
+    typedef hardware::hidl_bitfield<BufferUsage> BufferUsageBits;
+
+    CbManager();
+
+    class CbManagerImpl {
+    public:
+        virtual ~CbManagerImpl() {}
+        virtual native_handle_t* allocateBuffer(int width,
+                                                int height,
+                                                PixelFormat format,
+                                                BufferUsageBits usage) = 0;
+        virtual void freeBuffer(const native_handle_t* h) = 0;
+
+        virtual int lockBuffer(native_handle_t& handle,
+             BufferUsageBits usage,
+             int left, int top, int width, int height,
+             void** vaddr) = 0;
+
+        virtual int lockYCbCrBuffer(native_handle_t& handle,
+             BufferUsageBits usage,
+             int left, int top, int width, int height,
+             YCbCrLayout* ycbcr) = 0;
+
+        virtual int unlockBuffer(native_handle_t& handle) = 0;
+    };
+
+    native_handle_t* allocateBuffer(
+        int width, int height, PixelFormat format, BufferUsageBits usage) {
+        return mImpl->allocateBuffer(width, height, format, usage);
+    }
+
+    void freeBuffer(const native_handle_t* h) {
+        mImpl->freeBuffer(h);
+    }
+
+    int lockBuffer(native_handle_t& handle,
+             BufferUsageBits usage,
+             int left, int top, int width, int height,
+             void** vaddr) {
+        return mImpl->lockBuffer(handle, usage, left, top, width, height, vaddr);
+    }
+
+    int lockBuffer(buffer_handle_t h,
+             BufferUsageBits usage,
+             int left, int top, int width, int height,
+             void** vaddr) {
+        native_handle_t* cb = const_cast<native_handle_t*>(h);
+        if (cb) {
+            return lockBuffer(*cb, usage, left, top, width, height, vaddr);
+        } else {
+            return -1;
+        }
+    }
+
+
+    int lockYCbCrBuffer(native_handle_t& handle,
+                        BufferUsageBits usage,
+                        int left, int top, int width, int height,
+                        YCbCrLayout* ycbcr) {
+        return mImpl->lockYCbCrBuffer(handle, usage, left, top, width, height, ycbcr);
+    }
+
+    int lockYCbCrBuffer(buffer_handle_t h,
+                        BufferUsageBits usage,
+                        int left, int top, int width, int height,
+                        YCbCrLayout* ycbcr) {
+        native_handle_t* cb = const_cast<native_handle_t*>(h);
+        if (cb) {
+            return lockYCbCrBuffer(*cb, usage, left, top, width, height, ycbcr);
+        } else {
+            return -1;
+        }
+    }
+
+    int unlockBuffer(native_handle_t& handle) {
+        return mImpl->unlockBuffer(handle);
+    }
+
+    int unlockBuffer(buffer_handle_t h) {
+        native_handle_t* cb = const_cast<native_handle_t*>(h);
+        if (cb) {
+            return unlockBuffer(*cb);
+        } else {
+            return -1;
+        }
+    }
+
+    // Specific to goldfish, for obtaining offsets
+    // into host coherent memory
+    // (requires address space devce)
+    static uint64_t getOffset(const buffer_handle_t h) {
+        const cb_handle_t* cb = cb_handle_t::from(h);
+        if (!cb->isValid()) {
+            ALOGE("%s: FATAL: using incompatible native_handle_t for "
+                  "host coherent mapping offset",
+                  __func__);
+            abort();
+        }
+        return cb ? cb->getMmapedOffset() : -1;
+    }
+
+private:
+    std::unique_ptr<CbManagerImpl> mImpl;
+};
+
+}  // namespace android
+
+#endif  // ANDROID_GOLDFISH_OPENGL_SYSTEM_CBMANAGER_CBMANAGER_H
diff --git a/system/renderControl_enc/Android.mk b/system/renderControl_enc/Android.mk
index fa90bcb..f2cce50 100644
--- a/system/renderControl_enc/Android.mk
+++ b/system/renderControl_enc/Android.mk
@@ -2,6 +2,9 @@
 
 $(call emugl-begin-shared-library,lib_renderControl_enc)
 
+LOCAL_CFLAGS += \
+    -Wno-unused-function \
+
 LOCAL_SRC_FILES := \
     renderControl_client_context.cpp \
     renderControl_enc.cpp \
diff --git a/system/renderControl_enc/CMakeLists.txt b/system/renderControl_enc/CMakeLists.txt
index 40280fd..c874e25 100644
--- a/system/renderControl_enc/CMakeLists.txt
+++ b/system/renderControl_enc/CMakeLists.txt
@@ -1,10 +1,10 @@
 # This is an autogenerated file! Do not edit!
 # instead run make from .../device/generic/goldfish-opengl
 # which will re-generate this file.
-android_validate_sha256("${GOLDFISH_DEVICE_ROOT}/system/renderControl_enc/Android.mk" "f314acdb6134d3e545889739e6e9bf8837177ce2f3318106394c7656c5d8b992")
+android_validate_sha256("${GOLDFISH_DEVICE_ROOT}/system/renderControl_enc/Android.mk" "780a007ac7a3d2255372ddf40e03aeb10e4c759343d2532f6ddf769f4df73810")
 set(_renderControl_enc_src renderControl_client_context.cpp renderControl_enc.cpp renderControl_entry.cpp)
-android_add_shared_library(_renderControl_enc)
+android_add_library(TARGET _renderControl_enc SHARED LICENSE Apache-2.0 SRC renderControl_client_context.cpp renderControl_enc.cpp renderControl_entry.cpp)
 target_include_directories(_renderControl_enc PRIVATE ${GOLDFISH_DEVICE_ROOT}/shared/OpenglCodecCommon ${GOLDFISH_DEVICE_ROOT}/system/renderControl_enc ${GOLDFISH_DEVICE_ROOT}/./host/include/libOpenglRender ${GOLDFISH_DEVICE_ROOT}/./system/include ${GOLDFISH_DEVICE_ROOT}/./../../../external/qemu/android/android-emugl/guest)
 target_compile_definitions(_renderControl_enc PRIVATE "-DWITH_GLES2" "-DPLATFORM_SDK_VERSION=29" "-DGOLDFISH_HIDL_GRALLOC" "-DEMULATOR_OPENGL_POST_O=1" "-DHOST_BUILD" "-DANDROID" "-DGL_GLEXT_PROTOTYPES" "-DPAGE_SIZE=4096" "-DGOLDFISH_VULKAN")
-target_compile_options(_renderControl_enc PRIVATE "-fvisibility=default")
+target_compile_options(_renderControl_enc PRIVATE "-fvisibility=default" "-Wno-unused-parameter" "-Wno-unused-function")
 target_link_libraries(_renderControl_enc PRIVATE OpenglCodecCommon_host cutils utils log android-emu-shared)
\ No newline at end of file
diff --git a/system/renderControl_enc/renderControl_client_context.cpp b/system/renderControl_enc/renderControl_client_context.cpp
index 839f595..54c3f93 100644
--- a/system/renderControl_enc/renderControl_client_context.cpp
+++ b/system/renderControl_enc/renderControl_client_context.cpp
@@ -55,6 +55,9 @@
 	rcGetColorBufferDisplay = (rcGetColorBufferDisplay_client_proc_t) getProc("rcGetColorBufferDisplay", userData);
 	rcGetDisplayPose = (rcGetDisplayPose_client_proc_t) getProc("rcGetDisplayPose", userData);
 	rcSetDisplayPose = (rcSetDisplayPose_client_proc_t) getProc("rcSetDisplayPose", userData);
+	rcSetColorBufferVulkanMode = (rcSetColorBufferVulkanMode_client_proc_t) getProc("rcSetColorBufferVulkanMode", userData);
+	rcReadColorBufferYUV = (rcReadColorBufferYUV_client_proc_t) getProc("rcReadColorBufferYUV", userData);
+	rcIsSyncSignaled = (rcIsSyncSignaled_client_proc_t) getProc("rcIsSyncSignaled", userData);
 	return 0;
 }
 
diff --git a/system/renderControl_enc/renderControl_client_context.h b/system/renderControl_enc/renderControl_client_context.h
index bcfb7a0..12486c3 100644
--- a/system/renderControl_enc/renderControl_client_context.h
+++ b/system/renderControl_enc/renderControl_client_context.h
@@ -55,6 +55,9 @@
 	rcGetColorBufferDisplay_client_proc_t rcGetColorBufferDisplay;
 	rcGetDisplayPose_client_proc_t rcGetDisplayPose;
 	rcSetDisplayPose_client_proc_t rcSetDisplayPose;
+	rcSetColorBufferVulkanMode_client_proc_t rcSetColorBufferVulkanMode;
+	rcReadColorBufferYUV_client_proc_t rcReadColorBufferYUV;
+	rcIsSyncSignaled_client_proc_t rcIsSyncSignaled;
 	virtual ~renderControl_client_context_t() {}
 
 	typedef renderControl_client_context_t *CONTEXT_ACCESSOR_TYPE(void);
diff --git a/system/renderControl_enc/renderControl_client_proc.h b/system/renderControl_enc/renderControl_client_proc.h
index 71160a3..d64cf5c 100644
--- a/system/renderControl_enc/renderControl_client_proc.h
+++ b/system/renderControl_enc/renderControl_client_proc.h
@@ -50,13 +50,16 @@
 typedef uint32_t (renderControl_APIENTRY *rcCreateColorBufferDMA_client_proc_t) (void * ctx, uint32_t, uint32_t, GLenum, int);
 typedef void (renderControl_APIENTRY *rcWaitSyncKHR_client_proc_t) (void * ctx, uint64_t, EGLint);
 typedef GLint (renderControl_APIENTRY *rcCompose_client_proc_t) (void * ctx, uint32_t, void*);
-typedef GLint (renderControl_APIENTRY *rcCreateDisplay_client_proc_t) (void * ctx, uint32_t*);
-typedef GLint (renderControl_APIENTRY *rcDestroyDisplay_client_proc_t) (void * ctx, uint32_t);
-typedef GLint (renderControl_APIENTRY *rcSetDisplayColorBuffer_client_proc_t) (void * ctx, uint32_t, uint32_t);
-typedef GLint (renderControl_APIENTRY *rcGetDisplayColorBuffer_client_proc_t) (void * ctx, uint32_t, uint32_t*);
-typedef GLint (renderControl_APIENTRY *rcGetColorBufferDisplay_client_proc_t) (void * ctx, uint32_t, uint32_t*);
-typedef GLint (renderControl_APIENTRY *rcGetDisplayPose_client_proc_t) (void * ctx, uint32_t, uint32_t*, uint32_t*, uint32_t*, uint32_t*);
-typedef GLint (renderControl_APIENTRY *rcSetDisplayPose_client_proc_t) (void * ctx, uint32_t, uint32_t, uint32_t, uint32_t, uint32_t);
+typedef int (renderControl_APIENTRY *rcCreateDisplay_client_proc_t) (void * ctx, uint32_t*);
+typedef int (renderControl_APIENTRY *rcDestroyDisplay_client_proc_t) (void * ctx, uint32_t);
+typedef int (renderControl_APIENTRY *rcSetDisplayColorBuffer_client_proc_t) (void * ctx, uint32_t, uint32_t);
+typedef int (renderControl_APIENTRY *rcGetDisplayColorBuffer_client_proc_t) (void * ctx, uint32_t, uint32_t*);
+typedef int (renderControl_APIENTRY *rcGetColorBufferDisplay_client_proc_t) (void * ctx, uint32_t, uint32_t*);
+typedef int (renderControl_APIENTRY *rcGetDisplayPose_client_proc_t) (void * ctx, uint32_t, GLint*, GLint*, uint32_t*, uint32_t*);
+typedef int (renderControl_APIENTRY *rcSetDisplayPose_client_proc_t) (void * ctx, uint32_t, GLint, GLint, uint32_t, uint32_t);
+typedef GLint (renderControl_APIENTRY *rcSetColorBufferVulkanMode_client_proc_t) (void * ctx, uint32_t, uint32_t);
+typedef void (renderControl_APIENTRY *rcReadColorBufferYUV_client_proc_t) (void * ctx, uint32_t, GLint, GLint, GLint, GLint, void*, uint32_t);
+typedef int (renderControl_APIENTRY *rcIsSyncSignaled_client_proc_t) (void * ctx, uint64_t);
 
 
 #endif
diff --git a/system/renderControl_enc/renderControl_enc.cpp b/system/renderControl_enc/renderControl_enc.cpp
index bd6ad9f..d0c3c75 100644
--- a/system/renderControl_enc/renderControl_enc.cpp
+++ b/system/renderControl_enc/renderControl_enc.cpp
@@ -1436,7 +1436,7 @@
 	return retval;
 }
 
-GLint rcCreateDisplay_enc(void *self , uint32_t* displayId)
+int rcCreateDisplay_enc(void *self , uint32_t* displayId)
 {
 
 	renderControl_encoder_context_t *ctx = (renderControl_encoder_context_t *)self;
@@ -1463,7 +1463,7 @@
 	stream->readback(displayId, __size_displayId);
 	if (useChecksum) checksumCalculator->addBuffer(displayId, __size_displayId);
 
-	GLint retval;
+	int retval;
 	stream->readback(&retval, 4);
 	if (useChecksum) checksumCalculator->addBuffer(&retval, 4);
 	if (useChecksum) {
@@ -1479,7 +1479,7 @@
 	return retval;
 }
 
-GLint rcDestroyDisplay_enc(void *self , uint32_t displayId)
+int rcDestroyDisplay_enc(void *self , uint32_t displayId)
 {
 
 	renderControl_encoder_context_t *ctx = (renderControl_encoder_context_t *)self;
@@ -1503,7 +1503,7 @@
 	if (useChecksum) checksumCalculator->writeChecksum(ptr, checksumSize); ptr += checksumSize;
 
 
-	GLint retval;
+	int retval;
 	stream->readback(&retval, 4);
 	if (useChecksum) checksumCalculator->addBuffer(&retval, 4);
 	if (useChecksum) {
@@ -1519,7 +1519,7 @@
 	return retval;
 }
 
-GLint rcSetDisplayColorBuffer_enc(void *self , uint32_t displayId, uint32_t colorBuffer)
+int rcSetDisplayColorBuffer_enc(void *self , uint32_t displayId, uint32_t colorBuffer)
 {
 
 	renderControl_encoder_context_t *ctx = (renderControl_encoder_context_t *)self;
@@ -1544,7 +1544,7 @@
 	if (useChecksum) checksumCalculator->writeChecksum(ptr, checksumSize); ptr += checksumSize;
 
 
-	GLint retval;
+	int retval;
 	stream->readback(&retval, 4);
 	if (useChecksum) checksumCalculator->addBuffer(&retval, 4);
 	if (useChecksum) {
@@ -1560,7 +1560,7 @@
 	return retval;
 }
 
-GLint rcGetDisplayColorBuffer_enc(void *self , uint32_t displayId, uint32_t* colorBuffer)
+int rcGetDisplayColorBuffer_enc(void *self , uint32_t displayId, uint32_t* colorBuffer)
 {
 
 	renderControl_encoder_context_t *ctx = (renderControl_encoder_context_t *)self;
@@ -1588,7 +1588,7 @@
 	stream->readback(colorBuffer, __size_colorBuffer);
 	if (useChecksum) checksumCalculator->addBuffer(colorBuffer, __size_colorBuffer);
 
-	GLint retval;
+	int retval;
 	stream->readback(&retval, 4);
 	if (useChecksum) checksumCalculator->addBuffer(&retval, 4);
 	if (useChecksum) {
@@ -1604,7 +1604,7 @@
 	return retval;
 }
 
-GLint rcGetColorBufferDisplay_enc(void *self , uint32_t colorBuffer, uint32_t* displayId)
+int rcGetColorBufferDisplay_enc(void *self , uint32_t colorBuffer, uint32_t* displayId)
 {
 
 	renderControl_encoder_context_t *ctx = (renderControl_encoder_context_t *)self;
@@ -1632,7 +1632,7 @@
 	stream->readback(displayId, __size_displayId);
 	if (useChecksum) checksumCalculator->addBuffer(displayId, __size_displayId);
 
-	GLint retval;
+	int retval;
 	stream->readback(&retval, 4);
 	if (useChecksum) checksumCalculator->addBuffer(&retval, 4);
 	if (useChecksum) {
@@ -1648,7 +1648,7 @@
 	return retval;
 }
 
-GLint rcGetDisplayPose_enc(void *self , uint32_t displayId, uint32_t* x, uint32_t* y, uint32_t* w, uint32_t* h)
+int rcGetDisplayPose_enc(void *self , uint32_t displayId, GLint* x, GLint* y, uint32_t* w, uint32_t* h)
 {
 
 	renderControl_encoder_context_t *ctx = (renderControl_encoder_context_t *)self;
@@ -1656,8 +1656,8 @@
 	ChecksumCalculator *checksumCalculator = ctx->m_checksumCalculator;
 	bool useChecksum = checksumCalculator->getVersion() > 0;
 
-	const unsigned int __size_x =  sizeof(uint32_t);
-	const unsigned int __size_y =  sizeof(uint32_t);
+	const unsigned int __size_x =  sizeof(int32_t);
+	const unsigned int __size_y =  sizeof(int32_t);
 	const unsigned int __size_w =  sizeof(uint32_t);
 	const unsigned int __size_h =  sizeof(uint32_t);
 	 unsigned char *ptr;
@@ -1688,7 +1688,7 @@
 	stream->readback(h, __size_h);
 	if (useChecksum) checksumCalculator->addBuffer(h, __size_h);
 
-	GLint retval;
+	int retval;
 	stream->readback(&retval, 4);
 	if (useChecksum) checksumCalculator->addBuffer(&retval, 4);
 	if (useChecksum) {
@@ -1704,7 +1704,7 @@
 	return retval;
 }
 
-GLint rcSetDisplayPose_enc(void *self , uint32_t displayId, uint32_t x, uint32_t y, uint32_t w, uint32_t h)
+int rcSetDisplayPose_enc(void *self , uint32_t displayId, GLint x, GLint y, uint32_t w, uint32_t h)
 {
 
 	renderControl_encoder_context_t *ctx = (renderControl_encoder_context_t *)self;
@@ -1732,7 +1732,7 @@
 	if (useChecksum) checksumCalculator->writeChecksum(ptr, checksumSize); ptr += checksumSize;
 
 
-	GLint retval;
+	int retval;
 	stream->readback(&retval, 4);
 	if (useChecksum) checksumCalculator->addBuffer(&retval, 4);
 	if (useChecksum) {
@@ -1748,6 +1748,131 @@
 	return retval;
 }
 
+GLint rcSetColorBufferVulkanMode_enc(void *self , uint32_t colorBuffer, uint32_t mode)
+{
+
+	renderControl_encoder_context_t *ctx = (renderControl_encoder_context_t *)self;
+	IOStream *stream = ctx->m_stream;
+	ChecksumCalculator *checksumCalculator = ctx->m_checksumCalculator;
+	bool useChecksum = checksumCalculator->getVersion() > 0;
+
+	 unsigned char *ptr;
+	 unsigned char *buf;
+	 const size_t sizeWithoutChecksum = 8 + 4 + 4;
+	 const size_t checksumSize = checksumCalculator->checksumByteSize();
+	 const size_t totalSize = sizeWithoutChecksum + checksumSize;
+	buf = stream->alloc(totalSize);
+	ptr = buf;
+	int tmp = OP_rcSetColorBufferVulkanMode;memcpy(ptr, &tmp, 4); ptr += 4;
+	memcpy(ptr, &totalSize, 4);  ptr += 4;
+
+		memcpy(ptr, &colorBuffer, 4); ptr += 4;
+		memcpy(ptr, &mode, 4); ptr += 4;
+
+	if (useChecksum) checksumCalculator->addBuffer(buf, ptr-buf);
+	if (useChecksum) checksumCalculator->writeChecksum(ptr, checksumSize); ptr += checksumSize;
+
+
+	GLint retval;
+	stream->readback(&retval, 4);
+	if (useChecksum) checksumCalculator->addBuffer(&retval, 4);
+	if (useChecksum) {
+		unsigned char *checksumBufPtr = NULL;
+		unsigned char checksumBuf[ChecksumCalculator::kMaxChecksumSize];
+		if (checksumSize > 0) checksumBufPtr = &checksumBuf[0];
+		stream->readback(checksumBufPtr, checksumSize);
+		if (!checksumCalculator->validate(checksumBufPtr, checksumSize)) {
+			ALOGE("rcSetColorBufferVulkanMode: GL communication error, please report this issue to b.android.com.\n");
+			abort();
+		}
+	}
+	return retval;
+}
+
+void rcReadColorBufferYUV_enc(void *self , uint32_t colorbuffer, GLint x, GLint y, GLint width, GLint height, void* pixels, uint32_t pixels_size)
+{
+
+	renderControl_encoder_context_t *ctx = (renderControl_encoder_context_t *)self;
+	IOStream *stream = ctx->m_stream;
+	ChecksumCalculator *checksumCalculator = ctx->m_checksumCalculator;
+	bool useChecksum = checksumCalculator->getVersion() > 0;
+
+	const unsigned int __size_pixels =  pixels_size;
+	 unsigned char *ptr;
+	 unsigned char *buf;
+	 const size_t sizeWithoutChecksum = 8 + 4 + 4 + 4 + 4 + 4 + 0 + 4 + 1*4;
+	 const size_t checksumSize = checksumCalculator->checksumByteSize();
+	 const size_t totalSize = sizeWithoutChecksum + checksumSize;
+	buf = stream->alloc(totalSize);
+	ptr = buf;
+	int tmp = OP_rcReadColorBufferYUV;memcpy(ptr, &tmp, 4); ptr += 4;
+	memcpy(ptr, &totalSize, 4);  ptr += 4;
+
+		memcpy(ptr, &colorbuffer, 4); ptr += 4;
+		memcpy(ptr, &x, 4); ptr += 4;
+		memcpy(ptr, &y, 4); ptr += 4;
+		memcpy(ptr, &width, 4); ptr += 4;
+		memcpy(ptr, &height, 4); ptr += 4;
+	*(unsigned int *)(ptr) = __size_pixels; ptr += 4;
+		memcpy(ptr, &pixels_size, 4); ptr += 4;
+
+	if (useChecksum) checksumCalculator->addBuffer(buf, ptr-buf);
+	if (useChecksum) checksumCalculator->writeChecksum(ptr, checksumSize); ptr += checksumSize;
+
+	stream->readback(pixels, __size_pixels);
+	if (useChecksum) checksumCalculator->addBuffer(pixels, __size_pixels);
+	if (useChecksum) {
+		unsigned char *checksumBufPtr = NULL;
+		unsigned char checksumBuf[ChecksumCalculator::kMaxChecksumSize];
+		if (checksumSize > 0) checksumBufPtr = &checksumBuf[0];
+		stream->readback(checksumBufPtr, checksumSize);
+		if (!checksumCalculator->validate(checksumBufPtr, checksumSize)) {
+			ALOGE("rcReadColorBufferYUV: GL communication error, please report this issue to b.android.com.\n");
+			abort();
+		}
+	}
+}
+
+int rcIsSyncSignaled_enc(void *self , uint64_t sync)
+{
+
+	renderControl_encoder_context_t *ctx = (renderControl_encoder_context_t *)self;
+	IOStream *stream = ctx->m_stream;
+	ChecksumCalculator *checksumCalculator = ctx->m_checksumCalculator;
+	bool useChecksum = checksumCalculator->getVersion() > 0;
+
+	 unsigned char *ptr;
+	 unsigned char *buf;
+	 const size_t sizeWithoutChecksum = 8 + 8;
+	 const size_t checksumSize = checksumCalculator->checksumByteSize();
+	 const size_t totalSize = sizeWithoutChecksum + checksumSize;
+	buf = stream->alloc(totalSize);
+	ptr = buf;
+	int tmp = OP_rcIsSyncSignaled;memcpy(ptr, &tmp, 4); ptr += 4;
+	memcpy(ptr, &totalSize, 4);  ptr += 4;
+
+		memcpy(ptr, &sync, 8); ptr += 8;
+
+	if (useChecksum) checksumCalculator->addBuffer(buf, ptr-buf);
+	if (useChecksum) checksumCalculator->writeChecksum(ptr, checksumSize); ptr += checksumSize;
+
+
+	int retval;
+	stream->readback(&retval, 4);
+	if (useChecksum) checksumCalculator->addBuffer(&retval, 4);
+	if (useChecksum) {
+		unsigned char *checksumBufPtr = NULL;
+		unsigned char checksumBuf[ChecksumCalculator::kMaxChecksumSize];
+		if (checksumSize > 0) checksumBufPtr = &checksumBuf[0];
+		stream->readback(checksumBufPtr, checksumSize);
+		if (!checksumCalculator->validate(checksumBufPtr, checksumSize)) {
+			ALOGE("rcIsSyncSignaled: GL communication error, please report this issue to b.android.com.\n");
+			abort();
+		}
+	}
+	return retval;
+}
+
 }  // namespace
 
 renderControl_encoder_context_t::renderControl_encoder_context_t(IOStream *stream, ChecksumCalculator *checksumCalculator)
@@ -1800,5 +1925,8 @@
 	this->rcGetColorBufferDisplay = &rcGetColorBufferDisplay_enc;
 	this->rcGetDisplayPose = &rcGetDisplayPose_enc;
 	this->rcSetDisplayPose = &rcSetDisplayPose_enc;
+	this->rcSetColorBufferVulkanMode = &rcSetColorBufferVulkanMode_enc;
+	this->rcReadColorBufferYUV = &rcReadColorBufferYUV_enc;
+	this->rcIsSyncSignaled = &rcIsSyncSignaled_enc;
 }
 
diff --git a/system/renderControl_enc/renderControl_enc.h b/system/renderControl_enc/renderControl_enc.h
index 9c7b45f..ec1cf32 100644
--- a/system/renderControl_enc/renderControl_enc.h
+++ b/system/renderControl_enc/renderControl_enc.h
@@ -19,7 +19,7 @@
 	ChecksumCalculator *m_checksumCalculator;
 
 	renderControl_encoder_context_t(IOStream *stream, ChecksumCalculator *checksumCalculator);
-	virtual uint64_t lockAndWriteDma(void* data, uint32_t sz) { return 0; }
+	virtual uint64_t lockAndWriteDma(void*, uint32_t) { return 0; }
 };
 
 #endif  // GUARD_renderControl_encoder_context_t
diff --git a/system/renderControl_enc/renderControl_entry.cpp b/system/renderControl_enc/renderControl_entry.cpp
index f02745a..0395d8b 100644
--- a/system/renderControl_enc/renderControl_entry.cpp
+++ b/system/renderControl_enc/renderControl_entry.cpp
@@ -43,13 +43,16 @@
 	uint32_t rcCreateColorBufferDMA(uint32_t width, uint32_t height, GLenum internalFormat, int frameworkFormat);
 	void rcWaitSyncKHR(uint64_t sync, EGLint flags);
 	GLint rcCompose(uint32_t bufferSize, void* buffer);
-	GLint rcCreateDisplay(uint32_t* displayId);
-	GLint rcDestroyDisplay(uint32_t displayId);
-	GLint rcSetDisplayColorBuffer(uint32_t displayId, uint32_t colorBuffer);
-	GLint rcGetDisplayColorBuffer(uint32_t displayId, uint32_t* colorBuffer);
-	GLint rcGetColorBufferDisplay(uint32_t colorBuffer, uint32_t* displayId);
-	GLint rcGetDisplayPose(uint32_t displayId, uint32_t* x, uint32_t* y, uint32_t* w, uint32_t* h);
-	GLint rcSetDisplayPose(uint32_t displayId, uint32_t x, uint32_t y, uint32_t w, uint32_t h);
+	int rcCreateDisplay(uint32_t* displayId);
+	int rcDestroyDisplay(uint32_t displayId);
+	int rcSetDisplayColorBuffer(uint32_t displayId, uint32_t colorBuffer);
+	int rcGetDisplayColorBuffer(uint32_t displayId, uint32_t* colorBuffer);
+	int rcGetColorBufferDisplay(uint32_t colorBuffer, uint32_t* displayId);
+	int rcGetDisplayPose(uint32_t displayId, GLint* x, GLint* y, uint32_t* w, uint32_t* h);
+	int rcSetDisplayPose(uint32_t displayId, GLint x, GLint y, uint32_t w, uint32_t h);
+	GLint rcSetColorBufferVulkanMode(uint32_t colorBuffer, uint32_t mode);
+	void rcReadColorBufferYUV(uint32_t colorbuffer, GLint x, GLint y, GLint width, GLint height, void* pixels, uint32_t pixels_size);
+	int rcIsSyncSignaled(uint64_t sync);
 };
 
 #ifndef GET_CONTEXT
@@ -286,45 +289,63 @@
 	return ctx->rcCompose(ctx, bufferSize, buffer);
 }
 
-GLint rcCreateDisplay(uint32_t* displayId)
+int rcCreateDisplay(uint32_t* displayId)
 {
 	GET_CONTEXT;
 	return ctx->rcCreateDisplay(ctx, displayId);
 }
 
-GLint rcDestroyDisplay(uint32_t displayId)
+int rcDestroyDisplay(uint32_t displayId)
 {
 	GET_CONTEXT;
 	return ctx->rcDestroyDisplay(ctx, displayId);
 }
 
-GLint rcSetDisplayColorBuffer(uint32_t displayId, uint32_t colorBuffer)
+int rcSetDisplayColorBuffer(uint32_t displayId, uint32_t colorBuffer)
 {
 	GET_CONTEXT;
 	return ctx->rcSetDisplayColorBuffer(ctx, displayId, colorBuffer);
 }
 
-GLint rcGetDisplayColorBuffer(uint32_t displayId, uint32_t* colorBuffer)
+int rcGetDisplayColorBuffer(uint32_t displayId, uint32_t* colorBuffer)
 {
 	GET_CONTEXT;
 	return ctx->rcGetDisplayColorBuffer(ctx, displayId, colorBuffer);
 }
 
-GLint rcGetColorBufferDisplay(uint32_t colorBuffer, uint32_t* displayId)
+int rcGetColorBufferDisplay(uint32_t colorBuffer, uint32_t* displayId)
 {
 	GET_CONTEXT;
 	return ctx->rcGetColorBufferDisplay(ctx, colorBuffer, displayId);
 }
 
-GLint rcGetDisplayPose(uint32_t displayId, uint32_t* x, uint32_t* y, uint32_t* w, uint32_t* h)
+int rcGetDisplayPose(uint32_t displayId, GLint* x, GLint* y, uint32_t* w, uint32_t* h)
 {
 	GET_CONTEXT;
 	return ctx->rcGetDisplayPose(ctx, displayId, x, y, w, h);
 }
 
-GLint rcSetDisplayPose(uint32_t displayId, uint32_t x, uint32_t y, uint32_t w, uint32_t h)
+int rcSetDisplayPose(uint32_t displayId, GLint x, GLint y, uint32_t w, uint32_t h)
 {
 	GET_CONTEXT;
 	return ctx->rcSetDisplayPose(ctx, displayId, x, y, w, h);
 }
 
+GLint rcSetColorBufferVulkanMode(uint32_t colorBuffer, uint32_t mode)
+{
+	GET_CONTEXT;
+	return ctx->rcSetColorBufferVulkanMode(ctx, colorBuffer, mode);
+}
+
+void rcReadColorBufferYUV(uint32_t colorbuffer, GLint x, GLint y, GLint width, GLint height, void* pixels, uint32_t pixels_size)
+{
+	GET_CONTEXT;
+	ctx->rcReadColorBufferYUV(ctx, colorbuffer, x, y, width, height, pixels, pixels_size);
+}
+
+int rcIsSyncSignaled(uint64_t sync)
+{
+	GET_CONTEXT;
+	return ctx->rcIsSyncSignaled(ctx, sync);
+}
+
diff --git a/system/renderControl_enc/renderControl_ftable.h b/system/renderControl_enc/renderControl_ftable.h
index 5155f10..662ade8 100644
--- a/system/renderControl_enc/renderControl_ftable.h
+++ b/system/renderControl_enc/renderControl_ftable.h
@@ -53,6 +53,9 @@
 	{"rcGetColorBufferDisplay", (void*)rcGetColorBufferDisplay},
 	{"rcGetDisplayPose", (void*)rcGetDisplayPose},
 	{"rcSetDisplayPose", (void*)rcSetDisplayPose},
+	{"rcSetColorBufferVulkanMode", (void*)rcSetColorBufferVulkanMode},
+	{"rcReadColorBufferYUV", (void*)rcReadColorBufferYUV},
+	{"rcIsSyncSignaled", (void*)rcIsSyncSignaled},
 };
 static const int renderControl_num_funcs = sizeof(renderControl_funcs_by_name) / sizeof(struct _renderControl_funcs_by_name);
 
diff --git a/system/renderControl_enc/renderControl_opcodes.h b/system/renderControl_enc/renderControl_opcodes.h
index d98a40c..338a38e 100644
--- a/system/renderControl_enc/renderControl_opcodes.h
+++ b/system/renderControl_enc/renderControl_opcodes.h
@@ -48,7 +48,10 @@
 #define OP_rcGetColorBufferDisplay 					10042
 #define OP_rcGetDisplayPose 					10043
 #define OP_rcSetDisplayPose 					10044
-#define OP_last 					10045
+#define OP_rcSetColorBufferVulkanMode 					10045
+#define OP_rcReadColorBufferYUV 					10046
+#define OP_rcIsSyncSignaled 					10047
+#define OP_last 					10048
 
 
 #endif
diff --git a/system/vulkan/CMakeLists.txt b/system/vulkan/CMakeLists.txt
index 68a62d6..a71c07f 100644
--- a/system/vulkan/CMakeLists.txt
+++ b/system/vulkan/CMakeLists.txt
@@ -1,10 +1,10 @@
 # This is an autogenerated file! Do not edit!
 # instead run make from .../device/generic/goldfish-opengl
 # which will re-generate this file.
-android_validate_sha256("${GOLDFISH_DEVICE_ROOT}/system/vulkan/Android.mk" "7ec8946bc369a60407913f2257120f701fa2c6e2ce30e3f7148a8e7b0abca46a")
+android_validate_sha256("${GOLDFISH_DEVICE_ROOT}/system/vulkan/Android.mk" "691427017f29de6b082ad25cb73b87443d4072a04b4316897bb92983674ad5bf")
 set(vulkan.ranchu_src func_table.cpp goldfish_vulkan.cpp)
-android_add_shared_library(vulkan.ranchu)
-target_include_directories(vulkan.ranchu PRIVATE ${GOLDFISH_DEVICE_ROOT}/system/OpenglSystemCommon ${GOLDFISH_DEVICE_ROOT}/bionic/libc/private ${GOLDFISH_DEVICE_ROOT}/system/vulkan_enc ${GOLDFISH_DEVICE_ROOT}/android-emu ${GOLDFISH_DEVICE_ROOT}/system/renderControl_enc ${GOLDFISH_DEVICE_ROOT}/system/GLESv2_enc ${GOLDFISH_DEVICE_ROOT}/system/GLESv1_enc ${GOLDFISH_DEVICE_ROOT}/shared/OpenglCodecCommon ${GOLDFISH_DEVICE_ROOT}/system/vulkan ${GOLDFISH_DEVICE_ROOT}/./host/include/libOpenglRender ${GOLDFISH_DEVICE_ROOT}/./system/include ${GOLDFISH_DEVICE_ROOT}/./../../../external/qemu/android/android-emugl/guest ${GOLDFISH_DEVICE_ROOT}/./../../../external/qemu/android/android-emugl/host/include)
+android_add_library(TARGET vulkan.ranchu SHARED LICENSE Apache-2.0 SRC func_table.cpp goldfish_vulkan.cpp)
+target_include_directories(vulkan.ranchu PRIVATE ${GOLDFISH_DEVICE_ROOT}/system/OpenglSystemCommon/bionic-include ${GOLDFISH_DEVICE_ROOT}/system/OpenglSystemCommon ${GOLDFISH_DEVICE_ROOT}/bionic/libc/private ${GOLDFISH_DEVICE_ROOT}/bionic/libc/platform ${GOLDFISH_DEVICE_ROOT}/system/vulkan_enc ${GOLDFISH_DEVICE_ROOT}/android-emu ${GOLDFISH_DEVICE_ROOT}/system/renderControl_enc ${GOLDFISH_DEVICE_ROOT}/system/GLESv2_enc ${GOLDFISH_DEVICE_ROOT}/system/GLESv1_enc ${GOLDFISH_DEVICE_ROOT}/shared/OpenglCodecCommon ${GOLDFISH_DEVICE_ROOT}/system/vulkan ${GOLDFISH_DEVICE_ROOT}/./host/include/libOpenglRender ${GOLDFISH_DEVICE_ROOT}/./system/include ${GOLDFISH_DEVICE_ROOT}/./../../../external/qemu/android/android-emugl/guest ${GOLDFISH_DEVICE_ROOT}/./../../../external/qemu/android/android-emugl/host/include)
 target_compile_definitions(vulkan.ranchu PRIVATE "-DWITH_GLES2" "-DPLATFORM_SDK_VERSION=29" "-DGOLDFISH_HIDL_GRALLOC" "-DEMULATOR_OPENGL_POST_O=1" "-DHOST_BUILD" "-DANDROID" "-DGL_GLEXT_PROTOTYPES" "-DPAGE_SIZE=4096" "-DGOLDFISH_VULKAN" "-DLOG_TAG=\"goldfish_vulkan\"" "-DVK_USE_PLATFORM_ANDROID_KHR" "-DVK_NO_PROTOTYPES")
-target_compile_options(vulkan.ranchu PRIVATE "-fvisibility=default" "-Wno-missing-field-initializers" "-fvisibility=hidden" "-fstrict-aliasing")
-target_link_libraries(vulkan.ranchu PRIVATE OpenglSystemCommon android-emu-shared vulkan_enc gui cutils utils log _renderControl_enc GLESv2_enc GLESv1_enc OpenglCodecCommon_host)
\ No newline at end of file
+target_compile_options(vulkan.ranchu PRIVATE "-fvisibility=default" "-Wno-unused-parameter" "-Wno-missing-field-initializers" "-fvisibility=hidden" "-fstrict-aliasing" "-Wno-unused-function")
+target_link_libraries(vulkan.ranchu PRIVATE OpenglSystemCommon android-emu-shared vulkan_enc gui androidemu cutils utils log _renderControl_enc GLESv2_enc GLESv1_enc OpenglCodecCommon_host)
\ No newline at end of file
diff --git a/system/vulkan/func_table.cpp b/system/vulkan/func_table.cpp
index f5b380e..80f586f 100644
--- a/system/vulkan/func_table.cpp
+++ b/system/vulkan/func_table.cpp
@@ -31,6 +31,8 @@
 
 #include "goldfish_vk_private_defs.h"
 
+#include <log/log.h>
+
 // Stuff we are not going to use but if included,
 // will cause compile errors. These are Android Vulkan
 // required extensions, but the approach will be to
@@ -40,6 +42,11 @@
 
 namespace goldfish_vk {
 
+static void sOnInvalidDynamicallyCheckedCall(const char* apiname, const char* neededFeature)
+{
+    ALOGE("invalid call to %s: %s not supported", apiname, neededFeature);
+    abort();
+}
 #ifdef VK_VERSION_1_0
 static VkResult entry_vkCreateInstance(
     const VkInstanceCreateInfo* pCreateInfo,
@@ -244,7 +251,8 @@
     AEMU_SCOPED_TRACE("vkQueueWaitIdle");
     auto vkEnc = HostConnection::get()->vkEncoder();
     VkResult vkQueueWaitIdle_VkResult_return = (VkResult)0;
-    vkQueueWaitIdle_VkResult_return = vkEnc->vkQueueWaitIdle(queue);
+    auto resources = ResourceTracker::get();
+    vkQueueWaitIdle_VkResult_return = resources->on_vkQueueWaitIdle(vkEnc, VK_SUCCESS, queue);
     return vkQueueWaitIdle_VkResult_return;
 }
 static VkResult entry_vkDeviceWaitIdle(
@@ -423,7 +431,8 @@
     AEMU_SCOPED_TRACE("vkCreateFence");
     auto vkEnc = HostConnection::get()->vkEncoder();
     VkResult vkCreateFence_VkResult_return = (VkResult)0;
-    vkCreateFence_VkResult_return = vkEnc->vkCreateFence(device, pCreateInfo, pAllocator, pFence);
+    auto resources = ResourceTracker::get();
+    vkCreateFence_VkResult_return = resources->on_vkCreateFence(vkEnc, VK_SUCCESS, device, pCreateInfo, pAllocator, pFence);
     return vkCreateFence_VkResult_return;
 }
 static void entry_vkDestroyFence(
@@ -443,7 +452,8 @@
     AEMU_SCOPED_TRACE("vkResetFences");
     auto vkEnc = HostConnection::get()->vkEncoder();
     VkResult vkResetFences_VkResult_return = (VkResult)0;
-    vkResetFences_VkResult_return = vkEnc->vkResetFences(device, fenceCount, pFences);
+    auto resources = ResourceTracker::get();
+    vkResetFences_VkResult_return = resources->on_vkResetFences(vkEnc, VK_SUCCESS, device, fenceCount, pFences);
     return vkResetFences_VkResult_return;
 }
 static VkResult entry_vkGetFenceStatus(
@@ -466,7 +476,8 @@
     AEMU_SCOPED_TRACE("vkWaitForFences");
     auto vkEnc = HostConnection::get()->vkEncoder();
     VkResult vkWaitForFences_VkResult_return = (VkResult)0;
-    vkWaitForFences_VkResult_return = vkEnc->vkWaitForFences(device, fenceCount, pFences, waitAll, timeout);
+    auto resources = ResourceTracker::get();
+    vkWaitForFences_VkResult_return = resources->on_vkWaitForFences(vkEnc, VK_SUCCESS, device, fenceCount, pFences, waitAll, timeout);
     return vkWaitForFences_VkResult_return;
 }
 static VkResult entry_vkCreateSemaphore(
@@ -812,7 +823,8 @@
     AEMU_SCOPED_TRACE("vkCreateSampler");
     auto vkEnc = HostConnection::get()->vkEncoder();
     VkResult vkCreateSampler_VkResult_return = (VkResult)0;
-    vkCreateSampler_VkResult_return = vkEnc->vkCreateSampler(device, pCreateInfo, pAllocator, pSampler);
+    auto resources = ResourceTracker::get();
+    vkCreateSampler_VkResult_return = resources->on_vkCreateSampler(vkEnc, VK_SUCCESS, device, pCreateInfo, pAllocator, pSampler);
     return vkCreateSampler_VkResult_return;
 }
 static void entry_vkDestroySampler(
@@ -1021,6 +1033,7 @@
 {
     AEMU_SCOPED_TRACE("vkBeginCommandBuffer");
     auto vkEnc = HostConnection::get()->vkEncoder();
+    ResourceTracker::get()->syncEncodersForCommandBuffer(commandBuffer, vkEnc);
     VkResult vkBeginCommandBuffer_VkResult_return = (VkResult)0;
     auto resources = ResourceTracker::get();
     vkBeginCommandBuffer_VkResult_return = resources->on_vkBeginCommandBuffer(vkEnc, VK_SUCCESS, commandBuffer, pBeginInfo);
@@ -1031,6 +1044,7 @@
 {
     AEMU_SCOPED_TRACE("vkEndCommandBuffer");
     auto vkEnc = HostConnection::get()->vkEncoder();
+    ResourceTracker::get()->syncEncodersForCommandBuffer(commandBuffer, vkEnc);
     VkResult vkEndCommandBuffer_VkResult_return = (VkResult)0;
     auto resources = ResourceTracker::get();
     vkEndCommandBuffer_VkResult_return = resources->on_vkEndCommandBuffer(vkEnc, VK_SUCCESS, commandBuffer);
@@ -1042,6 +1056,7 @@
 {
     AEMU_SCOPED_TRACE("vkResetCommandBuffer");
     auto vkEnc = HostConnection::get()->vkEncoder();
+    ResourceTracker::get()->syncEncodersForCommandBuffer(commandBuffer, vkEnc);
     VkResult vkResetCommandBuffer_VkResult_return = (VkResult)0;
     auto resources = ResourceTracker::get();
     vkResetCommandBuffer_VkResult_return = resources->on_vkResetCommandBuffer(vkEnc, VK_SUCCESS, commandBuffer, flags);
@@ -1054,6 +1069,7 @@
 {
     AEMU_SCOPED_TRACE("vkCmdBindPipeline");
     auto vkEnc = HostConnection::get()->vkEncoder();
+    ResourceTracker::get()->syncEncodersForCommandBuffer(commandBuffer, vkEnc);
     vkEnc->vkCmdBindPipeline(commandBuffer, pipelineBindPoint, pipeline);
 }
 static void entry_vkCmdSetViewport(
@@ -1064,6 +1080,7 @@
 {
     AEMU_SCOPED_TRACE("vkCmdSetViewport");
     auto vkEnc = HostConnection::get()->vkEncoder();
+    ResourceTracker::get()->syncEncodersForCommandBuffer(commandBuffer, vkEnc);
     vkEnc->vkCmdSetViewport(commandBuffer, firstViewport, viewportCount, pViewports);
 }
 static void entry_vkCmdSetScissor(
@@ -1074,6 +1091,7 @@
 {
     AEMU_SCOPED_TRACE("vkCmdSetScissor");
     auto vkEnc = HostConnection::get()->vkEncoder();
+    ResourceTracker::get()->syncEncodersForCommandBuffer(commandBuffer, vkEnc);
     vkEnc->vkCmdSetScissor(commandBuffer, firstScissor, scissorCount, pScissors);
 }
 static void entry_vkCmdSetLineWidth(
@@ -1082,6 +1100,7 @@
 {
     AEMU_SCOPED_TRACE("vkCmdSetLineWidth");
     auto vkEnc = HostConnection::get()->vkEncoder();
+    ResourceTracker::get()->syncEncodersForCommandBuffer(commandBuffer, vkEnc);
     vkEnc->vkCmdSetLineWidth(commandBuffer, lineWidth);
 }
 static void entry_vkCmdSetDepthBias(
@@ -1092,6 +1111,7 @@
 {
     AEMU_SCOPED_TRACE("vkCmdSetDepthBias");
     auto vkEnc = HostConnection::get()->vkEncoder();
+    ResourceTracker::get()->syncEncodersForCommandBuffer(commandBuffer, vkEnc);
     vkEnc->vkCmdSetDepthBias(commandBuffer, depthBiasConstantFactor, depthBiasClamp, depthBiasSlopeFactor);
 }
 static void entry_vkCmdSetBlendConstants(
@@ -1100,6 +1120,7 @@
 {
     AEMU_SCOPED_TRACE("vkCmdSetBlendConstants");
     auto vkEnc = HostConnection::get()->vkEncoder();
+    ResourceTracker::get()->syncEncodersForCommandBuffer(commandBuffer, vkEnc);
     vkEnc->vkCmdSetBlendConstants(commandBuffer, blendConstants);
 }
 static void entry_vkCmdSetDepthBounds(
@@ -1109,6 +1130,7 @@
 {
     AEMU_SCOPED_TRACE("vkCmdSetDepthBounds");
     auto vkEnc = HostConnection::get()->vkEncoder();
+    ResourceTracker::get()->syncEncodersForCommandBuffer(commandBuffer, vkEnc);
     vkEnc->vkCmdSetDepthBounds(commandBuffer, minDepthBounds, maxDepthBounds);
 }
 static void entry_vkCmdSetStencilCompareMask(
@@ -1118,6 +1140,7 @@
 {
     AEMU_SCOPED_TRACE("vkCmdSetStencilCompareMask");
     auto vkEnc = HostConnection::get()->vkEncoder();
+    ResourceTracker::get()->syncEncodersForCommandBuffer(commandBuffer, vkEnc);
     vkEnc->vkCmdSetStencilCompareMask(commandBuffer, faceMask, compareMask);
 }
 static void entry_vkCmdSetStencilWriteMask(
@@ -1127,6 +1150,7 @@
 {
     AEMU_SCOPED_TRACE("vkCmdSetStencilWriteMask");
     auto vkEnc = HostConnection::get()->vkEncoder();
+    ResourceTracker::get()->syncEncodersForCommandBuffer(commandBuffer, vkEnc);
     vkEnc->vkCmdSetStencilWriteMask(commandBuffer, faceMask, writeMask);
 }
 static void entry_vkCmdSetStencilReference(
@@ -1136,6 +1160,7 @@
 {
     AEMU_SCOPED_TRACE("vkCmdSetStencilReference");
     auto vkEnc = HostConnection::get()->vkEncoder();
+    ResourceTracker::get()->syncEncodersForCommandBuffer(commandBuffer, vkEnc);
     vkEnc->vkCmdSetStencilReference(commandBuffer, faceMask, reference);
 }
 static void entry_vkCmdBindDescriptorSets(
@@ -1150,6 +1175,7 @@
 {
     AEMU_SCOPED_TRACE("vkCmdBindDescriptorSets");
     auto vkEnc = HostConnection::get()->vkEncoder();
+    ResourceTracker::get()->syncEncodersForCommandBuffer(commandBuffer, vkEnc);
     vkEnc->vkCmdBindDescriptorSets(commandBuffer, pipelineBindPoint, layout, firstSet, descriptorSetCount, pDescriptorSets, dynamicOffsetCount, pDynamicOffsets);
 }
 static void entry_vkCmdBindIndexBuffer(
@@ -1160,6 +1186,7 @@
 {
     AEMU_SCOPED_TRACE("vkCmdBindIndexBuffer");
     auto vkEnc = HostConnection::get()->vkEncoder();
+    ResourceTracker::get()->syncEncodersForCommandBuffer(commandBuffer, vkEnc);
     vkEnc->vkCmdBindIndexBuffer(commandBuffer, buffer, offset, indexType);
 }
 static void entry_vkCmdBindVertexBuffers(
@@ -1171,6 +1198,7 @@
 {
     AEMU_SCOPED_TRACE("vkCmdBindVertexBuffers");
     auto vkEnc = HostConnection::get()->vkEncoder();
+    ResourceTracker::get()->syncEncodersForCommandBuffer(commandBuffer, vkEnc);
     vkEnc->vkCmdBindVertexBuffers(commandBuffer, firstBinding, bindingCount, pBuffers, pOffsets);
 }
 static void entry_vkCmdDraw(
@@ -1182,6 +1210,7 @@
 {
     AEMU_SCOPED_TRACE("vkCmdDraw");
     auto vkEnc = HostConnection::get()->vkEncoder();
+    ResourceTracker::get()->syncEncodersForCommandBuffer(commandBuffer, vkEnc);
     vkEnc->vkCmdDraw(commandBuffer, vertexCount, instanceCount, firstVertex, firstInstance);
 }
 static void entry_vkCmdDrawIndexed(
@@ -1194,6 +1223,7 @@
 {
     AEMU_SCOPED_TRACE("vkCmdDrawIndexed");
     auto vkEnc = HostConnection::get()->vkEncoder();
+    ResourceTracker::get()->syncEncodersForCommandBuffer(commandBuffer, vkEnc);
     vkEnc->vkCmdDrawIndexed(commandBuffer, indexCount, instanceCount, firstIndex, vertexOffset, firstInstance);
 }
 static void entry_vkCmdDrawIndirect(
@@ -1205,6 +1235,7 @@
 {
     AEMU_SCOPED_TRACE("vkCmdDrawIndirect");
     auto vkEnc = HostConnection::get()->vkEncoder();
+    ResourceTracker::get()->syncEncodersForCommandBuffer(commandBuffer, vkEnc);
     vkEnc->vkCmdDrawIndirect(commandBuffer, buffer, offset, drawCount, stride);
 }
 static void entry_vkCmdDrawIndexedIndirect(
@@ -1216,6 +1247,7 @@
 {
     AEMU_SCOPED_TRACE("vkCmdDrawIndexedIndirect");
     auto vkEnc = HostConnection::get()->vkEncoder();
+    ResourceTracker::get()->syncEncodersForCommandBuffer(commandBuffer, vkEnc);
     vkEnc->vkCmdDrawIndexedIndirect(commandBuffer, buffer, offset, drawCount, stride);
 }
 static void entry_vkCmdDispatch(
@@ -1226,6 +1258,7 @@
 {
     AEMU_SCOPED_TRACE("vkCmdDispatch");
     auto vkEnc = HostConnection::get()->vkEncoder();
+    ResourceTracker::get()->syncEncodersForCommandBuffer(commandBuffer, vkEnc);
     vkEnc->vkCmdDispatch(commandBuffer, groupCountX, groupCountY, groupCountZ);
 }
 static void entry_vkCmdDispatchIndirect(
@@ -1235,6 +1268,7 @@
 {
     AEMU_SCOPED_TRACE("vkCmdDispatchIndirect");
     auto vkEnc = HostConnection::get()->vkEncoder();
+    ResourceTracker::get()->syncEncodersForCommandBuffer(commandBuffer, vkEnc);
     vkEnc->vkCmdDispatchIndirect(commandBuffer, buffer, offset);
 }
 static void entry_vkCmdCopyBuffer(
@@ -1246,6 +1280,7 @@
 {
     AEMU_SCOPED_TRACE("vkCmdCopyBuffer");
     auto vkEnc = HostConnection::get()->vkEncoder();
+    ResourceTracker::get()->syncEncodersForCommandBuffer(commandBuffer, vkEnc);
     vkEnc->vkCmdCopyBuffer(commandBuffer, srcBuffer, dstBuffer, regionCount, pRegions);
 }
 static void entry_vkCmdCopyImage(
@@ -1259,6 +1294,7 @@
 {
     AEMU_SCOPED_TRACE("vkCmdCopyImage");
     auto vkEnc = HostConnection::get()->vkEncoder();
+    ResourceTracker::get()->syncEncodersForCommandBuffer(commandBuffer, vkEnc);
     vkEnc->vkCmdCopyImage(commandBuffer, srcImage, srcImageLayout, dstImage, dstImageLayout, regionCount, pRegions);
 }
 static void entry_vkCmdBlitImage(
@@ -1273,6 +1309,7 @@
 {
     AEMU_SCOPED_TRACE("vkCmdBlitImage");
     auto vkEnc = HostConnection::get()->vkEncoder();
+    ResourceTracker::get()->syncEncodersForCommandBuffer(commandBuffer, vkEnc);
     vkEnc->vkCmdBlitImage(commandBuffer, srcImage, srcImageLayout, dstImage, dstImageLayout, regionCount, pRegions, filter);
 }
 static void entry_vkCmdCopyBufferToImage(
@@ -1285,6 +1322,7 @@
 {
     AEMU_SCOPED_TRACE("vkCmdCopyBufferToImage");
     auto vkEnc = HostConnection::get()->vkEncoder();
+    ResourceTracker::get()->syncEncodersForCommandBuffer(commandBuffer, vkEnc);
     vkEnc->vkCmdCopyBufferToImage(commandBuffer, srcBuffer, dstImage, dstImageLayout, regionCount, pRegions);
 }
 static void entry_vkCmdCopyImageToBuffer(
@@ -1297,6 +1335,7 @@
 {
     AEMU_SCOPED_TRACE("vkCmdCopyImageToBuffer");
     auto vkEnc = HostConnection::get()->vkEncoder();
+    ResourceTracker::get()->syncEncodersForCommandBuffer(commandBuffer, vkEnc);
     vkEnc->vkCmdCopyImageToBuffer(commandBuffer, srcImage, srcImageLayout, dstBuffer, regionCount, pRegions);
 }
 static void entry_vkCmdUpdateBuffer(
@@ -1308,6 +1347,7 @@
 {
     AEMU_SCOPED_TRACE("vkCmdUpdateBuffer");
     auto vkEnc = HostConnection::get()->vkEncoder();
+    ResourceTracker::get()->syncEncodersForCommandBuffer(commandBuffer, vkEnc);
     vkEnc->vkCmdUpdateBuffer(commandBuffer, dstBuffer, dstOffset, dataSize, pData);
 }
 static void entry_vkCmdFillBuffer(
@@ -1319,6 +1359,7 @@
 {
     AEMU_SCOPED_TRACE("vkCmdFillBuffer");
     auto vkEnc = HostConnection::get()->vkEncoder();
+    ResourceTracker::get()->syncEncodersForCommandBuffer(commandBuffer, vkEnc);
     vkEnc->vkCmdFillBuffer(commandBuffer, dstBuffer, dstOffset, size, data);
 }
 static void entry_vkCmdClearColorImage(
@@ -1331,6 +1372,7 @@
 {
     AEMU_SCOPED_TRACE("vkCmdClearColorImage");
     auto vkEnc = HostConnection::get()->vkEncoder();
+    ResourceTracker::get()->syncEncodersForCommandBuffer(commandBuffer, vkEnc);
     vkEnc->vkCmdClearColorImage(commandBuffer, image, imageLayout, pColor, rangeCount, pRanges);
 }
 static void entry_vkCmdClearDepthStencilImage(
@@ -1343,6 +1385,7 @@
 {
     AEMU_SCOPED_TRACE("vkCmdClearDepthStencilImage");
     auto vkEnc = HostConnection::get()->vkEncoder();
+    ResourceTracker::get()->syncEncodersForCommandBuffer(commandBuffer, vkEnc);
     vkEnc->vkCmdClearDepthStencilImage(commandBuffer, image, imageLayout, pDepthStencil, rangeCount, pRanges);
 }
 static void entry_vkCmdClearAttachments(
@@ -1354,6 +1397,7 @@
 {
     AEMU_SCOPED_TRACE("vkCmdClearAttachments");
     auto vkEnc = HostConnection::get()->vkEncoder();
+    ResourceTracker::get()->syncEncodersForCommandBuffer(commandBuffer, vkEnc);
     vkEnc->vkCmdClearAttachments(commandBuffer, attachmentCount, pAttachments, rectCount, pRects);
 }
 static void entry_vkCmdResolveImage(
@@ -1367,6 +1411,7 @@
 {
     AEMU_SCOPED_TRACE("vkCmdResolveImage");
     auto vkEnc = HostConnection::get()->vkEncoder();
+    ResourceTracker::get()->syncEncodersForCommandBuffer(commandBuffer, vkEnc);
     vkEnc->vkCmdResolveImage(commandBuffer, srcImage, srcImageLayout, dstImage, dstImageLayout, regionCount, pRegions);
 }
 static void entry_vkCmdSetEvent(
@@ -1376,6 +1421,7 @@
 {
     AEMU_SCOPED_TRACE("vkCmdSetEvent");
     auto vkEnc = HostConnection::get()->vkEncoder();
+    ResourceTracker::get()->syncEncodersForCommandBuffer(commandBuffer, vkEnc);
     vkEnc->vkCmdSetEvent(commandBuffer, event, stageMask);
 }
 static void entry_vkCmdResetEvent(
@@ -1385,6 +1431,7 @@
 {
     AEMU_SCOPED_TRACE("vkCmdResetEvent");
     auto vkEnc = HostConnection::get()->vkEncoder();
+    ResourceTracker::get()->syncEncodersForCommandBuffer(commandBuffer, vkEnc);
     vkEnc->vkCmdResetEvent(commandBuffer, event, stageMask);
 }
 static void entry_vkCmdWaitEvents(
@@ -1402,6 +1449,7 @@
 {
     AEMU_SCOPED_TRACE("vkCmdWaitEvents");
     auto vkEnc = HostConnection::get()->vkEncoder();
+    ResourceTracker::get()->syncEncodersForCommandBuffer(commandBuffer, vkEnc);
     vkEnc->vkCmdWaitEvents(commandBuffer, eventCount, pEvents, srcStageMask, dstStageMask, memoryBarrierCount, pMemoryBarriers, bufferMemoryBarrierCount, pBufferMemoryBarriers, imageMemoryBarrierCount, pImageMemoryBarriers);
 }
 static void entry_vkCmdPipelineBarrier(
@@ -1418,6 +1466,7 @@
 {
     AEMU_SCOPED_TRACE("vkCmdPipelineBarrier");
     auto vkEnc = HostConnection::get()->vkEncoder();
+    ResourceTracker::get()->syncEncodersForCommandBuffer(commandBuffer, vkEnc);
     vkEnc->vkCmdPipelineBarrier(commandBuffer, srcStageMask, dstStageMask, dependencyFlags, memoryBarrierCount, pMemoryBarriers, bufferMemoryBarrierCount, pBufferMemoryBarriers, imageMemoryBarrierCount, pImageMemoryBarriers);
 }
 static void entry_vkCmdBeginQuery(
@@ -1428,6 +1477,7 @@
 {
     AEMU_SCOPED_TRACE("vkCmdBeginQuery");
     auto vkEnc = HostConnection::get()->vkEncoder();
+    ResourceTracker::get()->syncEncodersForCommandBuffer(commandBuffer, vkEnc);
     vkEnc->vkCmdBeginQuery(commandBuffer, queryPool, query, flags);
 }
 static void entry_vkCmdEndQuery(
@@ -1437,6 +1487,7 @@
 {
     AEMU_SCOPED_TRACE("vkCmdEndQuery");
     auto vkEnc = HostConnection::get()->vkEncoder();
+    ResourceTracker::get()->syncEncodersForCommandBuffer(commandBuffer, vkEnc);
     vkEnc->vkCmdEndQuery(commandBuffer, queryPool, query);
 }
 static void entry_vkCmdResetQueryPool(
@@ -1447,6 +1498,7 @@
 {
     AEMU_SCOPED_TRACE("vkCmdResetQueryPool");
     auto vkEnc = HostConnection::get()->vkEncoder();
+    ResourceTracker::get()->syncEncodersForCommandBuffer(commandBuffer, vkEnc);
     vkEnc->vkCmdResetQueryPool(commandBuffer, queryPool, firstQuery, queryCount);
 }
 static void entry_vkCmdWriteTimestamp(
@@ -1457,6 +1509,7 @@
 {
     AEMU_SCOPED_TRACE("vkCmdWriteTimestamp");
     auto vkEnc = HostConnection::get()->vkEncoder();
+    ResourceTracker::get()->syncEncodersForCommandBuffer(commandBuffer, vkEnc);
     vkEnc->vkCmdWriteTimestamp(commandBuffer, pipelineStage, queryPool, query);
 }
 static void entry_vkCmdCopyQueryPoolResults(
@@ -1471,6 +1524,7 @@
 {
     AEMU_SCOPED_TRACE("vkCmdCopyQueryPoolResults");
     auto vkEnc = HostConnection::get()->vkEncoder();
+    ResourceTracker::get()->syncEncodersForCommandBuffer(commandBuffer, vkEnc);
     vkEnc->vkCmdCopyQueryPoolResults(commandBuffer, queryPool, firstQuery, queryCount, dstBuffer, dstOffset, stride, flags);
 }
 static void entry_vkCmdPushConstants(
@@ -1483,6 +1537,7 @@
 {
     AEMU_SCOPED_TRACE("vkCmdPushConstants");
     auto vkEnc = HostConnection::get()->vkEncoder();
+    ResourceTracker::get()->syncEncodersForCommandBuffer(commandBuffer, vkEnc);
     vkEnc->vkCmdPushConstants(commandBuffer, layout, stageFlags, offset, size, pValues);
 }
 static void entry_vkCmdBeginRenderPass(
@@ -1492,6 +1547,7 @@
 {
     AEMU_SCOPED_TRACE("vkCmdBeginRenderPass");
     auto vkEnc = HostConnection::get()->vkEncoder();
+    ResourceTracker::get()->syncEncodersForCommandBuffer(commandBuffer, vkEnc);
     vkEnc->vkCmdBeginRenderPass(commandBuffer, pRenderPassBegin, contents);
 }
 static void entry_vkCmdNextSubpass(
@@ -1500,6 +1556,7 @@
 {
     AEMU_SCOPED_TRACE("vkCmdNextSubpass");
     auto vkEnc = HostConnection::get()->vkEncoder();
+    ResourceTracker::get()->syncEncodersForCommandBuffer(commandBuffer, vkEnc);
     vkEnc->vkCmdNextSubpass(commandBuffer, contents);
 }
 static void entry_vkCmdEndRenderPass(
@@ -1507,6 +1564,7 @@
 {
     AEMU_SCOPED_TRACE("vkCmdEndRenderPass");
     auto vkEnc = HostConnection::get()->vkEncoder();
+    ResourceTracker::get()->syncEncodersForCommandBuffer(commandBuffer, vkEnc);
     vkEnc->vkCmdEndRenderPass(commandBuffer);
 }
 static void entry_vkCmdExecuteCommands(
@@ -1516,6 +1574,7 @@
 {
     AEMU_SCOPED_TRACE("vkCmdExecuteCommands");
     auto vkEnc = HostConnection::get()->vkEncoder();
+    ResourceTracker::get()->syncEncodersForCommandBuffer(commandBuffer, vkEnc);
     vkEnc->vkCmdExecuteCommands(commandBuffer, commandBufferCount, pCommandBuffers);
 }
 #endif
@@ -1541,6 +1600,22 @@
     vkBindBufferMemory2_VkResult_return = resources->on_vkBindBufferMemory2(vkEnc, VK_SUCCESS, device, bindInfoCount, pBindInfos);
     return vkBindBufferMemory2_VkResult_return;
 }
+static VkResult dynCheck_entry_vkBindBufferMemory2(
+    VkDevice device,
+    uint32_t bindInfoCount,
+    const VkBindBufferMemoryInfo* pBindInfos)
+{
+    auto resources = ResourceTracker::get();
+    if (resources->getApiVersionFromDevice(device) < VK_API_VERSION_1_1)
+    {
+        sOnInvalidDynamicallyCheckedCall("vkBindBufferMemory2", "VK_VERSION_1_1");
+    }
+    AEMU_SCOPED_TRACE("vkBindBufferMemory2");
+    auto vkEnc = HostConnection::get()->vkEncoder();
+    VkResult vkBindBufferMemory2_VkResult_return = (VkResult)0;
+    vkBindBufferMemory2_VkResult_return = resources->on_vkBindBufferMemory2(vkEnc, VK_SUCCESS, device, bindInfoCount, pBindInfos);
+    return vkBindBufferMemory2_VkResult_return;
+}
 static VkResult entry_vkBindImageMemory2(
     VkDevice device,
     uint32_t bindInfoCount,
@@ -1553,6 +1628,22 @@
     vkBindImageMemory2_VkResult_return = resources->on_vkBindImageMemory2(vkEnc, VK_SUCCESS, device, bindInfoCount, pBindInfos);
     return vkBindImageMemory2_VkResult_return;
 }
+static VkResult dynCheck_entry_vkBindImageMemory2(
+    VkDevice device,
+    uint32_t bindInfoCount,
+    const VkBindImageMemoryInfo* pBindInfos)
+{
+    auto resources = ResourceTracker::get();
+    if (resources->getApiVersionFromDevice(device) < VK_API_VERSION_1_1)
+    {
+        sOnInvalidDynamicallyCheckedCall("vkBindImageMemory2", "VK_VERSION_1_1");
+    }
+    AEMU_SCOPED_TRACE("vkBindImageMemory2");
+    auto vkEnc = HostConnection::get()->vkEncoder();
+    VkResult vkBindImageMemory2_VkResult_return = (VkResult)0;
+    vkBindImageMemory2_VkResult_return = resources->on_vkBindImageMemory2(vkEnc, VK_SUCCESS, device, bindInfoCount, pBindInfos);
+    return vkBindImageMemory2_VkResult_return;
+}
 static void entry_vkGetDeviceGroupPeerMemoryFeatures(
     VkDevice device,
     uint32_t heapIndex,
@@ -1564,12 +1655,29 @@
     auto vkEnc = HostConnection::get()->vkEncoder();
     vkEnc->vkGetDeviceGroupPeerMemoryFeatures(device, heapIndex, localDeviceIndex, remoteDeviceIndex, pPeerMemoryFeatures);
 }
+static void dynCheck_entry_vkGetDeviceGroupPeerMemoryFeatures(
+    VkDevice device,
+    uint32_t heapIndex,
+    uint32_t localDeviceIndex,
+    uint32_t remoteDeviceIndex,
+    VkPeerMemoryFeatureFlags* pPeerMemoryFeatures)
+{
+    auto resources = ResourceTracker::get();
+    if (resources->getApiVersionFromDevice(device) < VK_API_VERSION_1_1)
+    {
+        sOnInvalidDynamicallyCheckedCall("vkGetDeviceGroupPeerMemoryFeatures", "VK_VERSION_1_1");
+    }
+    AEMU_SCOPED_TRACE("vkGetDeviceGroupPeerMemoryFeatures");
+    auto vkEnc = HostConnection::get()->vkEncoder();
+    vkEnc->vkGetDeviceGroupPeerMemoryFeatures(device, heapIndex, localDeviceIndex, remoteDeviceIndex, pPeerMemoryFeatures);
+}
 static void entry_vkCmdSetDeviceMask(
     VkCommandBuffer commandBuffer,
     uint32_t deviceMask)
 {
     AEMU_SCOPED_TRACE("vkCmdSetDeviceMask");
     auto vkEnc = HostConnection::get()->vkEncoder();
+    ResourceTracker::get()->syncEncodersForCommandBuffer(commandBuffer, vkEnc);
     vkEnc->vkCmdSetDeviceMask(commandBuffer, deviceMask);
 }
 static void entry_vkCmdDispatchBase(
@@ -1583,6 +1691,7 @@
 {
     AEMU_SCOPED_TRACE("vkCmdDispatchBase");
     auto vkEnc = HostConnection::get()->vkEncoder();
+    ResourceTracker::get()->syncEncodersForCommandBuffer(commandBuffer, vkEnc);
     vkEnc->vkCmdDispatchBase(commandBuffer, baseGroupX, baseGroupY, baseGroupZ, groupCountX, groupCountY, groupCountZ);
 }
 static VkResult entry_vkEnumeratePhysicalDeviceGroups(
@@ -1606,6 +1715,20 @@
     auto resources = ResourceTracker::get();
     resources->on_vkGetImageMemoryRequirements2(vkEnc, device, pInfo, pMemoryRequirements);
 }
+static void dynCheck_entry_vkGetImageMemoryRequirements2(
+    VkDevice device,
+    const VkImageMemoryRequirementsInfo2* pInfo,
+    VkMemoryRequirements2* pMemoryRequirements)
+{
+    auto resources = ResourceTracker::get();
+    if (resources->getApiVersionFromDevice(device) < VK_API_VERSION_1_1)
+    {
+        sOnInvalidDynamicallyCheckedCall("vkGetImageMemoryRequirements2", "VK_VERSION_1_1");
+    }
+    AEMU_SCOPED_TRACE("vkGetImageMemoryRequirements2");
+    auto vkEnc = HostConnection::get()->vkEncoder();
+    resources->on_vkGetImageMemoryRequirements2(vkEnc, device, pInfo, pMemoryRequirements);
+}
 static void entry_vkGetBufferMemoryRequirements2(
     VkDevice device,
     const VkBufferMemoryRequirementsInfo2* pInfo,
@@ -1616,6 +1739,20 @@
     auto resources = ResourceTracker::get();
     resources->on_vkGetBufferMemoryRequirements2(vkEnc, device, pInfo, pMemoryRequirements);
 }
+static void dynCheck_entry_vkGetBufferMemoryRequirements2(
+    VkDevice device,
+    const VkBufferMemoryRequirementsInfo2* pInfo,
+    VkMemoryRequirements2* pMemoryRequirements)
+{
+    auto resources = ResourceTracker::get();
+    if (resources->getApiVersionFromDevice(device) < VK_API_VERSION_1_1)
+    {
+        sOnInvalidDynamicallyCheckedCall("vkGetBufferMemoryRequirements2", "VK_VERSION_1_1");
+    }
+    AEMU_SCOPED_TRACE("vkGetBufferMemoryRequirements2");
+    auto vkEnc = HostConnection::get()->vkEncoder();
+    resources->on_vkGetBufferMemoryRequirements2(vkEnc, device, pInfo, pMemoryRequirements);
+}
 static void entry_vkGetImageSparseMemoryRequirements2(
     VkDevice device,
     const VkImageSparseMemoryRequirementsInfo2* pInfo,
@@ -1626,6 +1763,21 @@
     auto vkEnc = HostConnection::get()->vkEncoder();
     vkEnc->vkGetImageSparseMemoryRequirements2(device, pInfo, pSparseMemoryRequirementCount, pSparseMemoryRequirements);
 }
+static void dynCheck_entry_vkGetImageSparseMemoryRequirements2(
+    VkDevice device,
+    const VkImageSparseMemoryRequirementsInfo2* pInfo,
+    uint32_t* pSparseMemoryRequirementCount,
+    VkSparseImageMemoryRequirements2* pSparseMemoryRequirements)
+{
+    auto resources = ResourceTracker::get();
+    if (resources->getApiVersionFromDevice(device) < VK_API_VERSION_1_1)
+    {
+        sOnInvalidDynamicallyCheckedCall("vkGetImageSparseMemoryRequirements2", "VK_VERSION_1_1");
+    }
+    AEMU_SCOPED_TRACE("vkGetImageSparseMemoryRequirements2");
+    auto vkEnc = HostConnection::get()->vkEncoder();
+    vkEnc->vkGetImageSparseMemoryRequirements2(device, pInfo, pSparseMemoryRequirementCount, pSparseMemoryRequirements);
+}
 static void entry_vkGetPhysicalDeviceFeatures2(
     VkPhysicalDevice physicalDevice,
     VkPhysicalDeviceFeatures2* pFeatures)
@@ -1699,6 +1851,20 @@
     auto vkEnc = HostConnection::get()->vkEncoder();
     vkEnc->vkTrimCommandPool(device, commandPool, flags);
 }
+static void dynCheck_entry_vkTrimCommandPool(
+    VkDevice device,
+    VkCommandPool commandPool,
+    VkCommandPoolTrimFlags flags)
+{
+    auto resources = ResourceTracker::get();
+    if (resources->getApiVersionFromDevice(device) < VK_API_VERSION_1_1)
+    {
+        sOnInvalidDynamicallyCheckedCall("vkTrimCommandPool", "VK_VERSION_1_1");
+    }
+    AEMU_SCOPED_TRACE("vkTrimCommandPool");
+    auto vkEnc = HostConnection::get()->vkEncoder();
+    vkEnc->vkTrimCommandPool(device, commandPool, flags);
+}
 static void entry_vkGetDeviceQueue2(
     VkDevice device,
     const VkDeviceQueueInfo2* pQueueInfo,
@@ -1708,6 +1874,20 @@
     auto vkEnc = HostConnection::get()->vkEncoder();
     vkEnc->vkGetDeviceQueue2(device, pQueueInfo, pQueue);
 }
+static void dynCheck_entry_vkGetDeviceQueue2(
+    VkDevice device,
+    const VkDeviceQueueInfo2* pQueueInfo,
+    VkQueue* pQueue)
+{
+    auto resources = ResourceTracker::get();
+    if (resources->getApiVersionFromDevice(device) < VK_API_VERSION_1_1)
+    {
+        sOnInvalidDynamicallyCheckedCall("vkGetDeviceQueue2", "VK_VERSION_1_1");
+    }
+    AEMU_SCOPED_TRACE("vkGetDeviceQueue2");
+    auto vkEnc = HostConnection::get()->vkEncoder();
+    vkEnc->vkGetDeviceQueue2(device, pQueueInfo, pQueue);
+}
 static VkResult entry_vkCreateSamplerYcbcrConversion(
     VkDevice device,
     const VkSamplerYcbcrConversionCreateInfo* pCreateInfo,
@@ -1721,6 +1901,23 @@
     vkCreateSamplerYcbcrConversion_VkResult_return = resources->on_vkCreateSamplerYcbcrConversion(vkEnc, VK_SUCCESS, device, pCreateInfo, pAllocator, pYcbcrConversion);
     return vkCreateSamplerYcbcrConversion_VkResult_return;
 }
+static VkResult dynCheck_entry_vkCreateSamplerYcbcrConversion(
+    VkDevice device,
+    const VkSamplerYcbcrConversionCreateInfo* pCreateInfo,
+    const VkAllocationCallbacks* pAllocator,
+    VkSamplerYcbcrConversion* pYcbcrConversion)
+{
+    auto resources = ResourceTracker::get();
+    if (resources->getApiVersionFromDevice(device) < VK_API_VERSION_1_1)
+    {
+        sOnInvalidDynamicallyCheckedCall("vkCreateSamplerYcbcrConversion", "VK_VERSION_1_1");
+    }
+    AEMU_SCOPED_TRACE("vkCreateSamplerYcbcrConversion");
+    auto vkEnc = HostConnection::get()->vkEncoder();
+    VkResult vkCreateSamplerYcbcrConversion_VkResult_return = (VkResult)0;
+    vkCreateSamplerYcbcrConversion_VkResult_return = resources->on_vkCreateSamplerYcbcrConversion(vkEnc, VK_SUCCESS, device, pCreateInfo, pAllocator, pYcbcrConversion);
+    return vkCreateSamplerYcbcrConversion_VkResult_return;
+}
 static void entry_vkDestroySamplerYcbcrConversion(
     VkDevice device,
     VkSamplerYcbcrConversion ycbcrConversion,
@@ -1728,7 +1925,22 @@
 {
     AEMU_SCOPED_TRACE("vkDestroySamplerYcbcrConversion");
     auto vkEnc = HostConnection::get()->vkEncoder();
-    vkEnc->vkDestroySamplerYcbcrConversion(device, ycbcrConversion, pAllocator);
+    auto resources = ResourceTracker::get();
+    resources->on_vkDestroySamplerYcbcrConversion(vkEnc, device, ycbcrConversion, pAllocator);
+}
+static void dynCheck_entry_vkDestroySamplerYcbcrConversion(
+    VkDevice device,
+    VkSamplerYcbcrConversion ycbcrConversion,
+    const VkAllocationCallbacks* pAllocator)
+{
+    auto resources = ResourceTracker::get();
+    if (resources->getApiVersionFromDevice(device) < VK_API_VERSION_1_1)
+    {
+        sOnInvalidDynamicallyCheckedCall("vkDestroySamplerYcbcrConversion", "VK_VERSION_1_1");
+    }
+    AEMU_SCOPED_TRACE("vkDestroySamplerYcbcrConversion");
+    auto vkEnc = HostConnection::get()->vkEncoder();
+    resources->on_vkDestroySamplerYcbcrConversion(vkEnc, device, ycbcrConversion, pAllocator);
 }
 static VkResult entry_vkCreateDescriptorUpdateTemplate(
     VkDevice device,
@@ -1742,6 +1954,23 @@
     vkCreateDescriptorUpdateTemplate_VkResult_return = vkEnc->vkCreateDescriptorUpdateTemplate(device, pCreateInfo, pAllocator, pDescriptorUpdateTemplate);
     return vkCreateDescriptorUpdateTemplate_VkResult_return;
 }
+static VkResult dynCheck_entry_vkCreateDescriptorUpdateTemplate(
+    VkDevice device,
+    const VkDescriptorUpdateTemplateCreateInfo* pCreateInfo,
+    const VkAllocationCallbacks* pAllocator,
+    VkDescriptorUpdateTemplate* pDescriptorUpdateTemplate)
+{
+    auto resources = ResourceTracker::get();
+    if (resources->getApiVersionFromDevice(device) < VK_API_VERSION_1_1)
+    {
+        sOnInvalidDynamicallyCheckedCall("vkCreateDescriptorUpdateTemplate", "VK_VERSION_1_1");
+    }
+    AEMU_SCOPED_TRACE("vkCreateDescriptorUpdateTemplate");
+    auto vkEnc = HostConnection::get()->vkEncoder();
+    VkResult vkCreateDescriptorUpdateTemplate_VkResult_return = (VkResult)0;
+    vkCreateDescriptorUpdateTemplate_VkResult_return = vkEnc->vkCreateDescriptorUpdateTemplate(device, pCreateInfo, pAllocator, pDescriptorUpdateTemplate);
+    return vkCreateDescriptorUpdateTemplate_VkResult_return;
+}
 static void entry_vkDestroyDescriptorUpdateTemplate(
     VkDevice device,
     VkDescriptorUpdateTemplate descriptorUpdateTemplate,
@@ -1751,6 +1980,20 @@
     auto vkEnc = HostConnection::get()->vkEncoder();
     vkEnc->vkDestroyDescriptorUpdateTemplate(device, descriptorUpdateTemplate, pAllocator);
 }
+static void dynCheck_entry_vkDestroyDescriptorUpdateTemplate(
+    VkDevice device,
+    VkDescriptorUpdateTemplate descriptorUpdateTemplate,
+    const VkAllocationCallbacks* pAllocator)
+{
+    auto resources = ResourceTracker::get();
+    if (resources->getApiVersionFromDevice(device) < VK_API_VERSION_1_1)
+    {
+        sOnInvalidDynamicallyCheckedCall("vkDestroyDescriptorUpdateTemplate", "VK_VERSION_1_1");
+    }
+    AEMU_SCOPED_TRACE("vkDestroyDescriptorUpdateTemplate");
+    auto vkEnc = HostConnection::get()->vkEncoder();
+    vkEnc->vkDestroyDescriptorUpdateTemplate(device, descriptorUpdateTemplate, pAllocator);
+}
 static void entry_vkUpdateDescriptorSetWithTemplate(
     VkDevice device,
     VkDescriptorSet descriptorSet,
@@ -1762,6 +2005,21 @@
     auto resources = ResourceTracker::get();
     resources->on_vkUpdateDescriptorSetWithTemplate(vkEnc, device, descriptorSet, descriptorUpdateTemplate, pData);
 }
+static void dynCheck_entry_vkUpdateDescriptorSetWithTemplate(
+    VkDevice device,
+    VkDescriptorSet descriptorSet,
+    VkDescriptorUpdateTemplate descriptorUpdateTemplate,
+    const void* pData)
+{
+    auto resources = ResourceTracker::get();
+    if (resources->getApiVersionFromDevice(device) < VK_API_VERSION_1_1)
+    {
+        sOnInvalidDynamicallyCheckedCall("vkUpdateDescriptorSetWithTemplate", "VK_VERSION_1_1");
+    }
+    AEMU_SCOPED_TRACE("vkUpdateDescriptorSetWithTemplate");
+    auto vkEnc = HostConnection::get()->vkEncoder();
+    resources->on_vkUpdateDescriptorSetWithTemplate(vkEnc, device, descriptorSet, descriptorUpdateTemplate, pData);
+}
 static void entry_vkGetPhysicalDeviceExternalBufferProperties(
     VkPhysicalDevice physicalDevice,
     const VkPhysicalDeviceExternalBufferInfo* pExternalBufferInfo,
@@ -1778,7 +2036,8 @@
 {
     AEMU_SCOPED_TRACE("vkGetPhysicalDeviceExternalFenceProperties");
     auto vkEnc = HostConnection::get()->vkEncoder();
-    vkEnc->vkGetPhysicalDeviceExternalFenceProperties(physicalDevice, pExternalFenceInfo, pExternalFenceProperties);
+    auto resources = ResourceTracker::get();
+    resources->on_vkGetPhysicalDeviceExternalFenceProperties(vkEnc, physicalDevice, pExternalFenceInfo, pExternalFenceProperties);
 }
 static void entry_vkGetPhysicalDeviceExternalSemaphoreProperties(
     VkPhysicalDevice physicalDevice,
@@ -1798,6 +2057,20 @@
     auto vkEnc = HostConnection::get()->vkEncoder();
     vkEnc->vkGetDescriptorSetLayoutSupport(device, pCreateInfo, pSupport);
 }
+static void dynCheck_entry_vkGetDescriptorSetLayoutSupport(
+    VkDevice device,
+    const VkDescriptorSetLayoutCreateInfo* pCreateInfo,
+    VkDescriptorSetLayoutSupport* pSupport)
+{
+    auto resources = ResourceTracker::get();
+    if (resources->getApiVersionFromDevice(device) < VK_API_VERSION_1_1)
+    {
+        sOnInvalidDynamicallyCheckedCall("vkGetDescriptorSetLayoutSupport", "VK_VERSION_1_1");
+    }
+    AEMU_SCOPED_TRACE("vkGetDescriptorSetLayoutSupport");
+    auto vkEnc = HostConnection::get()->vkEncoder();
+    vkEnc->vkGetDescriptorSetLayoutSupport(device, pCreateInfo, pSupport);
+}
 #endif
 #ifdef VK_KHR_surface
 static void entry_vkDestroySurfaceKHR(
@@ -1870,6 +2143,23 @@
     vkCreateSwapchainKHR_VkResult_return = vkEnc->vkCreateSwapchainKHR(device, pCreateInfo, pAllocator, pSwapchain);
     return vkCreateSwapchainKHR_VkResult_return;
 }
+static VkResult dynCheck_entry_vkCreateSwapchainKHR(
+    VkDevice device,
+    const VkSwapchainCreateInfoKHR* pCreateInfo,
+    const VkAllocationCallbacks* pAllocator,
+    VkSwapchainKHR* pSwapchain)
+{
+    auto resources = ResourceTracker::get();
+    if (!resources->hasDeviceExtension(device, "VK_KHR_swapchain"))
+    {
+        sOnInvalidDynamicallyCheckedCall("vkCreateSwapchainKHR", "VK_KHR_swapchain");
+    }
+    AEMU_SCOPED_TRACE("vkCreateSwapchainKHR");
+    auto vkEnc = HostConnection::get()->vkEncoder();
+    VkResult vkCreateSwapchainKHR_VkResult_return = (VkResult)0;
+    vkCreateSwapchainKHR_VkResult_return = vkEnc->vkCreateSwapchainKHR(device, pCreateInfo, pAllocator, pSwapchain);
+    return vkCreateSwapchainKHR_VkResult_return;
+}
 static void entry_vkDestroySwapchainKHR(
     VkDevice device,
     VkSwapchainKHR swapchain,
@@ -1879,6 +2169,20 @@
     auto vkEnc = HostConnection::get()->vkEncoder();
     vkEnc->vkDestroySwapchainKHR(device, swapchain, pAllocator);
 }
+static void dynCheck_entry_vkDestroySwapchainKHR(
+    VkDevice device,
+    VkSwapchainKHR swapchain,
+    const VkAllocationCallbacks* pAllocator)
+{
+    auto resources = ResourceTracker::get();
+    if (!resources->hasDeviceExtension(device, "VK_KHR_swapchain"))
+    {
+        sOnInvalidDynamicallyCheckedCall("vkDestroySwapchainKHR", "VK_KHR_swapchain");
+    }
+    AEMU_SCOPED_TRACE("vkDestroySwapchainKHR");
+    auto vkEnc = HostConnection::get()->vkEncoder();
+    vkEnc->vkDestroySwapchainKHR(device, swapchain, pAllocator);
+}
 static VkResult entry_vkGetSwapchainImagesKHR(
     VkDevice device,
     VkSwapchainKHR swapchain,
@@ -1891,6 +2195,23 @@
     vkGetSwapchainImagesKHR_VkResult_return = vkEnc->vkGetSwapchainImagesKHR(device, swapchain, pSwapchainImageCount, pSwapchainImages);
     return vkGetSwapchainImagesKHR_VkResult_return;
 }
+static VkResult dynCheck_entry_vkGetSwapchainImagesKHR(
+    VkDevice device,
+    VkSwapchainKHR swapchain,
+    uint32_t* pSwapchainImageCount,
+    VkImage* pSwapchainImages)
+{
+    auto resources = ResourceTracker::get();
+    if (!resources->hasDeviceExtension(device, "VK_KHR_swapchain"))
+    {
+        sOnInvalidDynamicallyCheckedCall("vkGetSwapchainImagesKHR", "VK_KHR_swapchain");
+    }
+    AEMU_SCOPED_TRACE("vkGetSwapchainImagesKHR");
+    auto vkEnc = HostConnection::get()->vkEncoder();
+    VkResult vkGetSwapchainImagesKHR_VkResult_return = (VkResult)0;
+    vkGetSwapchainImagesKHR_VkResult_return = vkEnc->vkGetSwapchainImagesKHR(device, swapchain, pSwapchainImageCount, pSwapchainImages);
+    return vkGetSwapchainImagesKHR_VkResult_return;
+}
 static VkResult entry_vkAcquireNextImageKHR(
     VkDevice device,
     VkSwapchainKHR swapchain,
@@ -1905,6 +2226,25 @@
     vkAcquireNextImageKHR_VkResult_return = vkEnc->vkAcquireNextImageKHR(device, swapchain, timeout, semaphore, fence, pImageIndex);
     return vkAcquireNextImageKHR_VkResult_return;
 }
+static VkResult dynCheck_entry_vkAcquireNextImageKHR(
+    VkDevice device,
+    VkSwapchainKHR swapchain,
+    uint64_t timeout,
+    VkSemaphore semaphore,
+    VkFence fence,
+    uint32_t* pImageIndex)
+{
+    auto resources = ResourceTracker::get();
+    if (!resources->hasDeviceExtension(device, "VK_KHR_swapchain"))
+    {
+        sOnInvalidDynamicallyCheckedCall("vkAcquireNextImageKHR", "VK_KHR_swapchain");
+    }
+    AEMU_SCOPED_TRACE("vkAcquireNextImageKHR");
+    auto vkEnc = HostConnection::get()->vkEncoder();
+    VkResult vkAcquireNextImageKHR_VkResult_return = (VkResult)0;
+    vkAcquireNextImageKHR_VkResult_return = vkEnc->vkAcquireNextImageKHR(device, swapchain, timeout, semaphore, fence, pImageIndex);
+    return vkAcquireNextImageKHR_VkResult_return;
+}
 static VkResult entry_vkQueuePresentKHR(
     VkQueue queue,
     const VkPresentInfoKHR* pPresentInfo)
@@ -1925,6 +2265,21 @@
     vkGetDeviceGroupPresentCapabilitiesKHR_VkResult_return = vkEnc->vkGetDeviceGroupPresentCapabilitiesKHR(device, pDeviceGroupPresentCapabilities);
     return vkGetDeviceGroupPresentCapabilitiesKHR_VkResult_return;
 }
+static VkResult dynCheck_entry_vkGetDeviceGroupPresentCapabilitiesKHR(
+    VkDevice device,
+    VkDeviceGroupPresentCapabilitiesKHR* pDeviceGroupPresentCapabilities)
+{
+    auto resources = ResourceTracker::get();
+    if (!resources->hasDeviceExtension(device, "VK_KHR_swapchain"))
+    {
+        sOnInvalidDynamicallyCheckedCall("vkGetDeviceGroupPresentCapabilitiesKHR", "VK_KHR_swapchain");
+    }
+    AEMU_SCOPED_TRACE("vkGetDeviceGroupPresentCapabilitiesKHR");
+    auto vkEnc = HostConnection::get()->vkEncoder();
+    VkResult vkGetDeviceGroupPresentCapabilitiesKHR_VkResult_return = (VkResult)0;
+    vkGetDeviceGroupPresentCapabilitiesKHR_VkResult_return = vkEnc->vkGetDeviceGroupPresentCapabilitiesKHR(device, pDeviceGroupPresentCapabilities);
+    return vkGetDeviceGroupPresentCapabilitiesKHR_VkResult_return;
+}
 static VkResult entry_vkGetDeviceGroupSurfacePresentModesKHR(
     VkDevice device,
     VkSurfaceKHR surface,
@@ -1936,6 +2291,22 @@
     vkGetDeviceGroupSurfacePresentModesKHR_VkResult_return = vkEnc->vkGetDeviceGroupSurfacePresentModesKHR(device, surface, pModes);
     return vkGetDeviceGroupSurfacePresentModesKHR_VkResult_return;
 }
+static VkResult dynCheck_entry_vkGetDeviceGroupSurfacePresentModesKHR(
+    VkDevice device,
+    VkSurfaceKHR surface,
+    VkDeviceGroupPresentModeFlagsKHR* pModes)
+{
+    auto resources = ResourceTracker::get();
+    if (!resources->hasDeviceExtension(device, "VK_KHR_swapchain"))
+    {
+        sOnInvalidDynamicallyCheckedCall("vkGetDeviceGroupSurfacePresentModesKHR", "VK_KHR_swapchain");
+    }
+    AEMU_SCOPED_TRACE("vkGetDeviceGroupSurfacePresentModesKHR");
+    auto vkEnc = HostConnection::get()->vkEncoder();
+    VkResult vkGetDeviceGroupSurfacePresentModesKHR_VkResult_return = (VkResult)0;
+    vkGetDeviceGroupSurfacePresentModesKHR_VkResult_return = vkEnc->vkGetDeviceGroupSurfacePresentModesKHR(device, surface, pModes);
+    return vkGetDeviceGroupSurfacePresentModesKHR_VkResult_return;
+}
 static VkResult entry_vkGetPhysicalDevicePresentRectanglesKHR(
     VkPhysicalDevice physicalDevice,
     VkSurfaceKHR surface,
@@ -1959,6 +2330,22 @@
     vkAcquireNextImage2KHR_VkResult_return = vkEnc->vkAcquireNextImage2KHR(device, pAcquireInfo, pImageIndex);
     return vkAcquireNextImage2KHR_VkResult_return;
 }
+static VkResult dynCheck_entry_vkAcquireNextImage2KHR(
+    VkDevice device,
+    const VkAcquireNextImageInfoKHR* pAcquireInfo,
+    uint32_t* pImageIndex)
+{
+    auto resources = ResourceTracker::get();
+    if (!resources->hasDeviceExtension(device, "VK_KHR_swapchain"))
+    {
+        sOnInvalidDynamicallyCheckedCall("vkAcquireNextImage2KHR", "VK_KHR_swapchain");
+    }
+    AEMU_SCOPED_TRACE("vkAcquireNextImage2KHR");
+    auto vkEnc = HostConnection::get()->vkEncoder();
+    VkResult vkAcquireNextImage2KHR_VkResult_return = (VkResult)0;
+    vkAcquireNextImage2KHR_VkResult_return = vkEnc->vkAcquireNextImage2KHR(device, pAcquireInfo, pImageIndex);
+    return vkAcquireNextImage2KHR_VkResult_return;
+}
 #endif
 #ifdef VK_KHR_display
 static VkResult entry_vkGetPhysicalDeviceDisplayPropertiesKHR(
@@ -2059,6 +2446,24 @@
     vkCreateSharedSwapchainsKHR_VkResult_return = vkEnc->vkCreateSharedSwapchainsKHR(device, swapchainCount, pCreateInfos, pAllocator, pSwapchains);
     return vkCreateSharedSwapchainsKHR_VkResult_return;
 }
+static VkResult dynCheck_entry_vkCreateSharedSwapchainsKHR(
+    VkDevice device,
+    uint32_t swapchainCount,
+    const VkSwapchainCreateInfoKHR* pCreateInfos,
+    const VkAllocationCallbacks* pAllocator,
+    VkSwapchainKHR* pSwapchains)
+{
+    auto resources = ResourceTracker::get();
+    if (!resources->hasDeviceExtension(device, "VK_KHR_display_swapchain"))
+    {
+        sOnInvalidDynamicallyCheckedCall("vkCreateSharedSwapchainsKHR", "VK_KHR_display_swapchain");
+    }
+    AEMU_SCOPED_TRACE("vkCreateSharedSwapchainsKHR");
+    auto vkEnc = HostConnection::get()->vkEncoder();
+    VkResult vkCreateSharedSwapchainsKHR_VkResult_return = (VkResult)0;
+    vkCreateSharedSwapchainsKHR_VkResult_return = vkEnc->vkCreateSharedSwapchainsKHR(device, swapchainCount, pCreateInfos, pAllocator, pSwapchains);
+    return vkCreateSharedSwapchainsKHR_VkResult_return;
+}
 #endif
 #ifdef VK_KHR_xlib_surface
 static VkResult entry_vkCreateXlibSurfaceKHR(
@@ -2282,12 +2687,29 @@
     auto vkEnc = HostConnection::get()->vkEncoder();
     vkEnc->vkGetDeviceGroupPeerMemoryFeaturesKHR(device, heapIndex, localDeviceIndex, remoteDeviceIndex, pPeerMemoryFeatures);
 }
+static void dynCheck_entry_vkGetDeviceGroupPeerMemoryFeaturesKHR(
+    VkDevice device,
+    uint32_t heapIndex,
+    uint32_t localDeviceIndex,
+    uint32_t remoteDeviceIndex,
+    VkPeerMemoryFeatureFlags* pPeerMemoryFeatures)
+{
+    auto resources = ResourceTracker::get();
+    if (!resources->hasDeviceExtension(device, "VK_KHR_device_group"))
+    {
+        sOnInvalidDynamicallyCheckedCall("vkGetDeviceGroupPeerMemoryFeaturesKHR", "VK_KHR_device_group");
+    }
+    AEMU_SCOPED_TRACE("vkGetDeviceGroupPeerMemoryFeaturesKHR");
+    auto vkEnc = HostConnection::get()->vkEncoder();
+    vkEnc->vkGetDeviceGroupPeerMemoryFeaturesKHR(device, heapIndex, localDeviceIndex, remoteDeviceIndex, pPeerMemoryFeatures);
+}
 static void entry_vkCmdSetDeviceMaskKHR(
     VkCommandBuffer commandBuffer,
     uint32_t deviceMask)
 {
     AEMU_SCOPED_TRACE("vkCmdSetDeviceMaskKHR");
     auto vkEnc = HostConnection::get()->vkEncoder();
+    ResourceTracker::get()->syncEncodersForCommandBuffer(commandBuffer, vkEnc);
     vkEnc->vkCmdSetDeviceMaskKHR(commandBuffer, deviceMask);
 }
 static void entry_vkCmdDispatchBaseKHR(
@@ -2301,6 +2723,7 @@
 {
     AEMU_SCOPED_TRACE("vkCmdDispatchBaseKHR");
     auto vkEnc = HostConnection::get()->vkEncoder();
+    ResourceTracker::get()->syncEncodersForCommandBuffer(commandBuffer, vkEnc);
     vkEnc->vkCmdDispatchBaseKHR(commandBuffer, baseGroupX, baseGroupY, baseGroupZ, groupCountX, groupCountY, groupCountZ);
 }
 #endif
@@ -2316,6 +2739,20 @@
     auto vkEnc = HostConnection::get()->vkEncoder();
     vkEnc->vkTrimCommandPoolKHR(device, commandPool, flags);
 }
+static void dynCheck_entry_vkTrimCommandPoolKHR(
+    VkDevice device,
+    VkCommandPool commandPool,
+    VkCommandPoolTrimFlags flags)
+{
+    auto resources = ResourceTracker::get();
+    if (!resources->hasDeviceExtension(device, "VK_KHR_maintenance1"))
+    {
+        sOnInvalidDynamicallyCheckedCall("vkTrimCommandPoolKHR", "VK_KHR_maintenance1");
+    }
+    AEMU_SCOPED_TRACE("vkTrimCommandPoolKHR");
+    auto vkEnc = HostConnection::get()->vkEncoder();
+    vkEnc->vkTrimCommandPoolKHR(device, commandPool, flags);
+}
 #endif
 #ifdef VK_KHR_device_group_creation
 static VkResult entry_vkEnumeratePhysicalDeviceGroupsKHR(
@@ -2355,6 +2792,22 @@
     vkGetMemoryWin32HandleKHR_VkResult_return = vkEnc->vkGetMemoryWin32HandleKHR(device, pGetWin32HandleInfo, pHandle);
     return vkGetMemoryWin32HandleKHR_VkResult_return;
 }
+static VkResult dynCheck_entry_vkGetMemoryWin32HandleKHR(
+    VkDevice device,
+    const VkMemoryGetWin32HandleInfoKHR* pGetWin32HandleInfo,
+    HANDLE* pHandle)
+{
+    auto resources = ResourceTracker::get();
+    if (!resources->hasDeviceExtension(device, "VK_KHR_external_memory_win32"))
+    {
+        sOnInvalidDynamicallyCheckedCall("vkGetMemoryWin32HandleKHR", "VK_KHR_external_memory_win32");
+    }
+    AEMU_SCOPED_TRACE("vkGetMemoryWin32HandleKHR");
+    auto vkEnc = HostConnection::get()->vkEncoder();
+    VkResult vkGetMemoryWin32HandleKHR_VkResult_return = (VkResult)0;
+    vkGetMemoryWin32HandleKHR_VkResult_return = vkEnc->vkGetMemoryWin32HandleKHR(device, pGetWin32HandleInfo, pHandle);
+    return vkGetMemoryWin32HandleKHR_VkResult_return;
+}
 static VkResult entry_vkGetMemoryWin32HandlePropertiesKHR(
     VkDevice device,
     VkExternalMemoryHandleTypeFlagBits handleType,
@@ -2367,6 +2820,23 @@
     vkGetMemoryWin32HandlePropertiesKHR_VkResult_return = vkEnc->vkGetMemoryWin32HandlePropertiesKHR(device, handleType, handle, pMemoryWin32HandleProperties);
     return vkGetMemoryWin32HandlePropertiesKHR_VkResult_return;
 }
+static VkResult dynCheck_entry_vkGetMemoryWin32HandlePropertiesKHR(
+    VkDevice device,
+    VkExternalMemoryHandleTypeFlagBits handleType,
+    HANDLE handle,
+    VkMemoryWin32HandlePropertiesKHR* pMemoryWin32HandleProperties)
+{
+    auto resources = ResourceTracker::get();
+    if (!resources->hasDeviceExtension(device, "VK_KHR_external_memory_win32"))
+    {
+        sOnInvalidDynamicallyCheckedCall("vkGetMemoryWin32HandlePropertiesKHR", "VK_KHR_external_memory_win32");
+    }
+    AEMU_SCOPED_TRACE("vkGetMemoryWin32HandlePropertiesKHR");
+    auto vkEnc = HostConnection::get()->vkEncoder();
+    VkResult vkGetMemoryWin32HandlePropertiesKHR_VkResult_return = (VkResult)0;
+    vkGetMemoryWin32HandlePropertiesKHR_VkResult_return = vkEnc->vkGetMemoryWin32HandlePropertiesKHR(device, handleType, handle, pMemoryWin32HandleProperties);
+    return vkGetMemoryWin32HandlePropertiesKHR_VkResult_return;
+}
 #endif
 #ifdef VK_KHR_external_memory_fd
 static VkResult entry_vkGetMemoryFdKHR(
@@ -2380,6 +2850,22 @@
     vkGetMemoryFdKHR_VkResult_return = vkEnc->vkGetMemoryFdKHR(device, pGetFdInfo, pFd);
     return vkGetMemoryFdKHR_VkResult_return;
 }
+static VkResult dynCheck_entry_vkGetMemoryFdKHR(
+    VkDevice device,
+    const VkMemoryGetFdInfoKHR* pGetFdInfo,
+    int* pFd)
+{
+    auto resources = ResourceTracker::get();
+    if (!resources->hasDeviceExtension(device, "VK_KHR_external_memory_fd"))
+    {
+        sOnInvalidDynamicallyCheckedCall("vkGetMemoryFdKHR", "VK_KHR_external_memory_fd");
+    }
+    AEMU_SCOPED_TRACE("vkGetMemoryFdKHR");
+    auto vkEnc = HostConnection::get()->vkEncoder();
+    VkResult vkGetMemoryFdKHR_VkResult_return = (VkResult)0;
+    vkGetMemoryFdKHR_VkResult_return = vkEnc->vkGetMemoryFdKHR(device, pGetFdInfo, pFd);
+    return vkGetMemoryFdKHR_VkResult_return;
+}
 static VkResult entry_vkGetMemoryFdPropertiesKHR(
     VkDevice device,
     VkExternalMemoryHandleTypeFlagBits handleType,
@@ -2392,6 +2878,23 @@
     vkGetMemoryFdPropertiesKHR_VkResult_return = vkEnc->vkGetMemoryFdPropertiesKHR(device, handleType, fd, pMemoryFdProperties);
     return vkGetMemoryFdPropertiesKHR_VkResult_return;
 }
+static VkResult dynCheck_entry_vkGetMemoryFdPropertiesKHR(
+    VkDevice device,
+    VkExternalMemoryHandleTypeFlagBits handleType,
+    int fd,
+    VkMemoryFdPropertiesKHR* pMemoryFdProperties)
+{
+    auto resources = ResourceTracker::get();
+    if (!resources->hasDeviceExtension(device, "VK_KHR_external_memory_fd"))
+    {
+        sOnInvalidDynamicallyCheckedCall("vkGetMemoryFdPropertiesKHR", "VK_KHR_external_memory_fd");
+    }
+    AEMU_SCOPED_TRACE("vkGetMemoryFdPropertiesKHR");
+    auto vkEnc = HostConnection::get()->vkEncoder();
+    VkResult vkGetMemoryFdPropertiesKHR_VkResult_return = (VkResult)0;
+    vkGetMemoryFdPropertiesKHR_VkResult_return = vkEnc->vkGetMemoryFdPropertiesKHR(device, handleType, fd, pMemoryFdProperties);
+    return vkGetMemoryFdPropertiesKHR_VkResult_return;
+}
 #endif
 #ifdef VK_KHR_win32_keyed_mutex
 #endif
@@ -2419,6 +2922,21 @@
     vkImportSemaphoreWin32HandleKHR_VkResult_return = vkEnc->vkImportSemaphoreWin32HandleKHR(device, pImportSemaphoreWin32HandleInfo);
     return vkImportSemaphoreWin32HandleKHR_VkResult_return;
 }
+static VkResult dynCheck_entry_vkImportSemaphoreWin32HandleKHR(
+    VkDevice device,
+    const VkImportSemaphoreWin32HandleInfoKHR* pImportSemaphoreWin32HandleInfo)
+{
+    auto resources = ResourceTracker::get();
+    if (!resources->hasDeviceExtension(device, "VK_KHR_external_semaphore_win32"))
+    {
+        sOnInvalidDynamicallyCheckedCall("vkImportSemaphoreWin32HandleKHR", "VK_KHR_external_semaphore_win32");
+    }
+    AEMU_SCOPED_TRACE("vkImportSemaphoreWin32HandleKHR");
+    auto vkEnc = HostConnection::get()->vkEncoder();
+    VkResult vkImportSemaphoreWin32HandleKHR_VkResult_return = (VkResult)0;
+    vkImportSemaphoreWin32HandleKHR_VkResult_return = vkEnc->vkImportSemaphoreWin32HandleKHR(device, pImportSemaphoreWin32HandleInfo);
+    return vkImportSemaphoreWin32HandleKHR_VkResult_return;
+}
 static VkResult entry_vkGetSemaphoreWin32HandleKHR(
     VkDevice device,
     const VkSemaphoreGetWin32HandleInfoKHR* pGetWin32HandleInfo,
@@ -2430,6 +2948,22 @@
     vkGetSemaphoreWin32HandleKHR_VkResult_return = vkEnc->vkGetSemaphoreWin32HandleKHR(device, pGetWin32HandleInfo, pHandle);
     return vkGetSemaphoreWin32HandleKHR_VkResult_return;
 }
+static VkResult dynCheck_entry_vkGetSemaphoreWin32HandleKHR(
+    VkDevice device,
+    const VkSemaphoreGetWin32HandleInfoKHR* pGetWin32HandleInfo,
+    HANDLE* pHandle)
+{
+    auto resources = ResourceTracker::get();
+    if (!resources->hasDeviceExtension(device, "VK_KHR_external_semaphore_win32"))
+    {
+        sOnInvalidDynamicallyCheckedCall("vkGetSemaphoreWin32HandleKHR", "VK_KHR_external_semaphore_win32");
+    }
+    AEMU_SCOPED_TRACE("vkGetSemaphoreWin32HandleKHR");
+    auto vkEnc = HostConnection::get()->vkEncoder();
+    VkResult vkGetSemaphoreWin32HandleKHR_VkResult_return = (VkResult)0;
+    vkGetSemaphoreWin32HandleKHR_VkResult_return = vkEnc->vkGetSemaphoreWin32HandleKHR(device, pGetWin32HandleInfo, pHandle);
+    return vkGetSemaphoreWin32HandleKHR_VkResult_return;
+}
 #endif
 #ifdef VK_KHR_external_semaphore_fd
 static VkResult entry_vkImportSemaphoreFdKHR(
@@ -2443,6 +2977,21 @@
     vkImportSemaphoreFdKHR_VkResult_return = resources->on_vkImportSemaphoreFdKHR(vkEnc, VK_SUCCESS, device, pImportSemaphoreFdInfo);
     return vkImportSemaphoreFdKHR_VkResult_return;
 }
+static VkResult dynCheck_entry_vkImportSemaphoreFdKHR(
+    VkDevice device,
+    const VkImportSemaphoreFdInfoKHR* pImportSemaphoreFdInfo)
+{
+    auto resources = ResourceTracker::get();
+    if (!resources->hasDeviceExtension(device, "VK_KHR_external_semaphore_fd"))
+    {
+        sOnInvalidDynamicallyCheckedCall("vkImportSemaphoreFdKHR", "VK_KHR_external_semaphore_fd");
+    }
+    AEMU_SCOPED_TRACE("vkImportSemaphoreFdKHR");
+    auto vkEnc = HostConnection::get()->vkEncoder();
+    VkResult vkImportSemaphoreFdKHR_VkResult_return = (VkResult)0;
+    vkImportSemaphoreFdKHR_VkResult_return = resources->on_vkImportSemaphoreFdKHR(vkEnc, VK_SUCCESS, device, pImportSemaphoreFdInfo);
+    return vkImportSemaphoreFdKHR_VkResult_return;
+}
 static VkResult entry_vkGetSemaphoreFdKHR(
     VkDevice device,
     const VkSemaphoreGetFdInfoKHR* pGetFdInfo,
@@ -2455,6 +3004,22 @@
     vkGetSemaphoreFdKHR_VkResult_return = resources->on_vkGetSemaphoreFdKHR(vkEnc, VK_SUCCESS, device, pGetFdInfo, pFd);
     return vkGetSemaphoreFdKHR_VkResult_return;
 }
+static VkResult dynCheck_entry_vkGetSemaphoreFdKHR(
+    VkDevice device,
+    const VkSemaphoreGetFdInfoKHR* pGetFdInfo,
+    int* pFd)
+{
+    auto resources = ResourceTracker::get();
+    if (!resources->hasDeviceExtension(device, "VK_KHR_external_semaphore_fd"))
+    {
+        sOnInvalidDynamicallyCheckedCall("vkGetSemaphoreFdKHR", "VK_KHR_external_semaphore_fd");
+    }
+    AEMU_SCOPED_TRACE("vkGetSemaphoreFdKHR");
+    auto vkEnc = HostConnection::get()->vkEncoder();
+    VkResult vkGetSemaphoreFdKHR_VkResult_return = (VkResult)0;
+    vkGetSemaphoreFdKHR_VkResult_return = resources->on_vkGetSemaphoreFdKHR(vkEnc, VK_SUCCESS, device, pGetFdInfo, pFd);
+    return vkGetSemaphoreFdKHR_VkResult_return;
+}
 #endif
 #ifdef VK_KHR_push_descriptor
 static void entry_vkCmdPushDescriptorSetKHR(
@@ -2467,6 +3032,7 @@
 {
     AEMU_SCOPED_TRACE("vkCmdPushDescriptorSetKHR");
     auto vkEnc = HostConnection::get()->vkEncoder();
+    ResourceTracker::get()->syncEncodersForCommandBuffer(commandBuffer, vkEnc);
     vkEnc->vkCmdPushDescriptorSetKHR(commandBuffer, pipelineBindPoint, layout, set, descriptorWriteCount, pDescriptorWrites);
 }
 static void entry_vkCmdPushDescriptorSetWithTemplateKHR(
@@ -2478,6 +3044,7 @@
 {
     AEMU_SCOPED_TRACE("vkCmdPushDescriptorSetWithTemplateKHR");
     auto vkEnc = HostConnection::get()->vkEncoder();
+    ResourceTracker::get()->syncEncodersForCommandBuffer(commandBuffer, vkEnc);
     vkEnc->vkCmdPushDescriptorSetWithTemplateKHR(commandBuffer, descriptorUpdateTemplate, layout, set, pData);
 }
 #endif
@@ -2498,6 +3065,23 @@
     vkCreateDescriptorUpdateTemplateKHR_VkResult_return = vkEnc->vkCreateDescriptorUpdateTemplateKHR(device, pCreateInfo, pAllocator, pDescriptorUpdateTemplate);
     return vkCreateDescriptorUpdateTemplateKHR_VkResult_return;
 }
+static VkResult dynCheck_entry_vkCreateDescriptorUpdateTemplateKHR(
+    VkDevice device,
+    const VkDescriptorUpdateTemplateCreateInfo* pCreateInfo,
+    const VkAllocationCallbacks* pAllocator,
+    VkDescriptorUpdateTemplate* pDescriptorUpdateTemplate)
+{
+    auto resources = ResourceTracker::get();
+    if (!resources->hasDeviceExtension(device, "VK_KHR_descriptor_update_template"))
+    {
+        sOnInvalidDynamicallyCheckedCall("vkCreateDescriptorUpdateTemplateKHR", "VK_KHR_descriptor_update_template");
+    }
+    AEMU_SCOPED_TRACE("vkCreateDescriptorUpdateTemplateKHR");
+    auto vkEnc = HostConnection::get()->vkEncoder();
+    VkResult vkCreateDescriptorUpdateTemplateKHR_VkResult_return = (VkResult)0;
+    vkCreateDescriptorUpdateTemplateKHR_VkResult_return = vkEnc->vkCreateDescriptorUpdateTemplateKHR(device, pCreateInfo, pAllocator, pDescriptorUpdateTemplate);
+    return vkCreateDescriptorUpdateTemplateKHR_VkResult_return;
+}
 static void entry_vkDestroyDescriptorUpdateTemplateKHR(
     VkDevice device,
     VkDescriptorUpdateTemplate descriptorUpdateTemplate,
@@ -2507,6 +3091,20 @@
     auto vkEnc = HostConnection::get()->vkEncoder();
     vkEnc->vkDestroyDescriptorUpdateTemplateKHR(device, descriptorUpdateTemplate, pAllocator);
 }
+static void dynCheck_entry_vkDestroyDescriptorUpdateTemplateKHR(
+    VkDevice device,
+    VkDescriptorUpdateTemplate descriptorUpdateTemplate,
+    const VkAllocationCallbacks* pAllocator)
+{
+    auto resources = ResourceTracker::get();
+    if (!resources->hasDeviceExtension(device, "VK_KHR_descriptor_update_template"))
+    {
+        sOnInvalidDynamicallyCheckedCall("vkDestroyDescriptorUpdateTemplateKHR", "VK_KHR_descriptor_update_template");
+    }
+    AEMU_SCOPED_TRACE("vkDestroyDescriptorUpdateTemplateKHR");
+    auto vkEnc = HostConnection::get()->vkEncoder();
+    vkEnc->vkDestroyDescriptorUpdateTemplateKHR(device, descriptorUpdateTemplate, pAllocator);
+}
 static void entry_vkUpdateDescriptorSetWithTemplateKHR(
     VkDevice device,
     VkDescriptorSet descriptorSet,
@@ -2517,6 +3115,21 @@
     auto vkEnc = HostConnection::get()->vkEncoder();
     vkEnc->vkUpdateDescriptorSetWithTemplateKHR(device, descriptorSet, descriptorUpdateTemplate, pData);
 }
+static void dynCheck_entry_vkUpdateDescriptorSetWithTemplateKHR(
+    VkDevice device,
+    VkDescriptorSet descriptorSet,
+    VkDescriptorUpdateTemplate descriptorUpdateTemplate,
+    const void* pData)
+{
+    auto resources = ResourceTracker::get();
+    if (!resources->hasDeviceExtension(device, "VK_KHR_descriptor_update_template"))
+    {
+        sOnInvalidDynamicallyCheckedCall("vkUpdateDescriptorSetWithTemplateKHR", "VK_KHR_descriptor_update_template");
+    }
+    AEMU_SCOPED_TRACE("vkUpdateDescriptorSetWithTemplateKHR");
+    auto vkEnc = HostConnection::get()->vkEncoder();
+    vkEnc->vkUpdateDescriptorSetWithTemplateKHR(device, descriptorSet, descriptorUpdateTemplate, pData);
+}
 #endif
 #ifdef VK_KHR_create_renderpass2
 static VkResult entry_vkCreateRenderPass2KHR(
@@ -2531,6 +3144,23 @@
     vkCreateRenderPass2KHR_VkResult_return = vkEnc->vkCreateRenderPass2KHR(device, pCreateInfo, pAllocator, pRenderPass);
     return vkCreateRenderPass2KHR_VkResult_return;
 }
+static VkResult dynCheck_entry_vkCreateRenderPass2KHR(
+    VkDevice device,
+    const VkRenderPassCreateInfo2KHR* pCreateInfo,
+    const VkAllocationCallbacks* pAllocator,
+    VkRenderPass* pRenderPass)
+{
+    auto resources = ResourceTracker::get();
+    if (!resources->hasDeviceExtension(device, "VK_KHR_create_renderpass2"))
+    {
+        sOnInvalidDynamicallyCheckedCall("vkCreateRenderPass2KHR", "VK_KHR_create_renderpass2");
+    }
+    AEMU_SCOPED_TRACE("vkCreateRenderPass2KHR");
+    auto vkEnc = HostConnection::get()->vkEncoder();
+    VkResult vkCreateRenderPass2KHR_VkResult_return = (VkResult)0;
+    vkCreateRenderPass2KHR_VkResult_return = vkEnc->vkCreateRenderPass2KHR(device, pCreateInfo, pAllocator, pRenderPass);
+    return vkCreateRenderPass2KHR_VkResult_return;
+}
 static void entry_vkCmdBeginRenderPass2KHR(
     VkCommandBuffer commandBuffer,
     const VkRenderPassBeginInfo* pRenderPassBegin,
@@ -2538,6 +3168,7 @@
 {
     AEMU_SCOPED_TRACE("vkCmdBeginRenderPass2KHR");
     auto vkEnc = HostConnection::get()->vkEncoder();
+    ResourceTracker::get()->syncEncodersForCommandBuffer(commandBuffer, vkEnc);
     vkEnc->vkCmdBeginRenderPass2KHR(commandBuffer, pRenderPassBegin, pSubpassBeginInfo);
 }
 static void entry_vkCmdNextSubpass2KHR(
@@ -2547,6 +3178,7 @@
 {
     AEMU_SCOPED_TRACE("vkCmdNextSubpass2KHR");
     auto vkEnc = HostConnection::get()->vkEncoder();
+    ResourceTracker::get()->syncEncodersForCommandBuffer(commandBuffer, vkEnc);
     vkEnc->vkCmdNextSubpass2KHR(commandBuffer, pSubpassBeginInfo, pSubpassEndInfo);
 }
 static void entry_vkCmdEndRenderPass2KHR(
@@ -2555,6 +3187,7 @@
 {
     AEMU_SCOPED_TRACE("vkCmdEndRenderPass2KHR");
     auto vkEnc = HostConnection::get()->vkEncoder();
+    ResourceTracker::get()->syncEncodersForCommandBuffer(commandBuffer, vkEnc);
     vkEnc->vkCmdEndRenderPass2KHR(commandBuffer, pSubpassEndInfo);
 }
 #endif
@@ -2569,6 +3202,21 @@
     vkGetSwapchainStatusKHR_VkResult_return = vkEnc->vkGetSwapchainStatusKHR(device, swapchain);
     return vkGetSwapchainStatusKHR_VkResult_return;
 }
+static VkResult dynCheck_entry_vkGetSwapchainStatusKHR(
+    VkDevice device,
+    VkSwapchainKHR swapchain)
+{
+    auto resources = ResourceTracker::get();
+    if (!resources->hasDeviceExtension(device, "VK_KHR_shared_presentable_image"))
+    {
+        sOnInvalidDynamicallyCheckedCall("vkGetSwapchainStatusKHR", "VK_KHR_shared_presentable_image");
+    }
+    AEMU_SCOPED_TRACE("vkGetSwapchainStatusKHR");
+    auto vkEnc = HostConnection::get()->vkEncoder();
+    VkResult vkGetSwapchainStatusKHR_VkResult_return = (VkResult)0;
+    vkGetSwapchainStatusKHR_VkResult_return = vkEnc->vkGetSwapchainStatusKHR(device, swapchain);
+    return vkGetSwapchainStatusKHR_VkResult_return;
+}
 #endif
 #ifdef VK_KHR_external_fence_capabilities
 static void entry_vkGetPhysicalDeviceExternalFencePropertiesKHR(
@@ -2578,7 +3226,8 @@
 {
     AEMU_SCOPED_TRACE("vkGetPhysicalDeviceExternalFencePropertiesKHR");
     auto vkEnc = HostConnection::get()->vkEncoder();
-    vkEnc->vkGetPhysicalDeviceExternalFencePropertiesKHR(physicalDevice, pExternalFenceInfo, pExternalFenceProperties);
+    auto resources = ResourceTracker::get();
+    resources->on_vkGetPhysicalDeviceExternalFencePropertiesKHR(vkEnc, physicalDevice, pExternalFenceInfo, pExternalFenceProperties);
 }
 #endif
 #ifdef VK_KHR_external_fence
@@ -2594,6 +3243,21 @@
     vkImportFenceWin32HandleKHR_VkResult_return = vkEnc->vkImportFenceWin32HandleKHR(device, pImportFenceWin32HandleInfo);
     return vkImportFenceWin32HandleKHR_VkResult_return;
 }
+static VkResult dynCheck_entry_vkImportFenceWin32HandleKHR(
+    VkDevice device,
+    const VkImportFenceWin32HandleInfoKHR* pImportFenceWin32HandleInfo)
+{
+    auto resources = ResourceTracker::get();
+    if (!resources->hasDeviceExtension(device, "VK_KHR_external_fence_win32"))
+    {
+        sOnInvalidDynamicallyCheckedCall("vkImportFenceWin32HandleKHR", "VK_KHR_external_fence_win32");
+    }
+    AEMU_SCOPED_TRACE("vkImportFenceWin32HandleKHR");
+    auto vkEnc = HostConnection::get()->vkEncoder();
+    VkResult vkImportFenceWin32HandleKHR_VkResult_return = (VkResult)0;
+    vkImportFenceWin32HandleKHR_VkResult_return = vkEnc->vkImportFenceWin32HandleKHR(device, pImportFenceWin32HandleInfo);
+    return vkImportFenceWin32HandleKHR_VkResult_return;
+}
 static VkResult entry_vkGetFenceWin32HandleKHR(
     VkDevice device,
     const VkFenceGetWin32HandleInfoKHR* pGetWin32HandleInfo,
@@ -2605,6 +3269,22 @@
     vkGetFenceWin32HandleKHR_VkResult_return = vkEnc->vkGetFenceWin32HandleKHR(device, pGetWin32HandleInfo, pHandle);
     return vkGetFenceWin32HandleKHR_VkResult_return;
 }
+static VkResult dynCheck_entry_vkGetFenceWin32HandleKHR(
+    VkDevice device,
+    const VkFenceGetWin32HandleInfoKHR* pGetWin32HandleInfo,
+    HANDLE* pHandle)
+{
+    auto resources = ResourceTracker::get();
+    if (!resources->hasDeviceExtension(device, "VK_KHR_external_fence_win32"))
+    {
+        sOnInvalidDynamicallyCheckedCall("vkGetFenceWin32HandleKHR", "VK_KHR_external_fence_win32");
+    }
+    AEMU_SCOPED_TRACE("vkGetFenceWin32HandleKHR");
+    auto vkEnc = HostConnection::get()->vkEncoder();
+    VkResult vkGetFenceWin32HandleKHR_VkResult_return = (VkResult)0;
+    vkGetFenceWin32HandleKHR_VkResult_return = vkEnc->vkGetFenceWin32HandleKHR(device, pGetWin32HandleInfo, pHandle);
+    return vkGetFenceWin32HandleKHR_VkResult_return;
+}
 #endif
 #ifdef VK_KHR_external_fence_fd
 static VkResult entry_vkImportFenceFdKHR(
@@ -2614,7 +3294,23 @@
     AEMU_SCOPED_TRACE("vkImportFenceFdKHR");
     auto vkEnc = HostConnection::get()->vkEncoder();
     VkResult vkImportFenceFdKHR_VkResult_return = (VkResult)0;
-    vkImportFenceFdKHR_VkResult_return = vkEnc->vkImportFenceFdKHR(device, pImportFenceFdInfo);
+    auto resources = ResourceTracker::get();
+    vkImportFenceFdKHR_VkResult_return = resources->on_vkImportFenceFdKHR(vkEnc, VK_SUCCESS, device, pImportFenceFdInfo);
+    return vkImportFenceFdKHR_VkResult_return;
+}
+static VkResult dynCheck_entry_vkImportFenceFdKHR(
+    VkDevice device,
+    const VkImportFenceFdInfoKHR* pImportFenceFdInfo)
+{
+    auto resources = ResourceTracker::get();
+    if (!resources->hasDeviceExtension(device, "VK_KHR_external_fence_fd"))
+    {
+        sOnInvalidDynamicallyCheckedCall("vkImportFenceFdKHR", "VK_KHR_external_fence_fd");
+    }
+    AEMU_SCOPED_TRACE("vkImportFenceFdKHR");
+    auto vkEnc = HostConnection::get()->vkEncoder();
+    VkResult vkImportFenceFdKHR_VkResult_return = (VkResult)0;
+    vkImportFenceFdKHR_VkResult_return = resources->on_vkImportFenceFdKHR(vkEnc, VK_SUCCESS, device, pImportFenceFdInfo);
     return vkImportFenceFdKHR_VkResult_return;
 }
 static VkResult entry_vkGetFenceFdKHR(
@@ -2625,7 +3321,24 @@
     AEMU_SCOPED_TRACE("vkGetFenceFdKHR");
     auto vkEnc = HostConnection::get()->vkEncoder();
     VkResult vkGetFenceFdKHR_VkResult_return = (VkResult)0;
-    vkGetFenceFdKHR_VkResult_return = vkEnc->vkGetFenceFdKHR(device, pGetFdInfo, pFd);
+    auto resources = ResourceTracker::get();
+    vkGetFenceFdKHR_VkResult_return = resources->on_vkGetFenceFdKHR(vkEnc, VK_SUCCESS, device, pGetFdInfo, pFd);
+    return vkGetFenceFdKHR_VkResult_return;
+}
+static VkResult dynCheck_entry_vkGetFenceFdKHR(
+    VkDevice device,
+    const VkFenceGetFdInfoKHR* pGetFdInfo,
+    int* pFd)
+{
+    auto resources = ResourceTracker::get();
+    if (!resources->hasDeviceExtension(device, "VK_KHR_external_fence_fd"))
+    {
+        sOnInvalidDynamicallyCheckedCall("vkGetFenceFdKHR", "VK_KHR_external_fence_fd");
+    }
+    AEMU_SCOPED_TRACE("vkGetFenceFdKHR");
+    auto vkEnc = HostConnection::get()->vkEncoder();
+    VkResult vkGetFenceFdKHR_VkResult_return = (VkResult)0;
+    vkGetFenceFdKHR_VkResult_return = resources->on_vkGetFenceFdKHR(vkEnc, VK_SUCCESS, device, pGetFdInfo, pFd);
     return vkGetFenceFdKHR_VkResult_return;
 }
 #endif
@@ -2722,6 +3435,20 @@
     auto resources = ResourceTracker::get();
     resources->on_vkGetImageMemoryRequirements2KHR(vkEnc, device, pInfo, pMemoryRequirements);
 }
+static void dynCheck_entry_vkGetImageMemoryRequirements2KHR(
+    VkDevice device,
+    const VkImageMemoryRequirementsInfo2* pInfo,
+    VkMemoryRequirements2* pMemoryRequirements)
+{
+    auto resources = ResourceTracker::get();
+    if (!resources->hasDeviceExtension(device, "VK_KHR_get_memory_requirements2"))
+    {
+        sOnInvalidDynamicallyCheckedCall("vkGetImageMemoryRequirements2KHR", "VK_KHR_get_memory_requirements2");
+    }
+    AEMU_SCOPED_TRACE("vkGetImageMemoryRequirements2KHR");
+    auto vkEnc = HostConnection::get()->vkEncoder();
+    resources->on_vkGetImageMemoryRequirements2KHR(vkEnc, device, pInfo, pMemoryRequirements);
+}
 static void entry_vkGetBufferMemoryRequirements2KHR(
     VkDevice device,
     const VkBufferMemoryRequirementsInfo2* pInfo,
@@ -2732,6 +3459,20 @@
     auto resources = ResourceTracker::get();
     resources->on_vkGetBufferMemoryRequirements2KHR(vkEnc, device, pInfo, pMemoryRequirements);
 }
+static void dynCheck_entry_vkGetBufferMemoryRequirements2KHR(
+    VkDevice device,
+    const VkBufferMemoryRequirementsInfo2* pInfo,
+    VkMemoryRequirements2* pMemoryRequirements)
+{
+    auto resources = ResourceTracker::get();
+    if (!resources->hasDeviceExtension(device, "VK_KHR_get_memory_requirements2"))
+    {
+        sOnInvalidDynamicallyCheckedCall("vkGetBufferMemoryRequirements2KHR", "VK_KHR_get_memory_requirements2");
+    }
+    AEMU_SCOPED_TRACE("vkGetBufferMemoryRequirements2KHR");
+    auto vkEnc = HostConnection::get()->vkEncoder();
+    resources->on_vkGetBufferMemoryRequirements2KHR(vkEnc, device, pInfo, pMemoryRequirements);
+}
 static void entry_vkGetImageSparseMemoryRequirements2KHR(
     VkDevice device,
     const VkImageSparseMemoryRequirementsInfo2* pInfo,
@@ -2742,6 +3483,21 @@
     auto vkEnc = HostConnection::get()->vkEncoder();
     vkEnc->vkGetImageSparseMemoryRequirements2KHR(device, pInfo, pSparseMemoryRequirementCount, pSparseMemoryRequirements);
 }
+static void dynCheck_entry_vkGetImageSparseMemoryRequirements2KHR(
+    VkDevice device,
+    const VkImageSparseMemoryRequirementsInfo2* pInfo,
+    uint32_t* pSparseMemoryRequirementCount,
+    VkSparseImageMemoryRequirements2* pSparseMemoryRequirements)
+{
+    auto resources = ResourceTracker::get();
+    if (!resources->hasDeviceExtension(device, "VK_KHR_get_memory_requirements2"))
+    {
+        sOnInvalidDynamicallyCheckedCall("vkGetImageSparseMemoryRequirements2KHR", "VK_KHR_get_memory_requirements2");
+    }
+    AEMU_SCOPED_TRACE("vkGetImageSparseMemoryRequirements2KHR");
+    auto vkEnc = HostConnection::get()->vkEncoder();
+    vkEnc->vkGetImageSparseMemoryRequirements2KHR(device, pInfo, pSparseMemoryRequirementCount, pSparseMemoryRequirements);
+}
 #endif
 #ifdef VK_KHR_image_format_list
 #endif
@@ -2759,6 +3515,23 @@
     vkCreateSamplerYcbcrConversionKHR_VkResult_return = resources->on_vkCreateSamplerYcbcrConversionKHR(vkEnc, VK_SUCCESS, device, pCreateInfo, pAllocator, pYcbcrConversion);
     return vkCreateSamplerYcbcrConversionKHR_VkResult_return;
 }
+static VkResult dynCheck_entry_vkCreateSamplerYcbcrConversionKHR(
+    VkDevice device,
+    const VkSamplerYcbcrConversionCreateInfo* pCreateInfo,
+    const VkAllocationCallbacks* pAllocator,
+    VkSamplerYcbcrConversion* pYcbcrConversion)
+{
+    auto resources = ResourceTracker::get();
+    if (!resources->hasDeviceExtension(device, "VK_KHR_sampler_ycbcr_conversion"))
+    {
+        sOnInvalidDynamicallyCheckedCall("vkCreateSamplerYcbcrConversionKHR", "VK_KHR_sampler_ycbcr_conversion");
+    }
+    AEMU_SCOPED_TRACE("vkCreateSamplerYcbcrConversionKHR");
+    auto vkEnc = HostConnection::get()->vkEncoder();
+    VkResult vkCreateSamplerYcbcrConversionKHR_VkResult_return = (VkResult)0;
+    vkCreateSamplerYcbcrConversionKHR_VkResult_return = resources->on_vkCreateSamplerYcbcrConversionKHR(vkEnc, VK_SUCCESS, device, pCreateInfo, pAllocator, pYcbcrConversion);
+    return vkCreateSamplerYcbcrConversionKHR_VkResult_return;
+}
 static void entry_vkDestroySamplerYcbcrConversionKHR(
     VkDevice device,
     VkSamplerYcbcrConversion ycbcrConversion,
@@ -2766,7 +3539,22 @@
 {
     AEMU_SCOPED_TRACE("vkDestroySamplerYcbcrConversionKHR");
     auto vkEnc = HostConnection::get()->vkEncoder();
-    vkEnc->vkDestroySamplerYcbcrConversionKHR(device, ycbcrConversion, pAllocator);
+    auto resources = ResourceTracker::get();
+    resources->on_vkDestroySamplerYcbcrConversionKHR(vkEnc, device, ycbcrConversion, pAllocator);
+}
+static void dynCheck_entry_vkDestroySamplerYcbcrConversionKHR(
+    VkDevice device,
+    VkSamplerYcbcrConversion ycbcrConversion,
+    const VkAllocationCallbacks* pAllocator)
+{
+    auto resources = ResourceTracker::get();
+    if (!resources->hasDeviceExtension(device, "VK_KHR_sampler_ycbcr_conversion"))
+    {
+        sOnInvalidDynamicallyCheckedCall("vkDestroySamplerYcbcrConversionKHR", "VK_KHR_sampler_ycbcr_conversion");
+    }
+    AEMU_SCOPED_TRACE("vkDestroySamplerYcbcrConversionKHR");
+    auto vkEnc = HostConnection::get()->vkEncoder();
+    resources->on_vkDestroySamplerYcbcrConversionKHR(vkEnc, device, ycbcrConversion, pAllocator);
 }
 #endif
 #ifdef VK_KHR_bind_memory2
@@ -2782,6 +3570,22 @@
     vkBindBufferMemory2KHR_VkResult_return = resources->on_vkBindBufferMemory2KHR(vkEnc, VK_SUCCESS, device, bindInfoCount, pBindInfos);
     return vkBindBufferMemory2KHR_VkResult_return;
 }
+static VkResult dynCheck_entry_vkBindBufferMemory2KHR(
+    VkDevice device,
+    uint32_t bindInfoCount,
+    const VkBindBufferMemoryInfo* pBindInfos)
+{
+    auto resources = ResourceTracker::get();
+    if (!resources->hasDeviceExtension(device, "VK_KHR_bind_memory2"))
+    {
+        sOnInvalidDynamicallyCheckedCall("vkBindBufferMemory2KHR", "VK_KHR_bind_memory2");
+    }
+    AEMU_SCOPED_TRACE("vkBindBufferMemory2KHR");
+    auto vkEnc = HostConnection::get()->vkEncoder();
+    VkResult vkBindBufferMemory2KHR_VkResult_return = (VkResult)0;
+    vkBindBufferMemory2KHR_VkResult_return = resources->on_vkBindBufferMemory2KHR(vkEnc, VK_SUCCESS, device, bindInfoCount, pBindInfos);
+    return vkBindBufferMemory2KHR_VkResult_return;
+}
 static VkResult entry_vkBindImageMemory2KHR(
     VkDevice device,
     uint32_t bindInfoCount,
@@ -2794,6 +3598,22 @@
     vkBindImageMemory2KHR_VkResult_return = resources->on_vkBindImageMemory2KHR(vkEnc, VK_SUCCESS, device, bindInfoCount, pBindInfos);
     return vkBindImageMemory2KHR_VkResult_return;
 }
+static VkResult dynCheck_entry_vkBindImageMemory2KHR(
+    VkDevice device,
+    uint32_t bindInfoCount,
+    const VkBindImageMemoryInfo* pBindInfos)
+{
+    auto resources = ResourceTracker::get();
+    if (!resources->hasDeviceExtension(device, "VK_KHR_bind_memory2"))
+    {
+        sOnInvalidDynamicallyCheckedCall("vkBindImageMemory2KHR", "VK_KHR_bind_memory2");
+    }
+    AEMU_SCOPED_TRACE("vkBindImageMemory2KHR");
+    auto vkEnc = HostConnection::get()->vkEncoder();
+    VkResult vkBindImageMemory2KHR_VkResult_return = (VkResult)0;
+    vkBindImageMemory2KHR_VkResult_return = resources->on_vkBindImageMemory2KHR(vkEnc, VK_SUCCESS, device, bindInfoCount, pBindInfos);
+    return vkBindImageMemory2KHR_VkResult_return;
+}
 #endif
 #ifdef VK_KHR_maintenance3
 static void entry_vkGetDescriptorSetLayoutSupportKHR(
@@ -2805,6 +3625,20 @@
     auto vkEnc = HostConnection::get()->vkEncoder();
     vkEnc->vkGetDescriptorSetLayoutSupportKHR(device, pCreateInfo, pSupport);
 }
+static void dynCheck_entry_vkGetDescriptorSetLayoutSupportKHR(
+    VkDevice device,
+    const VkDescriptorSetLayoutCreateInfo* pCreateInfo,
+    VkDescriptorSetLayoutSupport* pSupport)
+{
+    auto resources = ResourceTracker::get();
+    if (!resources->hasDeviceExtension(device, "VK_KHR_maintenance3"))
+    {
+        sOnInvalidDynamicallyCheckedCall("vkGetDescriptorSetLayoutSupportKHR", "VK_KHR_maintenance3");
+    }
+    AEMU_SCOPED_TRACE("vkGetDescriptorSetLayoutSupportKHR");
+    auto vkEnc = HostConnection::get()->vkEncoder();
+    vkEnc->vkGetDescriptorSetLayoutSupportKHR(device, pCreateInfo, pSupport);
+}
 #endif
 #ifdef VK_KHR_draw_indirect_count
 static void entry_vkCmdDrawIndirectCountKHR(
@@ -2818,6 +3652,7 @@
 {
     AEMU_SCOPED_TRACE("vkCmdDrawIndirectCountKHR");
     auto vkEnc = HostConnection::get()->vkEncoder();
+    ResourceTracker::get()->syncEncodersForCommandBuffer(commandBuffer, vkEnc);
     vkEnc->vkCmdDrawIndirectCountKHR(commandBuffer, buffer, offset, countBuffer, countBufferOffset, maxDrawCount, stride);
 }
 static void entry_vkCmdDrawIndexedIndirectCountKHR(
@@ -2831,6 +3666,7 @@
 {
     AEMU_SCOPED_TRACE("vkCmdDrawIndexedIndirectCountKHR");
     auto vkEnc = HostConnection::get()->vkEncoder();
+    ResourceTracker::get()->syncEncodersForCommandBuffer(commandBuffer, vkEnc);
     vkEnc->vkCmdDrawIndexedIndirectCountKHR(commandBuffer, buffer, offset, countBuffer, countBufferOffset, maxDrawCount, stride);
 }
 #endif
@@ -2849,6 +3685,23 @@
     vkGetSwapchainGrallocUsageANDROID_VkResult_return = vkEnc->vkGetSwapchainGrallocUsageANDROID(device, format, imageUsage, grallocUsage);
     return vkGetSwapchainGrallocUsageANDROID_VkResult_return;
 }
+static VkResult dynCheck_entry_vkGetSwapchainGrallocUsageANDROID(
+    VkDevice device,
+    VkFormat format,
+    VkImageUsageFlags imageUsage,
+    int* grallocUsage)
+{
+    auto resources = ResourceTracker::get();
+    if (!resources->hasDeviceExtension(device, "VK_ANDROID_native_buffer"))
+    {
+        sOnInvalidDynamicallyCheckedCall("vkGetSwapchainGrallocUsageANDROID", "VK_ANDROID_native_buffer");
+    }
+    AEMU_SCOPED_TRACE("vkGetSwapchainGrallocUsageANDROID");
+    auto vkEnc = HostConnection::get()->vkEncoder();
+    VkResult vkGetSwapchainGrallocUsageANDROID_VkResult_return = (VkResult)0;
+    vkGetSwapchainGrallocUsageANDROID_VkResult_return = vkEnc->vkGetSwapchainGrallocUsageANDROID(device, format, imageUsage, grallocUsage);
+    return vkGetSwapchainGrallocUsageANDROID_VkResult_return;
+}
 static VkResult entry_vkAcquireImageANDROID(
     VkDevice device,
     VkImage image,
@@ -2862,6 +3715,24 @@
     vkAcquireImageANDROID_VkResult_return = vkEnc->vkAcquireImageANDROID(device, image, nativeFenceFd, semaphore, fence);
     return vkAcquireImageANDROID_VkResult_return;
 }
+static VkResult dynCheck_entry_vkAcquireImageANDROID(
+    VkDevice device,
+    VkImage image,
+    int nativeFenceFd,
+    VkSemaphore semaphore,
+    VkFence fence)
+{
+    auto resources = ResourceTracker::get();
+    if (!resources->hasDeviceExtension(device, "VK_ANDROID_native_buffer"))
+    {
+        sOnInvalidDynamicallyCheckedCall("vkAcquireImageANDROID", "VK_ANDROID_native_buffer");
+    }
+    AEMU_SCOPED_TRACE("vkAcquireImageANDROID");
+    auto vkEnc = HostConnection::get()->vkEncoder();
+    VkResult vkAcquireImageANDROID_VkResult_return = (VkResult)0;
+    vkAcquireImageANDROID_VkResult_return = vkEnc->vkAcquireImageANDROID(device, image, nativeFenceFd, semaphore, fence);
+    return vkAcquireImageANDROID_VkResult_return;
+}
 static VkResult entry_vkQueueSignalReleaseImageANDROID(
     VkQueue queue,
     uint32_t waitSemaphoreCount,
@@ -2936,6 +3807,21 @@
     vkDebugMarkerSetObjectTagEXT_VkResult_return = vkEnc->vkDebugMarkerSetObjectTagEXT(device, pTagInfo);
     return vkDebugMarkerSetObjectTagEXT_VkResult_return;
 }
+static VkResult dynCheck_entry_vkDebugMarkerSetObjectTagEXT(
+    VkDevice device,
+    const VkDebugMarkerObjectTagInfoEXT* pTagInfo)
+{
+    auto resources = ResourceTracker::get();
+    if (!resources->hasDeviceExtension(device, "VK_EXT_debug_marker"))
+    {
+        sOnInvalidDynamicallyCheckedCall("vkDebugMarkerSetObjectTagEXT", "VK_EXT_debug_marker");
+    }
+    AEMU_SCOPED_TRACE("vkDebugMarkerSetObjectTagEXT");
+    auto vkEnc = HostConnection::get()->vkEncoder();
+    VkResult vkDebugMarkerSetObjectTagEXT_VkResult_return = (VkResult)0;
+    vkDebugMarkerSetObjectTagEXT_VkResult_return = vkEnc->vkDebugMarkerSetObjectTagEXT(device, pTagInfo);
+    return vkDebugMarkerSetObjectTagEXT_VkResult_return;
+}
 static VkResult entry_vkDebugMarkerSetObjectNameEXT(
     VkDevice device,
     const VkDebugMarkerObjectNameInfoEXT* pNameInfo)
@@ -2946,12 +3832,28 @@
     vkDebugMarkerSetObjectNameEXT_VkResult_return = vkEnc->vkDebugMarkerSetObjectNameEXT(device, pNameInfo);
     return vkDebugMarkerSetObjectNameEXT_VkResult_return;
 }
+static VkResult dynCheck_entry_vkDebugMarkerSetObjectNameEXT(
+    VkDevice device,
+    const VkDebugMarkerObjectNameInfoEXT* pNameInfo)
+{
+    auto resources = ResourceTracker::get();
+    if (!resources->hasDeviceExtension(device, "VK_EXT_debug_marker"))
+    {
+        sOnInvalidDynamicallyCheckedCall("vkDebugMarkerSetObjectNameEXT", "VK_EXT_debug_marker");
+    }
+    AEMU_SCOPED_TRACE("vkDebugMarkerSetObjectNameEXT");
+    auto vkEnc = HostConnection::get()->vkEncoder();
+    VkResult vkDebugMarkerSetObjectNameEXT_VkResult_return = (VkResult)0;
+    vkDebugMarkerSetObjectNameEXT_VkResult_return = vkEnc->vkDebugMarkerSetObjectNameEXT(device, pNameInfo);
+    return vkDebugMarkerSetObjectNameEXT_VkResult_return;
+}
 static void entry_vkCmdDebugMarkerBeginEXT(
     VkCommandBuffer commandBuffer,
     const VkDebugMarkerMarkerInfoEXT* pMarkerInfo)
 {
     AEMU_SCOPED_TRACE("vkCmdDebugMarkerBeginEXT");
     auto vkEnc = HostConnection::get()->vkEncoder();
+    ResourceTracker::get()->syncEncodersForCommandBuffer(commandBuffer, vkEnc);
     vkEnc->vkCmdDebugMarkerBeginEXT(commandBuffer, pMarkerInfo);
 }
 static void entry_vkCmdDebugMarkerEndEXT(
@@ -2959,6 +3861,7 @@
 {
     AEMU_SCOPED_TRACE("vkCmdDebugMarkerEndEXT");
     auto vkEnc = HostConnection::get()->vkEncoder();
+    ResourceTracker::get()->syncEncodersForCommandBuffer(commandBuffer, vkEnc);
     vkEnc->vkCmdDebugMarkerEndEXT(commandBuffer);
 }
 static void entry_vkCmdDebugMarkerInsertEXT(
@@ -2967,6 +3870,7 @@
 {
     AEMU_SCOPED_TRACE("vkCmdDebugMarkerInsertEXT");
     auto vkEnc = HostConnection::get()->vkEncoder();
+    ResourceTracker::get()->syncEncodersForCommandBuffer(commandBuffer, vkEnc);
     vkEnc->vkCmdDebugMarkerInsertEXT(commandBuffer, pMarkerInfo);
 }
 #endif
@@ -2986,6 +3890,7 @@
 {
     AEMU_SCOPED_TRACE("vkCmdDrawIndirectCountAMD");
     auto vkEnc = HostConnection::get()->vkEncoder();
+    ResourceTracker::get()->syncEncodersForCommandBuffer(commandBuffer, vkEnc);
     vkEnc->vkCmdDrawIndirectCountAMD(commandBuffer, buffer, offset, countBuffer, countBufferOffset, maxDrawCount, stride);
 }
 static void entry_vkCmdDrawIndexedIndirectCountAMD(
@@ -2999,6 +3904,7 @@
 {
     AEMU_SCOPED_TRACE("vkCmdDrawIndexedIndirectCountAMD");
     auto vkEnc = HostConnection::get()->vkEncoder();
+    ResourceTracker::get()->syncEncodersForCommandBuffer(commandBuffer, vkEnc);
     vkEnc->vkCmdDrawIndexedIndirectCountAMD(commandBuffer, buffer, offset, countBuffer, countBufferOffset, maxDrawCount, stride);
 }
 #endif
@@ -3025,6 +3931,25 @@
     vkGetShaderInfoAMD_VkResult_return = vkEnc->vkGetShaderInfoAMD(device, pipeline, shaderStage, infoType, pInfoSize, pInfo);
     return vkGetShaderInfoAMD_VkResult_return;
 }
+static VkResult dynCheck_entry_vkGetShaderInfoAMD(
+    VkDevice device,
+    VkPipeline pipeline,
+    VkShaderStageFlagBits shaderStage,
+    VkShaderInfoTypeAMD infoType,
+    size_t* pInfoSize,
+    void* pInfo)
+{
+    auto resources = ResourceTracker::get();
+    if (!resources->hasDeviceExtension(device, "VK_AMD_shader_info"))
+    {
+        sOnInvalidDynamicallyCheckedCall("vkGetShaderInfoAMD", "VK_AMD_shader_info");
+    }
+    AEMU_SCOPED_TRACE("vkGetShaderInfoAMD");
+    auto vkEnc = HostConnection::get()->vkEncoder();
+    VkResult vkGetShaderInfoAMD_VkResult_return = (VkResult)0;
+    vkGetShaderInfoAMD_VkResult_return = vkEnc->vkGetShaderInfoAMD(device, pipeline, shaderStage, infoType, pInfoSize, pInfo);
+    return vkGetShaderInfoAMD_VkResult_return;
+}
 #endif
 #ifdef VK_AMD_shader_image_load_store_lod
 #endif
@@ -3063,6 +3988,23 @@
     vkGetMemoryWin32HandleNV_VkResult_return = vkEnc->vkGetMemoryWin32HandleNV(device, memory, handleType, pHandle);
     return vkGetMemoryWin32HandleNV_VkResult_return;
 }
+static VkResult dynCheck_entry_vkGetMemoryWin32HandleNV(
+    VkDevice device,
+    VkDeviceMemory memory,
+    VkExternalMemoryHandleTypeFlagsNV handleType,
+    HANDLE* pHandle)
+{
+    auto resources = ResourceTracker::get();
+    if (!resources->hasDeviceExtension(device, "VK_NV_external_memory_win32"))
+    {
+        sOnInvalidDynamicallyCheckedCall("vkGetMemoryWin32HandleNV", "VK_NV_external_memory_win32");
+    }
+    AEMU_SCOPED_TRACE("vkGetMemoryWin32HandleNV");
+    auto vkEnc = HostConnection::get()->vkEncoder();
+    VkResult vkGetMemoryWin32HandleNV_VkResult_return = (VkResult)0;
+    vkGetMemoryWin32HandleNV_VkResult_return = vkEnc->vkGetMemoryWin32HandleNV(device, memory, handleType, pHandle);
+    return vkGetMemoryWin32HandleNV_VkResult_return;
+}
 #endif
 #ifdef VK_NV_win32_keyed_mutex
 #endif
@@ -3093,6 +4035,7 @@
 {
     AEMU_SCOPED_TRACE("vkCmdBeginConditionalRenderingEXT");
     auto vkEnc = HostConnection::get()->vkEncoder();
+    ResourceTracker::get()->syncEncodersForCommandBuffer(commandBuffer, vkEnc);
     vkEnc->vkCmdBeginConditionalRenderingEXT(commandBuffer, pConditionalRenderingBegin);
 }
 static void entry_vkCmdEndConditionalRenderingEXT(
@@ -3100,6 +4043,7 @@
 {
     AEMU_SCOPED_TRACE("vkCmdEndConditionalRenderingEXT");
     auto vkEnc = HostConnection::get()->vkEncoder();
+    ResourceTracker::get()->syncEncodersForCommandBuffer(commandBuffer, vkEnc);
     vkEnc->vkCmdEndConditionalRenderingEXT(commandBuffer);
 }
 #endif
@@ -3110,6 +4054,7 @@
 {
     AEMU_SCOPED_TRACE("vkCmdProcessCommandsNVX");
     auto vkEnc = HostConnection::get()->vkEncoder();
+    ResourceTracker::get()->syncEncodersForCommandBuffer(commandBuffer, vkEnc);
     vkEnc->vkCmdProcessCommandsNVX(commandBuffer, pProcessCommandsInfo);
 }
 static void entry_vkCmdReserveSpaceForCommandsNVX(
@@ -3118,6 +4063,7 @@
 {
     AEMU_SCOPED_TRACE("vkCmdReserveSpaceForCommandsNVX");
     auto vkEnc = HostConnection::get()->vkEncoder();
+    ResourceTracker::get()->syncEncodersForCommandBuffer(commandBuffer, vkEnc);
     vkEnc->vkCmdReserveSpaceForCommandsNVX(commandBuffer, pReserveSpaceInfo);
 }
 static VkResult entry_vkCreateIndirectCommandsLayoutNVX(
@@ -3132,6 +4078,23 @@
     vkCreateIndirectCommandsLayoutNVX_VkResult_return = vkEnc->vkCreateIndirectCommandsLayoutNVX(device, pCreateInfo, pAllocator, pIndirectCommandsLayout);
     return vkCreateIndirectCommandsLayoutNVX_VkResult_return;
 }
+static VkResult dynCheck_entry_vkCreateIndirectCommandsLayoutNVX(
+    VkDevice device,
+    const VkIndirectCommandsLayoutCreateInfoNVX* pCreateInfo,
+    const VkAllocationCallbacks* pAllocator,
+    VkIndirectCommandsLayoutNVX* pIndirectCommandsLayout)
+{
+    auto resources = ResourceTracker::get();
+    if (!resources->hasDeviceExtension(device, "VK_NVX_device_generated_commands"))
+    {
+        sOnInvalidDynamicallyCheckedCall("vkCreateIndirectCommandsLayoutNVX", "VK_NVX_device_generated_commands");
+    }
+    AEMU_SCOPED_TRACE("vkCreateIndirectCommandsLayoutNVX");
+    auto vkEnc = HostConnection::get()->vkEncoder();
+    VkResult vkCreateIndirectCommandsLayoutNVX_VkResult_return = (VkResult)0;
+    vkCreateIndirectCommandsLayoutNVX_VkResult_return = vkEnc->vkCreateIndirectCommandsLayoutNVX(device, pCreateInfo, pAllocator, pIndirectCommandsLayout);
+    return vkCreateIndirectCommandsLayoutNVX_VkResult_return;
+}
 static void entry_vkDestroyIndirectCommandsLayoutNVX(
     VkDevice device,
     VkIndirectCommandsLayoutNVX indirectCommandsLayout,
@@ -3141,6 +4104,20 @@
     auto vkEnc = HostConnection::get()->vkEncoder();
     vkEnc->vkDestroyIndirectCommandsLayoutNVX(device, indirectCommandsLayout, pAllocator);
 }
+static void dynCheck_entry_vkDestroyIndirectCommandsLayoutNVX(
+    VkDevice device,
+    VkIndirectCommandsLayoutNVX indirectCommandsLayout,
+    const VkAllocationCallbacks* pAllocator)
+{
+    auto resources = ResourceTracker::get();
+    if (!resources->hasDeviceExtension(device, "VK_NVX_device_generated_commands"))
+    {
+        sOnInvalidDynamicallyCheckedCall("vkDestroyIndirectCommandsLayoutNVX", "VK_NVX_device_generated_commands");
+    }
+    AEMU_SCOPED_TRACE("vkDestroyIndirectCommandsLayoutNVX");
+    auto vkEnc = HostConnection::get()->vkEncoder();
+    vkEnc->vkDestroyIndirectCommandsLayoutNVX(device, indirectCommandsLayout, pAllocator);
+}
 static VkResult entry_vkCreateObjectTableNVX(
     VkDevice device,
     const VkObjectTableCreateInfoNVX* pCreateInfo,
@@ -3153,6 +4130,23 @@
     vkCreateObjectTableNVX_VkResult_return = vkEnc->vkCreateObjectTableNVX(device, pCreateInfo, pAllocator, pObjectTable);
     return vkCreateObjectTableNVX_VkResult_return;
 }
+static VkResult dynCheck_entry_vkCreateObjectTableNVX(
+    VkDevice device,
+    const VkObjectTableCreateInfoNVX* pCreateInfo,
+    const VkAllocationCallbacks* pAllocator,
+    VkObjectTableNVX* pObjectTable)
+{
+    auto resources = ResourceTracker::get();
+    if (!resources->hasDeviceExtension(device, "VK_NVX_device_generated_commands"))
+    {
+        sOnInvalidDynamicallyCheckedCall("vkCreateObjectTableNVX", "VK_NVX_device_generated_commands");
+    }
+    AEMU_SCOPED_TRACE("vkCreateObjectTableNVX");
+    auto vkEnc = HostConnection::get()->vkEncoder();
+    VkResult vkCreateObjectTableNVX_VkResult_return = (VkResult)0;
+    vkCreateObjectTableNVX_VkResult_return = vkEnc->vkCreateObjectTableNVX(device, pCreateInfo, pAllocator, pObjectTable);
+    return vkCreateObjectTableNVX_VkResult_return;
+}
 static void entry_vkDestroyObjectTableNVX(
     VkDevice device,
     VkObjectTableNVX objectTable,
@@ -3162,6 +4156,20 @@
     auto vkEnc = HostConnection::get()->vkEncoder();
     vkEnc->vkDestroyObjectTableNVX(device, objectTable, pAllocator);
 }
+static void dynCheck_entry_vkDestroyObjectTableNVX(
+    VkDevice device,
+    VkObjectTableNVX objectTable,
+    const VkAllocationCallbacks* pAllocator)
+{
+    auto resources = ResourceTracker::get();
+    if (!resources->hasDeviceExtension(device, "VK_NVX_device_generated_commands"))
+    {
+        sOnInvalidDynamicallyCheckedCall("vkDestroyObjectTableNVX", "VK_NVX_device_generated_commands");
+    }
+    AEMU_SCOPED_TRACE("vkDestroyObjectTableNVX");
+    auto vkEnc = HostConnection::get()->vkEncoder();
+    vkEnc->vkDestroyObjectTableNVX(device, objectTable, pAllocator);
+}
 static VkResult entry_vkRegisterObjectsNVX(
     VkDevice device,
     VkObjectTableNVX objectTable,
@@ -3175,6 +4183,24 @@
     vkRegisterObjectsNVX_VkResult_return = vkEnc->vkRegisterObjectsNVX(device, objectTable, objectCount, ppObjectTableEntries, pObjectIndices);
     return vkRegisterObjectsNVX_VkResult_return;
 }
+static VkResult dynCheck_entry_vkRegisterObjectsNVX(
+    VkDevice device,
+    VkObjectTableNVX objectTable,
+    uint32_t objectCount,
+    const VkObjectTableEntryNVX* const* ppObjectTableEntries,
+    const uint32_t* pObjectIndices)
+{
+    auto resources = ResourceTracker::get();
+    if (!resources->hasDeviceExtension(device, "VK_NVX_device_generated_commands"))
+    {
+        sOnInvalidDynamicallyCheckedCall("vkRegisterObjectsNVX", "VK_NVX_device_generated_commands");
+    }
+    AEMU_SCOPED_TRACE("vkRegisterObjectsNVX");
+    auto vkEnc = HostConnection::get()->vkEncoder();
+    VkResult vkRegisterObjectsNVX_VkResult_return = (VkResult)0;
+    vkRegisterObjectsNVX_VkResult_return = vkEnc->vkRegisterObjectsNVX(device, objectTable, objectCount, ppObjectTableEntries, pObjectIndices);
+    return vkRegisterObjectsNVX_VkResult_return;
+}
 static VkResult entry_vkUnregisterObjectsNVX(
     VkDevice device,
     VkObjectTableNVX objectTable,
@@ -3188,6 +4214,24 @@
     vkUnregisterObjectsNVX_VkResult_return = vkEnc->vkUnregisterObjectsNVX(device, objectTable, objectCount, pObjectEntryTypes, pObjectIndices);
     return vkUnregisterObjectsNVX_VkResult_return;
 }
+static VkResult dynCheck_entry_vkUnregisterObjectsNVX(
+    VkDevice device,
+    VkObjectTableNVX objectTable,
+    uint32_t objectCount,
+    const VkObjectEntryTypeNVX* pObjectEntryTypes,
+    const uint32_t* pObjectIndices)
+{
+    auto resources = ResourceTracker::get();
+    if (!resources->hasDeviceExtension(device, "VK_NVX_device_generated_commands"))
+    {
+        sOnInvalidDynamicallyCheckedCall("vkUnregisterObjectsNVX", "VK_NVX_device_generated_commands");
+    }
+    AEMU_SCOPED_TRACE("vkUnregisterObjectsNVX");
+    auto vkEnc = HostConnection::get()->vkEncoder();
+    VkResult vkUnregisterObjectsNVX_VkResult_return = (VkResult)0;
+    vkUnregisterObjectsNVX_VkResult_return = vkEnc->vkUnregisterObjectsNVX(device, objectTable, objectCount, pObjectEntryTypes, pObjectIndices);
+    return vkUnregisterObjectsNVX_VkResult_return;
+}
 static void entry_vkGetPhysicalDeviceGeneratedCommandsPropertiesNVX(
     VkPhysicalDevice physicalDevice,
     VkDeviceGeneratedCommandsFeaturesNVX* pFeatures,
@@ -3207,6 +4251,7 @@
 {
     AEMU_SCOPED_TRACE("vkCmdSetViewportWScalingNV");
     auto vkEnc = HostConnection::get()->vkEncoder();
+    ResourceTracker::get()->syncEncodersForCommandBuffer(commandBuffer, vkEnc);
     vkEnc->vkCmdSetViewportWScalingNV(commandBuffer, firstViewport, viewportCount, pViewportWScalings);
 }
 #endif
@@ -3272,6 +4317,22 @@
     vkDisplayPowerControlEXT_VkResult_return = vkEnc->vkDisplayPowerControlEXT(device, display, pDisplayPowerInfo);
     return vkDisplayPowerControlEXT_VkResult_return;
 }
+static VkResult dynCheck_entry_vkDisplayPowerControlEXT(
+    VkDevice device,
+    VkDisplayKHR display,
+    const VkDisplayPowerInfoEXT* pDisplayPowerInfo)
+{
+    auto resources = ResourceTracker::get();
+    if (!resources->hasDeviceExtension(device, "VK_EXT_display_control"))
+    {
+        sOnInvalidDynamicallyCheckedCall("vkDisplayPowerControlEXT", "VK_EXT_display_control");
+    }
+    AEMU_SCOPED_TRACE("vkDisplayPowerControlEXT");
+    auto vkEnc = HostConnection::get()->vkEncoder();
+    VkResult vkDisplayPowerControlEXT_VkResult_return = (VkResult)0;
+    vkDisplayPowerControlEXT_VkResult_return = vkEnc->vkDisplayPowerControlEXT(device, display, pDisplayPowerInfo);
+    return vkDisplayPowerControlEXT_VkResult_return;
+}
 static VkResult entry_vkRegisterDeviceEventEXT(
     VkDevice device,
     const VkDeviceEventInfoEXT* pDeviceEventInfo,
@@ -3284,6 +4345,23 @@
     vkRegisterDeviceEventEXT_VkResult_return = vkEnc->vkRegisterDeviceEventEXT(device, pDeviceEventInfo, pAllocator, pFence);
     return vkRegisterDeviceEventEXT_VkResult_return;
 }
+static VkResult dynCheck_entry_vkRegisterDeviceEventEXT(
+    VkDevice device,
+    const VkDeviceEventInfoEXT* pDeviceEventInfo,
+    const VkAllocationCallbacks* pAllocator,
+    VkFence* pFence)
+{
+    auto resources = ResourceTracker::get();
+    if (!resources->hasDeviceExtension(device, "VK_EXT_display_control"))
+    {
+        sOnInvalidDynamicallyCheckedCall("vkRegisterDeviceEventEXT", "VK_EXT_display_control");
+    }
+    AEMU_SCOPED_TRACE("vkRegisterDeviceEventEXT");
+    auto vkEnc = HostConnection::get()->vkEncoder();
+    VkResult vkRegisterDeviceEventEXT_VkResult_return = (VkResult)0;
+    vkRegisterDeviceEventEXT_VkResult_return = vkEnc->vkRegisterDeviceEventEXT(device, pDeviceEventInfo, pAllocator, pFence);
+    return vkRegisterDeviceEventEXT_VkResult_return;
+}
 static VkResult entry_vkRegisterDisplayEventEXT(
     VkDevice device,
     VkDisplayKHR display,
@@ -3297,6 +4375,24 @@
     vkRegisterDisplayEventEXT_VkResult_return = vkEnc->vkRegisterDisplayEventEXT(device, display, pDisplayEventInfo, pAllocator, pFence);
     return vkRegisterDisplayEventEXT_VkResult_return;
 }
+static VkResult dynCheck_entry_vkRegisterDisplayEventEXT(
+    VkDevice device,
+    VkDisplayKHR display,
+    const VkDisplayEventInfoEXT* pDisplayEventInfo,
+    const VkAllocationCallbacks* pAllocator,
+    VkFence* pFence)
+{
+    auto resources = ResourceTracker::get();
+    if (!resources->hasDeviceExtension(device, "VK_EXT_display_control"))
+    {
+        sOnInvalidDynamicallyCheckedCall("vkRegisterDisplayEventEXT", "VK_EXT_display_control");
+    }
+    AEMU_SCOPED_TRACE("vkRegisterDisplayEventEXT");
+    auto vkEnc = HostConnection::get()->vkEncoder();
+    VkResult vkRegisterDisplayEventEXT_VkResult_return = (VkResult)0;
+    vkRegisterDisplayEventEXT_VkResult_return = vkEnc->vkRegisterDisplayEventEXT(device, display, pDisplayEventInfo, pAllocator, pFence);
+    return vkRegisterDisplayEventEXT_VkResult_return;
+}
 static VkResult entry_vkGetSwapchainCounterEXT(
     VkDevice device,
     VkSwapchainKHR swapchain,
@@ -3309,6 +4405,23 @@
     vkGetSwapchainCounterEXT_VkResult_return = vkEnc->vkGetSwapchainCounterEXT(device, swapchain, counter, pCounterValue);
     return vkGetSwapchainCounterEXT_VkResult_return;
 }
+static VkResult dynCheck_entry_vkGetSwapchainCounterEXT(
+    VkDevice device,
+    VkSwapchainKHR swapchain,
+    VkSurfaceCounterFlagBitsEXT counter,
+    uint64_t* pCounterValue)
+{
+    auto resources = ResourceTracker::get();
+    if (!resources->hasDeviceExtension(device, "VK_EXT_display_control"))
+    {
+        sOnInvalidDynamicallyCheckedCall("vkGetSwapchainCounterEXT", "VK_EXT_display_control");
+    }
+    AEMU_SCOPED_TRACE("vkGetSwapchainCounterEXT");
+    auto vkEnc = HostConnection::get()->vkEncoder();
+    VkResult vkGetSwapchainCounterEXT_VkResult_return = (VkResult)0;
+    vkGetSwapchainCounterEXT_VkResult_return = vkEnc->vkGetSwapchainCounterEXT(device, swapchain, counter, pCounterValue);
+    return vkGetSwapchainCounterEXT_VkResult_return;
+}
 #endif
 #ifdef VK_GOOGLE_display_timing
 static VkResult entry_vkGetRefreshCycleDurationGOOGLE(
@@ -3322,6 +4435,22 @@
     vkGetRefreshCycleDurationGOOGLE_VkResult_return = vkEnc->vkGetRefreshCycleDurationGOOGLE(device, swapchain, pDisplayTimingProperties);
     return vkGetRefreshCycleDurationGOOGLE_VkResult_return;
 }
+static VkResult dynCheck_entry_vkGetRefreshCycleDurationGOOGLE(
+    VkDevice device,
+    VkSwapchainKHR swapchain,
+    VkRefreshCycleDurationGOOGLE* pDisplayTimingProperties)
+{
+    auto resources = ResourceTracker::get();
+    if (!resources->hasDeviceExtension(device, "VK_GOOGLE_display_timing"))
+    {
+        sOnInvalidDynamicallyCheckedCall("vkGetRefreshCycleDurationGOOGLE", "VK_GOOGLE_display_timing");
+    }
+    AEMU_SCOPED_TRACE("vkGetRefreshCycleDurationGOOGLE");
+    auto vkEnc = HostConnection::get()->vkEncoder();
+    VkResult vkGetRefreshCycleDurationGOOGLE_VkResult_return = (VkResult)0;
+    vkGetRefreshCycleDurationGOOGLE_VkResult_return = vkEnc->vkGetRefreshCycleDurationGOOGLE(device, swapchain, pDisplayTimingProperties);
+    return vkGetRefreshCycleDurationGOOGLE_VkResult_return;
+}
 static VkResult entry_vkGetPastPresentationTimingGOOGLE(
     VkDevice device,
     VkSwapchainKHR swapchain,
@@ -3334,6 +4463,23 @@
     vkGetPastPresentationTimingGOOGLE_VkResult_return = vkEnc->vkGetPastPresentationTimingGOOGLE(device, swapchain, pPresentationTimingCount, pPresentationTimings);
     return vkGetPastPresentationTimingGOOGLE_VkResult_return;
 }
+static VkResult dynCheck_entry_vkGetPastPresentationTimingGOOGLE(
+    VkDevice device,
+    VkSwapchainKHR swapchain,
+    uint32_t* pPresentationTimingCount,
+    VkPastPresentationTimingGOOGLE* pPresentationTimings)
+{
+    auto resources = ResourceTracker::get();
+    if (!resources->hasDeviceExtension(device, "VK_GOOGLE_display_timing"))
+    {
+        sOnInvalidDynamicallyCheckedCall("vkGetPastPresentationTimingGOOGLE", "VK_GOOGLE_display_timing");
+    }
+    AEMU_SCOPED_TRACE("vkGetPastPresentationTimingGOOGLE");
+    auto vkEnc = HostConnection::get()->vkEncoder();
+    VkResult vkGetPastPresentationTimingGOOGLE_VkResult_return = (VkResult)0;
+    vkGetPastPresentationTimingGOOGLE_VkResult_return = vkEnc->vkGetPastPresentationTimingGOOGLE(device, swapchain, pPresentationTimingCount, pPresentationTimings);
+    return vkGetPastPresentationTimingGOOGLE_VkResult_return;
+}
 #endif
 #ifdef VK_NV_sample_mask_override_coverage
 #endif
@@ -3354,6 +4500,7 @@
 {
     AEMU_SCOPED_TRACE("vkCmdSetDiscardRectangleEXT");
     auto vkEnc = HostConnection::get()->vkEncoder();
+    ResourceTracker::get()->syncEncodersForCommandBuffer(commandBuffer, vkEnc);
     vkEnc->vkCmdSetDiscardRectangleEXT(commandBuffer, firstDiscardRectangle, discardRectangleCount, pDiscardRectangles);
 }
 #endif
@@ -3372,6 +4519,21 @@
     auto vkEnc = HostConnection::get()->vkEncoder();
     vkEnc->vkSetHdrMetadataEXT(device, swapchainCount, pSwapchains, pMetadata);
 }
+static void dynCheck_entry_vkSetHdrMetadataEXT(
+    VkDevice device,
+    uint32_t swapchainCount,
+    const VkSwapchainKHR* pSwapchains,
+    const VkHdrMetadataEXT* pMetadata)
+{
+    auto resources = ResourceTracker::get();
+    if (!resources->hasDeviceExtension(device, "VK_EXT_hdr_metadata"))
+    {
+        sOnInvalidDynamicallyCheckedCall("vkSetHdrMetadataEXT", "VK_EXT_hdr_metadata");
+    }
+    AEMU_SCOPED_TRACE("vkSetHdrMetadataEXT");
+    auto vkEnc = HostConnection::get()->vkEncoder();
+    vkEnc->vkSetHdrMetadataEXT(device, swapchainCount, pSwapchains, pMetadata);
+}
 #endif
 #ifdef VK_MVK_ios_surface
 static VkResult entry_vkCreateIOSSurfaceMVK(
@@ -3416,6 +4578,21 @@
     vkSetDebugUtilsObjectNameEXT_VkResult_return = vkEnc->vkSetDebugUtilsObjectNameEXT(device, pNameInfo);
     return vkSetDebugUtilsObjectNameEXT_VkResult_return;
 }
+static VkResult dynCheck_entry_vkSetDebugUtilsObjectNameEXT(
+    VkDevice device,
+    const VkDebugUtilsObjectNameInfoEXT* pNameInfo)
+{
+    auto resources = ResourceTracker::get();
+    if (!resources->hasDeviceExtension(device, "VK_EXT_debug_utils"))
+    {
+        sOnInvalidDynamicallyCheckedCall("vkSetDebugUtilsObjectNameEXT", "VK_EXT_debug_utils");
+    }
+    AEMU_SCOPED_TRACE("vkSetDebugUtilsObjectNameEXT");
+    auto vkEnc = HostConnection::get()->vkEncoder();
+    VkResult vkSetDebugUtilsObjectNameEXT_VkResult_return = (VkResult)0;
+    vkSetDebugUtilsObjectNameEXT_VkResult_return = vkEnc->vkSetDebugUtilsObjectNameEXT(device, pNameInfo);
+    return vkSetDebugUtilsObjectNameEXT_VkResult_return;
+}
 static VkResult entry_vkSetDebugUtilsObjectTagEXT(
     VkDevice device,
     const VkDebugUtilsObjectTagInfoEXT* pTagInfo)
@@ -3426,6 +4603,21 @@
     vkSetDebugUtilsObjectTagEXT_VkResult_return = vkEnc->vkSetDebugUtilsObjectTagEXT(device, pTagInfo);
     return vkSetDebugUtilsObjectTagEXT_VkResult_return;
 }
+static VkResult dynCheck_entry_vkSetDebugUtilsObjectTagEXT(
+    VkDevice device,
+    const VkDebugUtilsObjectTagInfoEXT* pTagInfo)
+{
+    auto resources = ResourceTracker::get();
+    if (!resources->hasDeviceExtension(device, "VK_EXT_debug_utils"))
+    {
+        sOnInvalidDynamicallyCheckedCall("vkSetDebugUtilsObjectTagEXT", "VK_EXT_debug_utils");
+    }
+    AEMU_SCOPED_TRACE("vkSetDebugUtilsObjectTagEXT");
+    auto vkEnc = HostConnection::get()->vkEncoder();
+    VkResult vkSetDebugUtilsObjectTagEXT_VkResult_return = (VkResult)0;
+    vkSetDebugUtilsObjectTagEXT_VkResult_return = vkEnc->vkSetDebugUtilsObjectTagEXT(device, pTagInfo);
+    return vkSetDebugUtilsObjectTagEXT_VkResult_return;
+}
 static void entry_vkQueueBeginDebugUtilsLabelEXT(
     VkQueue queue,
     const VkDebugUtilsLabelEXT* pLabelInfo)
@@ -3455,6 +4647,7 @@
 {
     AEMU_SCOPED_TRACE("vkCmdBeginDebugUtilsLabelEXT");
     auto vkEnc = HostConnection::get()->vkEncoder();
+    ResourceTracker::get()->syncEncodersForCommandBuffer(commandBuffer, vkEnc);
     vkEnc->vkCmdBeginDebugUtilsLabelEXT(commandBuffer, pLabelInfo);
 }
 static void entry_vkCmdEndDebugUtilsLabelEXT(
@@ -3462,6 +4655,7 @@
 {
     AEMU_SCOPED_TRACE("vkCmdEndDebugUtilsLabelEXT");
     auto vkEnc = HostConnection::get()->vkEncoder();
+    ResourceTracker::get()->syncEncodersForCommandBuffer(commandBuffer, vkEnc);
     vkEnc->vkCmdEndDebugUtilsLabelEXT(commandBuffer);
 }
 static void entry_vkCmdInsertDebugUtilsLabelEXT(
@@ -3470,6 +4664,7 @@
 {
     AEMU_SCOPED_TRACE("vkCmdInsertDebugUtilsLabelEXT");
     auto vkEnc = HostConnection::get()->vkEncoder();
+    ResourceTracker::get()->syncEncodersForCommandBuffer(commandBuffer, vkEnc);
     vkEnc->vkCmdInsertDebugUtilsLabelEXT(commandBuffer, pLabelInfo);
 }
 static VkResult entry_vkCreateDebugUtilsMessengerEXT(
@@ -3517,6 +4712,22 @@
     vkGetAndroidHardwareBufferPropertiesANDROID_VkResult_return = resources->on_vkGetAndroidHardwareBufferPropertiesANDROID(vkEnc, VK_SUCCESS, device, buffer, pProperties);
     return vkGetAndroidHardwareBufferPropertiesANDROID_VkResult_return;
 }
+static VkResult dynCheck_entry_vkGetAndroidHardwareBufferPropertiesANDROID(
+    VkDevice device,
+    const AHardwareBuffer* buffer,
+    VkAndroidHardwareBufferPropertiesANDROID* pProperties)
+{
+    auto resources = ResourceTracker::get();
+    if (!resources->hasDeviceExtension(device, "VK_ANDROID_external_memory_android_hardware_buffer"))
+    {
+        sOnInvalidDynamicallyCheckedCall("vkGetAndroidHardwareBufferPropertiesANDROID", "VK_ANDROID_external_memory_android_hardware_buffer");
+    }
+    AEMU_SCOPED_TRACE("vkGetAndroidHardwareBufferPropertiesANDROID");
+    auto vkEnc = HostConnection::get()->vkEncoder();
+    VkResult vkGetAndroidHardwareBufferPropertiesANDROID_VkResult_return = (VkResult)0;
+    vkGetAndroidHardwareBufferPropertiesANDROID_VkResult_return = resources->on_vkGetAndroidHardwareBufferPropertiesANDROID(vkEnc, VK_SUCCESS, device, buffer, pProperties);
+    return vkGetAndroidHardwareBufferPropertiesANDROID_VkResult_return;
+}
 static VkResult entry_vkGetMemoryAndroidHardwareBufferANDROID(
     VkDevice device,
     const VkMemoryGetAndroidHardwareBufferInfoANDROID* pInfo,
@@ -3529,6 +4740,22 @@
     vkGetMemoryAndroidHardwareBufferANDROID_VkResult_return = resources->on_vkGetMemoryAndroidHardwareBufferANDROID(vkEnc, VK_SUCCESS, device, pInfo, pBuffer);
     return vkGetMemoryAndroidHardwareBufferANDROID_VkResult_return;
 }
+static VkResult dynCheck_entry_vkGetMemoryAndroidHardwareBufferANDROID(
+    VkDevice device,
+    const VkMemoryGetAndroidHardwareBufferInfoANDROID* pInfo,
+    AHardwareBuffer** pBuffer)
+{
+    auto resources = ResourceTracker::get();
+    if (!resources->hasDeviceExtension(device, "VK_ANDROID_external_memory_android_hardware_buffer"))
+    {
+        sOnInvalidDynamicallyCheckedCall("vkGetMemoryAndroidHardwareBufferANDROID", "VK_ANDROID_external_memory_android_hardware_buffer");
+    }
+    AEMU_SCOPED_TRACE("vkGetMemoryAndroidHardwareBufferANDROID");
+    auto vkEnc = HostConnection::get()->vkEncoder();
+    VkResult vkGetMemoryAndroidHardwareBufferANDROID_VkResult_return = (VkResult)0;
+    vkGetMemoryAndroidHardwareBufferANDROID_VkResult_return = resources->on_vkGetMemoryAndroidHardwareBufferANDROID(vkEnc, VK_SUCCESS, device, pInfo, pBuffer);
+    return vkGetMemoryAndroidHardwareBufferANDROID_VkResult_return;
+}
 #endif
 #ifdef VK_EXT_sampler_filter_minmax
 #endif
@@ -3547,6 +4774,7 @@
 {
     AEMU_SCOPED_TRACE("vkCmdSetSampleLocationsEXT");
     auto vkEnc = HostConnection::get()->vkEncoder();
+    ResourceTracker::get()->syncEncodersForCommandBuffer(commandBuffer, vkEnc);
     vkEnc->vkCmdSetSampleLocationsEXT(commandBuffer, pSampleLocationsInfo);
 }
 static void entry_vkGetPhysicalDeviceMultisamplePropertiesEXT(
@@ -3582,6 +4810,23 @@
     vkCreateValidationCacheEXT_VkResult_return = vkEnc->vkCreateValidationCacheEXT(device, pCreateInfo, pAllocator, pValidationCache);
     return vkCreateValidationCacheEXT_VkResult_return;
 }
+static VkResult dynCheck_entry_vkCreateValidationCacheEXT(
+    VkDevice device,
+    const VkValidationCacheCreateInfoEXT* pCreateInfo,
+    const VkAllocationCallbacks* pAllocator,
+    VkValidationCacheEXT* pValidationCache)
+{
+    auto resources = ResourceTracker::get();
+    if (!resources->hasDeviceExtension(device, "VK_EXT_validation_cache"))
+    {
+        sOnInvalidDynamicallyCheckedCall("vkCreateValidationCacheEXT", "VK_EXT_validation_cache");
+    }
+    AEMU_SCOPED_TRACE("vkCreateValidationCacheEXT");
+    auto vkEnc = HostConnection::get()->vkEncoder();
+    VkResult vkCreateValidationCacheEXT_VkResult_return = (VkResult)0;
+    vkCreateValidationCacheEXT_VkResult_return = vkEnc->vkCreateValidationCacheEXT(device, pCreateInfo, pAllocator, pValidationCache);
+    return vkCreateValidationCacheEXT_VkResult_return;
+}
 static void entry_vkDestroyValidationCacheEXT(
     VkDevice device,
     VkValidationCacheEXT validationCache,
@@ -3591,6 +4836,20 @@
     auto vkEnc = HostConnection::get()->vkEncoder();
     vkEnc->vkDestroyValidationCacheEXT(device, validationCache, pAllocator);
 }
+static void dynCheck_entry_vkDestroyValidationCacheEXT(
+    VkDevice device,
+    VkValidationCacheEXT validationCache,
+    const VkAllocationCallbacks* pAllocator)
+{
+    auto resources = ResourceTracker::get();
+    if (!resources->hasDeviceExtension(device, "VK_EXT_validation_cache"))
+    {
+        sOnInvalidDynamicallyCheckedCall("vkDestroyValidationCacheEXT", "VK_EXT_validation_cache");
+    }
+    AEMU_SCOPED_TRACE("vkDestroyValidationCacheEXT");
+    auto vkEnc = HostConnection::get()->vkEncoder();
+    vkEnc->vkDestroyValidationCacheEXT(device, validationCache, pAllocator);
+}
 static VkResult entry_vkMergeValidationCachesEXT(
     VkDevice device,
     VkValidationCacheEXT dstCache,
@@ -3603,6 +4862,23 @@
     vkMergeValidationCachesEXT_VkResult_return = vkEnc->vkMergeValidationCachesEXT(device, dstCache, srcCacheCount, pSrcCaches);
     return vkMergeValidationCachesEXT_VkResult_return;
 }
+static VkResult dynCheck_entry_vkMergeValidationCachesEXT(
+    VkDevice device,
+    VkValidationCacheEXT dstCache,
+    uint32_t srcCacheCount,
+    const VkValidationCacheEXT* pSrcCaches)
+{
+    auto resources = ResourceTracker::get();
+    if (!resources->hasDeviceExtension(device, "VK_EXT_validation_cache"))
+    {
+        sOnInvalidDynamicallyCheckedCall("vkMergeValidationCachesEXT", "VK_EXT_validation_cache");
+    }
+    AEMU_SCOPED_TRACE("vkMergeValidationCachesEXT");
+    auto vkEnc = HostConnection::get()->vkEncoder();
+    VkResult vkMergeValidationCachesEXT_VkResult_return = (VkResult)0;
+    vkMergeValidationCachesEXT_VkResult_return = vkEnc->vkMergeValidationCachesEXT(device, dstCache, srcCacheCount, pSrcCaches);
+    return vkMergeValidationCachesEXT_VkResult_return;
+}
 static VkResult entry_vkGetValidationCacheDataEXT(
     VkDevice device,
     VkValidationCacheEXT validationCache,
@@ -3615,6 +4891,23 @@
     vkGetValidationCacheDataEXT_VkResult_return = vkEnc->vkGetValidationCacheDataEXT(device, validationCache, pDataSize, pData);
     return vkGetValidationCacheDataEXT_VkResult_return;
 }
+static VkResult dynCheck_entry_vkGetValidationCacheDataEXT(
+    VkDevice device,
+    VkValidationCacheEXT validationCache,
+    size_t* pDataSize,
+    void* pData)
+{
+    auto resources = ResourceTracker::get();
+    if (!resources->hasDeviceExtension(device, "VK_EXT_validation_cache"))
+    {
+        sOnInvalidDynamicallyCheckedCall("vkGetValidationCacheDataEXT", "VK_EXT_validation_cache");
+    }
+    AEMU_SCOPED_TRACE("vkGetValidationCacheDataEXT");
+    auto vkEnc = HostConnection::get()->vkEncoder();
+    VkResult vkGetValidationCacheDataEXT_VkResult_return = (VkResult)0;
+    vkGetValidationCacheDataEXT_VkResult_return = vkEnc->vkGetValidationCacheDataEXT(device, validationCache, pDataSize, pData);
+    return vkGetValidationCacheDataEXT_VkResult_return;
+}
 #endif
 #ifdef VK_EXT_descriptor_indexing
 #endif
@@ -3635,6 +4928,23 @@
     vkGetMemoryHostPointerPropertiesEXT_VkResult_return = vkEnc->vkGetMemoryHostPointerPropertiesEXT(device, handleType, pHostPointer, pMemoryHostPointerProperties);
     return vkGetMemoryHostPointerPropertiesEXT_VkResult_return;
 }
+static VkResult dynCheck_entry_vkGetMemoryHostPointerPropertiesEXT(
+    VkDevice device,
+    VkExternalMemoryHandleTypeFlagBits handleType,
+    const void* pHostPointer,
+    VkMemoryHostPointerPropertiesEXT* pMemoryHostPointerProperties)
+{
+    auto resources = ResourceTracker::get();
+    if (!resources->hasDeviceExtension(device, "VK_EXT_external_memory_host"))
+    {
+        sOnInvalidDynamicallyCheckedCall("vkGetMemoryHostPointerPropertiesEXT", "VK_EXT_external_memory_host");
+    }
+    AEMU_SCOPED_TRACE("vkGetMemoryHostPointerPropertiesEXT");
+    auto vkEnc = HostConnection::get()->vkEncoder();
+    VkResult vkGetMemoryHostPointerPropertiesEXT_VkResult_return = (VkResult)0;
+    vkGetMemoryHostPointerPropertiesEXT_VkResult_return = vkEnc->vkGetMemoryHostPointerPropertiesEXT(device, handleType, pHostPointer, pMemoryHostPointerProperties);
+    return vkGetMemoryHostPointerPropertiesEXT_VkResult_return;
+}
 #endif
 #ifdef VK_AMD_buffer_marker
 static void entry_vkCmdWriteBufferMarkerAMD(
@@ -3646,6 +4956,7 @@
 {
     AEMU_SCOPED_TRACE("vkCmdWriteBufferMarkerAMD");
     auto vkEnc = HostConnection::get()->vkEncoder();
+    ResourceTracker::get()->syncEncodersForCommandBuffer(commandBuffer, vkEnc);
     vkEnc->vkCmdWriteBufferMarkerAMD(commandBuffer, pipelineStage, dstBuffer, dstOffset, marker);
 }
 #endif
@@ -3662,6 +4973,7 @@
 {
     AEMU_SCOPED_TRACE("vkCmdSetCheckpointNV");
     auto vkEnc = HostConnection::get()->vkEncoder();
+    ResourceTracker::get()->syncEncodersForCommandBuffer(commandBuffer, vkEnc);
     vkEnc->vkCmdSetCheckpointNV(commandBuffer, pCheckpointMarker);
 }
 static void entry_vkGetQueueCheckpointDataNV(
@@ -3686,6 +4998,22 @@
     vkMapMemoryIntoAddressSpaceGOOGLE_VkResult_return = vkEnc->vkMapMemoryIntoAddressSpaceGOOGLE(device, memory, pAddress);
     return vkMapMemoryIntoAddressSpaceGOOGLE_VkResult_return;
 }
+static VkResult dynCheck_entry_vkMapMemoryIntoAddressSpaceGOOGLE(
+    VkDevice device,
+    VkDeviceMemory memory,
+    uint64_t* pAddress)
+{
+    auto resources = ResourceTracker::get();
+    if (!resources->hasDeviceExtension(device, "VK_GOOGLE_address_space"))
+    {
+        sOnInvalidDynamicallyCheckedCall("vkMapMemoryIntoAddressSpaceGOOGLE", "VK_GOOGLE_address_space");
+    }
+    AEMU_SCOPED_TRACE("vkMapMemoryIntoAddressSpaceGOOGLE");
+    auto vkEnc = HostConnection::get()->vkEncoder();
+    VkResult vkMapMemoryIntoAddressSpaceGOOGLE_VkResult_return = (VkResult)0;
+    vkMapMemoryIntoAddressSpaceGOOGLE_VkResult_return = vkEnc->vkMapMemoryIntoAddressSpaceGOOGLE(device, memory, pAddress);
+    return vkMapMemoryIntoAddressSpaceGOOGLE_VkResult_return;
+}
 #endif
 #ifdef VK_GOOGLE_color_buffer
 static VkResult entry_vkRegisterImageColorBufferGOOGLE(
@@ -3699,6 +5027,22 @@
     vkRegisterImageColorBufferGOOGLE_VkResult_return = vkEnc->vkRegisterImageColorBufferGOOGLE(device, image, colorBuffer);
     return vkRegisterImageColorBufferGOOGLE_VkResult_return;
 }
+static VkResult dynCheck_entry_vkRegisterImageColorBufferGOOGLE(
+    VkDevice device,
+    VkImage image,
+    uint32_t colorBuffer)
+{
+    auto resources = ResourceTracker::get();
+    if (!resources->hasDeviceExtension(device, "VK_GOOGLE_color_buffer"))
+    {
+        sOnInvalidDynamicallyCheckedCall("vkRegisterImageColorBufferGOOGLE", "VK_GOOGLE_color_buffer");
+    }
+    AEMU_SCOPED_TRACE("vkRegisterImageColorBufferGOOGLE");
+    auto vkEnc = HostConnection::get()->vkEncoder();
+    VkResult vkRegisterImageColorBufferGOOGLE_VkResult_return = (VkResult)0;
+    vkRegisterImageColorBufferGOOGLE_VkResult_return = vkEnc->vkRegisterImageColorBufferGOOGLE(device, image, colorBuffer);
+    return vkRegisterImageColorBufferGOOGLE_VkResult_return;
+}
 static VkResult entry_vkRegisterBufferColorBufferGOOGLE(
     VkDevice device,
     VkBuffer buffer,
@@ -3710,6 +5054,22 @@
     vkRegisterBufferColorBufferGOOGLE_VkResult_return = vkEnc->vkRegisterBufferColorBufferGOOGLE(device, buffer, colorBuffer);
     return vkRegisterBufferColorBufferGOOGLE_VkResult_return;
 }
+static VkResult dynCheck_entry_vkRegisterBufferColorBufferGOOGLE(
+    VkDevice device,
+    VkBuffer buffer,
+    uint32_t colorBuffer)
+{
+    auto resources = ResourceTracker::get();
+    if (!resources->hasDeviceExtension(device, "VK_GOOGLE_color_buffer"))
+    {
+        sOnInvalidDynamicallyCheckedCall("vkRegisterBufferColorBufferGOOGLE", "VK_GOOGLE_color_buffer");
+    }
+    AEMU_SCOPED_TRACE("vkRegisterBufferColorBufferGOOGLE");
+    auto vkEnc = HostConnection::get()->vkEncoder();
+    VkResult vkRegisterBufferColorBufferGOOGLE_VkResult_return = (VkResult)0;
+    vkRegisterBufferColorBufferGOOGLE_VkResult_return = vkEnc->vkRegisterBufferColorBufferGOOGLE(device, buffer, colorBuffer);
+    return vkRegisterBufferColorBufferGOOGLE_VkResult_return;
+}
 #endif
 #ifdef VK_GOOGLE_sized_descriptor_update_template
 static void entry_vkUpdateDescriptorSetWithTemplateSizedGOOGLE(
@@ -3730,6 +5090,29 @@
     auto vkEnc = HostConnection::get()->vkEncoder();
     vkEnc->vkUpdateDescriptorSetWithTemplateSizedGOOGLE(device, descriptorSet, descriptorUpdateTemplate, imageInfoCount, bufferInfoCount, bufferViewCount, pImageInfoEntryIndices, pBufferInfoEntryIndices, pBufferViewEntryIndices, pImageInfos, pBufferInfos, pBufferViews);
 }
+static void dynCheck_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)
+{
+    auto resources = ResourceTracker::get();
+    if (!resources->hasDeviceExtension(device, "VK_GOOGLE_sized_descriptor_update_template"))
+    {
+        sOnInvalidDynamicallyCheckedCall("vkUpdateDescriptorSetWithTemplateSizedGOOGLE", "VK_GOOGLE_sized_descriptor_update_template");
+    }
+    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(
@@ -3738,6 +5121,7 @@
 {
     AEMU_SCOPED_TRACE("vkBeginCommandBufferAsyncGOOGLE");
     auto vkEnc = HostConnection::get()->vkEncoder();
+    ResourceTracker::get()->syncEncodersForCommandBuffer(commandBuffer, vkEnc);
     vkEnc->vkBeginCommandBufferAsyncGOOGLE(commandBuffer, pBeginInfo);
 }
 static void entry_vkEndCommandBufferAsyncGOOGLE(
@@ -3745,6 +5129,7 @@
 {
     AEMU_SCOPED_TRACE("vkEndCommandBufferAsyncGOOGLE");
     auto vkEnc = HostConnection::get()->vkEncoder();
+    ResourceTracker::get()->syncEncodersForCommandBuffer(commandBuffer, vkEnc);
     vkEnc->vkEndCommandBufferAsyncGOOGLE(commandBuffer);
 }
 static void entry_vkResetCommandBufferAsyncGOOGLE(
@@ -3753,8 +5138,116 @@
 {
     AEMU_SCOPED_TRACE("vkResetCommandBufferAsyncGOOGLE");
     auto vkEnc = HostConnection::get()->vkEncoder();
+    ResourceTracker::get()->syncEncodersForCommandBuffer(commandBuffer, vkEnc);
     vkEnc->vkResetCommandBufferAsyncGOOGLE(commandBuffer, flags);
 }
+static void entry_vkCommandBufferHostSyncGOOGLE(
+    VkCommandBuffer commandBuffer,
+    uint32_t needHostSync,
+    uint32_t sequenceNumber)
+{
+    AEMU_SCOPED_TRACE("vkCommandBufferHostSyncGOOGLE");
+    auto vkEnc = HostConnection::get()->vkEncoder();
+    ResourceTracker::get()->syncEncodersForCommandBuffer(commandBuffer, vkEnc);
+    vkEnc->vkCommandBufferHostSyncGOOGLE(commandBuffer, needHostSync, sequenceNumber);
+}
+#endif
+#ifdef VK_GOOGLE_create_resources_with_requirements
+static VkResult entry_vkCreateImageWithRequirementsGOOGLE(
+    VkDevice device,
+    const VkImageCreateInfo* pCreateInfo,
+    const VkAllocationCallbacks* pAllocator,
+    VkImage* pImage,
+    VkMemoryRequirements* pMemoryRequirements)
+{
+    AEMU_SCOPED_TRACE("vkCreateImageWithRequirementsGOOGLE");
+    auto vkEnc = HostConnection::get()->vkEncoder();
+    VkResult vkCreateImageWithRequirementsGOOGLE_VkResult_return = (VkResult)0;
+    vkCreateImageWithRequirementsGOOGLE_VkResult_return = vkEnc->vkCreateImageWithRequirementsGOOGLE(device, pCreateInfo, pAllocator, pImage, pMemoryRequirements);
+    return vkCreateImageWithRequirementsGOOGLE_VkResult_return;
+}
+static VkResult dynCheck_entry_vkCreateImageWithRequirementsGOOGLE(
+    VkDevice device,
+    const VkImageCreateInfo* pCreateInfo,
+    const VkAllocationCallbacks* pAllocator,
+    VkImage* pImage,
+    VkMemoryRequirements* pMemoryRequirements)
+{
+    auto resources = ResourceTracker::get();
+    if (!resources->hasDeviceExtension(device, "VK_GOOGLE_create_resources_with_requirements"))
+    {
+        sOnInvalidDynamicallyCheckedCall("vkCreateImageWithRequirementsGOOGLE", "VK_GOOGLE_create_resources_with_requirements");
+    }
+    AEMU_SCOPED_TRACE("vkCreateImageWithRequirementsGOOGLE");
+    auto vkEnc = HostConnection::get()->vkEncoder();
+    VkResult vkCreateImageWithRequirementsGOOGLE_VkResult_return = (VkResult)0;
+    vkCreateImageWithRequirementsGOOGLE_VkResult_return = vkEnc->vkCreateImageWithRequirementsGOOGLE(device, pCreateInfo, pAllocator, pImage, pMemoryRequirements);
+    return vkCreateImageWithRequirementsGOOGLE_VkResult_return;
+}
+static VkResult entry_vkCreateBufferWithRequirementsGOOGLE(
+    VkDevice device,
+    const VkBufferCreateInfo* pCreateInfo,
+    const VkAllocationCallbacks* pAllocator,
+    VkBuffer* pBuffer,
+    VkMemoryRequirements* pMemoryRequirements)
+{
+    AEMU_SCOPED_TRACE("vkCreateBufferWithRequirementsGOOGLE");
+    auto vkEnc = HostConnection::get()->vkEncoder();
+    VkResult vkCreateBufferWithRequirementsGOOGLE_VkResult_return = (VkResult)0;
+    vkCreateBufferWithRequirementsGOOGLE_VkResult_return = vkEnc->vkCreateBufferWithRequirementsGOOGLE(device, pCreateInfo, pAllocator, pBuffer, pMemoryRequirements);
+    return vkCreateBufferWithRequirementsGOOGLE_VkResult_return;
+}
+static VkResult dynCheck_entry_vkCreateBufferWithRequirementsGOOGLE(
+    VkDevice device,
+    const VkBufferCreateInfo* pCreateInfo,
+    const VkAllocationCallbacks* pAllocator,
+    VkBuffer* pBuffer,
+    VkMemoryRequirements* pMemoryRequirements)
+{
+    auto resources = ResourceTracker::get();
+    if (!resources->hasDeviceExtension(device, "VK_GOOGLE_create_resources_with_requirements"))
+    {
+        sOnInvalidDynamicallyCheckedCall("vkCreateBufferWithRequirementsGOOGLE", "VK_GOOGLE_create_resources_with_requirements");
+    }
+    AEMU_SCOPED_TRACE("vkCreateBufferWithRequirementsGOOGLE");
+    auto vkEnc = HostConnection::get()->vkEncoder();
+    VkResult vkCreateBufferWithRequirementsGOOGLE_VkResult_return = (VkResult)0;
+    vkCreateBufferWithRequirementsGOOGLE_VkResult_return = vkEnc->vkCreateBufferWithRequirementsGOOGLE(device, pCreateInfo, pAllocator, pBuffer, pMemoryRequirements);
+    return vkCreateBufferWithRequirementsGOOGLE_VkResult_return;
+}
+#endif
+#ifdef VK_GOOGLE_address_space_info
+static VkResult entry_vkGetMemoryHostAddressInfoGOOGLE(
+    VkDevice device,
+    VkDeviceMemory memory,
+    uint64_t* pAddress,
+    uint64_t* pSize,
+    uint64_t* pHostmemId)
+{
+    AEMU_SCOPED_TRACE("vkGetMemoryHostAddressInfoGOOGLE");
+    auto vkEnc = HostConnection::get()->vkEncoder();
+    VkResult vkGetMemoryHostAddressInfoGOOGLE_VkResult_return = (VkResult)0;
+    vkGetMemoryHostAddressInfoGOOGLE_VkResult_return = vkEnc->vkGetMemoryHostAddressInfoGOOGLE(device, memory, pAddress, pSize, pHostmemId);
+    return vkGetMemoryHostAddressInfoGOOGLE_VkResult_return;
+}
+static VkResult dynCheck_entry_vkGetMemoryHostAddressInfoGOOGLE(
+    VkDevice device,
+    VkDeviceMemory memory,
+    uint64_t* pAddress,
+    uint64_t* pSize,
+    uint64_t* pHostmemId)
+{
+    auto resources = ResourceTracker::get();
+    if (!resources->hasDeviceExtension(device, "VK_GOOGLE_address_space_info"))
+    {
+        sOnInvalidDynamicallyCheckedCall("vkGetMemoryHostAddressInfoGOOGLE", "VK_GOOGLE_address_space_info");
+    }
+    AEMU_SCOPED_TRACE("vkGetMemoryHostAddressInfoGOOGLE");
+    auto vkEnc = HostConnection::get()->vkEncoder();
+    VkResult vkGetMemoryHostAddressInfoGOOGLE_VkResult_return = (VkResult)0;
+    vkGetMemoryHostAddressInfoGOOGLE_VkResult_return = vkEnc->vkGetMemoryHostAddressInfoGOOGLE(device, memory, pAddress, pSize, pHostmemId);
+    return vkGetMemoryHostAddressInfoGOOGLE_VkResult_return;
+}
 #endif
 void* goldfish_vulkan_get_proc_address(const char* name){
 #ifdef VK_VERSION_1_0
@@ -5186,6 +6679,26 @@
     {
         return nullptr;
     }
+    if (!strcmp(name, "vkCommandBufferHostSyncGOOGLE"))
+    {
+        return nullptr;
+    }
+#endif
+#ifdef VK_GOOGLE_create_resources_with_requirements
+    if (!strcmp(name, "vkCreateImageWithRequirementsGOOGLE"))
+    {
+        return nullptr;
+    }
+    if (!strcmp(name, "vkCreateBufferWithRequirementsGOOGLE"))
+    {
+        return nullptr;
+    }
+#endif
+#ifdef VK_GOOGLE_address_space_info
+    if (!strcmp(name, "vkGetMemoryHostAddressInfoGOOGLE"))
+    {
+        return nullptr;
+    }
 #endif
     return nullptr;
 }
@@ -5749,15 +7262,15 @@
     }
     if (!strcmp(name, "vkBindBufferMemory2"))
     {
-        return has1_1OrHigher ? (void*)entry_vkBindBufferMemory2 : nullptr;
+        return (void*)dynCheck_entry_vkBindBufferMemory2;
     }
     if (!strcmp(name, "vkBindImageMemory2"))
     {
-        return has1_1OrHigher ? (void*)entry_vkBindImageMemory2 : nullptr;
+        return (void*)dynCheck_entry_vkBindImageMemory2;
     }
     if (!strcmp(name, "vkGetDeviceGroupPeerMemoryFeatures"))
     {
-        return has1_1OrHigher ? (void*)entry_vkGetDeviceGroupPeerMemoryFeatures : nullptr;
+        return (void*)dynCheck_entry_vkGetDeviceGroupPeerMemoryFeatures;
     }
     if (!strcmp(name, "vkCmdSetDeviceMask"))
     {
@@ -5773,15 +7286,15 @@
     }
     if (!strcmp(name, "vkGetImageMemoryRequirements2"))
     {
-        return has1_1OrHigher ? (void*)entry_vkGetImageMemoryRequirements2 : nullptr;
+        return (void*)dynCheck_entry_vkGetImageMemoryRequirements2;
     }
     if (!strcmp(name, "vkGetBufferMemoryRequirements2"))
     {
-        return has1_1OrHigher ? (void*)entry_vkGetBufferMemoryRequirements2 : nullptr;
+        return (void*)dynCheck_entry_vkGetBufferMemoryRequirements2;
     }
     if (!strcmp(name, "vkGetImageSparseMemoryRequirements2"))
     {
-        return has1_1OrHigher ? (void*)entry_vkGetImageSparseMemoryRequirements2 : nullptr;
+        return (void*)dynCheck_entry_vkGetImageSparseMemoryRequirements2;
     }
     if (!strcmp(name, "vkGetPhysicalDeviceFeatures2"))
     {
@@ -5813,31 +7326,31 @@
     }
     if (!strcmp(name, "vkTrimCommandPool"))
     {
-        return has1_1OrHigher ? (void*)entry_vkTrimCommandPool : nullptr;
+        return (void*)dynCheck_entry_vkTrimCommandPool;
     }
     if (!strcmp(name, "vkGetDeviceQueue2"))
     {
-        return has1_1OrHigher ? (void*)entry_vkGetDeviceQueue2 : nullptr;
+        return (void*)dynCheck_entry_vkGetDeviceQueue2;
     }
     if (!strcmp(name, "vkCreateSamplerYcbcrConversion"))
     {
-        return has1_1OrHigher ? (void*)entry_vkCreateSamplerYcbcrConversion : nullptr;
+        return (void*)dynCheck_entry_vkCreateSamplerYcbcrConversion;
     }
     if (!strcmp(name, "vkDestroySamplerYcbcrConversion"))
     {
-        return has1_1OrHigher ? (void*)entry_vkDestroySamplerYcbcrConversion : nullptr;
+        return (void*)dynCheck_entry_vkDestroySamplerYcbcrConversion;
     }
     if (!strcmp(name, "vkCreateDescriptorUpdateTemplate"))
     {
-        return has1_1OrHigher ? (void*)entry_vkCreateDescriptorUpdateTemplate : nullptr;
+        return (void*)dynCheck_entry_vkCreateDescriptorUpdateTemplate;
     }
     if (!strcmp(name, "vkDestroyDescriptorUpdateTemplate"))
     {
-        return has1_1OrHigher ? (void*)entry_vkDestroyDescriptorUpdateTemplate : nullptr;
+        return (void*)dynCheck_entry_vkDestroyDescriptorUpdateTemplate;
     }
     if (!strcmp(name, "vkUpdateDescriptorSetWithTemplate"))
     {
-        return has1_1OrHigher ? (void*)entry_vkUpdateDescriptorSetWithTemplate : nullptr;
+        return (void*)dynCheck_entry_vkUpdateDescriptorSetWithTemplate;
     }
     if (!strcmp(name, "vkGetPhysicalDeviceExternalBufferProperties"))
     {
@@ -5853,7 +7366,7 @@
     }
     if (!strcmp(name, "vkGetDescriptorSetLayoutSupport"))
     {
-        return has1_1OrHigher ? (void*)entry_vkGetDescriptorSetLayoutSupport : nullptr;
+        return (void*)dynCheck_entry_vkGetDescriptorSetLayoutSupport;
     }
 #endif
 #ifdef VK_KHR_surface
@@ -5886,23 +7399,19 @@
 #ifdef VK_KHR_swapchain
     if (!strcmp(name, "vkCreateSwapchainKHR"))
     {
-        bool hasExt = resources->hasInstanceExtension(instance, "VK_KHR_swapchain");
-        return hasExt ? (void*)entry_vkCreateSwapchainKHR : nullptr;
+        return (void*)dynCheck_entry_vkCreateSwapchainKHR;
     }
     if (!strcmp(name, "vkDestroySwapchainKHR"))
     {
-        bool hasExt = resources->hasInstanceExtension(instance, "VK_KHR_swapchain");
-        return hasExt ? (void*)entry_vkDestroySwapchainKHR : nullptr;
+        return (void*)dynCheck_entry_vkDestroySwapchainKHR;
     }
     if (!strcmp(name, "vkGetSwapchainImagesKHR"))
     {
-        bool hasExt = resources->hasInstanceExtension(instance, "VK_KHR_swapchain");
-        return hasExt ? (void*)entry_vkGetSwapchainImagesKHR : nullptr;
+        return (void*)dynCheck_entry_vkGetSwapchainImagesKHR;
     }
     if (!strcmp(name, "vkAcquireNextImageKHR"))
     {
-        bool hasExt = resources->hasInstanceExtension(instance, "VK_KHR_swapchain");
-        return hasExt ? (void*)entry_vkAcquireNextImageKHR : nullptr;
+        return (void*)dynCheck_entry_vkAcquireNextImageKHR;
     }
     if (!strcmp(name, "vkQueuePresentKHR"))
     {
@@ -5911,13 +7420,11 @@
     }
     if (!strcmp(name, "vkGetDeviceGroupPresentCapabilitiesKHR"))
     {
-        bool hasExt = resources->hasInstanceExtension(instance, "VK_KHR_swapchain");
-        return hasExt ? (void*)entry_vkGetDeviceGroupPresentCapabilitiesKHR : nullptr;
+        return (void*)dynCheck_entry_vkGetDeviceGroupPresentCapabilitiesKHR;
     }
     if (!strcmp(name, "vkGetDeviceGroupSurfacePresentModesKHR"))
     {
-        bool hasExt = resources->hasInstanceExtension(instance, "VK_KHR_swapchain");
-        return hasExt ? (void*)entry_vkGetDeviceGroupSurfacePresentModesKHR : nullptr;
+        return (void*)dynCheck_entry_vkGetDeviceGroupSurfacePresentModesKHR;
     }
     if (!strcmp(name, "vkGetPhysicalDevicePresentRectanglesKHR"))
     {
@@ -5926,8 +7433,7 @@
     }
     if (!strcmp(name, "vkAcquireNextImage2KHR"))
     {
-        bool hasExt = resources->hasInstanceExtension(instance, "VK_KHR_swapchain");
-        return hasExt ? (void*)entry_vkAcquireNextImage2KHR : nullptr;
+        return (void*)dynCheck_entry_vkAcquireNextImage2KHR;
     }
 #endif
 #ifdef VK_KHR_display
@@ -5970,8 +7476,7 @@
 #ifdef VK_KHR_display_swapchain
     if (!strcmp(name, "vkCreateSharedSwapchainsKHR"))
     {
-        bool hasExt = resources->hasInstanceExtension(instance, "VK_KHR_display_swapchain");
-        return hasExt ? (void*)entry_vkCreateSharedSwapchainsKHR : nullptr;
+        return (void*)dynCheck_entry_vkCreateSharedSwapchainsKHR;
     }
 #endif
 #ifdef VK_KHR_xlib_surface
@@ -6081,8 +7586,7 @@
 #ifdef VK_KHR_device_group
     if (!strcmp(name, "vkGetDeviceGroupPeerMemoryFeaturesKHR"))
     {
-        bool hasExt = resources->hasInstanceExtension(instance, "VK_KHR_device_group");
-        return hasExt ? (void*)entry_vkGetDeviceGroupPeerMemoryFeaturesKHR : nullptr;
+        return (void*)dynCheck_entry_vkGetDeviceGroupPeerMemoryFeaturesKHR;
     }
     if (!strcmp(name, "vkCmdSetDeviceMaskKHR"))
     {
@@ -6098,8 +7602,7 @@
 #ifdef VK_KHR_maintenance1
     if (!strcmp(name, "vkTrimCommandPoolKHR"))
     {
-        bool hasExt = resources->hasInstanceExtension(instance, "VK_KHR_maintenance1");
-        return hasExt ? (void*)entry_vkTrimCommandPoolKHR : nullptr;
+        return (void*)dynCheck_entry_vkTrimCommandPoolKHR;
     }
 #endif
 #ifdef VK_KHR_device_group_creation
@@ -6119,25 +7622,21 @@
 #ifdef VK_KHR_external_memory_win32
     if (!strcmp(name, "vkGetMemoryWin32HandleKHR"))
     {
-        bool hasExt = resources->hasInstanceExtension(instance, "VK_KHR_external_memory_win32");
-        return hasExt ? (void*)entry_vkGetMemoryWin32HandleKHR : nullptr;
+        return (void*)dynCheck_entry_vkGetMemoryWin32HandleKHR;
     }
     if (!strcmp(name, "vkGetMemoryWin32HandlePropertiesKHR"))
     {
-        bool hasExt = resources->hasInstanceExtension(instance, "VK_KHR_external_memory_win32");
-        return hasExt ? (void*)entry_vkGetMemoryWin32HandlePropertiesKHR : nullptr;
+        return (void*)dynCheck_entry_vkGetMemoryWin32HandlePropertiesKHR;
     }
 #endif
 #ifdef VK_KHR_external_memory_fd
     if (!strcmp(name, "vkGetMemoryFdKHR"))
     {
-        bool hasExt = resources->hasInstanceExtension(instance, "VK_KHR_external_memory_fd");
-        return hasExt ? (void*)entry_vkGetMemoryFdKHR : nullptr;
+        return (void*)dynCheck_entry_vkGetMemoryFdKHR;
     }
     if (!strcmp(name, "vkGetMemoryFdPropertiesKHR"))
     {
-        bool hasExt = resources->hasInstanceExtension(instance, "VK_KHR_external_memory_fd");
-        return hasExt ? (void*)entry_vkGetMemoryFdPropertiesKHR : nullptr;
+        return (void*)dynCheck_entry_vkGetMemoryFdPropertiesKHR;
     }
 #endif
 #ifdef VK_KHR_external_semaphore_capabilities
@@ -6150,25 +7649,21 @@
 #ifdef VK_KHR_external_semaphore_win32
     if (!strcmp(name, "vkImportSemaphoreWin32HandleKHR"))
     {
-        bool hasExt = resources->hasInstanceExtension(instance, "VK_KHR_external_semaphore_win32");
-        return hasExt ? (void*)entry_vkImportSemaphoreWin32HandleKHR : nullptr;
+        return (void*)dynCheck_entry_vkImportSemaphoreWin32HandleKHR;
     }
     if (!strcmp(name, "vkGetSemaphoreWin32HandleKHR"))
     {
-        bool hasExt = resources->hasInstanceExtension(instance, "VK_KHR_external_semaphore_win32");
-        return hasExt ? (void*)entry_vkGetSemaphoreWin32HandleKHR : nullptr;
+        return (void*)dynCheck_entry_vkGetSemaphoreWin32HandleKHR;
     }
 #endif
 #ifdef VK_KHR_external_semaphore_fd
     if (!strcmp(name, "vkImportSemaphoreFdKHR"))
     {
-        bool hasExt = resources->hasInstanceExtension(instance, "VK_KHR_external_semaphore_fd");
-        return hasExt ? (void*)entry_vkImportSemaphoreFdKHR : nullptr;
+        return (void*)dynCheck_entry_vkImportSemaphoreFdKHR;
     }
     if (!strcmp(name, "vkGetSemaphoreFdKHR"))
     {
-        bool hasExt = resources->hasInstanceExtension(instance, "VK_KHR_external_semaphore_fd");
-        return hasExt ? (void*)entry_vkGetSemaphoreFdKHR : nullptr;
+        return (void*)dynCheck_entry_vkGetSemaphoreFdKHR;
     }
 #endif
 #ifdef VK_KHR_push_descriptor
@@ -6186,25 +7681,21 @@
 #ifdef VK_KHR_descriptor_update_template
     if (!strcmp(name, "vkCreateDescriptorUpdateTemplateKHR"))
     {
-        bool hasExt = resources->hasInstanceExtension(instance, "VK_KHR_descriptor_update_template");
-        return hasExt ? (void*)entry_vkCreateDescriptorUpdateTemplateKHR : nullptr;
+        return (void*)dynCheck_entry_vkCreateDescriptorUpdateTemplateKHR;
     }
     if (!strcmp(name, "vkDestroyDescriptorUpdateTemplateKHR"))
     {
-        bool hasExt = resources->hasInstanceExtension(instance, "VK_KHR_descriptor_update_template");
-        return hasExt ? (void*)entry_vkDestroyDescriptorUpdateTemplateKHR : nullptr;
+        return (void*)dynCheck_entry_vkDestroyDescriptorUpdateTemplateKHR;
     }
     if (!strcmp(name, "vkUpdateDescriptorSetWithTemplateKHR"))
     {
-        bool hasExt = resources->hasInstanceExtension(instance, "VK_KHR_descriptor_update_template");
-        return hasExt ? (void*)entry_vkUpdateDescriptorSetWithTemplateKHR : nullptr;
+        return (void*)dynCheck_entry_vkUpdateDescriptorSetWithTemplateKHR;
     }
 #endif
 #ifdef VK_KHR_create_renderpass2
     if (!strcmp(name, "vkCreateRenderPass2KHR"))
     {
-        bool hasExt = resources->hasInstanceExtension(instance, "VK_KHR_create_renderpass2");
-        return hasExt ? (void*)entry_vkCreateRenderPass2KHR : nullptr;
+        return (void*)dynCheck_entry_vkCreateRenderPass2KHR;
     }
     if (!strcmp(name, "vkCmdBeginRenderPass2KHR"))
     {
@@ -6225,8 +7716,7 @@
 #ifdef VK_KHR_shared_presentable_image
     if (!strcmp(name, "vkGetSwapchainStatusKHR"))
     {
-        bool hasExt = resources->hasInstanceExtension(instance, "VK_KHR_shared_presentable_image");
-        return hasExt ? (void*)entry_vkGetSwapchainStatusKHR : nullptr;
+        return (void*)dynCheck_entry_vkGetSwapchainStatusKHR;
     }
 #endif
 #ifdef VK_KHR_external_fence_capabilities
@@ -6239,25 +7729,21 @@
 #ifdef VK_KHR_external_fence_win32
     if (!strcmp(name, "vkImportFenceWin32HandleKHR"))
     {
-        bool hasExt = resources->hasInstanceExtension(instance, "VK_KHR_external_fence_win32");
-        return hasExt ? (void*)entry_vkImportFenceWin32HandleKHR : nullptr;
+        return (void*)dynCheck_entry_vkImportFenceWin32HandleKHR;
     }
     if (!strcmp(name, "vkGetFenceWin32HandleKHR"))
     {
-        bool hasExt = resources->hasInstanceExtension(instance, "VK_KHR_external_fence_win32");
-        return hasExt ? (void*)entry_vkGetFenceWin32HandleKHR : nullptr;
+        return (void*)dynCheck_entry_vkGetFenceWin32HandleKHR;
     }
 #endif
 #ifdef VK_KHR_external_fence_fd
     if (!strcmp(name, "vkImportFenceFdKHR"))
     {
-        bool hasExt = resources->hasInstanceExtension(instance, "VK_KHR_external_fence_fd");
-        return hasExt ? (void*)entry_vkImportFenceFdKHR : nullptr;
+        return (void*)dynCheck_entry_vkImportFenceFdKHR;
     }
     if (!strcmp(name, "vkGetFenceFdKHR"))
     {
-        bool hasExt = resources->hasInstanceExtension(instance, "VK_KHR_external_fence_fd");
-        return hasExt ? (void*)entry_vkGetFenceFdKHR : nullptr;
+        return (void*)dynCheck_entry_vkGetFenceFdKHR;
     }
 #endif
 #ifdef VK_KHR_get_surface_capabilities2
@@ -6297,49 +7783,41 @@
 #ifdef VK_KHR_get_memory_requirements2
     if (!strcmp(name, "vkGetImageMemoryRequirements2KHR"))
     {
-        bool hasExt = resources->hasInstanceExtension(instance, "VK_KHR_get_memory_requirements2");
-        return hasExt ? (void*)entry_vkGetImageMemoryRequirements2KHR : nullptr;
+        return (void*)dynCheck_entry_vkGetImageMemoryRequirements2KHR;
     }
     if (!strcmp(name, "vkGetBufferMemoryRequirements2KHR"))
     {
-        bool hasExt = resources->hasInstanceExtension(instance, "VK_KHR_get_memory_requirements2");
-        return hasExt ? (void*)entry_vkGetBufferMemoryRequirements2KHR : nullptr;
+        return (void*)dynCheck_entry_vkGetBufferMemoryRequirements2KHR;
     }
     if (!strcmp(name, "vkGetImageSparseMemoryRequirements2KHR"))
     {
-        bool hasExt = resources->hasInstanceExtension(instance, "VK_KHR_get_memory_requirements2");
-        return hasExt ? (void*)entry_vkGetImageSparseMemoryRequirements2KHR : nullptr;
+        return (void*)dynCheck_entry_vkGetImageSparseMemoryRequirements2KHR;
     }
 #endif
 #ifdef VK_KHR_sampler_ycbcr_conversion
     if (!strcmp(name, "vkCreateSamplerYcbcrConversionKHR"))
     {
-        bool hasExt = resources->hasInstanceExtension(instance, "VK_KHR_sampler_ycbcr_conversion");
-        return hasExt ? (void*)entry_vkCreateSamplerYcbcrConversionKHR : nullptr;
+        return (void*)dynCheck_entry_vkCreateSamplerYcbcrConversionKHR;
     }
     if (!strcmp(name, "vkDestroySamplerYcbcrConversionKHR"))
     {
-        bool hasExt = resources->hasInstanceExtension(instance, "VK_KHR_sampler_ycbcr_conversion");
-        return hasExt ? (void*)entry_vkDestroySamplerYcbcrConversionKHR : nullptr;
+        return (void*)dynCheck_entry_vkDestroySamplerYcbcrConversionKHR;
     }
 #endif
 #ifdef VK_KHR_bind_memory2
     if (!strcmp(name, "vkBindBufferMemory2KHR"))
     {
-        bool hasExt = resources->hasInstanceExtension(instance, "VK_KHR_bind_memory2");
-        return hasExt ? (void*)entry_vkBindBufferMemory2KHR : nullptr;
+        return (void*)dynCheck_entry_vkBindBufferMemory2KHR;
     }
     if (!strcmp(name, "vkBindImageMemory2KHR"))
     {
-        bool hasExt = resources->hasInstanceExtension(instance, "VK_KHR_bind_memory2");
-        return hasExt ? (void*)entry_vkBindImageMemory2KHR : nullptr;
+        return (void*)dynCheck_entry_vkBindImageMemory2KHR;
     }
 #endif
 #ifdef VK_KHR_maintenance3
     if (!strcmp(name, "vkGetDescriptorSetLayoutSupportKHR"))
     {
-        bool hasExt = resources->hasInstanceExtension(instance, "VK_KHR_maintenance3");
-        return hasExt ? (void*)entry_vkGetDescriptorSetLayoutSupportKHR : nullptr;
+        return (void*)dynCheck_entry_vkGetDescriptorSetLayoutSupportKHR;
     }
 #endif
 #ifdef VK_KHR_draw_indirect_count
@@ -6357,13 +7835,11 @@
 #ifdef VK_ANDROID_native_buffer
     if (!strcmp(name, "vkGetSwapchainGrallocUsageANDROID"))
     {
-        bool hasExt = resources->hasInstanceExtension(instance, "VK_ANDROID_native_buffer");
-        return hasExt ? (void*)entry_vkGetSwapchainGrallocUsageANDROID : nullptr;
+        return (void*)dynCheck_entry_vkGetSwapchainGrallocUsageANDROID;
     }
     if (!strcmp(name, "vkAcquireImageANDROID"))
     {
-        bool hasExt = resources->hasInstanceExtension(instance, "VK_ANDROID_native_buffer");
-        return hasExt ? (void*)entry_vkAcquireImageANDROID : nullptr;
+        return (void*)dynCheck_entry_vkAcquireImageANDROID;
     }
     if (!strcmp(name, "vkQueueSignalReleaseImageANDROID"))
     {
@@ -6391,13 +7867,11 @@
 #ifdef VK_EXT_debug_marker
     if (!strcmp(name, "vkDebugMarkerSetObjectTagEXT"))
     {
-        bool hasExt = resources->hasInstanceExtension(instance, "VK_EXT_debug_marker");
-        return hasExt ? (void*)entry_vkDebugMarkerSetObjectTagEXT : nullptr;
+        return (void*)dynCheck_entry_vkDebugMarkerSetObjectTagEXT;
     }
     if (!strcmp(name, "vkDebugMarkerSetObjectNameEXT"))
     {
-        bool hasExt = resources->hasInstanceExtension(instance, "VK_EXT_debug_marker");
-        return hasExt ? (void*)entry_vkDebugMarkerSetObjectNameEXT : nullptr;
+        return (void*)dynCheck_entry_vkDebugMarkerSetObjectNameEXT;
     }
     if (!strcmp(name, "vkCmdDebugMarkerBeginEXT"))
     {
@@ -6430,8 +7904,7 @@
 #ifdef VK_AMD_shader_info
     if (!strcmp(name, "vkGetShaderInfoAMD"))
     {
-        bool hasExt = resources->hasInstanceExtension(instance, "VK_AMD_shader_info");
-        return hasExt ? (void*)entry_vkGetShaderInfoAMD : nullptr;
+        return (void*)dynCheck_entry_vkGetShaderInfoAMD;
     }
 #endif
 #ifdef VK_NV_external_memory_capabilities
@@ -6444,8 +7917,7 @@
 #ifdef VK_NV_external_memory_win32
     if (!strcmp(name, "vkGetMemoryWin32HandleNV"))
     {
-        bool hasExt = resources->hasInstanceExtension(instance, "VK_NV_external_memory_win32");
-        return hasExt ? (void*)entry_vkGetMemoryWin32HandleNV : nullptr;
+        return (void*)dynCheck_entry_vkGetMemoryWin32HandleNV;
     }
 #endif
 #ifdef VK_NN_vi_surface
@@ -6480,33 +7952,27 @@
     }
     if (!strcmp(name, "vkCreateIndirectCommandsLayoutNVX"))
     {
-        bool hasExt = resources->hasInstanceExtension(instance, "VK_NVX_device_generated_commands");
-        return hasExt ? (void*)entry_vkCreateIndirectCommandsLayoutNVX : nullptr;
+        return (void*)dynCheck_entry_vkCreateIndirectCommandsLayoutNVX;
     }
     if (!strcmp(name, "vkDestroyIndirectCommandsLayoutNVX"))
     {
-        bool hasExt = resources->hasInstanceExtension(instance, "VK_NVX_device_generated_commands");
-        return hasExt ? (void*)entry_vkDestroyIndirectCommandsLayoutNVX : nullptr;
+        return (void*)dynCheck_entry_vkDestroyIndirectCommandsLayoutNVX;
     }
     if (!strcmp(name, "vkCreateObjectTableNVX"))
     {
-        bool hasExt = resources->hasInstanceExtension(instance, "VK_NVX_device_generated_commands");
-        return hasExt ? (void*)entry_vkCreateObjectTableNVX : nullptr;
+        return (void*)dynCheck_entry_vkCreateObjectTableNVX;
     }
     if (!strcmp(name, "vkDestroyObjectTableNVX"))
     {
-        bool hasExt = resources->hasInstanceExtension(instance, "VK_NVX_device_generated_commands");
-        return hasExt ? (void*)entry_vkDestroyObjectTableNVX : nullptr;
+        return (void*)dynCheck_entry_vkDestroyObjectTableNVX;
     }
     if (!strcmp(name, "vkRegisterObjectsNVX"))
     {
-        bool hasExt = resources->hasInstanceExtension(instance, "VK_NVX_device_generated_commands");
-        return hasExt ? (void*)entry_vkRegisterObjectsNVX : nullptr;
+        return (void*)dynCheck_entry_vkRegisterObjectsNVX;
     }
     if (!strcmp(name, "vkUnregisterObjectsNVX"))
     {
-        bool hasExt = resources->hasInstanceExtension(instance, "VK_NVX_device_generated_commands");
-        return hasExt ? (void*)entry_vkUnregisterObjectsNVX : nullptr;
+        return (void*)dynCheck_entry_vkUnregisterObjectsNVX;
     }
     if (!strcmp(name, "vkGetPhysicalDeviceGeneratedCommandsPropertiesNVX"))
     {
@@ -6550,35 +8016,29 @@
 #ifdef VK_EXT_display_control
     if (!strcmp(name, "vkDisplayPowerControlEXT"))
     {
-        bool hasExt = resources->hasInstanceExtension(instance, "VK_EXT_display_control");
-        return hasExt ? (void*)entry_vkDisplayPowerControlEXT : nullptr;
+        return (void*)dynCheck_entry_vkDisplayPowerControlEXT;
     }
     if (!strcmp(name, "vkRegisterDeviceEventEXT"))
     {
-        bool hasExt = resources->hasInstanceExtension(instance, "VK_EXT_display_control");
-        return hasExt ? (void*)entry_vkRegisterDeviceEventEXT : nullptr;
+        return (void*)dynCheck_entry_vkRegisterDeviceEventEXT;
     }
     if (!strcmp(name, "vkRegisterDisplayEventEXT"))
     {
-        bool hasExt = resources->hasInstanceExtension(instance, "VK_EXT_display_control");
-        return hasExt ? (void*)entry_vkRegisterDisplayEventEXT : nullptr;
+        return (void*)dynCheck_entry_vkRegisterDisplayEventEXT;
     }
     if (!strcmp(name, "vkGetSwapchainCounterEXT"))
     {
-        bool hasExt = resources->hasInstanceExtension(instance, "VK_EXT_display_control");
-        return hasExt ? (void*)entry_vkGetSwapchainCounterEXT : nullptr;
+        return (void*)dynCheck_entry_vkGetSwapchainCounterEXT;
     }
 #endif
 #ifdef VK_GOOGLE_display_timing
     if (!strcmp(name, "vkGetRefreshCycleDurationGOOGLE"))
     {
-        bool hasExt = resources->hasInstanceExtension(instance, "VK_GOOGLE_display_timing");
-        return hasExt ? (void*)entry_vkGetRefreshCycleDurationGOOGLE : nullptr;
+        return (void*)dynCheck_entry_vkGetRefreshCycleDurationGOOGLE;
     }
     if (!strcmp(name, "vkGetPastPresentationTimingGOOGLE"))
     {
-        bool hasExt = resources->hasInstanceExtension(instance, "VK_GOOGLE_display_timing");
-        return hasExt ? (void*)entry_vkGetPastPresentationTimingGOOGLE : nullptr;
+        return (void*)dynCheck_entry_vkGetPastPresentationTimingGOOGLE;
     }
 #endif
 #ifdef VK_EXT_discard_rectangles
@@ -6591,8 +8051,7 @@
 #ifdef VK_EXT_hdr_metadata
     if (!strcmp(name, "vkSetHdrMetadataEXT"))
     {
-        bool hasExt = resources->hasInstanceExtension(instance, "VK_EXT_hdr_metadata");
-        return hasExt ? (void*)entry_vkSetHdrMetadataEXT : nullptr;
+        return (void*)dynCheck_entry_vkSetHdrMetadataEXT;
     }
 #endif
 #ifdef VK_MVK_ios_surface
@@ -6612,13 +8071,11 @@
 #ifdef VK_EXT_debug_utils
     if (!strcmp(name, "vkSetDebugUtilsObjectNameEXT"))
     {
-        bool hasExt = resources->hasInstanceExtension(instance, "VK_EXT_debug_utils");
-        return hasExt ? (void*)entry_vkSetDebugUtilsObjectNameEXT : nullptr;
+        return (void*)dynCheck_entry_vkSetDebugUtilsObjectNameEXT;
     }
     if (!strcmp(name, "vkSetDebugUtilsObjectTagEXT"))
     {
-        bool hasExt = resources->hasInstanceExtension(instance, "VK_EXT_debug_utils");
-        return hasExt ? (void*)entry_vkSetDebugUtilsObjectTagEXT : nullptr;
+        return (void*)dynCheck_entry_vkSetDebugUtilsObjectTagEXT;
     }
     if (!strcmp(name, "vkQueueBeginDebugUtilsLabelEXT"))
     {
@@ -6669,13 +8126,11 @@
 #ifdef VK_ANDROID_external_memory_android_hardware_buffer
     if (!strcmp(name, "vkGetAndroidHardwareBufferPropertiesANDROID"))
     {
-        bool hasExt = resources->hasInstanceExtension(instance, "VK_ANDROID_external_memory_android_hardware_buffer");
-        return hasExt ? (void*)entry_vkGetAndroidHardwareBufferPropertiesANDROID : nullptr;
+        return (void*)dynCheck_entry_vkGetAndroidHardwareBufferPropertiesANDROID;
     }
     if (!strcmp(name, "vkGetMemoryAndroidHardwareBufferANDROID"))
     {
-        bool hasExt = resources->hasInstanceExtension(instance, "VK_ANDROID_external_memory_android_hardware_buffer");
-        return hasExt ? (void*)entry_vkGetMemoryAndroidHardwareBufferANDROID : nullptr;
+        return (void*)dynCheck_entry_vkGetMemoryAndroidHardwareBufferANDROID;
     }
 #endif
 #ifdef VK_EXT_sample_locations
@@ -6693,30 +8148,25 @@
 #ifdef VK_EXT_validation_cache
     if (!strcmp(name, "vkCreateValidationCacheEXT"))
     {
-        bool hasExt = resources->hasInstanceExtension(instance, "VK_EXT_validation_cache");
-        return hasExt ? (void*)entry_vkCreateValidationCacheEXT : nullptr;
+        return (void*)dynCheck_entry_vkCreateValidationCacheEXT;
     }
     if (!strcmp(name, "vkDestroyValidationCacheEXT"))
     {
-        bool hasExt = resources->hasInstanceExtension(instance, "VK_EXT_validation_cache");
-        return hasExt ? (void*)entry_vkDestroyValidationCacheEXT : nullptr;
+        return (void*)dynCheck_entry_vkDestroyValidationCacheEXT;
     }
     if (!strcmp(name, "vkMergeValidationCachesEXT"))
     {
-        bool hasExt = resources->hasInstanceExtension(instance, "VK_EXT_validation_cache");
-        return hasExt ? (void*)entry_vkMergeValidationCachesEXT : nullptr;
+        return (void*)dynCheck_entry_vkMergeValidationCachesEXT;
     }
     if (!strcmp(name, "vkGetValidationCacheDataEXT"))
     {
-        bool hasExt = resources->hasInstanceExtension(instance, "VK_EXT_validation_cache");
-        return hasExt ? (void*)entry_vkGetValidationCacheDataEXT : nullptr;
+        return (void*)dynCheck_entry_vkGetValidationCacheDataEXT;
     }
 #endif
 #ifdef VK_EXT_external_memory_host
     if (!strcmp(name, "vkGetMemoryHostPointerPropertiesEXT"))
     {
-        bool hasExt = resources->hasInstanceExtension(instance, "VK_EXT_external_memory_host");
-        return hasExt ? (void*)entry_vkGetMemoryHostPointerPropertiesEXT : nullptr;
+        return (void*)dynCheck_entry_vkGetMemoryHostPointerPropertiesEXT;
     }
 #endif
 #ifdef VK_AMD_buffer_marker
@@ -6741,27 +8191,23 @@
 #ifdef VK_GOOGLE_address_space
     if (!strcmp(name, "vkMapMemoryIntoAddressSpaceGOOGLE"))
     {
-        bool hasExt = resources->hasInstanceExtension(instance, "VK_GOOGLE_address_space");
-        return hasExt ? (void*)entry_vkMapMemoryIntoAddressSpaceGOOGLE : nullptr;
+        return (void*)dynCheck_entry_vkMapMemoryIntoAddressSpaceGOOGLE;
     }
 #endif
 #ifdef VK_GOOGLE_color_buffer
     if (!strcmp(name, "vkRegisterImageColorBufferGOOGLE"))
     {
-        bool hasExt = resources->hasInstanceExtension(instance, "VK_GOOGLE_color_buffer");
-        return hasExt ? (void*)entry_vkRegisterImageColorBufferGOOGLE : nullptr;
+        return (void*)dynCheck_entry_vkRegisterImageColorBufferGOOGLE;
     }
     if (!strcmp(name, "vkRegisterBufferColorBufferGOOGLE"))
     {
-        bool hasExt = resources->hasInstanceExtension(instance, "VK_GOOGLE_color_buffer");
-        return hasExt ? (void*)entry_vkRegisterBufferColorBufferGOOGLE : nullptr;
+        return (void*)dynCheck_entry_vkRegisterBufferColorBufferGOOGLE;
     }
 #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;
+        return (void*)dynCheck_entry_vkUpdateDescriptorSetWithTemplateSizedGOOGLE;
     }
 #endif
 #ifdef VK_GOOGLE_async_command_buffers
@@ -6780,6 +8226,27 @@
         bool hasExt = resources->hasInstanceExtension(instance, "VK_GOOGLE_async_command_buffers");
         return hasExt ? (void*)entry_vkResetCommandBufferAsyncGOOGLE : nullptr;
     }
+    if (!strcmp(name, "vkCommandBufferHostSyncGOOGLE"))
+    {
+        bool hasExt = resources->hasInstanceExtension(instance, "VK_GOOGLE_async_command_buffers");
+        return hasExt ? (void*)entry_vkCommandBufferHostSyncGOOGLE : nullptr;
+    }
+#endif
+#ifdef VK_GOOGLE_create_resources_with_requirements
+    if (!strcmp(name, "vkCreateImageWithRequirementsGOOGLE"))
+    {
+        return (void*)dynCheck_entry_vkCreateImageWithRequirementsGOOGLE;
+    }
+    if (!strcmp(name, "vkCreateBufferWithRequirementsGOOGLE"))
+    {
+        return (void*)dynCheck_entry_vkCreateBufferWithRequirementsGOOGLE;
+    }
+#endif
+#ifdef VK_GOOGLE_address_space_info
+    if (!strcmp(name, "vkGetMemoryHostAddressInfoGOOGLE"))
+    {
+        return (void*)dynCheck_entry_vkGetMemoryHostAddressInfoGOOGLE;
+    }
 #endif
     return nullptr;
 }
@@ -8374,6 +9841,30 @@
         bool hasExt = resources->hasDeviceExtension(device, "VK_GOOGLE_async_command_buffers");
         return hasExt ? (void*)entry_vkResetCommandBufferAsyncGOOGLE : nullptr;
     }
+    if (!strcmp(name, "vkCommandBufferHostSyncGOOGLE"))
+    {
+        bool hasExt = resources->hasDeviceExtension(device, "VK_GOOGLE_async_command_buffers");
+        return hasExt ? (void*)entry_vkCommandBufferHostSyncGOOGLE : nullptr;
+    }
+#endif
+#ifdef VK_GOOGLE_create_resources_with_requirements
+    if (!strcmp(name, "vkCreateImageWithRequirementsGOOGLE"))
+    {
+        bool hasExt = resources->hasDeviceExtension(device, "VK_GOOGLE_create_resources_with_requirements");
+        return hasExt ? (void*)entry_vkCreateImageWithRequirementsGOOGLE : nullptr;
+    }
+    if (!strcmp(name, "vkCreateBufferWithRequirementsGOOGLE"))
+    {
+        bool hasExt = resources->hasDeviceExtension(device, "VK_GOOGLE_create_resources_with_requirements");
+        return hasExt ? (void*)entry_vkCreateBufferWithRequirementsGOOGLE : nullptr;
+    }
+#endif
+#ifdef VK_GOOGLE_address_space_info
+    if (!strcmp(name, "vkGetMemoryHostAddressInfoGOOGLE"))
+    {
+        bool hasExt = resources->hasDeviceExtension(device, "VK_GOOGLE_address_space_info");
+        return hasExt ? (void*)entry_vkGetMemoryHostAddressInfoGOOGLE : nullptr;
+    }
 #endif
     return nullptr;
 }
diff --git a/system/vulkan/func_table.h b/system/vulkan/func_table.h
index 4d0e977..91ffd65 100644
--- a/system/vulkan/func_table.h
+++ b/system/vulkan/func_table.h
@@ -284,6 +284,10 @@
 #endif
 #ifdef VK_GOOGLE_async_command_buffers
 #endif
+#ifdef VK_GOOGLE_create_resources_with_requirements
+#endif
+#ifdef VK_GOOGLE_address_space_info
+#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 bf170e1..a9acba1 100644
--- a/system/vulkan/goldfish_vulkan.cpp
+++ b/system/vulkan/goldfish_vulkan.cpp
@@ -17,6 +17,17 @@
 
 #include <errno.h>
 #include <string.h>
+#ifdef VK_USE_PLATFORM_FUCHSIA
+#include <fuchsia/logger/llcpp/fidl.h>
+#include <lib/syslog/global.h>
+#include <lib/zx/channel.h>
+#include <lib/zx/socket.h>
+#include <lib/zxio/zxio.h>
+#include <lib/zxio/inception.h>
+#include <unistd.h>
+
+#include "services/service_connector.h"
+#endif
 
 #include "HostConnection.h"
 #include "ResourceTracker.h"
@@ -24,19 +35,10 @@
 
 #include "func_table.h"
 
-#include <array>
-#include <bitset>
-#include <mutex>
-
 // Used when there is no Vulkan support on the host.
 // Copied from frameworks/native/vulkan/libvulkan/stubhal.cpp
 namespace vkstubhal {
 
-const size_t kMaxInstances = 32;
-static std::mutex g_instance_mutex;
-static std::bitset<kMaxInstances> g_instance_used(false);
-static std::array<hwvulkan_dispatch_t, kMaxInstances> g_instances;
-
 [[noreturn]] VKAPI_ATTR void NoOp() {
     LOG_ALWAYS_FATAL("invalid stub function called");
 }
@@ -62,28 +64,19 @@
                         const VkAllocationCallbacks* /*allocator*/,
                         VkInstance* instance) {
     AEMU_SCOPED_TRACE("vkstubhal::CreateInstance");
-    std::lock_guard<std::mutex> lock(g_instance_mutex);
-    for (size_t i = 0; i < kMaxInstances; i++) {
-        if (!g_instance_used[i]) {
-            g_instance_used[i] = true;
-            g_instances[i].magic = HWVULKAN_DISPATCH_MAGIC;
-            *instance = reinterpret_cast<VkInstance>(&g_instances[i]);
-            return VK_SUCCESS;
-        }
-    }
-    ALOGE("no more instances available (max=%zu)", kMaxInstances);
-    return VK_ERROR_INITIALIZATION_FAILED;
+    auto dispatch = new hwvulkan_dispatch_t;
+    dispatch->magic = HWVULKAN_DISPATCH_MAGIC;
+    *instance = reinterpret_cast<VkInstance>(dispatch);
+    return VK_SUCCESS;
 }
 
 void DestroyInstance(VkInstance instance,
                      const VkAllocationCallbacks* /*allocator*/) {
     AEMU_SCOPED_TRACE("vkstubhal::DestroyInstance");
-    std::lock_guard<std::mutex> lock(g_instance_mutex);
-    ssize_t idx =
-        reinterpret_cast<hwvulkan_dispatch_t*>(instance) - &g_instances[0];
-    ALOG_ASSERT(idx >= 0 && static_cast<size_t>(idx) < g_instance_used.size(),
+    auto dispatch = reinterpret_cast<hwvulkan_dispatch_t*>(instance);
+    ALOG_ASSERT(dispatch->magic == HWVULKAN_DISPATCH_MAGIC,
                 "DestroyInstance: invalid instance handle");
-    g_instance_used[static_cast<size_t>(idx)] = false;
+    delete dispatch;
 }
 
 VkResult EnumeratePhysicalDevices(VkInstance /*instance*/,
@@ -94,6 +87,12 @@
     return VK_SUCCESS;
 }
 
+VkResult EnumerateInstanceVersion(uint32_t* pApiVersion) {
+    AEMU_SCOPED_TRACE("vkstubhal::EnumerateInstanceVersion");
+    *pApiVersion = VK_API_VERSION_1_0;
+    return VK_SUCCESS;
+}
+
 VkResult
 EnumeratePhysicalDeviceGroups(VkInstance /*instance*/,
                               uint32_t* count,
@@ -103,6 +102,66 @@
     return VK_SUCCESS;
 }
 
+VkResult
+CreateDebugReportCallbackEXT(VkInstance /*instance*/,
+                             const VkDebugReportCallbackCreateInfoEXT* /*pCreateInfo*/,
+                             const VkAllocationCallbacks* /*pAllocator*/,
+                             VkDebugReportCallbackEXT* pCallback)
+{
+    AEMU_SCOPED_TRACE("vkstubhal::CreateDebugReportCallbackEXT");
+    *pCallback = VK_NULL_HANDLE;
+    return VK_SUCCESS;
+}
+
+void
+DestroyDebugReportCallbackEXT(VkInstance /*instance*/,
+                              VkDebugReportCallbackEXT /*callback*/,
+                              const VkAllocationCallbacks* /*pAllocator*/)
+{
+    AEMU_SCOPED_TRACE("vkstubhal::DestroyDebugReportCallbackEXT");
+}
+
+void
+DebugReportMessageEXT(VkInstance /*instance*/,
+                      VkDebugReportFlagsEXT /*flags*/,
+                      VkDebugReportObjectTypeEXT /*objectType*/,
+                      uint64_t /*object*/,
+                      size_t /*location*/,
+                      int32_t /*messageCode*/,
+                      const char* /*pLayerPrefix*/,
+                      const char* /*pMessage*/)
+{
+    AEMU_SCOPED_TRACE("vkstubhal::DebugReportMessageEXT");
+}
+
+VkResult
+CreateDebugUtilsMessengerEXT(VkInstance /*instance*/,
+                             const VkDebugUtilsMessengerCreateInfoEXT* /*pCreateInfo*/,
+                             const VkAllocationCallbacks* /*pAllocator*/,
+                             VkDebugUtilsMessengerEXT* pMessenger)
+{
+    AEMU_SCOPED_TRACE("vkstubhal::CreateDebugUtilsMessengerEXT");
+    *pMessenger = VK_NULL_HANDLE;
+    return VK_SUCCESS;
+}
+
+void
+DestroyDebugUtilsMessengerEXT(VkInstance /*instance*/,
+                              VkDebugUtilsMessengerEXT /*messenger*/,
+                              const VkAllocationCallbacks* /*pAllocator*/)
+{
+    AEMU_SCOPED_TRACE("vkstubhal::DestroyDebugUtilsMessengerkEXT");
+}
+
+void
+SubmitDebugUtilsMessageEXT(VkInstance /*instance*/,
+                           VkDebugUtilsMessageSeverityFlagBitsEXT /*messageSeverity*/,
+                           VkDebugUtilsMessageTypeFlagsEXT /*messageTypes*/,
+                           const VkDebugUtilsMessengerCallbackDataEXT* /*pCallbackData*/)
+{
+    AEMU_SCOPED_TRACE("vkstubhal::SubmitDebugUtilsMessageEXT");
+}
+
 #ifdef VK_USE_PLATFORM_FUCHSIA
 VkResult
 GetMemoryZirconHandleFUCHSIA(VkDevice /*device*/,
@@ -183,11 +242,28 @@
             EnumerateInstanceExtensionProperties);
     if (strcmp(name, "vkEnumeratePhysicalDevices") == 0)
         return reinterpret_cast<PFN_vkVoidFunction>(EnumeratePhysicalDevices);
+    if (strcmp(name, "vkEnumerateInstanceVersion") == 0)
+        return reinterpret_cast<PFN_vkVoidFunction>(EnumerateInstanceVersion);
     if (strcmp(name, "vkEnumeratePhysicalDeviceGroups") == 0)
         return reinterpret_cast<PFN_vkVoidFunction>(
             EnumeratePhysicalDeviceGroups);
+    if (strcmp(name, "vkEnumeratePhysicalDeviceGroupsKHR") == 0)
+        return reinterpret_cast<PFN_vkVoidFunction>(
+            EnumeratePhysicalDeviceGroups);
     if (strcmp(name, "vkGetInstanceProcAddr") == 0)
         return reinterpret_cast<PFN_vkVoidFunction>(GetInstanceProcAddr);
+    if (strcmp(name, "vkCreateDebugReportCallbackEXT") == 0)
+        return reinterpret_cast<PFN_vkVoidFunction>(CreateDebugReportCallbackEXT);
+    if (strcmp(name, "vkDestroyDebugReportCallbackEXT") == 0)
+        return reinterpret_cast<PFN_vkVoidFunction>(DestroyDebugReportCallbackEXT);
+    if (strcmp(name, "vkDebugReportMessageEXT") == 0)
+        return reinterpret_cast<PFN_vkVoidFunction>(DebugReportMessageEXT);
+    if (strcmp(name, "vkCreateDebugUtilsMessengerEXT") == 0)
+        return reinterpret_cast<PFN_vkVoidFunction>(CreateDebugUtilsMessengerEXT);
+    if (strcmp(name, "vkDestroyDebugUtilsMessengerEXT") == 0)
+        return reinterpret_cast<PFN_vkVoidFunction>(DestroyDebugUtilsMessengerEXT);
+    if (strcmp(name, "vkSubmitDebugUtilsMessageEXT") == 0)
+        return reinterpret_cast<PFN_vkVoidFunction>(SubmitDebugUtilsMessageEXT);
 #ifdef VK_USE_PLATFORM_FUCHSIA
     if (strcmp(name, "vkGetMemoryZirconHandleFUCHSIA") == 0)
         return reinterpret_cast<PFN_vkVoidFunction>(GetMemoryZirconHandleFUCHSIA);
@@ -206,12 +282,31 @@
     if (strcmp(name, "vkGetBufferCollectionPropertiesFUCHSIA") == 0)
         return reinterpret_cast<PFN_vkVoidFunction>(GetBufferCollectionPropertiesFUCHSIA);
 #endif
-    // Per the spec, return NULL if instance is NULL.
-    if (!instance)
-        return nullptr;
-    // None of the other Vulkan functions should ever be called, as they all
-    // take a VkPhysicalDevice or other object obtained from a physical device.
-    return reinterpret_cast<PFN_vkVoidFunction>(NoOp);
+    // Return NoOp for entrypoints that should never be called.
+    if (strcmp(name, "vkGetPhysicalDeviceFeatures") == 0 ||
+        strcmp(name, "vkGetPhysicalDeviceProperties") == 0 ||
+        strcmp(name, "vkGetPhysicalDeviceFormatProperties") == 0 ||
+        strcmp(name, "vkGetPhysicalDeviceImageFormatProperties") == 0 ||
+        strcmp(name, "vkGetPhysicalDeviceMemoryProperties") == 0 ||
+        strcmp(name, "vkGetPhysicalDeviceQueueFamilyProperties") == 0 ||
+        strcmp(name, "vkGetDeviceProcAddr") == 0 ||
+        strcmp(name, "vkCreateDevice") == 0 ||
+        strcmp(name, "vkEnumerateDeviceExtensionProperties") == 0 ||
+        strcmp(name, "vkGetPhysicalDeviceSparseImageFormatProperties") == 0 ||
+        strcmp(name, "vkGetPhysicalDeviceFeatures2") == 0 ||
+        strcmp(name, "vkGetPhysicalDeviceProperties2") == 0 ||
+        strcmp(name, "vkGetPhysicalDeviceFormatProperties2") == 0 ||
+        strcmp(name, "vkGetPhysicalDeviceImageFormatProperties2") == 0 ||
+        strcmp(name, "vkGetPhysicalDeviceQueueFamilyProperties2") == 0 ||
+        strcmp(name, "vkGetPhysicalDeviceMemoryProperties2") == 0 ||
+        strcmp(name, "vkGetPhysicalDeviceSparseImageFormatProperties2") == 0 ||
+        strcmp(name, "vkGetPhysicalDeviceExternalBufferProperties") == 0 ||
+        strcmp(name, "vkGetPhysicalDeviceExternalFenceProperties") == 0 ||
+        strcmp(name, "vkGetPhysicalDeviceExternalSemaphoreProperties") == 0)
+        return reinterpret_cast<PFN_vkVoidFunction>(NoOp);
+
+    // Per the spec, return NULL for nonexistent entrypoints.
+    return nullptr;
 }
 
 } // namespace vkstubhal
@@ -257,13 +352,20 @@
         ALOGE("vulkan: Failed to get renderControl encoder context\n"); \
         return ret; \
     } \
+    goldfish_vk::ResourceTracker::get()->setupFeatures(rcEnc->featureInfo_const()); \
+    goldfish_vk::ResourceTracker::ThreadingCallbacks threadingCallbacks = { \
+        [] { auto hostCon = HostConnection::get(); \
+            ExtendedRCEncoderContext *rcEnc = hostCon->rcEncoder(); \
+            return hostCon; }, \
+        [](HostConnection* hostCon) { return hostCon->vkEncoder(); }, \
+    }; \
+    goldfish_vk::ResourceTracker::get()->setThreadingCallbacks(threadingCallbacks); \
+    auto hostSupportsVulkan = goldfish_vk::ResourceTracker::get()->hostSupportsVulkan(); \
     goldfish_vk::VkEncoder *vkEnc = hostCon->vkEncoder(); \
     if (!vkEnc) { \
         ALOGE("vulkan: Failed to get Vulkan encoder\n"); \
         return ret; \
     } \
-    goldfish_vk::ResourceTracker::get()->setupFeatures(rcEnc->featureInfo_const()); \
-    auto hostSupportsVulkan = goldfish_vk::ResourceTracker::get()->hostSupportsVulkan(); \
 
 VKAPI_ATTR
 VkResult EnumerateInstanceExtensionProperties(
@@ -568,20 +670,74 @@
 
 class VulkanDevice {
 public:
-    VulkanDevice() {
+    VulkanDevice() : mHostSupportsGoldfish(IsAccessible(QEMU_PIPE_PATH)) {
+        InitLogger();
         goldfish_vk::ResourceTracker::get();
     }
 
+    static void InitLogger();
+
+    static bool IsAccessible(const char* name) {
+        zx_handle_t handle = GetConnectToServiceFunction()(name);
+        if (handle == ZX_HANDLE_INVALID)
+            return false;
+
+        zxio_storage_t io_storage;
+        zx_status_t status = zxio_remote_init(&io_storage, handle, ZX_HANDLE_INVALID);
+        if (status != ZX_OK)
+            return false;
+
+        zxio_node_attributes_t attr;
+        status = zxio_attr_get(&io_storage.io, &attr);
+        zxio_close(&io_storage.io);
+        if (status != ZX_OK)
+            return false;
+
+        return true;
+    }
+
     static VulkanDevice& GetInstance() {
         static VulkanDevice g_instance;
         return g_instance;
     }
 
     PFN_vkVoidFunction GetInstanceProcAddr(VkInstance instance, const char* name) {
+        if (!mHostSupportsGoldfish) {
+            return vkstubhal::GetInstanceProcAddr(instance, name);
+        }
         return ::GetInstanceProcAddr(instance, name);
     }
+
+private:
+    const bool mHostSupportsGoldfish;
 };
 
+void VulkanDevice::InitLogger() {
+   zx_handle_t channel = GetConnectToServiceFunction()("/svc/fuchsia.logger.LogSink");
+   if (channel == ZX_HANDLE_INVALID)
+      return;
+
+  zx::socket local_socket, remote_socket;
+  zx_status_t status = zx::socket::create(ZX_SOCKET_DATAGRAM, &local_socket, &remote_socket);
+  if (status != ZX_OK)
+    return;
+
+  auto result = llcpp::fuchsia::logger::LogSink::Call::Connect(
+      zx::unowned_channel(channel), std::move(remote_socket));
+  zx_handle_close(channel);
+
+  if (result.status() != ZX_OK)
+    return;
+
+  fx_logger_config_t config = {.min_severity = FX_LOG_INFO,
+                               .console_fd = -1,
+                               .log_service_channel = local_socket.release(),
+                               .tags = nullptr,
+                               .num_tags = 0};
+
+  fx_log_init_with_config(&config);
+}
+
 extern "C" __attribute__((visibility("default"))) PFN_vkVoidFunction
 vk_icdGetInstanceProcAddr(VkInstance instance, const char* name) {
     return VulkanDevice::GetInstance().GetInstanceProcAddr(instance, name);
@@ -593,6 +749,34 @@
     return VK_SUCCESS;
 }
 
+typedef VkResult(VKAPI_PTR *PFN_vkConnectToServiceAddr)(const char *pName, uint32_t handle);
+
+namespace {
+
+PFN_vkConnectToServiceAddr g_vulkan_connector;
+
+zx_handle_t LocalConnectToServiceFunction(const char* pName) {
+    zx::channel remote_endpoint, local_endpoint;
+    zx_status_t status;
+    if ((status = zx::channel::create(0, &remote_endpoint, &local_endpoint)) != ZX_OK) {
+        ALOGE("zx::channel::create failed: %d", status);
+        return ZX_HANDLE_INVALID;
+    }
+    if ((status = g_vulkan_connector(pName, remote_endpoint.release())) != ZX_OK) {
+        ALOGE("vulkan_connector failed: %d", status);
+        return ZX_HANDLE_INVALID;
+    }
+    return local_endpoint.release();
+}
+
+}
+
+extern "C" __attribute__((visibility("default"))) void
+vk_icdInitializeConnectToServiceCallback(PFN_vkConnectToServiceAddr callback) {
+    g_vulkan_connector = callback;
+    SetConnectToServiceFunction(&LocalConnectToServiceFunction);
+}
+
 #endif
 
 } // namespace
diff --git a/system/vulkan_enc/Android.mk b/system/vulkan_enc/Android.mk
index c51aa7e..984db7f 100644
--- a/system/vulkan_enc/Android.mk
+++ b/system/vulkan_enc/Android.mk
@@ -12,7 +12,7 @@
 
 $(call emugl-begin-shared-library,libvulkan_enc)
 $(call emugl-export,C_INCLUDES,$(LOCAL_PATH))
-$(call emugl-import,libOpenglCodecCommon$(GOLDFISH_OPENGL_LIB_SUFFIX) libandroidemu)
+$(call emugl-import,libOpenglCodecCommon$(GOLDFISH_OPENGL_LIB_SUFFIX) libandroidemu lib_renderControl_enc)
 
 # Vulkan include dir
 ifeq (true,$(GOLDFISH_OPENGL_BUILD_FOR_HOST))
@@ -26,11 +26,15 @@
 LOCAL_C_INCLUDES += \
     $(LOCAL_PATH) \
     $(LOCAL_PATH)/../vulkan_enc \
+    external/libdrm \
+    external/minigbm/cros_gralloc \
 
 LOCAL_HEADER_LIBRARIES += \
     hwvulkan_headers \
     vulkan_headers \
 
+LOCAL_SHARED_LIBRARIES += libdrm
+
 endif
 
 LOCAL_CFLAGS += \
diff --git a/system/vulkan_enc/AndroidHardwareBuffer.cpp b/system/vulkan_enc/AndroidHardwareBuffer.cpp
index 5cebdc2..a40a3a7 100644
--- a/system/vulkan_enc/AndroidHardwareBuffer.cpp
+++ b/system/vulkan_enc/AndroidHardwareBuffer.cpp
@@ -14,7 +14,8 @@
 // limitations under the License.
 #include "AndroidHardwareBuffer.h"
 
-#include "gralloc_cb.h"
+#include "../OpenglSystemCommon/HostConnection.h"
+
 #include "vk_format_info.h"
 #include "vk_util.h"
 
@@ -53,6 +54,7 @@
 }
 
 VkResult getAndroidHardwareBufferPropertiesANDROID(
+    Gralloc* grallocHelper,
     const HostVisibleMemoryVirtualizationInfo* hostMemVirtInfo,
     VkDevice,
     const AHardwareBuffer* buffer,
@@ -111,10 +113,8 @@
 
     const native_handle_t *handle =
        AHardwareBuffer_getNativeHandle(buffer);
-    const cb_handle_t* cb_handle =
-        reinterpret_cast<const cb_handle_t*>(handle);
-    uint32_t colorBufferHandle = cb_handle->hostHandle;
-
+    uint32_t colorBufferHandle =
+        grallocHelper->getHostHandle(handle);
     if (!colorBufferHandle) {
         return VK_ERROR_INVALID_EXTERNAL_HANDLE;
     }
@@ -130,7 +130,7 @@
 
     pProperties->memoryTypeBits = memoryTypeBits;
     pProperties->allocationSize =
-        cb_handle->ashmemBase ? cb_handle->ashmemSize : 0;
+        grallocHelper->getAllocatedSize(handle);
 
     return VK_SUCCESS;
 }
@@ -157,6 +157,7 @@
 }
 
 VkResult importAndroidHardwareBuffer(
+    Gralloc* grallocHelper,
     const VkImportAndroidHardwareBufferInfoANDROID* info,
     struct AHardwareBuffer **importOut) {
 
@@ -164,12 +165,9 @@
         return VK_ERROR_INVALID_EXTERNAL_HANDLE;
     }
 
-    const native_handle_t *handle =
-       AHardwareBuffer_getNativeHandle(info->buffer);
-    const cb_handle_t* cb_handle =
-        reinterpret_cast<const cb_handle_t*>(handle);
-    uint32_t colorBufferHandle = cb_handle->hostHandle;
-
+    uint32_t colorBufferHandle =
+        grallocHelper->getHostHandle(
+            AHardwareBuffer_getNativeHandle(info->buffer));
     if (!colorBufferHandle) {
         return VK_ERROR_INVALID_EXTERNAL_HANDLE;
     }
@@ -212,12 +210,14 @@
        w = bufferSize;
        format = AHARDWAREBUFFER_FORMAT_BLOB;
        usage = AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN |
-               AHARDWAREBUFFER_USAGE_CPU_WRITE_OFTEN;
+               AHARDWAREBUFFER_USAGE_CPU_WRITE_OFTEN |
+               AHARDWAREBUFFER_USAGE_GPU_DATA_BUFFER;
     } else {
        w = allocationInfoAllocSize;
        format = AHARDWAREBUFFER_FORMAT_BLOB;
        usage = AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN |
-               AHARDWAREBUFFER_USAGE_CPU_WRITE_OFTEN;
+               AHARDWAREBUFFER_USAGE_CPU_WRITE_OFTEN |
+               AHARDWAREBUFFER_USAGE_GPU_DATA_BUFFER;
     }
 
     struct AHardwareBuffer *ahw = NULL;
diff --git a/system/vulkan_enc/AndroidHardwareBuffer.h b/system/vulkan_enc/AndroidHardwareBuffer.h
index 81e8cd9..6cd72bc 100644
--- a/system/vulkan_enc/AndroidHardwareBuffer.h
+++ b/system/vulkan_enc/AndroidHardwareBuffer.h
@@ -22,6 +22,8 @@
 // Structure similar to
 // https://github.com/mesa3d/mesa/blob/master/src/intel/vulkan/anv_android.c
 
+class Gralloc;
+
 namespace goldfish_vk {
 
 uint64_t
@@ -30,6 +32,7 @@
     const VkImageUsageFlags vk_usage);
 
 VkResult getAndroidHardwareBufferPropertiesANDROID(
+    Gralloc* grallocHelper,
     const HostVisibleMemoryVirtualizationInfo* hostMemVirtInfo,
     VkDevice device,
     const AHardwareBuffer* buffer,
@@ -39,6 +42,7 @@
     struct AHardwareBuffer **pBuffer);
 
 VkResult importAndroidHardwareBuffer(
+    Gralloc* grallocHelper,
     const VkImportAndroidHardwareBufferInfoANDROID* info,
     struct AHardwareBuffer **importOut);
 
diff --git a/system/vulkan_enc/CMakeLists.txt b/system/vulkan_enc/CMakeLists.txt
index 9d4e7e9..dec0c66 100644
--- a/system/vulkan_enc/CMakeLists.txt
+++ b/system/vulkan_enc/CMakeLists.txt
@@ -1,10 +1,10 @@
 # This is an autogenerated file! Do not edit!
 # instead run make from .../device/generic/goldfish-opengl
 # which will re-generate this file.
-android_validate_sha256("${GOLDFISH_DEVICE_ROOT}/system/vulkan_enc/Android.mk" "4e4982fe274cdee96492d57f444a19d3a979720f17df5d289961d77cbdb4054b")
+android_validate_sha256("${GOLDFISH_DEVICE_ROOT}/system/vulkan_enc/Android.mk" "a4b1fb11cf3e68cc49f055258b6b590798eeecb2d3e6e565c78549a39a341911")
 set(vulkan_enc_src AndroidHardwareBuffer.cpp HostVisibleMemoryVirtualization.cpp Resources.cpp Validation.cpp VulkanStreamGuest.cpp VulkanHandleMapping.cpp ResourceTracker.cpp VkEncoder.cpp goldfish_vk_extension_structs_guest.cpp goldfish_vk_marshaling_guest.cpp goldfish_vk_deepcopy_guest.cpp goldfish_vk_handlemap_guest.cpp goldfish_vk_transform_guest.cpp)
-android_add_shared_library(vulkan_enc)
-target_include_directories(vulkan_enc PRIVATE ${GOLDFISH_DEVICE_ROOT}/android-emu ${GOLDFISH_DEVICE_ROOT}/shared/OpenglCodecCommon ${GOLDFISH_DEVICE_ROOT}/system/vulkan_enc ${GOLDFISH_DEVICE_ROOT}/./host/include/libOpenglRender ${GOLDFISH_DEVICE_ROOT}/./system/include ${GOLDFISH_DEVICE_ROOT}/./../../../external/qemu/android/android-emugl/guest ${GOLDFISH_DEVICE_ROOT}/./../../../external/qemu/android/android-emugl/host/include ${GOLDFISH_DEVICE_ROOT}/./../../../external/qemu/android/android-emugl/host/include/vulkan)
+android_add_library(TARGET vulkan_enc SHARED LICENSE Apache-2.0 SRC AndroidHardwareBuffer.cpp HostVisibleMemoryVirtualization.cpp Resources.cpp Validation.cpp VulkanStreamGuest.cpp VulkanHandleMapping.cpp ResourceTracker.cpp VkEncoder.cpp goldfish_vk_extension_structs_guest.cpp goldfish_vk_marshaling_guest.cpp goldfish_vk_deepcopy_guest.cpp goldfish_vk_handlemap_guest.cpp goldfish_vk_transform_guest.cpp)
+target_include_directories(vulkan_enc PRIVATE ${GOLDFISH_DEVICE_ROOT}/system/renderControl_enc ${GOLDFISH_DEVICE_ROOT}/android-emu ${GOLDFISH_DEVICE_ROOT}/shared/OpenglCodecCommon ${GOLDFISH_DEVICE_ROOT}/system/vulkan_enc ${GOLDFISH_DEVICE_ROOT}/./host/include/libOpenglRender ${GOLDFISH_DEVICE_ROOT}/./system/include ${GOLDFISH_DEVICE_ROOT}/./../../../external/qemu/android/android-emugl/guest ${GOLDFISH_DEVICE_ROOT}/./../../../external/qemu/android/android-emugl/host/include ${GOLDFISH_DEVICE_ROOT}/./../../../external/qemu/android/android-emugl/host/include/vulkan)
 target_compile_definitions(vulkan_enc PRIVATE "-DWITH_GLES2" "-DPLATFORM_SDK_VERSION=29" "-DGOLDFISH_HIDL_GRALLOC" "-DEMULATOR_OPENGL_POST_O=1" "-DHOST_BUILD" "-DANDROID" "-DGL_GLEXT_PROTOTYPES" "-DPAGE_SIZE=4096" "-DGOLDFISH_VULKAN" "-DLOG_TAG=\"goldfish_vulkan\"" "-DVK_ANDROID_native_buffer" "-DVK_GOOGLE_address_space" "-DVK_USE_PLATFORM_ANDROID_KHR" "-DVK_NO_PROTOTYPES" "-D__ANDROID_API__=28")
-target_compile_options(vulkan_enc PRIVATE "-fvisibility=default" "-Wno-missing-field-initializers" "-Werror" "-fstrict-aliasing")
-target_link_libraries(vulkan_enc PRIVATE gui cutils utils log OpenglCodecCommon_host android-emu-shared)
\ No newline at end of file
+target_compile_options(vulkan_enc PRIVATE "-fvisibility=default" "-Wno-unused-parameter" "-Wno-missing-field-initializers" "-Werror" "-fstrict-aliasing")
+target_link_libraries(vulkan_enc PRIVATE gui _renderControl_enc androidemu cutils utils log OpenglCodecCommon_host android-emu-shared)
\ No newline at end of file
diff --git a/system/vulkan_enc/HostVisibleMemoryVirtualization.cpp b/system/vulkan_enc/HostVisibleMemoryVirtualization.cpp
index 2780d2a..2db7e6a 100644
--- a/system/vulkan_enc/HostVisibleMemoryVirtualization.cpp
+++ b/system/vulkan_enc/HostVisibleMemoryVirtualization.cpp
@@ -14,16 +14,18 @@
 // limitations under the License.
 #include "HostVisibleMemoryVirtualization.h"
 
-#include "android/base/SubAllocator.h"
+#include "android/base/AndroidSubAllocator.h"
 
 #include "Resources.h"
 #include "VkEncoder.h"
 
+#include "../OpenglSystemCommon/EmulatorFeatureInfo.h"
+
 #include <log/log.h>
 
 #include <set>
 
-using android::base::SubAllocator;
+using android::base::guest::SubAllocator;
 
 namespace goldfish_vk {
 
@@ -62,7 +64,7 @@
 void initHostVisibleMemoryVirtualizationInfo(
     VkPhysicalDevice physicalDevice,
     const VkPhysicalDeviceMemoryProperties* memoryProperties,
-    bool hasDirectMem,
+    const EmulatorFeatureInfo* featureInfo,
     HostVisibleMemoryVirtualizationInfo* info_out) {
 
     if (info_out->initialized) return;
@@ -73,10 +75,12 @@
     info_out->memoryPropertiesSupported =
         canFitVirtualHostVisibleMemoryInfo(memoryProperties);
 
-    info_out->directMemSupported = hasDirectMem;
+    info_out->directMemSupported = featureInfo->hasDirectMem;
+    info_out->virtioGpuNextSupported = featureInfo->hasVirtioGpuNext;
 
     if (!info_out->memoryPropertiesSupported ||
-        !info_out->directMemSupported) {
+        (!info_out->directMemSupported &&
+         !info_out->virtioGpuNextSupported)) {
         info_out->virtualizationSupported = false;
         return;
     }
@@ -296,7 +300,7 @@
     memset(toFree, 0x0, sizeof(SubAlloc));
 }
 
-bool canSubAlloc(android::base::SubAllocator* subAlloc, VkDeviceSize size) {
+bool canSubAlloc(android::base::guest::SubAllocator* subAlloc, VkDeviceSize size) {
     auto ptr = subAlloc->alloc(size);
     if (!ptr) return false;
     subAlloc->free(ptr);
diff --git a/system/vulkan_enc/HostVisibleMemoryVirtualization.h b/system/vulkan_enc/HostVisibleMemoryVirtualization.h
index ad25353..305dca2 100644
--- a/system/vulkan_enc/HostVisibleMemoryVirtualization.h
+++ b/system/vulkan_enc/HostVisibleMemoryVirtualization.h
@@ -18,11 +18,15 @@
 
 #define VIRTUAL_HOST_VISIBLE_HEAP_SIZE 512ULL * (1048576ULL)
 
+struct EmulatorFeatureInfo;
+
 namespace android {
 namespace base {
+namespace guest {
 
 class SubAllocator;
 
+} // namespace guest
 } // namespace base
 } // namespace android
 
@@ -35,6 +39,7 @@
     bool memoryPropertiesSupported;
     bool directMemSupported;
     bool virtualizationSupported;
+    bool virtioGpuNextSupported;
 
     VkPhysicalDevice physicalDevice;
 
@@ -56,7 +61,7 @@
 void initHostVisibleMemoryVirtualizationInfo(
     VkPhysicalDevice physicalDevice,
     const VkPhysicalDeviceMemoryProperties* memoryProperties,
-    bool directMemSupported,
+    const EmulatorFeatureInfo* featureInfo,
     HostVisibleMemoryVirtualizationInfo* info_out);
 
 bool isHostVisibleMemoryTypeIndexForGuest(
@@ -81,7 +86,7 @@
     VkDeviceSize allocSize = 0;
     VkDeviceSize mappedSize = 0;
     uint8_t* mappedPtr = nullptr;
-    android::base::SubAllocator* subAlloc = nullptr;
+    android::base::guest::SubAllocator* subAlloc = nullptr;
 };
 
 VkResult finishHostMemAllocInit(
@@ -106,7 +111,7 @@
 
     VkDeviceMemory baseMemory = VK_NULL_HANDLE;
     VkDeviceSize baseOffset = 0;
-    android::base::SubAllocator* subAlloc = nullptr;
+    android::base::guest::SubAllocator* subAlloc = nullptr;
     VkDeviceMemory subMemory = VK_NULL_HANDLE;
 };
 
@@ -117,5 +122,5 @@
 
 void subFreeHostMemory(SubAlloc* toFree);
 
-bool canSubAlloc(android::base::SubAllocator* subAlloc, VkDeviceSize size);
+bool canSubAlloc(android::base::guest::SubAllocator* subAlloc, VkDeviceSize size);
 } // namespace goldfish_vk
diff --git a/system/vulkan_enc/ResourceTracker.cpp b/system/vulkan_enc/ResourceTracker.cpp
index 4e86c20..dd2aba2 100644
--- a/system/vulkan_enc/ResourceTracker.cpp
+++ b/system/vulkan_enc/ResourceTracker.cpp
@@ -14,9 +14,13 @@
 // limitations under the License.
 
 #include "ResourceTracker.h"
+
+#include "android/base/threads/AndroidWorkPool.h"
+
 #include "goldfish_vk_private_defs.h"
 
 #include "../OpenglSystemCommon/EmulatorFeatureInfo.h"
+#include "../OpenglSystemCommon/HostConnection.h"
 
 #ifdef VK_USE_PLATFORM_ANDROID_KHR
 
@@ -29,22 +33,28 @@
 
 #include "AndroidHardwareBuffer.h"
 
+#ifndef HOST_BUILD
+#include <drm/virtgpu_drm.h>
+#include <xf86drm.h>
+#endif
+
+#include "VirtioGpuNext.h"
+
 #endif // VK_USE_PLATFORM_ANDROID_KHR
 
 #ifdef VK_USE_PLATFORM_FUCHSIA
 
 #include <cutils/native_handle.h>
-#include <fuchsia/hardware/goldfish/control/c/fidl.h>
+#include <fuchsia/hardware/goldfish/cpp/fidl.h>
 #include <fuchsia/sysmem/cpp/fidl.h>
-#include <lib/fdio/directory.h>
-#include <lib/fdio/fd.h>
-#include <lib/fdio/fdio.h>
-#include <lib/fdio/io.h>
 #include <lib/zx/channel.h>
+#include <lib/zx/vmo.h>
 #include <zircon/process.h>
 #include <zircon/syscalls.h>
 #include <zircon/syscalls/object.h>
 
+#include "services/service_connector.h"
+
 struct AHardwareBuffer;
 
 void AHardwareBuffer_release(AHardwareBuffer*) { }
@@ -58,6 +68,7 @@
 }
 
 VkResult importAndroidHardwareBuffer(
+    Gralloc *grallocHelper,
     const VkImportAndroidHardwareBufferInfoANDROID* info,
     struct AHardwareBuffer **importOut) {
   return VK_SUCCESS;
@@ -82,6 +93,7 @@
 }
 
 VkResult getAndroidHardwareBufferPropertiesANDROID(
+    Gralloc *grallocHelper,
     const goldfish_vk::HostVisibleMemoryVirtualizationInfo*,
     VkDevice,
     const AHardwareBuffer*,
@@ -98,7 +110,6 @@
 #include "android/base/AlignedBuf.h"
 #include "android/base/synchronization/AndroidLock.h"
 
-#include "gralloc_cb.h"
 #include "goldfish_address_space.h"
 #include "goldfish_vk_private_defs.h"
 #include "vk_format_info.h"
@@ -122,9 +133,8 @@
 #include "android/utils/tempfile.h"
 #endif
 
-#ifndef HAVE_MEMFD_CREATE
 static inline int
-memfd_create(const char *name, unsigned int flags) {
+inline_memfd_create(const char *name, unsigned int flags) {
 #ifdef HOST_BUILD
     TempFile* tmpFile = tempfile_create();
     return open(tempfile_path(tmpFile), O_RDWR);
@@ -133,7 +143,7 @@
     return syscall(SYS_memfd_create, name, flags);
 #endif
 }
-#endif // !HAVE_MEMFD_CREATE
+#define memfd_create inline_memfd_create
 #endif // !VK_USE_PLATFORM_ANDROID_KHR
 
 #define RESOURCE_TRACKER_DEBUG 0
@@ -151,6 +161,7 @@
 using android::aligned_buf_free;
 using android::base::guest::AutoLock;
 using android::base::guest::Lock;
+using android::base::guest::WorkPool;
 
 namespace goldfish_vk {
 
@@ -234,7 +245,11 @@
         std::vector<HostMemBlocks> hostMemBlocks { VK_MAX_MEMORY_TYPES };
         uint32_t apiVersion;
         std::set<std::string> enabledExtensions;
-        VkFence fence = VK_NULL_HANDLE;
+    };
+
+    struct VirtioGpuHostmemResourceInfo {
+        uint32_t resourceId = 0;
+        int primeFd = -1;
     };
 
     struct VkDeviceMemory_Info {
@@ -246,11 +261,17 @@
         bool directMapped = false;
         GoldfishAddressSpaceBlock*
             goldfishAddressSpaceBlock = nullptr;
+        VirtioGpuHostmemResourceInfo resInfo;
         SubAlloc subAlloc;
         AHardwareBuffer* ahw = nullptr;
         zx_handle_t vmoHandle = ZX_HANDLE_INVALID;
     };
 
+    struct VkCommandBuffer_Info {
+        VkEncoder** lastUsedEncoderPtr = nullptr;
+        uint32_t sequenceNumber = 0;
+    };
+
     // custom guest-side structs for images/buffers because of AHardwareBuffer :((
     struct VkImage_Info {
         VkDevice device;
@@ -260,6 +281,11 @@
         VkDeviceMemory currentBacking = VK_NULL_HANDLE;
         VkDeviceSize currentBackingOffset = 0;
         VkDeviceSize currentBackingSize = 0;
+        bool baseRequirementsKnown = false;
+        VkMemoryRequirements baseRequirements;
+#ifdef VK_USE_PLATFORM_FUCHSIA
+        bool isSysmemBackedMemory = false;
+#endif
     };
 
     struct VkBuffer_Info {
@@ -270,6 +296,8 @@
         VkDeviceMemory currentBacking = VK_NULL_HANDLE;
         VkDeviceSize currentBackingOffset = 0;
         VkDeviceSize currentBackingSize = 0;
+        bool baseRequirementsKnown = false;
+        VkMemoryRequirements baseRequirements;
     };
 
     struct VkSemaphore_Info {
@@ -290,6 +318,15 @@
         std::vector<VkBufferView> bufferViews;
     };
 
+    struct VkFence_Info {
+        VkDevice device;
+        bool external = false;
+        VkExportFenceCreateInfo exportFenceCreateInfo;
+#ifdef VK_USE_PLATFORM_ANDROID_KHR
+        int syncFd = -1;
+#endif
+    };
+
 #define HANDLE_REGISTER_IMPL_IMPL(type) \
     std::unordered_map<type, type##_Info> info_##type; \
     void register_##type(type obj) { \
@@ -326,6 +363,24 @@
         lock.unlock();
     }
 
+    void unregister_VkCommandBuffer(VkCommandBuffer commandBuffer) {
+        AutoLock lock(mLock);
+
+        auto it = info_VkCommandBuffer.find(commandBuffer);
+        if (it == info_VkCommandBuffer.end()) return;
+        auto& info = it->second;
+        auto lastUsedEncoder =
+            info.lastUsedEncoderPtr ?
+            *(info.lastUsedEncoderPtr) : nullptr;
+
+        if (lastUsedEncoder) {
+            lastUsedEncoder->unregisterCleanupCallback(commandBuffer);
+            delete info.lastUsedEncoderPtr;
+        }
+
+        info_VkCommandBuffer.erase(commandBuffer);
+    }
+
     void unregister_VkDeviceMemory(VkDeviceMemory mem) {
         AutoLock lock(mLock);
 
@@ -396,6 +451,23 @@
         info_VkDescriptorUpdateTemplate.erase(templ);
     }
 
+    void unregister_VkFence(VkFence fence) {
+        AutoLock lock(mLock);
+        auto it = info_VkFence.find(fence);
+        if (it == info_VkFence.end()) return;
+
+        auto& fenceInfo = it->second;
+        (void)fenceInfo;
+
+#ifdef VK_USE_PLATFORM_ANDROID_KHR
+        if (fenceInfo.syncFd >= 0) {
+            close(fenceInfo.syncFd);
+        }
+#endif
+
+        info_VkFence.erase(fence);
+    }
+
     // 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);
@@ -428,7 +500,7 @@
         info.memProps = memProps;
         initHostVisibleMemoryVirtualizationInfo(
             physdev, &memProps,
-            mFeatureInfo->hasDirectMem,
+            mFeatureInfo.get(),
             &mHostVisibleMemoryVirtInfo);
         info.apiVersion = props.apiVersion;
 
@@ -536,30 +608,44 @@
 
         if (mFeatureInfo->hasDirectMem) {
             mGoldfishAddressSpaceBlockProvider.reset(
-                new GoldfishAddressSpaceBlockProvider);
+                new GoldfishAddressSpaceBlockProvider(
+                    GoldfishAddressSpaceSubdeviceType::NoSubdevice));
         }
 
 #ifdef VK_USE_PLATFORM_FUCHSIA
         if (mFeatureInfo->hasVulkan) {
-            int fd = open("/dev/class/goldfish-control/000", O_RDWR);
-            if (fd < 0) {
+            zx::channel channel(GetConnectToServiceFunction()("/dev/class/goldfish-control/000"));
+            if (!channel) {
                 ALOGE("failed to open control device");
                 abort();
             }
-            zx_status_t status = fdio_get_service_handle(fd, &mControlDevice);
-            if (status != ZX_OK) {
-                ALOGE("failed to get control service handle, status %d", status);
-                abort();
+            mControlDevice.Bind(std::move(channel));
+
+            zx::channel sysmem_channel(GetConnectToServiceFunction()("/svc/fuchsia.sysmem.Allocator"));
+            if (!sysmem_channel) {
+                ALOGE("failed to open sysmem connection");
             }
-            status = fuchsia_hardware_goldfish_control_DeviceConnectSysmem(
-                mControlDevice,
-                mSysmemAllocator.NewRequest().TakeChannel().release());
-            if (status != ZX_OK) {
-                ALOGE("failed to get sysmem connection, status %d", status);
-                abort();
-            }
+            mSysmemAllocator.Bind(std::move(sysmem_channel));
         }
 #endif
+
+        if (mFeatureInfo->hasVulkanNullOptionalStrings) {
+            mStreamFeatureBits |= VULKAN_STREAM_FEATURE_NULL_OPTIONAL_STRINGS_BIT;
+        }
+        if (mFeatureInfo->hasVulkanIgnoredHandles) {
+            mStreamFeatureBits |= VULKAN_STREAM_FEATURE_IGNORED_HANDLES_BIT;
+        }
+
+#if !defined(HOST_BUILD) && defined(VK_USE_PLATFORM_ANDROID_KHR)
+        if (mFeatureInfo->hasVirtioGpuNext) {
+            ALOGD("%s: has virtio-gpu-next; create hostmem rendernode\n", __func__);
+            mRendernodeFd = drmOpenRender(128 /* RENDERNODE_MINOR */);
+        }
+#endif
+    }
+
+    void setThreadingCallbacks(const ResourceTracker::ThreadingCallbacks& callbacks) {
+        mThreadingCallbacks = callbacks;
     }
 
     bool hostSupportsVulkan() const {
@@ -572,11 +658,20 @@
         return mHostVisibleMemoryVirtInfo.virtualizationSupported;
     }
 
+    uint32_t getStreamFeatures() const {
+        return mStreamFeatureBits;
+    }
+
     bool supportsDeferredCommands() const {
         if (!mFeatureInfo) return false;
         return mFeatureInfo->hasDeferredVulkanCommands;
     }
 
+    bool supportsCreateResourcesWithRequirements() const {
+        if (!mFeatureInfo) return false;
+        return mFeatureInfo->hasVulkanCreateResourcesWithRequirements;
+    }
+
     int getHostInstanceExtensionIndex(const std::string& extName) const {
         int i = 0;
         for (const auto& prop : mHostInstanceExtensions) {
@@ -722,6 +817,7 @@
 #ifdef VK_USE_PLATFORM_ANDROID_KHR
             "VK_KHR_external_semaphore_capabilities",
             "VK_KHR_external_memory_capabilities",
+            "VK_KHR_external_fence_capabilities",
 #endif
             // TODO:
             // VK_KHR_external_memory_capabilities
@@ -754,9 +850,6 @@
         }
 
         VkExtensionProperties anbExtProps[] = {
-#ifdef VK_USE_PLATFORM_ANDROID_KHR
-            { "VK_ANDROID_native_buffer", 7 },
-#endif
 #ifdef VK_USE_PLATFORM_FUCHSIA
             { "VK_KHR_external_memory_capabilities", 1},
             { "VK_KHR_external_semaphore_capabilities", 1},
@@ -767,17 +860,43 @@
             filteredExts.push_back(anbExtProp);
         }
 
-        if (pPropertyCount) {
-            *pPropertyCount = filteredExts.size();
-        }
+        // Spec:
+        //
+        // https://www.khronos.org/registry/vulkan/specs/1.1-extensions/man/html/vkEnumerateInstanceExtensionProperties.html
+        //
+        // If pProperties is NULL, then the number of extensions properties
+        // available is returned in pPropertyCount. Otherwise, pPropertyCount
+        // must point to a variable set by the user to the number of elements
+        // in the pProperties array, and on return the variable is overwritten
+        // with the number of structures actually written to pProperties. If
+        // pPropertyCount is less than the number of extension properties
+        // available, at most pPropertyCount structures will be written. If
+        // pPropertyCount is smaller than the number of extensions available,
+        // VK_INCOMPLETE will be returned instead of VK_SUCCESS, to indicate
+        // that not all the available properties were returned.
+        //
+        // pPropertyCount must be a valid pointer to a uint32_t value
+        if (!pPropertyCount) return VK_ERROR_INITIALIZATION_FAILED;
 
-        if (pPropertyCount && pProperties) {
-            for (size_t i = 0; i < *pPropertyCount; ++i) {
+        if (!pProperties) {
+            *pPropertyCount = (uint32_t)filteredExts.size();
+            return VK_SUCCESS;
+        } else {
+            auto actualExtensionCount = (uint32_t)filteredExts.size();
+            if (*pPropertyCount > actualExtensionCount) {
+              *pPropertyCount = actualExtensionCount;
+            }
+
+            for (uint32_t i = 0; i < *pPropertyCount; ++i) {
                 pProperties[i] = filteredExts[i];
             }
-        }
 
-        return VK_SUCCESS;
+            if (actualExtensionCount > *pPropertyCount) {
+                return VK_INCOMPLETE;
+            }
+
+            return VK_SUCCESS;
+        }
     }
 
     VkResult on_vkEnumerateDeviceExtensionProperties(
@@ -790,18 +909,23 @@
 
         std::vector<const char*> allowedExtensionNames = {
             "VK_KHR_maintenance1",
+            "VK_KHR_maintenance2",
+            "VK_KHR_maintenance3",
             "VK_KHR_get_memory_requirements2",
             "VK_KHR_dedicated_allocation",
             "VK_KHR_bind_memory2",
             "VK_KHR_sampler_ycbcr_conversion",
+            "VK_KHR_shader_float16_int8",
+            "VK_AMD_gpu_shader_half_float",
+            "VK_NV_shader_subgroup_partitioned",
 #ifdef VK_USE_PLATFORM_ANDROID_KHR
             "VK_KHR_external_semaphore",
             "VK_KHR_external_semaphore_fd",
             // "VK_KHR_external_semaphore_win32", not exposed because it's translated to fd
             "VK_KHR_external_memory",
+            "VK_KHR_external_fence",
+            "VK_KHR_external_fence_fd",
 #endif
-            // "VK_KHR_maintenance2",
-            // "VK_KHR_maintenance3",
             // TODO:
             // VK_KHR_external_memory_capabilities
         };
@@ -875,15 +999,21 @@
         bool posixExtMemAvailable =
             getHostDeviceExtensionIndex(
                 "VK_KHR_external_memory_fd") != -1;
+        bool extMoltenVkAvailable =
+            getHostDeviceExtensionIndex(
+                "VK_MVK_moltenvk") != -1;
 
         bool hostHasExternalMemorySupport =
-            win32ExtMemAvailable || posixExtMemAvailable;
+            win32ExtMemAvailable || posixExtMemAvailable || extMoltenVkAvailable;
 
         if (hostHasExternalMemorySupport) {
 #ifdef VK_USE_PLATFORM_ANDROID_KHR
             filteredExts.push_back({
                 "VK_ANDROID_external_memory_android_hardware_buffer", 7
             });
+            filteredExts.push_back({
+                "VK_EXT_queue_family_foreign", 1
+            });
 #endif
 #ifdef VK_USE_PLATFORM_FUCHSIA
             filteredExts.push_back({
@@ -892,18 +1022,51 @@
 #endif
         }
 
-        if (pPropertyCount) {
-            *pPropertyCount = filteredExts.size();
-        }
+        // Spec:
+        //
+        // https://www.khronos.org/registry/vulkan/specs/1.1-extensions/man/html/vkEnumerateDeviceExtensionProperties.html
+        //
+        // pPropertyCount is a pointer to an integer related to the number of
+        // extension properties available or queried, and is treated in the
+        // same fashion as the
+        // vkEnumerateInstanceExtensionProperties::pPropertyCount parameter.
+        //
+        // https://www.khronos.org/registry/vulkan/specs/1.1-extensions/man/html/vkEnumerateInstanceExtensionProperties.html
+        //
+        // If pProperties is NULL, then the number of extensions properties
+        // available is returned in pPropertyCount. Otherwise, pPropertyCount
+        // must point to a variable set by the user to the number of elements
+        // in the pProperties array, and on return the variable is overwritten
+        // with the number of structures actually written to pProperties. If
+        // pPropertyCount is less than the number of extension properties
+        // available, at most pPropertyCount structures will be written. If
+        // pPropertyCount is smaller than the number of extensions available,
+        // VK_INCOMPLETE will be returned instead of VK_SUCCESS, to indicate
+        // that not all the available properties were returned.
+        //
+        // pPropertyCount must be a valid pointer to a uint32_t value
 
-        if (pPropertyCount && pProperties) {
-            for (size_t i = 0; i < *pPropertyCount; ++i) {
+        if (!pPropertyCount) return VK_ERROR_INITIALIZATION_FAILED;
+
+        if (!pProperties) {
+            *pPropertyCount = (uint32_t)filteredExts.size();
+            return VK_SUCCESS;
+        } else {
+            auto actualExtensionCount = (uint32_t)filteredExts.size();
+            if (*pPropertyCount > actualExtensionCount) {
+              *pPropertyCount = actualExtensionCount;
+            }
+
+            for (uint32_t i = 0; i < *pPropertyCount; ++i) {
                 pProperties[i] = filteredExts[i];
             }
+
+            if (actualExtensionCount > *pPropertyCount) {
+                return VK_INCOMPLETE;
+            }
+
+            return VK_SUCCESS;
         }
-
-
-        return VK_SUCCESS;
     }
 
     VkResult on_vkEnumeratePhysicalDevices(
@@ -919,18 +1082,26 @@
 
         AutoLock lock(mLock);
 
+        // When this function is called, we actually need to do two things:
+        // - Get full information about physical devices from the host,
+        // even if the guest did not ask for it
+        // - Serve the guest query according to the spec:
+        //
+        // https://www.khronos.org/registry/vulkan/specs/1.1-extensions/man/html/vkEnumeratePhysicalDevices.html
+
         auto it = info_VkInstance.find(instance);
 
         if (it == info_VkInstance.end()) return VK_ERROR_INITIALIZATION_FAILED;
 
         auto& info = it->second;
 
+        // Get the full host information here if it doesn't exist already.
         if (info.physicalDevices.empty()) {
-            uint32_t physdevCount = 0;
+            uint32_t hostPhysicalDeviceCount = 0;
 
             lock.unlock();
             VkResult countRes = enc->vkEnumeratePhysicalDevices(
-                instance, &physdevCount, nullptr);
+                instance, &hostPhysicalDeviceCount, nullptr);
             lock.lock();
 
             if (countRes != VK_SUCCESS) {
@@ -939,11 +1110,11 @@
                 return countRes;
             }
 
-            info.physicalDevices.resize(physdevCount);
+            info.physicalDevices.resize(hostPhysicalDeviceCount);
 
             lock.unlock();
             VkResult enumRes = enc->vkEnumeratePhysicalDevices(
-                instance, &physdevCount, info.physicalDevices.data());
+                instance, &hostPhysicalDeviceCount, info.physicalDevices.data());
             lock.lock();
 
             if (enumRes != VK_SUCCESS) {
@@ -953,16 +1124,41 @@
             }
         }
 
-        *pPhysicalDeviceCount = (uint32_t)info.physicalDevices.size();
+        // Serve the guest query according to the spec.
+        //
+        // https://www.khronos.org/registry/vulkan/specs/1.1-extensions/man/html/vkEnumeratePhysicalDevices.html
+        //
+        // If pPhysicalDevices is NULL, then the number of physical devices
+        // available is returned in pPhysicalDeviceCount. Otherwise,
+        // pPhysicalDeviceCount must point to a variable set by the user to the
+        // number of elements in the pPhysicalDevices array, and on return the
+        // variable is overwritten with the number of handles actually written
+        // to pPhysicalDevices. If pPhysicalDeviceCount is less than the number
+        // of physical devices available, at most pPhysicalDeviceCount
+        // structures will be written.  If pPhysicalDeviceCount is smaller than
+        // the number of physical devices available, VK_INCOMPLETE will be
+        // returned instead of VK_SUCCESS, to indicate that not all the
+        // available physical devices were returned.
 
-        if (pPhysicalDevices && *pPhysicalDeviceCount) {
-            memcpy(pPhysicalDevices,
-                   info.physicalDevices.data(),
-                   sizeof(VkPhysicalDevice) *
-                   info.physicalDevices.size());
+        if (!pPhysicalDevices) {
+            *pPhysicalDeviceCount = (uint32_t)info.physicalDevices.size();
+            return VK_SUCCESS;
+        } else {
+            uint32_t actualDeviceCount = (uint32_t)info.physicalDevices.size();
+            uint32_t toWrite = actualDeviceCount < *pPhysicalDeviceCount ? actualDeviceCount : *pPhysicalDeviceCount;
+
+            for (uint32_t i = 0; i < toWrite; ++i) {
+                pPhysicalDevices[i] = info.physicalDevices[i];
+            }
+
+            *pPhysicalDeviceCount = toWrite;
+
+            if (actualDeviceCount > *pPhysicalDeviceCount) {
+                return VK_INCOMPLETE;
+            }
+
+            return VK_SUCCESS;
         }
-
-        return VK_SUCCESS;
     }
 
     void on_vkGetPhysicalDeviceMemoryProperties(
@@ -973,7 +1169,7 @@
         initHostVisibleMemoryVirtualizationInfo(
             physdev,
             out,
-            mFeatureInfo->hasDirectMem,
+            mFeatureInfo.get(),
             &mHostVisibleMemoryVirtInfo);
 
         if (mHostVisibleMemoryVirtInfo.virtualizationSupported) {
@@ -989,7 +1185,7 @@
         initHostVisibleMemoryVirtualizationInfo(
             physdev,
             &out->memoryProperties,
-            mFeatureInfo->hasDirectMem,
+            mFeatureInfo.get(),
             &mHostVisibleMemoryVirtInfo);
 
         if (mHostVisibleMemoryVirtInfo.virtualizationSupported) {
@@ -1065,10 +1261,6 @@
                 destroyHostMemAlloc(enc, device, &block);
             }
         }
-
-        if (info.fence != VK_NULL_HANDLE) {
-            enc->vkDestroyFence(device, info.fence, nullptr);
-        }
     }
 
     VkResult on_vkGetAndroidHardwareBufferPropertiesANDROID(
@@ -1076,7 +1268,10 @@
         VkDevice device,
         const AHardwareBuffer* buffer,
         VkAndroidHardwareBufferPropertiesANDROID* pProperties) {
+        auto grallocHelper =
+            mThreadingCallbacks.hostConnectionGetFunc()->grallocHelper();
         return getAndroidHardwareBufferPropertiesANDROID(
+            grallocHelper,
             &mHostVisibleMemoryVirtInfo,
             device, buffer, pProperties);
     }
@@ -1161,9 +1356,6 @@
         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);
 
@@ -1297,7 +1489,7 @@
                                    fuchsia::sysmem::vulkanUsageTransferSrc |
                                    fuchsia::sysmem::vulkanUsageTransferDst |
                                    fuchsia::sysmem::vulkanUsageSampled;
-        constraints.min_buffer_count_for_camping = 1;
+        constraints.min_buffer_count = 1;
         constraints.has_buffer_memory_constraints = true;
         fuchsia::sysmem::BufferMemoryConstraints& buffer_constraints =
             constraints.buffer_memory_constraints;
@@ -1305,10 +1497,12 @@
         buffer_constraints.max_size_bytes = 0xffffffff;
         buffer_constraints.physically_contiguous_required = false;
         buffer_constraints.secure_required = false;
-        buffer_constraints.secure_permitted = false;
         buffer_constraints.ram_domain_supported = false;
         buffer_constraints.cpu_domain_supported = false;
-        buffer_constraints.gpu_domain_supported = true;
+        buffer_constraints.inaccessible_domain_supported = true;
+        buffer_constraints.heap_permitted_count = 1;
+        buffer_constraints.heap_permitted[0] =
+            fuchsia::sysmem::HeapType::GOLDFISH_DEVICE_LOCAL;
         constraints.image_format_constraints_count = 1;
         fuchsia::sysmem::ImageFormatConstraints& image_constraints =
             constraints.image_format_constraints[0];
@@ -1461,11 +1655,67 @@
 
             uint64_t directMappedAddr = 0;
 
-            mLock.unlock();
-            VkResult directMapResult =
-                enc->vkMapMemoryIntoAddressSpaceGOOGLE(
-                    device, hostMemAlloc.memory, &directMappedAddr);
-            mLock.lock();
+
+            VkResult directMapResult = VK_SUCCESS;
+            if (mFeatureInfo->hasDirectMem) {
+                mLock.unlock();
+                directMapResult =
+                    enc->vkMapMemoryIntoAddressSpaceGOOGLE(
+                            device, hostMemAlloc.memory, &directMappedAddr);
+                mLock.lock();
+            } else if (mFeatureInfo->hasVirtioGpuNext) {
+#if !defined(HOST_BUILD) && defined(VK_USE_PLATFORM_ANDROID_KHR)
+                uint64_t hvaSizeId[3];
+
+                mLock.unlock();
+                enc->vkGetMemoryHostAddressInfoGOOGLE(
+                        device, hostMemAlloc.memory,
+                        &hvaSizeId[0], &hvaSizeId[1], &hvaSizeId[2]);
+                ALOGD("%s: hvaOff, size: 0x%llx 0x%llx id: 0x%llx\n", __func__,
+                        (unsigned long long)hvaSizeId[0],
+                        (unsigned long long)hvaSizeId[1],
+                        (unsigned long long)hvaSizeId[2]);
+                mLock.lock();
+
+                struct drm_virtgpu_resource_create_v2 drm_rc_v2 = { 0 };
+                drm_rc_v2.args = (uint64_t)&hvaSizeId[2];
+                drm_rc_v2.args_size = sizeof(uint64_t);
+                drm_rc_v2.size = hvaSizeId[1];
+                drm_rc_v2.flags = VIRTGPU_RESOURCE_TYPE_HOST;
+
+                int res = drmIoctl(
+                    mRendernodeFd, DRM_IOCTL_VIRTGPU_RESOURCE_CREATE_V2, &drm_rc_v2);
+
+                if (res) {
+                    ALOGE("%s: Failed to resource create v2: sterror: %s errno: %d\n", __func__,
+                            strerror(errno), errno);
+                    abort();
+                }
+
+                struct drm_virtgpu_map map_info = {
+                    .handle = drm_rc_v2.bo_handle,
+                };
+
+                res = drmIoctl(mRendernodeFd, DRM_IOCTL_VIRTGPU_MAP, &map_info);
+                if (res) {
+                    ALOGE("%s: Failed to virtgpu map: sterror: %s errno: %d\n", __func__,
+                            strerror(errno), errno);
+                    abort();
+                }
+
+                directMappedAddr = (uint64_t)(uintptr_t)
+                    mmap64(0, hvaSizeId[1], PROT_WRITE, MAP_SHARED, mRendernodeFd, map_info.offset);
+
+                if (!directMappedAddr) {
+                    ALOGE("%s: mmap of virtio gpu resource failed\n", __func__);
+                    abort();
+                }
+
+                // add the host's page offset
+                directMappedAddr += (uint64_t)(uintptr_t)(hvaSizeId[0]) & (PAGE_SIZE - 1);
+				directMapResult = VK_SUCCESS;
+#endif // VK_USE_PLATFORM_ANDROID_KHR
+            }
 
             if (directMapResult != VK_SUCCESS) {
                 hostMemAlloc.initialized = true;
@@ -1662,16 +1912,15 @@
             ahw = importAhbInfoPtr->buffer;
             // We still need to acquire the AHardwareBuffer.
             importAndroidHardwareBuffer(
+                mThreadingCallbacks.hostConnectionGetFunc()->grallocHelper(),
                 importAhbInfoPtr, nullptr);
         }
 
         if (ahw) {
-            ALOGD("%s: Import AHardwareBulffer", __func__);
-            const native_handle_t *handle =
-                AHardwareBuffer_getNativeHandle(ahw);
-            const cb_handle_t* cb_handle =
-                reinterpret_cast<const cb_handle_t*>(handle);
-            importCbInfo.colorBuffer = cb_handle->hostHandle;
+            ALOGD("%s: Import AHardwareBuffer", __func__);
+            importCbInfo.colorBuffer =
+                mThreadingCallbacks.hostConnectionGetFunc()->grallocHelper()->
+                    getHostHandle(AHardwareBuffer_getNativeHandle(ahw));
             vk_append_struct(&structChainIter, &importCbInfo);
         }
 
@@ -1704,9 +1953,7 @@
         }
 
 #ifdef VK_USE_PLATFORM_FUCHSIA
-        if (vmo_handle == ZX_HANDLE_INVALID &&
-            !isHostVisibleMemoryTypeIndexForGuest(
-                &mHostVisibleMemoryVirtInfo, finalAllocInfo.memoryTypeIndex)) {
+        if (exportVmo) {
             bool hasDedicatedImage = dedicatedAllocInfoPtr &&
                 (dedicatedAllocInfoPtr->image != VK_NULL_HANDLE);
             VkImageCreateInfo imageCreateInfo = {};
@@ -1721,7 +1968,10 @@
                 imageCreateInfo = imageInfo.createInfo;
             }
 
-            if (imageCreateInfo.usage & VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT) {
+            if (imageCreateInfo.usage & (VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT |
+                                         VK_IMAGE_USAGE_TRANSFER_DST_BIT |
+                                         VK_IMAGE_USAGE_TRANSFER_SRC_BIT |
+                                         VK_IMAGE_USAGE_SAMPLED_BIT)) {
                 fuchsia::sysmem::BufferCollectionTokenSyncPtr token;
                 zx_status_t status = mSysmemAllocator->AllocateSharedCollection(
                     token.NewRequest());
@@ -1757,18 +2007,21 @@
 
                 collection->Close();
 
-                zx_handle_t vmo_copy;
-                status = zx_handle_duplicate(vmo_handle, ZX_RIGHT_SAME_RIGHTS, &vmo_copy);
+                zx::vmo vmo_copy;
+                status = zx_handle_duplicate(vmo_handle,
+                                             ZX_RIGHT_SAME_RIGHTS,
+                                             vmo_copy.reset_and_get_address());
                 if (status != ZX_OK) {
                     ALOGE("Failed to duplicate VMO: %d", status);
                     abort();
                 }
-                status = fuchsia_hardware_goldfish_control_DeviceCreateColorBuffer(
-                    mControlDevice,
-                    vmo_copy,
+                // TODO(reveman): Use imageCreateInfo.format to determine color
+                // buffer format.
+                status = mControlDevice->CreateColorBuffer(
+                    std::move(vmo_copy),
                     imageCreateInfo.extent.width,
                     imageCreateInfo.extent.height,
-                    fuchsia_hardware_goldfish_control_FormatType_BGRA,
+                    fuchsia::hardware::goldfish::ColorBufferFormatType::BGRA,
                     &status2);
                 if (status != ZX_OK || status2 != ZX_OK) {
                     ALOGE("CreateColorBuffer failed: %d:%d", status, status2);
@@ -1778,17 +2031,17 @@
         }
 
         if (vmo_handle != ZX_HANDLE_INVALID) {
-            zx_handle_t vmo_copy;
+            zx::vmo vmo_copy;
             zx_status_t status = zx_handle_duplicate(vmo_handle,
                                                      ZX_RIGHT_SAME_RIGHTS,
-                                                     &vmo_copy);
+                                                     vmo_copy.reset_and_get_address());
             if (status != ZX_OK) {
                 ALOGE("Failed to duplicate VMO: %d", status);
                 abort();
             }
             zx_status_t status2 = ZX_OK;
-            status = fuchsia_hardware_goldfish_control_DeviceGetColorBuffer(
-                mControlDevice, vmo_copy, &status2, &importCbInfo.colorBuffer);
+            status = mControlDevice->GetColorBuffer(
+                std::move(vmo_copy), &status2, &importCbInfo.colorBuffer);
             if (status != ZX_OK || status2 != ZX_OK) {
                 ALOGE("GetColorBuffer failed: %d:%d", status, status2);
             }
@@ -1796,8 +2049,6 @@
         }
 #endif
 
-        // TODO if (exportVmo) { }
-
         if (!isHostVisibleMemoryTypeIndexForGuest(
                 &mHostVisibleMemoryVirtInfo,
                 finalAllocInfo.memoryTypeIndex)) {
@@ -2026,12 +2277,10 @@
         dedicatedReqs->requiresDedicatedAllocation = VK_TRUE;
     }
 
-    void transformImageMemoryRequirementsForGuest(
+    void transformImageMemoryRequirementsForGuestLocked(
         VkImage image,
         VkMemoryRequirements* reqs) {
 
-        AutoLock lock(mLock);
-
         auto it = info_VkImage.find(image);
         if (it == info_VkImage.end()) return;
 
@@ -2040,18 +2289,16 @@
         if (!info.external ||
             !info.externalCreateInfo.handleTypes) {
             transformNonExternalResourceMemoryRequirementsForGuest(reqs);
-            return;
+        } else {
+            transformExternalResourceMemoryRequirementsForGuest(reqs);
         }
-
-        transformExternalResourceMemoryRequirementsForGuest(reqs);
+        setMemoryRequirementsForSysmemBackedImage(image, reqs);
     }
 
-    void transformBufferMemoryRequirementsForGuest(
+    void transformBufferMemoryRequirementsForGuestLocked(
         VkBuffer buffer,
         VkMemoryRequirements* reqs) {
 
-        AutoLock lock(mLock);
-
         auto it = info_VkBuffer.find(buffer);
         if (it == info_VkBuffer.end()) return;
 
@@ -2081,11 +2328,14 @@
             !info.externalCreateInfo.handleTypes) {
             transformNonExternalResourceMemoryRequirementsForGuest(
                 &reqs2->memoryRequirements);
+            setMemoryRequirementsForSysmemBackedImage(image, &reqs2->memoryRequirements);
             return;
         }
 
         transformExternalResourceMemoryRequirementsForGuest(&reqs2->memoryRequirements);
 
+        setMemoryRequirementsForSysmemBackedImage(image, &reqs2->memoryRequirements);
+
         VkMemoryDedicatedRequirements* dedicatedReqs =
             vk_find_struct<VkMemoryDedicatedRequirements>(reqs2);
 
@@ -2172,50 +2422,48 @@
 #ifdef VK_USE_PLATFORM_FUCHSIA
         const VkBufferCollectionImageCreateInfoFUCHSIA* extBufferCollectionPtr =
             vk_find_struct<VkBufferCollectionImageCreateInfoFUCHSIA>(pCreateInfo);
+        bool isSysmemBackedMemory = false;
         if (extBufferCollectionPtr) {
             auto collection = reinterpret_cast<fuchsia::sysmem::BufferCollectionSyncPtr*>(
                 extBufferCollectionPtr->collection);
             uint32_t index = extBufferCollectionPtr->index;
-            zx_handle_t vmo_handle = ZX_HANDLE_INVALID;
+            zx::vmo vmo;
 
             fuchsia::sysmem::BufferCollectionInfo_2 info;
             zx_status_t status2;
             zx_status_t status = (*collection)->WaitForBuffersAllocated(&status2, &info);
             if (status == ZX_OK && status2 == ZX_OK) {
                 if (index < info.buffer_count) {
-                    vmo_handle = info.buffers[index].vmo.release();
+                    vmo = std::move(info.buffers[index].vmo);
                 }
             } else {
                 ALOGE("WaitForBuffersAllocated failed: %d %d", status, status2);
             }
 
-            if (vmo_handle != ZX_HANDLE_INVALID) {
+            if (vmo.is_valid()) {
                 zx_status_t status2 = ZX_OK;
-                status = fuchsia_hardware_goldfish_control_DeviceCreateColorBuffer(
-                    mControlDevice,
-                    vmo_handle,
+                status = mControlDevice->CreateColorBuffer(
+                    std::move(vmo),
                     localCreateInfo.extent.width,
                     localCreateInfo.extent.height,
-                    fuchsia_hardware_goldfish_control_FormatType_BGRA,
+                    fuchsia::hardware::goldfish::ColorBufferFormatType::BGRA,
                     &status2);
-                if (status != ZX_OK || status2 != ZX_OK) {
+                if (status != ZX_OK || (status2 != ZX_OK && status2 != ZX_ERR_ALREADY_EXISTS)) {
                     ALOGE("CreateColorBuffer failed: %d:%d", status, status2);
                 }
             }
-        }
-
-        // Allow external memory for all color attachments on fuchsia.
-        if (localCreateInfo.usage & VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT) {
-            if (!extImgCiPtr) {
-                localExtImgCi.sType = VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO;
-                localExtImgCi.pNext = nullptr;
-                localExtImgCi.handleTypes = ~0; // handle type just needs to be non-zero
-                extImgCiPtr = &localExtImgCi;   // no vk_append_struct required
-            }
+            isSysmemBackedMemory = true;
         }
 #endif
 
-        VkResult res = enc->vkCreateImage(device, &localCreateInfo, pAllocator, pImage);
+        VkResult res;
+        VkMemoryRequirements memReqs;
+
+        if (supportsCreateResourcesWithRequirements()) {
+            res = enc->vkCreateImageWithRequirementsGOOGLE(device, &localCreateInfo, pAllocator, pImage, &memReqs);
+        } else {
+            res = enc->vkCreateImage(device, &localCreateInfo, pAllocator, pImage);
+        }
 
         if (res != VK_SUCCESS) return res;
 
@@ -2230,11 +2478,25 @@
         info.createInfo = *pCreateInfo;
         info.createInfo.pNext = nullptr;
 
-        if (!extImgCiPtr) return res;
+        if (supportsCreateResourcesWithRequirements()) {
+            info.baseRequirementsKnown = true;
+        }
 
-        info.external = true;
-        info.externalCreateInfo = *extImgCiPtr;
+        if (extImgCiPtr) {
+            info.external = true;
+            info.externalCreateInfo = *extImgCiPtr;
+        }
 
+#ifdef VK_USE_PLATFORM_FUCHSIA
+        if (isSysmemBackedMemory) {
+            info.isSysmemBackedMemory = true;
+        }
+#endif
+
+        if (info.baseRequirementsKnown) {
+            transformImageMemoryRequirementsForGuestLocked(*pImage, &memReqs);
+            info.baseRequirements = memReqs;
+        }
         return res;
     }
 
@@ -2251,7 +2513,15 @@
         const VkExternalFormatANDROID* extFormatAndroidPtr =
             vk_find_struct<VkExternalFormatANDROID>(pCreateInfo);
         if (extFormatAndroidPtr) {
-            if (extFormatAndroidPtr->externalFormat) {
+            if (extFormatAndroidPtr->externalFormat == AHARDWAREBUFFER_FORMAT_R5G6B5_UNORM) {
+                // We don't support external formats on host and it causes RGB565
+                // to fail in CtsGraphicsTestCases android.graphics.cts.BasicVulkanGpuTest
+                // when passed as an external format.
+                // We may consider doing this for all external formats.
+                // See b/134771579.
+                *pYcbcrConversion = VK_YCBCR_CONVERSION_DO_NOTHING;
+                return VK_SUCCESS;
+            } else if (extFormatAndroidPtr->externalFormat) {
                 localCreateInfo.format =
                     vk_format_from_android(extFormatAndroidPtr->externalFormat);
             }
@@ -2259,8 +2529,25 @@
 #endif
 
         VkEncoder* enc = (VkEncoder*)context;
-        return enc->vkCreateSamplerYcbcrConversion(
+        VkResult res = enc->vkCreateSamplerYcbcrConversion(
             device, &localCreateInfo, pAllocator, pYcbcrConversion);
+
+        if (*pYcbcrConversion == VK_YCBCR_CONVERSION_DO_NOTHING) {
+            ALOGE("FATAL: vkCreateSamplerYcbcrConversion returned a reserved value (VK_YCBCR_CONVERSION_DO_NOTHING)");
+            abort();
+        }
+        return res;
+    }
+
+    void on_vkDestroySamplerYcbcrConversion(
+        void* context,
+        VkDevice device,
+        VkSamplerYcbcrConversion ycbcrConversion,
+        const VkAllocationCallbacks* pAllocator) {
+        VkEncoder* enc = (VkEncoder*)context;
+        if (ycbcrConversion != VK_YCBCR_CONVERSION_DO_NOTHING) {
+            enc->vkDestroySamplerYcbcrConversion(device, ycbcrConversion, pAllocator);
+        }
     }
 
     VkResult on_vkCreateSamplerYcbcrConversionKHR(
@@ -2276,7 +2563,15 @@
         const VkExternalFormatANDROID* extFormatAndroidPtr =
             vk_find_struct<VkExternalFormatANDROID>(pCreateInfo);
         if (extFormatAndroidPtr) {
-            if (extFormatAndroidPtr->externalFormat) {
+            if (extFormatAndroidPtr->externalFormat == AHARDWAREBUFFER_FORMAT_R5G6B5_UNORM) {
+                // We don't support external formats on host and it causes RGB565
+                // to fail in CtsGraphicsTestCases android.graphics.cts.BasicVulkanGpuTest
+                // when passed as an external format.
+                // We may consider doing this for all external formats.
+                // See b/134771579.
+                *pYcbcrConversion = VK_YCBCR_CONVERSION_DO_NOTHING;
+                return VK_SUCCESS;
+            } else if (extFormatAndroidPtr->externalFormat) {
                 localCreateInfo.format =
                     vk_format_from_android(extFormatAndroidPtr->externalFormat);
             }
@@ -2284,8 +2579,409 @@
 #endif
 
         VkEncoder* enc = (VkEncoder*)context;
-        return enc->vkCreateSamplerYcbcrConversionKHR(
+        VkResult res = enc->vkCreateSamplerYcbcrConversionKHR(
             device, &localCreateInfo, pAllocator, pYcbcrConversion);
+
+        if (*pYcbcrConversion == VK_YCBCR_CONVERSION_DO_NOTHING) {
+            ALOGE("FATAL: vkCreateSamplerYcbcrConversionKHR returned a reserved value (VK_YCBCR_CONVERSION_DO_NOTHING)");
+            abort();
+        }
+        return res;
+    }
+
+    void on_vkDestroySamplerYcbcrConversionKHR(
+        void* context,
+        VkDevice device,
+        VkSamplerYcbcrConversion ycbcrConversion,
+        const VkAllocationCallbacks* pAllocator) {
+        VkEncoder* enc = (VkEncoder*)context;
+        if (ycbcrConversion != VK_YCBCR_CONVERSION_DO_NOTHING) {
+            enc->vkDestroySamplerYcbcrConversionKHR(device, ycbcrConversion, pAllocator);
+        }
+    }
+
+    VkResult on_vkCreateSampler(
+        void* context, VkResult,
+        VkDevice device,
+        const VkSamplerCreateInfo* pCreateInfo,
+        const VkAllocationCallbacks* pAllocator,
+        VkSampler* pSampler) {
+
+        VkSamplerCreateInfo localCreateInfo = vk_make_orphan_copy(*pCreateInfo);
+        vk_struct_chain_iterator structChainIter = vk_make_chain_iterator(&localCreateInfo);
+
+#ifdef VK_USE_PLATFORM_ANDROID_KHR
+        VkSamplerYcbcrConversionInfo localVkSamplerYcbcrConversionInfo;
+        const VkSamplerYcbcrConversionInfo* samplerYcbcrConversionInfo =
+            vk_find_struct<VkSamplerYcbcrConversionInfo>(pCreateInfo);
+        if (samplerYcbcrConversionInfo) {
+            if (samplerYcbcrConversionInfo->conversion != VK_YCBCR_CONVERSION_DO_NOTHING) {
+                localVkSamplerYcbcrConversionInfo = vk_make_orphan_copy(*samplerYcbcrConversionInfo);
+                vk_append_struct(&structChainIter, &localVkSamplerYcbcrConversionInfo);
+            }
+        }
+#endif
+
+        VkEncoder* enc = (VkEncoder*)context;
+        return enc->vkCreateSampler(device, &localCreateInfo, pAllocator, pSampler);
+    }
+
+    void on_vkGetPhysicalDeviceExternalFenceProperties(
+        void* context,
+        VkPhysicalDevice physicalDevice,
+        const VkPhysicalDeviceExternalFenceInfo* pExternalFenceInfo,
+        VkExternalFenceProperties* pExternalFenceProperties) {
+
+        (void)context;
+        (void)physicalDevice;
+
+        pExternalFenceProperties->exportFromImportedHandleTypes = 0;
+        pExternalFenceProperties->compatibleHandleTypes = 0;
+        pExternalFenceProperties->externalFenceFeatures = 0;
+
+        bool syncFd =
+            pExternalFenceInfo->handleType &
+            VK_EXTERNAL_FENCE_HANDLE_TYPE_SYNC_FD_BIT;
+
+        if (!syncFd) {
+            return;
+        }
+
+#ifdef VK_USE_PLATFORM_ANDROID_KHR
+        pExternalFenceProperties->exportFromImportedHandleTypes =
+            VK_EXTERNAL_FENCE_HANDLE_TYPE_SYNC_FD_BIT;
+        pExternalFenceProperties->compatibleHandleTypes =
+            VK_EXTERNAL_FENCE_HANDLE_TYPE_SYNC_FD_BIT;
+        pExternalFenceProperties->externalFenceFeatures =
+            VK_EXTERNAL_FENCE_FEATURE_IMPORTABLE_BIT |
+            VK_EXTERNAL_FENCE_FEATURE_EXPORTABLE_BIT;
+
+        ALOGD("%s: asked for sync fd, set the features\n", __func__);
+#endif
+    }
+
+    VkResult on_vkCreateFence(
+        void* context,
+        VkResult input_result,
+        VkDevice device,
+        const VkFenceCreateInfo* pCreateInfo,
+        const VkAllocationCallbacks* pAllocator, VkFence* pFence) {
+
+        VkEncoder* enc = (VkEncoder*)context;
+        VkFenceCreateInfo finalCreateInfo = *pCreateInfo;
+
+        const VkExportFenceCreateInfo* exportFenceInfoPtr =
+            vk_find_struct<VkExportFenceCreateInfo>(pCreateInfo);
+
+#ifdef VK_USE_PLATFORM_ANDROID_KHR
+        bool exportSyncFd =
+            exportFenceInfoPtr &&
+            (exportFenceInfoPtr->handleTypes &
+             VK_EXTERNAL_FENCE_HANDLE_TYPE_SYNC_FD_BIT);
+
+        if (exportSyncFd) {
+            ALOGV("%s: exporting sync fd, do not send pNext to host\n", __func__);
+            finalCreateInfo.pNext = nullptr;
+        }
+#endif
+
+        input_result = enc->vkCreateFence(
+            device, &finalCreateInfo, pAllocator, pFence);
+
+        if (input_result != VK_SUCCESS) return input_result;
+
+#ifdef VK_USE_PLATFORM_ANDROID_KHR
+        if (exportSyncFd) {
+            ALOGV("%s: ensure sync device\n", __func__);
+            ensureSyncDeviceFd();
+
+            ALOGV("%s: getting fence info\n", __func__);
+            AutoLock lock(mLock);
+            auto it = info_VkFence.find(*pFence);
+
+            if (it == info_VkFence.end())
+                return VK_ERROR_INITIALIZATION_FAILED;
+
+            auto& info = it->second;
+
+            info.external = true;
+            info.exportFenceCreateInfo = *exportFenceInfoPtr;
+            ALOGV("%s: info set (fence still -1). fence: %p\n", __func__, (void*)(*pFence));
+            // syncFd is still -1 because we expect user to explicitly
+            // export it via vkGetFenceFdKHR
+        }
+#endif
+
+        return input_result;
+    }
+
+    void on_vkDestroyFence(
+        void* context,
+        VkDevice device,
+        VkFence fence,
+        const VkAllocationCallbacks* pAllocator) {
+        VkEncoder* enc = (VkEncoder*)context;
+        enc->vkDestroyFence(device, fence, pAllocator);
+    }
+
+    VkResult on_vkResetFences(
+        void* context,
+        VkResult,
+        VkDevice device,
+        uint32_t fenceCount,
+        const VkFence* pFences) {
+
+        VkEncoder* enc = (VkEncoder*)context;
+        VkResult res = enc->vkResetFences(device, fenceCount, pFences);
+
+        if (res != VK_SUCCESS) return res;
+
+        if (!fenceCount) return res;
+
+        // Permanence: temporary
+        // on fence reset, close the fence fd
+        // and act like we need to GetFenceFdKHR/ImportFenceFdKHR again
+        AutoLock lock(mLock);
+        for (uint32_t i = 0; i < fenceCount; ++i) {
+            VkFence fence = pFences[i];
+            auto it = info_VkFence.find(fence);
+            auto& info = it->second;
+            if (!info.external) continue;
+
+#ifdef VK_USE_PLATFORM_ANDROID_KHR
+            if (info.syncFd >= 0) {
+                ALOGV("%s: resetting fence. make fd -1\n", __func__);
+                goldfish_sync_signal(info.syncFd);
+                close(info.syncFd);
+                info.syncFd = -1;
+            }
+#endif
+        }
+
+        return res;
+    }
+
+    VkResult on_vkImportFenceFdKHR(
+        void* context,
+        VkResult,
+        VkDevice device,
+        const VkImportFenceFdInfoKHR* pImportFenceFdInfo) {
+
+        (void)context;
+        (void)device;
+        (void)pImportFenceFdInfo;
+
+        // Transference: copy
+        // meaning dup() the incoming fd
+
+        VkEncoder* enc = (VkEncoder*)context;
+
+        bool hasFence = pImportFenceFdInfo->fence != VK_NULL_HANDLE;
+
+        if (!hasFence) return VK_ERROR_OUT_OF_HOST_MEMORY;
+
+#ifdef VK_USE_PLATFORM_ANDROID_KHR
+
+        bool syncFdImport =
+            pImportFenceFdInfo->handleType & VK_EXTERNAL_FENCE_HANDLE_TYPE_SYNC_FD_BIT;
+
+        if (!syncFdImport) {
+            ALOGV("%s: VK_ERROR_OUT_OF_HOST_MEMORY: no sync fd import\n", __func__);
+            return VK_ERROR_OUT_OF_HOST_MEMORY;
+        }
+
+        AutoLock lock(mLock);
+        auto it = info_VkFence.find(pImportFenceFdInfo->fence);
+        if (it == info_VkFence.end()) {
+            ALOGV("%s: VK_ERROR_OUT_OF_HOST_MEMORY: no fence info\n", __func__);
+            return VK_ERROR_OUT_OF_HOST_MEMORY;
+        }
+
+        auto& info = it->second;
+
+        if (info.syncFd >= 0) {
+            ALOGV("%s: previous sync fd exists, close it\n", __func__);
+            goldfish_sync_signal(info.syncFd);
+            close(info.syncFd);
+        }
+
+        if (pImportFenceFdInfo->fd < 0) {
+            ALOGV("%s: import -1, set to -1 and exit\n", __func__);
+            info.syncFd = -1;
+        } else {
+            ALOGV("%s: import actual fd, dup and close()\n", __func__);
+            info.syncFd = dup(pImportFenceFdInfo->fd);
+            close(pImportFenceFdInfo->fd);
+        }
+        return VK_SUCCESS;
+#else
+        return VK_ERROR_OUT_OF_HOST_MEMORY;
+#endif
+    }
+
+    VkResult on_vkGetFenceFdKHR(
+        void* context,
+        VkResult,
+        VkDevice device,
+        const VkFenceGetFdInfoKHR* pGetFdInfo,
+        int* pFd) {
+
+        // export operation.
+        // first check if fence is signaled
+        // then if so, return -1
+        // else, queue work
+
+        VkEncoder* enc = (VkEncoder*)context;
+
+        bool hasFence = pGetFdInfo->fence != VK_NULL_HANDLE;
+
+        if (!hasFence) {
+            ALOGV("%s: VK_ERROR_OUT_OF_HOST_MEMORY: no fence\n", __func__);
+            return VK_ERROR_OUT_OF_HOST_MEMORY;
+        }
+
+#ifdef VK_USE_PLATFORM_ANDROID_KHR
+        bool syncFdExport =
+            pGetFdInfo->handleType & VK_EXTERNAL_FENCE_HANDLE_TYPE_SYNC_FD_BIT;
+
+        if (!syncFdExport) {
+            ALOGV("%s: VK_ERROR_OUT_OF_HOST_MEMORY: no sync fd fence\n", __func__);
+            return VK_ERROR_OUT_OF_HOST_MEMORY;
+        }
+
+        VkResult currentFenceStatus = enc->vkGetFenceStatus(device, pGetFdInfo->fence);
+
+        if (VK_SUCCESS == currentFenceStatus) { // Fence already signaled
+            ALOGV("%s: VK_SUCCESS: already signaled\n", __func__);
+            *pFd = -1;
+            return VK_SUCCESS;
+        }
+
+        if (VK_ERROR_DEVICE_LOST == currentFenceStatus) { // Other error
+            ALOGV("%s: VK_ERROR_DEVICE_LOST: Other error\n", __func__);
+            *pFd = -1;
+            return VK_ERROR_DEVICE_LOST;
+        }
+
+        if (VK_NOT_READY == currentFenceStatus) { // Fence unsignaled; create fd here
+            AutoLock lock(mLock);
+
+            auto it = info_VkFence.find(pGetFdInfo->fence);
+            if (it == info_VkFence.end()) {
+                ALOGV("%s: VK_ERROR_OUT_OF_HOST_MEMORY: no fence info\n", __func__);
+                return VK_ERROR_OUT_OF_HOST_MEMORY;
+            }
+
+            auto& info = it->second;
+
+            bool syncFdCreated =
+                info.external &&
+                (info.exportFenceCreateInfo.handleTypes &
+                 VK_EXTERNAL_FENCE_HANDLE_TYPE_SYNC_FD_BIT);
+
+            if (!syncFdCreated) {
+                ALOGV("%s: VK_ERROR_OUT_OF_HOST_MEMORY: no sync fd created\n", __func__);
+                return VK_ERROR_OUT_OF_HOST_MEMORY;
+            }
+
+            goldfish_sync_queue_work(
+                mSyncDeviceFd,
+                get_host_u64_VkFence(pGetFdInfo->fence) /* the handle */,
+                GOLDFISH_SYNC_VULKAN_SEMAPHORE_SYNC /* thread handle (doubling as type field) */,
+                pFd);
+            // relinquish ownership
+            info.syncFd = -1;
+            ALOGV("%s: got fd: %d\n", __func__, *pFd);
+            return VK_SUCCESS;
+        }
+        return VK_ERROR_DEVICE_LOST;
+#else
+        return VK_ERROR_OUT_OF_HOST_MEMORY;
+#endif
+    }
+
+    VkResult on_vkWaitForFences(
+        void* context,
+        VkResult,
+        VkDevice device,
+        uint32_t fenceCount,
+        const VkFence* pFences,
+        VkBool32 waitAll,
+        uint64_t timeout) {
+
+        VkEncoder* enc = (VkEncoder*)context;
+
+#ifdef VK_USE_PLATFORM_ANDROID_KHR
+        std::vector<VkFence> fencesExternal;
+        std::vector<int> fencesExternalWaitFds;
+        std::vector<VkFence> fencesNonExternal;
+
+        AutoLock lock(mLock);
+
+        for (uint32_t i = 0; i < fenceCount; ++i) {
+            auto it = info_VkFence.find(pFences[i]);
+            if (it == info_VkFence.end()) continue;
+            const auto& info = it->second;
+            if (info.syncFd >= 0) {
+                fencesExternal.push_back(pFences[i]);
+                fencesExternalWaitFds.push_back(info.syncFd);
+            } else {
+                fencesNonExternal.push_back(pFences[i]);
+            }
+        }
+
+        if (fencesExternal.empty()) {
+            // No need for work pool, just wait with host driver.
+            return enc->vkWaitForFences(
+                device, fenceCount, pFences, waitAll, timeout);
+        } else {
+            // Depending on wait any or wait all,
+            // schedule a wait group with waitAny/waitAll
+            std::vector<WorkPool::Task> tasks;
+
+            ALOGV("%s: scheduling ext waits\n", __func__);
+
+            for (auto fd : fencesExternalWaitFds) {
+                ALOGV("%s: wait on %d\n", __func__, fd);
+                tasks.push_back([fd] {
+                    sync_wait(fd, 3000);
+                    ALOGV("done waiting on fd %d\n", fd);
+                });
+            }
+
+            if (!fencesNonExternal.empty()) {
+                tasks.push_back([this,
+                                 fencesNonExternal /* copy of vector */,
+                                 device, waitAll, timeout] {
+                    auto hostConn = mThreadingCallbacks.hostConnectionGetFunc();
+                    auto vkEncoder = mThreadingCallbacks.vkEncoderGetFunc(hostConn);
+                    ALOGV("%s: vkWaitForFences to host\n", __func__);
+                    vkEncoder->vkWaitForFences(device, fencesNonExternal.size(), fencesNonExternal.data(), waitAll, timeout);
+                });
+            }
+
+            auto waitGroupHandle = mWorkPool.schedule(tasks);
+
+            // Convert timeout to microseconds from nanoseconds
+            bool waitRes = false;
+            if (waitAll) {
+                waitRes = mWorkPool.waitAll(waitGroupHandle, timeout / 1000);
+            } else {
+                waitRes = mWorkPool.waitAny(waitGroupHandle, timeout / 1000);
+            }
+
+            if (waitRes) {
+                ALOGV("%s: VK_SUCCESS\n", __func__);
+                return VK_SUCCESS;
+            } else {
+                ALOGV("%s: VK_TIMEOUT\n", __func__);
+                return VK_TIMEOUT;
+            }
+        }
+#else
+        return enc->vkWaitForFences(
+            device, fenceCount, pFences, waitAll, timeout);
+#endif
     }
 
     void on_vkDestroyImage(
@@ -2295,14 +2991,54 @@
         enc->vkDestroyImage(device, image, pAllocator);
     }
 
+    void setMemoryRequirementsForSysmemBackedImage(
+        VkImage image, VkMemoryRequirements *pMemoryRequirements) {
+#ifdef VK_USE_PLATFORM_FUCHSIA
+        auto it = info_VkImage.find(image);
+        if (it == info_VkImage.end()) return;
+        auto& info = it->second;
+        if (info.isSysmemBackedMemory) {
+            auto width = info.createInfo.extent.width;
+            auto height = info.createInfo.extent.height;
+            pMemoryRequirements->size = width * height * 4;
+        }
+#else
+        // Bypass "unused parameter" checks.
+        (void)image;
+        (void)pMemoryRequirements;
+#endif
+    }
+
     void on_vkGetImageMemoryRequirements(
         void *context, VkDevice device, VkImage image,
         VkMemoryRequirements *pMemoryRequirements) {
+
+        AutoLock lock(mLock);
+
+        auto it = info_VkImage.find(image);
+        if (it == info_VkImage.end()) return;
+
+        auto& info = it->second;
+
+        if (info.baseRequirementsKnown) {
+            *pMemoryRequirements = info.baseRequirements;
+            return;
+        }
+
+        lock.unlock();
+
         VkEncoder* enc = (VkEncoder*)context;
+
         enc->vkGetImageMemoryRequirements(
             device, image, pMemoryRequirements);
-        transformImageMemoryRequirementsForGuest(
+
+        lock.lock();
+
+        transformImageMemoryRequirementsForGuestLocked(
             image, pMemoryRequirements);
+
+        info.baseRequirementsKnown = true;
+        info.baseRequirements = *pMemoryRequirements;
     }
 
     void on_vkGetImageMemoryRequirements2(
@@ -2354,7 +3090,14 @@
         VkBuffer *pBuffer) {
         VkEncoder* enc = (VkEncoder*)context;
 
-        VkResult res = enc->vkCreateBuffer(device, pCreateInfo, pAllocator, pBuffer);
+        VkResult res;
+        VkMemoryRequirements memReqs;
+
+        if (supportsCreateResourcesWithRequirements()) {
+            res = enc->vkCreateBufferWithRequirementsGOOGLE(device, pCreateInfo, pAllocator, pBuffer, &memReqs);
+        } else {
+            res = enc->vkCreateBuffer(device, pCreateInfo, pAllocator, pBuffer);
+        }
 
         if (res != VK_SUCCESS) return res;
 
@@ -2368,13 +3111,22 @@
         info.createInfo = *pCreateInfo;
         info.createInfo.pNext = nullptr;
 
+        if (supportsCreateResourcesWithRequirements()) {
+            info.baseRequirementsKnown = true;
+        }
+
         const VkExternalMemoryBufferCreateInfo* extBufCi =
             vk_find_struct<VkExternalMemoryBufferCreateInfo>(pCreateInfo);
 
-        if (!extBufCi) return res;
+        if (extBufCi) {
+            info.external = true;
+            info.externalCreateInfo = *extBufCi;
+        }
 
-        info.external = true;
-        info.externalCreateInfo = *extBufCi;
+        if (info.baseRequirementsKnown) {
+            transformBufferMemoryRequirementsForGuestLocked(*pBuffer, &memReqs);
+            info.baseRequirements = memReqs;
+        }
 
         return res;
     }
@@ -2388,11 +3140,31 @@
 
     void on_vkGetBufferMemoryRequirements(
         void* context, VkDevice device, VkBuffer buffer, VkMemoryRequirements *pMemoryRequirements) {
+
+        AutoLock lock(mLock);
+
+        auto it = info_VkBuffer.find(buffer);
+        if (it == info_VkBuffer.end()) return;
+
+        auto& info = it->second;
+
+        if (info.baseRequirementsKnown) {
+            *pMemoryRequirements = info.baseRequirements;
+            return;
+        }
+
+        lock.unlock();
+
         VkEncoder* enc = (VkEncoder*)context;
         enc->vkGetBufferMemoryRequirements(
             device, buffer, pMemoryRequirements);
-        transformBufferMemoryRequirementsForGuest(
+
+        lock.lock();
+
+        transformBufferMemoryRequirementsForGuestLocked(
             buffer, pMemoryRequirements);
+        info.baseRequirementsKnown = true;
+        info.baseRequirements = *pMemoryRequirements;
     }
 
     void on_vkGetBufferMemoryRequirements2(
@@ -2623,10 +3395,10 @@
         VkQueue queue, uint32_t submitCount, const VkSubmitInfo* pSubmits, VkFence fence) {
 
         std::vector<VkSemaphore> pre_signal_semaphores;
+        std::vector<zx_handle_t> pre_signal_events;
+        std::vector<int> pre_signal_sync_fds;
         std::vector<zx_handle_t> post_wait_events;
         std::vector<int> post_wait_sync_fds;
-        VkDevice device = VK_NULL_HANDLE;
-        VkFence* pFence = nullptr;
 
         VkEncoder* enc = (VkEncoder*)context;
 
@@ -2639,18 +3411,13 @@
                     auto& semInfo = it->second;
 #ifdef VK_USE_PLATFORM_FUCHSIA
                     if (semInfo.eventHandle) {
-                        // Wait here instead of passing semaphore to host.
-                        zx_object_wait_one(semInfo.eventHandle,
-                                           ZX_EVENT_SIGNALED,
-                                           ZX_TIME_INFINITE,
-                                           nullptr);
+                        pre_signal_events.push_back(semInfo.eventHandle);
                         pre_signal_semaphores.push_back(pSubmits[i].pWaitSemaphores[j]);
                     }
 #endif
 #ifdef VK_USE_PLATFORM_ANDROID_KHR
                     if (semInfo.syncFd >= 0) {
-                        // Wait here instead of passing semaphore to host.
-                        sync_wait(semInfo.syncFd, 3000);
+                        pre_signal_sync_fds.push_back(semInfo.syncFd);
                         pre_signal_semaphores.push_back(pSubmits[i].pWaitSemaphores[j]);
                     }
 #endif
@@ -2663,15 +3430,11 @@
 #ifdef VK_USE_PLATFORM_FUCHSIA
                     if (semInfo.eventHandle) {
                         post_wait_events.push_back(semInfo.eventHandle);
-                        device = semInfo.device;
-                        pFence = &info_VkDevice[device].fence;
                     }
 #endif
 #ifdef VK_USE_PLATFORM_ANDROID_KHR
                     if (semInfo.syncFd >= 0) {
                         post_wait_sync_fds.push_back(semInfo.syncFd);
-                        device = semInfo.device;
-                        pFence = &info_VkDevice[device].fence;
                     }
 #endif
                 }
@@ -2679,7 +3442,36 @@
         }
         lock.unlock();
 
-        if (!pre_signal_semaphores.empty()) {
+        if (pre_signal_semaphores.empty()) {
+            input_result = enc->vkQueueSubmit(queue, submitCount, pSubmits, fence);
+            if (input_result != VK_SUCCESS) return input_result;
+        } else {
+            // Schedule waits on the OS external objects and
+            // signal the wait semaphores
+            // in a separate thread.
+            std::vector<WorkPool::Task> preSignalTasks;
+            std::vector<WorkPool::Task> preSignalQueueSubmitTasks;;
+#ifdef VK_USE_PLATFORM_FUCHSIA
+            for (auto event : pre_signal_events) {
+                preSignalTasks.push_back([event] {
+                    zx_object_wait_one(
+                        event,
+                        ZX_EVENT_SIGNALED,
+                        ZX_TIME_INFINITE,
+                        nullptr);
+                });
+            }
+#endif
+#ifdef VK_USE_PLATFORM_ANDROID_KHR
+            for (auto fd : pre_signal_sync_fds) {
+                preSignalTasks.push_back([fd] {
+                    sync_wait(fd, 3000);
+                });
+            }
+#endif
+            auto waitGroupHandle = mWorkPool.schedule(preSignalTasks);
+            mWorkPool.waitAll(waitGroupHandle);
+
             VkSubmitInfo submit_info = {
                 .sType = VK_STRUCTURE_TYPE_SUBMIT_INFO,
                 .waitSemaphoreCount = 0,
@@ -2688,41 +3480,89 @@
                 .signalSemaphoreCount = static_cast<uint32_t>(pre_signal_semaphores.size()),
                 .pSignalSemaphores = pre_signal_semaphores.data()};
             enc->vkQueueSubmit(queue, 1, &submit_info, VK_NULL_HANDLE);
+
+            input_result = enc->vkQueueSubmit(queue, submitCount, pSubmits, fence);
+            if (input_result != VK_SUCCESS) return input_result;
         }
 
-        input_result = enc->vkQueueSubmit(queue, submitCount, pSubmits, fence);
+        lock.lock();
+        int externalFenceFdToSignal = -1;
 
-        if (input_result != VK_SUCCESS) return input_result;
-
-        if (post_wait_events.empty())
-            return VK_SUCCESS;
-
-        if (*pFence == VK_NULL_HANDLE) {
-            VkFenceCreateInfo fence_create_info = {
-                VK_STRUCTURE_TYPE_FENCE_CREATE_INFO, 0, 0,
-            };
-            enc->vkCreateFence(device, &fence_create_info, nullptr, pFence);
+#ifdef VK_USE_PLATFORM_ANDROID_KHR
+        if (fence != VK_NULL_HANDLE) {
+            auto it = info_VkFence.find(fence);
+            if (it != info_VkFence.end()) {
+                const auto& info = it->second;
+                if (info.syncFd >= 0) {
+                    externalFenceFdToSignal = info.syncFd;
+                }
+            }
         }
-        enc->vkQueueSubmit(queue, 0, nullptr, *pFence);
-        static constexpr uint64_t MAX_WAIT_NS =
-            5ULL * 1000ULL * 1000ULL * 1000ULL;
-        enc->vkWaitForFences(device, 1, pFence, VK_TRUE, MAX_WAIT_NS);
-        enc->vkResetFences(device, 1, pFence);
+#endif
+        if (externalFenceFdToSignal >= 0 ||
+            !post_wait_events.empty() ||
+            !post_wait_sync_fds.empty()) {
 
+            std::vector<WorkPool::Task> tasks;
+
+            tasks.push_back([this, queue, externalFenceFdToSignal,
+                             post_wait_events /* copy of zx handles */,
+                             post_wait_sync_fds /* copy of sync fds */] {
+                auto hostConn = mThreadingCallbacks.hostConnectionGetFunc();
+                auto vkEncoder = mThreadingCallbacks.vkEncoderGetFunc(hostConn);
+                auto waitIdleRes = vkEncoder->vkQueueWaitIdle(queue);
 #ifdef VK_USE_PLATFORM_FUCHSIA
-        for (auto& event : post_wait_events) {
-            zx_object_signal(event, 0, ZX_EVENT_SIGNALED);
-        }
+                (void)externalFenceFdToSignal;
+                for (auto& event : post_wait_events) {
+                    zx_object_signal(event, 0, ZX_EVENT_SIGNALED);
+                }
 #endif
 #ifdef VK_USE_PLATFORM_ANDROID_KHR
-        for (auto& fd : post_wait_sync_fds) {
-            goldfish_sync_signal(fd);
-        }
+                for (auto& fd : post_wait_sync_fds) {
+                    goldfish_sync_signal(fd);
+                }
+
+                if (externalFenceFdToSignal >= 0) {
+                    ALOGV("%s: external fence real signal: %d\n", __func__, externalFenceFdToSignal);
+                    goldfish_sync_signal(externalFenceFdToSignal);
+                }
 #endif
+            });
+            auto queueAsyncWaitHandle = mWorkPool.schedule(tasks);
+            auto& queueWorkItems = mQueueSensitiveWorkPoolItems[queue];
+            queueWorkItems.push_back(queueAsyncWaitHandle);
+        }
 
         return VK_SUCCESS;
     }
 
+    VkResult on_vkQueueWaitIdle(
+        void* context, VkResult,
+        VkQueue queue) {
+
+        VkEncoder* enc = (VkEncoder*)context;
+
+        AutoLock lock(mLock);
+        std::vector<WorkPool::WaitGroupHandle> toWait =
+            mQueueSensitiveWorkPoolItems[queue];
+        mQueueSensitiveWorkPoolItems[queue].clear();
+        lock.unlock();
+
+        if (toWait.empty()) {
+            ALOGV("%s: No queue-specific work pool items\n", __func__);
+            return enc->vkQueueWaitIdle(queue);
+        }
+
+        for (auto handle : toWait) {
+            ALOGV("%s: waiting on work group item: %llu\n", __func__, 
+                  (unsigned long long)handle);
+            mWorkPool.waitAll(handle);
+        }
+
+        // now done waiting, get the host's opinion
+        return enc->vkQueueWaitIdle(queue);
+    }
+
     void unwrap_VkNativeBufferANDROID(
         const VkImageCreateInfo* pCreateInfo,
         VkImageCreateInfo* local_pCreateInfo) {
@@ -2730,16 +3570,12 @@
         if (!pCreateInfo->pNext) return;
 
         const VkNativeBufferANDROID* nativeInfo =
-            reinterpret_cast<const VkNativeBufferANDROID*>(pCreateInfo->pNext);
-
-        if (VK_STRUCTURE_TYPE_NATIVE_BUFFER_ANDROID != nativeInfo->sType) {
+            vk_find_struct<VkNativeBufferANDROID>(pCreateInfo);
+        if (!nativeInfo) {
             return;
         }
 
-        const cb_handle_t* cb_handle =
-            reinterpret_cast<const cb_handle_t*>(nativeInfo->handle);
-
-        if (!cb_handle) return;
+        if (!nativeInfo->handle) return;
 
         VkNativeBufferANDROID* nativeInfoOut =
             reinterpret_cast<VkNativeBufferANDROID*>(
@@ -2751,13 +3587,31 @@
             abort();
         }
 
-        *(uint32_t*)(nativeInfoOut->handle) = cb_handle->hostHandle;
+        *(uint32_t*)(nativeInfoOut->handle) =
+            mThreadingCallbacks.hostConnectionGetFunc()->
+                grallocHelper()->getHostHandle(
+                    (const native_handle_t*)nativeInfo->handle);
     }
 
     void unwrap_vkAcquireImageANDROID_nativeFenceFd(int fd, int*) {
+#ifdef VK_USE_PLATFORM_ANDROID_KHR
         if (fd != -1) {
+            // Implicit Synchronization
             sync_wait(fd, 3000);
+            // From libvulkan's swapchain.cpp:
+            // """
+            // NOTE: we're relying on AcquireImageANDROID to close fence_clone,
+            // even if the call fails. We could close it ourselves on failure, but
+            // that would create a race condition if the driver closes it on a
+            // failure path: some other thread might create an fd with the same
+            // number between the time the driver closes it and the time we close
+            // it. We must assume one of: the driver *always* closes it even on
+            // failure, or *never* closes it on failure.
+            // """
+            // Therefore, assume contract where we need to close fd in this driver
+            close(fd);
         }
+#endif
     }
 
     // Action of vkMapMemoryIntoAddressSpaceGOOGLE:
@@ -3075,6 +3929,48 @@
             physicalDevice, pImageFormatInfo, pImageFormatProperties);
     }
 
+    uint32_t syncEncodersForCommandBuffer(VkCommandBuffer commandBuffer, VkEncoder* currentEncoder) {
+        AutoLock lock(mLock);
+
+        auto it = info_VkCommandBuffer.find(commandBuffer);
+        if (it == info_VkCommandBuffer.end()) return 0;
+
+        auto& info = it->second;
+
+        if (!info.lastUsedEncoderPtr) {
+            info.lastUsedEncoderPtr = new VkEncoder*;
+            *(info.lastUsedEncoderPtr) = currentEncoder;
+        }
+
+        auto lastUsedEncoderPtr = info.lastUsedEncoderPtr;
+
+        auto lastEncoder = *(lastUsedEncoderPtr);
+
+        // We always make lastUsedEncoderPtr track
+        // the current encoder, even if the last encoder
+        // is null.
+        *(lastUsedEncoderPtr) = currentEncoder;
+
+        if (!lastEncoder) return 0;
+        if (lastEncoder == currentEncoder) return 0;
+
+        info.sequenceNumber++;
+        lastEncoder->vkCommandBufferHostSyncGOOGLE(commandBuffer, false, info.sequenceNumber);
+        lastEncoder->flush();
+        info.sequenceNumber++;
+        currentEncoder->vkCommandBufferHostSyncGOOGLE(commandBuffer, true, info.sequenceNumber);
+
+        lastEncoder->unregisterCleanupCallback(commandBuffer);
+
+        currentEncoder->registerCleanupCallback(commandBuffer, [currentEncoder, lastUsedEncoderPtr]() {
+            if (*(lastUsedEncoderPtr) == currentEncoder) {
+                *(lastUsedEncoderPtr) = nullptr;
+            }
+        });
+
+        return 1;
+    }
+
     VkResult on_vkBeginCommandBuffer(
         void* context, VkResult input_result,
         VkCommandBuffer commandBuffer,
@@ -3088,6 +3984,7 @@
         }
 
         enc->vkBeginCommandBufferAsyncGOOGLE(commandBuffer, pBeginInfo);
+
         return VK_SUCCESS;
     }
 
@@ -3103,6 +4000,7 @@
         }
 
         enc->vkEndCommandBufferAsyncGOOGLE(commandBuffer);
+
         return VK_SUCCESS;
     }
 
@@ -3197,17 +4095,26 @@
     mutable Lock mLock;
     HostVisibleMemoryVirtualizationInfo mHostVisibleMemoryVirtInfo;
     std::unique_ptr<EmulatorFeatureInfo> mFeatureInfo;
+    ResourceTracker::ThreadingCallbacks mThreadingCallbacks;
+    uint32_t mStreamFeatureBits = 0;
     std::unique_ptr<GoldfishAddressSpaceBlockProvider> mGoldfishAddressSpaceBlockProvider;
 
     std::vector<VkExtensionProperties> mHostInstanceExtensions;
     std::vector<VkExtensionProperties> mHostDeviceExtensions;
 
     int mSyncDeviceFd = -1;
+#ifdef VK_USE_PLATFORM_ANDROID_KHR
+    int mRendernodeFd = -1;
+#endif
 
 #ifdef VK_USE_PLATFORM_FUCHSIA
-    zx_handle_t mControlDevice = ZX_HANDLE_INVALID;
+    fuchsia::hardware::goldfish::ControlDeviceSyncPtr mControlDevice;
     fuchsia::sysmem::AllocatorSyncPtr mSysmemAllocator;
 #endif
+
+    WorkPool mWorkPool { 4 };
+    std::unordered_map<VkQueue, std::vector<WorkPool::WaitGroupHandle>>
+        mQueueSensitiveWorkPoolItems;
 };
 
 ResourceTracker::ResourceTracker() : mImpl(new ResourceTracker::Impl()) { }
@@ -3269,6 +4176,10 @@
     mImpl->setupFeatures(features);
 }
 
+void ResourceTracker::setThreadingCallbacks(const ResourceTracker::ThreadingCallbacks& callbacks) {
+    mImpl->setThreadingCallbacks(callbacks);
+}
+
 bool ResourceTracker::hostSupportsVulkan() const {
     return mImpl->hostSupportsVulkan();
 }
@@ -3277,6 +4188,10 @@
     return mImpl->usingDirectMapping();
 }
 
+uint32_t ResourceTracker::getStreamFeatures() const {
+    return mImpl->getStreamFeatures();
+}
+
 uint32_t ResourceTracker::getApiVersionFromInstance(VkInstance instance) const {
     return mImpl->getApiVersionFromInstance(instance);
 }
@@ -3555,6 +4470,12 @@
         context, input_result, queue, submitCount, pSubmits, fence);
 }
 
+VkResult ResourceTracker::on_vkQueueWaitIdle(
+    void* context, VkResult input_result,
+    VkQueue queue) {
+    return mImpl->on_vkQueueWaitIdle(context, input_result, queue);
+}
+
 VkResult ResourceTracker::on_vkGetSemaphoreFdKHR(
     void* context, VkResult input_result,
     VkDevice device,
@@ -3683,6 +4604,15 @@
         context, input_result, device, pCreateInfo, pAllocator, pYcbcrConversion);
 }
 
+void ResourceTracker::on_vkDestroySamplerYcbcrConversion(
+    void* context,
+    VkDevice device,
+    VkSamplerYcbcrConversion ycbcrConversion,
+    const VkAllocationCallbacks* pAllocator) {
+    mImpl->on_vkDestroySamplerYcbcrConversion(
+        context, device, ycbcrConversion, pAllocator);
+}
+
 VkResult ResourceTracker::on_vkCreateSamplerYcbcrConversionKHR(
     void* context, VkResult input_result,
     VkDevice device,
@@ -3693,6 +4623,103 @@
         context, input_result, device, pCreateInfo, pAllocator, pYcbcrConversion);
 }
 
+void ResourceTracker::on_vkDestroySamplerYcbcrConversionKHR(
+    void* context,
+    VkDevice device,
+    VkSamplerYcbcrConversion ycbcrConversion,
+    const VkAllocationCallbacks* pAllocator) {
+    mImpl->on_vkDestroySamplerYcbcrConversionKHR(
+        context, device, ycbcrConversion, pAllocator);
+}
+
+VkResult ResourceTracker::on_vkCreateSampler(
+    void* context, VkResult input_result,
+    VkDevice device,
+    const VkSamplerCreateInfo* pCreateInfo,
+    const VkAllocationCallbacks* pAllocator,
+    VkSampler* pSampler) {
+    return mImpl->on_vkCreateSampler(
+        context, input_result, device, pCreateInfo, pAllocator, pSampler);
+}
+
+void ResourceTracker::on_vkGetPhysicalDeviceExternalFenceProperties(
+    void* context,
+    VkPhysicalDevice physicalDevice,
+    const VkPhysicalDeviceExternalFenceInfo* pExternalFenceInfo,
+    VkExternalFenceProperties* pExternalFenceProperties) {
+    mImpl->on_vkGetPhysicalDeviceExternalFenceProperties(
+        context, physicalDevice, pExternalFenceInfo, pExternalFenceProperties);
+}
+
+void ResourceTracker::on_vkGetPhysicalDeviceExternalFencePropertiesKHR(
+    void* context,
+    VkPhysicalDevice physicalDevice,
+    const VkPhysicalDeviceExternalFenceInfo* pExternalFenceInfo,
+    VkExternalFenceProperties* pExternalFenceProperties) {
+    mImpl->on_vkGetPhysicalDeviceExternalFenceProperties(
+        context, physicalDevice, pExternalFenceInfo, pExternalFenceProperties);
+}
+
+VkResult ResourceTracker::on_vkCreateFence(
+    void* context,
+    VkResult input_result,
+    VkDevice device,
+    const VkFenceCreateInfo* pCreateInfo,
+    const VkAllocationCallbacks* pAllocator, VkFence* pFence) {
+    return mImpl->on_vkCreateFence(
+        context, input_result, device, pCreateInfo, pAllocator, pFence);
+}
+
+void ResourceTracker::on_vkDestroyFence(
+    void* context,
+    VkDevice device,
+    VkFence fence,
+    const VkAllocationCallbacks* pAllocator) {
+    mImpl->on_vkDestroyFence(
+        context, device, fence, pAllocator);
+}
+
+VkResult ResourceTracker::on_vkResetFences(
+    void* context,
+    VkResult input_result,
+    VkDevice device,
+    uint32_t fenceCount,
+    const VkFence* pFences) {
+    return mImpl->on_vkResetFences(
+        context, input_result, device, fenceCount, pFences);
+}
+
+VkResult ResourceTracker::on_vkImportFenceFdKHR(
+    void* context,
+    VkResult input_result,
+    VkDevice device,
+    const VkImportFenceFdInfoKHR* pImportFenceFdInfo) {
+    return mImpl->on_vkImportFenceFdKHR(
+        context, input_result, device, pImportFenceFdInfo);
+}
+
+VkResult ResourceTracker::on_vkGetFenceFdKHR(
+    void* context,
+    VkResult input_result,
+    VkDevice device,
+    const VkFenceGetFdInfoKHR* pGetFdInfo,
+    int* pFd) {
+    return mImpl->on_vkGetFenceFdKHR(
+        context, input_result, device, pGetFdInfo, pFd);
+}
+
+VkResult ResourceTracker::on_vkWaitForFences(
+    void* context,
+    VkResult input_result,
+    VkDevice device,
+    uint32_t fenceCount,
+    const VkFence* pFences,
+    VkBool32 waitAll,
+    uint64_t timeout) {
+    return mImpl->on_vkWaitForFences(
+        context, input_result, device, fenceCount, pFences, waitAll, timeout);
+}
+
 VkResult ResourceTracker::on_vkMapMemoryIntoAddressSpaceGOOGLE_pre(
     void* context,
     VkResult input_result,
@@ -3766,6 +4793,10 @@
         pImageFormatProperties);
 }
 
+uint32_t ResourceTracker::syncEncodersForCommandBuffer(VkCommandBuffer commandBuffer, VkEncoder* current) {
+    return mImpl->syncEncodersForCommandBuffer(commandBuffer, current);
+}
+
 VkResult ResourceTracker::on_vkBeginCommandBuffer(
     void* context, VkResult input_result,
     VkCommandBuffer commandBuffer,
diff --git a/system/vulkan_enc/ResourceTracker.h b/system/vulkan_enc/ResourceTracker.h
index 6429d6f..791a2b2 100644
--- a/system/vulkan_enc/ResourceTracker.h
+++ b/system/vulkan_enc/ResourceTracker.h
@@ -26,8 +26,12 @@
 
 struct EmulatorFeatureInfo;
 
+class HostConnection;
+
 namespace goldfish_vk {
 
+class VkEncoder;
+
 class ResourceTracker {
 public:
     ResourceTracker();
@@ -38,6 +42,14 @@
     VulkanHandleMapping* destroyMapping();
     VulkanHandleMapping* defaultMapping();
 
+    using HostConnectionGetFunc = HostConnection* (*)();
+    using VkEncoderGetFunc = VkEncoder* (*)(HostConnection*);
+
+    struct ThreadingCallbacks {
+        HostConnectionGetFunc hostConnectionGetFunc = 0;
+        VkEncoderGetFunc vkEncoderGetFunc = 0;
+    };
+
 #define HANDLE_REGISTER_DECL(type) \
     void register_##type(type); \
     void unregister_##type(type); \
@@ -203,6 +215,10 @@
         void* context, VkResult input_result,
         VkQueue queue, uint32_t submitCount, const VkSubmitInfo* pSubmits, VkFence fence);
 
+    VkResult on_vkQueueWaitIdle(
+        void* context, VkResult input_result,
+        VkQueue queue);
+
     void unwrap_VkNativeBufferANDROID(
         const VkImageCreateInfo* pCreateInfo,
         VkImageCreateInfo* local_pCreateInfo);
@@ -269,12 +285,83 @@
         const VkSamplerYcbcrConversionCreateInfo* pCreateInfo,
         const VkAllocationCallbacks* pAllocator,
         VkSamplerYcbcrConversion* pYcbcrConversion);
+    void on_vkDestroySamplerYcbcrConversion(
+        void* context,
+        VkDevice device,
+        VkSamplerYcbcrConversion ycbcrConversion,
+        const VkAllocationCallbacks* pAllocator);
     VkResult on_vkCreateSamplerYcbcrConversionKHR(
         void* context, VkResult input_result,
         VkDevice device,
         const VkSamplerYcbcrConversionCreateInfo* pCreateInfo,
         const VkAllocationCallbacks* pAllocator,
         VkSamplerYcbcrConversion* pYcbcrConversion);
+    void on_vkDestroySamplerYcbcrConversionKHR(
+        void* context,
+        VkDevice device,
+        VkSamplerYcbcrConversion ycbcrConversion,
+        const VkAllocationCallbacks* pAllocator);
+
+    VkResult on_vkCreateSampler(
+        void* context, VkResult input_result,
+        VkDevice device,
+        const VkSamplerCreateInfo* pCreateInfo,
+        const VkAllocationCallbacks* pAllocator,
+        VkSampler* pSampler);
+
+    void on_vkGetPhysicalDeviceExternalFenceProperties(
+        void* context,
+        VkPhysicalDevice physicalDevice,
+        const VkPhysicalDeviceExternalFenceInfo* pExternalFenceInfo,
+        VkExternalFenceProperties* pExternalFenceProperties);
+
+    void on_vkGetPhysicalDeviceExternalFencePropertiesKHR(
+        void* context,
+        VkPhysicalDevice physicalDevice,
+        const VkPhysicalDeviceExternalFenceInfo* pExternalFenceInfo,
+        VkExternalFenceProperties* pExternalFenceProperties);
+
+    VkResult on_vkCreateFence(
+        void* context,
+        VkResult input_result,
+        VkDevice device,
+        const VkFenceCreateInfo* pCreateInfo,
+        const VkAllocationCallbacks* pAllocator, VkFence* pFence);
+
+    void on_vkDestroyFence(
+        void* context,
+        VkDevice device,
+        VkFence fence,
+        const VkAllocationCallbacks* pAllocator);
+
+    VkResult on_vkResetFences(
+        void* context,
+        VkResult input_result,
+        VkDevice device,
+        uint32_t fenceCount,
+        const VkFence* pFences);
+
+    VkResult on_vkImportFenceFdKHR(
+        void* context,
+        VkResult input_result,
+        VkDevice device,
+        const VkImportFenceFdInfoKHR* pImportFenceFdInfo);
+
+    VkResult on_vkGetFenceFdKHR(
+        void* context,
+        VkResult input_result,
+        VkDevice device,
+        const VkFenceGetFdInfoKHR* pGetFdInfo,
+        int* pFd);
+
+    VkResult on_vkWaitForFences(
+        void* context,
+        VkResult input_result,
+        VkDevice device,
+        uint32_t fenceCount,
+        const VkFence* pFences,
+        VkBool32 waitAll,
+        uint64_t timeout);
 
     VkResult on_vkMapMemoryIntoAddressSpaceGOOGLE_pre(
         void* context,
@@ -322,6 +409,8 @@
         const VkPhysicalDeviceImageFormatInfo2* pImageFormatInfo,
         VkImageFormatProperties2* pImageFormatProperties);
 
+    uint32_t syncEncodersForCommandBuffer(VkCommandBuffer commandBuffer, VkEncoder* current);
+
     VkResult on_vkBeginCommandBuffer(
         void* context, VkResult input_result,
         VkCommandBuffer commandBuffer,
@@ -347,8 +436,10 @@
     VkDeviceSize getNonCoherentExtendedSize(VkDevice device, VkDeviceSize basicSize) const;
     bool isValidMemoryRange(const VkMappedMemoryRange& range) const;
     void setupFeatures(const EmulatorFeatureInfo* features);
+    void setThreadingCallbacks(const ThreadingCallbacks& callbacks);
     bool hostSupportsVulkan() const;
     bool usingDirectMapping() const;
+    uint32_t getStreamFeatures() const;
     uint32_t getApiVersionFromInstance(VkInstance instance) const;
     uint32_t getApiVersionFromDevice(VkDevice device) const;
     bool hasInstanceExtension(VkInstance instance, const std::string& name) const;
diff --git a/system/vulkan_enc/VirtioGpuNext.h b/system/vulkan_enc/VirtioGpuNext.h
new file mode 100644
index 0000000..4037973
--- /dev/null
+++ b/system/vulkan_enc/VirtioGpuNext.h
@@ -0,0 +1,60 @@
+// Copyright (C) 2020 The Android Open Source Project
+// Copyright (C) 2020 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+#pragma once
+
+#ifndef HOST_BUILD
+#include "drm.h"
+#endif
+
+#define DRM_VIRTGPU_RESOURCE_CREATE_V2 0x0a
+
+struct drm_virtgpu_resource_create_v2 {
+#define VIRTGPU_RESOURCE_TYPE_MASK       0x0000f
+#define VIRTGPU_RESOURCE_TYPE_DEFAULT_V1 0x00001
+#define VIRTGPU_RESOURCE_TYPE_DEFAULT_V2 0x00002
+#define VIRTGPU_RESOURCE_TYPE_HOST       0x00003
+#define VIRTGPU_RESOURCE_TYPE_GUEST      0x00004
+/*
+ * Error cases:
+ * HOST_VISIBLE_BIT without VIRTGPU_RESOURCE_TYPE_HOST
+ */
+#define VIRTGPU_RESOURCE_HOST_MASK            0x000f0
+#define VIRTGPU_RESOURCE_HOST_VISIBLE_BIT     0x00010
+
+#define VIRTGPU_RESOURCE_GUEST_MASK                  0x00f00
+#define VIRTGPU_RESOURCE_GUEST_SHARED_BIT            0x00100
+#define VIRTGPU_RESOURCE_GUEST_EMULATED_COHERENT_BIT 0x00200
+
+#define VIRTGPU_RESOURCE_CACHE_MASK      0x0f000
+#define VIRTGPU_RESOURCE_CACHE_CACHED    0x01000
+#define VIRTGPU_RESOURCE_CACHE_UNCACHED  0x02000
+#define VIRTGPU_RESOURCE_CACHE_WC        0x03000
+/*
+ * VIRTGPU_RESOURCE_EXPORTABLE_BIT - host resource *can* be exported as an fd.
+ */
+#define VIRTGPU_RESOURCE_EXPORT_MASK    0xf0000
+#define VIRTGPU_RESOURCE_EXPORTABLE_BIT 0x10000
+	uint32_t flags;
+	uint32_t args_size;
+	uint64_t size;
+	uint32_t bo_handle;
+	uint32_t res_handle;
+	uint64_t args;
+};
+
+#define DRM_IOCTL_VIRTGPU_RESOURCE_CREATE_V2				\
+	DRM_IOWR(DRM_COMMAND_BASE + DRM_VIRTGPU_RESOURCE_CREATE_V2,	\
+		struct drm_virtgpu_resource_create_v2)
+
diff --git a/system/vulkan_enc/VkEncoder.cpp b/system/vulkan_enc/VkEncoder.cpp
index 42487ea..b5b6eea 100644
--- a/system/vulkan_enc/VkEncoder.cpp
+++ b/system/vulkan_enc/VkEncoder.cpp
@@ -33,6 +33,7 @@
 
 #include "android/base/AlignedBuf.h"
 #include "android/base/Pool.h"
+#include "android/base/synchronization/AndroidLock.h"
 
 #include <cutils/properties.h>
 
@@ -42,6 +43,9 @@
 #include "goldfish_vk_private_defs.h"
 #include "goldfish_vk_transform_guest.h"
 
+#include <unordered_map>
+
+
 
 namespace goldfish_vk {
 
@@ -51,6 +55,8 @@
 
 using android::aligned_buf_alloc;
 using android::aligned_buf_free;
+using android::base::guest::AutoLock;
+using android::base::guest::Lock;
 using android::base::Pool;
 
 class VkEncoder::Impl {
@@ -62,6 +68,14 @@
             m_logEncodes = atoi(encodeProp) > 0;
         }
     }
+
+    ~Impl() {
+        for (auto it : mCleanupCallbacks) {
+            fprintf(stderr, "%s: run cleanup callback for %p\n", __func__, it.first);
+            it.second();
+        }
+    }
+
     VulkanCountingStream* countingStream() { return &m_countingStream; }
     VulkanStreamGuest* stream() { return &m_stream; }
     Pool* pool() { return &m_pool; }
@@ -72,6 +86,27 @@
         if (!m_logEncodes) return;
         ALOGD("encoder log: %s", text);
     }
+
+    void flush() {
+        AutoLock encoderLock(lock);
+        m_stream.flush();
+    }
+
+    // Assume the lock for the current encoder is held.
+    void registerCleanupCallback(void* handle, VkEncoder::CleanupCallback cb) {
+        if (mCleanupCallbacks.end() == mCleanupCallbacks.find(handle)) {
+            mCleanupCallbacks[handle] = cb;
+        } else {
+            return;
+        }
+    }
+
+    void unregisterCleanupCallback(void* handle) {
+        mCleanupCallbacks.erase(handle);
+    }
+
+    Lock lock;
+
 private:
     VulkanCountingStream m_countingStream;
     VulkanStreamGuest m_stream;
@@ -79,11 +114,25 @@
 
     Validation m_validation;
     bool m_logEncodes;
+
+    std::unordered_map<void*, VkEncoder::CleanupCallback> mCleanupCallbacks;
 };
 
 VkEncoder::VkEncoder(IOStream *stream) :
     mImpl(new VkEncoder::Impl(stream)) { }
 
+void VkEncoder::flush() {
+    mImpl->flush();
+}
+
+void VkEncoder::registerCleanupCallback(void* handle, VkEncoder::CleanupCallback cb) {
+    mImpl->registerCleanupCallback(handle, cb);
+}
+
+void VkEncoder::unregisterCleanupCallback(void* handle) {
+    mImpl->unregisterCleanupCallback(handle);
+}
+
 #define VALIDATE_RET(retType, success, validate) \
     retType goldfish_vk_validateResult = validate; \
     if (goldfish_vk_validateResult != success) return goldfish_vk_validateResult; \
@@ -98,6 +147,7 @@
     const VkAllocationCallbacks* pAllocator,
     VkInstance* pInstance)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkCreateInstance encode");
     mImpl->log("start vkCreateInstance");
     auto stream = mImpl->stream();
@@ -172,7 +222,9 @@
     countingStream->clearPool();
     stream->clearPool();
     pool->freeAll();
+    encoderLock.unlock();
     mImpl->resources()->on_vkCreateInstance(this, vkCreateInstance_VkResult_return, pCreateInfo, pAllocator, pInstance);
+    encoderLock.lock();
     mImpl->log("finish vkCreateInstance");;
     return vkCreateInstance_VkResult_return;
 }
@@ -181,6 +233,7 @@
     VkInstance instance,
     const VkAllocationCallbacks* pAllocator)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkDestroyInstance encode");
     mImpl->log("start vkDestroyInstance");
     auto stream = mImpl->stream();
@@ -241,6 +294,7 @@
     uint32_t* pPhysicalDeviceCount,
     VkPhysicalDevice* pPhysicalDevices)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkEnumeratePhysicalDevices encode");
     mImpl->log("start vkEnumeratePhysicalDevices");
     auto stream = mImpl->stream();
@@ -351,6 +405,7 @@
     VkPhysicalDevice physicalDevice,
     VkPhysicalDeviceFeatures* pFeatures)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkGetPhysicalDeviceFeatures encode");
     mImpl->log("start vkGetPhysicalDeviceFeatures");
     auto stream = mImpl->stream();
@@ -391,6 +446,7 @@
     VkFormat format,
     VkFormatProperties* pFormatProperties)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkGetPhysicalDeviceFormatProperties encode");
     mImpl->log("start vkGetPhysicalDeviceFormatProperties");
     auto stream = mImpl->stream();
@@ -439,6 +495,7 @@
     VkImageCreateFlags flags,
     VkImageFormatProperties* pImageFormatProperties)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkGetPhysicalDeviceImageFormatProperties encode");
     mImpl->log("start vkGetPhysicalDeviceImageFormatProperties");
     auto stream = mImpl->stream();
@@ -504,6 +561,7 @@
     VkPhysicalDevice physicalDevice,
     VkPhysicalDeviceProperties* pProperties)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkGetPhysicalDeviceProperties encode");
     mImpl->log("start vkGetPhysicalDeviceProperties");
     auto stream = mImpl->stream();
@@ -544,6 +602,7 @@
     uint32_t* pQueueFamilyPropertyCount,
     VkQueueFamilyProperties* pQueueFamilyProperties)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkGetPhysicalDeviceQueueFamilyProperties encode");
     mImpl->log("start vkGetPhysicalDeviceQueueFamilyProperties");
     auto stream = mImpl->stream();
@@ -642,6 +701,7 @@
     VkPhysicalDevice physicalDevice,
     VkPhysicalDeviceMemoryProperties* pMemoryProperties)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkGetPhysicalDeviceMemoryProperties encode");
     mImpl->log("start vkGetPhysicalDeviceMemoryProperties");
     auto stream = mImpl->stream();
@@ -674,7 +734,9 @@
         transform_fromhost_VkPhysicalDeviceMemoryProperties(mImpl->resources(), (VkPhysicalDeviceMemoryProperties*)(pMemoryProperties));
     }
     AEMU_SCOPED_TRACE("vkGetPhysicalDeviceMemoryProperties returnUnmarshal");
+    encoderLock.unlock();
     mImpl->resources()->on_vkGetPhysicalDeviceMemoryProperties(this, physicalDevice, pMemoryProperties);
+    encoderLock.lock();
     mImpl->log("finish vkGetPhysicalDeviceMemoryProperties");;
 }
 
@@ -682,6 +744,7 @@
     VkInstance instance,
     const char* pName)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkGetInstanceProcAddr encode");
     mImpl->log("start vkGetInstanceProcAddr");
     auto stream = mImpl->stream();
@@ -728,6 +791,7 @@
     VkDevice device,
     const char* pName)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkGetDeviceProcAddr encode");
     mImpl->log("start vkGetDeviceProcAddr");
     auto stream = mImpl->stream();
@@ -776,6 +840,7 @@
     const VkAllocationCallbacks* pAllocator,
     VkDevice* pDevice)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkCreateDevice encode");
     mImpl->log("start vkCreateDevice");
     auto stream = mImpl->stream();
@@ -858,7 +923,9 @@
     countingStream->clearPool();
     stream->clearPool();
     pool->freeAll();
+    encoderLock.unlock();
     mImpl->resources()->on_vkCreateDevice(this, vkCreateDevice_VkResult_return, physicalDevice, pCreateInfo, pAllocator, pDevice);
+    encoderLock.lock();
     mImpl->log("finish vkCreateDevice");;
     return vkCreateDevice_VkResult_return;
 }
@@ -867,9 +934,12 @@
     VkDevice device,
     const VkAllocationCallbacks* pAllocator)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkDestroyDevice encode");
     mImpl->log("start vkDestroyDevice");
+    encoderLock.unlock();
     mImpl->resources()->on_vkDestroyDevice_pre(this, device, pAllocator);
+    encoderLock.lock();
     auto stream = mImpl->stream();
     auto countingStream = mImpl->countingStream();
     auto resources = mImpl->resources();
@@ -929,6 +999,7 @@
     uint32_t* pPropertyCount,
     VkExtensionProperties* pProperties)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkEnumerateInstanceExtensionProperties encode");
     mImpl->log("start vkEnumerateInstanceExtensionProperties");
     auto stream = mImpl->stream();
@@ -944,17 +1015,30 @@
     }
     countingStream->rewind();
     {
-        countingStream->putString(local_pLayerName);
+        if (countingStream->getFeatureBits() & VULKAN_STREAM_FEATURE_NULL_OPTIONAL_STRINGS_BIT)
+        {
+            // WARNING PTR CHECK
+            uint64_t cgen_var_53 = (uint64_t)(uintptr_t)local_pLayerName;
+            countingStream->putBe64(cgen_var_53);
+            if (local_pLayerName)
+            {
+                countingStream->putString(local_pLayerName);
+            }
+        }
+        else
+        {
+            countingStream->putString(local_pLayerName);
+        }
         // WARNING PTR CHECK
-        uint64_t cgen_var_53 = (uint64_t)(uintptr_t)pPropertyCount;
-        countingStream->putBe64(cgen_var_53);
+        uint64_t cgen_var_54 = (uint64_t)(uintptr_t)pPropertyCount;
+        countingStream->putBe64(cgen_var_54);
         if (pPropertyCount)
         {
             countingStream->write((uint32_t*)pPropertyCount, sizeof(uint32_t));
         }
         // WARNING PTR CHECK
-        uint64_t cgen_var_54 = (uint64_t)(uintptr_t)pProperties;
-        countingStream->putBe64(cgen_var_54);
+        uint64_t cgen_var_55 = (uint64_t)(uintptr_t)pProperties;
+        countingStream->putBe64(cgen_var_55);
         if (pProperties)
         {
             for (uint32_t i = 0; i < (uint32_t)(*(pPropertyCount)); ++i)
@@ -968,17 +1052,30 @@
     uint32_t opcode_vkEnumerateInstanceExtensionProperties = OP_vkEnumerateInstanceExtensionProperties;
     stream->write(&opcode_vkEnumerateInstanceExtensionProperties, sizeof(uint32_t));
     stream->write(&packetSize_vkEnumerateInstanceExtensionProperties, sizeof(uint32_t));
-    stream->putString(local_pLayerName);
+    if (stream->getFeatureBits() & VULKAN_STREAM_FEATURE_NULL_OPTIONAL_STRINGS_BIT)
+    {
+        // WARNING PTR CHECK
+        uint64_t cgen_var_56 = (uint64_t)(uintptr_t)local_pLayerName;
+        stream->putBe64(cgen_var_56);
+        if (local_pLayerName)
+        {
+            stream->putString(local_pLayerName);
+        }
+    }
+    else
+    {
+        stream->putString(local_pLayerName);
+    }
     // WARNING PTR CHECK
-    uint64_t cgen_var_55 = (uint64_t)(uintptr_t)pPropertyCount;
-    stream->putBe64(cgen_var_55);
+    uint64_t cgen_var_57 = (uint64_t)(uintptr_t)pPropertyCount;
+    stream->putBe64(cgen_var_57);
     if (pPropertyCount)
     {
         stream->write((uint32_t*)pPropertyCount, sizeof(uint32_t));
     }
     // WARNING PTR CHECK
-    uint64_t cgen_var_56 = (uint64_t)(uintptr_t)pProperties;
-    stream->putBe64(cgen_var_56);
+    uint64_t cgen_var_58 = (uint64_t)(uintptr_t)pProperties;
+    stream->putBe64(cgen_var_58);
     if (pProperties)
     {
         for (uint32_t i = 0; i < (uint32_t)(*(pPropertyCount)); ++i)
@@ -1035,6 +1132,7 @@
     uint32_t* pPropertyCount,
     VkExtensionProperties* pProperties)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkEnumerateDeviceExtensionProperties encode");
     mImpl->log("start vkEnumerateDeviceExtensionProperties");
     auto stream = mImpl->stream();
@@ -1052,20 +1150,33 @@
     }
     countingStream->rewind();
     {
-        uint64_t cgen_var_59;
-        countingStream->handleMapping()->mapHandles_VkPhysicalDevice_u64(&local_physicalDevice, &cgen_var_59, 1);
-        countingStream->write((uint64_t*)&cgen_var_59, 1 * 8);
-        countingStream->putString(local_pLayerName);
+        uint64_t cgen_var_61;
+        countingStream->handleMapping()->mapHandles_VkPhysicalDevice_u64(&local_physicalDevice, &cgen_var_61, 1);
+        countingStream->write((uint64_t*)&cgen_var_61, 1 * 8);
+        if (countingStream->getFeatureBits() & VULKAN_STREAM_FEATURE_NULL_OPTIONAL_STRINGS_BIT)
+        {
+            // WARNING PTR CHECK
+            uint64_t cgen_var_62 = (uint64_t)(uintptr_t)local_pLayerName;
+            countingStream->putBe64(cgen_var_62);
+            if (local_pLayerName)
+            {
+                countingStream->putString(local_pLayerName);
+            }
+        }
+        else
+        {
+            countingStream->putString(local_pLayerName);
+        }
         // WARNING PTR CHECK
-        uint64_t cgen_var_60 = (uint64_t)(uintptr_t)pPropertyCount;
-        countingStream->putBe64(cgen_var_60);
+        uint64_t cgen_var_63 = (uint64_t)(uintptr_t)pPropertyCount;
+        countingStream->putBe64(cgen_var_63);
         if (pPropertyCount)
         {
             countingStream->write((uint32_t*)pPropertyCount, sizeof(uint32_t));
         }
         // WARNING PTR CHECK
-        uint64_t cgen_var_61 = (uint64_t)(uintptr_t)pProperties;
-        countingStream->putBe64(cgen_var_61);
+        uint64_t cgen_var_64 = (uint64_t)(uintptr_t)pProperties;
+        countingStream->putBe64(cgen_var_64);
         if (pProperties)
         {
             for (uint32_t i = 0; i < (uint32_t)(*(pPropertyCount)); ++i)
@@ -1079,20 +1190,33 @@
     uint32_t opcode_vkEnumerateDeviceExtensionProperties = OP_vkEnumerateDeviceExtensionProperties;
     stream->write(&opcode_vkEnumerateDeviceExtensionProperties, sizeof(uint32_t));
     stream->write(&packetSize_vkEnumerateDeviceExtensionProperties, sizeof(uint32_t));
-    uint64_t cgen_var_62;
-    stream->handleMapping()->mapHandles_VkPhysicalDevice_u64(&local_physicalDevice, &cgen_var_62, 1);
-    stream->write((uint64_t*)&cgen_var_62, 1 * 8);
-    stream->putString(local_pLayerName);
+    uint64_t cgen_var_65;
+    stream->handleMapping()->mapHandles_VkPhysicalDevice_u64(&local_physicalDevice, &cgen_var_65, 1);
+    stream->write((uint64_t*)&cgen_var_65, 1 * 8);
+    if (stream->getFeatureBits() & VULKAN_STREAM_FEATURE_NULL_OPTIONAL_STRINGS_BIT)
+    {
+        // WARNING PTR CHECK
+        uint64_t cgen_var_66 = (uint64_t)(uintptr_t)local_pLayerName;
+        stream->putBe64(cgen_var_66);
+        if (local_pLayerName)
+        {
+            stream->putString(local_pLayerName);
+        }
+    }
+    else
+    {
+        stream->putString(local_pLayerName);
+    }
     // WARNING PTR CHECK
-    uint64_t cgen_var_63 = (uint64_t)(uintptr_t)pPropertyCount;
-    stream->putBe64(cgen_var_63);
+    uint64_t cgen_var_67 = (uint64_t)(uintptr_t)pPropertyCount;
+    stream->putBe64(cgen_var_67);
     if (pPropertyCount)
     {
         stream->write((uint32_t*)pPropertyCount, sizeof(uint32_t));
     }
     // WARNING PTR CHECK
-    uint64_t cgen_var_64 = (uint64_t)(uintptr_t)pProperties;
-    stream->putBe64(cgen_var_64);
+    uint64_t cgen_var_68 = (uint64_t)(uintptr_t)pProperties;
+    stream->putBe64(cgen_var_68);
     if (pProperties)
     {
         for (uint32_t i = 0; i < (uint32_t)(*(pPropertyCount)); ++i)
@@ -1147,6 +1271,7 @@
     uint32_t* pPropertyCount,
     VkLayerProperties* pProperties)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkEnumerateInstanceLayerProperties encode");
     mImpl->log("start vkEnumerateInstanceLayerProperties");
     auto stream = mImpl->stream();
@@ -1157,15 +1282,15 @@
     countingStream->rewind();
     {
         // WARNING PTR CHECK
-        uint64_t cgen_var_67 = (uint64_t)(uintptr_t)pPropertyCount;
-        countingStream->putBe64(cgen_var_67);
+        uint64_t cgen_var_71 = (uint64_t)(uintptr_t)pPropertyCount;
+        countingStream->putBe64(cgen_var_71);
         if (pPropertyCount)
         {
             countingStream->write((uint32_t*)pPropertyCount, sizeof(uint32_t));
         }
         // WARNING PTR CHECK
-        uint64_t cgen_var_68 = (uint64_t)(uintptr_t)pProperties;
-        countingStream->putBe64(cgen_var_68);
+        uint64_t cgen_var_72 = (uint64_t)(uintptr_t)pProperties;
+        countingStream->putBe64(cgen_var_72);
         if (pProperties)
         {
             for (uint32_t i = 0; i < (uint32_t)(*(pPropertyCount)); ++i)
@@ -1180,15 +1305,15 @@
     stream->write(&opcode_vkEnumerateInstanceLayerProperties, sizeof(uint32_t));
     stream->write(&packetSize_vkEnumerateInstanceLayerProperties, sizeof(uint32_t));
     // WARNING PTR CHECK
-    uint64_t cgen_var_69 = (uint64_t)(uintptr_t)pPropertyCount;
-    stream->putBe64(cgen_var_69);
+    uint64_t cgen_var_73 = (uint64_t)(uintptr_t)pPropertyCount;
+    stream->putBe64(cgen_var_73);
     if (pPropertyCount)
     {
         stream->write((uint32_t*)pPropertyCount, sizeof(uint32_t));
     }
     // WARNING PTR CHECK
-    uint64_t cgen_var_70 = (uint64_t)(uintptr_t)pProperties;
-    stream->putBe64(cgen_var_70);
+    uint64_t cgen_var_74 = (uint64_t)(uintptr_t)pProperties;
+    stream->putBe64(cgen_var_74);
     if (pProperties)
     {
         for (uint32_t i = 0; i < (uint32_t)(*(pPropertyCount)); ++i)
@@ -1244,6 +1369,7 @@
     uint32_t* pPropertyCount,
     VkLayerProperties* pProperties)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkEnumerateDeviceLayerProperties encode");
     mImpl->log("start vkEnumerateDeviceLayerProperties");
     auto stream = mImpl->stream();
@@ -1255,19 +1381,19 @@
     local_physicalDevice = physicalDevice;
     countingStream->rewind();
     {
-        uint64_t cgen_var_73;
-        countingStream->handleMapping()->mapHandles_VkPhysicalDevice_u64(&local_physicalDevice, &cgen_var_73, 1);
-        countingStream->write((uint64_t*)&cgen_var_73, 1 * 8);
+        uint64_t cgen_var_77;
+        countingStream->handleMapping()->mapHandles_VkPhysicalDevice_u64(&local_physicalDevice, &cgen_var_77, 1);
+        countingStream->write((uint64_t*)&cgen_var_77, 1 * 8);
         // WARNING PTR CHECK
-        uint64_t cgen_var_74 = (uint64_t)(uintptr_t)pPropertyCount;
-        countingStream->putBe64(cgen_var_74);
+        uint64_t cgen_var_78 = (uint64_t)(uintptr_t)pPropertyCount;
+        countingStream->putBe64(cgen_var_78);
         if (pPropertyCount)
         {
             countingStream->write((uint32_t*)pPropertyCount, sizeof(uint32_t));
         }
         // WARNING PTR CHECK
-        uint64_t cgen_var_75 = (uint64_t)(uintptr_t)pProperties;
-        countingStream->putBe64(cgen_var_75);
+        uint64_t cgen_var_79 = (uint64_t)(uintptr_t)pProperties;
+        countingStream->putBe64(cgen_var_79);
         if (pProperties)
         {
             for (uint32_t i = 0; i < (uint32_t)(*(pPropertyCount)); ++i)
@@ -1281,19 +1407,19 @@
     uint32_t opcode_vkEnumerateDeviceLayerProperties = OP_vkEnumerateDeviceLayerProperties;
     stream->write(&opcode_vkEnumerateDeviceLayerProperties, sizeof(uint32_t));
     stream->write(&packetSize_vkEnumerateDeviceLayerProperties, sizeof(uint32_t));
-    uint64_t cgen_var_76;
-    stream->handleMapping()->mapHandles_VkPhysicalDevice_u64(&local_physicalDevice, &cgen_var_76, 1);
-    stream->write((uint64_t*)&cgen_var_76, 1 * 8);
+    uint64_t cgen_var_80;
+    stream->handleMapping()->mapHandles_VkPhysicalDevice_u64(&local_physicalDevice, &cgen_var_80, 1);
+    stream->write((uint64_t*)&cgen_var_80, 1 * 8);
     // WARNING PTR CHECK
-    uint64_t cgen_var_77 = (uint64_t)(uintptr_t)pPropertyCount;
-    stream->putBe64(cgen_var_77);
+    uint64_t cgen_var_81 = (uint64_t)(uintptr_t)pPropertyCount;
+    stream->putBe64(cgen_var_81);
     if (pPropertyCount)
     {
         stream->write((uint32_t*)pPropertyCount, sizeof(uint32_t));
     }
     // WARNING PTR CHECK
-    uint64_t cgen_var_78 = (uint64_t)(uintptr_t)pProperties;
-    stream->putBe64(cgen_var_78);
+    uint64_t cgen_var_82 = (uint64_t)(uintptr_t)pProperties;
+    stream->putBe64(cgen_var_82);
     if (pProperties)
     {
         for (uint32_t i = 0; i < (uint32_t)(*(pPropertyCount)); ++i)
@@ -1350,6 +1476,7 @@
     uint32_t queueIndex,
     VkQueue* pQueue)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkGetDeviceQueue encode");
     mImpl->log("start vkGetDeviceQueue");
     auto stream = mImpl->stream();
@@ -1365,35 +1492,35 @@
     local_queueIndex = queueIndex;
     countingStream->rewind();
     {
-        uint64_t cgen_var_81;
-        countingStream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_81, 1);
-        countingStream->write((uint64_t*)&cgen_var_81, 1 * 8);
+        uint64_t cgen_var_85;
+        countingStream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_85, 1);
+        countingStream->write((uint64_t*)&cgen_var_85, 1 * 8);
         countingStream->write((uint32_t*)&local_queueFamilyIndex, sizeof(uint32_t));
         countingStream->write((uint32_t*)&local_queueIndex, sizeof(uint32_t));
-        uint64_t cgen_var_82;
-        countingStream->handleMapping()->mapHandles_VkQueue_u64(pQueue, &cgen_var_82, 1);
-        countingStream->write((uint64_t*)&cgen_var_82, 8);
+        uint64_t cgen_var_86;
+        countingStream->handleMapping()->mapHandles_VkQueue_u64(pQueue, &cgen_var_86, 1);
+        countingStream->write((uint64_t*)&cgen_var_86, 8);
     }
     uint32_t packetSize_vkGetDeviceQueue = 4 + 4 + (uint32_t)countingStream->bytesWritten();
     countingStream->rewind();
     uint32_t opcode_vkGetDeviceQueue = OP_vkGetDeviceQueue;
     stream->write(&opcode_vkGetDeviceQueue, sizeof(uint32_t));
     stream->write(&packetSize_vkGetDeviceQueue, sizeof(uint32_t));
-    uint64_t cgen_var_83;
-    stream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_83, 1);
-    stream->write((uint64_t*)&cgen_var_83, 1 * 8);
+    uint64_t cgen_var_87;
+    stream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_87, 1);
+    stream->write((uint64_t*)&cgen_var_87, 1 * 8);
     stream->write((uint32_t*)&local_queueFamilyIndex, sizeof(uint32_t));
     stream->write((uint32_t*)&local_queueIndex, sizeof(uint32_t));
     stream->unsetHandleMapping() /* emit_marshal, is handle, possibly out */;
-    uint64_t cgen_var_84;
-    stream->handleMapping()->mapHandles_VkQueue_u64(pQueue, &cgen_var_84, 1);
-    stream->write((uint64_t*)&cgen_var_84, 8);
+    uint64_t cgen_var_88;
+    stream->handleMapping()->mapHandles_VkQueue_u64(pQueue, &cgen_var_88, 1);
+    stream->write((uint64_t*)&cgen_var_88, 8);
     stream->setHandleMapping(resources->unwrapMapping());
     AEMU_SCOPED_TRACE("vkGetDeviceQueue readParams");
     stream->setHandleMapping(resources->createMapping());
-    uint64_t cgen_var_85;
-    stream->read((uint64_t*)&cgen_var_85, 8);
-    stream->handleMapping()->mapHandles_u64_VkQueue(&cgen_var_85, (VkQueue*)pQueue, 1);
+    uint64_t cgen_var_89;
+    stream->read((uint64_t*)&cgen_var_89, 8);
+    stream->handleMapping()->mapHandles_u64_VkQueue(&cgen_var_89, (VkQueue*)pQueue, 1);
     stream->unsetHandleMapping();
     AEMU_SCOPED_TRACE("vkGetDeviceQueue returnUnmarshal");
     mImpl->log("finish vkGetDeviceQueue");;
@@ -1405,6 +1532,7 @@
     const VkSubmitInfo* pSubmits,
     VkFence fence)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkQueueSubmit encode");
     mImpl->log("start vkQueueSubmit");
     auto stream = mImpl->stream();
@@ -1437,34 +1565,34 @@
     }
     countingStream->rewind();
     {
-        uint64_t cgen_var_86;
-        countingStream->handleMapping()->mapHandles_VkQueue_u64(&local_queue, &cgen_var_86, 1);
-        countingStream->write((uint64_t*)&cgen_var_86, 1 * 8);
+        uint64_t cgen_var_90;
+        countingStream->handleMapping()->mapHandles_VkQueue_u64(&local_queue, &cgen_var_90, 1);
+        countingStream->write((uint64_t*)&cgen_var_90, 1 * 8);
         countingStream->write((uint32_t*)&local_submitCount, sizeof(uint32_t));
         for (uint32_t i = 0; i < (uint32_t)((submitCount)); ++i)
         {
             marshal_VkSubmitInfo(countingStream, (VkSubmitInfo*)(local_pSubmits + i));
         }
-        uint64_t cgen_var_87;
-        countingStream->handleMapping()->mapHandles_VkFence_u64(&local_fence, &cgen_var_87, 1);
-        countingStream->write((uint64_t*)&cgen_var_87, 1 * 8);
+        uint64_t cgen_var_91;
+        countingStream->handleMapping()->mapHandles_VkFence_u64(&local_fence, &cgen_var_91, 1);
+        countingStream->write((uint64_t*)&cgen_var_91, 1 * 8);
     }
     uint32_t packetSize_vkQueueSubmit = 4 + 4 + (uint32_t)countingStream->bytesWritten();
     countingStream->rewind();
     uint32_t opcode_vkQueueSubmit = OP_vkQueueSubmit;
     stream->write(&opcode_vkQueueSubmit, sizeof(uint32_t));
     stream->write(&packetSize_vkQueueSubmit, sizeof(uint32_t));
-    uint64_t cgen_var_88;
-    stream->handleMapping()->mapHandles_VkQueue_u64(&local_queue, &cgen_var_88, 1);
-    stream->write((uint64_t*)&cgen_var_88, 1 * 8);
+    uint64_t cgen_var_92;
+    stream->handleMapping()->mapHandles_VkQueue_u64(&local_queue, &cgen_var_92, 1);
+    stream->write((uint64_t*)&cgen_var_92, 1 * 8);
     stream->write((uint32_t*)&local_submitCount, sizeof(uint32_t));
     for (uint32_t i = 0; i < (uint32_t)((submitCount)); ++i)
     {
         marshal_VkSubmitInfo(stream, (VkSubmitInfo*)(local_pSubmits + i));
     }
-    uint64_t cgen_var_89;
-    stream->handleMapping()->mapHandles_VkFence_u64(&local_fence, &cgen_var_89, 1);
-    stream->write((uint64_t*)&cgen_var_89, 1 * 8);
+    uint64_t cgen_var_93;
+    stream->handleMapping()->mapHandles_VkFence_u64(&local_fence, &cgen_var_93, 1);
+    stream->write((uint64_t*)&cgen_var_93, 1 * 8);
     AEMU_SCOPED_TRACE("vkQueueSubmit readParams");
     AEMU_SCOPED_TRACE("vkQueueSubmit returnUnmarshal");
     VkResult vkQueueSubmit_VkResult_return = (VkResult)0;
@@ -1479,6 +1607,7 @@
 VkResult VkEncoder::vkQueueWaitIdle(
     VkQueue queue)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkQueueWaitIdle encode");
     mImpl->log("start vkQueueWaitIdle");
     auto stream = mImpl->stream();
@@ -1490,18 +1619,18 @@
     local_queue = queue;
     countingStream->rewind();
     {
-        uint64_t cgen_var_90;
-        countingStream->handleMapping()->mapHandles_VkQueue_u64(&local_queue, &cgen_var_90, 1);
-        countingStream->write((uint64_t*)&cgen_var_90, 1 * 8);
+        uint64_t cgen_var_94;
+        countingStream->handleMapping()->mapHandles_VkQueue_u64(&local_queue, &cgen_var_94, 1);
+        countingStream->write((uint64_t*)&cgen_var_94, 1 * 8);
     }
     uint32_t packetSize_vkQueueWaitIdle = 4 + 4 + (uint32_t)countingStream->bytesWritten();
     countingStream->rewind();
     uint32_t opcode_vkQueueWaitIdle = OP_vkQueueWaitIdle;
     stream->write(&opcode_vkQueueWaitIdle, sizeof(uint32_t));
     stream->write(&packetSize_vkQueueWaitIdle, sizeof(uint32_t));
-    uint64_t cgen_var_91;
-    stream->handleMapping()->mapHandles_VkQueue_u64(&local_queue, &cgen_var_91, 1);
-    stream->write((uint64_t*)&cgen_var_91, 1 * 8);
+    uint64_t cgen_var_95;
+    stream->handleMapping()->mapHandles_VkQueue_u64(&local_queue, &cgen_var_95, 1);
+    stream->write((uint64_t*)&cgen_var_95, 1 * 8);
     AEMU_SCOPED_TRACE("vkQueueWaitIdle readParams");
     AEMU_SCOPED_TRACE("vkQueueWaitIdle returnUnmarshal");
     VkResult vkQueueWaitIdle_VkResult_return = (VkResult)0;
@@ -1516,6 +1645,7 @@
 VkResult VkEncoder::vkDeviceWaitIdle(
     VkDevice device)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkDeviceWaitIdle encode");
     mImpl->log("start vkDeviceWaitIdle");
     auto stream = mImpl->stream();
@@ -1527,18 +1657,18 @@
     local_device = device;
     countingStream->rewind();
     {
-        uint64_t cgen_var_92;
-        countingStream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_92, 1);
-        countingStream->write((uint64_t*)&cgen_var_92, 1 * 8);
+        uint64_t cgen_var_96;
+        countingStream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_96, 1);
+        countingStream->write((uint64_t*)&cgen_var_96, 1 * 8);
     }
     uint32_t packetSize_vkDeviceWaitIdle = 4 + 4 + (uint32_t)countingStream->bytesWritten();
     countingStream->rewind();
     uint32_t opcode_vkDeviceWaitIdle = OP_vkDeviceWaitIdle;
     stream->write(&opcode_vkDeviceWaitIdle, sizeof(uint32_t));
     stream->write(&packetSize_vkDeviceWaitIdle, sizeof(uint32_t));
-    uint64_t cgen_var_93;
-    stream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_93, 1);
-    stream->write((uint64_t*)&cgen_var_93, 1 * 8);
+    uint64_t cgen_var_97;
+    stream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_97, 1);
+    stream->write((uint64_t*)&cgen_var_97, 1 * 8);
     AEMU_SCOPED_TRACE("vkDeviceWaitIdle readParams");
     AEMU_SCOPED_TRACE("vkDeviceWaitIdle returnUnmarshal");
     VkResult vkDeviceWaitIdle_VkResult_return = (VkResult)0;
@@ -1556,6 +1686,7 @@
     const VkAllocationCallbacks* pAllocator,
     VkDeviceMemory* pMemory)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkAllocateMemory encode");
     mImpl->log("start vkAllocateMemory");
     auto stream = mImpl->stream();
@@ -1590,47 +1721,47 @@
     }
     countingStream->rewind();
     {
-        uint64_t cgen_var_94;
-        countingStream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_94, 1);
-        countingStream->write((uint64_t*)&cgen_var_94, 1 * 8);
+        uint64_t cgen_var_98;
+        countingStream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_98, 1);
+        countingStream->write((uint64_t*)&cgen_var_98, 1 * 8);
         marshal_VkMemoryAllocateInfo(countingStream, (VkMemoryAllocateInfo*)(local_pAllocateInfo));
         // WARNING PTR CHECK
-        uint64_t cgen_var_95 = (uint64_t)(uintptr_t)local_pAllocator;
-        countingStream->putBe64(cgen_var_95);
+        uint64_t cgen_var_99 = (uint64_t)(uintptr_t)local_pAllocator;
+        countingStream->putBe64(cgen_var_99);
         if (local_pAllocator)
         {
             marshal_VkAllocationCallbacks(countingStream, (VkAllocationCallbacks*)(local_pAllocator));
         }
-        uint64_t cgen_var_96;
-        countingStream->handleMapping()->mapHandles_VkDeviceMemory_u64(pMemory, &cgen_var_96, 1);
-        countingStream->write((uint64_t*)&cgen_var_96, 8);
+        uint64_t cgen_var_100;
+        countingStream->handleMapping()->mapHandles_VkDeviceMemory_u64(pMemory, &cgen_var_100, 1);
+        countingStream->write((uint64_t*)&cgen_var_100, 8);
     }
     uint32_t packetSize_vkAllocateMemory = 4 + 4 + (uint32_t)countingStream->bytesWritten();
     countingStream->rewind();
     uint32_t opcode_vkAllocateMemory = OP_vkAllocateMemory;
     stream->write(&opcode_vkAllocateMemory, sizeof(uint32_t));
     stream->write(&packetSize_vkAllocateMemory, sizeof(uint32_t));
-    uint64_t cgen_var_97;
-    stream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_97, 1);
-    stream->write((uint64_t*)&cgen_var_97, 1 * 8);
+    uint64_t cgen_var_101;
+    stream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_101, 1);
+    stream->write((uint64_t*)&cgen_var_101, 1 * 8);
     marshal_VkMemoryAllocateInfo(stream, (VkMemoryAllocateInfo*)(local_pAllocateInfo));
     // WARNING PTR CHECK
-    uint64_t cgen_var_98 = (uint64_t)(uintptr_t)local_pAllocator;
-    stream->putBe64(cgen_var_98);
+    uint64_t cgen_var_102 = (uint64_t)(uintptr_t)local_pAllocator;
+    stream->putBe64(cgen_var_102);
     if (local_pAllocator)
     {
         marshal_VkAllocationCallbacks(stream, (VkAllocationCallbacks*)(local_pAllocator));
     }
     stream->unsetHandleMapping() /* emit_marshal, is handle, possibly out */;
-    uint64_t cgen_var_99;
-    stream->handleMapping()->mapHandles_VkDeviceMemory_u64(pMemory, &cgen_var_99, 1);
-    stream->write((uint64_t*)&cgen_var_99, 8);
+    uint64_t cgen_var_103;
+    stream->handleMapping()->mapHandles_VkDeviceMemory_u64(pMemory, &cgen_var_103, 1);
+    stream->write((uint64_t*)&cgen_var_103, 8);
     stream->setHandleMapping(resources->unwrapMapping());
     AEMU_SCOPED_TRACE("vkAllocateMemory readParams");
     stream->setHandleMapping(resources->createMapping());
-    uint64_t cgen_var_100;
-    stream->read((uint64_t*)&cgen_var_100, 8);
-    stream->handleMapping()->mapHandles_u64_VkDeviceMemory(&cgen_var_100, (VkDeviceMemory*)pMemory, 1);
+    uint64_t cgen_var_104;
+    stream->read((uint64_t*)&cgen_var_104, 8);
+    stream->handleMapping()->mapHandles_u64_VkDeviceMemory(&cgen_var_104, (VkDeviceMemory*)pMemory, 1);
     stream->unsetHandleMapping();
     AEMU_SCOPED_TRACE("vkAllocateMemory returnUnmarshal");
     VkResult vkAllocateMemory_VkResult_return = (VkResult)0;
@@ -1647,6 +1778,7 @@
     VkDeviceMemory memory,
     const VkAllocationCallbacks* pAllocator)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkFreeMemory encode");
     mImpl->log("start vkFreeMemory");
     auto stream = mImpl->stream();
@@ -1669,15 +1801,15 @@
     mImpl->resources()->deviceMemoryTransform_tohost((VkDeviceMemory*)&local_memory, 1, (VkDeviceSize*)nullptr, 0, (VkDeviceSize*)nullptr, 0, (uint32_t*)nullptr, 0, (uint32_t*)nullptr, 0);
     countingStream->rewind();
     {
-        uint64_t cgen_var_101;
-        countingStream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_101, 1);
-        countingStream->write((uint64_t*)&cgen_var_101, 1 * 8);
-        uint64_t cgen_var_102;
-        countingStream->handleMapping()->mapHandles_VkDeviceMemory_u64(&local_memory, &cgen_var_102, 1);
-        countingStream->write((uint64_t*)&cgen_var_102, 1 * 8);
+        uint64_t cgen_var_105;
+        countingStream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_105, 1);
+        countingStream->write((uint64_t*)&cgen_var_105, 1 * 8);
+        uint64_t cgen_var_106;
+        countingStream->handleMapping()->mapHandles_VkDeviceMemory_u64(&local_memory, &cgen_var_106, 1);
+        countingStream->write((uint64_t*)&cgen_var_106, 1 * 8);
         // WARNING PTR CHECK
-        uint64_t cgen_var_103 = (uint64_t)(uintptr_t)local_pAllocator;
-        countingStream->putBe64(cgen_var_103);
+        uint64_t cgen_var_107 = (uint64_t)(uintptr_t)local_pAllocator;
+        countingStream->putBe64(cgen_var_107);
         if (local_pAllocator)
         {
             marshal_VkAllocationCallbacks(countingStream, (VkAllocationCallbacks*)(local_pAllocator));
@@ -1688,15 +1820,15 @@
     uint32_t opcode_vkFreeMemory = OP_vkFreeMemory;
     stream->write(&opcode_vkFreeMemory, sizeof(uint32_t));
     stream->write(&packetSize_vkFreeMemory, sizeof(uint32_t));
-    uint64_t cgen_var_104;
-    stream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_104, 1);
-    stream->write((uint64_t*)&cgen_var_104, 1 * 8);
-    uint64_t cgen_var_105;
-    stream->handleMapping()->mapHandles_VkDeviceMemory_u64(&local_memory, &cgen_var_105, 1);
-    stream->write((uint64_t*)&cgen_var_105, 1 * 8);
+    uint64_t cgen_var_108;
+    stream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_108, 1);
+    stream->write((uint64_t*)&cgen_var_108, 1 * 8);
+    uint64_t cgen_var_109;
+    stream->handleMapping()->mapHandles_VkDeviceMemory_u64(&local_memory, &cgen_var_109, 1);
+    stream->write((uint64_t*)&cgen_var_109, 1 * 8);
     // WARNING PTR CHECK
-    uint64_t cgen_var_106 = (uint64_t)(uintptr_t)local_pAllocator;
-    stream->putBe64(cgen_var_106);
+    uint64_t cgen_var_110 = (uint64_t)(uintptr_t)local_pAllocator;
+    stream->putBe64(cgen_var_110);
     if (local_pAllocator)
     {
         marshal_VkAllocationCallbacks(stream, (VkAllocationCallbacks*)(local_pAllocator));
@@ -1735,6 +1867,7 @@
     uint32_t memoryRangeCount,
     const VkMappedMemoryRange* pMemoryRanges)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkFlushMappedMemoryRanges encode");
     mImpl->log("start vkFlushMappedMemoryRanges");
     VALIDATE_RET(VkResult, VK_SUCCESS, mImpl->validation()->on_vkFlushMappedMemoryRanges(this, VK_SUCCESS, device, memoryRangeCount, pMemoryRanges));
@@ -1766,9 +1899,9 @@
     }
     countingStream->rewind();
     {
-        uint64_t cgen_var_107;
-        countingStream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_107, 1);
-        countingStream->write((uint64_t*)&cgen_var_107, 1 * 8);
+        uint64_t cgen_var_111;
+        countingStream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_111, 1);
+        countingStream->write((uint64_t*)&cgen_var_111, 1 * 8);
         countingStream->write((uint32_t*)&local_memoryRangeCount, sizeof(uint32_t));
         for (uint32_t i = 0; i < (uint32_t)((memoryRangeCount)); ++i)
         {
@@ -1799,9 +1932,9 @@
     uint32_t opcode_vkFlushMappedMemoryRanges = OP_vkFlushMappedMemoryRanges;
     stream->write(&opcode_vkFlushMappedMemoryRanges, sizeof(uint32_t));
     stream->write(&packetSize_vkFlushMappedMemoryRanges, sizeof(uint32_t));
-    uint64_t cgen_var_108;
-    stream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_108, 1);
-    stream->write((uint64_t*)&cgen_var_108, 1 * 8);
+    uint64_t cgen_var_112;
+    stream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_112, 1);
+    stream->write((uint64_t*)&cgen_var_112, 1 * 8);
     stream->write((uint32_t*)&local_memoryRangeCount, sizeof(uint32_t));
     for (uint32_t i = 0; i < (uint32_t)((memoryRangeCount)); ++i)
     {
@@ -1842,6 +1975,7 @@
     uint32_t memoryRangeCount,
     const VkMappedMemoryRange* pMemoryRanges)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkInvalidateMappedMemoryRanges encode");
     mImpl->log("start vkInvalidateMappedMemoryRanges");
     VALIDATE_RET(VkResult, VK_SUCCESS, mImpl->validation()->on_vkInvalidateMappedMemoryRanges(this, VK_SUCCESS, device, memoryRangeCount, pMemoryRanges));
@@ -1873,9 +2007,9 @@
     }
     countingStream->rewind();
     {
-        uint64_t cgen_var_109;
-        countingStream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_109, 1);
-        countingStream->write((uint64_t*)&cgen_var_109, 1 * 8);
+        uint64_t cgen_var_113;
+        countingStream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_113, 1);
+        countingStream->write((uint64_t*)&cgen_var_113, 1 * 8);
         countingStream->write((uint32_t*)&local_memoryRangeCount, sizeof(uint32_t));
         for (uint32_t i = 0; i < (uint32_t)((memoryRangeCount)); ++i)
         {
@@ -1887,9 +2021,9 @@
     uint32_t opcode_vkInvalidateMappedMemoryRanges = OP_vkInvalidateMappedMemoryRanges;
     stream->write(&opcode_vkInvalidateMappedMemoryRanges, sizeof(uint32_t));
     stream->write(&packetSize_vkInvalidateMappedMemoryRanges, sizeof(uint32_t));
-    uint64_t cgen_var_110;
-    stream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_110, 1);
-    stream->write((uint64_t*)&cgen_var_110, 1 * 8);
+    uint64_t cgen_var_114;
+    stream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_114, 1);
+    stream->write((uint64_t*)&cgen_var_114, 1 * 8);
     stream->write((uint32_t*)&local_memoryRangeCount, sizeof(uint32_t));
     for (uint32_t i = 0; i < (uint32_t)((memoryRangeCount)); ++i)
     {
@@ -1930,6 +2064,7 @@
     VkDeviceMemory memory,
     VkDeviceSize* pCommittedMemoryInBytes)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkGetDeviceMemoryCommitment encode");
     mImpl->log("start vkGetDeviceMemoryCommitment");
     auto stream = mImpl->stream();
@@ -1944,12 +2079,12 @@
     mImpl->resources()->deviceMemoryTransform_tohost((VkDeviceMemory*)&local_memory, 1, (VkDeviceSize*)nullptr, 0, (VkDeviceSize*)nullptr, 0, (uint32_t*)nullptr, 0, (uint32_t*)nullptr, 0);
     countingStream->rewind();
     {
-        uint64_t cgen_var_111;
-        countingStream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_111, 1);
-        countingStream->write((uint64_t*)&cgen_var_111, 1 * 8);
-        uint64_t cgen_var_112;
-        countingStream->handleMapping()->mapHandles_VkDeviceMemory_u64(&local_memory, &cgen_var_112, 1);
-        countingStream->write((uint64_t*)&cgen_var_112, 1 * 8);
+        uint64_t cgen_var_115;
+        countingStream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_115, 1);
+        countingStream->write((uint64_t*)&cgen_var_115, 1 * 8);
+        uint64_t cgen_var_116;
+        countingStream->handleMapping()->mapHandles_VkDeviceMemory_u64(&local_memory, &cgen_var_116, 1);
+        countingStream->write((uint64_t*)&cgen_var_116, 1 * 8);
         countingStream->write((VkDeviceSize*)pCommittedMemoryInBytes, sizeof(VkDeviceSize));
     }
     uint32_t packetSize_vkGetDeviceMemoryCommitment = 4 + 4 + (uint32_t)countingStream->bytesWritten();
@@ -1957,12 +2092,12 @@
     uint32_t opcode_vkGetDeviceMemoryCommitment = OP_vkGetDeviceMemoryCommitment;
     stream->write(&opcode_vkGetDeviceMemoryCommitment, sizeof(uint32_t));
     stream->write(&packetSize_vkGetDeviceMemoryCommitment, sizeof(uint32_t));
-    uint64_t cgen_var_113;
-    stream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_113, 1);
-    stream->write((uint64_t*)&cgen_var_113, 1 * 8);
-    uint64_t cgen_var_114;
-    stream->handleMapping()->mapHandles_VkDeviceMemory_u64(&local_memory, &cgen_var_114, 1);
-    stream->write((uint64_t*)&cgen_var_114, 1 * 8);
+    uint64_t cgen_var_117;
+    stream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_117, 1);
+    stream->write((uint64_t*)&cgen_var_117, 1 * 8);
+    uint64_t cgen_var_118;
+    stream->handleMapping()->mapHandles_VkDeviceMemory_u64(&local_memory, &cgen_var_118, 1);
+    stream->write((uint64_t*)&cgen_var_118, 1 * 8);
     stream->write((VkDeviceSize*)pCommittedMemoryInBytes, sizeof(VkDeviceSize));
     AEMU_SCOPED_TRACE("vkGetDeviceMemoryCommitment readParams");
     stream->read((VkDeviceSize*)pCommittedMemoryInBytes, sizeof(VkDeviceSize));
@@ -1976,6 +2111,7 @@
     VkDeviceMemory memory,
     VkDeviceSize memoryOffset)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkBindBufferMemory encode");
     mImpl->log("start vkBindBufferMemory");
     auto stream = mImpl->stream();
@@ -1994,15 +2130,15 @@
     mImpl->resources()->deviceMemoryTransform_tohost((VkDeviceMemory*)&local_memory, 1, (VkDeviceSize*)&local_memoryOffset, 1, (VkDeviceSize*)nullptr, 0, (uint32_t*)nullptr, 0, (uint32_t*)nullptr, 0);
     countingStream->rewind();
     {
-        uint64_t cgen_var_115;
-        countingStream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_115, 1);
-        countingStream->write((uint64_t*)&cgen_var_115, 1 * 8);
-        uint64_t cgen_var_116;
-        countingStream->handleMapping()->mapHandles_VkBuffer_u64(&local_buffer, &cgen_var_116, 1);
-        countingStream->write((uint64_t*)&cgen_var_116, 1 * 8);
-        uint64_t cgen_var_117;
-        countingStream->handleMapping()->mapHandles_VkDeviceMemory_u64(&local_memory, &cgen_var_117, 1);
-        countingStream->write((uint64_t*)&cgen_var_117, 1 * 8);
+        uint64_t cgen_var_119;
+        countingStream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_119, 1);
+        countingStream->write((uint64_t*)&cgen_var_119, 1 * 8);
+        uint64_t cgen_var_120;
+        countingStream->handleMapping()->mapHandles_VkBuffer_u64(&local_buffer, &cgen_var_120, 1);
+        countingStream->write((uint64_t*)&cgen_var_120, 1 * 8);
+        uint64_t cgen_var_121;
+        countingStream->handleMapping()->mapHandles_VkDeviceMemory_u64(&local_memory, &cgen_var_121, 1);
+        countingStream->write((uint64_t*)&cgen_var_121, 1 * 8);
         countingStream->write((VkDeviceSize*)&local_memoryOffset, sizeof(VkDeviceSize));
     }
     uint32_t packetSize_vkBindBufferMemory = 4 + 4 + (uint32_t)countingStream->bytesWritten();
@@ -2010,15 +2146,15 @@
     uint32_t opcode_vkBindBufferMemory = OP_vkBindBufferMemory;
     stream->write(&opcode_vkBindBufferMemory, sizeof(uint32_t));
     stream->write(&packetSize_vkBindBufferMemory, sizeof(uint32_t));
-    uint64_t cgen_var_118;
-    stream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_118, 1);
-    stream->write((uint64_t*)&cgen_var_118, 1 * 8);
-    uint64_t cgen_var_119;
-    stream->handleMapping()->mapHandles_VkBuffer_u64(&local_buffer, &cgen_var_119, 1);
-    stream->write((uint64_t*)&cgen_var_119, 1 * 8);
-    uint64_t cgen_var_120;
-    stream->handleMapping()->mapHandles_VkDeviceMemory_u64(&local_memory, &cgen_var_120, 1);
-    stream->write((uint64_t*)&cgen_var_120, 1 * 8);
+    uint64_t cgen_var_122;
+    stream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_122, 1);
+    stream->write((uint64_t*)&cgen_var_122, 1 * 8);
+    uint64_t cgen_var_123;
+    stream->handleMapping()->mapHandles_VkBuffer_u64(&local_buffer, &cgen_var_123, 1);
+    stream->write((uint64_t*)&cgen_var_123, 1 * 8);
+    uint64_t cgen_var_124;
+    stream->handleMapping()->mapHandles_VkDeviceMemory_u64(&local_memory, &cgen_var_124, 1);
+    stream->write((uint64_t*)&cgen_var_124, 1 * 8);
     stream->write((VkDeviceSize*)&local_memoryOffset, sizeof(VkDeviceSize));
     AEMU_SCOPED_TRACE("vkBindBufferMemory readParams");
     AEMU_SCOPED_TRACE("vkBindBufferMemory returnUnmarshal");
@@ -2037,6 +2173,7 @@
     VkDeviceMemory memory,
     VkDeviceSize memoryOffset)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkBindImageMemory encode");
     mImpl->log("start vkBindImageMemory");
     auto stream = mImpl->stream();
@@ -2055,15 +2192,15 @@
     mImpl->resources()->deviceMemoryTransform_tohost((VkDeviceMemory*)&local_memory, 1, (VkDeviceSize*)&local_memoryOffset, 1, (VkDeviceSize*)nullptr, 0, (uint32_t*)nullptr, 0, (uint32_t*)nullptr, 0);
     countingStream->rewind();
     {
-        uint64_t cgen_var_121;
-        countingStream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_121, 1);
-        countingStream->write((uint64_t*)&cgen_var_121, 1 * 8);
-        uint64_t cgen_var_122;
-        countingStream->handleMapping()->mapHandles_VkImage_u64(&local_image, &cgen_var_122, 1);
-        countingStream->write((uint64_t*)&cgen_var_122, 1 * 8);
-        uint64_t cgen_var_123;
-        countingStream->handleMapping()->mapHandles_VkDeviceMemory_u64(&local_memory, &cgen_var_123, 1);
-        countingStream->write((uint64_t*)&cgen_var_123, 1 * 8);
+        uint64_t cgen_var_125;
+        countingStream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_125, 1);
+        countingStream->write((uint64_t*)&cgen_var_125, 1 * 8);
+        uint64_t cgen_var_126;
+        countingStream->handleMapping()->mapHandles_VkImage_u64(&local_image, &cgen_var_126, 1);
+        countingStream->write((uint64_t*)&cgen_var_126, 1 * 8);
+        uint64_t cgen_var_127;
+        countingStream->handleMapping()->mapHandles_VkDeviceMemory_u64(&local_memory, &cgen_var_127, 1);
+        countingStream->write((uint64_t*)&cgen_var_127, 1 * 8);
         countingStream->write((VkDeviceSize*)&local_memoryOffset, sizeof(VkDeviceSize));
     }
     uint32_t packetSize_vkBindImageMemory = 4 + 4 + (uint32_t)countingStream->bytesWritten();
@@ -2071,15 +2208,15 @@
     uint32_t opcode_vkBindImageMemory = OP_vkBindImageMemory;
     stream->write(&opcode_vkBindImageMemory, sizeof(uint32_t));
     stream->write(&packetSize_vkBindImageMemory, sizeof(uint32_t));
-    uint64_t cgen_var_124;
-    stream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_124, 1);
-    stream->write((uint64_t*)&cgen_var_124, 1 * 8);
-    uint64_t cgen_var_125;
-    stream->handleMapping()->mapHandles_VkImage_u64(&local_image, &cgen_var_125, 1);
-    stream->write((uint64_t*)&cgen_var_125, 1 * 8);
-    uint64_t cgen_var_126;
-    stream->handleMapping()->mapHandles_VkDeviceMemory_u64(&local_memory, &cgen_var_126, 1);
-    stream->write((uint64_t*)&cgen_var_126, 1 * 8);
+    uint64_t cgen_var_128;
+    stream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_128, 1);
+    stream->write((uint64_t*)&cgen_var_128, 1 * 8);
+    uint64_t cgen_var_129;
+    stream->handleMapping()->mapHandles_VkImage_u64(&local_image, &cgen_var_129, 1);
+    stream->write((uint64_t*)&cgen_var_129, 1 * 8);
+    uint64_t cgen_var_130;
+    stream->handleMapping()->mapHandles_VkDeviceMemory_u64(&local_memory, &cgen_var_130, 1);
+    stream->write((uint64_t*)&cgen_var_130, 1 * 8);
     stream->write((VkDeviceSize*)&local_memoryOffset, sizeof(VkDeviceSize));
     AEMU_SCOPED_TRACE("vkBindImageMemory readParams");
     AEMU_SCOPED_TRACE("vkBindImageMemory returnUnmarshal");
@@ -2097,6 +2234,7 @@
     VkBuffer buffer,
     VkMemoryRequirements* pMemoryRequirements)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkGetBufferMemoryRequirements encode");
     mImpl->log("start vkGetBufferMemoryRequirements");
     auto stream = mImpl->stream();
@@ -2110,12 +2248,12 @@
     local_buffer = buffer;
     countingStream->rewind();
     {
-        uint64_t cgen_var_127;
-        countingStream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_127, 1);
-        countingStream->write((uint64_t*)&cgen_var_127, 1 * 8);
-        uint64_t cgen_var_128;
-        countingStream->handleMapping()->mapHandles_VkBuffer_u64(&local_buffer, &cgen_var_128, 1);
-        countingStream->write((uint64_t*)&cgen_var_128, 1 * 8);
+        uint64_t cgen_var_131;
+        countingStream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_131, 1);
+        countingStream->write((uint64_t*)&cgen_var_131, 1 * 8);
+        uint64_t cgen_var_132;
+        countingStream->handleMapping()->mapHandles_VkBuffer_u64(&local_buffer, &cgen_var_132, 1);
+        countingStream->write((uint64_t*)&cgen_var_132, 1 * 8);
         marshal_VkMemoryRequirements(countingStream, (VkMemoryRequirements*)(pMemoryRequirements));
     }
     uint32_t packetSize_vkGetBufferMemoryRequirements = 4 + 4 + (uint32_t)countingStream->bytesWritten();
@@ -2123,12 +2261,12 @@
     uint32_t opcode_vkGetBufferMemoryRequirements = OP_vkGetBufferMemoryRequirements;
     stream->write(&opcode_vkGetBufferMemoryRequirements, sizeof(uint32_t));
     stream->write(&packetSize_vkGetBufferMemoryRequirements, sizeof(uint32_t));
-    uint64_t cgen_var_129;
-    stream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_129, 1);
-    stream->write((uint64_t*)&cgen_var_129, 1 * 8);
-    uint64_t cgen_var_130;
-    stream->handleMapping()->mapHandles_VkBuffer_u64(&local_buffer, &cgen_var_130, 1);
-    stream->write((uint64_t*)&cgen_var_130, 1 * 8);
+    uint64_t cgen_var_133;
+    stream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_133, 1);
+    stream->write((uint64_t*)&cgen_var_133, 1 * 8);
+    uint64_t cgen_var_134;
+    stream->handleMapping()->mapHandles_VkBuffer_u64(&local_buffer, &cgen_var_134, 1);
+    stream->write((uint64_t*)&cgen_var_134, 1 * 8);
     marshal_VkMemoryRequirements(stream, (VkMemoryRequirements*)(pMemoryRequirements));
     AEMU_SCOPED_TRACE("vkGetBufferMemoryRequirements readParams");
     unmarshal_VkMemoryRequirements(stream, (VkMemoryRequirements*)(pMemoryRequirements));
@@ -2145,6 +2283,7 @@
     VkImage image,
     VkMemoryRequirements* pMemoryRequirements)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkGetImageMemoryRequirements encode");
     mImpl->log("start vkGetImageMemoryRequirements");
     auto stream = mImpl->stream();
@@ -2158,71 +2297,72 @@
     local_image = image;
     countingStream->rewind();
     {
-        uint64_t cgen_var_131;
-        countingStream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_131, 1);
-        countingStream->write((uint64_t*)&cgen_var_131, 1 * 8);
-        uint64_t cgen_var_132;
-        countingStream->handleMapping()->mapHandles_VkImage_u64(&local_image, &cgen_var_132, 1);
-        countingStream->write((uint64_t*)&cgen_var_132, 1 * 8);
-        marshal_VkMemoryRequirements(countingStream, (VkMemoryRequirements*)(pMemoryRequirements));
-    }
-    uint32_t packetSize_vkGetImageMemoryRequirements = 4 + 4 + (uint32_t)countingStream->bytesWritten();
-    countingStream->rewind();
-    uint32_t opcode_vkGetImageMemoryRequirements = OP_vkGetImageMemoryRequirements;
-    stream->write(&opcode_vkGetImageMemoryRequirements, sizeof(uint32_t));
-    stream->write(&packetSize_vkGetImageMemoryRequirements, sizeof(uint32_t));
-    uint64_t cgen_var_133;
-    stream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_133, 1);
-    stream->write((uint64_t*)&cgen_var_133, 1 * 8);
-    uint64_t cgen_var_134;
-    stream->handleMapping()->mapHandles_VkImage_u64(&local_image, &cgen_var_134, 1);
-    stream->write((uint64_t*)&cgen_var_134, 1 * 8);
-    marshal_VkMemoryRequirements(stream, (VkMemoryRequirements*)(pMemoryRequirements));
-    AEMU_SCOPED_TRACE("vkGetImageMemoryRequirements readParams");
-    unmarshal_VkMemoryRequirements(stream, (VkMemoryRequirements*)(pMemoryRequirements));
-    if (pMemoryRequirements)
-    {
-        transform_fromhost_VkMemoryRequirements(mImpl->resources(), (VkMemoryRequirements*)(pMemoryRequirements));
-    }
-    AEMU_SCOPED_TRACE("vkGetImageMemoryRequirements returnUnmarshal");
-    mImpl->log("finish vkGetImageMemoryRequirements");;
-}
-
-void VkEncoder::vkGetImageSparseMemoryRequirements(
-    VkDevice device,
-    VkImage image,
-    uint32_t* pSparseMemoryRequirementCount,
-    VkSparseImageMemoryRequirements* pSparseMemoryRequirements)
-{
-    AEMU_SCOPED_TRACE("vkGetImageSparseMemoryRequirements encode");
-    mImpl->log("start vkGetImageSparseMemoryRequirements");
-    auto stream = mImpl->stream();
-    auto countingStream = mImpl->countingStream();
-    auto resources = mImpl->resources();
-    auto pool = mImpl->pool();
-    stream->setHandleMapping(resources->unwrapMapping());
-    VkDevice local_device;
-    VkImage local_image;
-    local_device = device;
-    local_image = image;
-    countingStream->rewind();
-    {
         uint64_t cgen_var_135;
         countingStream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_135, 1);
         countingStream->write((uint64_t*)&cgen_var_135, 1 * 8);
         uint64_t cgen_var_136;
         countingStream->handleMapping()->mapHandles_VkImage_u64(&local_image, &cgen_var_136, 1);
         countingStream->write((uint64_t*)&cgen_var_136, 1 * 8);
+        marshal_VkMemoryRequirements(countingStream, (VkMemoryRequirements*)(pMemoryRequirements));
+    }
+    uint32_t packetSize_vkGetImageMemoryRequirements = 4 + 4 + (uint32_t)countingStream->bytesWritten();
+    countingStream->rewind();
+    uint32_t opcode_vkGetImageMemoryRequirements = OP_vkGetImageMemoryRequirements;
+    stream->write(&opcode_vkGetImageMemoryRequirements, sizeof(uint32_t));
+    stream->write(&packetSize_vkGetImageMemoryRequirements, sizeof(uint32_t));
+    uint64_t cgen_var_137;
+    stream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_137, 1);
+    stream->write((uint64_t*)&cgen_var_137, 1 * 8);
+    uint64_t cgen_var_138;
+    stream->handleMapping()->mapHandles_VkImage_u64(&local_image, &cgen_var_138, 1);
+    stream->write((uint64_t*)&cgen_var_138, 1 * 8);
+    marshal_VkMemoryRequirements(stream, (VkMemoryRequirements*)(pMemoryRequirements));
+    AEMU_SCOPED_TRACE("vkGetImageMemoryRequirements readParams");
+    unmarshal_VkMemoryRequirements(stream, (VkMemoryRequirements*)(pMemoryRequirements));
+    if (pMemoryRequirements)
+    {
+        transform_fromhost_VkMemoryRequirements(mImpl->resources(), (VkMemoryRequirements*)(pMemoryRequirements));
+    }
+    AEMU_SCOPED_TRACE("vkGetImageMemoryRequirements returnUnmarshal");
+    mImpl->log("finish vkGetImageMemoryRequirements");;
+}
+
+void VkEncoder::vkGetImageSparseMemoryRequirements(
+    VkDevice device,
+    VkImage image,
+    uint32_t* pSparseMemoryRequirementCount,
+    VkSparseImageMemoryRequirements* pSparseMemoryRequirements)
+{
+    AutoLock encoderLock(mImpl->lock);
+    AEMU_SCOPED_TRACE("vkGetImageSparseMemoryRequirements encode");
+    mImpl->log("start vkGetImageSparseMemoryRequirements");
+    auto stream = mImpl->stream();
+    auto countingStream = mImpl->countingStream();
+    auto resources = mImpl->resources();
+    auto pool = mImpl->pool();
+    stream->setHandleMapping(resources->unwrapMapping());
+    VkDevice local_device;
+    VkImage local_image;
+    local_device = device;
+    local_image = image;
+    countingStream->rewind();
+    {
+        uint64_t cgen_var_139;
+        countingStream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_139, 1);
+        countingStream->write((uint64_t*)&cgen_var_139, 1 * 8);
+        uint64_t cgen_var_140;
+        countingStream->handleMapping()->mapHandles_VkImage_u64(&local_image, &cgen_var_140, 1);
+        countingStream->write((uint64_t*)&cgen_var_140, 1 * 8);
         // WARNING PTR CHECK
-        uint64_t cgen_var_137 = (uint64_t)(uintptr_t)pSparseMemoryRequirementCount;
-        countingStream->putBe64(cgen_var_137);
+        uint64_t cgen_var_141 = (uint64_t)(uintptr_t)pSparseMemoryRequirementCount;
+        countingStream->putBe64(cgen_var_141);
         if (pSparseMemoryRequirementCount)
         {
             countingStream->write((uint32_t*)pSparseMemoryRequirementCount, sizeof(uint32_t));
         }
         // WARNING PTR CHECK
-        uint64_t cgen_var_138 = (uint64_t)(uintptr_t)pSparseMemoryRequirements;
-        countingStream->putBe64(cgen_var_138);
+        uint64_t cgen_var_142 = (uint64_t)(uintptr_t)pSparseMemoryRequirements;
+        countingStream->putBe64(cgen_var_142);
         if (pSparseMemoryRequirements)
         {
             for (uint32_t i = 0; i < (uint32_t)(*(pSparseMemoryRequirementCount)); ++i)
@@ -2236,22 +2376,22 @@
     uint32_t opcode_vkGetImageSparseMemoryRequirements = OP_vkGetImageSparseMemoryRequirements;
     stream->write(&opcode_vkGetImageSparseMemoryRequirements, sizeof(uint32_t));
     stream->write(&packetSize_vkGetImageSparseMemoryRequirements, sizeof(uint32_t));
-    uint64_t cgen_var_139;
-    stream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_139, 1);
-    stream->write((uint64_t*)&cgen_var_139, 1 * 8);
-    uint64_t cgen_var_140;
-    stream->handleMapping()->mapHandles_VkImage_u64(&local_image, &cgen_var_140, 1);
-    stream->write((uint64_t*)&cgen_var_140, 1 * 8);
+    uint64_t cgen_var_143;
+    stream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_143, 1);
+    stream->write((uint64_t*)&cgen_var_143, 1 * 8);
+    uint64_t cgen_var_144;
+    stream->handleMapping()->mapHandles_VkImage_u64(&local_image, &cgen_var_144, 1);
+    stream->write((uint64_t*)&cgen_var_144, 1 * 8);
     // WARNING PTR CHECK
-    uint64_t cgen_var_141 = (uint64_t)(uintptr_t)pSparseMemoryRequirementCount;
-    stream->putBe64(cgen_var_141);
+    uint64_t cgen_var_145 = (uint64_t)(uintptr_t)pSparseMemoryRequirementCount;
+    stream->putBe64(cgen_var_145);
     if (pSparseMemoryRequirementCount)
     {
         stream->write((uint32_t*)pSparseMemoryRequirementCount, sizeof(uint32_t));
     }
     // WARNING PTR CHECK
-    uint64_t cgen_var_142 = (uint64_t)(uintptr_t)pSparseMemoryRequirements;
-    stream->putBe64(cgen_var_142);
+    uint64_t cgen_var_146 = (uint64_t)(uintptr_t)pSparseMemoryRequirements;
+    stream->putBe64(cgen_var_146);
     if (pSparseMemoryRequirements)
     {
         for (uint32_t i = 0; i < (uint32_t)(*(pSparseMemoryRequirementCount)); ++i)
@@ -2306,6 +2446,7 @@
     uint32_t* pPropertyCount,
     VkSparseImageFormatProperties* pProperties)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkGetPhysicalDeviceSparseImageFormatProperties encode");
     mImpl->log("start vkGetPhysicalDeviceSparseImageFormatProperties");
     auto stream = mImpl->stream();
@@ -2327,24 +2468,24 @@
     local_tiling = tiling;
     countingStream->rewind();
     {
-        uint64_t cgen_var_145;
-        countingStream->handleMapping()->mapHandles_VkPhysicalDevice_u64(&local_physicalDevice, &cgen_var_145, 1);
-        countingStream->write((uint64_t*)&cgen_var_145, 1 * 8);
+        uint64_t cgen_var_149;
+        countingStream->handleMapping()->mapHandles_VkPhysicalDevice_u64(&local_physicalDevice, &cgen_var_149, 1);
+        countingStream->write((uint64_t*)&cgen_var_149, 1 * 8);
         countingStream->write((VkFormat*)&local_format, sizeof(VkFormat));
         countingStream->write((VkImageType*)&local_type, sizeof(VkImageType));
         countingStream->write((VkSampleCountFlagBits*)&local_samples, sizeof(VkSampleCountFlagBits));
         countingStream->write((VkImageUsageFlags*)&local_usage, sizeof(VkImageUsageFlags));
         countingStream->write((VkImageTiling*)&local_tiling, sizeof(VkImageTiling));
         // WARNING PTR CHECK
-        uint64_t cgen_var_146 = (uint64_t)(uintptr_t)pPropertyCount;
-        countingStream->putBe64(cgen_var_146);
+        uint64_t cgen_var_150 = (uint64_t)(uintptr_t)pPropertyCount;
+        countingStream->putBe64(cgen_var_150);
         if (pPropertyCount)
         {
             countingStream->write((uint32_t*)pPropertyCount, sizeof(uint32_t));
         }
         // WARNING PTR CHECK
-        uint64_t cgen_var_147 = (uint64_t)(uintptr_t)pProperties;
-        countingStream->putBe64(cgen_var_147);
+        uint64_t cgen_var_151 = (uint64_t)(uintptr_t)pProperties;
+        countingStream->putBe64(cgen_var_151);
         if (pProperties)
         {
             for (uint32_t i = 0; i < (uint32_t)(*(pPropertyCount)); ++i)
@@ -2358,24 +2499,24 @@
     uint32_t opcode_vkGetPhysicalDeviceSparseImageFormatProperties = OP_vkGetPhysicalDeviceSparseImageFormatProperties;
     stream->write(&opcode_vkGetPhysicalDeviceSparseImageFormatProperties, sizeof(uint32_t));
     stream->write(&packetSize_vkGetPhysicalDeviceSparseImageFormatProperties, sizeof(uint32_t));
-    uint64_t cgen_var_148;
-    stream->handleMapping()->mapHandles_VkPhysicalDevice_u64(&local_physicalDevice, &cgen_var_148, 1);
-    stream->write((uint64_t*)&cgen_var_148, 1 * 8);
+    uint64_t cgen_var_152;
+    stream->handleMapping()->mapHandles_VkPhysicalDevice_u64(&local_physicalDevice, &cgen_var_152, 1);
+    stream->write((uint64_t*)&cgen_var_152, 1 * 8);
     stream->write((VkFormat*)&local_format, sizeof(VkFormat));
     stream->write((VkImageType*)&local_type, sizeof(VkImageType));
     stream->write((VkSampleCountFlagBits*)&local_samples, sizeof(VkSampleCountFlagBits));
     stream->write((VkImageUsageFlags*)&local_usage, sizeof(VkImageUsageFlags));
     stream->write((VkImageTiling*)&local_tiling, sizeof(VkImageTiling));
     // WARNING PTR CHECK
-    uint64_t cgen_var_149 = (uint64_t)(uintptr_t)pPropertyCount;
-    stream->putBe64(cgen_var_149);
+    uint64_t cgen_var_153 = (uint64_t)(uintptr_t)pPropertyCount;
+    stream->putBe64(cgen_var_153);
     if (pPropertyCount)
     {
         stream->write((uint32_t*)pPropertyCount, sizeof(uint32_t));
     }
     // WARNING PTR CHECK
-    uint64_t cgen_var_150 = (uint64_t)(uintptr_t)pProperties;
-    stream->putBe64(cgen_var_150);
+    uint64_t cgen_var_154 = (uint64_t)(uintptr_t)pProperties;
+    stream->putBe64(cgen_var_154);
     if (pProperties)
     {
         for (uint32_t i = 0; i < (uint32_t)(*(pPropertyCount)); ++i)
@@ -2426,6 +2567,7 @@
     const VkBindSparseInfo* pBindInfo,
     VkFence fence)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkQueueBindSparse encode");
     mImpl->log("start vkQueueBindSparse");
     auto stream = mImpl->stream();
@@ -2458,34 +2600,34 @@
     }
     countingStream->rewind();
     {
-        uint64_t cgen_var_153;
-        countingStream->handleMapping()->mapHandles_VkQueue_u64(&local_queue, &cgen_var_153, 1);
-        countingStream->write((uint64_t*)&cgen_var_153, 1 * 8);
+        uint64_t cgen_var_157;
+        countingStream->handleMapping()->mapHandles_VkQueue_u64(&local_queue, &cgen_var_157, 1);
+        countingStream->write((uint64_t*)&cgen_var_157, 1 * 8);
         countingStream->write((uint32_t*)&local_bindInfoCount, sizeof(uint32_t));
         for (uint32_t i = 0; i < (uint32_t)((bindInfoCount)); ++i)
         {
             marshal_VkBindSparseInfo(countingStream, (VkBindSparseInfo*)(local_pBindInfo + i));
         }
-        uint64_t cgen_var_154;
-        countingStream->handleMapping()->mapHandles_VkFence_u64(&local_fence, &cgen_var_154, 1);
-        countingStream->write((uint64_t*)&cgen_var_154, 1 * 8);
+        uint64_t cgen_var_158;
+        countingStream->handleMapping()->mapHandles_VkFence_u64(&local_fence, &cgen_var_158, 1);
+        countingStream->write((uint64_t*)&cgen_var_158, 1 * 8);
     }
     uint32_t packetSize_vkQueueBindSparse = 4 + 4 + (uint32_t)countingStream->bytesWritten();
     countingStream->rewind();
     uint32_t opcode_vkQueueBindSparse = OP_vkQueueBindSparse;
     stream->write(&opcode_vkQueueBindSparse, sizeof(uint32_t));
     stream->write(&packetSize_vkQueueBindSparse, sizeof(uint32_t));
-    uint64_t cgen_var_155;
-    stream->handleMapping()->mapHandles_VkQueue_u64(&local_queue, &cgen_var_155, 1);
-    stream->write((uint64_t*)&cgen_var_155, 1 * 8);
+    uint64_t cgen_var_159;
+    stream->handleMapping()->mapHandles_VkQueue_u64(&local_queue, &cgen_var_159, 1);
+    stream->write((uint64_t*)&cgen_var_159, 1 * 8);
     stream->write((uint32_t*)&local_bindInfoCount, sizeof(uint32_t));
     for (uint32_t i = 0; i < (uint32_t)((bindInfoCount)); ++i)
     {
         marshal_VkBindSparseInfo(stream, (VkBindSparseInfo*)(local_pBindInfo + i));
     }
-    uint64_t cgen_var_156;
-    stream->handleMapping()->mapHandles_VkFence_u64(&local_fence, &cgen_var_156, 1);
-    stream->write((uint64_t*)&cgen_var_156, 1 * 8);
+    uint64_t cgen_var_160;
+    stream->handleMapping()->mapHandles_VkFence_u64(&local_fence, &cgen_var_160, 1);
+    stream->write((uint64_t*)&cgen_var_160, 1 * 8);
     AEMU_SCOPED_TRACE("vkQueueBindSparse readParams");
     AEMU_SCOPED_TRACE("vkQueueBindSparse returnUnmarshal");
     VkResult vkQueueBindSparse_VkResult_return = (VkResult)0;
@@ -2503,6 +2645,7 @@
     const VkAllocationCallbacks* pAllocator,
     VkFence* pFence)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkCreateFence encode");
     mImpl->log("start vkCreateFence");
     auto stream = mImpl->stream();
@@ -2537,47 +2680,47 @@
     }
     countingStream->rewind();
     {
-        uint64_t cgen_var_157;
-        countingStream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_157, 1);
-        countingStream->write((uint64_t*)&cgen_var_157, 1 * 8);
+        uint64_t cgen_var_161;
+        countingStream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_161, 1);
+        countingStream->write((uint64_t*)&cgen_var_161, 1 * 8);
         marshal_VkFenceCreateInfo(countingStream, (VkFenceCreateInfo*)(local_pCreateInfo));
         // WARNING PTR CHECK
-        uint64_t cgen_var_158 = (uint64_t)(uintptr_t)local_pAllocator;
-        countingStream->putBe64(cgen_var_158);
+        uint64_t cgen_var_162 = (uint64_t)(uintptr_t)local_pAllocator;
+        countingStream->putBe64(cgen_var_162);
         if (local_pAllocator)
         {
             marshal_VkAllocationCallbacks(countingStream, (VkAllocationCallbacks*)(local_pAllocator));
         }
-        uint64_t cgen_var_159;
-        countingStream->handleMapping()->mapHandles_VkFence_u64(pFence, &cgen_var_159, 1);
-        countingStream->write((uint64_t*)&cgen_var_159, 8);
+        uint64_t cgen_var_163;
+        countingStream->handleMapping()->mapHandles_VkFence_u64(pFence, &cgen_var_163, 1);
+        countingStream->write((uint64_t*)&cgen_var_163, 8);
     }
     uint32_t packetSize_vkCreateFence = 4 + 4 + (uint32_t)countingStream->bytesWritten();
     countingStream->rewind();
     uint32_t opcode_vkCreateFence = OP_vkCreateFence;
     stream->write(&opcode_vkCreateFence, sizeof(uint32_t));
     stream->write(&packetSize_vkCreateFence, sizeof(uint32_t));
-    uint64_t cgen_var_160;
-    stream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_160, 1);
-    stream->write((uint64_t*)&cgen_var_160, 1 * 8);
+    uint64_t cgen_var_164;
+    stream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_164, 1);
+    stream->write((uint64_t*)&cgen_var_164, 1 * 8);
     marshal_VkFenceCreateInfo(stream, (VkFenceCreateInfo*)(local_pCreateInfo));
     // WARNING PTR CHECK
-    uint64_t cgen_var_161 = (uint64_t)(uintptr_t)local_pAllocator;
-    stream->putBe64(cgen_var_161);
+    uint64_t cgen_var_165 = (uint64_t)(uintptr_t)local_pAllocator;
+    stream->putBe64(cgen_var_165);
     if (local_pAllocator)
     {
         marshal_VkAllocationCallbacks(stream, (VkAllocationCallbacks*)(local_pAllocator));
     }
     stream->unsetHandleMapping() /* emit_marshal, is handle, possibly out */;
-    uint64_t cgen_var_162;
-    stream->handleMapping()->mapHandles_VkFence_u64(pFence, &cgen_var_162, 1);
-    stream->write((uint64_t*)&cgen_var_162, 8);
+    uint64_t cgen_var_166;
+    stream->handleMapping()->mapHandles_VkFence_u64(pFence, &cgen_var_166, 1);
+    stream->write((uint64_t*)&cgen_var_166, 8);
     stream->setHandleMapping(resources->unwrapMapping());
     AEMU_SCOPED_TRACE("vkCreateFence readParams");
     stream->setHandleMapping(resources->createMapping());
-    uint64_t cgen_var_163;
-    stream->read((uint64_t*)&cgen_var_163, 8);
-    stream->handleMapping()->mapHandles_u64_VkFence(&cgen_var_163, (VkFence*)pFence, 1);
+    uint64_t cgen_var_167;
+    stream->read((uint64_t*)&cgen_var_167, 8);
+    stream->handleMapping()->mapHandles_u64_VkFence(&cgen_var_167, (VkFence*)pFence, 1);
     stream->unsetHandleMapping();
     AEMU_SCOPED_TRACE("vkCreateFence returnUnmarshal");
     VkResult vkCreateFence_VkResult_return = (VkResult)0;
@@ -2594,6 +2737,7 @@
     VkFence fence,
     const VkAllocationCallbacks* pAllocator)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkDestroyFence encode");
     mImpl->log("start vkDestroyFence");
     auto stream = mImpl->stream();
@@ -2619,15 +2763,15 @@
     }
     countingStream->rewind();
     {
-        uint64_t cgen_var_164;
-        countingStream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_164, 1);
-        countingStream->write((uint64_t*)&cgen_var_164, 1 * 8);
-        uint64_t cgen_var_165;
-        countingStream->handleMapping()->mapHandles_VkFence_u64(&local_fence, &cgen_var_165, 1);
-        countingStream->write((uint64_t*)&cgen_var_165, 1 * 8);
+        uint64_t cgen_var_168;
+        countingStream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_168, 1);
+        countingStream->write((uint64_t*)&cgen_var_168, 1 * 8);
+        uint64_t cgen_var_169;
+        countingStream->handleMapping()->mapHandles_VkFence_u64(&local_fence, &cgen_var_169, 1);
+        countingStream->write((uint64_t*)&cgen_var_169, 1 * 8);
         // WARNING PTR CHECK
-        uint64_t cgen_var_166 = (uint64_t)(uintptr_t)local_pAllocator;
-        countingStream->putBe64(cgen_var_166);
+        uint64_t cgen_var_170 = (uint64_t)(uintptr_t)local_pAllocator;
+        countingStream->putBe64(cgen_var_170);
         if (local_pAllocator)
         {
             marshal_VkAllocationCallbacks(countingStream, (VkAllocationCallbacks*)(local_pAllocator));
@@ -2638,15 +2782,15 @@
     uint32_t opcode_vkDestroyFence = OP_vkDestroyFence;
     stream->write(&opcode_vkDestroyFence, sizeof(uint32_t));
     stream->write(&packetSize_vkDestroyFence, sizeof(uint32_t));
-    uint64_t cgen_var_167;
-    stream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_167, 1);
-    stream->write((uint64_t*)&cgen_var_167, 1 * 8);
-    uint64_t cgen_var_168;
-    stream->handleMapping()->mapHandles_VkFence_u64(&local_fence, &cgen_var_168, 1);
-    stream->write((uint64_t*)&cgen_var_168, 1 * 8);
+    uint64_t cgen_var_171;
+    stream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_171, 1);
+    stream->write((uint64_t*)&cgen_var_171, 1 * 8);
+    uint64_t cgen_var_172;
+    stream->handleMapping()->mapHandles_VkFence_u64(&local_fence, &cgen_var_172, 1);
+    stream->write((uint64_t*)&cgen_var_172, 1 * 8);
     // WARNING PTR CHECK
-    uint64_t cgen_var_169 = (uint64_t)(uintptr_t)local_pAllocator;
-    stream->putBe64(cgen_var_169);
+    uint64_t cgen_var_173 = (uint64_t)(uintptr_t)local_pAllocator;
+    stream->putBe64(cgen_var_173);
     if (local_pAllocator)
     {
         marshal_VkAllocationCallbacks(stream, (VkAllocationCallbacks*)(local_pAllocator));
@@ -2662,6 +2806,7 @@
     uint32_t fenceCount,
     const VkFence* pFences)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkResetFences encode");
     mImpl->log("start vkResetFences");
     auto stream = mImpl->stream();
@@ -2681,16 +2826,16 @@
     }
     countingStream->rewind();
     {
-        uint64_t cgen_var_170;
-        countingStream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_170, 1);
-        countingStream->write((uint64_t*)&cgen_var_170, 1 * 8);
+        uint64_t cgen_var_174;
+        countingStream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_174, 1);
+        countingStream->write((uint64_t*)&cgen_var_174, 1 * 8);
         countingStream->write((uint32_t*)&local_fenceCount, sizeof(uint32_t));
         if (((fenceCount)))
         {
-            uint64_t* cgen_var_171;
-            countingStream->alloc((void**)&cgen_var_171, ((fenceCount)) * 8);
-            countingStream->handleMapping()->mapHandles_VkFence_u64(local_pFences, cgen_var_171, ((fenceCount)));
-            countingStream->write((uint64_t*)cgen_var_171, ((fenceCount)) * 8);
+            uint64_t* cgen_var_175;
+            countingStream->alloc((void**)&cgen_var_175, ((fenceCount)) * 8);
+            countingStream->handleMapping()->mapHandles_VkFence_u64(local_pFences, cgen_var_175, ((fenceCount)));
+            countingStream->write((uint64_t*)cgen_var_175, ((fenceCount)) * 8);
         }
     }
     uint32_t packetSize_vkResetFences = 4 + 4 + (uint32_t)countingStream->bytesWritten();
@@ -2698,16 +2843,16 @@
     uint32_t opcode_vkResetFences = OP_vkResetFences;
     stream->write(&opcode_vkResetFences, sizeof(uint32_t));
     stream->write(&packetSize_vkResetFences, sizeof(uint32_t));
-    uint64_t cgen_var_172;
-    stream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_172, 1);
-    stream->write((uint64_t*)&cgen_var_172, 1 * 8);
+    uint64_t cgen_var_176;
+    stream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_176, 1);
+    stream->write((uint64_t*)&cgen_var_176, 1 * 8);
     stream->write((uint32_t*)&local_fenceCount, sizeof(uint32_t));
     if (((fenceCount)))
     {
-        uint64_t* cgen_var_173;
-        stream->alloc((void**)&cgen_var_173, ((fenceCount)) * 8);
-        stream->handleMapping()->mapHandles_VkFence_u64(local_pFences, cgen_var_173, ((fenceCount)));
-        stream->write((uint64_t*)cgen_var_173, ((fenceCount)) * 8);
+        uint64_t* cgen_var_177;
+        stream->alloc((void**)&cgen_var_177, ((fenceCount)) * 8);
+        stream->handleMapping()->mapHandles_VkFence_u64(local_pFences, cgen_var_177, ((fenceCount)));
+        stream->write((uint64_t*)cgen_var_177, ((fenceCount)) * 8);
     }
     AEMU_SCOPED_TRACE("vkResetFences readParams");
     AEMU_SCOPED_TRACE("vkResetFences returnUnmarshal");
@@ -2724,6 +2869,7 @@
     VkDevice device,
     VkFence fence)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkGetFenceStatus encode");
     mImpl->log("start vkGetFenceStatus");
     auto stream = mImpl->stream();
@@ -2737,24 +2883,24 @@
     local_fence = fence;
     countingStream->rewind();
     {
-        uint64_t cgen_var_174;
-        countingStream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_174, 1);
-        countingStream->write((uint64_t*)&cgen_var_174, 1 * 8);
-        uint64_t cgen_var_175;
-        countingStream->handleMapping()->mapHandles_VkFence_u64(&local_fence, &cgen_var_175, 1);
-        countingStream->write((uint64_t*)&cgen_var_175, 1 * 8);
+        uint64_t cgen_var_178;
+        countingStream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_178, 1);
+        countingStream->write((uint64_t*)&cgen_var_178, 1 * 8);
+        uint64_t cgen_var_179;
+        countingStream->handleMapping()->mapHandles_VkFence_u64(&local_fence, &cgen_var_179, 1);
+        countingStream->write((uint64_t*)&cgen_var_179, 1 * 8);
     }
     uint32_t packetSize_vkGetFenceStatus = 4 + 4 + (uint32_t)countingStream->bytesWritten();
     countingStream->rewind();
     uint32_t opcode_vkGetFenceStatus = OP_vkGetFenceStatus;
     stream->write(&opcode_vkGetFenceStatus, sizeof(uint32_t));
     stream->write(&packetSize_vkGetFenceStatus, sizeof(uint32_t));
-    uint64_t cgen_var_176;
-    stream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_176, 1);
-    stream->write((uint64_t*)&cgen_var_176, 1 * 8);
-    uint64_t cgen_var_177;
-    stream->handleMapping()->mapHandles_VkFence_u64(&local_fence, &cgen_var_177, 1);
-    stream->write((uint64_t*)&cgen_var_177, 1 * 8);
+    uint64_t cgen_var_180;
+    stream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_180, 1);
+    stream->write((uint64_t*)&cgen_var_180, 1 * 8);
+    uint64_t cgen_var_181;
+    stream->handleMapping()->mapHandles_VkFence_u64(&local_fence, &cgen_var_181, 1);
+    stream->write((uint64_t*)&cgen_var_181, 1 * 8);
     AEMU_SCOPED_TRACE("vkGetFenceStatus readParams");
     AEMU_SCOPED_TRACE("vkGetFenceStatus returnUnmarshal");
     VkResult vkGetFenceStatus_VkResult_return = (VkResult)0;
@@ -2773,6 +2919,7 @@
     VkBool32 waitAll,
     uint64_t timeout)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkWaitForFences encode");
     mImpl->log("start vkWaitForFences");
     auto stream = mImpl->stream();
@@ -2796,16 +2943,16 @@
     local_timeout = timeout;
     countingStream->rewind();
     {
-        uint64_t cgen_var_178;
-        countingStream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_178, 1);
-        countingStream->write((uint64_t*)&cgen_var_178, 1 * 8);
+        uint64_t cgen_var_182;
+        countingStream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_182, 1);
+        countingStream->write((uint64_t*)&cgen_var_182, 1 * 8);
         countingStream->write((uint32_t*)&local_fenceCount, sizeof(uint32_t));
         if (((fenceCount)))
         {
-            uint64_t* cgen_var_179;
-            countingStream->alloc((void**)&cgen_var_179, ((fenceCount)) * 8);
-            countingStream->handleMapping()->mapHandles_VkFence_u64(local_pFences, cgen_var_179, ((fenceCount)));
-            countingStream->write((uint64_t*)cgen_var_179, ((fenceCount)) * 8);
+            uint64_t* cgen_var_183;
+            countingStream->alloc((void**)&cgen_var_183, ((fenceCount)) * 8);
+            countingStream->handleMapping()->mapHandles_VkFence_u64(local_pFences, cgen_var_183, ((fenceCount)));
+            countingStream->write((uint64_t*)cgen_var_183, ((fenceCount)) * 8);
         }
         countingStream->write((VkBool32*)&local_waitAll, sizeof(VkBool32));
         countingStream->write((uint64_t*)&local_timeout, sizeof(uint64_t));
@@ -2815,16 +2962,16 @@
     uint32_t opcode_vkWaitForFences = OP_vkWaitForFences;
     stream->write(&opcode_vkWaitForFences, sizeof(uint32_t));
     stream->write(&packetSize_vkWaitForFences, sizeof(uint32_t));
-    uint64_t cgen_var_180;
-    stream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_180, 1);
-    stream->write((uint64_t*)&cgen_var_180, 1 * 8);
+    uint64_t cgen_var_184;
+    stream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_184, 1);
+    stream->write((uint64_t*)&cgen_var_184, 1 * 8);
     stream->write((uint32_t*)&local_fenceCount, sizeof(uint32_t));
     if (((fenceCount)))
     {
-        uint64_t* cgen_var_181;
-        stream->alloc((void**)&cgen_var_181, ((fenceCount)) * 8);
-        stream->handleMapping()->mapHandles_VkFence_u64(local_pFences, cgen_var_181, ((fenceCount)));
-        stream->write((uint64_t*)cgen_var_181, ((fenceCount)) * 8);
+        uint64_t* cgen_var_185;
+        stream->alloc((void**)&cgen_var_185, ((fenceCount)) * 8);
+        stream->handleMapping()->mapHandles_VkFence_u64(local_pFences, cgen_var_185, ((fenceCount)));
+        stream->write((uint64_t*)cgen_var_185, ((fenceCount)) * 8);
     }
     stream->write((VkBool32*)&local_waitAll, sizeof(VkBool32));
     stream->write((uint64_t*)&local_timeout, sizeof(uint64_t));
@@ -2845,6 +2992,7 @@
     const VkAllocationCallbacks* pAllocator,
     VkSemaphore* pSemaphore)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkCreateSemaphore encode");
     mImpl->log("start vkCreateSemaphore");
     auto stream = mImpl->stream();
@@ -2879,47 +3027,47 @@
     }
     countingStream->rewind();
     {
-        uint64_t cgen_var_182;
-        countingStream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_182, 1);
-        countingStream->write((uint64_t*)&cgen_var_182, 1 * 8);
+        uint64_t cgen_var_186;
+        countingStream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_186, 1);
+        countingStream->write((uint64_t*)&cgen_var_186, 1 * 8);
         marshal_VkSemaphoreCreateInfo(countingStream, (VkSemaphoreCreateInfo*)(local_pCreateInfo));
         // WARNING PTR CHECK
-        uint64_t cgen_var_183 = (uint64_t)(uintptr_t)local_pAllocator;
-        countingStream->putBe64(cgen_var_183);
+        uint64_t cgen_var_187 = (uint64_t)(uintptr_t)local_pAllocator;
+        countingStream->putBe64(cgen_var_187);
         if (local_pAllocator)
         {
             marshal_VkAllocationCallbacks(countingStream, (VkAllocationCallbacks*)(local_pAllocator));
         }
-        uint64_t cgen_var_184;
-        countingStream->handleMapping()->mapHandles_VkSemaphore_u64(pSemaphore, &cgen_var_184, 1);
-        countingStream->write((uint64_t*)&cgen_var_184, 8);
+        uint64_t cgen_var_188;
+        countingStream->handleMapping()->mapHandles_VkSemaphore_u64(pSemaphore, &cgen_var_188, 1);
+        countingStream->write((uint64_t*)&cgen_var_188, 8);
     }
     uint32_t packetSize_vkCreateSemaphore = 4 + 4 + (uint32_t)countingStream->bytesWritten();
     countingStream->rewind();
     uint32_t opcode_vkCreateSemaphore = OP_vkCreateSemaphore;
     stream->write(&opcode_vkCreateSemaphore, sizeof(uint32_t));
     stream->write(&packetSize_vkCreateSemaphore, sizeof(uint32_t));
-    uint64_t cgen_var_185;
-    stream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_185, 1);
-    stream->write((uint64_t*)&cgen_var_185, 1 * 8);
+    uint64_t cgen_var_189;
+    stream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_189, 1);
+    stream->write((uint64_t*)&cgen_var_189, 1 * 8);
     marshal_VkSemaphoreCreateInfo(stream, (VkSemaphoreCreateInfo*)(local_pCreateInfo));
     // WARNING PTR CHECK
-    uint64_t cgen_var_186 = (uint64_t)(uintptr_t)local_pAllocator;
-    stream->putBe64(cgen_var_186);
+    uint64_t cgen_var_190 = (uint64_t)(uintptr_t)local_pAllocator;
+    stream->putBe64(cgen_var_190);
     if (local_pAllocator)
     {
         marshal_VkAllocationCallbacks(stream, (VkAllocationCallbacks*)(local_pAllocator));
     }
     stream->unsetHandleMapping() /* emit_marshal, is handle, possibly out */;
-    uint64_t cgen_var_187;
-    stream->handleMapping()->mapHandles_VkSemaphore_u64(pSemaphore, &cgen_var_187, 1);
-    stream->write((uint64_t*)&cgen_var_187, 8);
+    uint64_t cgen_var_191;
+    stream->handleMapping()->mapHandles_VkSemaphore_u64(pSemaphore, &cgen_var_191, 1);
+    stream->write((uint64_t*)&cgen_var_191, 8);
     stream->setHandleMapping(resources->unwrapMapping());
     AEMU_SCOPED_TRACE("vkCreateSemaphore readParams");
     stream->setHandleMapping(resources->createMapping());
-    uint64_t cgen_var_188;
-    stream->read((uint64_t*)&cgen_var_188, 8);
-    stream->handleMapping()->mapHandles_u64_VkSemaphore(&cgen_var_188, (VkSemaphore*)pSemaphore, 1);
+    uint64_t cgen_var_192;
+    stream->read((uint64_t*)&cgen_var_192, 8);
+    stream->handleMapping()->mapHandles_u64_VkSemaphore(&cgen_var_192, (VkSemaphore*)pSemaphore, 1);
     stream->unsetHandleMapping();
     AEMU_SCOPED_TRACE("vkCreateSemaphore returnUnmarshal");
     VkResult vkCreateSemaphore_VkResult_return = (VkResult)0;
@@ -2936,6 +3084,7 @@
     VkSemaphore semaphore,
     const VkAllocationCallbacks* pAllocator)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkDestroySemaphore encode");
     mImpl->log("start vkDestroySemaphore");
     auto stream = mImpl->stream();
@@ -2961,15 +3110,15 @@
     }
     countingStream->rewind();
     {
-        uint64_t cgen_var_189;
-        countingStream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_189, 1);
-        countingStream->write((uint64_t*)&cgen_var_189, 1 * 8);
-        uint64_t cgen_var_190;
-        countingStream->handleMapping()->mapHandles_VkSemaphore_u64(&local_semaphore, &cgen_var_190, 1);
-        countingStream->write((uint64_t*)&cgen_var_190, 1 * 8);
+        uint64_t cgen_var_193;
+        countingStream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_193, 1);
+        countingStream->write((uint64_t*)&cgen_var_193, 1 * 8);
+        uint64_t cgen_var_194;
+        countingStream->handleMapping()->mapHandles_VkSemaphore_u64(&local_semaphore, &cgen_var_194, 1);
+        countingStream->write((uint64_t*)&cgen_var_194, 1 * 8);
         // WARNING PTR CHECK
-        uint64_t cgen_var_191 = (uint64_t)(uintptr_t)local_pAllocator;
-        countingStream->putBe64(cgen_var_191);
+        uint64_t cgen_var_195 = (uint64_t)(uintptr_t)local_pAllocator;
+        countingStream->putBe64(cgen_var_195);
         if (local_pAllocator)
         {
             marshal_VkAllocationCallbacks(countingStream, (VkAllocationCallbacks*)(local_pAllocator));
@@ -2980,15 +3129,15 @@
     uint32_t opcode_vkDestroySemaphore = OP_vkDestroySemaphore;
     stream->write(&opcode_vkDestroySemaphore, sizeof(uint32_t));
     stream->write(&packetSize_vkDestroySemaphore, sizeof(uint32_t));
-    uint64_t cgen_var_192;
-    stream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_192, 1);
-    stream->write((uint64_t*)&cgen_var_192, 1 * 8);
-    uint64_t cgen_var_193;
-    stream->handleMapping()->mapHandles_VkSemaphore_u64(&local_semaphore, &cgen_var_193, 1);
-    stream->write((uint64_t*)&cgen_var_193, 1 * 8);
+    uint64_t cgen_var_196;
+    stream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_196, 1);
+    stream->write((uint64_t*)&cgen_var_196, 1 * 8);
+    uint64_t cgen_var_197;
+    stream->handleMapping()->mapHandles_VkSemaphore_u64(&local_semaphore, &cgen_var_197, 1);
+    stream->write((uint64_t*)&cgen_var_197, 1 * 8);
     // WARNING PTR CHECK
-    uint64_t cgen_var_194 = (uint64_t)(uintptr_t)local_pAllocator;
-    stream->putBe64(cgen_var_194);
+    uint64_t cgen_var_198 = (uint64_t)(uintptr_t)local_pAllocator;
+    stream->putBe64(cgen_var_198);
     if (local_pAllocator)
     {
         marshal_VkAllocationCallbacks(stream, (VkAllocationCallbacks*)(local_pAllocator));
@@ -3005,6 +3154,7 @@
     const VkAllocationCallbacks* pAllocator,
     VkEvent* pEvent)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkCreateEvent encode");
     mImpl->log("start vkCreateEvent");
     auto stream = mImpl->stream();
@@ -3039,47 +3189,47 @@
     }
     countingStream->rewind();
     {
-        uint64_t cgen_var_195;
-        countingStream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_195, 1);
-        countingStream->write((uint64_t*)&cgen_var_195, 1 * 8);
+        uint64_t cgen_var_199;
+        countingStream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_199, 1);
+        countingStream->write((uint64_t*)&cgen_var_199, 1 * 8);
         marshal_VkEventCreateInfo(countingStream, (VkEventCreateInfo*)(local_pCreateInfo));
         // WARNING PTR CHECK
-        uint64_t cgen_var_196 = (uint64_t)(uintptr_t)local_pAllocator;
-        countingStream->putBe64(cgen_var_196);
+        uint64_t cgen_var_200 = (uint64_t)(uintptr_t)local_pAllocator;
+        countingStream->putBe64(cgen_var_200);
         if (local_pAllocator)
         {
             marshal_VkAllocationCallbacks(countingStream, (VkAllocationCallbacks*)(local_pAllocator));
         }
-        uint64_t cgen_var_197;
-        countingStream->handleMapping()->mapHandles_VkEvent_u64(pEvent, &cgen_var_197, 1);
-        countingStream->write((uint64_t*)&cgen_var_197, 8);
+        uint64_t cgen_var_201;
+        countingStream->handleMapping()->mapHandles_VkEvent_u64(pEvent, &cgen_var_201, 1);
+        countingStream->write((uint64_t*)&cgen_var_201, 8);
     }
     uint32_t packetSize_vkCreateEvent = 4 + 4 + (uint32_t)countingStream->bytesWritten();
     countingStream->rewind();
     uint32_t opcode_vkCreateEvent = OP_vkCreateEvent;
     stream->write(&opcode_vkCreateEvent, sizeof(uint32_t));
     stream->write(&packetSize_vkCreateEvent, sizeof(uint32_t));
-    uint64_t cgen_var_198;
-    stream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_198, 1);
-    stream->write((uint64_t*)&cgen_var_198, 1 * 8);
+    uint64_t cgen_var_202;
+    stream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_202, 1);
+    stream->write((uint64_t*)&cgen_var_202, 1 * 8);
     marshal_VkEventCreateInfo(stream, (VkEventCreateInfo*)(local_pCreateInfo));
     // WARNING PTR CHECK
-    uint64_t cgen_var_199 = (uint64_t)(uintptr_t)local_pAllocator;
-    stream->putBe64(cgen_var_199);
+    uint64_t cgen_var_203 = (uint64_t)(uintptr_t)local_pAllocator;
+    stream->putBe64(cgen_var_203);
     if (local_pAllocator)
     {
         marshal_VkAllocationCallbacks(stream, (VkAllocationCallbacks*)(local_pAllocator));
     }
     stream->unsetHandleMapping() /* emit_marshal, is handle, possibly out */;
-    uint64_t cgen_var_200;
-    stream->handleMapping()->mapHandles_VkEvent_u64(pEvent, &cgen_var_200, 1);
-    stream->write((uint64_t*)&cgen_var_200, 8);
+    uint64_t cgen_var_204;
+    stream->handleMapping()->mapHandles_VkEvent_u64(pEvent, &cgen_var_204, 1);
+    stream->write((uint64_t*)&cgen_var_204, 8);
     stream->setHandleMapping(resources->unwrapMapping());
     AEMU_SCOPED_TRACE("vkCreateEvent readParams");
     stream->setHandleMapping(resources->createMapping());
-    uint64_t cgen_var_201;
-    stream->read((uint64_t*)&cgen_var_201, 8);
-    stream->handleMapping()->mapHandles_u64_VkEvent(&cgen_var_201, (VkEvent*)pEvent, 1);
+    uint64_t cgen_var_205;
+    stream->read((uint64_t*)&cgen_var_205, 8);
+    stream->handleMapping()->mapHandles_u64_VkEvent(&cgen_var_205, (VkEvent*)pEvent, 1);
     stream->unsetHandleMapping();
     AEMU_SCOPED_TRACE("vkCreateEvent returnUnmarshal");
     VkResult vkCreateEvent_VkResult_return = (VkResult)0;
@@ -3096,6 +3246,7 @@
     VkEvent event,
     const VkAllocationCallbacks* pAllocator)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkDestroyEvent encode");
     mImpl->log("start vkDestroyEvent");
     auto stream = mImpl->stream();
@@ -3121,15 +3272,15 @@
     }
     countingStream->rewind();
     {
-        uint64_t cgen_var_202;
-        countingStream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_202, 1);
-        countingStream->write((uint64_t*)&cgen_var_202, 1 * 8);
-        uint64_t cgen_var_203;
-        countingStream->handleMapping()->mapHandles_VkEvent_u64(&local_event, &cgen_var_203, 1);
-        countingStream->write((uint64_t*)&cgen_var_203, 1 * 8);
+        uint64_t cgen_var_206;
+        countingStream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_206, 1);
+        countingStream->write((uint64_t*)&cgen_var_206, 1 * 8);
+        uint64_t cgen_var_207;
+        countingStream->handleMapping()->mapHandles_VkEvent_u64(&local_event, &cgen_var_207, 1);
+        countingStream->write((uint64_t*)&cgen_var_207, 1 * 8);
         // WARNING PTR CHECK
-        uint64_t cgen_var_204 = (uint64_t)(uintptr_t)local_pAllocator;
-        countingStream->putBe64(cgen_var_204);
+        uint64_t cgen_var_208 = (uint64_t)(uintptr_t)local_pAllocator;
+        countingStream->putBe64(cgen_var_208);
         if (local_pAllocator)
         {
             marshal_VkAllocationCallbacks(countingStream, (VkAllocationCallbacks*)(local_pAllocator));
@@ -3140,15 +3291,15 @@
     uint32_t opcode_vkDestroyEvent = OP_vkDestroyEvent;
     stream->write(&opcode_vkDestroyEvent, sizeof(uint32_t));
     stream->write(&packetSize_vkDestroyEvent, sizeof(uint32_t));
-    uint64_t cgen_var_205;
-    stream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_205, 1);
-    stream->write((uint64_t*)&cgen_var_205, 1 * 8);
-    uint64_t cgen_var_206;
-    stream->handleMapping()->mapHandles_VkEvent_u64(&local_event, &cgen_var_206, 1);
-    stream->write((uint64_t*)&cgen_var_206, 1 * 8);
+    uint64_t cgen_var_209;
+    stream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_209, 1);
+    stream->write((uint64_t*)&cgen_var_209, 1 * 8);
+    uint64_t cgen_var_210;
+    stream->handleMapping()->mapHandles_VkEvent_u64(&local_event, &cgen_var_210, 1);
+    stream->write((uint64_t*)&cgen_var_210, 1 * 8);
     // WARNING PTR CHECK
-    uint64_t cgen_var_207 = (uint64_t)(uintptr_t)local_pAllocator;
-    stream->putBe64(cgen_var_207);
+    uint64_t cgen_var_211 = (uint64_t)(uintptr_t)local_pAllocator;
+    stream->putBe64(cgen_var_211);
     if (local_pAllocator)
     {
         marshal_VkAllocationCallbacks(stream, (VkAllocationCallbacks*)(local_pAllocator));
@@ -3163,6 +3314,7 @@
     VkDevice device,
     VkEvent event)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkGetEventStatus encode");
     mImpl->log("start vkGetEventStatus");
     auto stream = mImpl->stream();
@@ -3176,52 +3328,6 @@
     local_event = event;
     countingStream->rewind();
     {
-        uint64_t cgen_var_208;
-        countingStream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_208, 1);
-        countingStream->write((uint64_t*)&cgen_var_208, 1 * 8);
-        uint64_t cgen_var_209;
-        countingStream->handleMapping()->mapHandles_VkEvent_u64(&local_event, &cgen_var_209, 1);
-        countingStream->write((uint64_t*)&cgen_var_209, 1 * 8);
-    }
-    uint32_t packetSize_vkGetEventStatus = 4 + 4 + (uint32_t)countingStream->bytesWritten();
-    countingStream->rewind();
-    uint32_t opcode_vkGetEventStatus = OP_vkGetEventStatus;
-    stream->write(&opcode_vkGetEventStatus, sizeof(uint32_t));
-    stream->write(&packetSize_vkGetEventStatus, sizeof(uint32_t));
-    uint64_t cgen_var_210;
-    stream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_210, 1);
-    stream->write((uint64_t*)&cgen_var_210, 1 * 8);
-    uint64_t cgen_var_211;
-    stream->handleMapping()->mapHandles_VkEvent_u64(&local_event, &cgen_var_211, 1);
-    stream->write((uint64_t*)&cgen_var_211, 1 * 8);
-    AEMU_SCOPED_TRACE("vkGetEventStatus readParams");
-    AEMU_SCOPED_TRACE("vkGetEventStatus returnUnmarshal");
-    VkResult vkGetEventStatus_VkResult_return = (VkResult)0;
-    stream->read(&vkGetEventStatus_VkResult_return, sizeof(VkResult));
-    countingStream->clearPool();
-    stream->clearPool();
-    pool->freeAll();
-    mImpl->log("finish vkGetEventStatus");;
-    return vkGetEventStatus_VkResult_return;
-}
-
-VkResult VkEncoder::vkSetEvent(
-    VkDevice device,
-    VkEvent event)
-{
-    AEMU_SCOPED_TRACE("vkSetEvent encode");
-    mImpl->log("start vkSetEvent");
-    auto stream = mImpl->stream();
-    auto countingStream = mImpl->countingStream();
-    auto resources = mImpl->resources();
-    auto pool = mImpl->pool();
-    stream->setHandleMapping(resources->unwrapMapping());
-    VkDevice local_device;
-    VkEvent local_event;
-    local_device = device;
-    local_event = event;
-    countingStream->rewind();
-    {
         uint64_t cgen_var_212;
         countingStream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_212, 1);
         countingStream->write((uint64_t*)&cgen_var_212, 1 * 8);
@@ -3229,34 +3335,35 @@
         countingStream->handleMapping()->mapHandles_VkEvent_u64(&local_event, &cgen_var_213, 1);
         countingStream->write((uint64_t*)&cgen_var_213, 1 * 8);
     }
-    uint32_t packetSize_vkSetEvent = 4 + 4 + (uint32_t)countingStream->bytesWritten();
+    uint32_t packetSize_vkGetEventStatus = 4 + 4 + (uint32_t)countingStream->bytesWritten();
     countingStream->rewind();
-    uint32_t opcode_vkSetEvent = OP_vkSetEvent;
-    stream->write(&opcode_vkSetEvent, sizeof(uint32_t));
-    stream->write(&packetSize_vkSetEvent, sizeof(uint32_t));
+    uint32_t opcode_vkGetEventStatus = OP_vkGetEventStatus;
+    stream->write(&opcode_vkGetEventStatus, sizeof(uint32_t));
+    stream->write(&packetSize_vkGetEventStatus, sizeof(uint32_t));
     uint64_t cgen_var_214;
     stream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_214, 1);
     stream->write((uint64_t*)&cgen_var_214, 1 * 8);
     uint64_t cgen_var_215;
     stream->handleMapping()->mapHandles_VkEvent_u64(&local_event, &cgen_var_215, 1);
     stream->write((uint64_t*)&cgen_var_215, 1 * 8);
-    AEMU_SCOPED_TRACE("vkSetEvent readParams");
-    AEMU_SCOPED_TRACE("vkSetEvent returnUnmarshal");
-    VkResult vkSetEvent_VkResult_return = (VkResult)0;
-    stream->read(&vkSetEvent_VkResult_return, sizeof(VkResult));
+    AEMU_SCOPED_TRACE("vkGetEventStatus readParams");
+    AEMU_SCOPED_TRACE("vkGetEventStatus returnUnmarshal");
+    VkResult vkGetEventStatus_VkResult_return = (VkResult)0;
+    stream->read(&vkGetEventStatus_VkResult_return, sizeof(VkResult));
     countingStream->clearPool();
     stream->clearPool();
     pool->freeAll();
-    mImpl->log("finish vkSetEvent");;
-    return vkSetEvent_VkResult_return;
+    mImpl->log("finish vkGetEventStatus");;
+    return vkGetEventStatus_VkResult_return;
 }
 
-VkResult VkEncoder::vkResetEvent(
+VkResult VkEncoder::vkSetEvent(
     VkDevice device,
     VkEvent event)
 {
-    AEMU_SCOPED_TRACE("vkResetEvent encode");
-    mImpl->log("start vkResetEvent");
+    AutoLock encoderLock(mImpl->lock);
+    AEMU_SCOPED_TRACE("vkSetEvent encode");
+    mImpl->log("start vkSetEvent");
     auto stream = mImpl->stream();
     auto countingStream = mImpl->countingStream();
     auto resources = mImpl->resources();
@@ -3275,17 +3382,64 @@
         countingStream->handleMapping()->mapHandles_VkEvent_u64(&local_event, &cgen_var_217, 1);
         countingStream->write((uint64_t*)&cgen_var_217, 1 * 8);
     }
-    uint32_t packetSize_vkResetEvent = 4 + 4 + (uint32_t)countingStream->bytesWritten();
+    uint32_t packetSize_vkSetEvent = 4 + 4 + (uint32_t)countingStream->bytesWritten();
     countingStream->rewind();
-    uint32_t opcode_vkResetEvent = OP_vkResetEvent;
-    stream->write(&opcode_vkResetEvent, sizeof(uint32_t));
-    stream->write(&packetSize_vkResetEvent, sizeof(uint32_t));
+    uint32_t opcode_vkSetEvent = OP_vkSetEvent;
+    stream->write(&opcode_vkSetEvent, sizeof(uint32_t));
+    stream->write(&packetSize_vkSetEvent, sizeof(uint32_t));
     uint64_t cgen_var_218;
     stream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_218, 1);
     stream->write((uint64_t*)&cgen_var_218, 1 * 8);
     uint64_t cgen_var_219;
     stream->handleMapping()->mapHandles_VkEvent_u64(&local_event, &cgen_var_219, 1);
     stream->write((uint64_t*)&cgen_var_219, 1 * 8);
+    AEMU_SCOPED_TRACE("vkSetEvent readParams");
+    AEMU_SCOPED_TRACE("vkSetEvent returnUnmarshal");
+    VkResult vkSetEvent_VkResult_return = (VkResult)0;
+    stream->read(&vkSetEvent_VkResult_return, sizeof(VkResult));
+    countingStream->clearPool();
+    stream->clearPool();
+    pool->freeAll();
+    mImpl->log("finish vkSetEvent");;
+    return vkSetEvent_VkResult_return;
+}
+
+VkResult VkEncoder::vkResetEvent(
+    VkDevice device,
+    VkEvent event)
+{
+    AutoLock encoderLock(mImpl->lock);
+    AEMU_SCOPED_TRACE("vkResetEvent encode");
+    mImpl->log("start vkResetEvent");
+    auto stream = mImpl->stream();
+    auto countingStream = mImpl->countingStream();
+    auto resources = mImpl->resources();
+    auto pool = mImpl->pool();
+    stream->setHandleMapping(resources->unwrapMapping());
+    VkDevice local_device;
+    VkEvent local_event;
+    local_device = device;
+    local_event = event;
+    countingStream->rewind();
+    {
+        uint64_t cgen_var_220;
+        countingStream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_220, 1);
+        countingStream->write((uint64_t*)&cgen_var_220, 1 * 8);
+        uint64_t cgen_var_221;
+        countingStream->handleMapping()->mapHandles_VkEvent_u64(&local_event, &cgen_var_221, 1);
+        countingStream->write((uint64_t*)&cgen_var_221, 1 * 8);
+    }
+    uint32_t packetSize_vkResetEvent = 4 + 4 + (uint32_t)countingStream->bytesWritten();
+    countingStream->rewind();
+    uint32_t opcode_vkResetEvent = OP_vkResetEvent;
+    stream->write(&opcode_vkResetEvent, sizeof(uint32_t));
+    stream->write(&packetSize_vkResetEvent, sizeof(uint32_t));
+    uint64_t cgen_var_222;
+    stream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_222, 1);
+    stream->write((uint64_t*)&cgen_var_222, 1 * 8);
+    uint64_t cgen_var_223;
+    stream->handleMapping()->mapHandles_VkEvent_u64(&local_event, &cgen_var_223, 1);
+    stream->write((uint64_t*)&cgen_var_223, 1 * 8);
     AEMU_SCOPED_TRACE("vkResetEvent readParams");
     AEMU_SCOPED_TRACE("vkResetEvent returnUnmarshal");
     VkResult vkResetEvent_VkResult_return = (VkResult)0;
@@ -3303,6 +3457,7 @@
     const VkAllocationCallbacks* pAllocator,
     VkQueryPool* pQueryPool)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkCreateQueryPool encode");
     mImpl->log("start vkCreateQueryPool");
     auto stream = mImpl->stream();
@@ -3337,47 +3492,47 @@
     }
     countingStream->rewind();
     {
-        uint64_t cgen_var_220;
-        countingStream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_220, 1);
-        countingStream->write((uint64_t*)&cgen_var_220, 1 * 8);
+        uint64_t cgen_var_224;
+        countingStream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_224, 1);
+        countingStream->write((uint64_t*)&cgen_var_224, 1 * 8);
         marshal_VkQueryPoolCreateInfo(countingStream, (VkQueryPoolCreateInfo*)(local_pCreateInfo));
         // WARNING PTR CHECK
-        uint64_t cgen_var_221 = (uint64_t)(uintptr_t)local_pAllocator;
-        countingStream->putBe64(cgen_var_221);
+        uint64_t cgen_var_225 = (uint64_t)(uintptr_t)local_pAllocator;
+        countingStream->putBe64(cgen_var_225);
         if (local_pAllocator)
         {
             marshal_VkAllocationCallbacks(countingStream, (VkAllocationCallbacks*)(local_pAllocator));
         }
-        uint64_t cgen_var_222;
-        countingStream->handleMapping()->mapHandles_VkQueryPool_u64(pQueryPool, &cgen_var_222, 1);
-        countingStream->write((uint64_t*)&cgen_var_222, 8);
+        uint64_t cgen_var_226;
+        countingStream->handleMapping()->mapHandles_VkQueryPool_u64(pQueryPool, &cgen_var_226, 1);
+        countingStream->write((uint64_t*)&cgen_var_226, 8);
     }
     uint32_t packetSize_vkCreateQueryPool = 4 + 4 + (uint32_t)countingStream->bytesWritten();
     countingStream->rewind();
     uint32_t opcode_vkCreateQueryPool = OP_vkCreateQueryPool;
     stream->write(&opcode_vkCreateQueryPool, sizeof(uint32_t));
     stream->write(&packetSize_vkCreateQueryPool, sizeof(uint32_t));
-    uint64_t cgen_var_223;
-    stream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_223, 1);
-    stream->write((uint64_t*)&cgen_var_223, 1 * 8);
+    uint64_t cgen_var_227;
+    stream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_227, 1);
+    stream->write((uint64_t*)&cgen_var_227, 1 * 8);
     marshal_VkQueryPoolCreateInfo(stream, (VkQueryPoolCreateInfo*)(local_pCreateInfo));
     // WARNING PTR CHECK
-    uint64_t cgen_var_224 = (uint64_t)(uintptr_t)local_pAllocator;
-    stream->putBe64(cgen_var_224);
+    uint64_t cgen_var_228 = (uint64_t)(uintptr_t)local_pAllocator;
+    stream->putBe64(cgen_var_228);
     if (local_pAllocator)
     {
         marshal_VkAllocationCallbacks(stream, (VkAllocationCallbacks*)(local_pAllocator));
     }
     stream->unsetHandleMapping() /* emit_marshal, is handle, possibly out */;
-    uint64_t cgen_var_225;
-    stream->handleMapping()->mapHandles_VkQueryPool_u64(pQueryPool, &cgen_var_225, 1);
-    stream->write((uint64_t*)&cgen_var_225, 8);
+    uint64_t cgen_var_229;
+    stream->handleMapping()->mapHandles_VkQueryPool_u64(pQueryPool, &cgen_var_229, 1);
+    stream->write((uint64_t*)&cgen_var_229, 8);
     stream->setHandleMapping(resources->unwrapMapping());
     AEMU_SCOPED_TRACE("vkCreateQueryPool readParams");
     stream->setHandleMapping(resources->createMapping());
-    uint64_t cgen_var_226;
-    stream->read((uint64_t*)&cgen_var_226, 8);
-    stream->handleMapping()->mapHandles_u64_VkQueryPool(&cgen_var_226, (VkQueryPool*)pQueryPool, 1);
+    uint64_t cgen_var_230;
+    stream->read((uint64_t*)&cgen_var_230, 8);
+    stream->handleMapping()->mapHandles_u64_VkQueryPool(&cgen_var_230, (VkQueryPool*)pQueryPool, 1);
     stream->unsetHandleMapping();
     AEMU_SCOPED_TRACE("vkCreateQueryPool returnUnmarshal");
     VkResult vkCreateQueryPool_VkResult_return = (VkResult)0;
@@ -3394,6 +3549,7 @@
     VkQueryPool queryPool,
     const VkAllocationCallbacks* pAllocator)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkDestroyQueryPool encode");
     mImpl->log("start vkDestroyQueryPool");
     auto stream = mImpl->stream();
@@ -3419,15 +3575,15 @@
     }
     countingStream->rewind();
     {
-        uint64_t cgen_var_227;
-        countingStream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_227, 1);
-        countingStream->write((uint64_t*)&cgen_var_227, 1 * 8);
-        uint64_t cgen_var_228;
-        countingStream->handleMapping()->mapHandles_VkQueryPool_u64(&local_queryPool, &cgen_var_228, 1);
-        countingStream->write((uint64_t*)&cgen_var_228, 1 * 8);
+        uint64_t cgen_var_231;
+        countingStream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_231, 1);
+        countingStream->write((uint64_t*)&cgen_var_231, 1 * 8);
+        uint64_t cgen_var_232;
+        countingStream->handleMapping()->mapHandles_VkQueryPool_u64(&local_queryPool, &cgen_var_232, 1);
+        countingStream->write((uint64_t*)&cgen_var_232, 1 * 8);
         // WARNING PTR CHECK
-        uint64_t cgen_var_229 = (uint64_t)(uintptr_t)local_pAllocator;
-        countingStream->putBe64(cgen_var_229);
+        uint64_t cgen_var_233 = (uint64_t)(uintptr_t)local_pAllocator;
+        countingStream->putBe64(cgen_var_233);
         if (local_pAllocator)
         {
             marshal_VkAllocationCallbacks(countingStream, (VkAllocationCallbacks*)(local_pAllocator));
@@ -3438,15 +3594,15 @@
     uint32_t opcode_vkDestroyQueryPool = OP_vkDestroyQueryPool;
     stream->write(&opcode_vkDestroyQueryPool, sizeof(uint32_t));
     stream->write(&packetSize_vkDestroyQueryPool, sizeof(uint32_t));
-    uint64_t cgen_var_230;
-    stream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_230, 1);
-    stream->write((uint64_t*)&cgen_var_230, 1 * 8);
-    uint64_t cgen_var_231;
-    stream->handleMapping()->mapHandles_VkQueryPool_u64(&local_queryPool, &cgen_var_231, 1);
-    stream->write((uint64_t*)&cgen_var_231, 1 * 8);
+    uint64_t cgen_var_234;
+    stream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_234, 1);
+    stream->write((uint64_t*)&cgen_var_234, 1 * 8);
+    uint64_t cgen_var_235;
+    stream->handleMapping()->mapHandles_VkQueryPool_u64(&local_queryPool, &cgen_var_235, 1);
+    stream->write((uint64_t*)&cgen_var_235, 1 * 8);
     // WARNING PTR CHECK
-    uint64_t cgen_var_232 = (uint64_t)(uintptr_t)local_pAllocator;
-    stream->putBe64(cgen_var_232);
+    uint64_t cgen_var_236 = (uint64_t)(uintptr_t)local_pAllocator;
+    stream->putBe64(cgen_var_236);
     if (local_pAllocator)
     {
         marshal_VkAllocationCallbacks(stream, (VkAllocationCallbacks*)(local_pAllocator));
@@ -3467,6 +3623,7 @@
     VkDeviceSize stride,
     VkQueryResultFlags flags)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkGetQueryPoolResults encode");
     mImpl->log("start vkGetQueryPoolResults");
     auto stream = mImpl->stream();
@@ -3490,16 +3647,16 @@
     local_flags = flags;
     countingStream->rewind();
     {
-        uint64_t cgen_var_233;
-        countingStream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_233, 1);
-        countingStream->write((uint64_t*)&cgen_var_233, 1 * 8);
-        uint64_t cgen_var_234;
-        countingStream->handleMapping()->mapHandles_VkQueryPool_u64(&local_queryPool, &cgen_var_234, 1);
-        countingStream->write((uint64_t*)&cgen_var_234, 1 * 8);
+        uint64_t cgen_var_237;
+        countingStream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_237, 1);
+        countingStream->write((uint64_t*)&cgen_var_237, 1 * 8);
+        uint64_t cgen_var_238;
+        countingStream->handleMapping()->mapHandles_VkQueryPool_u64(&local_queryPool, &cgen_var_238, 1);
+        countingStream->write((uint64_t*)&cgen_var_238, 1 * 8);
         countingStream->write((uint32_t*)&local_firstQuery, sizeof(uint32_t));
         countingStream->write((uint32_t*)&local_queryCount, sizeof(uint32_t));
-        uint64_t cgen_var_235 = (uint64_t)local_dataSize;
-        countingStream->putBe64(cgen_var_235);
+        uint64_t cgen_var_239 = (uint64_t)local_dataSize;
+        countingStream->putBe64(cgen_var_239);
         countingStream->write((void*)pData, ((dataSize)) * sizeof(uint8_t));
         countingStream->write((VkDeviceSize*)&local_stride, sizeof(VkDeviceSize));
         countingStream->write((VkQueryResultFlags*)&local_flags, sizeof(VkQueryResultFlags));
@@ -3509,16 +3666,16 @@
     uint32_t opcode_vkGetQueryPoolResults = OP_vkGetQueryPoolResults;
     stream->write(&opcode_vkGetQueryPoolResults, sizeof(uint32_t));
     stream->write(&packetSize_vkGetQueryPoolResults, sizeof(uint32_t));
-    uint64_t cgen_var_236;
-    stream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_236, 1);
-    stream->write((uint64_t*)&cgen_var_236, 1 * 8);
-    uint64_t cgen_var_237;
-    stream->handleMapping()->mapHandles_VkQueryPool_u64(&local_queryPool, &cgen_var_237, 1);
-    stream->write((uint64_t*)&cgen_var_237, 1 * 8);
+    uint64_t cgen_var_240;
+    stream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_240, 1);
+    stream->write((uint64_t*)&cgen_var_240, 1 * 8);
+    uint64_t cgen_var_241;
+    stream->handleMapping()->mapHandles_VkQueryPool_u64(&local_queryPool, &cgen_var_241, 1);
+    stream->write((uint64_t*)&cgen_var_241, 1 * 8);
     stream->write((uint32_t*)&local_firstQuery, sizeof(uint32_t));
     stream->write((uint32_t*)&local_queryCount, sizeof(uint32_t));
-    uint64_t cgen_var_238 = (uint64_t)local_dataSize;
-    stream->putBe64(cgen_var_238);
+    uint64_t cgen_var_242 = (uint64_t)local_dataSize;
+    stream->putBe64(cgen_var_242);
     stream->write((void*)pData, ((dataSize)) * sizeof(uint8_t));
     stream->write((VkDeviceSize*)&local_stride, sizeof(VkDeviceSize));
     stream->write((VkQueryResultFlags*)&local_flags, sizeof(VkQueryResultFlags));
@@ -3540,6 +3697,7 @@
     const VkAllocationCallbacks* pAllocator,
     VkBuffer* pBuffer)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkCreateBuffer encode");
     mImpl->log("start vkCreateBuffer");
     auto stream = mImpl->stream();
@@ -3574,47 +3732,47 @@
     }
     countingStream->rewind();
     {
-        uint64_t cgen_var_239;
-        countingStream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_239, 1);
-        countingStream->write((uint64_t*)&cgen_var_239, 1 * 8);
+        uint64_t cgen_var_243;
+        countingStream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_243, 1);
+        countingStream->write((uint64_t*)&cgen_var_243, 1 * 8);
         marshal_VkBufferCreateInfo(countingStream, (VkBufferCreateInfo*)(local_pCreateInfo));
         // WARNING PTR CHECK
-        uint64_t cgen_var_240 = (uint64_t)(uintptr_t)local_pAllocator;
-        countingStream->putBe64(cgen_var_240);
+        uint64_t cgen_var_244 = (uint64_t)(uintptr_t)local_pAllocator;
+        countingStream->putBe64(cgen_var_244);
         if (local_pAllocator)
         {
             marshal_VkAllocationCallbacks(countingStream, (VkAllocationCallbacks*)(local_pAllocator));
         }
-        uint64_t cgen_var_241;
-        countingStream->handleMapping()->mapHandles_VkBuffer_u64(pBuffer, &cgen_var_241, 1);
-        countingStream->write((uint64_t*)&cgen_var_241, 8);
+        uint64_t cgen_var_245;
+        countingStream->handleMapping()->mapHandles_VkBuffer_u64(pBuffer, &cgen_var_245, 1);
+        countingStream->write((uint64_t*)&cgen_var_245, 8);
     }
     uint32_t packetSize_vkCreateBuffer = 4 + 4 + (uint32_t)countingStream->bytesWritten();
     countingStream->rewind();
     uint32_t opcode_vkCreateBuffer = OP_vkCreateBuffer;
     stream->write(&opcode_vkCreateBuffer, sizeof(uint32_t));
     stream->write(&packetSize_vkCreateBuffer, sizeof(uint32_t));
-    uint64_t cgen_var_242;
-    stream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_242, 1);
-    stream->write((uint64_t*)&cgen_var_242, 1 * 8);
+    uint64_t cgen_var_246;
+    stream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_246, 1);
+    stream->write((uint64_t*)&cgen_var_246, 1 * 8);
     marshal_VkBufferCreateInfo(stream, (VkBufferCreateInfo*)(local_pCreateInfo));
     // WARNING PTR CHECK
-    uint64_t cgen_var_243 = (uint64_t)(uintptr_t)local_pAllocator;
-    stream->putBe64(cgen_var_243);
+    uint64_t cgen_var_247 = (uint64_t)(uintptr_t)local_pAllocator;
+    stream->putBe64(cgen_var_247);
     if (local_pAllocator)
     {
         marshal_VkAllocationCallbacks(stream, (VkAllocationCallbacks*)(local_pAllocator));
     }
     stream->unsetHandleMapping() /* emit_marshal, is handle, possibly out */;
-    uint64_t cgen_var_244;
-    stream->handleMapping()->mapHandles_VkBuffer_u64(pBuffer, &cgen_var_244, 1);
-    stream->write((uint64_t*)&cgen_var_244, 8);
+    uint64_t cgen_var_248;
+    stream->handleMapping()->mapHandles_VkBuffer_u64(pBuffer, &cgen_var_248, 1);
+    stream->write((uint64_t*)&cgen_var_248, 8);
     stream->setHandleMapping(resources->unwrapMapping());
     AEMU_SCOPED_TRACE("vkCreateBuffer readParams");
     stream->setHandleMapping(resources->createMapping());
-    uint64_t cgen_var_245;
-    stream->read((uint64_t*)&cgen_var_245, 8);
-    stream->handleMapping()->mapHandles_u64_VkBuffer(&cgen_var_245, (VkBuffer*)pBuffer, 1);
+    uint64_t cgen_var_249;
+    stream->read((uint64_t*)&cgen_var_249, 8);
+    stream->handleMapping()->mapHandles_u64_VkBuffer(&cgen_var_249, (VkBuffer*)pBuffer, 1);
     stream->unsetHandleMapping();
     AEMU_SCOPED_TRACE("vkCreateBuffer returnUnmarshal");
     VkResult vkCreateBuffer_VkResult_return = (VkResult)0;
@@ -3631,6 +3789,7 @@
     VkBuffer buffer,
     const VkAllocationCallbacks* pAllocator)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkDestroyBuffer encode");
     mImpl->log("start vkDestroyBuffer");
     auto stream = mImpl->stream();
@@ -3656,15 +3815,15 @@
     }
     countingStream->rewind();
     {
-        uint64_t cgen_var_246;
-        countingStream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_246, 1);
-        countingStream->write((uint64_t*)&cgen_var_246, 1 * 8);
-        uint64_t cgen_var_247;
-        countingStream->handleMapping()->mapHandles_VkBuffer_u64(&local_buffer, &cgen_var_247, 1);
-        countingStream->write((uint64_t*)&cgen_var_247, 1 * 8);
+        uint64_t cgen_var_250;
+        countingStream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_250, 1);
+        countingStream->write((uint64_t*)&cgen_var_250, 1 * 8);
+        uint64_t cgen_var_251;
+        countingStream->handleMapping()->mapHandles_VkBuffer_u64(&local_buffer, &cgen_var_251, 1);
+        countingStream->write((uint64_t*)&cgen_var_251, 1 * 8);
         // WARNING PTR CHECK
-        uint64_t cgen_var_248 = (uint64_t)(uintptr_t)local_pAllocator;
-        countingStream->putBe64(cgen_var_248);
+        uint64_t cgen_var_252 = (uint64_t)(uintptr_t)local_pAllocator;
+        countingStream->putBe64(cgen_var_252);
         if (local_pAllocator)
         {
             marshal_VkAllocationCallbacks(countingStream, (VkAllocationCallbacks*)(local_pAllocator));
@@ -3675,15 +3834,15 @@
     uint32_t opcode_vkDestroyBuffer = OP_vkDestroyBuffer;
     stream->write(&opcode_vkDestroyBuffer, sizeof(uint32_t));
     stream->write(&packetSize_vkDestroyBuffer, sizeof(uint32_t));
-    uint64_t cgen_var_249;
-    stream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_249, 1);
-    stream->write((uint64_t*)&cgen_var_249, 1 * 8);
-    uint64_t cgen_var_250;
-    stream->handleMapping()->mapHandles_VkBuffer_u64(&local_buffer, &cgen_var_250, 1);
-    stream->write((uint64_t*)&cgen_var_250, 1 * 8);
+    uint64_t cgen_var_253;
+    stream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_253, 1);
+    stream->write((uint64_t*)&cgen_var_253, 1 * 8);
+    uint64_t cgen_var_254;
+    stream->handleMapping()->mapHandles_VkBuffer_u64(&local_buffer, &cgen_var_254, 1);
+    stream->write((uint64_t*)&cgen_var_254, 1 * 8);
     // WARNING PTR CHECK
-    uint64_t cgen_var_251 = (uint64_t)(uintptr_t)local_pAllocator;
-    stream->putBe64(cgen_var_251);
+    uint64_t cgen_var_255 = (uint64_t)(uintptr_t)local_pAllocator;
+    stream->putBe64(cgen_var_255);
     if (local_pAllocator)
     {
         marshal_VkAllocationCallbacks(stream, (VkAllocationCallbacks*)(local_pAllocator));
@@ -3700,6 +3859,7 @@
     const VkAllocationCallbacks* pAllocator,
     VkBufferView* pView)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkCreateBufferView encode");
     mImpl->log("start vkCreateBufferView");
     auto stream = mImpl->stream();
@@ -3734,47 +3894,47 @@
     }
     countingStream->rewind();
     {
-        uint64_t cgen_var_252;
-        countingStream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_252, 1);
-        countingStream->write((uint64_t*)&cgen_var_252, 1 * 8);
+        uint64_t cgen_var_256;
+        countingStream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_256, 1);
+        countingStream->write((uint64_t*)&cgen_var_256, 1 * 8);
         marshal_VkBufferViewCreateInfo(countingStream, (VkBufferViewCreateInfo*)(local_pCreateInfo));
         // WARNING PTR CHECK
-        uint64_t cgen_var_253 = (uint64_t)(uintptr_t)local_pAllocator;
-        countingStream->putBe64(cgen_var_253);
+        uint64_t cgen_var_257 = (uint64_t)(uintptr_t)local_pAllocator;
+        countingStream->putBe64(cgen_var_257);
         if (local_pAllocator)
         {
             marshal_VkAllocationCallbacks(countingStream, (VkAllocationCallbacks*)(local_pAllocator));
         }
-        uint64_t cgen_var_254;
-        countingStream->handleMapping()->mapHandles_VkBufferView_u64(pView, &cgen_var_254, 1);
-        countingStream->write((uint64_t*)&cgen_var_254, 8);
+        uint64_t cgen_var_258;
+        countingStream->handleMapping()->mapHandles_VkBufferView_u64(pView, &cgen_var_258, 1);
+        countingStream->write((uint64_t*)&cgen_var_258, 8);
     }
     uint32_t packetSize_vkCreateBufferView = 4 + 4 + (uint32_t)countingStream->bytesWritten();
     countingStream->rewind();
     uint32_t opcode_vkCreateBufferView = OP_vkCreateBufferView;
     stream->write(&opcode_vkCreateBufferView, sizeof(uint32_t));
     stream->write(&packetSize_vkCreateBufferView, sizeof(uint32_t));
-    uint64_t cgen_var_255;
-    stream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_255, 1);
-    stream->write((uint64_t*)&cgen_var_255, 1 * 8);
+    uint64_t cgen_var_259;
+    stream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_259, 1);
+    stream->write((uint64_t*)&cgen_var_259, 1 * 8);
     marshal_VkBufferViewCreateInfo(stream, (VkBufferViewCreateInfo*)(local_pCreateInfo));
     // WARNING PTR CHECK
-    uint64_t cgen_var_256 = (uint64_t)(uintptr_t)local_pAllocator;
-    stream->putBe64(cgen_var_256);
+    uint64_t cgen_var_260 = (uint64_t)(uintptr_t)local_pAllocator;
+    stream->putBe64(cgen_var_260);
     if (local_pAllocator)
     {
         marshal_VkAllocationCallbacks(stream, (VkAllocationCallbacks*)(local_pAllocator));
     }
     stream->unsetHandleMapping() /* emit_marshal, is handle, possibly out */;
-    uint64_t cgen_var_257;
-    stream->handleMapping()->mapHandles_VkBufferView_u64(pView, &cgen_var_257, 1);
-    stream->write((uint64_t*)&cgen_var_257, 8);
+    uint64_t cgen_var_261;
+    stream->handleMapping()->mapHandles_VkBufferView_u64(pView, &cgen_var_261, 1);
+    stream->write((uint64_t*)&cgen_var_261, 8);
     stream->setHandleMapping(resources->unwrapMapping());
     AEMU_SCOPED_TRACE("vkCreateBufferView readParams");
     stream->setHandleMapping(resources->createMapping());
-    uint64_t cgen_var_258;
-    stream->read((uint64_t*)&cgen_var_258, 8);
-    stream->handleMapping()->mapHandles_u64_VkBufferView(&cgen_var_258, (VkBufferView*)pView, 1);
+    uint64_t cgen_var_262;
+    stream->read((uint64_t*)&cgen_var_262, 8);
+    stream->handleMapping()->mapHandles_u64_VkBufferView(&cgen_var_262, (VkBufferView*)pView, 1);
     stream->unsetHandleMapping();
     AEMU_SCOPED_TRACE("vkCreateBufferView returnUnmarshal");
     VkResult vkCreateBufferView_VkResult_return = (VkResult)0;
@@ -3791,6 +3951,7 @@
     VkBufferView bufferView,
     const VkAllocationCallbacks* pAllocator)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkDestroyBufferView encode");
     mImpl->log("start vkDestroyBufferView");
     auto stream = mImpl->stream();
@@ -3816,15 +3977,15 @@
     }
     countingStream->rewind();
     {
-        uint64_t cgen_var_259;
-        countingStream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_259, 1);
-        countingStream->write((uint64_t*)&cgen_var_259, 1 * 8);
-        uint64_t cgen_var_260;
-        countingStream->handleMapping()->mapHandles_VkBufferView_u64(&local_bufferView, &cgen_var_260, 1);
-        countingStream->write((uint64_t*)&cgen_var_260, 1 * 8);
+        uint64_t cgen_var_263;
+        countingStream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_263, 1);
+        countingStream->write((uint64_t*)&cgen_var_263, 1 * 8);
+        uint64_t cgen_var_264;
+        countingStream->handleMapping()->mapHandles_VkBufferView_u64(&local_bufferView, &cgen_var_264, 1);
+        countingStream->write((uint64_t*)&cgen_var_264, 1 * 8);
         // WARNING PTR CHECK
-        uint64_t cgen_var_261 = (uint64_t)(uintptr_t)local_pAllocator;
-        countingStream->putBe64(cgen_var_261);
+        uint64_t cgen_var_265 = (uint64_t)(uintptr_t)local_pAllocator;
+        countingStream->putBe64(cgen_var_265);
         if (local_pAllocator)
         {
             marshal_VkAllocationCallbacks(countingStream, (VkAllocationCallbacks*)(local_pAllocator));
@@ -3835,15 +3996,15 @@
     uint32_t opcode_vkDestroyBufferView = OP_vkDestroyBufferView;
     stream->write(&opcode_vkDestroyBufferView, sizeof(uint32_t));
     stream->write(&packetSize_vkDestroyBufferView, sizeof(uint32_t));
-    uint64_t cgen_var_262;
-    stream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_262, 1);
-    stream->write((uint64_t*)&cgen_var_262, 1 * 8);
-    uint64_t cgen_var_263;
-    stream->handleMapping()->mapHandles_VkBufferView_u64(&local_bufferView, &cgen_var_263, 1);
-    stream->write((uint64_t*)&cgen_var_263, 1 * 8);
+    uint64_t cgen_var_266;
+    stream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_266, 1);
+    stream->write((uint64_t*)&cgen_var_266, 1 * 8);
+    uint64_t cgen_var_267;
+    stream->handleMapping()->mapHandles_VkBufferView_u64(&local_bufferView, &cgen_var_267, 1);
+    stream->write((uint64_t*)&cgen_var_267, 1 * 8);
     // WARNING PTR CHECK
-    uint64_t cgen_var_264 = (uint64_t)(uintptr_t)local_pAllocator;
-    stream->putBe64(cgen_var_264);
+    uint64_t cgen_var_268 = (uint64_t)(uintptr_t)local_pAllocator;
+    stream->putBe64(cgen_var_268);
     if (local_pAllocator)
     {
         marshal_VkAllocationCallbacks(stream, (VkAllocationCallbacks*)(local_pAllocator));
@@ -3860,6 +4021,7 @@
     const VkAllocationCallbacks* pAllocator,
     VkImage* pImage)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkCreateImage encode");
     mImpl->log("start vkCreateImage");
     auto stream = mImpl->stream();
@@ -3895,47 +4057,47 @@
     }
     countingStream->rewind();
     {
-        uint64_t cgen_var_265;
-        countingStream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_265, 1);
-        countingStream->write((uint64_t*)&cgen_var_265, 1 * 8);
+        uint64_t cgen_var_269;
+        countingStream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_269, 1);
+        countingStream->write((uint64_t*)&cgen_var_269, 1 * 8);
         marshal_VkImageCreateInfo(countingStream, (VkImageCreateInfo*)(local_pCreateInfo));
         // WARNING PTR CHECK
-        uint64_t cgen_var_266 = (uint64_t)(uintptr_t)local_pAllocator;
-        countingStream->putBe64(cgen_var_266);
+        uint64_t cgen_var_270 = (uint64_t)(uintptr_t)local_pAllocator;
+        countingStream->putBe64(cgen_var_270);
         if (local_pAllocator)
         {
             marshal_VkAllocationCallbacks(countingStream, (VkAllocationCallbacks*)(local_pAllocator));
         }
-        uint64_t cgen_var_267;
-        countingStream->handleMapping()->mapHandles_VkImage_u64(pImage, &cgen_var_267, 1);
-        countingStream->write((uint64_t*)&cgen_var_267, 8);
+        uint64_t cgen_var_271;
+        countingStream->handleMapping()->mapHandles_VkImage_u64(pImage, &cgen_var_271, 1);
+        countingStream->write((uint64_t*)&cgen_var_271, 8);
     }
     uint32_t packetSize_vkCreateImage = 4 + 4 + (uint32_t)countingStream->bytesWritten();
     countingStream->rewind();
     uint32_t opcode_vkCreateImage = OP_vkCreateImage;
     stream->write(&opcode_vkCreateImage, sizeof(uint32_t));
     stream->write(&packetSize_vkCreateImage, sizeof(uint32_t));
-    uint64_t cgen_var_268;
-    stream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_268, 1);
-    stream->write((uint64_t*)&cgen_var_268, 1 * 8);
+    uint64_t cgen_var_272;
+    stream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_272, 1);
+    stream->write((uint64_t*)&cgen_var_272, 1 * 8);
     marshal_VkImageCreateInfo(stream, (VkImageCreateInfo*)(local_pCreateInfo));
     // WARNING PTR CHECK
-    uint64_t cgen_var_269 = (uint64_t)(uintptr_t)local_pAllocator;
-    stream->putBe64(cgen_var_269);
+    uint64_t cgen_var_273 = (uint64_t)(uintptr_t)local_pAllocator;
+    stream->putBe64(cgen_var_273);
     if (local_pAllocator)
     {
         marshal_VkAllocationCallbacks(stream, (VkAllocationCallbacks*)(local_pAllocator));
     }
     stream->unsetHandleMapping() /* emit_marshal, is handle, possibly out */;
-    uint64_t cgen_var_270;
-    stream->handleMapping()->mapHandles_VkImage_u64(pImage, &cgen_var_270, 1);
-    stream->write((uint64_t*)&cgen_var_270, 8);
+    uint64_t cgen_var_274;
+    stream->handleMapping()->mapHandles_VkImage_u64(pImage, &cgen_var_274, 1);
+    stream->write((uint64_t*)&cgen_var_274, 8);
     stream->setHandleMapping(resources->unwrapMapping());
     AEMU_SCOPED_TRACE("vkCreateImage readParams");
     stream->setHandleMapping(resources->createMapping());
-    uint64_t cgen_var_271;
-    stream->read((uint64_t*)&cgen_var_271, 8);
-    stream->handleMapping()->mapHandles_u64_VkImage(&cgen_var_271, (VkImage*)pImage, 1);
+    uint64_t cgen_var_275;
+    stream->read((uint64_t*)&cgen_var_275, 8);
+    stream->handleMapping()->mapHandles_u64_VkImage(&cgen_var_275, (VkImage*)pImage, 1);
     stream->unsetHandleMapping();
     AEMU_SCOPED_TRACE("vkCreateImage returnUnmarshal");
     VkResult vkCreateImage_VkResult_return = (VkResult)0;
@@ -3952,6 +4114,7 @@
     VkImage image,
     const VkAllocationCallbacks* pAllocator)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkDestroyImage encode");
     mImpl->log("start vkDestroyImage");
     auto stream = mImpl->stream();
@@ -3977,15 +4140,15 @@
     }
     countingStream->rewind();
     {
-        uint64_t cgen_var_272;
-        countingStream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_272, 1);
-        countingStream->write((uint64_t*)&cgen_var_272, 1 * 8);
-        uint64_t cgen_var_273;
-        countingStream->handleMapping()->mapHandles_VkImage_u64(&local_image, &cgen_var_273, 1);
-        countingStream->write((uint64_t*)&cgen_var_273, 1 * 8);
+        uint64_t cgen_var_276;
+        countingStream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_276, 1);
+        countingStream->write((uint64_t*)&cgen_var_276, 1 * 8);
+        uint64_t cgen_var_277;
+        countingStream->handleMapping()->mapHandles_VkImage_u64(&local_image, &cgen_var_277, 1);
+        countingStream->write((uint64_t*)&cgen_var_277, 1 * 8);
         // WARNING PTR CHECK
-        uint64_t cgen_var_274 = (uint64_t)(uintptr_t)local_pAllocator;
-        countingStream->putBe64(cgen_var_274);
+        uint64_t cgen_var_278 = (uint64_t)(uintptr_t)local_pAllocator;
+        countingStream->putBe64(cgen_var_278);
         if (local_pAllocator)
         {
             marshal_VkAllocationCallbacks(countingStream, (VkAllocationCallbacks*)(local_pAllocator));
@@ -3996,15 +4159,15 @@
     uint32_t opcode_vkDestroyImage = OP_vkDestroyImage;
     stream->write(&opcode_vkDestroyImage, sizeof(uint32_t));
     stream->write(&packetSize_vkDestroyImage, sizeof(uint32_t));
-    uint64_t cgen_var_275;
-    stream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_275, 1);
-    stream->write((uint64_t*)&cgen_var_275, 1 * 8);
-    uint64_t cgen_var_276;
-    stream->handleMapping()->mapHandles_VkImage_u64(&local_image, &cgen_var_276, 1);
-    stream->write((uint64_t*)&cgen_var_276, 1 * 8);
+    uint64_t cgen_var_279;
+    stream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_279, 1);
+    stream->write((uint64_t*)&cgen_var_279, 1 * 8);
+    uint64_t cgen_var_280;
+    stream->handleMapping()->mapHandles_VkImage_u64(&local_image, &cgen_var_280, 1);
+    stream->write((uint64_t*)&cgen_var_280, 1 * 8);
     // WARNING PTR CHECK
-    uint64_t cgen_var_277 = (uint64_t)(uintptr_t)local_pAllocator;
-    stream->putBe64(cgen_var_277);
+    uint64_t cgen_var_281 = (uint64_t)(uintptr_t)local_pAllocator;
+    stream->putBe64(cgen_var_281);
     if (local_pAllocator)
     {
         marshal_VkAllocationCallbacks(stream, (VkAllocationCallbacks*)(local_pAllocator));
@@ -4021,6 +4184,7 @@
     const VkImageSubresource* pSubresource,
     VkSubresourceLayout* pLayout)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkGetImageSubresourceLayout encode");
     mImpl->log("start vkGetImageSubresourceLayout");
     auto stream = mImpl->stream();
@@ -4045,12 +4209,12 @@
     }
     countingStream->rewind();
     {
-        uint64_t cgen_var_278;
-        countingStream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_278, 1);
-        countingStream->write((uint64_t*)&cgen_var_278, 1 * 8);
-        uint64_t cgen_var_279;
-        countingStream->handleMapping()->mapHandles_VkImage_u64(&local_image, &cgen_var_279, 1);
-        countingStream->write((uint64_t*)&cgen_var_279, 1 * 8);
+        uint64_t cgen_var_282;
+        countingStream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_282, 1);
+        countingStream->write((uint64_t*)&cgen_var_282, 1 * 8);
+        uint64_t cgen_var_283;
+        countingStream->handleMapping()->mapHandles_VkImage_u64(&local_image, &cgen_var_283, 1);
+        countingStream->write((uint64_t*)&cgen_var_283, 1 * 8);
         marshal_VkImageSubresource(countingStream, (VkImageSubresource*)(local_pSubresource));
         marshal_VkSubresourceLayout(countingStream, (VkSubresourceLayout*)(pLayout));
     }
@@ -4059,12 +4223,12 @@
     uint32_t opcode_vkGetImageSubresourceLayout = OP_vkGetImageSubresourceLayout;
     stream->write(&opcode_vkGetImageSubresourceLayout, sizeof(uint32_t));
     stream->write(&packetSize_vkGetImageSubresourceLayout, sizeof(uint32_t));
-    uint64_t cgen_var_280;
-    stream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_280, 1);
-    stream->write((uint64_t*)&cgen_var_280, 1 * 8);
-    uint64_t cgen_var_281;
-    stream->handleMapping()->mapHandles_VkImage_u64(&local_image, &cgen_var_281, 1);
-    stream->write((uint64_t*)&cgen_var_281, 1 * 8);
+    uint64_t cgen_var_284;
+    stream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_284, 1);
+    stream->write((uint64_t*)&cgen_var_284, 1 * 8);
+    uint64_t cgen_var_285;
+    stream->handleMapping()->mapHandles_VkImage_u64(&local_image, &cgen_var_285, 1);
+    stream->write((uint64_t*)&cgen_var_285, 1 * 8);
     marshal_VkImageSubresource(stream, (VkImageSubresource*)(local_pSubresource));
     marshal_VkSubresourceLayout(stream, (VkSubresourceLayout*)(pLayout));
     AEMU_SCOPED_TRACE("vkGetImageSubresourceLayout readParams");
@@ -4083,6 +4247,7 @@
     const VkAllocationCallbacks* pAllocator,
     VkImageView* pView)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkCreateImageView encode");
     mImpl->log("start vkCreateImageView");
     auto stream = mImpl->stream();
@@ -4117,47 +4282,47 @@
     }
     countingStream->rewind();
     {
-        uint64_t cgen_var_282;
-        countingStream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_282, 1);
-        countingStream->write((uint64_t*)&cgen_var_282, 1 * 8);
+        uint64_t cgen_var_286;
+        countingStream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_286, 1);
+        countingStream->write((uint64_t*)&cgen_var_286, 1 * 8);
         marshal_VkImageViewCreateInfo(countingStream, (VkImageViewCreateInfo*)(local_pCreateInfo));
         // WARNING PTR CHECK
-        uint64_t cgen_var_283 = (uint64_t)(uintptr_t)local_pAllocator;
-        countingStream->putBe64(cgen_var_283);
+        uint64_t cgen_var_287 = (uint64_t)(uintptr_t)local_pAllocator;
+        countingStream->putBe64(cgen_var_287);
         if (local_pAllocator)
         {
             marshal_VkAllocationCallbacks(countingStream, (VkAllocationCallbacks*)(local_pAllocator));
         }
-        uint64_t cgen_var_284;
-        countingStream->handleMapping()->mapHandles_VkImageView_u64(pView, &cgen_var_284, 1);
-        countingStream->write((uint64_t*)&cgen_var_284, 8);
+        uint64_t cgen_var_288;
+        countingStream->handleMapping()->mapHandles_VkImageView_u64(pView, &cgen_var_288, 1);
+        countingStream->write((uint64_t*)&cgen_var_288, 8);
     }
     uint32_t packetSize_vkCreateImageView = 4 + 4 + (uint32_t)countingStream->bytesWritten();
     countingStream->rewind();
     uint32_t opcode_vkCreateImageView = OP_vkCreateImageView;
     stream->write(&opcode_vkCreateImageView, sizeof(uint32_t));
     stream->write(&packetSize_vkCreateImageView, sizeof(uint32_t));
-    uint64_t cgen_var_285;
-    stream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_285, 1);
-    stream->write((uint64_t*)&cgen_var_285, 1 * 8);
+    uint64_t cgen_var_289;
+    stream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_289, 1);
+    stream->write((uint64_t*)&cgen_var_289, 1 * 8);
     marshal_VkImageViewCreateInfo(stream, (VkImageViewCreateInfo*)(local_pCreateInfo));
     // WARNING PTR CHECK
-    uint64_t cgen_var_286 = (uint64_t)(uintptr_t)local_pAllocator;
-    stream->putBe64(cgen_var_286);
+    uint64_t cgen_var_290 = (uint64_t)(uintptr_t)local_pAllocator;
+    stream->putBe64(cgen_var_290);
     if (local_pAllocator)
     {
         marshal_VkAllocationCallbacks(stream, (VkAllocationCallbacks*)(local_pAllocator));
     }
     stream->unsetHandleMapping() /* emit_marshal, is handle, possibly out */;
-    uint64_t cgen_var_287;
-    stream->handleMapping()->mapHandles_VkImageView_u64(pView, &cgen_var_287, 1);
-    stream->write((uint64_t*)&cgen_var_287, 8);
+    uint64_t cgen_var_291;
+    stream->handleMapping()->mapHandles_VkImageView_u64(pView, &cgen_var_291, 1);
+    stream->write((uint64_t*)&cgen_var_291, 8);
     stream->setHandleMapping(resources->unwrapMapping());
     AEMU_SCOPED_TRACE("vkCreateImageView readParams");
     stream->setHandleMapping(resources->createMapping());
-    uint64_t cgen_var_288;
-    stream->read((uint64_t*)&cgen_var_288, 8);
-    stream->handleMapping()->mapHandles_u64_VkImageView(&cgen_var_288, (VkImageView*)pView, 1);
+    uint64_t cgen_var_292;
+    stream->read((uint64_t*)&cgen_var_292, 8);
+    stream->handleMapping()->mapHandles_u64_VkImageView(&cgen_var_292, (VkImageView*)pView, 1);
     stream->unsetHandleMapping();
     AEMU_SCOPED_TRACE("vkCreateImageView returnUnmarshal");
     VkResult vkCreateImageView_VkResult_return = (VkResult)0;
@@ -4174,6 +4339,7 @@
     VkImageView imageView,
     const VkAllocationCallbacks* pAllocator)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkDestroyImageView encode");
     mImpl->log("start vkDestroyImageView");
     auto stream = mImpl->stream();
@@ -4199,15 +4365,15 @@
     }
     countingStream->rewind();
     {
-        uint64_t cgen_var_289;
-        countingStream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_289, 1);
-        countingStream->write((uint64_t*)&cgen_var_289, 1 * 8);
-        uint64_t cgen_var_290;
-        countingStream->handleMapping()->mapHandles_VkImageView_u64(&local_imageView, &cgen_var_290, 1);
-        countingStream->write((uint64_t*)&cgen_var_290, 1 * 8);
+        uint64_t cgen_var_293;
+        countingStream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_293, 1);
+        countingStream->write((uint64_t*)&cgen_var_293, 1 * 8);
+        uint64_t cgen_var_294;
+        countingStream->handleMapping()->mapHandles_VkImageView_u64(&local_imageView, &cgen_var_294, 1);
+        countingStream->write((uint64_t*)&cgen_var_294, 1 * 8);
         // WARNING PTR CHECK
-        uint64_t cgen_var_291 = (uint64_t)(uintptr_t)local_pAllocator;
-        countingStream->putBe64(cgen_var_291);
+        uint64_t cgen_var_295 = (uint64_t)(uintptr_t)local_pAllocator;
+        countingStream->putBe64(cgen_var_295);
         if (local_pAllocator)
         {
             marshal_VkAllocationCallbacks(countingStream, (VkAllocationCallbacks*)(local_pAllocator));
@@ -4218,15 +4384,15 @@
     uint32_t opcode_vkDestroyImageView = OP_vkDestroyImageView;
     stream->write(&opcode_vkDestroyImageView, sizeof(uint32_t));
     stream->write(&packetSize_vkDestroyImageView, sizeof(uint32_t));
-    uint64_t cgen_var_292;
-    stream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_292, 1);
-    stream->write((uint64_t*)&cgen_var_292, 1 * 8);
-    uint64_t cgen_var_293;
-    stream->handleMapping()->mapHandles_VkImageView_u64(&local_imageView, &cgen_var_293, 1);
-    stream->write((uint64_t*)&cgen_var_293, 1 * 8);
+    uint64_t cgen_var_296;
+    stream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_296, 1);
+    stream->write((uint64_t*)&cgen_var_296, 1 * 8);
+    uint64_t cgen_var_297;
+    stream->handleMapping()->mapHandles_VkImageView_u64(&local_imageView, &cgen_var_297, 1);
+    stream->write((uint64_t*)&cgen_var_297, 1 * 8);
     // WARNING PTR CHECK
-    uint64_t cgen_var_294 = (uint64_t)(uintptr_t)local_pAllocator;
-    stream->putBe64(cgen_var_294);
+    uint64_t cgen_var_298 = (uint64_t)(uintptr_t)local_pAllocator;
+    stream->putBe64(cgen_var_298);
     if (local_pAllocator)
     {
         marshal_VkAllocationCallbacks(stream, (VkAllocationCallbacks*)(local_pAllocator));
@@ -4243,6 +4409,7 @@
     const VkAllocationCallbacks* pAllocator,
     VkShaderModule* pShaderModule)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkCreateShaderModule encode");
     mImpl->log("start vkCreateShaderModule");
     auto stream = mImpl->stream();
@@ -4277,47 +4444,47 @@
     }
     countingStream->rewind();
     {
-        uint64_t cgen_var_295;
-        countingStream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_295, 1);
-        countingStream->write((uint64_t*)&cgen_var_295, 1 * 8);
+        uint64_t cgen_var_299;
+        countingStream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_299, 1);
+        countingStream->write((uint64_t*)&cgen_var_299, 1 * 8);
         marshal_VkShaderModuleCreateInfo(countingStream, (VkShaderModuleCreateInfo*)(local_pCreateInfo));
         // WARNING PTR CHECK
-        uint64_t cgen_var_296 = (uint64_t)(uintptr_t)local_pAllocator;
-        countingStream->putBe64(cgen_var_296);
+        uint64_t cgen_var_300 = (uint64_t)(uintptr_t)local_pAllocator;
+        countingStream->putBe64(cgen_var_300);
         if (local_pAllocator)
         {
             marshal_VkAllocationCallbacks(countingStream, (VkAllocationCallbacks*)(local_pAllocator));
         }
-        uint64_t cgen_var_297;
-        countingStream->handleMapping()->mapHandles_VkShaderModule_u64(pShaderModule, &cgen_var_297, 1);
-        countingStream->write((uint64_t*)&cgen_var_297, 8);
+        uint64_t cgen_var_301;
+        countingStream->handleMapping()->mapHandles_VkShaderModule_u64(pShaderModule, &cgen_var_301, 1);
+        countingStream->write((uint64_t*)&cgen_var_301, 8);
     }
     uint32_t packetSize_vkCreateShaderModule = 4 + 4 + (uint32_t)countingStream->bytesWritten();
     countingStream->rewind();
     uint32_t opcode_vkCreateShaderModule = OP_vkCreateShaderModule;
     stream->write(&opcode_vkCreateShaderModule, sizeof(uint32_t));
     stream->write(&packetSize_vkCreateShaderModule, sizeof(uint32_t));
-    uint64_t cgen_var_298;
-    stream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_298, 1);
-    stream->write((uint64_t*)&cgen_var_298, 1 * 8);
+    uint64_t cgen_var_302;
+    stream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_302, 1);
+    stream->write((uint64_t*)&cgen_var_302, 1 * 8);
     marshal_VkShaderModuleCreateInfo(stream, (VkShaderModuleCreateInfo*)(local_pCreateInfo));
     // WARNING PTR CHECK
-    uint64_t cgen_var_299 = (uint64_t)(uintptr_t)local_pAllocator;
-    stream->putBe64(cgen_var_299);
+    uint64_t cgen_var_303 = (uint64_t)(uintptr_t)local_pAllocator;
+    stream->putBe64(cgen_var_303);
     if (local_pAllocator)
     {
         marshal_VkAllocationCallbacks(stream, (VkAllocationCallbacks*)(local_pAllocator));
     }
     stream->unsetHandleMapping() /* emit_marshal, is handle, possibly out */;
-    uint64_t cgen_var_300;
-    stream->handleMapping()->mapHandles_VkShaderModule_u64(pShaderModule, &cgen_var_300, 1);
-    stream->write((uint64_t*)&cgen_var_300, 8);
+    uint64_t cgen_var_304;
+    stream->handleMapping()->mapHandles_VkShaderModule_u64(pShaderModule, &cgen_var_304, 1);
+    stream->write((uint64_t*)&cgen_var_304, 8);
     stream->setHandleMapping(resources->unwrapMapping());
     AEMU_SCOPED_TRACE("vkCreateShaderModule readParams");
     stream->setHandleMapping(resources->createMapping());
-    uint64_t cgen_var_301;
-    stream->read((uint64_t*)&cgen_var_301, 8);
-    stream->handleMapping()->mapHandles_u64_VkShaderModule(&cgen_var_301, (VkShaderModule*)pShaderModule, 1);
+    uint64_t cgen_var_305;
+    stream->read((uint64_t*)&cgen_var_305, 8);
+    stream->handleMapping()->mapHandles_u64_VkShaderModule(&cgen_var_305, (VkShaderModule*)pShaderModule, 1);
     stream->unsetHandleMapping();
     AEMU_SCOPED_TRACE("vkCreateShaderModule returnUnmarshal");
     VkResult vkCreateShaderModule_VkResult_return = (VkResult)0;
@@ -4334,6 +4501,7 @@
     VkShaderModule shaderModule,
     const VkAllocationCallbacks* pAllocator)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkDestroyShaderModule encode");
     mImpl->log("start vkDestroyShaderModule");
     auto stream = mImpl->stream();
@@ -4359,15 +4527,15 @@
     }
     countingStream->rewind();
     {
-        uint64_t cgen_var_302;
-        countingStream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_302, 1);
-        countingStream->write((uint64_t*)&cgen_var_302, 1 * 8);
-        uint64_t cgen_var_303;
-        countingStream->handleMapping()->mapHandles_VkShaderModule_u64(&local_shaderModule, &cgen_var_303, 1);
-        countingStream->write((uint64_t*)&cgen_var_303, 1 * 8);
+        uint64_t cgen_var_306;
+        countingStream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_306, 1);
+        countingStream->write((uint64_t*)&cgen_var_306, 1 * 8);
+        uint64_t cgen_var_307;
+        countingStream->handleMapping()->mapHandles_VkShaderModule_u64(&local_shaderModule, &cgen_var_307, 1);
+        countingStream->write((uint64_t*)&cgen_var_307, 1 * 8);
         // WARNING PTR CHECK
-        uint64_t cgen_var_304 = (uint64_t)(uintptr_t)local_pAllocator;
-        countingStream->putBe64(cgen_var_304);
+        uint64_t cgen_var_308 = (uint64_t)(uintptr_t)local_pAllocator;
+        countingStream->putBe64(cgen_var_308);
         if (local_pAllocator)
         {
             marshal_VkAllocationCallbacks(countingStream, (VkAllocationCallbacks*)(local_pAllocator));
@@ -4378,15 +4546,15 @@
     uint32_t opcode_vkDestroyShaderModule = OP_vkDestroyShaderModule;
     stream->write(&opcode_vkDestroyShaderModule, sizeof(uint32_t));
     stream->write(&packetSize_vkDestroyShaderModule, sizeof(uint32_t));
-    uint64_t cgen_var_305;
-    stream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_305, 1);
-    stream->write((uint64_t*)&cgen_var_305, 1 * 8);
-    uint64_t cgen_var_306;
-    stream->handleMapping()->mapHandles_VkShaderModule_u64(&local_shaderModule, &cgen_var_306, 1);
-    stream->write((uint64_t*)&cgen_var_306, 1 * 8);
+    uint64_t cgen_var_309;
+    stream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_309, 1);
+    stream->write((uint64_t*)&cgen_var_309, 1 * 8);
+    uint64_t cgen_var_310;
+    stream->handleMapping()->mapHandles_VkShaderModule_u64(&local_shaderModule, &cgen_var_310, 1);
+    stream->write((uint64_t*)&cgen_var_310, 1 * 8);
     // WARNING PTR CHECK
-    uint64_t cgen_var_307 = (uint64_t)(uintptr_t)local_pAllocator;
-    stream->putBe64(cgen_var_307);
+    uint64_t cgen_var_311 = (uint64_t)(uintptr_t)local_pAllocator;
+    stream->putBe64(cgen_var_311);
     if (local_pAllocator)
     {
         marshal_VkAllocationCallbacks(stream, (VkAllocationCallbacks*)(local_pAllocator));
@@ -4403,6 +4571,7 @@
     const VkAllocationCallbacks* pAllocator,
     VkPipelineCache* pPipelineCache)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkCreatePipelineCache encode");
     mImpl->log("start vkCreatePipelineCache");
     auto stream = mImpl->stream();
@@ -4437,47 +4606,47 @@
     }
     countingStream->rewind();
     {
-        uint64_t cgen_var_308;
-        countingStream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_308, 1);
-        countingStream->write((uint64_t*)&cgen_var_308, 1 * 8);
+        uint64_t cgen_var_312;
+        countingStream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_312, 1);
+        countingStream->write((uint64_t*)&cgen_var_312, 1 * 8);
         marshal_VkPipelineCacheCreateInfo(countingStream, (VkPipelineCacheCreateInfo*)(local_pCreateInfo));
         // WARNING PTR CHECK
-        uint64_t cgen_var_309 = (uint64_t)(uintptr_t)local_pAllocator;
-        countingStream->putBe64(cgen_var_309);
+        uint64_t cgen_var_313 = (uint64_t)(uintptr_t)local_pAllocator;
+        countingStream->putBe64(cgen_var_313);
         if (local_pAllocator)
         {
             marshal_VkAllocationCallbacks(countingStream, (VkAllocationCallbacks*)(local_pAllocator));
         }
-        uint64_t cgen_var_310;
-        countingStream->handleMapping()->mapHandles_VkPipelineCache_u64(pPipelineCache, &cgen_var_310, 1);
-        countingStream->write((uint64_t*)&cgen_var_310, 8);
+        uint64_t cgen_var_314;
+        countingStream->handleMapping()->mapHandles_VkPipelineCache_u64(pPipelineCache, &cgen_var_314, 1);
+        countingStream->write((uint64_t*)&cgen_var_314, 8);
     }
     uint32_t packetSize_vkCreatePipelineCache = 4 + 4 + (uint32_t)countingStream->bytesWritten();
     countingStream->rewind();
     uint32_t opcode_vkCreatePipelineCache = OP_vkCreatePipelineCache;
     stream->write(&opcode_vkCreatePipelineCache, sizeof(uint32_t));
     stream->write(&packetSize_vkCreatePipelineCache, sizeof(uint32_t));
-    uint64_t cgen_var_311;
-    stream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_311, 1);
-    stream->write((uint64_t*)&cgen_var_311, 1 * 8);
+    uint64_t cgen_var_315;
+    stream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_315, 1);
+    stream->write((uint64_t*)&cgen_var_315, 1 * 8);
     marshal_VkPipelineCacheCreateInfo(stream, (VkPipelineCacheCreateInfo*)(local_pCreateInfo));
     // WARNING PTR CHECK
-    uint64_t cgen_var_312 = (uint64_t)(uintptr_t)local_pAllocator;
-    stream->putBe64(cgen_var_312);
+    uint64_t cgen_var_316 = (uint64_t)(uintptr_t)local_pAllocator;
+    stream->putBe64(cgen_var_316);
     if (local_pAllocator)
     {
         marshal_VkAllocationCallbacks(stream, (VkAllocationCallbacks*)(local_pAllocator));
     }
     stream->unsetHandleMapping() /* emit_marshal, is handle, possibly out */;
-    uint64_t cgen_var_313;
-    stream->handleMapping()->mapHandles_VkPipelineCache_u64(pPipelineCache, &cgen_var_313, 1);
-    stream->write((uint64_t*)&cgen_var_313, 8);
+    uint64_t cgen_var_317;
+    stream->handleMapping()->mapHandles_VkPipelineCache_u64(pPipelineCache, &cgen_var_317, 1);
+    stream->write((uint64_t*)&cgen_var_317, 8);
     stream->setHandleMapping(resources->unwrapMapping());
     AEMU_SCOPED_TRACE("vkCreatePipelineCache readParams");
     stream->setHandleMapping(resources->createMapping());
-    uint64_t cgen_var_314;
-    stream->read((uint64_t*)&cgen_var_314, 8);
-    stream->handleMapping()->mapHandles_u64_VkPipelineCache(&cgen_var_314, (VkPipelineCache*)pPipelineCache, 1);
+    uint64_t cgen_var_318;
+    stream->read((uint64_t*)&cgen_var_318, 8);
+    stream->handleMapping()->mapHandles_u64_VkPipelineCache(&cgen_var_318, (VkPipelineCache*)pPipelineCache, 1);
     stream->unsetHandleMapping();
     AEMU_SCOPED_TRACE("vkCreatePipelineCache returnUnmarshal");
     VkResult vkCreatePipelineCache_VkResult_return = (VkResult)0;
@@ -4494,6 +4663,7 @@
     VkPipelineCache pipelineCache,
     const VkAllocationCallbacks* pAllocator)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkDestroyPipelineCache encode");
     mImpl->log("start vkDestroyPipelineCache");
     auto stream = mImpl->stream();
@@ -4519,15 +4689,15 @@
     }
     countingStream->rewind();
     {
-        uint64_t cgen_var_315;
-        countingStream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_315, 1);
-        countingStream->write((uint64_t*)&cgen_var_315, 1 * 8);
-        uint64_t cgen_var_316;
-        countingStream->handleMapping()->mapHandles_VkPipelineCache_u64(&local_pipelineCache, &cgen_var_316, 1);
-        countingStream->write((uint64_t*)&cgen_var_316, 1 * 8);
+        uint64_t cgen_var_319;
+        countingStream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_319, 1);
+        countingStream->write((uint64_t*)&cgen_var_319, 1 * 8);
+        uint64_t cgen_var_320;
+        countingStream->handleMapping()->mapHandles_VkPipelineCache_u64(&local_pipelineCache, &cgen_var_320, 1);
+        countingStream->write((uint64_t*)&cgen_var_320, 1 * 8);
         // WARNING PTR CHECK
-        uint64_t cgen_var_317 = (uint64_t)(uintptr_t)local_pAllocator;
-        countingStream->putBe64(cgen_var_317);
+        uint64_t cgen_var_321 = (uint64_t)(uintptr_t)local_pAllocator;
+        countingStream->putBe64(cgen_var_321);
         if (local_pAllocator)
         {
             marshal_VkAllocationCallbacks(countingStream, (VkAllocationCallbacks*)(local_pAllocator));
@@ -4538,15 +4708,15 @@
     uint32_t opcode_vkDestroyPipelineCache = OP_vkDestroyPipelineCache;
     stream->write(&opcode_vkDestroyPipelineCache, sizeof(uint32_t));
     stream->write(&packetSize_vkDestroyPipelineCache, sizeof(uint32_t));
-    uint64_t cgen_var_318;
-    stream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_318, 1);
-    stream->write((uint64_t*)&cgen_var_318, 1 * 8);
-    uint64_t cgen_var_319;
-    stream->handleMapping()->mapHandles_VkPipelineCache_u64(&local_pipelineCache, &cgen_var_319, 1);
-    stream->write((uint64_t*)&cgen_var_319, 1 * 8);
+    uint64_t cgen_var_322;
+    stream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_322, 1);
+    stream->write((uint64_t*)&cgen_var_322, 1 * 8);
+    uint64_t cgen_var_323;
+    stream->handleMapping()->mapHandles_VkPipelineCache_u64(&local_pipelineCache, &cgen_var_323, 1);
+    stream->write((uint64_t*)&cgen_var_323, 1 * 8);
     // WARNING PTR CHECK
-    uint64_t cgen_var_320 = (uint64_t)(uintptr_t)local_pAllocator;
-    stream->putBe64(cgen_var_320);
+    uint64_t cgen_var_324 = (uint64_t)(uintptr_t)local_pAllocator;
+    stream->putBe64(cgen_var_324);
     if (local_pAllocator)
     {
         marshal_VkAllocationCallbacks(stream, (VkAllocationCallbacks*)(local_pAllocator));
@@ -4563,6 +4733,7 @@
     size_t* pDataSize,
     void* pData)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkGetPipelineCacheData encode");
     mImpl->log("start vkGetPipelineCacheData");
     auto stream = mImpl->stream();
@@ -4576,23 +4747,23 @@
     local_pipelineCache = pipelineCache;
     countingStream->rewind();
     {
-        uint64_t cgen_var_321;
-        countingStream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_321, 1);
-        countingStream->write((uint64_t*)&cgen_var_321, 1 * 8);
-        uint64_t cgen_var_322;
-        countingStream->handleMapping()->mapHandles_VkPipelineCache_u64(&local_pipelineCache, &cgen_var_322, 1);
-        countingStream->write((uint64_t*)&cgen_var_322, 1 * 8);
+        uint64_t cgen_var_325;
+        countingStream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_325, 1);
+        countingStream->write((uint64_t*)&cgen_var_325, 1 * 8);
+        uint64_t cgen_var_326;
+        countingStream->handleMapping()->mapHandles_VkPipelineCache_u64(&local_pipelineCache, &cgen_var_326, 1);
+        countingStream->write((uint64_t*)&cgen_var_326, 1 * 8);
         // WARNING PTR CHECK
-        uint64_t cgen_var_323 = (uint64_t)(uintptr_t)pDataSize;
-        countingStream->putBe64(cgen_var_323);
+        uint64_t cgen_var_327 = (uint64_t)(uintptr_t)pDataSize;
+        countingStream->putBe64(cgen_var_327);
         if (pDataSize)
         {
-            uint64_t cgen_var_324 = (uint64_t)(*pDataSize);
-            countingStream->putBe64(cgen_var_324);
+            uint64_t cgen_var_328 = (uint64_t)(*pDataSize);
+            countingStream->putBe64(cgen_var_328);
         }
         // WARNING PTR CHECK
-        uint64_t cgen_var_325 = (uint64_t)(uintptr_t)pData;
-        countingStream->putBe64(cgen_var_325);
+        uint64_t cgen_var_329 = (uint64_t)(uintptr_t)pData;
+        countingStream->putBe64(cgen_var_329);
         if (pData)
         {
             countingStream->write((void*)pData, (*(pDataSize)) * sizeof(uint8_t));
@@ -4603,23 +4774,23 @@
     uint32_t opcode_vkGetPipelineCacheData = OP_vkGetPipelineCacheData;
     stream->write(&opcode_vkGetPipelineCacheData, sizeof(uint32_t));
     stream->write(&packetSize_vkGetPipelineCacheData, sizeof(uint32_t));
-    uint64_t cgen_var_326;
-    stream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_326, 1);
-    stream->write((uint64_t*)&cgen_var_326, 1 * 8);
-    uint64_t cgen_var_327;
-    stream->handleMapping()->mapHandles_VkPipelineCache_u64(&local_pipelineCache, &cgen_var_327, 1);
-    stream->write((uint64_t*)&cgen_var_327, 1 * 8);
+    uint64_t cgen_var_330;
+    stream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_330, 1);
+    stream->write((uint64_t*)&cgen_var_330, 1 * 8);
+    uint64_t cgen_var_331;
+    stream->handleMapping()->mapHandles_VkPipelineCache_u64(&local_pipelineCache, &cgen_var_331, 1);
+    stream->write((uint64_t*)&cgen_var_331, 1 * 8);
     // WARNING PTR CHECK
-    uint64_t cgen_var_328 = (uint64_t)(uintptr_t)pDataSize;
-    stream->putBe64(cgen_var_328);
+    uint64_t cgen_var_332 = (uint64_t)(uintptr_t)pDataSize;
+    stream->putBe64(cgen_var_332);
     if (pDataSize)
     {
-        uint64_t cgen_var_329 = (uint64_t)(*pDataSize);
-        stream->putBe64(cgen_var_329);
+        uint64_t cgen_var_333 = (uint64_t)(*pDataSize);
+        stream->putBe64(cgen_var_333);
     }
     // WARNING PTR CHECK
-    uint64_t cgen_var_330 = (uint64_t)(uintptr_t)pData;
-    stream->putBe64(cgen_var_330);
+    uint64_t cgen_var_334 = (uint64_t)(uintptr_t)pData;
+    stream->putBe64(cgen_var_334);
     if (pData)
     {
         stream->write((void*)pData, (*(pDataSize)) * sizeof(uint8_t));
@@ -4663,6 +4834,7 @@
     uint32_t srcCacheCount,
     const VkPipelineCache* pSrcCaches)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkMergePipelineCaches encode");
     mImpl->log("start vkMergePipelineCaches");
     auto stream = mImpl->stream();
@@ -4684,19 +4856,19 @@
     }
     countingStream->rewind();
     {
-        uint64_t cgen_var_334;
-        countingStream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_334, 1);
-        countingStream->write((uint64_t*)&cgen_var_334, 1 * 8);
-        uint64_t cgen_var_335;
-        countingStream->handleMapping()->mapHandles_VkPipelineCache_u64(&local_dstCache, &cgen_var_335, 1);
-        countingStream->write((uint64_t*)&cgen_var_335, 1 * 8);
+        uint64_t cgen_var_338;
+        countingStream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_338, 1);
+        countingStream->write((uint64_t*)&cgen_var_338, 1 * 8);
+        uint64_t cgen_var_339;
+        countingStream->handleMapping()->mapHandles_VkPipelineCache_u64(&local_dstCache, &cgen_var_339, 1);
+        countingStream->write((uint64_t*)&cgen_var_339, 1 * 8);
         countingStream->write((uint32_t*)&local_srcCacheCount, sizeof(uint32_t));
         if (((srcCacheCount)))
         {
-            uint64_t* cgen_var_336;
-            countingStream->alloc((void**)&cgen_var_336, ((srcCacheCount)) * 8);
-            countingStream->handleMapping()->mapHandles_VkPipelineCache_u64(local_pSrcCaches, cgen_var_336, ((srcCacheCount)));
-            countingStream->write((uint64_t*)cgen_var_336, ((srcCacheCount)) * 8);
+            uint64_t* cgen_var_340;
+            countingStream->alloc((void**)&cgen_var_340, ((srcCacheCount)) * 8);
+            countingStream->handleMapping()->mapHandles_VkPipelineCache_u64(local_pSrcCaches, cgen_var_340, ((srcCacheCount)));
+            countingStream->write((uint64_t*)cgen_var_340, ((srcCacheCount)) * 8);
         }
     }
     uint32_t packetSize_vkMergePipelineCaches = 4 + 4 + (uint32_t)countingStream->bytesWritten();
@@ -4704,19 +4876,19 @@
     uint32_t opcode_vkMergePipelineCaches = OP_vkMergePipelineCaches;
     stream->write(&opcode_vkMergePipelineCaches, sizeof(uint32_t));
     stream->write(&packetSize_vkMergePipelineCaches, sizeof(uint32_t));
-    uint64_t cgen_var_337;
-    stream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_337, 1);
-    stream->write((uint64_t*)&cgen_var_337, 1 * 8);
-    uint64_t cgen_var_338;
-    stream->handleMapping()->mapHandles_VkPipelineCache_u64(&local_dstCache, &cgen_var_338, 1);
-    stream->write((uint64_t*)&cgen_var_338, 1 * 8);
+    uint64_t cgen_var_341;
+    stream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_341, 1);
+    stream->write((uint64_t*)&cgen_var_341, 1 * 8);
+    uint64_t cgen_var_342;
+    stream->handleMapping()->mapHandles_VkPipelineCache_u64(&local_dstCache, &cgen_var_342, 1);
+    stream->write((uint64_t*)&cgen_var_342, 1 * 8);
     stream->write((uint32_t*)&local_srcCacheCount, sizeof(uint32_t));
     if (((srcCacheCount)))
     {
-        uint64_t* cgen_var_339;
-        stream->alloc((void**)&cgen_var_339, ((srcCacheCount)) * 8);
-        stream->handleMapping()->mapHandles_VkPipelineCache_u64(local_pSrcCaches, cgen_var_339, ((srcCacheCount)));
-        stream->write((uint64_t*)cgen_var_339, ((srcCacheCount)) * 8);
+        uint64_t* cgen_var_343;
+        stream->alloc((void**)&cgen_var_343, ((srcCacheCount)) * 8);
+        stream->handleMapping()->mapHandles_VkPipelineCache_u64(local_pSrcCaches, cgen_var_343, ((srcCacheCount)));
+        stream->write((uint64_t*)cgen_var_343, ((srcCacheCount)) * 8);
     }
     AEMU_SCOPED_TRACE("vkMergePipelineCaches readParams");
     AEMU_SCOPED_TRACE("vkMergePipelineCaches returnUnmarshal");
@@ -4737,6 +4909,7 @@
     const VkAllocationCallbacks* pAllocator,
     VkPipeline* pPipelines)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkCreateGraphicsPipelines encode");
     mImpl->log("start vkCreateGraphicsPipelines");
     auto stream = mImpl->stream();
@@ -4781,30 +4954,30 @@
     }
     countingStream->rewind();
     {
-        uint64_t cgen_var_340;
-        countingStream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_340, 1);
-        countingStream->write((uint64_t*)&cgen_var_340, 1 * 8);
-        uint64_t cgen_var_341;
-        countingStream->handleMapping()->mapHandles_VkPipelineCache_u64(&local_pipelineCache, &cgen_var_341, 1);
-        countingStream->write((uint64_t*)&cgen_var_341, 1 * 8);
+        uint64_t cgen_var_344;
+        countingStream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_344, 1);
+        countingStream->write((uint64_t*)&cgen_var_344, 1 * 8);
+        uint64_t cgen_var_345;
+        countingStream->handleMapping()->mapHandles_VkPipelineCache_u64(&local_pipelineCache, &cgen_var_345, 1);
+        countingStream->write((uint64_t*)&cgen_var_345, 1 * 8);
         countingStream->write((uint32_t*)&local_createInfoCount, sizeof(uint32_t));
         for (uint32_t i = 0; i < (uint32_t)((createInfoCount)); ++i)
         {
             marshal_VkGraphicsPipelineCreateInfo(countingStream, (VkGraphicsPipelineCreateInfo*)(local_pCreateInfos + i));
         }
         // WARNING PTR CHECK
-        uint64_t cgen_var_342 = (uint64_t)(uintptr_t)local_pAllocator;
-        countingStream->putBe64(cgen_var_342);
+        uint64_t cgen_var_346 = (uint64_t)(uintptr_t)local_pAllocator;
+        countingStream->putBe64(cgen_var_346);
         if (local_pAllocator)
         {
             marshal_VkAllocationCallbacks(countingStream, (VkAllocationCallbacks*)(local_pAllocator));
         }
         if (((createInfoCount)))
         {
-            uint64_t* cgen_var_343;
-            countingStream->alloc((void**)&cgen_var_343, ((createInfoCount)) * 8);
-            countingStream->handleMapping()->mapHandles_VkPipeline_u64(pPipelines, cgen_var_343, ((createInfoCount)));
-            countingStream->write((uint64_t*)cgen_var_343, ((createInfoCount)) * 8);
+            uint64_t* cgen_var_347;
+            countingStream->alloc((void**)&cgen_var_347, ((createInfoCount)) * 8);
+            countingStream->handleMapping()->mapHandles_VkPipeline_u64(pPipelines, cgen_var_347, ((createInfoCount)));
+            countingStream->write((uint64_t*)cgen_var_347, ((createInfoCount)) * 8);
         }
     }
     uint32_t packetSize_vkCreateGraphicsPipelines = 4 + 4 + (uint32_t)countingStream->bytesWritten();
@@ -4812,20 +4985,20 @@
     uint32_t opcode_vkCreateGraphicsPipelines = OP_vkCreateGraphicsPipelines;
     stream->write(&opcode_vkCreateGraphicsPipelines, sizeof(uint32_t));
     stream->write(&packetSize_vkCreateGraphicsPipelines, sizeof(uint32_t));
-    uint64_t cgen_var_344;
-    stream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_344, 1);
-    stream->write((uint64_t*)&cgen_var_344, 1 * 8);
-    uint64_t cgen_var_345;
-    stream->handleMapping()->mapHandles_VkPipelineCache_u64(&local_pipelineCache, &cgen_var_345, 1);
-    stream->write((uint64_t*)&cgen_var_345, 1 * 8);
+    uint64_t cgen_var_348;
+    stream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_348, 1);
+    stream->write((uint64_t*)&cgen_var_348, 1 * 8);
+    uint64_t cgen_var_349;
+    stream->handleMapping()->mapHandles_VkPipelineCache_u64(&local_pipelineCache, &cgen_var_349, 1);
+    stream->write((uint64_t*)&cgen_var_349, 1 * 8);
     stream->write((uint32_t*)&local_createInfoCount, sizeof(uint32_t));
     for (uint32_t i = 0; i < (uint32_t)((createInfoCount)); ++i)
     {
         marshal_VkGraphicsPipelineCreateInfo(stream, (VkGraphicsPipelineCreateInfo*)(local_pCreateInfos + i));
     }
     // WARNING PTR CHECK
-    uint64_t cgen_var_346 = (uint64_t)(uintptr_t)local_pAllocator;
-    stream->putBe64(cgen_var_346);
+    uint64_t cgen_var_350 = (uint64_t)(uintptr_t)local_pAllocator;
+    stream->putBe64(cgen_var_350);
     if (local_pAllocator)
     {
         marshal_VkAllocationCallbacks(stream, (VkAllocationCallbacks*)(local_pAllocator));
@@ -4833,20 +5006,20 @@
     stream->unsetHandleMapping() /* emit_marshal, is handle, possibly out */;
     if (((createInfoCount)))
     {
-        uint64_t* cgen_var_347;
-        stream->alloc((void**)&cgen_var_347, ((createInfoCount)) * 8);
-        stream->handleMapping()->mapHandles_VkPipeline_u64(pPipelines, cgen_var_347, ((createInfoCount)));
-        stream->write((uint64_t*)cgen_var_347, ((createInfoCount)) * 8);
+        uint64_t* cgen_var_351;
+        stream->alloc((void**)&cgen_var_351, ((createInfoCount)) * 8);
+        stream->handleMapping()->mapHandles_VkPipeline_u64(pPipelines, cgen_var_351, ((createInfoCount)));
+        stream->write((uint64_t*)cgen_var_351, ((createInfoCount)) * 8);
     }
     stream->setHandleMapping(resources->unwrapMapping());
     AEMU_SCOPED_TRACE("vkCreateGraphicsPipelines readParams");
     stream->setHandleMapping(resources->createMapping());
     if (((createInfoCount)))
     {
-        uint64_t* cgen_var_348;
-        stream->alloc((void**)&cgen_var_348, ((createInfoCount)) * 8);
-        stream->read((uint64_t*)cgen_var_348, ((createInfoCount)) * 8);
-        stream->handleMapping()->mapHandles_u64_VkPipeline(cgen_var_348, (VkPipeline*)pPipelines, ((createInfoCount)));
+        uint64_t* cgen_var_352;
+        stream->alloc((void**)&cgen_var_352, ((createInfoCount)) * 8);
+        stream->read((uint64_t*)cgen_var_352, ((createInfoCount)) * 8);
+        stream->handleMapping()->mapHandles_u64_VkPipeline(cgen_var_352, (VkPipeline*)pPipelines, ((createInfoCount)));
     }
     stream->unsetHandleMapping();
     AEMU_SCOPED_TRACE("vkCreateGraphicsPipelines returnUnmarshal");
@@ -4867,6 +5040,7 @@
     const VkAllocationCallbacks* pAllocator,
     VkPipeline* pPipelines)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkCreateComputePipelines encode");
     mImpl->log("start vkCreateComputePipelines");
     auto stream = mImpl->stream();
@@ -4911,30 +5085,30 @@
     }
     countingStream->rewind();
     {
-        uint64_t cgen_var_349;
-        countingStream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_349, 1);
-        countingStream->write((uint64_t*)&cgen_var_349, 1 * 8);
-        uint64_t cgen_var_350;
-        countingStream->handleMapping()->mapHandles_VkPipelineCache_u64(&local_pipelineCache, &cgen_var_350, 1);
-        countingStream->write((uint64_t*)&cgen_var_350, 1 * 8);
+        uint64_t cgen_var_353;
+        countingStream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_353, 1);
+        countingStream->write((uint64_t*)&cgen_var_353, 1 * 8);
+        uint64_t cgen_var_354;
+        countingStream->handleMapping()->mapHandles_VkPipelineCache_u64(&local_pipelineCache, &cgen_var_354, 1);
+        countingStream->write((uint64_t*)&cgen_var_354, 1 * 8);
         countingStream->write((uint32_t*)&local_createInfoCount, sizeof(uint32_t));
         for (uint32_t i = 0; i < (uint32_t)((createInfoCount)); ++i)
         {
             marshal_VkComputePipelineCreateInfo(countingStream, (VkComputePipelineCreateInfo*)(local_pCreateInfos + i));
         }
         // WARNING PTR CHECK
-        uint64_t cgen_var_351 = (uint64_t)(uintptr_t)local_pAllocator;
-        countingStream->putBe64(cgen_var_351);
+        uint64_t cgen_var_355 = (uint64_t)(uintptr_t)local_pAllocator;
+        countingStream->putBe64(cgen_var_355);
         if (local_pAllocator)
         {
             marshal_VkAllocationCallbacks(countingStream, (VkAllocationCallbacks*)(local_pAllocator));
         }
         if (((createInfoCount)))
         {
-            uint64_t* cgen_var_352;
-            countingStream->alloc((void**)&cgen_var_352, ((createInfoCount)) * 8);
-            countingStream->handleMapping()->mapHandles_VkPipeline_u64(pPipelines, cgen_var_352, ((createInfoCount)));
-            countingStream->write((uint64_t*)cgen_var_352, ((createInfoCount)) * 8);
+            uint64_t* cgen_var_356;
+            countingStream->alloc((void**)&cgen_var_356, ((createInfoCount)) * 8);
+            countingStream->handleMapping()->mapHandles_VkPipeline_u64(pPipelines, cgen_var_356, ((createInfoCount)));
+            countingStream->write((uint64_t*)cgen_var_356, ((createInfoCount)) * 8);
         }
     }
     uint32_t packetSize_vkCreateComputePipelines = 4 + 4 + (uint32_t)countingStream->bytesWritten();
@@ -4942,20 +5116,20 @@
     uint32_t opcode_vkCreateComputePipelines = OP_vkCreateComputePipelines;
     stream->write(&opcode_vkCreateComputePipelines, sizeof(uint32_t));
     stream->write(&packetSize_vkCreateComputePipelines, sizeof(uint32_t));
-    uint64_t cgen_var_353;
-    stream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_353, 1);
-    stream->write((uint64_t*)&cgen_var_353, 1 * 8);
-    uint64_t cgen_var_354;
-    stream->handleMapping()->mapHandles_VkPipelineCache_u64(&local_pipelineCache, &cgen_var_354, 1);
-    stream->write((uint64_t*)&cgen_var_354, 1 * 8);
+    uint64_t cgen_var_357;
+    stream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_357, 1);
+    stream->write((uint64_t*)&cgen_var_357, 1 * 8);
+    uint64_t cgen_var_358;
+    stream->handleMapping()->mapHandles_VkPipelineCache_u64(&local_pipelineCache, &cgen_var_358, 1);
+    stream->write((uint64_t*)&cgen_var_358, 1 * 8);
     stream->write((uint32_t*)&local_createInfoCount, sizeof(uint32_t));
     for (uint32_t i = 0; i < (uint32_t)((createInfoCount)); ++i)
     {
         marshal_VkComputePipelineCreateInfo(stream, (VkComputePipelineCreateInfo*)(local_pCreateInfos + i));
     }
     // WARNING PTR CHECK
-    uint64_t cgen_var_355 = (uint64_t)(uintptr_t)local_pAllocator;
-    stream->putBe64(cgen_var_355);
+    uint64_t cgen_var_359 = (uint64_t)(uintptr_t)local_pAllocator;
+    stream->putBe64(cgen_var_359);
     if (local_pAllocator)
     {
         marshal_VkAllocationCallbacks(stream, (VkAllocationCallbacks*)(local_pAllocator));
@@ -4963,20 +5137,20 @@
     stream->unsetHandleMapping() /* emit_marshal, is handle, possibly out */;
     if (((createInfoCount)))
     {
-        uint64_t* cgen_var_356;
-        stream->alloc((void**)&cgen_var_356, ((createInfoCount)) * 8);
-        stream->handleMapping()->mapHandles_VkPipeline_u64(pPipelines, cgen_var_356, ((createInfoCount)));
-        stream->write((uint64_t*)cgen_var_356, ((createInfoCount)) * 8);
+        uint64_t* cgen_var_360;
+        stream->alloc((void**)&cgen_var_360, ((createInfoCount)) * 8);
+        stream->handleMapping()->mapHandles_VkPipeline_u64(pPipelines, cgen_var_360, ((createInfoCount)));
+        stream->write((uint64_t*)cgen_var_360, ((createInfoCount)) * 8);
     }
     stream->setHandleMapping(resources->unwrapMapping());
     AEMU_SCOPED_TRACE("vkCreateComputePipelines readParams");
     stream->setHandleMapping(resources->createMapping());
     if (((createInfoCount)))
     {
-        uint64_t* cgen_var_357;
-        stream->alloc((void**)&cgen_var_357, ((createInfoCount)) * 8);
-        stream->read((uint64_t*)cgen_var_357, ((createInfoCount)) * 8);
-        stream->handleMapping()->mapHandles_u64_VkPipeline(cgen_var_357, (VkPipeline*)pPipelines, ((createInfoCount)));
+        uint64_t* cgen_var_361;
+        stream->alloc((void**)&cgen_var_361, ((createInfoCount)) * 8);
+        stream->read((uint64_t*)cgen_var_361, ((createInfoCount)) * 8);
+        stream->handleMapping()->mapHandles_u64_VkPipeline(cgen_var_361, (VkPipeline*)pPipelines, ((createInfoCount)));
     }
     stream->unsetHandleMapping();
     AEMU_SCOPED_TRACE("vkCreateComputePipelines returnUnmarshal");
@@ -4994,6 +5168,7 @@
     VkPipeline pipeline,
     const VkAllocationCallbacks* pAllocator)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkDestroyPipeline encode");
     mImpl->log("start vkDestroyPipeline");
     auto stream = mImpl->stream();
@@ -5019,15 +5194,15 @@
     }
     countingStream->rewind();
     {
-        uint64_t cgen_var_358;
-        countingStream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_358, 1);
-        countingStream->write((uint64_t*)&cgen_var_358, 1 * 8);
-        uint64_t cgen_var_359;
-        countingStream->handleMapping()->mapHandles_VkPipeline_u64(&local_pipeline, &cgen_var_359, 1);
-        countingStream->write((uint64_t*)&cgen_var_359, 1 * 8);
+        uint64_t cgen_var_362;
+        countingStream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_362, 1);
+        countingStream->write((uint64_t*)&cgen_var_362, 1 * 8);
+        uint64_t cgen_var_363;
+        countingStream->handleMapping()->mapHandles_VkPipeline_u64(&local_pipeline, &cgen_var_363, 1);
+        countingStream->write((uint64_t*)&cgen_var_363, 1 * 8);
         // WARNING PTR CHECK
-        uint64_t cgen_var_360 = (uint64_t)(uintptr_t)local_pAllocator;
-        countingStream->putBe64(cgen_var_360);
+        uint64_t cgen_var_364 = (uint64_t)(uintptr_t)local_pAllocator;
+        countingStream->putBe64(cgen_var_364);
         if (local_pAllocator)
         {
             marshal_VkAllocationCallbacks(countingStream, (VkAllocationCallbacks*)(local_pAllocator));
@@ -5038,15 +5213,15 @@
     uint32_t opcode_vkDestroyPipeline = OP_vkDestroyPipeline;
     stream->write(&opcode_vkDestroyPipeline, sizeof(uint32_t));
     stream->write(&packetSize_vkDestroyPipeline, sizeof(uint32_t));
-    uint64_t cgen_var_361;
-    stream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_361, 1);
-    stream->write((uint64_t*)&cgen_var_361, 1 * 8);
-    uint64_t cgen_var_362;
-    stream->handleMapping()->mapHandles_VkPipeline_u64(&local_pipeline, &cgen_var_362, 1);
-    stream->write((uint64_t*)&cgen_var_362, 1 * 8);
+    uint64_t cgen_var_365;
+    stream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_365, 1);
+    stream->write((uint64_t*)&cgen_var_365, 1 * 8);
+    uint64_t cgen_var_366;
+    stream->handleMapping()->mapHandles_VkPipeline_u64(&local_pipeline, &cgen_var_366, 1);
+    stream->write((uint64_t*)&cgen_var_366, 1 * 8);
     // WARNING PTR CHECK
-    uint64_t cgen_var_363 = (uint64_t)(uintptr_t)local_pAllocator;
-    stream->putBe64(cgen_var_363);
+    uint64_t cgen_var_367 = (uint64_t)(uintptr_t)local_pAllocator;
+    stream->putBe64(cgen_var_367);
     if (local_pAllocator)
     {
         marshal_VkAllocationCallbacks(stream, (VkAllocationCallbacks*)(local_pAllocator));
@@ -5063,6 +5238,7 @@
     const VkAllocationCallbacks* pAllocator,
     VkPipelineLayout* pPipelineLayout)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkCreatePipelineLayout encode");
     mImpl->log("start vkCreatePipelineLayout");
     auto stream = mImpl->stream();
@@ -5097,47 +5273,47 @@
     }
     countingStream->rewind();
     {
-        uint64_t cgen_var_364;
-        countingStream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_364, 1);
-        countingStream->write((uint64_t*)&cgen_var_364, 1 * 8);
+        uint64_t cgen_var_368;
+        countingStream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_368, 1);
+        countingStream->write((uint64_t*)&cgen_var_368, 1 * 8);
         marshal_VkPipelineLayoutCreateInfo(countingStream, (VkPipelineLayoutCreateInfo*)(local_pCreateInfo));
         // WARNING PTR CHECK
-        uint64_t cgen_var_365 = (uint64_t)(uintptr_t)local_pAllocator;
-        countingStream->putBe64(cgen_var_365);
+        uint64_t cgen_var_369 = (uint64_t)(uintptr_t)local_pAllocator;
+        countingStream->putBe64(cgen_var_369);
         if (local_pAllocator)
         {
             marshal_VkAllocationCallbacks(countingStream, (VkAllocationCallbacks*)(local_pAllocator));
         }
-        uint64_t cgen_var_366;
-        countingStream->handleMapping()->mapHandles_VkPipelineLayout_u64(pPipelineLayout, &cgen_var_366, 1);
-        countingStream->write((uint64_t*)&cgen_var_366, 8);
+        uint64_t cgen_var_370;
+        countingStream->handleMapping()->mapHandles_VkPipelineLayout_u64(pPipelineLayout, &cgen_var_370, 1);
+        countingStream->write((uint64_t*)&cgen_var_370, 8);
     }
     uint32_t packetSize_vkCreatePipelineLayout = 4 + 4 + (uint32_t)countingStream->bytesWritten();
     countingStream->rewind();
     uint32_t opcode_vkCreatePipelineLayout = OP_vkCreatePipelineLayout;
     stream->write(&opcode_vkCreatePipelineLayout, sizeof(uint32_t));
     stream->write(&packetSize_vkCreatePipelineLayout, sizeof(uint32_t));
-    uint64_t cgen_var_367;
-    stream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_367, 1);
-    stream->write((uint64_t*)&cgen_var_367, 1 * 8);
+    uint64_t cgen_var_371;
+    stream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_371, 1);
+    stream->write((uint64_t*)&cgen_var_371, 1 * 8);
     marshal_VkPipelineLayoutCreateInfo(stream, (VkPipelineLayoutCreateInfo*)(local_pCreateInfo));
     // WARNING PTR CHECK
-    uint64_t cgen_var_368 = (uint64_t)(uintptr_t)local_pAllocator;
-    stream->putBe64(cgen_var_368);
+    uint64_t cgen_var_372 = (uint64_t)(uintptr_t)local_pAllocator;
+    stream->putBe64(cgen_var_372);
     if (local_pAllocator)
     {
         marshal_VkAllocationCallbacks(stream, (VkAllocationCallbacks*)(local_pAllocator));
     }
     stream->unsetHandleMapping() /* emit_marshal, is handle, possibly out */;
-    uint64_t cgen_var_369;
-    stream->handleMapping()->mapHandles_VkPipelineLayout_u64(pPipelineLayout, &cgen_var_369, 1);
-    stream->write((uint64_t*)&cgen_var_369, 8);
+    uint64_t cgen_var_373;
+    stream->handleMapping()->mapHandles_VkPipelineLayout_u64(pPipelineLayout, &cgen_var_373, 1);
+    stream->write((uint64_t*)&cgen_var_373, 8);
     stream->setHandleMapping(resources->unwrapMapping());
     AEMU_SCOPED_TRACE("vkCreatePipelineLayout readParams");
     stream->setHandleMapping(resources->createMapping());
-    uint64_t cgen_var_370;
-    stream->read((uint64_t*)&cgen_var_370, 8);
-    stream->handleMapping()->mapHandles_u64_VkPipelineLayout(&cgen_var_370, (VkPipelineLayout*)pPipelineLayout, 1);
+    uint64_t cgen_var_374;
+    stream->read((uint64_t*)&cgen_var_374, 8);
+    stream->handleMapping()->mapHandles_u64_VkPipelineLayout(&cgen_var_374, (VkPipelineLayout*)pPipelineLayout, 1);
     stream->unsetHandleMapping();
     AEMU_SCOPED_TRACE("vkCreatePipelineLayout returnUnmarshal");
     VkResult vkCreatePipelineLayout_VkResult_return = (VkResult)0;
@@ -5154,6 +5330,7 @@
     VkPipelineLayout pipelineLayout,
     const VkAllocationCallbacks* pAllocator)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkDestroyPipelineLayout encode");
     mImpl->log("start vkDestroyPipelineLayout");
     auto stream = mImpl->stream();
@@ -5179,15 +5356,15 @@
     }
     countingStream->rewind();
     {
-        uint64_t cgen_var_371;
-        countingStream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_371, 1);
-        countingStream->write((uint64_t*)&cgen_var_371, 1 * 8);
-        uint64_t cgen_var_372;
-        countingStream->handleMapping()->mapHandles_VkPipelineLayout_u64(&local_pipelineLayout, &cgen_var_372, 1);
-        countingStream->write((uint64_t*)&cgen_var_372, 1 * 8);
+        uint64_t cgen_var_375;
+        countingStream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_375, 1);
+        countingStream->write((uint64_t*)&cgen_var_375, 1 * 8);
+        uint64_t cgen_var_376;
+        countingStream->handleMapping()->mapHandles_VkPipelineLayout_u64(&local_pipelineLayout, &cgen_var_376, 1);
+        countingStream->write((uint64_t*)&cgen_var_376, 1 * 8);
         // WARNING PTR CHECK
-        uint64_t cgen_var_373 = (uint64_t)(uintptr_t)local_pAllocator;
-        countingStream->putBe64(cgen_var_373);
+        uint64_t cgen_var_377 = (uint64_t)(uintptr_t)local_pAllocator;
+        countingStream->putBe64(cgen_var_377);
         if (local_pAllocator)
         {
             marshal_VkAllocationCallbacks(countingStream, (VkAllocationCallbacks*)(local_pAllocator));
@@ -5198,15 +5375,15 @@
     uint32_t opcode_vkDestroyPipelineLayout = OP_vkDestroyPipelineLayout;
     stream->write(&opcode_vkDestroyPipelineLayout, sizeof(uint32_t));
     stream->write(&packetSize_vkDestroyPipelineLayout, sizeof(uint32_t));
-    uint64_t cgen_var_374;
-    stream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_374, 1);
-    stream->write((uint64_t*)&cgen_var_374, 1 * 8);
-    uint64_t cgen_var_375;
-    stream->handleMapping()->mapHandles_VkPipelineLayout_u64(&local_pipelineLayout, &cgen_var_375, 1);
-    stream->write((uint64_t*)&cgen_var_375, 1 * 8);
+    uint64_t cgen_var_378;
+    stream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_378, 1);
+    stream->write((uint64_t*)&cgen_var_378, 1 * 8);
+    uint64_t cgen_var_379;
+    stream->handleMapping()->mapHandles_VkPipelineLayout_u64(&local_pipelineLayout, &cgen_var_379, 1);
+    stream->write((uint64_t*)&cgen_var_379, 1 * 8);
     // WARNING PTR CHECK
-    uint64_t cgen_var_376 = (uint64_t)(uintptr_t)local_pAllocator;
-    stream->putBe64(cgen_var_376);
+    uint64_t cgen_var_380 = (uint64_t)(uintptr_t)local_pAllocator;
+    stream->putBe64(cgen_var_380);
     if (local_pAllocator)
     {
         marshal_VkAllocationCallbacks(stream, (VkAllocationCallbacks*)(local_pAllocator));
@@ -5223,6 +5400,7 @@
     const VkAllocationCallbacks* pAllocator,
     VkSampler* pSampler)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkCreateSampler encode");
     mImpl->log("start vkCreateSampler");
     auto stream = mImpl->stream();
@@ -5257,47 +5435,47 @@
     }
     countingStream->rewind();
     {
-        uint64_t cgen_var_377;
-        countingStream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_377, 1);
-        countingStream->write((uint64_t*)&cgen_var_377, 1 * 8);
+        uint64_t cgen_var_381;
+        countingStream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_381, 1);
+        countingStream->write((uint64_t*)&cgen_var_381, 1 * 8);
         marshal_VkSamplerCreateInfo(countingStream, (VkSamplerCreateInfo*)(local_pCreateInfo));
         // WARNING PTR CHECK
-        uint64_t cgen_var_378 = (uint64_t)(uintptr_t)local_pAllocator;
-        countingStream->putBe64(cgen_var_378);
+        uint64_t cgen_var_382 = (uint64_t)(uintptr_t)local_pAllocator;
+        countingStream->putBe64(cgen_var_382);
         if (local_pAllocator)
         {
             marshal_VkAllocationCallbacks(countingStream, (VkAllocationCallbacks*)(local_pAllocator));
         }
-        uint64_t cgen_var_379;
-        countingStream->handleMapping()->mapHandles_VkSampler_u64(pSampler, &cgen_var_379, 1);
-        countingStream->write((uint64_t*)&cgen_var_379, 8);
+        uint64_t cgen_var_383;
+        countingStream->handleMapping()->mapHandles_VkSampler_u64(pSampler, &cgen_var_383, 1);
+        countingStream->write((uint64_t*)&cgen_var_383, 8);
     }
     uint32_t packetSize_vkCreateSampler = 4 + 4 + (uint32_t)countingStream->bytesWritten();
     countingStream->rewind();
     uint32_t opcode_vkCreateSampler = OP_vkCreateSampler;
     stream->write(&opcode_vkCreateSampler, sizeof(uint32_t));
     stream->write(&packetSize_vkCreateSampler, sizeof(uint32_t));
-    uint64_t cgen_var_380;
-    stream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_380, 1);
-    stream->write((uint64_t*)&cgen_var_380, 1 * 8);
+    uint64_t cgen_var_384;
+    stream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_384, 1);
+    stream->write((uint64_t*)&cgen_var_384, 1 * 8);
     marshal_VkSamplerCreateInfo(stream, (VkSamplerCreateInfo*)(local_pCreateInfo));
     // WARNING PTR CHECK
-    uint64_t cgen_var_381 = (uint64_t)(uintptr_t)local_pAllocator;
-    stream->putBe64(cgen_var_381);
+    uint64_t cgen_var_385 = (uint64_t)(uintptr_t)local_pAllocator;
+    stream->putBe64(cgen_var_385);
     if (local_pAllocator)
     {
         marshal_VkAllocationCallbacks(stream, (VkAllocationCallbacks*)(local_pAllocator));
     }
     stream->unsetHandleMapping() /* emit_marshal, is handle, possibly out */;
-    uint64_t cgen_var_382;
-    stream->handleMapping()->mapHandles_VkSampler_u64(pSampler, &cgen_var_382, 1);
-    stream->write((uint64_t*)&cgen_var_382, 8);
+    uint64_t cgen_var_386;
+    stream->handleMapping()->mapHandles_VkSampler_u64(pSampler, &cgen_var_386, 1);
+    stream->write((uint64_t*)&cgen_var_386, 8);
     stream->setHandleMapping(resources->unwrapMapping());
     AEMU_SCOPED_TRACE("vkCreateSampler readParams");
     stream->setHandleMapping(resources->createMapping());
-    uint64_t cgen_var_383;
-    stream->read((uint64_t*)&cgen_var_383, 8);
-    stream->handleMapping()->mapHandles_u64_VkSampler(&cgen_var_383, (VkSampler*)pSampler, 1);
+    uint64_t cgen_var_387;
+    stream->read((uint64_t*)&cgen_var_387, 8);
+    stream->handleMapping()->mapHandles_u64_VkSampler(&cgen_var_387, (VkSampler*)pSampler, 1);
     stream->unsetHandleMapping();
     AEMU_SCOPED_TRACE("vkCreateSampler returnUnmarshal");
     VkResult vkCreateSampler_VkResult_return = (VkResult)0;
@@ -5314,6 +5492,7 @@
     VkSampler sampler,
     const VkAllocationCallbacks* pAllocator)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkDestroySampler encode");
     mImpl->log("start vkDestroySampler");
     auto stream = mImpl->stream();
@@ -5339,15 +5518,15 @@
     }
     countingStream->rewind();
     {
-        uint64_t cgen_var_384;
-        countingStream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_384, 1);
-        countingStream->write((uint64_t*)&cgen_var_384, 1 * 8);
-        uint64_t cgen_var_385;
-        countingStream->handleMapping()->mapHandles_VkSampler_u64(&local_sampler, &cgen_var_385, 1);
-        countingStream->write((uint64_t*)&cgen_var_385, 1 * 8);
+        uint64_t cgen_var_388;
+        countingStream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_388, 1);
+        countingStream->write((uint64_t*)&cgen_var_388, 1 * 8);
+        uint64_t cgen_var_389;
+        countingStream->handleMapping()->mapHandles_VkSampler_u64(&local_sampler, &cgen_var_389, 1);
+        countingStream->write((uint64_t*)&cgen_var_389, 1 * 8);
         // WARNING PTR CHECK
-        uint64_t cgen_var_386 = (uint64_t)(uintptr_t)local_pAllocator;
-        countingStream->putBe64(cgen_var_386);
+        uint64_t cgen_var_390 = (uint64_t)(uintptr_t)local_pAllocator;
+        countingStream->putBe64(cgen_var_390);
         if (local_pAllocator)
         {
             marshal_VkAllocationCallbacks(countingStream, (VkAllocationCallbacks*)(local_pAllocator));
@@ -5358,15 +5537,15 @@
     uint32_t opcode_vkDestroySampler = OP_vkDestroySampler;
     stream->write(&opcode_vkDestroySampler, sizeof(uint32_t));
     stream->write(&packetSize_vkDestroySampler, sizeof(uint32_t));
-    uint64_t cgen_var_387;
-    stream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_387, 1);
-    stream->write((uint64_t*)&cgen_var_387, 1 * 8);
-    uint64_t cgen_var_388;
-    stream->handleMapping()->mapHandles_VkSampler_u64(&local_sampler, &cgen_var_388, 1);
-    stream->write((uint64_t*)&cgen_var_388, 1 * 8);
+    uint64_t cgen_var_391;
+    stream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_391, 1);
+    stream->write((uint64_t*)&cgen_var_391, 1 * 8);
+    uint64_t cgen_var_392;
+    stream->handleMapping()->mapHandles_VkSampler_u64(&local_sampler, &cgen_var_392, 1);
+    stream->write((uint64_t*)&cgen_var_392, 1 * 8);
     // WARNING PTR CHECK
-    uint64_t cgen_var_389 = (uint64_t)(uintptr_t)local_pAllocator;
-    stream->putBe64(cgen_var_389);
+    uint64_t cgen_var_393 = (uint64_t)(uintptr_t)local_pAllocator;
+    stream->putBe64(cgen_var_393);
     if (local_pAllocator)
     {
         marshal_VkAllocationCallbacks(stream, (VkAllocationCallbacks*)(local_pAllocator));
@@ -5383,6 +5562,7 @@
     const VkAllocationCallbacks* pAllocator,
     VkDescriptorSetLayout* pSetLayout)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkCreateDescriptorSetLayout encode");
     mImpl->log("start vkCreateDescriptorSetLayout");
     auto stream = mImpl->stream();
@@ -5417,47 +5597,47 @@
     }
     countingStream->rewind();
     {
-        uint64_t cgen_var_390;
-        countingStream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_390, 1);
-        countingStream->write((uint64_t*)&cgen_var_390, 1 * 8);
+        uint64_t cgen_var_394;
+        countingStream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_394, 1);
+        countingStream->write((uint64_t*)&cgen_var_394, 1 * 8);
         marshal_VkDescriptorSetLayoutCreateInfo(countingStream, (VkDescriptorSetLayoutCreateInfo*)(local_pCreateInfo));
         // WARNING PTR CHECK
-        uint64_t cgen_var_391 = (uint64_t)(uintptr_t)local_pAllocator;
-        countingStream->putBe64(cgen_var_391);
+        uint64_t cgen_var_395 = (uint64_t)(uintptr_t)local_pAllocator;
+        countingStream->putBe64(cgen_var_395);
         if (local_pAllocator)
         {
             marshal_VkAllocationCallbacks(countingStream, (VkAllocationCallbacks*)(local_pAllocator));
         }
-        uint64_t cgen_var_392;
-        countingStream->handleMapping()->mapHandles_VkDescriptorSetLayout_u64(pSetLayout, &cgen_var_392, 1);
-        countingStream->write((uint64_t*)&cgen_var_392, 8);
+        uint64_t cgen_var_396;
+        countingStream->handleMapping()->mapHandles_VkDescriptorSetLayout_u64(pSetLayout, &cgen_var_396, 1);
+        countingStream->write((uint64_t*)&cgen_var_396, 8);
     }
     uint32_t packetSize_vkCreateDescriptorSetLayout = 4 + 4 + (uint32_t)countingStream->bytesWritten();
     countingStream->rewind();
     uint32_t opcode_vkCreateDescriptorSetLayout = OP_vkCreateDescriptorSetLayout;
     stream->write(&opcode_vkCreateDescriptorSetLayout, sizeof(uint32_t));
     stream->write(&packetSize_vkCreateDescriptorSetLayout, sizeof(uint32_t));
-    uint64_t cgen_var_393;
-    stream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_393, 1);
-    stream->write((uint64_t*)&cgen_var_393, 1 * 8);
+    uint64_t cgen_var_397;
+    stream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_397, 1);
+    stream->write((uint64_t*)&cgen_var_397, 1 * 8);
     marshal_VkDescriptorSetLayoutCreateInfo(stream, (VkDescriptorSetLayoutCreateInfo*)(local_pCreateInfo));
     // WARNING PTR CHECK
-    uint64_t cgen_var_394 = (uint64_t)(uintptr_t)local_pAllocator;
-    stream->putBe64(cgen_var_394);
+    uint64_t cgen_var_398 = (uint64_t)(uintptr_t)local_pAllocator;
+    stream->putBe64(cgen_var_398);
     if (local_pAllocator)
     {
         marshal_VkAllocationCallbacks(stream, (VkAllocationCallbacks*)(local_pAllocator));
     }
     stream->unsetHandleMapping() /* emit_marshal, is handle, possibly out */;
-    uint64_t cgen_var_395;
-    stream->handleMapping()->mapHandles_VkDescriptorSetLayout_u64(pSetLayout, &cgen_var_395, 1);
-    stream->write((uint64_t*)&cgen_var_395, 8);
+    uint64_t cgen_var_399;
+    stream->handleMapping()->mapHandles_VkDescriptorSetLayout_u64(pSetLayout, &cgen_var_399, 1);
+    stream->write((uint64_t*)&cgen_var_399, 8);
     stream->setHandleMapping(resources->unwrapMapping());
     AEMU_SCOPED_TRACE("vkCreateDescriptorSetLayout readParams");
     stream->setHandleMapping(resources->createMapping());
-    uint64_t cgen_var_396;
-    stream->read((uint64_t*)&cgen_var_396, 8);
-    stream->handleMapping()->mapHandles_u64_VkDescriptorSetLayout(&cgen_var_396, (VkDescriptorSetLayout*)pSetLayout, 1);
+    uint64_t cgen_var_400;
+    stream->read((uint64_t*)&cgen_var_400, 8);
+    stream->handleMapping()->mapHandles_u64_VkDescriptorSetLayout(&cgen_var_400, (VkDescriptorSetLayout*)pSetLayout, 1);
     stream->unsetHandleMapping();
     AEMU_SCOPED_TRACE("vkCreateDescriptorSetLayout returnUnmarshal");
     VkResult vkCreateDescriptorSetLayout_VkResult_return = (VkResult)0;
@@ -5474,6 +5654,7 @@
     VkDescriptorSetLayout descriptorSetLayout,
     const VkAllocationCallbacks* pAllocator)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkDestroyDescriptorSetLayout encode");
     mImpl->log("start vkDestroyDescriptorSetLayout");
     auto stream = mImpl->stream();
@@ -5499,15 +5680,15 @@
     }
     countingStream->rewind();
     {
-        uint64_t cgen_var_397;
-        countingStream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_397, 1);
-        countingStream->write((uint64_t*)&cgen_var_397, 1 * 8);
-        uint64_t cgen_var_398;
-        countingStream->handleMapping()->mapHandles_VkDescriptorSetLayout_u64(&local_descriptorSetLayout, &cgen_var_398, 1);
-        countingStream->write((uint64_t*)&cgen_var_398, 1 * 8);
+        uint64_t cgen_var_401;
+        countingStream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_401, 1);
+        countingStream->write((uint64_t*)&cgen_var_401, 1 * 8);
+        uint64_t cgen_var_402;
+        countingStream->handleMapping()->mapHandles_VkDescriptorSetLayout_u64(&local_descriptorSetLayout, &cgen_var_402, 1);
+        countingStream->write((uint64_t*)&cgen_var_402, 1 * 8);
         // WARNING PTR CHECK
-        uint64_t cgen_var_399 = (uint64_t)(uintptr_t)local_pAllocator;
-        countingStream->putBe64(cgen_var_399);
+        uint64_t cgen_var_403 = (uint64_t)(uintptr_t)local_pAllocator;
+        countingStream->putBe64(cgen_var_403);
         if (local_pAllocator)
         {
             marshal_VkAllocationCallbacks(countingStream, (VkAllocationCallbacks*)(local_pAllocator));
@@ -5518,15 +5699,15 @@
     uint32_t opcode_vkDestroyDescriptorSetLayout = OP_vkDestroyDescriptorSetLayout;
     stream->write(&opcode_vkDestroyDescriptorSetLayout, sizeof(uint32_t));
     stream->write(&packetSize_vkDestroyDescriptorSetLayout, sizeof(uint32_t));
-    uint64_t cgen_var_400;
-    stream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_400, 1);
-    stream->write((uint64_t*)&cgen_var_400, 1 * 8);
-    uint64_t cgen_var_401;
-    stream->handleMapping()->mapHandles_VkDescriptorSetLayout_u64(&local_descriptorSetLayout, &cgen_var_401, 1);
-    stream->write((uint64_t*)&cgen_var_401, 1 * 8);
+    uint64_t cgen_var_404;
+    stream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_404, 1);
+    stream->write((uint64_t*)&cgen_var_404, 1 * 8);
+    uint64_t cgen_var_405;
+    stream->handleMapping()->mapHandles_VkDescriptorSetLayout_u64(&local_descriptorSetLayout, &cgen_var_405, 1);
+    stream->write((uint64_t*)&cgen_var_405, 1 * 8);
     // WARNING PTR CHECK
-    uint64_t cgen_var_402 = (uint64_t)(uintptr_t)local_pAllocator;
-    stream->putBe64(cgen_var_402);
+    uint64_t cgen_var_406 = (uint64_t)(uintptr_t)local_pAllocator;
+    stream->putBe64(cgen_var_406);
     if (local_pAllocator)
     {
         marshal_VkAllocationCallbacks(stream, (VkAllocationCallbacks*)(local_pAllocator));
@@ -5543,6 +5724,7 @@
     const VkAllocationCallbacks* pAllocator,
     VkDescriptorPool* pDescriptorPool)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkCreateDescriptorPool encode");
     mImpl->log("start vkCreateDescriptorPool");
     auto stream = mImpl->stream();
@@ -5577,47 +5759,47 @@
     }
     countingStream->rewind();
     {
-        uint64_t cgen_var_403;
-        countingStream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_403, 1);
-        countingStream->write((uint64_t*)&cgen_var_403, 1 * 8);
+        uint64_t cgen_var_407;
+        countingStream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_407, 1);
+        countingStream->write((uint64_t*)&cgen_var_407, 1 * 8);
         marshal_VkDescriptorPoolCreateInfo(countingStream, (VkDescriptorPoolCreateInfo*)(local_pCreateInfo));
         // WARNING PTR CHECK
-        uint64_t cgen_var_404 = (uint64_t)(uintptr_t)local_pAllocator;
-        countingStream->putBe64(cgen_var_404);
+        uint64_t cgen_var_408 = (uint64_t)(uintptr_t)local_pAllocator;
+        countingStream->putBe64(cgen_var_408);
         if (local_pAllocator)
         {
             marshal_VkAllocationCallbacks(countingStream, (VkAllocationCallbacks*)(local_pAllocator));
         }
-        uint64_t cgen_var_405;
-        countingStream->handleMapping()->mapHandles_VkDescriptorPool_u64(pDescriptorPool, &cgen_var_405, 1);
-        countingStream->write((uint64_t*)&cgen_var_405, 8);
+        uint64_t cgen_var_409;
+        countingStream->handleMapping()->mapHandles_VkDescriptorPool_u64(pDescriptorPool, &cgen_var_409, 1);
+        countingStream->write((uint64_t*)&cgen_var_409, 8);
     }
     uint32_t packetSize_vkCreateDescriptorPool = 4 + 4 + (uint32_t)countingStream->bytesWritten();
     countingStream->rewind();
     uint32_t opcode_vkCreateDescriptorPool = OP_vkCreateDescriptorPool;
     stream->write(&opcode_vkCreateDescriptorPool, sizeof(uint32_t));
     stream->write(&packetSize_vkCreateDescriptorPool, sizeof(uint32_t));
-    uint64_t cgen_var_406;
-    stream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_406, 1);
-    stream->write((uint64_t*)&cgen_var_406, 1 * 8);
+    uint64_t cgen_var_410;
+    stream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_410, 1);
+    stream->write((uint64_t*)&cgen_var_410, 1 * 8);
     marshal_VkDescriptorPoolCreateInfo(stream, (VkDescriptorPoolCreateInfo*)(local_pCreateInfo));
     // WARNING PTR CHECK
-    uint64_t cgen_var_407 = (uint64_t)(uintptr_t)local_pAllocator;
-    stream->putBe64(cgen_var_407);
+    uint64_t cgen_var_411 = (uint64_t)(uintptr_t)local_pAllocator;
+    stream->putBe64(cgen_var_411);
     if (local_pAllocator)
     {
         marshal_VkAllocationCallbacks(stream, (VkAllocationCallbacks*)(local_pAllocator));
     }
     stream->unsetHandleMapping() /* emit_marshal, is handle, possibly out */;
-    uint64_t cgen_var_408;
-    stream->handleMapping()->mapHandles_VkDescriptorPool_u64(pDescriptorPool, &cgen_var_408, 1);
-    stream->write((uint64_t*)&cgen_var_408, 8);
+    uint64_t cgen_var_412;
+    stream->handleMapping()->mapHandles_VkDescriptorPool_u64(pDescriptorPool, &cgen_var_412, 1);
+    stream->write((uint64_t*)&cgen_var_412, 8);
     stream->setHandleMapping(resources->unwrapMapping());
     AEMU_SCOPED_TRACE("vkCreateDescriptorPool readParams");
     stream->setHandleMapping(resources->createMapping());
-    uint64_t cgen_var_409;
-    stream->read((uint64_t*)&cgen_var_409, 8);
-    stream->handleMapping()->mapHandles_u64_VkDescriptorPool(&cgen_var_409, (VkDescriptorPool*)pDescriptorPool, 1);
+    uint64_t cgen_var_413;
+    stream->read((uint64_t*)&cgen_var_413, 8);
+    stream->handleMapping()->mapHandles_u64_VkDescriptorPool(&cgen_var_413, (VkDescriptorPool*)pDescriptorPool, 1);
     stream->unsetHandleMapping();
     AEMU_SCOPED_TRACE("vkCreateDescriptorPool returnUnmarshal");
     VkResult vkCreateDescriptorPool_VkResult_return = (VkResult)0;
@@ -5634,6 +5816,7 @@
     VkDescriptorPool descriptorPool,
     const VkAllocationCallbacks* pAllocator)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkDestroyDescriptorPool encode");
     mImpl->log("start vkDestroyDescriptorPool");
     auto stream = mImpl->stream();
@@ -5659,15 +5842,15 @@
     }
     countingStream->rewind();
     {
-        uint64_t cgen_var_410;
-        countingStream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_410, 1);
-        countingStream->write((uint64_t*)&cgen_var_410, 1 * 8);
-        uint64_t cgen_var_411;
-        countingStream->handleMapping()->mapHandles_VkDescriptorPool_u64(&local_descriptorPool, &cgen_var_411, 1);
-        countingStream->write((uint64_t*)&cgen_var_411, 1 * 8);
+        uint64_t cgen_var_414;
+        countingStream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_414, 1);
+        countingStream->write((uint64_t*)&cgen_var_414, 1 * 8);
+        uint64_t cgen_var_415;
+        countingStream->handleMapping()->mapHandles_VkDescriptorPool_u64(&local_descriptorPool, &cgen_var_415, 1);
+        countingStream->write((uint64_t*)&cgen_var_415, 1 * 8);
         // WARNING PTR CHECK
-        uint64_t cgen_var_412 = (uint64_t)(uintptr_t)local_pAllocator;
-        countingStream->putBe64(cgen_var_412);
+        uint64_t cgen_var_416 = (uint64_t)(uintptr_t)local_pAllocator;
+        countingStream->putBe64(cgen_var_416);
         if (local_pAllocator)
         {
             marshal_VkAllocationCallbacks(countingStream, (VkAllocationCallbacks*)(local_pAllocator));
@@ -5678,15 +5861,15 @@
     uint32_t opcode_vkDestroyDescriptorPool = OP_vkDestroyDescriptorPool;
     stream->write(&opcode_vkDestroyDescriptorPool, sizeof(uint32_t));
     stream->write(&packetSize_vkDestroyDescriptorPool, sizeof(uint32_t));
-    uint64_t cgen_var_413;
-    stream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_413, 1);
-    stream->write((uint64_t*)&cgen_var_413, 1 * 8);
-    uint64_t cgen_var_414;
-    stream->handleMapping()->mapHandles_VkDescriptorPool_u64(&local_descriptorPool, &cgen_var_414, 1);
-    stream->write((uint64_t*)&cgen_var_414, 1 * 8);
+    uint64_t cgen_var_417;
+    stream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_417, 1);
+    stream->write((uint64_t*)&cgen_var_417, 1 * 8);
+    uint64_t cgen_var_418;
+    stream->handleMapping()->mapHandles_VkDescriptorPool_u64(&local_descriptorPool, &cgen_var_418, 1);
+    stream->write((uint64_t*)&cgen_var_418, 1 * 8);
     // WARNING PTR CHECK
-    uint64_t cgen_var_415 = (uint64_t)(uintptr_t)local_pAllocator;
-    stream->putBe64(cgen_var_415);
+    uint64_t cgen_var_419 = (uint64_t)(uintptr_t)local_pAllocator;
+    stream->putBe64(cgen_var_419);
     if (local_pAllocator)
     {
         marshal_VkAllocationCallbacks(stream, (VkAllocationCallbacks*)(local_pAllocator));
@@ -5702,6 +5885,7 @@
     VkDescriptorPool descriptorPool,
     VkDescriptorPoolResetFlags flags)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkResetDescriptorPool encode");
     mImpl->log("start vkResetDescriptorPool");
     auto stream = mImpl->stream();
@@ -5717,12 +5901,12 @@
     local_flags = flags;
     countingStream->rewind();
     {
-        uint64_t cgen_var_416;
-        countingStream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_416, 1);
-        countingStream->write((uint64_t*)&cgen_var_416, 1 * 8);
-        uint64_t cgen_var_417;
-        countingStream->handleMapping()->mapHandles_VkDescriptorPool_u64(&local_descriptorPool, &cgen_var_417, 1);
-        countingStream->write((uint64_t*)&cgen_var_417, 1 * 8);
+        uint64_t cgen_var_420;
+        countingStream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_420, 1);
+        countingStream->write((uint64_t*)&cgen_var_420, 1 * 8);
+        uint64_t cgen_var_421;
+        countingStream->handleMapping()->mapHandles_VkDescriptorPool_u64(&local_descriptorPool, &cgen_var_421, 1);
+        countingStream->write((uint64_t*)&cgen_var_421, 1 * 8);
         countingStream->write((VkDescriptorPoolResetFlags*)&local_flags, sizeof(VkDescriptorPoolResetFlags));
     }
     uint32_t packetSize_vkResetDescriptorPool = 4 + 4 + (uint32_t)countingStream->bytesWritten();
@@ -5730,12 +5914,12 @@
     uint32_t opcode_vkResetDescriptorPool = OP_vkResetDescriptorPool;
     stream->write(&opcode_vkResetDescriptorPool, sizeof(uint32_t));
     stream->write(&packetSize_vkResetDescriptorPool, sizeof(uint32_t));
-    uint64_t cgen_var_418;
-    stream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_418, 1);
-    stream->write((uint64_t*)&cgen_var_418, 1 * 8);
-    uint64_t cgen_var_419;
-    stream->handleMapping()->mapHandles_VkDescriptorPool_u64(&local_descriptorPool, &cgen_var_419, 1);
-    stream->write((uint64_t*)&cgen_var_419, 1 * 8);
+    uint64_t cgen_var_422;
+    stream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_422, 1);
+    stream->write((uint64_t*)&cgen_var_422, 1 * 8);
+    uint64_t cgen_var_423;
+    stream->handleMapping()->mapHandles_VkDescriptorPool_u64(&local_descriptorPool, &cgen_var_423, 1);
+    stream->write((uint64_t*)&cgen_var_423, 1 * 8);
     stream->write((VkDescriptorPoolResetFlags*)&local_flags, sizeof(VkDescriptorPoolResetFlags));
     AEMU_SCOPED_TRACE("vkResetDescriptorPool readParams");
     AEMU_SCOPED_TRACE("vkResetDescriptorPool returnUnmarshal");
@@ -5753,6 +5937,7 @@
     const VkDescriptorSetAllocateInfo* pAllocateInfo,
     VkDescriptorSet* pDescriptorSets)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkAllocateDescriptorSets encode");
     mImpl->log("start vkAllocateDescriptorSets");
     auto stream = mImpl->stream();
@@ -5775,16 +5960,16 @@
     }
     countingStream->rewind();
     {
-        uint64_t cgen_var_420;
-        countingStream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_420, 1);
-        countingStream->write((uint64_t*)&cgen_var_420, 1 * 8);
+        uint64_t cgen_var_424;
+        countingStream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_424, 1);
+        countingStream->write((uint64_t*)&cgen_var_424, 1 * 8);
         marshal_VkDescriptorSetAllocateInfo(countingStream, (VkDescriptorSetAllocateInfo*)(local_pAllocateInfo));
         if (pAllocateInfo->descriptorSetCount)
         {
-            uint64_t* cgen_var_421;
-            countingStream->alloc((void**)&cgen_var_421, pAllocateInfo->descriptorSetCount * 8);
-            countingStream->handleMapping()->mapHandles_VkDescriptorSet_u64(pDescriptorSets, cgen_var_421, pAllocateInfo->descriptorSetCount);
-            countingStream->write((uint64_t*)cgen_var_421, pAllocateInfo->descriptorSetCount * 8);
+            uint64_t* cgen_var_425;
+            countingStream->alloc((void**)&cgen_var_425, pAllocateInfo->descriptorSetCount * 8);
+            countingStream->handleMapping()->mapHandles_VkDescriptorSet_u64(pDescriptorSets, cgen_var_425, pAllocateInfo->descriptorSetCount);
+            countingStream->write((uint64_t*)cgen_var_425, pAllocateInfo->descriptorSetCount * 8);
         }
     }
     uint32_t packetSize_vkAllocateDescriptorSets = 4 + 4 + (uint32_t)countingStream->bytesWritten();
@@ -5792,27 +5977,27 @@
     uint32_t opcode_vkAllocateDescriptorSets = OP_vkAllocateDescriptorSets;
     stream->write(&opcode_vkAllocateDescriptorSets, sizeof(uint32_t));
     stream->write(&packetSize_vkAllocateDescriptorSets, sizeof(uint32_t));
-    uint64_t cgen_var_422;
-    stream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_422, 1);
-    stream->write((uint64_t*)&cgen_var_422, 1 * 8);
+    uint64_t cgen_var_426;
+    stream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_426, 1);
+    stream->write((uint64_t*)&cgen_var_426, 1 * 8);
     marshal_VkDescriptorSetAllocateInfo(stream, (VkDescriptorSetAllocateInfo*)(local_pAllocateInfo));
     stream->unsetHandleMapping() /* emit_marshal, is handle, possibly out */;
     if (pAllocateInfo->descriptorSetCount)
     {
-        uint64_t* cgen_var_423;
-        stream->alloc((void**)&cgen_var_423, pAllocateInfo->descriptorSetCount * 8);
-        stream->handleMapping()->mapHandles_VkDescriptorSet_u64(pDescriptorSets, cgen_var_423, pAllocateInfo->descriptorSetCount);
-        stream->write((uint64_t*)cgen_var_423, pAllocateInfo->descriptorSetCount * 8);
+        uint64_t* cgen_var_427;
+        stream->alloc((void**)&cgen_var_427, pAllocateInfo->descriptorSetCount * 8);
+        stream->handleMapping()->mapHandles_VkDescriptorSet_u64(pDescriptorSets, cgen_var_427, pAllocateInfo->descriptorSetCount);
+        stream->write((uint64_t*)cgen_var_427, pAllocateInfo->descriptorSetCount * 8);
     }
     stream->setHandleMapping(resources->unwrapMapping());
     AEMU_SCOPED_TRACE("vkAllocateDescriptorSets readParams");
     stream->setHandleMapping(resources->createMapping());
     if (pAllocateInfo->descriptorSetCount)
     {
-        uint64_t* cgen_var_424;
-        stream->alloc((void**)&cgen_var_424, pAllocateInfo->descriptorSetCount * 8);
-        stream->read((uint64_t*)cgen_var_424, pAllocateInfo->descriptorSetCount * 8);
-        stream->handleMapping()->mapHandles_u64_VkDescriptorSet(cgen_var_424, (VkDescriptorSet*)pDescriptorSets, pAllocateInfo->descriptorSetCount);
+        uint64_t* cgen_var_428;
+        stream->alloc((void**)&cgen_var_428, pAllocateInfo->descriptorSetCount * 8);
+        stream->read((uint64_t*)cgen_var_428, pAllocateInfo->descriptorSetCount * 8);
+        stream->handleMapping()->mapHandles_u64_VkDescriptorSet(cgen_var_428, (VkDescriptorSet*)pDescriptorSets, pAllocateInfo->descriptorSetCount);
     }
     stream->unsetHandleMapping();
     AEMU_SCOPED_TRACE("vkAllocateDescriptorSets returnUnmarshal");
@@ -5831,6 +6016,7 @@
     uint32_t descriptorSetCount,
     const VkDescriptorSet* pDescriptorSets)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkFreeDescriptorSets encode");
     mImpl->log("start vkFreeDescriptorSets");
     auto stream = mImpl->stream();
@@ -5852,24 +6038,24 @@
     }
     countingStream->rewind();
     {
-        uint64_t cgen_var_425;
-        countingStream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_425, 1);
-        countingStream->write((uint64_t*)&cgen_var_425, 1 * 8);
-        uint64_t cgen_var_426;
-        countingStream->handleMapping()->mapHandles_VkDescriptorPool_u64(&local_descriptorPool, &cgen_var_426, 1);
-        countingStream->write((uint64_t*)&cgen_var_426, 1 * 8);
+        uint64_t cgen_var_429;
+        countingStream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_429, 1);
+        countingStream->write((uint64_t*)&cgen_var_429, 1 * 8);
+        uint64_t cgen_var_430;
+        countingStream->handleMapping()->mapHandles_VkDescriptorPool_u64(&local_descriptorPool, &cgen_var_430, 1);
+        countingStream->write((uint64_t*)&cgen_var_430, 1 * 8);
         countingStream->write((uint32_t*)&local_descriptorSetCount, sizeof(uint32_t));
         // WARNING PTR CHECK
-        uint64_t cgen_var_427 = (uint64_t)(uintptr_t)local_pDescriptorSets;
-        countingStream->putBe64(cgen_var_427);
+        uint64_t cgen_var_431 = (uint64_t)(uintptr_t)local_pDescriptorSets;
+        countingStream->putBe64(cgen_var_431);
         if (local_pDescriptorSets)
         {
             if (((descriptorSetCount)))
             {
-                uint64_t* cgen_var_428;
-                countingStream->alloc((void**)&cgen_var_428, ((descriptorSetCount)) * 8);
-                countingStream->handleMapping()->mapHandles_VkDescriptorSet_u64(local_pDescriptorSets, cgen_var_428, ((descriptorSetCount)));
-                countingStream->write((uint64_t*)cgen_var_428, ((descriptorSetCount)) * 8);
+                uint64_t* cgen_var_432;
+                countingStream->alloc((void**)&cgen_var_432, ((descriptorSetCount)) * 8);
+                countingStream->handleMapping()->mapHandles_VkDescriptorSet_u64(local_pDescriptorSets, cgen_var_432, ((descriptorSetCount)));
+                countingStream->write((uint64_t*)cgen_var_432, ((descriptorSetCount)) * 8);
             }
         }
     }
@@ -5878,24 +6064,24 @@
     uint32_t opcode_vkFreeDescriptorSets = OP_vkFreeDescriptorSets;
     stream->write(&opcode_vkFreeDescriptorSets, sizeof(uint32_t));
     stream->write(&packetSize_vkFreeDescriptorSets, sizeof(uint32_t));
-    uint64_t cgen_var_429;
-    stream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_429, 1);
-    stream->write((uint64_t*)&cgen_var_429, 1 * 8);
-    uint64_t cgen_var_430;
-    stream->handleMapping()->mapHandles_VkDescriptorPool_u64(&local_descriptorPool, &cgen_var_430, 1);
-    stream->write((uint64_t*)&cgen_var_430, 1 * 8);
+    uint64_t cgen_var_433;
+    stream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_433, 1);
+    stream->write((uint64_t*)&cgen_var_433, 1 * 8);
+    uint64_t cgen_var_434;
+    stream->handleMapping()->mapHandles_VkDescriptorPool_u64(&local_descriptorPool, &cgen_var_434, 1);
+    stream->write((uint64_t*)&cgen_var_434, 1 * 8);
     stream->write((uint32_t*)&local_descriptorSetCount, sizeof(uint32_t));
     // WARNING PTR CHECK
-    uint64_t cgen_var_431 = (uint64_t)(uintptr_t)local_pDescriptorSets;
-    stream->putBe64(cgen_var_431);
+    uint64_t cgen_var_435 = (uint64_t)(uintptr_t)local_pDescriptorSets;
+    stream->putBe64(cgen_var_435);
     if (local_pDescriptorSets)
     {
         if (((descriptorSetCount)))
         {
-            uint64_t* cgen_var_432;
-            stream->alloc((void**)&cgen_var_432, ((descriptorSetCount)) * 8);
-            stream->handleMapping()->mapHandles_VkDescriptorSet_u64(local_pDescriptorSets, cgen_var_432, ((descriptorSetCount)));
-            stream->write((uint64_t*)cgen_var_432, ((descriptorSetCount)) * 8);
+            uint64_t* cgen_var_436;
+            stream->alloc((void**)&cgen_var_436, ((descriptorSetCount)) * 8);
+            stream->handleMapping()->mapHandles_VkDescriptorSet_u64(local_pDescriptorSets, cgen_var_436, ((descriptorSetCount)));
+            stream->write((uint64_t*)cgen_var_436, ((descriptorSetCount)) * 8);
         }
     }
     AEMU_SCOPED_TRACE("vkFreeDescriptorSets readParams");
@@ -5920,6 +6106,7 @@
     uint32_t descriptorCopyCount,
     const VkCopyDescriptorSet* pDescriptorCopies)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkUpdateDescriptorSets encode");
     mImpl->log("start vkUpdateDescriptorSets");
     auto stream = mImpl->stream();
@@ -5969,9 +6156,9 @@
     }
     countingStream->rewind();
     {
-        uint64_t cgen_var_433;
-        countingStream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_433, 1);
-        countingStream->write((uint64_t*)&cgen_var_433, 1 * 8);
+        uint64_t cgen_var_437;
+        countingStream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_437, 1);
+        countingStream->write((uint64_t*)&cgen_var_437, 1 * 8);
         countingStream->write((uint32_t*)&local_descriptorWriteCount, sizeof(uint32_t));
         for (uint32_t i = 0; i < (uint32_t)((descriptorWriteCount)); ++i)
         {
@@ -5988,9 +6175,9 @@
     uint32_t opcode_vkUpdateDescriptorSets = OP_vkUpdateDescriptorSets;
     stream->write(&opcode_vkUpdateDescriptorSets, sizeof(uint32_t));
     stream->write(&packetSize_vkUpdateDescriptorSets, sizeof(uint32_t));
-    uint64_t cgen_var_434;
-    stream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_434, 1);
-    stream->write((uint64_t*)&cgen_var_434, 1 * 8);
+    uint64_t cgen_var_438;
+    stream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_438, 1);
+    stream->write((uint64_t*)&cgen_var_438, 1 * 8);
     stream->write((uint32_t*)&local_descriptorWriteCount, sizeof(uint32_t));
     for (uint32_t i = 0; i < (uint32_t)((descriptorWriteCount)); ++i)
     {
@@ -6012,6 +6199,7 @@
     const VkAllocationCallbacks* pAllocator,
     VkFramebuffer* pFramebuffer)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkCreateFramebuffer encode");
     mImpl->log("start vkCreateFramebuffer");
     auto stream = mImpl->stream();
@@ -6046,47 +6234,47 @@
     }
     countingStream->rewind();
     {
-        uint64_t cgen_var_435;
-        countingStream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_435, 1);
-        countingStream->write((uint64_t*)&cgen_var_435, 1 * 8);
+        uint64_t cgen_var_439;
+        countingStream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_439, 1);
+        countingStream->write((uint64_t*)&cgen_var_439, 1 * 8);
         marshal_VkFramebufferCreateInfo(countingStream, (VkFramebufferCreateInfo*)(local_pCreateInfo));
         // WARNING PTR CHECK
-        uint64_t cgen_var_436 = (uint64_t)(uintptr_t)local_pAllocator;
-        countingStream->putBe64(cgen_var_436);
+        uint64_t cgen_var_440 = (uint64_t)(uintptr_t)local_pAllocator;
+        countingStream->putBe64(cgen_var_440);
         if (local_pAllocator)
         {
             marshal_VkAllocationCallbacks(countingStream, (VkAllocationCallbacks*)(local_pAllocator));
         }
-        uint64_t cgen_var_437;
-        countingStream->handleMapping()->mapHandles_VkFramebuffer_u64(pFramebuffer, &cgen_var_437, 1);
-        countingStream->write((uint64_t*)&cgen_var_437, 8);
+        uint64_t cgen_var_441;
+        countingStream->handleMapping()->mapHandles_VkFramebuffer_u64(pFramebuffer, &cgen_var_441, 1);
+        countingStream->write((uint64_t*)&cgen_var_441, 8);
     }
     uint32_t packetSize_vkCreateFramebuffer = 4 + 4 + (uint32_t)countingStream->bytesWritten();
     countingStream->rewind();
     uint32_t opcode_vkCreateFramebuffer = OP_vkCreateFramebuffer;
     stream->write(&opcode_vkCreateFramebuffer, sizeof(uint32_t));
     stream->write(&packetSize_vkCreateFramebuffer, sizeof(uint32_t));
-    uint64_t cgen_var_438;
-    stream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_438, 1);
-    stream->write((uint64_t*)&cgen_var_438, 1 * 8);
+    uint64_t cgen_var_442;
+    stream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_442, 1);
+    stream->write((uint64_t*)&cgen_var_442, 1 * 8);
     marshal_VkFramebufferCreateInfo(stream, (VkFramebufferCreateInfo*)(local_pCreateInfo));
     // WARNING PTR CHECK
-    uint64_t cgen_var_439 = (uint64_t)(uintptr_t)local_pAllocator;
-    stream->putBe64(cgen_var_439);
+    uint64_t cgen_var_443 = (uint64_t)(uintptr_t)local_pAllocator;
+    stream->putBe64(cgen_var_443);
     if (local_pAllocator)
     {
         marshal_VkAllocationCallbacks(stream, (VkAllocationCallbacks*)(local_pAllocator));
     }
     stream->unsetHandleMapping() /* emit_marshal, is handle, possibly out */;
-    uint64_t cgen_var_440;
-    stream->handleMapping()->mapHandles_VkFramebuffer_u64(pFramebuffer, &cgen_var_440, 1);
-    stream->write((uint64_t*)&cgen_var_440, 8);
+    uint64_t cgen_var_444;
+    stream->handleMapping()->mapHandles_VkFramebuffer_u64(pFramebuffer, &cgen_var_444, 1);
+    stream->write((uint64_t*)&cgen_var_444, 8);
     stream->setHandleMapping(resources->unwrapMapping());
     AEMU_SCOPED_TRACE("vkCreateFramebuffer readParams");
     stream->setHandleMapping(resources->createMapping());
-    uint64_t cgen_var_441;
-    stream->read((uint64_t*)&cgen_var_441, 8);
-    stream->handleMapping()->mapHandles_u64_VkFramebuffer(&cgen_var_441, (VkFramebuffer*)pFramebuffer, 1);
+    uint64_t cgen_var_445;
+    stream->read((uint64_t*)&cgen_var_445, 8);
+    stream->handleMapping()->mapHandles_u64_VkFramebuffer(&cgen_var_445, (VkFramebuffer*)pFramebuffer, 1);
     stream->unsetHandleMapping();
     AEMU_SCOPED_TRACE("vkCreateFramebuffer returnUnmarshal");
     VkResult vkCreateFramebuffer_VkResult_return = (VkResult)0;
@@ -6103,6 +6291,7 @@
     VkFramebuffer framebuffer,
     const VkAllocationCallbacks* pAllocator)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkDestroyFramebuffer encode");
     mImpl->log("start vkDestroyFramebuffer");
     auto stream = mImpl->stream();
@@ -6128,15 +6317,15 @@
     }
     countingStream->rewind();
     {
-        uint64_t cgen_var_442;
-        countingStream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_442, 1);
-        countingStream->write((uint64_t*)&cgen_var_442, 1 * 8);
-        uint64_t cgen_var_443;
-        countingStream->handleMapping()->mapHandles_VkFramebuffer_u64(&local_framebuffer, &cgen_var_443, 1);
-        countingStream->write((uint64_t*)&cgen_var_443, 1 * 8);
+        uint64_t cgen_var_446;
+        countingStream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_446, 1);
+        countingStream->write((uint64_t*)&cgen_var_446, 1 * 8);
+        uint64_t cgen_var_447;
+        countingStream->handleMapping()->mapHandles_VkFramebuffer_u64(&local_framebuffer, &cgen_var_447, 1);
+        countingStream->write((uint64_t*)&cgen_var_447, 1 * 8);
         // WARNING PTR CHECK
-        uint64_t cgen_var_444 = (uint64_t)(uintptr_t)local_pAllocator;
-        countingStream->putBe64(cgen_var_444);
+        uint64_t cgen_var_448 = (uint64_t)(uintptr_t)local_pAllocator;
+        countingStream->putBe64(cgen_var_448);
         if (local_pAllocator)
         {
             marshal_VkAllocationCallbacks(countingStream, (VkAllocationCallbacks*)(local_pAllocator));
@@ -6147,15 +6336,15 @@
     uint32_t opcode_vkDestroyFramebuffer = OP_vkDestroyFramebuffer;
     stream->write(&opcode_vkDestroyFramebuffer, sizeof(uint32_t));
     stream->write(&packetSize_vkDestroyFramebuffer, sizeof(uint32_t));
-    uint64_t cgen_var_445;
-    stream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_445, 1);
-    stream->write((uint64_t*)&cgen_var_445, 1 * 8);
-    uint64_t cgen_var_446;
-    stream->handleMapping()->mapHandles_VkFramebuffer_u64(&local_framebuffer, &cgen_var_446, 1);
-    stream->write((uint64_t*)&cgen_var_446, 1 * 8);
+    uint64_t cgen_var_449;
+    stream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_449, 1);
+    stream->write((uint64_t*)&cgen_var_449, 1 * 8);
+    uint64_t cgen_var_450;
+    stream->handleMapping()->mapHandles_VkFramebuffer_u64(&local_framebuffer, &cgen_var_450, 1);
+    stream->write((uint64_t*)&cgen_var_450, 1 * 8);
     // WARNING PTR CHECK
-    uint64_t cgen_var_447 = (uint64_t)(uintptr_t)local_pAllocator;
-    stream->putBe64(cgen_var_447);
+    uint64_t cgen_var_451 = (uint64_t)(uintptr_t)local_pAllocator;
+    stream->putBe64(cgen_var_451);
     if (local_pAllocator)
     {
         marshal_VkAllocationCallbacks(stream, (VkAllocationCallbacks*)(local_pAllocator));
@@ -6172,6 +6361,7 @@
     const VkAllocationCallbacks* pAllocator,
     VkRenderPass* pRenderPass)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkCreateRenderPass encode");
     mImpl->log("start vkCreateRenderPass");
     auto stream = mImpl->stream();
@@ -6206,47 +6396,47 @@
     }
     countingStream->rewind();
     {
-        uint64_t cgen_var_448;
-        countingStream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_448, 1);
-        countingStream->write((uint64_t*)&cgen_var_448, 1 * 8);
+        uint64_t cgen_var_452;
+        countingStream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_452, 1);
+        countingStream->write((uint64_t*)&cgen_var_452, 1 * 8);
         marshal_VkRenderPassCreateInfo(countingStream, (VkRenderPassCreateInfo*)(local_pCreateInfo));
         // WARNING PTR CHECK
-        uint64_t cgen_var_449 = (uint64_t)(uintptr_t)local_pAllocator;
-        countingStream->putBe64(cgen_var_449);
+        uint64_t cgen_var_453 = (uint64_t)(uintptr_t)local_pAllocator;
+        countingStream->putBe64(cgen_var_453);
         if (local_pAllocator)
         {
             marshal_VkAllocationCallbacks(countingStream, (VkAllocationCallbacks*)(local_pAllocator));
         }
-        uint64_t cgen_var_450;
-        countingStream->handleMapping()->mapHandles_VkRenderPass_u64(pRenderPass, &cgen_var_450, 1);
-        countingStream->write((uint64_t*)&cgen_var_450, 8);
+        uint64_t cgen_var_454;
+        countingStream->handleMapping()->mapHandles_VkRenderPass_u64(pRenderPass, &cgen_var_454, 1);
+        countingStream->write((uint64_t*)&cgen_var_454, 8);
     }
     uint32_t packetSize_vkCreateRenderPass = 4 + 4 + (uint32_t)countingStream->bytesWritten();
     countingStream->rewind();
     uint32_t opcode_vkCreateRenderPass = OP_vkCreateRenderPass;
     stream->write(&opcode_vkCreateRenderPass, sizeof(uint32_t));
     stream->write(&packetSize_vkCreateRenderPass, sizeof(uint32_t));
-    uint64_t cgen_var_451;
-    stream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_451, 1);
-    stream->write((uint64_t*)&cgen_var_451, 1 * 8);
+    uint64_t cgen_var_455;
+    stream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_455, 1);
+    stream->write((uint64_t*)&cgen_var_455, 1 * 8);
     marshal_VkRenderPassCreateInfo(stream, (VkRenderPassCreateInfo*)(local_pCreateInfo));
     // WARNING PTR CHECK
-    uint64_t cgen_var_452 = (uint64_t)(uintptr_t)local_pAllocator;
-    stream->putBe64(cgen_var_452);
+    uint64_t cgen_var_456 = (uint64_t)(uintptr_t)local_pAllocator;
+    stream->putBe64(cgen_var_456);
     if (local_pAllocator)
     {
         marshal_VkAllocationCallbacks(stream, (VkAllocationCallbacks*)(local_pAllocator));
     }
     stream->unsetHandleMapping() /* emit_marshal, is handle, possibly out */;
-    uint64_t cgen_var_453;
-    stream->handleMapping()->mapHandles_VkRenderPass_u64(pRenderPass, &cgen_var_453, 1);
-    stream->write((uint64_t*)&cgen_var_453, 8);
+    uint64_t cgen_var_457;
+    stream->handleMapping()->mapHandles_VkRenderPass_u64(pRenderPass, &cgen_var_457, 1);
+    stream->write((uint64_t*)&cgen_var_457, 8);
     stream->setHandleMapping(resources->unwrapMapping());
     AEMU_SCOPED_TRACE("vkCreateRenderPass readParams");
     stream->setHandleMapping(resources->createMapping());
-    uint64_t cgen_var_454;
-    stream->read((uint64_t*)&cgen_var_454, 8);
-    stream->handleMapping()->mapHandles_u64_VkRenderPass(&cgen_var_454, (VkRenderPass*)pRenderPass, 1);
+    uint64_t cgen_var_458;
+    stream->read((uint64_t*)&cgen_var_458, 8);
+    stream->handleMapping()->mapHandles_u64_VkRenderPass(&cgen_var_458, (VkRenderPass*)pRenderPass, 1);
     stream->unsetHandleMapping();
     AEMU_SCOPED_TRACE("vkCreateRenderPass returnUnmarshal");
     VkResult vkCreateRenderPass_VkResult_return = (VkResult)0;
@@ -6263,6 +6453,7 @@
     VkRenderPass renderPass,
     const VkAllocationCallbacks* pAllocator)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkDestroyRenderPass encode");
     mImpl->log("start vkDestroyRenderPass");
     auto stream = mImpl->stream();
@@ -6288,15 +6479,15 @@
     }
     countingStream->rewind();
     {
-        uint64_t cgen_var_455;
-        countingStream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_455, 1);
-        countingStream->write((uint64_t*)&cgen_var_455, 1 * 8);
-        uint64_t cgen_var_456;
-        countingStream->handleMapping()->mapHandles_VkRenderPass_u64(&local_renderPass, &cgen_var_456, 1);
-        countingStream->write((uint64_t*)&cgen_var_456, 1 * 8);
+        uint64_t cgen_var_459;
+        countingStream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_459, 1);
+        countingStream->write((uint64_t*)&cgen_var_459, 1 * 8);
+        uint64_t cgen_var_460;
+        countingStream->handleMapping()->mapHandles_VkRenderPass_u64(&local_renderPass, &cgen_var_460, 1);
+        countingStream->write((uint64_t*)&cgen_var_460, 1 * 8);
         // WARNING PTR CHECK
-        uint64_t cgen_var_457 = (uint64_t)(uintptr_t)local_pAllocator;
-        countingStream->putBe64(cgen_var_457);
+        uint64_t cgen_var_461 = (uint64_t)(uintptr_t)local_pAllocator;
+        countingStream->putBe64(cgen_var_461);
         if (local_pAllocator)
         {
             marshal_VkAllocationCallbacks(countingStream, (VkAllocationCallbacks*)(local_pAllocator));
@@ -6307,15 +6498,15 @@
     uint32_t opcode_vkDestroyRenderPass = OP_vkDestroyRenderPass;
     stream->write(&opcode_vkDestroyRenderPass, sizeof(uint32_t));
     stream->write(&packetSize_vkDestroyRenderPass, sizeof(uint32_t));
-    uint64_t cgen_var_458;
-    stream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_458, 1);
-    stream->write((uint64_t*)&cgen_var_458, 1 * 8);
-    uint64_t cgen_var_459;
-    stream->handleMapping()->mapHandles_VkRenderPass_u64(&local_renderPass, &cgen_var_459, 1);
-    stream->write((uint64_t*)&cgen_var_459, 1 * 8);
+    uint64_t cgen_var_462;
+    stream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_462, 1);
+    stream->write((uint64_t*)&cgen_var_462, 1 * 8);
+    uint64_t cgen_var_463;
+    stream->handleMapping()->mapHandles_VkRenderPass_u64(&local_renderPass, &cgen_var_463, 1);
+    stream->write((uint64_t*)&cgen_var_463, 1 * 8);
     // WARNING PTR CHECK
-    uint64_t cgen_var_460 = (uint64_t)(uintptr_t)local_pAllocator;
-    stream->putBe64(cgen_var_460);
+    uint64_t cgen_var_464 = (uint64_t)(uintptr_t)local_pAllocator;
+    stream->putBe64(cgen_var_464);
     if (local_pAllocator)
     {
         marshal_VkAllocationCallbacks(stream, (VkAllocationCallbacks*)(local_pAllocator));
@@ -6331,6 +6522,7 @@
     VkRenderPass renderPass,
     VkExtent2D* pGranularity)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkGetRenderAreaGranularity encode");
     mImpl->log("start vkGetRenderAreaGranularity");
     auto stream = mImpl->stream();
@@ -6344,12 +6536,12 @@
     local_renderPass = renderPass;
     countingStream->rewind();
     {
-        uint64_t cgen_var_461;
-        countingStream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_461, 1);
-        countingStream->write((uint64_t*)&cgen_var_461, 1 * 8);
-        uint64_t cgen_var_462;
-        countingStream->handleMapping()->mapHandles_VkRenderPass_u64(&local_renderPass, &cgen_var_462, 1);
-        countingStream->write((uint64_t*)&cgen_var_462, 1 * 8);
+        uint64_t cgen_var_465;
+        countingStream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_465, 1);
+        countingStream->write((uint64_t*)&cgen_var_465, 1 * 8);
+        uint64_t cgen_var_466;
+        countingStream->handleMapping()->mapHandles_VkRenderPass_u64(&local_renderPass, &cgen_var_466, 1);
+        countingStream->write((uint64_t*)&cgen_var_466, 1 * 8);
         marshal_VkExtent2D(countingStream, (VkExtent2D*)(pGranularity));
     }
     uint32_t packetSize_vkGetRenderAreaGranularity = 4 + 4 + (uint32_t)countingStream->bytesWritten();
@@ -6357,12 +6549,12 @@
     uint32_t opcode_vkGetRenderAreaGranularity = OP_vkGetRenderAreaGranularity;
     stream->write(&opcode_vkGetRenderAreaGranularity, sizeof(uint32_t));
     stream->write(&packetSize_vkGetRenderAreaGranularity, sizeof(uint32_t));
-    uint64_t cgen_var_463;
-    stream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_463, 1);
-    stream->write((uint64_t*)&cgen_var_463, 1 * 8);
-    uint64_t cgen_var_464;
-    stream->handleMapping()->mapHandles_VkRenderPass_u64(&local_renderPass, &cgen_var_464, 1);
-    stream->write((uint64_t*)&cgen_var_464, 1 * 8);
+    uint64_t cgen_var_467;
+    stream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_467, 1);
+    stream->write((uint64_t*)&cgen_var_467, 1 * 8);
+    uint64_t cgen_var_468;
+    stream->handleMapping()->mapHandles_VkRenderPass_u64(&local_renderPass, &cgen_var_468, 1);
+    stream->write((uint64_t*)&cgen_var_468, 1 * 8);
     marshal_VkExtent2D(stream, (VkExtent2D*)(pGranularity));
     AEMU_SCOPED_TRACE("vkGetRenderAreaGranularity readParams");
     unmarshal_VkExtent2D(stream, (VkExtent2D*)(pGranularity));
@@ -6380,6 +6572,7 @@
     const VkAllocationCallbacks* pAllocator,
     VkCommandPool* pCommandPool)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkCreateCommandPool encode");
     mImpl->log("start vkCreateCommandPool");
     auto stream = mImpl->stream();
@@ -6414,47 +6607,47 @@
     }
     countingStream->rewind();
     {
-        uint64_t cgen_var_465;
-        countingStream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_465, 1);
-        countingStream->write((uint64_t*)&cgen_var_465, 1 * 8);
+        uint64_t cgen_var_469;
+        countingStream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_469, 1);
+        countingStream->write((uint64_t*)&cgen_var_469, 1 * 8);
         marshal_VkCommandPoolCreateInfo(countingStream, (VkCommandPoolCreateInfo*)(local_pCreateInfo));
         // WARNING PTR CHECK
-        uint64_t cgen_var_466 = (uint64_t)(uintptr_t)local_pAllocator;
-        countingStream->putBe64(cgen_var_466);
+        uint64_t cgen_var_470 = (uint64_t)(uintptr_t)local_pAllocator;
+        countingStream->putBe64(cgen_var_470);
         if (local_pAllocator)
         {
             marshal_VkAllocationCallbacks(countingStream, (VkAllocationCallbacks*)(local_pAllocator));
         }
-        uint64_t cgen_var_467;
-        countingStream->handleMapping()->mapHandles_VkCommandPool_u64(pCommandPool, &cgen_var_467, 1);
-        countingStream->write((uint64_t*)&cgen_var_467, 8);
+        uint64_t cgen_var_471;
+        countingStream->handleMapping()->mapHandles_VkCommandPool_u64(pCommandPool, &cgen_var_471, 1);
+        countingStream->write((uint64_t*)&cgen_var_471, 8);
     }
     uint32_t packetSize_vkCreateCommandPool = 4 + 4 + (uint32_t)countingStream->bytesWritten();
     countingStream->rewind();
     uint32_t opcode_vkCreateCommandPool = OP_vkCreateCommandPool;
     stream->write(&opcode_vkCreateCommandPool, sizeof(uint32_t));
     stream->write(&packetSize_vkCreateCommandPool, sizeof(uint32_t));
-    uint64_t cgen_var_468;
-    stream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_468, 1);
-    stream->write((uint64_t*)&cgen_var_468, 1 * 8);
+    uint64_t cgen_var_472;
+    stream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_472, 1);
+    stream->write((uint64_t*)&cgen_var_472, 1 * 8);
     marshal_VkCommandPoolCreateInfo(stream, (VkCommandPoolCreateInfo*)(local_pCreateInfo));
     // WARNING PTR CHECK
-    uint64_t cgen_var_469 = (uint64_t)(uintptr_t)local_pAllocator;
-    stream->putBe64(cgen_var_469);
+    uint64_t cgen_var_473 = (uint64_t)(uintptr_t)local_pAllocator;
+    stream->putBe64(cgen_var_473);
     if (local_pAllocator)
     {
         marshal_VkAllocationCallbacks(stream, (VkAllocationCallbacks*)(local_pAllocator));
     }
     stream->unsetHandleMapping() /* emit_marshal, is handle, possibly out */;
-    uint64_t cgen_var_470;
-    stream->handleMapping()->mapHandles_VkCommandPool_u64(pCommandPool, &cgen_var_470, 1);
-    stream->write((uint64_t*)&cgen_var_470, 8);
+    uint64_t cgen_var_474;
+    stream->handleMapping()->mapHandles_VkCommandPool_u64(pCommandPool, &cgen_var_474, 1);
+    stream->write((uint64_t*)&cgen_var_474, 8);
     stream->setHandleMapping(resources->unwrapMapping());
     AEMU_SCOPED_TRACE("vkCreateCommandPool readParams");
     stream->setHandleMapping(resources->createMapping());
-    uint64_t cgen_var_471;
-    stream->read((uint64_t*)&cgen_var_471, 8);
-    stream->handleMapping()->mapHandles_u64_VkCommandPool(&cgen_var_471, (VkCommandPool*)pCommandPool, 1);
+    uint64_t cgen_var_475;
+    stream->read((uint64_t*)&cgen_var_475, 8);
+    stream->handleMapping()->mapHandles_u64_VkCommandPool(&cgen_var_475, (VkCommandPool*)pCommandPool, 1);
     stream->unsetHandleMapping();
     AEMU_SCOPED_TRACE("vkCreateCommandPool returnUnmarshal");
     VkResult vkCreateCommandPool_VkResult_return = (VkResult)0;
@@ -6471,6 +6664,7 @@
     VkCommandPool commandPool,
     const VkAllocationCallbacks* pAllocator)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkDestroyCommandPool encode");
     mImpl->log("start vkDestroyCommandPool");
     auto stream = mImpl->stream();
@@ -6496,15 +6690,15 @@
     }
     countingStream->rewind();
     {
-        uint64_t cgen_var_472;
-        countingStream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_472, 1);
-        countingStream->write((uint64_t*)&cgen_var_472, 1 * 8);
-        uint64_t cgen_var_473;
-        countingStream->handleMapping()->mapHandles_VkCommandPool_u64(&local_commandPool, &cgen_var_473, 1);
-        countingStream->write((uint64_t*)&cgen_var_473, 1 * 8);
+        uint64_t cgen_var_476;
+        countingStream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_476, 1);
+        countingStream->write((uint64_t*)&cgen_var_476, 1 * 8);
+        uint64_t cgen_var_477;
+        countingStream->handleMapping()->mapHandles_VkCommandPool_u64(&local_commandPool, &cgen_var_477, 1);
+        countingStream->write((uint64_t*)&cgen_var_477, 1 * 8);
         // WARNING PTR CHECK
-        uint64_t cgen_var_474 = (uint64_t)(uintptr_t)local_pAllocator;
-        countingStream->putBe64(cgen_var_474);
+        uint64_t cgen_var_478 = (uint64_t)(uintptr_t)local_pAllocator;
+        countingStream->putBe64(cgen_var_478);
         if (local_pAllocator)
         {
             marshal_VkAllocationCallbacks(countingStream, (VkAllocationCallbacks*)(local_pAllocator));
@@ -6515,15 +6709,15 @@
     uint32_t opcode_vkDestroyCommandPool = OP_vkDestroyCommandPool;
     stream->write(&opcode_vkDestroyCommandPool, sizeof(uint32_t));
     stream->write(&packetSize_vkDestroyCommandPool, sizeof(uint32_t));
-    uint64_t cgen_var_475;
-    stream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_475, 1);
-    stream->write((uint64_t*)&cgen_var_475, 1 * 8);
-    uint64_t cgen_var_476;
-    stream->handleMapping()->mapHandles_VkCommandPool_u64(&local_commandPool, &cgen_var_476, 1);
-    stream->write((uint64_t*)&cgen_var_476, 1 * 8);
+    uint64_t cgen_var_479;
+    stream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_479, 1);
+    stream->write((uint64_t*)&cgen_var_479, 1 * 8);
+    uint64_t cgen_var_480;
+    stream->handleMapping()->mapHandles_VkCommandPool_u64(&local_commandPool, &cgen_var_480, 1);
+    stream->write((uint64_t*)&cgen_var_480, 1 * 8);
     // WARNING PTR CHECK
-    uint64_t cgen_var_477 = (uint64_t)(uintptr_t)local_pAllocator;
-    stream->putBe64(cgen_var_477);
+    uint64_t cgen_var_481 = (uint64_t)(uintptr_t)local_pAllocator;
+    stream->putBe64(cgen_var_481);
     if (local_pAllocator)
     {
         marshal_VkAllocationCallbacks(stream, (VkAllocationCallbacks*)(local_pAllocator));
@@ -6539,6 +6733,7 @@
     VkCommandPool commandPool,
     VkCommandPoolResetFlags flags)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkResetCommandPool encode");
     mImpl->log("start vkResetCommandPool");
     auto stream = mImpl->stream();
@@ -6554,12 +6749,12 @@
     local_flags = flags;
     countingStream->rewind();
     {
-        uint64_t cgen_var_478;
-        countingStream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_478, 1);
-        countingStream->write((uint64_t*)&cgen_var_478, 1 * 8);
-        uint64_t cgen_var_479;
-        countingStream->handleMapping()->mapHandles_VkCommandPool_u64(&local_commandPool, &cgen_var_479, 1);
-        countingStream->write((uint64_t*)&cgen_var_479, 1 * 8);
+        uint64_t cgen_var_482;
+        countingStream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_482, 1);
+        countingStream->write((uint64_t*)&cgen_var_482, 1 * 8);
+        uint64_t cgen_var_483;
+        countingStream->handleMapping()->mapHandles_VkCommandPool_u64(&local_commandPool, &cgen_var_483, 1);
+        countingStream->write((uint64_t*)&cgen_var_483, 1 * 8);
         countingStream->write((VkCommandPoolResetFlags*)&local_flags, sizeof(VkCommandPoolResetFlags));
     }
     uint32_t packetSize_vkResetCommandPool = 4 + 4 + (uint32_t)countingStream->bytesWritten();
@@ -6567,12 +6762,12 @@
     uint32_t opcode_vkResetCommandPool = OP_vkResetCommandPool;
     stream->write(&opcode_vkResetCommandPool, sizeof(uint32_t));
     stream->write(&packetSize_vkResetCommandPool, sizeof(uint32_t));
-    uint64_t cgen_var_480;
-    stream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_480, 1);
-    stream->write((uint64_t*)&cgen_var_480, 1 * 8);
-    uint64_t cgen_var_481;
-    stream->handleMapping()->mapHandles_VkCommandPool_u64(&local_commandPool, &cgen_var_481, 1);
-    stream->write((uint64_t*)&cgen_var_481, 1 * 8);
+    uint64_t cgen_var_484;
+    stream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_484, 1);
+    stream->write((uint64_t*)&cgen_var_484, 1 * 8);
+    uint64_t cgen_var_485;
+    stream->handleMapping()->mapHandles_VkCommandPool_u64(&local_commandPool, &cgen_var_485, 1);
+    stream->write((uint64_t*)&cgen_var_485, 1 * 8);
     stream->write((VkCommandPoolResetFlags*)&local_flags, sizeof(VkCommandPoolResetFlags));
     AEMU_SCOPED_TRACE("vkResetCommandPool readParams");
     AEMU_SCOPED_TRACE("vkResetCommandPool returnUnmarshal");
@@ -6590,6 +6785,7 @@
     const VkCommandBufferAllocateInfo* pAllocateInfo,
     VkCommandBuffer* pCommandBuffers)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkAllocateCommandBuffers encode");
     mImpl->log("start vkAllocateCommandBuffers");
     auto stream = mImpl->stream();
@@ -6612,16 +6808,16 @@
     }
     countingStream->rewind();
     {
-        uint64_t cgen_var_482;
-        countingStream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_482, 1);
-        countingStream->write((uint64_t*)&cgen_var_482, 1 * 8);
+        uint64_t cgen_var_486;
+        countingStream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_486, 1);
+        countingStream->write((uint64_t*)&cgen_var_486, 1 * 8);
         marshal_VkCommandBufferAllocateInfo(countingStream, (VkCommandBufferAllocateInfo*)(local_pAllocateInfo));
         if (pAllocateInfo->commandBufferCount)
         {
-            uint64_t* cgen_var_483;
-            countingStream->alloc((void**)&cgen_var_483, pAllocateInfo->commandBufferCount * 8);
-            countingStream->handleMapping()->mapHandles_VkCommandBuffer_u64(pCommandBuffers, cgen_var_483, pAllocateInfo->commandBufferCount);
-            countingStream->write((uint64_t*)cgen_var_483, pAllocateInfo->commandBufferCount * 8);
+            uint64_t* cgen_var_487;
+            countingStream->alloc((void**)&cgen_var_487, pAllocateInfo->commandBufferCount * 8);
+            countingStream->handleMapping()->mapHandles_VkCommandBuffer_u64(pCommandBuffers, cgen_var_487, pAllocateInfo->commandBufferCount);
+            countingStream->write((uint64_t*)cgen_var_487, pAllocateInfo->commandBufferCount * 8);
         }
     }
     uint32_t packetSize_vkAllocateCommandBuffers = 4 + 4 + (uint32_t)countingStream->bytesWritten();
@@ -6629,27 +6825,27 @@
     uint32_t opcode_vkAllocateCommandBuffers = OP_vkAllocateCommandBuffers;
     stream->write(&opcode_vkAllocateCommandBuffers, sizeof(uint32_t));
     stream->write(&packetSize_vkAllocateCommandBuffers, sizeof(uint32_t));
-    uint64_t cgen_var_484;
-    stream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_484, 1);
-    stream->write((uint64_t*)&cgen_var_484, 1 * 8);
+    uint64_t cgen_var_488;
+    stream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_488, 1);
+    stream->write((uint64_t*)&cgen_var_488, 1 * 8);
     marshal_VkCommandBufferAllocateInfo(stream, (VkCommandBufferAllocateInfo*)(local_pAllocateInfo));
     stream->unsetHandleMapping() /* emit_marshal, is handle, possibly out */;
     if (pAllocateInfo->commandBufferCount)
     {
-        uint64_t* cgen_var_485;
-        stream->alloc((void**)&cgen_var_485, pAllocateInfo->commandBufferCount * 8);
-        stream->handleMapping()->mapHandles_VkCommandBuffer_u64(pCommandBuffers, cgen_var_485, pAllocateInfo->commandBufferCount);
-        stream->write((uint64_t*)cgen_var_485, pAllocateInfo->commandBufferCount * 8);
+        uint64_t* cgen_var_489;
+        stream->alloc((void**)&cgen_var_489, pAllocateInfo->commandBufferCount * 8);
+        stream->handleMapping()->mapHandles_VkCommandBuffer_u64(pCommandBuffers, cgen_var_489, pAllocateInfo->commandBufferCount);
+        stream->write((uint64_t*)cgen_var_489, pAllocateInfo->commandBufferCount * 8);
     }
     stream->setHandleMapping(resources->unwrapMapping());
     AEMU_SCOPED_TRACE("vkAllocateCommandBuffers readParams");
     stream->setHandleMapping(resources->createMapping());
     if (pAllocateInfo->commandBufferCount)
     {
-        uint64_t* cgen_var_486;
-        stream->alloc((void**)&cgen_var_486, pAllocateInfo->commandBufferCount * 8);
-        stream->read((uint64_t*)cgen_var_486, pAllocateInfo->commandBufferCount * 8);
-        stream->handleMapping()->mapHandles_u64_VkCommandBuffer(cgen_var_486, (VkCommandBuffer*)pCommandBuffers, pAllocateInfo->commandBufferCount);
+        uint64_t* cgen_var_490;
+        stream->alloc((void**)&cgen_var_490, pAllocateInfo->commandBufferCount * 8);
+        stream->read((uint64_t*)cgen_var_490, pAllocateInfo->commandBufferCount * 8);
+        stream->handleMapping()->mapHandles_u64_VkCommandBuffer(cgen_var_490, (VkCommandBuffer*)pCommandBuffers, pAllocateInfo->commandBufferCount);
     }
     stream->unsetHandleMapping();
     AEMU_SCOPED_TRACE("vkAllocateCommandBuffers returnUnmarshal");
@@ -6668,6 +6864,7 @@
     uint32_t commandBufferCount,
     const VkCommandBuffer* pCommandBuffers)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkFreeCommandBuffers encode");
     mImpl->log("start vkFreeCommandBuffers");
     auto stream = mImpl->stream();
@@ -6689,24 +6886,24 @@
     }
     countingStream->rewind();
     {
-        uint64_t cgen_var_487;
-        countingStream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_487, 1);
-        countingStream->write((uint64_t*)&cgen_var_487, 1 * 8);
-        uint64_t cgen_var_488;
-        countingStream->handleMapping()->mapHandles_VkCommandPool_u64(&local_commandPool, &cgen_var_488, 1);
-        countingStream->write((uint64_t*)&cgen_var_488, 1 * 8);
+        uint64_t cgen_var_491;
+        countingStream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_491, 1);
+        countingStream->write((uint64_t*)&cgen_var_491, 1 * 8);
+        uint64_t cgen_var_492;
+        countingStream->handleMapping()->mapHandles_VkCommandPool_u64(&local_commandPool, &cgen_var_492, 1);
+        countingStream->write((uint64_t*)&cgen_var_492, 1 * 8);
         countingStream->write((uint32_t*)&local_commandBufferCount, sizeof(uint32_t));
         // WARNING PTR CHECK
-        uint64_t cgen_var_489 = (uint64_t)(uintptr_t)local_pCommandBuffers;
-        countingStream->putBe64(cgen_var_489);
+        uint64_t cgen_var_493 = (uint64_t)(uintptr_t)local_pCommandBuffers;
+        countingStream->putBe64(cgen_var_493);
         if (local_pCommandBuffers)
         {
             if (((commandBufferCount)))
             {
-                uint64_t* cgen_var_490;
-                countingStream->alloc((void**)&cgen_var_490, ((commandBufferCount)) * 8);
-                countingStream->handleMapping()->mapHandles_VkCommandBuffer_u64(local_pCommandBuffers, cgen_var_490, ((commandBufferCount)));
-                countingStream->write((uint64_t*)cgen_var_490, ((commandBufferCount)) * 8);
+                uint64_t* cgen_var_494;
+                countingStream->alloc((void**)&cgen_var_494, ((commandBufferCount)) * 8);
+                countingStream->handleMapping()->mapHandles_VkCommandBuffer_u64(local_pCommandBuffers, cgen_var_494, ((commandBufferCount)));
+                countingStream->write((uint64_t*)cgen_var_494, ((commandBufferCount)) * 8);
             }
         }
     }
@@ -6715,24 +6912,24 @@
     uint32_t opcode_vkFreeCommandBuffers = OP_vkFreeCommandBuffers;
     stream->write(&opcode_vkFreeCommandBuffers, sizeof(uint32_t));
     stream->write(&packetSize_vkFreeCommandBuffers, sizeof(uint32_t));
-    uint64_t cgen_var_491;
-    stream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_491, 1);
-    stream->write((uint64_t*)&cgen_var_491, 1 * 8);
-    uint64_t cgen_var_492;
-    stream->handleMapping()->mapHandles_VkCommandPool_u64(&local_commandPool, &cgen_var_492, 1);
-    stream->write((uint64_t*)&cgen_var_492, 1 * 8);
+    uint64_t cgen_var_495;
+    stream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_495, 1);
+    stream->write((uint64_t*)&cgen_var_495, 1 * 8);
+    uint64_t cgen_var_496;
+    stream->handleMapping()->mapHandles_VkCommandPool_u64(&local_commandPool, &cgen_var_496, 1);
+    stream->write((uint64_t*)&cgen_var_496, 1 * 8);
     stream->write((uint32_t*)&local_commandBufferCount, sizeof(uint32_t));
     // WARNING PTR CHECK
-    uint64_t cgen_var_493 = (uint64_t)(uintptr_t)local_pCommandBuffers;
-    stream->putBe64(cgen_var_493);
+    uint64_t cgen_var_497 = (uint64_t)(uintptr_t)local_pCommandBuffers;
+    stream->putBe64(cgen_var_497);
     if (local_pCommandBuffers)
     {
         if (((commandBufferCount)))
         {
-            uint64_t* cgen_var_494;
-            stream->alloc((void**)&cgen_var_494, ((commandBufferCount)) * 8);
-            stream->handleMapping()->mapHandles_VkCommandBuffer_u64(local_pCommandBuffers, cgen_var_494, ((commandBufferCount)));
-            stream->write((uint64_t*)cgen_var_494, ((commandBufferCount)) * 8);
+            uint64_t* cgen_var_498;
+            stream->alloc((void**)&cgen_var_498, ((commandBufferCount)) * 8);
+            stream->handleMapping()->mapHandles_VkCommandBuffer_u64(local_pCommandBuffers, cgen_var_498, ((commandBufferCount)));
+            stream->write((uint64_t*)cgen_var_498, ((commandBufferCount)) * 8);
         }
     }
     AEMU_SCOPED_TRACE("vkFreeCommandBuffers readParams");
@@ -6748,6 +6945,7 @@
     VkCommandBuffer commandBuffer,
     const VkCommandBufferBeginInfo* pBeginInfo)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkBeginCommandBuffer encode");
     mImpl->log("start vkBeginCommandBuffer");
     auto stream = mImpl->stream();
@@ -6770,9 +6968,9 @@
     }
     countingStream->rewind();
     {
-        uint64_t cgen_var_495;
-        countingStream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_495, 1);
-        countingStream->write((uint64_t*)&cgen_var_495, 1 * 8);
+        uint64_t cgen_var_499;
+        countingStream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_499, 1);
+        countingStream->write((uint64_t*)&cgen_var_499, 1 * 8);
         marshal_VkCommandBufferBeginInfo(countingStream, (VkCommandBufferBeginInfo*)(local_pBeginInfo));
     }
     uint32_t packetSize_vkBeginCommandBuffer = 4 + 4 + (uint32_t)countingStream->bytesWritten();
@@ -6780,9 +6978,9 @@
     uint32_t opcode_vkBeginCommandBuffer = OP_vkBeginCommandBuffer;
     stream->write(&opcode_vkBeginCommandBuffer, sizeof(uint32_t));
     stream->write(&packetSize_vkBeginCommandBuffer, sizeof(uint32_t));
-    uint64_t cgen_var_496;
-    stream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_496, 1);
-    stream->write((uint64_t*)&cgen_var_496, 1 * 8);
+    uint64_t cgen_var_500;
+    stream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_500, 1);
+    stream->write((uint64_t*)&cgen_var_500, 1 * 8);
     marshal_VkCommandBufferBeginInfo(stream, (VkCommandBufferBeginInfo*)(local_pBeginInfo));
     AEMU_SCOPED_TRACE("vkBeginCommandBuffer readParams");
     AEMU_SCOPED_TRACE("vkBeginCommandBuffer returnUnmarshal");
@@ -6798,6 +6996,7 @@
 VkResult VkEncoder::vkEndCommandBuffer(
     VkCommandBuffer commandBuffer)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkEndCommandBuffer encode");
     mImpl->log("start vkEndCommandBuffer");
     auto stream = mImpl->stream();
@@ -6809,18 +7008,18 @@
     local_commandBuffer = commandBuffer;
     countingStream->rewind();
     {
-        uint64_t cgen_var_497;
-        countingStream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_497, 1);
-        countingStream->write((uint64_t*)&cgen_var_497, 1 * 8);
+        uint64_t cgen_var_501;
+        countingStream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_501, 1);
+        countingStream->write((uint64_t*)&cgen_var_501, 1 * 8);
     }
     uint32_t packetSize_vkEndCommandBuffer = 4 + 4 + (uint32_t)countingStream->bytesWritten();
     countingStream->rewind();
     uint32_t opcode_vkEndCommandBuffer = OP_vkEndCommandBuffer;
     stream->write(&opcode_vkEndCommandBuffer, sizeof(uint32_t));
     stream->write(&packetSize_vkEndCommandBuffer, sizeof(uint32_t));
-    uint64_t cgen_var_498;
-    stream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_498, 1);
-    stream->write((uint64_t*)&cgen_var_498, 1 * 8);
+    uint64_t cgen_var_502;
+    stream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_502, 1);
+    stream->write((uint64_t*)&cgen_var_502, 1 * 8);
     AEMU_SCOPED_TRACE("vkEndCommandBuffer readParams");
     AEMU_SCOPED_TRACE("vkEndCommandBuffer returnUnmarshal");
     VkResult vkEndCommandBuffer_VkResult_return = (VkResult)0;
@@ -6836,6 +7035,7 @@
     VkCommandBuffer commandBuffer,
     VkCommandBufferResetFlags flags)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkResetCommandBuffer encode");
     mImpl->log("start vkResetCommandBuffer");
     auto stream = mImpl->stream();
@@ -6849,9 +7049,9 @@
     local_flags = flags;
     countingStream->rewind();
     {
-        uint64_t cgen_var_499;
-        countingStream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_499, 1);
-        countingStream->write((uint64_t*)&cgen_var_499, 1 * 8);
+        uint64_t cgen_var_503;
+        countingStream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_503, 1);
+        countingStream->write((uint64_t*)&cgen_var_503, 1 * 8);
         countingStream->write((VkCommandBufferResetFlags*)&local_flags, sizeof(VkCommandBufferResetFlags));
     }
     uint32_t packetSize_vkResetCommandBuffer = 4 + 4 + (uint32_t)countingStream->bytesWritten();
@@ -6859,9 +7059,9 @@
     uint32_t opcode_vkResetCommandBuffer = OP_vkResetCommandBuffer;
     stream->write(&opcode_vkResetCommandBuffer, sizeof(uint32_t));
     stream->write(&packetSize_vkResetCommandBuffer, sizeof(uint32_t));
-    uint64_t cgen_var_500;
-    stream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_500, 1);
-    stream->write((uint64_t*)&cgen_var_500, 1 * 8);
+    uint64_t cgen_var_504;
+    stream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_504, 1);
+    stream->write((uint64_t*)&cgen_var_504, 1 * 8);
     stream->write((VkCommandBufferResetFlags*)&local_flags, sizeof(VkCommandBufferResetFlags));
     AEMU_SCOPED_TRACE("vkResetCommandBuffer readParams");
     AEMU_SCOPED_TRACE("vkResetCommandBuffer returnUnmarshal");
@@ -6879,6 +7079,7 @@
     VkPipelineBindPoint pipelineBindPoint,
     VkPipeline pipeline)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkCmdBindPipeline encode");
     mImpl->log("start vkCmdBindPipeline");
     auto stream = mImpl->stream();
@@ -6894,26 +7095,26 @@
     local_pipeline = pipeline;
     countingStream->rewind();
     {
-        uint64_t cgen_var_501;
-        countingStream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_501, 1);
-        countingStream->write((uint64_t*)&cgen_var_501, 1 * 8);
+        uint64_t cgen_var_505;
+        countingStream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_505, 1);
+        countingStream->write((uint64_t*)&cgen_var_505, 1 * 8);
         countingStream->write((VkPipelineBindPoint*)&local_pipelineBindPoint, sizeof(VkPipelineBindPoint));
-        uint64_t cgen_var_502;
-        countingStream->handleMapping()->mapHandles_VkPipeline_u64(&local_pipeline, &cgen_var_502, 1);
-        countingStream->write((uint64_t*)&cgen_var_502, 1 * 8);
+        uint64_t cgen_var_506;
+        countingStream->handleMapping()->mapHandles_VkPipeline_u64(&local_pipeline, &cgen_var_506, 1);
+        countingStream->write((uint64_t*)&cgen_var_506, 1 * 8);
     }
     uint32_t packetSize_vkCmdBindPipeline = 4 + 4 + (uint32_t)countingStream->bytesWritten();
     countingStream->rewind();
     uint32_t opcode_vkCmdBindPipeline = OP_vkCmdBindPipeline;
     stream->write(&opcode_vkCmdBindPipeline, sizeof(uint32_t));
     stream->write(&packetSize_vkCmdBindPipeline, sizeof(uint32_t));
-    uint64_t cgen_var_503;
-    stream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_503, 1);
-    stream->write((uint64_t*)&cgen_var_503, 1 * 8);
+    uint64_t cgen_var_507;
+    stream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_507, 1);
+    stream->write((uint64_t*)&cgen_var_507, 1 * 8);
     stream->write((VkPipelineBindPoint*)&local_pipelineBindPoint, sizeof(VkPipelineBindPoint));
-    uint64_t cgen_var_504;
-    stream->handleMapping()->mapHandles_VkPipeline_u64(&local_pipeline, &cgen_var_504, 1);
-    stream->write((uint64_t*)&cgen_var_504, 1 * 8);
+    uint64_t cgen_var_508;
+    stream->handleMapping()->mapHandles_VkPipeline_u64(&local_pipeline, &cgen_var_508, 1);
+    stream->write((uint64_t*)&cgen_var_508, 1 * 8);
     AEMU_SCOPED_TRACE("vkCmdBindPipeline readParams");
     AEMU_SCOPED_TRACE("vkCmdBindPipeline returnUnmarshal");
     mImpl->log("finish vkCmdBindPipeline");;
@@ -6925,6 +7126,7 @@
     uint32_t viewportCount,
     const VkViewport* pViewports)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkCmdSetViewport encode");
     mImpl->log("start vkCmdSetViewport");
     auto stream = mImpl->stream();
@@ -6957,9 +7159,9 @@
     }
     countingStream->rewind();
     {
-        uint64_t cgen_var_505;
-        countingStream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_505, 1);
-        countingStream->write((uint64_t*)&cgen_var_505, 1 * 8);
+        uint64_t cgen_var_509;
+        countingStream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_509, 1);
+        countingStream->write((uint64_t*)&cgen_var_509, 1 * 8);
         countingStream->write((uint32_t*)&local_firstViewport, sizeof(uint32_t));
         countingStream->write((uint32_t*)&local_viewportCount, sizeof(uint32_t));
         for (uint32_t i = 0; i < (uint32_t)((viewportCount)); ++i)
@@ -6972,9 +7174,9 @@
     uint32_t opcode_vkCmdSetViewport = OP_vkCmdSetViewport;
     stream->write(&opcode_vkCmdSetViewport, sizeof(uint32_t));
     stream->write(&packetSize_vkCmdSetViewport, sizeof(uint32_t));
-    uint64_t cgen_var_506;
-    stream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_506, 1);
-    stream->write((uint64_t*)&cgen_var_506, 1 * 8);
+    uint64_t cgen_var_510;
+    stream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_510, 1);
+    stream->write((uint64_t*)&cgen_var_510, 1 * 8);
     stream->write((uint32_t*)&local_firstViewport, sizeof(uint32_t));
     stream->write((uint32_t*)&local_viewportCount, sizeof(uint32_t));
     for (uint32_t i = 0; i < (uint32_t)((viewportCount)); ++i)
@@ -6992,6 +7194,7 @@
     uint32_t scissorCount,
     const VkRect2D* pScissors)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkCmdSetScissor encode");
     mImpl->log("start vkCmdSetScissor");
     auto stream = mImpl->stream();
@@ -7024,9 +7227,9 @@
     }
     countingStream->rewind();
     {
-        uint64_t cgen_var_507;
-        countingStream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_507, 1);
-        countingStream->write((uint64_t*)&cgen_var_507, 1 * 8);
+        uint64_t cgen_var_511;
+        countingStream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_511, 1);
+        countingStream->write((uint64_t*)&cgen_var_511, 1 * 8);
         countingStream->write((uint32_t*)&local_firstScissor, sizeof(uint32_t));
         countingStream->write((uint32_t*)&local_scissorCount, sizeof(uint32_t));
         for (uint32_t i = 0; i < (uint32_t)((scissorCount)); ++i)
@@ -7039,9 +7242,9 @@
     uint32_t opcode_vkCmdSetScissor = OP_vkCmdSetScissor;
     stream->write(&opcode_vkCmdSetScissor, sizeof(uint32_t));
     stream->write(&packetSize_vkCmdSetScissor, sizeof(uint32_t));
-    uint64_t cgen_var_508;
-    stream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_508, 1);
-    stream->write((uint64_t*)&cgen_var_508, 1 * 8);
+    uint64_t cgen_var_512;
+    stream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_512, 1);
+    stream->write((uint64_t*)&cgen_var_512, 1 * 8);
     stream->write((uint32_t*)&local_firstScissor, sizeof(uint32_t));
     stream->write((uint32_t*)&local_scissorCount, sizeof(uint32_t));
     for (uint32_t i = 0; i < (uint32_t)((scissorCount)); ++i)
@@ -7057,6 +7260,7 @@
     VkCommandBuffer commandBuffer,
     float lineWidth)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkCmdSetLineWidth encode");
     mImpl->log("start vkCmdSetLineWidth");
     auto stream = mImpl->stream();
@@ -7070,9 +7274,9 @@
     local_lineWidth = lineWidth;
     countingStream->rewind();
     {
-        uint64_t cgen_var_509;
-        countingStream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_509, 1);
-        countingStream->write((uint64_t*)&cgen_var_509, 1 * 8);
+        uint64_t cgen_var_513;
+        countingStream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_513, 1);
+        countingStream->write((uint64_t*)&cgen_var_513, 1 * 8);
         countingStream->write((float*)&local_lineWidth, sizeof(float));
     }
     uint32_t packetSize_vkCmdSetLineWidth = 4 + 4 + (uint32_t)countingStream->bytesWritten();
@@ -7080,9 +7284,9 @@
     uint32_t opcode_vkCmdSetLineWidth = OP_vkCmdSetLineWidth;
     stream->write(&opcode_vkCmdSetLineWidth, sizeof(uint32_t));
     stream->write(&packetSize_vkCmdSetLineWidth, sizeof(uint32_t));
-    uint64_t cgen_var_510;
-    stream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_510, 1);
-    stream->write((uint64_t*)&cgen_var_510, 1 * 8);
+    uint64_t cgen_var_514;
+    stream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_514, 1);
+    stream->write((uint64_t*)&cgen_var_514, 1 * 8);
     stream->write((float*)&local_lineWidth, sizeof(float));
     AEMU_SCOPED_TRACE("vkCmdSetLineWidth readParams");
     AEMU_SCOPED_TRACE("vkCmdSetLineWidth returnUnmarshal");
@@ -7095,6 +7299,7 @@
     float depthBiasClamp,
     float depthBiasSlopeFactor)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkCmdSetDepthBias encode");
     mImpl->log("start vkCmdSetDepthBias");
     auto stream = mImpl->stream();
@@ -7112,9 +7317,9 @@
     local_depthBiasSlopeFactor = depthBiasSlopeFactor;
     countingStream->rewind();
     {
-        uint64_t cgen_var_511;
-        countingStream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_511, 1);
-        countingStream->write((uint64_t*)&cgen_var_511, 1 * 8);
+        uint64_t cgen_var_515;
+        countingStream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_515, 1);
+        countingStream->write((uint64_t*)&cgen_var_515, 1 * 8);
         countingStream->write((float*)&local_depthBiasConstantFactor, sizeof(float));
         countingStream->write((float*)&local_depthBiasClamp, sizeof(float));
         countingStream->write((float*)&local_depthBiasSlopeFactor, sizeof(float));
@@ -7124,9 +7329,9 @@
     uint32_t opcode_vkCmdSetDepthBias = OP_vkCmdSetDepthBias;
     stream->write(&opcode_vkCmdSetDepthBias, sizeof(uint32_t));
     stream->write(&packetSize_vkCmdSetDepthBias, sizeof(uint32_t));
-    uint64_t cgen_var_512;
-    stream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_512, 1);
-    stream->write((uint64_t*)&cgen_var_512, 1 * 8);
+    uint64_t cgen_var_516;
+    stream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_516, 1);
+    stream->write((uint64_t*)&cgen_var_516, 1 * 8);
     stream->write((float*)&local_depthBiasConstantFactor, sizeof(float));
     stream->write((float*)&local_depthBiasClamp, sizeof(float));
     stream->write((float*)&local_depthBiasSlopeFactor, sizeof(float));
@@ -7139,6 +7344,7 @@
     VkCommandBuffer commandBuffer,
     const float blendConstants[4])
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkCmdSetBlendConstants encode");
     mImpl->log("start vkCmdSetBlendConstants");
     auto stream = mImpl->stream();
@@ -7149,23 +7355,23 @@
     VkCommandBuffer local_commandBuffer;
     float local_blendConstants[4];
     local_commandBuffer = commandBuffer;
-    memcpy(&local_blendConstants, &blendConstants, 4 * sizeof(const float));
+    memcpy(local_blendConstants, blendConstants, 4 * sizeof(const float));
     countingStream->rewind();
     {
-        uint64_t cgen_var_513;
-        countingStream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_513, 1);
-        countingStream->write((uint64_t*)&cgen_var_513, 1 * 8);
-        countingStream->write((float*)&local_blendConstants, 4 * sizeof(float));
+        uint64_t cgen_var_517;
+        countingStream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_517, 1);
+        countingStream->write((uint64_t*)&cgen_var_517, 1 * 8);
+        countingStream->write((float*)local_blendConstants, 4 * sizeof(float));
     }
     uint32_t packetSize_vkCmdSetBlendConstants = 4 + 4 + (uint32_t)countingStream->bytesWritten();
     countingStream->rewind();
     uint32_t opcode_vkCmdSetBlendConstants = OP_vkCmdSetBlendConstants;
     stream->write(&opcode_vkCmdSetBlendConstants, sizeof(uint32_t));
     stream->write(&packetSize_vkCmdSetBlendConstants, sizeof(uint32_t));
-    uint64_t cgen_var_514;
-    stream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_514, 1);
-    stream->write((uint64_t*)&cgen_var_514, 1 * 8);
-    stream->write((float*)&local_blendConstants, 4 * sizeof(float));
+    uint64_t cgen_var_518;
+    stream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_518, 1);
+    stream->write((uint64_t*)&cgen_var_518, 1 * 8);
+    stream->write((float*)local_blendConstants, 4 * sizeof(float));
     AEMU_SCOPED_TRACE("vkCmdSetBlendConstants readParams");
     AEMU_SCOPED_TRACE("vkCmdSetBlendConstants returnUnmarshal");
     mImpl->log("finish vkCmdSetBlendConstants");;
@@ -7176,6 +7382,7 @@
     float minDepthBounds,
     float maxDepthBounds)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkCmdSetDepthBounds encode");
     mImpl->log("start vkCmdSetDepthBounds");
     auto stream = mImpl->stream();
@@ -7191,9 +7398,9 @@
     local_maxDepthBounds = maxDepthBounds;
     countingStream->rewind();
     {
-        uint64_t cgen_var_515;
-        countingStream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_515, 1);
-        countingStream->write((uint64_t*)&cgen_var_515, 1 * 8);
+        uint64_t cgen_var_519;
+        countingStream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_519, 1);
+        countingStream->write((uint64_t*)&cgen_var_519, 1 * 8);
         countingStream->write((float*)&local_minDepthBounds, sizeof(float));
         countingStream->write((float*)&local_maxDepthBounds, sizeof(float));
     }
@@ -7202,9 +7409,9 @@
     uint32_t opcode_vkCmdSetDepthBounds = OP_vkCmdSetDepthBounds;
     stream->write(&opcode_vkCmdSetDepthBounds, sizeof(uint32_t));
     stream->write(&packetSize_vkCmdSetDepthBounds, sizeof(uint32_t));
-    uint64_t cgen_var_516;
-    stream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_516, 1);
-    stream->write((uint64_t*)&cgen_var_516, 1 * 8);
+    uint64_t cgen_var_520;
+    stream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_520, 1);
+    stream->write((uint64_t*)&cgen_var_520, 1 * 8);
     stream->write((float*)&local_minDepthBounds, sizeof(float));
     stream->write((float*)&local_maxDepthBounds, sizeof(float));
     AEMU_SCOPED_TRACE("vkCmdSetDepthBounds readParams");
@@ -7217,6 +7424,7 @@
     VkStencilFaceFlags faceMask,
     uint32_t compareMask)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkCmdSetStencilCompareMask encode");
     mImpl->log("start vkCmdSetStencilCompareMask");
     auto stream = mImpl->stream();
@@ -7232,9 +7440,9 @@
     local_compareMask = compareMask;
     countingStream->rewind();
     {
-        uint64_t cgen_var_517;
-        countingStream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_517, 1);
-        countingStream->write((uint64_t*)&cgen_var_517, 1 * 8);
+        uint64_t cgen_var_521;
+        countingStream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_521, 1);
+        countingStream->write((uint64_t*)&cgen_var_521, 1 * 8);
         countingStream->write((VkStencilFaceFlags*)&local_faceMask, sizeof(VkStencilFaceFlags));
         countingStream->write((uint32_t*)&local_compareMask, sizeof(uint32_t));
     }
@@ -7243,9 +7451,9 @@
     uint32_t opcode_vkCmdSetStencilCompareMask = OP_vkCmdSetStencilCompareMask;
     stream->write(&opcode_vkCmdSetStencilCompareMask, sizeof(uint32_t));
     stream->write(&packetSize_vkCmdSetStencilCompareMask, sizeof(uint32_t));
-    uint64_t cgen_var_518;
-    stream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_518, 1);
-    stream->write((uint64_t*)&cgen_var_518, 1 * 8);
+    uint64_t cgen_var_522;
+    stream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_522, 1);
+    stream->write((uint64_t*)&cgen_var_522, 1 * 8);
     stream->write((VkStencilFaceFlags*)&local_faceMask, sizeof(VkStencilFaceFlags));
     stream->write((uint32_t*)&local_compareMask, sizeof(uint32_t));
     AEMU_SCOPED_TRACE("vkCmdSetStencilCompareMask readParams");
@@ -7258,6 +7466,7 @@
     VkStencilFaceFlags faceMask,
     uint32_t writeMask)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkCmdSetStencilWriteMask encode");
     mImpl->log("start vkCmdSetStencilWriteMask");
     auto stream = mImpl->stream();
@@ -7273,9 +7482,9 @@
     local_writeMask = writeMask;
     countingStream->rewind();
     {
-        uint64_t cgen_var_519;
-        countingStream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_519, 1);
-        countingStream->write((uint64_t*)&cgen_var_519, 1 * 8);
+        uint64_t cgen_var_523;
+        countingStream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_523, 1);
+        countingStream->write((uint64_t*)&cgen_var_523, 1 * 8);
         countingStream->write((VkStencilFaceFlags*)&local_faceMask, sizeof(VkStencilFaceFlags));
         countingStream->write((uint32_t*)&local_writeMask, sizeof(uint32_t));
     }
@@ -7284,9 +7493,9 @@
     uint32_t opcode_vkCmdSetStencilWriteMask = OP_vkCmdSetStencilWriteMask;
     stream->write(&opcode_vkCmdSetStencilWriteMask, sizeof(uint32_t));
     stream->write(&packetSize_vkCmdSetStencilWriteMask, sizeof(uint32_t));
-    uint64_t cgen_var_520;
-    stream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_520, 1);
-    stream->write((uint64_t*)&cgen_var_520, 1 * 8);
+    uint64_t cgen_var_524;
+    stream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_524, 1);
+    stream->write((uint64_t*)&cgen_var_524, 1 * 8);
     stream->write((VkStencilFaceFlags*)&local_faceMask, sizeof(VkStencilFaceFlags));
     stream->write((uint32_t*)&local_writeMask, sizeof(uint32_t));
     AEMU_SCOPED_TRACE("vkCmdSetStencilWriteMask readParams");
@@ -7299,6 +7508,7 @@
     VkStencilFaceFlags faceMask,
     uint32_t reference)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkCmdSetStencilReference encode");
     mImpl->log("start vkCmdSetStencilReference");
     auto stream = mImpl->stream();
@@ -7314,9 +7524,9 @@
     local_reference = reference;
     countingStream->rewind();
     {
-        uint64_t cgen_var_521;
-        countingStream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_521, 1);
-        countingStream->write((uint64_t*)&cgen_var_521, 1 * 8);
+        uint64_t cgen_var_525;
+        countingStream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_525, 1);
+        countingStream->write((uint64_t*)&cgen_var_525, 1 * 8);
         countingStream->write((VkStencilFaceFlags*)&local_faceMask, sizeof(VkStencilFaceFlags));
         countingStream->write((uint32_t*)&local_reference, sizeof(uint32_t));
     }
@@ -7325,9 +7535,9 @@
     uint32_t opcode_vkCmdSetStencilReference = OP_vkCmdSetStencilReference;
     stream->write(&opcode_vkCmdSetStencilReference, sizeof(uint32_t));
     stream->write(&packetSize_vkCmdSetStencilReference, sizeof(uint32_t));
-    uint64_t cgen_var_522;
-    stream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_522, 1);
-    stream->write((uint64_t*)&cgen_var_522, 1 * 8);
+    uint64_t cgen_var_526;
+    stream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_526, 1);
+    stream->write((uint64_t*)&cgen_var_526, 1 * 8);
     stream->write((VkStencilFaceFlags*)&local_faceMask, sizeof(VkStencilFaceFlags));
     stream->write((uint32_t*)&local_reference, sizeof(uint32_t));
     AEMU_SCOPED_TRACE("vkCmdSetStencilReference readParams");
@@ -7345,6 +7555,7 @@
     uint32_t dynamicOffsetCount,
     const uint32_t* pDynamicOffsets)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkCmdBindDescriptorSets encode");
     mImpl->log("start vkCmdBindDescriptorSets");
     auto stream = mImpl->stream();
@@ -7378,21 +7589,21 @@
     }
     countingStream->rewind();
     {
-        uint64_t cgen_var_523;
-        countingStream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_523, 1);
-        countingStream->write((uint64_t*)&cgen_var_523, 1 * 8);
+        uint64_t cgen_var_527;
+        countingStream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_527, 1);
+        countingStream->write((uint64_t*)&cgen_var_527, 1 * 8);
         countingStream->write((VkPipelineBindPoint*)&local_pipelineBindPoint, sizeof(VkPipelineBindPoint));
-        uint64_t cgen_var_524;
-        countingStream->handleMapping()->mapHandles_VkPipelineLayout_u64(&local_layout, &cgen_var_524, 1);
-        countingStream->write((uint64_t*)&cgen_var_524, 1 * 8);
+        uint64_t cgen_var_528;
+        countingStream->handleMapping()->mapHandles_VkPipelineLayout_u64(&local_layout, &cgen_var_528, 1);
+        countingStream->write((uint64_t*)&cgen_var_528, 1 * 8);
         countingStream->write((uint32_t*)&local_firstSet, sizeof(uint32_t));
         countingStream->write((uint32_t*)&local_descriptorSetCount, sizeof(uint32_t));
         if (((descriptorSetCount)))
         {
-            uint64_t* cgen_var_525;
-            countingStream->alloc((void**)&cgen_var_525, ((descriptorSetCount)) * 8);
-            countingStream->handleMapping()->mapHandles_VkDescriptorSet_u64(local_pDescriptorSets, cgen_var_525, ((descriptorSetCount)));
-            countingStream->write((uint64_t*)cgen_var_525, ((descriptorSetCount)) * 8);
+            uint64_t* cgen_var_529;
+            countingStream->alloc((void**)&cgen_var_529, ((descriptorSetCount)) * 8);
+            countingStream->handleMapping()->mapHandles_VkDescriptorSet_u64(local_pDescriptorSets, cgen_var_529, ((descriptorSetCount)));
+            countingStream->write((uint64_t*)cgen_var_529, ((descriptorSetCount)) * 8);
         }
         countingStream->write((uint32_t*)&local_dynamicOffsetCount, sizeof(uint32_t));
         countingStream->write((uint32_t*)local_pDynamicOffsets, ((dynamicOffsetCount)) * sizeof(uint32_t));
@@ -7402,21 +7613,21 @@
     uint32_t opcode_vkCmdBindDescriptorSets = OP_vkCmdBindDescriptorSets;
     stream->write(&opcode_vkCmdBindDescriptorSets, sizeof(uint32_t));
     stream->write(&packetSize_vkCmdBindDescriptorSets, sizeof(uint32_t));
-    uint64_t cgen_var_526;
-    stream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_526, 1);
-    stream->write((uint64_t*)&cgen_var_526, 1 * 8);
+    uint64_t cgen_var_530;
+    stream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_530, 1);
+    stream->write((uint64_t*)&cgen_var_530, 1 * 8);
     stream->write((VkPipelineBindPoint*)&local_pipelineBindPoint, sizeof(VkPipelineBindPoint));
-    uint64_t cgen_var_527;
-    stream->handleMapping()->mapHandles_VkPipelineLayout_u64(&local_layout, &cgen_var_527, 1);
-    stream->write((uint64_t*)&cgen_var_527, 1 * 8);
+    uint64_t cgen_var_531;
+    stream->handleMapping()->mapHandles_VkPipelineLayout_u64(&local_layout, &cgen_var_531, 1);
+    stream->write((uint64_t*)&cgen_var_531, 1 * 8);
     stream->write((uint32_t*)&local_firstSet, sizeof(uint32_t));
     stream->write((uint32_t*)&local_descriptorSetCount, sizeof(uint32_t));
     if (((descriptorSetCount)))
     {
-        uint64_t* cgen_var_528;
-        stream->alloc((void**)&cgen_var_528, ((descriptorSetCount)) * 8);
-        stream->handleMapping()->mapHandles_VkDescriptorSet_u64(local_pDescriptorSets, cgen_var_528, ((descriptorSetCount)));
-        stream->write((uint64_t*)cgen_var_528, ((descriptorSetCount)) * 8);
+        uint64_t* cgen_var_532;
+        stream->alloc((void**)&cgen_var_532, ((descriptorSetCount)) * 8);
+        stream->handleMapping()->mapHandles_VkDescriptorSet_u64(local_pDescriptorSets, cgen_var_532, ((descriptorSetCount)));
+        stream->write((uint64_t*)cgen_var_532, ((descriptorSetCount)) * 8);
     }
     stream->write((uint32_t*)&local_dynamicOffsetCount, sizeof(uint32_t));
     stream->write((uint32_t*)local_pDynamicOffsets, ((dynamicOffsetCount)) * sizeof(uint32_t));
@@ -7431,6 +7642,7 @@
     VkDeviceSize offset,
     VkIndexType indexType)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkCmdBindIndexBuffer encode");
     mImpl->log("start vkCmdBindIndexBuffer");
     auto stream = mImpl->stream();
@@ -7448,12 +7660,12 @@
     local_indexType = indexType;
     countingStream->rewind();
     {
-        uint64_t cgen_var_529;
-        countingStream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_529, 1);
-        countingStream->write((uint64_t*)&cgen_var_529, 1 * 8);
-        uint64_t cgen_var_530;
-        countingStream->handleMapping()->mapHandles_VkBuffer_u64(&local_buffer, &cgen_var_530, 1);
-        countingStream->write((uint64_t*)&cgen_var_530, 1 * 8);
+        uint64_t cgen_var_533;
+        countingStream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_533, 1);
+        countingStream->write((uint64_t*)&cgen_var_533, 1 * 8);
+        uint64_t cgen_var_534;
+        countingStream->handleMapping()->mapHandles_VkBuffer_u64(&local_buffer, &cgen_var_534, 1);
+        countingStream->write((uint64_t*)&cgen_var_534, 1 * 8);
         countingStream->write((VkDeviceSize*)&local_offset, sizeof(VkDeviceSize));
         countingStream->write((VkIndexType*)&local_indexType, sizeof(VkIndexType));
     }
@@ -7462,12 +7674,12 @@
     uint32_t opcode_vkCmdBindIndexBuffer = OP_vkCmdBindIndexBuffer;
     stream->write(&opcode_vkCmdBindIndexBuffer, sizeof(uint32_t));
     stream->write(&packetSize_vkCmdBindIndexBuffer, sizeof(uint32_t));
-    uint64_t cgen_var_531;
-    stream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_531, 1);
-    stream->write((uint64_t*)&cgen_var_531, 1 * 8);
-    uint64_t cgen_var_532;
-    stream->handleMapping()->mapHandles_VkBuffer_u64(&local_buffer, &cgen_var_532, 1);
-    stream->write((uint64_t*)&cgen_var_532, 1 * 8);
+    uint64_t cgen_var_535;
+    stream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_535, 1);
+    stream->write((uint64_t*)&cgen_var_535, 1 * 8);
+    uint64_t cgen_var_536;
+    stream->handleMapping()->mapHandles_VkBuffer_u64(&local_buffer, &cgen_var_536, 1);
+    stream->write((uint64_t*)&cgen_var_536, 1 * 8);
     stream->write((VkDeviceSize*)&local_offset, sizeof(VkDeviceSize));
     stream->write((VkIndexType*)&local_indexType, sizeof(VkIndexType));
     AEMU_SCOPED_TRACE("vkCmdBindIndexBuffer readParams");
@@ -7482,6 +7694,7 @@
     const VkBuffer* pBuffers,
     const VkDeviceSize* pOffsets)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkCmdBindVertexBuffers encode");
     mImpl->log("start vkCmdBindVertexBuffers");
     auto stream = mImpl->stream();
@@ -7509,17 +7722,17 @@
     }
     countingStream->rewind();
     {
-        uint64_t cgen_var_533;
-        countingStream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_533, 1);
-        countingStream->write((uint64_t*)&cgen_var_533, 1 * 8);
+        uint64_t cgen_var_537;
+        countingStream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_537, 1);
+        countingStream->write((uint64_t*)&cgen_var_537, 1 * 8);
         countingStream->write((uint32_t*)&local_firstBinding, sizeof(uint32_t));
         countingStream->write((uint32_t*)&local_bindingCount, sizeof(uint32_t));
         if (((bindingCount)))
         {
-            uint64_t* cgen_var_534;
-            countingStream->alloc((void**)&cgen_var_534, ((bindingCount)) * 8);
-            countingStream->handleMapping()->mapHandles_VkBuffer_u64(local_pBuffers, cgen_var_534, ((bindingCount)));
-            countingStream->write((uint64_t*)cgen_var_534, ((bindingCount)) * 8);
+            uint64_t* cgen_var_538;
+            countingStream->alloc((void**)&cgen_var_538, ((bindingCount)) * 8);
+            countingStream->handleMapping()->mapHandles_VkBuffer_u64(local_pBuffers, cgen_var_538, ((bindingCount)));
+            countingStream->write((uint64_t*)cgen_var_538, ((bindingCount)) * 8);
         }
         countingStream->write((VkDeviceSize*)local_pOffsets, ((bindingCount)) * sizeof(VkDeviceSize));
     }
@@ -7528,17 +7741,17 @@
     uint32_t opcode_vkCmdBindVertexBuffers = OP_vkCmdBindVertexBuffers;
     stream->write(&opcode_vkCmdBindVertexBuffers, sizeof(uint32_t));
     stream->write(&packetSize_vkCmdBindVertexBuffers, sizeof(uint32_t));
-    uint64_t cgen_var_535;
-    stream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_535, 1);
-    stream->write((uint64_t*)&cgen_var_535, 1 * 8);
+    uint64_t cgen_var_539;
+    stream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_539, 1);
+    stream->write((uint64_t*)&cgen_var_539, 1 * 8);
     stream->write((uint32_t*)&local_firstBinding, sizeof(uint32_t));
     stream->write((uint32_t*)&local_bindingCount, sizeof(uint32_t));
     if (((bindingCount)))
     {
-        uint64_t* cgen_var_536;
-        stream->alloc((void**)&cgen_var_536, ((bindingCount)) * 8);
-        stream->handleMapping()->mapHandles_VkBuffer_u64(local_pBuffers, cgen_var_536, ((bindingCount)));
-        stream->write((uint64_t*)cgen_var_536, ((bindingCount)) * 8);
+        uint64_t* cgen_var_540;
+        stream->alloc((void**)&cgen_var_540, ((bindingCount)) * 8);
+        stream->handleMapping()->mapHandles_VkBuffer_u64(local_pBuffers, cgen_var_540, ((bindingCount)));
+        stream->write((uint64_t*)cgen_var_540, ((bindingCount)) * 8);
     }
     stream->write((VkDeviceSize*)local_pOffsets, ((bindingCount)) * sizeof(VkDeviceSize));
     AEMU_SCOPED_TRACE("vkCmdBindVertexBuffers readParams");
@@ -7553,6 +7766,7 @@
     uint32_t firstVertex,
     uint32_t firstInstance)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkCmdDraw encode");
     mImpl->log("start vkCmdDraw");
     auto stream = mImpl->stream();
@@ -7572,9 +7786,9 @@
     local_firstInstance = firstInstance;
     countingStream->rewind();
     {
-        uint64_t cgen_var_537;
-        countingStream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_537, 1);
-        countingStream->write((uint64_t*)&cgen_var_537, 1 * 8);
+        uint64_t cgen_var_541;
+        countingStream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_541, 1);
+        countingStream->write((uint64_t*)&cgen_var_541, 1 * 8);
         countingStream->write((uint32_t*)&local_vertexCount, sizeof(uint32_t));
         countingStream->write((uint32_t*)&local_instanceCount, sizeof(uint32_t));
         countingStream->write((uint32_t*)&local_firstVertex, sizeof(uint32_t));
@@ -7585,9 +7799,9 @@
     uint32_t opcode_vkCmdDraw = OP_vkCmdDraw;
     stream->write(&opcode_vkCmdDraw, sizeof(uint32_t));
     stream->write(&packetSize_vkCmdDraw, sizeof(uint32_t));
-    uint64_t cgen_var_538;
-    stream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_538, 1);
-    stream->write((uint64_t*)&cgen_var_538, 1 * 8);
+    uint64_t cgen_var_542;
+    stream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_542, 1);
+    stream->write((uint64_t*)&cgen_var_542, 1 * 8);
     stream->write((uint32_t*)&local_vertexCount, sizeof(uint32_t));
     stream->write((uint32_t*)&local_instanceCount, sizeof(uint32_t));
     stream->write((uint32_t*)&local_firstVertex, sizeof(uint32_t));
@@ -7605,6 +7819,7 @@
     int32_t vertexOffset,
     uint32_t firstInstance)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkCmdDrawIndexed encode");
     mImpl->log("start vkCmdDrawIndexed");
     auto stream = mImpl->stream();
@@ -7626,9 +7841,9 @@
     local_firstInstance = firstInstance;
     countingStream->rewind();
     {
-        uint64_t cgen_var_539;
-        countingStream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_539, 1);
-        countingStream->write((uint64_t*)&cgen_var_539, 1 * 8);
+        uint64_t cgen_var_543;
+        countingStream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_543, 1);
+        countingStream->write((uint64_t*)&cgen_var_543, 1 * 8);
         countingStream->write((uint32_t*)&local_indexCount, sizeof(uint32_t));
         countingStream->write((uint32_t*)&local_instanceCount, sizeof(uint32_t));
         countingStream->write((uint32_t*)&local_firstIndex, sizeof(uint32_t));
@@ -7640,9 +7855,9 @@
     uint32_t opcode_vkCmdDrawIndexed = OP_vkCmdDrawIndexed;
     stream->write(&opcode_vkCmdDrawIndexed, sizeof(uint32_t));
     stream->write(&packetSize_vkCmdDrawIndexed, sizeof(uint32_t));
-    uint64_t cgen_var_540;
-    stream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_540, 1);
-    stream->write((uint64_t*)&cgen_var_540, 1 * 8);
+    uint64_t cgen_var_544;
+    stream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_544, 1);
+    stream->write((uint64_t*)&cgen_var_544, 1 * 8);
     stream->write((uint32_t*)&local_indexCount, sizeof(uint32_t));
     stream->write((uint32_t*)&local_instanceCount, sizeof(uint32_t));
     stream->write((uint32_t*)&local_firstIndex, sizeof(uint32_t));
@@ -7660,6 +7875,7 @@
     uint32_t drawCount,
     uint32_t stride)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkCmdDrawIndirect encode");
     mImpl->log("start vkCmdDrawIndirect");
     auto stream = mImpl->stream();
@@ -7679,61 +7895,6 @@
     local_stride = stride;
     countingStream->rewind();
     {
-        uint64_t cgen_var_541;
-        countingStream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_541, 1);
-        countingStream->write((uint64_t*)&cgen_var_541, 1 * 8);
-        uint64_t cgen_var_542;
-        countingStream->handleMapping()->mapHandles_VkBuffer_u64(&local_buffer, &cgen_var_542, 1);
-        countingStream->write((uint64_t*)&cgen_var_542, 1 * 8);
-        countingStream->write((VkDeviceSize*)&local_offset, sizeof(VkDeviceSize));
-        countingStream->write((uint32_t*)&local_drawCount, sizeof(uint32_t));
-        countingStream->write((uint32_t*)&local_stride, sizeof(uint32_t));
-    }
-    uint32_t packetSize_vkCmdDrawIndirect = 4 + 4 + (uint32_t)countingStream->bytesWritten();
-    countingStream->rewind();
-    uint32_t opcode_vkCmdDrawIndirect = OP_vkCmdDrawIndirect;
-    stream->write(&opcode_vkCmdDrawIndirect, sizeof(uint32_t));
-    stream->write(&packetSize_vkCmdDrawIndirect, sizeof(uint32_t));
-    uint64_t cgen_var_543;
-    stream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_543, 1);
-    stream->write((uint64_t*)&cgen_var_543, 1 * 8);
-    uint64_t cgen_var_544;
-    stream->handleMapping()->mapHandles_VkBuffer_u64(&local_buffer, &cgen_var_544, 1);
-    stream->write((uint64_t*)&cgen_var_544, 1 * 8);
-    stream->write((VkDeviceSize*)&local_offset, sizeof(VkDeviceSize));
-    stream->write((uint32_t*)&local_drawCount, sizeof(uint32_t));
-    stream->write((uint32_t*)&local_stride, sizeof(uint32_t));
-    AEMU_SCOPED_TRACE("vkCmdDrawIndirect readParams");
-    AEMU_SCOPED_TRACE("vkCmdDrawIndirect returnUnmarshal");
-    mImpl->log("finish vkCmdDrawIndirect");;
-}
-
-void VkEncoder::vkCmdDrawIndexedIndirect(
-    VkCommandBuffer commandBuffer,
-    VkBuffer buffer,
-    VkDeviceSize offset,
-    uint32_t drawCount,
-    uint32_t stride)
-{
-    AEMU_SCOPED_TRACE("vkCmdDrawIndexedIndirect encode");
-    mImpl->log("start vkCmdDrawIndexedIndirect");
-    auto stream = mImpl->stream();
-    auto countingStream = mImpl->countingStream();
-    auto resources = mImpl->resources();
-    auto pool = mImpl->pool();
-    stream->setHandleMapping(resources->unwrapMapping());
-    VkCommandBuffer local_commandBuffer;
-    VkBuffer local_buffer;
-    VkDeviceSize local_offset;
-    uint32_t local_drawCount;
-    uint32_t local_stride;
-    local_commandBuffer = commandBuffer;
-    local_buffer = buffer;
-    local_offset = offset;
-    local_drawCount = drawCount;
-    local_stride = stride;
-    countingStream->rewind();
-    {
         uint64_t cgen_var_545;
         countingStream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_545, 1);
         countingStream->write((uint64_t*)&cgen_var_545, 1 * 8);
@@ -7744,11 +7905,11 @@
         countingStream->write((uint32_t*)&local_drawCount, sizeof(uint32_t));
         countingStream->write((uint32_t*)&local_stride, sizeof(uint32_t));
     }
-    uint32_t packetSize_vkCmdDrawIndexedIndirect = 4 + 4 + (uint32_t)countingStream->bytesWritten();
+    uint32_t packetSize_vkCmdDrawIndirect = 4 + 4 + (uint32_t)countingStream->bytesWritten();
     countingStream->rewind();
-    uint32_t opcode_vkCmdDrawIndexedIndirect = OP_vkCmdDrawIndexedIndirect;
-    stream->write(&opcode_vkCmdDrawIndexedIndirect, sizeof(uint32_t));
-    stream->write(&packetSize_vkCmdDrawIndexedIndirect, sizeof(uint32_t));
+    uint32_t opcode_vkCmdDrawIndirect = OP_vkCmdDrawIndirect;
+    stream->write(&opcode_vkCmdDrawIndirect, sizeof(uint32_t));
+    stream->write(&packetSize_vkCmdDrawIndirect, sizeof(uint32_t));
     uint64_t cgen_var_547;
     stream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_547, 1);
     stream->write((uint64_t*)&cgen_var_547, 1 * 8);
@@ -7758,6 +7919,62 @@
     stream->write((VkDeviceSize*)&local_offset, sizeof(VkDeviceSize));
     stream->write((uint32_t*)&local_drawCount, sizeof(uint32_t));
     stream->write((uint32_t*)&local_stride, sizeof(uint32_t));
+    AEMU_SCOPED_TRACE("vkCmdDrawIndirect readParams");
+    AEMU_SCOPED_TRACE("vkCmdDrawIndirect returnUnmarshal");
+    mImpl->log("finish vkCmdDrawIndirect");;
+}
+
+void VkEncoder::vkCmdDrawIndexedIndirect(
+    VkCommandBuffer commandBuffer,
+    VkBuffer buffer,
+    VkDeviceSize offset,
+    uint32_t drawCount,
+    uint32_t stride)
+{
+    AutoLock encoderLock(mImpl->lock);
+    AEMU_SCOPED_TRACE("vkCmdDrawIndexedIndirect encode");
+    mImpl->log("start vkCmdDrawIndexedIndirect");
+    auto stream = mImpl->stream();
+    auto countingStream = mImpl->countingStream();
+    auto resources = mImpl->resources();
+    auto pool = mImpl->pool();
+    stream->setHandleMapping(resources->unwrapMapping());
+    VkCommandBuffer local_commandBuffer;
+    VkBuffer local_buffer;
+    VkDeviceSize local_offset;
+    uint32_t local_drawCount;
+    uint32_t local_stride;
+    local_commandBuffer = commandBuffer;
+    local_buffer = buffer;
+    local_offset = offset;
+    local_drawCount = drawCount;
+    local_stride = stride;
+    countingStream->rewind();
+    {
+        uint64_t cgen_var_549;
+        countingStream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_549, 1);
+        countingStream->write((uint64_t*)&cgen_var_549, 1 * 8);
+        uint64_t cgen_var_550;
+        countingStream->handleMapping()->mapHandles_VkBuffer_u64(&local_buffer, &cgen_var_550, 1);
+        countingStream->write((uint64_t*)&cgen_var_550, 1 * 8);
+        countingStream->write((VkDeviceSize*)&local_offset, sizeof(VkDeviceSize));
+        countingStream->write((uint32_t*)&local_drawCount, sizeof(uint32_t));
+        countingStream->write((uint32_t*)&local_stride, sizeof(uint32_t));
+    }
+    uint32_t packetSize_vkCmdDrawIndexedIndirect = 4 + 4 + (uint32_t)countingStream->bytesWritten();
+    countingStream->rewind();
+    uint32_t opcode_vkCmdDrawIndexedIndirect = OP_vkCmdDrawIndexedIndirect;
+    stream->write(&opcode_vkCmdDrawIndexedIndirect, sizeof(uint32_t));
+    stream->write(&packetSize_vkCmdDrawIndexedIndirect, sizeof(uint32_t));
+    uint64_t cgen_var_551;
+    stream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_551, 1);
+    stream->write((uint64_t*)&cgen_var_551, 1 * 8);
+    uint64_t cgen_var_552;
+    stream->handleMapping()->mapHandles_VkBuffer_u64(&local_buffer, &cgen_var_552, 1);
+    stream->write((uint64_t*)&cgen_var_552, 1 * 8);
+    stream->write((VkDeviceSize*)&local_offset, sizeof(VkDeviceSize));
+    stream->write((uint32_t*)&local_drawCount, sizeof(uint32_t));
+    stream->write((uint32_t*)&local_stride, sizeof(uint32_t));
     AEMU_SCOPED_TRACE("vkCmdDrawIndexedIndirect readParams");
     AEMU_SCOPED_TRACE("vkCmdDrawIndexedIndirect returnUnmarshal");
     mImpl->log("finish vkCmdDrawIndexedIndirect");;
@@ -7769,6 +7986,7 @@
     uint32_t groupCountY,
     uint32_t groupCountZ)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkCmdDispatch encode");
     mImpl->log("start vkCmdDispatch");
     auto stream = mImpl->stream();
@@ -7786,9 +8004,9 @@
     local_groupCountZ = groupCountZ;
     countingStream->rewind();
     {
-        uint64_t cgen_var_549;
-        countingStream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_549, 1);
-        countingStream->write((uint64_t*)&cgen_var_549, 1 * 8);
+        uint64_t cgen_var_553;
+        countingStream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_553, 1);
+        countingStream->write((uint64_t*)&cgen_var_553, 1 * 8);
         countingStream->write((uint32_t*)&local_groupCountX, sizeof(uint32_t));
         countingStream->write((uint32_t*)&local_groupCountY, sizeof(uint32_t));
         countingStream->write((uint32_t*)&local_groupCountZ, sizeof(uint32_t));
@@ -7798,9 +8016,9 @@
     uint32_t opcode_vkCmdDispatch = OP_vkCmdDispatch;
     stream->write(&opcode_vkCmdDispatch, sizeof(uint32_t));
     stream->write(&packetSize_vkCmdDispatch, sizeof(uint32_t));
-    uint64_t cgen_var_550;
-    stream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_550, 1);
-    stream->write((uint64_t*)&cgen_var_550, 1 * 8);
+    uint64_t cgen_var_554;
+    stream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_554, 1);
+    stream->write((uint64_t*)&cgen_var_554, 1 * 8);
     stream->write((uint32_t*)&local_groupCountX, sizeof(uint32_t));
     stream->write((uint32_t*)&local_groupCountY, sizeof(uint32_t));
     stream->write((uint32_t*)&local_groupCountZ, sizeof(uint32_t));
@@ -7814,6 +8032,7 @@
     VkBuffer buffer,
     VkDeviceSize offset)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkCmdDispatchIndirect encode");
     mImpl->log("start vkCmdDispatchIndirect");
     auto stream = mImpl->stream();
@@ -7829,12 +8048,12 @@
     local_offset = offset;
     countingStream->rewind();
     {
-        uint64_t cgen_var_551;
-        countingStream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_551, 1);
-        countingStream->write((uint64_t*)&cgen_var_551, 1 * 8);
-        uint64_t cgen_var_552;
-        countingStream->handleMapping()->mapHandles_VkBuffer_u64(&local_buffer, &cgen_var_552, 1);
-        countingStream->write((uint64_t*)&cgen_var_552, 1 * 8);
+        uint64_t cgen_var_555;
+        countingStream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_555, 1);
+        countingStream->write((uint64_t*)&cgen_var_555, 1 * 8);
+        uint64_t cgen_var_556;
+        countingStream->handleMapping()->mapHandles_VkBuffer_u64(&local_buffer, &cgen_var_556, 1);
+        countingStream->write((uint64_t*)&cgen_var_556, 1 * 8);
         countingStream->write((VkDeviceSize*)&local_offset, sizeof(VkDeviceSize));
     }
     uint32_t packetSize_vkCmdDispatchIndirect = 4 + 4 + (uint32_t)countingStream->bytesWritten();
@@ -7842,12 +8061,12 @@
     uint32_t opcode_vkCmdDispatchIndirect = OP_vkCmdDispatchIndirect;
     stream->write(&opcode_vkCmdDispatchIndirect, sizeof(uint32_t));
     stream->write(&packetSize_vkCmdDispatchIndirect, sizeof(uint32_t));
-    uint64_t cgen_var_553;
-    stream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_553, 1);
-    stream->write((uint64_t*)&cgen_var_553, 1 * 8);
-    uint64_t cgen_var_554;
-    stream->handleMapping()->mapHandles_VkBuffer_u64(&local_buffer, &cgen_var_554, 1);
-    stream->write((uint64_t*)&cgen_var_554, 1 * 8);
+    uint64_t cgen_var_557;
+    stream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_557, 1);
+    stream->write((uint64_t*)&cgen_var_557, 1 * 8);
+    uint64_t cgen_var_558;
+    stream->handleMapping()->mapHandles_VkBuffer_u64(&local_buffer, &cgen_var_558, 1);
+    stream->write((uint64_t*)&cgen_var_558, 1 * 8);
     stream->write((VkDeviceSize*)&local_offset, sizeof(VkDeviceSize));
     AEMU_SCOPED_TRACE("vkCmdDispatchIndirect readParams");
     AEMU_SCOPED_TRACE("vkCmdDispatchIndirect returnUnmarshal");
@@ -7861,6 +8080,7 @@
     uint32_t regionCount,
     const VkBufferCopy* pRegions)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkCmdCopyBuffer encode");
     mImpl->log("start vkCmdCopyBuffer");
     auto stream = mImpl->stream();
@@ -7895,15 +8115,15 @@
     }
     countingStream->rewind();
     {
-        uint64_t cgen_var_555;
-        countingStream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_555, 1);
-        countingStream->write((uint64_t*)&cgen_var_555, 1 * 8);
-        uint64_t cgen_var_556;
-        countingStream->handleMapping()->mapHandles_VkBuffer_u64(&local_srcBuffer, &cgen_var_556, 1);
-        countingStream->write((uint64_t*)&cgen_var_556, 1 * 8);
-        uint64_t cgen_var_557;
-        countingStream->handleMapping()->mapHandles_VkBuffer_u64(&local_dstBuffer, &cgen_var_557, 1);
-        countingStream->write((uint64_t*)&cgen_var_557, 1 * 8);
+        uint64_t cgen_var_559;
+        countingStream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_559, 1);
+        countingStream->write((uint64_t*)&cgen_var_559, 1 * 8);
+        uint64_t cgen_var_560;
+        countingStream->handleMapping()->mapHandles_VkBuffer_u64(&local_srcBuffer, &cgen_var_560, 1);
+        countingStream->write((uint64_t*)&cgen_var_560, 1 * 8);
+        uint64_t cgen_var_561;
+        countingStream->handleMapping()->mapHandles_VkBuffer_u64(&local_dstBuffer, &cgen_var_561, 1);
+        countingStream->write((uint64_t*)&cgen_var_561, 1 * 8);
         countingStream->write((uint32_t*)&local_regionCount, sizeof(uint32_t));
         for (uint32_t i = 0; i < (uint32_t)((regionCount)); ++i)
         {
@@ -7915,15 +8135,15 @@
     uint32_t opcode_vkCmdCopyBuffer = OP_vkCmdCopyBuffer;
     stream->write(&opcode_vkCmdCopyBuffer, sizeof(uint32_t));
     stream->write(&packetSize_vkCmdCopyBuffer, sizeof(uint32_t));
-    uint64_t cgen_var_558;
-    stream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_558, 1);
-    stream->write((uint64_t*)&cgen_var_558, 1 * 8);
-    uint64_t cgen_var_559;
-    stream->handleMapping()->mapHandles_VkBuffer_u64(&local_srcBuffer, &cgen_var_559, 1);
-    stream->write((uint64_t*)&cgen_var_559, 1 * 8);
-    uint64_t cgen_var_560;
-    stream->handleMapping()->mapHandles_VkBuffer_u64(&local_dstBuffer, &cgen_var_560, 1);
-    stream->write((uint64_t*)&cgen_var_560, 1 * 8);
+    uint64_t cgen_var_562;
+    stream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_562, 1);
+    stream->write((uint64_t*)&cgen_var_562, 1 * 8);
+    uint64_t cgen_var_563;
+    stream->handleMapping()->mapHandles_VkBuffer_u64(&local_srcBuffer, &cgen_var_563, 1);
+    stream->write((uint64_t*)&cgen_var_563, 1 * 8);
+    uint64_t cgen_var_564;
+    stream->handleMapping()->mapHandles_VkBuffer_u64(&local_dstBuffer, &cgen_var_564, 1);
+    stream->write((uint64_t*)&cgen_var_564, 1 * 8);
     stream->write((uint32_t*)&local_regionCount, sizeof(uint32_t));
     for (uint32_t i = 0; i < (uint32_t)((regionCount)); ++i)
     {
@@ -7943,6 +8163,7 @@
     uint32_t regionCount,
     const VkImageCopy* pRegions)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkCmdCopyImage encode");
     mImpl->log("start vkCmdCopyImage");
     auto stream = mImpl->stream();
@@ -7981,16 +8202,16 @@
     }
     countingStream->rewind();
     {
-        uint64_t cgen_var_561;
-        countingStream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_561, 1);
-        countingStream->write((uint64_t*)&cgen_var_561, 1 * 8);
-        uint64_t cgen_var_562;
-        countingStream->handleMapping()->mapHandles_VkImage_u64(&local_srcImage, &cgen_var_562, 1);
-        countingStream->write((uint64_t*)&cgen_var_562, 1 * 8);
+        uint64_t cgen_var_565;
+        countingStream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_565, 1);
+        countingStream->write((uint64_t*)&cgen_var_565, 1 * 8);
+        uint64_t cgen_var_566;
+        countingStream->handleMapping()->mapHandles_VkImage_u64(&local_srcImage, &cgen_var_566, 1);
+        countingStream->write((uint64_t*)&cgen_var_566, 1 * 8);
         countingStream->write((VkImageLayout*)&local_srcImageLayout, sizeof(VkImageLayout));
-        uint64_t cgen_var_563;
-        countingStream->handleMapping()->mapHandles_VkImage_u64(&local_dstImage, &cgen_var_563, 1);
-        countingStream->write((uint64_t*)&cgen_var_563, 1 * 8);
+        uint64_t cgen_var_567;
+        countingStream->handleMapping()->mapHandles_VkImage_u64(&local_dstImage, &cgen_var_567, 1);
+        countingStream->write((uint64_t*)&cgen_var_567, 1 * 8);
         countingStream->write((VkImageLayout*)&local_dstImageLayout, sizeof(VkImageLayout));
         countingStream->write((uint32_t*)&local_regionCount, sizeof(uint32_t));
         for (uint32_t i = 0; i < (uint32_t)((regionCount)); ++i)
@@ -8003,16 +8224,16 @@
     uint32_t opcode_vkCmdCopyImage = OP_vkCmdCopyImage;
     stream->write(&opcode_vkCmdCopyImage, sizeof(uint32_t));
     stream->write(&packetSize_vkCmdCopyImage, sizeof(uint32_t));
-    uint64_t cgen_var_564;
-    stream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_564, 1);
-    stream->write((uint64_t*)&cgen_var_564, 1 * 8);
-    uint64_t cgen_var_565;
-    stream->handleMapping()->mapHandles_VkImage_u64(&local_srcImage, &cgen_var_565, 1);
-    stream->write((uint64_t*)&cgen_var_565, 1 * 8);
+    uint64_t cgen_var_568;
+    stream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_568, 1);
+    stream->write((uint64_t*)&cgen_var_568, 1 * 8);
+    uint64_t cgen_var_569;
+    stream->handleMapping()->mapHandles_VkImage_u64(&local_srcImage, &cgen_var_569, 1);
+    stream->write((uint64_t*)&cgen_var_569, 1 * 8);
     stream->write((VkImageLayout*)&local_srcImageLayout, sizeof(VkImageLayout));
-    uint64_t cgen_var_566;
-    stream->handleMapping()->mapHandles_VkImage_u64(&local_dstImage, &cgen_var_566, 1);
-    stream->write((uint64_t*)&cgen_var_566, 1 * 8);
+    uint64_t cgen_var_570;
+    stream->handleMapping()->mapHandles_VkImage_u64(&local_dstImage, &cgen_var_570, 1);
+    stream->write((uint64_t*)&cgen_var_570, 1 * 8);
     stream->write((VkImageLayout*)&local_dstImageLayout, sizeof(VkImageLayout));
     stream->write((uint32_t*)&local_regionCount, sizeof(uint32_t));
     for (uint32_t i = 0; i < (uint32_t)((regionCount)); ++i)
@@ -8034,6 +8255,7 @@
     const VkImageBlit* pRegions,
     VkFilter filter)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkCmdBlitImage encode");
     mImpl->log("start vkCmdBlitImage");
     auto stream = mImpl->stream();
@@ -8074,16 +8296,16 @@
     }
     countingStream->rewind();
     {
-        uint64_t cgen_var_567;
-        countingStream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_567, 1);
-        countingStream->write((uint64_t*)&cgen_var_567, 1 * 8);
-        uint64_t cgen_var_568;
-        countingStream->handleMapping()->mapHandles_VkImage_u64(&local_srcImage, &cgen_var_568, 1);
-        countingStream->write((uint64_t*)&cgen_var_568, 1 * 8);
+        uint64_t cgen_var_571;
+        countingStream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_571, 1);
+        countingStream->write((uint64_t*)&cgen_var_571, 1 * 8);
+        uint64_t cgen_var_572;
+        countingStream->handleMapping()->mapHandles_VkImage_u64(&local_srcImage, &cgen_var_572, 1);
+        countingStream->write((uint64_t*)&cgen_var_572, 1 * 8);
         countingStream->write((VkImageLayout*)&local_srcImageLayout, sizeof(VkImageLayout));
-        uint64_t cgen_var_569;
-        countingStream->handleMapping()->mapHandles_VkImage_u64(&local_dstImage, &cgen_var_569, 1);
-        countingStream->write((uint64_t*)&cgen_var_569, 1 * 8);
+        uint64_t cgen_var_573;
+        countingStream->handleMapping()->mapHandles_VkImage_u64(&local_dstImage, &cgen_var_573, 1);
+        countingStream->write((uint64_t*)&cgen_var_573, 1 * 8);
         countingStream->write((VkImageLayout*)&local_dstImageLayout, sizeof(VkImageLayout));
         countingStream->write((uint32_t*)&local_regionCount, sizeof(uint32_t));
         for (uint32_t i = 0; i < (uint32_t)((regionCount)); ++i)
@@ -8097,16 +8319,16 @@
     uint32_t opcode_vkCmdBlitImage = OP_vkCmdBlitImage;
     stream->write(&opcode_vkCmdBlitImage, sizeof(uint32_t));
     stream->write(&packetSize_vkCmdBlitImage, sizeof(uint32_t));
-    uint64_t cgen_var_570;
-    stream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_570, 1);
-    stream->write((uint64_t*)&cgen_var_570, 1 * 8);
-    uint64_t cgen_var_571;
-    stream->handleMapping()->mapHandles_VkImage_u64(&local_srcImage, &cgen_var_571, 1);
-    stream->write((uint64_t*)&cgen_var_571, 1 * 8);
+    uint64_t cgen_var_574;
+    stream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_574, 1);
+    stream->write((uint64_t*)&cgen_var_574, 1 * 8);
+    uint64_t cgen_var_575;
+    stream->handleMapping()->mapHandles_VkImage_u64(&local_srcImage, &cgen_var_575, 1);
+    stream->write((uint64_t*)&cgen_var_575, 1 * 8);
     stream->write((VkImageLayout*)&local_srcImageLayout, sizeof(VkImageLayout));
-    uint64_t cgen_var_572;
-    stream->handleMapping()->mapHandles_VkImage_u64(&local_dstImage, &cgen_var_572, 1);
-    stream->write((uint64_t*)&cgen_var_572, 1 * 8);
+    uint64_t cgen_var_576;
+    stream->handleMapping()->mapHandles_VkImage_u64(&local_dstImage, &cgen_var_576, 1);
+    stream->write((uint64_t*)&cgen_var_576, 1 * 8);
     stream->write((VkImageLayout*)&local_dstImageLayout, sizeof(VkImageLayout));
     stream->write((uint32_t*)&local_regionCount, sizeof(uint32_t));
     for (uint32_t i = 0; i < (uint32_t)((regionCount)); ++i)
@@ -8127,6 +8349,7 @@
     uint32_t regionCount,
     const VkBufferImageCopy* pRegions)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkCmdCopyBufferToImage encode");
     mImpl->log("start vkCmdCopyBufferToImage");
     auto stream = mImpl->stream();
@@ -8163,15 +8386,15 @@
     }
     countingStream->rewind();
     {
-        uint64_t cgen_var_573;
-        countingStream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_573, 1);
-        countingStream->write((uint64_t*)&cgen_var_573, 1 * 8);
-        uint64_t cgen_var_574;
-        countingStream->handleMapping()->mapHandles_VkBuffer_u64(&local_srcBuffer, &cgen_var_574, 1);
-        countingStream->write((uint64_t*)&cgen_var_574, 1 * 8);
-        uint64_t cgen_var_575;
-        countingStream->handleMapping()->mapHandles_VkImage_u64(&local_dstImage, &cgen_var_575, 1);
-        countingStream->write((uint64_t*)&cgen_var_575, 1 * 8);
+        uint64_t cgen_var_577;
+        countingStream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_577, 1);
+        countingStream->write((uint64_t*)&cgen_var_577, 1 * 8);
+        uint64_t cgen_var_578;
+        countingStream->handleMapping()->mapHandles_VkBuffer_u64(&local_srcBuffer, &cgen_var_578, 1);
+        countingStream->write((uint64_t*)&cgen_var_578, 1 * 8);
+        uint64_t cgen_var_579;
+        countingStream->handleMapping()->mapHandles_VkImage_u64(&local_dstImage, &cgen_var_579, 1);
+        countingStream->write((uint64_t*)&cgen_var_579, 1 * 8);
         countingStream->write((VkImageLayout*)&local_dstImageLayout, sizeof(VkImageLayout));
         countingStream->write((uint32_t*)&local_regionCount, sizeof(uint32_t));
         for (uint32_t i = 0; i < (uint32_t)((regionCount)); ++i)
@@ -8184,15 +8407,15 @@
     uint32_t opcode_vkCmdCopyBufferToImage = OP_vkCmdCopyBufferToImage;
     stream->write(&opcode_vkCmdCopyBufferToImage, sizeof(uint32_t));
     stream->write(&packetSize_vkCmdCopyBufferToImage, sizeof(uint32_t));
-    uint64_t cgen_var_576;
-    stream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_576, 1);
-    stream->write((uint64_t*)&cgen_var_576, 1 * 8);
-    uint64_t cgen_var_577;
-    stream->handleMapping()->mapHandles_VkBuffer_u64(&local_srcBuffer, &cgen_var_577, 1);
-    stream->write((uint64_t*)&cgen_var_577, 1 * 8);
-    uint64_t cgen_var_578;
-    stream->handleMapping()->mapHandles_VkImage_u64(&local_dstImage, &cgen_var_578, 1);
-    stream->write((uint64_t*)&cgen_var_578, 1 * 8);
+    uint64_t cgen_var_580;
+    stream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_580, 1);
+    stream->write((uint64_t*)&cgen_var_580, 1 * 8);
+    uint64_t cgen_var_581;
+    stream->handleMapping()->mapHandles_VkBuffer_u64(&local_srcBuffer, &cgen_var_581, 1);
+    stream->write((uint64_t*)&cgen_var_581, 1 * 8);
+    uint64_t cgen_var_582;
+    stream->handleMapping()->mapHandles_VkImage_u64(&local_dstImage, &cgen_var_582, 1);
+    stream->write((uint64_t*)&cgen_var_582, 1 * 8);
     stream->write((VkImageLayout*)&local_dstImageLayout, sizeof(VkImageLayout));
     stream->write((uint32_t*)&local_regionCount, sizeof(uint32_t));
     for (uint32_t i = 0; i < (uint32_t)((regionCount)); ++i)
@@ -8212,6 +8435,7 @@
     uint32_t regionCount,
     const VkBufferImageCopy* pRegions)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkCmdCopyImageToBuffer encode");
     mImpl->log("start vkCmdCopyImageToBuffer");
     auto stream = mImpl->stream();
@@ -8248,16 +8472,16 @@
     }
     countingStream->rewind();
     {
-        uint64_t cgen_var_579;
-        countingStream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_579, 1);
-        countingStream->write((uint64_t*)&cgen_var_579, 1 * 8);
-        uint64_t cgen_var_580;
-        countingStream->handleMapping()->mapHandles_VkImage_u64(&local_srcImage, &cgen_var_580, 1);
-        countingStream->write((uint64_t*)&cgen_var_580, 1 * 8);
+        uint64_t cgen_var_583;
+        countingStream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_583, 1);
+        countingStream->write((uint64_t*)&cgen_var_583, 1 * 8);
+        uint64_t cgen_var_584;
+        countingStream->handleMapping()->mapHandles_VkImage_u64(&local_srcImage, &cgen_var_584, 1);
+        countingStream->write((uint64_t*)&cgen_var_584, 1 * 8);
         countingStream->write((VkImageLayout*)&local_srcImageLayout, sizeof(VkImageLayout));
-        uint64_t cgen_var_581;
-        countingStream->handleMapping()->mapHandles_VkBuffer_u64(&local_dstBuffer, &cgen_var_581, 1);
-        countingStream->write((uint64_t*)&cgen_var_581, 1 * 8);
+        uint64_t cgen_var_585;
+        countingStream->handleMapping()->mapHandles_VkBuffer_u64(&local_dstBuffer, &cgen_var_585, 1);
+        countingStream->write((uint64_t*)&cgen_var_585, 1 * 8);
         countingStream->write((uint32_t*)&local_regionCount, sizeof(uint32_t));
         for (uint32_t i = 0; i < (uint32_t)((regionCount)); ++i)
         {
@@ -8269,16 +8493,16 @@
     uint32_t opcode_vkCmdCopyImageToBuffer = OP_vkCmdCopyImageToBuffer;
     stream->write(&opcode_vkCmdCopyImageToBuffer, sizeof(uint32_t));
     stream->write(&packetSize_vkCmdCopyImageToBuffer, sizeof(uint32_t));
-    uint64_t cgen_var_582;
-    stream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_582, 1);
-    stream->write((uint64_t*)&cgen_var_582, 1 * 8);
-    uint64_t cgen_var_583;
-    stream->handleMapping()->mapHandles_VkImage_u64(&local_srcImage, &cgen_var_583, 1);
-    stream->write((uint64_t*)&cgen_var_583, 1 * 8);
+    uint64_t cgen_var_586;
+    stream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_586, 1);
+    stream->write((uint64_t*)&cgen_var_586, 1 * 8);
+    uint64_t cgen_var_587;
+    stream->handleMapping()->mapHandles_VkImage_u64(&local_srcImage, &cgen_var_587, 1);
+    stream->write((uint64_t*)&cgen_var_587, 1 * 8);
     stream->write((VkImageLayout*)&local_srcImageLayout, sizeof(VkImageLayout));
-    uint64_t cgen_var_584;
-    stream->handleMapping()->mapHandles_VkBuffer_u64(&local_dstBuffer, &cgen_var_584, 1);
-    stream->write((uint64_t*)&cgen_var_584, 1 * 8);
+    uint64_t cgen_var_588;
+    stream->handleMapping()->mapHandles_VkBuffer_u64(&local_dstBuffer, &cgen_var_588, 1);
+    stream->write((uint64_t*)&cgen_var_588, 1 * 8);
     stream->write((uint32_t*)&local_regionCount, sizeof(uint32_t));
     for (uint32_t i = 0; i < (uint32_t)((regionCount)); ++i)
     {
@@ -8296,6 +8520,7 @@
     VkDeviceSize dataSize,
     const void* pData)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkCmdUpdateBuffer encode");
     mImpl->log("start vkCmdUpdateBuffer");
     auto stream = mImpl->stream();
@@ -8319,12 +8544,12 @@
     }
     countingStream->rewind();
     {
-        uint64_t cgen_var_585;
-        countingStream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_585, 1);
-        countingStream->write((uint64_t*)&cgen_var_585, 1 * 8);
-        uint64_t cgen_var_586;
-        countingStream->handleMapping()->mapHandles_VkBuffer_u64(&local_dstBuffer, &cgen_var_586, 1);
-        countingStream->write((uint64_t*)&cgen_var_586, 1 * 8);
+        uint64_t cgen_var_589;
+        countingStream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_589, 1);
+        countingStream->write((uint64_t*)&cgen_var_589, 1 * 8);
+        uint64_t cgen_var_590;
+        countingStream->handleMapping()->mapHandles_VkBuffer_u64(&local_dstBuffer, &cgen_var_590, 1);
+        countingStream->write((uint64_t*)&cgen_var_590, 1 * 8);
         countingStream->write((VkDeviceSize*)&local_dstOffset, sizeof(VkDeviceSize));
         countingStream->write((VkDeviceSize*)&local_dataSize, sizeof(VkDeviceSize));
         countingStream->write((void*)local_pData, ((dataSize)) * sizeof(uint8_t));
@@ -8334,12 +8559,12 @@
     uint32_t opcode_vkCmdUpdateBuffer = OP_vkCmdUpdateBuffer;
     stream->write(&opcode_vkCmdUpdateBuffer, sizeof(uint32_t));
     stream->write(&packetSize_vkCmdUpdateBuffer, sizeof(uint32_t));
-    uint64_t cgen_var_587;
-    stream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_587, 1);
-    stream->write((uint64_t*)&cgen_var_587, 1 * 8);
-    uint64_t cgen_var_588;
-    stream->handleMapping()->mapHandles_VkBuffer_u64(&local_dstBuffer, &cgen_var_588, 1);
-    stream->write((uint64_t*)&cgen_var_588, 1 * 8);
+    uint64_t cgen_var_591;
+    stream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_591, 1);
+    stream->write((uint64_t*)&cgen_var_591, 1 * 8);
+    uint64_t cgen_var_592;
+    stream->handleMapping()->mapHandles_VkBuffer_u64(&local_dstBuffer, &cgen_var_592, 1);
+    stream->write((uint64_t*)&cgen_var_592, 1 * 8);
     stream->write((VkDeviceSize*)&local_dstOffset, sizeof(VkDeviceSize));
     stream->write((VkDeviceSize*)&local_dataSize, sizeof(VkDeviceSize));
     stream->write((void*)local_pData, ((dataSize)) * sizeof(uint8_t));
@@ -8355,6 +8580,7 @@
     VkDeviceSize size,
     uint32_t data)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkCmdFillBuffer encode");
     mImpl->log("start vkCmdFillBuffer");
     auto stream = mImpl->stream();
@@ -8374,12 +8600,12 @@
     local_data = data;
     countingStream->rewind();
     {
-        uint64_t cgen_var_589;
-        countingStream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_589, 1);
-        countingStream->write((uint64_t*)&cgen_var_589, 1 * 8);
-        uint64_t cgen_var_590;
-        countingStream->handleMapping()->mapHandles_VkBuffer_u64(&local_dstBuffer, &cgen_var_590, 1);
-        countingStream->write((uint64_t*)&cgen_var_590, 1 * 8);
+        uint64_t cgen_var_593;
+        countingStream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_593, 1);
+        countingStream->write((uint64_t*)&cgen_var_593, 1 * 8);
+        uint64_t cgen_var_594;
+        countingStream->handleMapping()->mapHandles_VkBuffer_u64(&local_dstBuffer, &cgen_var_594, 1);
+        countingStream->write((uint64_t*)&cgen_var_594, 1 * 8);
         countingStream->write((VkDeviceSize*)&local_dstOffset, sizeof(VkDeviceSize));
         countingStream->write((VkDeviceSize*)&local_size, sizeof(VkDeviceSize));
         countingStream->write((uint32_t*)&local_data, sizeof(uint32_t));
@@ -8389,12 +8615,12 @@
     uint32_t opcode_vkCmdFillBuffer = OP_vkCmdFillBuffer;
     stream->write(&opcode_vkCmdFillBuffer, sizeof(uint32_t));
     stream->write(&packetSize_vkCmdFillBuffer, sizeof(uint32_t));
-    uint64_t cgen_var_591;
-    stream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_591, 1);
-    stream->write((uint64_t*)&cgen_var_591, 1 * 8);
-    uint64_t cgen_var_592;
-    stream->handleMapping()->mapHandles_VkBuffer_u64(&local_dstBuffer, &cgen_var_592, 1);
-    stream->write((uint64_t*)&cgen_var_592, 1 * 8);
+    uint64_t cgen_var_595;
+    stream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_595, 1);
+    stream->write((uint64_t*)&cgen_var_595, 1 * 8);
+    uint64_t cgen_var_596;
+    stream->handleMapping()->mapHandles_VkBuffer_u64(&local_dstBuffer, &cgen_var_596, 1);
+    stream->write((uint64_t*)&cgen_var_596, 1 * 8);
     stream->write((VkDeviceSize*)&local_dstOffset, sizeof(VkDeviceSize));
     stream->write((VkDeviceSize*)&local_size, sizeof(VkDeviceSize));
     stream->write((uint32_t*)&local_data, sizeof(uint32_t));
@@ -8411,6 +8637,7 @@
     uint32_t rangeCount,
     const VkImageSubresourceRange* pRanges)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkCmdClearColorImage encode");
     mImpl->log("start vkCmdClearColorImage");
     auto stream = mImpl->stream();
@@ -8456,12 +8683,12 @@
     }
     countingStream->rewind();
     {
-        uint64_t cgen_var_593;
-        countingStream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_593, 1);
-        countingStream->write((uint64_t*)&cgen_var_593, 1 * 8);
-        uint64_t cgen_var_594;
-        countingStream->handleMapping()->mapHandles_VkImage_u64(&local_image, &cgen_var_594, 1);
-        countingStream->write((uint64_t*)&cgen_var_594, 1 * 8);
+        uint64_t cgen_var_597;
+        countingStream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_597, 1);
+        countingStream->write((uint64_t*)&cgen_var_597, 1 * 8);
+        uint64_t cgen_var_598;
+        countingStream->handleMapping()->mapHandles_VkImage_u64(&local_image, &cgen_var_598, 1);
+        countingStream->write((uint64_t*)&cgen_var_598, 1 * 8);
         countingStream->write((VkImageLayout*)&local_imageLayout, sizeof(VkImageLayout));
         marshal_VkClearColorValue(countingStream, (VkClearColorValue*)(local_pColor));
         countingStream->write((uint32_t*)&local_rangeCount, sizeof(uint32_t));
@@ -8475,12 +8702,12 @@
     uint32_t opcode_vkCmdClearColorImage = OP_vkCmdClearColorImage;
     stream->write(&opcode_vkCmdClearColorImage, sizeof(uint32_t));
     stream->write(&packetSize_vkCmdClearColorImage, sizeof(uint32_t));
-    uint64_t cgen_var_595;
-    stream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_595, 1);
-    stream->write((uint64_t*)&cgen_var_595, 1 * 8);
-    uint64_t cgen_var_596;
-    stream->handleMapping()->mapHandles_VkImage_u64(&local_image, &cgen_var_596, 1);
-    stream->write((uint64_t*)&cgen_var_596, 1 * 8);
+    uint64_t cgen_var_599;
+    stream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_599, 1);
+    stream->write((uint64_t*)&cgen_var_599, 1 * 8);
+    uint64_t cgen_var_600;
+    stream->handleMapping()->mapHandles_VkImage_u64(&local_image, &cgen_var_600, 1);
+    stream->write((uint64_t*)&cgen_var_600, 1 * 8);
     stream->write((VkImageLayout*)&local_imageLayout, sizeof(VkImageLayout));
     marshal_VkClearColorValue(stream, (VkClearColorValue*)(local_pColor));
     stream->write((uint32_t*)&local_rangeCount, sizeof(uint32_t));
@@ -8501,6 +8728,7 @@
     uint32_t rangeCount,
     const VkImageSubresourceRange* pRanges)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkCmdClearDepthStencilImage encode");
     mImpl->log("start vkCmdClearDepthStencilImage");
     auto stream = mImpl->stream();
@@ -8546,12 +8774,12 @@
     }
     countingStream->rewind();
     {
-        uint64_t cgen_var_597;
-        countingStream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_597, 1);
-        countingStream->write((uint64_t*)&cgen_var_597, 1 * 8);
-        uint64_t cgen_var_598;
-        countingStream->handleMapping()->mapHandles_VkImage_u64(&local_image, &cgen_var_598, 1);
-        countingStream->write((uint64_t*)&cgen_var_598, 1 * 8);
+        uint64_t cgen_var_601;
+        countingStream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_601, 1);
+        countingStream->write((uint64_t*)&cgen_var_601, 1 * 8);
+        uint64_t cgen_var_602;
+        countingStream->handleMapping()->mapHandles_VkImage_u64(&local_image, &cgen_var_602, 1);
+        countingStream->write((uint64_t*)&cgen_var_602, 1 * 8);
         countingStream->write((VkImageLayout*)&local_imageLayout, sizeof(VkImageLayout));
         marshal_VkClearDepthStencilValue(countingStream, (VkClearDepthStencilValue*)(local_pDepthStencil));
         countingStream->write((uint32_t*)&local_rangeCount, sizeof(uint32_t));
@@ -8565,12 +8793,12 @@
     uint32_t opcode_vkCmdClearDepthStencilImage = OP_vkCmdClearDepthStencilImage;
     stream->write(&opcode_vkCmdClearDepthStencilImage, sizeof(uint32_t));
     stream->write(&packetSize_vkCmdClearDepthStencilImage, sizeof(uint32_t));
-    uint64_t cgen_var_599;
-    stream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_599, 1);
-    stream->write((uint64_t*)&cgen_var_599, 1 * 8);
-    uint64_t cgen_var_600;
-    stream->handleMapping()->mapHandles_VkImage_u64(&local_image, &cgen_var_600, 1);
-    stream->write((uint64_t*)&cgen_var_600, 1 * 8);
+    uint64_t cgen_var_603;
+    stream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_603, 1);
+    stream->write((uint64_t*)&cgen_var_603, 1 * 8);
+    uint64_t cgen_var_604;
+    stream->handleMapping()->mapHandles_VkImage_u64(&local_image, &cgen_var_604, 1);
+    stream->write((uint64_t*)&cgen_var_604, 1 * 8);
     stream->write((VkImageLayout*)&local_imageLayout, sizeof(VkImageLayout));
     marshal_VkClearDepthStencilValue(stream, (VkClearDepthStencilValue*)(local_pDepthStencil));
     stream->write((uint32_t*)&local_rangeCount, sizeof(uint32_t));
@@ -8590,6 +8818,7 @@
     uint32_t rectCount,
     const VkClearRect* pRects)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkCmdClearAttachments encode");
     mImpl->log("start vkCmdClearAttachments");
     auto stream = mImpl->stream();
@@ -8639,9 +8868,9 @@
     }
     countingStream->rewind();
     {
-        uint64_t cgen_var_601;
-        countingStream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_601, 1);
-        countingStream->write((uint64_t*)&cgen_var_601, 1 * 8);
+        uint64_t cgen_var_605;
+        countingStream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_605, 1);
+        countingStream->write((uint64_t*)&cgen_var_605, 1 * 8);
         countingStream->write((uint32_t*)&local_attachmentCount, sizeof(uint32_t));
         for (uint32_t i = 0; i < (uint32_t)((attachmentCount)); ++i)
         {
@@ -8658,9 +8887,9 @@
     uint32_t opcode_vkCmdClearAttachments = OP_vkCmdClearAttachments;
     stream->write(&opcode_vkCmdClearAttachments, sizeof(uint32_t));
     stream->write(&packetSize_vkCmdClearAttachments, sizeof(uint32_t));
-    uint64_t cgen_var_602;
-    stream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_602, 1);
-    stream->write((uint64_t*)&cgen_var_602, 1 * 8);
+    uint64_t cgen_var_606;
+    stream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_606, 1);
+    stream->write((uint64_t*)&cgen_var_606, 1 * 8);
     stream->write((uint32_t*)&local_attachmentCount, sizeof(uint32_t));
     for (uint32_t i = 0; i < (uint32_t)((attachmentCount)); ++i)
     {
@@ -8685,6 +8914,7 @@
     uint32_t regionCount,
     const VkImageResolve* pRegions)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkCmdResolveImage encode");
     mImpl->log("start vkCmdResolveImage");
     auto stream = mImpl->stream();
@@ -8723,16 +8953,16 @@
     }
     countingStream->rewind();
     {
-        uint64_t cgen_var_603;
-        countingStream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_603, 1);
-        countingStream->write((uint64_t*)&cgen_var_603, 1 * 8);
-        uint64_t cgen_var_604;
-        countingStream->handleMapping()->mapHandles_VkImage_u64(&local_srcImage, &cgen_var_604, 1);
-        countingStream->write((uint64_t*)&cgen_var_604, 1 * 8);
+        uint64_t cgen_var_607;
+        countingStream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_607, 1);
+        countingStream->write((uint64_t*)&cgen_var_607, 1 * 8);
+        uint64_t cgen_var_608;
+        countingStream->handleMapping()->mapHandles_VkImage_u64(&local_srcImage, &cgen_var_608, 1);
+        countingStream->write((uint64_t*)&cgen_var_608, 1 * 8);
         countingStream->write((VkImageLayout*)&local_srcImageLayout, sizeof(VkImageLayout));
-        uint64_t cgen_var_605;
-        countingStream->handleMapping()->mapHandles_VkImage_u64(&local_dstImage, &cgen_var_605, 1);
-        countingStream->write((uint64_t*)&cgen_var_605, 1 * 8);
+        uint64_t cgen_var_609;
+        countingStream->handleMapping()->mapHandles_VkImage_u64(&local_dstImage, &cgen_var_609, 1);
+        countingStream->write((uint64_t*)&cgen_var_609, 1 * 8);
         countingStream->write((VkImageLayout*)&local_dstImageLayout, sizeof(VkImageLayout));
         countingStream->write((uint32_t*)&local_regionCount, sizeof(uint32_t));
         for (uint32_t i = 0; i < (uint32_t)((regionCount)); ++i)
@@ -8745,16 +8975,16 @@
     uint32_t opcode_vkCmdResolveImage = OP_vkCmdResolveImage;
     stream->write(&opcode_vkCmdResolveImage, sizeof(uint32_t));
     stream->write(&packetSize_vkCmdResolveImage, sizeof(uint32_t));
-    uint64_t cgen_var_606;
-    stream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_606, 1);
-    stream->write((uint64_t*)&cgen_var_606, 1 * 8);
-    uint64_t cgen_var_607;
-    stream->handleMapping()->mapHandles_VkImage_u64(&local_srcImage, &cgen_var_607, 1);
-    stream->write((uint64_t*)&cgen_var_607, 1 * 8);
+    uint64_t cgen_var_610;
+    stream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_610, 1);
+    stream->write((uint64_t*)&cgen_var_610, 1 * 8);
+    uint64_t cgen_var_611;
+    stream->handleMapping()->mapHandles_VkImage_u64(&local_srcImage, &cgen_var_611, 1);
+    stream->write((uint64_t*)&cgen_var_611, 1 * 8);
     stream->write((VkImageLayout*)&local_srcImageLayout, sizeof(VkImageLayout));
-    uint64_t cgen_var_608;
-    stream->handleMapping()->mapHandles_VkImage_u64(&local_dstImage, &cgen_var_608, 1);
-    stream->write((uint64_t*)&cgen_var_608, 1 * 8);
+    uint64_t cgen_var_612;
+    stream->handleMapping()->mapHandles_VkImage_u64(&local_dstImage, &cgen_var_612, 1);
+    stream->write((uint64_t*)&cgen_var_612, 1 * 8);
     stream->write((VkImageLayout*)&local_dstImageLayout, sizeof(VkImageLayout));
     stream->write((uint32_t*)&local_regionCount, sizeof(uint32_t));
     for (uint32_t i = 0; i < (uint32_t)((regionCount)); ++i)
@@ -8771,6 +9001,7 @@
     VkEvent event,
     VkPipelineStageFlags stageMask)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkCmdSetEvent encode");
     mImpl->log("start vkCmdSetEvent");
     auto stream = mImpl->stream();
@@ -8786,51 +9017,6 @@
     local_stageMask = stageMask;
     countingStream->rewind();
     {
-        uint64_t cgen_var_609;
-        countingStream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_609, 1);
-        countingStream->write((uint64_t*)&cgen_var_609, 1 * 8);
-        uint64_t cgen_var_610;
-        countingStream->handleMapping()->mapHandles_VkEvent_u64(&local_event, &cgen_var_610, 1);
-        countingStream->write((uint64_t*)&cgen_var_610, 1 * 8);
-        countingStream->write((VkPipelineStageFlags*)&local_stageMask, sizeof(VkPipelineStageFlags));
-    }
-    uint32_t packetSize_vkCmdSetEvent = 4 + 4 + (uint32_t)countingStream->bytesWritten();
-    countingStream->rewind();
-    uint32_t opcode_vkCmdSetEvent = OP_vkCmdSetEvent;
-    stream->write(&opcode_vkCmdSetEvent, sizeof(uint32_t));
-    stream->write(&packetSize_vkCmdSetEvent, sizeof(uint32_t));
-    uint64_t cgen_var_611;
-    stream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_611, 1);
-    stream->write((uint64_t*)&cgen_var_611, 1 * 8);
-    uint64_t cgen_var_612;
-    stream->handleMapping()->mapHandles_VkEvent_u64(&local_event, &cgen_var_612, 1);
-    stream->write((uint64_t*)&cgen_var_612, 1 * 8);
-    stream->write((VkPipelineStageFlags*)&local_stageMask, sizeof(VkPipelineStageFlags));
-    AEMU_SCOPED_TRACE("vkCmdSetEvent readParams");
-    AEMU_SCOPED_TRACE("vkCmdSetEvent returnUnmarshal");
-    mImpl->log("finish vkCmdSetEvent");;
-}
-
-void VkEncoder::vkCmdResetEvent(
-    VkCommandBuffer commandBuffer,
-    VkEvent event,
-    VkPipelineStageFlags stageMask)
-{
-    AEMU_SCOPED_TRACE("vkCmdResetEvent encode");
-    mImpl->log("start vkCmdResetEvent");
-    auto stream = mImpl->stream();
-    auto countingStream = mImpl->countingStream();
-    auto resources = mImpl->resources();
-    auto pool = mImpl->pool();
-    stream->setHandleMapping(resources->unwrapMapping());
-    VkCommandBuffer local_commandBuffer;
-    VkEvent local_event;
-    VkPipelineStageFlags local_stageMask;
-    local_commandBuffer = commandBuffer;
-    local_event = event;
-    local_stageMask = stageMask;
-    countingStream->rewind();
-    {
         uint64_t cgen_var_613;
         countingStream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_613, 1);
         countingStream->write((uint64_t*)&cgen_var_613, 1 * 8);
@@ -8839,11 +9025,11 @@
         countingStream->write((uint64_t*)&cgen_var_614, 1 * 8);
         countingStream->write((VkPipelineStageFlags*)&local_stageMask, sizeof(VkPipelineStageFlags));
     }
-    uint32_t packetSize_vkCmdResetEvent = 4 + 4 + (uint32_t)countingStream->bytesWritten();
+    uint32_t packetSize_vkCmdSetEvent = 4 + 4 + (uint32_t)countingStream->bytesWritten();
     countingStream->rewind();
-    uint32_t opcode_vkCmdResetEvent = OP_vkCmdResetEvent;
-    stream->write(&opcode_vkCmdResetEvent, sizeof(uint32_t));
-    stream->write(&packetSize_vkCmdResetEvent, sizeof(uint32_t));
+    uint32_t opcode_vkCmdSetEvent = OP_vkCmdSetEvent;
+    stream->write(&opcode_vkCmdSetEvent, sizeof(uint32_t));
+    stream->write(&packetSize_vkCmdSetEvent, sizeof(uint32_t));
     uint64_t cgen_var_615;
     stream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_615, 1);
     stream->write((uint64_t*)&cgen_var_615, 1 * 8);
@@ -8851,6 +9037,52 @@
     stream->handleMapping()->mapHandles_VkEvent_u64(&local_event, &cgen_var_616, 1);
     stream->write((uint64_t*)&cgen_var_616, 1 * 8);
     stream->write((VkPipelineStageFlags*)&local_stageMask, sizeof(VkPipelineStageFlags));
+    AEMU_SCOPED_TRACE("vkCmdSetEvent readParams");
+    AEMU_SCOPED_TRACE("vkCmdSetEvent returnUnmarshal");
+    mImpl->log("finish vkCmdSetEvent");;
+}
+
+void VkEncoder::vkCmdResetEvent(
+    VkCommandBuffer commandBuffer,
+    VkEvent event,
+    VkPipelineStageFlags stageMask)
+{
+    AutoLock encoderLock(mImpl->lock);
+    AEMU_SCOPED_TRACE("vkCmdResetEvent encode");
+    mImpl->log("start vkCmdResetEvent");
+    auto stream = mImpl->stream();
+    auto countingStream = mImpl->countingStream();
+    auto resources = mImpl->resources();
+    auto pool = mImpl->pool();
+    stream->setHandleMapping(resources->unwrapMapping());
+    VkCommandBuffer local_commandBuffer;
+    VkEvent local_event;
+    VkPipelineStageFlags local_stageMask;
+    local_commandBuffer = commandBuffer;
+    local_event = event;
+    local_stageMask = stageMask;
+    countingStream->rewind();
+    {
+        uint64_t cgen_var_617;
+        countingStream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_617, 1);
+        countingStream->write((uint64_t*)&cgen_var_617, 1 * 8);
+        uint64_t cgen_var_618;
+        countingStream->handleMapping()->mapHandles_VkEvent_u64(&local_event, &cgen_var_618, 1);
+        countingStream->write((uint64_t*)&cgen_var_618, 1 * 8);
+        countingStream->write((VkPipelineStageFlags*)&local_stageMask, sizeof(VkPipelineStageFlags));
+    }
+    uint32_t packetSize_vkCmdResetEvent = 4 + 4 + (uint32_t)countingStream->bytesWritten();
+    countingStream->rewind();
+    uint32_t opcode_vkCmdResetEvent = OP_vkCmdResetEvent;
+    stream->write(&opcode_vkCmdResetEvent, sizeof(uint32_t));
+    stream->write(&packetSize_vkCmdResetEvent, sizeof(uint32_t));
+    uint64_t cgen_var_619;
+    stream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_619, 1);
+    stream->write((uint64_t*)&cgen_var_619, 1 * 8);
+    uint64_t cgen_var_620;
+    stream->handleMapping()->mapHandles_VkEvent_u64(&local_event, &cgen_var_620, 1);
+    stream->write((uint64_t*)&cgen_var_620, 1 * 8);
+    stream->write((VkPipelineStageFlags*)&local_stageMask, sizeof(VkPipelineStageFlags));
     AEMU_SCOPED_TRACE("vkCmdResetEvent readParams");
     AEMU_SCOPED_TRACE("vkCmdResetEvent returnUnmarshal");
     mImpl->log("finish vkCmdResetEvent");;
@@ -8869,6 +9101,7 @@
     uint32_t imageMemoryBarrierCount,
     const VkImageMemoryBarrier* pImageMemoryBarriers)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkCmdWaitEvents encode");
     mImpl->log("start vkCmdWaitEvents");
     auto stream = mImpl->stream();
@@ -8949,16 +9182,16 @@
     }
     countingStream->rewind();
     {
-        uint64_t cgen_var_617;
-        countingStream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_617, 1);
-        countingStream->write((uint64_t*)&cgen_var_617, 1 * 8);
+        uint64_t cgen_var_621;
+        countingStream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_621, 1);
+        countingStream->write((uint64_t*)&cgen_var_621, 1 * 8);
         countingStream->write((uint32_t*)&local_eventCount, sizeof(uint32_t));
         if (((eventCount)))
         {
-            uint64_t* cgen_var_618;
-            countingStream->alloc((void**)&cgen_var_618, ((eventCount)) * 8);
-            countingStream->handleMapping()->mapHandles_VkEvent_u64(local_pEvents, cgen_var_618, ((eventCount)));
-            countingStream->write((uint64_t*)cgen_var_618, ((eventCount)) * 8);
+            uint64_t* cgen_var_622;
+            countingStream->alloc((void**)&cgen_var_622, ((eventCount)) * 8);
+            countingStream->handleMapping()->mapHandles_VkEvent_u64(local_pEvents, cgen_var_622, ((eventCount)));
+            countingStream->write((uint64_t*)cgen_var_622, ((eventCount)) * 8);
         }
         countingStream->write((VkPipelineStageFlags*)&local_srcStageMask, sizeof(VkPipelineStageFlags));
         countingStream->write((VkPipelineStageFlags*)&local_dstStageMask, sizeof(VkPipelineStageFlags));
@@ -8983,16 +9216,16 @@
     uint32_t opcode_vkCmdWaitEvents = OP_vkCmdWaitEvents;
     stream->write(&opcode_vkCmdWaitEvents, sizeof(uint32_t));
     stream->write(&packetSize_vkCmdWaitEvents, sizeof(uint32_t));
-    uint64_t cgen_var_619;
-    stream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_619, 1);
-    stream->write((uint64_t*)&cgen_var_619, 1 * 8);
+    uint64_t cgen_var_623;
+    stream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_623, 1);
+    stream->write((uint64_t*)&cgen_var_623, 1 * 8);
     stream->write((uint32_t*)&local_eventCount, sizeof(uint32_t));
     if (((eventCount)))
     {
-        uint64_t* cgen_var_620;
-        stream->alloc((void**)&cgen_var_620, ((eventCount)) * 8);
-        stream->handleMapping()->mapHandles_VkEvent_u64(local_pEvents, cgen_var_620, ((eventCount)));
-        stream->write((uint64_t*)cgen_var_620, ((eventCount)) * 8);
+        uint64_t* cgen_var_624;
+        stream->alloc((void**)&cgen_var_624, ((eventCount)) * 8);
+        stream->handleMapping()->mapHandles_VkEvent_u64(local_pEvents, cgen_var_624, ((eventCount)));
+        stream->write((uint64_t*)cgen_var_624, ((eventCount)) * 8);
     }
     stream->write((VkPipelineStageFlags*)&local_srcStageMask, sizeof(VkPipelineStageFlags));
     stream->write((VkPipelineStageFlags*)&local_dstStageMask, sizeof(VkPipelineStageFlags));
@@ -9028,6 +9261,7 @@
     uint32_t imageMemoryBarrierCount,
     const VkImageMemoryBarrier* pImageMemoryBarriers)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkCmdPipelineBarrier encode");
     mImpl->log("start vkCmdPipelineBarrier");
     auto stream = mImpl->stream();
@@ -9102,9 +9336,9 @@
     }
     countingStream->rewind();
     {
-        uint64_t cgen_var_621;
-        countingStream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_621, 1);
-        countingStream->write((uint64_t*)&cgen_var_621, 1 * 8);
+        uint64_t cgen_var_625;
+        countingStream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_625, 1);
+        countingStream->write((uint64_t*)&cgen_var_625, 1 * 8);
         countingStream->write((VkPipelineStageFlags*)&local_srcStageMask, sizeof(VkPipelineStageFlags));
         countingStream->write((VkPipelineStageFlags*)&local_dstStageMask, sizeof(VkPipelineStageFlags));
         countingStream->write((VkDependencyFlags*)&local_dependencyFlags, sizeof(VkDependencyFlags));
@@ -9129,9 +9363,9 @@
     uint32_t opcode_vkCmdPipelineBarrier = OP_vkCmdPipelineBarrier;
     stream->write(&opcode_vkCmdPipelineBarrier, sizeof(uint32_t));
     stream->write(&packetSize_vkCmdPipelineBarrier, sizeof(uint32_t));
-    uint64_t cgen_var_622;
-    stream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_622, 1);
-    stream->write((uint64_t*)&cgen_var_622, 1 * 8);
+    uint64_t cgen_var_626;
+    stream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_626, 1);
+    stream->write((uint64_t*)&cgen_var_626, 1 * 8);
     stream->write((VkPipelineStageFlags*)&local_srcStageMask, sizeof(VkPipelineStageFlags));
     stream->write((VkPipelineStageFlags*)&local_dstStageMask, sizeof(VkPipelineStageFlags));
     stream->write((VkDependencyFlags*)&local_dependencyFlags, sizeof(VkDependencyFlags));
@@ -9161,6 +9395,7 @@
     uint32_t query,
     VkQueryControlFlags flags)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkCmdBeginQuery encode");
     mImpl->log("start vkCmdBeginQuery");
     auto stream = mImpl->stream();
@@ -9178,12 +9413,12 @@
     local_flags = flags;
     countingStream->rewind();
     {
-        uint64_t cgen_var_623;
-        countingStream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_623, 1);
-        countingStream->write((uint64_t*)&cgen_var_623, 1 * 8);
-        uint64_t cgen_var_624;
-        countingStream->handleMapping()->mapHandles_VkQueryPool_u64(&local_queryPool, &cgen_var_624, 1);
-        countingStream->write((uint64_t*)&cgen_var_624, 1 * 8);
+        uint64_t cgen_var_627;
+        countingStream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_627, 1);
+        countingStream->write((uint64_t*)&cgen_var_627, 1 * 8);
+        uint64_t cgen_var_628;
+        countingStream->handleMapping()->mapHandles_VkQueryPool_u64(&local_queryPool, &cgen_var_628, 1);
+        countingStream->write((uint64_t*)&cgen_var_628, 1 * 8);
         countingStream->write((uint32_t*)&local_query, sizeof(uint32_t));
         countingStream->write((VkQueryControlFlags*)&local_flags, sizeof(VkQueryControlFlags));
     }
@@ -9192,12 +9427,12 @@
     uint32_t opcode_vkCmdBeginQuery = OP_vkCmdBeginQuery;
     stream->write(&opcode_vkCmdBeginQuery, sizeof(uint32_t));
     stream->write(&packetSize_vkCmdBeginQuery, sizeof(uint32_t));
-    uint64_t cgen_var_625;
-    stream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_625, 1);
-    stream->write((uint64_t*)&cgen_var_625, 1 * 8);
-    uint64_t cgen_var_626;
-    stream->handleMapping()->mapHandles_VkQueryPool_u64(&local_queryPool, &cgen_var_626, 1);
-    stream->write((uint64_t*)&cgen_var_626, 1 * 8);
+    uint64_t cgen_var_629;
+    stream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_629, 1);
+    stream->write((uint64_t*)&cgen_var_629, 1 * 8);
+    uint64_t cgen_var_630;
+    stream->handleMapping()->mapHandles_VkQueryPool_u64(&local_queryPool, &cgen_var_630, 1);
+    stream->write((uint64_t*)&cgen_var_630, 1 * 8);
     stream->write((uint32_t*)&local_query, sizeof(uint32_t));
     stream->write((VkQueryControlFlags*)&local_flags, sizeof(VkQueryControlFlags));
     AEMU_SCOPED_TRACE("vkCmdBeginQuery readParams");
@@ -9210,6 +9445,7 @@
     VkQueryPool queryPool,
     uint32_t query)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkCmdEndQuery encode");
     mImpl->log("start vkCmdEndQuery");
     auto stream = mImpl->stream();
@@ -9225,12 +9461,12 @@
     local_query = query;
     countingStream->rewind();
     {
-        uint64_t cgen_var_627;
-        countingStream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_627, 1);
-        countingStream->write((uint64_t*)&cgen_var_627, 1 * 8);
-        uint64_t cgen_var_628;
-        countingStream->handleMapping()->mapHandles_VkQueryPool_u64(&local_queryPool, &cgen_var_628, 1);
-        countingStream->write((uint64_t*)&cgen_var_628, 1 * 8);
+        uint64_t cgen_var_631;
+        countingStream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_631, 1);
+        countingStream->write((uint64_t*)&cgen_var_631, 1 * 8);
+        uint64_t cgen_var_632;
+        countingStream->handleMapping()->mapHandles_VkQueryPool_u64(&local_queryPool, &cgen_var_632, 1);
+        countingStream->write((uint64_t*)&cgen_var_632, 1 * 8);
         countingStream->write((uint32_t*)&local_query, sizeof(uint32_t));
     }
     uint32_t packetSize_vkCmdEndQuery = 4 + 4 + (uint32_t)countingStream->bytesWritten();
@@ -9238,12 +9474,12 @@
     uint32_t opcode_vkCmdEndQuery = OP_vkCmdEndQuery;
     stream->write(&opcode_vkCmdEndQuery, sizeof(uint32_t));
     stream->write(&packetSize_vkCmdEndQuery, sizeof(uint32_t));
-    uint64_t cgen_var_629;
-    stream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_629, 1);
-    stream->write((uint64_t*)&cgen_var_629, 1 * 8);
-    uint64_t cgen_var_630;
-    stream->handleMapping()->mapHandles_VkQueryPool_u64(&local_queryPool, &cgen_var_630, 1);
-    stream->write((uint64_t*)&cgen_var_630, 1 * 8);
+    uint64_t cgen_var_633;
+    stream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_633, 1);
+    stream->write((uint64_t*)&cgen_var_633, 1 * 8);
+    uint64_t cgen_var_634;
+    stream->handleMapping()->mapHandles_VkQueryPool_u64(&local_queryPool, &cgen_var_634, 1);
+    stream->write((uint64_t*)&cgen_var_634, 1 * 8);
     stream->write((uint32_t*)&local_query, sizeof(uint32_t));
     AEMU_SCOPED_TRACE("vkCmdEndQuery readParams");
     AEMU_SCOPED_TRACE("vkCmdEndQuery returnUnmarshal");
@@ -9256,6 +9492,7 @@
     uint32_t firstQuery,
     uint32_t queryCount)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkCmdResetQueryPool encode");
     mImpl->log("start vkCmdResetQueryPool");
     auto stream = mImpl->stream();
@@ -9273,12 +9510,12 @@
     local_queryCount = queryCount;
     countingStream->rewind();
     {
-        uint64_t cgen_var_631;
-        countingStream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_631, 1);
-        countingStream->write((uint64_t*)&cgen_var_631, 1 * 8);
-        uint64_t cgen_var_632;
-        countingStream->handleMapping()->mapHandles_VkQueryPool_u64(&local_queryPool, &cgen_var_632, 1);
-        countingStream->write((uint64_t*)&cgen_var_632, 1 * 8);
+        uint64_t cgen_var_635;
+        countingStream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_635, 1);
+        countingStream->write((uint64_t*)&cgen_var_635, 1 * 8);
+        uint64_t cgen_var_636;
+        countingStream->handleMapping()->mapHandles_VkQueryPool_u64(&local_queryPool, &cgen_var_636, 1);
+        countingStream->write((uint64_t*)&cgen_var_636, 1 * 8);
         countingStream->write((uint32_t*)&local_firstQuery, sizeof(uint32_t));
         countingStream->write((uint32_t*)&local_queryCount, sizeof(uint32_t));
     }
@@ -9287,12 +9524,12 @@
     uint32_t opcode_vkCmdResetQueryPool = OP_vkCmdResetQueryPool;
     stream->write(&opcode_vkCmdResetQueryPool, sizeof(uint32_t));
     stream->write(&packetSize_vkCmdResetQueryPool, sizeof(uint32_t));
-    uint64_t cgen_var_633;
-    stream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_633, 1);
-    stream->write((uint64_t*)&cgen_var_633, 1 * 8);
-    uint64_t cgen_var_634;
-    stream->handleMapping()->mapHandles_VkQueryPool_u64(&local_queryPool, &cgen_var_634, 1);
-    stream->write((uint64_t*)&cgen_var_634, 1 * 8);
+    uint64_t cgen_var_637;
+    stream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_637, 1);
+    stream->write((uint64_t*)&cgen_var_637, 1 * 8);
+    uint64_t cgen_var_638;
+    stream->handleMapping()->mapHandles_VkQueryPool_u64(&local_queryPool, &cgen_var_638, 1);
+    stream->write((uint64_t*)&cgen_var_638, 1 * 8);
     stream->write((uint32_t*)&local_firstQuery, sizeof(uint32_t));
     stream->write((uint32_t*)&local_queryCount, sizeof(uint32_t));
     AEMU_SCOPED_TRACE("vkCmdResetQueryPool readParams");
@@ -9306,6 +9543,7 @@
     VkQueryPool queryPool,
     uint32_t query)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkCmdWriteTimestamp encode");
     mImpl->log("start vkCmdWriteTimestamp");
     auto stream = mImpl->stream();
@@ -9323,13 +9561,13 @@
     local_query = query;
     countingStream->rewind();
     {
-        uint64_t cgen_var_635;
-        countingStream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_635, 1);
-        countingStream->write((uint64_t*)&cgen_var_635, 1 * 8);
+        uint64_t cgen_var_639;
+        countingStream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_639, 1);
+        countingStream->write((uint64_t*)&cgen_var_639, 1 * 8);
         countingStream->write((VkPipelineStageFlagBits*)&local_pipelineStage, sizeof(VkPipelineStageFlagBits));
-        uint64_t cgen_var_636;
-        countingStream->handleMapping()->mapHandles_VkQueryPool_u64(&local_queryPool, &cgen_var_636, 1);
-        countingStream->write((uint64_t*)&cgen_var_636, 1 * 8);
+        uint64_t cgen_var_640;
+        countingStream->handleMapping()->mapHandles_VkQueryPool_u64(&local_queryPool, &cgen_var_640, 1);
+        countingStream->write((uint64_t*)&cgen_var_640, 1 * 8);
         countingStream->write((uint32_t*)&local_query, sizeof(uint32_t));
     }
     uint32_t packetSize_vkCmdWriteTimestamp = 4 + 4 + (uint32_t)countingStream->bytesWritten();
@@ -9337,13 +9575,13 @@
     uint32_t opcode_vkCmdWriteTimestamp = OP_vkCmdWriteTimestamp;
     stream->write(&opcode_vkCmdWriteTimestamp, sizeof(uint32_t));
     stream->write(&packetSize_vkCmdWriteTimestamp, sizeof(uint32_t));
-    uint64_t cgen_var_637;
-    stream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_637, 1);
-    stream->write((uint64_t*)&cgen_var_637, 1 * 8);
+    uint64_t cgen_var_641;
+    stream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_641, 1);
+    stream->write((uint64_t*)&cgen_var_641, 1 * 8);
     stream->write((VkPipelineStageFlagBits*)&local_pipelineStage, sizeof(VkPipelineStageFlagBits));
-    uint64_t cgen_var_638;
-    stream->handleMapping()->mapHandles_VkQueryPool_u64(&local_queryPool, &cgen_var_638, 1);
-    stream->write((uint64_t*)&cgen_var_638, 1 * 8);
+    uint64_t cgen_var_642;
+    stream->handleMapping()->mapHandles_VkQueryPool_u64(&local_queryPool, &cgen_var_642, 1);
+    stream->write((uint64_t*)&cgen_var_642, 1 * 8);
     stream->write((uint32_t*)&local_query, sizeof(uint32_t));
     AEMU_SCOPED_TRACE("vkCmdWriteTimestamp readParams");
     AEMU_SCOPED_TRACE("vkCmdWriteTimestamp returnUnmarshal");
@@ -9360,6 +9598,7 @@
     VkDeviceSize stride,
     VkQueryResultFlags flags)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkCmdCopyQueryPoolResults encode");
     mImpl->log("start vkCmdCopyQueryPoolResults");
     auto stream = mImpl->stream();
@@ -9385,17 +9624,17 @@
     local_flags = flags;
     countingStream->rewind();
     {
-        uint64_t cgen_var_639;
-        countingStream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_639, 1);
-        countingStream->write((uint64_t*)&cgen_var_639, 1 * 8);
-        uint64_t cgen_var_640;
-        countingStream->handleMapping()->mapHandles_VkQueryPool_u64(&local_queryPool, &cgen_var_640, 1);
-        countingStream->write((uint64_t*)&cgen_var_640, 1 * 8);
+        uint64_t cgen_var_643;
+        countingStream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_643, 1);
+        countingStream->write((uint64_t*)&cgen_var_643, 1 * 8);
+        uint64_t cgen_var_644;
+        countingStream->handleMapping()->mapHandles_VkQueryPool_u64(&local_queryPool, &cgen_var_644, 1);
+        countingStream->write((uint64_t*)&cgen_var_644, 1 * 8);
         countingStream->write((uint32_t*)&local_firstQuery, sizeof(uint32_t));
         countingStream->write((uint32_t*)&local_queryCount, sizeof(uint32_t));
-        uint64_t cgen_var_641;
-        countingStream->handleMapping()->mapHandles_VkBuffer_u64(&local_dstBuffer, &cgen_var_641, 1);
-        countingStream->write((uint64_t*)&cgen_var_641, 1 * 8);
+        uint64_t cgen_var_645;
+        countingStream->handleMapping()->mapHandles_VkBuffer_u64(&local_dstBuffer, &cgen_var_645, 1);
+        countingStream->write((uint64_t*)&cgen_var_645, 1 * 8);
         countingStream->write((VkDeviceSize*)&local_dstOffset, sizeof(VkDeviceSize));
         countingStream->write((VkDeviceSize*)&local_stride, sizeof(VkDeviceSize));
         countingStream->write((VkQueryResultFlags*)&local_flags, sizeof(VkQueryResultFlags));
@@ -9405,17 +9644,17 @@
     uint32_t opcode_vkCmdCopyQueryPoolResults = OP_vkCmdCopyQueryPoolResults;
     stream->write(&opcode_vkCmdCopyQueryPoolResults, sizeof(uint32_t));
     stream->write(&packetSize_vkCmdCopyQueryPoolResults, sizeof(uint32_t));
-    uint64_t cgen_var_642;
-    stream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_642, 1);
-    stream->write((uint64_t*)&cgen_var_642, 1 * 8);
-    uint64_t cgen_var_643;
-    stream->handleMapping()->mapHandles_VkQueryPool_u64(&local_queryPool, &cgen_var_643, 1);
-    stream->write((uint64_t*)&cgen_var_643, 1 * 8);
+    uint64_t cgen_var_646;
+    stream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_646, 1);
+    stream->write((uint64_t*)&cgen_var_646, 1 * 8);
+    uint64_t cgen_var_647;
+    stream->handleMapping()->mapHandles_VkQueryPool_u64(&local_queryPool, &cgen_var_647, 1);
+    stream->write((uint64_t*)&cgen_var_647, 1 * 8);
     stream->write((uint32_t*)&local_firstQuery, sizeof(uint32_t));
     stream->write((uint32_t*)&local_queryCount, sizeof(uint32_t));
-    uint64_t cgen_var_644;
-    stream->handleMapping()->mapHandles_VkBuffer_u64(&local_dstBuffer, &cgen_var_644, 1);
-    stream->write((uint64_t*)&cgen_var_644, 1 * 8);
+    uint64_t cgen_var_648;
+    stream->handleMapping()->mapHandles_VkBuffer_u64(&local_dstBuffer, &cgen_var_648, 1);
+    stream->write((uint64_t*)&cgen_var_648, 1 * 8);
     stream->write((VkDeviceSize*)&local_dstOffset, sizeof(VkDeviceSize));
     stream->write((VkDeviceSize*)&local_stride, sizeof(VkDeviceSize));
     stream->write((VkQueryResultFlags*)&local_flags, sizeof(VkQueryResultFlags));
@@ -9432,6 +9671,7 @@
     uint32_t size,
     const void* pValues)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkCmdPushConstants encode");
     mImpl->log("start vkCmdPushConstants");
     auto stream = mImpl->stream();
@@ -9457,12 +9697,12 @@
     }
     countingStream->rewind();
     {
-        uint64_t cgen_var_645;
-        countingStream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_645, 1);
-        countingStream->write((uint64_t*)&cgen_var_645, 1 * 8);
-        uint64_t cgen_var_646;
-        countingStream->handleMapping()->mapHandles_VkPipelineLayout_u64(&local_layout, &cgen_var_646, 1);
-        countingStream->write((uint64_t*)&cgen_var_646, 1 * 8);
+        uint64_t cgen_var_649;
+        countingStream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_649, 1);
+        countingStream->write((uint64_t*)&cgen_var_649, 1 * 8);
+        uint64_t cgen_var_650;
+        countingStream->handleMapping()->mapHandles_VkPipelineLayout_u64(&local_layout, &cgen_var_650, 1);
+        countingStream->write((uint64_t*)&cgen_var_650, 1 * 8);
         countingStream->write((VkShaderStageFlags*)&local_stageFlags, sizeof(VkShaderStageFlags));
         countingStream->write((uint32_t*)&local_offset, sizeof(uint32_t));
         countingStream->write((uint32_t*)&local_size, sizeof(uint32_t));
@@ -9473,12 +9713,12 @@
     uint32_t opcode_vkCmdPushConstants = OP_vkCmdPushConstants;
     stream->write(&opcode_vkCmdPushConstants, sizeof(uint32_t));
     stream->write(&packetSize_vkCmdPushConstants, sizeof(uint32_t));
-    uint64_t cgen_var_647;
-    stream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_647, 1);
-    stream->write((uint64_t*)&cgen_var_647, 1 * 8);
-    uint64_t cgen_var_648;
-    stream->handleMapping()->mapHandles_VkPipelineLayout_u64(&local_layout, &cgen_var_648, 1);
-    stream->write((uint64_t*)&cgen_var_648, 1 * 8);
+    uint64_t cgen_var_651;
+    stream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_651, 1);
+    stream->write((uint64_t*)&cgen_var_651, 1 * 8);
+    uint64_t cgen_var_652;
+    stream->handleMapping()->mapHandles_VkPipelineLayout_u64(&local_layout, &cgen_var_652, 1);
+    stream->write((uint64_t*)&cgen_var_652, 1 * 8);
     stream->write((VkShaderStageFlags*)&local_stageFlags, sizeof(VkShaderStageFlags));
     stream->write((uint32_t*)&local_offset, sizeof(uint32_t));
     stream->write((uint32_t*)&local_size, sizeof(uint32_t));
@@ -9493,6 +9733,7 @@
     const VkRenderPassBeginInfo* pRenderPassBegin,
     VkSubpassContents contents)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkCmdBeginRenderPass encode");
     mImpl->log("start vkCmdBeginRenderPass");
     auto stream = mImpl->stream();
@@ -9517,9 +9758,9 @@
     }
     countingStream->rewind();
     {
-        uint64_t cgen_var_649;
-        countingStream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_649, 1);
-        countingStream->write((uint64_t*)&cgen_var_649, 1 * 8);
+        uint64_t cgen_var_653;
+        countingStream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_653, 1);
+        countingStream->write((uint64_t*)&cgen_var_653, 1 * 8);
         marshal_VkRenderPassBeginInfo(countingStream, (VkRenderPassBeginInfo*)(local_pRenderPassBegin));
         countingStream->write((VkSubpassContents*)&local_contents, sizeof(VkSubpassContents));
     }
@@ -9528,9 +9769,9 @@
     uint32_t opcode_vkCmdBeginRenderPass = OP_vkCmdBeginRenderPass;
     stream->write(&opcode_vkCmdBeginRenderPass, sizeof(uint32_t));
     stream->write(&packetSize_vkCmdBeginRenderPass, sizeof(uint32_t));
-    uint64_t cgen_var_650;
-    stream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_650, 1);
-    stream->write((uint64_t*)&cgen_var_650, 1 * 8);
+    uint64_t cgen_var_654;
+    stream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_654, 1);
+    stream->write((uint64_t*)&cgen_var_654, 1 * 8);
     marshal_VkRenderPassBeginInfo(stream, (VkRenderPassBeginInfo*)(local_pRenderPassBegin));
     stream->write((VkSubpassContents*)&local_contents, sizeof(VkSubpassContents));
     AEMU_SCOPED_TRACE("vkCmdBeginRenderPass readParams");
@@ -9542,6 +9783,7 @@
     VkCommandBuffer commandBuffer,
     VkSubpassContents contents)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkCmdNextSubpass encode");
     mImpl->log("start vkCmdNextSubpass");
     auto stream = mImpl->stream();
@@ -9555,9 +9797,9 @@
     local_contents = contents;
     countingStream->rewind();
     {
-        uint64_t cgen_var_651;
-        countingStream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_651, 1);
-        countingStream->write((uint64_t*)&cgen_var_651, 1 * 8);
+        uint64_t cgen_var_655;
+        countingStream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_655, 1);
+        countingStream->write((uint64_t*)&cgen_var_655, 1 * 8);
         countingStream->write((VkSubpassContents*)&local_contents, sizeof(VkSubpassContents));
     }
     uint32_t packetSize_vkCmdNextSubpass = 4 + 4 + (uint32_t)countingStream->bytesWritten();
@@ -9565,9 +9807,9 @@
     uint32_t opcode_vkCmdNextSubpass = OP_vkCmdNextSubpass;
     stream->write(&opcode_vkCmdNextSubpass, sizeof(uint32_t));
     stream->write(&packetSize_vkCmdNextSubpass, sizeof(uint32_t));
-    uint64_t cgen_var_652;
-    stream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_652, 1);
-    stream->write((uint64_t*)&cgen_var_652, 1 * 8);
+    uint64_t cgen_var_656;
+    stream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_656, 1);
+    stream->write((uint64_t*)&cgen_var_656, 1 * 8);
     stream->write((VkSubpassContents*)&local_contents, sizeof(VkSubpassContents));
     AEMU_SCOPED_TRACE("vkCmdNextSubpass readParams");
     AEMU_SCOPED_TRACE("vkCmdNextSubpass returnUnmarshal");
@@ -9577,6 +9819,7 @@
 void VkEncoder::vkCmdEndRenderPass(
     VkCommandBuffer commandBuffer)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkCmdEndRenderPass encode");
     mImpl->log("start vkCmdEndRenderPass");
     auto stream = mImpl->stream();
@@ -9588,18 +9831,18 @@
     local_commandBuffer = commandBuffer;
     countingStream->rewind();
     {
-        uint64_t cgen_var_653;
-        countingStream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_653, 1);
-        countingStream->write((uint64_t*)&cgen_var_653, 1 * 8);
+        uint64_t cgen_var_657;
+        countingStream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_657, 1);
+        countingStream->write((uint64_t*)&cgen_var_657, 1 * 8);
     }
     uint32_t packetSize_vkCmdEndRenderPass = 4 + 4 + (uint32_t)countingStream->bytesWritten();
     countingStream->rewind();
     uint32_t opcode_vkCmdEndRenderPass = OP_vkCmdEndRenderPass;
     stream->write(&opcode_vkCmdEndRenderPass, sizeof(uint32_t));
     stream->write(&packetSize_vkCmdEndRenderPass, sizeof(uint32_t));
-    uint64_t cgen_var_654;
-    stream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_654, 1);
-    stream->write((uint64_t*)&cgen_var_654, 1 * 8);
+    uint64_t cgen_var_658;
+    stream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_658, 1);
+    stream->write((uint64_t*)&cgen_var_658, 1 * 8);
     AEMU_SCOPED_TRACE("vkCmdEndRenderPass readParams");
     AEMU_SCOPED_TRACE("vkCmdEndRenderPass returnUnmarshal");
     mImpl->log("finish vkCmdEndRenderPass");;
@@ -9610,6 +9853,7 @@
     uint32_t commandBufferCount,
     const VkCommandBuffer* pCommandBuffers)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkCmdExecuteCommands encode");
     mImpl->log("start vkCmdExecuteCommands");
     auto stream = mImpl->stream();
@@ -9629,16 +9873,16 @@
     }
     countingStream->rewind();
     {
-        uint64_t cgen_var_655;
-        countingStream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_655, 1);
-        countingStream->write((uint64_t*)&cgen_var_655, 1 * 8);
+        uint64_t cgen_var_659;
+        countingStream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_659, 1);
+        countingStream->write((uint64_t*)&cgen_var_659, 1 * 8);
         countingStream->write((uint32_t*)&local_commandBufferCount, sizeof(uint32_t));
         if (((commandBufferCount)))
         {
-            uint64_t* cgen_var_656;
-            countingStream->alloc((void**)&cgen_var_656, ((commandBufferCount)) * 8);
-            countingStream->handleMapping()->mapHandles_VkCommandBuffer_u64(local_pCommandBuffers, cgen_var_656, ((commandBufferCount)));
-            countingStream->write((uint64_t*)cgen_var_656, ((commandBufferCount)) * 8);
+            uint64_t* cgen_var_660;
+            countingStream->alloc((void**)&cgen_var_660, ((commandBufferCount)) * 8);
+            countingStream->handleMapping()->mapHandles_VkCommandBuffer_u64(local_pCommandBuffers, cgen_var_660, ((commandBufferCount)));
+            countingStream->write((uint64_t*)cgen_var_660, ((commandBufferCount)) * 8);
         }
     }
     uint32_t packetSize_vkCmdExecuteCommands = 4 + 4 + (uint32_t)countingStream->bytesWritten();
@@ -9646,16 +9890,16 @@
     uint32_t opcode_vkCmdExecuteCommands = OP_vkCmdExecuteCommands;
     stream->write(&opcode_vkCmdExecuteCommands, sizeof(uint32_t));
     stream->write(&packetSize_vkCmdExecuteCommands, sizeof(uint32_t));
-    uint64_t cgen_var_657;
-    stream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_657, 1);
-    stream->write((uint64_t*)&cgen_var_657, 1 * 8);
+    uint64_t cgen_var_661;
+    stream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_661, 1);
+    stream->write((uint64_t*)&cgen_var_661, 1 * 8);
     stream->write((uint32_t*)&local_commandBufferCount, sizeof(uint32_t));
     if (((commandBufferCount)))
     {
-        uint64_t* cgen_var_658;
-        stream->alloc((void**)&cgen_var_658, ((commandBufferCount)) * 8);
-        stream->handleMapping()->mapHandles_VkCommandBuffer_u64(local_pCommandBuffers, cgen_var_658, ((commandBufferCount)));
-        stream->write((uint64_t*)cgen_var_658, ((commandBufferCount)) * 8);
+        uint64_t* cgen_var_662;
+        stream->alloc((void**)&cgen_var_662, ((commandBufferCount)) * 8);
+        stream->handleMapping()->mapHandles_VkCommandBuffer_u64(local_pCommandBuffers, cgen_var_662, ((commandBufferCount)));
+        stream->write((uint64_t*)cgen_var_662, ((commandBufferCount)) * 8);
     }
     AEMU_SCOPED_TRACE("vkCmdExecuteCommands readParams");
     AEMU_SCOPED_TRACE("vkCmdExecuteCommands returnUnmarshal");
@@ -9667,6 +9911,7 @@
 VkResult VkEncoder::vkEnumerateInstanceVersion(
     uint32_t* pApiVersion)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkEnumerateInstanceVersion encode");
     mImpl->log("start vkEnumerateInstanceVersion");
     auto stream = mImpl->stream();
@@ -9701,6 +9946,7 @@
     uint32_t bindInfoCount,
     const VkBindBufferMemoryInfo* pBindInfos)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkBindBufferMemory2 encode");
     mImpl->log("start vkBindBufferMemory2");
     auto stream = mImpl->stream();
@@ -9731,9 +9977,9 @@
     }
     countingStream->rewind();
     {
-        uint64_t cgen_var_659;
-        countingStream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_659, 1);
-        countingStream->write((uint64_t*)&cgen_var_659, 1 * 8);
+        uint64_t cgen_var_663;
+        countingStream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_663, 1);
+        countingStream->write((uint64_t*)&cgen_var_663, 1 * 8);
         countingStream->write((uint32_t*)&local_bindInfoCount, sizeof(uint32_t));
         for (uint32_t i = 0; i < (uint32_t)((bindInfoCount)); ++i)
         {
@@ -9745,9 +9991,9 @@
     uint32_t opcode_vkBindBufferMemory2 = OP_vkBindBufferMemory2;
     stream->write(&opcode_vkBindBufferMemory2, sizeof(uint32_t));
     stream->write(&packetSize_vkBindBufferMemory2, sizeof(uint32_t));
-    uint64_t cgen_var_660;
-    stream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_660, 1);
-    stream->write((uint64_t*)&cgen_var_660, 1 * 8);
+    uint64_t cgen_var_664;
+    stream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_664, 1);
+    stream->write((uint64_t*)&cgen_var_664, 1 * 8);
     stream->write((uint32_t*)&local_bindInfoCount, sizeof(uint32_t));
     for (uint32_t i = 0; i < (uint32_t)((bindInfoCount)); ++i)
     {
@@ -9769,6 +10015,7 @@
     uint32_t bindInfoCount,
     const VkBindImageMemoryInfo* pBindInfos)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkBindImageMemory2 encode");
     mImpl->log("start vkBindImageMemory2");
     auto stream = mImpl->stream();
@@ -9799,9 +10046,9 @@
     }
     countingStream->rewind();
     {
-        uint64_t cgen_var_661;
-        countingStream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_661, 1);
-        countingStream->write((uint64_t*)&cgen_var_661, 1 * 8);
+        uint64_t cgen_var_665;
+        countingStream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_665, 1);
+        countingStream->write((uint64_t*)&cgen_var_665, 1 * 8);
         countingStream->write((uint32_t*)&local_bindInfoCount, sizeof(uint32_t));
         for (uint32_t i = 0; i < (uint32_t)((bindInfoCount)); ++i)
         {
@@ -9813,9 +10060,9 @@
     uint32_t opcode_vkBindImageMemory2 = OP_vkBindImageMemory2;
     stream->write(&opcode_vkBindImageMemory2, sizeof(uint32_t));
     stream->write(&packetSize_vkBindImageMemory2, sizeof(uint32_t));
-    uint64_t cgen_var_662;
-    stream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_662, 1);
-    stream->write((uint64_t*)&cgen_var_662, 1 * 8);
+    uint64_t cgen_var_666;
+    stream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_666, 1);
+    stream->write((uint64_t*)&cgen_var_666, 1 * 8);
     stream->write((uint32_t*)&local_bindInfoCount, sizeof(uint32_t));
     for (uint32_t i = 0; i < (uint32_t)((bindInfoCount)); ++i)
     {
@@ -9839,6 +10086,7 @@
     uint32_t remoteDeviceIndex,
     VkPeerMemoryFeatureFlags* pPeerMemoryFeatures)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkGetDeviceGroupPeerMemoryFeatures encode");
     mImpl->log("start vkGetDeviceGroupPeerMemoryFeatures");
     auto stream = mImpl->stream();
@@ -9856,9 +10104,9 @@
     local_remoteDeviceIndex = remoteDeviceIndex;
     countingStream->rewind();
     {
-        uint64_t cgen_var_663;
-        countingStream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_663, 1);
-        countingStream->write((uint64_t*)&cgen_var_663, 1 * 8);
+        uint64_t cgen_var_667;
+        countingStream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_667, 1);
+        countingStream->write((uint64_t*)&cgen_var_667, 1 * 8);
         countingStream->write((uint32_t*)&local_heapIndex, sizeof(uint32_t));
         countingStream->write((uint32_t*)&local_localDeviceIndex, sizeof(uint32_t));
         countingStream->write((uint32_t*)&local_remoteDeviceIndex, sizeof(uint32_t));
@@ -9869,9 +10117,9 @@
     uint32_t opcode_vkGetDeviceGroupPeerMemoryFeatures = OP_vkGetDeviceGroupPeerMemoryFeatures;
     stream->write(&opcode_vkGetDeviceGroupPeerMemoryFeatures, sizeof(uint32_t));
     stream->write(&packetSize_vkGetDeviceGroupPeerMemoryFeatures, sizeof(uint32_t));
-    uint64_t cgen_var_664;
-    stream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_664, 1);
-    stream->write((uint64_t*)&cgen_var_664, 1 * 8);
+    uint64_t cgen_var_668;
+    stream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_668, 1);
+    stream->write((uint64_t*)&cgen_var_668, 1 * 8);
     stream->write((uint32_t*)&local_heapIndex, sizeof(uint32_t));
     stream->write((uint32_t*)&local_localDeviceIndex, sizeof(uint32_t));
     stream->write((uint32_t*)&local_remoteDeviceIndex, sizeof(uint32_t));
@@ -9886,6 +10134,7 @@
     VkCommandBuffer commandBuffer,
     uint32_t deviceMask)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkCmdSetDeviceMask encode");
     mImpl->log("start vkCmdSetDeviceMask");
     auto stream = mImpl->stream();
@@ -9899,9 +10148,9 @@
     local_deviceMask = deviceMask;
     countingStream->rewind();
     {
-        uint64_t cgen_var_665;
-        countingStream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_665, 1);
-        countingStream->write((uint64_t*)&cgen_var_665, 1 * 8);
+        uint64_t cgen_var_669;
+        countingStream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_669, 1);
+        countingStream->write((uint64_t*)&cgen_var_669, 1 * 8);
         countingStream->write((uint32_t*)&local_deviceMask, sizeof(uint32_t));
     }
     uint32_t packetSize_vkCmdSetDeviceMask = 4 + 4 + (uint32_t)countingStream->bytesWritten();
@@ -9909,9 +10158,9 @@
     uint32_t opcode_vkCmdSetDeviceMask = OP_vkCmdSetDeviceMask;
     stream->write(&opcode_vkCmdSetDeviceMask, sizeof(uint32_t));
     stream->write(&packetSize_vkCmdSetDeviceMask, sizeof(uint32_t));
-    uint64_t cgen_var_666;
-    stream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_666, 1);
-    stream->write((uint64_t*)&cgen_var_666, 1 * 8);
+    uint64_t cgen_var_670;
+    stream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_670, 1);
+    stream->write((uint64_t*)&cgen_var_670, 1 * 8);
     stream->write((uint32_t*)&local_deviceMask, sizeof(uint32_t));
     AEMU_SCOPED_TRACE("vkCmdSetDeviceMask readParams");
     AEMU_SCOPED_TRACE("vkCmdSetDeviceMask returnUnmarshal");
@@ -9927,6 +10176,7 @@
     uint32_t groupCountY,
     uint32_t groupCountZ)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkCmdDispatchBase encode");
     mImpl->log("start vkCmdDispatchBase");
     auto stream = mImpl->stream();
@@ -9950,9 +10200,9 @@
     local_groupCountZ = groupCountZ;
     countingStream->rewind();
     {
-        uint64_t cgen_var_667;
-        countingStream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_667, 1);
-        countingStream->write((uint64_t*)&cgen_var_667, 1 * 8);
+        uint64_t cgen_var_671;
+        countingStream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_671, 1);
+        countingStream->write((uint64_t*)&cgen_var_671, 1 * 8);
         countingStream->write((uint32_t*)&local_baseGroupX, sizeof(uint32_t));
         countingStream->write((uint32_t*)&local_baseGroupY, sizeof(uint32_t));
         countingStream->write((uint32_t*)&local_baseGroupZ, sizeof(uint32_t));
@@ -9965,9 +10215,9 @@
     uint32_t opcode_vkCmdDispatchBase = OP_vkCmdDispatchBase;
     stream->write(&opcode_vkCmdDispatchBase, sizeof(uint32_t));
     stream->write(&packetSize_vkCmdDispatchBase, sizeof(uint32_t));
-    uint64_t cgen_var_668;
-    stream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_668, 1);
-    stream->write((uint64_t*)&cgen_var_668, 1 * 8);
+    uint64_t cgen_var_672;
+    stream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_672, 1);
+    stream->write((uint64_t*)&cgen_var_672, 1 * 8);
     stream->write((uint32_t*)&local_baseGroupX, sizeof(uint32_t));
     stream->write((uint32_t*)&local_baseGroupY, sizeof(uint32_t));
     stream->write((uint32_t*)&local_baseGroupZ, sizeof(uint32_t));
@@ -9984,6 +10234,7 @@
     uint32_t* pPhysicalDeviceGroupCount,
     VkPhysicalDeviceGroupProperties* pPhysicalDeviceGroupProperties)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkEnumeratePhysicalDeviceGroups encode");
     mImpl->log("start vkEnumeratePhysicalDeviceGroups");
     auto stream = mImpl->stream();
@@ -9995,19 +10246,19 @@
     local_instance = instance;
     countingStream->rewind();
     {
-        uint64_t cgen_var_669;
-        countingStream->handleMapping()->mapHandles_VkInstance_u64(&local_instance, &cgen_var_669, 1);
-        countingStream->write((uint64_t*)&cgen_var_669, 1 * 8);
+        uint64_t cgen_var_673;
+        countingStream->handleMapping()->mapHandles_VkInstance_u64(&local_instance, &cgen_var_673, 1);
+        countingStream->write((uint64_t*)&cgen_var_673, 1 * 8);
         // WARNING PTR CHECK
-        uint64_t cgen_var_670 = (uint64_t)(uintptr_t)pPhysicalDeviceGroupCount;
-        countingStream->putBe64(cgen_var_670);
+        uint64_t cgen_var_674 = (uint64_t)(uintptr_t)pPhysicalDeviceGroupCount;
+        countingStream->putBe64(cgen_var_674);
         if (pPhysicalDeviceGroupCount)
         {
             countingStream->write((uint32_t*)pPhysicalDeviceGroupCount, sizeof(uint32_t));
         }
         // WARNING PTR CHECK
-        uint64_t cgen_var_671 = (uint64_t)(uintptr_t)pPhysicalDeviceGroupProperties;
-        countingStream->putBe64(cgen_var_671);
+        uint64_t cgen_var_675 = (uint64_t)(uintptr_t)pPhysicalDeviceGroupProperties;
+        countingStream->putBe64(cgen_var_675);
         if (pPhysicalDeviceGroupProperties)
         {
             for (uint32_t i = 0; i < (uint32_t)(*(pPhysicalDeviceGroupCount)); ++i)
@@ -10021,19 +10272,19 @@
     uint32_t opcode_vkEnumeratePhysicalDeviceGroups = OP_vkEnumeratePhysicalDeviceGroups;
     stream->write(&opcode_vkEnumeratePhysicalDeviceGroups, sizeof(uint32_t));
     stream->write(&packetSize_vkEnumeratePhysicalDeviceGroups, sizeof(uint32_t));
-    uint64_t cgen_var_672;
-    stream->handleMapping()->mapHandles_VkInstance_u64(&local_instance, &cgen_var_672, 1);
-    stream->write((uint64_t*)&cgen_var_672, 1 * 8);
+    uint64_t cgen_var_676;
+    stream->handleMapping()->mapHandles_VkInstance_u64(&local_instance, &cgen_var_676, 1);
+    stream->write((uint64_t*)&cgen_var_676, 1 * 8);
     // WARNING PTR CHECK
-    uint64_t cgen_var_673 = (uint64_t)(uintptr_t)pPhysicalDeviceGroupCount;
-    stream->putBe64(cgen_var_673);
+    uint64_t cgen_var_677 = (uint64_t)(uintptr_t)pPhysicalDeviceGroupCount;
+    stream->putBe64(cgen_var_677);
     if (pPhysicalDeviceGroupCount)
     {
         stream->write((uint32_t*)pPhysicalDeviceGroupCount, sizeof(uint32_t));
     }
     // WARNING PTR CHECK
-    uint64_t cgen_var_674 = (uint64_t)(uintptr_t)pPhysicalDeviceGroupProperties;
-    stream->putBe64(cgen_var_674);
+    uint64_t cgen_var_678 = (uint64_t)(uintptr_t)pPhysicalDeviceGroupProperties;
+    stream->putBe64(cgen_var_678);
     if (pPhysicalDeviceGroupProperties)
     {
         for (uint32_t i = 0; i < (uint32_t)(*(pPhysicalDeviceGroupCount)); ++i)
@@ -10089,6 +10340,7 @@
     const VkImageMemoryRequirementsInfo2* pInfo,
     VkMemoryRequirements2* pMemoryRequirements)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkGetImageMemoryRequirements2 encode");
     mImpl->log("start vkGetImageMemoryRequirements2");
     auto stream = mImpl->stream();
@@ -10111,9 +10363,9 @@
     }
     countingStream->rewind();
     {
-        uint64_t cgen_var_677;
-        countingStream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_677, 1);
-        countingStream->write((uint64_t*)&cgen_var_677, 1 * 8);
+        uint64_t cgen_var_681;
+        countingStream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_681, 1);
+        countingStream->write((uint64_t*)&cgen_var_681, 1 * 8);
         marshal_VkImageMemoryRequirementsInfo2(countingStream, (VkImageMemoryRequirementsInfo2*)(local_pInfo));
         marshal_VkMemoryRequirements2(countingStream, (VkMemoryRequirements2*)(pMemoryRequirements));
     }
@@ -10122,9 +10374,9 @@
     uint32_t opcode_vkGetImageMemoryRequirements2 = OP_vkGetImageMemoryRequirements2;
     stream->write(&opcode_vkGetImageMemoryRequirements2, sizeof(uint32_t));
     stream->write(&packetSize_vkGetImageMemoryRequirements2, sizeof(uint32_t));
-    uint64_t cgen_var_678;
-    stream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_678, 1);
-    stream->write((uint64_t*)&cgen_var_678, 1 * 8);
+    uint64_t cgen_var_682;
+    stream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_682, 1);
+    stream->write((uint64_t*)&cgen_var_682, 1 * 8);
     marshal_VkImageMemoryRequirementsInfo2(stream, (VkImageMemoryRequirementsInfo2*)(local_pInfo));
     marshal_VkMemoryRequirements2(stream, (VkMemoryRequirements2*)(pMemoryRequirements));
     AEMU_SCOPED_TRACE("vkGetImageMemoryRequirements2 readParams");
@@ -10142,6 +10394,7 @@
     const VkBufferMemoryRequirementsInfo2* pInfo,
     VkMemoryRequirements2* pMemoryRequirements)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkGetBufferMemoryRequirements2 encode");
     mImpl->log("start vkGetBufferMemoryRequirements2");
     auto stream = mImpl->stream();
@@ -10164,9 +10417,9 @@
     }
     countingStream->rewind();
     {
-        uint64_t cgen_var_679;
-        countingStream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_679, 1);
-        countingStream->write((uint64_t*)&cgen_var_679, 1 * 8);
+        uint64_t cgen_var_683;
+        countingStream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_683, 1);
+        countingStream->write((uint64_t*)&cgen_var_683, 1 * 8);
         marshal_VkBufferMemoryRequirementsInfo2(countingStream, (VkBufferMemoryRequirementsInfo2*)(local_pInfo));
         marshal_VkMemoryRequirements2(countingStream, (VkMemoryRequirements2*)(pMemoryRequirements));
     }
@@ -10175,9 +10428,9 @@
     uint32_t opcode_vkGetBufferMemoryRequirements2 = OP_vkGetBufferMemoryRequirements2;
     stream->write(&opcode_vkGetBufferMemoryRequirements2, sizeof(uint32_t));
     stream->write(&packetSize_vkGetBufferMemoryRequirements2, sizeof(uint32_t));
-    uint64_t cgen_var_680;
-    stream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_680, 1);
-    stream->write((uint64_t*)&cgen_var_680, 1 * 8);
+    uint64_t cgen_var_684;
+    stream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_684, 1);
+    stream->write((uint64_t*)&cgen_var_684, 1 * 8);
     marshal_VkBufferMemoryRequirementsInfo2(stream, (VkBufferMemoryRequirementsInfo2*)(local_pInfo));
     marshal_VkMemoryRequirements2(stream, (VkMemoryRequirements2*)(pMemoryRequirements));
     AEMU_SCOPED_TRACE("vkGetBufferMemoryRequirements2 readParams");
@@ -10196,6 +10449,7 @@
     uint32_t* pSparseMemoryRequirementCount,
     VkSparseImageMemoryRequirements2* pSparseMemoryRequirements)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkGetImageSparseMemoryRequirements2 encode");
     mImpl->log("start vkGetImageSparseMemoryRequirements2");
     auto stream = mImpl->stream();
@@ -10218,20 +10472,20 @@
     }
     countingStream->rewind();
     {
-        uint64_t cgen_var_681;
-        countingStream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_681, 1);
-        countingStream->write((uint64_t*)&cgen_var_681, 1 * 8);
+        uint64_t cgen_var_685;
+        countingStream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_685, 1);
+        countingStream->write((uint64_t*)&cgen_var_685, 1 * 8);
         marshal_VkImageSparseMemoryRequirementsInfo2(countingStream, (VkImageSparseMemoryRequirementsInfo2*)(local_pInfo));
         // WARNING PTR CHECK
-        uint64_t cgen_var_682 = (uint64_t)(uintptr_t)pSparseMemoryRequirementCount;
-        countingStream->putBe64(cgen_var_682);
+        uint64_t cgen_var_686 = (uint64_t)(uintptr_t)pSparseMemoryRequirementCount;
+        countingStream->putBe64(cgen_var_686);
         if (pSparseMemoryRequirementCount)
         {
             countingStream->write((uint32_t*)pSparseMemoryRequirementCount, sizeof(uint32_t));
         }
         // WARNING PTR CHECK
-        uint64_t cgen_var_683 = (uint64_t)(uintptr_t)pSparseMemoryRequirements;
-        countingStream->putBe64(cgen_var_683);
+        uint64_t cgen_var_687 = (uint64_t)(uintptr_t)pSparseMemoryRequirements;
+        countingStream->putBe64(cgen_var_687);
         if (pSparseMemoryRequirements)
         {
             for (uint32_t i = 0; i < (uint32_t)(*(pSparseMemoryRequirementCount)); ++i)
@@ -10245,20 +10499,20 @@
     uint32_t opcode_vkGetImageSparseMemoryRequirements2 = OP_vkGetImageSparseMemoryRequirements2;
     stream->write(&opcode_vkGetImageSparseMemoryRequirements2, sizeof(uint32_t));
     stream->write(&packetSize_vkGetImageSparseMemoryRequirements2, sizeof(uint32_t));
-    uint64_t cgen_var_684;
-    stream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_684, 1);
-    stream->write((uint64_t*)&cgen_var_684, 1 * 8);
+    uint64_t cgen_var_688;
+    stream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_688, 1);
+    stream->write((uint64_t*)&cgen_var_688, 1 * 8);
     marshal_VkImageSparseMemoryRequirementsInfo2(stream, (VkImageSparseMemoryRequirementsInfo2*)(local_pInfo));
     // WARNING PTR CHECK
-    uint64_t cgen_var_685 = (uint64_t)(uintptr_t)pSparseMemoryRequirementCount;
-    stream->putBe64(cgen_var_685);
+    uint64_t cgen_var_689 = (uint64_t)(uintptr_t)pSparseMemoryRequirementCount;
+    stream->putBe64(cgen_var_689);
     if (pSparseMemoryRequirementCount)
     {
         stream->write((uint32_t*)pSparseMemoryRequirementCount, sizeof(uint32_t));
     }
     // WARNING PTR CHECK
-    uint64_t cgen_var_686 = (uint64_t)(uintptr_t)pSparseMemoryRequirements;
-    stream->putBe64(cgen_var_686);
+    uint64_t cgen_var_690 = (uint64_t)(uintptr_t)pSparseMemoryRequirements;
+    stream->putBe64(cgen_var_690);
     if (pSparseMemoryRequirements)
     {
         for (uint32_t i = 0; i < (uint32_t)(*(pSparseMemoryRequirementCount)); ++i)
@@ -10307,6 +10561,7 @@
     VkPhysicalDevice physicalDevice,
     VkPhysicalDeviceFeatures2* pFeatures)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkGetPhysicalDeviceFeatures2 encode");
     mImpl->log("start vkGetPhysicalDeviceFeatures2");
     auto stream = mImpl->stream();
@@ -10318,9 +10573,9 @@
     local_physicalDevice = physicalDevice;
     countingStream->rewind();
     {
-        uint64_t cgen_var_689;
-        countingStream->handleMapping()->mapHandles_VkPhysicalDevice_u64(&local_physicalDevice, &cgen_var_689, 1);
-        countingStream->write((uint64_t*)&cgen_var_689, 1 * 8);
+        uint64_t cgen_var_693;
+        countingStream->handleMapping()->mapHandles_VkPhysicalDevice_u64(&local_physicalDevice, &cgen_var_693, 1);
+        countingStream->write((uint64_t*)&cgen_var_693, 1 * 8);
         marshal_VkPhysicalDeviceFeatures2(countingStream, (VkPhysicalDeviceFeatures2*)(pFeatures));
     }
     uint32_t packetSize_vkGetPhysicalDeviceFeatures2 = 4 + 4 + (uint32_t)countingStream->bytesWritten();
@@ -10328,9 +10583,9 @@
     uint32_t opcode_vkGetPhysicalDeviceFeatures2 = OP_vkGetPhysicalDeviceFeatures2;
     stream->write(&opcode_vkGetPhysicalDeviceFeatures2, sizeof(uint32_t));
     stream->write(&packetSize_vkGetPhysicalDeviceFeatures2, sizeof(uint32_t));
-    uint64_t cgen_var_690;
-    stream->handleMapping()->mapHandles_VkPhysicalDevice_u64(&local_physicalDevice, &cgen_var_690, 1);
-    stream->write((uint64_t*)&cgen_var_690, 1 * 8);
+    uint64_t cgen_var_694;
+    stream->handleMapping()->mapHandles_VkPhysicalDevice_u64(&local_physicalDevice, &cgen_var_694, 1);
+    stream->write((uint64_t*)&cgen_var_694, 1 * 8);
     marshal_VkPhysicalDeviceFeatures2(stream, (VkPhysicalDeviceFeatures2*)(pFeatures));
     AEMU_SCOPED_TRACE("vkGetPhysicalDeviceFeatures2 readParams");
     unmarshal_VkPhysicalDeviceFeatures2(stream, (VkPhysicalDeviceFeatures2*)(pFeatures));
@@ -10346,6 +10601,7 @@
     VkPhysicalDevice physicalDevice,
     VkPhysicalDeviceProperties2* pProperties)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkGetPhysicalDeviceProperties2 encode");
     mImpl->log("start vkGetPhysicalDeviceProperties2");
     auto stream = mImpl->stream();
@@ -10357,9 +10613,9 @@
     local_physicalDevice = physicalDevice;
     countingStream->rewind();
     {
-        uint64_t cgen_var_691;
-        countingStream->handleMapping()->mapHandles_VkPhysicalDevice_u64(&local_physicalDevice, &cgen_var_691, 1);
-        countingStream->write((uint64_t*)&cgen_var_691, 1 * 8);
+        uint64_t cgen_var_695;
+        countingStream->handleMapping()->mapHandles_VkPhysicalDevice_u64(&local_physicalDevice, &cgen_var_695, 1);
+        countingStream->write((uint64_t*)&cgen_var_695, 1 * 8);
         marshal_VkPhysicalDeviceProperties2(countingStream, (VkPhysicalDeviceProperties2*)(pProperties));
     }
     uint32_t packetSize_vkGetPhysicalDeviceProperties2 = 4 + 4 + (uint32_t)countingStream->bytesWritten();
@@ -10367,9 +10623,9 @@
     uint32_t opcode_vkGetPhysicalDeviceProperties2 = OP_vkGetPhysicalDeviceProperties2;
     stream->write(&opcode_vkGetPhysicalDeviceProperties2, sizeof(uint32_t));
     stream->write(&packetSize_vkGetPhysicalDeviceProperties2, sizeof(uint32_t));
-    uint64_t cgen_var_692;
-    stream->handleMapping()->mapHandles_VkPhysicalDevice_u64(&local_physicalDevice, &cgen_var_692, 1);
-    stream->write((uint64_t*)&cgen_var_692, 1 * 8);
+    uint64_t cgen_var_696;
+    stream->handleMapping()->mapHandles_VkPhysicalDevice_u64(&local_physicalDevice, &cgen_var_696, 1);
+    stream->write((uint64_t*)&cgen_var_696, 1 * 8);
     marshal_VkPhysicalDeviceProperties2(stream, (VkPhysicalDeviceProperties2*)(pProperties));
     AEMU_SCOPED_TRACE("vkGetPhysicalDeviceProperties2 readParams");
     unmarshal_VkPhysicalDeviceProperties2(stream, (VkPhysicalDeviceProperties2*)(pProperties));
@@ -10386,6 +10642,7 @@
     VkFormat format,
     VkFormatProperties2* pFormatProperties)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkGetPhysicalDeviceFormatProperties2 encode");
     mImpl->log("start vkGetPhysicalDeviceFormatProperties2");
     auto stream = mImpl->stream();
@@ -10399,9 +10656,9 @@
     local_format = format;
     countingStream->rewind();
     {
-        uint64_t cgen_var_693;
-        countingStream->handleMapping()->mapHandles_VkPhysicalDevice_u64(&local_physicalDevice, &cgen_var_693, 1);
-        countingStream->write((uint64_t*)&cgen_var_693, 1 * 8);
+        uint64_t cgen_var_697;
+        countingStream->handleMapping()->mapHandles_VkPhysicalDevice_u64(&local_physicalDevice, &cgen_var_697, 1);
+        countingStream->write((uint64_t*)&cgen_var_697, 1 * 8);
         countingStream->write((VkFormat*)&local_format, sizeof(VkFormat));
         marshal_VkFormatProperties2(countingStream, (VkFormatProperties2*)(pFormatProperties));
     }
@@ -10410,9 +10667,9 @@
     uint32_t opcode_vkGetPhysicalDeviceFormatProperties2 = OP_vkGetPhysicalDeviceFormatProperties2;
     stream->write(&opcode_vkGetPhysicalDeviceFormatProperties2, sizeof(uint32_t));
     stream->write(&packetSize_vkGetPhysicalDeviceFormatProperties2, sizeof(uint32_t));
-    uint64_t cgen_var_694;
-    stream->handleMapping()->mapHandles_VkPhysicalDevice_u64(&local_physicalDevice, &cgen_var_694, 1);
-    stream->write((uint64_t*)&cgen_var_694, 1 * 8);
+    uint64_t cgen_var_698;
+    stream->handleMapping()->mapHandles_VkPhysicalDevice_u64(&local_physicalDevice, &cgen_var_698, 1);
+    stream->write((uint64_t*)&cgen_var_698, 1 * 8);
     stream->write((VkFormat*)&local_format, sizeof(VkFormat));
     marshal_VkFormatProperties2(stream, (VkFormatProperties2*)(pFormatProperties));
     AEMU_SCOPED_TRACE("vkGetPhysicalDeviceFormatProperties2 readParams");
@@ -10430,6 +10687,7 @@
     const VkPhysicalDeviceImageFormatInfo2* pImageFormatInfo,
     VkImageFormatProperties2* pImageFormatProperties)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkGetPhysicalDeviceImageFormatProperties2 encode");
     mImpl->log("start vkGetPhysicalDeviceImageFormatProperties2");
     auto stream = mImpl->stream();
@@ -10452,9 +10710,9 @@
     }
     countingStream->rewind();
     {
-        uint64_t cgen_var_695;
-        countingStream->handleMapping()->mapHandles_VkPhysicalDevice_u64(&local_physicalDevice, &cgen_var_695, 1);
-        countingStream->write((uint64_t*)&cgen_var_695, 1 * 8);
+        uint64_t cgen_var_699;
+        countingStream->handleMapping()->mapHandles_VkPhysicalDevice_u64(&local_physicalDevice, &cgen_var_699, 1);
+        countingStream->write((uint64_t*)&cgen_var_699, 1 * 8);
         marshal_VkPhysicalDeviceImageFormatInfo2(countingStream, (VkPhysicalDeviceImageFormatInfo2*)(local_pImageFormatInfo));
         marshal_VkImageFormatProperties2(countingStream, (VkImageFormatProperties2*)(pImageFormatProperties));
     }
@@ -10463,9 +10721,9 @@
     uint32_t opcode_vkGetPhysicalDeviceImageFormatProperties2 = OP_vkGetPhysicalDeviceImageFormatProperties2;
     stream->write(&opcode_vkGetPhysicalDeviceImageFormatProperties2, sizeof(uint32_t));
     stream->write(&packetSize_vkGetPhysicalDeviceImageFormatProperties2, sizeof(uint32_t));
-    uint64_t cgen_var_696;
-    stream->handleMapping()->mapHandles_VkPhysicalDevice_u64(&local_physicalDevice, &cgen_var_696, 1);
-    stream->write((uint64_t*)&cgen_var_696, 1 * 8);
+    uint64_t cgen_var_700;
+    stream->handleMapping()->mapHandles_VkPhysicalDevice_u64(&local_physicalDevice, &cgen_var_700, 1);
+    stream->write((uint64_t*)&cgen_var_700, 1 * 8);
     marshal_VkPhysicalDeviceImageFormatInfo2(stream, (VkPhysicalDeviceImageFormatInfo2*)(local_pImageFormatInfo));
     marshal_VkImageFormatProperties2(stream, (VkImageFormatProperties2*)(pImageFormatProperties));
     AEMU_SCOPED_TRACE("vkGetPhysicalDeviceImageFormatProperties2 readParams");
@@ -10489,6 +10747,7 @@
     uint32_t* pQueueFamilyPropertyCount,
     VkQueueFamilyProperties2* pQueueFamilyProperties)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkGetPhysicalDeviceQueueFamilyProperties2 encode");
     mImpl->log("start vkGetPhysicalDeviceQueueFamilyProperties2");
     auto stream = mImpl->stream();
@@ -10500,19 +10759,19 @@
     local_physicalDevice = physicalDevice;
     countingStream->rewind();
     {
-        uint64_t cgen_var_697;
-        countingStream->handleMapping()->mapHandles_VkPhysicalDevice_u64(&local_physicalDevice, &cgen_var_697, 1);
-        countingStream->write((uint64_t*)&cgen_var_697, 1 * 8);
+        uint64_t cgen_var_701;
+        countingStream->handleMapping()->mapHandles_VkPhysicalDevice_u64(&local_physicalDevice, &cgen_var_701, 1);
+        countingStream->write((uint64_t*)&cgen_var_701, 1 * 8);
         // WARNING PTR CHECK
-        uint64_t cgen_var_698 = (uint64_t)(uintptr_t)pQueueFamilyPropertyCount;
-        countingStream->putBe64(cgen_var_698);
+        uint64_t cgen_var_702 = (uint64_t)(uintptr_t)pQueueFamilyPropertyCount;
+        countingStream->putBe64(cgen_var_702);
         if (pQueueFamilyPropertyCount)
         {
             countingStream->write((uint32_t*)pQueueFamilyPropertyCount, sizeof(uint32_t));
         }
         // WARNING PTR CHECK
-        uint64_t cgen_var_699 = (uint64_t)(uintptr_t)pQueueFamilyProperties;
-        countingStream->putBe64(cgen_var_699);
+        uint64_t cgen_var_703 = (uint64_t)(uintptr_t)pQueueFamilyProperties;
+        countingStream->putBe64(cgen_var_703);
         if (pQueueFamilyProperties)
         {
             for (uint32_t i = 0; i < (uint32_t)(*(pQueueFamilyPropertyCount)); ++i)
@@ -10526,19 +10785,19 @@
     uint32_t opcode_vkGetPhysicalDeviceQueueFamilyProperties2 = OP_vkGetPhysicalDeviceQueueFamilyProperties2;
     stream->write(&opcode_vkGetPhysicalDeviceQueueFamilyProperties2, sizeof(uint32_t));
     stream->write(&packetSize_vkGetPhysicalDeviceQueueFamilyProperties2, sizeof(uint32_t));
-    uint64_t cgen_var_700;
-    stream->handleMapping()->mapHandles_VkPhysicalDevice_u64(&local_physicalDevice, &cgen_var_700, 1);
-    stream->write((uint64_t*)&cgen_var_700, 1 * 8);
+    uint64_t cgen_var_704;
+    stream->handleMapping()->mapHandles_VkPhysicalDevice_u64(&local_physicalDevice, &cgen_var_704, 1);
+    stream->write((uint64_t*)&cgen_var_704, 1 * 8);
     // WARNING PTR CHECK
-    uint64_t cgen_var_701 = (uint64_t)(uintptr_t)pQueueFamilyPropertyCount;
-    stream->putBe64(cgen_var_701);
+    uint64_t cgen_var_705 = (uint64_t)(uintptr_t)pQueueFamilyPropertyCount;
+    stream->putBe64(cgen_var_705);
     if (pQueueFamilyPropertyCount)
     {
         stream->write((uint32_t*)pQueueFamilyPropertyCount, sizeof(uint32_t));
     }
     // WARNING PTR CHECK
-    uint64_t cgen_var_702 = (uint64_t)(uintptr_t)pQueueFamilyProperties;
-    stream->putBe64(cgen_var_702);
+    uint64_t cgen_var_706 = (uint64_t)(uintptr_t)pQueueFamilyProperties;
+    stream->putBe64(cgen_var_706);
     if (pQueueFamilyProperties)
     {
         for (uint32_t i = 0; i < (uint32_t)(*(pQueueFamilyPropertyCount)); ++i)
@@ -10587,6 +10846,7 @@
     VkPhysicalDevice physicalDevice,
     VkPhysicalDeviceMemoryProperties2* pMemoryProperties)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkGetPhysicalDeviceMemoryProperties2 encode");
     mImpl->log("start vkGetPhysicalDeviceMemoryProperties2");
     auto stream = mImpl->stream();
@@ -10598,9 +10858,9 @@
     local_physicalDevice = physicalDevice;
     countingStream->rewind();
     {
-        uint64_t cgen_var_705;
-        countingStream->handleMapping()->mapHandles_VkPhysicalDevice_u64(&local_physicalDevice, &cgen_var_705, 1);
-        countingStream->write((uint64_t*)&cgen_var_705, 1 * 8);
+        uint64_t cgen_var_709;
+        countingStream->handleMapping()->mapHandles_VkPhysicalDevice_u64(&local_physicalDevice, &cgen_var_709, 1);
+        countingStream->write((uint64_t*)&cgen_var_709, 1 * 8);
         marshal_VkPhysicalDeviceMemoryProperties2(countingStream, (VkPhysicalDeviceMemoryProperties2*)(pMemoryProperties));
     }
     uint32_t packetSize_vkGetPhysicalDeviceMemoryProperties2 = 4 + 4 + (uint32_t)countingStream->bytesWritten();
@@ -10608,9 +10868,9 @@
     uint32_t opcode_vkGetPhysicalDeviceMemoryProperties2 = OP_vkGetPhysicalDeviceMemoryProperties2;
     stream->write(&opcode_vkGetPhysicalDeviceMemoryProperties2, sizeof(uint32_t));
     stream->write(&packetSize_vkGetPhysicalDeviceMemoryProperties2, sizeof(uint32_t));
-    uint64_t cgen_var_706;
-    stream->handleMapping()->mapHandles_VkPhysicalDevice_u64(&local_physicalDevice, &cgen_var_706, 1);
-    stream->write((uint64_t*)&cgen_var_706, 1 * 8);
+    uint64_t cgen_var_710;
+    stream->handleMapping()->mapHandles_VkPhysicalDevice_u64(&local_physicalDevice, &cgen_var_710, 1);
+    stream->write((uint64_t*)&cgen_var_710, 1 * 8);
     marshal_VkPhysicalDeviceMemoryProperties2(stream, (VkPhysicalDeviceMemoryProperties2*)(pMemoryProperties));
     AEMU_SCOPED_TRACE("vkGetPhysicalDeviceMemoryProperties2 readParams");
     unmarshal_VkPhysicalDeviceMemoryProperties2(stream, (VkPhysicalDeviceMemoryProperties2*)(pMemoryProperties));
@@ -10619,7 +10879,9 @@
         transform_fromhost_VkPhysicalDeviceMemoryProperties2(mImpl->resources(), (VkPhysicalDeviceMemoryProperties2*)(pMemoryProperties));
     }
     AEMU_SCOPED_TRACE("vkGetPhysicalDeviceMemoryProperties2 returnUnmarshal");
+    encoderLock.unlock();
     mImpl->resources()->on_vkGetPhysicalDeviceMemoryProperties2(this, physicalDevice, pMemoryProperties);
+    encoderLock.lock();
     mImpl->log("finish vkGetPhysicalDeviceMemoryProperties2");;
 }
 
@@ -10629,6 +10891,7 @@
     uint32_t* pPropertyCount,
     VkSparseImageFormatProperties2* pProperties)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkGetPhysicalDeviceSparseImageFormatProperties2 encode");
     mImpl->log("start vkGetPhysicalDeviceSparseImageFormatProperties2");
     auto stream = mImpl->stream();
@@ -10651,20 +10914,20 @@
     }
     countingStream->rewind();
     {
-        uint64_t cgen_var_707;
-        countingStream->handleMapping()->mapHandles_VkPhysicalDevice_u64(&local_physicalDevice, &cgen_var_707, 1);
-        countingStream->write((uint64_t*)&cgen_var_707, 1 * 8);
+        uint64_t cgen_var_711;
+        countingStream->handleMapping()->mapHandles_VkPhysicalDevice_u64(&local_physicalDevice, &cgen_var_711, 1);
+        countingStream->write((uint64_t*)&cgen_var_711, 1 * 8);
         marshal_VkPhysicalDeviceSparseImageFormatInfo2(countingStream, (VkPhysicalDeviceSparseImageFormatInfo2*)(local_pFormatInfo));
         // WARNING PTR CHECK
-        uint64_t cgen_var_708 = (uint64_t)(uintptr_t)pPropertyCount;
-        countingStream->putBe64(cgen_var_708);
+        uint64_t cgen_var_712 = (uint64_t)(uintptr_t)pPropertyCount;
+        countingStream->putBe64(cgen_var_712);
         if (pPropertyCount)
         {
             countingStream->write((uint32_t*)pPropertyCount, sizeof(uint32_t));
         }
         // WARNING PTR CHECK
-        uint64_t cgen_var_709 = (uint64_t)(uintptr_t)pProperties;
-        countingStream->putBe64(cgen_var_709);
+        uint64_t cgen_var_713 = (uint64_t)(uintptr_t)pProperties;
+        countingStream->putBe64(cgen_var_713);
         if (pProperties)
         {
             for (uint32_t i = 0; i < (uint32_t)(*(pPropertyCount)); ++i)
@@ -10678,20 +10941,20 @@
     uint32_t opcode_vkGetPhysicalDeviceSparseImageFormatProperties2 = OP_vkGetPhysicalDeviceSparseImageFormatProperties2;
     stream->write(&opcode_vkGetPhysicalDeviceSparseImageFormatProperties2, sizeof(uint32_t));
     stream->write(&packetSize_vkGetPhysicalDeviceSparseImageFormatProperties2, sizeof(uint32_t));
-    uint64_t cgen_var_710;
-    stream->handleMapping()->mapHandles_VkPhysicalDevice_u64(&local_physicalDevice, &cgen_var_710, 1);
-    stream->write((uint64_t*)&cgen_var_710, 1 * 8);
+    uint64_t cgen_var_714;
+    stream->handleMapping()->mapHandles_VkPhysicalDevice_u64(&local_physicalDevice, &cgen_var_714, 1);
+    stream->write((uint64_t*)&cgen_var_714, 1 * 8);
     marshal_VkPhysicalDeviceSparseImageFormatInfo2(stream, (VkPhysicalDeviceSparseImageFormatInfo2*)(local_pFormatInfo));
     // WARNING PTR CHECK
-    uint64_t cgen_var_711 = (uint64_t)(uintptr_t)pPropertyCount;
-    stream->putBe64(cgen_var_711);
+    uint64_t cgen_var_715 = (uint64_t)(uintptr_t)pPropertyCount;
+    stream->putBe64(cgen_var_715);
     if (pPropertyCount)
     {
         stream->write((uint32_t*)pPropertyCount, sizeof(uint32_t));
     }
     // WARNING PTR CHECK
-    uint64_t cgen_var_712 = (uint64_t)(uintptr_t)pProperties;
-    stream->putBe64(cgen_var_712);
+    uint64_t cgen_var_716 = (uint64_t)(uintptr_t)pProperties;
+    stream->putBe64(cgen_var_716);
     if (pProperties)
     {
         for (uint32_t i = 0; i < (uint32_t)(*(pPropertyCount)); ++i)
@@ -10741,6 +11004,7 @@
     VkCommandPool commandPool,
     VkCommandPoolTrimFlags flags)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkTrimCommandPool encode");
     mImpl->log("start vkTrimCommandPool");
     auto stream = mImpl->stream();
@@ -10756,12 +11020,12 @@
     local_flags = flags;
     countingStream->rewind();
     {
-        uint64_t cgen_var_715;
-        countingStream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_715, 1);
-        countingStream->write((uint64_t*)&cgen_var_715, 1 * 8);
-        uint64_t cgen_var_716;
-        countingStream->handleMapping()->mapHandles_VkCommandPool_u64(&local_commandPool, &cgen_var_716, 1);
-        countingStream->write((uint64_t*)&cgen_var_716, 1 * 8);
+        uint64_t cgen_var_719;
+        countingStream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_719, 1);
+        countingStream->write((uint64_t*)&cgen_var_719, 1 * 8);
+        uint64_t cgen_var_720;
+        countingStream->handleMapping()->mapHandles_VkCommandPool_u64(&local_commandPool, &cgen_var_720, 1);
+        countingStream->write((uint64_t*)&cgen_var_720, 1 * 8);
         countingStream->write((VkCommandPoolTrimFlags*)&local_flags, sizeof(VkCommandPoolTrimFlags));
     }
     uint32_t packetSize_vkTrimCommandPool = 4 + 4 + (uint32_t)countingStream->bytesWritten();
@@ -10769,12 +11033,12 @@
     uint32_t opcode_vkTrimCommandPool = OP_vkTrimCommandPool;
     stream->write(&opcode_vkTrimCommandPool, sizeof(uint32_t));
     stream->write(&packetSize_vkTrimCommandPool, sizeof(uint32_t));
-    uint64_t cgen_var_717;
-    stream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_717, 1);
-    stream->write((uint64_t*)&cgen_var_717, 1 * 8);
-    uint64_t cgen_var_718;
-    stream->handleMapping()->mapHandles_VkCommandPool_u64(&local_commandPool, &cgen_var_718, 1);
-    stream->write((uint64_t*)&cgen_var_718, 1 * 8);
+    uint64_t cgen_var_721;
+    stream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_721, 1);
+    stream->write((uint64_t*)&cgen_var_721, 1 * 8);
+    uint64_t cgen_var_722;
+    stream->handleMapping()->mapHandles_VkCommandPool_u64(&local_commandPool, &cgen_var_722, 1);
+    stream->write((uint64_t*)&cgen_var_722, 1 * 8);
     stream->write((VkCommandPoolTrimFlags*)&local_flags, sizeof(VkCommandPoolTrimFlags));
     AEMU_SCOPED_TRACE("vkTrimCommandPool readParams");
     AEMU_SCOPED_TRACE("vkTrimCommandPool returnUnmarshal");
@@ -10786,6 +11050,7 @@
     const VkDeviceQueueInfo2* pQueueInfo,
     VkQueue* pQueue)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkGetDeviceQueue2 encode");
     mImpl->log("start vkGetDeviceQueue2");
     auto stream = mImpl->stream();
@@ -10808,32 +11073,32 @@
     }
     countingStream->rewind();
     {
-        uint64_t cgen_var_719;
-        countingStream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_719, 1);
-        countingStream->write((uint64_t*)&cgen_var_719, 1 * 8);
+        uint64_t cgen_var_723;
+        countingStream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_723, 1);
+        countingStream->write((uint64_t*)&cgen_var_723, 1 * 8);
         marshal_VkDeviceQueueInfo2(countingStream, (VkDeviceQueueInfo2*)(local_pQueueInfo));
-        uint64_t cgen_var_720;
-        countingStream->handleMapping()->mapHandles_VkQueue_u64(pQueue, &cgen_var_720, 1);
-        countingStream->write((uint64_t*)&cgen_var_720, 8);
+        uint64_t cgen_var_724;
+        countingStream->handleMapping()->mapHandles_VkQueue_u64(pQueue, &cgen_var_724, 1);
+        countingStream->write((uint64_t*)&cgen_var_724, 8);
     }
     uint32_t packetSize_vkGetDeviceQueue2 = 4 + 4 + (uint32_t)countingStream->bytesWritten();
     countingStream->rewind();
     uint32_t opcode_vkGetDeviceQueue2 = OP_vkGetDeviceQueue2;
     stream->write(&opcode_vkGetDeviceQueue2, sizeof(uint32_t));
     stream->write(&packetSize_vkGetDeviceQueue2, sizeof(uint32_t));
-    uint64_t cgen_var_721;
-    stream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_721, 1);
-    stream->write((uint64_t*)&cgen_var_721, 1 * 8);
+    uint64_t cgen_var_725;
+    stream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_725, 1);
+    stream->write((uint64_t*)&cgen_var_725, 1 * 8);
     marshal_VkDeviceQueueInfo2(stream, (VkDeviceQueueInfo2*)(local_pQueueInfo));
     stream->unsetHandleMapping() /* emit_marshal, is handle, possibly out */;
-    uint64_t cgen_var_722;
-    stream->handleMapping()->mapHandles_VkQueue_u64(pQueue, &cgen_var_722, 1);
-    stream->write((uint64_t*)&cgen_var_722, 8);
+    uint64_t cgen_var_726;
+    stream->handleMapping()->mapHandles_VkQueue_u64(pQueue, &cgen_var_726, 1);
+    stream->write((uint64_t*)&cgen_var_726, 8);
     stream->setHandleMapping(resources->unwrapMapping());
     AEMU_SCOPED_TRACE("vkGetDeviceQueue2 readParams");
-    uint64_t cgen_var_723;
-    stream->read((uint64_t*)&cgen_var_723, 8);
-    stream->handleMapping()->mapHandles_u64_VkQueue(&cgen_var_723, (VkQueue*)pQueue, 1);
+    uint64_t cgen_var_727;
+    stream->read((uint64_t*)&cgen_var_727, 8);
+    stream->handleMapping()->mapHandles_u64_VkQueue(&cgen_var_727, (VkQueue*)pQueue, 1);
     AEMU_SCOPED_TRACE("vkGetDeviceQueue2 returnUnmarshal");
     mImpl->log("finish vkGetDeviceQueue2");;
 }
@@ -10844,6 +11109,7 @@
     const VkAllocationCallbacks* pAllocator,
     VkSamplerYcbcrConversion* pYcbcrConversion)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkCreateSamplerYcbcrConversion encode");
     mImpl->log("start vkCreateSamplerYcbcrConversion");
     auto stream = mImpl->stream();
@@ -10878,47 +11144,47 @@
     }
     countingStream->rewind();
     {
-        uint64_t cgen_var_724;
-        countingStream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_724, 1);
-        countingStream->write((uint64_t*)&cgen_var_724, 1 * 8);
+        uint64_t cgen_var_728;
+        countingStream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_728, 1);
+        countingStream->write((uint64_t*)&cgen_var_728, 1 * 8);
         marshal_VkSamplerYcbcrConversionCreateInfo(countingStream, (VkSamplerYcbcrConversionCreateInfo*)(local_pCreateInfo));
         // WARNING PTR CHECK
-        uint64_t cgen_var_725 = (uint64_t)(uintptr_t)local_pAllocator;
-        countingStream->putBe64(cgen_var_725);
+        uint64_t cgen_var_729 = (uint64_t)(uintptr_t)local_pAllocator;
+        countingStream->putBe64(cgen_var_729);
         if (local_pAllocator)
         {
             marshal_VkAllocationCallbacks(countingStream, (VkAllocationCallbacks*)(local_pAllocator));
         }
-        uint64_t cgen_var_726;
-        countingStream->handleMapping()->mapHandles_VkSamplerYcbcrConversion_u64(pYcbcrConversion, &cgen_var_726, 1);
-        countingStream->write((uint64_t*)&cgen_var_726, 8);
+        uint64_t cgen_var_730;
+        countingStream->handleMapping()->mapHandles_VkSamplerYcbcrConversion_u64(pYcbcrConversion, &cgen_var_730, 1);
+        countingStream->write((uint64_t*)&cgen_var_730, 8);
     }
     uint32_t packetSize_vkCreateSamplerYcbcrConversion = 4 + 4 + (uint32_t)countingStream->bytesWritten();
     countingStream->rewind();
     uint32_t opcode_vkCreateSamplerYcbcrConversion = OP_vkCreateSamplerYcbcrConversion;
     stream->write(&opcode_vkCreateSamplerYcbcrConversion, sizeof(uint32_t));
     stream->write(&packetSize_vkCreateSamplerYcbcrConversion, sizeof(uint32_t));
-    uint64_t cgen_var_727;
-    stream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_727, 1);
-    stream->write((uint64_t*)&cgen_var_727, 1 * 8);
+    uint64_t cgen_var_731;
+    stream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_731, 1);
+    stream->write((uint64_t*)&cgen_var_731, 1 * 8);
     marshal_VkSamplerYcbcrConversionCreateInfo(stream, (VkSamplerYcbcrConversionCreateInfo*)(local_pCreateInfo));
     // WARNING PTR CHECK
-    uint64_t cgen_var_728 = (uint64_t)(uintptr_t)local_pAllocator;
-    stream->putBe64(cgen_var_728);
+    uint64_t cgen_var_732 = (uint64_t)(uintptr_t)local_pAllocator;
+    stream->putBe64(cgen_var_732);
     if (local_pAllocator)
     {
         marshal_VkAllocationCallbacks(stream, (VkAllocationCallbacks*)(local_pAllocator));
     }
     stream->unsetHandleMapping() /* emit_marshal, is handle, possibly out */;
-    uint64_t cgen_var_729;
-    stream->handleMapping()->mapHandles_VkSamplerYcbcrConversion_u64(pYcbcrConversion, &cgen_var_729, 1);
-    stream->write((uint64_t*)&cgen_var_729, 8);
+    uint64_t cgen_var_733;
+    stream->handleMapping()->mapHandles_VkSamplerYcbcrConversion_u64(pYcbcrConversion, &cgen_var_733, 1);
+    stream->write((uint64_t*)&cgen_var_733, 8);
     stream->setHandleMapping(resources->unwrapMapping());
     AEMU_SCOPED_TRACE("vkCreateSamplerYcbcrConversion readParams");
     stream->setHandleMapping(resources->createMapping());
-    uint64_t cgen_var_730;
-    stream->read((uint64_t*)&cgen_var_730, 8);
-    stream->handleMapping()->mapHandles_u64_VkSamplerYcbcrConversion(&cgen_var_730, (VkSamplerYcbcrConversion*)pYcbcrConversion, 1);
+    uint64_t cgen_var_734;
+    stream->read((uint64_t*)&cgen_var_734, 8);
+    stream->handleMapping()->mapHandles_u64_VkSamplerYcbcrConversion(&cgen_var_734, (VkSamplerYcbcrConversion*)pYcbcrConversion, 1);
     stream->unsetHandleMapping();
     AEMU_SCOPED_TRACE("vkCreateSamplerYcbcrConversion returnUnmarshal");
     VkResult vkCreateSamplerYcbcrConversion_VkResult_return = (VkResult)0;
@@ -10935,6 +11201,7 @@
     VkSamplerYcbcrConversion ycbcrConversion,
     const VkAllocationCallbacks* pAllocator)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkDestroySamplerYcbcrConversion encode");
     mImpl->log("start vkDestroySamplerYcbcrConversion");
     auto stream = mImpl->stream();
@@ -10960,15 +11227,15 @@
     }
     countingStream->rewind();
     {
-        uint64_t cgen_var_731;
-        countingStream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_731, 1);
-        countingStream->write((uint64_t*)&cgen_var_731, 1 * 8);
-        uint64_t cgen_var_732;
-        countingStream->handleMapping()->mapHandles_VkSamplerYcbcrConversion_u64(&local_ycbcrConversion, &cgen_var_732, 1);
-        countingStream->write((uint64_t*)&cgen_var_732, 1 * 8);
+        uint64_t cgen_var_735;
+        countingStream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_735, 1);
+        countingStream->write((uint64_t*)&cgen_var_735, 1 * 8);
+        uint64_t cgen_var_736;
+        countingStream->handleMapping()->mapHandles_VkSamplerYcbcrConversion_u64(&local_ycbcrConversion, &cgen_var_736, 1);
+        countingStream->write((uint64_t*)&cgen_var_736, 1 * 8);
         // WARNING PTR CHECK
-        uint64_t cgen_var_733 = (uint64_t)(uintptr_t)local_pAllocator;
-        countingStream->putBe64(cgen_var_733);
+        uint64_t cgen_var_737 = (uint64_t)(uintptr_t)local_pAllocator;
+        countingStream->putBe64(cgen_var_737);
         if (local_pAllocator)
         {
             marshal_VkAllocationCallbacks(countingStream, (VkAllocationCallbacks*)(local_pAllocator));
@@ -10979,15 +11246,15 @@
     uint32_t opcode_vkDestroySamplerYcbcrConversion = OP_vkDestroySamplerYcbcrConversion;
     stream->write(&opcode_vkDestroySamplerYcbcrConversion, sizeof(uint32_t));
     stream->write(&packetSize_vkDestroySamplerYcbcrConversion, sizeof(uint32_t));
-    uint64_t cgen_var_734;
-    stream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_734, 1);
-    stream->write((uint64_t*)&cgen_var_734, 1 * 8);
-    uint64_t cgen_var_735;
-    stream->handleMapping()->mapHandles_VkSamplerYcbcrConversion_u64(&local_ycbcrConversion, &cgen_var_735, 1);
-    stream->write((uint64_t*)&cgen_var_735, 1 * 8);
+    uint64_t cgen_var_738;
+    stream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_738, 1);
+    stream->write((uint64_t*)&cgen_var_738, 1 * 8);
+    uint64_t cgen_var_739;
+    stream->handleMapping()->mapHandles_VkSamplerYcbcrConversion_u64(&local_ycbcrConversion, &cgen_var_739, 1);
+    stream->write((uint64_t*)&cgen_var_739, 1 * 8);
     // WARNING PTR CHECK
-    uint64_t cgen_var_736 = (uint64_t)(uintptr_t)local_pAllocator;
-    stream->putBe64(cgen_var_736);
+    uint64_t cgen_var_740 = (uint64_t)(uintptr_t)local_pAllocator;
+    stream->putBe64(cgen_var_740);
     if (local_pAllocator)
     {
         marshal_VkAllocationCallbacks(stream, (VkAllocationCallbacks*)(local_pAllocator));
@@ -11004,6 +11271,7 @@
     const VkAllocationCallbacks* pAllocator,
     VkDescriptorUpdateTemplate* pDescriptorUpdateTemplate)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkCreateDescriptorUpdateTemplate encode");
     mImpl->log("start vkCreateDescriptorUpdateTemplate");
     auto stream = mImpl->stream();
@@ -11038,47 +11306,47 @@
     }
     countingStream->rewind();
     {
-        uint64_t cgen_var_737;
-        countingStream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_737, 1);
-        countingStream->write((uint64_t*)&cgen_var_737, 1 * 8);
+        uint64_t cgen_var_741;
+        countingStream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_741, 1);
+        countingStream->write((uint64_t*)&cgen_var_741, 1 * 8);
         marshal_VkDescriptorUpdateTemplateCreateInfo(countingStream, (VkDescriptorUpdateTemplateCreateInfo*)(local_pCreateInfo));
         // WARNING PTR CHECK
-        uint64_t cgen_var_738 = (uint64_t)(uintptr_t)local_pAllocator;
-        countingStream->putBe64(cgen_var_738);
+        uint64_t cgen_var_742 = (uint64_t)(uintptr_t)local_pAllocator;
+        countingStream->putBe64(cgen_var_742);
         if (local_pAllocator)
         {
             marshal_VkAllocationCallbacks(countingStream, (VkAllocationCallbacks*)(local_pAllocator));
         }
-        uint64_t cgen_var_739;
-        countingStream->handleMapping()->mapHandles_VkDescriptorUpdateTemplate_u64(pDescriptorUpdateTemplate, &cgen_var_739, 1);
-        countingStream->write((uint64_t*)&cgen_var_739, 8);
+        uint64_t cgen_var_743;
+        countingStream->handleMapping()->mapHandles_VkDescriptorUpdateTemplate_u64(pDescriptorUpdateTemplate, &cgen_var_743, 1);
+        countingStream->write((uint64_t*)&cgen_var_743, 8);
     }
     uint32_t packetSize_vkCreateDescriptorUpdateTemplate = 4 + 4 + (uint32_t)countingStream->bytesWritten();
     countingStream->rewind();
     uint32_t opcode_vkCreateDescriptorUpdateTemplate = OP_vkCreateDescriptorUpdateTemplate;
     stream->write(&opcode_vkCreateDescriptorUpdateTemplate, sizeof(uint32_t));
     stream->write(&packetSize_vkCreateDescriptorUpdateTemplate, sizeof(uint32_t));
-    uint64_t cgen_var_740;
-    stream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_740, 1);
-    stream->write((uint64_t*)&cgen_var_740, 1 * 8);
+    uint64_t cgen_var_744;
+    stream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_744, 1);
+    stream->write((uint64_t*)&cgen_var_744, 1 * 8);
     marshal_VkDescriptorUpdateTemplateCreateInfo(stream, (VkDescriptorUpdateTemplateCreateInfo*)(local_pCreateInfo));
     // WARNING PTR CHECK
-    uint64_t cgen_var_741 = (uint64_t)(uintptr_t)local_pAllocator;
-    stream->putBe64(cgen_var_741);
+    uint64_t cgen_var_745 = (uint64_t)(uintptr_t)local_pAllocator;
+    stream->putBe64(cgen_var_745);
     if (local_pAllocator)
     {
         marshal_VkAllocationCallbacks(stream, (VkAllocationCallbacks*)(local_pAllocator));
     }
     stream->unsetHandleMapping() /* emit_marshal, is handle, possibly out */;
-    uint64_t cgen_var_742;
-    stream->handleMapping()->mapHandles_VkDescriptorUpdateTemplate_u64(pDescriptorUpdateTemplate, &cgen_var_742, 1);
-    stream->write((uint64_t*)&cgen_var_742, 8);
+    uint64_t cgen_var_746;
+    stream->handleMapping()->mapHandles_VkDescriptorUpdateTemplate_u64(pDescriptorUpdateTemplate, &cgen_var_746, 1);
+    stream->write((uint64_t*)&cgen_var_746, 8);
     stream->setHandleMapping(resources->unwrapMapping());
     AEMU_SCOPED_TRACE("vkCreateDescriptorUpdateTemplate readParams");
     stream->setHandleMapping(resources->createMapping());
-    uint64_t cgen_var_743;
-    stream->read((uint64_t*)&cgen_var_743, 8);
-    stream->handleMapping()->mapHandles_u64_VkDescriptorUpdateTemplate(&cgen_var_743, (VkDescriptorUpdateTemplate*)pDescriptorUpdateTemplate, 1);
+    uint64_t cgen_var_747;
+    stream->read((uint64_t*)&cgen_var_747, 8);
+    stream->handleMapping()->mapHandles_u64_VkDescriptorUpdateTemplate(&cgen_var_747, (VkDescriptorUpdateTemplate*)pDescriptorUpdateTemplate, 1);
     stream->unsetHandleMapping();
     AEMU_SCOPED_TRACE("vkCreateDescriptorUpdateTemplate returnUnmarshal");
     VkResult vkCreateDescriptorUpdateTemplate_VkResult_return = (VkResult)0;
@@ -11086,7 +11354,9 @@
     countingStream->clearPool();
     stream->clearPool();
     pool->freeAll();
+    encoderLock.unlock();
     mImpl->resources()->on_vkCreateDescriptorUpdateTemplate(this, vkCreateDescriptorUpdateTemplate_VkResult_return, device, pCreateInfo, pAllocator, pDescriptorUpdateTemplate);
+    encoderLock.lock();
     mImpl->log("finish vkCreateDescriptorUpdateTemplate");;
     return vkCreateDescriptorUpdateTemplate_VkResult_return;
 }
@@ -11096,6 +11366,7 @@
     VkDescriptorUpdateTemplate descriptorUpdateTemplate,
     const VkAllocationCallbacks* pAllocator)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkDestroyDescriptorUpdateTemplate encode");
     mImpl->log("start vkDestroyDescriptorUpdateTemplate");
     auto stream = mImpl->stream();
@@ -11121,15 +11392,15 @@
     }
     countingStream->rewind();
     {
-        uint64_t cgen_var_744;
-        countingStream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_744, 1);
-        countingStream->write((uint64_t*)&cgen_var_744, 1 * 8);
-        uint64_t cgen_var_745;
-        countingStream->handleMapping()->mapHandles_VkDescriptorUpdateTemplate_u64(&local_descriptorUpdateTemplate, &cgen_var_745, 1);
-        countingStream->write((uint64_t*)&cgen_var_745, 1 * 8);
+        uint64_t cgen_var_748;
+        countingStream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_748, 1);
+        countingStream->write((uint64_t*)&cgen_var_748, 1 * 8);
+        uint64_t cgen_var_749;
+        countingStream->handleMapping()->mapHandles_VkDescriptorUpdateTemplate_u64(&local_descriptorUpdateTemplate, &cgen_var_749, 1);
+        countingStream->write((uint64_t*)&cgen_var_749, 1 * 8);
         // WARNING PTR CHECK
-        uint64_t cgen_var_746 = (uint64_t)(uintptr_t)local_pAllocator;
-        countingStream->putBe64(cgen_var_746);
+        uint64_t cgen_var_750 = (uint64_t)(uintptr_t)local_pAllocator;
+        countingStream->putBe64(cgen_var_750);
         if (local_pAllocator)
         {
             marshal_VkAllocationCallbacks(countingStream, (VkAllocationCallbacks*)(local_pAllocator));
@@ -11140,15 +11411,15 @@
     uint32_t opcode_vkDestroyDescriptorUpdateTemplate = OP_vkDestroyDescriptorUpdateTemplate;
     stream->write(&opcode_vkDestroyDescriptorUpdateTemplate, sizeof(uint32_t));
     stream->write(&packetSize_vkDestroyDescriptorUpdateTemplate, sizeof(uint32_t));
-    uint64_t cgen_var_747;
-    stream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_747, 1);
-    stream->write((uint64_t*)&cgen_var_747, 1 * 8);
-    uint64_t cgen_var_748;
-    stream->handleMapping()->mapHandles_VkDescriptorUpdateTemplate_u64(&local_descriptorUpdateTemplate, &cgen_var_748, 1);
-    stream->write((uint64_t*)&cgen_var_748, 1 * 8);
+    uint64_t cgen_var_751;
+    stream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_751, 1);
+    stream->write((uint64_t*)&cgen_var_751, 1 * 8);
+    uint64_t cgen_var_752;
+    stream->handleMapping()->mapHandles_VkDescriptorUpdateTemplate_u64(&local_descriptorUpdateTemplate, &cgen_var_752, 1);
+    stream->write((uint64_t*)&cgen_var_752, 1 * 8);
     // WARNING PTR CHECK
-    uint64_t cgen_var_749 = (uint64_t)(uintptr_t)local_pAllocator;
-    stream->putBe64(cgen_var_749);
+    uint64_t cgen_var_753 = (uint64_t)(uintptr_t)local_pAllocator;
+    stream->putBe64(cgen_var_753);
     if (local_pAllocator)
     {
         marshal_VkAllocationCallbacks(stream, (VkAllocationCallbacks*)(local_pAllocator));
@@ -11165,6 +11436,7 @@
     VkDescriptorUpdateTemplate descriptorUpdateTemplate,
     const void* pData)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkUpdateDescriptorSetWithTemplate encode");
     mImpl->log("start vkUpdateDescriptorSetWithTemplate");
     auto stream = mImpl->stream();
@@ -11186,18 +11458,18 @@
     }
     countingStream->rewind();
     {
-        uint64_t cgen_var_750;
-        countingStream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_750, 1);
-        countingStream->write((uint64_t*)&cgen_var_750, 1 * 8);
-        uint64_t cgen_var_751;
-        countingStream->handleMapping()->mapHandles_VkDescriptorSet_u64(&local_descriptorSet, &cgen_var_751, 1);
-        countingStream->write((uint64_t*)&cgen_var_751, 1 * 8);
-        uint64_t cgen_var_752;
-        countingStream->handleMapping()->mapHandles_VkDescriptorUpdateTemplate_u64(&local_descriptorUpdateTemplate, &cgen_var_752, 1);
-        countingStream->write((uint64_t*)&cgen_var_752, 1 * 8);
+        uint64_t cgen_var_754;
+        countingStream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_754, 1);
+        countingStream->write((uint64_t*)&cgen_var_754, 1 * 8);
+        uint64_t cgen_var_755;
+        countingStream->handleMapping()->mapHandles_VkDescriptorSet_u64(&local_descriptorSet, &cgen_var_755, 1);
+        countingStream->write((uint64_t*)&cgen_var_755, 1 * 8);
+        uint64_t cgen_var_756;
+        countingStream->handleMapping()->mapHandles_VkDescriptorUpdateTemplate_u64(&local_descriptorUpdateTemplate, &cgen_var_756, 1);
+        countingStream->write((uint64_t*)&cgen_var_756, 1 * 8);
         // WARNING PTR CHECK
-        uint64_t cgen_var_753 = (uint64_t)(uintptr_t)local_pData;
-        countingStream->putBe64(cgen_var_753);
+        uint64_t cgen_var_757 = (uint64_t)(uintptr_t)local_pData;
+        countingStream->putBe64(cgen_var_757);
         if (local_pData)
         {
             countingStream->write((void*)local_pData, sizeof(uint8_t));
@@ -11208,18 +11480,18 @@
     uint32_t opcode_vkUpdateDescriptorSetWithTemplate = OP_vkUpdateDescriptorSetWithTemplate;
     stream->write(&opcode_vkUpdateDescriptorSetWithTemplate, sizeof(uint32_t));
     stream->write(&packetSize_vkUpdateDescriptorSetWithTemplate, sizeof(uint32_t));
-    uint64_t cgen_var_754;
-    stream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_754, 1);
-    stream->write((uint64_t*)&cgen_var_754, 1 * 8);
-    uint64_t cgen_var_755;
-    stream->handleMapping()->mapHandles_VkDescriptorSet_u64(&local_descriptorSet, &cgen_var_755, 1);
-    stream->write((uint64_t*)&cgen_var_755, 1 * 8);
-    uint64_t cgen_var_756;
-    stream->handleMapping()->mapHandles_VkDescriptorUpdateTemplate_u64(&local_descriptorUpdateTemplate, &cgen_var_756, 1);
-    stream->write((uint64_t*)&cgen_var_756, 1 * 8);
+    uint64_t cgen_var_758;
+    stream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_758, 1);
+    stream->write((uint64_t*)&cgen_var_758, 1 * 8);
+    uint64_t cgen_var_759;
+    stream->handleMapping()->mapHandles_VkDescriptorSet_u64(&local_descriptorSet, &cgen_var_759, 1);
+    stream->write((uint64_t*)&cgen_var_759, 1 * 8);
+    uint64_t cgen_var_760;
+    stream->handleMapping()->mapHandles_VkDescriptorUpdateTemplate_u64(&local_descriptorUpdateTemplate, &cgen_var_760, 1);
+    stream->write((uint64_t*)&cgen_var_760, 1 * 8);
     // WARNING PTR CHECK
-    uint64_t cgen_var_757 = (uint64_t)(uintptr_t)local_pData;
-    stream->putBe64(cgen_var_757);
+    uint64_t cgen_var_761 = (uint64_t)(uintptr_t)local_pData;
+    stream->putBe64(cgen_var_761);
     if (local_pData)
     {
         stream->write((void*)local_pData, sizeof(uint8_t));
@@ -11234,6 +11506,7 @@
     const VkPhysicalDeviceExternalBufferInfo* pExternalBufferInfo,
     VkExternalBufferProperties* pExternalBufferProperties)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkGetPhysicalDeviceExternalBufferProperties encode");
     mImpl->log("start vkGetPhysicalDeviceExternalBufferProperties");
     auto stream = mImpl->stream();
@@ -11257,9 +11530,9 @@
     }
     countingStream->rewind();
     {
-        uint64_t cgen_var_758;
-        countingStream->handleMapping()->mapHandles_VkPhysicalDevice_u64(&local_physicalDevice, &cgen_var_758, 1);
-        countingStream->write((uint64_t*)&cgen_var_758, 1 * 8);
+        uint64_t cgen_var_762;
+        countingStream->handleMapping()->mapHandles_VkPhysicalDevice_u64(&local_physicalDevice, &cgen_var_762, 1);
+        countingStream->write((uint64_t*)&cgen_var_762, 1 * 8);
         marshal_VkPhysicalDeviceExternalBufferInfo(countingStream, (VkPhysicalDeviceExternalBufferInfo*)(local_pExternalBufferInfo));
         marshal_VkExternalBufferProperties(countingStream, (VkExternalBufferProperties*)(pExternalBufferProperties));
     }
@@ -11268,9 +11541,9 @@
     uint32_t opcode_vkGetPhysicalDeviceExternalBufferProperties = OP_vkGetPhysicalDeviceExternalBufferProperties;
     stream->write(&opcode_vkGetPhysicalDeviceExternalBufferProperties, sizeof(uint32_t));
     stream->write(&packetSize_vkGetPhysicalDeviceExternalBufferProperties, sizeof(uint32_t));
-    uint64_t cgen_var_759;
-    stream->handleMapping()->mapHandles_VkPhysicalDevice_u64(&local_physicalDevice, &cgen_var_759, 1);
-    stream->write((uint64_t*)&cgen_var_759, 1 * 8);
+    uint64_t cgen_var_763;
+    stream->handleMapping()->mapHandles_VkPhysicalDevice_u64(&local_physicalDevice, &cgen_var_763, 1);
+    stream->write((uint64_t*)&cgen_var_763, 1 * 8);
     marshal_VkPhysicalDeviceExternalBufferInfo(stream, (VkPhysicalDeviceExternalBufferInfo*)(local_pExternalBufferInfo));
     marshal_VkExternalBufferProperties(stream, (VkExternalBufferProperties*)(pExternalBufferProperties));
     AEMU_SCOPED_TRACE("vkGetPhysicalDeviceExternalBufferProperties readParams");
@@ -11289,6 +11562,7 @@
     const VkPhysicalDeviceExternalFenceInfo* pExternalFenceInfo,
     VkExternalFenceProperties* pExternalFenceProperties)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkGetPhysicalDeviceExternalFenceProperties encode");
     mImpl->log("start vkGetPhysicalDeviceExternalFenceProperties");
     auto stream = mImpl->stream();
@@ -11311,9 +11585,9 @@
     }
     countingStream->rewind();
     {
-        uint64_t cgen_var_760;
-        countingStream->handleMapping()->mapHandles_VkPhysicalDevice_u64(&local_physicalDevice, &cgen_var_760, 1);
-        countingStream->write((uint64_t*)&cgen_var_760, 1 * 8);
+        uint64_t cgen_var_764;
+        countingStream->handleMapping()->mapHandles_VkPhysicalDevice_u64(&local_physicalDevice, &cgen_var_764, 1);
+        countingStream->write((uint64_t*)&cgen_var_764, 1 * 8);
         marshal_VkPhysicalDeviceExternalFenceInfo(countingStream, (VkPhysicalDeviceExternalFenceInfo*)(local_pExternalFenceInfo));
         marshal_VkExternalFenceProperties(countingStream, (VkExternalFenceProperties*)(pExternalFenceProperties));
     }
@@ -11322,9 +11596,9 @@
     uint32_t opcode_vkGetPhysicalDeviceExternalFenceProperties = OP_vkGetPhysicalDeviceExternalFenceProperties;
     stream->write(&opcode_vkGetPhysicalDeviceExternalFenceProperties, sizeof(uint32_t));
     stream->write(&packetSize_vkGetPhysicalDeviceExternalFenceProperties, sizeof(uint32_t));
-    uint64_t cgen_var_761;
-    stream->handleMapping()->mapHandles_VkPhysicalDevice_u64(&local_physicalDevice, &cgen_var_761, 1);
-    stream->write((uint64_t*)&cgen_var_761, 1 * 8);
+    uint64_t cgen_var_765;
+    stream->handleMapping()->mapHandles_VkPhysicalDevice_u64(&local_physicalDevice, &cgen_var_765, 1);
+    stream->write((uint64_t*)&cgen_var_765, 1 * 8);
     marshal_VkPhysicalDeviceExternalFenceInfo(stream, (VkPhysicalDeviceExternalFenceInfo*)(local_pExternalFenceInfo));
     marshal_VkExternalFenceProperties(stream, (VkExternalFenceProperties*)(pExternalFenceProperties));
     AEMU_SCOPED_TRACE("vkGetPhysicalDeviceExternalFenceProperties readParams");
@@ -11342,6 +11616,7 @@
     const VkPhysicalDeviceExternalSemaphoreInfo* pExternalSemaphoreInfo,
     VkExternalSemaphoreProperties* pExternalSemaphoreProperties)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkGetPhysicalDeviceExternalSemaphoreProperties encode");
     mImpl->log("start vkGetPhysicalDeviceExternalSemaphoreProperties");
     auto stream = mImpl->stream();
@@ -11364,9 +11639,9 @@
     }
     countingStream->rewind();
     {
-        uint64_t cgen_var_762;
-        countingStream->handleMapping()->mapHandles_VkPhysicalDevice_u64(&local_physicalDevice, &cgen_var_762, 1);
-        countingStream->write((uint64_t*)&cgen_var_762, 1 * 8);
+        uint64_t cgen_var_766;
+        countingStream->handleMapping()->mapHandles_VkPhysicalDevice_u64(&local_physicalDevice, &cgen_var_766, 1);
+        countingStream->write((uint64_t*)&cgen_var_766, 1 * 8);
         marshal_VkPhysicalDeviceExternalSemaphoreInfo(countingStream, (VkPhysicalDeviceExternalSemaphoreInfo*)(local_pExternalSemaphoreInfo));
         marshal_VkExternalSemaphoreProperties(countingStream, (VkExternalSemaphoreProperties*)(pExternalSemaphoreProperties));
     }
@@ -11375,9 +11650,9 @@
     uint32_t opcode_vkGetPhysicalDeviceExternalSemaphoreProperties = OP_vkGetPhysicalDeviceExternalSemaphoreProperties;
     stream->write(&opcode_vkGetPhysicalDeviceExternalSemaphoreProperties, sizeof(uint32_t));
     stream->write(&packetSize_vkGetPhysicalDeviceExternalSemaphoreProperties, sizeof(uint32_t));
-    uint64_t cgen_var_763;
-    stream->handleMapping()->mapHandles_VkPhysicalDevice_u64(&local_physicalDevice, &cgen_var_763, 1);
-    stream->write((uint64_t*)&cgen_var_763, 1 * 8);
+    uint64_t cgen_var_767;
+    stream->handleMapping()->mapHandles_VkPhysicalDevice_u64(&local_physicalDevice, &cgen_var_767, 1);
+    stream->write((uint64_t*)&cgen_var_767, 1 * 8);
     marshal_VkPhysicalDeviceExternalSemaphoreInfo(stream, (VkPhysicalDeviceExternalSemaphoreInfo*)(local_pExternalSemaphoreInfo));
     marshal_VkExternalSemaphoreProperties(stream, (VkExternalSemaphoreProperties*)(pExternalSemaphoreProperties));
     AEMU_SCOPED_TRACE("vkGetPhysicalDeviceExternalSemaphoreProperties readParams");
@@ -11395,6 +11670,7 @@
     const VkDescriptorSetLayoutCreateInfo* pCreateInfo,
     VkDescriptorSetLayoutSupport* pSupport)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkGetDescriptorSetLayoutSupport encode");
     mImpl->log("start vkGetDescriptorSetLayoutSupport");
     auto stream = mImpl->stream();
@@ -11417,9 +11693,9 @@
     }
     countingStream->rewind();
     {
-        uint64_t cgen_var_764;
-        countingStream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_764, 1);
-        countingStream->write((uint64_t*)&cgen_var_764, 1 * 8);
+        uint64_t cgen_var_768;
+        countingStream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_768, 1);
+        countingStream->write((uint64_t*)&cgen_var_768, 1 * 8);
         marshal_VkDescriptorSetLayoutCreateInfo(countingStream, (VkDescriptorSetLayoutCreateInfo*)(local_pCreateInfo));
         marshal_VkDescriptorSetLayoutSupport(countingStream, (VkDescriptorSetLayoutSupport*)(pSupport));
     }
@@ -11428,9 +11704,9 @@
     uint32_t opcode_vkGetDescriptorSetLayoutSupport = OP_vkGetDescriptorSetLayoutSupport;
     stream->write(&opcode_vkGetDescriptorSetLayoutSupport, sizeof(uint32_t));
     stream->write(&packetSize_vkGetDescriptorSetLayoutSupport, sizeof(uint32_t));
-    uint64_t cgen_var_765;
-    stream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_765, 1);
-    stream->write((uint64_t*)&cgen_var_765, 1 * 8);
+    uint64_t cgen_var_769;
+    stream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_769, 1);
+    stream->write((uint64_t*)&cgen_var_769, 1 * 8);
     marshal_VkDescriptorSetLayoutCreateInfo(stream, (VkDescriptorSetLayoutCreateInfo*)(local_pCreateInfo));
     marshal_VkDescriptorSetLayoutSupport(stream, (VkDescriptorSetLayoutSupport*)(pSupport));
     AEMU_SCOPED_TRACE("vkGetDescriptorSetLayoutSupport readParams");
@@ -11450,6 +11726,7 @@
     VkSurfaceKHR surface,
     const VkAllocationCallbacks* pAllocator)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkDestroySurfaceKHR encode");
     mImpl->log("start vkDestroySurfaceKHR");
     auto stream = mImpl->stream();
@@ -11475,15 +11752,15 @@
     }
     countingStream->rewind();
     {
-        uint64_t cgen_var_766;
-        countingStream->handleMapping()->mapHandles_VkInstance_u64(&local_instance, &cgen_var_766, 1);
-        countingStream->write((uint64_t*)&cgen_var_766, 1 * 8);
-        uint64_t cgen_var_767;
-        countingStream->handleMapping()->mapHandles_VkSurfaceKHR_u64(&local_surface, &cgen_var_767, 1);
-        countingStream->write((uint64_t*)&cgen_var_767, 1 * 8);
+        uint64_t cgen_var_770;
+        countingStream->handleMapping()->mapHandles_VkInstance_u64(&local_instance, &cgen_var_770, 1);
+        countingStream->write((uint64_t*)&cgen_var_770, 1 * 8);
+        uint64_t cgen_var_771;
+        countingStream->handleMapping()->mapHandles_VkSurfaceKHR_u64(&local_surface, &cgen_var_771, 1);
+        countingStream->write((uint64_t*)&cgen_var_771, 1 * 8);
         // WARNING PTR CHECK
-        uint64_t cgen_var_768 = (uint64_t)(uintptr_t)local_pAllocator;
-        countingStream->putBe64(cgen_var_768);
+        uint64_t cgen_var_772 = (uint64_t)(uintptr_t)local_pAllocator;
+        countingStream->putBe64(cgen_var_772);
         if (local_pAllocator)
         {
             marshal_VkAllocationCallbacks(countingStream, (VkAllocationCallbacks*)(local_pAllocator));
@@ -11494,15 +11771,15 @@
     uint32_t opcode_vkDestroySurfaceKHR = OP_vkDestroySurfaceKHR;
     stream->write(&opcode_vkDestroySurfaceKHR, sizeof(uint32_t));
     stream->write(&packetSize_vkDestroySurfaceKHR, sizeof(uint32_t));
-    uint64_t cgen_var_769;
-    stream->handleMapping()->mapHandles_VkInstance_u64(&local_instance, &cgen_var_769, 1);
-    stream->write((uint64_t*)&cgen_var_769, 1 * 8);
-    uint64_t cgen_var_770;
-    stream->handleMapping()->mapHandles_VkSurfaceKHR_u64(&local_surface, &cgen_var_770, 1);
-    stream->write((uint64_t*)&cgen_var_770, 1 * 8);
+    uint64_t cgen_var_773;
+    stream->handleMapping()->mapHandles_VkInstance_u64(&local_instance, &cgen_var_773, 1);
+    stream->write((uint64_t*)&cgen_var_773, 1 * 8);
+    uint64_t cgen_var_774;
+    stream->handleMapping()->mapHandles_VkSurfaceKHR_u64(&local_surface, &cgen_var_774, 1);
+    stream->write((uint64_t*)&cgen_var_774, 1 * 8);
     // WARNING PTR CHECK
-    uint64_t cgen_var_771 = (uint64_t)(uintptr_t)local_pAllocator;
-    stream->putBe64(cgen_var_771);
+    uint64_t cgen_var_775 = (uint64_t)(uintptr_t)local_pAllocator;
+    stream->putBe64(cgen_var_775);
     if (local_pAllocator)
     {
         marshal_VkAllocationCallbacks(stream, (VkAllocationCallbacks*)(local_pAllocator));
@@ -11519,6 +11796,7 @@
     VkSurfaceKHR surface,
     VkBool32* pSupported)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkGetPhysicalDeviceSurfaceSupportKHR encode");
     mImpl->log("start vkGetPhysicalDeviceSurfaceSupportKHR");
     auto stream = mImpl->stream();
@@ -11534,13 +11812,13 @@
     local_surface = surface;
     countingStream->rewind();
     {
-        uint64_t cgen_var_772;
-        countingStream->handleMapping()->mapHandles_VkPhysicalDevice_u64(&local_physicalDevice, &cgen_var_772, 1);
-        countingStream->write((uint64_t*)&cgen_var_772, 1 * 8);
+        uint64_t cgen_var_776;
+        countingStream->handleMapping()->mapHandles_VkPhysicalDevice_u64(&local_physicalDevice, &cgen_var_776, 1);
+        countingStream->write((uint64_t*)&cgen_var_776, 1 * 8);
         countingStream->write((uint32_t*)&local_queueFamilyIndex, sizeof(uint32_t));
-        uint64_t cgen_var_773;
-        countingStream->handleMapping()->mapHandles_VkSurfaceKHR_u64(&local_surface, &cgen_var_773, 1);
-        countingStream->write((uint64_t*)&cgen_var_773, 1 * 8);
+        uint64_t cgen_var_777;
+        countingStream->handleMapping()->mapHandles_VkSurfaceKHR_u64(&local_surface, &cgen_var_777, 1);
+        countingStream->write((uint64_t*)&cgen_var_777, 1 * 8);
         countingStream->write((VkBool32*)pSupported, sizeof(VkBool32));
     }
     uint32_t packetSize_vkGetPhysicalDeviceSurfaceSupportKHR = 4 + 4 + (uint32_t)countingStream->bytesWritten();
@@ -11548,13 +11826,13 @@
     uint32_t opcode_vkGetPhysicalDeviceSurfaceSupportKHR = OP_vkGetPhysicalDeviceSurfaceSupportKHR;
     stream->write(&opcode_vkGetPhysicalDeviceSurfaceSupportKHR, sizeof(uint32_t));
     stream->write(&packetSize_vkGetPhysicalDeviceSurfaceSupportKHR, sizeof(uint32_t));
-    uint64_t cgen_var_774;
-    stream->handleMapping()->mapHandles_VkPhysicalDevice_u64(&local_physicalDevice, &cgen_var_774, 1);
-    stream->write((uint64_t*)&cgen_var_774, 1 * 8);
+    uint64_t cgen_var_778;
+    stream->handleMapping()->mapHandles_VkPhysicalDevice_u64(&local_physicalDevice, &cgen_var_778, 1);
+    stream->write((uint64_t*)&cgen_var_778, 1 * 8);
     stream->write((uint32_t*)&local_queueFamilyIndex, sizeof(uint32_t));
-    uint64_t cgen_var_775;
-    stream->handleMapping()->mapHandles_VkSurfaceKHR_u64(&local_surface, &cgen_var_775, 1);
-    stream->write((uint64_t*)&cgen_var_775, 1 * 8);
+    uint64_t cgen_var_779;
+    stream->handleMapping()->mapHandles_VkSurfaceKHR_u64(&local_surface, &cgen_var_779, 1);
+    stream->write((uint64_t*)&cgen_var_779, 1 * 8);
     stream->write((VkBool32*)pSupported, sizeof(VkBool32));
     AEMU_SCOPED_TRACE("vkGetPhysicalDeviceSurfaceSupportKHR readParams");
     stream->read((VkBool32*)pSupported, sizeof(VkBool32));
@@ -11573,6 +11851,7 @@
     VkSurfaceKHR surface,
     VkSurfaceCapabilitiesKHR* pSurfaceCapabilities)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkGetPhysicalDeviceSurfaceCapabilitiesKHR encode");
     mImpl->log("start vkGetPhysicalDeviceSurfaceCapabilitiesKHR");
     auto stream = mImpl->stream();
@@ -11586,12 +11865,12 @@
     local_surface = surface;
     countingStream->rewind();
     {
-        uint64_t cgen_var_776;
-        countingStream->handleMapping()->mapHandles_VkPhysicalDevice_u64(&local_physicalDevice, &cgen_var_776, 1);
-        countingStream->write((uint64_t*)&cgen_var_776, 1 * 8);
-        uint64_t cgen_var_777;
-        countingStream->handleMapping()->mapHandles_VkSurfaceKHR_u64(&local_surface, &cgen_var_777, 1);
-        countingStream->write((uint64_t*)&cgen_var_777, 1 * 8);
+        uint64_t cgen_var_780;
+        countingStream->handleMapping()->mapHandles_VkPhysicalDevice_u64(&local_physicalDevice, &cgen_var_780, 1);
+        countingStream->write((uint64_t*)&cgen_var_780, 1 * 8);
+        uint64_t cgen_var_781;
+        countingStream->handleMapping()->mapHandles_VkSurfaceKHR_u64(&local_surface, &cgen_var_781, 1);
+        countingStream->write((uint64_t*)&cgen_var_781, 1 * 8);
         marshal_VkSurfaceCapabilitiesKHR(countingStream, (VkSurfaceCapabilitiesKHR*)(pSurfaceCapabilities));
     }
     uint32_t packetSize_vkGetPhysicalDeviceSurfaceCapabilitiesKHR = 4 + 4 + (uint32_t)countingStream->bytesWritten();
@@ -11599,12 +11878,12 @@
     uint32_t opcode_vkGetPhysicalDeviceSurfaceCapabilitiesKHR = OP_vkGetPhysicalDeviceSurfaceCapabilitiesKHR;
     stream->write(&opcode_vkGetPhysicalDeviceSurfaceCapabilitiesKHR, sizeof(uint32_t));
     stream->write(&packetSize_vkGetPhysicalDeviceSurfaceCapabilitiesKHR, sizeof(uint32_t));
-    uint64_t cgen_var_778;
-    stream->handleMapping()->mapHandles_VkPhysicalDevice_u64(&local_physicalDevice, &cgen_var_778, 1);
-    stream->write((uint64_t*)&cgen_var_778, 1 * 8);
-    uint64_t cgen_var_779;
-    stream->handleMapping()->mapHandles_VkSurfaceKHR_u64(&local_surface, &cgen_var_779, 1);
-    stream->write((uint64_t*)&cgen_var_779, 1 * 8);
+    uint64_t cgen_var_782;
+    stream->handleMapping()->mapHandles_VkPhysicalDevice_u64(&local_physicalDevice, &cgen_var_782, 1);
+    stream->write((uint64_t*)&cgen_var_782, 1 * 8);
+    uint64_t cgen_var_783;
+    stream->handleMapping()->mapHandles_VkSurfaceKHR_u64(&local_surface, &cgen_var_783, 1);
+    stream->write((uint64_t*)&cgen_var_783, 1 * 8);
     marshal_VkSurfaceCapabilitiesKHR(stream, (VkSurfaceCapabilitiesKHR*)(pSurfaceCapabilities));
     AEMU_SCOPED_TRACE("vkGetPhysicalDeviceSurfaceCapabilitiesKHR readParams");
     unmarshal_VkSurfaceCapabilitiesKHR(stream, (VkSurfaceCapabilitiesKHR*)(pSurfaceCapabilities));
@@ -11628,6 +11907,7 @@
     uint32_t* pSurfaceFormatCount,
     VkSurfaceFormatKHR* pSurfaceFormats)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkGetPhysicalDeviceSurfaceFormatsKHR encode");
     mImpl->log("start vkGetPhysicalDeviceSurfaceFormatsKHR");
     auto stream = mImpl->stream();
@@ -11641,22 +11921,22 @@
     local_surface = surface;
     countingStream->rewind();
     {
-        uint64_t cgen_var_780;
-        countingStream->handleMapping()->mapHandles_VkPhysicalDevice_u64(&local_physicalDevice, &cgen_var_780, 1);
-        countingStream->write((uint64_t*)&cgen_var_780, 1 * 8);
-        uint64_t cgen_var_781;
-        countingStream->handleMapping()->mapHandles_VkSurfaceKHR_u64(&local_surface, &cgen_var_781, 1);
-        countingStream->write((uint64_t*)&cgen_var_781, 1 * 8);
+        uint64_t cgen_var_784;
+        countingStream->handleMapping()->mapHandles_VkPhysicalDevice_u64(&local_physicalDevice, &cgen_var_784, 1);
+        countingStream->write((uint64_t*)&cgen_var_784, 1 * 8);
+        uint64_t cgen_var_785;
+        countingStream->handleMapping()->mapHandles_VkSurfaceKHR_u64(&local_surface, &cgen_var_785, 1);
+        countingStream->write((uint64_t*)&cgen_var_785, 1 * 8);
         // WARNING PTR CHECK
-        uint64_t cgen_var_782 = (uint64_t)(uintptr_t)pSurfaceFormatCount;
-        countingStream->putBe64(cgen_var_782);
+        uint64_t cgen_var_786 = (uint64_t)(uintptr_t)pSurfaceFormatCount;
+        countingStream->putBe64(cgen_var_786);
         if (pSurfaceFormatCount)
         {
             countingStream->write((uint32_t*)pSurfaceFormatCount, sizeof(uint32_t));
         }
         // WARNING PTR CHECK
-        uint64_t cgen_var_783 = (uint64_t)(uintptr_t)pSurfaceFormats;
-        countingStream->putBe64(cgen_var_783);
+        uint64_t cgen_var_787 = (uint64_t)(uintptr_t)pSurfaceFormats;
+        countingStream->putBe64(cgen_var_787);
         if (pSurfaceFormats)
         {
             for (uint32_t i = 0; i < (uint32_t)(*(pSurfaceFormatCount)); ++i)
@@ -11670,22 +11950,22 @@
     uint32_t opcode_vkGetPhysicalDeviceSurfaceFormatsKHR = OP_vkGetPhysicalDeviceSurfaceFormatsKHR;
     stream->write(&opcode_vkGetPhysicalDeviceSurfaceFormatsKHR, sizeof(uint32_t));
     stream->write(&packetSize_vkGetPhysicalDeviceSurfaceFormatsKHR, sizeof(uint32_t));
-    uint64_t cgen_var_784;
-    stream->handleMapping()->mapHandles_VkPhysicalDevice_u64(&local_physicalDevice, &cgen_var_784, 1);
-    stream->write((uint64_t*)&cgen_var_784, 1 * 8);
-    uint64_t cgen_var_785;
-    stream->handleMapping()->mapHandles_VkSurfaceKHR_u64(&local_surface, &cgen_var_785, 1);
-    stream->write((uint64_t*)&cgen_var_785, 1 * 8);
+    uint64_t cgen_var_788;
+    stream->handleMapping()->mapHandles_VkPhysicalDevice_u64(&local_physicalDevice, &cgen_var_788, 1);
+    stream->write((uint64_t*)&cgen_var_788, 1 * 8);
+    uint64_t cgen_var_789;
+    stream->handleMapping()->mapHandles_VkSurfaceKHR_u64(&local_surface, &cgen_var_789, 1);
+    stream->write((uint64_t*)&cgen_var_789, 1 * 8);
     // WARNING PTR CHECK
-    uint64_t cgen_var_786 = (uint64_t)(uintptr_t)pSurfaceFormatCount;
-    stream->putBe64(cgen_var_786);
+    uint64_t cgen_var_790 = (uint64_t)(uintptr_t)pSurfaceFormatCount;
+    stream->putBe64(cgen_var_790);
     if (pSurfaceFormatCount)
     {
         stream->write((uint32_t*)pSurfaceFormatCount, sizeof(uint32_t));
     }
     // WARNING PTR CHECK
-    uint64_t cgen_var_787 = (uint64_t)(uintptr_t)pSurfaceFormats;
-    stream->putBe64(cgen_var_787);
+    uint64_t cgen_var_791 = (uint64_t)(uintptr_t)pSurfaceFormats;
+    stream->putBe64(cgen_var_791);
     if (pSurfaceFormats)
     {
         for (uint32_t i = 0; i < (uint32_t)(*(pSurfaceFormatCount)); ++i)
@@ -11742,6 +12022,7 @@
     uint32_t* pPresentModeCount,
     VkPresentModeKHR* pPresentModes)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkGetPhysicalDeviceSurfacePresentModesKHR encode");
     mImpl->log("start vkGetPhysicalDeviceSurfacePresentModesKHR");
     auto stream = mImpl->stream();
@@ -11755,22 +12036,22 @@
     local_surface = surface;
     countingStream->rewind();
     {
-        uint64_t cgen_var_790;
-        countingStream->handleMapping()->mapHandles_VkPhysicalDevice_u64(&local_physicalDevice, &cgen_var_790, 1);
-        countingStream->write((uint64_t*)&cgen_var_790, 1 * 8);
-        uint64_t cgen_var_791;
-        countingStream->handleMapping()->mapHandles_VkSurfaceKHR_u64(&local_surface, &cgen_var_791, 1);
-        countingStream->write((uint64_t*)&cgen_var_791, 1 * 8);
+        uint64_t cgen_var_794;
+        countingStream->handleMapping()->mapHandles_VkPhysicalDevice_u64(&local_physicalDevice, &cgen_var_794, 1);
+        countingStream->write((uint64_t*)&cgen_var_794, 1 * 8);
+        uint64_t cgen_var_795;
+        countingStream->handleMapping()->mapHandles_VkSurfaceKHR_u64(&local_surface, &cgen_var_795, 1);
+        countingStream->write((uint64_t*)&cgen_var_795, 1 * 8);
         // WARNING PTR CHECK
-        uint64_t cgen_var_792 = (uint64_t)(uintptr_t)pPresentModeCount;
-        countingStream->putBe64(cgen_var_792);
+        uint64_t cgen_var_796 = (uint64_t)(uintptr_t)pPresentModeCount;
+        countingStream->putBe64(cgen_var_796);
         if (pPresentModeCount)
         {
             countingStream->write((uint32_t*)pPresentModeCount, sizeof(uint32_t));
         }
         // WARNING PTR CHECK
-        uint64_t cgen_var_793 = (uint64_t)(uintptr_t)pPresentModes;
-        countingStream->putBe64(cgen_var_793);
+        uint64_t cgen_var_797 = (uint64_t)(uintptr_t)pPresentModes;
+        countingStream->putBe64(cgen_var_797);
         if (pPresentModes)
         {
             countingStream->write((VkPresentModeKHR*)pPresentModes, (*(pPresentModeCount)) * sizeof(VkPresentModeKHR));
@@ -11781,22 +12062,22 @@
     uint32_t opcode_vkGetPhysicalDeviceSurfacePresentModesKHR = OP_vkGetPhysicalDeviceSurfacePresentModesKHR;
     stream->write(&opcode_vkGetPhysicalDeviceSurfacePresentModesKHR, sizeof(uint32_t));
     stream->write(&packetSize_vkGetPhysicalDeviceSurfacePresentModesKHR, sizeof(uint32_t));
-    uint64_t cgen_var_794;
-    stream->handleMapping()->mapHandles_VkPhysicalDevice_u64(&local_physicalDevice, &cgen_var_794, 1);
-    stream->write((uint64_t*)&cgen_var_794, 1 * 8);
-    uint64_t cgen_var_795;
-    stream->handleMapping()->mapHandles_VkSurfaceKHR_u64(&local_surface, &cgen_var_795, 1);
-    stream->write((uint64_t*)&cgen_var_795, 1 * 8);
+    uint64_t cgen_var_798;
+    stream->handleMapping()->mapHandles_VkPhysicalDevice_u64(&local_physicalDevice, &cgen_var_798, 1);
+    stream->write((uint64_t*)&cgen_var_798, 1 * 8);
+    uint64_t cgen_var_799;
+    stream->handleMapping()->mapHandles_VkSurfaceKHR_u64(&local_surface, &cgen_var_799, 1);
+    stream->write((uint64_t*)&cgen_var_799, 1 * 8);
     // WARNING PTR CHECK
-    uint64_t cgen_var_796 = (uint64_t)(uintptr_t)pPresentModeCount;
-    stream->putBe64(cgen_var_796);
+    uint64_t cgen_var_800 = (uint64_t)(uintptr_t)pPresentModeCount;
+    stream->putBe64(cgen_var_800);
     if (pPresentModeCount)
     {
         stream->write((uint32_t*)pPresentModeCount, sizeof(uint32_t));
     }
     // WARNING PTR CHECK
-    uint64_t cgen_var_797 = (uint64_t)(uintptr_t)pPresentModes;
-    stream->putBe64(cgen_var_797);
+    uint64_t cgen_var_801 = (uint64_t)(uintptr_t)pPresentModes;
+    stream->putBe64(cgen_var_801);
     if (pPresentModes)
     {
         stream->write((VkPresentModeKHR*)pPresentModes, (*(pPresentModeCount)) * sizeof(VkPresentModeKHR));
@@ -11842,6 +12123,7 @@
     const VkAllocationCallbacks* pAllocator,
     VkSwapchainKHR* pSwapchain)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkCreateSwapchainKHR encode");
     mImpl->log("start vkCreateSwapchainKHR");
     auto stream = mImpl->stream();
@@ -11876,47 +12158,47 @@
     }
     countingStream->rewind();
     {
-        uint64_t cgen_var_800;
-        countingStream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_800, 1);
-        countingStream->write((uint64_t*)&cgen_var_800, 1 * 8);
+        uint64_t cgen_var_804;
+        countingStream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_804, 1);
+        countingStream->write((uint64_t*)&cgen_var_804, 1 * 8);
         marshal_VkSwapchainCreateInfoKHR(countingStream, (VkSwapchainCreateInfoKHR*)(local_pCreateInfo));
         // WARNING PTR CHECK
-        uint64_t cgen_var_801 = (uint64_t)(uintptr_t)local_pAllocator;
-        countingStream->putBe64(cgen_var_801);
+        uint64_t cgen_var_805 = (uint64_t)(uintptr_t)local_pAllocator;
+        countingStream->putBe64(cgen_var_805);
         if (local_pAllocator)
         {
             marshal_VkAllocationCallbacks(countingStream, (VkAllocationCallbacks*)(local_pAllocator));
         }
-        uint64_t cgen_var_802;
-        countingStream->handleMapping()->mapHandles_VkSwapchainKHR_u64(pSwapchain, &cgen_var_802, 1);
-        countingStream->write((uint64_t*)&cgen_var_802, 8);
+        uint64_t cgen_var_806;
+        countingStream->handleMapping()->mapHandles_VkSwapchainKHR_u64(pSwapchain, &cgen_var_806, 1);
+        countingStream->write((uint64_t*)&cgen_var_806, 8);
     }
     uint32_t packetSize_vkCreateSwapchainKHR = 4 + 4 + (uint32_t)countingStream->bytesWritten();
     countingStream->rewind();
     uint32_t opcode_vkCreateSwapchainKHR = OP_vkCreateSwapchainKHR;
     stream->write(&opcode_vkCreateSwapchainKHR, sizeof(uint32_t));
     stream->write(&packetSize_vkCreateSwapchainKHR, sizeof(uint32_t));
-    uint64_t cgen_var_803;
-    stream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_803, 1);
-    stream->write((uint64_t*)&cgen_var_803, 1 * 8);
+    uint64_t cgen_var_807;
+    stream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_807, 1);
+    stream->write((uint64_t*)&cgen_var_807, 1 * 8);
     marshal_VkSwapchainCreateInfoKHR(stream, (VkSwapchainCreateInfoKHR*)(local_pCreateInfo));
     // WARNING PTR CHECK
-    uint64_t cgen_var_804 = (uint64_t)(uintptr_t)local_pAllocator;
-    stream->putBe64(cgen_var_804);
+    uint64_t cgen_var_808 = (uint64_t)(uintptr_t)local_pAllocator;
+    stream->putBe64(cgen_var_808);
     if (local_pAllocator)
     {
         marshal_VkAllocationCallbacks(stream, (VkAllocationCallbacks*)(local_pAllocator));
     }
     stream->unsetHandleMapping() /* emit_marshal, is handle, possibly out */;
-    uint64_t cgen_var_805;
-    stream->handleMapping()->mapHandles_VkSwapchainKHR_u64(pSwapchain, &cgen_var_805, 1);
-    stream->write((uint64_t*)&cgen_var_805, 8);
+    uint64_t cgen_var_809;
+    stream->handleMapping()->mapHandles_VkSwapchainKHR_u64(pSwapchain, &cgen_var_809, 1);
+    stream->write((uint64_t*)&cgen_var_809, 8);
     stream->setHandleMapping(resources->unwrapMapping());
     AEMU_SCOPED_TRACE("vkCreateSwapchainKHR readParams");
     stream->setHandleMapping(resources->createMapping());
-    uint64_t cgen_var_806;
-    stream->read((uint64_t*)&cgen_var_806, 8);
-    stream->handleMapping()->mapHandles_u64_VkSwapchainKHR(&cgen_var_806, (VkSwapchainKHR*)pSwapchain, 1);
+    uint64_t cgen_var_810;
+    stream->read((uint64_t*)&cgen_var_810, 8);
+    stream->handleMapping()->mapHandles_u64_VkSwapchainKHR(&cgen_var_810, (VkSwapchainKHR*)pSwapchain, 1);
     stream->unsetHandleMapping();
     AEMU_SCOPED_TRACE("vkCreateSwapchainKHR returnUnmarshal");
     VkResult vkCreateSwapchainKHR_VkResult_return = (VkResult)0;
@@ -11933,6 +12215,7 @@
     VkSwapchainKHR swapchain,
     const VkAllocationCallbacks* pAllocator)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkDestroySwapchainKHR encode");
     mImpl->log("start vkDestroySwapchainKHR");
     auto stream = mImpl->stream();
@@ -11958,15 +12241,15 @@
     }
     countingStream->rewind();
     {
-        uint64_t cgen_var_807;
-        countingStream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_807, 1);
-        countingStream->write((uint64_t*)&cgen_var_807, 1 * 8);
-        uint64_t cgen_var_808;
-        countingStream->handleMapping()->mapHandles_VkSwapchainKHR_u64(&local_swapchain, &cgen_var_808, 1);
-        countingStream->write((uint64_t*)&cgen_var_808, 1 * 8);
+        uint64_t cgen_var_811;
+        countingStream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_811, 1);
+        countingStream->write((uint64_t*)&cgen_var_811, 1 * 8);
+        uint64_t cgen_var_812;
+        countingStream->handleMapping()->mapHandles_VkSwapchainKHR_u64(&local_swapchain, &cgen_var_812, 1);
+        countingStream->write((uint64_t*)&cgen_var_812, 1 * 8);
         // WARNING PTR CHECK
-        uint64_t cgen_var_809 = (uint64_t)(uintptr_t)local_pAllocator;
-        countingStream->putBe64(cgen_var_809);
+        uint64_t cgen_var_813 = (uint64_t)(uintptr_t)local_pAllocator;
+        countingStream->putBe64(cgen_var_813);
         if (local_pAllocator)
         {
             marshal_VkAllocationCallbacks(countingStream, (VkAllocationCallbacks*)(local_pAllocator));
@@ -11977,15 +12260,15 @@
     uint32_t opcode_vkDestroySwapchainKHR = OP_vkDestroySwapchainKHR;
     stream->write(&opcode_vkDestroySwapchainKHR, sizeof(uint32_t));
     stream->write(&packetSize_vkDestroySwapchainKHR, sizeof(uint32_t));
-    uint64_t cgen_var_810;
-    stream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_810, 1);
-    stream->write((uint64_t*)&cgen_var_810, 1 * 8);
-    uint64_t cgen_var_811;
-    stream->handleMapping()->mapHandles_VkSwapchainKHR_u64(&local_swapchain, &cgen_var_811, 1);
-    stream->write((uint64_t*)&cgen_var_811, 1 * 8);
+    uint64_t cgen_var_814;
+    stream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_814, 1);
+    stream->write((uint64_t*)&cgen_var_814, 1 * 8);
+    uint64_t cgen_var_815;
+    stream->handleMapping()->mapHandles_VkSwapchainKHR_u64(&local_swapchain, &cgen_var_815, 1);
+    stream->write((uint64_t*)&cgen_var_815, 1 * 8);
     // WARNING PTR CHECK
-    uint64_t cgen_var_812 = (uint64_t)(uintptr_t)local_pAllocator;
-    stream->putBe64(cgen_var_812);
+    uint64_t cgen_var_816 = (uint64_t)(uintptr_t)local_pAllocator;
+    stream->putBe64(cgen_var_816);
     if (local_pAllocator)
     {
         marshal_VkAllocationCallbacks(stream, (VkAllocationCallbacks*)(local_pAllocator));
@@ -12002,6 +12285,7 @@
     uint32_t* pSwapchainImageCount,
     VkImage* pSwapchainImages)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkGetSwapchainImagesKHR encode");
     mImpl->log("start vkGetSwapchainImagesKHR");
     auto stream = mImpl->stream();
@@ -12015,30 +12299,30 @@
     local_swapchain = swapchain;
     countingStream->rewind();
     {
-        uint64_t cgen_var_813;
-        countingStream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_813, 1);
-        countingStream->write((uint64_t*)&cgen_var_813, 1 * 8);
-        uint64_t cgen_var_814;
-        countingStream->handleMapping()->mapHandles_VkSwapchainKHR_u64(&local_swapchain, &cgen_var_814, 1);
-        countingStream->write((uint64_t*)&cgen_var_814, 1 * 8);
+        uint64_t cgen_var_817;
+        countingStream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_817, 1);
+        countingStream->write((uint64_t*)&cgen_var_817, 1 * 8);
+        uint64_t cgen_var_818;
+        countingStream->handleMapping()->mapHandles_VkSwapchainKHR_u64(&local_swapchain, &cgen_var_818, 1);
+        countingStream->write((uint64_t*)&cgen_var_818, 1 * 8);
         // WARNING PTR CHECK
-        uint64_t cgen_var_815 = (uint64_t)(uintptr_t)pSwapchainImageCount;
-        countingStream->putBe64(cgen_var_815);
+        uint64_t cgen_var_819 = (uint64_t)(uintptr_t)pSwapchainImageCount;
+        countingStream->putBe64(cgen_var_819);
         if (pSwapchainImageCount)
         {
             countingStream->write((uint32_t*)pSwapchainImageCount, sizeof(uint32_t));
         }
         // WARNING PTR CHECK
-        uint64_t cgen_var_816 = (uint64_t)(uintptr_t)pSwapchainImages;
-        countingStream->putBe64(cgen_var_816);
+        uint64_t cgen_var_820 = (uint64_t)(uintptr_t)pSwapchainImages;
+        countingStream->putBe64(cgen_var_820);
         if (pSwapchainImages)
         {
             if ((*(pSwapchainImageCount)))
             {
-                uint64_t* cgen_var_817;
-                countingStream->alloc((void**)&cgen_var_817, (*(pSwapchainImageCount)) * 8);
-                countingStream->handleMapping()->mapHandles_VkImage_u64(pSwapchainImages, cgen_var_817, (*(pSwapchainImageCount)));
-                countingStream->write((uint64_t*)cgen_var_817, (*(pSwapchainImageCount)) * 8);
+                uint64_t* cgen_var_821;
+                countingStream->alloc((void**)&cgen_var_821, (*(pSwapchainImageCount)) * 8);
+                countingStream->handleMapping()->mapHandles_VkImage_u64(pSwapchainImages, cgen_var_821, (*(pSwapchainImageCount)));
+                countingStream->write((uint64_t*)cgen_var_821, (*(pSwapchainImageCount)) * 8);
             }
         }
     }
@@ -12047,31 +12331,31 @@
     uint32_t opcode_vkGetSwapchainImagesKHR = OP_vkGetSwapchainImagesKHR;
     stream->write(&opcode_vkGetSwapchainImagesKHR, sizeof(uint32_t));
     stream->write(&packetSize_vkGetSwapchainImagesKHR, sizeof(uint32_t));
-    uint64_t cgen_var_818;
-    stream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_818, 1);
-    stream->write((uint64_t*)&cgen_var_818, 1 * 8);
-    uint64_t cgen_var_819;
-    stream->handleMapping()->mapHandles_VkSwapchainKHR_u64(&local_swapchain, &cgen_var_819, 1);
-    stream->write((uint64_t*)&cgen_var_819, 1 * 8);
+    uint64_t cgen_var_822;
+    stream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_822, 1);
+    stream->write((uint64_t*)&cgen_var_822, 1 * 8);
+    uint64_t cgen_var_823;
+    stream->handleMapping()->mapHandles_VkSwapchainKHR_u64(&local_swapchain, &cgen_var_823, 1);
+    stream->write((uint64_t*)&cgen_var_823, 1 * 8);
     // WARNING PTR CHECK
-    uint64_t cgen_var_820 = (uint64_t)(uintptr_t)pSwapchainImageCount;
-    stream->putBe64(cgen_var_820);
+    uint64_t cgen_var_824 = (uint64_t)(uintptr_t)pSwapchainImageCount;
+    stream->putBe64(cgen_var_824);
     if (pSwapchainImageCount)
     {
         stream->write((uint32_t*)pSwapchainImageCount, sizeof(uint32_t));
     }
     stream->unsetHandleMapping() /* emit_marshal, is handle, possibly out */;
     // WARNING PTR CHECK
-    uint64_t cgen_var_821 = (uint64_t)(uintptr_t)pSwapchainImages;
-    stream->putBe64(cgen_var_821);
+    uint64_t cgen_var_825 = (uint64_t)(uintptr_t)pSwapchainImages;
+    stream->putBe64(cgen_var_825);
     if (pSwapchainImages)
     {
         if ((*(pSwapchainImageCount)))
         {
-            uint64_t* cgen_var_822;
-            stream->alloc((void**)&cgen_var_822, (*(pSwapchainImageCount)) * 8);
-            stream->handleMapping()->mapHandles_VkImage_u64(pSwapchainImages, cgen_var_822, (*(pSwapchainImageCount)));
-            stream->write((uint64_t*)cgen_var_822, (*(pSwapchainImageCount)) * 8);
+            uint64_t* cgen_var_826;
+            stream->alloc((void**)&cgen_var_826, (*(pSwapchainImageCount)) * 8);
+            stream->handleMapping()->mapHandles_VkImage_u64(pSwapchainImages, cgen_var_826, (*(pSwapchainImageCount)));
+            stream->write((uint64_t*)cgen_var_826, (*(pSwapchainImageCount)) * 8);
         }
     }
     stream->setHandleMapping(resources->unwrapMapping());
@@ -12098,10 +12382,10 @@
         }
         if ((*(pSwapchainImageCount)))
         {
-            uint64_t* cgen_var_825;
-            stream->alloc((void**)&cgen_var_825, (*(pSwapchainImageCount)) * 8);
-            stream->read((uint64_t*)cgen_var_825, (*(pSwapchainImageCount)) * 8);
-            stream->handleMapping()->mapHandles_u64_VkImage(cgen_var_825, (VkImage*)pSwapchainImages, (*(pSwapchainImageCount)));
+            uint64_t* cgen_var_829;
+            stream->alloc((void**)&cgen_var_829, (*(pSwapchainImageCount)) * 8);
+            stream->read((uint64_t*)cgen_var_829, (*(pSwapchainImageCount)) * 8);
+            stream->handleMapping()->mapHandles_u64_VkImage(cgen_var_829, (VkImage*)pSwapchainImages, (*(pSwapchainImageCount)));
         }
     }
     AEMU_SCOPED_TRACE("vkGetSwapchainImagesKHR returnUnmarshal");
@@ -12122,6 +12406,7 @@
     VkFence fence,
     uint32_t* pImageIndex)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkAcquireNextImageKHR encode");
     mImpl->log("start vkAcquireNextImageKHR");
     auto stream = mImpl->stream();
@@ -12141,19 +12426,19 @@
     local_fence = fence;
     countingStream->rewind();
     {
-        uint64_t cgen_var_826;
-        countingStream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_826, 1);
-        countingStream->write((uint64_t*)&cgen_var_826, 1 * 8);
-        uint64_t cgen_var_827;
-        countingStream->handleMapping()->mapHandles_VkSwapchainKHR_u64(&local_swapchain, &cgen_var_827, 1);
-        countingStream->write((uint64_t*)&cgen_var_827, 1 * 8);
+        uint64_t cgen_var_830;
+        countingStream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_830, 1);
+        countingStream->write((uint64_t*)&cgen_var_830, 1 * 8);
+        uint64_t cgen_var_831;
+        countingStream->handleMapping()->mapHandles_VkSwapchainKHR_u64(&local_swapchain, &cgen_var_831, 1);
+        countingStream->write((uint64_t*)&cgen_var_831, 1 * 8);
         countingStream->write((uint64_t*)&local_timeout, sizeof(uint64_t));
-        uint64_t cgen_var_828;
-        countingStream->handleMapping()->mapHandles_VkSemaphore_u64(&local_semaphore, &cgen_var_828, 1);
-        countingStream->write((uint64_t*)&cgen_var_828, 1 * 8);
-        uint64_t cgen_var_829;
-        countingStream->handleMapping()->mapHandles_VkFence_u64(&local_fence, &cgen_var_829, 1);
-        countingStream->write((uint64_t*)&cgen_var_829, 1 * 8);
+        uint64_t cgen_var_832;
+        countingStream->handleMapping()->mapHandles_VkSemaphore_u64(&local_semaphore, &cgen_var_832, 1);
+        countingStream->write((uint64_t*)&cgen_var_832, 1 * 8);
+        uint64_t cgen_var_833;
+        countingStream->handleMapping()->mapHandles_VkFence_u64(&local_fence, &cgen_var_833, 1);
+        countingStream->write((uint64_t*)&cgen_var_833, 1 * 8);
         countingStream->write((uint32_t*)pImageIndex, sizeof(uint32_t));
     }
     uint32_t packetSize_vkAcquireNextImageKHR = 4 + 4 + (uint32_t)countingStream->bytesWritten();
@@ -12161,19 +12446,19 @@
     uint32_t opcode_vkAcquireNextImageKHR = OP_vkAcquireNextImageKHR;
     stream->write(&opcode_vkAcquireNextImageKHR, sizeof(uint32_t));
     stream->write(&packetSize_vkAcquireNextImageKHR, sizeof(uint32_t));
-    uint64_t cgen_var_830;
-    stream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_830, 1);
-    stream->write((uint64_t*)&cgen_var_830, 1 * 8);
-    uint64_t cgen_var_831;
-    stream->handleMapping()->mapHandles_VkSwapchainKHR_u64(&local_swapchain, &cgen_var_831, 1);
-    stream->write((uint64_t*)&cgen_var_831, 1 * 8);
+    uint64_t cgen_var_834;
+    stream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_834, 1);
+    stream->write((uint64_t*)&cgen_var_834, 1 * 8);
+    uint64_t cgen_var_835;
+    stream->handleMapping()->mapHandles_VkSwapchainKHR_u64(&local_swapchain, &cgen_var_835, 1);
+    stream->write((uint64_t*)&cgen_var_835, 1 * 8);
     stream->write((uint64_t*)&local_timeout, sizeof(uint64_t));
-    uint64_t cgen_var_832;
-    stream->handleMapping()->mapHandles_VkSemaphore_u64(&local_semaphore, &cgen_var_832, 1);
-    stream->write((uint64_t*)&cgen_var_832, 1 * 8);
-    uint64_t cgen_var_833;
-    stream->handleMapping()->mapHandles_VkFence_u64(&local_fence, &cgen_var_833, 1);
-    stream->write((uint64_t*)&cgen_var_833, 1 * 8);
+    uint64_t cgen_var_836;
+    stream->handleMapping()->mapHandles_VkSemaphore_u64(&local_semaphore, &cgen_var_836, 1);
+    stream->write((uint64_t*)&cgen_var_836, 1 * 8);
+    uint64_t cgen_var_837;
+    stream->handleMapping()->mapHandles_VkFence_u64(&local_fence, &cgen_var_837, 1);
+    stream->write((uint64_t*)&cgen_var_837, 1 * 8);
     stream->write((uint32_t*)pImageIndex, sizeof(uint32_t));
     AEMU_SCOPED_TRACE("vkAcquireNextImageKHR readParams");
     stream->read((uint32_t*)pImageIndex, sizeof(uint32_t));
@@ -12191,6 +12476,7 @@
     VkQueue queue,
     const VkPresentInfoKHR* pPresentInfo)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkQueuePresentKHR encode");
     mImpl->log("start vkQueuePresentKHR");
     auto stream = mImpl->stream();
@@ -12213,9 +12499,9 @@
     }
     countingStream->rewind();
     {
-        uint64_t cgen_var_834;
-        countingStream->handleMapping()->mapHandles_VkQueue_u64(&local_queue, &cgen_var_834, 1);
-        countingStream->write((uint64_t*)&cgen_var_834, 1 * 8);
+        uint64_t cgen_var_838;
+        countingStream->handleMapping()->mapHandles_VkQueue_u64(&local_queue, &cgen_var_838, 1);
+        countingStream->write((uint64_t*)&cgen_var_838, 1 * 8);
         marshal_VkPresentInfoKHR(countingStream, (VkPresentInfoKHR*)(local_pPresentInfo));
     }
     uint32_t packetSize_vkQueuePresentKHR = 4 + 4 + (uint32_t)countingStream->bytesWritten();
@@ -12223,9 +12509,9 @@
     uint32_t opcode_vkQueuePresentKHR = OP_vkQueuePresentKHR;
     stream->write(&opcode_vkQueuePresentKHR, sizeof(uint32_t));
     stream->write(&packetSize_vkQueuePresentKHR, sizeof(uint32_t));
-    uint64_t cgen_var_835;
-    stream->handleMapping()->mapHandles_VkQueue_u64(&local_queue, &cgen_var_835, 1);
-    stream->write((uint64_t*)&cgen_var_835, 1 * 8);
+    uint64_t cgen_var_839;
+    stream->handleMapping()->mapHandles_VkQueue_u64(&local_queue, &cgen_var_839, 1);
+    stream->write((uint64_t*)&cgen_var_839, 1 * 8);
     marshal_VkPresentInfoKHR(stream, (VkPresentInfoKHR*)(local_pPresentInfo));
     AEMU_SCOPED_TRACE("vkQueuePresentKHR readParams");
     AEMU_SCOPED_TRACE("vkQueuePresentKHR returnUnmarshal");
@@ -12242,6 +12528,7 @@
     VkDevice device,
     VkDeviceGroupPresentCapabilitiesKHR* pDeviceGroupPresentCapabilities)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkGetDeviceGroupPresentCapabilitiesKHR encode");
     mImpl->log("start vkGetDeviceGroupPresentCapabilitiesKHR");
     auto stream = mImpl->stream();
@@ -12253,9 +12540,9 @@
     local_device = device;
     countingStream->rewind();
     {
-        uint64_t cgen_var_836;
-        countingStream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_836, 1);
-        countingStream->write((uint64_t*)&cgen_var_836, 1 * 8);
+        uint64_t cgen_var_840;
+        countingStream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_840, 1);
+        countingStream->write((uint64_t*)&cgen_var_840, 1 * 8);
         marshal_VkDeviceGroupPresentCapabilitiesKHR(countingStream, (VkDeviceGroupPresentCapabilitiesKHR*)(pDeviceGroupPresentCapabilities));
     }
     uint32_t packetSize_vkGetDeviceGroupPresentCapabilitiesKHR = 4 + 4 + (uint32_t)countingStream->bytesWritten();
@@ -12263,9 +12550,9 @@
     uint32_t opcode_vkGetDeviceGroupPresentCapabilitiesKHR = OP_vkGetDeviceGroupPresentCapabilitiesKHR;
     stream->write(&opcode_vkGetDeviceGroupPresentCapabilitiesKHR, sizeof(uint32_t));
     stream->write(&packetSize_vkGetDeviceGroupPresentCapabilitiesKHR, sizeof(uint32_t));
-    uint64_t cgen_var_837;
-    stream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_837, 1);
-    stream->write((uint64_t*)&cgen_var_837, 1 * 8);
+    uint64_t cgen_var_841;
+    stream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_841, 1);
+    stream->write((uint64_t*)&cgen_var_841, 1 * 8);
     marshal_VkDeviceGroupPresentCapabilitiesKHR(stream, (VkDeviceGroupPresentCapabilitiesKHR*)(pDeviceGroupPresentCapabilities));
     AEMU_SCOPED_TRACE("vkGetDeviceGroupPresentCapabilitiesKHR readParams");
     unmarshal_VkDeviceGroupPresentCapabilitiesKHR(stream, (VkDeviceGroupPresentCapabilitiesKHR*)(pDeviceGroupPresentCapabilities));
@@ -12288,6 +12575,7 @@
     VkSurfaceKHR surface,
     VkDeviceGroupPresentModeFlagsKHR* pModes)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkGetDeviceGroupSurfacePresentModesKHR encode");
     mImpl->log("start vkGetDeviceGroupSurfacePresentModesKHR");
     auto stream = mImpl->stream();
@@ -12301,15 +12589,15 @@
     local_surface = surface;
     countingStream->rewind();
     {
-        uint64_t cgen_var_838;
-        countingStream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_838, 1);
-        countingStream->write((uint64_t*)&cgen_var_838, 1 * 8);
-        uint64_t cgen_var_839;
-        countingStream->handleMapping()->mapHandles_VkSurfaceKHR_u64(&local_surface, &cgen_var_839, 1);
-        countingStream->write((uint64_t*)&cgen_var_839, 1 * 8);
+        uint64_t cgen_var_842;
+        countingStream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_842, 1);
+        countingStream->write((uint64_t*)&cgen_var_842, 1 * 8);
+        uint64_t cgen_var_843;
+        countingStream->handleMapping()->mapHandles_VkSurfaceKHR_u64(&local_surface, &cgen_var_843, 1);
+        countingStream->write((uint64_t*)&cgen_var_843, 1 * 8);
         // WARNING PTR CHECK
-        uint64_t cgen_var_840 = (uint64_t)(uintptr_t)pModes;
-        countingStream->putBe64(cgen_var_840);
+        uint64_t cgen_var_844 = (uint64_t)(uintptr_t)pModes;
+        countingStream->putBe64(cgen_var_844);
         if (pModes)
         {
             countingStream->write((VkDeviceGroupPresentModeFlagsKHR*)pModes, sizeof(VkDeviceGroupPresentModeFlagsKHR));
@@ -12320,15 +12608,15 @@
     uint32_t opcode_vkGetDeviceGroupSurfacePresentModesKHR = OP_vkGetDeviceGroupSurfacePresentModesKHR;
     stream->write(&opcode_vkGetDeviceGroupSurfacePresentModesKHR, sizeof(uint32_t));
     stream->write(&packetSize_vkGetDeviceGroupSurfacePresentModesKHR, sizeof(uint32_t));
-    uint64_t cgen_var_841;
-    stream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_841, 1);
-    stream->write((uint64_t*)&cgen_var_841, 1 * 8);
-    uint64_t cgen_var_842;
-    stream->handleMapping()->mapHandles_VkSurfaceKHR_u64(&local_surface, &cgen_var_842, 1);
-    stream->write((uint64_t*)&cgen_var_842, 1 * 8);
+    uint64_t cgen_var_845;
+    stream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_845, 1);
+    stream->write((uint64_t*)&cgen_var_845, 1 * 8);
+    uint64_t cgen_var_846;
+    stream->handleMapping()->mapHandles_VkSurfaceKHR_u64(&local_surface, &cgen_var_846, 1);
+    stream->write((uint64_t*)&cgen_var_846, 1 * 8);
     // WARNING PTR CHECK
-    uint64_t cgen_var_843 = (uint64_t)(uintptr_t)pModes;
-    stream->putBe64(cgen_var_843);
+    uint64_t cgen_var_847 = (uint64_t)(uintptr_t)pModes;
+    stream->putBe64(cgen_var_847);
     if (pModes)
     {
         stream->write((VkDeviceGroupPresentModeFlagsKHR*)pModes, sizeof(VkDeviceGroupPresentModeFlagsKHR));
@@ -12361,6 +12649,7 @@
     uint32_t* pRectCount,
     VkRect2D* pRects)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkGetPhysicalDevicePresentRectanglesKHR encode");
     mImpl->log("start vkGetPhysicalDevicePresentRectanglesKHR");
     auto stream = mImpl->stream();
@@ -12374,22 +12663,22 @@
     local_surface = surface;
     countingStream->rewind();
     {
-        uint64_t cgen_var_845;
-        countingStream->handleMapping()->mapHandles_VkPhysicalDevice_u64(&local_physicalDevice, &cgen_var_845, 1);
-        countingStream->write((uint64_t*)&cgen_var_845, 1 * 8);
-        uint64_t cgen_var_846;
-        countingStream->handleMapping()->mapHandles_VkSurfaceKHR_u64(&local_surface, &cgen_var_846, 1);
-        countingStream->write((uint64_t*)&cgen_var_846, 1 * 8);
+        uint64_t cgen_var_849;
+        countingStream->handleMapping()->mapHandles_VkPhysicalDevice_u64(&local_physicalDevice, &cgen_var_849, 1);
+        countingStream->write((uint64_t*)&cgen_var_849, 1 * 8);
+        uint64_t cgen_var_850;
+        countingStream->handleMapping()->mapHandles_VkSurfaceKHR_u64(&local_surface, &cgen_var_850, 1);
+        countingStream->write((uint64_t*)&cgen_var_850, 1 * 8);
         // WARNING PTR CHECK
-        uint64_t cgen_var_847 = (uint64_t)(uintptr_t)pRectCount;
-        countingStream->putBe64(cgen_var_847);
+        uint64_t cgen_var_851 = (uint64_t)(uintptr_t)pRectCount;
+        countingStream->putBe64(cgen_var_851);
         if (pRectCount)
         {
             countingStream->write((uint32_t*)pRectCount, sizeof(uint32_t));
         }
         // WARNING PTR CHECK
-        uint64_t cgen_var_848 = (uint64_t)(uintptr_t)pRects;
-        countingStream->putBe64(cgen_var_848);
+        uint64_t cgen_var_852 = (uint64_t)(uintptr_t)pRects;
+        countingStream->putBe64(cgen_var_852);
         if (pRects)
         {
             for (uint32_t i = 0; i < (uint32_t)(*(pRectCount)); ++i)
@@ -12403,22 +12692,22 @@
     uint32_t opcode_vkGetPhysicalDevicePresentRectanglesKHR = OP_vkGetPhysicalDevicePresentRectanglesKHR;
     stream->write(&opcode_vkGetPhysicalDevicePresentRectanglesKHR, sizeof(uint32_t));
     stream->write(&packetSize_vkGetPhysicalDevicePresentRectanglesKHR, sizeof(uint32_t));
-    uint64_t cgen_var_849;
-    stream->handleMapping()->mapHandles_VkPhysicalDevice_u64(&local_physicalDevice, &cgen_var_849, 1);
-    stream->write((uint64_t*)&cgen_var_849, 1 * 8);
-    uint64_t cgen_var_850;
-    stream->handleMapping()->mapHandles_VkSurfaceKHR_u64(&local_surface, &cgen_var_850, 1);
-    stream->write((uint64_t*)&cgen_var_850, 1 * 8);
+    uint64_t cgen_var_853;
+    stream->handleMapping()->mapHandles_VkPhysicalDevice_u64(&local_physicalDevice, &cgen_var_853, 1);
+    stream->write((uint64_t*)&cgen_var_853, 1 * 8);
+    uint64_t cgen_var_854;
+    stream->handleMapping()->mapHandles_VkSurfaceKHR_u64(&local_surface, &cgen_var_854, 1);
+    stream->write((uint64_t*)&cgen_var_854, 1 * 8);
     // WARNING PTR CHECK
-    uint64_t cgen_var_851 = (uint64_t)(uintptr_t)pRectCount;
-    stream->putBe64(cgen_var_851);
+    uint64_t cgen_var_855 = (uint64_t)(uintptr_t)pRectCount;
+    stream->putBe64(cgen_var_855);
     if (pRectCount)
     {
         stream->write((uint32_t*)pRectCount, sizeof(uint32_t));
     }
     // WARNING PTR CHECK
-    uint64_t cgen_var_852 = (uint64_t)(uintptr_t)pRects;
-    stream->putBe64(cgen_var_852);
+    uint64_t cgen_var_856 = (uint64_t)(uintptr_t)pRects;
+    stream->putBe64(cgen_var_856);
     if (pRects)
     {
         for (uint32_t i = 0; i < (uint32_t)(*(pRectCount)); ++i)
@@ -12474,6 +12763,7 @@
     const VkAcquireNextImageInfoKHR* pAcquireInfo,
     uint32_t* pImageIndex)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkAcquireNextImage2KHR encode");
     mImpl->log("start vkAcquireNextImage2KHR");
     auto stream = mImpl->stream();
@@ -12496,9 +12786,9 @@
     }
     countingStream->rewind();
     {
-        uint64_t cgen_var_855;
-        countingStream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_855, 1);
-        countingStream->write((uint64_t*)&cgen_var_855, 1 * 8);
+        uint64_t cgen_var_859;
+        countingStream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_859, 1);
+        countingStream->write((uint64_t*)&cgen_var_859, 1 * 8);
         marshal_VkAcquireNextImageInfoKHR(countingStream, (VkAcquireNextImageInfoKHR*)(local_pAcquireInfo));
         countingStream->write((uint32_t*)pImageIndex, sizeof(uint32_t));
     }
@@ -12507,9 +12797,9 @@
     uint32_t opcode_vkAcquireNextImage2KHR = OP_vkAcquireNextImage2KHR;
     stream->write(&opcode_vkAcquireNextImage2KHR, sizeof(uint32_t));
     stream->write(&packetSize_vkAcquireNextImage2KHR, sizeof(uint32_t));
-    uint64_t cgen_var_856;
-    stream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_856, 1);
-    stream->write((uint64_t*)&cgen_var_856, 1 * 8);
+    uint64_t cgen_var_860;
+    stream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_860, 1);
+    stream->write((uint64_t*)&cgen_var_860, 1 * 8);
     marshal_VkAcquireNextImageInfoKHR(stream, (VkAcquireNextImageInfoKHR*)(local_pAcquireInfo));
     stream->write((uint32_t*)pImageIndex, sizeof(uint32_t));
     AEMU_SCOPED_TRACE("vkAcquireNextImage2KHR readParams");
@@ -12531,6 +12821,7 @@
     uint32_t* pPropertyCount,
     VkDisplayPropertiesKHR* pProperties)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkGetPhysicalDeviceDisplayPropertiesKHR encode");
     mImpl->log("start vkGetPhysicalDeviceDisplayPropertiesKHR");
     auto stream = mImpl->stream();
@@ -12542,19 +12833,19 @@
     local_physicalDevice = physicalDevice;
     countingStream->rewind();
     {
-        uint64_t cgen_var_857;
-        countingStream->handleMapping()->mapHandles_VkPhysicalDevice_u64(&local_physicalDevice, &cgen_var_857, 1);
-        countingStream->write((uint64_t*)&cgen_var_857, 1 * 8);
+        uint64_t cgen_var_861;
+        countingStream->handleMapping()->mapHandles_VkPhysicalDevice_u64(&local_physicalDevice, &cgen_var_861, 1);
+        countingStream->write((uint64_t*)&cgen_var_861, 1 * 8);
         // WARNING PTR CHECK
-        uint64_t cgen_var_858 = (uint64_t)(uintptr_t)pPropertyCount;
-        countingStream->putBe64(cgen_var_858);
+        uint64_t cgen_var_862 = (uint64_t)(uintptr_t)pPropertyCount;
+        countingStream->putBe64(cgen_var_862);
         if (pPropertyCount)
         {
             countingStream->write((uint32_t*)pPropertyCount, sizeof(uint32_t));
         }
         // WARNING PTR CHECK
-        uint64_t cgen_var_859 = (uint64_t)(uintptr_t)pProperties;
-        countingStream->putBe64(cgen_var_859);
+        uint64_t cgen_var_863 = (uint64_t)(uintptr_t)pProperties;
+        countingStream->putBe64(cgen_var_863);
         if (pProperties)
         {
             for (uint32_t i = 0; i < (uint32_t)(*(pPropertyCount)); ++i)
@@ -12568,19 +12859,19 @@
     uint32_t opcode_vkGetPhysicalDeviceDisplayPropertiesKHR = OP_vkGetPhysicalDeviceDisplayPropertiesKHR;
     stream->write(&opcode_vkGetPhysicalDeviceDisplayPropertiesKHR, sizeof(uint32_t));
     stream->write(&packetSize_vkGetPhysicalDeviceDisplayPropertiesKHR, sizeof(uint32_t));
-    uint64_t cgen_var_860;
-    stream->handleMapping()->mapHandles_VkPhysicalDevice_u64(&local_physicalDevice, &cgen_var_860, 1);
-    stream->write((uint64_t*)&cgen_var_860, 1 * 8);
+    uint64_t cgen_var_864;
+    stream->handleMapping()->mapHandles_VkPhysicalDevice_u64(&local_physicalDevice, &cgen_var_864, 1);
+    stream->write((uint64_t*)&cgen_var_864, 1 * 8);
     // WARNING PTR CHECK
-    uint64_t cgen_var_861 = (uint64_t)(uintptr_t)pPropertyCount;
-    stream->putBe64(cgen_var_861);
+    uint64_t cgen_var_865 = (uint64_t)(uintptr_t)pPropertyCount;
+    stream->putBe64(cgen_var_865);
     if (pPropertyCount)
     {
         stream->write((uint32_t*)pPropertyCount, sizeof(uint32_t));
     }
     // WARNING PTR CHECK
-    uint64_t cgen_var_862 = (uint64_t)(uintptr_t)pProperties;
-    stream->putBe64(cgen_var_862);
+    uint64_t cgen_var_866 = (uint64_t)(uintptr_t)pProperties;
+    stream->putBe64(cgen_var_866);
     if (pProperties)
     {
         for (uint32_t i = 0; i < (uint32_t)(*(pPropertyCount)); ++i)
@@ -12636,6 +12927,7 @@
     uint32_t* pPropertyCount,
     VkDisplayPlanePropertiesKHR* pProperties)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkGetPhysicalDeviceDisplayPlanePropertiesKHR encode");
     mImpl->log("start vkGetPhysicalDeviceDisplayPlanePropertiesKHR");
     auto stream = mImpl->stream();
@@ -12647,19 +12939,19 @@
     local_physicalDevice = physicalDevice;
     countingStream->rewind();
     {
-        uint64_t cgen_var_865;
-        countingStream->handleMapping()->mapHandles_VkPhysicalDevice_u64(&local_physicalDevice, &cgen_var_865, 1);
-        countingStream->write((uint64_t*)&cgen_var_865, 1 * 8);
+        uint64_t cgen_var_869;
+        countingStream->handleMapping()->mapHandles_VkPhysicalDevice_u64(&local_physicalDevice, &cgen_var_869, 1);
+        countingStream->write((uint64_t*)&cgen_var_869, 1 * 8);
         // WARNING PTR CHECK
-        uint64_t cgen_var_866 = (uint64_t)(uintptr_t)pPropertyCount;
-        countingStream->putBe64(cgen_var_866);
+        uint64_t cgen_var_870 = (uint64_t)(uintptr_t)pPropertyCount;
+        countingStream->putBe64(cgen_var_870);
         if (pPropertyCount)
         {
             countingStream->write((uint32_t*)pPropertyCount, sizeof(uint32_t));
         }
         // WARNING PTR CHECK
-        uint64_t cgen_var_867 = (uint64_t)(uintptr_t)pProperties;
-        countingStream->putBe64(cgen_var_867);
+        uint64_t cgen_var_871 = (uint64_t)(uintptr_t)pProperties;
+        countingStream->putBe64(cgen_var_871);
         if (pProperties)
         {
             for (uint32_t i = 0; i < (uint32_t)(*(pPropertyCount)); ++i)
@@ -12673,19 +12965,19 @@
     uint32_t opcode_vkGetPhysicalDeviceDisplayPlanePropertiesKHR = OP_vkGetPhysicalDeviceDisplayPlanePropertiesKHR;
     stream->write(&opcode_vkGetPhysicalDeviceDisplayPlanePropertiesKHR, sizeof(uint32_t));
     stream->write(&packetSize_vkGetPhysicalDeviceDisplayPlanePropertiesKHR, sizeof(uint32_t));
-    uint64_t cgen_var_868;
-    stream->handleMapping()->mapHandles_VkPhysicalDevice_u64(&local_physicalDevice, &cgen_var_868, 1);
-    stream->write((uint64_t*)&cgen_var_868, 1 * 8);
+    uint64_t cgen_var_872;
+    stream->handleMapping()->mapHandles_VkPhysicalDevice_u64(&local_physicalDevice, &cgen_var_872, 1);
+    stream->write((uint64_t*)&cgen_var_872, 1 * 8);
     // WARNING PTR CHECK
-    uint64_t cgen_var_869 = (uint64_t)(uintptr_t)pPropertyCount;
-    stream->putBe64(cgen_var_869);
+    uint64_t cgen_var_873 = (uint64_t)(uintptr_t)pPropertyCount;
+    stream->putBe64(cgen_var_873);
     if (pPropertyCount)
     {
         stream->write((uint32_t*)pPropertyCount, sizeof(uint32_t));
     }
     // WARNING PTR CHECK
-    uint64_t cgen_var_870 = (uint64_t)(uintptr_t)pProperties;
-    stream->putBe64(cgen_var_870);
+    uint64_t cgen_var_874 = (uint64_t)(uintptr_t)pProperties;
+    stream->putBe64(cgen_var_874);
     if (pProperties)
     {
         for (uint32_t i = 0; i < (uint32_t)(*(pPropertyCount)); ++i)
@@ -12742,6 +13034,7 @@
     uint32_t* pDisplayCount,
     VkDisplayKHR* pDisplays)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkGetDisplayPlaneSupportedDisplaysKHR encode");
     mImpl->log("start vkGetDisplayPlaneSupportedDisplaysKHR");
     auto stream = mImpl->stream();
@@ -12755,28 +13048,28 @@
     local_planeIndex = planeIndex;
     countingStream->rewind();
     {
-        uint64_t cgen_var_873;
-        countingStream->handleMapping()->mapHandles_VkPhysicalDevice_u64(&local_physicalDevice, &cgen_var_873, 1);
-        countingStream->write((uint64_t*)&cgen_var_873, 1 * 8);
+        uint64_t cgen_var_877;
+        countingStream->handleMapping()->mapHandles_VkPhysicalDevice_u64(&local_physicalDevice, &cgen_var_877, 1);
+        countingStream->write((uint64_t*)&cgen_var_877, 1 * 8);
         countingStream->write((uint32_t*)&local_planeIndex, sizeof(uint32_t));
         // WARNING PTR CHECK
-        uint64_t cgen_var_874 = (uint64_t)(uintptr_t)pDisplayCount;
-        countingStream->putBe64(cgen_var_874);
+        uint64_t cgen_var_878 = (uint64_t)(uintptr_t)pDisplayCount;
+        countingStream->putBe64(cgen_var_878);
         if (pDisplayCount)
         {
             countingStream->write((uint32_t*)pDisplayCount, sizeof(uint32_t));
         }
         // WARNING PTR CHECK
-        uint64_t cgen_var_875 = (uint64_t)(uintptr_t)pDisplays;
-        countingStream->putBe64(cgen_var_875);
+        uint64_t cgen_var_879 = (uint64_t)(uintptr_t)pDisplays;
+        countingStream->putBe64(cgen_var_879);
         if (pDisplays)
         {
             if ((*(pDisplayCount)))
             {
-                uint64_t* cgen_var_876;
-                countingStream->alloc((void**)&cgen_var_876, (*(pDisplayCount)) * 8);
-                countingStream->handleMapping()->mapHandles_VkDisplayKHR_u64(pDisplays, cgen_var_876, (*(pDisplayCount)));
-                countingStream->write((uint64_t*)cgen_var_876, (*(pDisplayCount)) * 8);
+                uint64_t* cgen_var_880;
+                countingStream->alloc((void**)&cgen_var_880, (*(pDisplayCount)) * 8);
+                countingStream->handleMapping()->mapHandles_VkDisplayKHR_u64(pDisplays, cgen_var_880, (*(pDisplayCount)));
+                countingStream->write((uint64_t*)cgen_var_880, (*(pDisplayCount)) * 8);
             }
         }
     }
@@ -12785,29 +13078,29 @@
     uint32_t opcode_vkGetDisplayPlaneSupportedDisplaysKHR = OP_vkGetDisplayPlaneSupportedDisplaysKHR;
     stream->write(&opcode_vkGetDisplayPlaneSupportedDisplaysKHR, sizeof(uint32_t));
     stream->write(&packetSize_vkGetDisplayPlaneSupportedDisplaysKHR, sizeof(uint32_t));
-    uint64_t cgen_var_877;
-    stream->handleMapping()->mapHandles_VkPhysicalDevice_u64(&local_physicalDevice, &cgen_var_877, 1);
-    stream->write((uint64_t*)&cgen_var_877, 1 * 8);
+    uint64_t cgen_var_881;
+    stream->handleMapping()->mapHandles_VkPhysicalDevice_u64(&local_physicalDevice, &cgen_var_881, 1);
+    stream->write((uint64_t*)&cgen_var_881, 1 * 8);
     stream->write((uint32_t*)&local_planeIndex, sizeof(uint32_t));
     // WARNING PTR CHECK
-    uint64_t cgen_var_878 = (uint64_t)(uintptr_t)pDisplayCount;
-    stream->putBe64(cgen_var_878);
+    uint64_t cgen_var_882 = (uint64_t)(uintptr_t)pDisplayCount;
+    stream->putBe64(cgen_var_882);
     if (pDisplayCount)
     {
         stream->write((uint32_t*)pDisplayCount, sizeof(uint32_t));
     }
     stream->unsetHandleMapping() /* emit_marshal, is handle, possibly out */;
     // WARNING PTR CHECK
-    uint64_t cgen_var_879 = (uint64_t)(uintptr_t)pDisplays;
-    stream->putBe64(cgen_var_879);
+    uint64_t cgen_var_883 = (uint64_t)(uintptr_t)pDisplays;
+    stream->putBe64(cgen_var_883);
     if (pDisplays)
     {
         if ((*(pDisplayCount)))
         {
-            uint64_t* cgen_var_880;
-            stream->alloc((void**)&cgen_var_880, (*(pDisplayCount)) * 8);
-            stream->handleMapping()->mapHandles_VkDisplayKHR_u64(pDisplays, cgen_var_880, (*(pDisplayCount)));
-            stream->write((uint64_t*)cgen_var_880, (*(pDisplayCount)) * 8);
+            uint64_t* cgen_var_884;
+            stream->alloc((void**)&cgen_var_884, (*(pDisplayCount)) * 8);
+            stream->handleMapping()->mapHandles_VkDisplayKHR_u64(pDisplays, cgen_var_884, (*(pDisplayCount)));
+            stream->write((uint64_t*)cgen_var_884, (*(pDisplayCount)) * 8);
         }
     }
     stream->setHandleMapping(resources->unwrapMapping());
@@ -12834,10 +13127,10 @@
         }
         if ((*(pDisplayCount)))
         {
-            uint64_t* cgen_var_883;
-            stream->alloc((void**)&cgen_var_883, (*(pDisplayCount)) * 8);
-            stream->read((uint64_t*)cgen_var_883, (*(pDisplayCount)) * 8);
-            stream->handleMapping()->mapHandles_u64_VkDisplayKHR(cgen_var_883, (VkDisplayKHR*)pDisplays, (*(pDisplayCount)));
+            uint64_t* cgen_var_887;
+            stream->alloc((void**)&cgen_var_887, (*(pDisplayCount)) * 8);
+            stream->read((uint64_t*)cgen_var_887, (*(pDisplayCount)) * 8);
+            stream->handleMapping()->mapHandles_u64_VkDisplayKHR(cgen_var_887, (VkDisplayKHR*)pDisplays, (*(pDisplayCount)));
         }
     }
     AEMU_SCOPED_TRACE("vkGetDisplayPlaneSupportedDisplaysKHR returnUnmarshal");
@@ -12856,6 +13149,7 @@
     uint32_t* pPropertyCount,
     VkDisplayModePropertiesKHR* pProperties)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkGetDisplayModePropertiesKHR encode");
     mImpl->log("start vkGetDisplayModePropertiesKHR");
     auto stream = mImpl->stream();
@@ -12869,22 +13163,22 @@
     local_display = display;
     countingStream->rewind();
     {
-        uint64_t cgen_var_884;
-        countingStream->handleMapping()->mapHandles_VkPhysicalDevice_u64(&local_physicalDevice, &cgen_var_884, 1);
-        countingStream->write((uint64_t*)&cgen_var_884, 1 * 8);
-        uint64_t cgen_var_885;
-        countingStream->handleMapping()->mapHandles_VkDisplayKHR_u64(&local_display, &cgen_var_885, 1);
-        countingStream->write((uint64_t*)&cgen_var_885, 1 * 8);
+        uint64_t cgen_var_888;
+        countingStream->handleMapping()->mapHandles_VkPhysicalDevice_u64(&local_physicalDevice, &cgen_var_888, 1);
+        countingStream->write((uint64_t*)&cgen_var_888, 1 * 8);
+        uint64_t cgen_var_889;
+        countingStream->handleMapping()->mapHandles_VkDisplayKHR_u64(&local_display, &cgen_var_889, 1);
+        countingStream->write((uint64_t*)&cgen_var_889, 1 * 8);
         // WARNING PTR CHECK
-        uint64_t cgen_var_886 = (uint64_t)(uintptr_t)pPropertyCount;
-        countingStream->putBe64(cgen_var_886);
+        uint64_t cgen_var_890 = (uint64_t)(uintptr_t)pPropertyCount;
+        countingStream->putBe64(cgen_var_890);
         if (pPropertyCount)
         {
             countingStream->write((uint32_t*)pPropertyCount, sizeof(uint32_t));
         }
         // WARNING PTR CHECK
-        uint64_t cgen_var_887 = (uint64_t)(uintptr_t)pProperties;
-        countingStream->putBe64(cgen_var_887);
+        uint64_t cgen_var_891 = (uint64_t)(uintptr_t)pProperties;
+        countingStream->putBe64(cgen_var_891);
         if (pProperties)
         {
             for (uint32_t i = 0; i < (uint32_t)(*(pPropertyCount)); ++i)
@@ -12898,22 +13192,22 @@
     uint32_t opcode_vkGetDisplayModePropertiesKHR = OP_vkGetDisplayModePropertiesKHR;
     stream->write(&opcode_vkGetDisplayModePropertiesKHR, sizeof(uint32_t));
     stream->write(&packetSize_vkGetDisplayModePropertiesKHR, sizeof(uint32_t));
-    uint64_t cgen_var_888;
-    stream->handleMapping()->mapHandles_VkPhysicalDevice_u64(&local_physicalDevice, &cgen_var_888, 1);
-    stream->write((uint64_t*)&cgen_var_888, 1 * 8);
-    uint64_t cgen_var_889;
-    stream->handleMapping()->mapHandles_VkDisplayKHR_u64(&local_display, &cgen_var_889, 1);
-    stream->write((uint64_t*)&cgen_var_889, 1 * 8);
+    uint64_t cgen_var_892;
+    stream->handleMapping()->mapHandles_VkPhysicalDevice_u64(&local_physicalDevice, &cgen_var_892, 1);
+    stream->write((uint64_t*)&cgen_var_892, 1 * 8);
+    uint64_t cgen_var_893;
+    stream->handleMapping()->mapHandles_VkDisplayKHR_u64(&local_display, &cgen_var_893, 1);
+    stream->write((uint64_t*)&cgen_var_893, 1 * 8);
     // WARNING PTR CHECK
-    uint64_t cgen_var_890 = (uint64_t)(uintptr_t)pPropertyCount;
-    stream->putBe64(cgen_var_890);
+    uint64_t cgen_var_894 = (uint64_t)(uintptr_t)pPropertyCount;
+    stream->putBe64(cgen_var_894);
     if (pPropertyCount)
     {
         stream->write((uint32_t*)pPropertyCount, sizeof(uint32_t));
     }
     // WARNING PTR CHECK
-    uint64_t cgen_var_891 = (uint64_t)(uintptr_t)pProperties;
-    stream->putBe64(cgen_var_891);
+    uint64_t cgen_var_895 = (uint64_t)(uintptr_t)pProperties;
+    stream->putBe64(cgen_var_895);
     if (pProperties)
     {
         for (uint32_t i = 0; i < (uint32_t)(*(pPropertyCount)); ++i)
@@ -12971,6 +13265,7 @@
     const VkAllocationCallbacks* pAllocator,
     VkDisplayModeKHR* pMode)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkCreateDisplayModeKHR encode");
     mImpl->log("start vkCreateDisplayModeKHR");
     auto stream = mImpl->stream();
@@ -13007,53 +13302,53 @@
     }
     countingStream->rewind();
     {
-        uint64_t cgen_var_894;
-        countingStream->handleMapping()->mapHandles_VkPhysicalDevice_u64(&local_physicalDevice, &cgen_var_894, 1);
-        countingStream->write((uint64_t*)&cgen_var_894, 1 * 8);
-        uint64_t cgen_var_895;
-        countingStream->handleMapping()->mapHandles_VkDisplayKHR_u64(&local_display, &cgen_var_895, 1);
-        countingStream->write((uint64_t*)&cgen_var_895, 1 * 8);
+        uint64_t cgen_var_898;
+        countingStream->handleMapping()->mapHandles_VkPhysicalDevice_u64(&local_physicalDevice, &cgen_var_898, 1);
+        countingStream->write((uint64_t*)&cgen_var_898, 1 * 8);
+        uint64_t cgen_var_899;
+        countingStream->handleMapping()->mapHandles_VkDisplayKHR_u64(&local_display, &cgen_var_899, 1);
+        countingStream->write((uint64_t*)&cgen_var_899, 1 * 8);
         marshal_VkDisplayModeCreateInfoKHR(countingStream, (VkDisplayModeCreateInfoKHR*)(local_pCreateInfo));
         // WARNING PTR CHECK
-        uint64_t cgen_var_896 = (uint64_t)(uintptr_t)local_pAllocator;
-        countingStream->putBe64(cgen_var_896);
+        uint64_t cgen_var_900 = (uint64_t)(uintptr_t)local_pAllocator;
+        countingStream->putBe64(cgen_var_900);
         if (local_pAllocator)
         {
             marshal_VkAllocationCallbacks(countingStream, (VkAllocationCallbacks*)(local_pAllocator));
         }
-        uint64_t cgen_var_897;
-        countingStream->handleMapping()->mapHandles_VkDisplayModeKHR_u64(pMode, &cgen_var_897, 1);
-        countingStream->write((uint64_t*)&cgen_var_897, 8);
+        uint64_t cgen_var_901;
+        countingStream->handleMapping()->mapHandles_VkDisplayModeKHR_u64(pMode, &cgen_var_901, 1);
+        countingStream->write((uint64_t*)&cgen_var_901, 8);
     }
     uint32_t packetSize_vkCreateDisplayModeKHR = 4 + 4 + (uint32_t)countingStream->bytesWritten();
     countingStream->rewind();
     uint32_t opcode_vkCreateDisplayModeKHR = OP_vkCreateDisplayModeKHR;
     stream->write(&opcode_vkCreateDisplayModeKHR, sizeof(uint32_t));
     stream->write(&packetSize_vkCreateDisplayModeKHR, sizeof(uint32_t));
-    uint64_t cgen_var_898;
-    stream->handleMapping()->mapHandles_VkPhysicalDevice_u64(&local_physicalDevice, &cgen_var_898, 1);
-    stream->write((uint64_t*)&cgen_var_898, 1 * 8);
-    uint64_t cgen_var_899;
-    stream->handleMapping()->mapHandles_VkDisplayKHR_u64(&local_display, &cgen_var_899, 1);
-    stream->write((uint64_t*)&cgen_var_899, 1 * 8);
+    uint64_t cgen_var_902;
+    stream->handleMapping()->mapHandles_VkPhysicalDevice_u64(&local_physicalDevice, &cgen_var_902, 1);
+    stream->write((uint64_t*)&cgen_var_902, 1 * 8);
+    uint64_t cgen_var_903;
+    stream->handleMapping()->mapHandles_VkDisplayKHR_u64(&local_display, &cgen_var_903, 1);
+    stream->write((uint64_t*)&cgen_var_903, 1 * 8);
     marshal_VkDisplayModeCreateInfoKHR(stream, (VkDisplayModeCreateInfoKHR*)(local_pCreateInfo));
     // WARNING PTR CHECK
-    uint64_t cgen_var_900 = (uint64_t)(uintptr_t)local_pAllocator;
-    stream->putBe64(cgen_var_900);
+    uint64_t cgen_var_904 = (uint64_t)(uintptr_t)local_pAllocator;
+    stream->putBe64(cgen_var_904);
     if (local_pAllocator)
     {
         marshal_VkAllocationCallbacks(stream, (VkAllocationCallbacks*)(local_pAllocator));
     }
     stream->unsetHandleMapping() /* emit_marshal, is handle, possibly out */;
-    uint64_t cgen_var_901;
-    stream->handleMapping()->mapHandles_VkDisplayModeKHR_u64(pMode, &cgen_var_901, 1);
-    stream->write((uint64_t*)&cgen_var_901, 8);
+    uint64_t cgen_var_905;
+    stream->handleMapping()->mapHandles_VkDisplayModeKHR_u64(pMode, &cgen_var_905, 1);
+    stream->write((uint64_t*)&cgen_var_905, 8);
     stream->setHandleMapping(resources->unwrapMapping());
     AEMU_SCOPED_TRACE("vkCreateDisplayModeKHR readParams");
     stream->setHandleMapping(resources->createMapping());
-    uint64_t cgen_var_902;
-    stream->read((uint64_t*)&cgen_var_902, 8);
-    stream->handleMapping()->mapHandles_u64_VkDisplayModeKHR(&cgen_var_902, (VkDisplayModeKHR*)pMode, 1);
+    uint64_t cgen_var_906;
+    stream->read((uint64_t*)&cgen_var_906, 8);
+    stream->handleMapping()->mapHandles_u64_VkDisplayModeKHR(&cgen_var_906, (VkDisplayModeKHR*)pMode, 1);
     stream->unsetHandleMapping();
     AEMU_SCOPED_TRACE("vkCreateDisplayModeKHR returnUnmarshal");
     VkResult vkCreateDisplayModeKHR_VkResult_return = (VkResult)0;
@@ -13071,6 +13366,7 @@
     uint32_t planeIndex,
     VkDisplayPlaneCapabilitiesKHR* pCapabilities)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkGetDisplayPlaneCapabilitiesKHR encode");
     mImpl->log("start vkGetDisplayPlaneCapabilitiesKHR");
     auto stream = mImpl->stream();
@@ -13086,12 +13382,12 @@
     local_planeIndex = planeIndex;
     countingStream->rewind();
     {
-        uint64_t cgen_var_903;
-        countingStream->handleMapping()->mapHandles_VkPhysicalDevice_u64(&local_physicalDevice, &cgen_var_903, 1);
-        countingStream->write((uint64_t*)&cgen_var_903, 1 * 8);
-        uint64_t cgen_var_904;
-        countingStream->handleMapping()->mapHandles_VkDisplayModeKHR_u64(&local_mode, &cgen_var_904, 1);
-        countingStream->write((uint64_t*)&cgen_var_904, 1 * 8);
+        uint64_t cgen_var_907;
+        countingStream->handleMapping()->mapHandles_VkPhysicalDevice_u64(&local_physicalDevice, &cgen_var_907, 1);
+        countingStream->write((uint64_t*)&cgen_var_907, 1 * 8);
+        uint64_t cgen_var_908;
+        countingStream->handleMapping()->mapHandles_VkDisplayModeKHR_u64(&local_mode, &cgen_var_908, 1);
+        countingStream->write((uint64_t*)&cgen_var_908, 1 * 8);
         countingStream->write((uint32_t*)&local_planeIndex, sizeof(uint32_t));
         marshal_VkDisplayPlaneCapabilitiesKHR(countingStream, (VkDisplayPlaneCapabilitiesKHR*)(pCapabilities));
     }
@@ -13100,12 +13396,12 @@
     uint32_t opcode_vkGetDisplayPlaneCapabilitiesKHR = OP_vkGetDisplayPlaneCapabilitiesKHR;
     stream->write(&opcode_vkGetDisplayPlaneCapabilitiesKHR, sizeof(uint32_t));
     stream->write(&packetSize_vkGetDisplayPlaneCapabilitiesKHR, sizeof(uint32_t));
-    uint64_t cgen_var_905;
-    stream->handleMapping()->mapHandles_VkPhysicalDevice_u64(&local_physicalDevice, &cgen_var_905, 1);
-    stream->write((uint64_t*)&cgen_var_905, 1 * 8);
-    uint64_t cgen_var_906;
-    stream->handleMapping()->mapHandles_VkDisplayModeKHR_u64(&local_mode, &cgen_var_906, 1);
-    stream->write((uint64_t*)&cgen_var_906, 1 * 8);
+    uint64_t cgen_var_909;
+    stream->handleMapping()->mapHandles_VkPhysicalDevice_u64(&local_physicalDevice, &cgen_var_909, 1);
+    stream->write((uint64_t*)&cgen_var_909, 1 * 8);
+    uint64_t cgen_var_910;
+    stream->handleMapping()->mapHandles_VkDisplayModeKHR_u64(&local_mode, &cgen_var_910, 1);
+    stream->write((uint64_t*)&cgen_var_910, 1 * 8);
     stream->write((uint32_t*)&local_planeIndex, sizeof(uint32_t));
     marshal_VkDisplayPlaneCapabilitiesKHR(stream, (VkDisplayPlaneCapabilitiesKHR*)(pCapabilities));
     AEMU_SCOPED_TRACE("vkGetDisplayPlaneCapabilitiesKHR readParams");
@@ -13130,6 +13426,7 @@
     const VkAllocationCallbacks* pAllocator,
     VkSurfaceKHR* pSurface)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkCreateDisplayPlaneSurfaceKHR encode");
     mImpl->log("start vkCreateDisplayPlaneSurfaceKHR");
     auto stream = mImpl->stream();
@@ -13164,46 +13461,46 @@
     }
     countingStream->rewind();
     {
-        uint64_t cgen_var_907;
-        countingStream->handleMapping()->mapHandles_VkInstance_u64(&local_instance, &cgen_var_907, 1);
-        countingStream->write((uint64_t*)&cgen_var_907, 1 * 8);
+        uint64_t cgen_var_911;
+        countingStream->handleMapping()->mapHandles_VkInstance_u64(&local_instance, &cgen_var_911, 1);
+        countingStream->write((uint64_t*)&cgen_var_911, 1 * 8);
         marshal_VkDisplaySurfaceCreateInfoKHR(countingStream, (VkDisplaySurfaceCreateInfoKHR*)(local_pCreateInfo));
         // WARNING PTR CHECK
-        uint64_t cgen_var_908 = (uint64_t)(uintptr_t)local_pAllocator;
-        countingStream->putBe64(cgen_var_908);
+        uint64_t cgen_var_912 = (uint64_t)(uintptr_t)local_pAllocator;
+        countingStream->putBe64(cgen_var_912);
         if (local_pAllocator)
         {
             marshal_VkAllocationCallbacks(countingStream, (VkAllocationCallbacks*)(local_pAllocator));
         }
-        uint64_t cgen_var_909;
-        countingStream->handleMapping()->mapHandles_VkSurfaceKHR_u64(pSurface, &cgen_var_909, 1);
-        countingStream->write((uint64_t*)&cgen_var_909, 8);
+        uint64_t cgen_var_913;
+        countingStream->handleMapping()->mapHandles_VkSurfaceKHR_u64(pSurface, &cgen_var_913, 1);
+        countingStream->write((uint64_t*)&cgen_var_913, 8);
     }
     uint32_t packetSize_vkCreateDisplayPlaneSurfaceKHR = 4 + 4 + (uint32_t)countingStream->bytesWritten();
     countingStream->rewind();
     uint32_t opcode_vkCreateDisplayPlaneSurfaceKHR = OP_vkCreateDisplayPlaneSurfaceKHR;
     stream->write(&opcode_vkCreateDisplayPlaneSurfaceKHR, sizeof(uint32_t));
     stream->write(&packetSize_vkCreateDisplayPlaneSurfaceKHR, sizeof(uint32_t));
-    uint64_t cgen_var_910;
-    stream->handleMapping()->mapHandles_VkInstance_u64(&local_instance, &cgen_var_910, 1);
-    stream->write((uint64_t*)&cgen_var_910, 1 * 8);
+    uint64_t cgen_var_914;
+    stream->handleMapping()->mapHandles_VkInstance_u64(&local_instance, &cgen_var_914, 1);
+    stream->write((uint64_t*)&cgen_var_914, 1 * 8);
     marshal_VkDisplaySurfaceCreateInfoKHR(stream, (VkDisplaySurfaceCreateInfoKHR*)(local_pCreateInfo));
     // WARNING PTR CHECK
-    uint64_t cgen_var_911 = (uint64_t)(uintptr_t)local_pAllocator;
-    stream->putBe64(cgen_var_911);
+    uint64_t cgen_var_915 = (uint64_t)(uintptr_t)local_pAllocator;
+    stream->putBe64(cgen_var_915);
     if (local_pAllocator)
     {
         marshal_VkAllocationCallbacks(stream, (VkAllocationCallbacks*)(local_pAllocator));
     }
     stream->unsetHandleMapping() /* emit_marshal, is handle, possibly out */;
-    uint64_t cgen_var_912;
-    stream->handleMapping()->mapHandles_VkSurfaceKHR_u64(pSurface, &cgen_var_912, 1);
-    stream->write((uint64_t*)&cgen_var_912, 8);
+    uint64_t cgen_var_916;
+    stream->handleMapping()->mapHandles_VkSurfaceKHR_u64(pSurface, &cgen_var_916, 1);
+    stream->write((uint64_t*)&cgen_var_916, 8);
     stream->setHandleMapping(resources->unwrapMapping());
     AEMU_SCOPED_TRACE("vkCreateDisplayPlaneSurfaceKHR readParams");
-    uint64_t cgen_var_913;
-    stream->read((uint64_t*)&cgen_var_913, 8);
-    stream->handleMapping()->mapHandles_u64_VkSurfaceKHR(&cgen_var_913, (VkSurfaceKHR*)pSurface, 1);
+    uint64_t cgen_var_917;
+    stream->read((uint64_t*)&cgen_var_917, 8);
+    stream->handleMapping()->mapHandles_u64_VkSurfaceKHR(&cgen_var_917, (VkSurfaceKHR*)pSurface, 1);
     AEMU_SCOPED_TRACE("vkCreateDisplayPlaneSurfaceKHR returnUnmarshal");
     VkResult vkCreateDisplayPlaneSurfaceKHR_VkResult_return = (VkResult)0;
     stream->read(&vkCreateDisplayPlaneSurfaceKHR_VkResult_return, sizeof(VkResult));
@@ -13223,6 +13520,7 @@
     const VkAllocationCallbacks* pAllocator,
     VkSwapchainKHR* pSwapchains)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkCreateSharedSwapchainsKHR encode");
     mImpl->log("start vkCreateSharedSwapchainsKHR");
     auto stream = mImpl->stream();
@@ -13265,27 +13563,27 @@
     }
     countingStream->rewind();
     {
-        uint64_t cgen_var_914;
-        countingStream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_914, 1);
-        countingStream->write((uint64_t*)&cgen_var_914, 1 * 8);
+        uint64_t cgen_var_918;
+        countingStream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_918, 1);
+        countingStream->write((uint64_t*)&cgen_var_918, 1 * 8);
         countingStream->write((uint32_t*)&local_swapchainCount, sizeof(uint32_t));
         for (uint32_t i = 0; i < (uint32_t)((swapchainCount)); ++i)
         {
             marshal_VkSwapchainCreateInfoKHR(countingStream, (VkSwapchainCreateInfoKHR*)(local_pCreateInfos + i));
         }
         // WARNING PTR CHECK
-        uint64_t cgen_var_915 = (uint64_t)(uintptr_t)local_pAllocator;
-        countingStream->putBe64(cgen_var_915);
+        uint64_t cgen_var_919 = (uint64_t)(uintptr_t)local_pAllocator;
+        countingStream->putBe64(cgen_var_919);
         if (local_pAllocator)
         {
             marshal_VkAllocationCallbacks(countingStream, (VkAllocationCallbacks*)(local_pAllocator));
         }
         if (((swapchainCount)))
         {
-            uint64_t* cgen_var_916;
-            countingStream->alloc((void**)&cgen_var_916, ((swapchainCount)) * 8);
-            countingStream->handleMapping()->mapHandles_VkSwapchainKHR_u64(pSwapchains, cgen_var_916, ((swapchainCount)));
-            countingStream->write((uint64_t*)cgen_var_916, ((swapchainCount)) * 8);
+            uint64_t* cgen_var_920;
+            countingStream->alloc((void**)&cgen_var_920, ((swapchainCount)) * 8);
+            countingStream->handleMapping()->mapHandles_VkSwapchainKHR_u64(pSwapchains, cgen_var_920, ((swapchainCount)));
+            countingStream->write((uint64_t*)cgen_var_920, ((swapchainCount)) * 8);
         }
     }
     uint32_t packetSize_vkCreateSharedSwapchainsKHR = 4 + 4 + (uint32_t)countingStream->bytesWritten();
@@ -13293,17 +13591,17 @@
     uint32_t opcode_vkCreateSharedSwapchainsKHR = OP_vkCreateSharedSwapchainsKHR;
     stream->write(&opcode_vkCreateSharedSwapchainsKHR, sizeof(uint32_t));
     stream->write(&packetSize_vkCreateSharedSwapchainsKHR, sizeof(uint32_t));
-    uint64_t cgen_var_917;
-    stream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_917, 1);
-    stream->write((uint64_t*)&cgen_var_917, 1 * 8);
+    uint64_t cgen_var_921;
+    stream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_921, 1);
+    stream->write((uint64_t*)&cgen_var_921, 1 * 8);
     stream->write((uint32_t*)&local_swapchainCount, sizeof(uint32_t));
     for (uint32_t i = 0; i < (uint32_t)((swapchainCount)); ++i)
     {
         marshal_VkSwapchainCreateInfoKHR(stream, (VkSwapchainCreateInfoKHR*)(local_pCreateInfos + i));
     }
     // WARNING PTR CHECK
-    uint64_t cgen_var_918 = (uint64_t)(uintptr_t)local_pAllocator;
-    stream->putBe64(cgen_var_918);
+    uint64_t cgen_var_922 = (uint64_t)(uintptr_t)local_pAllocator;
+    stream->putBe64(cgen_var_922);
     if (local_pAllocator)
     {
         marshal_VkAllocationCallbacks(stream, (VkAllocationCallbacks*)(local_pAllocator));
@@ -13311,19 +13609,19 @@
     stream->unsetHandleMapping() /* emit_marshal, is handle, possibly out */;
     if (((swapchainCount)))
     {
-        uint64_t* cgen_var_919;
-        stream->alloc((void**)&cgen_var_919, ((swapchainCount)) * 8);
-        stream->handleMapping()->mapHandles_VkSwapchainKHR_u64(pSwapchains, cgen_var_919, ((swapchainCount)));
-        stream->write((uint64_t*)cgen_var_919, ((swapchainCount)) * 8);
+        uint64_t* cgen_var_923;
+        stream->alloc((void**)&cgen_var_923, ((swapchainCount)) * 8);
+        stream->handleMapping()->mapHandles_VkSwapchainKHR_u64(pSwapchains, cgen_var_923, ((swapchainCount)));
+        stream->write((uint64_t*)cgen_var_923, ((swapchainCount)) * 8);
     }
     stream->setHandleMapping(resources->unwrapMapping());
     AEMU_SCOPED_TRACE("vkCreateSharedSwapchainsKHR readParams");
     if (((swapchainCount)))
     {
-        uint64_t* cgen_var_920;
-        stream->alloc((void**)&cgen_var_920, ((swapchainCount)) * 8);
-        stream->read((uint64_t*)cgen_var_920, ((swapchainCount)) * 8);
-        stream->handleMapping()->mapHandles_u64_VkSwapchainKHR(cgen_var_920, (VkSwapchainKHR*)pSwapchains, ((swapchainCount)));
+        uint64_t* cgen_var_924;
+        stream->alloc((void**)&cgen_var_924, ((swapchainCount)) * 8);
+        stream->read((uint64_t*)cgen_var_924, ((swapchainCount)) * 8);
+        stream->handleMapping()->mapHandles_u64_VkSwapchainKHR(cgen_var_924, (VkSwapchainKHR*)pSwapchains, ((swapchainCount)));
     }
     AEMU_SCOPED_TRACE("vkCreateSharedSwapchainsKHR returnUnmarshal");
     VkResult vkCreateSharedSwapchainsKHR_VkResult_return = (VkResult)0;
@@ -13343,6 +13641,7 @@
     const VkAllocationCallbacks* pAllocator,
     VkSurfaceKHR* pSurface)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkCreateXlibSurfaceKHR encode");
     mImpl->log("start vkCreateXlibSurfaceKHR");
     auto stream = mImpl->stream();
@@ -13377,46 +13676,46 @@
     }
     countingStream->rewind();
     {
-        uint64_t cgen_var_921;
-        countingStream->handleMapping()->mapHandles_VkInstance_u64(&local_instance, &cgen_var_921, 1);
-        countingStream->write((uint64_t*)&cgen_var_921, 1 * 8);
+        uint64_t cgen_var_925;
+        countingStream->handleMapping()->mapHandles_VkInstance_u64(&local_instance, &cgen_var_925, 1);
+        countingStream->write((uint64_t*)&cgen_var_925, 1 * 8);
         marshal_VkXlibSurfaceCreateInfoKHR(countingStream, (VkXlibSurfaceCreateInfoKHR*)(local_pCreateInfo));
         // WARNING PTR CHECK
-        uint64_t cgen_var_922 = (uint64_t)(uintptr_t)local_pAllocator;
-        countingStream->putBe64(cgen_var_922);
+        uint64_t cgen_var_926 = (uint64_t)(uintptr_t)local_pAllocator;
+        countingStream->putBe64(cgen_var_926);
         if (local_pAllocator)
         {
             marshal_VkAllocationCallbacks(countingStream, (VkAllocationCallbacks*)(local_pAllocator));
         }
-        uint64_t cgen_var_923;
-        countingStream->handleMapping()->mapHandles_VkSurfaceKHR_u64(pSurface, &cgen_var_923, 1);
-        countingStream->write((uint64_t*)&cgen_var_923, 8);
+        uint64_t cgen_var_927;
+        countingStream->handleMapping()->mapHandles_VkSurfaceKHR_u64(pSurface, &cgen_var_927, 1);
+        countingStream->write((uint64_t*)&cgen_var_927, 8);
     }
     uint32_t packetSize_vkCreateXlibSurfaceKHR = 4 + 4 + (uint32_t)countingStream->bytesWritten();
     countingStream->rewind();
     uint32_t opcode_vkCreateXlibSurfaceKHR = OP_vkCreateXlibSurfaceKHR;
     stream->write(&opcode_vkCreateXlibSurfaceKHR, sizeof(uint32_t));
     stream->write(&packetSize_vkCreateXlibSurfaceKHR, sizeof(uint32_t));
-    uint64_t cgen_var_924;
-    stream->handleMapping()->mapHandles_VkInstance_u64(&local_instance, &cgen_var_924, 1);
-    stream->write((uint64_t*)&cgen_var_924, 1 * 8);
+    uint64_t cgen_var_928;
+    stream->handleMapping()->mapHandles_VkInstance_u64(&local_instance, &cgen_var_928, 1);
+    stream->write((uint64_t*)&cgen_var_928, 1 * 8);
     marshal_VkXlibSurfaceCreateInfoKHR(stream, (VkXlibSurfaceCreateInfoKHR*)(local_pCreateInfo));
     // WARNING PTR CHECK
-    uint64_t cgen_var_925 = (uint64_t)(uintptr_t)local_pAllocator;
-    stream->putBe64(cgen_var_925);
+    uint64_t cgen_var_929 = (uint64_t)(uintptr_t)local_pAllocator;
+    stream->putBe64(cgen_var_929);
     if (local_pAllocator)
     {
         marshal_VkAllocationCallbacks(stream, (VkAllocationCallbacks*)(local_pAllocator));
     }
     stream->unsetHandleMapping() /* emit_marshal, is handle, possibly out */;
-    uint64_t cgen_var_926;
-    stream->handleMapping()->mapHandles_VkSurfaceKHR_u64(pSurface, &cgen_var_926, 1);
-    stream->write((uint64_t*)&cgen_var_926, 8);
+    uint64_t cgen_var_930;
+    stream->handleMapping()->mapHandles_VkSurfaceKHR_u64(pSurface, &cgen_var_930, 1);
+    stream->write((uint64_t*)&cgen_var_930, 8);
     stream->setHandleMapping(resources->unwrapMapping());
     AEMU_SCOPED_TRACE("vkCreateXlibSurfaceKHR readParams");
-    uint64_t cgen_var_927;
-    stream->read((uint64_t*)&cgen_var_927, 8);
-    stream->handleMapping()->mapHandles_u64_VkSurfaceKHR(&cgen_var_927, (VkSurfaceKHR*)pSurface, 1);
+    uint64_t cgen_var_931;
+    stream->read((uint64_t*)&cgen_var_931, 8);
+    stream->handleMapping()->mapHandles_u64_VkSurfaceKHR(&cgen_var_931, (VkSurfaceKHR*)pSurface, 1);
     AEMU_SCOPED_TRACE("vkCreateXlibSurfaceKHR returnUnmarshal");
     VkResult vkCreateXlibSurfaceKHR_VkResult_return = (VkResult)0;
     stream->read(&vkCreateXlibSurfaceKHR_VkResult_return, sizeof(VkResult));
@@ -13433,6 +13732,7 @@
     Display* dpy,
     VisualID visualID)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkGetPhysicalDeviceXlibPresentationSupportKHR encode");
     mImpl->log("start vkGetPhysicalDeviceXlibPresentationSupportKHR");
     auto stream = mImpl->stream();
@@ -13448,9 +13748,9 @@
     local_visualID = visualID;
     countingStream->rewind();
     {
-        uint64_t cgen_var_928;
-        countingStream->handleMapping()->mapHandles_VkPhysicalDevice_u64(&local_physicalDevice, &cgen_var_928, 1);
-        countingStream->write((uint64_t*)&cgen_var_928, 1 * 8);
+        uint64_t cgen_var_932;
+        countingStream->handleMapping()->mapHandles_VkPhysicalDevice_u64(&local_physicalDevice, &cgen_var_932, 1);
+        countingStream->write((uint64_t*)&cgen_var_932, 1 * 8);
         countingStream->write((uint32_t*)&local_queueFamilyIndex, sizeof(uint32_t));
         countingStream->write((Display*)dpy, sizeof(Display));
         countingStream->write((VisualID*)&local_visualID, sizeof(VisualID));
@@ -13460,9 +13760,9 @@
     uint32_t opcode_vkGetPhysicalDeviceXlibPresentationSupportKHR = OP_vkGetPhysicalDeviceXlibPresentationSupportKHR;
     stream->write(&opcode_vkGetPhysicalDeviceXlibPresentationSupportKHR, sizeof(uint32_t));
     stream->write(&packetSize_vkGetPhysicalDeviceXlibPresentationSupportKHR, sizeof(uint32_t));
-    uint64_t cgen_var_929;
-    stream->handleMapping()->mapHandles_VkPhysicalDevice_u64(&local_physicalDevice, &cgen_var_929, 1);
-    stream->write((uint64_t*)&cgen_var_929, 1 * 8);
+    uint64_t cgen_var_933;
+    stream->handleMapping()->mapHandles_VkPhysicalDevice_u64(&local_physicalDevice, &cgen_var_933, 1);
+    stream->write((uint64_t*)&cgen_var_933, 1 * 8);
     stream->write((uint32_t*)&local_queueFamilyIndex, sizeof(uint32_t));
     stream->write((Display*)dpy, sizeof(Display));
     stream->write((VisualID*)&local_visualID, sizeof(VisualID));
@@ -13486,6 +13786,7 @@
     const VkAllocationCallbacks* pAllocator,
     VkSurfaceKHR* pSurface)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkCreateXcbSurfaceKHR encode");
     mImpl->log("start vkCreateXcbSurfaceKHR");
     auto stream = mImpl->stream();
@@ -13520,46 +13821,46 @@
     }
     countingStream->rewind();
     {
-        uint64_t cgen_var_930;
-        countingStream->handleMapping()->mapHandles_VkInstance_u64(&local_instance, &cgen_var_930, 1);
-        countingStream->write((uint64_t*)&cgen_var_930, 1 * 8);
+        uint64_t cgen_var_934;
+        countingStream->handleMapping()->mapHandles_VkInstance_u64(&local_instance, &cgen_var_934, 1);
+        countingStream->write((uint64_t*)&cgen_var_934, 1 * 8);
         marshal_VkXcbSurfaceCreateInfoKHR(countingStream, (VkXcbSurfaceCreateInfoKHR*)(local_pCreateInfo));
         // WARNING PTR CHECK
-        uint64_t cgen_var_931 = (uint64_t)(uintptr_t)local_pAllocator;
-        countingStream->putBe64(cgen_var_931);
+        uint64_t cgen_var_935 = (uint64_t)(uintptr_t)local_pAllocator;
+        countingStream->putBe64(cgen_var_935);
         if (local_pAllocator)
         {
             marshal_VkAllocationCallbacks(countingStream, (VkAllocationCallbacks*)(local_pAllocator));
         }
-        uint64_t cgen_var_932;
-        countingStream->handleMapping()->mapHandles_VkSurfaceKHR_u64(pSurface, &cgen_var_932, 1);
-        countingStream->write((uint64_t*)&cgen_var_932, 8);
+        uint64_t cgen_var_936;
+        countingStream->handleMapping()->mapHandles_VkSurfaceKHR_u64(pSurface, &cgen_var_936, 1);
+        countingStream->write((uint64_t*)&cgen_var_936, 8);
     }
     uint32_t packetSize_vkCreateXcbSurfaceKHR = 4 + 4 + (uint32_t)countingStream->bytesWritten();
     countingStream->rewind();
     uint32_t opcode_vkCreateXcbSurfaceKHR = OP_vkCreateXcbSurfaceKHR;
     stream->write(&opcode_vkCreateXcbSurfaceKHR, sizeof(uint32_t));
     stream->write(&packetSize_vkCreateXcbSurfaceKHR, sizeof(uint32_t));
-    uint64_t cgen_var_933;
-    stream->handleMapping()->mapHandles_VkInstance_u64(&local_instance, &cgen_var_933, 1);
-    stream->write((uint64_t*)&cgen_var_933, 1 * 8);
+    uint64_t cgen_var_937;
+    stream->handleMapping()->mapHandles_VkInstance_u64(&local_instance, &cgen_var_937, 1);
+    stream->write((uint64_t*)&cgen_var_937, 1 * 8);
     marshal_VkXcbSurfaceCreateInfoKHR(stream, (VkXcbSurfaceCreateInfoKHR*)(local_pCreateInfo));
     // WARNING PTR CHECK
-    uint64_t cgen_var_934 = (uint64_t)(uintptr_t)local_pAllocator;
-    stream->putBe64(cgen_var_934);
+    uint64_t cgen_var_938 = (uint64_t)(uintptr_t)local_pAllocator;
+    stream->putBe64(cgen_var_938);
     if (local_pAllocator)
     {
         marshal_VkAllocationCallbacks(stream, (VkAllocationCallbacks*)(local_pAllocator));
     }
     stream->unsetHandleMapping() /* emit_marshal, is handle, possibly out */;
-    uint64_t cgen_var_935;
-    stream->handleMapping()->mapHandles_VkSurfaceKHR_u64(pSurface, &cgen_var_935, 1);
-    stream->write((uint64_t*)&cgen_var_935, 8);
+    uint64_t cgen_var_939;
+    stream->handleMapping()->mapHandles_VkSurfaceKHR_u64(pSurface, &cgen_var_939, 1);
+    stream->write((uint64_t*)&cgen_var_939, 8);
     stream->setHandleMapping(resources->unwrapMapping());
     AEMU_SCOPED_TRACE("vkCreateXcbSurfaceKHR readParams");
-    uint64_t cgen_var_936;
-    stream->read((uint64_t*)&cgen_var_936, 8);
-    stream->handleMapping()->mapHandles_u64_VkSurfaceKHR(&cgen_var_936, (VkSurfaceKHR*)pSurface, 1);
+    uint64_t cgen_var_940;
+    stream->read((uint64_t*)&cgen_var_940, 8);
+    stream->handleMapping()->mapHandles_u64_VkSurfaceKHR(&cgen_var_940, (VkSurfaceKHR*)pSurface, 1);
     AEMU_SCOPED_TRACE("vkCreateXcbSurfaceKHR returnUnmarshal");
     VkResult vkCreateXcbSurfaceKHR_VkResult_return = (VkResult)0;
     stream->read(&vkCreateXcbSurfaceKHR_VkResult_return, sizeof(VkResult));
@@ -13576,6 +13877,7 @@
     xcb_connection_t* connection,
     xcb_visualid_t visual_id)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkGetPhysicalDeviceXcbPresentationSupportKHR encode");
     mImpl->log("start vkGetPhysicalDeviceXcbPresentationSupportKHR");
     auto stream = mImpl->stream();
@@ -13591,9 +13893,9 @@
     local_visual_id = visual_id;
     countingStream->rewind();
     {
-        uint64_t cgen_var_937;
-        countingStream->handleMapping()->mapHandles_VkPhysicalDevice_u64(&local_physicalDevice, &cgen_var_937, 1);
-        countingStream->write((uint64_t*)&cgen_var_937, 1 * 8);
+        uint64_t cgen_var_941;
+        countingStream->handleMapping()->mapHandles_VkPhysicalDevice_u64(&local_physicalDevice, &cgen_var_941, 1);
+        countingStream->write((uint64_t*)&cgen_var_941, 1 * 8);
         countingStream->write((uint32_t*)&local_queueFamilyIndex, sizeof(uint32_t));
         countingStream->write((xcb_connection_t*)connection, sizeof(xcb_connection_t));
         countingStream->write((xcb_visualid_t*)&local_visual_id, sizeof(xcb_visualid_t));
@@ -13603,9 +13905,9 @@
     uint32_t opcode_vkGetPhysicalDeviceXcbPresentationSupportKHR = OP_vkGetPhysicalDeviceXcbPresentationSupportKHR;
     stream->write(&opcode_vkGetPhysicalDeviceXcbPresentationSupportKHR, sizeof(uint32_t));
     stream->write(&packetSize_vkGetPhysicalDeviceXcbPresentationSupportKHR, sizeof(uint32_t));
-    uint64_t cgen_var_938;
-    stream->handleMapping()->mapHandles_VkPhysicalDevice_u64(&local_physicalDevice, &cgen_var_938, 1);
-    stream->write((uint64_t*)&cgen_var_938, 1 * 8);
+    uint64_t cgen_var_942;
+    stream->handleMapping()->mapHandles_VkPhysicalDevice_u64(&local_physicalDevice, &cgen_var_942, 1);
+    stream->write((uint64_t*)&cgen_var_942, 1 * 8);
     stream->write((uint32_t*)&local_queueFamilyIndex, sizeof(uint32_t));
     stream->write((xcb_connection_t*)connection, sizeof(xcb_connection_t));
     stream->write((xcb_visualid_t*)&local_visual_id, sizeof(xcb_visualid_t));
@@ -13629,6 +13931,7 @@
     const VkAllocationCallbacks* pAllocator,
     VkSurfaceKHR* pSurface)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkCreateWaylandSurfaceKHR encode");
     mImpl->log("start vkCreateWaylandSurfaceKHR");
     auto stream = mImpl->stream();
@@ -13663,46 +13966,46 @@
     }
     countingStream->rewind();
     {
-        uint64_t cgen_var_939;
-        countingStream->handleMapping()->mapHandles_VkInstance_u64(&local_instance, &cgen_var_939, 1);
-        countingStream->write((uint64_t*)&cgen_var_939, 1 * 8);
+        uint64_t cgen_var_943;
+        countingStream->handleMapping()->mapHandles_VkInstance_u64(&local_instance, &cgen_var_943, 1);
+        countingStream->write((uint64_t*)&cgen_var_943, 1 * 8);
         marshal_VkWaylandSurfaceCreateInfoKHR(countingStream, (VkWaylandSurfaceCreateInfoKHR*)(local_pCreateInfo));
         // WARNING PTR CHECK
-        uint64_t cgen_var_940 = (uint64_t)(uintptr_t)local_pAllocator;
-        countingStream->putBe64(cgen_var_940);
+        uint64_t cgen_var_944 = (uint64_t)(uintptr_t)local_pAllocator;
+        countingStream->putBe64(cgen_var_944);
         if (local_pAllocator)
         {
             marshal_VkAllocationCallbacks(countingStream, (VkAllocationCallbacks*)(local_pAllocator));
         }
-        uint64_t cgen_var_941;
-        countingStream->handleMapping()->mapHandles_VkSurfaceKHR_u64(pSurface, &cgen_var_941, 1);
-        countingStream->write((uint64_t*)&cgen_var_941, 8);
+        uint64_t cgen_var_945;
+        countingStream->handleMapping()->mapHandles_VkSurfaceKHR_u64(pSurface, &cgen_var_945, 1);
+        countingStream->write((uint64_t*)&cgen_var_945, 8);
     }
     uint32_t packetSize_vkCreateWaylandSurfaceKHR = 4 + 4 + (uint32_t)countingStream->bytesWritten();
     countingStream->rewind();
     uint32_t opcode_vkCreateWaylandSurfaceKHR = OP_vkCreateWaylandSurfaceKHR;
     stream->write(&opcode_vkCreateWaylandSurfaceKHR, sizeof(uint32_t));
     stream->write(&packetSize_vkCreateWaylandSurfaceKHR, sizeof(uint32_t));
-    uint64_t cgen_var_942;
-    stream->handleMapping()->mapHandles_VkInstance_u64(&local_instance, &cgen_var_942, 1);
-    stream->write((uint64_t*)&cgen_var_942, 1 * 8);
+    uint64_t cgen_var_946;
+    stream->handleMapping()->mapHandles_VkInstance_u64(&local_instance, &cgen_var_946, 1);
+    stream->write((uint64_t*)&cgen_var_946, 1 * 8);
     marshal_VkWaylandSurfaceCreateInfoKHR(stream, (VkWaylandSurfaceCreateInfoKHR*)(local_pCreateInfo));
     // WARNING PTR CHECK
-    uint64_t cgen_var_943 = (uint64_t)(uintptr_t)local_pAllocator;
-    stream->putBe64(cgen_var_943);
+    uint64_t cgen_var_947 = (uint64_t)(uintptr_t)local_pAllocator;
+    stream->putBe64(cgen_var_947);
     if (local_pAllocator)
     {
         marshal_VkAllocationCallbacks(stream, (VkAllocationCallbacks*)(local_pAllocator));
     }
     stream->unsetHandleMapping() /* emit_marshal, is handle, possibly out */;
-    uint64_t cgen_var_944;
-    stream->handleMapping()->mapHandles_VkSurfaceKHR_u64(pSurface, &cgen_var_944, 1);
-    stream->write((uint64_t*)&cgen_var_944, 8);
+    uint64_t cgen_var_948;
+    stream->handleMapping()->mapHandles_VkSurfaceKHR_u64(pSurface, &cgen_var_948, 1);
+    stream->write((uint64_t*)&cgen_var_948, 8);
     stream->setHandleMapping(resources->unwrapMapping());
     AEMU_SCOPED_TRACE("vkCreateWaylandSurfaceKHR readParams");
-    uint64_t cgen_var_945;
-    stream->read((uint64_t*)&cgen_var_945, 8);
-    stream->handleMapping()->mapHandles_u64_VkSurfaceKHR(&cgen_var_945, (VkSurfaceKHR*)pSurface, 1);
+    uint64_t cgen_var_949;
+    stream->read((uint64_t*)&cgen_var_949, 8);
+    stream->handleMapping()->mapHandles_u64_VkSurfaceKHR(&cgen_var_949, (VkSurfaceKHR*)pSurface, 1);
     AEMU_SCOPED_TRACE("vkCreateWaylandSurfaceKHR returnUnmarshal");
     VkResult vkCreateWaylandSurfaceKHR_VkResult_return = (VkResult)0;
     stream->read(&vkCreateWaylandSurfaceKHR_VkResult_return, sizeof(VkResult));
@@ -13718,6 +14021,7 @@
     uint32_t queueFamilyIndex,
     wl_display* display)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkGetPhysicalDeviceWaylandPresentationSupportKHR encode");
     mImpl->log("start vkGetPhysicalDeviceWaylandPresentationSupportKHR");
     auto stream = mImpl->stream();
@@ -13731,9 +14035,9 @@
     local_queueFamilyIndex = queueFamilyIndex;
     countingStream->rewind();
     {
-        uint64_t cgen_var_946;
-        countingStream->handleMapping()->mapHandles_VkPhysicalDevice_u64(&local_physicalDevice, &cgen_var_946, 1);
-        countingStream->write((uint64_t*)&cgen_var_946, 1 * 8);
+        uint64_t cgen_var_950;
+        countingStream->handleMapping()->mapHandles_VkPhysicalDevice_u64(&local_physicalDevice, &cgen_var_950, 1);
+        countingStream->write((uint64_t*)&cgen_var_950, 1 * 8);
         countingStream->write((uint32_t*)&local_queueFamilyIndex, sizeof(uint32_t));
         countingStream->write((wl_display*)display, sizeof(wl_display));
     }
@@ -13742,9 +14046,9 @@
     uint32_t opcode_vkGetPhysicalDeviceWaylandPresentationSupportKHR = OP_vkGetPhysicalDeviceWaylandPresentationSupportKHR;
     stream->write(&opcode_vkGetPhysicalDeviceWaylandPresentationSupportKHR, sizeof(uint32_t));
     stream->write(&packetSize_vkGetPhysicalDeviceWaylandPresentationSupportKHR, sizeof(uint32_t));
-    uint64_t cgen_var_947;
-    stream->handleMapping()->mapHandles_VkPhysicalDevice_u64(&local_physicalDevice, &cgen_var_947, 1);
-    stream->write((uint64_t*)&cgen_var_947, 1 * 8);
+    uint64_t cgen_var_951;
+    stream->handleMapping()->mapHandles_VkPhysicalDevice_u64(&local_physicalDevice, &cgen_var_951, 1);
+    stream->write((uint64_t*)&cgen_var_951, 1 * 8);
     stream->write((uint32_t*)&local_queueFamilyIndex, sizeof(uint32_t));
     stream->write((wl_display*)display, sizeof(wl_display));
     AEMU_SCOPED_TRACE("vkGetPhysicalDeviceWaylandPresentationSupportKHR readParams");
@@ -13767,6 +14071,7 @@
     const VkAllocationCallbacks* pAllocator,
     VkSurfaceKHR* pSurface)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkCreateMirSurfaceKHR encode");
     mImpl->log("start vkCreateMirSurfaceKHR");
     auto stream = mImpl->stream();
@@ -13801,46 +14106,46 @@
     }
     countingStream->rewind();
     {
-        uint64_t cgen_var_948;
-        countingStream->handleMapping()->mapHandles_VkInstance_u64(&local_instance, &cgen_var_948, 1);
-        countingStream->write((uint64_t*)&cgen_var_948, 1 * 8);
+        uint64_t cgen_var_952;
+        countingStream->handleMapping()->mapHandles_VkInstance_u64(&local_instance, &cgen_var_952, 1);
+        countingStream->write((uint64_t*)&cgen_var_952, 1 * 8);
         marshal_VkMirSurfaceCreateInfoKHR(countingStream, (VkMirSurfaceCreateInfoKHR*)(local_pCreateInfo));
         // WARNING PTR CHECK
-        uint64_t cgen_var_949 = (uint64_t)(uintptr_t)local_pAllocator;
-        countingStream->putBe64(cgen_var_949);
+        uint64_t cgen_var_953 = (uint64_t)(uintptr_t)local_pAllocator;
+        countingStream->putBe64(cgen_var_953);
         if (local_pAllocator)
         {
             marshal_VkAllocationCallbacks(countingStream, (VkAllocationCallbacks*)(local_pAllocator));
         }
-        uint64_t cgen_var_950;
-        countingStream->handleMapping()->mapHandles_VkSurfaceKHR_u64(pSurface, &cgen_var_950, 1);
-        countingStream->write((uint64_t*)&cgen_var_950, 8);
+        uint64_t cgen_var_954;
+        countingStream->handleMapping()->mapHandles_VkSurfaceKHR_u64(pSurface, &cgen_var_954, 1);
+        countingStream->write((uint64_t*)&cgen_var_954, 8);
     }
     uint32_t packetSize_vkCreateMirSurfaceKHR = 4 + 4 + (uint32_t)countingStream->bytesWritten();
     countingStream->rewind();
     uint32_t opcode_vkCreateMirSurfaceKHR = OP_vkCreateMirSurfaceKHR;
     stream->write(&opcode_vkCreateMirSurfaceKHR, sizeof(uint32_t));
     stream->write(&packetSize_vkCreateMirSurfaceKHR, sizeof(uint32_t));
-    uint64_t cgen_var_951;
-    stream->handleMapping()->mapHandles_VkInstance_u64(&local_instance, &cgen_var_951, 1);
-    stream->write((uint64_t*)&cgen_var_951, 1 * 8);
+    uint64_t cgen_var_955;
+    stream->handleMapping()->mapHandles_VkInstance_u64(&local_instance, &cgen_var_955, 1);
+    stream->write((uint64_t*)&cgen_var_955, 1 * 8);
     marshal_VkMirSurfaceCreateInfoKHR(stream, (VkMirSurfaceCreateInfoKHR*)(local_pCreateInfo));
     // WARNING PTR CHECK
-    uint64_t cgen_var_952 = (uint64_t)(uintptr_t)local_pAllocator;
-    stream->putBe64(cgen_var_952);
+    uint64_t cgen_var_956 = (uint64_t)(uintptr_t)local_pAllocator;
+    stream->putBe64(cgen_var_956);
     if (local_pAllocator)
     {
         marshal_VkAllocationCallbacks(stream, (VkAllocationCallbacks*)(local_pAllocator));
     }
     stream->unsetHandleMapping() /* emit_marshal, is handle, possibly out */;
-    uint64_t cgen_var_953;
-    stream->handleMapping()->mapHandles_VkSurfaceKHR_u64(pSurface, &cgen_var_953, 1);
-    stream->write((uint64_t*)&cgen_var_953, 8);
+    uint64_t cgen_var_957;
+    stream->handleMapping()->mapHandles_VkSurfaceKHR_u64(pSurface, &cgen_var_957, 1);
+    stream->write((uint64_t*)&cgen_var_957, 8);
     stream->setHandleMapping(resources->unwrapMapping());
     AEMU_SCOPED_TRACE("vkCreateMirSurfaceKHR readParams");
-    uint64_t cgen_var_954;
-    stream->read((uint64_t*)&cgen_var_954, 8);
-    stream->handleMapping()->mapHandles_u64_VkSurfaceKHR(&cgen_var_954, (VkSurfaceKHR*)pSurface, 1);
+    uint64_t cgen_var_958;
+    stream->read((uint64_t*)&cgen_var_958, 8);
+    stream->handleMapping()->mapHandles_u64_VkSurfaceKHR(&cgen_var_958, (VkSurfaceKHR*)pSurface, 1);
     AEMU_SCOPED_TRACE("vkCreateMirSurfaceKHR returnUnmarshal");
     VkResult vkCreateMirSurfaceKHR_VkResult_return = (VkResult)0;
     stream->read(&vkCreateMirSurfaceKHR_VkResult_return, sizeof(VkResult));
@@ -13856,6 +14161,7 @@
     uint32_t queueFamilyIndex,
     MirConnection* connection)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkGetPhysicalDeviceMirPresentationSupportKHR encode");
     mImpl->log("start vkGetPhysicalDeviceMirPresentationSupportKHR");
     auto stream = mImpl->stream();
@@ -13869,9 +14175,9 @@
     local_queueFamilyIndex = queueFamilyIndex;
     countingStream->rewind();
     {
-        uint64_t cgen_var_955;
-        countingStream->handleMapping()->mapHandles_VkPhysicalDevice_u64(&local_physicalDevice, &cgen_var_955, 1);
-        countingStream->write((uint64_t*)&cgen_var_955, 1 * 8);
+        uint64_t cgen_var_959;
+        countingStream->handleMapping()->mapHandles_VkPhysicalDevice_u64(&local_physicalDevice, &cgen_var_959, 1);
+        countingStream->write((uint64_t*)&cgen_var_959, 1 * 8);
         countingStream->write((uint32_t*)&local_queueFamilyIndex, sizeof(uint32_t));
         countingStream->write((MirConnection*)connection, sizeof(MirConnection));
     }
@@ -13880,9 +14186,9 @@
     uint32_t opcode_vkGetPhysicalDeviceMirPresentationSupportKHR = OP_vkGetPhysicalDeviceMirPresentationSupportKHR;
     stream->write(&opcode_vkGetPhysicalDeviceMirPresentationSupportKHR, sizeof(uint32_t));
     stream->write(&packetSize_vkGetPhysicalDeviceMirPresentationSupportKHR, sizeof(uint32_t));
-    uint64_t cgen_var_956;
-    stream->handleMapping()->mapHandles_VkPhysicalDevice_u64(&local_physicalDevice, &cgen_var_956, 1);
-    stream->write((uint64_t*)&cgen_var_956, 1 * 8);
+    uint64_t cgen_var_960;
+    stream->handleMapping()->mapHandles_VkPhysicalDevice_u64(&local_physicalDevice, &cgen_var_960, 1);
+    stream->write((uint64_t*)&cgen_var_960, 1 * 8);
     stream->write((uint32_t*)&local_queueFamilyIndex, sizeof(uint32_t));
     stream->write((MirConnection*)connection, sizeof(MirConnection));
     AEMU_SCOPED_TRACE("vkGetPhysicalDeviceMirPresentationSupportKHR readParams");
@@ -13905,6 +14211,7 @@
     const VkAllocationCallbacks* pAllocator,
     VkSurfaceKHR* pSurface)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkCreateAndroidSurfaceKHR encode");
     mImpl->log("start vkCreateAndroidSurfaceKHR");
     auto stream = mImpl->stream();
@@ -13939,46 +14246,46 @@
     }
     countingStream->rewind();
     {
-        uint64_t cgen_var_957;
-        countingStream->handleMapping()->mapHandles_VkInstance_u64(&local_instance, &cgen_var_957, 1);
-        countingStream->write((uint64_t*)&cgen_var_957, 1 * 8);
+        uint64_t cgen_var_961;
+        countingStream->handleMapping()->mapHandles_VkInstance_u64(&local_instance, &cgen_var_961, 1);
+        countingStream->write((uint64_t*)&cgen_var_961, 1 * 8);
         marshal_VkAndroidSurfaceCreateInfoKHR(countingStream, (VkAndroidSurfaceCreateInfoKHR*)(local_pCreateInfo));
         // WARNING PTR CHECK
-        uint64_t cgen_var_958 = (uint64_t)(uintptr_t)local_pAllocator;
-        countingStream->putBe64(cgen_var_958);
+        uint64_t cgen_var_962 = (uint64_t)(uintptr_t)local_pAllocator;
+        countingStream->putBe64(cgen_var_962);
         if (local_pAllocator)
         {
             marshal_VkAllocationCallbacks(countingStream, (VkAllocationCallbacks*)(local_pAllocator));
         }
-        uint64_t cgen_var_959;
-        countingStream->handleMapping()->mapHandles_VkSurfaceKHR_u64(pSurface, &cgen_var_959, 1);
-        countingStream->write((uint64_t*)&cgen_var_959, 8);
+        uint64_t cgen_var_963;
+        countingStream->handleMapping()->mapHandles_VkSurfaceKHR_u64(pSurface, &cgen_var_963, 1);
+        countingStream->write((uint64_t*)&cgen_var_963, 8);
     }
     uint32_t packetSize_vkCreateAndroidSurfaceKHR = 4 + 4 + (uint32_t)countingStream->bytesWritten();
     countingStream->rewind();
     uint32_t opcode_vkCreateAndroidSurfaceKHR = OP_vkCreateAndroidSurfaceKHR;
     stream->write(&opcode_vkCreateAndroidSurfaceKHR, sizeof(uint32_t));
     stream->write(&packetSize_vkCreateAndroidSurfaceKHR, sizeof(uint32_t));
-    uint64_t cgen_var_960;
-    stream->handleMapping()->mapHandles_VkInstance_u64(&local_instance, &cgen_var_960, 1);
-    stream->write((uint64_t*)&cgen_var_960, 1 * 8);
+    uint64_t cgen_var_964;
+    stream->handleMapping()->mapHandles_VkInstance_u64(&local_instance, &cgen_var_964, 1);
+    stream->write((uint64_t*)&cgen_var_964, 1 * 8);
     marshal_VkAndroidSurfaceCreateInfoKHR(stream, (VkAndroidSurfaceCreateInfoKHR*)(local_pCreateInfo));
     // WARNING PTR CHECK
-    uint64_t cgen_var_961 = (uint64_t)(uintptr_t)local_pAllocator;
-    stream->putBe64(cgen_var_961);
+    uint64_t cgen_var_965 = (uint64_t)(uintptr_t)local_pAllocator;
+    stream->putBe64(cgen_var_965);
     if (local_pAllocator)
     {
         marshal_VkAllocationCallbacks(stream, (VkAllocationCallbacks*)(local_pAllocator));
     }
     stream->unsetHandleMapping() /* emit_marshal, is handle, possibly out */;
-    uint64_t cgen_var_962;
-    stream->handleMapping()->mapHandles_VkSurfaceKHR_u64(pSurface, &cgen_var_962, 1);
-    stream->write((uint64_t*)&cgen_var_962, 8);
+    uint64_t cgen_var_966;
+    stream->handleMapping()->mapHandles_VkSurfaceKHR_u64(pSurface, &cgen_var_966, 1);
+    stream->write((uint64_t*)&cgen_var_966, 8);
     stream->setHandleMapping(resources->unwrapMapping());
     AEMU_SCOPED_TRACE("vkCreateAndroidSurfaceKHR readParams");
-    uint64_t cgen_var_963;
-    stream->read((uint64_t*)&cgen_var_963, 8);
-    stream->handleMapping()->mapHandles_u64_VkSurfaceKHR(&cgen_var_963, (VkSurfaceKHR*)pSurface, 1);
+    uint64_t cgen_var_967;
+    stream->read((uint64_t*)&cgen_var_967, 8);
+    stream->handleMapping()->mapHandles_u64_VkSurfaceKHR(&cgen_var_967, (VkSurfaceKHR*)pSurface, 1);
     AEMU_SCOPED_TRACE("vkCreateAndroidSurfaceKHR returnUnmarshal");
     VkResult vkCreateAndroidSurfaceKHR_VkResult_return = (VkResult)0;
     stream->read(&vkCreateAndroidSurfaceKHR_VkResult_return, sizeof(VkResult));
@@ -13997,6 +14304,7 @@
     const VkAllocationCallbacks* pAllocator,
     VkSurfaceKHR* pSurface)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkCreateWin32SurfaceKHR encode");
     mImpl->log("start vkCreateWin32SurfaceKHR");
     auto stream = mImpl->stream();
@@ -14031,46 +14339,46 @@
     }
     countingStream->rewind();
     {
-        uint64_t cgen_var_964;
-        countingStream->handleMapping()->mapHandles_VkInstance_u64(&local_instance, &cgen_var_964, 1);
-        countingStream->write((uint64_t*)&cgen_var_964, 1 * 8);
+        uint64_t cgen_var_968;
+        countingStream->handleMapping()->mapHandles_VkInstance_u64(&local_instance, &cgen_var_968, 1);
+        countingStream->write((uint64_t*)&cgen_var_968, 1 * 8);
         marshal_VkWin32SurfaceCreateInfoKHR(countingStream, (VkWin32SurfaceCreateInfoKHR*)(local_pCreateInfo));
         // WARNING PTR CHECK
-        uint64_t cgen_var_965 = (uint64_t)(uintptr_t)local_pAllocator;
-        countingStream->putBe64(cgen_var_965);
+        uint64_t cgen_var_969 = (uint64_t)(uintptr_t)local_pAllocator;
+        countingStream->putBe64(cgen_var_969);
         if (local_pAllocator)
         {
             marshal_VkAllocationCallbacks(countingStream, (VkAllocationCallbacks*)(local_pAllocator));
         }
-        uint64_t cgen_var_966;
-        countingStream->handleMapping()->mapHandles_VkSurfaceKHR_u64(pSurface, &cgen_var_966, 1);
-        countingStream->write((uint64_t*)&cgen_var_966, 8);
+        uint64_t cgen_var_970;
+        countingStream->handleMapping()->mapHandles_VkSurfaceKHR_u64(pSurface, &cgen_var_970, 1);
+        countingStream->write((uint64_t*)&cgen_var_970, 8);
     }
     uint32_t packetSize_vkCreateWin32SurfaceKHR = 4 + 4 + (uint32_t)countingStream->bytesWritten();
     countingStream->rewind();
     uint32_t opcode_vkCreateWin32SurfaceKHR = OP_vkCreateWin32SurfaceKHR;
     stream->write(&opcode_vkCreateWin32SurfaceKHR, sizeof(uint32_t));
     stream->write(&packetSize_vkCreateWin32SurfaceKHR, sizeof(uint32_t));
-    uint64_t cgen_var_967;
-    stream->handleMapping()->mapHandles_VkInstance_u64(&local_instance, &cgen_var_967, 1);
-    stream->write((uint64_t*)&cgen_var_967, 1 * 8);
+    uint64_t cgen_var_971;
+    stream->handleMapping()->mapHandles_VkInstance_u64(&local_instance, &cgen_var_971, 1);
+    stream->write((uint64_t*)&cgen_var_971, 1 * 8);
     marshal_VkWin32SurfaceCreateInfoKHR(stream, (VkWin32SurfaceCreateInfoKHR*)(local_pCreateInfo));
     // WARNING PTR CHECK
-    uint64_t cgen_var_968 = (uint64_t)(uintptr_t)local_pAllocator;
-    stream->putBe64(cgen_var_968);
+    uint64_t cgen_var_972 = (uint64_t)(uintptr_t)local_pAllocator;
+    stream->putBe64(cgen_var_972);
     if (local_pAllocator)
     {
         marshal_VkAllocationCallbacks(stream, (VkAllocationCallbacks*)(local_pAllocator));
     }
     stream->unsetHandleMapping() /* emit_marshal, is handle, possibly out */;
-    uint64_t cgen_var_969;
-    stream->handleMapping()->mapHandles_VkSurfaceKHR_u64(pSurface, &cgen_var_969, 1);
-    stream->write((uint64_t*)&cgen_var_969, 8);
+    uint64_t cgen_var_973;
+    stream->handleMapping()->mapHandles_VkSurfaceKHR_u64(pSurface, &cgen_var_973, 1);
+    stream->write((uint64_t*)&cgen_var_973, 8);
     stream->setHandleMapping(resources->unwrapMapping());
     AEMU_SCOPED_TRACE("vkCreateWin32SurfaceKHR readParams");
-    uint64_t cgen_var_970;
-    stream->read((uint64_t*)&cgen_var_970, 8);
-    stream->handleMapping()->mapHandles_u64_VkSurfaceKHR(&cgen_var_970, (VkSurfaceKHR*)pSurface, 1);
+    uint64_t cgen_var_974;
+    stream->read((uint64_t*)&cgen_var_974, 8);
+    stream->handleMapping()->mapHandles_u64_VkSurfaceKHR(&cgen_var_974, (VkSurfaceKHR*)pSurface, 1);
     AEMU_SCOPED_TRACE("vkCreateWin32SurfaceKHR returnUnmarshal");
     VkResult vkCreateWin32SurfaceKHR_VkResult_return = (VkResult)0;
     stream->read(&vkCreateWin32SurfaceKHR_VkResult_return, sizeof(VkResult));
@@ -14085,6 +14393,7 @@
     VkPhysicalDevice physicalDevice,
     uint32_t queueFamilyIndex)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkGetPhysicalDeviceWin32PresentationSupportKHR encode");
     mImpl->log("start vkGetPhysicalDeviceWin32PresentationSupportKHR");
     auto stream = mImpl->stream();
@@ -14098,9 +14407,9 @@
     local_queueFamilyIndex = queueFamilyIndex;
     countingStream->rewind();
     {
-        uint64_t cgen_var_971;
-        countingStream->handleMapping()->mapHandles_VkPhysicalDevice_u64(&local_physicalDevice, &cgen_var_971, 1);
-        countingStream->write((uint64_t*)&cgen_var_971, 1 * 8);
+        uint64_t cgen_var_975;
+        countingStream->handleMapping()->mapHandles_VkPhysicalDevice_u64(&local_physicalDevice, &cgen_var_975, 1);
+        countingStream->write((uint64_t*)&cgen_var_975, 1 * 8);
         countingStream->write((uint32_t*)&local_queueFamilyIndex, sizeof(uint32_t));
     }
     uint32_t packetSize_vkGetPhysicalDeviceWin32PresentationSupportKHR = 4 + 4 + (uint32_t)countingStream->bytesWritten();
@@ -14108,9 +14417,9 @@
     uint32_t opcode_vkGetPhysicalDeviceWin32PresentationSupportKHR = OP_vkGetPhysicalDeviceWin32PresentationSupportKHR;
     stream->write(&opcode_vkGetPhysicalDeviceWin32PresentationSupportKHR, sizeof(uint32_t));
     stream->write(&packetSize_vkGetPhysicalDeviceWin32PresentationSupportKHR, sizeof(uint32_t));
-    uint64_t cgen_var_972;
-    stream->handleMapping()->mapHandles_VkPhysicalDevice_u64(&local_physicalDevice, &cgen_var_972, 1);
-    stream->write((uint64_t*)&cgen_var_972, 1 * 8);
+    uint64_t cgen_var_976;
+    stream->handleMapping()->mapHandles_VkPhysicalDevice_u64(&local_physicalDevice, &cgen_var_976, 1);
+    stream->write((uint64_t*)&cgen_var_976, 1 * 8);
     stream->write((uint32_t*)&local_queueFamilyIndex, sizeof(uint32_t));
     AEMU_SCOPED_TRACE("vkGetPhysicalDeviceWin32PresentationSupportKHR readParams");
     AEMU_SCOPED_TRACE("vkGetPhysicalDeviceWin32PresentationSupportKHR returnUnmarshal");
@@ -14133,6 +14442,7 @@
     VkPhysicalDevice physicalDevice,
     VkPhysicalDeviceFeatures2* pFeatures)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkGetPhysicalDeviceFeatures2KHR encode");
     mImpl->log("start vkGetPhysicalDeviceFeatures2KHR");
     auto stream = mImpl->stream();
@@ -14144,9 +14454,9 @@
     local_physicalDevice = physicalDevice;
     countingStream->rewind();
     {
-        uint64_t cgen_var_973;
-        countingStream->handleMapping()->mapHandles_VkPhysicalDevice_u64(&local_physicalDevice, &cgen_var_973, 1);
-        countingStream->write((uint64_t*)&cgen_var_973, 1 * 8);
+        uint64_t cgen_var_977;
+        countingStream->handleMapping()->mapHandles_VkPhysicalDevice_u64(&local_physicalDevice, &cgen_var_977, 1);
+        countingStream->write((uint64_t*)&cgen_var_977, 1 * 8);
         marshal_VkPhysicalDeviceFeatures2(countingStream, (VkPhysicalDeviceFeatures2*)(pFeatures));
     }
     uint32_t packetSize_vkGetPhysicalDeviceFeatures2KHR = 4 + 4 + (uint32_t)countingStream->bytesWritten();
@@ -14154,9 +14464,9 @@
     uint32_t opcode_vkGetPhysicalDeviceFeatures2KHR = OP_vkGetPhysicalDeviceFeatures2KHR;
     stream->write(&opcode_vkGetPhysicalDeviceFeatures2KHR, sizeof(uint32_t));
     stream->write(&packetSize_vkGetPhysicalDeviceFeatures2KHR, sizeof(uint32_t));
-    uint64_t cgen_var_974;
-    stream->handleMapping()->mapHandles_VkPhysicalDevice_u64(&local_physicalDevice, &cgen_var_974, 1);
-    stream->write((uint64_t*)&cgen_var_974, 1 * 8);
+    uint64_t cgen_var_978;
+    stream->handleMapping()->mapHandles_VkPhysicalDevice_u64(&local_physicalDevice, &cgen_var_978, 1);
+    stream->write((uint64_t*)&cgen_var_978, 1 * 8);
     marshal_VkPhysicalDeviceFeatures2(stream, (VkPhysicalDeviceFeatures2*)(pFeatures));
     AEMU_SCOPED_TRACE("vkGetPhysicalDeviceFeatures2KHR readParams");
     unmarshal_VkPhysicalDeviceFeatures2(stream, (VkPhysicalDeviceFeatures2*)(pFeatures));
@@ -14172,6 +14482,7 @@
     VkPhysicalDevice physicalDevice,
     VkPhysicalDeviceProperties2* pProperties)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkGetPhysicalDeviceProperties2KHR encode");
     mImpl->log("start vkGetPhysicalDeviceProperties2KHR");
     auto stream = mImpl->stream();
@@ -14183,9 +14494,9 @@
     local_physicalDevice = physicalDevice;
     countingStream->rewind();
     {
-        uint64_t cgen_var_975;
-        countingStream->handleMapping()->mapHandles_VkPhysicalDevice_u64(&local_physicalDevice, &cgen_var_975, 1);
-        countingStream->write((uint64_t*)&cgen_var_975, 1 * 8);
+        uint64_t cgen_var_979;
+        countingStream->handleMapping()->mapHandles_VkPhysicalDevice_u64(&local_physicalDevice, &cgen_var_979, 1);
+        countingStream->write((uint64_t*)&cgen_var_979, 1 * 8);
         marshal_VkPhysicalDeviceProperties2(countingStream, (VkPhysicalDeviceProperties2*)(pProperties));
     }
     uint32_t packetSize_vkGetPhysicalDeviceProperties2KHR = 4 + 4 + (uint32_t)countingStream->bytesWritten();
@@ -14193,9 +14504,9 @@
     uint32_t opcode_vkGetPhysicalDeviceProperties2KHR = OP_vkGetPhysicalDeviceProperties2KHR;
     stream->write(&opcode_vkGetPhysicalDeviceProperties2KHR, sizeof(uint32_t));
     stream->write(&packetSize_vkGetPhysicalDeviceProperties2KHR, sizeof(uint32_t));
-    uint64_t cgen_var_976;
-    stream->handleMapping()->mapHandles_VkPhysicalDevice_u64(&local_physicalDevice, &cgen_var_976, 1);
-    stream->write((uint64_t*)&cgen_var_976, 1 * 8);
+    uint64_t cgen_var_980;
+    stream->handleMapping()->mapHandles_VkPhysicalDevice_u64(&local_physicalDevice, &cgen_var_980, 1);
+    stream->write((uint64_t*)&cgen_var_980, 1 * 8);
     marshal_VkPhysicalDeviceProperties2(stream, (VkPhysicalDeviceProperties2*)(pProperties));
     AEMU_SCOPED_TRACE("vkGetPhysicalDeviceProperties2KHR readParams");
     unmarshal_VkPhysicalDeviceProperties2(stream, (VkPhysicalDeviceProperties2*)(pProperties));
@@ -14212,6 +14523,7 @@
     VkFormat format,
     VkFormatProperties2* pFormatProperties)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkGetPhysicalDeviceFormatProperties2KHR encode");
     mImpl->log("start vkGetPhysicalDeviceFormatProperties2KHR");
     auto stream = mImpl->stream();
@@ -14225,9 +14537,9 @@
     local_format = format;
     countingStream->rewind();
     {
-        uint64_t cgen_var_977;
-        countingStream->handleMapping()->mapHandles_VkPhysicalDevice_u64(&local_physicalDevice, &cgen_var_977, 1);
-        countingStream->write((uint64_t*)&cgen_var_977, 1 * 8);
+        uint64_t cgen_var_981;
+        countingStream->handleMapping()->mapHandles_VkPhysicalDevice_u64(&local_physicalDevice, &cgen_var_981, 1);
+        countingStream->write((uint64_t*)&cgen_var_981, 1 * 8);
         countingStream->write((VkFormat*)&local_format, sizeof(VkFormat));
         marshal_VkFormatProperties2(countingStream, (VkFormatProperties2*)(pFormatProperties));
     }
@@ -14236,9 +14548,9 @@
     uint32_t opcode_vkGetPhysicalDeviceFormatProperties2KHR = OP_vkGetPhysicalDeviceFormatProperties2KHR;
     stream->write(&opcode_vkGetPhysicalDeviceFormatProperties2KHR, sizeof(uint32_t));
     stream->write(&packetSize_vkGetPhysicalDeviceFormatProperties2KHR, sizeof(uint32_t));
-    uint64_t cgen_var_978;
-    stream->handleMapping()->mapHandles_VkPhysicalDevice_u64(&local_physicalDevice, &cgen_var_978, 1);
-    stream->write((uint64_t*)&cgen_var_978, 1 * 8);
+    uint64_t cgen_var_982;
+    stream->handleMapping()->mapHandles_VkPhysicalDevice_u64(&local_physicalDevice, &cgen_var_982, 1);
+    stream->write((uint64_t*)&cgen_var_982, 1 * 8);
     stream->write((VkFormat*)&local_format, sizeof(VkFormat));
     marshal_VkFormatProperties2(stream, (VkFormatProperties2*)(pFormatProperties));
     AEMU_SCOPED_TRACE("vkGetPhysicalDeviceFormatProperties2KHR readParams");
@@ -14256,6 +14568,7 @@
     const VkPhysicalDeviceImageFormatInfo2* pImageFormatInfo,
     VkImageFormatProperties2* pImageFormatProperties)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkGetPhysicalDeviceImageFormatProperties2KHR encode");
     mImpl->log("start vkGetPhysicalDeviceImageFormatProperties2KHR");
     auto stream = mImpl->stream();
@@ -14278,9 +14591,9 @@
     }
     countingStream->rewind();
     {
-        uint64_t cgen_var_979;
-        countingStream->handleMapping()->mapHandles_VkPhysicalDevice_u64(&local_physicalDevice, &cgen_var_979, 1);
-        countingStream->write((uint64_t*)&cgen_var_979, 1 * 8);
+        uint64_t cgen_var_983;
+        countingStream->handleMapping()->mapHandles_VkPhysicalDevice_u64(&local_physicalDevice, &cgen_var_983, 1);
+        countingStream->write((uint64_t*)&cgen_var_983, 1 * 8);
         marshal_VkPhysicalDeviceImageFormatInfo2(countingStream, (VkPhysicalDeviceImageFormatInfo2*)(local_pImageFormatInfo));
         marshal_VkImageFormatProperties2(countingStream, (VkImageFormatProperties2*)(pImageFormatProperties));
     }
@@ -14289,9 +14602,9 @@
     uint32_t opcode_vkGetPhysicalDeviceImageFormatProperties2KHR = OP_vkGetPhysicalDeviceImageFormatProperties2KHR;
     stream->write(&opcode_vkGetPhysicalDeviceImageFormatProperties2KHR, sizeof(uint32_t));
     stream->write(&packetSize_vkGetPhysicalDeviceImageFormatProperties2KHR, sizeof(uint32_t));
-    uint64_t cgen_var_980;
-    stream->handleMapping()->mapHandles_VkPhysicalDevice_u64(&local_physicalDevice, &cgen_var_980, 1);
-    stream->write((uint64_t*)&cgen_var_980, 1 * 8);
+    uint64_t cgen_var_984;
+    stream->handleMapping()->mapHandles_VkPhysicalDevice_u64(&local_physicalDevice, &cgen_var_984, 1);
+    stream->write((uint64_t*)&cgen_var_984, 1 * 8);
     marshal_VkPhysicalDeviceImageFormatInfo2(stream, (VkPhysicalDeviceImageFormatInfo2*)(local_pImageFormatInfo));
     marshal_VkImageFormatProperties2(stream, (VkImageFormatProperties2*)(pImageFormatProperties));
     AEMU_SCOPED_TRACE("vkGetPhysicalDeviceImageFormatProperties2KHR readParams");
@@ -14315,6 +14628,7 @@
     uint32_t* pQueueFamilyPropertyCount,
     VkQueueFamilyProperties2* pQueueFamilyProperties)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkGetPhysicalDeviceQueueFamilyProperties2KHR encode");
     mImpl->log("start vkGetPhysicalDeviceQueueFamilyProperties2KHR");
     auto stream = mImpl->stream();
@@ -14326,19 +14640,19 @@
     local_physicalDevice = physicalDevice;
     countingStream->rewind();
     {
-        uint64_t cgen_var_981;
-        countingStream->handleMapping()->mapHandles_VkPhysicalDevice_u64(&local_physicalDevice, &cgen_var_981, 1);
-        countingStream->write((uint64_t*)&cgen_var_981, 1 * 8);
+        uint64_t cgen_var_985;
+        countingStream->handleMapping()->mapHandles_VkPhysicalDevice_u64(&local_physicalDevice, &cgen_var_985, 1);
+        countingStream->write((uint64_t*)&cgen_var_985, 1 * 8);
         // WARNING PTR CHECK
-        uint64_t cgen_var_982 = (uint64_t)(uintptr_t)pQueueFamilyPropertyCount;
-        countingStream->putBe64(cgen_var_982);
+        uint64_t cgen_var_986 = (uint64_t)(uintptr_t)pQueueFamilyPropertyCount;
+        countingStream->putBe64(cgen_var_986);
         if (pQueueFamilyPropertyCount)
         {
             countingStream->write((uint32_t*)pQueueFamilyPropertyCount, sizeof(uint32_t));
         }
         // WARNING PTR CHECK
-        uint64_t cgen_var_983 = (uint64_t)(uintptr_t)pQueueFamilyProperties;
-        countingStream->putBe64(cgen_var_983);
+        uint64_t cgen_var_987 = (uint64_t)(uintptr_t)pQueueFamilyProperties;
+        countingStream->putBe64(cgen_var_987);
         if (pQueueFamilyProperties)
         {
             for (uint32_t i = 0; i < (uint32_t)(*(pQueueFamilyPropertyCount)); ++i)
@@ -14352,19 +14666,19 @@
     uint32_t opcode_vkGetPhysicalDeviceQueueFamilyProperties2KHR = OP_vkGetPhysicalDeviceQueueFamilyProperties2KHR;
     stream->write(&opcode_vkGetPhysicalDeviceQueueFamilyProperties2KHR, sizeof(uint32_t));
     stream->write(&packetSize_vkGetPhysicalDeviceQueueFamilyProperties2KHR, sizeof(uint32_t));
-    uint64_t cgen_var_984;
-    stream->handleMapping()->mapHandles_VkPhysicalDevice_u64(&local_physicalDevice, &cgen_var_984, 1);
-    stream->write((uint64_t*)&cgen_var_984, 1 * 8);
+    uint64_t cgen_var_988;
+    stream->handleMapping()->mapHandles_VkPhysicalDevice_u64(&local_physicalDevice, &cgen_var_988, 1);
+    stream->write((uint64_t*)&cgen_var_988, 1 * 8);
     // WARNING PTR CHECK
-    uint64_t cgen_var_985 = (uint64_t)(uintptr_t)pQueueFamilyPropertyCount;
-    stream->putBe64(cgen_var_985);
+    uint64_t cgen_var_989 = (uint64_t)(uintptr_t)pQueueFamilyPropertyCount;
+    stream->putBe64(cgen_var_989);
     if (pQueueFamilyPropertyCount)
     {
         stream->write((uint32_t*)pQueueFamilyPropertyCount, sizeof(uint32_t));
     }
     // WARNING PTR CHECK
-    uint64_t cgen_var_986 = (uint64_t)(uintptr_t)pQueueFamilyProperties;
-    stream->putBe64(cgen_var_986);
+    uint64_t cgen_var_990 = (uint64_t)(uintptr_t)pQueueFamilyProperties;
+    stream->putBe64(cgen_var_990);
     if (pQueueFamilyProperties)
     {
         for (uint32_t i = 0; i < (uint32_t)(*(pQueueFamilyPropertyCount)); ++i)
@@ -14413,6 +14727,7 @@
     VkPhysicalDevice physicalDevice,
     VkPhysicalDeviceMemoryProperties2* pMemoryProperties)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkGetPhysicalDeviceMemoryProperties2KHR encode");
     mImpl->log("start vkGetPhysicalDeviceMemoryProperties2KHR");
     auto stream = mImpl->stream();
@@ -14424,9 +14739,9 @@
     local_physicalDevice = physicalDevice;
     countingStream->rewind();
     {
-        uint64_t cgen_var_989;
-        countingStream->handleMapping()->mapHandles_VkPhysicalDevice_u64(&local_physicalDevice, &cgen_var_989, 1);
-        countingStream->write((uint64_t*)&cgen_var_989, 1 * 8);
+        uint64_t cgen_var_993;
+        countingStream->handleMapping()->mapHandles_VkPhysicalDevice_u64(&local_physicalDevice, &cgen_var_993, 1);
+        countingStream->write((uint64_t*)&cgen_var_993, 1 * 8);
         marshal_VkPhysicalDeviceMemoryProperties2(countingStream, (VkPhysicalDeviceMemoryProperties2*)(pMemoryProperties));
     }
     uint32_t packetSize_vkGetPhysicalDeviceMemoryProperties2KHR = 4 + 4 + (uint32_t)countingStream->bytesWritten();
@@ -14434,9 +14749,9 @@
     uint32_t opcode_vkGetPhysicalDeviceMemoryProperties2KHR = OP_vkGetPhysicalDeviceMemoryProperties2KHR;
     stream->write(&opcode_vkGetPhysicalDeviceMemoryProperties2KHR, sizeof(uint32_t));
     stream->write(&packetSize_vkGetPhysicalDeviceMemoryProperties2KHR, sizeof(uint32_t));
-    uint64_t cgen_var_990;
-    stream->handleMapping()->mapHandles_VkPhysicalDevice_u64(&local_physicalDevice, &cgen_var_990, 1);
-    stream->write((uint64_t*)&cgen_var_990, 1 * 8);
+    uint64_t cgen_var_994;
+    stream->handleMapping()->mapHandles_VkPhysicalDevice_u64(&local_physicalDevice, &cgen_var_994, 1);
+    stream->write((uint64_t*)&cgen_var_994, 1 * 8);
     marshal_VkPhysicalDeviceMemoryProperties2(stream, (VkPhysicalDeviceMemoryProperties2*)(pMemoryProperties));
     AEMU_SCOPED_TRACE("vkGetPhysicalDeviceMemoryProperties2KHR readParams");
     unmarshal_VkPhysicalDeviceMemoryProperties2(stream, (VkPhysicalDeviceMemoryProperties2*)(pMemoryProperties));
@@ -14445,7 +14760,9 @@
         transform_fromhost_VkPhysicalDeviceMemoryProperties2(mImpl->resources(), (VkPhysicalDeviceMemoryProperties2*)(pMemoryProperties));
     }
     AEMU_SCOPED_TRACE("vkGetPhysicalDeviceMemoryProperties2KHR returnUnmarshal");
+    encoderLock.unlock();
     mImpl->resources()->on_vkGetPhysicalDeviceMemoryProperties2KHR(this, physicalDevice, pMemoryProperties);
+    encoderLock.lock();
     mImpl->log("finish vkGetPhysicalDeviceMemoryProperties2KHR");;
 }
 
@@ -14455,6 +14772,7 @@
     uint32_t* pPropertyCount,
     VkSparseImageFormatProperties2* pProperties)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkGetPhysicalDeviceSparseImageFormatProperties2KHR encode");
     mImpl->log("start vkGetPhysicalDeviceSparseImageFormatProperties2KHR");
     auto stream = mImpl->stream();
@@ -14477,20 +14795,20 @@
     }
     countingStream->rewind();
     {
-        uint64_t cgen_var_991;
-        countingStream->handleMapping()->mapHandles_VkPhysicalDevice_u64(&local_physicalDevice, &cgen_var_991, 1);
-        countingStream->write((uint64_t*)&cgen_var_991, 1 * 8);
+        uint64_t cgen_var_995;
+        countingStream->handleMapping()->mapHandles_VkPhysicalDevice_u64(&local_physicalDevice, &cgen_var_995, 1);
+        countingStream->write((uint64_t*)&cgen_var_995, 1 * 8);
         marshal_VkPhysicalDeviceSparseImageFormatInfo2(countingStream, (VkPhysicalDeviceSparseImageFormatInfo2*)(local_pFormatInfo));
         // WARNING PTR CHECK
-        uint64_t cgen_var_992 = (uint64_t)(uintptr_t)pPropertyCount;
-        countingStream->putBe64(cgen_var_992);
+        uint64_t cgen_var_996 = (uint64_t)(uintptr_t)pPropertyCount;
+        countingStream->putBe64(cgen_var_996);
         if (pPropertyCount)
         {
             countingStream->write((uint32_t*)pPropertyCount, sizeof(uint32_t));
         }
         // WARNING PTR CHECK
-        uint64_t cgen_var_993 = (uint64_t)(uintptr_t)pProperties;
-        countingStream->putBe64(cgen_var_993);
+        uint64_t cgen_var_997 = (uint64_t)(uintptr_t)pProperties;
+        countingStream->putBe64(cgen_var_997);
         if (pProperties)
         {
             for (uint32_t i = 0; i < (uint32_t)(*(pPropertyCount)); ++i)
@@ -14504,20 +14822,20 @@
     uint32_t opcode_vkGetPhysicalDeviceSparseImageFormatProperties2KHR = OP_vkGetPhysicalDeviceSparseImageFormatProperties2KHR;
     stream->write(&opcode_vkGetPhysicalDeviceSparseImageFormatProperties2KHR, sizeof(uint32_t));
     stream->write(&packetSize_vkGetPhysicalDeviceSparseImageFormatProperties2KHR, sizeof(uint32_t));
-    uint64_t cgen_var_994;
-    stream->handleMapping()->mapHandles_VkPhysicalDevice_u64(&local_physicalDevice, &cgen_var_994, 1);
-    stream->write((uint64_t*)&cgen_var_994, 1 * 8);
+    uint64_t cgen_var_998;
+    stream->handleMapping()->mapHandles_VkPhysicalDevice_u64(&local_physicalDevice, &cgen_var_998, 1);
+    stream->write((uint64_t*)&cgen_var_998, 1 * 8);
     marshal_VkPhysicalDeviceSparseImageFormatInfo2(stream, (VkPhysicalDeviceSparseImageFormatInfo2*)(local_pFormatInfo));
     // WARNING PTR CHECK
-    uint64_t cgen_var_995 = (uint64_t)(uintptr_t)pPropertyCount;
-    stream->putBe64(cgen_var_995);
+    uint64_t cgen_var_999 = (uint64_t)(uintptr_t)pPropertyCount;
+    stream->putBe64(cgen_var_999);
     if (pPropertyCount)
     {
         stream->write((uint32_t*)pPropertyCount, sizeof(uint32_t));
     }
     // WARNING PTR CHECK
-    uint64_t cgen_var_996 = (uint64_t)(uintptr_t)pProperties;
-    stream->putBe64(cgen_var_996);
+    uint64_t cgen_var_1000 = (uint64_t)(uintptr_t)pProperties;
+    stream->putBe64(cgen_var_1000);
     if (pProperties)
     {
         for (uint32_t i = 0; i < (uint32_t)(*(pPropertyCount)); ++i)
@@ -14571,6 +14889,7 @@
     uint32_t remoteDeviceIndex,
     VkPeerMemoryFeatureFlags* pPeerMemoryFeatures)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkGetDeviceGroupPeerMemoryFeaturesKHR encode");
     mImpl->log("start vkGetDeviceGroupPeerMemoryFeaturesKHR");
     auto stream = mImpl->stream();
@@ -14588,9 +14907,9 @@
     local_remoteDeviceIndex = remoteDeviceIndex;
     countingStream->rewind();
     {
-        uint64_t cgen_var_999;
-        countingStream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_999, 1);
-        countingStream->write((uint64_t*)&cgen_var_999, 1 * 8);
+        uint64_t cgen_var_1003;
+        countingStream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_1003, 1);
+        countingStream->write((uint64_t*)&cgen_var_1003, 1 * 8);
         countingStream->write((uint32_t*)&local_heapIndex, sizeof(uint32_t));
         countingStream->write((uint32_t*)&local_localDeviceIndex, sizeof(uint32_t));
         countingStream->write((uint32_t*)&local_remoteDeviceIndex, sizeof(uint32_t));
@@ -14601,9 +14920,9 @@
     uint32_t opcode_vkGetDeviceGroupPeerMemoryFeaturesKHR = OP_vkGetDeviceGroupPeerMemoryFeaturesKHR;
     stream->write(&opcode_vkGetDeviceGroupPeerMemoryFeaturesKHR, sizeof(uint32_t));
     stream->write(&packetSize_vkGetDeviceGroupPeerMemoryFeaturesKHR, sizeof(uint32_t));
-    uint64_t cgen_var_1000;
-    stream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_1000, 1);
-    stream->write((uint64_t*)&cgen_var_1000, 1 * 8);
+    uint64_t cgen_var_1004;
+    stream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_1004, 1);
+    stream->write((uint64_t*)&cgen_var_1004, 1 * 8);
     stream->write((uint32_t*)&local_heapIndex, sizeof(uint32_t));
     stream->write((uint32_t*)&local_localDeviceIndex, sizeof(uint32_t));
     stream->write((uint32_t*)&local_remoteDeviceIndex, sizeof(uint32_t));
@@ -14618,6 +14937,7 @@
     VkCommandBuffer commandBuffer,
     uint32_t deviceMask)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkCmdSetDeviceMaskKHR encode");
     mImpl->log("start vkCmdSetDeviceMaskKHR");
     auto stream = mImpl->stream();
@@ -14631,9 +14951,9 @@
     local_deviceMask = deviceMask;
     countingStream->rewind();
     {
-        uint64_t cgen_var_1001;
-        countingStream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_1001, 1);
-        countingStream->write((uint64_t*)&cgen_var_1001, 1 * 8);
+        uint64_t cgen_var_1005;
+        countingStream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_1005, 1);
+        countingStream->write((uint64_t*)&cgen_var_1005, 1 * 8);
         countingStream->write((uint32_t*)&local_deviceMask, sizeof(uint32_t));
     }
     uint32_t packetSize_vkCmdSetDeviceMaskKHR = 4 + 4 + (uint32_t)countingStream->bytesWritten();
@@ -14641,9 +14961,9 @@
     uint32_t opcode_vkCmdSetDeviceMaskKHR = OP_vkCmdSetDeviceMaskKHR;
     stream->write(&opcode_vkCmdSetDeviceMaskKHR, sizeof(uint32_t));
     stream->write(&packetSize_vkCmdSetDeviceMaskKHR, sizeof(uint32_t));
-    uint64_t cgen_var_1002;
-    stream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_1002, 1);
-    stream->write((uint64_t*)&cgen_var_1002, 1 * 8);
+    uint64_t cgen_var_1006;
+    stream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_1006, 1);
+    stream->write((uint64_t*)&cgen_var_1006, 1 * 8);
     stream->write((uint32_t*)&local_deviceMask, sizeof(uint32_t));
     AEMU_SCOPED_TRACE("vkCmdSetDeviceMaskKHR readParams");
     AEMU_SCOPED_TRACE("vkCmdSetDeviceMaskKHR returnUnmarshal");
@@ -14659,6 +14979,7 @@
     uint32_t groupCountY,
     uint32_t groupCountZ)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkCmdDispatchBaseKHR encode");
     mImpl->log("start vkCmdDispatchBaseKHR");
     auto stream = mImpl->stream();
@@ -14682,9 +15003,9 @@
     local_groupCountZ = groupCountZ;
     countingStream->rewind();
     {
-        uint64_t cgen_var_1003;
-        countingStream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_1003, 1);
-        countingStream->write((uint64_t*)&cgen_var_1003, 1 * 8);
+        uint64_t cgen_var_1007;
+        countingStream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_1007, 1);
+        countingStream->write((uint64_t*)&cgen_var_1007, 1 * 8);
         countingStream->write((uint32_t*)&local_baseGroupX, sizeof(uint32_t));
         countingStream->write((uint32_t*)&local_baseGroupY, sizeof(uint32_t));
         countingStream->write((uint32_t*)&local_baseGroupZ, sizeof(uint32_t));
@@ -14697,9 +15018,9 @@
     uint32_t opcode_vkCmdDispatchBaseKHR = OP_vkCmdDispatchBaseKHR;
     stream->write(&opcode_vkCmdDispatchBaseKHR, sizeof(uint32_t));
     stream->write(&packetSize_vkCmdDispatchBaseKHR, sizeof(uint32_t));
-    uint64_t cgen_var_1004;
-    stream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_1004, 1);
-    stream->write((uint64_t*)&cgen_var_1004, 1 * 8);
+    uint64_t cgen_var_1008;
+    stream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_1008, 1);
+    stream->write((uint64_t*)&cgen_var_1008, 1 * 8);
     stream->write((uint32_t*)&local_baseGroupX, sizeof(uint32_t));
     stream->write((uint32_t*)&local_baseGroupY, sizeof(uint32_t));
     stream->write((uint32_t*)&local_baseGroupZ, sizeof(uint32_t));
@@ -14720,6 +15041,7 @@
     VkCommandPool commandPool,
     VkCommandPoolTrimFlags flags)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkTrimCommandPoolKHR encode");
     mImpl->log("start vkTrimCommandPoolKHR");
     auto stream = mImpl->stream();
@@ -14735,12 +15057,12 @@
     local_flags = flags;
     countingStream->rewind();
     {
-        uint64_t cgen_var_1005;
-        countingStream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_1005, 1);
-        countingStream->write((uint64_t*)&cgen_var_1005, 1 * 8);
-        uint64_t cgen_var_1006;
-        countingStream->handleMapping()->mapHandles_VkCommandPool_u64(&local_commandPool, &cgen_var_1006, 1);
-        countingStream->write((uint64_t*)&cgen_var_1006, 1 * 8);
+        uint64_t cgen_var_1009;
+        countingStream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_1009, 1);
+        countingStream->write((uint64_t*)&cgen_var_1009, 1 * 8);
+        uint64_t cgen_var_1010;
+        countingStream->handleMapping()->mapHandles_VkCommandPool_u64(&local_commandPool, &cgen_var_1010, 1);
+        countingStream->write((uint64_t*)&cgen_var_1010, 1 * 8);
         countingStream->write((VkCommandPoolTrimFlags*)&local_flags, sizeof(VkCommandPoolTrimFlags));
     }
     uint32_t packetSize_vkTrimCommandPoolKHR = 4 + 4 + (uint32_t)countingStream->bytesWritten();
@@ -14748,12 +15070,12 @@
     uint32_t opcode_vkTrimCommandPoolKHR = OP_vkTrimCommandPoolKHR;
     stream->write(&opcode_vkTrimCommandPoolKHR, sizeof(uint32_t));
     stream->write(&packetSize_vkTrimCommandPoolKHR, sizeof(uint32_t));
-    uint64_t cgen_var_1007;
-    stream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_1007, 1);
-    stream->write((uint64_t*)&cgen_var_1007, 1 * 8);
-    uint64_t cgen_var_1008;
-    stream->handleMapping()->mapHandles_VkCommandPool_u64(&local_commandPool, &cgen_var_1008, 1);
-    stream->write((uint64_t*)&cgen_var_1008, 1 * 8);
+    uint64_t cgen_var_1011;
+    stream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_1011, 1);
+    stream->write((uint64_t*)&cgen_var_1011, 1 * 8);
+    uint64_t cgen_var_1012;
+    stream->handleMapping()->mapHandles_VkCommandPool_u64(&local_commandPool, &cgen_var_1012, 1);
+    stream->write((uint64_t*)&cgen_var_1012, 1 * 8);
     stream->write((VkCommandPoolTrimFlags*)&local_flags, sizeof(VkCommandPoolTrimFlags));
     AEMU_SCOPED_TRACE("vkTrimCommandPoolKHR readParams");
     AEMU_SCOPED_TRACE("vkTrimCommandPoolKHR returnUnmarshal");
@@ -14767,6 +15089,7 @@
     uint32_t* pPhysicalDeviceGroupCount,
     VkPhysicalDeviceGroupProperties* pPhysicalDeviceGroupProperties)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkEnumeratePhysicalDeviceGroupsKHR encode");
     mImpl->log("start vkEnumeratePhysicalDeviceGroupsKHR");
     auto stream = mImpl->stream();
@@ -14778,19 +15101,19 @@
     local_instance = instance;
     countingStream->rewind();
     {
-        uint64_t cgen_var_1009;
-        countingStream->handleMapping()->mapHandles_VkInstance_u64(&local_instance, &cgen_var_1009, 1);
-        countingStream->write((uint64_t*)&cgen_var_1009, 1 * 8);
+        uint64_t cgen_var_1013;
+        countingStream->handleMapping()->mapHandles_VkInstance_u64(&local_instance, &cgen_var_1013, 1);
+        countingStream->write((uint64_t*)&cgen_var_1013, 1 * 8);
         // WARNING PTR CHECK
-        uint64_t cgen_var_1010 = (uint64_t)(uintptr_t)pPhysicalDeviceGroupCount;
-        countingStream->putBe64(cgen_var_1010);
+        uint64_t cgen_var_1014 = (uint64_t)(uintptr_t)pPhysicalDeviceGroupCount;
+        countingStream->putBe64(cgen_var_1014);
         if (pPhysicalDeviceGroupCount)
         {
             countingStream->write((uint32_t*)pPhysicalDeviceGroupCount, sizeof(uint32_t));
         }
         // WARNING PTR CHECK
-        uint64_t cgen_var_1011 = (uint64_t)(uintptr_t)pPhysicalDeviceGroupProperties;
-        countingStream->putBe64(cgen_var_1011);
+        uint64_t cgen_var_1015 = (uint64_t)(uintptr_t)pPhysicalDeviceGroupProperties;
+        countingStream->putBe64(cgen_var_1015);
         if (pPhysicalDeviceGroupProperties)
         {
             for (uint32_t i = 0; i < (uint32_t)(*(pPhysicalDeviceGroupCount)); ++i)
@@ -14804,19 +15127,19 @@
     uint32_t opcode_vkEnumeratePhysicalDeviceGroupsKHR = OP_vkEnumeratePhysicalDeviceGroupsKHR;
     stream->write(&opcode_vkEnumeratePhysicalDeviceGroupsKHR, sizeof(uint32_t));
     stream->write(&packetSize_vkEnumeratePhysicalDeviceGroupsKHR, sizeof(uint32_t));
-    uint64_t cgen_var_1012;
-    stream->handleMapping()->mapHandles_VkInstance_u64(&local_instance, &cgen_var_1012, 1);
-    stream->write((uint64_t*)&cgen_var_1012, 1 * 8);
+    uint64_t cgen_var_1016;
+    stream->handleMapping()->mapHandles_VkInstance_u64(&local_instance, &cgen_var_1016, 1);
+    stream->write((uint64_t*)&cgen_var_1016, 1 * 8);
     // WARNING PTR CHECK
-    uint64_t cgen_var_1013 = (uint64_t)(uintptr_t)pPhysicalDeviceGroupCount;
-    stream->putBe64(cgen_var_1013);
+    uint64_t cgen_var_1017 = (uint64_t)(uintptr_t)pPhysicalDeviceGroupCount;
+    stream->putBe64(cgen_var_1017);
     if (pPhysicalDeviceGroupCount)
     {
         stream->write((uint32_t*)pPhysicalDeviceGroupCount, sizeof(uint32_t));
     }
     // WARNING PTR CHECK
-    uint64_t cgen_var_1014 = (uint64_t)(uintptr_t)pPhysicalDeviceGroupProperties;
-    stream->putBe64(cgen_var_1014);
+    uint64_t cgen_var_1018 = (uint64_t)(uintptr_t)pPhysicalDeviceGroupProperties;
+    stream->putBe64(cgen_var_1018);
     if (pPhysicalDeviceGroupProperties)
     {
         for (uint32_t i = 0; i < (uint32_t)(*(pPhysicalDeviceGroupCount)); ++i)
@@ -14874,6 +15197,7 @@
     const VkPhysicalDeviceExternalBufferInfo* pExternalBufferInfo,
     VkExternalBufferProperties* pExternalBufferProperties)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkGetPhysicalDeviceExternalBufferPropertiesKHR encode");
     mImpl->log("start vkGetPhysicalDeviceExternalBufferPropertiesKHR");
     auto stream = mImpl->stream();
@@ -14897,9 +15221,9 @@
     }
     countingStream->rewind();
     {
-        uint64_t cgen_var_1017;
-        countingStream->handleMapping()->mapHandles_VkPhysicalDevice_u64(&local_physicalDevice, &cgen_var_1017, 1);
-        countingStream->write((uint64_t*)&cgen_var_1017, 1 * 8);
+        uint64_t cgen_var_1021;
+        countingStream->handleMapping()->mapHandles_VkPhysicalDevice_u64(&local_physicalDevice, &cgen_var_1021, 1);
+        countingStream->write((uint64_t*)&cgen_var_1021, 1 * 8);
         marshal_VkPhysicalDeviceExternalBufferInfo(countingStream, (VkPhysicalDeviceExternalBufferInfo*)(local_pExternalBufferInfo));
         marshal_VkExternalBufferProperties(countingStream, (VkExternalBufferProperties*)(pExternalBufferProperties));
     }
@@ -14908,9 +15232,9 @@
     uint32_t opcode_vkGetPhysicalDeviceExternalBufferPropertiesKHR = OP_vkGetPhysicalDeviceExternalBufferPropertiesKHR;
     stream->write(&opcode_vkGetPhysicalDeviceExternalBufferPropertiesKHR, sizeof(uint32_t));
     stream->write(&packetSize_vkGetPhysicalDeviceExternalBufferPropertiesKHR, sizeof(uint32_t));
-    uint64_t cgen_var_1018;
-    stream->handleMapping()->mapHandles_VkPhysicalDevice_u64(&local_physicalDevice, &cgen_var_1018, 1);
-    stream->write((uint64_t*)&cgen_var_1018, 1 * 8);
+    uint64_t cgen_var_1022;
+    stream->handleMapping()->mapHandles_VkPhysicalDevice_u64(&local_physicalDevice, &cgen_var_1022, 1);
+    stream->write((uint64_t*)&cgen_var_1022, 1 * 8);
     marshal_VkPhysicalDeviceExternalBufferInfo(stream, (VkPhysicalDeviceExternalBufferInfo*)(local_pExternalBufferInfo));
     marshal_VkExternalBufferProperties(stream, (VkExternalBufferProperties*)(pExternalBufferProperties));
     AEMU_SCOPED_TRACE("vkGetPhysicalDeviceExternalBufferPropertiesKHR readParams");
@@ -14933,6 +15257,7 @@
     const VkMemoryGetWin32HandleInfoKHR* pGetWin32HandleInfo,
     HANDLE* pHandle)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkGetMemoryWin32HandleKHR encode");
     mImpl->log("start vkGetMemoryWin32HandleKHR");
     auto stream = mImpl->stream();
@@ -14955,9 +15280,9 @@
     }
     countingStream->rewind();
     {
-        uint64_t cgen_var_1019;
-        countingStream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_1019, 1);
-        countingStream->write((uint64_t*)&cgen_var_1019, 1 * 8);
+        uint64_t cgen_var_1023;
+        countingStream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_1023, 1);
+        countingStream->write((uint64_t*)&cgen_var_1023, 1 * 8);
         marshal_VkMemoryGetWin32HandleInfoKHR(countingStream, (VkMemoryGetWin32HandleInfoKHR*)(local_pGetWin32HandleInfo));
         countingStream->write((HANDLE*)pHandle, sizeof(HANDLE));
     }
@@ -14966,9 +15291,9 @@
     uint32_t opcode_vkGetMemoryWin32HandleKHR = OP_vkGetMemoryWin32HandleKHR;
     stream->write(&opcode_vkGetMemoryWin32HandleKHR, sizeof(uint32_t));
     stream->write(&packetSize_vkGetMemoryWin32HandleKHR, sizeof(uint32_t));
-    uint64_t cgen_var_1020;
-    stream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_1020, 1);
-    stream->write((uint64_t*)&cgen_var_1020, 1 * 8);
+    uint64_t cgen_var_1024;
+    stream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_1024, 1);
+    stream->write((uint64_t*)&cgen_var_1024, 1 * 8);
     marshal_VkMemoryGetWin32HandleInfoKHR(stream, (VkMemoryGetWin32HandleInfoKHR*)(local_pGetWin32HandleInfo));
     stream->write((HANDLE*)pHandle, sizeof(HANDLE));
     AEMU_SCOPED_TRACE("vkGetMemoryWin32HandleKHR readParams");
@@ -14989,6 +15314,7 @@
     HANDLE handle,
     VkMemoryWin32HandlePropertiesKHR* pMemoryWin32HandleProperties)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkGetMemoryWin32HandlePropertiesKHR encode");
     mImpl->log("start vkGetMemoryWin32HandlePropertiesKHR");
     auto stream = mImpl->stream();
@@ -15004,9 +15330,9 @@
     local_handle = handle;
     countingStream->rewind();
     {
-        uint64_t cgen_var_1021;
-        countingStream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_1021, 1);
-        countingStream->write((uint64_t*)&cgen_var_1021, 1 * 8);
+        uint64_t cgen_var_1025;
+        countingStream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_1025, 1);
+        countingStream->write((uint64_t*)&cgen_var_1025, 1 * 8);
         countingStream->write((VkExternalMemoryHandleTypeFlagBits*)&local_handleType, sizeof(VkExternalMemoryHandleTypeFlagBits));
         countingStream->write((HANDLE*)&local_handle, sizeof(HANDLE));
         marshal_VkMemoryWin32HandlePropertiesKHR(countingStream, (VkMemoryWin32HandlePropertiesKHR*)(pMemoryWin32HandleProperties));
@@ -15016,9 +15342,9 @@
     uint32_t opcode_vkGetMemoryWin32HandlePropertiesKHR = OP_vkGetMemoryWin32HandlePropertiesKHR;
     stream->write(&opcode_vkGetMemoryWin32HandlePropertiesKHR, sizeof(uint32_t));
     stream->write(&packetSize_vkGetMemoryWin32HandlePropertiesKHR, sizeof(uint32_t));
-    uint64_t cgen_var_1022;
-    stream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_1022, 1);
-    stream->write((uint64_t*)&cgen_var_1022, 1 * 8);
+    uint64_t cgen_var_1026;
+    stream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_1026, 1);
+    stream->write((uint64_t*)&cgen_var_1026, 1 * 8);
     stream->write((VkExternalMemoryHandleTypeFlagBits*)&local_handleType, sizeof(VkExternalMemoryHandleTypeFlagBits));
     stream->write((HANDLE*)&local_handle, sizeof(HANDLE));
     marshal_VkMemoryWin32HandlePropertiesKHR(stream, (VkMemoryWin32HandlePropertiesKHR*)(pMemoryWin32HandleProperties));
@@ -15045,6 +15371,7 @@
     const VkMemoryGetFdInfoKHR* pGetFdInfo,
     int* pFd)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkGetMemoryFdKHR encode");
     mImpl->log("start vkGetMemoryFdKHR");
     auto stream = mImpl->stream();
@@ -15067,9 +15394,9 @@
     }
     countingStream->rewind();
     {
-        uint64_t cgen_var_1023;
-        countingStream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_1023, 1);
-        countingStream->write((uint64_t*)&cgen_var_1023, 1 * 8);
+        uint64_t cgen_var_1027;
+        countingStream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_1027, 1);
+        countingStream->write((uint64_t*)&cgen_var_1027, 1 * 8);
         marshal_VkMemoryGetFdInfoKHR(countingStream, (VkMemoryGetFdInfoKHR*)(local_pGetFdInfo));
         countingStream->write((int*)pFd, sizeof(int));
     }
@@ -15078,9 +15405,9 @@
     uint32_t opcode_vkGetMemoryFdKHR = OP_vkGetMemoryFdKHR;
     stream->write(&opcode_vkGetMemoryFdKHR, sizeof(uint32_t));
     stream->write(&packetSize_vkGetMemoryFdKHR, sizeof(uint32_t));
-    uint64_t cgen_var_1024;
-    stream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_1024, 1);
-    stream->write((uint64_t*)&cgen_var_1024, 1 * 8);
+    uint64_t cgen_var_1028;
+    stream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_1028, 1);
+    stream->write((uint64_t*)&cgen_var_1028, 1 * 8);
     marshal_VkMemoryGetFdInfoKHR(stream, (VkMemoryGetFdInfoKHR*)(local_pGetFdInfo));
     stream->write((int*)pFd, sizeof(int));
     AEMU_SCOPED_TRACE("vkGetMemoryFdKHR readParams");
@@ -15101,6 +15428,7 @@
     int fd,
     VkMemoryFdPropertiesKHR* pMemoryFdProperties)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkGetMemoryFdPropertiesKHR encode");
     mImpl->log("start vkGetMemoryFdPropertiesKHR");
     auto stream = mImpl->stream();
@@ -15116,9 +15444,9 @@
     local_fd = fd;
     countingStream->rewind();
     {
-        uint64_t cgen_var_1025;
-        countingStream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_1025, 1);
-        countingStream->write((uint64_t*)&cgen_var_1025, 1 * 8);
+        uint64_t cgen_var_1029;
+        countingStream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_1029, 1);
+        countingStream->write((uint64_t*)&cgen_var_1029, 1 * 8);
         countingStream->write((VkExternalMemoryHandleTypeFlagBits*)&local_handleType, sizeof(VkExternalMemoryHandleTypeFlagBits));
         countingStream->write((int*)&local_fd, sizeof(int));
         marshal_VkMemoryFdPropertiesKHR(countingStream, (VkMemoryFdPropertiesKHR*)(pMemoryFdProperties));
@@ -15128,9 +15456,9 @@
     uint32_t opcode_vkGetMemoryFdPropertiesKHR = OP_vkGetMemoryFdPropertiesKHR;
     stream->write(&opcode_vkGetMemoryFdPropertiesKHR, sizeof(uint32_t));
     stream->write(&packetSize_vkGetMemoryFdPropertiesKHR, sizeof(uint32_t));
-    uint64_t cgen_var_1026;
-    stream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_1026, 1);
-    stream->write((uint64_t*)&cgen_var_1026, 1 * 8);
+    uint64_t cgen_var_1030;
+    stream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_1030, 1);
+    stream->write((uint64_t*)&cgen_var_1030, 1 * 8);
     stream->write((VkExternalMemoryHandleTypeFlagBits*)&local_handleType, sizeof(VkExternalMemoryHandleTypeFlagBits));
     stream->write((int*)&local_fd, sizeof(int));
     marshal_VkMemoryFdPropertiesKHR(stream, (VkMemoryFdPropertiesKHR*)(pMemoryFdProperties));
@@ -15159,6 +15487,7 @@
     const VkPhysicalDeviceExternalSemaphoreInfo* pExternalSemaphoreInfo,
     VkExternalSemaphoreProperties* pExternalSemaphoreProperties)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkGetPhysicalDeviceExternalSemaphorePropertiesKHR encode");
     mImpl->log("start vkGetPhysicalDeviceExternalSemaphorePropertiesKHR");
     auto stream = mImpl->stream();
@@ -15181,9 +15510,9 @@
     }
     countingStream->rewind();
     {
-        uint64_t cgen_var_1027;
-        countingStream->handleMapping()->mapHandles_VkPhysicalDevice_u64(&local_physicalDevice, &cgen_var_1027, 1);
-        countingStream->write((uint64_t*)&cgen_var_1027, 1 * 8);
+        uint64_t cgen_var_1031;
+        countingStream->handleMapping()->mapHandles_VkPhysicalDevice_u64(&local_physicalDevice, &cgen_var_1031, 1);
+        countingStream->write((uint64_t*)&cgen_var_1031, 1 * 8);
         marshal_VkPhysicalDeviceExternalSemaphoreInfo(countingStream, (VkPhysicalDeviceExternalSemaphoreInfo*)(local_pExternalSemaphoreInfo));
         marshal_VkExternalSemaphoreProperties(countingStream, (VkExternalSemaphoreProperties*)(pExternalSemaphoreProperties));
     }
@@ -15192,9 +15521,9 @@
     uint32_t opcode_vkGetPhysicalDeviceExternalSemaphorePropertiesKHR = OP_vkGetPhysicalDeviceExternalSemaphorePropertiesKHR;
     stream->write(&opcode_vkGetPhysicalDeviceExternalSemaphorePropertiesKHR, sizeof(uint32_t));
     stream->write(&packetSize_vkGetPhysicalDeviceExternalSemaphorePropertiesKHR, sizeof(uint32_t));
-    uint64_t cgen_var_1028;
-    stream->handleMapping()->mapHandles_VkPhysicalDevice_u64(&local_physicalDevice, &cgen_var_1028, 1);
-    stream->write((uint64_t*)&cgen_var_1028, 1 * 8);
+    uint64_t cgen_var_1032;
+    stream->handleMapping()->mapHandles_VkPhysicalDevice_u64(&local_physicalDevice, &cgen_var_1032, 1);
+    stream->write((uint64_t*)&cgen_var_1032, 1 * 8);
     marshal_VkPhysicalDeviceExternalSemaphoreInfo(stream, (VkPhysicalDeviceExternalSemaphoreInfo*)(local_pExternalSemaphoreInfo));
     marshal_VkExternalSemaphoreProperties(stream, (VkExternalSemaphoreProperties*)(pExternalSemaphoreProperties));
     AEMU_SCOPED_TRACE("vkGetPhysicalDeviceExternalSemaphorePropertiesKHR readParams");
@@ -15215,6 +15544,7 @@
     VkDevice device,
     const VkImportSemaphoreWin32HandleInfoKHR* pImportSemaphoreWin32HandleInfo)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkImportSemaphoreWin32HandleKHR encode");
     mImpl->log("start vkImportSemaphoreWin32HandleKHR");
     auto stream = mImpl->stream();
@@ -15237,9 +15567,9 @@
     }
     countingStream->rewind();
     {
-        uint64_t cgen_var_1029;
-        countingStream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_1029, 1);
-        countingStream->write((uint64_t*)&cgen_var_1029, 1 * 8);
+        uint64_t cgen_var_1033;
+        countingStream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_1033, 1);
+        countingStream->write((uint64_t*)&cgen_var_1033, 1 * 8);
         marshal_VkImportSemaphoreWin32HandleInfoKHR(countingStream, (VkImportSemaphoreWin32HandleInfoKHR*)(local_pImportSemaphoreWin32HandleInfo));
     }
     uint32_t packetSize_vkImportSemaphoreWin32HandleKHR = 4 + 4 + (uint32_t)countingStream->bytesWritten();
@@ -15247,9 +15577,9 @@
     uint32_t opcode_vkImportSemaphoreWin32HandleKHR = OP_vkImportSemaphoreWin32HandleKHR;
     stream->write(&opcode_vkImportSemaphoreWin32HandleKHR, sizeof(uint32_t));
     stream->write(&packetSize_vkImportSemaphoreWin32HandleKHR, sizeof(uint32_t));
-    uint64_t cgen_var_1030;
-    stream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_1030, 1);
-    stream->write((uint64_t*)&cgen_var_1030, 1 * 8);
+    uint64_t cgen_var_1034;
+    stream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_1034, 1);
+    stream->write((uint64_t*)&cgen_var_1034, 1 * 8);
     marshal_VkImportSemaphoreWin32HandleInfoKHR(stream, (VkImportSemaphoreWin32HandleInfoKHR*)(local_pImportSemaphoreWin32HandleInfo));
     AEMU_SCOPED_TRACE("vkImportSemaphoreWin32HandleKHR readParams");
     AEMU_SCOPED_TRACE("vkImportSemaphoreWin32HandleKHR returnUnmarshal");
@@ -15267,6 +15597,7 @@
     const VkSemaphoreGetWin32HandleInfoKHR* pGetWin32HandleInfo,
     HANDLE* pHandle)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkGetSemaphoreWin32HandleKHR encode");
     mImpl->log("start vkGetSemaphoreWin32HandleKHR");
     auto stream = mImpl->stream();
@@ -15289,9 +15620,9 @@
     }
     countingStream->rewind();
     {
-        uint64_t cgen_var_1031;
-        countingStream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_1031, 1);
-        countingStream->write((uint64_t*)&cgen_var_1031, 1 * 8);
+        uint64_t cgen_var_1035;
+        countingStream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_1035, 1);
+        countingStream->write((uint64_t*)&cgen_var_1035, 1 * 8);
         marshal_VkSemaphoreGetWin32HandleInfoKHR(countingStream, (VkSemaphoreGetWin32HandleInfoKHR*)(local_pGetWin32HandleInfo));
         countingStream->write((HANDLE*)pHandle, sizeof(HANDLE));
     }
@@ -15300,9 +15631,9 @@
     uint32_t opcode_vkGetSemaphoreWin32HandleKHR = OP_vkGetSemaphoreWin32HandleKHR;
     stream->write(&opcode_vkGetSemaphoreWin32HandleKHR, sizeof(uint32_t));
     stream->write(&packetSize_vkGetSemaphoreWin32HandleKHR, sizeof(uint32_t));
-    uint64_t cgen_var_1032;
-    stream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_1032, 1);
-    stream->write((uint64_t*)&cgen_var_1032, 1 * 8);
+    uint64_t cgen_var_1036;
+    stream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_1036, 1);
+    stream->write((uint64_t*)&cgen_var_1036, 1 * 8);
     marshal_VkSemaphoreGetWin32HandleInfoKHR(stream, (VkSemaphoreGetWin32HandleInfoKHR*)(local_pGetWin32HandleInfo));
     stream->write((HANDLE*)pHandle, sizeof(HANDLE));
     AEMU_SCOPED_TRACE("vkGetSemaphoreWin32HandleKHR readParams");
@@ -15323,6 +15654,7 @@
     VkDevice device,
     const VkImportSemaphoreFdInfoKHR* pImportSemaphoreFdInfo)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkImportSemaphoreFdKHR encode");
     mImpl->log("start vkImportSemaphoreFdKHR");
     auto stream = mImpl->stream();
@@ -15345,9 +15677,9 @@
     }
     countingStream->rewind();
     {
-        uint64_t cgen_var_1033;
-        countingStream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_1033, 1);
-        countingStream->write((uint64_t*)&cgen_var_1033, 1 * 8);
+        uint64_t cgen_var_1037;
+        countingStream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_1037, 1);
+        countingStream->write((uint64_t*)&cgen_var_1037, 1 * 8);
         marshal_VkImportSemaphoreFdInfoKHR(countingStream, (VkImportSemaphoreFdInfoKHR*)(local_pImportSemaphoreFdInfo));
     }
     uint32_t packetSize_vkImportSemaphoreFdKHR = 4 + 4 + (uint32_t)countingStream->bytesWritten();
@@ -15355,9 +15687,9 @@
     uint32_t opcode_vkImportSemaphoreFdKHR = OP_vkImportSemaphoreFdKHR;
     stream->write(&opcode_vkImportSemaphoreFdKHR, sizeof(uint32_t));
     stream->write(&packetSize_vkImportSemaphoreFdKHR, sizeof(uint32_t));
-    uint64_t cgen_var_1034;
-    stream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_1034, 1);
-    stream->write((uint64_t*)&cgen_var_1034, 1 * 8);
+    uint64_t cgen_var_1038;
+    stream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_1038, 1);
+    stream->write((uint64_t*)&cgen_var_1038, 1 * 8);
     marshal_VkImportSemaphoreFdInfoKHR(stream, (VkImportSemaphoreFdInfoKHR*)(local_pImportSemaphoreFdInfo));
     AEMU_SCOPED_TRACE("vkImportSemaphoreFdKHR readParams");
     AEMU_SCOPED_TRACE("vkImportSemaphoreFdKHR returnUnmarshal");
@@ -15375,6 +15707,7 @@
     const VkSemaphoreGetFdInfoKHR* pGetFdInfo,
     int* pFd)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkGetSemaphoreFdKHR encode");
     mImpl->log("start vkGetSemaphoreFdKHR");
     auto stream = mImpl->stream();
@@ -15397,9 +15730,9 @@
     }
     countingStream->rewind();
     {
-        uint64_t cgen_var_1035;
-        countingStream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_1035, 1);
-        countingStream->write((uint64_t*)&cgen_var_1035, 1 * 8);
+        uint64_t cgen_var_1039;
+        countingStream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_1039, 1);
+        countingStream->write((uint64_t*)&cgen_var_1039, 1 * 8);
         marshal_VkSemaphoreGetFdInfoKHR(countingStream, (VkSemaphoreGetFdInfoKHR*)(local_pGetFdInfo));
         countingStream->write((int*)pFd, sizeof(int));
     }
@@ -15408,9 +15741,9 @@
     uint32_t opcode_vkGetSemaphoreFdKHR = OP_vkGetSemaphoreFdKHR;
     stream->write(&opcode_vkGetSemaphoreFdKHR, sizeof(uint32_t));
     stream->write(&packetSize_vkGetSemaphoreFdKHR, sizeof(uint32_t));
-    uint64_t cgen_var_1036;
-    stream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_1036, 1);
-    stream->write((uint64_t*)&cgen_var_1036, 1 * 8);
+    uint64_t cgen_var_1040;
+    stream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_1040, 1);
+    stream->write((uint64_t*)&cgen_var_1040, 1 * 8);
     marshal_VkSemaphoreGetFdInfoKHR(stream, (VkSemaphoreGetFdInfoKHR*)(local_pGetFdInfo));
     stream->write((int*)pFd, sizeof(int));
     AEMU_SCOPED_TRACE("vkGetSemaphoreFdKHR readParams");
@@ -15435,6 +15768,7 @@
     uint32_t descriptorWriteCount,
     const VkWriteDescriptorSet* pDescriptorWrites)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkCmdPushDescriptorSetKHR encode");
     mImpl->log("start vkCmdPushDescriptorSetKHR");
     auto stream = mImpl->stream();
@@ -15471,13 +15805,13 @@
     }
     countingStream->rewind();
     {
-        uint64_t cgen_var_1037;
-        countingStream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_1037, 1);
-        countingStream->write((uint64_t*)&cgen_var_1037, 1 * 8);
+        uint64_t cgen_var_1041;
+        countingStream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_1041, 1);
+        countingStream->write((uint64_t*)&cgen_var_1041, 1 * 8);
         countingStream->write((VkPipelineBindPoint*)&local_pipelineBindPoint, sizeof(VkPipelineBindPoint));
-        uint64_t cgen_var_1038;
-        countingStream->handleMapping()->mapHandles_VkPipelineLayout_u64(&local_layout, &cgen_var_1038, 1);
-        countingStream->write((uint64_t*)&cgen_var_1038, 1 * 8);
+        uint64_t cgen_var_1042;
+        countingStream->handleMapping()->mapHandles_VkPipelineLayout_u64(&local_layout, &cgen_var_1042, 1);
+        countingStream->write((uint64_t*)&cgen_var_1042, 1 * 8);
         countingStream->write((uint32_t*)&local_set, sizeof(uint32_t));
         countingStream->write((uint32_t*)&local_descriptorWriteCount, sizeof(uint32_t));
         for (uint32_t i = 0; i < (uint32_t)((descriptorWriteCount)); ++i)
@@ -15490,13 +15824,13 @@
     uint32_t opcode_vkCmdPushDescriptorSetKHR = OP_vkCmdPushDescriptorSetKHR;
     stream->write(&opcode_vkCmdPushDescriptorSetKHR, sizeof(uint32_t));
     stream->write(&packetSize_vkCmdPushDescriptorSetKHR, sizeof(uint32_t));
-    uint64_t cgen_var_1039;
-    stream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_1039, 1);
-    stream->write((uint64_t*)&cgen_var_1039, 1 * 8);
+    uint64_t cgen_var_1043;
+    stream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_1043, 1);
+    stream->write((uint64_t*)&cgen_var_1043, 1 * 8);
     stream->write((VkPipelineBindPoint*)&local_pipelineBindPoint, sizeof(VkPipelineBindPoint));
-    uint64_t cgen_var_1040;
-    stream->handleMapping()->mapHandles_VkPipelineLayout_u64(&local_layout, &cgen_var_1040, 1);
-    stream->write((uint64_t*)&cgen_var_1040, 1 * 8);
+    uint64_t cgen_var_1044;
+    stream->handleMapping()->mapHandles_VkPipelineLayout_u64(&local_layout, &cgen_var_1044, 1);
+    stream->write((uint64_t*)&cgen_var_1044, 1 * 8);
     stream->write((uint32_t*)&local_set, sizeof(uint32_t));
     stream->write((uint32_t*)&local_descriptorWriteCount, sizeof(uint32_t));
     for (uint32_t i = 0; i < (uint32_t)((descriptorWriteCount)); ++i)
@@ -15515,6 +15849,7 @@
     uint32_t set,
     const void* pData)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkCmdPushDescriptorSetWithTemplateKHR encode");
     mImpl->log("start vkCmdPushDescriptorSetWithTemplateKHR");
     auto stream = mImpl->stream();
@@ -15538,19 +15873,19 @@
     }
     countingStream->rewind();
     {
-        uint64_t cgen_var_1041;
-        countingStream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_1041, 1);
-        countingStream->write((uint64_t*)&cgen_var_1041, 1 * 8);
-        uint64_t cgen_var_1042;
-        countingStream->handleMapping()->mapHandles_VkDescriptorUpdateTemplate_u64(&local_descriptorUpdateTemplate, &cgen_var_1042, 1);
-        countingStream->write((uint64_t*)&cgen_var_1042, 1 * 8);
-        uint64_t cgen_var_1043;
-        countingStream->handleMapping()->mapHandles_VkPipelineLayout_u64(&local_layout, &cgen_var_1043, 1);
-        countingStream->write((uint64_t*)&cgen_var_1043, 1 * 8);
+        uint64_t cgen_var_1045;
+        countingStream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_1045, 1);
+        countingStream->write((uint64_t*)&cgen_var_1045, 1 * 8);
+        uint64_t cgen_var_1046;
+        countingStream->handleMapping()->mapHandles_VkDescriptorUpdateTemplate_u64(&local_descriptorUpdateTemplate, &cgen_var_1046, 1);
+        countingStream->write((uint64_t*)&cgen_var_1046, 1 * 8);
+        uint64_t cgen_var_1047;
+        countingStream->handleMapping()->mapHandles_VkPipelineLayout_u64(&local_layout, &cgen_var_1047, 1);
+        countingStream->write((uint64_t*)&cgen_var_1047, 1 * 8);
         countingStream->write((uint32_t*)&local_set, sizeof(uint32_t));
         // WARNING PTR CHECK
-        uint64_t cgen_var_1044 = (uint64_t)(uintptr_t)local_pData;
-        countingStream->putBe64(cgen_var_1044);
+        uint64_t cgen_var_1048 = (uint64_t)(uintptr_t)local_pData;
+        countingStream->putBe64(cgen_var_1048);
         if (local_pData)
         {
             countingStream->write((void*)local_pData, sizeof(uint8_t));
@@ -15561,19 +15896,19 @@
     uint32_t opcode_vkCmdPushDescriptorSetWithTemplateKHR = OP_vkCmdPushDescriptorSetWithTemplateKHR;
     stream->write(&opcode_vkCmdPushDescriptorSetWithTemplateKHR, sizeof(uint32_t));
     stream->write(&packetSize_vkCmdPushDescriptorSetWithTemplateKHR, sizeof(uint32_t));
-    uint64_t cgen_var_1045;
-    stream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_1045, 1);
-    stream->write((uint64_t*)&cgen_var_1045, 1 * 8);
-    uint64_t cgen_var_1046;
-    stream->handleMapping()->mapHandles_VkDescriptorUpdateTemplate_u64(&local_descriptorUpdateTemplate, &cgen_var_1046, 1);
-    stream->write((uint64_t*)&cgen_var_1046, 1 * 8);
-    uint64_t cgen_var_1047;
-    stream->handleMapping()->mapHandles_VkPipelineLayout_u64(&local_layout, &cgen_var_1047, 1);
-    stream->write((uint64_t*)&cgen_var_1047, 1 * 8);
+    uint64_t cgen_var_1049;
+    stream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_1049, 1);
+    stream->write((uint64_t*)&cgen_var_1049, 1 * 8);
+    uint64_t cgen_var_1050;
+    stream->handleMapping()->mapHandles_VkDescriptorUpdateTemplate_u64(&local_descriptorUpdateTemplate, &cgen_var_1050, 1);
+    stream->write((uint64_t*)&cgen_var_1050, 1 * 8);
+    uint64_t cgen_var_1051;
+    stream->handleMapping()->mapHandles_VkPipelineLayout_u64(&local_layout, &cgen_var_1051, 1);
+    stream->write((uint64_t*)&cgen_var_1051, 1 * 8);
     stream->write((uint32_t*)&local_set, sizeof(uint32_t));
     // WARNING PTR CHECK
-    uint64_t cgen_var_1048 = (uint64_t)(uintptr_t)local_pData;
-    stream->putBe64(cgen_var_1048);
+    uint64_t cgen_var_1052 = (uint64_t)(uintptr_t)local_pData;
+    stream->putBe64(cgen_var_1052);
     if (local_pData)
     {
         stream->write((void*)local_pData, sizeof(uint8_t));
@@ -15595,6 +15930,7 @@
     const VkAllocationCallbacks* pAllocator,
     VkDescriptorUpdateTemplate* pDescriptorUpdateTemplate)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkCreateDescriptorUpdateTemplateKHR encode");
     mImpl->log("start vkCreateDescriptorUpdateTemplateKHR");
     auto stream = mImpl->stream();
@@ -15629,47 +15965,47 @@
     }
     countingStream->rewind();
     {
-        uint64_t cgen_var_1049;
-        countingStream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_1049, 1);
-        countingStream->write((uint64_t*)&cgen_var_1049, 1 * 8);
+        uint64_t cgen_var_1053;
+        countingStream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_1053, 1);
+        countingStream->write((uint64_t*)&cgen_var_1053, 1 * 8);
         marshal_VkDescriptorUpdateTemplateCreateInfo(countingStream, (VkDescriptorUpdateTemplateCreateInfo*)(local_pCreateInfo));
         // WARNING PTR CHECK
-        uint64_t cgen_var_1050 = (uint64_t)(uintptr_t)local_pAllocator;
-        countingStream->putBe64(cgen_var_1050);
+        uint64_t cgen_var_1054 = (uint64_t)(uintptr_t)local_pAllocator;
+        countingStream->putBe64(cgen_var_1054);
         if (local_pAllocator)
         {
             marshal_VkAllocationCallbacks(countingStream, (VkAllocationCallbacks*)(local_pAllocator));
         }
-        uint64_t cgen_var_1051;
-        countingStream->handleMapping()->mapHandles_VkDescriptorUpdateTemplate_u64(pDescriptorUpdateTemplate, &cgen_var_1051, 1);
-        countingStream->write((uint64_t*)&cgen_var_1051, 8);
+        uint64_t cgen_var_1055;
+        countingStream->handleMapping()->mapHandles_VkDescriptorUpdateTemplate_u64(pDescriptorUpdateTemplate, &cgen_var_1055, 1);
+        countingStream->write((uint64_t*)&cgen_var_1055, 8);
     }
     uint32_t packetSize_vkCreateDescriptorUpdateTemplateKHR = 4 + 4 + (uint32_t)countingStream->bytesWritten();
     countingStream->rewind();
     uint32_t opcode_vkCreateDescriptorUpdateTemplateKHR = OP_vkCreateDescriptorUpdateTemplateKHR;
     stream->write(&opcode_vkCreateDescriptorUpdateTemplateKHR, sizeof(uint32_t));
     stream->write(&packetSize_vkCreateDescriptorUpdateTemplateKHR, sizeof(uint32_t));
-    uint64_t cgen_var_1052;
-    stream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_1052, 1);
-    stream->write((uint64_t*)&cgen_var_1052, 1 * 8);
+    uint64_t cgen_var_1056;
+    stream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_1056, 1);
+    stream->write((uint64_t*)&cgen_var_1056, 1 * 8);
     marshal_VkDescriptorUpdateTemplateCreateInfo(stream, (VkDescriptorUpdateTemplateCreateInfo*)(local_pCreateInfo));
     // WARNING PTR CHECK
-    uint64_t cgen_var_1053 = (uint64_t)(uintptr_t)local_pAllocator;
-    stream->putBe64(cgen_var_1053);
+    uint64_t cgen_var_1057 = (uint64_t)(uintptr_t)local_pAllocator;
+    stream->putBe64(cgen_var_1057);
     if (local_pAllocator)
     {
         marshal_VkAllocationCallbacks(stream, (VkAllocationCallbacks*)(local_pAllocator));
     }
     stream->unsetHandleMapping() /* emit_marshal, is handle, possibly out */;
-    uint64_t cgen_var_1054;
-    stream->handleMapping()->mapHandles_VkDescriptorUpdateTemplate_u64(pDescriptorUpdateTemplate, &cgen_var_1054, 1);
-    stream->write((uint64_t*)&cgen_var_1054, 8);
+    uint64_t cgen_var_1058;
+    stream->handleMapping()->mapHandles_VkDescriptorUpdateTemplate_u64(pDescriptorUpdateTemplate, &cgen_var_1058, 1);
+    stream->write((uint64_t*)&cgen_var_1058, 8);
     stream->setHandleMapping(resources->unwrapMapping());
     AEMU_SCOPED_TRACE("vkCreateDescriptorUpdateTemplateKHR readParams");
     stream->setHandleMapping(resources->createMapping());
-    uint64_t cgen_var_1055;
-    stream->read((uint64_t*)&cgen_var_1055, 8);
-    stream->handleMapping()->mapHandles_u64_VkDescriptorUpdateTemplate(&cgen_var_1055, (VkDescriptorUpdateTemplate*)pDescriptorUpdateTemplate, 1);
+    uint64_t cgen_var_1059;
+    stream->read((uint64_t*)&cgen_var_1059, 8);
+    stream->handleMapping()->mapHandles_u64_VkDescriptorUpdateTemplate(&cgen_var_1059, (VkDescriptorUpdateTemplate*)pDescriptorUpdateTemplate, 1);
     stream->unsetHandleMapping();
     AEMU_SCOPED_TRACE("vkCreateDescriptorUpdateTemplateKHR returnUnmarshal");
     VkResult vkCreateDescriptorUpdateTemplateKHR_VkResult_return = (VkResult)0;
@@ -15677,7 +16013,9 @@
     countingStream->clearPool();
     stream->clearPool();
     pool->freeAll();
+    encoderLock.unlock();
     mImpl->resources()->on_vkCreateDescriptorUpdateTemplateKHR(this, vkCreateDescriptorUpdateTemplateKHR_VkResult_return, device, pCreateInfo, pAllocator, pDescriptorUpdateTemplate);
+    encoderLock.lock();
     mImpl->log("finish vkCreateDescriptorUpdateTemplateKHR");;
     return vkCreateDescriptorUpdateTemplateKHR_VkResult_return;
 }
@@ -15687,6 +16025,7 @@
     VkDescriptorUpdateTemplate descriptorUpdateTemplate,
     const VkAllocationCallbacks* pAllocator)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkDestroyDescriptorUpdateTemplateKHR encode");
     mImpl->log("start vkDestroyDescriptorUpdateTemplateKHR");
     auto stream = mImpl->stream();
@@ -15712,15 +16051,15 @@
     }
     countingStream->rewind();
     {
-        uint64_t cgen_var_1056;
-        countingStream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_1056, 1);
-        countingStream->write((uint64_t*)&cgen_var_1056, 1 * 8);
-        uint64_t cgen_var_1057;
-        countingStream->handleMapping()->mapHandles_VkDescriptorUpdateTemplate_u64(&local_descriptorUpdateTemplate, &cgen_var_1057, 1);
-        countingStream->write((uint64_t*)&cgen_var_1057, 1 * 8);
+        uint64_t cgen_var_1060;
+        countingStream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_1060, 1);
+        countingStream->write((uint64_t*)&cgen_var_1060, 1 * 8);
+        uint64_t cgen_var_1061;
+        countingStream->handleMapping()->mapHandles_VkDescriptorUpdateTemplate_u64(&local_descriptorUpdateTemplate, &cgen_var_1061, 1);
+        countingStream->write((uint64_t*)&cgen_var_1061, 1 * 8);
         // WARNING PTR CHECK
-        uint64_t cgen_var_1058 = (uint64_t)(uintptr_t)local_pAllocator;
-        countingStream->putBe64(cgen_var_1058);
+        uint64_t cgen_var_1062 = (uint64_t)(uintptr_t)local_pAllocator;
+        countingStream->putBe64(cgen_var_1062);
         if (local_pAllocator)
         {
             marshal_VkAllocationCallbacks(countingStream, (VkAllocationCallbacks*)(local_pAllocator));
@@ -15731,15 +16070,15 @@
     uint32_t opcode_vkDestroyDescriptorUpdateTemplateKHR = OP_vkDestroyDescriptorUpdateTemplateKHR;
     stream->write(&opcode_vkDestroyDescriptorUpdateTemplateKHR, sizeof(uint32_t));
     stream->write(&packetSize_vkDestroyDescriptorUpdateTemplateKHR, sizeof(uint32_t));
-    uint64_t cgen_var_1059;
-    stream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_1059, 1);
-    stream->write((uint64_t*)&cgen_var_1059, 1 * 8);
-    uint64_t cgen_var_1060;
-    stream->handleMapping()->mapHandles_VkDescriptorUpdateTemplate_u64(&local_descriptorUpdateTemplate, &cgen_var_1060, 1);
-    stream->write((uint64_t*)&cgen_var_1060, 1 * 8);
+    uint64_t cgen_var_1063;
+    stream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_1063, 1);
+    stream->write((uint64_t*)&cgen_var_1063, 1 * 8);
+    uint64_t cgen_var_1064;
+    stream->handleMapping()->mapHandles_VkDescriptorUpdateTemplate_u64(&local_descriptorUpdateTemplate, &cgen_var_1064, 1);
+    stream->write((uint64_t*)&cgen_var_1064, 1 * 8);
     // WARNING PTR CHECK
-    uint64_t cgen_var_1061 = (uint64_t)(uintptr_t)local_pAllocator;
-    stream->putBe64(cgen_var_1061);
+    uint64_t cgen_var_1065 = (uint64_t)(uintptr_t)local_pAllocator;
+    stream->putBe64(cgen_var_1065);
     if (local_pAllocator)
     {
         marshal_VkAllocationCallbacks(stream, (VkAllocationCallbacks*)(local_pAllocator));
@@ -15756,6 +16095,7 @@
     VkDescriptorUpdateTemplate descriptorUpdateTemplate,
     const void* pData)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkUpdateDescriptorSetWithTemplateKHR encode");
     mImpl->log("start vkUpdateDescriptorSetWithTemplateKHR");
     auto stream = mImpl->stream();
@@ -15777,18 +16117,18 @@
     }
     countingStream->rewind();
     {
-        uint64_t cgen_var_1062;
-        countingStream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_1062, 1);
-        countingStream->write((uint64_t*)&cgen_var_1062, 1 * 8);
-        uint64_t cgen_var_1063;
-        countingStream->handleMapping()->mapHandles_VkDescriptorSet_u64(&local_descriptorSet, &cgen_var_1063, 1);
-        countingStream->write((uint64_t*)&cgen_var_1063, 1 * 8);
-        uint64_t cgen_var_1064;
-        countingStream->handleMapping()->mapHandles_VkDescriptorUpdateTemplate_u64(&local_descriptorUpdateTemplate, &cgen_var_1064, 1);
-        countingStream->write((uint64_t*)&cgen_var_1064, 1 * 8);
+        uint64_t cgen_var_1066;
+        countingStream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_1066, 1);
+        countingStream->write((uint64_t*)&cgen_var_1066, 1 * 8);
+        uint64_t cgen_var_1067;
+        countingStream->handleMapping()->mapHandles_VkDescriptorSet_u64(&local_descriptorSet, &cgen_var_1067, 1);
+        countingStream->write((uint64_t*)&cgen_var_1067, 1 * 8);
+        uint64_t cgen_var_1068;
+        countingStream->handleMapping()->mapHandles_VkDescriptorUpdateTemplate_u64(&local_descriptorUpdateTemplate, &cgen_var_1068, 1);
+        countingStream->write((uint64_t*)&cgen_var_1068, 1 * 8);
         // WARNING PTR CHECK
-        uint64_t cgen_var_1065 = (uint64_t)(uintptr_t)local_pData;
-        countingStream->putBe64(cgen_var_1065);
+        uint64_t cgen_var_1069 = (uint64_t)(uintptr_t)local_pData;
+        countingStream->putBe64(cgen_var_1069);
         if (local_pData)
         {
             countingStream->write((void*)local_pData, sizeof(uint8_t));
@@ -15799,18 +16139,18 @@
     uint32_t opcode_vkUpdateDescriptorSetWithTemplateKHR = OP_vkUpdateDescriptorSetWithTemplateKHR;
     stream->write(&opcode_vkUpdateDescriptorSetWithTemplateKHR, sizeof(uint32_t));
     stream->write(&packetSize_vkUpdateDescriptorSetWithTemplateKHR, sizeof(uint32_t));
-    uint64_t cgen_var_1066;
-    stream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_1066, 1);
-    stream->write((uint64_t*)&cgen_var_1066, 1 * 8);
-    uint64_t cgen_var_1067;
-    stream->handleMapping()->mapHandles_VkDescriptorSet_u64(&local_descriptorSet, &cgen_var_1067, 1);
-    stream->write((uint64_t*)&cgen_var_1067, 1 * 8);
-    uint64_t cgen_var_1068;
-    stream->handleMapping()->mapHandles_VkDescriptorUpdateTemplate_u64(&local_descriptorUpdateTemplate, &cgen_var_1068, 1);
-    stream->write((uint64_t*)&cgen_var_1068, 1 * 8);
+    uint64_t cgen_var_1070;
+    stream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_1070, 1);
+    stream->write((uint64_t*)&cgen_var_1070, 1 * 8);
+    uint64_t cgen_var_1071;
+    stream->handleMapping()->mapHandles_VkDescriptorSet_u64(&local_descriptorSet, &cgen_var_1071, 1);
+    stream->write((uint64_t*)&cgen_var_1071, 1 * 8);
+    uint64_t cgen_var_1072;
+    stream->handleMapping()->mapHandles_VkDescriptorUpdateTemplate_u64(&local_descriptorUpdateTemplate, &cgen_var_1072, 1);
+    stream->write((uint64_t*)&cgen_var_1072, 1 * 8);
     // WARNING PTR CHECK
-    uint64_t cgen_var_1069 = (uint64_t)(uintptr_t)local_pData;
-    stream->putBe64(cgen_var_1069);
+    uint64_t cgen_var_1073 = (uint64_t)(uintptr_t)local_pData;
+    stream->putBe64(cgen_var_1073);
     if (local_pData)
     {
         stream->write((void*)local_pData, sizeof(uint8_t));
@@ -15828,6 +16168,7 @@
     const VkAllocationCallbacks* pAllocator,
     VkRenderPass* pRenderPass)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkCreateRenderPass2KHR encode");
     mImpl->log("start vkCreateRenderPass2KHR");
     auto stream = mImpl->stream();
@@ -15862,46 +16203,46 @@
     }
     countingStream->rewind();
     {
-        uint64_t cgen_var_1070;
-        countingStream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_1070, 1);
-        countingStream->write((uint64_t*)&cgen_var_1070, 1 * 8);
+        uint64_t cgen_var_1074;
+        countingStream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_1074, 1);
+        countingStream->write((uint64_t*)&cgen_var_1074, 1 * 8);
         marshal_VkRenderPassCreateInfo2KHR(countingStream, (VkRenderPassCreateInfo2KHR*)(local_pCreateInfo));
         // WARNING PTR CHECK
-        uint64_t cgen_var_1071 = (uint64_t)(uintptr_t)local_pAllocator;
-        countingStream->putBe64(cgen_var_1071);
+        uint64_t cgen_var_1075 = (uint64_t)(uintptr_t)local_pAllocator;
+        countingStream->putBe64(cgen_var_1075);
         if (local_pAllocator)
         {
             marshal_VkAllocationCallbacks(countingStream, (VkAllocationCallbacks*)(local_pAllocator));
         }
-        uint64_t cgen_var_1072;
-        countingStream->handleMapping()->mapHandles_VkRenderPass_u64(pRenderPass, &cgen_var_1072, 1);
-        countingStream->write((uint64_t*)&cgen_var_1072, 8);
+        uint64_t cgen_var_1076;
+        countingStream->handleMapping()->mapHandles_VkRenderPass_u64(pRenderPass, &cgen_var_1076, 1);
+        countingStream->write((uint64_t*)&cgen_var_1076, 8);
     }
     uint32_t packetSize_vkCreateRenderPass2KHR = 4 + 4 + (uint32_t)countingStream->bytesWritten();
     countingStream->rewind();
     uint32_t opcode_vkCreateRenderPass2KHR = OP_vkCreateRenderPass2KHR;
     stream->write(&opcode_vkCreateRenderPass2KHR, sizeof(uint32_t));
     stream->write(&packetSize_vkCreateRenderPass2KHR, sizeof(uint32_t));
-    uint64_t cgen_var_1073;
-    stream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_1073, 1);
-    stream->write((uint64_t*)&cgen_var_1073, 1 * 8);
+    uint64_t cgen_var_1077;
+    stream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_1077, 1);
+    stream->write((uint64_t*)&cgen_var_1077, 1 * 8);
     marshal_VkRenderPassCreateInfo2KHR(stream, (VkRenderPassCreateInfo2KHR*)(local_pCreateInfo));
     // WARNING PTR CHECK
-    uint64_t cgen_var_1074 = (uint64_t)(uintptr_t)local_pAllocator;
-    stream->putBe64(cgen_var_1074);
+    uint64_t cgen_var_1078 = (uint64_t)(uintptr_t)local_pAllocator;
+    stream->putBe64(cgen_var_1078);
     if (local_pAllocator)
     {
         marshal_VkAllocationCallbacks(stream, (VkAllocationCallbacks*)(local_pAllocator));
     }
     stream->unsetHandleMapping() /* emit_marshal, is handle, possibly out */;
-    uint64_t cgen_var_1075;
-    stream->handleMapping()->mapHandles_VkRenderPass_u64(pRenderPass, &cgen_var_1075, 1);
-    stream->write((uint64_t*)&cgen_var_1075, 8);
+    uint64_t cgen_var_1079;
+    stream->handleMapping()->mapHandles_VkRenderPass_u64(pRenderPass, &cgen_var_1079, 1);
+    stream->write((uint64_t*)&cgen_var_1079, 8);
     stream->setHandleMapping(resources->unwrapMapping());
     AEMU_SCOPED_TRACE("vkCreateRenderPass2KHR readParams");
-    uint64_t cgen_var_1076;
-    stream->read((uint64_t*)&cgen_var_1076, 8);
-    stream->handleMapping()->mapHandles_u64_VkRenderPass(&cgen_var_1076, (VkRenderPass*)pRenderPass, 1);
+    uint64_t cgen_var_1080;
+    stream->read((uint64_t*)&cgen_var_1080, 8);
+    stream->handleMapping()->mapHandles_u64_VkRenderPass(&cgen_var_1080, (VkRenderPass*)pRenderPass, 1);
     AEMU_SCOPED_TRACE("vkCreateRenderPass2KHR returnUnmarshal");
     VkResult vkCreateRenderPass2KHR_VkResult_return = (VkResult)0;
     stream->read(&vkCreateRenderPass2KHR_VkResult_return, sizeof(VkResult));
@@ -15917,6 +16258,7 @@
     const VkRenderPassBeginInfo* pRenderPassBegin,
     const VkSubpassBeginInfoKHR* pSubpassBeginInfo)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkCmdBeginRenderPass2KHR encode");
     mImpl->log("start vkCmdBeginRenderPass2KHR");
     auto stream = mImpl->stream();
@@ -15950,9 +16292,9 @@
     }
     countingStream->rewind();
     {
-        uint64_t cgen_var_1077;
-        countingStream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_1077, 1);
-        countingStream->write((uint64_t*)&cgen_var_1077, 1 * 8);
+        uint64_t cgen_var_1081;
+        countingStream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_1081, 1);
+        countingStream->write((uint64_t*)&cgen_var_1081, 1 * 8);
         marshal_VkRenderPassBeginInfo(countingStream, (VkRenderPassBeginInfo*)(local_pRenderPassBegin));
         marshal_VkSubpassBeginInfoKHR(countingStream, (VkSubpassBeginInfoKHR*)(local_pSubpassBeginInfo));
     }
@@ -15961,9 +16303,9 @@
     uint32_t opcode_vkCmdBeginRenderPass2KHR = OP_vkCmdBeginRenderPass2KHR;
     stream->write(&opcode_vkCmdBeginRenderPass2KHR, sizeof(uint32_t));
     stream->write(&packetSize_vkCmdBeginRenderPass2KHR, sizeof(uint32_t));
-    uint64_t cgen_var_1078;
-    stream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_1078, 1);
-    stream->write((uint64_t*)&cgen_var_1078, 1 * 8);
+    uint64_t cgen_var_1082;
+    stream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_1082, 1);
+    stream->write((uint64_t*)&cgen_var_1082, 1 * 8);
     marshal_VkRenderPassBeginInfo(stream, (VkRenderPassBeginInfo*)(local_pRenderPassBegin));
     marshal_VkSubpassBeginInfoKHR(stream, (VkSubpassBeginInfoKHR*)(local_pSubpassBeginInfo));
     AEMU_SCOPED_TRACE("vkCmdBeginRenderPass2KHR readParams");
@@ -15976,6 +16318,7 @@
     const VkSubpassBeginInfoKHR* pSubpassBeginInfo,
     const VkSubpassEndInfoKHR* pSubpassEndInfo)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkCmdNextSubpass2KHR encode");
     mImpl->log("start vkCmdNextSubpass2KHR");
     auto stream = mImpl->stream();
@@ -16009,9 +16352,9 @@
     }
     countingStream->rewind();
     {
-        uint64_t cgen_var_1079;
-        countingStream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_1079, 1);
-        countingStream->write((uint64_t*)&cgen_var_1079, 1 * 8);
+        uint64_t cgen_var_1083;
+        countingStream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_1083, 1);
+        countingStream->write((uint64_t*)&cgen_var_1083, 1 * 8);
         marshal_VkSubpassBeginInfoKHR(countingStream, (VkSubpassBeginInfoKHR*)(local_pSubpassBeginInfo));
         marshal_VkSubpassEndInfoKHR(countingStream, (VkSubpassEndInfoKHR*)(local_pSubpassEndInfo));
     }
@@ -16020,9 +16363,9 @@
     uint32_t opcode_vkCmdNextSubpass2KHR = OP_vkCmdNextSubpass2KHR;
     stream->write(&opcode_vkCmdNextSubpass2KHR, sizeof(uint32_t));
     stream->write(&packetSize_vkCmdNextSubpass2KHR, sizeof(uint32_t));
-    uint64_t cgen_var_1080;
-    stream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_1080, 1);
-    stream->write((uint64_t*)&cgen_var_1080, 1 * 8);
+    uint64_t cgen_var_1084;
+    stream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_1084, 1);
+    stream->write((uint64_t*)&cgen_var_1084, 1 * 8);
     marshal_VkSubpassBeginInfoKHR(stream, (VkSubpassBeginInfoKHR*)(local_pSubpassBeginInfo));
     marshal_VkSubpassEndInfoKHR(stream, (VkSubpassEndInfoKHR*)(local_pSubpassEndInfo));
     AEMU_SCOPED_TRACE("vkCmdNextSubpass2KHR readParams");
@@ -16034,6 +16377,7 @@
     VkCommandBuffer commandBuffer,
     const VkSubpassEndInfoKHR* pSubpassEndInfo)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkCmdEndRenderPass2KHR encode");
     mImpl->log("start vkCmdEndRenderPass2KHR");
     auto stream = mImpl->stream();
@@ -16056,9 +16400,9 @@
     }
     countingStream->rewind();
     {
-        uint64_t cgen_var_1081;
-        countingStream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_1081, 1);
-        countingStream->write((uint64_t*)&cgen_var_1081, 1 * 8);
+        uint64_t cgen_var_1085;
+        countingStream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_1085, 1);
+        countingStream->write((uint64_t*)&cgen_var_1085, 1 * 8);
         marshal_VkSubpassEndInfoKHR(countingStream, (VkSubpassEndInfoKHR*)(local_pSubpassEndInfo));
     }
     uint32_t packetSize_vkCmdEndRenderPass2KHR = 4 + 4 + (uint32_t)countingStream->bytesWritten();
@@ -16066,9 +16410,9 @@
     uint32_t opcode_vkCmdEndRenderPass2KHR = OP_vkCmdEndRenderPass2KHR;
     stream->write(&opcode_vkCmdEndRenderPass2KHR, sizeof(uint32_t));
     stream->write(&packetSize_vkCmdEndRenderPass2KHR, sizeof(uint32_t));
-    uint64_t cgen_var_1082;
-    stream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_1082, 1);
-    stream->write((uint64_t*)&cgen_var_1082, 1 * 8);
+    uint64_t cgen_var_1086;
+    stream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_1086, 1);
+    stream->write((uint64_t*)&cgen_var_1086, 1 * 8);
     marshal_VkSubpassEndInfoKHR(stream, (VkSubpassEndInfoKHR*)(local_pSubpassEndInfo));
     AEMU_SCOPED_TRACE("vkCmdEndRenderPass2KHR readParams");
     AEMU_SCOPED_TRACE("vkCmdEndRenderPass2KHR returnUnmarshal");
@@ -16081,6 +16425,7 @@
     VkDevice device,
     VkSwapchainKHR swapchain)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkGetSwapchainStatusKHR encode");
     mImpl->log("start vkGetSwapchainStatusKHR");
     auto stream = mImpl->stream();
@@ -16094,24 +16439,24 @@
     local_swapchain = swapchain;
     countingStream->rewind();
     {
-        uint64_t cgen_var_1083;
-        countingStream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_1083, 1);
-        countingStream->write((uint64_t*)&cgen_var_1083, 1 * 8);
-        uint64_t cgen_var_1084;
-        countingStream->handleMapping()->mapHandles_VkSwapchainKHR_u64(&local_swapchain, &cgen_var_1084, 1);
-        countingStream->write((uint64_t*)&cgen_var_1084, 1 * 8);
+        uint64_t cgen_var_1087;
+        countingStream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_1087, 1);
+        countingStream->write((uint64_t*)&cgen_var_1087, 1 * 8);
+        uint64_t cgen_var_1088;
+        countingStream->handleMapping()->mapHandles_VkSwapchainKHR_u64(&local_swapchain, &cgen_var_1088, 1);
+        countingStream->write((uint64_t*)&cgen_var_1088, 1 * 8);
     }
     uint32_t packetSize_vkGetSwapchainStatusKHR = 4 + 4 + (uint32_t)countingStream->bytesWritten();
     countingStream->rewind();
     uint32_t opcode_vkGetSwapchainStatusKHR = OP_vkGetSwapchainStatusKHR;
     stream->write(&opcode_vkGetSwapchainStatusKHR, sizeof(uint32_t));
     stream->write(&packetSize_vkGetSwapchainStatusKHR, sizeof(uint32_t));
-    uint64_t cgen_var_1085;
-    stream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_1085, 1);
-    stream->write((uint64_t*)&cgen_var_1085, 1 * 8);
-    uint64_t cgen_var_1086;
-    stream->handleMapping()->mapHandles_VkSwapchainKHR_u64(&local_swapchain, &cgen_var_1086, 1);
-    stream->write((uint64_t*)&cgen_var_1086, 1 * 8);
+    uint64_t cgen_var_1089;
+    stream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_1089, 1);
+    stream->write((uint64_t*)&cgen_var_1089, 1 * 8);
+    uint64_t cgen_var_1090;
+    stream->handleMapping()->mapHandles_VkSwapchainKHR_u64(&local_swapchain, &cgen_var_1090, 1);
+    stream->write((uint64_t*)&cgen_var_1090, 1 * 8);
     AEMU_SCOPED_TRACE("vkGetSwapchainStatusKHR readParams");
     AEMU_SCOPED_TRACE("vkGetSwapchainStatusKHR returnUnmarshal");
     VkResult vkGetSwapchainStatusKHR_VkResult_return = (VkResult)0;
@@ -16130,6 +16475,7 @@
     const VkPhysicalDeviceExternalFenceInfo* pExternalFenceInfo,
     VkExternalFenceProperties* pExternalFenceProperties)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkGetPhysicalDeviceExternalFencePropertiesKHR encode");
     mImpl->log("start vkGetPhysicalDeviceExternalFencePropertiesKHR");
     auto stream = mImpl->stream();
@@ -16152,9 +16498,9 @@
     }
     countingStream->rewind();
     {
-        uint64_t cgen_var_1087;
-        countingStream->handleMapping()->mapHandles_VkPhysicalDevice_u64(&local_physicalDevice, &cgen_var_1087, 1);
-        countingStream->write((uint64_t*)&cgen_var_1087, 1 * 8);
+        uint64_t cgen_var_1091;
+        countingStream->handleMapping()->mapHandles_VkPhysicalDevice_u64(&local_physicalDevice, &cgen_var_1091, 1);
+        countingStream->write((uint64_t*)&cgen_var_1091, 1 * 8);
         marshal_VkPhysicalDeviceExternalFenceInfo(countingStream, (VkPhysicalDeviceExternalFenceInfo*)(local_pExternalFenceInfo));
         marshal_VkExternalFenceProperties(countingStream, (VkExternalFenceProperties*)(pExternalFenceProperties));
     }
@@ -16163,9 +16509,9 @@
     uint32_t opcode_vkGetPhysicalDeviceExternalFencePropertiesKHR = OP_vkGetPhysicalDeviceExternalFencePropertiesKHR;
     stream->write(&opcode_vkGetPhysicalDeviceExternalFencePropertiesKHR, sizeof(uint32_t));
     stream->write(&packetSize_vkGetPhysicalDeviceExternalFencePropertiesKHR, sizeof(uint32_t));
-    uint64_t cgen_var_1088;
-    stream->handleMapping()->mapHandles_VkPhysicalDevice_u64(&local_physicalDevice, &cgen_var_1088, 1);
-    stream->write((uint64_t*)&cgen_var_1088, 1 * 8);
+    uint64_t cgen_var_1092;
+    stream->handleMapping()->mapHandles_VkPhysicalDevice_u64(&local_physicalDevice, &cgen_var_1092, 1);
+    stream->write((uint64_t*)&cgen_var_1092, 1 * 8);
     marshal_VkPhysicalDeviceExternalFenceInfo(stream, (VkPhysicalDeviceExternalFenceInfo*)(local_pExternalFenceInfo));
     marshal_VkExternalFenceProperties(stream, (VkExternalFenceProperties*)(pExternalFenceProperties));
     AEMU_SCOPED_TRACE("vkGetPhysicalDeviceExternalFencePropertiesKHR readParams");
@@ -16186,6 +16532,7 @@
     VkDevice device,
     const VkImportFenceWin32HandleInfoKHR* pImportFenceWin32HandleInfo)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkImportFenceWin32HandleKHR encode");
     mImpl->log("start vkImportFenceWin32HandleKHR");
     auto stream = mImpl->stream();
@@ -16208,9 +16555,9 @@
     }
     countingStream->rewind();
     {
-        uint64_t cgen_var_1089;
-        countingStream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_1089, 1);
-        countingStream->write((uint64_t*)&cgen_var_1089, 1 * 8);
+        uint64_t cgen_var_1093;
+        countingStream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_1093, 1);
+        countingStream->write((uint64_t*)&cgen_var_1093, 1 * 8);
         marshal_VkImportFenceWin32HandleInfoKHR(countingStream, (VkImportFenceWin32HandleInfoKHR*)(local_pImportFenceWin32HandleInfo));
     }
     uint32_t packetSize_vkImportFenceWin32HandleKHR = 4 + 4 + (uint32_t)countingStream->bytesWritten();
@@ -16218,9 +16565,9 @@
     uint32_t opcode_vkImportFenceWin32HandleKHR = OP_vkImportFenceWin32HandleKHR;
     stream->write(&opcode_vkImportFenceWin32HandleKHR, sizeof(uint32_t));
     stream->write(&packetSize_vkImportFenceWin32HandleKHR, sizeof(uint32_t));
-    uint64_t cgen_var_1090;
-    stream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_1090, 1);
-    stream->write((uint64_t*)&cgen_var_1090, 1 * 8);
+    uint64_t cgen_var_1094;
+    stream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_1094, 1);
+    stream->write((uint64_t*)&cgen_var_1094, 1 * 8);
     marshal_VkImportFenceWin32HandleInfoKHR(stream, (VkImportFenceWin32HandleInfoKHR*)(local_pImportFenceWin32HandleInfo));
     AEMU_SCOPED_TRACE("vkImportFenceWin32HandleKHR readParams");
     AEMU_SCOPED_TRACE("vkImportFenceWin32HandleKHR returnUnmarshal");
@@ -16238,6 +16585,7 @@
     const VkFenceGetWin32HandleInfoKHR* pGetWin32HandleInfo,
     HANDLE* pHandle)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkGetFenceWin32HandleKHR encode");
     mImpl->log("start vkGetFenceWin32HandleKHR");
     auto stream = mImpl->stream();
@@ -16260,9 +16608,9 @@
     }
     countingStream->rewind();
     {
-        uint64_t cgen_var_1091;
-        countingStream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_1091, 1);
-        countingStream->write((uint64_t*)&cgen_var_1091, 1 * 8);
+        uint64_t cgen_var_1095;
+        countingStream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_1095, 1);
+        countingStream->write((uint64_t*)&cgen_var_1095, 1 * 8);
         marshal_VkFenceGetWin32HandleInfoKHR(countingStream, (VkFenceGetWin32HandleInfoKHR*)(local_pGetWin32HandleInfo));
         countingStream->write((HANDLE*)pHandle, sizeof(HANDLE));
     }
@@ -16271,9 +16619,9 @@
     uint32_t opcode_vkGetFenceWin32HandleKHR = OP_vkGetFenceWin32HandleKHR;
     stream->write(&opcode_vkGetFenceWin32HandleKHR, sizeof(uint32_t));
     stream->write(&packetSize_vkGetFenceWin32HandleKHR, sizeof(uint32_t));
-    uint64_t cgen_var_1092;
-    stream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_1092, 1);
-    stream->write((uint64_t*)&cgen_var_1092, 1 * 8);
+    uint64_t cgen_var_1096;
+    stream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_1096, 1);
+    stream->write((uint64_t*)&cgen_var_1096, 1 * 8);
     marshal_VkFenceGetWin32HandleInfoKHR(stream, (VkFenceGetWin32HandleInfoKHR*)(local_pGetWin32HandleInfo));
     stream->write((HANDLE*)pHandle, sizeof(HANDLE));
     AEMU_SCOPED_TRACE("vkGetFenceWin32HandleKHR readParams");
@@ -16294,6 +16642,7 @@
     VkDevice device,
     const VkImportFenceFdInfoKHR* pImportFenceFdInfo)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkImportFenceFdKHR encode");
     mImpl->log("start vkImportFenceFdKHR");
     auto stream = mImpl->stream();
@@ -16316,9 +16665,9 @@
     }
     countingStream->rewind();
     {
-        uint64_t cgen_var_1093;
-        countingStream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_1093, 1);
-        countingStream->write((uint64_t*)&cgen_var_1093, 1 * 8);
+        uint64_t cgen_var_1097;
+        countingStream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_1097, 1);
+        countingStream->write((uint64_t*)&cgen_var_1097, 1 * 8);
         marshal_VkImportFenceFdInfoKHR(countingStream, (VkImportFenceFdInfoKHR*)(local_pImportFenceFdInfo));
     }
     uint32_t packetSize_vkImportFenceFdKHR = 4 + 4 + (uint32_t)countingStream->bytesWritten();
@@ -16326,9 +16675,9 @@
     uint32_t opcode_vkImportFenceFdKHR = OP_vkImportFenceFdKHR;
     stream->write(&opcode_vkImportFenceFdKHR, sizeof(uint32_t));
     stream->write(&packetSize_vkImportFenceFdKHR, sizeof(uint32_t));
-    uint64_t cgen_var_1094;
-    stream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_1094, 1);
-    stream->write((uint64_t*)&cgen_var_1094, 1 * 8);
+    uint64_t cgen_var_1098;
+    stream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_1098, 1);
+    stream->write((uint64_t*)&cgen_var_1098, 1 * 8);
     marshal_VkImportFenceFdInfoKHR(stream, (VkImportFenceFdInfoKHR*)(local_pImportFenceFdInfo));
     AEMU_SCOPED_TRACE("vkImportFenceFdKHR readParams");
     AEMU_SCOPED_TRACE("vkImportFenceFdKHR returnUnmarshal");
@@ -16346,6 +16695,7 @@
     const VkFenceGetFdInfoKHR* pGetFdInfo,
     int* pFd)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkGetFenceFdKHR encode");
     mImpl->log("start vkGetFenceFdKHR");
     auto stream = mImpl->stream();
@@ -16368,9 +16718,9 @@
     }
     countingStream->rewind();
     {
-        uint64_t cgen_var_1095;
-        countingStream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_1095, 1);
-        countingStream->write((uint64_t*)&cgen_var_1095, 1 * 8);
+        uint64_t cgen_var_1099;
+        countingStream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_1099, 1);
+        countingStream->write((uint64_t*)&cgen_var_1099, 1 * 8);
         marshal_VkFenceGetFdInfoKHR(countingStream, (VkFenceGetFdInfoKHR*)(local_pGetFdInfo));
         countingStream->write((int*)pFd, sizeof(int));
     }
@@ -16379,9 +16729,9 @@
     uint32_t opcode_vkGetFenceFdKHR = OP_vkGetFenceFdKHR;
     stream->write(&opcode_vkGetFenceFdKHR, sizeof(uint32_t));
     stream->write(&packetSize_vkGetFenceFdKHR, sizeof(uint32_t));
-    uint64_t cgen_var_1096;
-    stream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_1096, 1);
-    stream->write((uint64_t*)&cgen_var_1096, 1 * 8);
+    uint64_t cgen_var_1100;
+    stream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_1100, 1);
+    stream->write((uint64_t*)&cgen_var_1100, 1 * 8);
     marshal_VkFenceGetFdInfoKHR(stream, (VkFenceGetFdInfoKHR*)(local_pGetFdInfo));
     stream->write((int*)pFd, sizeof(int));
     AEMU_SCOPED_TRACE("vkGetFenceFdKHR readParams");
@@ -16405,6 +16755,7 @@
     const VkPhysicalDeviceSurfaceInfo2KHR* pSurfaceInfo,
     VkSurfaceCapabilities2KHR* pSurfaceCapabilities)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkGetPhysicalDeviceSurfaceCapabilities2KHR encode");
     mImpl->log("start vkGetPhysicalDeviceSurfaceCapabilities2KHR");
     auto stream = mImpl->stream();
@@ -16427,9 +16778,9 @@
     }
     countingStream->rewind();
     {
-        uint64_t cgen_var_1097;
-        countingStream->handleMapping()->mapHandles_VkPhysicalDevice_u64(&local_physicalDevice, &cgen_var_1097, 1);
-        countingStream->write((uint64_t*)&cgen_var_1097, 1 * 8);
+        uint64_t cgen_var_1101;
+        countingStream->handleMapping()->mapHandles_VkPhysicalDevice_u64(&local_physicalDevice, &cgen_var_1101, 1);
+        countingStream->write((uint64_t*)&cgen_var_1101, 1 * 8);
         marshal_VkPhysicalDeviceSurfaceInfo2KHR(countingStream, (VkPhysicalDeviceSurfaceInfo2KHR*)(local_pSurfaceInfo));
         marshal_VkSurfaceCapabilities2KHR(countingStream, (VkSurfaceCapabilities2KHR*)(pSurfaceCapabilities));
     }
@@ -16438,9 +16789,9 @@
     uint32_t opcode_vkGetPhysicalDeviceSurfaceCapabilities2KHR = OP_vkGetPhysicalDeviceSurfaceCapabilities2KHR;
     stream->write(&opcode_vkGetPhysicalDeviceSurfaceCapabilities2KHR, sizeof(uint32_t));
     stream->write(&packetSize_vkGetPhysicalDeviceSurfaceCapabilities2KHR, sizeof(uint32_t));
-    uint64_t cgen_var_1098;
-    stream->handleMapping()->mapHandles_VkPhysicalDevice_u64(&local_physicalDevice, &cgen_var_1098, 1);
-    stream->write((uint64_t*)&cgen_var_1098, 1 * 8);
+    uint64_t cgen_var_1102;
+    stream->handleMapping()->mapHandles_VkPhysicalDevice_u64(&local_physicalDevice, &cgen_var_1102, 1);
+    stream->write((uint64_t*)&cgen_var_1102, 1 * 8);
     marshal_VkPhysicalDeviceSurfaceInfo2KHR(stream, (VkPhysicalDeviceSurfaceInfo2KHR*)(local_pSurfaceInfo));
     marshal_VkSurfaceCapabilities2KHR(stream, (VkSurfaceCapabilities2KHR*)(pSurfaceCapabilities));
     AEMU_SCOPED_TRACE("vkGetPhysicalDeviceSurfaceCapabilities2KHR readParams");
@@ -16465,6 +16816,7 @@
     uint32_t* pSurfaceFormatCount,
     VkSurfaceFormat2KHR* pSurfaceFormats)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkGetPhysicalDeviceSurfaceFormats2KHR encode");
     mImpl->log("start vkGetPhysicalDeviceSurfaceFormats2KHR");
     auto stream = mImpl->stream();
@@ -16487,20 +16839,20 @@
     }
     countingStream->rewind();
     {
-        uint64_t cgen_var_1099;
-        countingStream->handleMapping()->mapHandles_VkPhysicalDevice_u64(&local_physicalDevice, &cgen_var_1099, 1);
-        countingStream->write((uint64_t*)&cgen_var_1099, 1 * 8);
+        uint64_t cgen_var_1103;
+        countingStream->handleMapping()->mapHandles_VkPhysicalDevice_u64(&local_physicalDevice, &cgen_var_1103, 1);
+        countingStream->write((uint64_t*)&cgen_var_1103, 1 * 8);
         marshal_VkPhysicalDeviceSurfaceInfo2KHR(countingStream, (VkPhysicalDeviceSurfaceInfo2KHR*)(local_pSurfaceInfo));
         // WARNING PTR CHECK
-        uint64_t cgen_var_1100 = (uint64_t)(uintptr_t)pSurfaceFormatCount;
-        countingStream->putBe64(cgen_var_1100);
+        uint64_t cgen_var_1104 = (uint64_t)(uintptr_t)pSurfaceFormatCount;
+        countingStream->putBe64(cgen_var_1104);
         if (pSurfaceFormatCount)
         {
             countingStream->write((uint32_t*)pSurfaceFormatCount, sizeof(uint32_t));
         }
         // WARNING PTR CHECK
-        uint64_t cgen_var_1101 = (uint64_t)(uintptr_t)pSurfaceFormats;
-        countingStream->putBe64(cgen_var_1101);
+        uint64_t cgen_var_1105 = (uint64_t)(uintptr_t)pSurfaceFormats;
+        countingStream->putBe64(cgen_var_1105);
         if (pSurfaceFormats)
         {
             for (uint32_t i = 0; i < (uint32_t)(*(pSurfaceFormatCount)); ++i)
@@ -16514,20 +16866,20 @@
     uint32_t opcode_vkGetPhysicalDeviceSurfaceFormats2KHR = OP_vkGetPhysicalDeviceSurfaceFormats2KHR;
     stream->write(&opcode_vkGetPhysicalDeviceSurfaceFormats2KHR, sizeof(uint32_t));
     stream->write(&packetSize_vkGetPhysicalDeviceSurfaceFormats2KHR, sizeof(uint32_t));
-    uint64_t cgen_var_1102;
-    stream->handleMapping()->mapHandles_VkPhysicalDevice_u64(&local_physicalDevice, &cgen_var_1102, 1);
-    stream->write((uint64_t*)&cgen_var_1102, 1 * 8);
+    uint64_t cgen_var_1106;
+    stream->handleMapping()->mapHandles_VkPhysicalDevice_u64(&local_physicalDevice, &cgen_var_1106, 1);
+    stream->write((uint64_t*)&cgen_var_1106, 1 * 8);
     marshal_VkPhysicalDeviceSurfaceInfo2KHR(stream, (VkPhysicalDeviceSurfaceInfo2KHR*)(local_pSurfaceInfo));
     // WARNING PTR CHECK
-    uint64_t cgen_var_1103 = (uint64_t)(uintptr_t)pSurfaceFormatCount;
-    stream->putBe64(cgen_var_1103);
+    uint64_t cgen_var_1107 = (uint64_t)(uintptr_t)pSurfaceFormatCount;
+    stream->putBe64(cgen_var_1107);
     if (pSurfaceFormatCount)
     {
         stream->write((uint32_t*)pSurfaceFormatCount, sizeof(uint32_t));
     }
     // WARNING PTR CHECK
-    uint64_t cgen_var_1104 = (uint64_t)(uintptr_t)pSurfaceFormats;
-    stream->putBe64(cgen_var_1104);
+    uint64_t cgen_var_1108 = (uint64_t)(uintptr_t)pSurfaceFormats;
+    stream->putBe64(cgen_var_1108);
     if (pSurfaceFormats)
     {
         for (uint32_t i = 0; i < (uint32_t)(*(pSurfaceFormatCount)); ++i)
@@ -16587,6 +16939,7 @@
     uint32_t* pPropertyCount,
     VkDisplayProperties2KHR* pProperties)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkGetPhysicalDeviceDisplayProperties2KHR encode");
     mImpl->log("start vkGetPhysicalDeviceDisplayProperties2KHR");
     auto stream = mImpl->stream();
@@ -16598,19 +16951,19 @@
     local_physicalDevice = physicalDevice;
     countingStream->rewind();
     {
-        uint64_t cgen_var_1107;
-        countingStream->handleMapping()->mapHandles_VkPhysicalDevice_u64(&local_physicalDevice, &cgen_var_1107, 1);
-        countingStream->write((uint64_t*)&cgen_var_1107, 1 * 8);
+        uint64_t cgen_var_1111;
+        countingStream->handleMapping()->mapHandles_VkPhysicalDevice_u64(&local_physicalDevice, &cgen_var_1111, 1);
+        countingStream->write((uint64_t*)&cgen_var_1111, 1 * 8);
         // WARNING PTR CHECK
-        uint64_t cgen_var_1108 = (uint64_t)(uintptr_t)pPropertyCount;
-        countingStream->putBe64(cgen_var_1108);
+        uint64_t cgen_var_1112 = (uint64_t)(uintptr_t)pPropertyCount;
+        countingStream->putBe64(cgen_var_1112);
         if (pPropertyCount)
         {
             countingStream->write((uint32_t*)pPropertyCount, sizeof(uint32_t));
         }
         // WARNING PTR CHECK
-        uint64_t cgen_var_1109 = (uint64_t)(uintptr_t)pProperties;
-        countingStream->putBe64(cgen_var_1109);
+        uint64_t cgen_var_1113 = (uint64_t)(uintptr_t)pProperties;
+        countingStream->putBe64(cgen_var_1113);
         if (pProperties)
         {
             for (uint32_t i = 0; i < (uint32_t)(*(pPropertyCount)); ++i)
@@ -16624,19 +16977,19 @@
     uint32_t opcode_vkGetPhysicalDeviceDisplayProperties2KHR = OP_vkGetPhysicalDeviceDisplayProperties2KHR;
     stream->write(&opcode_vkGetPhysicalDeviceDisplayProperties2KHR, sizeof(uint32_t));
     stream->write(&packetSize_vkGetPhysicalDeviceDisplayProperties2KHR, sizeof(uint32_t));
-    uint64_t cgen_var_1110;
-    stream->handleMapping()->mapHandles_VkPhysicalDevice_u64(&local_physicalDevice, &cgen_var_1110, 1);
-    stream->write((uint64_t*)&cgen_var_1110, 1 * 8);
+    uint64_t cgen_var_1114;
+    stream->handleMapping()->mapHandles_VkPhysicalDevice_u64(&local_physicalDevice, &cgen_var_1114, 1);
+    stream->write((uint64_t*)&cgen_var_1114, 1 * 8);
     // WARNING PTR CHECK
-    uint64_t cgen_var_1111 = (uint64_t)(uintptr_t)pPropertyCount;
-    stream->putBe64(cgen_var_1111);
+    uint64_t cgen_var_1115 = (uint64_t)(uintptr_t)pPropertyCount;
+    stream->putBe64(cgen_var_1115);
     if (pPropertyCount)
     {
         stream->write((uint32_t*)pPropertyCount, sizeof(uint32_t));
     }
     // WARNING PTR CHECK
-    uint64_t cgen_var_1112 = (uint64_t)(uintptr_t)pProperties;
-    stream->putBe64(cgen_var_1112);
+    uint64_t cgen_var_1116 = (uint64_t)(uintptr_t)pProperties;
+    stream->putBe64(cgen_var_1116);
     if (pProperties)
     {
         for (uint32_t i = 0; i < (uint32_t)(*(pPropertyCount)); ++i)
@@ -16692,6 +17045,7 @@
     uint32_t* pPropertyCount,
     VkDisplayPlaneProperties2KHR* pProperties)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkGetPhysicalDeviceDisplayPlaneProperties2KHR encode");
     mImpl->log("start vkGetPhysicalDeviceDisplayPlaneProperties2KHR");
     auto stream = mImpl->stream();
@@ -16703,19 +17057,19 @@
     local_physicalDevice = physicalDevice;
     countingStream->rewind();
     {
-        uint64_t cgen_var_1115;
-        countingStream->handleMapping()->mapHandles_VkPhysicalDevice_u64(&local_physicalDevice, &cgen_var_1115, 1);
-        countingStream->write((uint64_t*)&cgen_var_1115, 1 * 8);
+        uint64_t cgen_var_1119;
+        countingStream->handleMapping()->mapHandles_VkPhysicalDevice_u64(&local_physicalDevice, &cgen_var_1119, 1);
+        countingStream->write((uint64_t*)&cgen_var_1119, 1 * 8);
         // WARNING PTR CHECK
-        uint64_t cgen_var_1116 = (uint64_t)(uintptr_t)pPropertyCount;
-        countingStream->putBe64(cgen_var_1116);
+        uint64_t cgen_var_1120 = (uint64_t)(uintptr_t)pPropertyCount;
+        countingStream->putBe64(cgen_var_1120);
         if (pPropertyCount)
         {
             countingStream->write((uint32_t*)pPropertyCount, sizeof(uint32_t));
         }
         // WARNING PTR CHECK
-        uint64_t cgen_var_1117 = (uint64_t)(uintptr_t)pProperties;
-        countingStream->putBe64(cgen_var_1117);
+        uint64_t cgen_var_1121 = (uint64_t)(uintptr_t)pProperties;
+        countingStream->putBe64(cgen_var_1121);
         if (pProperties)
         {
             for (uint32_t i = 0; i < (uint32_t)(*(pPropertyCount)); ++i)
@@ -16729,19 +17083,19 @@
     uint32_t opcode_vkGetPhysicalDeviceDisplayPlaneProperties2KHR = OP_vkGetPhysicalDeviceDisplayPlaneProperties2KHR;
     stream->write(&opcode_vkGetPhysicalDeviceDisplayPlaneProperties2KHR, sizeof(uint32_t));
     stream->write(&packetSize_vkGetPhysicalDeviceDisplayPlaneProperties2KHR, sizeof(uint32_t));
-    uint64_t cgen_var_1118;
-    stream->handleMapping()->mapHandles_VkPhysicalDevice_u64(&local_physicalDevice, &cgen_var_1118, 1);
-    stream->write((uint64_t*)&cgen_var_1118, 1 * 8);
+    uint64_t cgen_var_1122;
+    stream->handleMapping()->mapHandles_VkPhysicalDevice_u64(&local_physicalDevice, &cgen_var_1122, 1);
+    stream->write((uint64_t*)&cgen_var_1122, 1 * 8);
     // WARNING PTR CHECK
-    uint64_t cgen_var_1119 = (uint64_t)(uintptr_t)pPropertyCount;
-    stream->putBe64(cgen_var_1119);
+    uint64_t cgen_var_1123 = (uint64_t)(uintptr_t)pPropertyCount;
+    stream->putBe64(cgen_var_1123);
     if (pPropertyCount)
     {
         stream->write((uint32_t*)pPropertyCount, sizeof(uint32_t));
     }
     // WARNING PTR CHECK
-    uint64_t cgen_var_1120 = (uint64_t)(uintptr_t)pProperties;
-    stream->putBe64(cgen_var_1120);
+    uint64_t cgen_var_1124 = (uint64_t)(uintptr_t)pProperties;
+    stream->putBe64(cgen_var_1124);
     if (pProperties)
     {
         for (uint32_t i = 0; i < (uint32_t)(*(pPropertyCount)); ++i)
@@ -16798,6 +17152,7 @@
     uint32_t* pPropertyCount,
     VkDisplayModeProperties2KHR* pProperties)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkGetDisplayModeProperties2KHR encode");
     mImpl->log("start vkGetDisplayModeProperties2KHR");
     auto stream = mImpl->stream();
@@ -16811,22 +17166,22 @@
     local_display = display;
     countingStream->rewind();
     {
-        uint64_t cgen_var_1123;
-        countingStream->handleMapping()->mapHandles_VkPhysicalDevice_u64(&local_physicalDevice, &cgen_var_1123, 1);
-        countingStream->write((uint64_t*)&cgen_var_1123, 1 * 8);
-        uint64_t cgen_var_1124;
-        countingStream->handleMapping()->mapHandles_VkDisplayKHR_u64(&local_display, &cgen_var_1124, 1);
-        countingStream->write((uint64_t*)&cgen_var_1124, 1 * 8);
+        uint64_t cgen_var_1127;
+        countingStream->handleMapping()->mapHandles_VkPhysicalDevice_u64(&local_physicalDevice, &cgen_var_1127, 1);
+        countingStream->write((uint64_t*)&cgen_var_1127, 1 * 8);
+        uint64_t cgen_var_1128;
+        countingStream->handleMapping()->mapHandles_VkDisplayKHR_u64(&local_display, &cgen_var_1128, 1);
+        countingStream->write((uint64_t*)&cgen_var_1128, 1 * 8);
         // WARNING PTR CHECK
-        uint64_t cgen_var_1125 = (uint64_t)(uintptr_t)pPropertyCount;
-        countingStream->putBe64(cgen_var_1125);
+        uint64_t cgen_var_1129 = (uint64_t)(uintptr_t)pPropertyCount;
+        countingStream->putBe64(cgen_var_1129);
         if (pPropertyCount)
         {
             countingStream->write((uint32_t*)pPropertyCount, sizeof(uint32_t));
         }
         // WARNING PTR CHECK
-        uint64_t cgen_var_1126 = (uint64_t)(uintptr_t)pProperties;
-        countingStream->putBe64(cgen_var_1126);
+        uint64_t cgen_var_1130 = (uint64_t)(uintptr_t)pProperties;
+        countingStream->putBe64(cgen_var_1130);
         if (pProperties)
         {
             for (uint32_t i = 0; i < (uint32_t)(*(pPropertyCount)); ++i)
@@ -16840,22 +17195,22 @@
     uint32_t opcode_vkGetDisplayModeProperties2KHR = OP_vkGetDisplayModeProperties2KHR;
     stream->write(&opcode_vkGetDisplayModeProperties2KHR, sizeof(uint32_t));
     stream->write(&packetSize_vkGetDisplayModeProperties2KHR, sizeof(uint32_t));
-    uint64_t cgen_var_1127;
-    stream->handleMapping()->mapHandles_VkPhysicalDevice_u64(&local_physicalDevice, &cgen_var_1127, 1);
-    stream->write((uint64_t*)&cgen_var_1127, 1 * 8);
-    uint64_t cgen_var_1128;
-    stream->handleMapping()->mapHandles_VkDisplayKHR_u64(&local_display, &cgen_var_1128, 1);
-    stream->write((uint64_t*)&cgen_var_1128, 1 * 8);
+    uint64_t cgen_var_1131;
+    stream->handleMapping()->mapHandles_VkPhysicalDevice_u64(&local_physicalDevice, &cgen_var_1131, 1);
+    stream->write((uint64_t*)&cgen_var_1131, 1 * 8);
+    uint64_t cgen_var_1132;
+    stream->handleMapping()->mapHandles_VkDisplayKHR_u64(&local_display, &cgen_var_1132, 1);
+    stream->write((uint64_t*)&cgen_var_1132, 1 * 8);
     // WARNING PTR CHECK
-    uint64_t cgen_var_1129 = (uint64_t)(uintptr_t)pPropertyCount;
-    stream->putBe64(cgen_var_1129);
+    uint64_t cgen_var_1133 = (uint64_t)(uintptr_t)pPropertyCount;
+    stream->putBe64(cgen_var_1133);
     if (pPropertyCount)
     {
         stream->write((uint32_t*)pPropertyCount, sizeof(uint32_t));
     }
     // WARNING PTR CHECK
-    uint64_t cgen_var_1130 = (uint64_t)(uintptr_t)pProperties;
-    stream->putBe64(cgen_var_1130);
+    uint64_t cgen_var_1134 = (uint64_t)(uintptr_t)pProperties;
+    stream->putBe64(cgen_var_1134);
     if (pProperties)
     {
         for (uint32_t i = 0; i < (uint32_t)(*(pPropertyCount)); ++i)
@@ -16911,6 +17266,7 @@
     const VkDisplayPlaneInfo2KHR* pDisplayPlaneInfo,
     VkDisplayPlaneCapabilities2KHR* pCapabilities)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkGetDisplayPlaneCapabilities2KHR encode");
     mImpl->log("start vkGetDisplayPlaneCapabilities2KHR");
     auto stream = mImpl->stream();
@@ -16933,9 +17289,9 @@
     }
     countingStream->rewind();
     {
-        uint64_t cgen_var_1133;
-        countingStream->handleMapping()->mapHandles_VkPhysicalDevice_u64(&local_physicalDevice, &cgen_var_1133, 1);
-        countingStream->write((uint64_t*)&cgen_var_1133, 1 * 8);
+        uint64_t cgen_var_1137;
+        countingStream->handleMapping()->mapHandles_VkPhysicalDevice_u64(&local_physicalDevice, &cgen_var_1137, 1);
+        countingStream->write((uint64_t*)&cgen_var_1137, 1 * 8);
         marshal_VkDisplayPlaneInfo2KHR(countingStream, (VkDisplayPlaneInfo2KHR*)(local_pDisplayPlaneInfo));
         marshal_VkDisplayPlaneCapabilities2KHR(countingStream, (VkDisplayPlaneCapabilities2KHR*)(pCapabilities));
     }
@@ -16944,9 +17300,9 @@
     uint32_t opcode_vkGetDisplayPlaneCapabilities2KHR = OP_vkGetDisplayPlaneCapabilities2KHR;
     stream->write(&opcode_vkGetDisplayPlaneCapabilities2KHR, sizeof(uint32_t));
     stream->write(&packetSize_vkGetDisplayPlaneCapabilities2KHR, sizeof(uint32_t));
-    uint64_t cgen_var_1134;
-    stream->handleMapping()->mapHandles_VkPhysicalDevice_u64(&local_physicalDevice, &cgen_var_1134, 1);
-    stream->write((uint64_t*)&cgen_var_1134, 1 * 8);
+    uint64_t cgen_var_1138;
+    stream->handleMapping()->mapHandles_VkPhysicalDevice_u64(&local_physicalDevice, &cgen_var_1138, 1);
+    stream->write((uint64_t*)&cgen_var_1138, 1 * 8);
     marshal_VkDisplayPlaneInfo2KHR(stream, (VkDisplayPlaneInfo2KHR*)(local_pDisplayPlaneInfo));
     marshal_VkDisplayPlaneCapabilities2KHR(stream, (VkDisplayPlaneCapabilities2KHR*)(pCapabilities));
     AEMU_SCOPED_TRACE("vkGetDisplayPlaneCapabilities2KHR readParams");
@@ -16978,6 +17334,7 @@
     const VkImageMemoryRequirementsInfo2* pInfo,
     VkMemoryRequirements2* pMemoryRequirements)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkGetImageMemoryRequirements2KHR encode");
     mImpl->log("start vkGetImageMemoryRequirements2KHR");
     auto stream = mImpl->stream();
@@ -17000,9 +17357,9 @@
     }
     countingStream->rewind();
     {
-        uint64_t cgen_var_1135;
-        countingStream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_1135, 1);
-        countingStream->write((uint64_t*)&cgen_var_1135, 1 * 8);
+        uint64_t cgen_var_1139;
+        countingStream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_1139, 1);
+        countingStream->write((uint64_t*)&cgen_var_1139, 1 * 8);
         marshal_VkImageMemoryRequirementsInfo2(countingStream, (VkImageMemoryRequirementsInfo2*)(local_pInfo));
         marshal_VkMemoryRequirements2(countingStream, (VkMemoryRequirements2*)(pMemoryRequirements));
     }
@@ -17011,9 +17368,9 @@
     uint32_t opcode_vkGetImageMemoryRequirements2KHR = OP_vkGetImageMemoryRequirements2KHR;
     stream->write(&opcode_vkGetImageMemoryRequirements2KHR, sizeof(uint32_t));
     stream->write(&packetSize_vkGetImageMemoryRequirements2KHR, sizeof(uint32_t));
-    uint64_t cgen_var_1136;
-    stream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_1136, 1);
-    stream->write((uint64_t*)&cgen_var_1136, 1 * 8);
+    uint64_t cgen_var_1140;
+    stream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_1140, 1);
+    stream->write((uint64_t*)&cgen_var_1140, 1 * 8);
     marshal_VkImageMemoryRequirementsInfo2(stream, (VkImageMemoryRequirementsInfo2*)(local_pInfo));
     marshal_VkMemoryRequirements2(stream, (VkMemoryRequirements2*)(pMemoryRequirements));
     AEMU_SCOPED_TRACE("vkGetImageMemoryRequirements2KHR readParams");
@@ -17031,6 +17388,7 @@
     const VkBufferMemoryRequirementsInfo2* pInfo,
     VkMemoryRequirements2* pMemoryRequirements)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkGetBufferMemoryRequirements2KHR encode");
     mImpl->log("start vkGetBufferMemoryRequirements2KHR");
     auto stream = mImpl->stream();
@@ -17053,9 +17411,9 @@
     }
     countingStream->rewind();
     {
-        uint64_t cgen_var_1137;
-        countingStream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_1137, 1);
-        countingStream->write((uint64_t*)&cgen_var_1137, 1 * 8);
+        uint64_t cgen_var_1141;
+        countingStream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_1141, 1);
+        countingStream->write((uint64_t*)&cgen_var_1141, 1 * 8);
         marshal_VkBufferMemoryRequirementsInfo2(countingStream, (VkBufferMemoryRequirementsInfo2*)(local_pInfo));
         marshal_VkMemoryRequirements2(countingStream, (VkMemoryRequirements2*)(pMemoryRequirements));
     }
@@ -17064,9 +17422,9 @@
     uint32_t opcode_vkGetBufferMemoryRequirements2KHR = OP_vkGetBufferMemoryRequirements2KHR;
     stream->write(&opcode_vkGetBufferMemoryRequirements2KHR, sizeof(uint32_t));
     stream->write(&packetSize_vkGetBufferMemoryRequirements2KHR, sizeof(uint32_t));
-    uint64_t cgen_var_1138;
-    stream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_1138, 1);
-    stream->write((uint64_t*)&cgen_var_1138, 1 * 8);
+    uint64_t cgen_var_1142;
+    stream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_1142, 1);
+    stream->write((uint64_t*)&cgen_var_1142, 1 * 8);
     marshal_VkBufferMemoryRequirementsInfo2(stream, (VkBufferMemoryRequirementsInfo2*)(local_pInfo));
     marshal_VkMemoryRequirements2(stream, (VkMemoryRequirements2*)(pMemoryRequirements));
     AEMU_SCOPED_TRACE("vkGetBufferMemoryRequirements2KHR readParams");
@@ -17085,6 +17443,7 @@
     uint32_t* pSparseMemoryRequirementCount,
     VkSparseImageMemoryRequirements2* pSparseMemoryRequirements)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkGetImageSparseMemoryRequirements2KHR encode");
     mImpl->log("start vkGetImageSparseMemoryRequirements2KHR");
     auto stream = mImpl->stream();
@@ -17107,20 +17466,20 @@
     }
     countingStream->rewind();
     {
-        uint64_t cgen_var_1139;
-        countingStream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_1139, 1);
-        countingStream->write((uint64_t*)&cgen_var_1139, 1 * 8);
+        uint64_t cgen_var_1143;
+        countingStream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_1143, 1);
+        countingStream->write((uint64_t*)&cgen_var_1143, 1 * 8);
         marshal_VkImageSparseMemoryRequirementsInfo2(countingStream, (VkImageSparseMemoryRequirementsInfo2*)(local_pInfo));
         // WARNING PTR CHECK
-        uint64_t cgen_var_1140 = (uint64_t)(uintptr_t)pSparseMemoryRequirementCount;
-        countingStream->putBe64(cgen_var_1140);
+        uint64_t cgen_var_1144 = (uint64_t)(uintptr_t)pSparseMemoryRequirementCount;
+        countingStream->putBe64(cgen_var_1144);
         if (pSparseMemoryRequirementCount)
         {
             countingStream->write((uint32_t*)pSparseMemoryRequirementCount, sizeof(uint32_t));
         }
         // WARNING PTR CHECK
-        uint64_t cgen_var_1141 = (uint64_t)(uintptr_t)pSparseMemoryRequirements;
-        countingStream->putBe64(cgen_var_1141);
+        uint64_t cgen_var_1145 = (uint64_t)(uintptr_t)pSparseMemoryRequirements;
+        countingStream->putBe64(cgen_var_1145);
         if (pSparseMemoryRequirements)
         {
             for (uint32_t i = 0; i < (uint32_t)(*(pSparseMemoryRequirementCount)); ++i)
@@ -17134,20 +17493,20 @@
     uint32_t opcode_vkGetImageSparseMemoryRequirements2KHR = OP_vkGetImageSparseMemoryRequirements2KHR;
     stream->write(&opcode_vkGetImageSparseMemoryRequirements2KHR, sizeof(uint32_t));
     stream->write(&packetSize_vkGetImageSparseMemoryRequirements2KHR, sizeof(uint32_t));
-    uint64_t cgen_var_1142;
-    stream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_1142, 1);
-    stream->write((uint64_t*)&cgen_var_1142, 1 * 8);
+    uint64_t cgen_var_1146;
+    stream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_1146, 1);
+    stream->write((uint64_t*)&cgen_var_1146, 1 * 8);
     marshal_VkImageSparseMemoryRequirementsInfo2(stream, (VkImageSparseMemoryRequirementsInfo2*)(local_pInfo));
     // WARNING PTR CHECK
-    uint64_t cgen_var_1143 = (uint64_t)(uintptr_t)pSparseMemoryRequirementCount;
-    stream->putBe64(cgen_var_1143);
+    uint64_t cgen_var_1147 = (uint64_t)(uintptr_t)pSparseMemoryRequirementCount;
+    stream->putBe64(cgen_var_1147);
     if (pSparseMemoryRequirementCount)
     {
         stream->write((uint32_t*)pSparseMemoryRequirementCount, sizeof(uint32_t));
     }
     // WARNING PTR CHECK
-    uint64_t cgen_var_1144 = (uint64_t)(uintptr_t)pSparseMemoryRequirements;
-    stream->putBe64(cgen_var_1144);
+    uint64_t cgen_var_1148 = (uint64_t)(uintptr_t)pSparseMemoryRequirements;
+    stream->putBe64(cgen_var_1148);
     if (pSparseMemoryRequirements)
     {
         for (uint32_t i = 0; i < (uint32_t)(*(pSparseMemoryRequirementCount)); ++i)
@@ -17202,6 +17561,7 @@
     const VkAllocationCallbacks* pAllocator,
     VkSamplerYcbcrConversion* pYcbcrConversion)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkCreateSamplerYcbcrConversionKHR encode");
     mImpl->log("start vkCreateSamplerYcbcrConversionKHR");
     auto stream = mImpl->stream();
@@ -17236,47 +17596,47 @@
     }
     countingStream->rewind();
     {
-        uint64_t cgen_var_1147;
-        countingStream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_1147, 1);
-        countingStream->write((uint64_t*)&cgen_var_1147, 1 * 8);
+        uint64_t cgen_var_1151;
+        countingStream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_1151, 1);
+        countingStream->write((uint64_t*)&cgen_var_1151, 1 * 8);
         marshal_VkSamplerYcbcrConversionCreateInfo(countingStream, (VkSamplerYcbcrConversionCreateInfo*)(local_pCreateInfo));
         // WARNING PTR CHECK
-        uint64_t cgen_var_1148 = (uint64_t)(uintptr_t)local_pAllocator;
-        countingStream->putBe64(cgen_var_1148);
+        uint64_t cgen_var_1152 = (uint64_t)(uintptr_t)local_pAllocator;
+        countingStream->putBe64(cgen_var_1152);
         if (local_pAllocator)
         {
             marshal_VkAllocationCallbacks(countingStream, (VkAllocationCallbacks*)(local_pAllocator));
         }
-        uint64_t cgen_var_1149;
-        countingStream->handleMapping()->mapHandles_VkSamplerYcbcrConversion_u64(pYcbcrConversion, &cgen_var_1149, 1);
-        countingStream->write((uint64_t*)&cgen_var_1149, 8);
+        uint64_t cgen_var_1153;
+        countingStream->handleMapping()->mapHandles_VkSamplerYcbcrConversion_u64(pYcbcrConversion, &cgen_var_1153, 1);
+        countingStream->write((uint64_t*)&cgen_var_1153, 8);
     }
     uint32_t packetSize_vkCreateSamplerYcbcrConversionKHR = 4 + 4 + (uint32_t)countingStream->bytesWritten();
     countingStream->rewind();
     uint32_t opcode_vkCreateSamplerYcbcrConversionKHR = OP_vkCreateSamplerYcbcrConversionKHR;
     stream->write(&opcode_vkCreateSamplerYcbcrConversionKHR, sizeof(uint32_t));
     stream->write(&packetSize_vkCreateSamplerYcbcrConversionKHR, sizeof(uint32_t));
-    uint64_t cgen_var_1150;
-    stream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_1150, 1);
-    stream->write((uint64_t*)&cgen_var_1150, 1 * 8);
+    uint64_t cgen_var_1154;
+    stream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_1154, 1);
+    stream->write((uint64_t*)&cgen_var_1154, 1 * 8);
     marshal_VkSamplerYcbcrConversionCreateInfo(stream, (VkSamplerYcbcrConversionCreateInfo*)(local_pCreateInfo));
     // WARNING PTR CHECK
-    uint64_t cgen_var_1151 = (uint64_t)(uintptr_t)local_pAllocator;
-    stream->putBe64(cgen_var_1151);
+    uint64_t cgen_var_1155 = (uint64_t)(uintptr_t)local_pAllocator;
+    stream->putBe64(cgen_var_1155);
     if (local_pAllocator)
     {
         marshal_VkAllocationCallbacks(stream, (VkAllocationCallbacks*)(local_pAllocator));
     }
     stream->unsetHandleMapping() /* emit_marshal, is handle, possibly out */;
-    uint64_t cgen_var_1152;
-    stream->handleMapping()->mapHandles_VkSamplerYcbcrConversion_u64(pYcbcrConversion, &cgen_var_1152, 1);
-    stream->write((uint64_t*)&cgen_var_1152, 8);
+    uint64_t cgen_var_1156;
+    stream->handleMapping()->mapHandles_VkSamplerYcbcrConversion_u64(pYcbcrConversion, &cgen_var_1156, 1);
+    stream->write((uint64_t*)&cgen_var_1156, 8);
     stream->setHandleMapping(resources->unwrapMapping());
     AEMU_SCOPED_TRACE("vkCreateSamplerYcbcrConversionKHR readParams");
     stream->setHandleMapping(resources->createMapping());
-    uint64_t cgen_var_1153;
-    stream->read((uint64_t*)&cgen_var_1153, 8);
-    stream->handleMapping()->mapHandles_u64_VkSamplerYcbcrConversion(&cgen_var_1153, (VkSamplerYcbcrConversion*)pYcbcrConversion, 1);
+    uint64_t cgen_var_1157;
+    stream->read((uint64_t*)&cgen_var_1157, 8);
+    stream->handleMapping()->mapHandles_u64_VkSamplerYcbcrConversion(&cgen_var_1157, (VkSamplerYcbcrConversion*)pYcbcrConversion, 1);
     stream->unsetHandleMapping();
     AEMU_SCOPED_TRACE("vkCreateSamplerYcbcrConversionKHR returnUnmarshal");
     VkResult vkCreateSamplerYcbcrConversionKHR_VkResult_return = (VkResult)0;
@@ -17293,6 +17653,7 @@
     VkSamplerYcbcrConversion ycbcrConversion,
     const VkAllocationCallbacks* pAllocator)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkDestroySamplerYcbcrConversionKHR encode");
     mImpl->log("start vkDestroySamplerYcbcrConversionKHR");
     auto stream = mImpl->stream();
@@ -17318,15 +17679,15 @@
     }
     countingStream->rewind();
     {
-        uint64_t cgen_var_1154;
-        countingStream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_1154, 1);
-        countingStream->write((uint64_t*)&cgen_var_1154, 1 * 8);
-        uint64_t cgen_var_1155;
-        countingStream->handleMapping()->mapHandles_VkSamplerYcbcrConversion_u64(&local_ycbcrConversion, &cgen_var_1155, 1);
-        countingStream->write((uint64_t*)&cgen_var_1155, 1 * 8);
+        uint64_t cgen_var_1158;
+        countingStream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_1158, 1);
+        countingStream->write((uint64_t*)&cgen_var_1158, 1 * 8);
+        uint64_t cgen_var_1159;
+        countingStream->handleMapping()->mapHandles_VkSamplerYcbcrConversion_u64(&local_ycbcrConversion, &cgen_var_1159, 1);
+        countingStream->write((uint64_t*)&cgen_var_1159, 1 * 8);
         // WARNING PTR CHECK
-        uint64_t cgen_var_1156 = (uint64_t)(uintptr_t)local_pAllocator;
-        countingStream->putBe64(cgen_var_1156);
+        uint64_t cgen_var_1160 = (uint64_t)(uintptr_t)local_pAllocator;
+        countingStream->putBe64(cgen_var_1160);
         if (local_pAllocator)
         {
             marshal_VkAllocationCallbacks(countingStream, (VkAllocationCallbacks*)(local_pAllocator));
@@ -17337,15 +17698,15 @@
     uint32_t opcode_vkDestroySamplerYcbcrConversionKHR = OP_vkDestroySamplerYcbcrConversionKHR;
     stream->write(&opcode_vkDestroySamplerYcbcrConversionKHR, sizeof(uint32_t));
     stream->write(&packetSize_vkDestroySamplerYcbcrConversionKHR, sizeof(uint32_t));
-    uint64_t cgen_var_1157;
-    stream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_1157, 1);
-    stream->write((uint64_t*)&cgen_var_1157, 1 * 8);
-    uint64_t cgen_var_1158;
-    stream->handleMapping()->mapHandles_VkSamplerYcbcrConversion_u64(&local_ycbcrConversion, &cgen_var_1158, 1);
-    stream->write((uint64_t*)&cgen_var_1158, 1 * 8);
+    uint64_t cgen_var_1161;
+    stream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_1161, 1);
+    stream->write((uint64_t*)&cgen_var_1161, 1 * 8);
+    uint64_t cgen_var_1162;
+    stream->handleMapping()->mapHandles_VkSamplerYcbcrConversion_u64(&local_ycbcrConversion, &cgen_var_1162, 1);
+    stream->write((uint64_t*)&cgen_var_1162, 1 * 8);
     // WARNING PTR CHECK
-    uint64_t cgen_var_1159 = (uint64_t)(uintptr_t)local_pAllocator;
-    stream->putBe64(cgen_var_1159);
+    uint64_t cgen_var_1163 = (uint64_t)(uintptr_t)local_pAllocator;
+    stream->putBe64(cgen_var_1163);
     if (local_pAllocator)
     {
         marshal_VkAllocationCallbacks(stream, (VkAllocationCallbacks*)(local_pAllocator));
@@ -17363,6 +17724,7 @@
     uint32_t bindInfoCount,
     const VkBindBufferMemoryInfo* pBindInfos)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkBindBufferMemory2KHR encode");
     mImpl->log("start vkBindBufferMemory2KHR");
     auto stream = mImpl->stream();
@@ -17393,9 +17755,9 @@
     }
     countingStream->rewind();
     {
-        uint64_t cgen_var_1160;
-        countingStream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_1160, 1);
-        countingStream->write((uint64_t*)&cgen_var_1160, 1 * 8);
+        uint64_t cgen_var_1164;
+        countingStream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_1164, 1);
+        countingStream->write((uint64_t*)&cgen_var_1164, 1 * 8);
         countingStream->write((uint32_t*)&local_bindInfoCount, sizeof(uint32_t));
         for (uint32_t i = 0; i < (uint32_t)((bindInfoCount)); ++i)
         {
@@ -17407,9 +17769,9 @@
     uint32_t opcode_vkBindBufferMemory2KHR = OP_vkBindBufferMemory2KHR;
     stream->write(&opcode_vkBindBufferMemory2KHR, sizeof(uint32_t));
     stream->write(&packetSize_vkBindBufferMemory2KHR, sizeof(uint32_t));
-    uint64_t cgen_var_1161;
-    stream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_1161, 1);
-    stream->write((uint64_t*)&cgen_var_1161, 1 * 8);
+    uint64_t cgen_var_1165;
+    stream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_1165, 1);
+    stream->write((uint64_t*)&cgen_var_1165, 1 * 8);
     stream->write((uint32_t*)&local_bindInfoCount, sizeof(uint32_t));
     for (uint32_t i = 0; i < (uint32_t)((bindInfoCount)); ++i)
     {
@@ -17431,6 +17793,7 @@
     uint32_t bindInfoCount,
     const VkBindImageMemoryInfo* pBindInfos)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkBindImageMemory2KHR encode");
     mImpl->log("start vkBindImageMemory2KHR");
     auto stream = mImpl->stream();
@@ -17461,9 +17824,9 @@
     }
     countingStream->rewind();
     {
-        uint64_t cgen_var_1162;
-        countingStream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_1162, 1);
-        countingStream->write((uint64_t*)&cgen_var_1162, 1 * 8);
+        uint64_t cgen_var_1166;
+        countingStream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_1166, 1);
+        countingStream->write((uint64_t*)&cgen_var_1166, 1 * 8);
         countingStream->write((uint32_t*)&local_bindInfoCount, sizeof(uint32_t));
         for (uint32_t i = 0; i < (uint32_t)((bindInfoCount)); ++i)
         {
@@ -17475,9 +17838,9 @@
     uint32_t opcode_vkBindImageMemory2KHR = OP_vkBindImageMemory2KHR;
     stream->write(&opcode_vkBindImageMemory2KHR, sizeof(uint32_t));
     stream->write(&packetSize_vkBindImageMemory2KHR, sizeof(uint32_t));
-    uint64_t cgen_var_1163;
-    stream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_1163, 1);
-    stream->write((uint64_t*)&cgen_var_1163, 1 * 8);
+    uint64_t cgen_var_1167;
+    stream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_1167, 1);
+    stream->write((uint64_t*)&cgen_var_1167, 1 * 8);
     stream->write((uint32_t*)&local_bindInfoCount, sizeof(uint32_t));
     for (uint32_t i = 0; i < (uint32_t)((bindInfoCount)); ++i)
     {
@@ -17501,6 +17864,7 @@
     const VkDescriptorSetLayoutCreateInfo* pCreateInfo,
     VkDescriptorSetLayoutSupport* pSupport)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkGetDescriptorSetLayoutSupportKHR encode");
     mImpl->log("start vkGetDescriptorSetLayoutSupportKHR");
     auto stream = mImpl->stream();
@@ -17523,9 +17887,9 @@
     }
     countingStream->rewind();
     {
-        uint64_t cgen_var_1164;
-        countingStream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_1164, 1);
-        countingStream->write((uint64_t*)&cgen_var_1164, 1 * 8);
+        uint64_t cgen_var_1168;
+        countingStream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_1168, 1);
+        countingStream->write((uint64_t*)&cgen_var_1168, 1 * 8);
         marshal_VkDescriptorSetLayoutCreateInfo(countingStream, (VkDescriptorSetLayoutCreateInfo*)(local_pCreateInfo));
         marshal_VkDescriptorSetLayoutSupport(countingStream, (VkDescriptorSetLayoutSupport*)(pSupport));
     }
@@ -17534,9 +17898,9 @@
     uint32_t opcode_vkGetDescriptorSetLayoutSupportKHR = OP_vkGetDescriptorSetLayoutSupportKHR;
     stream->write(&opcode_vkGetDescriptorSetLayoutSupportKHR, sizeof(uint32_t));
     stream->write(&packetSize_vkGetDescriptorSetLayoutSupportKHR, sizeof(uint32_t));
-    uint64_t cgen_var_1165;
-    stream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_1165, 1);
-    stream->write((uint64_t*)&cgen_var_1165, 1 * 8);
+    uint64_t cgen_var_1169;
+    stream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_1169, 1);
+    stream->write((uint64_t*)&cgen_var_1169, 1 * 8);
     marshal_VkDescriptorSetLayoutCreateInfo(stream, (VkDescriptorSetLayoutCreateInfo*)(local_pCreateInfo));
     marshal_VkDescriptorSetLayoutSupport(stream, (VkDescriptorSetLayoutSupport*)(pSupport));
     AEMU_SCOPED_TRACE("vkGetDescriptorSetLayoutSupportKHR readParams");
@@ -17560,6 +17924,7 @@
     uint32_t maxDrawCount,
     uint32_t stride)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkCmdDrawIndirectCountKHR encode");
     mImpl->log("start vkCmdDrawIndirectCountKHR");
     auto stream = mImpl->stream();
@@ -17583,16 +17948,16 @@
     local_stride = stride;
     countingStream->rewind();
     {
-        uint64_t cgen_var_1166;
-        countingStream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_1166, 1);
-        countingStream->write((uint64_t*)&cgen_var_1166, 1 * 8);
-        uint64_t cgen_var_1167;
-        countingStream->handleMapping()->mapHandles_VkBuffer_u64(&local_buffer, &cgen_var_1167, 1);
-        countingStream->write((uint64_t*)&cgen_var_1167, 1 * 8);
+        uint64_t cgen_var_1170;
+        countingStream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_1170, 1);
+        countingStream->write((uint64_t*)&cgen_var_1170, 1 * 8);
+        uint64_t cgen_var_1171;
+        countingStream->handleMapping()->mapHandles_VkBuffer_u64(&local_buffer, &cgen_var_1171, 1);
+        countingStream->write((uint64_t*)&cgen_var_1171, 1 * 8);
         countingStream->write((VkDeviceSize*)&local_offset, sizeof(VkDeviceSize));
-        uint64_t cgen_var_1168;
-        countingStream->handleMapping()->mapHandles_VkBuffer_u64(&local_countBuffer, &cgen_var_1168, 1);
-        countingStream->write((uint64_t*)&cgen_var_1168, 1 * 8);
+        uint64_t cgen_var_1172;
+        countingStream->handleMapping()->mapHandles_VkBuffer_u64(&local_countBuffer, &cgen_var_1172, 1);
+        countingStream->write((uint64_t*)&cgen_var_1172, 1 * 8);
         countingStream->write((VkDeviceSize*)&local_countBufferOffset, sizeof(VkDeviceSize));
         countingStream->write((uint32_t*)&local_maxDrawCount, sizeof(uint32_t));
         countingStream->write((uint32_t*)&local_stride, sizeof(uint32_t));
@@ -17602,16 +17967,16 @@
     uint32_t opcode_vkCmdDrawIndirectCountKHR = OP_vkCmdDrawIndirectCountKHR;
     stream->write(&opcode_vkCmdDrawIndirectCountKHR, sizeof(uint32_t));
     stream->write(&packetSize_vkCmdDrawIndirectCountKHR, sizeof(uint32_t));
-    uint64_t cgen_var_1169;
-    stream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_1169, 1);
-    stream->write((uint64_t*)&cgen_var_1169, 1 * 8);
-    uint64_t cgen_var_1170;
-    stream->handleMapping()->mapHandles_VkBuffer_u64(&local_buffer, &cgen_var_1170, 1);
-    stream->write((uint64_t*)&cgen_var_1170, 1 * 8);
+    uint64_t cgen_var_1173;
+    stream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_1173, 1);
+    stream->write((uint64_t*)&cgen_var_1173, 1 * 8);
+    uint64_t cgen_var_1174;
+    stream->handleMapping()->mapHandles_VkBuffer_u64(&local_buffer, &cgen_var_1174, 1);
+    stream->write((uint64_t*)&cgen_var_1174, 1 * 8);
     stream->write((VkDeviceSize*)&local_offset, sizeof(VkDeviceSize));
-    uint64_t cgen_var_1171;
-    stream->handleMapping()->mapHandles_VkBuffer_u64(&local_countBuffer, &cgen_var_1171, 1);
-    stream->write((uint64_t*)&cgen_var_1171, 1 * 8);
+    uint64_t cgen_var_1175;
+    stream->handleMapping()->mapHandles_VkBuffer_u64(&local_countBuffer, &cgen_var_1175, 1);
+    stream->write((uint64_t*)&cgen_var_1175, 1 * 8);
     stream->write((VkDeviceSize*)&local_countBufferOffset, sizeof(VkDeviceSize));
     stream->write((uint32_t*)&local_maxDrawCount, sizeof(uint32_t));
     stream->write((uint32_t*)&local_stride, sizeof(uint32_t));
@@ -17629,6 +17994,7 @@
     uint32_t maxDrawCount,
     uint32_t stride)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkCmdDrawIndexedIndirectCountKHR encode");
     mImpl->log("start vkCmdDrawIndexedIndirectCountKHR");
     auto stream = mImpl->stream();
@@ -17652,16 +18018,16 @@
     local_stride = stride;
     countingStream->rewind();
     {
-        uint64_t cgen_var_1172;
-        countingStream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_1172, 1);
-        countingStream->write((uint64_t*)&cgen_var_1172, 1 * 8);
-        uint64_t cgen_var_1173;
-        countingStream->handleMapping()->mapHandles_VkBuffer_u64(&local_buffer, &cgen_var_1173, 1);
-        countingStream->write((uint64_t*)&cgen_var_1173, 1 * 8);
+        uint64_t cgen_var_1176;
+        countingStream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_1176, 1);
+        countingStream->write((uint64_t*)&cgen_var_1176, 1 * 8);
+        uint64_t cgen_var_1177;
+        countingStream->handleMapping()->mapHandles_VkBuffer_u64(&local_buffer, &cgen_var_1177, 1);
+        countingStream->write((uint64_t*)&cgen_var_1177, 1 * 8);
         countingStream->write((VkDeviceSize*)&local_offset, sizeof(VkDeviceSize));
-        uint64_t cgen_var_1174;
-        countingStream->handleMapping()->mapHandles_VkBuffer_u64(&local_countBuffer, &cgen_var_1174, 1);
-        countingStream->write((uint64_t*)&cgen_var_1174, 1 * 8);
+        uint64_t cgen_var_1178;
+        countingStream->handleMapping()->mapHandles_VkBuffer_u64(&local_countBuffer, &cgen_var_1178, 1);
+        countingStream->write((uint64_t*)&cgen_var_1178, 1 * 8);
         countingStream->write((VkDeviceSize*)&local_countBufferOffset, sizeof(VkDeviceSize));
         countingStream->write((uint32_t*)&local_maxDrawCount, sizeof(uint32_t));
         countingStream->write((uint32_t*)&local_stride, sizeof(uint32_t));
@@ -17671,16 +18037,16 @@
     uint32_t opcode_vkCmdDrawIndexedIndirectCountKHR = OP_vkCmdDrawIndexedIndirectCountKHR;
     stream->write(&opcode_vkCmdDrawIndexedIndirectCountKHR, sizeof(uint32_t));
     stream->write(&packetSize_vkCmdDrawIndexedIndirectCountKHR, sizeof(uint32_t));
-    uint64_t cgen_var_1175;
-    stream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_1175, 1);
-    stream->write((uint64_t*)&cgen_var_1175, 1 * 8);
-    uint64_t cgen_var_1176;
-    stream->handleMapping()->mapHandles_VkBuffer_u64(&local_buffer, &cgen_var_1176, 1);
-    stream->write((uint64_t*)&cgen_var_1176, 1 * 8);
+    uint64_t cgen_var_1179;
+    stream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_1179, 1);
+    stream->write((uint64_t*)&cgen_var_1179, 1 * 8);
+    uint64_t cgen_var_1180;
+    stream->handleMapping()->mapHandles_VkBuffer_u64(&local_buffer, &cgen_var_1180, 1);
+    stream->write((uint64_t*)&cgen_var_1180, 1 * 8);
     stream->write((VkDeviceSize*)&local_offset, sizeof(VkDeviceSize));
-    uint64_t cgen_var_1177;
-    stream->handleMapping()->mapHandles_VkBuffer_u64(&local_countBuffer, &cgen_var_1177, 1);
-    stream->write((uint64_t*)&cgen_var_1177, 1 * 8);
+    uint64_t cgen_var_1181;
+    stream->handleMapping()->mapHandles_VkBuffer_u64(&local_countBuffer, &cgen_var_1181, 1);
+    stream->write((uint64_t*)&cgen_var_1181, 1 * 8);
     stream->write((VkDeviceSize*)&local_countBufferOffset, sizeof(VkDeviceSize));
     stream->write((uint32_t*)&local_maxDrawCount, sizeof(uint32_t));
     stream->write((uint32_t*)&local_stride, sizeof(uint32_t));
@@ -17699,6 +18065,7 @@
     VkImageUsageFlags imageUsage,
     int* grallocUsage)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkGetSwapchainGrallocUsageANDROID encode");
     mImpl->log("start vkGetSwapchainGrallocUsageANDROID");
     auto stream = mImpl->stream();
@@ -17714,9 +18081,9 @@
     local_imageUsage = imageUsage;
     countingStream->rewind();
     {
-        uint64_t cgen_var_1178;
-        countingStream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_1178, 1);
-        countingStream->write((uint64_t*)&cgen_var_1178, 1 * 8);
+        uint64_t cgen_var_1182;
+        countingStream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_1182, 1);
+        countingStream->write((uint64_t*)&cgen_var_1182, 1 * 8);
         countingStream->write((VkFormat*)&local_format, sizeof(VkFormat));
         countingStream->write((VkImageUsageFlags*)&local_imageUsage, sizeof(VkImageUsageFlags));
         countingStream->write((int*)grallocUsage, sizeof(int));
@@ -17726,9 +18093,9 @@
     uint32_t opcode_vkGetSwapchainGrallocUsageANDROID = OP_vkGetSwapchainGrallocUsageANDROID;
     stream->write(&opcode_vkGetSwapchainGrallocUsageANDROID, sizeof(uint32_t));
     stream->write(&packetSize_vkGetSwapchainGrallocUsageANDROID, sizeof(uint32_t));
-    uint64_t cgen_var_1179;
-    stream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_1179, 1);
-    stream->write((uint64_t*)&cgen_var_1179, 1 * 8);
+    uint64_t cgen_var_1183;
+    stream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_1183, 1);
+    stream->write((uint64_t*)&cgen_var_1183, 1 * 8);
     stream->write((VkFormat*)&local_format, sizeof(VkFormat));
     stream->write((VkImageUsageFlags*)&local_imageUsage, sizeof(VkImageUsageFlags));
     stream->write((int*)grallocUsage, sizeof(int));
@@ -17751,6 +18118,7 @@
     VkSemaphore semaphore,
     VkFence fence)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkAcquireImageANDROID encode");
     mImpl->log("start vkAcquireImageANDROID");
     auto stream = mImpl->stream();
@@ -17771,38 +18139,38 @@
     mImpl->resources()->unwrap_vkAcquireImageANDROID_nativeFenceFd(nativeFenceFd, &local_nativeFenceFd);
     countingStream->rewind();
     {
-        uint64_t cgen_var_1180;
-        countingStream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_1180, 1);
-        countingStream->write((uint64_t*)&cgen_var_1180, 1 * 8);
-        uint64_t cgen_var_1181;
-        countingStream->handleMapping()->mapHandles_VkImage_u64(&local_image, &cgen_var_1181, 1);
-        countingStream->write((uint64_t*)&cgen_var_1181, 1 * 8);
+        uint64_t cgen_var_1184;
+        countingStream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_1184, 1);
+        countingStream->write((uint64_t*)&cgen_var_1184, 1 * 8);
+        uint64_t cgen_var_1185;
+        countingStream->handleMapping()->mapHandles_VkImage_u64(&local_image, &cgen_var_1185, 1);
+        countingStream->write((uint64_t*)&cgen_var_1185, 1 * 8);
         countingStream->write((int*)&local_nativeFenceFd, sizeof(int));
-        uint64_t cgen_var_1182;
-        countingStream->handleMapping()->mapHandles_VkSemaphore_u64(&local_semaphore, &cgen_var_1182, 1);
-        countingStream->write((uint64_t*)&cgen_var_1182, 1 * 8);
-        uint64_t cgen_var_1183;
-        countingStream->handleMapping()->mapHandles_VkFence_u64(&local_fence, &cgen_var_1183, 1);
-        countingStream->write((uint64_t*)&cgen_var_1183, 1 * 8);
+        uint64_t cgen_var_1186;
+        countingStream->handleMapping()->mapHandles_VkSemaphore_u64(&local_semaphore, &cgen_var_1186, 1);
+        countingStream->write((uint64_t*)&cgen_var_1186, 1 * 8);
+        uint64_t cgen_var_1187;
+        countingStream->handleMapping()->mapHandles_VkFence_u64(&local_fence, &cgen_var_1187, 1);
+        countingStream->write((uint64_t*)&cgen_var_1187, 1 * 8);
     }
     uint32_t packetSize_vkAcquireImageANDROID = 4 + 4 + (uint32_t)countingStream->bytesWritten();
     countingStream->rewind();
     uint32_t opcode_vkAcquireImageANDROID = OP_vkAcquireImageANDROID;
     stream->write(&opcode_vkAcquireImageANDROID, sizeof(uint32_t));
     stream->write(&packetSize_vkAcquireImageANDROID, sizeof(uint32_t));
-    uint64_t cgen_var_1184;
-    stream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_1184, 1);
-    stream->write((uint64_t*)&cgen_var_1184, 1 * 8);
-    uint64_t cgen_var_1185;
-    stream->handleMapping()->mapHandles_VkImage_u64(&local_image, &cgen_var_1185, 1);
-    stream->write((uint64_t*)&cgen_var_1185, 1 * 8);
+    uint64_t cgen_var_1188;
+    stream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_1188, 1);
+    stream->write((uint64_t*)&cgen_var_1188, 1 * 8);
+    uint64_t cgen_var_1189;
+    stream->handleMapping()->mapHandles_VkImage_u64(&local_image, &cgen_var_1189, 1);
+    stream->write((uint64_t*)&cgen_var_1189, 1 * 8);
     stream->write((int*)&local_nativeFenceFd, sizeof(int));
-    uint64_t cgen_var_1186;
-    stream->handleMapping()->mapHandles_VkSemaphore_u64(&local_semaphore, &cgen_var_1186, 1);
-    stream->write((uint64_t*)&cgen_var_1186, 1 * 8);
-    uint64_t cgen_var_1187;
-    stream->handleMapping()->mapHandles_VkFence_u64(&local_fence, &cgen_var_1187, 1);
-    stream->write((uint64_t*)&cgen_var_1187, 1 * 8);
+    uint64_t cgen_var_1190;
+    stream->handleMapping()->mapHandles_VkSemaphore_u64(&local_semaphore, &cgen_var_1190, 1);
+    stream->write((uint64_t*)&cgen_var_1190, 1 * 8);
+    uint64_t cgen_var_1191;
+    stream->handleMapping()->mapHandles_VkFence_u64(&local_fence, &cgen_var_1191, 1);
+    stream->write((uint64_t*)&cgen_var_1191, 1 * 8);
     AEMU_SCOPED_TRACE("vkAcquireImageANDROID readParams");
     AEMU_SCOPED_TRACE("vkAcquireImageANDROID returnUnmarshal");
     VkResult vkAcquireImageANDROID_VkResult_return = (VkResult)0;
@@ -17821,6 +18189,7 @@
     VkImage image,
     int* pNativeFenceFd)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkQueueSignalReleaseImageANDROID encode");
     mImpl->log("start vkQueueSignalReleaseImageANDROID");
     auto stream = mImpl->stream();
@@ -17842,26 +18211,26 @@
     local_image = image;
     countingStream->rewind();
     {
-        uint64_t cgen_var_1188;
-        countingStream->handleMapping()->mapHandles_VkQueue_u64(&local_queue, &cgen_var_1188, 1);
-        countingStream->write((uint64_t*)&cgen_var_1188, 1 * 8);
+        uint64_t cgen_var_1192;
+        countingStream->handleMapping()->mapHandles_VkQueue_u64(&local_queue, &cgen_var_1192, 1);
+        countingStream->write((uint64_t*)&cgen_var_1192, 1 * 8);
         countingStream->write((uint32_t*)&local_waitSemaphoreCount, sizeof(uint32_t));
         // WARNING PTR CHECK
-        uint64_t cgen_var_1189 = (uint64_t)(uintptr_t)local_pWaitSemaphores;
-        countingStream->putBe64(cgen_var_1189);
+        uint64_t cgen_var_1193 = (uint64_t)(uintptr_t)local_pWaitSemaphores;
+        countingStream->putBe64(cgen_var_1193);
         if (local_pWaitSemaphores)
         {
             if (((waitSemaphoreCount)))
             {
-                uint64_t* cgen_var_1190;
-                countingStream->alloc((void**)&cgen_var_1190, ((waitSemaphoreCount)) * 8);
-                countingStream->handleMapping()->mapHandles_VkSemaphore_u64(local_pWaitSemaphores, cgen_var_1190, ((waitSemaphoreCount)));
-                countingStream->write((uint64_t*)cgen_var_1190, ((waitSemaphoreCount)) * 8);
+                uint64_t* cgen_var_1194;
+                countingStream->alloc((void**)&cgen_var_1194, ((waitSemaphoreCount)) * 8);
+                countingStream->handleMapping()->mapHandles_VkSemaphore_u64(local_pWaitSemaphores, cgen_var_1194, ((waitSemaphoreCount)));
+                countingStream->write((uint64_t*)cgen_var_1194, ((waitSemaphoreCount)) * 8);
             }
         }
-        uint64_t cgen_var_1191;
-        countingStream->handleMapping()->mapHandles_VkImage_u64(&local_image, &cgen_var_1191, 1);
-        countingStream->write((uint64_t*)&cgen_var_1191, 1 * 8);
+        uint64_t cgen_var_1195;
+        countingStream->handleMapping()->mapHandles_VkImage_u64(&local_image, &cgen_var_1195, 1);
+        countingStream->write((uint64_t*)&cgen_var_1195, 1 * 8);
         countingStream->write((int*)pNativeFenceFd, sizeof(int));
     }
     uint32_t packetSize_vkQueueSignalReleaseImageANDROID = 4 + 4 + (uint32_t)countingStream->bytesWritten();
@@ -17869,26 +18238,26 @@
     uint32_t opcode_vkQueueSignalReleaseImageANDROID = OP_vkQueueSignalReleaseImageANDROID;
     stream->write(&opcode_vkQueueSignalReleaseImageANDROID, sizeof(uint32_t));
     stream->write(&packetSize_vkQueueSignalReleaseImageANDROID, sizeof(uint32_t));
-    uint64_t cgen_var_1192;
-    stream->handleMapping()->mapHandles_VkQueue_u64(&local_queue, &cgen_var_1192, 1);
-    stream->write((uint64_t*)&cgen_var_1192, 1 * 8);
+    uint64_t cgen_var_1196;
+    stream->handleMapping()->mapHandles_VkQueue_u64(&local_queue, &cgen_var_1196, 1);
+    stream->write((uint64_t*)&cgen_var_1196, 1 * 8);
     stream->write((uint32_t*)&local_waitSemaphoreCount, sizeof(uint32_t));
     // WARNING PTR CHECK
-    uint64_t cgen_var_1193 = (uint64_t)(uintptr_t)local_pWaitSemaphores;
-    stream->putBe64(cgen_var_1193);
+    uint64_t cgen_var_1197 = (uint64_t)(uintptr_t)local_pWaitSemaphores;
+    stream->putBe64(cgen_var_1197);
     if (local_pWaitSemaphores)
     {
         if (((waitSemaphoreCount)))
         {
-            uint64_t* cgen_var_1194;
-            stream->alloc((void**)&cgen_var_1194, ((waitSemaphoreCount)) * 8);
-            stream->handleMapping()->mapHandles_VkSemaphore_u64(local_pWaitSemaphores, cgen_var_1194, ((waitSemaphoreCount)));
-            stream->write((uint64_t*)cgen_var_1194, ((waitSemaphoreCount)) * 8);
+            uint64_t* cgen_var_1198;
+            stream->alloc((void**)&cgen_var_1198, ((waitSemaphoreCount)) * 8);
+            stream->handleMapping()->mapHandles_VkSemaphore_u64(local_pWaitSemaphores, cgen_var_1198, ((waitSemaphoreCount)));
+            stream->write((uint64_t*)cgen_var_1198, ((waitSemaphoreCount)) * 8);
         }
     }
-    uint64_t cgen_var_1195;
-    stream->handleMapping()->mapHandles_VkImage_u64(&local_image, &cgen_var_1195, 1);
-    stream->write((uint64_t*)&cgen_var_1195, 1 * 8);
+    uint64_t cgen_var_1199;
+    stream->handleMapping()->mapHandles_VkImage_u64(&local_image, &cgen_var_1199, 1);
+    stream->write((uint64_t*)&cgen_var_1199, 1 * 8);
     stream->write((int*)pNativeFenceFd, sizeof(int));
     AEMU_SCOPED_TRACE("vkQueueSignalReleaseImageANDROID readParams");
     stream->read((int*)pNativeFenceFd, sizeof(int));
@@ -17910,6 +18279,7 @@
     const VkAllocationCallbacks* pAllocator,
     VkDebugReportCallbackEXT* pCallback)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkCreateDebugReportCallbackEXT encode");
     mImpl->log("start vkCreateDebugReportCallbackEXT");
     auto stream = mImpl->stream();
@@ -17944,47 +18314,47 @@
     }
     countingStream->rewind();
     {
-        uint64_t cgen_var_1196;
-        countingStream->handleMapping()->mapHandles_VkInstance_u64(&local_instance, &cgen_var_1196, 1);
-        countingStream->write((uint64_t*)&cgen_var_1196, 1 * 8);
+        uint64_t cgen_var_1200;
+        countingStream->handleMapping()->mapHandles_VkInstance_u64(&local_instance, &cgen_var_1200, 1);
+        countingStream->write((uint64_t*)&cgen_var_1200, 1 * 8);
         marshal_VkDebugReportCallbackCreateInfoEXT(countingStream, (VkDebugReportCallbackCreateInfoEXT*)(local_pCreateInfo));
         // WARNING PTR CHECK
-        uint64_t cgen_var_1197 = (uint64_t)(uintptr_t)local_pAllocator;
-        countingStream->putBe64(cgen_var_1197);
+        uint64_t cgen_var_1201 = (uint64_t)(uintptr_t)local_pAllocator;
+        countingStream->putBe64(cgen_var_1201);
         if (local_pAllocator)
         {
             marshal_VkAllocationCallbacks(countingStream, (VkAllocationCallbacks*)(local_pAllocator));
         }
-        uint64_t cgen_var_1198;
-        countingStream->handleMapping()->mapHandles_VkDebugReportCallbackEXT_u64(pCallback, &cgen_var_1198, 1);
-        countingStream->write((uint64_t*)&cgen_var_1198, 8);
+        uint64_t cgen_var_1202;
+        countingStream->handleMapping()->mapHandles_VkDebugReportCallbackEXT_u64(pCallback, &cgen_var_1202, 1);
+        countingStream->write((uint64_t*)&cgen_var_1202, 8);
     }
     uint32_t packetSize_vkCreateDebugReportCallbackEXT = 4 + 4 + (uint32_t)countingStream->bytesWritten();
     countingStream->rewind();
     uint32_t opcode_vkCreateDebugReportCallbackEXT = OP_vkCreateDebugReportCallbackEXT;
     stream->write(&opcode_vkCreateDebugReportCallbackEXT, sizeof(uint32_t));
     stream->write(&packetSize_vkCreateDebugReportCallbackEXT, sizeof(uint32_t));
-    uint64_t cgen_var_1199;
-    stream->handleMapping()->mapHandles_VkInstance_u64(&local_instance, &cgen_var_1199, 1);
-    stream->write((uint64_t*)&cgen_var_1199, 1 * 8);
+    uint64_t cgen_var_1203;
+    stream->handleMapping()->mapHandles_VkInstance_u64(&local_instance, &cgen_var_1203, 1);
+    stream->write((uint64_t*)&cgen_var_1203, 1 * 8);
     marshal_VkDebugReportCallbackCreateInfoEXT(stream, (VkDebugReportCallbackCreateInfoEXT*)(local_pCreateInfo));
     // WARNING PTR CHECK
-    uint64_t cgen_var_1200 = (uint64_t)(uintptr_t)local_pAllocator;
-    stream->putBe64(cgen_var_1200);
+    uint64_t cgen_var_1204 = (uint64_t)(uintptr_t)local_pAllocator;
+    stream->putBe64(cgen_var_1204);
     if (local_pAllocator)
     {
         marshal_VkAllocationCallbacks(stream, (VkAllocationCallbacks*)(local_pAllocator));
     }
     stream->unsetHandleMapping() /* emit_marshal, is handle, possibly out */;
-    uint64_t cgen_var_1201;
-    stream->handleMapping()->mapHandles_VkDebugReportCallbackEXT_u64(pCallback, &cgen_var_1201, 1);
-    stream->write((uint64_t*)&cgen_var_1201, 8);
+    uint64_t cgen_var_1205;
+    stream->handleMapping()->mapHandles_VkDebugReportCallbackEXT_u64(pCallback, &cgen_var_1205, 1);
+    stream->write((uint64_t*)&cgen_var_1205, 8);
     stream->setHandleMapping(resources->unwrapMapping());
     AEMU_SCOPED_TRACE("vkCreateDebugReportCallbackEXT readParams");
     stream->setHandleMapping(resources->createMapping());
-    uint64_t cgen_var_1202;
-    stream->read((uint64_t*)&cgen_var_1202, 8);
-    stream->handleMapping()->mapHandles_u64_VkDebugReportCallbackEXT(&cgen_var_1202, (VkDebugReportCallbackEXT*)pCallback, 1);
+    uint64_t cgen_var_1206;
+    stream->read((uint64_t*)&cgen_var_1206, 8);
+    stream->handleMapping()->mapHandles_u64_VkDebugReportCallbackEXT(&cgen_var_1206, (VkDebugReportCallbackEXT*)pCallback, 1);
     stream->unsetHandleMapping();
     AEMU_SCOPED_TRACE("vkCreateDebugReportCallbackEXT returnUnmarshal");
     VkResult vkCreateDebugReportCallbackEXT_VkResult_return = (VkResult)0;
@@ -18001,6 +18371,7 @@
     VkDebugReportCallbackEXT callback,
     const VkAllocationCallbacks* pAllocator)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkDestroyDebugReportCallbackEXT encode");
     mImpl->log("start vkDestroyDebugReportCallbackEXT");
     auto stream = mImpl->stream();
@@ -18026,15 +18397,15 @@
     }
     countingStream->rewind();
     {
-        uint64_t cgen_var_1203;
-        countingStream->handleMapping()->mapHandles_VkInstance_u64(&local_instance, &cgen_var_1203, 1);
-        countingStream->write((uint64_t*)&cgen_var_1203, 1 * 8);
-        uint64_t cgen_var_1204;
-        countingStream->handleMapping()->mapHandles_VkDebugReportCallbackEXT_u64(&local_callback, &cgen_var_1204, 1);
-        countingStream->write((uint64_t*)&cgen_var_1204, 1 * 8);
+        uint64_t cgen_var_1207;
+        countingStream->handleMapping()->mapHandles_VkInstance_u64(&local_instance, &cgen_var_1207, 1);
+        countingStream->write((uint64_t*)&cgen_var_1207, 1 * 8);
+        uint64_t cgen_var_1208;
+        countingStream->handleMapping()->mapHandles_VkDebugReportCallbackEXT_u64(&local_callback, &cgen_var_1208, 1);
+        countingStream->write((uint64_t*)&cgen_var_1208, 1 * 8);
         // WARNING PTR CHECK
-        uint64_t cgen_var_1205 = (uint64_t)(uintptr_t)local_pAllocator;
-        countingStream->putBe64(cgen_var_1205);
+        uint64_t cgen_var_1209 = (uint64_t)(uintptr_t)local_pAllocator;
+        countingStream->putBe64(cgen_var_1209);
         if (local_pAllocator)
         {
             marshal_VkAllocationCallbacks(countingStream, (VkAllocationCallbacks*)(local_pAllocator));
@@ -18045,15 +18416,15 @@
     uint32_t opcode_vkDestroyDebugReportCallbackEXT = OP_vkDestroyDebugReportCallbackEXT;
     stream->write(&opcode_vkDestroyDebugReportCallbackEXT, sizeof(uint32_t));
     stream->write(&packetSize_vkDestroyDebugReportCallbackEXT, sizeof(uint32_t));
-    uint64_t cgen_var_1206;
-    stream->handleMapping()->mapHandles_VkInstance_u64(&local_instance, &cgen_var_1206, 1);
-    stream->write((uint64_t*)&cgen_var_1206, 1 * 8);
-    uint64_t cgen_var_1207;
-    stream->handleMapping()->mapHandles_VkDebugReportCallbackEXT_u64(&local_callback, &cgen_var_1207, 1);
-    stream->write((uint64_t*)&cgen_var_1207, 1 * 8);
+    uint64_t cgen_var_1210;
+    stream->handleMapping()->mapHandles_VkInstance_u64(&local_instance, &cgen_var_1210, 1);
+    stream->write((uint64_t*)&cgen_var_1210, 1 * 8);
+    uint64_t cgen_var_1211;
+    stream->handleMapping()->mapHandles_VkDebugReportCallbackEXT_u64(&local_callback, &cgen_var_1211, 1);
+    stream->write((uint64_t*)&cgen_var_1211, 1 * 8);
     // WARNING PTR CHECK
-    uint64_t cgen_var_1208 = (uint64_t)(uintptr_t)local_pAllocator;
-    stream->putBe64(cgen_var_1208);
+    uint64_t cgen_var_1212 = (uint64_t)(uintptr_t)local_pAllocator;
+    stream->putBe64(cgen_var_1212);
     if (local_pAllocator)
     {
         marshal_VkAllocationCallbacks(stream, (VkAllocationCallbacks*)(local_pAllocator));
@@ -18074,6 +18445,7 @@
     const char* pLayerPrefix,
     const char* pMessage)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkDebugReportMessageEXT encode");
     mImpl->log("start vkDebugReportMessageEXT");
     auto stream = mImpl->stream();
@@ -18107,14 +18479,14 @@
     }
     countingStream->rewind();
     {
-        uint64_t cgen_var_1209;
-        countingStream->handleMapping()->mapHandles_VkInstance_u64(&local_instance, &cgen_var_1209, 1);
-        countingStream->write((uint64_t*)&cgen_var_1209, 1 * 8);
+        uint64_t cgen_var_1213;
+        countingStream->handleMapping()->mapHandles_VkInstance_u64(&local_instance, &cgen_var_1213, 1);
+        countingStream->write((uint64_t*)&cgen_var_1213, 1 * 8);
         countingStream->write((VkDebugReportFlagsEXT*)&local_flags, sizeof(VkDebugReportFlagsEXT));
         countingStream->write((VkDebugReportObjectTypeEXT*)&local_objectType, sizeof(VkDebugReportObjectTypeEXT));
         countingStream->write((uint64_t*)&local_object, sizeof(uint64_t));
-        uint64_t cgen_var_1210 = (uint64_t)local_location;
-        countingStream->putBe64(cgen_var_1210);
+        uint64_t cgen_var_1214 = (uint64_t)local_location;
+        countingStream->putBe64(cgen_var_1214);
         countingStream->write((int32_t*)&local_messageCode, sizeof(int32_t));
         countingStream->putString(local_pLayerPrefix);
         countingStream->putString(local_pMessage);
@@ -18124,14 +18496,14 @@
     uint32_t opcode_vkDebugReportMessageEXT = OP_vkDebugReportMessageEXT;
     stream->write(&opcode_vkDebugReportMessageEXT, sizeof(uint32_t));
     stream->write(&packetSize_vkDebugReportMessageEXT, sizeof(uint32_t));
-    uint64_t cgen_var_1211;
-    stream->handleMapping()->mapHandles_VkInstance_u64(&local_instance, &cgen_var_1211, 1);
-    stream->write((uint64_t*)&cgen_var_1211, 1 * 8);
+    uint64_t cgen_var_1215;
+    stream->handleMapping()->mapHandles_VkInstance_u64(&local_instance, &cgen_var_1215, 1);
+    stream->write((uint64_t*)&cgen_var_1215, 1 * 8);
     stream->write((VkDebugReportFlagsEXT*)&local_flags, sizeof(VkDebugReportFlagsEXT));
     stream->write((VkDebugReportObjectTypeEXT*)&local_objectType, sizeof(VkDebugReportObjectTypeEXT));
     stream->write((uint64_t*)&local_object, sizeof(uint64_t));
-    uint64_t cgen_var_1212 = (uint64_t)local_location;
-    stream->putBe64(cgen_var_1212);
+    uint64_t cgen_var_1216 = (uint64_t)local_location;
+    stream->putBe64(cgen_var_1216);
     stream->write((int32_t*)&local_messageCode, sizeof(int32_t));
     stream->putString(local_pLayerPrefix);
     stream->putString(local_pMessage);
@@ -18158,6 +18530,7 @@
     VkDevice device,
     const VkDebugMarkerObjectTagInfoEXT* pTagInfo)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkDebugMarkerSetObjectTagEXT encode");
     mImpl->log("start vkDebugMarkerSetObjectTagEXT");
     auto stream = mImpl->stream();
@@ -18180,9 +18553,9 @@
     }
     countingStream->rewind();
     {
-        uint64_t cgen_var_1213;
-        countingStream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_1213, 1);
-        countingStream->write((uint64_t*)&cgen_var_1213, 1 * 8);
+        uint64_t cgen_var_1217;
+        countingStream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_1217, 1);
+        countingStream->write((uint64_t*)&cgen_var_1217, 1 * 8);
         marshal_VkDebugMarkerObjectTagInfoEXT(countingStream, (VkDebugMarkerObjectTagInfoEXT*)(local_pTagInfo));
     }
     uint32_t packetSize_vkDebugMarkerSetObjectTagEXT = 4 + 4 + (uint32_t)countingStream->bytesWritten();
@@ -18190,9 +18563,9 @@
     uint32_t opcode_vkDebugMarkerSetObjectTagEXT = OP_vkDebugMarkerSetObjectTagEXT;
     stream->write(&opcode_vkDebugMarkerSetObjectTagEXT, sizeof(uint32_t));
     stream->write(&packetSize_vkDebugMarkerSetObjectTagEXT, sizeof(uint32_t));
-    uint64_t cgen_var_1214;
-    stream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_1214, 1);
-    stream->write((uint64_t*)&cgen_var_1214, 1 * 8);
+    uint64_t cgen_var_1218;
+    stream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_1218, 1);
+    stream->write((uint64_t*)&cgen_var_1218, 1 * 8);
     marshal_VkDebugMarkerObjectTagInfoEXT(stream, (VkDebugMarkerObjectTagInfoEXT*)(local_pTagInfo));
     AEMU_SCOPED_TRACE("vkDebugMarkerSetObjectTagEXT readParams");
     AEMU_SCOPED_TRACE("vkDebugMarkerSetObjectTagEXT returnUnmarshal");
@@ -18209,6 +18582,7 @@
     VkDevice device,
     const VkDebugMarkerObjectNameInfoEXT* pNameInfo)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkDebugMarkerSetObjectNameEXT encode");
     mImpl->log("start vkDebugMarkerSetObjectNameEXT");
     auto stream = mImpl->stream();
@@ -18231,9 +18605,9 @@
     }
     countingStream->rewind();
     {
-        uint64_t cgen_var_1215;
-        countingStream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_1215, 1);
-        countingStream->write((uint64_t*)&cgen_var_1215, 1 * 8);
+        uint64_t cgen_var_1219;
+        countingStream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_1219, 1);
+        countingStream->write((uint64_t*)&cgen_var_1219, 1 * 8);
         marshal_VkDebugMarkerObjectNameInfoEXT(countingStream, (VkDebugMarkerObjectNameInfoEXT*)(local_pNameInfo));
     }
     uint32_t packetSize_vkDebugMarkerSetObjectNameEXT = 4 + 4 + (uint32_t)countingStream->bytesWritten();
@@ -18241,9 +18615,9 @@
     uint32_t opcode_vkDebugMarkerSetObjectNameEXT = OP_vkDebugMarkerSetObjectNameEXT;
     stream->write(&opcode_vkDebugMarkerSetObjectNameEXT, sizeof(uint32_t));
     stream->write(&packetSize_vkDebugMarkerSetObjectNameEXT, sizeof(uint32_t));
-    uint64_t cgen_var_1216;
-    stream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_1216, 1);
-    stream->write((uint64_t*)&cgen_var_1216, 1 * 8);
+    uint64_t cgen_var_1220;
+    stream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_1220, 1);
+    stream->write((uint64_t*)&cgen_var_1220, 1 * 8);
     marshal_VkDebugMarkerObjectNameInfoEXT(stream, (VkDebugMarkerObjectNameInfoEXT*)(local_pNameInfo));
     AEMU_SCOPED_TRACE("vkDebugMarkerSetObjectNameEXT readParams");
     AEMU_SCOPED_TRACE("vkDebugMarkerSetObjectNameEXT returnUnmarshal");
@@ -18260,6 +18634,7 @@
     VkCommandBuffer commandBuffer,
     const VkDebugMarkerMarkerInfoEXT* pMarkerInfo)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkCmdDebugMarkerBeginEXT encode");
     mImpl->log("start vkCmdDebugMarkerBeginEXT");
     auto stream = mImpl->stream();
@@ -18282,95 +18657,97 @@
     }
     countingStream->rewind();
     {
-        uint64_t cgen_var_1217;
-        countingStream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_1217, 1);
-        countingStream->write((uint64_t*)&cgen_var_1217, 1 * 8);
-        marshal_VkDebugMarkerMarkerInfoEXT(countingStream, (VkDebugMarkerMarkerInfoEXT*)(local_pMarkerInfo));
-    }
-    uint32_t packetSize_vkCmdDebugMarkerBeginEXT = 4 + 4 + (uint32_t)countingStream->bytesWritten();
-    countingStream->rewind();
-    uint32_t opcode_vkCmdDebugMarkerBeginEXT = OP_vkCmdDebugMarkerBeginEXT;
-    stream->write(&opcode_vkCmdDebugMarkerBeginEXT, sizeof(uint32_t));
-    stream->write(&packetSize_vkCmdDebugMarkerBeginEXT, sizeof(uint32_t));
-    uint64_t cgen_var_1218;
-    stream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_1218, 1);
-    stream->write((uint64_t*)&cgen_var_1218, 1 * 8);
-    marshal_VkDebugMarkerMarkerInfoEXT(stream, (VkDebugMarkerMarkerInfoEXT*)(local_pMarkerInfo));
-    AEMU_SCOPED_TRACE("vkCmdDebugMarkerBeginEXT readParams");
-    AEMU_SCOPED_TRACE("vkCmdDebugMarkerBeginEXT returnUnmarshal");
-    mImpl->log("finish vkCmdDebugMarkerBeginEXT");;
-}
-
-void VkEncoder::vkCmdDebugMarkerEndEXT(
-    VkCommandBuffer commandBuffer)
-{
-    AEMU_SCOPED_TRACE("vkCmdDebugMarkerEndEXT encode");
-    mImpl->log("start vkCmdDebugMarkerEndEXT");
-    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_1219;
-        countingStream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_1219, 1);
-        countingStream->write((uint64_t*)&cgen_var_1219, 1 * 8);
-    }
-    uint32_t packetSize_vkCmdDebugMarkerEndEXT = 4 + 4 + (uint32_t)countingStream->bytesWritten();
-    countingStream->rewind();
-    uint32_t opcode_vkCmdDebugMarkerEndEXT = OP_vkCmdDebugMarkerEndEXT;
-    stream->write(&opcode_vkCmdDebugMarkerEndEXT, sizeof(uint32_t));
-    stream->write(&packetSize_vkCmdDebugMarkerEndEXT, sizeof(uint32_t));
-    uint64_t cgen_var_1220;
-    stream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_1220, 1);
-    stream->write((uint64_t*)&cgen_var_1220, 1 * 8);
-    AEMU_SCOPED_TRACE("vkCmdDebugMarkerEndEXT readParams");
-    AEMU_SCOPED_TRACE("vkCmdDebugMarkerEndEXT returnUnmarshal");
-    mImpl->log("finish vkCmdDebugMarkerEndEXT");;
-}
-
-void VkEncoder::vkCmdDebugMarkerInsertEXT(
-    VkCommandBuffer commandBuffer,
-    const VkDebugMarkerMarkerInfoEXT* pMarkerInfo)
-{
-    AEMU_SCOPED_TRACE("vkCmdDebugMarkerInsertEXT encode");
-    mImpl->log("start vkCmdDebugMarkerInsertEXT");
-    auto stream = mImpl->stream();
-    auto countingStream = mImpl->countingStream();
-    auto resources = mImpl->resources();
-    auto pool = mImpl->pool();
-    stream->setHandleMapping(resources->unwrapMapping());
-    VkCommandBuffer local_commandBuffer;
-    VkDebugMarkerMarkerInfoEXT* local_pMarkerInfo;
-    local_commandBuffer = commandBuffer;
-    local_pMarkerInfo = nullptr;
-    if (pMarkerInfo)
-    {
-        local_pMarkerInfo = (VkDebugMarkerMarkerInfoEXT*)pool->alloc(sizeof(const VkDebugMarkerMarkerInfoEXT));
-        deepcopy_VkDebugMarkerMarkerInfoEXT(pool, pMarkerInfo, (VkDebugMarkerMarkerInfoEXT*)(local_pMarkerInfo));
-    }
-    if (local_pMarkerInfo)
-    {
-        transform_tohost_VkDebugMarkerMarkerInfoEXT(mImpl->resources(), (VkDebugMarkerMarkerInfoEXT*)(local_pMarkerInfo));
-    }
-    countingStream->rewind();
-    {
         uint64_t cgen_var_1221;
         countingStream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_1221, 1);
         countingStream->write((uint64_t*)&cgen_var_1221, 1 * 8);
         marshal_VkDebugMarkerMarkerInfoEXT(countingStream, (VkDebugMarkerMarkerInfoEXT*)(local_pMarkerInfo));
     }
+    uint32_t packetSize_vkCmdDebugMarkerBeginEXT = 4 + 4 + (uint32_t)countingStream->bytesWritten();
+    countingStream->rewind();
+    uint32_t opcode_vkCmdDebugMarkerBeginEXT = OP_vkCmdDebugMarkerBeginEXT;
+    stream->write(&opcode_vkCmdDebugMarkerBeginEXT, sizeof(uint32_t));
+    stream->write(&packetSize_vkCmdDebugMarkerBeginEXT, sizeof(uint32_t));
+    uint64_t cgen_var_1222;
+    stream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_1222, 1);
+    stream->write((uint64_t*)&cgen_var_1222, 1 * 8);
+    marshal_VkDebugMarkerMarkerInfoEXT(stream, (VkDebugMarkerMarkerInfoEXT*)(local_pMarkerInfo));
+    AEMU_SCOPED_TRACE("vkCmdDebugMarkerBeginEXT readParams");
+    AEMU_SCOPED_TRACE("vkCmdDebugMarkerBeginEXT returnUnmarshal");
+    mImpl->log("finish vkCmdDebugMarkerBeginEXT");;
+}
+
+void VkEncoder::vkCmdDebugMarkerEndEXT(
+    VkCommandBuffer commandBuffer)
+{
+    AutoLock encoderLock(mImpl->lock);
+    AEMU_SCOPED_TRACE("vkCmdDebugMarkerEndEXT encode");
+    mImpl->log("start vkCmdDebugMarkerEndEXT");
+    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_1223;
+        countingStream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_1223, 1);
+        countingStream->write((uint64_t*)&cgen_var_1223, 1 * 8);
+    }
+    uint32_t packetSize_vkCmdDebugMarkerEndEXT = 4 + 4 + (uint32_t)countingStream->bytesWritten();
+    countingStream->rewind();
+    uint32_t opcode_vkCmdDebugMarkerEndEXT = OP_vkCmdDebugMarkerEndEXT;
+    stream->write(&opcode_vkCmdDebugMarkerEndEXT, sizeof(uint32_t));
+    stream->write(&packetSize_vkCmdDebugMarkerEndEXT, sizeof(uint32_t));
+    uint64_t cgen_var_1224;
+    stream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_1224, 1);
+    stream->write((uint64_t*)&cgen_var_1224, 1 * 8);
+    AEMU_SCOPED_TRACE("vkCmdDebugMarkerEndEXT readParams");
+    AEMU_SCOPED_TRACE("vkCmdDebugMarkerEndEXT returnUnmarshal");
+    mImpl->log("finish vkCmdDebugMarkerEndEXT");;
+}
+
+void VkEncoder::vkCmdDebugMarkerInsertEXT(
+    VkCommandBuffer commandBuffer,
+    const VkDebugMarkerMarkerInfoEXT* pMarkerInfo)
+{
+    AutoLock encoderLock(mImpl->lock);
+    AEMU_SCOPED_TRACE("vkCmdDebugMarkerInsertEXT encode");
+    mImpl->log("start vkCmdDebugMarkerInsertEXT");
+    auto stream = mImpl->stream();
+    auto countingStream = mImpl->countingStream();
+    auto resources = mImpl->resources();
+    auto pool = mImpl->pool();
+    stream->setHandleMapping(resources->unwrapMapping());
+    VkCommandBuffer local_commandBuffer;
+    VkDebugMarkerMarkerInfoEXT* local_pMarkerInfo;
+    local_commandBuffer = commandBuffer;
+    local_pMarkerInfo = nullptr;
+    if (pMarkerInfo)
+    {
+        local_pMarkerInfo = (VkDebugMarkerMarkerInfoEXT*)pool->alloc(sizeof(const VkDebugMarkerMarkerInfoEXT));
+        deepcopy_VkDebugMarkerMarkerInfoEXT(pool, pMarkerInfo, (VkDebugMarkerMarkerInfoEXT*)(local_pMarkerInfo));
+    }
+    if (local_pMarkerInfo)
+    {
+        transform_tohost_VkDebugMarkerMarkerInfoEXT(mImpl->resources(), (VkDebugMarkerMarkerInfoEXT*)(local_pMarkerInfo));
+    }
+    countingStream->rewind();
+    {
+        uint64_t cgen_var_1225;
+        countingStream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_1225, 1);
+        countingStream->write((uint64_t*)&cgen_var_1225, 1 * 8);
+        marshal_VkDebugMarkerMarkerInfoEXT(countingStream, (VkDebugMarkerMarkerInfoEXT*)(local_pMarkerInfo));
+    }
     uint32_t packetSize_vkCmdDebugMarkerInsertEXT = 4 + 4 + (uint32_t)countingStream->bytesWritten();
     countingStream->rewind();
     uint32_t opcode_vkCmdDebugMarkerInsertEXT = OP_vkCmdDebugMarkerInsertEXT;
     stream->write(&opcode_vkCmdDebugMarkerInsertEXT, sizeof(uint32_t));
     stream->write(&packetSize_vkCmdDebugMarkerInsertEXT, sizeof(uint32_t));
-    uint64_t cgen_var_1222;
-    stream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_1222, 1);
-    stream->write((uint64_t*)&cgen_var_1222, 1 * 8);
+    uint64_t cgen_var_1226;
+    stream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_1226, 1);
+    stream->write((uint64_t*)&cgen_var_1226, 1 * 8);
     marshal_VkDebugMarkerMarkerInfoEXT(stream, (VkDebugMarkerMarkerInfoEXT*)(local_pMarkerInfo));
     AEMU_SCOPED_TRACE("vkCmdDebugMarkerInsertEXT readParams");
     AEMU_SCOPED_TRACE("vkCmdDebugMarkerInsertEXT returnUnmarshal");
@@ -18392,6 +18769,7 @@
     uint32_t maxDrawCount,
     uint32_t stride)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkCmdDrawIndirectCountAMD encode");
     mImpl->log("start vkCmdDrawIndirectCountAMD");
     auto stream = mImpl->stream();
@@ -18415,16 +18793,16 @@
     local_stride = stride;
     countingStream->rewind();
     {
-        uint64_t cgen_var_1223;
-        countingStream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_1223, 1);
-        countingStream->write((uint64_t*)&cgen_var_1223, 1 * 8);
-        uint64_t cgen_var_1224;
-        countingStream->handleMapping()->mapHandles_VkBuffer_u64(&local_buffer, &cgen_var_1224, 1);
-        countingStream->write((uint64_t*)&cgen_var_1224, 1 * 8);
+        uint64_t cgen_var_1227;
+        countingStream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_1227, 1);
+        countingStream->write((uint64_t*)&cgen_var_1227, 1 * 8);
+        uint64_t cgen_var_1228;
+        countingStream->handleMapping()->mapHandles_VkBuffer_u64(&local_buffer, &cgen_var_1228, 1);
+        countingStream->write((uint64_t*)&cgen_var_1228, 1 * 8);
         countingStream->write((VkDeviceSize*)&local_offset, sizeof(VkDeviceSize));
-        uint64_t cgen_var_1225;
-        countingStream->handleMapping()->mapHandles_VkBuffer_u64(&local_countBuffer, &cgen_var_1225, 1);
-        countingStream->write((uint64_t*)&cgen_var_1225, 1 * 8);
+        uint64_t cgen_var_1229;
+        countingStream->handleMapping()->mapHandles_VkBuffer_u64(&local_countBuffer, &cgen_var_1229, 1);
+        countingStream->write((uint64_t*)&cgen_var_1229, 1 * 8);
         countingStream->write((VkDeviceSize*)&local_countBufferOffset, sizeof(VkDeviceSize));
         countingStream->write((uint32_t*)&local_maxDrawCount, sizeof(uint32_t));
         countingStream->write((uint32_t*)&local_stride, sizeof(uint32_t));
@@ -18434,16 +18812,16 @@
     uint32_t opcode_vkCmdDrawIndirectCountAMD = OP_vkCmdDrawIndirectCountAMD;
     stream->write(&opcode_vkCmdDrawIndirectCountAMD, sizeof(uint32_t));
     stream->write(&packetSize_vkCmdDrawIndirectCountAMD, sizeof(uint32_t));
-    uint64_t cgen_var_1226;
-    stream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_1226, 1);
-    stream->write((uint64_t*)&cgen_var_1226, 1 * 8);
-    uint64_t cgen_var_1227;
-    stream->handleMapping()->mapHandles_VkBuffer_u64(&local_buffer, &cgen_var_1227, 1);
-    stream->write((uint64_t*)&cgen_var_1227, 1 * 8);
+    uint64_t cgen_var_1230;
+    stream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_1230, 1);
+    stream->write((uint64_t*)&cgen_var_1230, 1 * 8);
+    uint64_t cgen_var_1231;
+    stream->handleMapping()->mapHandles_VkBuffer_u64(&local_buffer, &cgen_var_1231, 1);
+    stream->write((uint64_t*)&cgen_var_1231, 1 * 8);
     stream->write((VkDeviceSize*)&local_offset, sizeof(VkDeviceSize));
-    uint64_t cgen_var_1228;
-    stream->handleMapping()->mapHandles_VkBuffer_u64(&local_countBuffer, &cgen_var_1228, 1);
-    stream->write((uint64_t*)&cgen_var_1228, 1 * 8);
+    uint64_t cgen_var_1232;
+    stream->handleMapping()->mapHandles_VkBuffer_u64(&local_countBuffer, &cgen_var_1232, 1);
+    stream->write((uint64_t*)&cgen_var_1232, 1 * 8);
     stream->write((VkDeviceSize*)&local_countBufferOffset, sizeof(VkDeviceSize));
     stream->write((uint32_t*)&local_maxDrawCount, sizeof(uint32_t));
     stream->write((uint32_t*)&local_stride, sizeof(uint32_t));
@@ -18461,6 +18839,7 @@
     uint32_t maxDrawCount,
     uint32_t stride)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkCmdDrawIndexedIndirectCountAMD encode");
     mImpl->log("start vkCmdDrawIndexedIndirectCountAMD");
     auto stream = mImpl->stream();
@@ -18484,16 +18863,16 @@
     local_stride = stride;
     countingStream->rewind();
     {
-        uint64_t cgen_var_1229;
-        countingStream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_1229, 1);
-        countingStream->write((uint64_t*)&cgen_var_1229, 1 * 8);
-        uint64_t cgen_var_1230;
-        countingStream->handleMapping()->mapHandles_VkBuffer_u64(&local_buffer, &cgen_var_1230, 1);
-        countingStream->write((uint64_t*)&cgen_var_1230, 1 * 8);
+        uint64_t cgen_var_1233;
+        countingStream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_1233, 1);
+        countingStream->write((uint64_t*)&cgen_var_1233, 1 * 8);
+        uint64_t cgen_var_1234;
+        countingStream->handleMapping()->mapHandles_VkBuffer_u64(&local_buffer, &cgen_var_1234, 1);
+        countingStream->write((uint64_t*)&cgen_var_1234, 1 * 8);
         countingStream->write((VkDeviceSize*)&local_offset, sizeof(VkDeviceSize));
-        uint64_t cgen_var_1231;
-        countingStream->handleMapping()->mapHandles_VkBuffer_u64(&local_countBuffer, &cgen_var_1231, 1);
-        countingStream->write((uint64_t*)&cgen_var_1231, 1 * 8);
+        uint64_t cgen_var_1235;
+        countingStream->handleMapping()->mapHandles_VkBuffer_u64(&local_countBuffer, &cgen_var_1235, 1);
+        countingStream->write((uint64_t*)&cgen_var_1235, 1 * 8);
         countingStream->write((VkDeviceSize*)&local_countBufferOffset, sizeof(VkDeviceSize));
         countingStream->write((uint32_t*)&local_maxDrawCount, sizeof(uint32_t));
         countingStream->write((uint32_t*)&local_stride, sizeof(uint32_t));
@@ -18503,16 +18882,16 @@
     uint32_t opcode_vkCmdDrawIndexedIndirectCountAMD = OP_vkCmdDrawIndexedIndirectCountAMD;
     stream->write(&opcode_vkCmdDrawIndexedIndirectCountAMD, sizeof(uint32_t));
     stream->write(&packetSize_vkCmdDrawIndexedIndirectCountAMD, sizeof(uint32_t));
-    uint64_t cgen_var_1232;
-    stream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_1232, 1);
-    stream->write((uint64_t*)&cgen_var_1232, 1 * 8);
-    uint64_t cgen_var_1233;
-    stream->handleMapping()->mapHandles_VkBuffer_u64(&local_buffer, &cgen_var_1233, 1);
-    stream->write((uint64_t*)&cgen_var_1233, 1 * 8);
+    uint64_t cgen_var_1236;
+    stream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_1236, 1);
+    stream->write((uint64_t*)&cgen_var_1236, 1 * 8);
+    uint64_t cgen_var_1237;
+    stream->handleMapping()->mapHandles_VkBuffer_u64(&local_buffer, &cgen_var_1237, 1);
+    stream->write((uint64_t*)&cgen_var_1237, 1 * 8);
     stream->write((VkDeviceSize*)&local_offset, sizeof(VkDeviceSize));
-    uint64_t cgen_var_1234;
-    stream->handleMapping()->mapHandles_VkBuffer_u64(&local_countBuffer, &cgen_var_1234, 1);
-    stream->write((uint64_t*)&cgen_var_1234, 1 * 8);
+    uint64_t cgen_var_1238;
+    stream->handleMapping()->mapHandles_VkBuffer_u64(&local_countBuffer, &cgen_var_1238, 1);
+    stream->write((uint64_t*)&cgen_var_1238, 1 * 8);
     stream->write((VkDeviceSize*)&local_countBufferOffset, sizeof(VkDeviceSize));
     stream->write((uint32_t*)&local_maxDrawCount, sizeof(uint32_t));
     stream->write((uint32_t*)&local_stride, sizeof(uint32_t));
@@ -18539,6 +18918,7 @@
     size_t* pInfoSize,
     void* pInfo)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkGetShaderInfoAMD encode");
     mImpl->log("start vkGetShaderInfoAMD");
     auto stream = mImpl->stream();
@@ -18556,25 +18936,25 @@
     local_infoType = infoType;
     countingStream->rewind();
     {
-        uint64_t cgen_var_1235;
-        countingStream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_1235, 1);
-        countingStream->write((uint64_t*)&cgen_var_1235, 1 * 8);
-        uint64_t cgen_var_1236;
-        countingStream->handleMapping()->mapHandles_VkPipeline_u64(&local_pipeline, &cgen_var_1236, 1);
-        countingStream->write((uint64_t*)&cgen_var_1236, 1 * 8);
+        uint64_t cgen_var_1239;
+        countingStream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_1239, 1);
+        countingStream->write((uint64_t*)&cgen_var_1239, 1 * 8);
+        uint64_t cgen_var_1240;
+        countingStream->handleMapping()->mapHandles_VkPipeline_u64(&local_pipeline, &cgen_var_1240, 1);
+        countingStream->write((uint64_t*)&cgen_var_1240, 1 * 8);
         countingStream->write((VkShaderStageFlagBits*)&local_shaderStage, sizeof(VkShaderStageFlagBits));
         countingStream->write((VkShaderInfoTypeAMD*)&local_infoType, sizeof(VkShaderInfoTypeAMD));
         // WARNING PTR CHECK
-        uint64_t cgen_var_1237 = (uint64_t)(uintptr_t)pInfoSize;
-        countingStream->putBe64(cgen_var_1237);
+        uint64_t cgen_var_1241 = (uint64_t)(uintptr_t)pInfoSize;
+        countingStream->putBe64(cgen_var_1241);
         if (pInfoSize)
         {
-            uint64_t cgen_var_1238 = (uint64_t)(*pInfoSize);
-            countingStream->putBe64(cgen_var_1238);
+            uint64_t cgen_var_1242 = (uint64_t)(*pInfoSize);
+            countingStream->putBe64(cgen_var_1242);
         }
         // WARNING PTR CHECK
-        uint64_t cgen_var_1239 = (uint64_t)(uintptr_t)pInfo;
-        countingStream->putBe64(cgen_var_1239);
+        uint64_t cgen_var_1243 = (uint64_t)(uintptr_t)pInfo;
+        countingStream->putBe64(cgen_var_1243);
         if (pInfo)
         {
             countingStream->write((void*)pInfo, (*(pInfoSize)) * sizeof(uint8_t));
@@ -18585,25 +18965,25 @@
     uint32_t opcode_vkGetShaderInfoAMD = OP_vkGetShaderInfoAMD;
     stream->write(&opcode_vkGetShaderInfoAMD, sizeof(uint32_t));
     stream->write(&packetSize_vkGetShaderInfoAMD, sizeof(uint32_t));
-    uint64_t cgen_var_1240;
-    stream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_1240, 1);
-    stream->write((uint64_t*)&cgen_var_1240, 1 * 8);
-    uint64_t cgen_var_1241;
-    stream->handleMapping()->mapHandles_VkPipeline_u64(&local_pipeline, &cgen_var_1241, 1);
-    stream->write((uint64_t*)&cgen_var_1241, 1 * 8);
+    uint64_t cgen_var_1244;
+    stream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_1244, 1);
+    stream->write((uint64_t*)&cgen_var_1244, 1 * 8);
+    uint64_t cgen_var_1245;
+    stream->handleMapping()->mapHandles_VkPipeline_u64(&local_pipeline, &cgen_var_1245, 1);
+    stream->write((uint64_t*)&cgen_var_1245, 1 * 8);
     stream->write((VkShaderStageFlagBits*)&local_shaderStage, sizeof(VkShaderStageFlagBits));
     stream->write((VkShaderInfoTypeAMD*)&local_infoType, sizeof(VkShaderInfoTypeAMD));
     // WARNING PTR CHECK
-    uint64_t cgen_var_1242 = (uint64_t)(uintptr_t)pInfoSize;
-    stream->putBe64(cgen_var_1242);
+    uint64_t cgen_var_1246 = (uint64_t)(uintptr_t)pInfoSize;
+    stream->putBe64(cgen_var_1246);
     if (pInfoSize)
     {
-        uint64_t cgen_var_1243 = (uint64_t)(*pInfoSize);
-        stream->putBe64(cgen_var_1243);
+        uint64_t cgen_var_1247 = (uint64_t)(*pInfoSize);
+        stream->putBe64(cgen_var_1247);
     }
     // WARNING PTR CHECK
-    uint64_t cgen_var_1244 = (uint64_t)(uintptr_t)pInfo;
-    stream->putBe64(cgen_var_1244);
+    uint64_t cgen_var_1248 = (uint64_t)(uintptr_t)pInfo;
+    stream->putBe64(cgen_var_1248);
     if (pInfo)
     {
         stream->write((void*)pInfo, (*(pInfoSize)) * sizeof(uint8_t));
@@ -18657,6 +19037,7 @@
     VkExternalMemoryHandleTypeFlagsNV externalHandleType,
     VkExternalImageFormatPropertiesNV* pExternalImageFormatProperties)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkGetPhysicalDeviceExternalImageFormatPropertiesNV encode");
     mImpl->log("start vkGetPhysicalDeviceExternalImageFormatPropertiesNV");
     auto stream = mImpl->stream();
@@ -18680,9 +19061,9 @@
     local_externalHandleType = externalHandleType;
     countingStream->rewind();
     {
-        uint64_t cgen_var_1248;
-        countingStream->handleMapping()->mapHandles_VkPhysicalDevice_u64(&local_physicalDevice, &cgen_var_1248, 1);
-        countingStream->write((uint64_t*)&cgen_var_1248, 1 * 8);
+        uint64_t cgen_var_1252;
+        countingStream->handleMapping()->mapHandles_VkPhysicalDevice_u64(&local_physicalDevice, &cgen_var_1252, 1);
+        countingStream->write((uint64_t*)&cgen_var_1252, 1 * 8);
         countingStream->write((VkFormat*)&local_format, sizeof(VkFormat));
         countingStream->write((VkImageType*)&local_type, sizeof(VkImageType));
         countingStream->write((VkImageTiling*)&local_tiling, sizeof(VkImageTiling));
@@ -18696,9 +19077,9 @@
     uint32_t opcode_vkGetPhysicalDeviceExternalImageFormatPropertiesNV = OP_vkGetPhysicalDeviceExternalImageFormatPropertiesNV;
     stream->write(&opcode_vkGetPhysicalDeviceExternalImageFormatPropertiesNV, sizeof(uint32_t));
     stream->write(&packetSize_vkGetPhysicalDeviceExternalImageFormatPropertiesNV, sizeof(uint32_t));
-    uint64_t cgen_var_1249;
-    stream->handleMapping()->mapHandles_VkPhysicalDevice_u64(&local_physicalDevice, &cgen_var_1249, 1);
-    stream->write((uint64_t*)&cgen_var_1249, 1 * 8);
+    uint64_t cgen_var_1253;
+    stream->handleMapping()->mapHandles_VkPhysicalDevice_u64(&local_physicalDevice, &cgen_var_1253, 1);
+    stream->write((uint64_t*)&cgen_var_1253, 1 * 8);
     stream->write((VkFormat*)&local_format, sizeof(VkFormat));
     stream->write((VkImageType*)&local_type, sizeof(VkImageType));
     stream->write((VkImageTiling*)&local_tiling, sizeof(VkImageTiling));
@@ -18732,6 +19113,7 @@
     VkExternalMemoryHandleTypeFlagsNV handleType,
     HANDLE* pHandle)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkGetMemoryWin32HandleNV encode");
     mImpl->log("start vkGetMemoryWin32HandleNV");
     auto stream = mImpl->stream();
@@ -18748,12 +19130,12 @@
     mImpl->resources()->deviceMemoryTransform_tohost((VkDeviceMemory*)&local_memory, 1, (VkDeviceSize*)nullptr, 0, (VkDeviceSize*)nullptr, 0, (uint32_t*)nullptr, 0, (uint32_t*)nullptr, 0);
     countingStream->rewind();
     {
-        uint64_t cgen_var_1250;
-        countingStream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_1250, 1);
-        countingStream->write((uint64_t*)&cgen_var_1250, 1 * 8);
-        uint64_t cgen_var_1251;
-        countingStream->handleMapping()->mapHandles_VkDeviceMemory_u64(&local_memory, &cgen_var_1251, 1);
-        countingStream->write((uint64_t*)&cgen_var_1251, 1 * 8);
+        uint64_t cgen_var_1254;
+        countingStream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_1254, 1);
+        countingStream->write((uint64_t*)&cgen_var_1254, 1 * 8);
+        uint64_t cgen_var_1255;
+        countingStream->handleMapping()->mapHandles_VkDeviceMemory_u64(&local_memory, &cgen_var_1255, 1);
+        countingStream->write((uint64_t*)&cgen_var_1255, 1 * 8);
         countingStream->write((VkExternalMemoryHandleTypeFlagsNV*)&local_handleType, sizeof(VkExternalMemoryHandleTypeFlagsNV));
         countingStream->write((HANDLE*)pHandle, sizeof(HANDLE));
     }
@@ -18762,12 +19144,12 @@
     uint32_t opcode_vkGetMemoryWin32HandleNV = OP_vkGetMemoryWin32HandleNV;
     stream->write(&opcode_vkGetMemoryWin32HandleNV, sizeof(uint32_t));
     stream->write(&packetSize_vkGetMemoryWin32HandleNV, sizeof(uint32_t));
-    uint64_t cgen_var_1252;
-    stream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_1252, 1);
-    stream->write((uint64_t*)&cgen_var_1252, 1 * 8);
-    uint64_t cgen_var_1253;
-    stream->handleMapping()->mapHandles_VkDeviceMemory_u64(&local_memory, &cgen_var_1253, 1);
-    stream->write((uint64_t*)&cgen_var_1253, 1 * 8);
+    uint64_t cgen_var_1256;
+    stream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_1256, 1);
+    stream->write((uint64_t*)&cgen_var_1256, 1 * 8);
+    uint64_t cgen_var_1257;
+    stream->handleMapping()->mapHandles_VkDeviceMemory_u64(&local_memory, &cgen_var_1257, 1);
+    stream->write((uint64_t*)&cgen_var_1257, 1 * 8);
     stream->write((VkExternalMemoryHandleTypeFlagsNV*)&local_handleType, sizeof(VkExternalMemoryHandleTypeFlagsNV));
     stream->write((HANDLE*)pHandle, sizeof(HANDLE));
     AEMU_SCOPED_TRACE("vkGetMemoryWin32HandleNV readParams");
@@ -18794,6 +19176,7 @@
     const VkAllocationCallbacks* pAllocator,
     VkSurfaceKHR* pSurface)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkCreateViSurfaceNN encode");
     mImpl->log("start vkCreateViSurfaceNN");
     auto stream = mImpl->stream();
@@ -18828,46 +19211,46 @@
     }
     countingStream->rewind();
     {
-        uint64_t cgen_var_1254;
-        countingStream->handleMapping()->mapHandles_VkInstance_u64(&local_instance, &cgen_var_1254, 1);
-        countingStream->write((uint64_t*)&cgen_var_1254, 1 * 8);
+        uint64_t cgen_var_1258;
+        countingStream->handleMapping()->mapHandles_VkInstance_u64(&local_instance, &cgen_var_1258, 1);
+        countingStream->write((uint64_t*)&cgen_var_1258, 1 * 8);
         marshal_VkViSurfaceCreateInfoNN(countingStream, (VkViSurfaceCreateInfoNN*)(local_pCreateInfo));
         // WARNING PTR CHECK
-        uint64_t cgen_var_1255 = (uint64_t)(uintptr_t)local_pAllocator;
-        countingStream->putBe64(cgen_var_1255);
+        uint64_t cgen_var_1259 = (uint64_t)(uintptr_t)local_pAllocator;
+        countingStream->putBe64(cgen_var_1259);
         if (local_pAllocator)
         {
             marshal_VkAllocationCallbacks(countingStream, (VkAllocationCallbacks*)(local_pAllocator));
         }
-        uint64_t cgen_var_1256;
-        countingStream->handleMapping()->mapHandles_VkSurfaceKHR_u64(pSurface, &cgen_var_1256, 1);
-        countingStream->write((uint64_t*)&cgen_var_1256, 8);
+        uint64_t cgen_var_1260;
+        countingStream->handleMapping()->mapHandles_VkSurfaceKHR_u64(pSurface, &cgen_var_1260, 1);
+        countingStream->write((uint64_t*)&cgen_var_1260, 8);
     }
     uint32_t packetSize_vkCreateViSurfaceNN = 4 + 4 + (uint32_t)countingStream->bytesWritten();
     countingStream->rewind();
     uint32_t opcode_vkCreateViSurfaceNN = OP_vkCreateViSurfaceNN;
     stream->write(&opcode_vkCreateViSurfaceNN, sizeof(uint32_t));
     stream->write(&packetSize_vkCreateViSurfaceNN, sizeof(uint32_t));
-    uint64_t cgen_var_1257;
-    stream->handleMapping()->mapHandles_VkInstance_u64(&local_instance, &cgen_var_1257, 1);
-    stream->write((uint64_t*)&cgen_var_1257, 1 * 8);
+    uint64_t cgen_var_1261;
+    stream->handleMapping()->mapHandles_VkInstance_u64(&local_instance, &cgen_var_1261, 1);
+    stream->write((uint64_t*)&cgen_var_1261, 1 * 8);
     marshal_VkViSurfaceCreateInfoNN(stream, (VkViSurfaceCreateInfoNN*)(local_pCreateInfo));
     // WARNING PTR CHECK
-    uint64_t cgen_var_1258 = (uint64_t)(uintptr_t)local_pAllocator;
-    stream->putBe64(cgen_var_1258);
+    uint64_t cgen_var_1262 = (uint64_t)(uintptr_t)local_pAllocator;
+    stream->putBe64(cgen_var_1262);
     if (local_pAllocator)
     {
         marshal_VkAllocationCallbacks(stream, (VkAllocationCallbacks*)(local_pAllocator));
     }
     stream->unsetHandleMapping() /* emit_marshal, is handle, possibly out */;
-    uint64_t cgen_var_1259;
-    stream->handleMapping()->mapHandles_VkSurfaceKHR_u64(pSurface, &cgen_var_1259, 1);
-    stream->write((uint64_t*)&cgen_var_1259, 8);
+    uint64_t cgen_var_1263;
+    stream->handleMapping()->mapHandles_VkSurfaceKHR_u64(pSurface, &cgen_var_1263, 1);
+    stream->write((uint64_t*)&cgen_var_1263, 8);
     stream->setHandleMapping(resources->unwrapMapping());
     AEMU_SCOPED_TRACE("vkCreateViSurfaceNN readParams");
-    uint64_t cgen_var_1260;
-    stream->read((uint64_t*)&cgen_var_1260, 8);
-    stream->handleMapping()->mapHandles_u64_VkSurfaceKHR(&cgen_var_1260, (VkSurfaceKHR*)pSurface, 1);
+    uint64_t cgen_var_1264;
+    stream->read((uint64_t*)&cgen_var_1264, 8);
+    stream->handleMapping()->mapHandles_u64_VkSurfaceKHR(&cgen_var_1264, (VkSurfaceKHR*)pSurface, 1);
     AEMU_SCOPED_TRACE("vkCreateViSurfaceNN returnUnmarshal");
     VkResult vkCreateViSurfaceNN_VkResult_return = (VkResult)0;
     stream->read(&vkCreateViSurfaceNN_VkResult_return, sizeof(VkResult));
@@ -18888,6 +19271,7 @@
     VkCommandBuffer commandBuffer,
     const VkConditionalRenderingBeginInfoEXT* pConditionalRenderingBegin)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkCmdBeginConditionalRenderingEXT encode");
     mImpl->log("start vkCmdBeginConditionalRenderingEXT");
     auto stream = mImpl->stream();
@@ -18910,9 +19294,9 @@
     }
     countingStream->rewind();
     {
-        uint64_t cgen_var_1261;
-        countingStream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_1261, 1);
-        countingStream->write((uint64_t*)&cgen_var_1261, 1 * 8);
+        uint64_t cgen_var_1265;
+        countingStream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_1265, 1);
+        countingStream->write((uint64_t*)&cgen_var_1265, 1 * 8);
         marshal_VkConditionalRenderingBeginInfoEXT(countingStream, (VkConditionalRenderingBeginInfoEXT*)(local_pConditionalRenderingBegin));
     }
     uint32_t packetSize_vkCmdBeginConditionalRenderingEXT = 4 + 4 + (uint32_t)countingStream->bytesWritten();
@@ -18920,9 +19304,9 @@
     uint32_t opcode_vkCmdBeginConditionalRenderingEXT = OP_vkCmdBeginConditionalRenderingEXT;
     stream->write(&opcode_vkCmdBeginConditionalRenderingEXT, sizeof(uint32_t));
     stream->write(&packetSize_vkCmdBeginConditionalRenderingEXT, sizeof(uint32_t));
-    uint64_t cgen_var_1262;
-    stream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_1262, 1);
-    stream->write((uint64_t*)&cgen_var_1262, 1 * 8);
+    uint64_t cgen_var_1266;
+    stream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_1266, 1);
+    stream->write((uint64_t*)&cgen_var_1266, 1 * 8);
     marshal_VkConditionalRenderingBeginInfoEXT(stream, (VkConditionalRenderingBeginInfoEXT*)(local_pConditionalRenderingBegin));
     AEMU_SCOPED_TRACE("vkCmdBeginConditionalRenderingEXT readParams");
     AEMU_SCOPED_TRACE("vkCmdBeginConditionalRenderingEXT returnUnmarshal");
@@ -18932,6 +19316,7 @@
 void VkEncoder::vkCmdEndConditionalRenderingEXT(
     VkCommandBuffer commandBuffer)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkCmdEndConditionalRenderingEXT encode");
     mImpl->log("start vkCmdEndConditionalRenderingEXT");
     auto stream = mImpl->stream();
@@ -18943,18 +19328,18 @@
     local_commandBuffer = commandBuffer;
     countingStream->rewind();
     {
-        uint64_t cgen_var_1263;
-        countingStream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_1263, 1);
-        countingStream->write((uint64_t*)&cgen_var_1263, 1 * 8);
+        uint64_t cgen_var_1267;
+        countingStream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_1267, 1);
+        countingStream->write((uint64_t*)&cgen_var_1267, 1 * 8);
     }
     uint32_t packetSize_vkCmdEndConditionalRenderingEXT = 4 + 4 + (uint32_t)countingStream->bytesWritten();
     countingStream->rewind();
     uint32_t opcode_vkCmdEndConditionalRenderingEXT = OP_vkCmdEndConditionalRenderingEXT;
     stream->write(&opcode_vkCmdEndConditionalRenderingEXT, sizeof(uint32_t));
     stream->write(&packetSize_vkCmdEndConditionalRenderingEXT, sizeof(uint32_t));
-    uint64_t cgen_var_1264;
-    stream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_1264, 1);
-    stream->write((uint64_t*)&cgen_var_1264, 1 * 8);
+    uint64_t cgen_var_1268;
+    stream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_1268, 1);
+    stream->write((uint64_t*)&cgen_var_1268, 1 * 8);
     AEMU_SCOPED_TRACE("vkCmdEndConditionalRenderingEXT readParams");
     AEMU_SCOPED_TRACE("vkCmdEndConditionalRenderingEXT returnUnmarshal");
     mImpl->log("finish vkCmdEndConditionalRenderingEXT");;
@@ -18966,6 +19351,7 @@
     VkCommandBuffer commandBuffer,
     const VkCmdProcessCommandsInfoNVX* pProcessCommandsInfo)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkCmdProcessCommandsNVX encode");
     mImpl->log("start vkCmdProcessCommandsNVX");
     auto stream = mImpl->stream();
@@ -18988,9 +19374,9 @@
     }
     countingStream->rewind();
     {
-        uint64_t cgen_var_1265;
-        countingStream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_1265, 1);
-        countingStream->write((uint64_t*)&cgen_var_1265, 1 * 8);
+        uint64_t cgen_var_1269;
+        countingStream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_1269, 1);
+        countingStream->write((uint64_t*)&cgen_var_1269, 1 * 8);
         marshal_VkCmdProcessCommandsInfoNVX(countingStream, (VkCmdProcessCommandsInfoNVX*)(local_pProcessCommandsInfo));
     }
     uint32_t packetSize_vkCmdProcessCommandsNVX = 4 + 4 + (uint32_t)countingStream->bytesWritten();
@@ -18998,9 +19384,9 @@
     uint32_t opcode_vkCmdProcessCommandsNVX = OP_vkCmdProcessCommandsNVX;
     stream->write(&opcode_vkCmdProcessCommandsNVX, sizeof(uint32_t));
     stream->write(&packetSize_vkCmdProcessCommandsNVX, sizeof(uint32_t));
-    uint64_t cgen_var_1266;
-    stream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_1266, 1);
-    stream->write((uint64_t*)&cgen_var_1266, 1 * 8);
+    uint64_t cgen_var_1270;
+    stream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_1270, 1);
+    stream->write((uint64_t*)&cgen_var_1270, 1 * 8);
     marshal_VkCmdProcessCommandsInfoNVX(stream, (VkCmdProcessCommandsInfoNVX*)(local_pProcessCommandsInfo));
     AEMU_SCOPED_TRACE("vkCmdProcessCommandsNVX readParams");
     AEMU_SCOPED_TRACE("vkCmdProcessCommandsNVX returnUnmarshal");
@@ -19011,6 +19397,7 @@
     VkCommandBuffer commandBuffer,
     const VkCmdReserveSpaceForCommandsInfoNVX* pReserveSpaceInfo)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkCmdReserveSpaceForCommandsNVX encode");
     mImpl->log("start vkCmdReserveSpaceForCommandsNVX");
     auto stream = mImpl->stream();
@@ -19033,9 +19420,9 @@
     }
     countingStream->rewind();
     {
-        uint64_t cgen_var_1267;
-        countingStream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_1267, 1);
-        countingStream->write((uint64_t*)&cgen_var_1267, 1 * 8);
+        uint64_t cgen_var_1271;
+        countingStream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_1271, 1);
+        countingStream->write((uint64_t*)&cgen_var_1271, 1 * 8);
         marshal_VkCmdReserveSpaceForCommandsInfoNVX(countingStream, (VkCmdReserveSpaceForCommandsInfoNVX*)(local_pReserveSpaceInfo));
     }
     uint32_t packetSize_vkCmdReserveSpaceForCommandsNVX = 4 + 4 + (uint32_t)countingStream->bytesWritten();
@@ -19043,9 +19430,9 @@
     uint32_t opcode_vkCmdReserveSpaceForCommandsNVX = OP_vkCmdReserveSpaceForCommandsNVX;
     stream->write(&opcode_vkCmdReserveSpaceForCommandsNVX, sizeof(uint32_t));
     stream->write(&packetSize_vkCmdReserveSpaceForCommandsNVX, sizeof(uint32_t));
-    uint64_t cgen_var_1268;
-    stream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_1268, 1);
-    stream->write((uint64_t*)&cgen_var_1268, 1 * 8);
+    uint64_t cgen_var_1272;
+    stream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_1272, 1);
+    stream->write((uint64_t*)&cgen_var_1272, 1 * 8);
     marshal_VkCmdReserveSpaceForCommandsInfoNVX(stream, (VkCmdReserveSpaceForCommandsInfoNVX*)(local_pReserveSpaceInfo));
     AEMU_SCOPED_TRACE("vkCmdReserveSpaceForCommandsNVX readParams");
     AEMU_SCOPED_TRACE("vkCmdReserveSpaceForCommandsNVX returnUnmarshal");
@@ -19058,6 +19445,7 @@
     const VkAllocationCallbacks* pAllocator,
     VkIndirectCommandsLayoutNVX* pIndirectCommandsLayout)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkCreateIndirectCommandsLayoutNVX encode");
     mImpl->log("start vkCreateIndirectCommandsLayoutNVX");
     auto stream = mImpl->stream();
@@ -19092,47 +19480,47 @@
     }
     countingStream->rewind();
     {
-        uint64_t cgen_var_1269;
-        countingStream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_1269, 1);
-        countingStream->write((uint64_t*)&cgen_var_1269, 1 * 8);
+        uint64_t cgen_var_1273;
+        countingStream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_1273, 1);
+        countingStream->write((uint64_t*)&cgen_var_1273, 1 * 8);
         marshal_VkIndirectCommandsLayoutCreateInfoNVX(countingStream, (VkIndirectCommandsLayoutCreateInfoNVX*)(local_pCreateInfo));
         // WARNING PTR CHECK
-        uint64_t cgen_var_1270 = (uint64_t)(uintptr_t)local_pAllocator;
-        countingStream->putBe64(cgen_var_1270);
+        uint64_t cgen_var_1274 = (uint64_t)(uintptr_t)local_pAllocator;
+        countingStream->putBe64(cgen_var_1274);
         if (local_pAllocator)
         {
             marshal_VkAllocationCallbacks(countingStream, (VkAllocationCallbacks*)(local_pAllocator));
         }
-        uint64_t cgen_var_1271;
-        countingStream->handleMapping()->mapHandles_VkIndirectCommandsLayoutNVX_u64(pIndirectCommandsLayout, &cgen_var_1271, 1);
-        countingStream->write((uint64_t*)&cgen_var_1271, 8);
+        uint64_t cgen_var_1275;
+        countingStream->handleMapping()->mapHandles_VkIndirectCommandsLayoutNVX_u64(pIndirectCommandsLayout, &cgen_var_1275, 1);
+        countingStream->write((uint64_t*)&cgen_var_1275, 8);
     }
     uint32_t packetSize_vkCreateIndirectCommandsLayoutNVX = 4 + 4 + (uint32_t)countingStream->bytesWritten();
     countingStream->rewind();
     uint32_t opcode_vkCreateIndirectCommandsLayoutNVX = OP_vkCreateIndirectCommandsLayoutNVX;
     stream->write(&opcode_vkCreateIndirectCommandsLayoutNVX, sizeof(uint32_t));
     stream->write(&packetSize_vkCreateIndirectCommandsLayoutNVX, sizeof(uint32_t));
-    uint64_t cgen_var_1272;
-    stream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_1272, 1);
-    stream->write((uint64_t*)&cgen_var_1272, 1 * 8);
+    uint64_t cgen_var_1276;
+    stream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_1276, 1);
+    stream->write((uint64_t*)&cgen_var_1276, 1 * 8);
     marshal_VkIndirectCommandsLayoutCreateInfoNVX(stream, (VkIndirectCommandsLayoutCreateInfoNVX*)(local_pCreateInfo));
     // WARNING PTR CHECK
-    uint64_t cgen_var_1273 = (uint64_t)(uintptr_t)local_pAllocator;
-    stream->putBe64(cgen_var_1273);
+    uint64_t cgen_var_1277 = (uint64_t)(uintptr_t)local_pAllocator;
+    stream->putBe64(cgen_var_1277);
     if (local_pAllocator)
     {
         marshal_VkAllocationCallbacks(stream, (VkAllocationCallbacks*)(local_pAllocator));
     }
     stream->unsetHandleMapping() /* emit_marshal, is handle, possibly out */;
-    uint64_t cgen_var_1274;
-    stream->handleMapping()->mapHandles_VkIndirectCommandsLayoutNVX_u64(pIndirectCommandsLayout, &cgen_var_1274, 1);
-    stream->write((uint64_t*)&cgen_var_1274, 8);
+    uint64_t cgen_var_1278;
+    stream->handleMapping()->mapHandles_VkIndirectCommandsLayoutNVX_u64(pIndirectCommandsLayout, &cgen_var_1278, 1);
+    stream->write((uint64_t*)&cgen_var_1278, 8);
     stream->setHandleMapping(resources->unwrapMapping());
     AEMU_SCOPED_TRACE("vkCreateIndirectCommandsLayoutNVX readParams");
     stream->setHandleMapping(resources->createMapping());
-    uint64_t cgen_var_1275;
-    stream->read((uint64_t*)&cgen_var_1275, 8);
-    stream->handleMapping()->mapHandles_u64_VkIndirectCommandsLayoutNVX(&cgen_var_1275, (VkIndirectCommandsLayoutNVX*)pIndirectCommandsLayout, 1);
+    uint64_t cgen_var_1279;
+    stream->read((uint64_t*)&cgen_var_1279, 8);
+    stream->handleMapping()->mapHandles_u64_VkIndirectCommandsLayoutNVX(&cgen_var_1279, (VkIndirectCommandsLayoutNVX*)pIndirectCommandsLayout, 1);
     stream->unsetHandleMapping();
     AEMU_SCOPED_TRACE("vkCreateIndirectCommandsLayoutNVX returnUnmarshal");
     VkResult vkCreateIndirectCommandsLayoutNVX_VkResult_return = (VkResult)0;
@@ -19149,6 +19537,7 @@
     VkIndirectCommandsLayoutNVX indirectCommandsLayout,
     const VkAllocationCallbacks* pAllocator)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkDestroyIndirectCommandsLayoutNVX encode");
     mImpl->log("start vkDestroyIndirectCommandsLayoutNVX");
     auto stream = mImpl->stream();
@@ -19174,15 +19563,15 @@
     }
     countingStream->rewind();
     {
-        uint64_t cgen_var_1276;
-        countingStream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_1276, 1);
-        countingStream->write((uint64_t*)&cgen_var_1276, 1 * 8);
-        uint64_t cgen_var_1277;
-        countingStream->handleMapping()->mapHandles_VkIndirectCommandsLayoutNVX_u64(&local_indirectCommandsLayout, &cgen_var_1277, 1);
-        countingStream->write((uint64_t*)&cgen_var_1277, 1 * 8);
+        uint64_t cgen_var_1280;
+        countingStream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_1280, 1);
+        countingStream->write((uint64_t*)&cgen_var_1280, 1 * 8);
+        uint64_t cgen_var_1281;
+        countingStream->handleMapping()->mapHandles_VkIndirectCommandsLayoutNVX_u64(&local_indirectCommandsLayout, &cgen_var_1281, 1);
+        countingStream->write((uint64_t*)&cgen_var_1281, 1 * 8);
         // WARNING PTR CHECK
-        uint64_t cgen_var_1278 = (uint64_t)(uintptr_t)local_pAllocator;
-        countingStream->putBe64(cgen_var_1278);
+        uint64_t cgen_var_1282 = (uint64_t)(uintptr_t)local_pAllocator;
+        countingStream->putBe64(cgen_var_1282);
         if (local_pAllocator)
         {
             marshal_VkAllocationCallbacks(countingStream, (VkAllocationCallbacks*)(local_pAllocator));
@@ -19193,15 +19582,15 @@
     uint32_t opcode_vkDestroyIndirectCommandsLayoutNVX = OP_vkDestroyIndirectCommandsLayoutNVX;
     stream->write(&opcode_vkDestroyIndirectCommandsLayoutNVX, sizeof(uint32_t));
     stream->write(&packetSize_vkDestroyIndirectCommandsLayoutNVX, sizeof(uint32_t));
-    uint64_t cgen_var_1279;
-    stream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_1279, 1);
-    stream->write((uint64_t*)&cgen_var_1279, 1 * 8);
-    uint64_t cgen_var_1280;
-    stream->handleMapping()->mapHandles_VkIndirectCommandsLayoutNVX_u64(&local_indirectCommandsLayout, &cgen_var_1280, 1);
-    stream->write((uint64_t*)&cgen_var_1280, 1 * 8);
+    uint64_t cgen_var_1283;
+    stream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_1283, 1);
+    stream->write((uint64_t*)&cgen_var_1283, 1 * 8);
+    uint64_t cgen_var_1284;
+    stream->handleMapping()->mapHandles_VkIndirectCommandsLayoutNVX_u64(&local_indirectCommandsLayout, &cgen_var_1284, 1);
+    stream->write((uint64_t*)&cgen_var_1284, 1 * 8);
     // WARNING PTR CHECK
-    uint64_t cgen_var_1281 = (uint64_t)(uintptr_t)local_pAllocator;
-    stream->putBe64(cgen_var_1281);
+    uint64_t cgen_var_1285 = (uint64_t)(uintptr_t)local_pAllocator;
+    stream->putBe64(cgen_var_1285);
     if (local_pAllocator)
     {
         marshal_VkAllocationCallbacks(stream, (VkAllocationCallbacks*)(local_pAllocator));
@@ -19218,6 +19607,7 @@
     const VkAllocationCallbacks* pAllocator,
     VkObjectTableNVX* pObjectTable)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkCreateObjectTableNVX encode");
     mImpl->log("start vkCreateObjectTableNVX");
     auto stream = mImpl->stream();
@@ -19252,47 +19642,47 @@
     }
     countingStream->rewind();
     {
-        uint64_t cgen_var_1282;
-        countingStream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_1282, 1);
-        countingStream->write((uint64_t*)&cgen_var_1282, 1 * 8);
+        uint64_t cgen_var_1286;
+        countingStream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_1286, 1);
+        countingStream->write((uint64_t*)&cgen_var_1286, 1 * 8);
         marshal_VkObjectTableCreateInfoNVX(countingStream, (VkObjectTableCreateInfoNVX*)(local_pCreateInfo));
         // WARNING PTR CHECK
-        uint64_t cgen_var_1283 = (uint64_t)(uintptr_t)local_pAllocator;
-        countingStream->putBe64(cgen_var_1283);
+        uint64_t cgen_var_1287 = (uint64_t)(uintptr_t)local_pAllocator;
+        countingStream->putBe64(cgen_var_1287);
         if (local_pAllocator)
         {
             marshal_VkAllocationCallbacks(countingStream, (VkAllocationCallbacks*)(local_pAllocator));
         }
-        uint64_t cgen_var_1284;
-        countingStream->handleMapping()->mapHandles_VkObjectTableNVX_u64(pObjectTable, &cgen_var_1284, 1);
-        countingStream->write((uint64_t*)&cgen_var_1284, 8);
+        uint64_t cgen_var_1288;
+        countingStream->handleMapping()->mapHandles_VkObjectTableNVX_u64(pObjectTable, &cgen_var_1288, 1);
+        countingStream->write((uint64_t*)&cgen_var_1288, 8);
     }
     uint32_t packetSize_vkCreateObjectTableNVX = 4 + 4 + (uint32_t)countingStream->bytesWritten();
     countingStream->rewind();
     uint32_t opcode_vkCreateObjectTableNVX = OP_vkCreateObjectTableNVX;
     stream->write(&opcode_vkCreateObjectTableNVX, sizeof(uint32_t));
     stream->write(&packetSize_vkCreateObjectTableNVX, sizeof(uint32_t));
-    uint64_t cgen_var_1285;
-    stream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_1285, 1);
-    stream->write((uint64_t*)&cgen_var_1285, 1 * 8);
+    uint64_t cgen_var_1289;
+    stream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_1289, 1);
+    stream->write((uint64_t*)&cgen_var_1289, 1 * 8);
     marshal_VkObjectTableCreateInfoNVX(stream, (VkObjectTableCreateInfoNVX*)(local_pCreateInfo));
     // WARNING PTR CHECK
-    uint64_t cgen_var_1286 = (uint64_t)(uintptr_t)local_pAllocator;
-    stream->putBe64(cgen_var_1286);
+    uint64_t cgen_var_1290 = (uint64_t)(uintptr_t)local_pAllocator;
+    stream->putBe64(cgen_var_1290);
     if (local_pAllocator)
     {
         marshal_VkAllocationCallbacks(stream, (VkAllocationCallbacks*)(local_pAllocator));
     }
     stream->unsetHandleMapping() /* emit_marshal, is handle, possibly out */;
-    uint64_t cgen_var_1287;
-    stream->handleMapping()->mapHandles_VkObjectTableNVX_u64(pObjectTable, &cgen_var_1287, 1);
-    stream->write((uint64_t*)&cgen_var_1287, 8);
+    uint64_t cgen_var_1291;
+    stream->handleMapping()->mapHandles_VkObjectTableNVX_u64(pObjectTable, &cgen_var_1291, 1);
+    stream->write((uint64_t*)&cgen_var_1291, 8);
     stream->setHandleMapping(resources->unwrapMapping());
     AEMU_SCOPED_TRACE("vkCreateObjectTableNVX readParams");
     stream->setHandleMapping(resources->createMapping());
-    uint64_t cgen_var_1288;
-    stream->read((uint64_t*)&cgen_var_1288, 8);
-    stream->handleMapping()->mapHandles_u64_VkObjectTableNVX(&cgen_var_1288, (VkObjectTableNVX*)pObjectTable, 1);
+    uint64_t cgen_var_1292;
+    stream->read((uint64_t*)&cgen_var_1292, 8);
+    stream->handleMapping()->mapHandles_u64_VkObjectTableNVX(&cgen_var_1292, (VkObjectTableNVX*)pObjectTable, 1);
     stream->unsetHandleMapping();
     AEMU_SCOPED_TRACE("vkCreateObjectTableNVX returnUnmarshal");
     VkResult vkCreateObjectTableNVX_VkResult_return = (VkResult)0;
@@ -19309,6 +19699,7 @@
     VkObjectTableNVX objectTable,
     const VkAllocationCallbacks* pAllocator)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkDestroyObjectTableNVX encode");
     mImpl->log("start vkDestroyObjectTableNVX");
     auto stream = mImpl->stream();
@@ -19334,15 +19725,15 @@
     }
     countingStream->rewind();
     {
-        uint64_t cgen_var_1289;
-        countingStream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_1289, 1);
-        countingStream->write((uint64_t*)&cgen_var_1289, 1 * 8);
-        uint64_t cgen_var_1290;
-        countingStream->handleMapping()->mapHandles_VkObjectTableNVX_u64(&local_objectTable, &cgen_var_1290, 1);
-        countingStream->write((uint64_t*)&cgen_var_1290, 1 * 8);
+        uint64_t cgen_var_1293;
+        countingStream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_1293, 1);
+        countingStream->write((uint64_t*)&cgen_var_1293, 1 * 8);
+        uint64_t cgen_var_1294;
+        countingStream->handleMapping()->mapHandles_VkObjectTableNVX_u64(&local_objectTable, &cgen_var_1294, 1);
+        countingStream->write((uint64_t*)&cgen_var_1294, 1 * 8);
         // WARNING PTR CHECK
-        uint64_t cgen_var_1291 = (uint64_t)(uintptr_t)local_pAllocator;
-        countingStream->putBe64(cgen_var_1291);
+        uint64_t cgen_var_1295 = (uint64_t)(uintptr_t)local_pAllocator;
+        countingStream->putBe64(cgen_var_1295);
         if (local_pAllocator)
         {
             marshal_VkAllocationCallbacks(countingStream, (VkAllocationCallbacks*)(local_pAllocator));
@@ -19353,15 +19744,15 @@
     uint32_t opcode_vkDestroyObjectTableNVX = OP_vkDestroyObjectTableNVX;
     stream->write(&opcode_vkDestroyObjectTableNVX, sizeof(uint32_t));
     stream->write(&packetSize_vkDestroyObjectTableNVX, sizeof(uint32_t));
-    uint64_t cgen_var_1292;
-    stream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_1292, 1);
-    stream->write((uint64_t*)&cgen_var_1292, 1 * 8);
-    uint64_t cgen_var_1293;
-    stream->handleMapping()->mapHandles_VkObjectTableNVX_u64(&local_objectTable, &cgen_var_1293, 1);
-    stream->write((uint64_t*)&cgen_var_1293, 1 * 8);
+    uint64_t cgen_var_1296;
+    stream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_1296, 1);
+    stream->write((uint64_t*)&cgen_var_1296, 1 * 8);
+    uint64_t cgen_var_1297;
+    stream->handleMapping()->mapHandles_VkObjectTableNVX_u64(&local_objectTable, &cgen_var_1297, 1);
+    stream->write((uint64_t*)&cgen_var_1297, 1 * 8);
     // WARNING PTR CHECK
-    uint64_t cgen_var_1294 = (uint64_t)(uintptr_t)local_pAllocator;
-    stream->putBe64(cgen_var_1294);
+    uint64_t cgen_var_1298 = (uint64_t)(uintptr_t)local_pAllocator;
+    stream->putBe64(cgen_var_1298);
     if (local_pAllocator)
     {
         marshal_VkAllocationCallbacks(stream, (VkAllocationCallbacks*)(local_pAllocator));
@@ -19379,6 +19770,7 @@
     const VkObjectTableEntryNVX* const* ppObjectTableEntries,
     const uint32_t* pObjectIndices)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkRegisterObjectsNVX encode");
     mImpl->log("start vkRegisterObjectsNVX");
     auto stream = mImpl->stream();
@@ -19403,12 +19795,12 @@
     (void)local_ppObjectTableEntries;
     countingStream->rewind();
     {
-        uint64_t cgen_var_1295;
-        countingStream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_1295, 1);
-        countingStream->write((uint64_t*)&cgen_var_1295, 1 * 8);
-        uint64_t cgen_var_1296;
-        countingStream->handleMapping()->mapHandles_VkObjectTableNVX_u64(&local_objectTable, &cgen_var_1296, 1);
-        countingStream->write((uint64_t*)&cgen_var_1296, 1 * 8);
+        uint64_t cgen_var_1299;
+        countingStream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_1299, 1);
+        countingStream->write((uint64_t*)&cgen_var_1299, 1 * 8);
+        uint64_t cgen_var_1300;
+        countingStream->handleMapping()->mapHandles_VkObjectTableNVX_u64(&local_objectTable, &cgen_var_1300, 1);
+        countingStream->write((uint64_t*)&cgen_var_1300, 1 * 8);
         countingStream->write((uint32_t*)&local_objectCount, sizeof(uint32_t));
         (void)local_ppObjectTableEntries;
         countingStream->write((uint32_t*)local_pObjectIndices, ((objectCount)) * sizeof(uint32_t));
@@ -19418,12 +19810,12 @@
     uint32_t opcode_vkRegisterObjectsNVX = OP_vkRegisterObjectsNVX;
     stream->write(&opcode_vkRegisterObjectsNVX, sizeof(uint32_t));
     stream->write(&packetSize_vkRegisterObjectsNVX, sizeof(uint32_t));
-    uint64_t cgen_var_1297;
-    stream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_1297, 1);
-    stream->write((uint64_t*)&cgen_var_1297, 1 * 8);
-    uint64_t cgen_var_1298;
-    stream->handleMapping()->mapHandles_VkObjectTableNVX_u64(&local_objectTable, &cgen_var_1298, 1);
-    stream->write((uint64_t*)&cgen_var_1298, 1 * 8);
+    uint64_t cgen_var_1301;
+    stream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_1301, 1);
+    stream->write((uint64_t*)&cgen_var_1301, 1 * 8);
+    uint64_t cgen_var_1302;
+    stream->handleMapping()->mapHandles_VkObjectTableNVX_u64(&local_objectTable, &cgen_var_1302, 1);
+    stream->write((uint64_t*)&cgen_var_1302, 1 * 8);
     stream->write((uint32_t*)&local_objectCount, sizeof(uint32_t));
     (void)local_ppObjectTableEntries;
     stream->write((uint32_t*)local_pObjectIndices, ((objectCount)) * sizeof(uint32_t));
@@ -19445,6 +19837,7 @@
     const VkObjectEntryTypeNVX* pObjectEntryTypes,
     const uint32_t* pObjectIndices)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkUnregisterObjectsNVX encode");
     mImpl->log("start vkUnregisterObjectsNVX");
     auto stream = mImpl->stream();
@@ -19472,12 +19865,12 @@
     }
     countingStream->rewind();
     {
-        uint64_t cgen_var_1299;
-        countingStream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_1299, 1);
-        countingStream->write((uint64_t*)&cgen_var_1299, 1 * 8);
-        uint64_t cgen_var_1300;
-        countingStream->handleMapping()->mapHandles_VkObjectTableNVX_u64(&local_objectTable, &cgen_var_1300, 1);
-        countingStream->write((uint64_t*)&cgen_var_1300, 1 * 8);
+        uint64_t cgen_var_1303;
+        countingStream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_1303, 1);
+        countingStream->write((uint64_t*)&cgen_var_1303, 1 * 8);
+        uint64_t cgen_var_1304;
+        countingStream->handleMapping()->mapHandles_VkObjectTableNVX_u64(&local_objectTable, &cgen_var_1304, 1);
+        countingStream->write((uint64_t*)&cgen_var_1304, 1 * 8);
         countingStream->write((uint32_t*)&local_objectCount, sizeof(uint32_t));
         countingStream->write((VkObjectEntryTypeNVX*)local_pObjectEntryTypes, ((objectCount)) * sizeof(VkObjectEntryTypeNVX));
         countingStream->write((uint32_t*)local_pObjectIndices, ((objectCount)) * sizeof(uint32_t));
@@ -19487,12 +19880,12 @@
     uint32_t opcode_vkUnregisterObjectsNVX = OP_vkUnregisterObjectsNVX;
     stream->write(&opcode_vkUnregisterObjectsNVX, sizeof(uint32_t));
     stream->write(&packetSize_vkUnregisterObjectsNVX, sizeof(uint32_t));
-    uint64_t cgen_var_1301;
-    stream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_1301, 1);
-    stream->write((uint64_t*)&cgen_var_1301, 1 * 8);
-    uint64_t cgen_var_1302;
-    stream->handleMapping()->mapHandles_VkObjectTableNVX_u64(&local_objectTable, &cgen_var_1302, 1);
-    stream->write((uint64_t*)&cgen_var_1302, 1 * 8);
+    uint64_t cgen_var_1305;
+    stream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_1305, 1);
+    stream->write((uint64_t*)&cgen_var_1305, 1 * 8);
+    uint64_t cgen_var_1306;
+    stream->handleMapping()->mapHandles_VkObjectTableNVX_u64(&local_objectTable, &cgen_var_1306, 1);
+    stream->write((uint64_t*)&cgen_var_1306, 1 * 8);
     stream->write((uint32_t*)&local_objectCount, sizeof(uint32_t));
     stream->write((VkObjectEntryTypeNVX*)local_pObjectEntryTypes, ((objectCount)) * sizeof(VkObjectEntryTypeNVX));
     stream->write((uint32_t*)local_pObjectIndices, ((objectCount)) * sizeof(uint32_t));
@@ -19512,6 +19905,7 @@
     VkDeviceGeneratedCommandsFeaturesNVX* pFeatures,
     VkDeviceGeneratedCommandsLimitsNVX* pLimits)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkGetPhysicalDeviceGeneratedCommandsPropertiesNVX encode");
     mImpl->log("start vkGetPhysicalDeviceGeneratedCommandsPropertiesNVX");
     auto stream = mImpl->stream();
@@ -19523,9 +19917,9 @@
     local_physicalDevice = physicalDevice;
     countingStream->rewind();
     {
-        uint64_t cgen_var_1303;
-        countingStream->handleMapping()->mapHandles_VkPhysicalDevice_u64(&local_physicalDevice, &cgen_var_1303, 1);
-        countingStream->write((uint64_t*)&cgen_var_1303, 1 * 8);
+        uint64_t cgen_var_1307;
+        countingStream->handleMapping()->mapHandles_VkPhysicalDevice_u64(&local_physicalDevice, &cgen_var_1307, 1);
+        countingStream->write((uint64_t*)&cgen_var_1307, 1 * 8);
         marshal_VkDeviceGeneratedCommandsFeaturesNVX(countingStream, (VkDeviceGeneratedCommandsFeaturesNVX*)(pFeatures));
         marshal_VkDeviceGeneratedCommandsLimitsNVX(countingStream, (VkDeviceGeneratedCommandsLimitsNVX*)(pLimits));
     }
@@ -19534,9 +19928,9 @@
     uint32_t opcode_vkGetPhysicalDeviceGeneratedCommandsPropertiesNVX = OP_vkGetPhysicalDeviceGeneratedCommandsPropertiesNVX;
     stream->write(&opcode_vkGetPhysicalDeviceGeneratedCommandsPropertiesNVX, sizeof(uint32_t));
     stream->write(&packetSize_vkGetPhysicalDeviceGeneratedCommandsPropertiesNVX, sizeof(uint32_t));
-    uint64_t cgen_var_1304;
-    stream->handleMapping()->mapHandles_VkPhysicalDevice_u64(&local_physicalDevice, &cgen_var_1304, 1);
-    stream->write((uint64_t*)&cgen_var_1304, 1 * 8);
+    uint64_t cgen_var_1308;
+    stream->handleMapping()->mapHandles_VkPhysicalDevice_u64(&local_physicalDevice, &cgen_var_1308, 1);
+    stream->write((uint64_t*)&cgen_var_1308, 1 * 8);
     marshal_VkDeviceGeneratedCommandsFeaturesNVX(stream, (VkDeviceGeneratedCommandsFeaturesNVX*)(pFeatures));
     marshal_VkDeviceGeneratedCommandsLimitsNVX(stream, (VkDeviceGeneratedCommandsLimitsNVX*)(pLimits));
     AEMU_SCOPED_TRACE("vkGetPhysicalDeviceGeneratedCommandsPropertiesNVX readParams");
@@ -19562,6 +19956,7 @@
     uint32_t viewportCount,
     const VkViewportWScalingNV* pViewportWScalings)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkCmdSetViewportWScalingNV encode");
     mImpl->log("start vkCmdSetViewportWScalingNV");
     auto stream = mImpl->stream();
@@ -19594,9 +19989,9 @@
     }
     countingStream->rewind();
     {
-        uint64_t cgen_var_1305;
-        countingStream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_1305, 1);
-        countingStream->write((uint64_t*)&cgen_var_1305, 1 * 8);
+        uint64_t cgen_var_1309;
+        countingStream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_1309, 1);
+        countingStream->write((uint64_t*)&cgen_var_1309, 1 * 8);
         countingStream->write((uint32_t*)&local_firstViewport, sizeof(uint32_t));
         countingStream->write((uint32_t*)&local_viewportCount, sizeof(uint32_t));
         for (uint32_t i = 0; i < (uint32_t)((viewportCount)); ++i)
@@ -19609,9 +20004,9 @@
     uint32_t opcode_vkCmdSetViewportWScalingNV = OP_vkCmdSetViewportWScalingNV;
     stream->write(&opcode_vkCmdSetViewportWScalingNV, sizeof(uint32_t));
     stream->write(&packetSize_vkCmdSetViewportWScalingNV, sizeof(uint32_t));
-    uint64_t cgen_var_1306;
-    stream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_1306, 1);
-    stream->write((uint64_t*)&cgen_var_1306, 1 * 8);
+    uint64_t cgen_var_1310;
+    stream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_1310, 1);
+    stream->write((uint64_t*)&cgen_var_1310, 1 * 8);
     stream->write((uint32_t*)&local_firstViewport, sizeof(uint32_t));
     stream->write((uint32_t*)&local_viewportCount, sizeof(uint32_t));
     for (uint32_t i = 0; i < (uint32_t)((viewportCount)); ++i)
@@ -19629,6 +20024,7 @@
     VkPhysicalDevice physicalDevice,
     VkDisplayKHR display)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkReleaseDisplayEXT encode");
     mImpl->log("start vkReleaseDisplayEXT");
     auto stream = mImpl->stream();
@@ -19642,24 +20038,24 @@
     local_display = display;
     countingStream->rewind();
     {
-        uint64_t cgen_var_1307;
-        countingStream->handleMapping()->mapHandles_VkPhysicalDevice_u64(&local_physicalDevice, &cgen_var_1307, 1);
-        countingStream->write((uint64_t*)&cgen_var_1307, 1 * 8);
-        uint64_t cgen_var_1308;
-        countingStream->handleMapping()->mapHandles_VkDisplayKHR_u64(&local_display, &cgen_var_1308, 1);
-        countingStream->write((uint64_t*)&cgen_var_1308, 1 * 8);
+        uint64_t cgen_var_1311;
+        countingStream->handleMapping()->mapHandles_VkPhysicalDevice_u64(&local_physicalDevice, &cgen_var_1311, 1);
+        countingStream->write((uint64_t*)&cgen_var_1311, 1 * 8);
+        uint64_t cgen_var_1312;
+        countingStream->handleMapping()->mapHandles_VkDisplayKHR_u64(&local_display, &cgen_var_1312, 1);
+        countingStream->write((uint64_t*)&cgen_var_1312, 1 * 8);
     }
     uint32_t packetSize_vkReleaseDisplayEXT = 4 + 4 + (uint32_t)countingStream->bytesWritten();
     countingStream->rewind();
     uint32_t opcode_vkReleaseDisplayEXT = OP_vkReleaseDisplayEXT;
     stream->write(&opcode_vkReleaseDisplayEXT, sizeof(uint32_t));
     stream->write(&packetSize_vkReleaseDisplayEXT, sizeof(uint32_t));
-    uint64_t cgen_var_1309;
-    stream->handleMapping()->mapHandles_VkPhysicalDevice_u64(&local_physicalDevice, &cgen_var_1309, 1);
-    stream->write((uint64_t*)&cgen_var_1309, 1 * 8);
-    uint64_t cgen_var_1310;
-    stream->handleMapping()->mapHandles_VkDisplayKHR_u64(&local_display, &cgen_var_1310, 1);
-    stream->write((uint64_t*)&cgen_var_1310, 1 * 8);
+    uint64_t cgen_var_1313;
+    stream->handleMapping()->mapHandles_VkPhysicalDevice_u64(&local_physicalDevice, &cgen_var_1313, 1);
+    stream->write((uint64_t*)&cgen_var_1313, 1 * 8);
+    uint64_t cgen_var_1314;
+    stream->handleMapping()->mapHandles_VkDisplayKHR_u64(&local_display, &cgen_var_1314, 1);
+    stream->write((uint64_t*)&cgen_var_1314, 1 * 8);
     AEMU_SCOPED_TRACE("vkReleaseDisplayEXT readParams");
     AEMU_SCOPED_TRACE("vkReleaseDisplayEXT returnUnmarshal");
     VkResult vkReleaseDisplayEXT_VkResult_return = (VkResult)0;
@@ -19678,6 +20074,7 @@
     Display* dpy,
     VkDisplayKHR display)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkAcquireXlibDisplayEXT encode");
     mImpl->log("start vkAcquireXlibDisplayEXT");
     auto stream = mImpl->stream();
@@ -19691,26 +20088,26 @@
     local_display = display;
     countingStream->rewind();
     {
-        uint64_t cgen_var_1311;
-        countingStream->handleMapping()->mapHandles_VkPhysicalDevice_u64(&local_physicalDevice, &cgen_var_1311, 1);
-        countingStream->write((uint64_t*)&cgen_var_1311, 1 * 8);
+        uint64_t cgen_var_1315;
+        countingStream->handleMapping()->mapHandles_VkPhysicalDevice_u64(&local_physicalDevice, &cgen_var_1315, 1);
+        countingStream->write((uint64_t*)&cgen_var_1315, 1 * 8);
         countingStream->write((Display*)dpy, sizeof(Display));
-        uint64_t cgen_var_1312;
-        countingStream->handleMapping()->mapHandles_VkDisplayKHR_u64(&local_display, &cgen_var_1312, 1);
-        countingStream->write((uint64_t*)&cgen_var_1312, 1 * 8);
+        uint64_t cgen_var_1316;
+        countingStream->handleMapping()->mapHandles_VkDisplayKHR_u64(&local_display, &cgen_var_1316, 1);
+        countingStream->write((uint64_t*)&cgen_var_1316, 1 * 8);
     }
     uint32_t packetSize_vkAcquireXlibDisplayEXT = 4 + 4 + (uint32_t)countingStream->bytesWritten();
     countingStream->rewind();
     uint32_t opcode_vkAcquireXlibDisplayEXT = OP_vkAcquireXlibDisplayEXT;
     stream->write(&opcode_vkAcquireXlibDisplayEXT, sizeof(uint32_t));
     stream->write(&packetSize_vkAcquireXlibDisplayEXT, sizeof(uint32_t));
-    uint64_t cgen_var_1313;
-    stream->handleMapping()->mapHandles_VkPhysicalDevice_u64(&local_physicalDevice, &cgen_var_1313, 1);
-    stream->write((uint64_t*)&cgen_var_1313, 1 * 8);
+    uint64_t cgen_var_1317;
+    stream->handleMapping()->mapHandles_VkPhysicalDevice_u64(&local_physicalDevice, &cgen_var_1317, 1);
+    stream->write((uint64_t*)&cgen_var_1317, 1 * 8);
     stream->write((Display*)dpy, sizeof(Display));
-    uint64_t cgen_var_1314;
-    stream->handleMapping()->mapHandles_VkDisplayKHR_u64(&local_display, &cgen_var_1314, 1);
-    stream->write((uint64_t*)&cgen_var_1314, 1 * 8);
+    uint64_t cgen_var_1318;
+    stream->handleMapping()->mapHandles_VkDisplayKHR_u64(&local_display, &cgen_var_1318, 1);
+    stream->write((uint64_t*)&cgen_var_1318, 1 * 8);
     AEMU_SCOPED_TRACE("vkAcquireXlibDisplayEXT readParams");
     stream->read((Display*)dpy, sizeof(Display));
     AEMU_SCOPED_TRACE("vkAcquireXlibDisplayEXT returnUnmarshal");
@@ -19729,6 +20126,7 @@
     RROutput rrOutput,
     VkDisplayKHR* pDisplay)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkGetRandROutputDisplayEXT encode");
     mImpl->log("start vkGetRandROutputDisplayEXT");
     auto stream = mImpl->stream();
@@ -19742,35 +20140,35 @@
     local_rrOutput = rrOutput;
     countingStream->rewind();
     {
-        uint64_t cgen_var_1315;
-        countingStream->handleMapping()->mapHandles_VkPhysicalDevice_u64(&local_physicalDevice, &cgen_var_1315, 1);
-        countingStream->write((uint64_t*)&cgen_var_1315, 1 * 8);
+        uint64_t cgen_var_1319;
+        countingStream->handleMapping()->mapHandles_VkPhysicalDevice_u64(&local_physicalDevice, &cgen_var_1319, 1);
+        countingStream->write((uint64_t*)&cgen_var_1319, 1 * 8);
         countingStream->write((Display*)dpy, sizeof(Display));
         countingStream->write((RROutput*)&local_rrOutput, sizeof(RROutput));
-        uint64_t cgen_var_1316;
-        countingStream->handleMapping()->mapHandles_VkDisplayKHR_u64(pDisplay, &cgen_var_1316, 1);
-        countingStream->write((uint64_t*)&cgen_var_1316, 8);
+        uint64_t cgen_var_1320;
+        countingStream->handleMapping()->mapHandles_VkDisplayKHR_u64(pDisplay, &cgen_var_1320, 1);
+        countingStream->write((uint64_t*)&cgen_var_1320, 8);
     }
     uint32_t packetSize_vkGetRandROutputDisplayEXT = 4 + 4 + (uint32_t)countingStream->bytesWritten();
     countingStream->rewind();
     uint32_t opcode_vkGetRandROutputDisplayEXT = OP_vkGetRandROutputDisplayEXT;
     stream->write(&opcode_vkGetRandROutputDisplayEXT, sizeof(uint32_t));
     stream->write(&packetSize_vkGetRandROutputDisplayEXT, sizeof(uint32_t));
-    uint64_t cgen_var_1317;
-    stream->handleMapping()->mapHandles_VkPhysicalDevice_u64(&local_physicalDevice, &cgen_var_1317, 1);
-    stream->write((uint64_t*)&cgen_var_1317, 1 * 8);
+    uint64_t cgen_var_1321;
+    stream->handleMapping()->mapHandles_VkPhysicalDevice_u64(&local_physicalDevice, &cgen_var_1321, 1);
+    stream->write((uint64_t*)&cgen_var_1321, 1 * 8);
     stream->write((Display*)dpy, sizeof(Display));
     stream->write((RROutput*)&local_rrOutput, sizeof(RROutput));
     stream->unsetHandleMapping() /* emit_marshal, is handle, possibly out */;
-    uint64_t cgen_var_1318;
-    stream->handleMapping()->mapHandles_VkDisplayKHR_u64(pDisplay, &cgen_var_1318, 1);
-    stream->write((uint64_t*)&cgen_var_1318, 8);
+    uint64_t cgen_var_1322;
+    stream->handleMapping()->mapHandles_VkDisplayKHR_u64(pDisplay, &cgen_var_1322, 1);
+    stream->write((uint64_t*)&cgen_var_1322, 8);
     stream->setHandleMapping(resources->unwrapMapping());
     AEMU_SCOPED_TRACE("vkGetRandROutputDisplayEXT readParams");
     stream->read((Display*)dpy, sizeof(Display));
-    uint64_t cgen_var_1319;
-    stream->read((uint64_t*)&cgen_var_1319, 8);
-    stream->handleMapping()->mapHandles_u64_VkDisplayKHR(&cgen_var_1319, (VkDisplayKHR*)pDisplay, 1);
+    uint64_t cgen_var_1323;
+    stream->read((uint64_t*)&cgen_var_1323, 8);
+    stream->handleMapping()->mapHandles_u64_VkDisplayKHR(&cgen_var_1323, (VkDisplayKHR*)pDisplay, 1);
     AEMU_SCOPED_TRACE("vkGetRandROutputDisplayEXT returnUnmarshal");
     VkResult vkGetRandROutputDisplayEXT_VkResult_return = (VkResult)0;
     stream->read(&vkGetRandROutputDisplayEXT_VkResult_return, sizeof(VkResult));
@@ -19788,6 +20186,7 @@
     VkSurfaceKHR surface,
     VkSurfaceCapabilities2EXT* pSurfaceCapabilities)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkGetPhysicalDeviceSurfaceCapabilities2EXT encode");
     mImpl->log("start vkGetPhysicalDeviceSurfaceCapabilities2EXT");
     auto stream = mImpl->stream();
@@ -19801,12 +20200,12 @@
     local_surface = surface;
     countingStream->rewind();
     {
-        uint64_t cgen_var_1320;
-        countingStream->handleMapping()->mapHandles_VkPhysicalDevice_u64(&local_physicalDevice, &cgen_var_1320, 1);
-        countingStream->write((uint64_t*)&cgen_var_1320, 1 * 8);
-        uint64_t cgen_var_1321;
-        countingStream->handleMapping()->mapHandles_VkSurfaceKHR_u64(&local_surface, &cgen_var_1321, 1);
-        countingStream->write((uint64_t*)&cgen_var_1321, 1 * 8);
+        uint64_t cgen_var_1324;
+        countingStream->handleMapping()->mapHandles_VkPhysicalDevice_u64(&local_physicalDevice, &cgen_var_1324, 1);
+        countingStream->write((uint64_t*)&cgen_var_1324, 1 * 8);
+        uint64_t cgen_var_1325;
+        countingStream->handleMapping()->mapHandles_VkSurfaceKHR_u64(&local_surface, &cgen_var_1325, 1);
+        countingStream->write((uint64_t*)&cgen_var_1325, 1 * 8);
         marshal_VkSurfaceCapabilities2EXT(countingStream, (VkSurfaceCapabilities2EXT*)(pSurfaceCapabilities));
     }
     uint32_t packetSize_vkGetPhysicalDeviceSurfaceCapabilities2EXT = 4 + 4 + (uint32_t)countingStream->bytesWritten();
@@ -19814,12 +20213,12 @@
     uint32_t opcode_vkGetPhysicalDeviceSurfaceCapabilities2EXT = OP_vkGetPhysicalDeviceSurfaceCapabilities2EXT;
     stream->write(&opcode_vkGetPhysicalDeviceSurfaceCapabilities2EXT, sizeof(uint32_t));
     stream->write(&packetSize_vkGetPhysicalDeviceSurfaceCapabilities2EXT, sizeof(uint32_t));
-    uint64_t cgen_var_1322;
-    stream->handleMapping()->mapHandles_VkPhysicalDevice_u64(&local_physicalDevice, &cgen_var_1322, 1);
-    stream->write((uint64_t*)&cgen_var_1322, 1 * 8);
-    uint64_t cgen_var_1323;
-    stream->handleMapping()->mapHandles_VkSurfaceKHR_u64(&local_surface, &cgen_var_1323, 1);
-    stream->write((uint64_t*)&cgen_var_1323, 1 * 8);
+    uint64_t cgen_var_1326;
+    stream->handleMapping()->mapHandles_VkPhysicalDevice_u64(&local_physicalDevice, &cgen_var_1326, 1);
+    stream->write((uint64_t*)&cgen_var_1326, 1 * 8);
+    uint64_t cgen_var_1327;
+    stream->handleMapping()->mapHandles_VkSurfaceKHR_u64(&local_surface, &cgen_var_1327, 1);
+    stream->write((uint64_t*)&cgen_var_1327, 1 * 8);
     marshal_VkSurfaceCapabilities2EXT(stream, (VkSurfaceCapabilities2EXT*)(pSurfaceCapabilities));
     AEMU_SCOPED_TRACE("vkGetPhysicalDeviceSurfaceCapabilities2EXT readParams");
     unmarshal_VkSurfaceCapabilities2EXT(stream, (VkSurfaceCapabilities2EXT*)(pSurfaceCapabilities));
@@ -19844,6 +20243,7 @@
     VkDisplayKHR display,
     const VkDisplayPowerInfoEXT* pDisplayPowerInfo)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkDisplayPowerControlEXT encode");
     mImpl->log("start vkDisplayPowerControlEXT");
     auto stream = mImpl->stream();
@@ -19868,12 +20268,12 @@
     }
     countingStream->rewind();
     {
-        uint64_t cgen_var_1324;
-        countingStream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_1324, 1);
-        countingStream->write((uint64_t*)&cgen_var_1324, 1 * 8);
-        uint64_t cgen_var_1325;
-        countingStream->handleMapping()->mapHandles_VkDisplayKHR_u64(&local_display, &cgen_var_1325, 1);
-        countingStream->write((uint64_t*)&cgen_var_1325, 1 * 8);
+        uint64_t cgen_var_1328;
+        countingStream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_1328, 1);
+        countingStream->write((uint64_t*)&cgen_var_1328, 1 * 8);
+        uint64_t cgen_var_1329;
+        countingStream->handleMapping()->mapHandles_VkDisplayKHR_u64(&local_display, &cgen_var_1329, 1);
+        countingStream->write((uint64_t*)&cgen_var_1329, 1 * 8);
         marshal_VkDisplayPowerInfoEXT(countingStream, (VkDisplayPowerInfoEXT*)(local_pDisplayPowerInfo));
     }
     uint32_t packetSize_vkDisplayPowerControlEXT = 4 + 4 + (uint32_t)countingStream->bytesWritten();
@@ -19881,12 +20281,12 @@
     uint32_t opcode_vkDisplayPowerControlEXT = OP_vkDisplayPowerControlEXT;
     stream->write(&opcode_vkDisplayPowerControlEXT, sizeof(uint32_t));
     stream->write(&packetSize_vkDisplayPowerControlEXT, sizeof(uint32_t));
-    uint64_t cgen_var_1326;
-    stream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_1326, 1);
-    stream->write((uint64_t*)&cgen_var_1326, 1 * 8);
-    uint64_t cgen_var_1327;
-    stream->handleMapping()->mapHandles_VkDisplayKHR_u64(&local_display, &cgen_var_1327, 1);
-    stream->write((uint64_t*)&cgen_var_1327, 1 * 8);
+    uint64_t cgen_var_1330;
+    stream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_1330, 1);
+    stream->write((uint64_t*)&cgen_var_1330, 1 * 8);
+    uint64_t cgen_var_1331;
+    stream->handleMapping()->mapHandles_VkDisplayKHR_u64(&local_display, &cgen_var_1331, 1);
+    stream->write((uint64_t*)&cgen_var_1331, 1 * 8);
     marshal_VkDisplayPowerInfoEXT(stream, (VkDisplayPowerInfoEXT*)(local_pDisplayPowerInfo));
     AEMU_SCOPED_TRACE("vkDisplayPowerControlEXT readParams");
     AEMU_SCOPED_TRACE("vkDisplayPowerControlEXT returnUnmarshal");
@@ -19905,6 +20305,7 @@
     const VkAllocationCallbacks* pAllocator,
     VkFence* pFence)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkRegisterDeviceEventEXT encode");
     mImpl->log("start vkRegisterDeviceEventEXT");
     auto stream = mImpl->stream();
@@ -19939,46 +20340,46 @@
     }
     countingStream->rewind();
     {
-        uint64_t cgen_var_1328;
-        countingStream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_1328, 1);
-        countingStream->write((uint64_t*)&cgen_var_1328, 1 * 8);
+        uint64_t cgen_var_1332;
+        countingStream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_1332, 1);
+        countingStream->write((uint64_t*)&cgen_var_1332, 1 * 8);
         marshal_VkDeviceEventInfoEXT(countingStream, (VkDeviceEventInfoEXT*)(local_pDeviceEventInfo));
         // WARNING PTR CHECK
-        uint64_t cgen_var_1329 = (uint64_t)(uintptr_t)local_pAllocator;
-        countingStream->putBe64(cgen_var_1329);
+        uint64_t cgen_var_1333 = (uint64_t)(uintptr_t)local_pAllocator;
+        countingStream->putBe64(cgen_var_1333);
         if (local_pAllocator)
         {
             marshal_VkAllocationCallbacks(countingStream, (VkAllocationCallbacks*)(local_pAllocator));
         }
-        uint64_t cgen_var_1330;
-        countingStream->handleMapping()->mapHandles_VkFence_u64(pFence, &cgen_var_1330, 1);
-        countingStream->write((uint64_t*)&cgen_var_1330, 8);
+        uint64_t cgen_var_1334;
+        countingStream->handleMapping()->mapHandles_VkFence_u64(pFence, &cgen_var_1334, 1);
+        countingStream->write((uint64_t*)&cgen_var_1334, 8);
     }
     uint32_t packetSize_vkRegisterDeviceEventEXT = 4 + 4 + (uint32_t)countingStream->bytesWritten();
     countingStream->rewind();
     uint32_t opcode_vkRegisterDeviceEventEXT = OP_vkRegisterDeviceEventEXT;
     stream->write(&opcode_vkRegisterDeviceEventEXT, sizeof(uint32_t));
     stream->write(&packetSize_vkRegisterDeviceEventEXT, sizeof(uint32_t));
-    uint64_t cgen_var_1331;
-    stream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_1331, 1);
-    stream->write((uint64_t*)&cgen_var_1331, 1 * 8);
+    uint64_t cgen_var_1335;
+    stream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_1335, 1);
+    stream->write((uint64_t*)&cgen_var_1335, 1 * 8);
     marshal_VkDeviceEventInfoEXT(stream, (VkDeviceEventInfoEXT*)(local_pDeviceEventInfo));
     // WARNING PTR CHECK
-    uint64_t cgen_var_1332 = (uint64_t)(uintptr_t)local_pAllocator;
-    stream->putBe64(cgen_var_1332);
+    uint64_t cgen_var_1336 = (uint64_t)(uintptr_t)local_pAllocator;
+    stream->putBe64(cgen_var_1336);
     if (local_pAllocator)
     {
         marshal_VkAllocationCallbacks(stream, (VkAllocationCallbacks*)(local_pAllocator));
     }
     stream->unsetHandleMapping() /* emit_marshal, is handle, possibly out */;
-    uint64_t cgen_var_1333;
-    stream->handleMapping()->mapHandles_VkFence_u64(pFence, &cgen_var_1333, 1);
-    stream->write((uint64_t*)&cgen_var_1333, 8);
+    uint64_t cgen_var_1337;
+    stream->handleMapping()->mapHandles_VkFence_u64(pFence, &cgen_var_1337, 1);
+    stream->write((uint64_t*)&cgen_var_1337, 8);
     stream->setHandleMapping(resources->unwrapMapping());
     AEMU_SCOPED_TRACE("vkRegisterDeviceEventEXT readParams");
-    uint64_t cgen_var_1334;
-    stream->read((uint64_t*)&cgen_var_1334, 8);
-    stream->handleMapping()->mapHandles_u64_VkFence(&cgen_var_1334, (VkFence*)pFence, 1);
+    uint64_t cgen_var_1338;
+    stream->read((uint64_t*)&cgen_var_1338, 8);
+    stream->handleMapping()->mapHandles_u64_VkFence(&cgen_var_1338, (VkFence*)pFence, 1);
     AEMU_SCOPED_TRACE("vkRegisterDeviceEventEXT returnUnmarshal");
     VkResult vkRegisterDeviceEventEXT_VkResult_return = (VkResult)0;
     stream->read(&vkRegisterDeviceEventEXT_VkResult_return, sizeof(VkResult));
@@ -19996,6 +20397,7 @@
     const VkAllocationCallbacks* pAllocator,
     VkFence* pFence)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkRegisterDisplayEventEXT encode");
     mImpl->log("start vkRegisterDisplayEventEXT");
     auto stream = mImpl->stream();
@@ -20032,52 +20434,52 @@
     }
     countingStream->rewind();
     {
-        uint64_t cgen_var_1335;
-        countingStream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_1335, 1);
-        countingStream->write((uint64_t*)&cgen_var_1335, 1 * 8);
-        uint64_t cgen_var_1336;
-        countingStream->handleMapping()->mapHandles_VkDisplayKHR_u64(&local_display, &cgen_var_1336, 1);
-        countingStream->write((uint64_t*)&cgen_var_1336, 1 * 8);
+        uint64_t cgen_var_1339;
+        countingStream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_1339, 1);
+        countingStream->write((uint64_t*)&cgen_var_1339, 1 * 8);
+        uint64_t cgen_var_1340;
+        countingStream->handleMapping()->mapHandles_VkDisplayKHR_u64(&local_display, &cgen_var_1340, 1);
+        countingStream->write((uint64_t*)&cgen_var_1340, 1 * 8);
         marshal_VkDisplayEventInfoEXT(countingStream, (VkDisplayEventInfoEXT*)(local_pDisplayEventInfo));
         // WARNING PTR CHECK
-        uint64_t cgen_var_1337 = (uint64_t)(uintptr_t)local_pAllocator;
-        countingStream->putBe64(cgen_var_1337);
+        uint64_t cgen_var_1341 = (uint64_t)(uintptr_t)local_pAllocator;
+        countingStream->putBe64(cgen_var_1341);
         if (local_pAllocator)
         {
             marshal_VkAllocationCallbacks(countingStream, (VkAllocationCallbacks*)(local_pAllocator));
         }
-        uint64_t cgen_var_1338;
-        countingStream->handleMapping()->mapHandles_VkFence_u64(pFence, &cgen_var_1338, 1);
-        countingStream->write((uint64_t*)&cgen_var_1338, 8);
+        uint64_t cgen_var_1342;
+        countingStream->handleMapping()->mapHandles_VkFence_u64(pFence, &cgen_var_1342, 1);
+        countingStream->write((uint64_t*)&cgen_var_1342, 8);
     }
     uint32_t packetSize_vkRegisterDisplayEventEXT = 4 + 4 + (uint32_t)countingStream->bytesWritten();
     countingStream->rewind();
     uint32_t opcode_vkRegisterDisplayEventEXT = OP_vkRegisterDisplayEventEXT;
     stream->write(&opcode_vkRegisterDisplayEventEXT, sizeof(uint32_t));
     stream->write(&packetSize_vkRegisterDisplayEventEXT, sizeof(uint32_t));
-    uint64_t cgen_var_1339;
-    stream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_1339, 1);
-    stream->write((uint64_t*)&cgen_var_1339, 1 * 8);
-    uint64_t cgen_var_1340;
-    stream->handleMapping()->mapHandles_VkDisplayKHR_u64(&local_display, &cgen_var_1340, 1);
-    stream->write((uint64_t*)&cgen_var_1340, 1 * 8);
+    uint64_t cgen_var_1343;
+    stream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_1343, 1);
+    stream->write((uint64_t*)&cgen_var_1343, 1 * 8);
+    uint64_t cgen_var_1344;
+    stream->handleMapping()->mapHandles_VkDisplayKHR_u64(&local_display, &cgen_var_1344, 1);
+    stream->write((uint64_t*)&cgen_var_1344, 1 * 8);
     marshal_VkDisplayEventInfoEXT(stream, (VkDisplayEventInfoEXT*)(local_pDisplayEventInfo));
     // WARNING PTR CHECK
-    uint64_t cgen_var_1341 = (uint64_t)(uintptr_t)local_pAllocator;
-    stream->putBe64(cgen_var_1341);
+    uint64_t cgen_var_1345 = (uint64_t)(uintptr_t)local_pAllocator;
+    stream->putBe64(cgen_var_1345);
     if (local_pAllocator)
     {
         marshal_VkAllocationCallbacks(stream, (VkAllocationCallbacks*)(local_pAllocator));
     }
     stream->unsetHandleMapping() /* emit_marshal, is handle, possibly out */;
-    uint64_t cgen_var_1342;
-    stream->handleMapping()->mapHandles_VkFence_u64(pFence, &cgen_var_1342, 1);
-    stream->write((uint64_t*)&cgen_var_1342, 8);
+    uint64_t cgen_var_1346;
+    stream->handleMapping()->mapHandles_VkFence_u64(pFence, &cgen_var_1346, 1);
+    stream->write((uint64_t*)&cgen_var_1346, 8);
     stream->setHandleMapping(resources->unwrapMapping());
     AEMU_SCOPED_TRACE("vkRegisterDisplayEventEXT readParams");
-    uint64_t cgen_var_1343;
-    stream->read((uint64_t*)&cgen_var_1343, 8);
-    stream->handleMapping()->mapHandles_u64_VkFence(&cgen_var_1343, (VkFence*)pFence, 1);
+    uint64_t cgen_var_1347;
+    stream->read((uint64_t*)&cgen_var_1347, 8);
+    stream->handleMapping()->mapHandles_u64_VkFence(&cgen_var_1347, (VkFence*)pFence, 1);
     AEMU_SCOPED_TRACE("vkRegisterDisplayEventEXT returnUnmarshal");
     VkResult vkRegisterDisplayEventEXT_VkResult_return = (VkResult)0;
     stream->read(&vkRegisterDisplayEventEXT_VkResult_return, sizeof(VkResult));
@@ -20094,6 +20496,7 @@
     VkSurfaceCounterFlagBitsEXT counter,
     uint64_t* pCounterValue)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkGetSwapchainCounterEXT encode");
     mImpl->log("start vkGetSwapchainCounterEXT");
     auto stream = mImpl->stream();
@@ -20109,12 +20512,12 @@
     local_counter = counter;
     countingStream->rewind();
     {
-        uint64_t cgen_var_1344;
-        countingStream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_1344, 1);
-        countingStream->write((uint64_t*)&cgen_var_1344, 1 * 8);
-        uint64_t cgen_var_1345;
-        countingStream->handleMapping()->mapHandles_VkSwapchainKHR_u64(&local_swapchain, &cgen_var_1345, 1);
-        countingStream->write((uint64_t*)&cgen_var_1345, 1 * 8);
+        uint64_t cgen_var_1348;
+        countingStream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_1348, 1);
+        countingStream->write((uint64_t*)&cgen_var_1348, 1 * 8);
+        uint64_t cgen_var_1349;
+        countingStream->handleMapping()->mapHandles_VkSwapchainKHR_u64(&local_swapchain, &cgen_var_1349, 1);
+        countingStream->write((uint64_t*)&cgen_var_1349, 1 * 8);
         countingStream->write((VkSurfaceCounterFlagBitsEXT*)&local_counter, sizeof(VkSurfaceCounterFlagBitsEXT));
         countingStream->write((uint64_t*)pCounterValue, sizeof(uint64_t));
     }
@@ -20123,12 +20526,12 @@
     uint32_t opcode_vkGetSwapchainCounterEXT = OP_vkGetSwapchainCounterEXT;
     stream->write(&opcode_vkGetSwapchainCounterEXT, sizeof(uint32_t));
     stream->write(&packetSize_vkGetSwapchainCounterEXT, sizeof(uint32_t));
-    uint64_t cgen_var_1346;
-    stream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_1346, 1);
-    stream->write((uint64_t*)&cgen_var_1346, 1 * 8);
-    uint64_t cgen_var_1347;
-    stream->handleMapping()->mapHandles_VkSwapchainKHR_u64(&local_swapchain, &cgen_var_1347, 1);
-    stream->write((uint64_t*)&cgen_var_1347, 1 * 8);
+    uint64_t cgen_var_1350;
+    stream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_1350, 1);
+    stream->write((uint64_t*)&cgen_var_1350, 1 * 8);
+    uint64_t cgen_var_1351;
+    stream->handleMapping()->mapHandles_VkSwapchainKHR_u64(&local_swapchain, &cgen_var_1351, 1);
+    stream->write((uint64_t*)&cgen_var_1351, 1 * 8);
     stream->write((VkSurfaceCounterFlagBitsEXT*)&local_counter, sizeof(VkSurfaceCounterFlagBitsEXT));
     stream->write((uint64_t*)pCounterValue, sizeof(uint64_t));
     AEMU_SCOPED_TRACE("vkGetSwapchainCounterEXT readParams");
@@ -20150,6 +20553,7 @@
     VkSwapchainKHR swapchain,
     VkRefreshCycleDurationGOOGLE* pDisplayTimingProperties)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkGetRefreshCycleDurationGOOGLE encode");
     mImpl->log("start vkGetRefreshCycleDurationGOOGLE");
     auto stream = mImpl->stream();
@@ -20163,12 +20567,12 @@
     local_swapchain = swapchain;
     countingStream->rewind();
     {
-        uint64_t cgen_var_1348;
-        countingStream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_1348, 1);
-        countingStream->write((uint64_t*)&cgen_var_1348, 1 * 8);
-        uint64_t cgen_var_1349;
-        countingStream->handleMapping()->mapHandles_VkSwapchainKHR_u64(&local_swapchain, &cgen_var_1349, 1);
-        countingStream->write((uint64_t*)&cgen_var_1349, 1 * 8);
+        uint64_t cgen_var_1352;
+        countingStream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_1352, 1);
+        countingStream->write((uint64_t*)&cgen_var_1352, 1 * 8);
+        uint64_t cgen_var_1353;
+        countingStream->handleMapping()->mapHandles_VkSwapchainKHR_u64(&local_swapchain, &cgen_var_1353, 1);
+        countingStream->write((uint64_t*)&cgen_var_1353, 1 * 8);
         marshal_VkRefreshCycleDurationGOOGLE(countingStream, (VkRefreshCycleDurationGOOGLE*)(pDisplayTimingProperties));
     }
     uint32_t packetSize_vkGetRefreshCycleDurationGOOGLE = 4 + 4 + (uint32_t)countingStream->bytesWritten();
@@ -20176,12 +20580,12 @@
     uint32_t opcode_vkGetRefreshCycleDurationGOOGLE = OP_vkGetRefreshCycleDurationGOOGLE;
     stream->write(&opcode_vkGetRefreshCycleDurationGOOGLE, sizeof(uint32_t));
     stream->write(&packetSize_vkGetRefreshCycleDurationGOOGLE, sizeof(uint32_t));
-    uint64_t cgen_var_1350;
-    stream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_1350, 1);
-    stream->write((uint64_t*)&cgen_var_1350, 1 * 8);
-    uint64_t cgen_var_1351;
-    stream->handleMapping()->mapHandles_VkSwapchainKHR_u64(&local_swapchain, &cgen_var_1351, 1);
-    stream->write((uint64_t*)&cgen_var_1351, 1 * 8);
+    uint64_t cgen_var_1354;
+    stream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_1354, 1);
+    stream->write((uint64_t*)&cgen_var_1354, 1 * 8);
+    uint64_t cgen_var_1355;
+    stream->handleMapping()->mapHandles_VkSwapchainKHR_u64(&local_swapchain, &cgen_var_1355, 1);
+    stream->write((uint64_t*)&cgen_var_1355, 1 * 8);
     marshal_VkRefreshCycleDurationGOOGLE(stream, (VkRefreshCycleDurationGOOGLE*)(pDisplayTimingProperties));
     AEMU_SCOPED_TRACE("vkGetRefreshCycleDurationGOOGLE readParams");
     unmarshal_VkRefreshCycleDurationGOOGLE(stream, (VkRefreshCycleDurationGOOGLE*)(pDisplayTimingProperties));
@@ -20205,6 +20609,7 @@
     uint32_t* pPresentationTimingCount,
     VkPastPresentationTimingGOOGLE* pPresentationTimings)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkGetPastPresentationTimingGOOGLE encode");
     mImpl->log("start vkGetPastPresentationTimingGOOGLE");
     auto stream = mImpl->stream();
@@ -20218,22 +20623,22 @@
     local_swapchain = swapchain;
     countingStream->rewind();
     {
-        uint64_t cgen_var_1352;
-        countingStream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_1352, 1);
-        countingStream->write((uint64_t*)&cgen_var_1352, 1 * 8);
-        uint64_t cgen_var_1353;
-        countingStream->handleMapping()->mapHandles_VkSwapchainKHR_u64(&local_swapchain, &cgen_var_1353, 1);
-        countingStream->write((uint64_t*)&cgen_var_1353, 1 * 8);
+        uint64_t cgen_var_1356;
+        countingStream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_1356, 1);
+        countingStream->write((uint64_t*)&cgen_var_1356, 1 * 8);
+        uint64_t cgen_var_1357;
+        countingStream->handleMapping()->mapHandles_VkSwapchainKHR_u64(&local_swapchain, &cgen_var_1357, 1);
+        countingStream->write((uint64_t*)&cgen_var_1357, 1 * 8);
         // WARNING PTR CHECK
-        uint64_t cgen_var_1354 = (uint64_t)(uintptr_t)pPresentationTimingCount;
-        countingStream->putBe64(cgen_var_1354);
+        uint64_t cgen_var_1358 = (uint64_t)(uintptr_t)pPresentationTimingCount;
+        countingStream->putBe64(cgen_var_1358);
         if (pPresentationTimingCount)
         {
             countingStream->write((uint32_t*)pPresentationTimingCount, sizeof(uint32_t));
         }
         // WARNING PTR CHECK
-        uint64_t cgen_var_1355 = (uint64_t)(uintptr_t)pPresentationTimings;
-        countingStream->putBe64(cgen_var_1355);
+        uint64_t cgen_var_1359 = (uint64_t)(uintptr_t)pPresentationTimings;
+        countingStream->putBe64(cgen_var_1359);
         if (pPresentationTimings)
         {
             for (uint32_t i = 0; i < (uint32_t)(*(pPresentationTimingCount)); ++i)
@@ -20247,22 +20652,22 @@
     uint32_t opcode_vkGetPastPresentationTimingGOOGLE = OP_vkGetPastPresentationTimingGOOGLE;
     stream->write(&opcode_vkGetPastPresentationTimingGOOGLE, sizeof(uint32_t));
     stream->write(&packetSize_vkGetPastPresentationTimingGOOGLE, sizeof(uint32_t));
-    uint64_t cgen_var_1356;
-    stream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_1356, 1);
-    stream->write((uint64_t*)&cgen_var_1356, 1 * 8);
-    uint64_t cgen_var_1357;
-    stream->handleMapping()->mapHandles_VkSwapchainKHR_u64(&local_swapchain, &cgen_var_1357, 1);
-    stream->write((uint64_t*)&cgen_var_1357, 1 * 8);
+    uint64_t cgen_var_1360;
+    stream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_1360, 1);
+    stream->write((uint64_t*)&cgen_var_1360, 1 * 8);
+    uint64_t cgen_var_1361;
+    stream->handleMapping()->mapHandles_VkSwapchainKHR_u64(&local_swapchain, &cgen_var_1361, 1);
+    stream->write((uint64_t*)&cgen_var_1361, 1 * 8);
     // WARNING PTR CHECK
-    uint64_t cgen_var_1358 = (uint64_t)(uintptr_t)pPresentationTimingCount;
-    stream->putBe64(cgen_var_1358);
+    uint64_t cgen_var_1362 = (uint64_t)(uintptr_t)pPresentationTimingCount;
+    stream->putBe64(cgen_var_1362);
     if (pPresentationTimingCount)
     {
         stream->write((uint32_t*)pPresentationTimingCount, sizeof(uint32_t));
     }
     // WARNING PTR CHECK
-    uint64_t cgen_var_1359 = (uint64_t)(uintptr_t)pPresentationTimings;
-    stream->putBe64(cgen_var_1359);
+    uint64_t cgen_var_1363 = (uint64_t)(uintptr_t)pPresentationTimings;
+    stream->putBe64(cgen_var_1363);
     if (pPresentationTimings)
     {
         for (uint32_t i = 0; i < (uint32_t)(*(pPresentationTimingCount)); ++i)
@@ -20331,6 +20736,7 @@
     uint32_t discardRectangleCount,
     const VkRect2D* pDiscardRectangles)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkCmdSetDiscardRectangleEXT encode");
     mImpl->log("start vkCmdSetDiscardRectangleEXT");
     auto stream = mImpl->stream();
@@ -20363,9 +20769,9 @@
     }
     countingStream->rewind();
     {
-        uint64_t cgen_var_1362;
-        countingStream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_1362, 1);
-        countingStream->write((uint64_t*)&cgen_var_1362, 1 * 8);
+        uint64_t cgen_var_1366;
+        countingStream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_1366, 1);
+        countingStream->write((uint64_t*)&cgen_var_1366, 1 * 8);
         countingStream->write((uint32_t*)&local_firstDiscardRectangle, sizeof(uint32_t));
         countingStream->write((uint32_t*)&local_discardRectangleCount, sizeof(uint32_t));
         for (uint32_t i = 0; i < (uint32_t)((discardRectangleCount)); ++i)
@@ -20378,9 +20784,9 @@
     uint32_t opcode_vkCmdSetDiscardRectangleEXT = OP_vkCmdSetDiscardRectangleEXT;
     stream->write(&opcode_vkCmdSetDiscardRectangleEXT, sizeof(uint32_t));
     stream->write(&packetSize_vkCmdSetDiscardRectangleEXT, sizeof(uint32_t));
-    uint64_t cgen_var_1363;
-    stream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_1363, 1);
-    stream->write((uint64_t*)&cgen_var_1363, 1 * 8);
+    uint64_t cgen_var_1367;
+    stream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_1367, 1);
+    stream->write((uint64_t*)&cgen_var_1367, 1 * 8);
     stream->write((uint32_t*)&local_firstDiscardRectangle, sizeof(uint32_t));
     stream->write((uint32_t*)&local_discardRectangleCount, sizeof(uint32_t));
     for (uint32_t i = 0; i < (uint32_t)((discardRectangleCount)); ++i)
@@ -20404,6 +20810,7 @@
     const VkSwapchainKHR* pSwapchains,
     const VkHdrMetadataEXT* pMetadata)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkSetHdrMetadataEXT encode");
     mImpl->log("start vkSetHdrMetadataEXT");
     auto stream = mImpl->stream();
@@ -20440,16 +20847,16 @@
     }
     countingStream->rewind();
     {
-        uint64_t cgen_var_1364;
-        countingStream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_1364, 1);
-        countingStream->write((uint64_t*)&cgen_var_1364, 1 * 8);
+        uint64_t cgen_var_1368;
+        countingStream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_1368, 1);
+        countingStream->write((uint64_t*)&cgen_var_1368, 1 * 8);
         countingStream->write((uint32_t*)&local_swapchainCount, sizeof(uint32_t));
         if (((swapchainCount)))
         {
-            uint64_t* cgen_var_1365;
-            countingStream->alloc((void**)&cgen_var_1365, ((swapchainCount)) * 8);
-            countingStream->handleMapping()->mapHandles_VkSwapchainKHR_u64(local_pSwapchains, cgen_var_1365, ((swapchainCount)));
-            countingStream->write((uint64_t*)cgen_var_1365, ((swapchainCount)) * 8);
+            uint64_t* cgen_var_1369;
+            countingStream->alloc((void**)&cgen_var_1369, ((swapchainCount)) * 8);
+            countingStream->handleMapping()->mapHandles_VkSwapchainKHR_u64(local_pSwapchains, cgen_var_1369, ((swapchainCount)));
+            countingStream->write((uint64_t*)cgen_var_1369, ((swapchainCount)) * 8);
         }
         for (uint32_t i = 0; i < (uint32_t)((swapchainCount)); ++i)
         {
@@ -20461,16 +20868,16 @@
     uint32_t opcode_vkSetHdrMetadataEXT = OP_vkSetHdrMetadataEXT;
     stream->write(&opcode_vkSetHdrMetadataEXT, sizeof(uint32_t));
     stream->write(&packetSize_vkSetHdrMetadataEXT, sizeof(uint32_t));
-    uint64_t cgen_var_1366;
-    stream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_1366, 1);
-    stream->write((uint64_t*)&cgen_var_1366, 1 * 8);
+    uint64_t cgen_var_1370;
+    stream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_1370, 1);
+    stream->write((uint64_t*)&cgen_var_1370, 1 * 8);
     stream->write((uint32_t*)&local_swapchainCount, sizeof(uint32_t));
     if (((swapchainCount)))
     {
-        uint64_t* cgen_var_1367;
-        stream->alloc((void**)&cgen_var_1367, ((swapchainCount)) * 8);
-        stream->handleMapping()->mapHandles_VkSwapchainKHR_u64(local_pSwapchains, cgen_var_1367, ((swapchainCount)));
-        stream->write((uint64_t*)cgen_var_1367, ((swapchainCount)) * 8);
+        uint64_t* cgen_var_1371;
+        stream->alloc((void**)&cgen_var_1371, ((swapchainCount)) * 8);
+        stream->handleMapping()->mapHandles_VkSwapchainKHR_u64(local_pSwapchains, cgen_var_1371, ((swapchainCount)));
+        stream->write((uint64_t*)cgen_var_1371, ((swapchainCount)) * 8);
     }
     for (uint32_t i = 0; i < (uint32_t)((swapchainCount)); ++i)
     {
@@ -20489,6 +20896,7 @@
     const VkAllocationCallbacks* pAllocator,
     VkSurfaceKHR* pSurface)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkCreateIOSSurfaceMVK encode");
     mImpl->log("start vkCreateIOSSurfaceMVK");
     auto stream = mImpl->stream();
@@ -20523,46 +20931,46 @@
     }
     countingStream->rewind();
     {
-        uint64_t cgen_var_1368;
-        countingStream->handleMapping()->mapHandles_VkInstance_u64(&local_instance, &cgen_var_1368, 1);
-        countingStream->write((uint64_t*)&cgen_var_1368, 1 * 8);
+        uint64_t cgen_var_1372;
+        countingStream->handleMapping()->mapHandles_VkInstance_u64(&local_instance, &cgen_var_1372, 1);
+        countingStream->write((uint64_t*)&cgen_var_1372, 1 * 8);
         marshal_VkIOSSurfaceCreateInfoMVK(countingStream, (VkIOSSurfaceCreateInfoMVK*)(local_pCreateInfo));
         // WARNING PTR CHECK
-        uint64_t cgen_var_1369 = (uint64_t)(uintptr_t)local_pAllocator;
-        countingStream->putBe64(cgen_var_1369);
+        uint64_t cgen_var_1373 = (uint64_t)(uintptr_t)local_pAllocator;
+        countingStream->putBe64(cgen_var_1373);
         if (local_pAllocator)
         {
             marshal_VkAllocationCallbacks(countingStream, (VkAllocationCallbacks*)(local_pAllocator));
         }
-        uint64_t cgen_var_1370;
-        countingStream->handleMapping()->mapHandles_VkSurfaceKHR_u64(pSurface, &cgen_var_1370, 1);
-        countingStream->write((uint64_t*)&cgen_var_1370, 8);
+        uint64_t cgen_var_1374;
+        countingStream->handleMapping()->mapHandles_VkSurfaceKHR_u64(pSurface, &cgen_var_1374, 1);
+        countingStream->write((uint64_t*)&cgen_var_1374, 8);
     }
     uint32_t packetSize_vkCreateIOSSurfaceMVK = 4 + 4 + (uint32_t)countingStream->bytesWritten();
     countingStream->rewind();
     uint32_t opcode_vkCreateIOSSurfaceMVK = OP_vkCreateIOSSurfaceMVK;
     stream->write(&opcode_vkCreateIOSSurfaceMVK, sizeof(uint32_t));
     stream->write(&packetSize_vkCreateIOSSurfaceMVK, sizeof(uint32_t));
-    uint64_t cgen_var_1371;
-    stream->handleMapping()->mapHandles_VkInstance_u64(&local_instance, &cgen_var_1371, 1);
-    stream->write((uint64_t*)&cgen_var_1371, 1 * 8);
+    uint64_t cgen_var_1375;
+    stream->handleMapping()->mapHandles_VkInstance_u64(&local_instance, &cgen_var_1375, 1);
+    stream->write((uint64_t*)&cgen_var_1375, 1 * 8);
     marshal_VkIOSSurfaceCreateInfoMVK(stream, (VkIOSSurfaceCreateInfoMVK*)(local_pCreateInfo));
     // WARNING PTR CHECK
-    uint64_t cgen_var_1372 = (uint64_t)(uintptr_t)local_pAllocator;
-    stream->putBe64(cgen_var_1372);
+    uint64_t cgen_var_1376 = (uint64_t)(uintptr_t)local_pAllocator;
+    stream->putBe64(cgen_var_1376);
     if (local_pAllocator)
     {
         marshal_VkAllocationCallbacks(stream, (VkAllocationCallbacks*)(local_pAllocator));
     }
     stream->unsetHandleMapping() /* emit_marshal, is handle, possibly out */;
-    uint64_t cgen_var_1373;
-    stream->handleMapping()->mapHandles_VkSurfaceKHR_u64(pSurface, &cgen_var_1373, 1);
-    stream->write((uint64_t*)&cgen_var_1373, 8);
+    uint64_t cgen_var_1377;
+    stream->handleMapping()->mapHandles_VkSurfaceKHR_u64(pSurface, &cgen_var_1377, 1);
+    stream->write((uint64_t*)&cgen_var_1377, 8);
     stream->setHandleMapping(resources->unwrapMapping());
     AEMU_SCOPED_TRACE("vkCreateIOSSurfaceMVK readParams");
-    uint64_t cgen_var_1374;
-    stream->read((uint64_t*)&cgen_var_1374, 8);
-    stream->handleMapping()->mapHandles_u64_VkSurfaceKHR(&cgen_var_1374, (VkSurfaceKHR*)pSurface, 1);
+    uint64_t cgen_var_1378;
+    stream->read((uint64_t*)&cgen_var_1378, 8);
+    stream->handleMapping()->mapHandles_u64_VkSurfaceKHR(&cgen_var_1378, (VkSurfaceKHR*)pSurface, 1);
     AEMU_SCOPED_TRACE("vkCreateIOSSurfaceMVK returnUnmarshal");
     VkResult vkCreateIOSSurfaceMVK_VkResult_return = (VkResult)0;
     stream->read(&vkCreateIOSSurfaceMVK_VkResult_return, sizeof(VkResult));
@@ -20581,6 +20989,7 @@
     const VkAllocationCallbacks* pAllocator,
     VkSurfaceKHR* pSurface)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkCreateMacOSSurfaceMVK encode");
     mImpl->log("start vkCreateMacOSSurfaceMVK");
     auto stream = mImpl->stream();
@@ -20615,46 +21024,46 @@
     }
     countingStream->rewind();
     {
-        uint64_t cgen_var_1375;
-        countingStream->handleMapping()->mapHandles_VkInstance_u64(&local_instance, &cgen_var_1375, 1);
-        countingStream->write((uint64_t*)&cgen_var_1375, 1 * 8);
+        uint64_t cgen_var_1379;
+        countingStream->handleMapping()->mapHandles_VkInstance_u64(&local_instance, &cgen_var_1379, 1);
+        countingStream->write((uint64_t*)&cgen_var_1379, 1 * 8);
         marshal_VkMacOSSurfaceCreateInfoMVK(countingStream, (VkMacOSSurfaceCreateInfoMVK*)(local_pCreateInfo));
         // WARNING PTR CHECK
-        uint64_t cgen_var_1376 = (uint64_t)(uintptr_t)local_pAllocator;
-        countingStream->putBe64(cgen_var_1376);
+        uint64_t cgen_var_1380 = (uint64_t)(uintptr_t)local_pAllocator;
+        countingStream->putBe64(cgen_var_1380);
         if (local_pAllocator)
         {
             marshal_VkAllocationCallbacks(countingStream, (VkAllocationCallbacks*)(local_pAllocator));
         }
-        uint64_t cgen_var_1377;
-        countingStream->handleMapping()->mapHandles_VkSurfaceKHR_u64(pSurface, &cgen_var_1377, 1);
-        countingStream->write((uint64_t*)&cgen_var_1377, 8);
+        uint64_t cgen_var_1381;
+        countingStream->handleMapping()->mapHandles_VkSurfaceKHR_u64(pSurface, &cgen_var_1381, 1);
+        countingStream->write((uint64_t*)&cgen_var_1381, 8);
     }
     uint32_t packetSize_vkCreateMacOSSurfaceMVK = 4 + 4 + (uint32_t)countingStream->bytesWritten();
     countingStream->rewind();
     uint32_t opcode_vkCreateMacOSSurfaceMVK = OP_vkCreateMacOSSurfaceMVK;
     stream->write(&opcode_vkCreateMacOSSurfaceMVK, sizeof(uint32_t));
     stream->write(&packetSize_vkCreateMacOSSurfaceMVK, sizeof(uint32_t));
-    uint64_t cgen_var_1378;
-    stream->handleMapping()->mapHandles_VkInstance_u64(&local_instance, &cgen_var_1378, 1);
-    stream->write((uint64_t*)&cgen_var_1378, 1 * 8);
+    uint64_t cgen_var_1382;
+    stream->handleMapping()->mapHandles_VkInstance_u64(&local_instance, &cgen_var_1382, 1);
+    stream->write((uint64_t*)&cgen_var_1382, 1 * 8);
     marshal_VkMacOSSurfaceCreateInfoMVK(stream, (VkMacOSSurfaceCreateInfoMVK*)(local_pCreateInfo));
     // WARNING PTR CHECK
-    uint64_t cgen_var_1379 = (uint64_t)(uintptr_t)local_pAllocator;
-    stream->putBe64(cgen_var_1379);
+    uint64_t cgen_var_1383 = (uint64_t)(uintptr_t)local_pAllocator;
+    stream->putBe64(cgen_var_1383);
     if (local_pAllocator)
     {
         marshal_VkAllocationCallbacks(stream, (VkAllocationCallbacks*)(local_pAllocator));
     }
     stream->unsetHandleMapping() /* emit_marshal, is handle, possibly out */;
-    uint64_t cgen_var_1380;
-    stream->handleMapping()->mapHandles_VkSurfaceKHR_u64(pSurface, &cgen_var_1380, 1);
-    stream->write((uint64_t*)&cgen_var_1380, 8);
+    uint64_t cgen_var_1384;
+    stream->handleMapping()->mapHandles_VkSurfaceKHR_u64(pSurface, &cgen_var_1384, 1);
+    stream->write((uint64_t*)&cgen_var_1384, 8);
     stream->setHandleMapping(resources->unwrapMapping());
     AEMU_SCOPED_TRACE("vkCreateMacOSSurfaceMVK readParams");
-    uint64_t cgen_var_1381;
-    stream->read((uint64_t*)&cgen_var_1381, 8);
-    stream->handleMapping()->mapHandles_u64_VkSurfaceKHR(&cgen_var_1381, (VkSurfaceKHR*)pSurface, 1);
+    uint64_t cgen_var_1385;
+    stream->read((uint64_t*)&cgen_var_1385, 8);
+    stream->handleMapping()->mapHandles_u64_VkSurfaceKHR(&cgen_var_1385, (VkSurfaceKHR*)pSurface, 1);
     AEMU_SCOPED_TRACE("vkCreateMacOSSurfaceMVK returnUnmarshal");
     VkResult vkCreateMacOSSurfaceMVK_VkResult_return = (VkResult)0;
     stream->read(&vkCreateMacOSSurfaceMVK_VkResult_return, sizeof(VkResult));
@@ -20675,6 +21084,7 @@
     VkDevice device,
     const VkDebugUtilsObjectNameInfoEXT* pNameInfo)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkSetDebugUtilsObjectNameEXT encode");
     mImpl->log("start vkSetDebugUtilsObjectNameEXT");
     auto stream = mImpl->stream();
@@ -20697,9 +21107,9 @@
     }
     countingStream->rewind();
     {
-        uint64_t cgen_var_1382;
-        countingStream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_1382, 1);
-        countingStream->write((uint64_t*)&cgen_var_1382, 1 * 8);
+        uint64_t cgen_var_1386;
+        countingStream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_1386, 1);
+        countingStream->write((uint64_t*)&cgen_var_1386, 1 * 8);
         marshal_VkDebugUtilsObjectNameInfoEXT(countingStream, (VkDebugUtilsObjectNameInfoEXT*)(local_pNameInfo));
     }
     uint32_t packetSize_vkSetDebugUtilsObjectNameEXT = 4 + 4 + (uint32_t)countingStream->bytesWritten();
@@ -20707,9 +21117,9 @@
     uint32_t opcode_vkSetDebugUtilsObjectNameEXT = OP_vkSetDebugUtilsObjectNameEXT;
     stream->write(&opcode_vkSetDebugUtilsObjectNameEXT, sizeof(uint32_t));
     stream->write(&packetSize_vkSetDebugUtilsObjectNameEXT, sizeof(uint32_t));
-    uint64_t cgen_var_1383;
-    stream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_1383, 1);
-    stream->write((uint64_t*)&cgen_var_1383, 1 * 8);
+    uint64_t cgen_var_1387;
+    stream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_1387, 1);
+    stream->write((uint64_t*)&cgen_var_1387, 1 * 8);
     marshal_VkDebugUtilsObjectNameInfoEXT(stream, (VkDebugUtilsObjectNameInfoEXT*)(local_pNameInfo));
     AEMU_SCOPED_TRACE("vkSetDebugUtilsObjectNameEXT readParams");
     AEMU_SCOPED_TRACE("vkSetDebugUtilsObjectNameEXT returnUnmarshal");
@@ -20726,6 +21136,7 @@
     VkDevice device,
     const VkDebugUtilsObjectTagInfoEXT* pTagInfo)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkSetDebugUtilsObjectTagEXT encode");
     mImpl->log("start vkSetDebugUtilsObjectTagEXT");
     auto stream = mImpl->stream();
@@ -20748,9 +21159,9 @@
     }
     countingStream->rewind();
     {
-        uint64_t cgen_var_1384;
-        countingStream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_1384, 1);
-        countingStream->write((uint64_t*)&cgen_var_1384, 1 * 8);
+        uint64_t cgen_var_1388;
+        countingStream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_1388, 1);
+        countingStream->write((uint64_t*)&cgen_var_1388, 1 * 8);
         marshal_VkDebugUtilsObjectTagInfoEXT(countingStream, (VkDebugUtilsObjectTagInfoEXT*)(local_pTagInfo));
     }
     uint32_t packetSize_vkSetDebugUtilsObjectTagEXT = 4 + 4 + (uint32_t)countingStream->bytesWritten();
@@ -20758,9 +21169,9 @@
     uint32_t opcode_vkSetDebugUtilsObjectTagEXT = OP_vkSetDebugUtilsObjectTagEXT;
     stream->write(&opcode_vkSetDebugUtilsObjectTagEXT, sizeof(uint32_t));
     stream->write(&packetSize_vkSetDebugUtilsObjectTagEXT, sizeof(uint32_t));
-    uint64_t cgen_var_1385;
-    stream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_1385, 1);
-    stream->write((uint64_t*)&cgen_var_1385, 1 * 8);
+    uint64_t cgen_var_1389;
+    stream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_1389, 1);
+    stream->write((uint64_t*)&cgen_var_1389, 1 * 8);
     marshal_VkDebugUtilsObjectTagInfoEXT(stream, (VkDebugUtilsObjectTagInfoEXT*)(local_pTagInfo));
     AEMU_SCOPED_TRACE("vkSetDebugUtilsObjectTagEXT readParams");
     AEMU_SCOPED_TRACE("vkSetDebugUtilsObjectTagEXT returnUnmarshal");
@@ -20777,6 +21188,7 @@
     VkQueue queue,
     const VkDebugUtilsLabelEXT* pLabelInfo)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkQueueBeginDebugUtilsLabelEXT encode");
     mImpl->log("start vkQueueBeginDebugUtilsLabelEXT");
     auto stream = mImpl->stream();
@@ -20799,115 +21211,72 @@
     }
     countingStream->rewind();
     {
-        uint64_t cgen_var_1386;
-        countingStream->handleMapping()->mapHandles_VkQueue_u64(&local_queue, &cgen_var_1386, 1);
-        countingStream->write((uint64_t*)&cgen_var_1386, 1 * 8);
-        marshal_VkDebugUtilsLabelEXT(countingStream, (VkDebugUtilsLabelEXT*)(local_pLabelInfo));
-    }
-    uint32_t packetSize_vkQueueBeginDebugUtilsLabelEXT = 4 + 4 + (uint32_t)countingStream->bytesWritten();
-    countingStream->rewind();
-    uint32_t opcode_vkQueueBeginDebugUtilsLabelEXT = OP_vkQueueBeginDebugUtilsLabelEXT;
-    stream->write(&opcode_vkQueueBeginDebugUtilsLabelEXT, sizeof(uint32_t));
-    stream->write(&packetSize_vkQueueBeginDebugUtilsLabelEXT, sizeof(uint32_t));
-    uint64_t cgen_var_1387;
-    stream->handleMapping()->mapHandles_VkQueue_u64(&local_queue, &cgen_var_1387, 1);
-    stream->write((uint64_t*)&cgen_var_1387, 1 * 8);
-    marshal_VkDebugUtilsLabelEXT(stream, (VkDebugUtilsLabelEXT*)(local_pLabelInfo));
-    AEMU_SCOPED_TRACE("vkQueueBeginDebugUtilsLabelEXT readParams");
-    AEMU_SCOPED_TRACE("vkQueueBeginDebugUtilsLabelEXT returnUnmarshal");
-    mImpl->log("finish vkQueueBeginDebugUtilsLabelEXT");;
-}
-
-void VkEncoder::vkQueueEndDebugUtilsLabelEXT(
-    VkQueue queue)
-{
-    AEMU_SCOPED_TRACE("vkQueueEndDebugUtilsLabelEXT encode");
-    mImpl->log("start vkQueueEndDebugUtilsLabelEXT");
-    auto stream = mImpl->stream();
-    auto countingStream = mImpl->countingStream();
-    auto resources = mImpl->resources();
-    auto pool = mImpl->pool();
-    stream->setHandleMapping(resources->unwrapMapping());
-    VkQueue local_queue;
-    local_queue = queue;
-    countingStream->rewind();
-    {
-        uint64_t cgen_var_1388;
-        countingStream->handleMapping()->mapHandles_VkQueue_u64(&local_queue, &cgen_var_1388, 1);
-        countingStream->write((uint64_t*)&cgen_var_1388, 1 * 8);
-    }
-    uint32_t packetSize_vkQueueEndDebugUtilsLabelEXT = 4 + 4 + (uint32_t)countingStream->bytesWritten();
-    countingStream->rewind();
-    uint32_t opcode_vkQueueEndDebugUtilsLabelEXT = OP_vkQueueEndDebugUtilsLabelEXT;
-    stream->write(&opcode_vkQueueEndDebugUtilsLabelEXT, sizeof(uint32_t));
-    stream->write(&packetSize_vkQueueEndDebugUtilsLabelEXT, sizeof(uint32_t));
-    uint64_t cgen_var_1389;
-    stream->handleMapping()->mapHandles_VkQueue_u64(&local_queue, &cgen_var_1389, 1);
-    stream->write((uint64_t*)&cgen_var_1389, 1 * 8);
-    AEMU_SCOPED_TRACE("vkQueueEndDebugUtilsLabelEXT readParams");
-    AEMU_SCOPED_TRACE("vkQueueEndDebugUtilsLabelEXT returnUnmarshal");
-    mImpl->log("finish vkQueueEndDebugUtilsLabelEXT");;
-}
-
-void VkEncoder::vkQueueInsertDebugUtilsLabelEXT(
-    VkQueue queue,
-    const VkDebugUtilsLabelEXT* pLabelInfo)
-{
-    AEMU_SCOPED_TRACE("vkQueueInsertDebugUtilsLabelEXT encode");
-    mImpl->log("start vkQueueInsertDebugUtilsLabelEXT");
-    auto stream = mImpl->stream();
-    auto countingStream = mImpl->countingStream();
-    auto resources = mImpl->resources();
-    auto pool = mImpl->pool();
-    stream->setHandleMapping(resources->unwrapMapping());
-    VkQueue local_queue;
-    VkDebugUtilsLabelEXT* local_pLabelInfo;
-    local_queue = queue;
-    local_pLabelInfo = nullptr;
-    if (pLabelInfo)
-    {
-        local_pLabelInfo = (VkDebugUtilsLabelEXT*)pool->alloc(sizeof(const VkDebugUtilsLabelEXT));
-        deepcopy_VkDebugUtilsLabelEXT(pool, pLabelInfo, (VkDebugUtilsLabelEXT*)(local_pLabelInfo));
-    }
-    if (local_pLabelInfo)
-    {
-        transform_tohost_VkDebugUtilsLabelEXT(mImpl->resources(), (VkDebugUtilsLabelEXT*)(local_pLabelInfo));
-    }
-    countingStream->rewind();
-    {
         uint64_t cgen_var_1390;
         countingStream->handleMapping()->mapHandles_VkQueue_u64(&local_queue, &cgen_var_1390, 1);
         countingStream->write((uint64_t*)&cgen_var_1390, 1 * 8);
         marshal_VkDebugUtilsLabelEXT(countingStream, (VkDebugUtilsLabelEXT*)(local_pLabelInfo));
     }
-    uint32_t packetSize_vkQueueInsertDebugUtilsLabelEXT = 4 + 4 + (uint32_t)countingStream->bytesWritten();
+    uint32_t packetSize_vkQueueBeginDebugUtilsLabelEXT = 4 + 4 + (uint32_t)countingStream->bytesWritten();
     countingStream->rewind();
-    uint32_t opcode_vkQueueInsertDebugUtilsLabelEXT = OP_vkQueueInsertDebugUtilsLabelEXT;
-    stream->write(&opcode_vkQueueInsertDebugUtilsLabelEXT, sizeof(uint32_t));
-    stream->write(&packetSize_vkQueueInsertDebugUtilsLabelEXT, sizeof(uint32_t));
+    uint32_t opcode_vkQueueBeginDebugUtilsLabelEXT = OP_vkQueueBeginDebugUtilsLabelEXT;
+    stream->write(&opcode_vkQueueBeginDebugUtilsLabelEXT, sizeof(uint32_t));
+    stream->write(&packetSize_vkQueueBeginDebugUtilsLabelEXT, sizeof(uint32_t));
     uint64_t cgen_var_1391;
     stream->handleMapping()->mapHandles_VkQueue_u64(&local_queue, &cgen_var_1391, 1);
     stream->write((uint64_t*)&cgen_var_1391, 1 * 8);
     marshal_VkDebugUtilsLabelEXT(stream, (VkDebugUtilsLabelEXT*)(local_pLabelInfo));
-    AEMU_SCOPED_TRACE("vkQueueInsertDebugUtilsLabelEXT readParams");
-    AEMU_SCOPED_TRACE("vkQueueInsertDebugUtilsLabelEXT returnUnmarshal");
-    mImpl->log("finish vkQueueInsertDebugUtilsLabelEXT");;
+    AEMU_SCOPED_TRACE("vkQueueBeginDebugUtilsLabelEXT readParams");
+    AEMU_SCOPED_TRACE("vkQueueBeginDebugUtilsLabelEXT returnUnmarshal");
+    mImpl->log("finish vkQueueBeginDebugUtilsLabelEXT");;
 }
 
-void VkEncoder::vkCmdBeginDebugUtilsLabelEXT(
-    VkCommandBuffer commandBuffer,
-    const VkDebugUtilsLabelEXT* pLabelInfo)
+void VkEncoder::vkQueueEndDebugUtilsLabelEXT(
+    VkQueue queue)
 {
-    AEMU_SCOPED_TRACE("vkCmdBeginDebugUtilsLabelEXT encode");
-    mImpl->log("start vkCmdBeginDebugUtilsLabelEXT");
+    AutoLock encoderLock(mImpl->lock);
+    AEMU_SCOPED_TRACE("vkQueueEndDebugUtilsLabelEXT encode");
+    mImpl->log("start vkQueueEndDebugUtilsLabelEXT");
     auto stream = mImpl->stream();
     auto countingStream = mImpl->countingStream();
     auto resources = mImpl->resources();
     auto pool = mImpl->pool();
     stream->setHandleMapping(resources->unwrapMapping());
-    VkCommandBuffer local_commandBuffer;
+    VkQueue local_queue;
+    local_queue = queue;
+    countingStream->rewind();
+    {
+        uint64_t cgen_var_1392;
+        countingStream->handleMapping()->mapHandles_VkQueue_u64(&local_queue, &cgen_var_1392, 1);
+        countingStream->write((uint64_t*)&cgen_var_1392, 1 * 8);
+    }
+    uint32_t packetSize_vkQueueEndDebugUtilsLabelEXT = 4 + 4 + (uint32_t)countingStream->bytesWritten();
+    countingStream->rewind();
+    uint32_t opcode_vkQueueEndDebugUtilsLabelEXT = OP_vkQueueEndDebugUtilsLabelEXT;
+    stream->write(&opcode_vkQueueEndDebugUtilsLabelEXT, sizeof(uint32_t));
+    stream->write(&packetSize_vkQueueEndDebugUtilsLabelEXT, sizeof(uint32_t));
+    uint64_t cgen_var_1393;
+    stream->handleMapping()->mapHandles_VkQueue_u64(&local_queue, &cgen_var_1393, 1);
+    stream->write((uint64_t*)&cgen_var_1393, 1 * 8);
+    AEMU_SCOPED_TRACE("vkQueueEndDebugUtilsLabelEXT readParams");
+    AEMU_SCOPED_TRACE("vkQueueEndDebugUtilsLabelEXT returnUnmarshal");
+    mImpl->log("finish vkQueueEndDebugUtilsLabelEXT");;
+}
+
+void VkEncoder::vkQueueInsertDebugUtilsLabelEXT(
+    VkQueue queue,
+    const VkDebugUtilsLabelEXT* pLabelInfo)
+{
+    AutoLock encoderLock(mImpl->lock);
+    AEMU_SCOPED_TRACE("vkQueueInsertDebugUtilsLabelEXT encode");
+    mImpl->log("start vkQueueInsertDebugUtilsLabelEXT");
+    auto stream = mImpl->stream();
+    auto countingStream = mImpl->countingStream();
+    auto resources = mImpl->resources();
+    auto pool = mImpl->pool();
+    stream->setHandleMapping(resources->unwrapMapping());
+    VkQueue local_queue;
     VkDebugUtilsLabelEXT* local_pLabelInfo;
-    local_commandBuffer = commandBuffer;
+    local_queue = queue;
     local_pLabelInfo = nullptr;
     if (pLabelInfo)
     {
@@ -20920,62 +21289,32 @@
     }
     countingStream->rewind();
     {
-        uint64_t cgen_var_1392;
-        countingStream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_1392, 1);
-        countingStream->write((uint64_t*)&cgen_var_1392, 1 * 8);
+        uint64_t cgen_var_1394;
+        countingStream->handleMapping()->mapHandles_VkQueue_u64(&local_queue, &cgen_var_1394, 1);
+        countingStream->write((uint64_t*)&cgen_var_1394, 1 * 8);
         marshal_VkDebugUtilsLabelEXT(countingStream, (VkDebugUtilsLabelEXT*)(local_pLabelInfo));
     }
-    uint32_t packetSize_vkCmdBeginDebugUtilsLabelEXT = 4 + 4 + (uint32_t)countingStream->bytesWritten();
+    uint32_t packetSize_vkQueueInsertDebugUtilsLabelEXT = 4 + 4 + (uint32_t)countingStream->bytesWritten();
     countingStream->rewind();
-    uint32_t opcode_vkCmdBeginDebugUtilsLabelEXT = OP_vkCmdBeginDebugUtilsLabelEXT;
-    stream->write(&opcode_vkCmdBeginDebugUtilsLabelEXT, sizeof(uint32_t));
-    stream->write(&packetSize_vkCmdBeginDebugUtilsLabelEXT, sizeof(uint32_t));
-    uint64_t cgen_var_1393;
-    stream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_1393, 1);
-    stream->write((uint64_t*)&cgen_var_1393, 1 * 8);
-    marshal_VkDebugUtilsLabelEXT(stream, (VkDebugUtilsLabelEXT*)(local_pLabelInfo));
-    AEMU_SCOPED_TRACE("vkCmdBeginDebugUtilsLabelEXT readParams");
-    AEMU_SCOPED_TRACE("vkCmdBeginDebugUtilsLabelEXT returnUnmarshal");
-    mImpl->log("finish vkCmdBeginDebugUtilsLabelEXT");;
-}
-
-void VkEncoder::vkCmdEndDebugUtilsLabelEXT(
-    VkCommandBuffer commandBuffer)
-{
-    AEMU_SCOPED_TRACE("vkCmdEndDebugUtilsLabelEXT encode");
-    mImpl->log("start vkCmdEndDebugUtilsLabelEXT");
-    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_1394;
-        countingStream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_1394, 1);
-        countingStream->write((uint64_t*)&cgen_var_1394, 1 * 8);
-    }
-    uint32_t packetSize_vkCmdEndDebugUtilsLabelEXT = 4 + 4 + (uint32_t)countingStream->bytesWritten();
-    countingStream->rewind();
-    uint32_t opcode_vkCmdEndDebugUtilsLabelEXT = OP_vkCmdEndDebugUtilsLabelEXT;
-    stream->write(&opcode_vkCmdEndDebugUtilsLabelEXT, sizeof(uint32_t));
-    stream->write(&packetSize_vkCmdEndDebugUtilsLabelEXT, sizeof(uint32_t));
+    uint32_t opcode_vkQueueInsertDebugUtilsLabelEXT = OP_vkQueueInsertDebugUtilsLabelEXT;
+    stream->write(&opcode_vkQueueInsertDebugUtilsLabelEXT, sizeof(uint32_t));
+    stream->write(&packetSize_vkQueueInsertDebugUtilsLabelEXT, sizeof(uint32_t));
     uint64_t cgen_var_1395;
-    stream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_1395, 1);
+    stream->handleMapping()->mapHandles_VkQueue_u64(&local_queue, &cgen_var_1395, 1);
     stream->write((uint64_t*)&cgen_var_1395, 1 * 8);
-    AEMU_SCOPED_TRACE("vkCmdEndDebugUtilsLabelEXT readParams");
-    AEMU_SCOPED_TRACE("vkCmdEndDebugUtilsLabelEXT returnUnmarshal");
-    mImpl->log("finish vkCmdEndDebugUtilsLabelEXT");;
+    marshal_VkDebugUtilsLabelEXT(stream, (VkDebugUtilsLabelEXT*)(local_pLabelInfo));
+    AEMU_SCOPED_TRACE("vkQueueInsertDebugUtilsLabelEXT readParams");
+    AEMU_SCOPED_TRACE("vkQueueInsertDebugUtilsLabelEXT returnUnmarshal");
+    mImpl->log("finish vkQueueInsertDebugUtilsLabelEXT");;
 }
 
-void VkEncoder::vkCmdInsertDebugUtilsLabelEXT(
+void VkEncoder::vkCmdBeginDebugUtilsLabelEXT(
     VkCommandBuffer commandBuffer,
     const VkDebugUtilsLabelEXT* pLabelInfo)
 {
-    AEMU_SCOPED_TRACE("vkCmdInsertDebugUtilsLabelEXT encode");
-    mImpl->log("start vkCmdInsertDebugUtilsLabelEXT");
+    AutoLock encoderLock(mImpl->lock);
+    AEMU_SCOPED_TRACE("vkCmdBeginDebugUtilsLabelEXT encode");
+    mImpl->log("start vkCmdBeginDebugUtilsLabelEXT");
     auto stream = mImpl->stream();
     auto countingStream = mImpl->countingStream();
     auto resources = mImpl->resources();
@@ -21001,14 +21340,92 @@
         countingStream->write((uint64_t*)&cgen_var_1396, 1 * 8);
         marshal_VkDebugUtilsLabelEXT(countingStream, (VkDebugUtilsLabelEXT*)(local_pLabelInfo));
     }
+    uint32_t packetSize_vkCmdBeginDebugUtilsLabelEXT = 4 + 4 + (uint32_t)countingStream->bytesWritten();
+    countingStream->rewind();
+    uint32_t opcode_vkCmdBeginDebugUtilsLabelEXT = OP_vkCmdBeginDebugUtilsLabelEXT;
+    stream->write(&opcode_vkCmdBeginDebugUtilsLabelEXT, sizeof(uint32_t));
+    stream->write(&packetSize_vkCmdBeginDebugUtilsLabelEXT, sizeof(uint32_t));
+    uint64_t cgen_var_1397;
+    stream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_1397, 1);
+    stream->write((uint64_t*)&cgen_var_1397, 1 * 8);
+    marshal_VkDebugUtilsLabelEXT(stream, (VkDebugUtilsLabelEXT*)(local_pLabelInfo));
+    AEMU_SCOPED_TRACE("vkCmdBeginDebugUtilsLabelEXT readParams");
+    AEMU_SCOPED_TRACE("vkCmdBeginDebugUtilsLabelEXT returnUnmarshal");
+    mImpl->log("finish vkCmdBeginDebugUtilsLabelEXT");;
+}
+
+void VkEncoder::vkCmdEndDebugUtilsLabelEXT(
+    VkCommandBuffer commandBuffer)
+{
+    AutoLock encoderLock(mImpl->lock);
+    AEMU_SCOPED_TRACE("vkCmdEndDebugUtilsLabelEXT encode");
+    mImpl->log("start vkCmdEndDebugUtilsLabelEXT");
+    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_1398;
+        countingStream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_1398, 1);
+        countingStream->write((uint64_t*)&cgen_var_1398, 1 * 8);
+    }
+    uint32_t packetSize_vkCmdEndDebugUtilsLabelEXT = 4 + 4 + (uint32_t)countingStream->bytesWritten();
+    countingStream->rewind();
+    uint32_t opcode_vkCmdEndDebugUtilsLabelEXT = OP_vkCmdEndDebugUtilsLabelEXT;
+    stream->write(&opcode_vkCmdEndDebugUtilsLabelEXT, sizeof(uint32_t));
+    stream->write(&packetSize_vkCmdEndDebugUtilsLabelEXT, sizeof(uint32_t));
+    uint64_t cgen_var_1399;
+    stream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_1399, 1);
+    stream->write((uint64_t*)&cgen_var_1399, 1 * 8);
+    AEMU_SCOPED_TRACE("vkCmdEndDebugUtilsLabelEXT readParams");
+    AEMU_SCOPED_TRACE("vkCmdEndDebugUtilsLabelEXT returnUnmarshal");
+    mImpl->log("finish vkCmdEndDebugUtilsLabelEXT");;
+}
+
+void VkEncoder::vkCmdInsertDebugUtilsLabelEXT(
+    VkCommandBuffer commandBuffer,
+    const VkDebugUtilsLabelEXT* pLabelInfo)
+{
+    AutoLock encoderLock(mImpl->lock);
+    AEMU_SCOPED_TRACE("vkCmdInsertDebugUtilsLabelEXT encode");
+    mImpl->log("start vkCmdInsertDebugUtilsLabelEXT");
+    auto stream = mImpl->stream();
+    auto countingStream = mImpl->countingStream();
+    auto resources = mImpl->resources();
+    auto pool = mImpl->pool();
+    stream->setHandleMapping(resources->unwrapMapping());
+    VkCommandBuffer local_commandBuffer;
+    VkDebugUtilsLabelEXT* local_pLabelInfo;
+    local_commandBuffer = commandBuffer;
+    local_pLabelInfo = nullptr;
+    if (pLabelInfo)
+    {
+        local_pLabelInfo = (VkDebugUtilsLabelEXT*)pool->alloc(sizeof(const VkDebugUtilsLabelEXT));
+        deepcopy_VkDebugUtilsLabelEXT(pool, pLabelInfo, (VkDebugUtilsLabelEXT*)(local_pLabelInfo));
+    }
+    if (local_pLabelInfo)
+    {
+        transform_tohost_VkDebugUtilsLabelEXT(mImpl->resources(), (VkDebugUtilsLabelEXT*)(local_pLabelInfo));
+    }
+    countingStream->rewind();
+    {
+        uint64_t cgen_var_1400;
+        countingStream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_1400, 1);
+        countingStream->write((uint64_t*)&cgen_var_1400, 1 * 8);
+        marshal_VkDebugUtilsLabelEXT(countingStream, (VkDebugUtilsLabelEXT*)(local_pLabelInfo));
+    }
     uint32_t packetSize_vkCmdInsertDebugUtilsLabelEXT = 4 + 4 + (uint32_t)countingStream->bytesWritten();
     countingStream->rewind();
     uint32_t opcode_vkCmdInsertDebugUtilsLabelEXT = OP_vkCmdInsertDebugUtilsLabelEXT;
     stream->write(&opcode_vkCmdInsertDebugUtilsLabelEXT, sizeof(uint32_t));
     stream->write(&packetSize_vkCmdInsertDebugUtilsLabelEXT, sizeof(uint32_t));
-    uint64_t cgen_var_1397;
-    stream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_1397, 1);
-    stream->write((uint64_t*)&cgen_var_1397, 1 * 8);
+    uint64_t cgen_var_1401;
+    stream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_1401, 1);
+    stream->write((uint64_t*)&cgen_var_1401, 1 * 8);
     marshal_VkDebugUtilsLabelEXT(stream, (VkDebugUtilsLabelEXT*)(local_pLabelInfo));
     AEMU_SCOPED_TRACE("vkCmdInsertDebugUtilsLabelEXT readParams");
     AEMU_SCOPED_TRACE("vkCmdInsertDebugUtilsLabelEXT returnUnmarshal");
@@ -21021,6 +21438,7 @@
     const VkAllocationCallbacks* pAllocator,
     VkDebugUtilsMessengerEXT* pMessenger)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkCreateDebugUtilsMessengerEXT encode");
     mImpl->log("start vkCreateDebugUtilsMessengerEXT");
     auto stream = mImpl->stream();
@@ -21055,47 +21473,47 @@
     }
     countingStream->rewind();
     {
-        uint64_t cgen_var_1398;
-        countingStream->handleMapping()->mapHandles_VkInstance_u64(&local_instance, &cgen_var_1398, 1);
-        countingStream->write((uint64_t*)&cgen_var_1398, 1 * 8);
+        uint64_t cgen_var_1402;
+        countingStream->handleMapping()->mapHandles_VkInstance_u64(&local_instance, &cgen_var_1402, 1);
+        countingStream->write((uint64_t*)&cgen_var_1402, 1 * 8);
         marshal_VkDebugUtilsMessengerCreateInfoEXT(countingStream, (VkDebugUtilsMessengerCreateInfoEXT*)(local_pCreateInfo));
         // WARNING PTR CHECK
-        uint64_t cgen_var_1399 = (uint64_t)(uintptr_t)local_pAllocator;
-        countingStream->putBe64(cgen_var_1399);
+        uint64_t cgen_var_1403 = (uint64_t)(uintptr_t)local_pAllocator;
+        countingStream->putBe64(cgen_var_1403);
         if (local_pAllocator)
         {
             marshal_VkAllocationCallbacks(countingStream, (VkAllocationCallbacks*)(local_pAllocator));
         }
-        uint64_t cgen_var_1400;
-        countingStream->handleMapping()->mapHandles_VkDebugUtilsMessengerEXT_u64(pMessenger, &cgen_var_1400, 1);
-        countingStream->write((uint64_t*)&cgen_var_1400, 8);
+        uint64_t cgen_var_1404;
+        countingStream->handleMapping()->mapHandles_VkDebugUtilsMessengerEXT_u64(pMessenger, &cgen_var_1404, 1);
+        countingStream->write((uint64_t*)&cgen_var_1404, 8);
     }
     uint32_t packetSize_vkCreateDebugUtilsMessengerEXT = 4 + 4 + (uint32_t)countingStream->bytesWritten();
     countingStream->rewind();
     uint32_t opcode_vkCreateDebugUtilsMessengerEXT = OP_vkCreateDebugUtilsMessengerEXT;
     stream->write(&opcode_vkCreateDebugUtilsMessengerEXT, sizeof(uint32_t));
     stream->write(&packetSize_vkCreateDebugUtilsMessengerEXT, sizeof(uint32_t));
-    uint64_t cgen_var_1401;
-    stream->handleMapping()->mapHandles_VkInstance_u64(&local_instance, &cgen_var_1401, 1);
-    stream->write((uint64_t*)&cgen_var_1401, 1 * 8);
+    uint64_t cgen_var_1405;
+    stream->handleMapping()->mapHandles_VkInstance_u64(&local_instance, &cgen_var_1405, 1);
+    stream->write((uint64_t*)&cgen_var_1405, 1 * 8);
     marshal_VkDebugUtilsMessengerCreateInfoEXT(stream, (VkDebugUtilsMessengerCreateInfoEXT*)(local_pCreateInfo));
     // WARNING PTR CHECK
-    uint64_t cgen_var_1402 = (uint64_t)(uintptr_t)local_pAllocator;
-    stream->putBe64(cgen_var_1402);
+    uint64_t cgen_var_1406 = (uint64_t)(uintptr_t)local_pAllocator;
+    stream->putBe64(cgen_var_1406);
     if (local_pAllocator)
     {
         marshal_VkAllocationCallbacks(stream, (VkAllocationCallbacks*)(local_pAllocator));
     }
     stream->unsetHandleMapping() /* emit_marshal, is handle, possibly out */;
-    uint64_t cgen_var_1403;
-    stream->handleMapping()->mapHandles_VkDebugUtilsMessengerEXT_u64(pMessenger, &cgen_var_1403, 1);
-    stream->write((uint64_t*)&cgen_var_1403, 8);
+    uint64_t cgen_var_1407;
+    stream->handleMapping()->mapHandles_VkDebugUtilsMessengerEXT_u64(pMessenger, &cgen_var_1407, 1);
+    stream->write((uint64_t*)&cgen_var_1407, 8);
     stream->setHandleMapping(resources->unwrapMapping());
     AEMU_SCOPED_TRACE("vkCreateDebugUtilsMessengerEXT readParams");
     stream->setHandleMapping(resources->createMapping());
-    uint64_t cgen_var_1404;
-    stream->read((uint64_t*)&cgen_var_1404, 8);
-    stream->handleMapping()->mapHandles_u64_VkDebugUtilsMessengerEXT(&cgen_var_1404, (VkDebugUtilsMessengerEXT*)pMessenger, 1);
+    uint64_t cgen_var_1408;
+    stream->read((uint64_t*)&cgen_var_1408, 8);
+    stream->handleMapping()->mapHandles_u64_VkDebugUtilsMessengerEXT(&cgen_var_1408, (VkDebugUtilsMessengerEXT*)pMessenger, 1);
     stream->unsetHandleMapping();
     AEMU_SCOPED_TRACE("vkCreateDebugUtilsMessengerEXT returnUnmarshal");
     VkResult vkCreateDebugUtilsMessengerEXT_VkResult_return = (VkResult)0;
@@ -21112,6 +21530,7 @@
     VkDebugUtilsMessengerEXT messenger,
     const VkAllocationCallbacks* pAllocator)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkDestroyDebugUtilsMessengerEXT encode");
     mImpl->log("start vkDestroyDebugUtilsMessengerEXT");
     auto stream = mImpl->stream();
@@ -21137,15 +21556,15 @@
     }
     countingStream->rewind();
     {
-        uint64_t cgen_var_1405;
-        countingStream->handleMapping()->mapHandles_VkInstance_u64(&local_instance, &cgen_var_1405, 1);
-        countingStream->write((uint64_t*)&cgen_var_1405, 1 * 8);
-        uint64_t cgen_var_1406;
-        countingStream->handleMapping()->mapHandles_VkDebugUtilsMessengerEXT_u64(&local_messenger, &cgen_var_1406, 1);
-        countingStream->write((uint64_t*)&cgen_var_1406, 1 * 8);
+        uint64_t cgen_var_1409;
+        countingStream->handleMapping()->mapHandles_VkInstance_u64(&local_instance, &cgen_var_1409, 1);
+        countingStream->write((uint64_t*)&cgen_var_1409, 1 * 8);
+        uint64_t cgen_var_1410;
+        countingStream->handleMapping()->mapHandles_VkDebugUtilsMessengerEXT_u64(&local_messenger, &cgen_var_1410, 1);
+        countingStream->write((uint64_t*)&cgen_var_1410, 1 * 8);
         // WARNING PTR CHECK
-        uint64_t cgen_var_1407 = (uint64_t)(uintptr_t)local_pAllocator;
-        countingStream->putBe64(cgen_var_1407);
+        uint64_t cgen_var_1411 = (uint64_t)(uintptr_t)local_pAllocator;
+        countingStream->putBe64(cgen_var_1411);
         if (local_pAllocator)
         {
             marshal_VkAllocationCallbacks(countingStream, (VkAllocationCallbacks*)(local_pAllocator));
@@ -21156,15 +21575,15 @@
     uint32_t opcode_vkDestroyDebugUtilsMessengerEXT = OP_vkDestroyDebugUtilsMessengerEXT;
     stream->write(&opcode_vkDestroyDebugUtilsMessengerEXT, sizeof(uint32_t));
     stream->write(&packetSize_vkDestroyDebugUtilsMessengerEXT, sizeof(uint32_t));
-    uint64_t cgen_var_1408;
-    stream->handleMapping()->mapHandles_VkInstance_u64(&local_instance, &cgen_var_1408, 1);
-    stream->write((uint64_t*)&cgen_var_1408, 1 * 8);
-    uint64_t cgen_var_1409;
-    stream->handleMapping()->mapHandles_VkDebugUtilsMessengerEXT_u64(&local_messenger, &cgen_var_1409, 1);
-    stream->write((uint64_t*)&cgen_var_1409, 1 * 8);
+    uint64_t cgen_var_1412;
+    stream->handleMapping()->mapHandles_VkInstance_u64(&local_instance, &cgen_var_1412, 1);
+    stream->write((uint64_t*)&cgen_var_1412, 1 * 8);
+    uint64_t cgen_var_1413;
+    stream->handleMapping()->mapHandles_VkDebugUtilsMessengerEXT_u64(&local_messenger, &cgen_var_1413, 1);
+    stream->write((uint64_t*)&cgen_var_1413, 1 * 8);
     // WARNING PTR CHECK
-    uint64_t cgen_var_1410 = (uint64_t)(uintptr_t)local_pAllocator;
-    stream->putBe64(cgen_var_1410);
+    uint64_t cgen_var_1414 = (uint64_t)(uintptr_t)local_pAllocator;
+    stream->putBe64(cgen_var_1414);
     if (local_pAllocator)
     {
         marshal_VkAllocationCallbacks(stream, (VkAllocationCallbacks*)(local_pAllocator));
@@ -21181,6 +21600,7 @@
     VkDebugUtilsMessageTypeFlagsEXT messageTypes,
     const VkDebugUtilsMessengerCallbackDataEXT* pCallbackData)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkSubmitDebugUtilsMessageEXT encode");
     mImpl->log("start vkSubmitDebugUtilsMessageEXT");
     auto stream = mImpl->stream();
@@ -21207,9 +21627,9 @@
     }
     countingStream->rewind();
     {
-        uint64_t cgen_var_1411;
-        countingStream->handleMapping()->mapHandles_VkInstance_u64(&local_instance, &cgen_var_1411, 1);
-        countingStream->write((uint64_t*)&cgen_var_1411, 1 * 8);
+        uint64_t cgen_var_1415;
+        countingStream->handleMapping()->mapHandles_VkInstance_u64(&local_instance, &cgen_var_1415, 1);
+        countingStream->write((uint64_t*)&cgen_var_1415, 1 * 8);
         countingStream->write((VkDebugUtilsMessageSeverityFlagBitsEXT*)&local_messageSeverity, sizeof(VkDebugUtilsMessageSeverityFlagBitsEXT));
         countingStream->write((VkDebugUtilsMessageTypeFlagsEXT*)&local_messageTypes, sizeof(VkDebugUtilsMessageTypeFlagsEXT));
         marshal_VkDebugUtilsMessengerCallbackDataEXT(countingStream, (VkDebugUtilsMessengerCallbackDataEXT*)(local_pCallbackData));
@@ -21219,9 +21639,9 @@
     uint32_t opcode_vkSubmitDebugUtilsMessageEXT = OP_vkSubmitDebugUtilsMessageEXT;
     stream->write(&opcode_vkSubmitDebugUtilsMessageEXT, sizeof(uint32_t));
     stream->write(&packetSize_vkSubmitDebugUtilsMessageEXT, sizeof(uint32_t));
-    uint64_t cgen_var_1412;
-    stream->handleMapping()->mapHandles_VkInstance_u64(&local_instance, &cgen_var_1412, 1);
-    stream->write((uint64_t*)&cgen_var_1412, 1 * 8);
+    uint64_t cgen_var_1416;
+    stream->handleMapping()->mapHandles_VkInstance_u64(&local_instance, &cgen_var_1416, 1);
+    stream->write((uint64_t*)&cgen_var_1416, 1 * 8);
     stream->write((VkDebugUtilsMessageSeverityFlagBitsEXT*)&local_messageSeverity, sizeof(VkDebugUtilsMessageSeverityFlagBitsEXT));
     stream->write((VkDebugUtilsMessageTypeFlagsEXT*)&local_messageTypes, sizeof(VkDebugUtilsMessageTypeFlagsEXT));
     marshal_VkDebugUtilsMessengerCallbackDataEXT(stream, (VkDebugUtilsMessengerCallbackDataEXT*)(local_pCallbackData));
@@ -21237,6 +21657,7 @@
     const AHardwareBuffer* buffer,
     VkAndroidHardwareBufferPropertiesANDROID* pProperties)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkGetAndroidHardwareBufferPropertiesANDROID encode");
     mImpl->log("start vkGetAndroidHardwareBufferPropertiesANDROID");
     auto stream = mImpl->stream();
@@ -21254,9 +21675,9 @@
     }
     countingStream->rewind();
     {
-        uint64_t cgen_var_1413;
-        countingStream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_1413, 1);
-        countingStream->write((uint64_t*)&cgen_var_1413, 1 * 8);
+        uint64_t cgen_var_1417;
+        countingStream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_1417, 1);
+        countingStream->write((uint64_t*)&cgen_var_1417, 1 * 8);
         countingStream->write((AHardwareBuffer*)local_buffer, sizeof(AHardwareBuffer));
         marshal_VkAndroidHardwareBufferPropertiesANDROID(countingStream, (VkAndroidHardwareBufferPropertiesANDROID*)(pProperties));
     }
@@ -21265,9 +21686,9 @@
     uint32_t opcode_vkGetAndroidHardwareBufferPropertiesANDROID = OP_vkGetAndroidHardwareBufferPropertiesANDROID;
     stream->write(&opcode_vkGetAndroidHardwareBufferPropertiesANDROID, sizeof(uint32_t));
     stream->write(&packetSize_vkGetAndroidHardwareBufferPropertiesANDROID, sizeof(uint32_t));
-    uint64_t cgen_var_1414;
-    stream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_1414, 1);
-    stream->write((uint64_t*)&cgen_var_1414, 1 * 8);
+    uint64_t cgen_var_1418;
+    stream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_1418, 1);
+    stream->write((uint64_t*)&cgen_var_1418, 1 * 8);
     stream->write((AHardwareBuffer*)local_buffer, sizeof(AHardwareBuffer));
     marshal_VkAndroidHardwareBufferPropertiesANDROID(stream, (VkAndroidHardwareBufferPropertiesANDROID*)(pProperties));
     AEMU_SCOPED_TRACE("vkGetAndroidHardwareBufferPropertiesANDROID readParams");
@@ -21291,6 +21712,7 @@
     const VkMemoryGetAndroidHardwareBufferInfoANDROID* pInfo,
     AHardwareBuffer** pBuffer)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkGetMemoryAndroidHardwareBufferANDROID encode");
     mImpl->log("start vkGetMemoryAndroidHardwareBufferANDROID");
     auto stream = mImpl->stream();
@@ -21313,9 +21735,9 @@
     }
     countingStream->rewind();
     {
-        uint64_t cgen_var_1415;
-        countingStream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_1415, 1);
-        countingStream->write((uint64_t*)&cgen_var_1415, 1 * 8);
+        uint64_t cgen_var_1419;
+        countingStream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_1419, 1);
+        countingStream->write((uint64_t*)&cgen_var_1419, 1 * 8);
         marshal_VkMemoryGetAndroidHardwareBufferInfoANDROID(countingStream, (VkMemoryGetAndroidHardwareBufferInfoANDROID*)(local_pInfo));
         countingStream->write((AHardwareBuffer**)pBuffer, sizeof(AHardwareBuffer*));
     }
@@ -21324,9 +21746,9 @@
     uint32_t opcode_vkGetMemoryAndroidHardwareBufferANDROID = OP_vkGetMemoryAndroidHardwareBufferANDROID;
     stream->write(&opcode_vkGetMemoryAndroidHardwareBufferANDROID, sizeof(uint32_t));
     stream->write(&packetSize_vkGetMemoryAndroidHardwareBufferANDROID, sizeof(uint32_t));
-    uint64_t cgen_var_1416;
-    stream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_1416, 1);
-    stream->write((uint64_t*)&cgen_var_1416, 1 * 8);
+    uint64_t cgen_var_1420;
+    stream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_1420, 1);
+    stream->write((uint64_t*)&cgen_var_1420, 1 * 8);
     marshal_VkMemoryGetAndroidHardwareBufferInfoANDROID(stream, (VkMemoryGetAndroidHardwareBufferInfoANDROID*)(local_pInfo));
     stream->write((AHardwareBuffer**)pBuffer, sizeof(AHardwareBuffer*));
     AEMU_SCOPED_TRACE("vkGetMemoryAndroidHardwareBufferANDROID readParams");
@@ -21357,6 +21779,7 @@
     VkCommandBuffer commandBuffer,
     const VkSampleLocationsInfoEXT* pSampleLocationsInfo)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkCmdSetSampleLocationsEXT encode");
     mImpl->log("start vkCmdSetSampleLocationsEXT");
     auto stream = mImpl->stream();
@@ -21379,9 +21802,9 @@
     }
     countingStream->rewind();
     {
-        uint64_t cgen_var_1417;
-        countingStream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_1417, 1);
-        countingStream->write((uint64_t*)&cgen_var_1417, 1 * 8);
+        uint64_t cgen_var_1421;
+        countingStream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_1421, 1);
+        countingStream->write((uint64_t*)&cgen_var_1421, 1 * 8);
         marshal_VkSampleLocationsInfoEXT(countingStream, (VkSampleLocationsInfoEXT*)(local_pSampleLocationsInfo));
     }
     uint32_t packetSize_vkCmdSetSampleLocationsEXT = 4 + 4 + (uint32_t)countingStream->bytesWritten();
@@ -21389,9 +21812,9 @@
     uint32_t opcode_vkCmdSetSampleLocationsEXT = OP_vkCmdSetSampleLocationsEXT;
     stream->write(&opcode_vkCmdSetSampleLocationsEXT, sizeof(uint32_t));
     stream->write(&packetSize_vkCmdSetSampleLocationsEXT, sizeof(uint32_t));
-    uint64_t cgen_var_1418;
-    stream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_1418, 1);
-    stream->write((uint64_t*)&cgen_var_1418, 1 * 8);
+    uint64_t cgen_var_1422;
+    stream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_1422, 1);
+    stream->write((uint64_t*)&cgen_var_1422, 1 * 8);
     marshal_VkSampleLocationsInfoEXT(stream, (VkSampleLocationsInfoEXT*)(local_pSampleLocationsInfo));
     AEMU_SCOPED_TRACE("vkCmdSetSampleLocationsEXT readParams");
     AEMU_SCOPED_TRACE("vkCmdSetSampleLocationsEXT returnUnmarshal");
@@ -21403,6 +21826,7 @@
     VkSampleCountFlagBits samples,
     VkMultisamplePropertiesEXT* pMultisampleProperties)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkGetPhysicalDeviceMultisamplePropertiesEXT encode");
     mImpl->log("start vkGetPhysicalDeviceMultisamplePropertiesEXT");
     auto stream = mImpl->stream();
@@ -21416,9 +21840,9 @@
     local_samples = samples;
     countingStream->rewind();
     {
-        uint64_t cgen_var_1419;
-        countingStream->handleMapping()->mapHandles_VkPhysicalDevice_u64(&local_physicalDevice, &cgen_var_1419, 1);
-        countingStream->write((uint64_t*)&cgen_var_1419, 1 * 8);
+        uint64_t cgen_var_1423;
+        countingStream->handleMapping()->mapHandles_VkPhysicalDevice_u64(&local_physicalDevice, &cgen_var_1423, 1);
+        countingStream->write((uint64_t*)&cgen_var_1423, 1 * 8);
         countingStream->write((VkSampleCountFlagBits*)&local_samples, sizeof(VkSampleCountFlagBits));
         marshal_VkMultisamplePropertiesEXT(countingStream, (VkMultisamplePropertiesEXT*)(pMultisampleProperties));
     }
@@ -21427,9 +21851,9 @@
     uint32_t opcode_vkGetPhysicalDeviceMultisamplePropertiesEXT = OP_vkGetPhysicalDeviceMultisamplePropertiesEXT;
     stream->write(&opcode_vkGetPhysicalDeviceMultisamplePropertiesEXT, sizeof(uint32_t));
     stream->write(&packetSize_vkGetPhysicalDeviceMultisamplePropertiesEXT, sizeof(uint32_t));
-    uint64_t cgen_var_1420;
-    stream->handleMapping()->mapHandles_VkPhysicalDevice_u64(&local_physicalDevice, &cgen_var_1420, 1);
-    stream->write((uint64_t*)&cgen_var_1420, 1 * 8);
+    uint64_t cgen_var_1424;
+    stream->handleMapping()->mapHandles_VkPhysicalDevice_u64(&local_physicalDevice, &cgen_var_1424, 1);
+    stream->write((uint64_t*)&cgen_var_1424, 1 * 8);
     stream->write((VkSampleCountFlagBits*)&local_samples, sizeof(VkSampleCountFlagBits));
     marshal_VkMultisamplePropertiesEXT(stream, (VkMultisamplePropertiesEXT*)(pMultisampleProperties));
     AEMU_SCOPED_TRACE("vkGetPhysicalDeviceMultisamplePropertiesEXT readParams");
@@ -21460,6 +21884,7 @@
     const VkAllocationCallbacks* pAllocator,
     VkValidationCacheEXT* pValidationCache)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkCreateValidationCacheEXT encode");
     mImpl->log("start vkCreateValidationCacheEXT");
     auto stream = mImpl->stream();
@@ -21494,47 +21919,47 @@
     }
     countingStream->rewind();
     {
-        uint64_t cgen_var_1421;
-        countingStream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_1421, 1);
-        countingStream->write((uint64_t*)&cgen_var_1421, 1 * 8);
+        uint64_t cgen_var_1425;
+        countingStream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_1425, 1);
+        countingStream->write((uint64_t*)&cgen_var_1425, 1 * 8);
         marshal_VkValidationCacheCreateInfoEXT(countingStream, (VkValidationCacheCreateInfoEXT*)(local_pCreateInfo));
         // WARNING PTR CHECK
-        uint64_t cgen_var_1422 = (uint64_t)(uintptr_t)local_pAllocator;
-        countingStream->putBe64(cgen_var_1422);
+        uint64_t cgen_var_1426 = (uint64_t)(uintptr_t)local_pAllocator;
+        countingStream->putBe64(cgen_var_1426);
         if (local_pAllocator)
         {
             marshal_VkAllocationCallbacks(countingStream, (VkAllocationCallbacks*)(local_pAllocator));
         }
-        uint64_t cgen_var_1423;
-        countingStream->handleMapping()->mapHandles_VkValidationCacheEXT_u64(pValidationCache, &cgen_var_1423, 1);
-        countingStream->write((uint64_t*)&cgen_var_1423, 8);
+        uint64_t cgen_var_1427;
+        countingStream->handleMapping()->mapHandles_VkValidationCacheEXT_u64(pValidationCache, &cgen_var_1427, 1);
+        countingStream->write((uint64_t*)&cgen_var_1427, 8);
     }
     uint32_t packetSize_vkCreateValidationCacheEXT = 4 + 4 + (uint32_t)countingStream->bytesWritten();
     countingStream->rewind();
     uint32_t opcode_vkCreateValidationCacheEXT = OP_vkCreateValidationCacheEXT;
     stream->write(&opcode_vkCreateValidationCacheEXT, sizeof(uint32_t));
     stream->write(&packetSize_vkCreateValidationCacheEXT, sizeof(uint32_t));
-    uint64_t cgen_var_1424;
-    stream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_1424, 1);
-    stream->write((uint64_t*)&cgen_var_1424, 1 * 8);
+    uint64_t cgen_var_1428;
+    stream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_1428, 1);
+    stream->write((uint64_t*)&cgen_var_1428, 1 * 8);
     marshal_VkValidationCacheCreateInfoEXT(stream, (VkValidationCacheCreateInfoEXT*)(local_pCreateInfo));
     // WARNING PTR CHECK
-    uint64_t cgen_var_1425 = (uint64_t)(uintptr_t)local_pAllocator;
-    stream->putBe64(cgen_var_1425);
+    uint64_t cgen_var_1429 = (uint64_t)(uintptr_t)local_pAllocator;
+    stream->putBe64(cgen_var_1429);
     if (local_pAllocator)
     {
         marshal_VkAllocationCallbacks(stream, (VkAllocationCallbacks*)(local_pAllocator));
     }
     stream->unsetHandleMapping() /* emit_marshal, is handle, possibly out */;
-    uint64_t cgen_var_1426;
-    stream->handleMapping()->mapHandles_VkValidationCacheEXT_u64(pValidationCache, &cgen_var_1426, 1);
-    stream->write((uint64_t*)&cgen_var_1426, 8);
+    uint64_t cgen_var_1430;
+    stream->handleMapping()->mapHandles_VkValidationCacheEXT_u64(pValidationCache, &cgen_var_1430, 1);
+    stream->write((uint64_t*)&cgen_var_1430, 8);
     stream->setHandleMapping(resources->unwrapMapping());
     AEMU_SCOPED_TRACE("vkCreateValidationCacheEXT readParams");
     stream->setHandleMapping(resources->createMapping());
-    uint64_t cgen_var_1427;
-    stream->read((uint64_t*)&cgen_var_1427, 8);
-    stream->handleMapping()->mapHandles_u64_VkValidationCacheEXT(&cgen_var_1427, (VkValidationCacheEXT*)pValidationCache, 1);
+    uint64_t cgen_var_1431;
+    stream->read((uint64_t*)&cgen_var_1431, 8);
+    stream->handleMapping()->mapHandles_u64_VkValidationCacheEXT(&cgen_var_1431, (VkValidationCacheEXT*)pValidationCache, 1);
     stream->unsetHandleMapping();
     AEMU_SCOPED_TRACE("vkCreateValidationCacheEXT returnUnmarshal");
     VkResult vkCreateValidationCacheEXT_VkResult_return = (VkResult)0;
@@ -21551,6 +21976,7 @@
     VkValidationCacheEXT validationCache,
     const VkAllocationCallbacks* pAllocator)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkDestroyValidationCacheEXT encode");
     mImpl->log("start vkDestroyValidationCacheEXT");
     auto stream = mImpl->stream();
@@ -21576,15 +22002,15 @@
     }
     countingStream->rewind();
     {
-        uint64_t cgen_var_1428;
-        countingStream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_1428, 1);
-        countingStream->write((uint64_t*)&cgen_var_1428, 1 * 8);
-        uint64_t cgen_var_1429;
-        countingStream->handleMapping()->mapHandles_VkValidationCacheEXT_u64(&local_validationCache, &cgen_var_1429, 1);
-        countingStream->write((uint64_t*)&cgen_var_1429, 1 * 8);
+        uint64_t cgen_var_1432;
+        countingStream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_1432, 1);
+        countingStream->write((uint64_t*)&cgen_var_1432, 1 * 8);
+        uint64_t cgen_var_1433;
+        countingStream->handleMapping()->mapHandles_VkValidationCacheEXT_u64(&local_validationCache, &cgen_var_1433, 1);
+        countingStream->write((uint64_t*)&cgen_var_1433, 1 * 8);
         // WARNING PTR CHECK
-        uint64_t cgen_var_1430 = (uint64_t)(uintptr_t)local_pAllocator;
-        countingStream->putBe64(cgen_var_1430);
+        uint64_t cgen_var_1434 = (uint64_t)(uintptr_t)local_pAllocator;
+        countingStream->putBe64(cgen_var_1434);
         if (local_pAllocator)
         {
             marshal_VkAllocationCallbacks(countingStream, (VkAllocationCallbacks*)(local_pAllocator));
@@ -21595,15 +22021,15 @@
     uint32_t opcode_vkDestroyValidationCacheEXT = OP_vkDestroyValidationCacheEXT;
     stream->write(&opcode_vkDestroyValidationCacheEXT, sizeof(uint32_t));
     stream->write(&packetSize_vkDestroyValidationCacheEXT, sizeof(uint32_t));
-    uint64_t cgen_var_1431;
-    stream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_1431, 1);
-    stream->write((uint64_t*)&cgen_var_1431, 1 * 8);
-    uint64_t cgen_var_1432;
-    stream->handleMapping()->mapHandles_VkValidationCacheEXT_u64(&local_validationCache, &cgen_var_1432, 1);
-    stream->write((uint64_t*)&cgen_var_1432, 1 * 8);
+    uint64_t cgen_var_1435;
+    stream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_1435, 1);
+    stream->write((uint64_t*)&cgen_var_1435, 1 * 8);
+    uint64_t cgen_var_1436;
+    stream->handleMapping()->mapHandles_VkValidationCacheEXT_u64(&local_validationCache, &cgen_var_1436, 1);
+    stream->write((uint64_t*)&cgen_var_1436, 1 * 8);
     // WARNING PTR CHECK
-    uint64_t cgen_var_1433 = (uint64_t)(uintptr_t)local_pAllocator;
-    stream->putBe64(cgen_var_1433);
+    uint64_t cgen_var_1437 = (uint64_t)(uintptr_t)local_pAllocator;
+    stream->putBe64(cgen_var_1437);
     if (local_pAllocator)
     {
         marshal_VkAllocationCallbacks(stream, (VkAllocationCallbacks*)(local_pAllocator));
@@ -21620,6 +22046,7 @@
     uint32_t srcCacheCount,
     const VkValidationCacheEXT* pSrcCaches)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkMergeValidationCachesEXT encode");
     mImpl->log("start vkMergeValidationCachesEXT");
     auto stream = mImpl->stream();
@@ -21641,19 +22068,19 @@
     }
     countingStream->rewind();
     {
-        uint64_t cgen_var_1434;
-        countingStream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_1434, 1);
-        countingStream->write((uint64_t*)&cgen_var_1434, 1 * 8);
-        uint64_t cgen_var_1435;
-        countingStream->handleMapping()->mapHandles_VkValidationCacheEXT_u64(&local_dstCache, &cgen_var_1435, 1);
-        countingStream->write((uint64_t*)&cgen_var_1435, 1 * 8);
+        uint64_t cgen_var_1438;
+        countingStream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_1438, 1);
+        countingStream->write((uint64_t*)&cgen_var_1438, 1 * 8);
+        uint64_t cgen_var_1439;
+        countingStream->handleMapping()->mapHandles_VkValidationCacheEXT_u64(&local_dstCache, &cgen_var_1439, 1);
+        countingStream->write((uint64_t*)&cgen_var_1439, 1 * 8);
         countingStream->write((uint32_t*)&local_srcCacheCount, sizeof(uint32_t));
         if (((srcCacheCount)))
         {
-            uint64_t* cgen_var_1436;
-            countingStream->alloc((void**)&cgen_var_1436, ((srcCacheCount)) * 8);
-            countingStream->handleMapping()->mapHandles_VkValidationCacheEXT_u64(local_pSrcCaches, cgen_var_1436, ((srcCacheCount)));
-            countingStream->write((uint64_t*)cgen_var_1436, ((srcCacheCount)) * 8);
+            uint64_t* cgen_var_1440;
+            countingStream->alloc((void**)&cgen_var_1440, ((srcCacheCount)) * 8);
+            countingStream->handleMapping()->mapHandles_VkValidationCacheEXT_u64(local_pSrcCaches, cgen_var_1440, ((srcCacheCount)));
+            countingStream->write((uint64_t*)cgen_var_1440, ((srcCacheCount)) * 8);
         }
     }
     uint32_t packetSize_vkMergeValidationCachesEXT = 4 + 4 + (uint32_t)countingStream->bytesWritten();
@@ -21661,19 +22088,19 @@
     uint32_t opcode_vkMergeValidationCachesEXT = OP_vkMergeValidationCachesEXT;
     stream->write(&opcode_vkMergeValidationCachesEXT, sizeof(uint32_t));
     stream->write(&packetSize_vkMergeValidationCachesEXT, sizeof(uint32_t));
-    uint64_t cgen_var_1437;
-    stream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_1437, 1);
-    stream->write((uint64_t*)&cgen_var_1437, 1 * 8);
-    uint64_t cgen_var_1438;
-    stream->handleMapping()->mapHandles_VkValidationCacheEXT_u64(&local_dstCache, &cgen_var_1438, 1);
-    stream->write((uint64_t*)&cgen_var_1438, 1 * 8);
+    uint64_t cgen_var_1441;
+    stream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_1441, 1);
+    stream->write((uint64_t*)&cgen_var_1441, 1 * 8);
+    uint64_t cgen_var_1442;
+    stream->handleMapping()->mapHandles_VkValidationCacheEXT_u64(&local_dstCache, &cgen_var_1442, 1);
+    stream->write((uint64_t*)&cgen_var_1442, 1 * 8);
     stream->write((uint32_t*)&local_srcCacheCount, sizeof(uint32_t));
     if (((srcCacheCount)))
     {
-        uint64_t* cgen_var_1439;
-        stream->alloc((void**)&cgen_var_1439, ((srcCacheCount)) * 8);
-        stream->handleMapping()->mapHandles_VkValidationCacheEXT_u64(local_pSrcCaches, cgen_var_1439, ((srcCacheCount)));
-        stream->write((uint64_t*)cgen_var_1439, ((srcCacheCount)) * 8);
+        uint64_t* cgen_var_1443;
+        stream->alloc((void**)&cgen_var_1443, ((srcCacheCount)) * 8);
+        stream->handleMapping()->mapHandles_VkValidationCacheEXT_u64(local_pSrcCaches, cgen_var_1443, ((srcCacheCount)));
+        stream->write((uint64_t*)cgen_var_1443, ((srcCacheCount)) * 8);
     }
     AEMU_SCOPED_TRACE("vkMergeValidationCachesEXT readParams");
     AEMU_SCOPED_TRACE("vkMergeValidationCachesEXT returnUnmarshal");
@@ -21692,6 +22119,7 @@
     size_t* pDataSize,
     void* pData)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkGetValidationCacheDataEXT encode");
     mImpl->log("start vkGetValidationCacheDataEXT");
     auto stream = mImpl->stream();
@@ -21705,23 +22133,23 @@
     local_validationCache = validationCache;
     countingStream->rewind();
     {
-        uint64_t cgen_var_1440;
-        countingStream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_1440, 1);
-        countingStream->write((uint64_t*)&cgen_var_1440, 1 * 8);
-        uint64_t cgen_var_1441;
-        countingStream->handleMapping()->mapHandles_VkValidationCacheEXT_u64(&local_validationCache, &cgen_var_1441, 1);
-        countingStream->write((uint64_t*)&cgen_var_1441, 1 * 8);
+        uint64_t cgen_var_1444;
+        countingStream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_1444, 1);
+        countingStream->write((uint64_t*)&cgen_var_1444, 1 * 8);
+        uint64_t cgen_var_1445;
+        countingStream->handleMapping()->mapHandles_VkValidationCacheEXT_u64(&local_validationCache, &cgen_var_1445, 1);
+        countingStream->write((uint64_t*)&cgen_var_1445, 1 * 8);
         // WARNING PTR CHECK
-        uint64_t cgen_var_1442 = (uint64_t)(uintptr_t)pDataSize;
-        countingStream->putBe64(cgen_var_1442);
+        uint64_t cgen_var_1446 = (uint64_t)(uintptr_t)pDataSize;
+        countingStream->putBe64(cgen_var_1446);
         if (pDataSize)
         {
-            uint64_t cgen_var_1443 = (uint64_t)(*pDataSize);
-            countingStream->putBe64(cgen_var_1443);
+            uint64_t cgen_var_1447 = (uint64_t)(*pDataSize);
+            countingStream->putBe64(cgen_var_1447);
         }
         // WARNING PTR CHECK
-        uint64_t cgen_var_1444 = (uint64_t)(uintptr_t)pData;
-        countingStream->putBe64(cgen_var_1444);
+        uint64_t cgen_var_1448 = (uint64_t)(uintptr_t)pData;
+        countingStream->putBe64(cgen_var_1448);
         if (pData)
         {
             countingStream->write((void*)pData, (*(pDataSize)) * sizeof(uint8_t));
@@ -21732,23 +22160,23 @@
     uint32_t opcode_vkGetValidationCacheDataEXT = OP_vkGetValidationCacheDataEXT;
     stream->write(&opcode_vkGetValidationCacheDataEXT, sizeof(uint32_t));
     stream->write(&packetSize_vkGetValidationCacheDataEXT, sizeof(uint32_t));
-    uint64_t cgen_var_1445;
-    stream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_1445, 1);
-    stream->write((uint64_t*)&cgen_var_1445, 1 * 8);
-    uint64_t cgen_var_1446;
-    stream->handleMapping()->mapHandles_VkValidationCacheEXT_u64(&local_validationCache, &cgen_var_1446, 1);
-    stream->write((uint64_t*)&cgen_var_1446, 1 * 8);
+    uint64_t cgen_var_1449;
+    stream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_1449, 1);
+    stream->write((uint64_t*)&cgen_var_1449, 1 * 8);
+    uint64_t cgen_var_1450;
+    stream->handleMapping()->mapHandles_VkValidationCacheEXT_u64(&local_validationCache, &cgen_var_1450, 1);
+    stream->write((uint64_t*)&cgen_var_1450, 1 * 8);
     // WARNING PTR CHECK
-    uint64_t cgen_var_1447 = (uint64_t)(uintptr_t)pDataSize;
-    stream->putBe64(cgen_var_1447);
+    uint64_t cgen_var_1451 = (uint64_t)(uintptr_t)pDataSize;
+    stream->putBe64(cgen_var_1451);
     if (pDataSize)
     {
-        uint64_t cgen_var_1448 = (uint64_t)(*pDataSize);
-        stream->putBe64(cgen_var_1448);
+        uint64_t cgen_var_1452 = (uint64_t)(*pDataSize);
+        stream->putBe64(cgen_var_1452);
     }
     // WARNING PTR CHECK
-    uint64_t cgen_var_1449 = (uint64_t)(uintptr_t)pData;
-    stream->putBe64(cgen_var_1449);
+    uint64_t cgen_var_1453 = (uint64_t)(uintptr_t)pData;
+    stream->putBe64(cgen_var_1453);
     if (pData)
     {
         stream->write((void*)pData, (*(pDataSize)) * sizeof(uint8_t));
@@ -21800,6 +22228,7 @@
     const void* pHostPointer,
     VkMemoryHostPointerPropertiesEXT* pMemoryHostPointerProperties)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkGetMemoryHostPointerPropertiesEXT encode");
     mImpl->log("start vkGetMemoryHostPointerPropertiesEXT");
     auto stream = mImpl->stream();
@@ -21819,13 +22248,13 @@
     }
     countingStream->rewind();
     {
-        uint64_t cgen_var_1453;
-        countingStream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_1453, 1);
-        countingStream->write((uint64_t*)&cgen_var_1453, 1 * 8);
+        uint64_t cgen_var_1457;
+        countingStream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_1457, 1);
+        countingStream->write((uint64_t*)&cgen_var_1457, 1 * 8);
         countingStream->write((VkExternalMemoryHandleTypeFlagBits*)&local_handleType, sizeof(VkExternalMemoryHandleTypeFlagBits));
         // WARNING PTR CHECK
-        uint64_t cgen_var_1454 = (uint64_t)(uintptr_t)local_pHostPointer;
-        countingStream->putBe64(cgen_var_1454);
+        uint64_t cgen_var_1458 = (uint64_t)(uintptr_t)local_pHostPointer;
+        countingStream->putBe64(cgen_var_1458);
         if (local_pHostPointer)
         {
             countingStream->write((void*)local_pHostPointer, sizeof(uint8_t));
@@ -21837,13 +22266,13 @@
     uint32_t opcode_vkGetMemoryHostPointerPropertiesEXT = OP_vkGetMemoryHostPointerPropertiesEXT;
     stream->write(&opcode_vkGetMemoryHostPointerPropertiesEXT, sizeof(uint32_t));
     stream->write(&packetSize_vkGetMemoryHostPointerPropertiesEXT, sizeof(uint32_t));
-    uint64_t cgen_var_1455;
-    stream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_1455, 1);
-    stream->write((uint64_t*)&cgen_var_1455, 1 * 8);
+    uint64_t cgen_var_1459;
+    stream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_1459, 1);
+    stream->write((uint64_t*)&cgen_var_1459, 1 * 8);
     stream->write((VkExternalMemoryHandleTypeFlagBits*)&local_handleType, sizeof(VkExternalMemoryHandleTypeFlagBits));
     // WARNING PTR CHECK
-    uint64_t cgen_var_1456 = (uint64_t)(uintptr_t)local_pHostPointer;
-    stream->putBe64(cgen_var_1456);
+    uint64_t cgen_var_1460 = (uint64_t)(uintptr_t)local_pHostPointer;
+    stream->putBe64(cgen_var_1460);
     if (local_pHostPointer)
     {
         stream->write((void*)local_pHostPointer, sizeof(uint8_t));
@@ -21874,6 +22303,7 @@
     VkDeviceSize dstOffset,
     uint32_t marker)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkCmdWriteBufferMarkerAMD encode");
     mImpl->log("start vkCmdWriteBufferMarkerAMD");
     auto stream = mImpl->stream();
@@ -21893,13 +22323,13 @@
     local_marker = marker;
     countingStream->rewind();
     {
-        uint64_t cgen_var_1457;
-        countingStream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_1457, 1);
-        countingStream->write((uint64_t*)&cgen_var_1457, 1 * 8);
+        uint64_t cgen_var_1461;
+        countingStream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_1461, 1);
+        countingStream->write((uint64_t*)&cgen_var_1461, 1 * 8);
         countingStream->write((VkPipelineStageFlagBits*)&local_pipelineStage, sizeof(VkPipelineStageFlagBits));
-        uint64_t cgen_var_1458;
-        countingStream->handleMapping()->mapHandles_VkBuffer_u64(&local_dstBuffer, &cgen_var_1458, 1);
-        countingStream->write((uint64_t*)&cgen_var_1458, 1 * 8);
+        uint64_t cgen_var_1462;
+        countingStream->handleMapping()->mapHandles_VkBuffer_u64(&local_dstBuffer, &cgen_var_1462, 1);
+        countingStream->write((uint64_t*)&cgen_var_1462, 1 * 8);
         countingStream->write((VkDeviceSize*)&local_dstOffset, sizeof(VkDeviceSize));
         countingStream->write((uint32_t*)&local_marker, sizeof(uint32_t));
     }
@@ -21908,13 +22338,13 @@
     uint32_t opcode_vkCmdWriteBufferMarkerAMD = OP_vkCmdWriteBufferMarkerAMD;
     stream->write(&opcode_vkCmdWriteBufferMarkerAMD, sizeof(uint32_t));
     stream->write(&packetSize_vkCmdWriteBufferMarkerAMD, sizeof(uint32_t));
-    uint64_t cgen_var_1459;
-    stream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_1459, 1);
-    stream->write((uint64_t*)&cgen_var_1459, 1 * 8);
+    uint64_t cgen_var_1463;
+    stream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_1463, 1);
+    stream->write((uint64_t*)&cgen_var_1463, 1 * 8);
     stream->write((VkPipelineStageFlagBits*)&local_pipelineStage, sizeof(VkPipelineStageFlagBits));
-    uint64_t cgen_var_1460;
-    stream->handleMapping()->mapHandles_VkBuffer_u64(&local_dstBuffer, &cgen_var_1460, 1);
-    stream->write((uint64_t*)&cgen_var_1460, 1 * 8);
+    uint64_t cgen_var_1464;
+    stream->handleMapping()->mapHandles_VkBuffer_u64(&local_dstBuffer, &cgen_var_1464, 1);
+    stream->write((uint64_t*)&cgen_var_1464, 1 * 8);
     stream->write((VkDeviceSize*)&local_dstOffset, sizeof(VkDeviceSize));
     stream->write((uint32_t*)&local_marker, sizeof(uint32_t));
     AEMU_SCOPED_TRACE("vkCmdWriteBufferMarkerAMD readParams");
@@ -21934,6 +22364,7 @@
     VkCommandBuffer commandBuffer,
     const void* pCheckpointMarker)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkCmdSetCheckpointNV encode");
     mImpl->log("start vkCmdSetCheckpointNV");
     auto stream = mImpl->stream();
@@ -21951,12 +22382,12 @@
     }
     countingStream->rewind();
     {
-        uint64_t cgen_var_1461;
-        countingStream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_1461, 1);
-        countingStream->write((uint64_t*)&cgen_var_1461, 1 * 8);
+        uint64_t cgen_var_1465;
+        countingStream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_1465, 1);
+        countingStream->write((uint64_t*)&cgen_var_1465, 1 * 8);
         // WARNING PTR CHECK
-        uint64_t cgen_var_1462 = (uint64_t)(uintptr_t)local_pCheckpointMarker;
-        countingStream->putBe64(cgen_var_1462);
+        uint64_t cgen_var_1466 = (uint64_t)(uintptr_t)local_pCheckpointMarker;
+        countingStream->putBe64(cgen_var_1466);
         if (local_pCheckpointMarker)
         {
             countingStream->write((void*)local_pCheckpointMarker, sizeof(uint8_t));
@@ -21967,12 +22398,12 @@
     uint32_t opcode_vkCmdSetCheckpointNV = OP_vkCmdSetCheckpointNV;
     stream->write(&opcode_vkCmdSetCheckpointNV, sizeof(uint32_t));
     stream->write(&packetSize_vkCmdSetCheckpointNV, sizeof(uint32_t));
-    uint64_t cgen_var_1463;
-    stream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_1463, 1);
-    stream->write((uint64_t*)&cgen_var_1463, 1 * 8);
+    uint64_t cgen_var_1467;
+    stream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_1467, 1);
+    stream->write((uint64_t*)&cgen_var_1467, 1 * 8);
     // WARNING PTR CHECK
-    uint64_t cgen_var_1464 = (uint64_t)(uintptr_t)local_pCheckpointMarker;
-    stream->putBe64(cgen_var_1464);
+    uint64_t cgen_var_1468 = (uint64_t)(uintptr_t)local_pCheckpointMarker;
+    stream->putBe64(cgen_var_1468);
     if (local_pCheckpointMarker)
     {
         stream->write((void*)local_pCheckpointMarker, sizeof(uint8_t));
@@ -21987,6 +22418,7 @@
     uint32_t* pCheckpointDataCount,
     VkCheckpointDataNV* pCheckpointData)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkGetQueueCheckpointDataNV encode");
     mImpl->log("start vkGetQueueCheckpointDataNV");
     auto stream = mImpl->stream();
@@ -21998,19 +22430,19 @@
     local_queue = queue;
     countingStream->rewind();
     {
-        uint64_t cgen_var_1465;
-        countingStream->handleMapping()->mapHandles_VkQueue_u64(&local_queue, &cgen_var_1465, 1);
-        countingStream->write((uint64_t*)&cgen_var_1465, 1 * 8);
+        uint64_t cgen_var_1469;
+        countingStream->handleMapping()->mapHandles_VkQueue_u64(&local_queue, &cgen_var_1469, 1);
+        countingStream->write((uint64_t*)&cgen_var_1469, 1 * 8);
         // WARNING PTR CHECK
-        uint64_t cgen_var_1466 = (uint64_t)(uintptr_t)pCheckpointDataCount;
-        countingStream->putBe64(cgen_var_1466);
+        uint64_t cgen_var_1470 = (uint64_t)(uintptr_t)pCheckpointDataCount;
+        countingStream->putBe64(cgen_var_1470);
         if (pCheckpointDataCount)
         {
             countingStream->write((uint32_t*)pCheckpointDataCount, sizeof(uint32_t));
         }
         // WARNING PTR CHECK
-        uint64_t cgen_var_1467 = (uint64_t)(uintptr_t)pCheckpointData;
-        countingStream->putBe64(cgen_var_1467);
+        uint64_t cgen_var_1471 = (uint64_t)(uintptr_t)pCheckpointData;
+        countingStream->putBe64(cgen_var_1471);
         if (pCheckpointData)
         {
             for (uint32_t i = 0; i < (uint32_t)(*(pCheckpointDataCount)); ++i)
@@ -22024,19 +22456,19 @@
     uint32_t opcode_vkGetQueueCheckpointDataNV = OP_vkGetQueueCheckpointDataNV;
     stream->write(&opcode_vkGetQueueCheckpointDataNV, sizeof(uint32_t));
     stream->write(&packetSize_vkGetQueueCheckpointDataNV, sizeof(uint32_t));
-    uint64_t cgen_var_1468;
-    stream->handleMapping()->mapHandles_VkQueue_u64(&local_queue, &cgen_var_1468, 1);
-    stream->write((uint64_t*)&cgen_var_1468, 1 * 8);
+    uint64_t cgen_var_1472;
+    stream->handleMapping()->mapHandles_VkQueue_u64(&local_queue, &cgen_var_1472, 1);
+    stream->write((uint64_t*)&cgen_var_1472, 1 * 8);
     // WARNING PTR CHECK
-    uint64_t cgen_var_1469 = (uint64_t)(uintptr_t)pCheckpointDataCount;
-    stream->putBe64(cgen_var_1469);
+    uint64_t cgen_var_1473 = (uint64_t)(uintptr_t)pCheckpointDataCount;
+    stream->putBe64(cgen_var_1473);
     if (pCheckpointDataCount)
     {
         stream->write((uint32_t*)pCheckpointDataCount, sizeof(uint32_t));
     }
     // WARNING PTR CHECK
-    uint64_t cgen_var_1470 = (uint64_t)(uintptr_t)pCheckpointData;
-    stream->putBe64(cgen_var_1470);
+    uint64_t cgen_var_1474 = (uint64_t)(uintptr_t)pCheckpointData;
+    stream->putBe64(cgen_var_1474);
     if (pCheckpointData)
     {
         for (uint32_t i = 0; i < (uint32_t)(*(pCheckpointDataCount)); ++i)
@@ -22088,9 +22520,12 @@
     VkDeviceMemory memory,
     uint64_t* pAddress)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkMapMemoryIntoAddressSpaceGOOGLE encode");
     mImpl->log("start vkMapMemoryIntoAddressSpaceGOOGLE");
+    encoderLock.unlock();
     mImpl->resources()->on_vkMapMemoryIntoAddressSpaceGOOGLE_pre(this, VK_SUCCESS, device, memory, pAddress);
+    encoderLock.lock();
     auto stream = mImpl->stream();
     auto countingStream = mImpl->countingStream();
     auto resources = mImpl->resources();
@@ -22103,15 +22538,15 @@
     mImpl->resources()->deviceMemoryTransform_tohost((VkDeviceMemory*)&local_memory, 1, (VkDeviceSize*)nullptr, 0, (VkDeviceSize*)nullptr, 0, (uint32_t*)nullptr, 0, (uint32_t*)nullptr, 0);
     countingStream->rewind();
     {
-        uint64_t cgen_var_1473;
-        countingStream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_1473, 1);
-        countingStream->write((uint64_t*)&cgen_var_1473, 1 * 8);
-        uint64_t cgen_var_1474;
-        countingStream->handleMapping()->mapHandles_VkDeviceMemory_u64(&local_memory, &cgen_var_1474, 1);
-        countingStream->write((uint64_t*)&cgen_var_1474, 1 * 8);
+        uint64_t cgen_var_1477;
+        countingStream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_1477, 1);
+        countingStream->write((uint64_t*)&cgen_var_1477, 1 * 8);
+        uint64_t cgen_var_1478;
+        countingStream->handleMapping()->mapHandles_VkDeviceMemory_u64(&local_memory, &cgen_var_1478, 1);
+        countingStream->write((uint64_t*)&cgen_var_1478, 1 * 8);
         // WARNING PTR CHECK
-        uint64_t cgen_var_1475 = (uint64_t)(uintptr_t)pAddress;
-        countingStream->putBe64(cgen_var_1475);
+        uint64_t cgen_var_1479 = (uint64_t)(uintptr_t)pAddress;
+        countingStream->putBe64(cgen_var_1479);
         if (pAddress)
         {
             countingStream->write((uint64_t*)pAddress, sizeof(uint64_t));
@@ -22122,15 +22557,15 @@
     uint32_t opcode_vkMapMemoryIntoAddressSpaceGOOGLE = OP_vkMapMemoryIntoAddressSpaceGOOGLE;
     stream->write(&opcode_vkMapMemoryIntoAddressSpaceGOOGLE, sizeof(uint32_t));
     stream->write(&packetSize_vkMapMemoryIntoAddressSpaceGOOGLE, sizeof(uint32_t));
-    uint64_t cgen_var_1476;
-    stream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_1476, 1);
-    stream->write((uint64_t*)&cgen_var_1476, 1 * 8);
-    uint64_t cgen_var_1477;
-    stream->handleMapping()->mapHandles_VkDeviceMemory_u64(&local_memory, &cgen_var_1477, 1);
-    stream->write((uint64_t*)&cgen_var_1477, 1 * 8);
+    uint64_t cgen_var_1480;
+    stream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_1480, 1);
+    stream->write((uint64_t*)&cgen_var_1480, 1 * 8);
+    uint64_t cgen_var_1481;
+    stream->handleMapping()->mapHandles_VkDeviceMemory_u64(&local_memory, &cgen_var_1481, 1);
+    stream->write((uint64_t*)&cgen_var_1481, 1 * 8);
     // WARNING PTR CHECK
-    uint64_t cgen_var_1478 = (uint64_t)(uintptr_t)pAddress;
-    stream->putBe64(cgen_var_1478);
+    uint64_t cgen_var_1482 = (uint64_t)(uintptr_t)pAddress;
+    stream->putBe64(cgen_var_1482);
     if (pAddress)
     {
         stream->write((uint64_t*)pAddress, sizeof(uint64_t));
@@ -22153,7 +22588,9 @@
     countingStream->clearPool();
     stream->clearPool();
     pool->freeAll();
+    encoderLock.unlock();
     mImpl->resources()->on_vkMapMemoryIntoAddressSpaceGOOGLE(this, vkMapMemoryIntoAddressSpaceGOOGLE_VkResult_return, device, memory, pAddress);
+    encoderLock.lock();
     mImpl->log("finish vkMapMemoryIntoAddressSpaceGOOGLE");;
     return vkMapMemoryIntoAddressSpaceGOOGLE_VkResult_return;
 }
@@ -22165,6 +22602,7 @@
     VkImage image,
     uint32_t colorBuffer)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkRegisterImageColorBufferGOOGLE encode");
     mImpl->log("start vkRegisterImageColorBufferGOOGLE");
     auto stream = mImpl->stream();
@@ -22180,12 +22618,12 @@
     local_colorBuffer = colorBuffer;
     countingStream->rewind();
     {
-        uint64_t cgen_var_1480;
-        countingStream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_1480, 1);
-        countingStream->write((uint64_t*)&cgen_var_1480, 1 * 8);
-        uint64_t cgen_var_1481;
-        countingStream->handleMapping()->mapHandles_VkImage_u64(&local_image, &cgen_var_1481, 1);
-        countingStream->write((uint64_t*)&cgen_var_1481, 1 * 8);
+        uint64_t cgen_var_1484;
+        countingStream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_1484, 1);
+        countingStream->write((uint64_t*)&cgen_var_1484, 1 * 8);
+        uint64_t cgen_var_1485;
+        countingStream->handleMapping()->mapHandles_VkImage_u64(&local_image, &cgen_var_1485, 1);
+        countingStream->write((uint64_t*)&cgen_var_1485, 1 * 8);
         countingStream->write((uint32_t*)&local_colorBuffer, sizeof(uint32_t));
     }
     uint32_t packetSize_vkRegisterImageColorBufferGOOGLE = 4 + 4 + (uint32_t)countingStream->bytesWritten();
@@ -22193,12 +22631,12 @@
     uint32_t opcode_vkRegisterImageColorBufferGOOGLE = OP_vkRegisterImageColorBufferGOOGLE;
     stream->write(&opcode_vkRegisterImageColorBufferGOOGLE, sizeof(uint32_t));
     stream->write(&packetSize_vkRegisterImageColorBufferGOOGLE, sizeof(uint32_t));
-    uint64_t cgen_var_1482;
-    stream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_1482, 1);
-    stream->write((uint64_t*)&cgen_var_1482, 1 * 8);
-    uint64_t cgen_var_1483;
-    stream->handleMapping()->mapHandles_VkImage_u64(&local_image, &cgen_var_1483, 1);
-    stream->write((uint64_t*)&cgen_var_1483, 1 * 8);
+    uint64_t cgen_var_1486;
+    stream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_1486, 1);
+    stream->write((uint64_t*)&cgen_var_1486, 1 * 8);
+    uint64_t cgen_var_1487;
+    stream->handleMapping()->mapHandles_VkImage_u64(&local_image, &cgen_var_1487, 1);
+    stream->write((uint64_t*)&cgen_var_1487, 1 * 8);
     stream->write((uint32_t*)&local_colorBuffer, sizeof(uint32_t));
     AEMU_SCOPED_TRACE("vkRegisterImageColorBufferGOOGLE readParams");
     AEMU_SCOPED_TRACE("vkRegisterImageColorBufferGOOGLE returnUnmarshal");
@@ -22216,6 +22654,7 @@
     VkBuffer buffer,
     uint32_t colorBuffer)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkRegisterBufferColorBufferGOOGLE encode");
     mImpl->log("start vkRegisterBufferColorBufferGOOGLE");
     auto stream = mImpl->stream();
@@ -22231,12 +22670,12 @@
     local_colorBuffer = colorBuffer;
     countingStream->rewind();
     {
-        uint64_t cgen_var_1484;
-        countingStream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_1484, 1);
-        countingStream->write((uint64_t*)&cgen_var_1484, 1 * 8);
-        uint64_t cgen_var_1485;
-        countingStream->handleMapping()->mapHandles_VkBuffer_u64(&local_buffer, &cgen_var_1485, 1);
-        countingStream->write((uint64_t*)&cgen_var_1485, 1 * 8);
+        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_VkBuffer_u64(&local_buffer, &cgen_var_1489, 1);
+        countingStream->write((uint64_t*)&cgen_var_1489, 1 * 8);
         countingStream->write((uint32_t*)&local_colorBuffer, sizeof(uint32_t));
     }
     uint32_t packetSize_vkRegisterBufferColorBufferGOOGLE = 4 + 4 + (uint32_t)countingStream->bytesWritten();
@@ -22244,12 +22683,12 @@
     uint32_t opcode_vkRegisterBufferColorBufferGOOGLE = OP_vkRegisterBufferColorBufferGOOGLE;
     stream->write(&opcode_vkRegisterBufferColorBufferGOOGLE, sizeof(uint32_t));
     stream->write(&packetSize_vkRegisterBufferColorBufferGOOGLE, sizeof(uint32_t));
-    uint64_t cgen_var_1486;
-    stream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_1486, 1);
-    stream->write((uint64_t*)&cgen_var_1486, 1 * 8);
-    uint64_t cgen_var_1487;
-    stream->handleMapping()->mapHandles_VkBuffer_u64(&local_buffer, &cgen_var_1487, 1);
-    stream->write((uint64_t*)&cgen_var_1487, 1 * 8);
+    uint64_t cgen_var_1490;
+    stream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_1490, 1);
+    stream->write((uint64_t*)&cgen_var_1490, 1 * 8);
+    uint64_t cgen_var_1491;
+    stream->handleMapping()->mapHandles_VkBuffer_u64(&local_buffer, &cgen_var_1491, 1);
+    stream->write((uint64_t*)&cgen_var_1491, 1 * 8);
     stream->write((uint32_t*)&local_colorBuffer, sizeof(uint32_t));
     AEMU_SCOPED_TRACE("vkRegisterBufferColorBufferGOOGLE readParams");
     AEMU_SCOPED_TRACE("vkRegisterBufferColorBufferGOOGLE returnUnmarshal");
@@ -22278,6 +22717,7 @@
     const VkDescriptorBufferInfo* pBufferInfos,
     const VkBufferView* pBufferViews)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkUpdateDescriptorSetWithTemplateSizedGOOGLE encode");
     mImpl->log("start vkUpdateDescriptorSetWithTemplateSizedGOOGLE");
     auto stream = mImpl->stream();
@@ -22357,42 +22797,42 @@
     }
     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);
+        uint64_t cgen_var_1492;
+        countingStream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_1492, 1);
+        countingStream->write((uint64_t*)&cgen_var_1492, 1 * 8);
+        uint64_t cgen_var_1493;
+        countingStream->handleMapping()->mapHandles_VkDescriptorSet_u64(&local_descriptorSet, &cgen_var_1493, 1);
+        countingStream->write((uint64_t*)&cgen_var_1493, 1 * 8);
+        uint64_t cgen_var_1494;
+        countingStream->handleMapping()->mapHandles_VkDescriptorUpdateTemplate_u64(&local_descriptorUpdateTemplate, &cgen_var_1494, 1);
+        countingStream->write((uint64_t*)&cgen_var_1494, 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);
+        uint64_t cgen_var_1495 = (uint64_t)(uintptr_t)local_pImageInfoEntryIndices;
+        countingStream->putBe64(cgen_var_1495);
         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);
+        uint64_t cgen_var_1496 = (uint64_t)(uintptr_t)local_pBufferInfoEntryIndices;
+        countingStream->putBe64(cgen_var_1496);
         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);
+        uint64_t cgen_var_1497 = (uint64_t)(uintptr_t)local_pBufferViewEntryIndices;
+        countingStream->putBe64(cgen_var_1497);
         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);
+        uint64_t cgen_var_1498 = (uint64_t)(uintptr_t)local_pImageInfos;
+        countingStream->putBe64(cgen_var_1498);
         if (local_pImageInfos)
         {
             for (uint32_t i = 0; i < (uint32_t)((imageInfoCount)); ++i)
@@ -22401,8 +22841,8 @@
             }
         }
         // WARNING PTR CHECK
-        uint64_t cgen_var_1495 = (uint64_t)(uintptr_t)local_pBufferInfos;
-        countingStream->putBe64(cgen_var_1495);
+        uint64_t cgen_var_1499 = (uint64_t)(uintptr_t)local_pBufferInfos;
+        countingStream->putBe64(cgen_var_1499);
         if (local_pBufferInfos)
         {
             for (uint32_t i = 0; i < (uint32_t)((bufferInfoCount)); ++i)
@@ -22411,16 +22851,16 @@
             }
         }
         // WARNING PTR CHECK
-        uint64_t cgen_var_1496 = (uint64_t)(uintptr_t)local_pBufferViews;
-        countingStream->putBe64(cgen_var_1496);
+        uint64_t cgen_var_1500 = (uint64_t)(uintptr_t)local_pBufferViews;
+        countingStream->putBe64(cgen_var_1500);
         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);
+                uint64_t* cgen_var_1501;
+                countingStream->alloc((void**)&cgen_var_1501, ((bufferViewCount)) * 8);
+                countingStream->handleMapping()->mapHandles_VkBufferView_u64(local_pBufferViews, cgen_var_1501, ((bufferViewCount)));
+                countingStream->write((uint64_t*)cgen_var_1501, ((bufferViewCount)) * 8);
             }
         }
     }
@@ -22429,42 +22869,42 @@
     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);
+    uint64_t cgen_var_1502;
+    stream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_1502, 1);
+    stream->write((uint64_t*)&cgen_var_1502, 1 * 8);
+    uint64_t cgen_var_1503;
+    stream->handleMapping()->mapHandles_VkDescriptorSet_u64(&local_descriptorSet, &cgen_var_1503, 1);
+    stream->write((uint64_t*)&cgen_var_1503, 1 * 8);
+    uint64_t cgen_var_1504;
+    stream->handleMapping()->mapHandles_VkDescriptorUpdateTemplate_u64(&local_descriptorUpdateTemplate, &cgen_var_1504, 1);
+    stream->write((uint64_t*)&cgen_var_1504, 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);
+    uint64_t cgen_var_1505 = (uint64_t)(uintptr_t)local_pImageInfoEntryIndices;
+    stream->putBe64(cgen_var_1505);
     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);
+    uint64_t cgen_var_1506 = (uint64_t)(uintptr_t)local_pBufferInfoEntryIndices;
+    stream->putBe64(cgen_var_1506);
     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);
+    uint64_t cgen_var_1507 = (uint64_t)(uintptr_t)local_pBufferViewEntryIndices;
+    stream->putBe64(cgen_var_1507);
     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);
+    uint64_t cgen_var_1508 = (uint64_t)(uintptr_t)local_pImageInfos;
+    stream->putBe64(cgen_var_1508);
     if (local_pImageInfos)
     {
         for (uint32_t i = 0; i < (uint32_t)((imageInfoCount)); ++i)
@@ -22473,8 +22913,8 @@
         }
     }
     // WARNING PTR CHECK
-    uint64_t cgen_var_1505 = (uint64_t)(uintptr_t)local_pBufferInfos;
-    stream->putBe64(cgen_var_1505);
+    uint64_t cgen_var_1509 = (uint64_t)(uintptr_t)local_pBufferInfos;
+    stream->putBe64(cgen_var_1509);
     if (local_pBufferInfos)
     {
         for (uint32_t i = 0; i < (uint32_t)((bufferInfoCount)); ++i)
@@ -22483,16 +22923,16 @@
         }
     }
     // WARNING PTR CHECK
-    uint64_t cgen_var_1506 = (uint64_t)(uintptr_t)local_pBufferViews;
-    stream->putBe64(cgen_var_1506);
+    uint64_t cgen_var_1510 = (uint64_t)(uintptr_t)local_pBufferViews;
+    stream->putBe64(cgen_var_1510);
     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);
+            uint64_t* cgen_var_1511;
+            stream->alloc((void**)&cgen_var_1511, ((bufferViewCount)) * 8);
+            stream->handleMapping()->mapHandles_VkBufferView_u64(local_pBufferViews, cgen_var_1511, ((bufferViewCount)));
+            stream->write((uint64_t*)cgen_var_1511, ((bufferViewCount)) * 8);
         }
     }
     AEMU_SCOPED_TRACE("vkUpdateDescriptorSetWithTemplateSizedGOOGLE readParams");
@@ -22506,6 +22946,7 @@
     VkCommandBuffer commandBuffer,
     const VkCommandBufferBeginInfo* pBeginInfo)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkBeginCommandBufferAsyncGOOGLE encode");
     mImpl->log("start vkBeginCommandBufferAsyncGOOGLE");
     auto stream = mImpl->stream();
@@ -22528,9 +22969,9 @@
     }
     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);
+        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);
         marshal_VkCommandBufferBeginInfo(countingStream, (VkCommandBufferBeginInfo*)(local_pBeginInfo));
     }
     uint32_t packetSize_vkBeginCommandBufferAsyncGOOGLE = 4 + 4 + (uint32_t)countingStream->bytesWritten();
@@ -22538,9 +22979,9 @@
     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);
+    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);
     marshal_VkCommandBufferBeginInfo(stream, (VkCommandBufferBeginInfo*)(local_pBeginInfo));
     AEMU_SCOPED_TRACE("vkBeginCommandBufferAsyncGOOGLE readParams");
     AEMU_SCOPED_TRACE("vkBeginCommandBufferAsyncGOOGLE returnUnmarshal");
@@ -22550,6 +22991,7 @@
 void VkEncoder::vkEndCommandBufferAsyncGOOGLE(
     VkCommandBuffer commandBuffer)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkEndCommandBufferAsyncGOOGLE encode");
     mImpl->log("start vkEndCommandBufferAsyncGOOGLE");
     auto stream = mImpl->stream();
@@ -22561,18 +23003,18 @@
     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);
+        uint64_t cgen_var_1514;
+        countingStream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_1514, 1);
+        countingStream->write((uint64_t*)&cgen_var_1514, 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);
+    uint64_t cgen_var_1515;
+    stream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_1515, 1);
+    stream->write((uint64_t*)&cgen_var_1515, 1 * 8);
     AEMU_SCOPED_TRACE("vkEndCommandBufferAsyncGOOGLE readParams");
     AEMU_SCOPED_TRACE("vkEndCommandBufferAsyncGOOGLE returnUnmarshal");
     mImpl->log("finish vkEndCommandBufferAsyncGOOGLE");;
@@ -22582,6 +23024,7 @@
     VkCommandBuffer commandBuffer,
     VkCommandBufferResetFlags flags)
 {
+    AutoLock encoderLock(mImpl->lock);
     AEMU_SCOPED_TRACE("vkResetCommandBufferAsyncGOOGLE encode");
     mImpl->log("start vkResetCommandBufferAsyncGOOGLE");
     auto stream = mImpl->stream();
@@ -22595,9 +23038,9 @@
     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);
+        uint64_t cgen_var_1516;
+        countingStream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_1516, 1);
+        countingStream->write((uint64_t*)&cgen_var_1516, 1 * 8);
         countingStream->write((VkCommandBufferResetFlags*)&local_flags, sizeof(VkCommandBufferResetFlags));
     }
     uint32_t packetSize_vkResetCommandBufferAsyncGOOGLE = 4 + 4 + (uint32_t)countingStream->bytesWritten();
@@ -22605,15 +23048,390 @@
     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);
+    uint64_t cgen_var_1517;
+    stream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_1517, 1);
+    stream->write((uint64_t*)&cgen_var_1517, 1 * 8);
     stream->write((VkCommandBufferResetFlags*)&local_flags, sizeof(VkCommandBufferResetFlags));
     AEMU_SCOPED_TRACE("vkResetCommandBufferAsyncGOOGLE readParams");
     AEMU_SCOPED_TRACE("vkResetCommandBufferAsyncGOOGLE returnUnmarshal");
     mImpl->log("finish vkResetCommandBufferAsyncGOOGLE");;
 }
 
+void VkEncoder::vkCommandBufferHostSyncGOOGLE(
+    VkCommandBuffer commandBuffer,
+    uint32_t needHostSync,
+    uint32_t sequenceNumber)
+{
+    AutoLock encoderLock(mImpl->lock);
+    AEMU_SCOPED_TRACE("vkCommandBufferHostSyncGOOGLE encode");
+    mImpl->log("start vkCommandBufferHostSyncGOOGLE");
+    auto stream = mImpl->stream();
+    auto countingStream = mImpl->countingStream();
+    auto resources = mImpl->resources();
+    auto pool = mImpl->pool();
+    stream->setHandleMapping(resources->unwrapMapping());
+    VkCommandBuffer local_commandBuffer;
+    uint32_t local_needHostSync;
+    uint32_t local_sequenceNumber;
+    local_commandBuffer = commandBuffer;
+    local_needHostSync = needHostSync;
+    local_sequenceNumber = sequenceNumber;
+    countingStream->rewind();
+    {
+        uint64_t cgen_var_1518;
+        countingStream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_1518, 1);
+        countingStream->write((uint64_t*)&cgen_var_1518, 1 * 8);
+        countingStream->write((uint32_t*)&local_needHostSync, sizeof(uint32_t));
+        countingStream->write((uint32_t*)&local_sequenceNumber, sizeof(uint32_t));
+    }
+    uint32_t packetSize_vkCommandBufferHostSyncGOOGLE = 4 + 4 + (uint32_t)countingStream->bytesWritten();
+    countingStream->rewind();
+    uint32_t opcode_vkCommandBufferHostSyncGOOGLE = OP_vkCommandBufferHostSyncGOOGLE;
+    stream->write(&opcode_vkCommandBufferHostSyncGOOGLE, sizeof(uint32_t));
+    stream->write(&packetSize_vkCommandBufferHostSyncGOOGLE, sizeof(uint32_t));
+    uint64_t cgen_var_1519;
+    stream->handleMapping()->mapHandles_VkCommandBuffer_u64(&local_commandBuffer, &cgen_var_1519, 1);
+    stream->write((uint64_t*)&cgen_var_1519, 1 * 8);
+    stream->write((uint32_t*)&local_needHostSync, sizeof(uint32_t));
+    stream->write((uint32_t*)&local_sequenceNumber, sizeof(uint32_t));
+    AEMU_SCOPED_TRACE("vkCommandBufferHostSyncGOOGLE readParams");
+    AEMU_SCOPED_TRACE("vkCommandBufferHostSyncGOOGLE returnUnmarshal");
+    mImpl->log("finish vkCommandBufferHostSyncGOOGLE");;
+}
+
+#endif
+#ifdef VK_GOOGLE_create_resources_with_requirements
+VkResult VkEncoder::vkCreateImageWithRequirementsGOOGLE(
+    VkDevice device,
+    const VkImageCreateInfo* pCreateInfo,
+    const VkAllocationCallbacks* pAllocator,
+    VkImage* pImage,
+    VkMemoryRequirements* pMemoryRequirements)
+{
+    AutoLock encoderLock(mImpl->lock);
+    AEMU_SCOPED_TRACE("vkCreateImageWithRequirementsGOOGLE encode");
+    mImpl->log("start vkCreateImageWithRequirementsGOOGLE");
+    auto stream = mImpl->stream();
+    auto countingStream = mImpl->countingStream();
+    auto resources = mImpl->resources();
+    auto pool = mImpl->pool();
+    stream->setHandleMapping(resources->unwrapMapping());
+    VkDevice local_device;
+    VkImageCreateInfo* local_pCreateInfo;
+    VkAllocationCallbacks* local_pAllocator;
+    local_device = device;
+    local_pCreateInfo = nullptr;
+    if (pCreateInfo)
+    {
+        local_pCreateInfo = (VkImageCreateInfo*)pool->alloc(sizeof(const VkImageCreateInfo));
+        deepcopy_VkImageCreateInfo(pool, pCreateInfo, (VkImageCreateInfo*)(local_pCreateInfo));
+    }
+    local_pAllocator = nullptr;
+    if (pAllocator)
+    {
+        local_pAllocator = (VkAllocationCallbacks*)pool->alloc(sizeof(const VkAllocationCallbacks));
+        deepcopy_VkAllocationCallbacks(pool, pAllocator, (VkAllocationCallbacks*)(local_pAllocator));
+    }
+    mImpl->resources()->unwrap_VkNativeBufferANDROID(pCreateInfo, local_pCreateInfo);
+    local_pAllocator = nullptr;
+    if (local_pCreateInfo)
+    {
+        transform_tohost_VkImageCreateInfo(mImpl->resources(), (VkImageCreateInfo*)(local_pCreateInfo));
+    }
+    if (local_pAllocator)
+    {
+        transform_tohost_VkAllocationCallbacks(mImpl->resources(), (VkAllocationCallbacks*)(local_pAllocator));
+    }
+    countingStream->rewind();
+    {
+        uint64_t cgen_var_1520;
+        countingStream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_1520, 1);
+        countingStream->write((uint64_t*)&cgen_var_1520, 1 * 8);
+        marshal_VkImageCreateInfo(countingStream, (VkImageCreateInfo*)(local_pCreateInfo));
+        // WARNING PTR CHECK
+        uint64_t cgen_var_1521 = (uint64_t)(uintptr_t)local_pAllocator;
+        countingStream->putBe64(cgen_var_1521);
+        if (local_pAllocator)
+        {
+            marshal_VkAllocationCallbacks(countingStream, (VkAllocationCallbacks*)(local_pAllocator));
+        }
+        uint64_t cgen_var_1522;
+        countingStream->handleMapping()->mapHandles_VkImage_u64(pImage, &cgen_var_1522, 1);
+        countingStream->write((uint64_t*)&cgen_var_1522, 8);
+        marshal_VkMemoryRequirements(countingStream, (VkMemoryRequirements*)(pMemoryRequirements));
+    }
+    uint32_t packetSize_vkCreateImageWithRequirementsGOOGLE = 4 + 4 + (uint32_t)countingStream->bytesWritten();
+    countingStream->rewind();
+    uint32_t opcode_vkCreateImageWithRequirementsGOOGLE = OP_vkCreateImageWithRequirementsGOOGLE;
+    stream->write(&opcode_vkCreateImageWithRequirementsGOOGLE, sizeof(uint32_t));
+    stream->write(&packetSize_vkCreateImageWithRequirementsGOOGLE, sizeof(uint32_t));
+    uint64_t cgen_var_1523;
+    stream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_1523, 1);
+    stream->write((uint64_t*)&cgen_var_1523, 1 * 8);
+    marshal_VkImageCreateInfo(stream, (VkImageCreateInfo*)(local_pCreateInfo));
+    // WARNING PTR CHECK
+    uint64_t cgen_var_1524 = (uint64_t)(uintptr_t)local_pAllocator;
+    stream->putBe64(cgen_var_1524);
+    if (local_pAllocator)
+    {
+        marshal_VkAllocationCallbacks(stream, (VkAllocationCallbacks*)(local_pAllocator));
+    }
+    stream->unsetHandleMapping() /* emit_marshal, is handle, possibly out */;
+    uint64_t cgen_var_1525;
+    stream->handleMapping()->mapHandles_VkImage_u64(pImage, &cgen_var_1525, 1);
+    stream->write((uint64_t*)&cgen_var_1525, 8);
+    stream->setHandleMapping(resources->unwrapMapping());
+    marshal_VkMemoryRequirements(stream, (VkMemoryRequirements*)(pMemoryRequirements));
+    AEMU_SCOPED_TRACE("vkCreateImageWithRequirementsGOOGLE readParams");
+    stream->setHandleMapping(resources->createMapping());
+    uint64_t cgen_var_1526;
+    stream->read((uint64_t*)&cgen_var_1526, 8);
+    stream->handleMapping()->mapHandles_u64_VkImage(&cgen_var_1526, (VkImage*)pImage, 1);
+    stream->unsetHandleMapping();
+    unmarshal_VkMemoryRequirements(stream, (VkMemoryRequirements*)(pMemoryRequirements));
+    if (pMemoryRequirements)
+    {
+        transform_fromhost_VkMemoryRequirements(mImpl->resources(), (VkMemoryRequirements*)(pMemoryRequirements));
+    }
+    AEMU_SCOPED_TRACE("vkCreateImageWithRequirementsGOOGLE returnUnmarshal");
+    VkResult vkCreateImageWithRequirementsGOOGLE_VkResult_return = (VkResult)0;
+    stream->read(&vkCreateImageWithRequirementsGOOGLE_VkResult_return, sizeof(VkResult));
+    countingStream->clearPool();
+    stream->clearPool();
+    pool->freeAll();
+    mImpl->log("finish vkCreateImageWithRequirementsGOOGLE");;
+    return vkCreateImageWithRequirementsGOOGLE_VkResult_return;
+}
+
+VkResult VkEncoder::vkCreateBufferWithRequirementsGOOGLE(
+    VkDevice device,
+    const VkBufferCreateInfo* pCreateInfo,
+    const VkAllocationCallbacks* pAllocator,
+    VkBuffer* pBuffer,
+    VkMemoryRequirements* pMemoryRequirements)
+{
+    AutoLock encoderLock(mImpl->lock);
+    AEMU_SCOPED_TRACE("vkCreateBufferWithRequirementsGOOGLE encode");
+    mImpl->log("start vkCreateBufferWithRequirementsGOOGLE");
+    auto stream = mImpl->stream();
+    auto countingStream = mImpl->countingStream();
+    auto resources = mImpl->resources();
+    auto pool = mImpl->pool();
+    stream->setHandleMapping(resources->unwrapMapping());
+    VkDevice local_device;
+    VkBufferCreateInfo* local_pCreateInfo;
+    VkAllocationCallbacks* local_pAllocator;
+    local_device = device;
+    local_pCreateInfo = nullptr;
+    if (pCreateInfo)
+    {
+        local_pCreateInfo = (VkBufferCreateInfo*)pool->alloc(sizeof(const VkBufferCreateInfo));
+        deepcopy_VkBufferCreateInfo(pool, pCreateInfo, (VkBufferCreateInfo*)(local_pCreateInfo));
+    }
+    local_pAllocator = nullptr;
+    if (pAllocator)
+    {
+        local_pAllocator = (VkAllocationCallbacks*)pool->alloc(sizeof(const VkAllocationCallbacks));
+        deepcopy_VkAllocationCallbacks(pool, pAllocator, (VkAllocationCallbacks*)(local_pAllocator));
+    }
+    local_pAllocator = nullptr;
+    if (local_pCreateInfo)
+    {
+        transform_tohost_VkBufferCreateInfo(mImpl->resources(), (VkBufferCreateInfo*)(local_pCreateInfo));
+    }
+    if (local_pAllocator)
+    {
+        transform_tohost_VkAllocationCallbacks(mImpl->resources(), (VkAllocationCallbacks*)(local_pAllocator));
+    }
+    countingStream->rewind();
+    {
+        uint64_t cgen_var_1527;
+        countingStream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_1527, 1);
+        countingStream->write((uint64_t*)&cgen_var_1527, 1 * 8);
+        marshal_VkBufferCreateInfo(countingStream, (VkBufferCreateInfo*)(local_pCreateInfo));
+        // WARNING PTR CHECK
+        uint64_t cgen_var_1528 = (uint64_t)(uintptr_t)local_pAllocator;
+        countingStream->putBe64(cgen_var_1528);
+        if (local_pAllocator)
+        {
+            marshal_VkAllocationCallbacks(countingStream, (VkAllocationCallbacks*)(local_pAllocator));
+        }
+        uint64_t cgen_var_1529;
+        countingStream->handleMapping()->mapHandles_VkBuffer_u64(pBuffer, &cgen_var_1529, 1);
+        countingStream->write((uint64_t*)&cgen_var_1529, 8);
+        marshal_VkMemoryRequirements(countingStream, (VkMemoryRequirements*)(pMemoryRequirements));
+    }
+    uint32_t packetSize_vkCreateBufferWithRequirementsGOOGLE = 4 + 4 + (uint32_t)countingStream->bytesWritten();
+    countingStream->rewind();
+    uint32_t opcode_vkCreateBufferWithRequirementsGOOGLE = OP_vkCreateBufferWithRequirementsGOOGLE;
+    stream->write(&opcode_vkCreateBufferWithRequirementsGOOGLE, sizeof(uint32_t));
+    stream->write(&packetSize_vkCreateBufferWithRequirementsGOOGLE, sizeof(uint32_t));
+    uint64_t cgen_var_1530;
+    stream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_1530, 1);
+    stream->write((uint64_t*)&cgen_var_1530, 1 * 8);
+    marshal_VkBufferCreateInfo(stream, (VkBufferCreateInfo*)(local_pCreateInfo));
+    // WARNING PTR CHECK
+    uint64_t cgen_var_1531 = (uint64_t)(uintptr_t)local_pAllocator;
+    stream->putBe64(cgen_var_1531);
+    if (local_pAllocator)
+    {
+        marshal_VkAllocationCallbacks(stream, (VkAllocationCallbacks*)(local_pAllocator));
+    }
+    stream->unsetHandleMapping() /* emit_marshal, is handle, possibly out */;
+    uint64_t cgen_var_1532;
+    stream->handleMapping()->mapHandles_VkBuffer_u64(pBuffer, &cgen_var_1532, 1);
+    stream->write((uint64_t*)&cgen_var_1532, 8);
+    stream->setHandleMapping(resources->unwrapMapping());
+    marshal_VkMemoryRequirements(stream, (VkMemoryRequirements*)(pMemoryRequirements));
+    AEMU_SCOPED_TRACE("vkCreateBufferWithRequirementsGOOGLE readParams");
+    stream->setHandleMapping(resources->createMapping());
+    uint64_t cgen_var_1533;
+    stream->read((uint64_t*)&cgen_var_1533, 8);
+    stream->handleMapping()->mapHandles_u64_VkBuffer(&cgen_var_1533, (VkBuffer*)pBuffer, 1);
+    stream->unsetHandleMapping();
+    unmarshal_VkMemoryRequirements(stream, (VkMemoryRequirements*)(pMemoryRequirements));
+    if (pMemoryRequirements)
+    {
+        transform_fromhost_VkMemoryRequirements(mImpl->resources(), (VkMemoryRequirements*)(pMemoryRequirements));
+    }
+    AEMU_SCOPED_TRACE("vkCreateBufferWithRequirementsGOOGLE returnUnmarshal");
+    VkResult vkCreateBufferWithRequirementsGOOGLE_VkResult_return = (VkResult)0;
+    stream->read(&vkCreateBufferWithRequirementsGOOGLE_VkResult_return, sizeof(VkResult));
+    countingStream->clearPool();
+    stream->clearPool();
+    pool->freeAll();
+    mImpl->log("finish vkCreateBufferWithRequirementsGOOGLE");;
+    return vkCreateBufferWithRequirementsGOOGLE_VkResult_return;
+}
+
+#endif
+#ifdef VK_GOOGLE_address_space_info
+VkResult VkEncoder::vkGetMemoryHostAddressInfoGOOGLE(
+    VkDevice device,
+    VkDeviceMemory memory,
+    uint64_t* pAddress,
+    uint64_t* pSize,
+    uint64_t* pHostmemId)
+{
+    AutoLock encoderLock(mImpl->lock);
+    AEMU_SCOPED_TRACE("vkGetMemoryHostAddressInfoGOOGLE encode");
+    mImpl->log("start vkGetMemoryHostAddressInfoGOOGLE");
+    auto stream = mImpl->stream();
+    auto countingStream = mImpl->countingStream();
+    auto resources = mImpl->resources();
+    auto pool = mImpl->pool();
+    stream->setHandleMapping(resources->unwrapMapping());
+    VkDevice local_device;
+    VkDeviceMemory local_memory;
+    local_device = device;
+    local_memory = memory;
+    mImpl->resources()->deviceMemoryTransform_tohost((VkDeviceMemory*)&local_memory, 1, (VkDeviceSize*)nullptr, 0, (VkDeviceSize*)nullptr, 0, (uint32_t*)nullptr, 0, (uint32_t*)nullptr, 0);
+    countingStream->rewind();
+    {
+        uint64_t cgen_var_1534;
+        countingStream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_1534, 1);
+        countingStream->write((uint64_t*)&cgen_var_1534, 1 * 8);
+        uint64_t cgen_var_1535;
+        countingStream->handleMapping()->mapHandles_VkDeviceMemory_u64(&local_memory, &cgen_var_1535, 1);
+        countingStream->write((uint64_t*)&cgen_var_1535, 1 * 8);
+        // WARNING PTR CHECK
+        uint64_t cgen_var_1536 = (uint64_t)(uintptr_t)pAddress;
+        countingStream->putBe64(cgen_var_1536);
+        if (pAddress)
+        {
+            countingStream->write((uint64_t*)pAddress, sizeof(uint64_t));
+        }
+        // WARNING PTR CHECK
+        uint64_t cgen_var_1537 = (uint64_t)(uintptr_t)pSize;
+        countingStream->putBe64(cgen_var_1537);
+        if (pSize)
+        {
+            countingStream->write((uint64_t*)pSize, sizeof(uint64_t));
+        }
+        // WARNING PTR CHECK
+        uint64_t cgen_var_1538 = (uint64_t)(uintptr_t)pHostmemId;
+        countingStream->putBe64(cgen_var_1538);
+        if (pHostmemId)
+        {
+            countingStream->write((uint64_t*)pHostmemId, sizeof(uint64_t));
+        }
+    }
+    uint32_t packetSize_vkGetMemoryHostAddressInfoGOOGLE = 4 + 4 + (uint32_t)countingStream->bytesWritten();
+    countingStream->rewind();
+    uint32_t opcode_vkGetMemoryHostAddressInfoGOOGLE = OP_vkGetMemoryHostAddressInfoGOOGLE;
+    stream->write(&opcode_vkGetMemoryHostAddressInfoGOOGLE, sizeof(uint32_t));
+    stream->write(&packetSize_vkGetMemoryHostAddressInfoGOOGLE, sizeof(uint32_t));
+    uint64_t cgen_var_1539;
+    stream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_1539, 1);
+    stream->write((uint64_t*)&cgen_var_1539, 1 * 8);
+    uint64_t cgen_var_1540;
+    stream->handleMapping()->mapHandles_VkDeviceMemory_u64(&local_memory, &cgen_var_1540, 1);
+    stream->write((uint64_t*)&cgen_var_1540, 1 * 8);
+    // WARNING PTR CHECK
+    uint64_t cgen_var_1541 = (uint64_t)(uintptr_t)pAddress;
+    stream->putBe64(cgen_var_1541);
+    if (pAddress)
+    {
+        stream->write((uint64_t*)pAddress, sizeof(uint64_t));
+    }
+    // WARNING PTR CHECK
+    uint64_t cgen_var_1542 = (uint64_t)(uintptr_t)pSize;
+    stream->putBe64(cgen_var_1542);
+    if (pSize)
+    {
+        stream->write((uint64_t*)pSize, sizeof(uint64_t));
+    }
+    // WARNING PTR CHECK
+    uint64_t cgen_var_1543 = (uint64_t)(uintptr_t)pHostmemId;
+    stream->putBe64(cgen_var_1543);
+    if (pHostmemId)
+    {
+        stream->write((uint64_t*)pHostmemId, sizeof(uint64_t));
+    }
+    AEMU_SCOPED_TRACE("vkGetMemoryHostAddressInfoGOOGLE readParams");
+    // WARNING PTR CHECK
+    uint64_t* check_pAddress;
+    check_pAddress = (uint64_t*)(uintptr_t)stream->getBe64();
+    if (pAddress)
+    {
+        if (!(check_pAddress))
+        {
+            fprintf(stderr, "fatal: pAddress inconsistent between guest and host\n");
+        }
+        stream->read((uint64_t*)pAddress, sizeof(uint64_t));
+    }
+    // WARNING PTR CHECK
+    uint64_t* check_pSize;
+    check_pSize = (uint64_t*)(uintptr_t)stream->getBe64();
+    if (pSize)
+    {
+        if (!(check_pSize))
+        {
+            fprintf(stderr, "fatal: pSize inconsistent between guest and host\n");
+        }
+        stream->read((uint64_t*)pSize, sizeof(uint64_t));
+    }
+    // WARNING PTR CHECK
+    uint64_t* check_pHostmemId;
+    check_pHostmemId = (uint64_t*)(uintptr_t)stream->getBe64();
+    if (pHostmemId)
+    {
+        if (!(check_pHostmemId))
+        {
+            fprintf(stderr, "fatal: pHostmemId inconsistent between guest and host\n");
+        }
+        stream->read((uint64_t*)pHostmemId, sizeof(uint64_t));
+    }
+    AEMU_SCOPED_TRACE("vkGetMemoryHostAddressInfoGOOGLE returnUnmarshal");
+    VkResult vkGetMemoryHostAddressInfoGOOGLE_VkResult_return = (VkResult)0;
+    stream->read(&vkGetMemoryHostAddressInfoGOOGLE_VkResult_return, sizeof(VkResult));
+    countingStream->clearPool();
+    stream->clearPool();
+    pool->freeAll();
+    mImpl->log("finish vkGetMemoryHostAddressInfoGOOGLE");;
+    return vkGetMemoryHostAddressInfoGOOGLE_VkResult_return;
+}
+
 #endif
 
 } // namespace goldfish_vk
diff --git a/system/vulkan_enc/VkEncoder.h b/system/vulkan_enc/VkEncoder.h
index 8328b32..4cab74f 100644
--- a/system/vulkan_enc/VkEncoder.h
+++ b/system/vulkan_enc/VkEncoder.h
@@ -28,6 +28,7 @@
 
 
 #include "goldfish_vk_private_defs.h"
+#include <functional>
 #include <memory>
 class IOStream;
 
@@ -39,6 +40,12 @@
 public:
     VkEncoder(IOStream* stream);
     ~VkEncoder();
+
+    void flush();
+
+    using CleanupCallback = std::function<void()>;
+    void registerCleanupCallback(void* handle, CleanupCallback cb);
+    void unregisterCleanupCallback(void* handle);
 #ifdef VK_VERSION_1_0
     VkResult vkCreateInstance(
     const VkInstanceCreateInfo* pCreateInfo,
@@ -1781,6 +1788,32 @@
     void vkResetCommandBufferAsyncGOOGLE(
     VkCommandBuffer commandBuffer,
         VkCommandBufferResetFlags flags);
+    void vkCommandBufferHostSyncGOOGLE(
+    VkCommandBuffer commandBuffer,
+        uint32_t needHostSync,
+        uint32_t sequenceNumber);
+#endif
+#ifdef VK_GOOGLE_create_resources_with_requirements
+    VkResult vkCreateImageWithRequirementsGOOGLE(
+    VkDevice device,
+        const VkImageCreateInfo* pCreateInfo,
+        const VkAllocationCallbacks* pAllocator,
+        VkImage* pImage,
+        VkMemoryRequirements* pMemoryRequirements);
+    VkResult vkCreateBufferWithRequirementsGOOGLE(
+    VkDevice device,
+        const VkBufferCreateInfo* pCreateInfo,
+        const VkAllocationCallbacks* pAllocator,
+        VkBuffer* pBuffer,
+        VkMemoryRequirements* pMemoryRequirements);
+#endif
+#ifdef VK_GOOGLE_address_space_info
+    VkResult vkGetMemoryHostAddressInfoGOOGLE(
+    VkDevice device,
+        VkDeviceMemory memory,
+        uint64_t* pAddress,
+        uint64_t* pSize,
+        uint64_t* pHostmemId);
 #endif
 
 private:
diff --git a/system/vulkan_enc/VulkanHandles.h b/system/vulkan_enc/VulkanHandles.h
index 481e601..b8bd801 100644
--- a/system/vulkan_enc/VulkanHandles.h
+++ b/system/vulkan_enc/VulkanHandles.h
@@ -19,11 +19,11 @@
 #define GOLDFISH_VK_LIST_TRIVIAL_DISPATCHABLE_HANDLE_TYPES(f) \
     f(VkPhysicalDevice) \
     f(VkQueue) \
-    f(VkCommandBuffer) \
 
 #define GOLDFISH_VK_LIST_DISPATCHABLE_HANDLE_TYPES(f) \
     f(VkInstance) \
     f(VkDevice) \
+    f(VkCommandBuffer) \
     GOLDFISH_VK_LIST_TRIVIAL_DISPATCHABLE_HANDLE_TYPES(f)
 
 #define GOLDFISH_VK_LIST_TRIVIAL_NON_DISPATCHABLE_HANDLE_TYPES(f) \
@@ -40,7 +40,6 @@
     f(VkRenderPass) \
     f(VkFramebuffer) \
     f(VkCommandPool) \
-    f(VkFence) \
     f(VkEvent) \
     f(VkQueryPool) \
     f(VkSamplerYcbcrConversion) \
@@ -60,6 +59,7 @@
     f(VkImage) \
     f(VkSemaphore) \
     f(VkDescriptorUpdateTemplate) \
+    f(VkFence) \
     GOLDFISH_VK_LIST_TRIVIAL_NON_DISPATCHABLE_HANDLE_TYPES(f) \
 
 #define GOLDFISH_VK_LIST_HANDLE_TYPES(f) \
diff --git a/system/vulkan_enc/VulkanStreamGuest.cpp b/system/vulkan_enc/VulkanStreamGuest.cpp
index bbb5437..43f3706 100644
--- a/system/vulkan_enc/VulkanStreamGuest.cpp
+++ b/system/vulkan_enc/VulkanStreamGuest.cpp
@@ -14,6 +14,7 @@
 #include "VulkanStreamGuest.h"
 
 #include "IOStream.h"
+#include "ResourceTracker.h"
 
 #include "android/base/Pool.h"
 #include "android/base/Tracing.h"
@@ -27,7 +28,10 @@
 
 class VulkanStreamGuest::Impl : public android::base::Stream {
 public:
-    Impl(IOStream* stream) : mStream(stream) { unsetHandleMapping(); }
+    Impl(IOStream* stream) : mStream(stream) {
+        unsetHandleMapping();
+        mFeatureBits = ResourceTracker::get()->getStreamFeatures();
+    }
 
     ~Impl() { }
 
@@ -49,8 +53,7 @@
     }
 
     ssize_t read(void *buffer, size_t size) override {
-        commitWrite();
-        if (!mStream->readFully(buffer, size)) {
+        if (!mStream->readback(buffer, size)) {
             ALOGE("FATAL: Could not read back %zu bytes", size);
             abort();
         }
@@ -77,6 +80,10 @@
         commitWrite();
     }
 
+    uint32_t getFeatureBits() const {
+        return mFeatureBits;
+    }
+
 private:
     size_t oustandingWriteBuffer() const {
         return mWritePos;
@@ -107,6 +114,7 @@
     IOStream* mStream = nullptr;
     DefaultHandleMapping mDefaultHandleMapping;
     VulkanHandleMapping* mCurrentHandleMapping;
+    uint32_t mFeatureBits = 0;
 };
 
 VulkanStreamGuest::VulkanStreamGuest(IOStream *stream) :
@@ -178,6 +186,10 @@
     mImpl->flush();
 }
 
+uint32_t VulkanStreamGuest::getFeatureBits() const {
+    return mImpl->getFeatureBits();
+}
+
 VulkanCountingStream::VulkanCountingStream() : VulkanStreamGuest(nullptr) { }
 VulkanCountingStream::~VulkanCountingStream() = default;
 
diff --git a/system/vulkan_enc/VulkanStreamGuest.h b/system/vulkan_enc/VulkanStreamGuest.h
index 8fa4aaa..d70b9fb 100644
--- a/system/vulkan_enc/VulkanStreamGuest.h
+++ b/system/vulkan_enc/VulkanStreamGuest.h
@@ -16,6 +16,8 @@
 #include "android/base/files/Stream.h"
 #include "android/base/files/StreamSerializing.h"
 
+#include "goldfish_vk_private_defs.h"
+
 #include "VulkanHandleMapping.h"
 
 #include <memory>
@@ -51,6 +53,9 @@
     VulkanHandleMapping* handleMapping() const;
 
     void flush();
+
+    uint32_t getFeatureBits() const;
+
 private:
     class Impl;
     std::unique_ptr<Impl> mImpl;
diff --git a/system/vulkan_enc/goldfish_vk_deepcopy_guest.cpp b/system/vulkan_enc/goldfish_vk_deepcopy_guest.cpp
index 5b004c0..917ca59 100644
--- a/system/vulkan_enc/goldfish_vk_deepcopy_guest.cpp
+++ b/system/vulkan_enc/goldfish_vk_deepcopy_guest.cpp
@@ -6384,6 +6384,10 @@
 #endif
 #ifdef VK_GOOGLE_async_command_buffers
 #endif
+#ifdef VK_GOOGLE_create_resources_with_requirements
+#endif
+#ifdef VK_GOOGLE_address_space_info
+#endif
 void deepcopy_extension_struct(
     Pool* pool,
     const void* structExtension,
diff --git a/system/vulkan_enc/goldfish_vk_deepcopy_guest.h b/system/vulkan_enc/goldfish_vk_deepcopy_guest.h
index b367ee0..b1ffaa6 100644
--- a/system/vulkan_enc/goldfish_vk_deepcopy_guest.h
+++ b/system/vulkan_enc/goldfish_vk_deepcopy_guest.h
@@ -2026,5 +2026,9 @@
 #endif
 #ifdef VK_GOOGLE_async_command_buffers
 #endif
+#ifdef VK_GOOGLE_create_resources_with_requirements
+#endif
+#ifdef VK_GOOGLE_address_space_info
+#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 c42f6e8..08bba9f 100644
--- a/system/vulkan_enc/goldfish_vk_extension_structs_guest.cpp
+++ b/system/vulkan_enc/goldfish_vk_extension_structs_guest.cpp
@@ -282,6 +282,10 @@
 #endif
 #ifdef VK_GOOGLE_async_command_buffers
 #endif
+#ifdef VK_GOOGLE_create_resources_with_requirements
+#endif
+#ifdef VK_GOOGLE_address_space_info
+#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 1d671f8..4fa4e3c 100644
--- a/system/vulkan_enc/goldfish_vk_extension_structs_guest.h
+++ b/system/vulkan_enc/goldfish_vk_extension_structs_guest.h
@@ -299,5 +299,9 @@
 #endif
 #ifdef VK_GOOGLE_async_command_buffers
 #endif
+#ifdef VK_GOOGLE_create_resources_with_requirements
+#endif
+#ifdef VK_GOOGLE_address_space_info
+#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 7d16b31..56adc3a 100644
--- a/system/vulkan_enc/goldfish_vk_handlemap_guest.cpp
+++ b/system/vulkan_enc/goldfish_vk_handlemap_guest.cpp
@@ -4748,6 +4748,10 @@
 #endif
 #ifdef VK_GOOGLE_async_command_buffers
 #endif
+#ifdef VK_GOOGLE_create_resources_with_requirements
+#endif
+#ifdef VK_GOOGLE_address_space_info
+#endif
 void handlemap_extension_struct(
     VulkanHandleMapping* handlemap,
     void* structExtension_out)
diff --git a/system/vulkan_enc/goldfish_vk_handlemap_guest.h b/system/vulkan_enc/goldfish_vk_handlemap_guest.h
index e973064..8785741 100644
--- a/system/vulkan_enc/goldfish_vk_handlemap_guest.h
+++ b/system/vulkan_enc/goldfish_vk_handlemap_guest.h
@@ -1679,5 +1679,9 @@
 #endif
 #ifdef VK_GOOGLE_async_command_buffers
 #endif
+#ifdef VK_GOOGLE_create_resources_with_requirements
+#endif
+#ifdef VK_GOOGLE_address_space_info
+#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 a67e9ad..24b8112 100644
--- a/system/vulkan_enc/goldfish_vk_marshaling_guest.cpp
+++ b/system/vulkan_enc/goldfish_vk_marshaling_guest.cpp
@@ -52,9 +52,35 @@
         vkStream->write((const void*)forMarshaling->pNext, sizeof(VkStructureType));
         marshal_extension_struct(vkStream, forMarshaling->pNext);
     }
-    vkStream->putString(forMarshaling->pApplicationName);
+    if (vkStream->getFeatureBits() & VULKAN_STREAM_FEATURE_NULL_OPTIONAL_STRINGS_BIT)
+    {
+        // WARNING PTR CHECK
+        uint64_t cgen_var_0 = (uint64_t)(uintptr_t)forMarshaling->pApplicationName;
+        vkStream->putBe64(cgen_var_0);
+        if (forMarshaling->pApplicationName)
+        {
+            vkStream->putString(forMarshaling->pApplicationName);
+        }
+    }
+    else
+    {
+        vkStream->putString(forMarshaling->pApplicationName);
+    }
     vkStream->write((uint32_t*)&forMarshaling->applicationVersion, sizeof(uint32_t));
-    vkStream->putString(forMarshaling->pEngineName);
+    if (vkStream->getFeatureBits() & VULKAN_STREAM_FEATURE_NULL_OPTIONAL_STRINGS_BIT)
+    {
+        // WARNING PTR CHECK
+        uint64_t cgen_var_1 = (uint64_t)(uintptr_t)forMarshaling->pEngineName;
+        vkStream->putBe64(cgen_var_1);
+        if (forMarshaling->pEngineName)
+        {
+            vkStream->putString(forMarshaling->pEngineName);
+        }
+    }
+    else
+    {
+        vkStream->putString(forMarshaling->pEngineName);
+    }
     vkStream->write((uint32_t*)&forMarshaling->engineVersion, sizeof(uint32_t));
     vkStream->write((uint32_t*)&forMarshaling->apiVersion, sizeof(uint32_t));
 }
@@ -72,9 +98,43 @@
         vkStream->read((void*)(&pNext_placeholder), sizeof(VkStructureType));
         unmarshal_extension_struct(vkStream, (void*)(forUnmarshaling->pNext));
     }
-    vkStream->loadStringInPlace((char**)&forUnmarshaling->pApplicationName);
+    if (vkStream->getFeatureBits() & VULKAN_STREAM_FEATURE_NULL_OPTIONAL_STRINGS_BIT)
+    {
+        // WARNING PTR CHECK
+        const char* check_pApplicationName;
+        check_pApplicationName = (const char*)(uintptr_t)vkStream->getBe64();
+        if (forUnmarshaling->pApplicationName)
+        {
+            if (!(check_pApplicationName))
+            {
+                fprintf(stderr, "fatal: forUnmarshaling->pApplicationName inconsistent between guest and host\n");
+            }
+            vkStream->loadStringInPlace((char**)&forUnmarshaling->pApplicationName);
+        }
+    }
+    else
+    {
+        vkStream->loadStringInPlace((char**)&forUnmarshaling->pApplicationName);
+    }
     vkStream->read((uint32_t*)&forUnmarshaling->applicationVersion, sizeof(uint32_t));
-    vkStream->loadStringInPlace((char**)&forUnmarshaling->pEngineName);
+    if (vkStream->getFeatureBits() & VULKAN_STREAM_FEATURE_NULL_OPTIONAL_STRINGS_BIT)
+    {
+        // WARNING PTR CHECK
+        const char* check_pEngineName;
+        check_pEngineName = (const char*)(uintptr_t)vkStream->getBe64();
+        if (forUnmarshaling->pEngineName)
+        {
+            if (!(check_pEngineName))
+            {
+                fprintf(stderr, "fatal: forUnmarshaling->pEngineName inconsistent between guest and host\n");
+            }
+            vkStream->loadStringInPlace((char**)&forUnmarshaling->pEngineName);
+        }
+    }
+    else
+    {
+        vkStream->loadStringInPlace((char**)&forUnmarshaling->pEngineName);
+    }
     vkStream->read((uint32_t*)&forUnmarshaling->engineVersion, sizeof(uint32_t));
     vkStream->read((uint32_t*)&forUnmarshaling->apiVersion, sizeof(uint32_t));
 }
@@ -93,8 +153,8 @@
     }
     vkStream->write((VkInstanceCreateFlags*)&forMarshaling->flags, sizeof(VkInstanceCreateFlags));
     // WARNING PTR CHECK
-    uint64_t cgen_var_0 = (uint64_t)(uintptr_t)forMarshaling->pApplicationInfo;
-    vkStream->putBe64(cgen_var_0);
+    uint64_t cgen_var_4 = (uint64_t)(uintptr_t)forMarshaling->pApplicationInfo;
+    vkStream->putBe64(cgen_var_4);
     if (forMarshaling->pApplicationInfo)
     {
         marshal_VkApplicationInfo(vkStream, (const VkApplicationInfo*)(forMarshaling->pApplicationInfo));
@@ -141,22 +201,22 @@
     const VkAllocationCallbacks* forMarshaling)
 {
     // WARNING PTR CHECK
-    uint64_t cgen_var_2 = (uint64_t)(uintptr_t)forMarshaling->pUserData;
-    vkStream->putBe64(cgen_var_2);
+    uint64_t cgen_var_6 = (uint64_t)(uintptr_t)forMarshaling->pUserData;
+    vkStream->putBe64(cgen_var_6);
     if (forMarshaling->pUserData)
     {
         vkStream->write((void*)forMarshaling->pUserData, sizeof(uint8_t));
     }
-    uint64_t cgen_var_3 = (uint64_t)forMarshaling->pfnAllocation;
-    vkStream->putBe64(cgen_var_3);
-    uint64_t cgen_var_4 = (uint64_t)forMarshaling->pfnReallocation;
-    vkStream->putBe64(cgen_var_4);
-    uint64_t cgen_var_5 = (uint64_t)forMarshaling->pfnFree;
-    vkStream->putBe64(cgen_var_5);
-    uint64_t cgen_var_6 = (uint64_t)forMarshaling->pfnInternalAllocation;
-    vkStream->putBe64(cgen_var_6);
-    uint64_t cgen_var_7 = (uint64_t)forMarshaling->pfnInternalFree;
+    uint64_t cgen_var_7 = (uint64_t)forMarshaling->pfnAllocation;
     vkStream->putBe64(cgen_var_7);
+    uint64_t cgen_var_8 = (uint64_t)forMarshaling->pfnReallocation;
+    vkStream->putBe64(cgen_var_8);
+    uint64_t cgen_var_9 = (uint64_t)forMarshaling->pfnFree;
+    vkStream->putBe64(cgen_var_9);
+    uint64_t cgen_var_10 = (uint64_t)forMarshaling->pfnInternalAllocation;
+    vkStream->putBe64(cgen_var_10);
+    uint64_t cgen_var_11 = (uint64_t)forMarshaling->pfnInternalFree;
+    vkStream->putBe64(cgen_var_11);
 }
 
 void unmarshal_VkAllocationCallbacks(
@@ -431,8 +491,8 @@
     vkStream->write((uint32_t*)forMarshaling->maxViewportDimensions, 2 * sizeof(uint32_t));
     vkStream->write((float*)forMarshaling->viewportBoundsRange, 2 * sizeof(float));
     vkStream->write((uint32_t*)&forMarshaling->viewportSubPixelBits, sizeof(uint32_t));
-    uint64_t cgen_var_14 = (uint64_t)forMarshaling->minMemoryMapAlignment;
-    vkStream->putBe64(cgen_var_14);
+    uint64_t cgen_var_18 = (uint64_t)forMarshaling->minMemoryMapAlignment;
+    vkStream->putBe64(cgen_var_18);
     vkStream->write((VkDeviceSize*)&forMarshaling->minTexelBufferOffsetAlignment, sizeof(VkDeviceSize));
     vkStream->write((VkDeviceSize*)&forMarshaling->minUniformBufferOffsetAlignment, sizeof(VkDeviceSize));
     vkStream->write((VkDeviceSize*)&forMarshaling->minStorageBufferOffsetAlignment, sizeof(VkDeviceSize));
@@ -782,8 +842,8 @@
     vkStream->write((uint32_t*)&forMarshaling->enabledExtensionCount, sizeof(uint32_t));
     saveStringArray(vkStream, forMarshaling->ppEnabledExtensionNames, forMarshaling->enabledExtensionCount);
     // WARNING PTR CHECK
-    uint64_t cgen_var_16 = (uint64_t)(uintptr_t)forMarshaling->pEnabledFeatures;
-    vkStream->putBe64(cgen_var_16);
+    uint64_t cgen_var_20 = (uint64_t)(uintptr_t)forMarshaling->pEnabledFeatures;
+    vkStream->putBe64(cgen_var_20);
     if (forMarshaling->pEnabledFeatures)
     {
         marshal_VkPhysicalDeviceFeatures(vkStream, (const VkPhysicalDeviceFeatures*)(forMarshaling->pEnabledFeatures));
@@ -877,27 +937,27 @@
     vkStream->write((uint32_t*)&forMarshaling->waitSemaphoreCount, sizeof(uint32_t));
     if (forMarshaling->waitSemaphoreCount)
     {
-        uint64_t* cgen_var_18;
-        vkStream->alloc((void**)&cgen_var_18, forMarshaling->waitSemaphoreCount * 8);
-        vkStream->handleMapping()->mapHandles_VkSemaphore_u64(forMarshaling->pWaitSemaphores, cgen_var_18, forMarshaling->waitSemaphoreCount);
-        vkStream->write((uint64_t*)cgen_var_18, forMarshaling->waitSemaphoreCount * 8);
+        uint64_t* cgen_var_22;
+        vkStream->alloc((void**)&cgen_var_22, forMarshaling->waitSemaphoreCount * 8);
+        vkStream->handleMapping()->mapHandles_VkSemaphore_u64(forMarshaling->pWaitSemaphores, cgen_var_22, forMarshaling->waitSemaphoreCount);
+        vkStream->write((uint64_t*)cgen_var_22, forMarshaling->waitSemaphoreCount * 8);
     }
     vkStream->write((const VkPipelineStageFlags*)forMarshaling->pWaitDstStageMask, forMarshaling->waitSemaphoreCount * sizeof(const VkPipelineStageFlags));
     vkStream->write((uint32_t*)&forMarshaling->commandBufferCount, sizeof(uint32_t));
     if (forMarshaling->commandBufferCount)
     {
-        uint64_t* cgen_var_19;
-        vkStream->alloc((void**)&cgen_var_19, forMarshaling->commandBufferCount * 8);
-        vkStream->handleMapping()->mapHandles_VkCommandBuffer_u64(forMarshaling->pCommandBuffers, cgen_var_19, forMarshaling->commandBufferCount);
-        vkStream->write((uint64_t*)cgen_var_19, forMarshaling->commandBufferCount * 8);
+        uint64_t* cgen_var_23;
+        vkStream->alloc((void**)&cgen_var_23, forMarshaling->commandBufferCount * 8);
+        vkStream->handleMapping()->mapHandles_VkCommandBuffer_u64(forMarshaling->pCommandBuffers, cgen_var_23, forMarshaling->commandBufferCount);
+        vkStream->write((uint64_t*)cgen_var_23, forMarshaling->commandBufferCount * 8);
     }
     vkStream->write((uint32_t*)&forMarshaling->signalSemaphoreCount, sizeof(uint32_t));
     if (forMarshaling->signalSemaphoreCount)
     {
-        uint64_t* cgen_var_20;
-        vkStream->alloc((void**)&cgen_var_20, forMarshaling->signalSemaphoreCount * 8);
-        vkStream->handleMapping()->mapHandles_VkSemaphore_u64(forMarshaling->pSignalSemaphores, cgen_var_20, forMarshaling->signalSemaphoreCount);
-        vkStream->write((uint64_t*)cgen_var_20, forMarshaling->signalSemaphoreCount * 8);
+        uint64_t* cgen_var_24;
+        vkStream->alloc((void**)&cgen_var_24, forMarshaling->signalSemaphoreCount * 8);
+        vkStream->handleMapping()->mapHandles_VkSemaphore_u64(forMarshaling->pSignalSemaphores, cgen_var_24, forMarshaling->signalSemaphoreCount);
+        vkStream->write((uint64_t*)cgen_var_24, forMarshaling->signalSemaphoreCount * 8);
     }
 }
 
@@ -917,27 +977,27 @@
     vkStream->read((uint32_t*)&forUnmarshaling->waitSemaphoreCount, sizeof(uint32_t));
     if (forUnmarshaling->waitSemaphoreCount)
     {
-        uint64_t* cgen_var_21;
-        vkStream->alloc((void**)&cgen_var_21, forUnmarshaling->waitSemaphoreCount * 8);
-        vkStream->read((uint64_t*)cgen_var_21, forUnmarshaling->waitSemaphoreCount * 8);
-        vkStream->handleMapping()->mapHandles_u64_VkSemaphore(cgen_var_21, (VkSemaphore*)forUnmarshaling->pWaitSemaphores, forUnmarshaling->waitSemaphoreCount);
+        uint64_t* cgen_var_25;
+        vkStream->alloc((void**)&cgen_var_25, forUnmarshaling->waitSemaphoreCount * 8);
+        vkStream->read((uint64_t*)cgen_var_25, forUnmarshaling->waitSemaphoreCount * 8);
+        vkStream->handleMapping()->mapHandles_u64_VkSemaphore(cgen_var_25, (VkSemaphore*)forUnmarshaling->pWaitSemaphores, forUnmarshaling->waitSemaphoreCount);
     }
     vkStream->read((VkPipelineStageFlags*)forUnmarshaling->pWaitDstStageMask, forUnmarshaling->waitSemaphoreCount * sizeof(const VkPipelineStageFlags));
     vkStream->read((uint32_t*)&forUnmarshaling->commandBufferCount, sizeof(uint32_t));
     if (forUnmarshaling->commandBufferCount)
     {
-        uint64_t* cgen_var_22;
-        vkStream->alloc((void**)&cgen_var_22, forUnmarshaling->commandBufferCount * 8);
-        vkStream->read((uint64_t*)cgen_var_22, forUnmarshaling->commandBufferCount * 8);
-        vkStream->handleMapping()->mapHandles_u64_VkCommandBuffer(cgen_var_22, (VkCommandBuffer*)forUnmarshaling->pCommandBuffers, forUnmarshaling->commandBufferCount);
+        uint64_t* cgen_var_26;
+        vkStream->alloc((void**)&cgen_var_26, forUnmarshaling->commandBufferCount * 8);
+        vkStream->read((uint64_t*)cgen_var_26, forUnmarshaling->commandBufferCount * 8);
+        vkStream->handleMapping()->mapHandles_u64_VkCommandBuffer(cgen_var_26, (VkCommandBuffer*)forUnmarshaling->pCommandBuffers, forUnmarshaling->commandBufferCount);
     }
     vkStream->read((uint32_t*)&forUnmarshaling->signalSemaphoreCount, sizeof(uint32_t));
     if (forUnmarshaling->signalSemaphoreCount)
     {
-        uint64_t* cgen_var_23;
-        vkStream->alloc((void**)&cgen_var_23, forUnmarshaling->signalSemaphoreCount * 8);
-        vkStream->read((uint64_t*)cgen_var_23, forUnmarshaling->signalSemaphoreCount * 8);
-        vkStream->handleMapping()->mapHandles_u64_VkSemaphore(cgen_var_23, (VkSemaphore*)forUnmarshaling->pSignalSemaphores, forUnmarshaling->signalSemaphoreCount);
+        uint64_t* cgen_var_27;
+        vkStream->alloc((void**)&cgen_var_27, forUnmarshaling->signalSemaphoreCount * 8);
+        vkStream->read((uint64_t*)cgen_var_27, forUnmarshaling->signalSemaphoreCount * 8);
+        vkStream->handleMapping()->mapHandles_u64_VkSemaphore(cgen_var_27, (VkSemaphore*)forUnmarshaling->pSignalSemaphores, forUnmarshaling->signalSemaphoreCount);
     }
 }
 
@@ -986,9 +1046,9 @@
         vkStream->write((const void*)forMarshaling->pNext, sizeof(VkStructureType));
         marshal_extension_struct(vkStream, forMarshaling->pNext);
     }
-    uint64_t cgen_var_24;
-    vkStream->handleMapping()->mapHandles_VkDeviceMemory_u64(&forMarshaling->memory, &cgen_var_24, 1);
-    vkStream->write((uint64_t*)&cgen_var_24, 1 * 8);
+    uint64_t cgen_var_28;
+    vkStream->handleMapping()->mapHandles_VkDeviceMemory_u64(&forMarshaling->memory, &cgen_var_28, 1);
+    vkStream->write((uint64_t*)&cgen_var_28, 1 * 8);
     vkStream->write((VkDeviceSize*)&forMarshaling->offset, sizeof(VkDeviceSize));
     vkStream->write((VkDeviceSize*)&forMarshaling->size, sizeof(VkDeviceSize));
 }
@@ -1006,9 +1066,9 @@
         vkStream->read((void*)(&pNext_placeholder), sizeof(VkStructureType));
         unmarshal_extension_struct(vkStream, (void*)(forUnmarshaling->pNext));
     }
-    uint64_t cgen_var_25;
-    vkStream->read((uint64_t*)&cgen_var_25, 1 * 8);
-    vkStream->handleMapping()->mapHandles_u64_VkDeviceMemory(&cgen_var_25, (VkDeviceMemory*)&forUnmarshaling->memory, 1);
+    uint64_t cgen_var_29;
+    vkStream->read((uint64_t*)&cgen_var_29, 1 * 8);
+    vkStream->handleMapping()->mapHandles_u64_VkDeviceMemory(&cgen_var_29, (VkDeviceMemory*)&forUnmarshaling->memory, 1);
     vkStream->read((VkDeviceSize*)&forUnmarshaling->offset, sizeof(VkDeviceSize));
     vkStream->read((VkDeviceSize*)&forUnmarshaling->size, sizeof(VkDeviceSize));
 }
@@ -1077,9 +1137,9 @@
 {
     vkStream->write((VkDeviceSize*)&forMarshaling->resourceOffset, sizeof(VkDeviceSize));
     vkStream->write((VkDeviceSize*)&forMarshaling->size, sizeof(VkDeviceSize));
-    uint64_t cgen_var_26;
-    vkStream->handleMapping()->mapHandles_VkDeviceMemory_u64(&forMarshaling->memory, &cgen_var_26, 1);
-    vkStream->write((uint64_t*)&cgen_var_26, 1 * 8);
+    uint64_t cgen_var_30;
+    vkStream->handleMapping()->mapHandles_VkDeviceMemory_u64(&forMarshaling->memory, &cgen_var_30, 1);
+    vkStream->write((uint64_t*)&cgen_var_30, 1 * 8);
     vkStream->write((VkDeviceSize*)&forMarshaling->memoryOffset, sizeof(VkDeviceSize));
     vkStream->write((VkSparseMemoryBindFlags*)&forMarshaling->flags, sizeof(VkSparseMemoryBindFlags));
 }
@@ -1090,9 +1150,9 @@
 {
     vkStream->read((VkDeviceSize*)&forUnmarshaling->resourceOffset, sizeof(VkDeviceSize));
     vkStream->read((VkDeviceSize*)&forUnmarshaling->size, sizeof(VkDeviceSize));
-    uint64_t cgen_var_27;
-    vkStream->read((uint64_t*)&cgen_var_27, 1 * 8);
-    vkStream->handleMapping()->mapHandles_u64_VkDeviceMemory(&cgen_var_27, (VkDeviceMemory*)&forUnmarshaling->memory, 1);
+    uint64_t cgen_var_31;
+    vkStream->read((uint64_t*)&cgen_var_31, 1 * 8);
+    vkStream->handleMapping()->mapHandles_u64_VkDeviceMemory(&cgen_var_31, (VkDeviceMemory*)&forUnmarshaling->memory, 1);
     vkStream->read((VkDeviceSize*)&forUnmarshaling->memoryOffset, sizeof(VkDeviceSize));
     vkStream->read((VkSparseMemoryBindFlags*)&forUnmarshaling->flags, sizeof(VkSparseMemoryBindFlags));
 }
@@ -1101,9 +1161,9 @@
     VulkanStreamGuest* vkStream,
     const VkSparseBufferMemoryBindInfo* forMarshaling)
 {
-    uint64_t cgen_var_28;
-    vkStream->handleMapping()->mapHandles_VkBuffer_u64(&forMarshaling->buffer, &cgen_var_28, 1);
-    vkStream->write((uint64_t*)&cgen_var_28, 1 * 8);
+    uint64_t cgen_var_32;
+    vkStream->handleMapping()->mapHandles_VkBuffer_u64(&forMarshaling->buffer, &cgen_var_32, 1);
+    vkStream->write((uint64_t*)&cgen_var_32, 1 * 8);
     vkStream->write((uint32_t*)&forMarshaling->bindCount, sizeof(uint32_t));
     for (uint32_t i = 0; i < (uint32_t)forMarshaling->bindCount; ++i)
     {
@@ -1115,9 +1175,9 @@
     VulkanStreamGuest* vkStream,
     VkSparseBufferMemoryBindInfo* forUnmarshaling)
 {
-    uint64_t cgen_var_29;
-    vkStream->read((uint64_t*)&cgen_var_29, 1 * 8);
-    vkStream->handleMapping()->mapHandles_u64_VkBuffer(&cgen_var_29, (VkBuffer*)&forUnmarshaling->buffer, 1);
+    uint64_t cgen_var_33;
+    vkStream->read((uint64_t*)&cgen_var_33, 1 * 8);
+    vkStream->handleMapping()->mapHandles_u64_VkBuffer(&cgen_var_33, (VkBuffer*)&forUnmarshaling->buffer, 1);
     vkStream->read((uint32_t*)&forUnmarshaling->bindCount, sizeof(uint32_t));
     for (uint32_t i = 0; i < (uint32_t)forUnmarshaling->bindCount; ++i)
     {
@@ -1129,9 +1189,9 @@
     VulkanStreamGuest* vkStream,
     const VkSparseImageOpaqueMemoryBindInfo* forMarshaling)
 {
-    uint64_t cgen_var_30;
-    vkStream->handleMapping()->mapHandles_VkImage_u64(&forMarshaling->image, &cgen_var_30, 1);
-    vkStream->write((uint64_t*)&cgen_var_30, 1 * 8);
+    uint64_t cgen_var_34;
+    vkStream->handleMapping()->mapHandles_VkImage_u64(&forMarshaling->image, &cgen_var_34, 1);
+    vkStream->write((uint64_t*)&cgen_var_34, 1 * 8);
     vkStream->write((uint32_t*)&forMarshaling->bindCount, sizeof(uint32_t));
     for (uint32_t i = 0; i < (uint32_t)forMarshaling->bindCount; ++i)
     {
@@ -1143,9 +1203,9 @@
     VulkanStreamGuest* vkStream,
     VkSparseImageOpaqueMemoryBindInfo* forUnmarshaling)
 {
-    uint64_t cgen_var_31;
-    vkStream->read((uint64_t*)&cgen_var_31, 1 * 8);
-    vkStream->handleMapping()->mapHandles_u64_VkImage(&cgen_var_31, (VkImage*)&forUnmarshaling->image, 1);
+    uint64_t cgen_var_35;
+    vkStream->read((uint64_t*)&cgen_var_35, 1 * 8);
+    vkStream->handleMapping()->mapHandles_u64_VkImage(&cgen_var_35, (VkImage*)&forUnmarshaling->image, 1);
     vkStream->read((uint32_t*)&forUnmarshaling->bindCount, sizeof(uint32_t));
     for (uint32_t i = 0; i < (uint32_t)forUnmarshaling->bindCount; ++i)
     {
@@ -1196,9 +1256,9 @@
     marshal_VkImageSubresource(vkStream, (VkImageSubresource*)(&forMarshaling->subresource));
     marshal_VkOffset3D(vkStream, (VkOffset3D*)(&forMarshaling->offset));
     marshal_VkExtent3D(vkStream, (VkExtent3D*)(&forMarshaling->extent));
-    uint64_t cgen_var_32;
-    vkStream->handleMapping()->mapHandles_VkDeviceMemory_u64(&forMarshaling->memory, &cgen_var_32, 1);
-    vkStream->write((uint64_t*)&cgen_var_32, 1 * 8);
+    uint64_t cgen_var_36;
+    vkStream->handleMapping()->mapHandles_VkDeviceMemory_u64(&forMarshaling->memory, &cgen_var_36, 1);
+    vkStream->write((uint64_t*)&cgen_var_36, 1 * 8);
     vkStream->write((VkDeviceSize*)&forMarshaling->memoryOffset, sizeof(VkDeviceSize));
     vkStream->write((VkSparseMemoryBindFlags*)&forMarshaling->flags, sizeof(VkSparseMemoryBindFlags));
 }
@@ -1210,9 +1270,9 @@
     unmarshal_VkImageSubresource(vkStream, (VkImageSubresource*)(&forUnmarshaling->subresource));
     unmarshal_VkOffset3D(vkStream, (VkOffset3D*)(&forUnmarshaling->offset));
     unmarshal_VkExtent3D(vkStream, (VkExtent3D*)(&forUnmarshaling->extent));
-    uint64_t cgen_var_33;
-    vkStream->read((uint64_t*)&cgen_var_33, 1 * 8);
-    vkStream->handleMapping()->mapHandles_u64_VkDeviceMemory(&cgen_var_33, (VkDeviceMemory*)&forUnmarshaling->memory, 1);
+    uint64_t cgen_var_37;
+    vkStream->read((uint64_t*)&cgen_var_37, 1 * 8);
+    vkStream->handleMapping()->mapHandles_u64_VkDeviceMemory(&cgen_var_37, (VkDeviceMemory*)&forUnmarshaling->memory, 1);
     vkStream->read((VkDeviceSize*)&forUnmarshaling->memoryOffset, sizeof(VkDeviceSize));
     vkStream->read((VkSparseMemoryBindFlags*)&forUnmarshaling->flags, sizeof(VkSparseMemoryBindFlags));
 }
@@ -1221,9 +1281,9 @@
     VulkanStreamGuest* vkStream,
     const VkSparseImageMemoryBindInfo* forMarshaling)
 {
-    uint64_t cgen_var_34;
-    vkStream->handleMapping()->mapHandles_VkImage_u64(&forMarshaling->image, &cgen_var_34, 1);
-    vkStream->write((uint64_t*)&cgen_var_34, 1 * 8);
+    uint64_t cgen_var_38;
+    vkStream->handleMapping()->mapHandles_VkImage_u64(&forMarshaling->image, &cgen_var_38, 1);
+    vkStream->write((uint64_t*)&cgen_var_38, 1 * 8);
     vkStream->write((uint32_t*)&forMarshaling->bindCount, sizeof(uint32_t));
     for (uint32_t i = 0; i < (uint32_t)forMarshaling->bindCount; ++i)
     {
@@ -1235,9 +1295,9 @@
     VulkanStreamGuest* vkStream,
     VkSparseImageMemoryBindInfo* forUnmarshaling)
 {
-    uint64_t cgen_var_35;
-    vkStream->read((uint64_t*)&cgen_var_35, 1 * 8);
-    vkStream->handleMapping()->mapHandles_u64_VkImage(&cgen_var_35, (VkImage*)&forUnmarshaling->image, 1);
+    uint64_t cgen_var_39;
+    vkStream->read((uint64_t*)&cgen_var_39, 1 * 8);
+    vkStream->handleMapping()->mapHandles_u64_VkImage(&cgen_var_39, (VkImage*)&forUnmarshaling->image, 1);
     vkStream->read((uint32_t*)&forUnmarshaling->bindCount, sizeof(uint32_t));
     for (uint32_t i = 0; i < (uint32_t)forUnmarshaling->bindCount; ++i)
     {
@@ -1260,10 +1320,10 @@
     vkStream->write((uint32_t*)&forMarshaling->waitSemaphoreCount, sizeof(uint32_t));
     if (forMarshaling->waitSemaphoreCount)
     {
-        uint64_t* cgen_var_36;
-        vkStream->alloc((void**)&cgen_var_36, forMarshaling->waitSemaphoreCount * 8);
-        vkStream->handleMapping()->mapHandles_VkSemaphore_u64(forMarshaling->pWaitSemaphores, cgen_var_36, forMarshaling->waitSemaphoreCount);
-        vkStream->write((uint64_t*)cgen_var_36, forMarshaling->waitSemaphoreCount * 8);
+        uint64_t* cgen_var_40;
+        vkStream->alloc((void**)&cgen_var_40, forMarshaling->waitSemaphoreCount * 8);
+        vkStream->handleMapping()->mapHandles_VkSemaphore_u64(forMarshaling->pWaitSemaphores, cgen_var_40, forMarshaling->waitSemaphoreCount);
+        vkStream->write((uint64_t*)cgen_var_40, forMarshaling->waitSemaphoreCount * 8);
     }
     vkStream->write((uint32_t*)&forMarshaling->bufferBindCount, sizeof(uint32_t));
     for (uint32_t i = 0; i < (uint32_t)forMarshaling->bufferBindCount; ++i)
@@ -1283,10 +1343,10 @@
     vkStream->write((uint32_t*)&forMarshaling->signalSemaphoreCount, sizeof(uint32_t));
     if (forMarshaling->signalSemaphoreCount)
     {
-        uint64_t* cgen_var_37;
-        vkStream->alloc((void**)&cgen_var_37, forMarshaling->signalSemaphoreCount * 8);
-        vkStream->handleMapping()->mapHandles_VkSemaphore_u64(forMarshaling->pSignalSemaphores, cgen_var_37, forMarshaling->signalSemaphoreCount);
-        vkStream->write((uint64_t*)cgen_var_37, forMarshaling->signalSemaphoreCount * 8);
+        uint64_t* cgen_var_41;
+        vkStream->alloc((void**)&cgen_var_41, forMarshaling->signalSemaphoreCount * 8);
+        vkStream->handleMapping()->mapHandles_VkSemaphore_u64(forMarshaling->pSignalSemaphores, cgen_var_41, forMarshaling->signalSemaphoreCount);
+        vkStream->write((uint64_t*)cgen_var_41, forMarshaling->signalSemaphoreCount * 8);
     }
 }
 
@@ -1306,10 +1366,10 @@
     vkStream->read((uint32_t*)&forUnmarshaling->waitSemaphoreCount, sizeof(uint32_t));
     if (forUnmarshaling->waitSemaphoreCount)
     {
-        uint64_t* cgen_var_38;
-        vkStream->alloc((void**)&cgen_var_38, forUnmarshaling->waitSemaphoreCount * 8);
-        vkStream->read((uint64_t*)cgen_var_38, forUnmarshaling->waitSemaphoreCount * 8);
-        vkStream->handleMapping()->mapHandles_u64_VkSemaphore(cgen_var_38, (VkSemaphore*)forUnmarshaling->pWaitSemaphores, forUnmarshaling->waitSemaphoreCount);
+        uint64_t* cgen_var_42;
+        vkStream->alloc((void**)&cgen_var_42, forUnmarshaling->waitSemaphoreCount * 8);
+        vkStream->read((uint64_t*)cgen_var_42, forUnmarshaling->waitSemaphoreCount * 8);
+        vkStream->handleMapping()->mapHandles_u64_VkSemaphore(cgen_var_42, (VkSemaphore*)forUnmarshaling->pWaitSemaphores, forUnmarshaling->waitSemaphoreCount);
     }
     vkStream->read((uint32_t*)&forUnmarshaling->bufferBindCount, sizeof(uint32_t));
     for (uint32_t i = 0; i < (uint32_t)forUnmarshaling->bufferBindCount; ++i)
@@ -1329,10 +1389,10 @@
     vkStream->read((uint32_t*)&forUnmarshaling->signalSemaphoreCount, sizeof(uint32_t));
     if (forUnmarshaling->signalSemaphoreCount)
     {
-        uint64_t* cgen_var_39;
-        vkStream->alloc((void**)&cgen_var_39, forUnmarshaling->signalSemaphoreCount * 8);
-        vkStream->read((uint64_t*)cgen_var_39, forUnmarshaling->signalSemaphoreCount * 8);
-        vkStream->handleMapping()->mapHandles_u64_VkSemaphore(cgen_var_39, (VkSemaphore*)forUnmarshaling->pSignalSemaphores, forUnmarshaling->signalSemaphoreCount);
+        uint64_t* cgen_var_43;
+        vkStream->alloc((void**)&cgen_var_43, forUnmarshaling->signalSemaphoreCount * 8);
+        vkStream->read((uint64_t*)cgen_var_43, forUnmarshaling->signalSemaphoreCount * 8);
+        vkStream->handleMapping()->mapHandles_u64_VkSemaphore(cgen_var_43, (VkSemaphore*)forUnmarshaling->pSignalSemaphores, forUnmarshaling->signalSemaphoreCount);
     }
 }
 
@@ -1484,8 +1544,8 @@
     vkStream->write((VkSharingMode*)&forMarshaling->sharingMode, sizeof(VkSharingMode));
     vkStream->write((uint32_t*)&forMarshaling->queueFamilyIndexCount, sizeof(uint32_t));
     // WARNING PTR CHECK
-    uint64_t cgen_var_40 = (uint64_t)(uintptr_t)forMarshaling->pQueueFamilyIndices;
-    vkStream->putBe64(cgen_var_40);
+    uint64_t cgen_var_44 = (uint64_t)(uintptr_t)forMarshaling->pQueueFamilyIndices;
+    vkStream->putBe64(cgen_var_44);
     if (forMarshaling->pQueueFamilyIndices)
     {
         vkStream->write((const uint32_t*)forMarshaling->pQueueFamilyIndices, forMarshaling->queueFamilyIndexCount * sizeof(const uint32_t));
@@ -1536,9 +1596,9 @@
         marshal_extension_struct(vkStream, forMarshaling->pNext);
     }
     vkStream->write((VkBufferViewCreateFlags*)&forMarshaling->flags, sizeof(VkBufferViewCreateFlags));
-    uint64_t cgen_var_42;
-    vkStream->handleMapping()->mapHandles_VkBuffer_u64(&forMarshaling->buffer, &cgen_var_42, 1);
-    vkStream->write((uint64_t*)&cgen_var_42, 1 * 8);
+    uint64_t cgen_var_46;
+    vkStream->handleMapping()->mapHandles_VkBuffer_u64(&forMarshaling->buffer, &cgen_var_46, 1);
+    vkStream->write((uint64_t*)&cgen_var_46, 1 * 8);
     vkStream->write((VkFormat*)&forMarshaling->format, sizeof(VkFormat));
     vkStream->write((VkDeviceSize*)&forMarshaling->offset, sizeof(VkDeviceSize));
     vkStream->write((VkDeviceSize*)&forMarshaling->range, sizeof(VkDeviceSize));
@@ -1558,9 +1618,9 @@
         unmarshal_extension_struct(vkStream, (void*)(forUnmarshaling->pNext));
     }
     vkStream->read((VkBufferViewCreateFlags*)&forUnmarshaling->flags, sizeof(VkBufferViewCreateFlags));
-    uint64_t cgen_var_43;
-    vkStream->read((uint64_t*)&cgen_var_43, 1 * 8);
-    vkStream->handleMapping()->mapHandles_u64_VkBuffer(&cgen_var_43, (VkBuffer*)&forUnmarshaling->buffer, 1);
+    uint64_t cgen_var_47;
+    vkStream->read((uint64_t*)&cgen_var_47, 1 * 8);
+    vkStream->handleMapping()->mapHandles_u64_VkBuffer(&cgen_var_47, (VkBuffer*)&forUnmarshaling->buffer, 1);
     vkStream->read((VkFormat*)&forUnmarshaling->format, sizeof(VkFormat));
     vkStream->read((VkDeviceSize*)&forUnmarshaling->offset, sizeof(VkDeviceSize));
     vkStream->read((VkDeviceSize*)&forUnmarshaling->range, sizeof(VkDeviceSize));
@@ -1590,8 +1650,8 @@
     vkStream->write((VkSharingMode*)&forMarshaling->sharingMode, sizeof(VkSharingMode));
     vkStream->write((uint32_t*)&forMarshaling->queueFamilyIndexCount, sizeof(uint32_t));
     // WARNING PTR CHECK
-    uint64_t cgen_var_44 = (uint64_t)(uintptr_t)forMarshaling->pQueueFamilyIndices;
-    vkStream->putBe64(cgen_var_44);
+    uint64_t cgen_var_48 = (uint64_t)(uintptr_t)forMarshaling->pQueueFamilyIndices;
+    vkStream->putBe64(cgen_var_48);
     if (forMarshaling->pQueueFamilyIndices)
     {
         vkStream->write((const uint32_t*)forMarshaling->pQueueFamilyIndices, forMarshaling->queueFamilyIndexCount * sizeof(const uint32_t));
@@ -1714,9 +1774,9 @@
         marshal_extension_struct(vkStream, forMarshaling->pNext);
     }
     vkStream->write((VkImageViewCreateFlags*)&forMarshaling->flags, sizeof(VkImageViewCreateFlags));
-    uint64_t cgen_var_46;
-    vkStream->handleMapping()->mapHandles_VkImage_u64(&forMarshaling->image, &cgen_var_46, 1);
-    vkStream->write((uint64_t*)&cgen_var_46, 1 * 8);
+    uint64_t cgen_var_50;
+    vkStream->handleMapping()->mapHandles_VkImage_u64(&forMarshaling->image, &cgen_var_50, 1);
+    vkStream->write((uint64_t*)&cgen_var_50, 1 * 8);
     vkStream->write((VkImageViewType*)&forMarshaling->viewType, sizeof(VkImageViewType));
     vkStream->write((VkFormat*)&forMarshaling->format, sizeof(VkFormat));
     marshal_VkComponentMapping(vkStream, (VkComponentMapping*)(&forMarshaling->components));
@@ -1737,9 +1797,9 @@
         unmarshal_extension_struct(vkStream, (void*)(forUnmarshaling->pNext));
     }
     vkStream->read((VkImageViewCreateFlags*)&forUnmarshaling->flags, sizeof(VkImageViewCreateFlags));
-    uint64_t cgen_var_47;
-    vkStream->read((uint64_t*)&cgen_var_47, 1 * 8);
-    vkStream->handleMapping()->mapHandles_u64_VkImage(&cgen_var_47, (VkImage*)&forUnmarshaling->image, 1);
+    uint64_t cgen_var_51;
+    vkStream->read((uint64_t*)&cgen_var_51, 1 * 8);
+    vkStream->handleMapping()->mapHandles_u64_VkImage(&cgen_var_51, (VkImage*)&forUnmarshaling->image, 1);
     vkStream->read((VkImageViewType*)&forUnmarshaling->viewType, sizeof(VkImageViewType));
     vkStream->read((VkFormat*)&forUnmarshaling->format, sizeof(VkFormat));
     unmarshal_VkComponentMapping(vkStream, (VkComponentMapping*)(&forUnmarshaling->components));
@@ -1759,8 +1819,8 @@
         marshal_extension_struct(vkStream, forMarshaling->pNext);
     }
     vkStream->write((VkShaderModuleCreateFlags*)&forMarshaling->flags, sizeof(VkShaderModuleCreateFlags));
-    uint64_t cgen_var_48 = (uint64_t)forMarshaling->codeSize;
-    vkStream->putBe64(cgen_var_48);
+    uint64_t cgen_var_52 = (uint64_t)forMarshaling->codeSize;
+    vkStream->putBe64(cgen_var_52);
     vkStream->write((const uint32_t*)forMarshaling->pCode, (forMarshaling->codeSize / 4) * sizeof(const uint32_t));
 }
 
@@ -1795,8 +1855,8 @@
         marshal_extension_struct(vkStream, forMarshaling->pNext);
     }
     vkStream->write((VkPipelineCacheCreateFlags*)&forMarshaling->flags, sizeof(VkPipelineCacheCreateFlags));
-    uint64_t cgen_var_50 = (uint64_t)forMarshaling->initialDataSize;
-    vkStream->putBe64(cgen_var_50);
+    uint64_t cgen_var_54 = (uint64_t)forMarshaling->initialDataSize;
+    vkStream->putBe64(cgen_var_54);
     vkStream->write((const void*)forMarshaling->pInitialData, forMarshaling->initialDataSize * sizeof(const uint8_t));
 }
 
@@ -1824,8 +1884,8 @@
 {
     vkStream->write((uint32_t*)&forMarshaling->constantID, sizeof(uint32_t));
     vkStream->write((uint32_t*)&forMarshaling->offset, sizeof(uint32_t));
-    uint64_t cgen_var_52 = (uint64_t)forMarshaling->size;
-    vkStream->putBe64(cgen_var_52);
+    uint64_t cgen_var_56 = (uint64_t)forMarshaling->size;
+    vkStream->putBe64(cgen_var_56);
 }
 
 void unmarshal_VkSpecializationMapEntry(
@@ -1846,8 +1906,8 @@
     {
         marshal_VkSpecializationMapEntry(vkStream, (const VkSpecializationMapEntry*)(forMarshaling->pMapEntries + i));
     }
-    uint64_t cgen_var_54 = (uint64_t)forMarshaling->dataSize;
-    vkStream->putBe64(cgen_var_54);
+    uint64_t cgen_var_58 = (uint64_t)forMarshaling->dataSize;
+    vkStream->putBe64(cgen_var_58);
     vkStream->write((const void*)forMarshaling->pData, forMarshaling->dataSize * sizeof(const uint8_t));
 }
 
@@ -1878,13 +1938,13 @@
     }
     vkStream->write((VkPipelineShaderStageCreateFlags*)&forMarshaling->flags, sizeof(VkPipelineShaderStageCreateFlags));
     vkStream->write((VkShaderStageFlagBits*)&forMarshaling->stage, sizeof(VkShaderStageFlagBits));
-    uint64_t cgen_var_56;
-    vkStream->handleMapping()->mapHandles_VkShaderModule_u64(&forMarshaling->module, &cgen_var_56, 1);
-    vkStream->write((uint64_t*)&cgen_var_56, 1 * 8);
+    uint64_t cgen_var_60;
+    vkStream->handleMapping()->mapHandles_VkShaderModule_u64(&forMarshaling->module, &cgen_var_60, 1);
+    vkStream->write((uint64_t*)&cgen_var_60, 1 * 8);
     vkStream->putString(forMarshaling->pName);
     // WARNING PTR CHECK
-    uint64_t cgen_var_57 = (uint64_t)(uintptr_t)forMarshaling->pSpecializationInfo;
-    vkStream->putBe64(cgen_var_57);
+    uint64_t cgen_var_61 = (uint64_t)(uintptr_t)forMarshaling->pSpecializationInfo;
+    vkStream->putBe64(cgen_var_61);
     if (forMarshaling->pSpecializationInfo)
     {
         marshal_VkSpecializationInfo(vkStream, (const VkSpecializationInfo*)(forMarshaling->pSpecializationInfo));
@@ -1906,9 +1966,9 @@
     }
     vkStream->read((VkPipelineShaderStageCreateFlags*)&forUnmarshaling->flags, sizeof(VkPipelineShaderStageCreateFlags));
     vkStream->read((VkShaderStageFlagBits*)&forUnmarshaling->stage, sizeof(VkShaderStageFlagBits));
-    uint64_t cgen_var_58;
-    vkStream->read((uint64_t*)&cgen_var_58, 1 * 8);
-    vkStream->handleMapping()->mapHandles_u64_VkShaderModule(&cgen_var_58, (VkShaderModule*)&forUnmarshaling->module, 1);
+    uint64_t cgen_var_62;
+    vkStream->read((uint64_t*)&cgen_var_62, 1 * 8);
+    vkStream->handleMapping()->mapHandles_u64_VkShaderModule(&cgen_var_62, (VkShaderModule*)&forUnmarshaling->module, 1);
     vkStream->loadStringInPlace((char**)&forUnmarshaling->pName);
     // WARNING PTR CHECK
     const VkSpecializationInfo* check_pSpecializationInfo;
@@ -2167,8 +2227,8 @@
     vkStream->write((VkPipelineViewportStateCreateFlags*)&forMarshaling->flags, sizeof(VkPipelineViewportStateCreateFlags));
     vkStream->write((uint32_t*)&forMarshaling->viewportCount, sizeof(uint32_t));
     // WARNING PTR CHECK
-    uint64_t cgen_var_60 = (uint64_t)(uintptr_t)forMarshaling->pViewports;
-    vkStream->putBe64(cgen_var_60);
+    uint64_t cgen_var_64 = (uint64_t)(uintptr_t)forMarshaling->pViewports;
+    vkStream->putBe64(cgen_var_64);
     if (forMarshaling->pViewports)
     {
         for (uint32_t i = 0; i < (uint32_t)forMarshaling->viewportCount; ++i)
@@ -2178,8 +2238,8 @@
     }
     vkStream->write((uint32_t*)&forMarshaling->scissorCount, sizeof(uint32_t));
     // WARNING PTR CHECK
-    uint64_t cgen_var_61 = (uint64_t)(uintptr_t)forMarshaling->pScissors;
-    vkStream->putBe64(cgen_var_61);
+    uint64_t cgen_var_65 = (uint64_t)(uintptr_t)forMarshaling->pScissors;
+    vkStream->putBe64(cgen_var_65);
     if (forMarshaling->pScissors)
     {
         for (uint32_t i = 0; i < (uint32_t)forMarshaling->scissorCount; ++i)
@@ -2303,8 +2363,8 @@
     vkStream->write((VkBool32*)&forMarshaling->sampleShadingEnable, sizeof(VkBool32));
     vkStream->write((float*)&forMarshaling->minSampleShading, sizeof(float));
     // WARNING PTR CHECK
-    uint64_t cgen_var_64 = (uint64_t)(uintptr_t)forMarshaling->pSampleMask;
-    vkStream->putBe64(cgen_var_64);
+    uint64_t cgen_var_68 = (uint64_t)(uintptr_t)forMarshaling->pSampleMask;
+    vkStream->putBe64(cgen_var_68);
     if (forMarshaling->pSampleMask)
     {
         vkStream->write((const VkSampleMask*)forMarshaling->pSampleMask, (((forMarshaling->rasterizationSamples) + 31) / 32) * sizeof(const VkSampleMask));
@@ -2534,6 +2594,20 @@
     VulkanStreamGuest* vkStream,
     const VkGraphicsPipelineCreateInfo* forMarshaling)
 {
+    uint32_t hasRasterization = 1;
+    if (vkStream->getFeatureBits() & VULKAN_STREAM_FEATURE_IGNORED_HANDLES_BIT)
+    {
+        hasRasterization = (((0 == forMarshaling->pRasterizationState)) ? (0) : (!((*(forMarshaling->pRasterizationState)).rasterizerDiscardEnable)));
+        uint32_t cgen_var_70 = (uint32_t)hasRasterization;
+        vkStream->putBe32(cgen_var_70);
+    }
+    uint32_t hasTessellation = 1;
+    if (vkStream->getFeatureBits() & VULKAN_STREAM_FEATURE_IGNORED_HANDLES_BIT)
+    {
+        hasTessellation = arrayany(forMarshaling->pStages, 0, forMarshaling->stageCount, [](VkPipelineShaderStageCreateInfo s) { return ((s.stage == VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT) || (s.stage == VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT)); });
+        uint32_t cgen_var_71 = (uint32_t)hasTessellation;
+        vkStream->putBe32(cgen_var_71);
+    }
     vkStream->write((VkStructureType*)&forMarshaling->sType, sizeof(VkStructureType));
     size_t pNext_size = goldfish_vk_extension_struct_size(forMarshaling->pNext);
     vkStream->putBe32(pNext_size);
@@ -2548,61 +2622,103 @@
     {
         marshal_VkPipelineShaderStageCreateInfo(vkStream, (const VkPipelineShaderStageCreateInfo*)(forMarshaling->pStages + i));
     }
-    marshal_VkPipelineVertexInputStateCreateInfo(vkStream, (const VkPipelineVertexInputStateCreateInfo*)(forMarshaling->pVertexInputState));
-    marshal_VkPipelineInputAssemblyStateCreateInfo(vkStream, (const VkPipelineInputAssemblyStateCreateInfo*)(forMarshaling->pInputAssemblyState));
     // WARNING PTR CHECK
-    uint64_t cgen_var_66 = (uint64_t)(uintptr_t)forMarshaling->pTessellationState;
-    vkStream->putBe64(cgen_var_66);
+    if (vkStream->getFeatureBits() & VULKAN_STREAM_FEATURE_IGNORED_HANDLES_BIT)
+    {
+        uint64_t cgen_var_72 = (uint64_t)(uintptr_t)forMarshaling->pVertexInputState;
+        vkStream->putBe64(cgen_var_72);
+    }
+    if ((!(vkStream->getFeatureBits() & VULKAN_STREAM_FEATURE_IGNORED_HANDLES_BIT) || forMarshaling->pVertexInputState))
+    {
+        marshal_VkPipelineVertexInputStateCreateInfo(vkStream, (const VkPipelineVertexInputStateCreateInfo*)(forMarshaling->pVertexInputState));
+    }
+    // WARNING PTR CHECK
+    if (vkStream->getFeatureBits() & VULKAN_STREAM_FEATURE_IGNORED_HANDLES_BIT)
+    {
+        uint64_t cgen_var_73 = (uint64_t)(uintptr_t)forMarshaling->pInputAssemblyState;
+        vkStream->putBe64(cgen_var_73);
+    }
+    if ((!(vkStream->getFeatureBits() & VULKAN_STREAM_FEATURE_IGNORED_HANDLES_BIT) || forMarshaling->pInputAssemblyState))
+    {
+        marshal_VkPipelineInputAssemblyStateCreateInfo(vkStream, (const VkPipelineInputAssemblyStateCreateInfo*)(forMarshaling->pInputAssemblyState));
+    }
+    // WARNING PTR CHECK
+    uint64_t cgen_var_74 = (uint64_t)(uintptr_t)forMarshaling->pTessellationState;
+    vkStream->putBe64(cgen_var_74);
     if (forMarshaling->pTessellationState)
     {
-        marshal_VkPipelineTessellationStateCreateInfo(vkStream, (const VkPipelineTessellationStateCreateInfo*)(forMarshaling->pTessellationState));
+        if (hasTessellation)
+        {
+            marshal_VkPipelineTessellationStateCreateInfo(vkStream, (const VkPipelineTessellationStateCreateInfo*)(forMarshaling->pTessellationState));
+        }
     }
     // WARNING PTR CHECK
-    uint64_t cgen_var_67 = (uint64_t)(uintptr_t)forMarshaling->pViewportState;
-    vkStream->putBe64(cgen_var_67);
+    uint64_t cgen_var_75 = (uint64_t)(uintptr_t)forMarshaling->pViewportState;
+    vkStream->putBe64(cgen_var_75);
     if (forMarshaling->pViewportState)
     {
-        marshal_VkPipelineViewportStateCreateInfo(vkStream, (const VkPipelineViewportStateCreateInfo*)(forMarshaling->pViewportState));
+        if (hasRasterization)
+        {
+            marshal_VkPipelineViewportStateCreateInfo(vkStream, (const VkPipelineViewportStateCreateInfo*)(forMarshaling->pViewportState));
+        }
     }
-    marshal_VkPipelineRasterizationStateCreateInfo(vkStream, (const VkPipelineRasterizationStateCreateInfo*)(forMarshaling->pRasterizationState));
     // WARNING PTR CHECK
-    uint64_t cgen_var_68 = (uint64_t)(uintptr_t)forMarshaling->pMultisampleState;
-    vkStream->putBe64(cgen_var_68);
+    if (vkStream->getFeatureBits() & VULKAN_STREAM_FEATURE_IGNORED_HANDLES_BIT)
+    {
+        uint64_t cgen_var_76 = (uint64_t)(uintptr_t)forMarshaling->pRasterizationState;
+        vkStream->putBe64(cgen_var_76);
+    }
+    if ((!(vkStream->getFeatureBits() & VULKAN_STREAM_FEATURE_IGNORED_HANDLES_BIT) || forMarshaling->pRasterizationState))
+    {
+        marshal_VkPipelineRasterizationStateCreateInfo(vkStream, (const VkPipelineRasterizationStateCreateInfo*)(forMarshaling->pRasterizationState));
+    }
+    // WARNING PTR CHECK
+    uint64_t cgen_var_77 = (uint64_t)(uintptr_t)forMarshaling->pMultisampleState;
+    vkStream->putBe64(cgen_var_77);
     if (forMarshaling->pMultisampleState)
     {
-        marshal_VkPipelineMultisampleStateCreateInfo(vkStream, (const VkPipelineMultisampleStateCreateInfo*)(forMarshaling->pMultisampleState));
+        if (hasRasterization)
+        {
+            marshal_VkPipelineMultisampleStateCreateInfo(vkStream, (const VkPipelineMultisampleStateCreateInfo*)(forMarshaling->pMultisampleState));
+        }
     }
     // WARNING PTR CHECK
-    uint64_t cgen_var_69 = (uint64_t)(uintptr_t)forMarshaling->pDepthStencilState;
-    vkStream->putBe64(cgen_var_69);
+    uint64_t cgen_var_78 = (uint64_t)(uintptr_t)forMarshaling->pDepthStencilState;
+    vkStream->putBe64(cgen_var_78);
     if (forMarshaling->pDepthStencilState)
     {
-        marshal_VkPipelineDepthStencilStateCreateInfo(vkStream, (const VkPipelineDepthStencilStateCreateInfo*)(forMarshaling->pDepthStencilState));
+        if (hasRasterization)
+        {
+            marshal_VkPipelineDepthStencilStateCreateInfo(vkStream, (const VkPipelineDepthStencilStateCreateInfo*)(forMarshaling->pDepthStencilState));
+        }
     }
     // WARNING PTR CHECK
-    uint64_t cgen_var_70 = (uint64_t)(uintptr_t)forMarshaling->pColorBlendState;
-    vkStream->putBe64(cgen_var_70);
+    uint64_t cgen_var_79 = (uint64_t)(uintptr_t)forMarshaling->pColorBlendState;
+    vkStream->putBe64(cgen_var_79);
     if (forMarshaling->pColorBlendState)
     {
-        marshal_VkPipelineColorBlendStateCreateInfo(vkStream, (const VkPipelineColorBlendStateCreateInfo*)(forMarshaling->pColorBlendState));
+        if (hasRasterization)
+        {
+            marshal_VkPipelineColorBlendStateCreateInfo(vkStream, (const VkPipelineColorBlendStateCreateInfo*)(forMarshaling->pColorBlendState));
+        }
     }
     // WARNING PTR CHECK
-    uint64_t cgen_var_71 = (uint64_t)(uintptr_t)forMarshaling->pDynamicState;
-    vkStream->putBe64(cgen_var_71);
+    uint64_t cgen_var_80 = (uint64_t)(uintptr_t)forMarshaling->pDynamicState;
+    vkStream->putBe64(cgen_var_80);
     if (forMarshaling->pDynamicState)
     {
         marshal_VkPipelineDynamicStateCreateInfo(vkStream, (const VkPipelineDynamicStateCreateInfo*)(forMarshaling->pDynamicState));
     }
-    uint64_t cgen_var_72;
-    vkStream->handleMapping()->mapHandles_VkPipelineLayout_u64(&forMarshaling->layout, &cgen_var_72, 1);
-    vkStream->write((uint64_t*)&cgen_var_72, 1 * 8);
-    uint64_t cgen_var_73;
-    vkStream->handleMapping()->mapHandles_VkRenderPass_u64(&forMarshaling->renderPass, &cgen_var_73, 1);
-    vkStream->write((uint64_t*)&cgen_var_73, 1 * 8);
+    uint64_t cgen_var_81;
+    vkStream->handleMapping()->mapHandles_VkPipelineLayout_u64(&forMarshaling->layout, &cgen_var_81, 1);
+    vkStream->write((uint64_t*)&cgen_var_81, 1 * 8);
+    uint64_t cgen_var_82;
+    vkStream->handleMapping()->mapHandles_VkRenderPass_u64(&forMarshaling->renderPass, &cgen_var_82, 1);
+    vkStream->write((uint64_t*)&cgen_var_82, 1 * 8);
     vkStream->write((uint32_t*)&forMarshaling->subpass, sizeof(uint32_t));
-    uint64_t cgen_var_74;
-    vkStream->handleMapping()->mapHandles_VkPipeline_u64(&forMarshaling->basePipelineHandle, &cgen_var_74, 1);
-    vkStream->write((uint64_t*)&cgen_var_74, 1 * 8);
+    uint64_t cgen_var_83;
+    vkStream->handleMapping()->mapHandles_VkPipeline_u64(&forMarshaling->basePipelineHandle, &cgen_var_83, 1);
+    vkStream->write((uint64_t*)&cgen_var_83, 1 * 8);
     vkStream->write((int32_t*)&forMarshaling->basePipelineIndex, sizeof(int32_t));
 }
 
@@ -2610,6 +2726,16 @@
     VulkanStreamGuest* vkStream,
     VkGraphicsPipelineCreateInfo* forUnmarshaling)
 {
+    uint32_t hasRasterization = 1;
+    if (vkStream->getFeatureBits() & VULKAN_STREAM_FEATURE_IGNORED_HANDLES_BIT)
+    {
+        hasRasterization = (const uint32_t)vkStream->getBe32();
+    }
+    uint32_t hasTessellation = 1;
+    if (vkStream->getFeatureBits() & VULKAN_STREAM_FEATURE_IGNORED_HANDLES_BIT)
+    {
+        hasTessellation = (const uint32_t)vkStream->getBe32();
+    }
     vkStream->read((VkStructureType*)&forUnmarshaling->sType, sizeof(VkStructureType));
     size_t pNext_size;
     pNext_size = vkStream->getBe32();
@@ -2625,8 +2751,26 @@
     {
         unmarshal_VkPipelineShaderStageCreateInfo(vkStream, (VkPipelineShaderStageCreateInfo*)(forUnmarshaling->pStages + i));
     }
-    unmarshal_VkPipelineVertexInputStateCreateInfo(vkStream, (VkPipelineVertexInputStateCreateInfo*)(forUnmarshaling->pVertexInputState));
-    unmarshal_VkPipelineInputAssemblyStateCreateInfo(vkStream, (VkPipelineInputAssemblyStateCreateInfo*)(forUnmarshaling->pInputAssemblyState));
+    // WARNING PTR CHECK
+    const VkPipelineVertexInputStateCreateInfo* check_pVertexInputState;
+    if (vkStream->getFeatureBits() & VULKAN_STREAM_FEATURE_IGNORED_HANDLES_BIT)
+    {
+        check_pVertexInputState = (const VkPipelineVertexInputStateCreateInfo*)(uintptr_t)vkStream->getBe64();
+    }
+    if ((!(vkStream->getFeatureBits() & VULKAN_STREAM_FEATURE_IGNORED_HANDLES_BIT) || forUnmarshaling->pVertexInputState))
+    {
+        unmarshal_VkPipelineVertexInputStateCreateInfo(vkStream, (VkPipelineVertexInputStateCreateInfo*)(forUnmarshaling->pVertexInputState));
+    }
+    // WARNING PTR CHECK
+    const VkPipelineInputAssemblyStateCreateInfo* check_pInputAssemblyState;
+    if (vkStream->getFeatureBits() & VULKAN_STREAM_FEATURE_IGNORED_HANDLES_BIT)
+    {
+        check_pInputAssemblyState = (const VkPipelineInputAssemblyStateCreateInfo*)(uintptr_t)vkStream->getBe64();
+    }
+    if ((!(vkStream->getFeatureBits() & VULKAN_STREAM_FEATURE_IGNORED_HANDLES_BIT) || forUnmarshaling->pInputAssemblyState))
+    {
+        unmarshal_VkPipelineInputAssemblyStateCreateInfo(vkStream, (VkPipelineInputAssemblyStateCreateInfo*)(forUnmarshaling->pInputAssemblyState));
+    }
     // WARNING PTR CHECK
     const VkPipelineTessellationStateCreateInfo* check_pTessellationState;
     check_pTessellationState = (const VkPipelineTessellationStateCreateInfo*)(uintptr_t)vkStream->getBe64();
@@ -2636,7 +2780,14 @@
         {
             fprintf(stderr, "fatal: forUnmarshaling->pTessellationState inconsistent between guest and host\n");
         }
-        unmarshal_VkPipelineTessellationStateCreateInfo(vkStream, (VkPipelineTessellationStateCreateInfo*)(forUnmarshaling->pTessellationState));
+        if (hasTessellation)
+        {
+            unmarshal_VkPipelineTessellationStateCreateInfo(vkStream, (VkPipelineTessellationStateCreateInfo*)(forUnmarshaling->pTessellationState));
+        }
+        else
+        {
+            forUnmarshaling->pTessellationState = 0;
+        }
     }
     // WARNING PTR CHECK
     const VkPipelineViewportStateCreateInfo* check_pViewportState;
@@ -2647,9 +2798,25 @@
         {
             fprintf(stderr, "fatal: forUnmarshaling->pViewportState inconsistent between guest and host\n");
         }
-        unmarshal_VkPipelineViewportStateCreateInfo(vkStream, (VkPipelineViewportStateCreateInfo*)(forUnmarshaling->pViewportState));
+        if (hasRasterization)
+        {
+            unmarshal_VkPipelineViewportStateCreateInfo(vkStream, (VkPipelineViewportStateCreateInfo*)(forUnmarshaling->pViewportState));
+        }
+        else
+        {
+            forUnmarshaling->pViewportState = 0;
+        }
     }
-    unmarshal_VkPipelineRasterizationStateCreateInfo(vkStream, (VkPipelineRasterizationStateCreateInfo*)(forUnmarshaling->pRasterizationState));
+    // WARNING PTR CHECK
+    const VkPipelineRasterizationStateCreateInfo* check_pRasterizationState;
+    if (vkStream->getFeatureBits() & VULKAN_STREAM_FEATURE_IGNORED_HANDLES_BIT)
+    {
+        check_pRasterizationState = (const VkPipelineRasterizationStateCreateInfo*)(uintptr_t)vkStream->getBe64();
+    }
+    if ((!(vkStream->getFeatureBits() & VULKAN_STREAM_FEATURE_IGNORED_HANDLES_BIT) || forUnmarshaling->pRasterizationState))
+    {
+        unmarshal_VkPipelineRasterizationStateCreateInfo(vkStream, (VkPipelineRasterizationStateCreateInfo*)(forUnmarshaling->pRasterizationState));
+    }
     // WARNING PTR CHECK
     const VkPipelineMultisampleStateCreateInfo* check_pMultisampleState;
     check_pMultisampleState = (const VkPipelineMultisampleStateCreateInfo*)(uintptr_t)vkStream->getBe64();
@@ -2659,7 +2826,14 @@
         {
             fprintf(stderr, "fatal: forUnmarshaling->pMultisampleState inconsistent between guest and host\n");
         }
-        unmarshal_VkPipelineMultisampleStateCreateInfo(vkStream, (VkPipelineMultisampleStateCreateInfo*)(forUnmarshaling->pMultisampleState));
+        if (hasRasterization)
+        {
+            unmarshal_VkPipelineMultisampleStateCreateInfo(vkStream, (VkPipelineMultisampleStateCreateInfo*)(forUnmarshaling->pMultisampleState));
+        }
+        else
+        {
+            forUnmarshaling->pMultisampleState = 0;
+        }
     }
     // WARNING PTR CHECK
     const VkPipelineDepthStencilStateCreateInfo* check_pDepthStencilState;
@@ -2670,7 +2844,14 @@
         {
             fprintf(stderr, "fatal: forUnmarshaling->pDepthStencilState inconsistent between guest and host\n");
         }
-        unmarshal_VkPipelineDepthStencilStateCreateInfo(vkStream, (VkPipelineDepthStencilStateCreateInfo*)(forUnmarshaling->pDepthStencilState));
+        if (hasRasterization)
+        {
+            unmarshal_VkPipelineDepthStencilStateCreateInfo(vkStream, (VkPipelineDepthStencilStateCreateInfo*)(forUnmarshaling->pDepthStencilState));
+        }
+        else
+        {
+            forUnmarshaling->pDepthStencilState = 0;
+        }
     }
     // WARNING PTR CHECK
     const VkPipelineColorBlendStateCreateInfo* check_pColorBlendState;
@@ -2681,7 +2862,14 @@
         {
             fprintf(stderr, "fatal: forUnmarshaling->pColorBlendState inconsistent between guest and host\n");
         }
-        unmarshal_VkPipelineColorBlendStateCreateInfo(vkStream, (VkPipelineColorBlendStateCreateInfo*)(forUnmarshaling->pColorBlendState));
+        if (hasRasterization)
+        {
+            unmarshal_VkPipelineColorBlendStateCreateInfo(vkStream, (VkPipelineColorBlendStateCreateInfo*)(forUnmarshaling->pColorBlendState));
+        }
+        else
+        {
+            forUnmarshaling->pColorBlendState = 0;
+        }
     }
     // WARNING PTR CHECK
     const VkPipelineDynamicStateCreateInfo* check_pDynamicState;
@@ -2694,16 +2882,16 @@
         }
         unmarshal_VkPipelineDynamicStateCreateInfo(vkStream, (VkPipelineDynamicStateCreateInfo*)(forUnmarshaling->pDynamicState));
     }
-    uint64_t cgen_var_81;
-    vkStream->read((uint64_t*)&cgen_var_81, 1 * 8);
-    vkStream->handleMapping()->mapHandles_u64_VkPipelineLayout(&cgen_var_81, (VkPipelineLayout*)&forUnmarshaling->layout, 1);
-    uint64_t cgen_var_82;
-    vkStream->read((uint64_t*)&cgen_var_82, 1 * 8);
-    vkStream->handleMapping()->mapHandles_u64_VkRenderPass(&cgen_var_82, (VkRenderPass*)&forUnmarshaling->renderPass, 1);
+    uint64_t cgen_var_95;
+    vkStream->read((uint64_t*)&cgen_var_95, 1 * 8);
+    vkStream->handleMapping()->mapHandles_u64_VkPipelineLayout(&cgen_var_95, (VkPipelineLayout*)&forUnmarshaling->layout, 1);
+    uint64_t cgen_var_96;
+    vkStream->read((uint64_t*)&cgen_var_96, 1 * 8);
+    vkStream->handleMapping()->mapHandles_u64_VkRenderPass(&cgen_var_96, (VkRenderPass*)&forUnmarshaling->renderPass, 1);
     vkStream->read((uint32_t*)&forUnmarshaling->subpass, sizeof(uint32_t));
-    uint64_t cgen_var_83;
-    vkStream->read((uint64_t*)&cgen_var_83, 1 * 8);
-    vkStream->handleMapping()->mapHandles_u64_VkPipeline(&cgen_var_83, (VkPipeline*)&forUnmarshaling->basePipelineHandle, 1);
+    uint64_t cgen_var_97;
+    vkStream->read((uint64_t*)&cgen_var_97, 1 * 8);
+    vkStream->handleMapping()->mapHandles_u64_VkPipeline(&cgen_var_97, (VkPipeline*)&forUnmarshaling->basePipelineHandle, 1);
     vkStream->read((int32_t*)&forUnmarshaling->basePipelineIndex, sizeof(int32_t));
 }
 
@@ -2721,12 +2909,12 @@
     }
     vkStream->write((VkPipelineCreateFlags*)&forMarshaling->flags, sizeof(VkPipelineCreateFlags));
     marshal_VkPipelineShaderStageCreateInfo(vkStream, (VkPipelineShaderStageCreateInfo*)(&forMarshaling->stage));
-    uint64_t cgen_var_84;
-    vkStream->handleMapping()->mapHandles_VkPipelineLayout_u64(&forMarshaling->layout, &cgen_var_84, 1);
-    vkStream->write((uint64_t*)&cgen_var_84, 1 * 8);
-    uint64_t cgen_var_85;
-    vkStream->handleMapping()->mapHandles_VkPipeline_u64(&forMarshaling->basePipelineHandle, &cgen_var_85, 1);
-    vkStream->write((uint64_t*)&cgen_var_85, 1 * 8);
+    uint64_t cgen_var_98;
+    vkStream->handleMapping()->mapHandles_VkPipelineLayout_u64(&forMarshaling->layout, &cgen_var_98, 1);
+    vkStream->write((uint64_t*)&cgen_var_98, 1 * 8);
+    uint64_t cgen_var_99;
+    vkStream->handleMapping()->mapHandles_VkPipeline_u64(&forMarshaling->basePipelineHandle, &cgen_var_99, 1);
+    vkStream->write((uint64_t*)&cgen_var_99, 1 * 8);
     vkStream->write((int32_t*)&forMarshaling->basePipelineIndex, sizeof(int32_t));
 }
 
@@ -2745,12 +2933,12 @@
     }
     vkStream->read((VkPipelineCreateFlags*)&forUnmarshaling->flags, sizeof(VkPipelineCreateFlags));
     unmarshal_VkPipelineShaderStageCreateInfo(vkStream, (VkPipelineShaderStageCreateInfo*)(&forUnmarshaling->stage));
-    uint64_t cgen_var_86;
-    vkStream->read((uint64_t*)&cgen_var_86, 1 * 8);
-    vkStream->handleMapping()->mapHandles_u64_VkPipelineLayout(&cgen_var_86, (VkPipelineLayout*)&forUnmarshaling->layout, 1);
-    uint64_t cgen_var_87;
-    vkStream->read((uint64_t*)&cgen_var_87, 1 * 8);
-    vkStream->handleMapping()->mapHandles_u64_VkPipeline(&cgen_var_87, (VkPipeline*)&forUnmarshaling->basePipelineHandle, 1);
+    uint64_t cgen_var_100;
+    vkStream->read((uint64_t*)&cgen_var_100, 1 * 8);
+    vkStream->handleMapping()->mapHandles_u64_VkPipelineLayout(&cgen_var_100, (VkPipelineLayout*)&forUnmarshaling->layout, 1);
+    uint64_t cgen_var_101;
+    vkStream->read((uint64_t*)&cgen_var_101, 1 * 8);
+    vkStream->handleMapping()->mapHandles_u64_VkPipeline(&cgen_var_101, (VkPipeline*)&forUnmarshaling->basePipelineHandle, 1);
     vkStream->read((int32_t*)&forUnmarshaling->basePipelineIndex, sizeof(int32_t));
 }
 
@@ -2788,10 +2976,10 @@
     vkStream->write((uint32_t*)&forMarshaling->setLayoutCount, sizeof(uint32_t));
     if (forMarshaling->setLayoutCount)
     {
-        uint64_t* cgen_var_88;
-        vkStream->alloc((void**)&cgen_var_88, forMarshaling->setLayoutCount * 8);
-        vkStream->handleMapping()->mapHandles_VkDescriptorSetLayout_u64(forMarshaling->pSetLayouts, cgen_var_88, forMarshaling->setLayoutCount);
-        vkStream->write((uint64_t*)cgen_var_88, forMarshaling->setLayoutCount * 8);
+        uint64_t* cgen_var_102;
+        vkStream->alloc((void**)&cgen_var_102, forMarshaling->setLayoutCount * 8);
+        vkStream->handleMapping()->mapHandles_VkDescriptorSetLayout_u64(forMarshaling->pSetLayouts, cgen_var_102, forMarshaling->setLayoutCount);
+        vkStream->write((uint64_t*)cgen_var_102, forMarshaling->setLayoutCount * 8);
     }
     vkStream->write((uint32_t*)&forMarshaling->pushConstantRangeCount, sizeof(uint32_t));
     for (uint32_t i = 0; i < (uint32_t)forMarshaling->pushConstantRangeCount; ++i)
@@ -2817,10 +3005,10 @@
     vkStream->read((uint32_t*)&forUnmarshaling->setLayoutCount, sizeof(uint32_t));
     if (forUnmarshaling->setLayoutCount)
     {
-        uint64_t* cgen_var_89;
-        vkStream->alloc((void**)&cgen_var_89, forUnmarshaling->setLayoutCount * 8);
-        vkStream->read((uint64_t*)cgen_var_89, forUnmarshaling->setLayoutCount * 8);
-        vkStream->handleMapping()->mapHandles_u64_VkDescriptorSetLayout(cgen_var_89, (VkDescriptorSetLayout*)forUnmarshaling->pSetLayouts, forUnmarshaling->setLayoutCount);
+        uint64_t* cgen_var_103;
+        vkStream->alloc((void**)&cgen_var_103, forUnmarshaling->setLayoutCount * 8);
+        vkStream->read((uint64_t*)cgen_var_103, forUnmarshaling->setLayoutCount * 8);
+        vkStream->handleMapping()->mapHandles_u64_VkDescriptorSetLayout(cgen_var_103, (VkDescriptorSetLayout*)forUnmarshaling->pSetLayouts, forUnmarshaling->setLayoutCount);
     }
     vkStream->read((uint32_t*)&forUnmarshaling->pushConstantRangeCount, sizeof(uint32_t));
     for (uint32_t i = 0; i < (uint32_t)forUnmarshaling->pushConstantRangeCount; ++i)
@@ -2899,16 +3087,16 @@
     vkStream->write((uint32_t*)&forMarshaling->descriptorCount, sizeof(uint32_t));
     vkStream->write((VkShaderStageFlags*)&forMarshaling->stageFlags, sizeof(VkShaderStageFlags));
     // WARNING PTR CHECK
-    uint64_t cgen_var_90 = (uint64_t)(uintptr_t)forMarshaling->pImmutableSamplers;
-    vkStream->putBe64(cgen_var_90);
+    uint64_t cgen_var_104 = (uint64_t)(uintptr_t)forMarshaling->pImmutableSamplers;
+    vkStream->putBe64(cgen_var_104);
     if (forMarshaling->pImmutableSamplers)
     {
         if (forMarshaling->descriptorCount)
         {
-            uint64_t* cgen_var_91;
-            vkStream->alloc((void**)&cgen_var_91, forMarshaling->descriptorCount * 8);
-            vkStream->handleMapping()->mapHandles_VkSampler_u64(forMarshaling->pImmutableSamplers, cgen_var_91, forMarshaling->descriptorCount);
-            vkStream->write((uint64_t*)cgen_var_91, forMarshaling->descriptorCount * 8);
+            uint64_t* cgen_var_105;
+            vkStream->alloc((void**)&cgen_var_105, forMarshaling->descriptorCount * 8);
+            vkStream->handleMapping()->mapHandles_VkSampler_u64(forMarshaling->pImmutableSamplers, cgen_var_105, forMarshaling->descriptorCount);
+            vkStream->write((uint64_t*)cgen_var_105, forMarshaling->descriptorCount * 8);
         }
     }
 }
@@ -2932,10 +3120,10 @@
         }
         if (forUnmarshaling->descriptorCount)
         {
-            uint64_t* cgen_var_93;
-            vkStream->alloc((void**)&cgen_var_93, forUnmarshaling->descriptorCount * 8);
-            vkStream->read((uint64_t*)cgen_var_93, forUnmarshaling->descriptorCount * 8);
-            vkStream->handleMapping()->mapHandles_u64_VkSampler(cgen_var_93, (VkSampler*)forUnmarshaling->pImmutableSamplers, forUnmarshaling->descriptorCount);
+            uint64_t* cgen_var_107;
+            vkStream->alloc((void**)&cgen_var_107, forUnmarshaling->descriptorCount * 8);
+            vkStream->read((uint64_t*)cgen_var_107, forUnmarshaling->descriptorCount * 8);
+            vkStream->handleMapping()->mapHandles_u64_VkSampler(cgen_var_107, (VkSampler*)forUnmarshaling->pImmutableSamplers, forUnmarshaling->descriptorCount);
         }
     }
 }
@@ -3052,16 +3240,16 @@
         vkStream->write((const void*)forMarshaling->pNext, sizeof(VkStructureType));
         marshal_extension_struct(vkStream, forMarshaling->pNext);
     }
-    uint64_t cgen_var_94;
-    vkStream->handleMapping()->mapHandles_VkDescriptorPool_u64(&forMarshaling->descriptorPool, &cgen_var_94, 1);
-    vkStream->write((uint64_t*)&cgen_var_94, 1 * 8);
+    uint64_t cgen_var_108;
+    vkStream->handleMapping()->mapHandles_VkDescriptorPool_u64(&forMarshaling->descriptorPool, &cgen_var_108, 1);
+    vkStream->write((uint64_t*)&cgen_var_108, 1 * 8);
     vkStream->write((uint32_t*)&forMarshaling->descriptorSetCount, sizeof(uint32_t));
     if (forMarshaling->descriptorSetCount)
     {
-        uint64_t* cgen_var_95;
-        vkStream->alloc((void**)&cgen_var_95, forMarshaling->descriptorSetCount * 8);
-        vkStream->handleMapping()->mapHandles_VkDescriptorSetLayout_u64(forMarshaling->pSetLayouts, cgen_var_95, forMarshaling->descriptorSetCount);
-        vkStream->write((uint64_t*)cgen_var_95, forMarshaling->descriptorSetCount * 8);
+        uint64_t* cgen_var_109;
+        vkStream->alloc((void**)&cgen_var_109, forMarshaling->descriptorSetCount * 8);
+        vkStream->handleMapping()->mapHandles_VkDescriptorSetLayout_u64(forMarshaling->pSetLayouts, cgen_var_109, forMarshaling->descriptorSetCount);
+        vkStream->write((uint64_t*)cgen_var_109, forMarshaling->descriptorSetCount * 8);
     }
 }
 
@@ -3078,16 +3266,16 @@
         vkStream->read((void*)(&pNext_placeholder), sizeof(VkStructureType));
         unmarshal_extension_struct(vkStream, (void*)(forUnmarshaling->pNext));
     }
-    uint64_t cgen_var_96;
-    vkStream->read((uint64_t*)&cgen_var_96, 1 * 8);
-    vkStream->handleMapping()->mapHandles_u64_VkDescriptorPool(&cgen_var_96, (VkDescriptorPool*)&forUnmarshaling->descriptorPool, 1);
+    uint64_t cgen_var_110;
+    vkStream->read((uint64_t*)&cgen_var_110, 1 * 8);
+    vkStream->handleMapping()->mapHandles_u64_VkDescriptorPool(&cgen_var_110, (VkDescriptorPool*)&forUnmarshaling->descriptorPool, 1);
     vkStream->read((uint32_t*)&forUnmarshaling->descriptorSetCount, sizeof(uint32_t));
     if (forUnmarshaling->descriptorSetCount)
     {
-        uint64_t* cgen_var_97;
-        vkStream->alloc((void**)&cgen_var_97, forUnmarshaling->descriptorSetCount * 8);
-        vkStream->read((uint64_t*)cgen_var_97, forUnmarshaling->descriptorSetCount * 8);
-        vkStream->handleMapping()->mapHandles_u64_VkDescriptorSetLayout(cgen_var_97, (VkDescriptorSetLayout*)forUnmarshaling->pSetLayouts, forUnmarshaling->descriptorSetCount);
+        uint64_t* cgen_var_111;
+        vkStream->alloc((void**)&cgen_var_111, forUnmarshaling->descriptorSetCount * 8);
+        vkStream->read((uint64_t*)cgen_var_111, forUnmarshaling->descriptorSetCount * 8);
+        vkStream->handleMapping()->mapHandles_u64_VkDescriptorSetLayout(cgen_var_111, (VkDescriptorSetLayout*)forUnmarshaling->pSetLayouts, forUnmarshaling->descriptorSetCount);
     }
 }
 
@@ -3095,12 +3283,12 @@
     VulkanStreamGuest* vkStream,
     const VkDescriptorImageInfo* forMarshaling)
 {
-    uint64_t cgen_var_98;
-    vkStream->handleMapping()->mapHandles_VkSampler_u64(&forMarshaling->sampler, &cgen_var_98, 1);
-    vkStream->write((uint64_t*)&cgen_var_98, 1 * 8);
-    uint64_t cgen_var_99;
-    vkStream->handleMapping()->mapHandles_VkImageView_u64(&forMarshaling->imageView, &cgen_var_99, 1);
-    vkStream->write((uint64_t*)&cgen_var_99, 1 * 8);
+    uint64_t cgen_var_112;
+    vkStream->handleMapping()->mapHandles_VkSampler_u64(&forMarshaling->sampler, &cgen_var_112, 1);
+    vkStream->write((uint64_t*)&cgen_var_112, 1 * 8);
+    uint64_t cgen_var_113;
+    vkStream->handleMapping()->mapHandles_VkImageView_u64(&forMarshaling->imageView, &cgen_var_113, 1);
+    vkStream->write((uint64_t*)&cgen_var_113, 1 * 8);
     vkStream->write((VkImageLayout*)&forMarshaling->imageLayout, sizeof(VkImageLayout));
 }
 
@@ -3108,12 +3296,12 @@
     VulkanStreamGuest* vkStream,
     VkDescriptorImageInfo* forUnmarshaling)
 {
-    uint64_t cgen_var_100;
-    vkStream->read((uint64_t*)&cgen_var_100, 1 * 8);
-    vkStream->handleMapping()->mapHandles_u64_VkSampler(&cgen_var_100, (VkSampler*)&forUnmarshaling->sampler, 1);
-    uint64_t cgen_var_101;
-    vkStream->read((uint64_t*)&cgen_var_101, 1 * 8);
-    vkStream->handleMapping()->mapHandles_u64_VkImageView(&cgen_var_101, (VkImageView*)&forUnmarshaling->imageView, 1);
+    uint64_t cgen_var_114;
+    vkStream->read((uint64_t*)&cgen_var_114, 1 * 8);
+    vkStream->handleMapping()->mapHandles_u64_VkSampler(&cgen_var_114, (VkSampler*)&forUnmarshaling->sampler, 1);
+    uint64_t cgen_var_115;
+    vkStream->read((uint64_t*)&cgen_var_115, 1 * 8);
+    vkStream->handleMapping()->mapHandles_u64_VkImageView(&cgen_var_115, (VkImageView*)&forUnmarshaling->imageView, 1);
     vkStream->read((VkImageLayout*)&forUnmarshaling->imageLayout, sizeof(VkImageLayout));
 }
 
@@ -3121,9 +3309,9 @@
     VulkanStreamGuest* vkStream,
     const VkDescriptorBufferInfo* forMarshaling)
 {
-    uint64_t cgen_var_102;
-    vkStream->handleMapping()->mapHandles_VkBuffer_u64(&forMarshaling->buffer, &cgen_var_102, 1);
-    vkStream->write((uint64_t*)&cgen_var_102, 1 * 8);
+    uint64_t cgen_var_116;
+    vkStream->handleMapping()->mapHandles_VkBuffer_u64(&forMarshaling->buffer, &cgen_var_116, 1);
+    vkStream->write((uint64_t*)&cgen_var_116, 1 * 8);
     vkStream->write((VkDeviceSize*)&forMarshaling->offset, sizeof(VkDeviceSize));
     vkStream->write((VkDeviceSize*)&forMarshaling->range, sizeof(VkDeviceSize));
 }
@@ -3132,9 +3320,9 @@
     VulkanStreamGuest* vkStream,
     VkDescriptorBufferInfo* forUnmarshaling)
 {
-    uint64_t cgen_var_103;
-    vkStream->read((uint64_t*)&cgen_var_103, 1 * 8);
-    vkStream->handleMapping()->mapHandles_u64_VkBuffer(&cgen_var_103, (VkBuffer*)&forUnmarshaling->buffer, 1);
+    uint64_t cgen_var_117;
+    vkStream->read((uint64_t*)&cgen_var_117, 1 * 8);
+    vkStream->handleMapping()->mapHandles_u64_VkBuffer(&cgen_var_117, (VkBuffer*)&forUnmarshaling->buffer, 1);
     vkStream->read((VkDeviceSize*)&forUnmarshaling->offset, sizeof(VkDeviceSize));
     vkStream->read((VkDeviceSize*)&forUnmarshaling->range, sizeof(VkDeviceSize));
 }
@@ -3151,44 +3339,53 @@
         vkStream->write((const void*)forMarshaling->pNext, sizeof(VkStructureType));
         marshal_extension_struct(vkStream, forMarshaling->pNext);
     }
-    uint64_t cgen_var_104;
-    vkStream->handleMapping()->mapHandles_VkDescriptorSet_u64(&forMarshaling->dstSet, &cgen_var_104, 1);
-    vkStream->write((uint64_t*)&cgen_var_104, 1 * 8);
+    uint64_t cgen_var_118;
+    vkStream->handleMapping()->mapHandles_VkDescriptorSet_u64(&forMarshaling->dstSet, &cgen_var_118, 1);
+    vkStream->write((uint64_t*)&cgen_var_118, 1 * 8);
     vkStream->write((uint32_t*)&forMarshaling->dstBinding, sizeof(uint32_t));
     vkStream->write((uint32_t*)&forMarshaling->dstArrayElement, sizeof(uint32_t));
     vkStream->write((uint32_t*)&forMarshaling->descriptorCount, sizeof(uint32_t));
     vkStream->write((VkDescriptorType*)&forMarshaling->descriptorType, sizeof(VkDescriptorType));
     // WARNING PTR CHECK
-    uint64_t cgen_var_105 = (uint64_t)(uintptr_t)forMarshaling->pImageInfo;
-    vkStream->putBe64(cgen_var_105);
+    uint64_t cgen_var_119 = (uint64_t)(uintptr_t)forMarshaling->pImageInfo;
+    vkStream->putBe64(cgen_var_119);
     if (forMarshaling->pImageInfo)
     {
-        for (uint32_t i = 0; i < (uint32_t)forMarshaling->descriptorCount; ++i)
+        if ((!(vkStream->getFeatureBits() & VULKAN_STREAM_FEATURE_IGNORED_HANDLES_BIT) || ((VK_DESCRIPTOR_TYPE_SAMPLER == forMarshaling->descriptorType) || (VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER == forMarshaling->descriptorType) || (VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE == forMarshaling->descriptorType) || (VK_DESCRIPTOR_TYPE_STORAGE_IMAGE == forMarshaling->descriptorType) || (VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT == forMarshaling->descriptorType))))
         {
-            marshal_VkDescriptorImageInfo(vkStream, (const VkDescriptorImageInfo*)(forMarshaling->pImageInfo + i));
+            for (uint32_t i = 0; i < (uint32_t)forMarshaling->descriptorCount; ++i)
+            {
+                marshal_VkDescriptorImageInfo(vkStream, (const VkDescriptorImageInfo*)(forMarshaling->pImageInfo + i));
+            }
         }
     }
     // WARNING PTR CHECK
-    uint64_t cgen_var_106 = (uint64_t)(uintptr_t)forMarshaling->pBufferInfo;
-    vkStream->putBe64(cgen_var_106);
+    uint64_t cgen_var_120 = (uint64_t)(uintptr_t)forMarshaling->pBufferInfo;
+    vkStream->putBe64(cgen_var_120);
     if (forMarshaling->pBufferInfo)
     {
-        for (uint32_t i = 0; i < (uint32_t)forMarshaling->descriptorCount; ++i)
+        if ((!(vkStream->getFeatureBits() & VULKAN_STREAM_FEATURE_IGNORED_HANDLES_BIT) || ((VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER == forMarshaling->descriptorType) || (VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC == forMarshaling->descriptorType) || (VK_DESCRIPTOR_TYPE_STORAGE_BUFFER == forMarshaling->descriptorType) || (VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC == forMarshaling->descriptorType))))
         {
-            marshal_VkDescriptorBufferInfo(vkStream, (const VkDescriptorBufferInfo*)(forMarshaling->pBufferInfo + i));
+            for (uint32_t i = 0; i < (uint32_t)forMarshaling->descriptorCount; ++i)
+            {
+                marshal_VkDescriptorBufferInfo(vkStream, (const VkDescriptorBufferInfo*)(forMarshaling->pBufferInfo + i));
+            }
         }
     }
     // WARNING PTR CHECK
-    uint64_t cgen_var_107 = (uint64_t)(uintptr_t)forMarshaling->pTexelBufferView;
-    vkStream->putBe64(cgen_var_107);
+    uint64_t cgen_var_121 = (uint64_t)(uintptr_t)forMarshaling->pTexelBufferView;
+    vkStream->putBe64(cgen_var_121);
     if (forMarshaling->pTexelBufferView)
     {
-        if (forMarshaling->descriptorCount)
+        if ((!(vkStream->getFeatureBits() & VULKAN_STREAM_FEATURE_IGNORED_HANDLES_BIT) || ((VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER == forMarshaling->descriptorType) || (VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER == forMarshaling->descriptorType))))
         {
-            uint64_t* cgen_var_108;
-            vkStream->alloc((void**)&cgen_var_108, forMarshaling->descriptorCount * 8);
-            vkStream->handleMapping()->mapHandles_VkBufferView_u64(forMarshaling->pTexelBufferView, cgen_var_108, forMarshaling->descriptorCount);
-            vkStream->write((uint64_t*)cgen_var_108, forMarshaling->descriptorCount * 8);
+            if (forMarshaling->descriptorCount)
+            {
+                uint64_t* cgen_var_122;
+                vkStream->alloc((void**)&cgen_var_122, forMarshaling->descriptorCount * 8);
+                vkStream->handleMapping()->mapHandles_VkBufferView_u64(forMarshaling->pTexelBufferView, cgen_var_122, forMarshaling->descriptorCount);
+                vkStream->write((uint64_t*)cgen_var_122, forMarshaling->descriptorCount * 8);
+            }
         }
     }
 }
@@ -3206,9 +3403,9 @@
         vkStream->read((void*)(&pNext_placeholder), sizeof(VkStructureType));
         unmarshal_extension_struct(vkStream, (void*)(forUnmarshaling->pNext));
     }
-    uint64_t cgen_var_109;
-    vkStream->read((uint64_t*)&cgen_var_109, 1 * 8);
-    vkStream->handleMapping()->mapHandles_u64_VkDescriptorSet(&cgen_var_109, (VkDescriptorSet*)&forUnmarshaling->dstSet, 1);
+    uint64_t cgen_var_123;
+    vkStream->read((uint64_t*)&cgen_var_123, 1 * 8);
+    vkStream->handleMapping()->mapHandles_u64_VkDescriptorSet(&cgen_var_123, (VkDescriptorSet*)&forUnmarshaling->dstSet, 1);
     vkStream->read((uint32_t*)&forUnmarshaling->dstBinding, sizeof(uint32_t));
     vkStream->read((uint32_t*)&forUnmarshaling->dstArrayElement, sizeof(uint32_t));
     vkStream->read((uint32_t*)&forUnmarshaling->descriptorCount, sizeof(uint32_t));
@@ -3222,9 +3419,16 @@
         {
             fprintf(stderr, "fatal: forUnmarshaling->pImageInfo inconsistent between guest and host\n");
         }
-        for (uint32_t i = 0; i < (uint32_t)forUnmarshaling->descriptorCount; ++i)
+        if ((!(vkStream->getFeatureBits() & VULKAN_STREAM_FEATURE_IGNORED_HANDLES_BIT) || ((VK_DESCRIPTOR_TYPE_SAMPLER == forUnmarshaling->descriptorType) || (VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER == forUnmarshaling->descriptorType) || (VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE == forUnmarshaling->descriptorType) || (VK_DESCRIPTOR_TYPE_STORAGE_IMAGE == forUnmarshaling->descriptorType) || (VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT == forUnmarshaling->descriptorType))))
         {
-            unmarshal_VkDescriptorImageInfo(vkStream, (VkDescriptorImageInfo*)(forUnmarshaling->pImageInfo + i));
+            for (uint32_t i = 0; i < (uint32_t)forUnmarshaling->descriptorCount; ++i)
+            {
+                unmarshal_VkDescriptorImageInfo(vkStream, (VkDescriptorImageInfo*)(forUnmarshaling->pImageInfo + i));
+            }
+        }
+        else
+        {
+            forUnmarshaling->pImageInfo = 0;
         }
     }
     // WARNING PTR CHECK
@@ -3236,9 +3440,16 @@
         {
             fprintf(stderr, "fatal: forUnmarshaling->pBufferInfo inconsistent between guest and host\n");
         }
-        for (uint32_t i = 0; i < (uint32_t)forUnmarshaling->descriptorCount; ++i)
+        if ((!(vkStream->getFeatureBits() & VULKAN_STREAM_FEATURE_IGNORED_HANDLES_BIT) || ((VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER == forUnmarshaling->descriptorType) || (VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC == forUnmarshaling->descriptorType) || (VK_DESCRIPTOR_TYPE_STORAGE_BUFFER == forUnmarshaling->descriptorType) || (VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC == forUnmarshaling->descriptorType))))
         {
-            unmarshal_VkDescriptorBufferInfo(vkStream, (VkDescriptorBufferInfo*)(forUnmarshaling->pBufferInfo + i));
+            for (uint32_t i = 0; i < (uint32_t)forUnmarshaling->descriptorCount; ++i)
+            {
+                unmarshal_VkDescriptorBufferInfo(vkStream, (VkDescriptorBufferInfo*)(forUnmarshaling->pBufferInfo + i));
+            }
+        }
+        else
+        {
+            forUnmarshaling->pBufferInfo = 0;
         }
     }
     // WARNING PTR CHECK
@@ -3250,12 +3461,19 @@
         {
             fprintf(stderr, "fatal: forUnmarshaling->pTexelBufferView inconsistent between guest and host\n");
         }
-        if (forUnmarshaling->descriptorCount)
+        if ((!(vkStream->getFeatureBits() & VULKAN_STREAM_FEATURE_IGNORED_HANDLES_BIT) || ((VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER == forUnmarshaling->descriptorType) || (VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER == forUnmarshaling->descriptorType))))
         {
-            uint64_t* cgen_var_113;
-            vkStream->alloc((void**)&cgen_var_113, forUnmarshaling->descriptorCount * 8);
-            vkStream->read((uint64_t*)cgen_var_113, forUnmarshaling->descriptorCount * 8);
-            vkStream->handleMapping()->mapHandles_u64_VkBufferView(cgen_var_113, (VkBufferView*)forUnmarshaling->pTexelBufferView, forUnmarshaling->descriptorCount);
+            if (forUnmarshaling->descriptorCount)
+            {
+                uint64_t* cgen_var_127;
+                vkStream->alloc((void**)&cgen_var_127, forUnmarshaling->descriptorCount * 8);
+                vkStream->read((uint64_t*)cgen_var_127, forUnmarshaling->descriptorCount * 8);
+                vkStream->handleMapping()->mapHandles_u64_VkBufferView(cgen_var_127, (VkBufferView*)forUnmarshaling->pTexelBufferView, forUnmarshaling->descriptorCount);
+            }
+        }
+        else
+        {
+            forUnmarshaling->pTexelBufferView = 0;
         }
     }
 }
@@ -3272,14 +3490,14 @@
         vkStream->write((const void*)forMarshaling->pNext, sizeof(VkStructureType));
         marshal_extension_struct(vkStream, forMarshaling->pNext);
     }
-    uint64_t cgen_var_114;
-    vkStream->handleMapping()->mapHandles_VkDescriptorSet_u64(&forMarshaling->srcSet, &cgen_var_114, 1);
-    vkStream->write((uint64_t*)&cgen_var_114, 1 * 8);
+    uint64_t cgen_var_128;
+    vkStream->handleMapping()->mapHandles_VkDescriptorSet_u64(&forMarshaling->srcSet, &cgen_var_128, 1);
+    vkStream->write((uint64_t*)&cgen_var_128, 1 * 8);
     vkStream->write((uint32_t*)&forMarshaling->srcBinding, sizeof(uint32_t));
     vkStream->write((uint32_t*)&forMarshaling->srcArrayElement, sizeof(uint32_t));
-    uint64_t cgen_var_115;
-    vkStream->handleMapping()->mapHandles_VkDescriptorSet_u64(&forMarshaling->dstSet, &cgen_var_115, 1);
-    vkStream->write((uint64_t*)&cgen_var_115, 1 * 8);
+    uint64_t cgen_var_129;
+    vkStream->handleMapping()->mapHandles_VkDescriptorSet_u64(&forMarshaling->dstSet, &cgen_var_129, 1);
+    vkStream->write((uint64_t*)&cgen_var_129, 1 * 8);
     vkStream->write((uint32_t*)&forMarshaling->dstBinding, sizeof(uint32_t));
     vkStream->write((uint32_t*)&forMarshaling->dstArrayElement, sizeof(uint32_t));
     vkStream->write((uint32_t*)&forMarshaling->descriptorCount, sizeof(uint32_t));
@@ -3298,14 +3516,14 @@
         vkStream->read((void*)(&pNext_placeholder), sizeof(VkStructureType));
         unmarshal_extension_struct(vkStream, (void*)(forUnmarshaling->pNext));
     }
-    uint64_t cgen_var_116;
-    vkStream->read((uint64_t*)&cgen_var_116, 1 * 8);
-    vkStream->handleMapping()->mapHandles_u64_VkDescriptorSet(&cgen_var_116, (VkDescriptorSet*)&forUnmarshaling->srcSet, 1);
+    uint64_t cgen_var_130;
+    vkStream->read((uint64_t*)&cgen_var_130, 1 * 8);
+    vkStream->handleMapping()->mapHandles_u64_VkDescriptorSet(&cgen_var_130, (VkDescriptorSet*)&forUnmarshaling->srcSet, 1);
     vkStream->read((uint32_t*)&forUnmarshaling->srcBinding, sizeof(uint32_t));
     vkStream->read((uint32_t*)&forUnmarshaling->srcArrayElement, sizeof(uint32_t));
-    uint64_t cgen_var_117;
-    vkStream->read((uint64_t*)&cgen_var_117, 1 * 8);
-    vkStream->handleMapping()->mapHandles_u64_VkDescriptorSet(&cgen_var_117, (VkDescriptorSet*)&forUnmarshaling->dstSet, 1);
+    uint64_t cgen_var_131;
+    vkStream->read((uint64_t*)&cgen_var_131, 1 * 8);
+    vkStream->handleMapping()->mapHandles_u64_VkDescriptorSet(&cgen_var_131, (VkDescriptorSet*)&forUnmarshaling->dstSet, 1);
     vkStream->read((uint32_t*)&forUnmarshaling->dstBinding, sizeof(uint32_t));
     vkStream->read((uint32_t*)&forUnmarshaling->dstArrayElement, sizeof(uint32_t));
     vkStream->read((uint32_t*)&forUnmarshaling->descriptorCount, sizeof(uint32_t));
@@ -3324,16 +3542,16 @@
         marshal_extension_struct(vkStream, forMarshaling->pNext);
     }
     vkStream->write((VkFramebufferCreateFlags*)&forMarshaling->flags, sizeof(VkFramebufferCreateFlags));
-    uint64_t cgen_var_118;
-    vkStream->handleMapping()->mapHandles_VkRenderPass_u64(&forMarshaling->renderPass, &cgen_var_118, 1);
-    vkStream->write((uint64_t*)&cgen_var_118, 1 * 8);
+    uint64_t cgen_var_132;
+    vkStream->handleMapping()->mapHandles_VkRenderPass_u64(&forMarshaling->renderPass, &cgen_var_132, 1);
+    vkStream->write((uint64_t*)&cgen_var_132, 1 * 8);
     vkStream->write((uint32_t*)&forMarshaling->attachmentCount, sizeof(uint32_t));
     if (forMarshaling->attachmentCount)
     {
-        uint64_t* cgen_var_119;
-        vkStream->alloc((void**)&cgen_var_119, forMarshaling->attachmentCount * 8);
-        vkStream->handleMapping()->mapHandles_VkImageView_u64(forMarshaling->pAttachments, cgen_var_119, forMarshaling->attachmentCount);
-        vkStream->write((uint64_t*)cgen_var_119, forMarshaling->attachmentCount * 8);
+        uint64_t* cgen_var_133;
+        vkStream->alloc((void**)&cgen_var_133, forMarshaling->attachmentCount * 8);
+        vkStream->handleMapping()->mapHandles_VkImageView_u64(forMarshaling->pAttachments, cgen_var_133, forMarshaling->attachmentCount);
+        vkStream->write((uint64_t*)cgen_var_133, forMarshaling->attachmentCount * 8);
     }
     vkStream->write((uint32_t*)&forMarshaling->width, sizeof(uint32_t));
     vkStream->write((uint32_t*)&forMarshaling->height, sizeof(uint32_t));
@@ -3354,16 +3572,16 @@
         unmarshal_extension_struct(vkStream, (void*)(forUnmarshaling->pNext));
     }
     vkStream->read((VkFramebufferCreateFlags*)&forUnmarshaling->flags, sizeof(VkFramebufferCreateFlags));
-    uint64_t cgen_var_120;
-    vkStream->read((uint64_t*)&cgen_var_120, 1 * 8);
-    vkStream->handleMapping()->mapHandles_u64_VkRenderPass(&cgen_var_120, (VkRenderPass*)&forUnmarshaling->renderPass, 1);
+    uint64_t cgen_var_134;
+    vkStream->read((uint64_t*)&cgen_var_134, 1 * 8);
+    vkStream->handleMapping()->mapHandles_u64_VkRenderPass(&cgen_var_134, (VkRenderPass*)&forUnmarshaling->renderPass, 1);
     vkStream->read((uint32_t*)&forUnmarshaling->attachmentCount, sizeof(uint32_t));
     if (forUnmarshaling->attachmentCount)
     {
-        uint64_t* cgen_var_121;
-        vkStream->alloc((void**)&cgen_var_121, forUnmarshaling->attachmentCount * 8);
-        vkStream->read((uint64_t*)cgen_var_121, forUnmarshaling->attachmentCount * 8);
-        vkStream->handleMapping()->mapHandles_u64_VkImageView(cgen_var_121, (VkImageView*)forUnmarshaling->pAttachments, forUnmarshaling->attachmentCount);
+        uint64_t* cgen_var_135;
+        vkStream->alloc((void**)&cgen_var_135, forUnmarshaling->attachmentCount * 8);
+        vkStream->read((uint64_t*)cgen_var_135, forUnmarshaling->attachmentCount * 8);
+        vkStream->handleMapping()->mapHandles_u64_VkImageView(cgen_var_135, (VkImageView*)forUnmarshaling->pAttachments, forUnmarshaling->attachmentCount);
     }
     vkStream->read((uint32_t*)&forUnmarshaling->width, sizeof(uint32_t));
     vkStream->read((uint32_t*)&forUnmarshaling->height, sizeof(uint32_t));
@@ -3433,8 +3651,8 @@
         marshal_VkAttachmentReference(vkStream, (const VkAttachmentReference*)(forMarshaling->pColorAttachments + i));
     }
     // WARNING PTR CHECK
-    uint64_t cgen_var_122 = (uint64_t)(uintptr_t)forMarshaling->pResolveAttachments;
-    vkStream->putBe64(cgen_var_122);
+    uint64_t cgen_var_136 = (uint64_t)(uintptr_t)forMarshaling->pResolveAttachments;
+    vkStream->putBe64(cgen_var_136);
     if (forMarshaling->pResolveAttachments)
     {
         for (uint32_t i = 0; i < (uint32_t)forMarshaling->colorAttachmentCount; ++i)
@@ -3443,8 +3661,8 @@
         }
     }
     // WARNING PTR CHECK
-    uint64_t cgen_var_123 = (uint64_t)(uintptr_t)forMarshaling->pDepthStencilAttachment;
-    vkStream->putBe64(cgen_var_123);
+    uint64_t cgen_var_137 = (uint64_t)(uintptr_t)forMarshaling->pDepthStencilAttachment;
+    vkStream->putBe64(cgen_var_137);
     if (forMarshaling->pDepthStencilAttachment)
     {
         marshal_VkAttachmentReference(vkStream, (const VkAttachmentReference*)(forMarshaling->pDepthStencilAttachment));
@@ -3630,9 +3848,9 @@
         vkStream->write((const void*)forMarshaling->pNext, sizeof(VkStructureType));
         marshal_extension_struct(vkStream, forMarshaling->pNext);
     }
-    uint64_t cgen_var_126;
-    vkStream->handleMapping()->mapHandles_VkCommandPool_u64(&forMarshaling->commandPool, &cgen_var_126, 1);
-    vkStream->write((uint64_t*)&cgen_var_126, 1 * 8);
+    uint64_t cgen_var_140;
+    vkStream->handleMapping()->mapHandles_VkCommandPool_u64(&forMarshaling->commandPool, &cgen_var_140, 1);
+    vkStream->write((uint64_t*)&cgen_var_140, 1 * 8);
     vkStream->write((VkCommandBufferLevel*)&forMarshaling->level, sizeof(VkCommandBufferLevel));
     vkStream->write((uint32_t*)&forMarshaling->commandBufferCount, sizeof(uint32_t));
 }
@@ -3650,9 +3868,9 @@
         vkStream->read((void*)(&pNext_placeholder), sizeof(VkStructureType));
         unmarshal_extension_struct(vkStream, (void*)(forUnmarshaling->pNext));
     }
-    uint64_t cgen_var_127;
-    vkStream->read((uint64_t*)&cgen_var_127, 1 * 8);
-    vkStream->handleMapping()->mapHandles_u64_VkCommandPool(&cgen_var_127, (VkCommandPool*)&forUnmarshaling->commandPool, 1);
+    uint64_t cgen_var_141;
+    vkStream->read((uint64_t*)&cgen_var_141, 1 * 8);
+    vkStream->handleMapping()->mapHandles_u64_VkCommandPool(&cgen_var_141, (VkCommandPool*)&forUnmarshaling->commandPool, 1);
     vkStream->read((VkCommandBufferLevel*)&forUnmarshaling->level, sizeof(VkCommandBufferLevel));
     vkStream->read((uint32_t*)&forUnmarshaling->commandBufferCount, sizeof(uint32_t));
 }
@@ -3669,13 +3887,13 @@
         vkStream->write((const void*)forMarshaling->pNext, sizeof(VkStructureType));
         marshal_extension_struct(vkStream, forMarshaling->pNext);
     }
-    uint64_t cgen_var_128;
-    vkStream->handleMapping()->mapHandles_VkRenderPass_u64(&forMarshaling->renderPass, &cgen_var_128, 1);
-    vkStream->write((uint64_t*)&cgen_var_128, 1 * 8);
+    uint64_t cgen_var_142;
+    vkStream->handleMapping()->mapHandles_VkRenderPass_u64(&forMarshaling->renderPass, &cgen_var_142, 1);
+    vkStream->write((uint64_t*)&cgen_var_142, 1 * 8);
     vkStream->write((uint32_t*)&forMarshaling->subpass, sizeof(uint32_t));
-    uint64_t cgen_var_129;
-    vkStream->handleMapping()->mapHandles_VkFramebuffer_u64(&forMarshaling->framebuffer, &cgen_var_129, 1);
-    vkStream->write((uint64_t*)&cgen_var_129, 1 * 8);
+    uint64_t cgen_var_143;
+    vkStream->handleMapping()->mapHandles_VkFramebuffer_u64(&forMarshaling->framebuffer, &cgen_var_143, 1);
+    vkStream->write((uint64_t*)&cgen_var_143, 1 * 8);
     vkStream->write((VkBool32*)&forMarshaling->occlusionQueryEnable, sizeof(VkBool32));
     vkStream->write((VkQueryControlFlags*)&forMarshaling->queryFlags, sizeof(VkQueryControlFlags));
     vkStream->write((VkQueryPipelineStatisticFlags*)&forMarshaling->pipelineStatistics, sizeof(VkQueryPipelineStatisticFlags));
@@ -3694,13 +3912,13 @@
         vkStream->read((void*)(&pNext_placeholder), sizeof(VkStructureType));
         unmarshal_extension_struct(vkStream, (void*)(forUnmarshaling->pNext));
     }
-    uint64_t cgen_var_130;
-    vkStream->read((uint64_t*)&cgen_var_130, 1 * 8);
-    vkStream->handleMapping()->mapHandles_u64_VkRenderPass(&cgen_var_130, (VkRenderPass*)&forUnmarshaling->renderPass, 1);
+    uint64_t cgen_var_144;
+    vkStream->read((uint64_t*)&cgen_var_144, 1 * 8);
+    vkStream->handleMapping()->mapHandles_u64_VkRenderPass(&cgen_var_144, (VkRenderPass*)&forUnmarshaling->renderPass, 1);
     vkStream->read((uint32_t*)&forUnmarshaling->subpass, sizeof(uint32_t));
-    uint64_t cgen_var_131;
-    vkStream->read((uint64_t*)&cgen_var_131, 1 * 8);
-    vkStream->handleMapping()->mapHandles_u64_VkFramebuffer(&cgen_var_131, (VkFramebuffer*)&forUnmarshaling->framebuffer, 1);
+    uint64_t cgen_var_145;
+    vkStream->read((uint64_t*)&cgen_var_145, 1 * 8);
+    vkStream->handleMapping()->mapHandles_u64_VkFramebuffer(&cgen_var_145, (VkFramebuffer*)&forUnmarshaling->framebuffer, 1);
     vkStream->read((VkBool32*)&forUnmarshaling->occlusionQueryEnable, sizeof(VkBool32));
     vkStream->read((VkQueryControlFlags*)&forUnmarshaling->queryFlags, sizeof(VkQueryControlFlags));
     vkStream->read((VkQueryPipelineStatisticFlags*)&forUnmarshaling->pipelineStatistics, sizeof(VkQueryPipelineStatisticFlags));
@@ -3720,8 +3938,8 @@
     }
     vkStream->write((VkCommandBufferUsageFlags*)&forMarshaling->flags, sizeof(VkCommandBufferUsageFlags));
     // WARNING PTR CHECK
-    uint64_t cgen_var_132 = (uint64_t)(uintptr_t)forMarshaling->pInheritanceInfo;
-    vkStream->putBe64(cgen_var_132);
+    uint64_t cgen_var_146 = (uint64_t)(uintptr_t)forMarshaling->pInheritanceInfo;
+    vkStream->putBe64(cgen_var_146);
     if (forMarshaling->pInheritanceInfo)
     {
         marshal_VkCommandBufferInheritanceInfo(vkStream, (const VkCommandBufferInheritanceInfo*)(forMarshaling->pInheritanceInfo));
@@ -4022,9 +4240,9 @@
     vkStream->write((VkAccessFlags*)&forMarshaling->dstAccessMask, sizeof(VkAccessFlags));
     vkStream->write((uint32_t*)&forMarshaling->srcQueueFamilyIndex, sizeof(uint32_t));
     vkStream->write((uint32_t*)&forMarshaling->dstQueueFamilyIndex, sizeof(uint32_t));
-    uint64_t cgen_var_134;
-    vkStream->handleMapping()->mapHandles_VkBuffer_u64(&forMarshaling->buffer, &cgen_var_134, 1);
-    vkStream->write((uint64_t*)&cgen_var_134, 1 * 8);
+    uint64_t cgen_var_148;
+    vkStream->handleMapping()->mapHandles_VkBuffer_u64(&forMarshaling->buffer, &cgen_var_148, 1);
+    vkStream->write((uint64_t*)&cgen_var_148, 1 * 8);
     vkStream->write((VkDeviceSize*)&forMarshaling->offset, sizeof(VkDeviceSize));
     vkStream->write((VkDeviceSize*)&forMarshaling->size, sizeof(VkDeviceSize));
 }
@@ -4046,9 +4264,9 @@
     vkStream->read((VkAccessFlags*)&forUnmarshaling->dstAccessMask, sizeof(VkAccessFlags));
     vkStream->read((uint32_t*)&forUnmarshaling->srcQueueFamilyIndex, sizeof(uint32_t));
     vkStream->read((uint32_t*)&forUnmarshaling->dstQueueFamilyIndex, sizeof(uint32_t));
-    uint64_t cgen_var_135;
-    vkStream->read((uint64_t*)&cgen_var_135, 1 * 8);
-    vkStream->handleMapping()->mapHandles_u64_VkBuffer(&cgen_var_135, (VkBuffer*)&forUnmarshaling->buffer, 1);
+    uint64_t cgen_var_149;
+    vkStream->read((uint64_t*)&cgen_var_149, 1 * 8);
+    vkStream->handleMapping()->mapHandles_u64_VkBuffer(&cgen_var_149, (VkBuffer*)&forUnmarshaling->buffer, 1);
     vkStream->read((VkDeviceSize*)&forUnmarshaling->offset, sizeof(VkDeviceSize));
     vkStream->read((VkDeviceSize*)&forUnmarshaling->size, sizeof(VkDeviceSize));
 }
@@ -4071,9 +4289,9 @@
     vkStream->write((VkImageLayout*)&forMarshaling->newLayout, sizeof(VkImageLayout));
     vkStream->write((uint32_t*)&forMarshaling->srcQueueFamilyIndex, sizeof(uint32_t));
     vkStream->write((uint32_t*)&forMarshaling->dstQueueFamilyIndex, sizeof(uint32_t));
-    uint64_t cgen_var_136;
-    vkStream->handleMapping()->mapHandles_VkImage_u64(&forMarshaling->image, &cgen_var_136, 1);
-    vkStream->write((uint64_t*)&cgen_var_136, 1 * 8);
+    uint64_t cgen_var_150;
+    vkStream->handleMapping()->mapHandles_VkImage_u64(&forMarshaling->image, &cgen_var_150, 1);
+    vkStream->write((uint64_t*)&cgen_var_150, 1 * 8);
     marshal_VkImageSubresourceRange(vkStream, (VkImageSubresourceRange*)(&forMarshaling->subresourceRange));
 }
 
@@ -4096,9 +4314,9 @@
     vkStream->read((VkImageLayout*)&forUnmarshaling->newLayout, sizeof(VkImageLayout));
     vkStream->read((uint32_t*)&forUnmarshaling->srcQueueFamilyIndex, sizeof(uint32_t));
     vkStream->read((uint32_t*)&forUnmarshaling->dstQueueFamilyIndex, sizeof(uint32_t));
-    uint64_t cgen_var_137;
-    vkStream->read((uint64_t*)&cgen_var_137, 1 * 8);
-    vkStream->handleMapping()->mapHandles_u64_VkImage(&cgen_var_137, (VkImage*)&forUnmarshaling->image, 1);
+    uint64_t cgen_var_151;
+    vkStream->read((uint64_t*)&cgen_var_151, 1 * 8);
+    vkStream->handleMapping()->mapHandles_u64_VkImage(&cgen_var_151, (VkImage*)&forUnmarshaling->image, 1);
     unmarshal_VkImageSubresourceRange(vkStream, (VkImageSubresourceRange*)(&forUnmarshaling->subresourceRange));
 }
 
@@ -4114,17 +4332,17 @@
         vkStream->write((const void*)forMarshaling->pNext, sizeof(VkStructureType));
         marshal_extension_struct(vkStream, forMarshaling->pNext);
     }
-    uint64_t cgen_var_138;
-    vkStream->handleMapping()->mapHandles_VkRenderPass_u64(&forMarshaling->renderPass, &cgen_var_138, 1);
-    vkStream->write((uint64_t*)&cgen_var_138, 1 * 8);
-    uint64_t cgen_var_139;
-    vkStream->handleMapping()->mapHandles_VkFramebuffer_u64(&forMarshaling->framebuffer, &cgen_var_139, 1);
-    vkStream->write((uint64_t*)&cgen_var_139, 1 * 8);
+    uint64_t cgen_var_152;
+    vkStream->handleMapping()->mapHandles_VkRenderPass_u64(&forMarshaling->renderPass, &cgen_var_152, 1);
+    vkStream->write((uint64_t*)&cgen_var_152, 1 * 8);
+    uint64_t cgen_var_153;
+    vkStream->handleMapping()->mapHandles_VkFramebuffer_u64(&forMarshaling->framebuffer, &cgen_var_153, 1);
+    vkStream->write((uint64_t*)&cgen_var_153, 1 * 8);
     marshal_VkRect2D(vkStream, (VkRect2D*)(&forMarshaling->renderArea));
     vkStream->write((uint32_t*)&forMarshaling->clearValueCount, sizeof(uint32_t));
     // WARNING PTR CHECK
-    uint64_t cgen_var_140 = (uint64_t)(uintptr_t)forMarshaling->pClearValues;
-    vkStream->putBe64(cgen_var_140);
+    uint64_t cgen_var_154 = (uint64_t)(uintptr_t)forMarshaling->pClearValues;
+    vkStream->putBe64(cgen_var_154);
     if (forMarshaling->pClearValues)
     {
         for (uint32_t i = 0; i < (uint32_t)forMarshaling->clearValueCount; ++i)
@@ -4147,12 +4365,12 @@
         vkStream->read((void*)(&pNext_placeholder), sizeof(VkStructureType));
         unmarshal_extension_struct(vkStream, (void*)(forUnmarshaling->pNext));
     }
-    uint64_t cgen_var_141;
-    vkStream->read((uint64_t*)&cgen_var_141, 1 * 8);
-    vkStream->handleMapping()->mapHandles_u64_VkRenderPass(&cgen_var_141, (VkRenderPass*)&forUnmarshaling->renderPass, 1);
-    uint64_t cgen_var_142;
-    vkStream->read((uint64_t*)&cgen_var_142, 1 * 8);
-    vkStream->handleMapping()->mapHandles_u64_VkFramebuffer(&cgen_var_142, (VkFramebuffer*)&forUnmarshaling->framebuffer, 1);
+    uint64_t cgen_var_155;
+    vkStream->read((uint64_t*)&cgen_var_155, 1 * 8);
+    vkStream->handleMapping()->mapHandles_u64_VkRenderPass(&cgen_var_155, (VkRenderPass*)&forUnmarshaling->renderPass, 1);
+    uint64_t cgen_var_156;
+    vkStream->read((uint64_t*)&cgen_var_156, 1 * 8);
+    vkStream->handleMapping()->mapHandles_u64_VkFramebuffer(&cgen_var_156, (VkFramebuffer*)&forUnmarshaling->framebuffer, 1);
     unmarshal_VkRect2D(vkStream, (VkRect2D*)(&forUnmarshaling->renderArea));
     vkStream->read((uint32_t*)&forUnmarshaling->clearValueCount, sizeof(uint32_t));
     // WARNING PTR CHECK
@@ -4340,12 +4558,12 @@
         vkStream->write((const void*)forMarshaling->pNext, sizeof(VkStructureType));
         marshal_extension_struct(vkStream, forMarshaling->pNext);
     }
-    uint64_t cgen_var_144;
-    vkStream->handleMapping()->mapHandles_VkBuffer_u64(&forMarshaling->buffer, &cgen_var_144, 1);
-    vkStream->write((uint64_t*)&cgen_var_144, 1 * 8);
-    uint64_t cgen_var_145;
-    vkStream->handleMapping()->mapHandles_VkDeviceMemory_u64(&forMarshaling->memory, &cgen_var_145, 1);
-    vkStream->write((uint64_t*)&cgen_var_145, 1 * 8);
+    uint64_t cgen_var_158;
+    vkStream->handleMapping()->mapHandles_VkBuffer_u64(&forMarshaling->buffer, &cgen_var_158, 1);
+    vkStream->write((uint64_t*)&cgen_var_158, 1 * 8);
+    uint64_t cgen_var_159;
+    vkStream->handleMapping()->mapHandles_VkDeviceMemory_u64(&forMarshaling->memory, &cgen_var_159, 1);
+    vkStream->write((uint64_t*)&cgen_var_159, 1 * 8);
     vkStream->write((VkDeviceSize*)&forMarshaling->memoryOffset, sizeof(VkDeviceSize));
 }
 
@@ -4362,12 +4580,12 @@
         vkStream->read((void*)(&pNext_placeholder), sizeof(VkStructureType));
         unmarshal_extension_struct(vkStream, (void*)(forUnmarshaling->pNext));
     }
-    uint64_t cgen_var_146;
-    vkStream->read((uint64_t*)&cgen_var_146, 1 * 8);
-    vkStream->handleMapping()->mapHandles_u64_VkBuffer(&cgen_var_146, (VkBuffer*)&forUnmarshaling->buffer, 1);
-    uint64_t cgen_var_147;
-    vkStream->read((uint64_t*)&cgen_var_147, 1 * 8);
-    vkStream->handleMapping()->mapHandles_u64_VkDeviceMemory(&cgen_var_147, (VkDeviceMemory*)&forUnmarshaling->memory, 1);
+    uint64_t cgen_var_160;
+    vkStream->read((uint64_t*)&cgen_var_160, 1 * 8);
+    vkStream->handleMapping()->mapHandles_u64_VkBuffer(&cgen_var_160, (VkBuffer*)&forUnmarshaling->buffer, 1);
+    uint64_t cgen_var_161;
+    vkStream->read((uint64_t*)&cgen_var_161, 1 * 8);
+    vkStream->handleMapping()->mapHandles_u64_VkDeviceMemory(&cgen_var_161, (VkDeviceMemory*)&forUnmarshaling->memory, 1);
     vkStream->read((VkDeviceSize*)&forUnmarshaling->memoryOffset, sizeof(VkDeviceSize));
 }
 
@@ -4383,12 +4601,12 @@
         vkStream->write((const void*)forMarshaling->pNext, sizeof(VkStructureType));
         marshal_extension_struct(vkStream, forMarshaling->pNext);
     }
-    uint64_t cgen_var_148;
-    vkStream->handleMapping()->mapHandles_VkImage_u64(&forMarshaling->image, &cgen_var_148, 1);
-    vkStream->write((uint64_t*)&cgen_var_148, 1 * 8);
-    uint64_t cgen_var_149;
-    vkStream->handleMapping()->mapHandles_VkDeviceMemory_u64(&forMarshaling->memory, &cgen_var_149, 1);
-    vkStream->write((uint64_t*)&cgen_var_149, 1 * 8);
+    uint64_t cgen_var_162;
+    vkStream->handleMapping()->mapHandles_VkImage_u64(&forMarshaling->image, &cgen_var_162, 1);
+    vkStream->write((uint64_t*)&cgen_var_162, 1 * 8);
+    uint64_t cgen_var_163;
+    vkStream->handleMapping()->mapHandles_VkDeviceMemory_u64(&forMarshaling->memory, &cgen_var_163, 1);
+    vkStream->write((uint64_t*)&cgen_var_163, 1 * 8);
     vkStream->write((VkDeviceSize*)&forMarshaling->memoryOffset, sizeof(VkDeviceSize));
 }
 
@@ -4405,12 +4623,12 @@
         vkStream->read((void*)(&pNext_placeholder), sizeof(VkStructureType));
         unmarshal_extension_struct(vkStream, (void*)(forUnmarshaling->pNext));
     }
-    uint64_t cgen_var_150;
-    vkStream->read((uint64_t*)&cgen_var_150, 1 * 8);
-    vkStream->handleMapping()->mapHandles_u64_VkImage(&cgen_var_150, (VkImage*)&forUnmarshaling->image, 1);
-    uint64_t cgen_var_151;
-    vkStream->read((uint64_t*)&cgen_var_151, 1 * 8);
-    vkStream->handleMapping()->mapHandles_u64_VkDeviceMemory(&cgen_var_151, (VkDeviceMemory*)&forUnmarshaling->memory, 1);
+    uint64_t cgen_var_164;
+    vkStream->read((uint64_t*)&cgen_var_164, 1 * 8);
+    vkStream->handleMapping()->mapHandles_u64_VkImage(&cgen_var_164, (VkImage*)&forUnmarshaling->image, 1);
+    uint64_t cgen_var_165;
+    vkStream->read((uint64_t*)&cgen_var_165, 1 * 8);
+    vkStream->handleMapping()->mapHandles_u64_VkDeviceMemory(&cgen_var_165, (VkDeviceMemory*)&forUnmarshaling->memory, 1);
     vkStream->read((VkDeviceSize*)&forUnmarshaling->memoryOffset, sizeof(VkDeviceSize));
 }
 
@@ -4496,12 +4714,12 @@
         vkStream->write((const void*)forMarshaling->pNext, sizeof(VkStructureType));
         marshal_extension_struct(vkStream, forMarshaling->pNext);
     }
-    uint64_t cgen_var_152;
-    vkStream->handleMapping()->mapHandles_VkImage_u64(&forMarshaling->image, &cgen_var_152, 1);
-    vkStream->write((uint64_t*)&cgen_var_152, 1 * 8);
-    uint64_t cgen_var_153;
-    vkStream->handleMapping()->mapHandles_VkBuffer_u64(&forMarshaling->buffer, &cgen_var_153, 1);
-    vkStream->write((uint64_t*)&cgen_var_153, 1 * 8);
+    uint64_t cgen_var_166;
+    vkStream->handleMapping()->mapHandles_VkImage_u64(&forMarshaling->image, &cgen_var_166, 1);
+    vkStream->write((uint64_t*)&cgen_var_166, 1 * 8);
+    uint64_t cgen_var_167;
+    vkStream->handleMapping()->mapHandles_VkBuffer_u64(&forMarshaling->buffer, &cgen_var_167, 1);
+    vkStream->write((uint64_t*)&cgen_var_167, 1 * 8);
 }
 
 void unmarshal_VkMemoryDedicatedAllocateInfo(
@@ -4517,12 +4735,12 @@
         vkStream->read((void*)(&pNext_placeholder), sizeof(VkStructureType));
         unmarshal_extension_struct(vkStream, (void*)(forUnmarshaling->pNext));
     }
-    uint64_t cgen_var_154;
-    vkStream->read((uint64_t*)&cgen_var_154, 1 * 8);
-    vkStream->handleMapping()->mapHandles_u64_VkImage(&cgen_var_154, (VkImage*)&forUnmarshaling->image, 1);
-    uint64_t cgen_var_155;
-    vkStream->read((uint64_t*)&cgen_var_155, 1 * 8);
-    vkStream->handleMapping()->mapHandles_u64_VkBuffer(&cgen_var_155, (VkBuffer*)&forUnmarshaling->buffer, 1);
+    uint64_t cgen_var_168;
+    vkStream->read((uint64_t*)&cgen_var_168, 1 * 8);
+    vkStream->handleMapping()->mapHandles_u64_VkImage(&cgen_var_168, (VkImage*)&forUnmarshaling->image, 1);
+    uint64_t cgen_var_169;
+    vkStream->read((uint64_t*)&cgen_var_169, 1 * 8);
+    vkStream->handleMapping()->mapHandles_u64_VkBuffer(&cgen_var_169, (VkBuffer*)&forUnmarshaling->buffer, 1);
 }
 
 void marshal_VkMemoryAllocateFlagsInfo(
@@ -4830,10 +5048,10 @@
     vkStream->write((uint32_t*)&forMarshaling->physicalDeviceCount, sizeof(uint32_t));
     if (forMarshaling->physicalDeviceCount)
     {
-        uint64_t* cgen_var_156;
-        vkStream->alloc((void**)&cgen_var_156, forMarshaling->physicalDeviceCount * 8);
-        vkStream->handleMapping()->mapHandles_VkPhysicalDevice_u64(forMarshaling->pPhysicalDevices, cgen_var_156, forMarshaling->physicalDeviceCount);
-        vkStream->write((uint64_t*)cgen_var_156, forMarshaling->physicalDeviceCount * 8);
+        uint64_t* cgen_var_170;
+        vkStream->alloc((void**)&cgen_var_170, forMarshaling->physicalDeviceCount * 8);
+        vkStream->handleMapping()->mapHandles_VkPhysicalDevice_u64(forMarshaling->pPhysicalDevices, cgen_var_170, forMarshaling->physicalDeviceCount);
+        vkStream->write((uint64_t*)cgen_var_170, forMarshaling->physicalDeviceCount * 8);
     }
 }
 
@@ -4853,10 +5071,10 @@
     vkStream->read((uint32_t*)&forUnmarshaling->physicalDeviceCount, sizeof(uint32_t));
     if (forUnmarshaling->physicalDeviceCount)
     {
-        uint64_t* cgen_var_157;
-        vkStream->alloc((void**)&cgen_var_157, forUnmarshaling->physicalDeviceCount * 8);
-        vkStream->read((uint64_t*)cgen_var_157, forUnmarshaling->physicalDeviceCount * 8);
-        vkStream->handleMapping()->mapHandles_u64_VkPhysicalDevice(cgen_var_157, (VkPhysicalDevice*)forUnmarshaling->pPhysicalDevices, forUnmarshaling->physicalDeviceCount);
+        uint64_t* cgen_var_171;
+        vkStream->alloc((void**)&cgen_var_171, forUnmarshaling->physicalDeviceCount * 8);
+        vkStream->read((uint64_t*)cgen_var_171, forUnmarshaling->physicalDeviceCount * 8);
+        vkStream->handleMapping()->mapHandles_u64_VkPhysicalDevice(cgen_var_171, (VkPhysicalDevice*)forUnmarshaling->pPhysicalDevices, forUnmarshaling->physicalDeviceCount);
     }
 }
 
@@ -4872,9 +5090,9 @@
         vkStream->write((const void*)forMarshaling->pNext, sizeof(VkStructureType));
         marshal_extension_struct(vkStream, forMarshaling->pNext);
     }
-    uint64_t cgen_var_158;
-    vkStream->handleMapping()->mapHandles_VkBuffer_u64(&forMarshaling->buffer, &cgen_var_158, 1);
-    vkStream->write((uint64_t*)&cgen_var_158, 1 * 8);
+    uint64_t cgen_var_172;
+    vkStream->handleMapping()->mapHandles_VkBuffer_u64(&forMarshaling->buffer, &cgen_var_172, 1);
+    vkStream->write((uint64_t*)&cgen_var_172, 1 * 8);
 }
 
 void unmarshal_VkBufferMemoryRequirementsInfo2(
@@ -4890,9 +5108,9 @@
         vkStream->read((void*)(&pNext_placeholder), sizeof(VkStructureType));
         unmarshal_extension_struct(vkStream, (void*)(forUnmarshaling->pNext));
     }
-    uint64_t cgen_var_159;
-    vkStream->read((uint64_t*)&cgen_var_159, 1 * 8);
-    vkStream->handleMapping()->mapHandles_u64_VkBuffer(&cgen_var_159, (VkBuffer*)&forUnmarshaling->buffer, 1);
+    uint64_t cgen_var_173;
+    vkStream->read((uint64_t*)&cgen_var_173, 1 * 8);
+    vkStream->handleMapping()->mapHandles_u64_VkBuffer(&cgen_var_173, (VkBuffer*)&forUnmarshaling->buffer, 1);
 }
 
 void marshal_VkImageMemoryRequirementsInfo2(
@@ -4907,9 +5125,9 @@
         vkStream->write((const void*)forMarshaling->pNext, sizeof(VkStructureType));
         marshal_extension_struct(vkStream, forMarshaling->pNext);
     }
-    uint64_t cgen_var_160;
-    vkStream->handleMapping()->mapHandles_VkImage_u64(&forMarshaling->image, &cgen_var_160, 1);
-    vkStream->write((uint64_t*)&cgen_var_160, 1 * 8);
+    uint64_t cgen_var_174;
+    vkStream->handleMapping()->mapHandles_VkImage_u64(&forMarshaling->image, &cgen_var_174, 1);
+    vkStream->write((uint64_t*)&cgen_var_174, 1 * 8);
 }
 
 void unmarshal_VkImageMemoryRequirementsInfo2(
@@ -4925,9 +5143,9 @@
         vkStream->read((void*)(&pNext_placeholder), sizeof(VkStructureType));
         unmarshal_extension_struct(vkStream, (void*)(forUnmarshaling->pNext));
     }
-    uint64_t cgen_var_161;
-    vkStream->read((uint64_t*)&cgen_var_161, 1 * 8);
-    vkStream->handleMapping()->mapHandles_u64_VkImage(&cgen_var_161, (VkImage*)&forUnmarshaling->image, 1);
+    uint64_t cgen_var_175;
+    vkStream->read((uint64_t*)&cgen_var_175, 1 * 8);
+    vkStream->handleMapping()->mapHandles_u64_VkImage(&cgen_var_175, (VkImage*)&forUnmarshaling->image, 1);
 }
 
 void marshal_VkImageSparseMemoryRequirementsInfo2(
@@ -4942,9 +5160,9 @@
         vkStream->write((const void*)forMarshaling->pNext, sizeof(VkStructureType));
         marshal_extension_struct(vkStream, forMarshaling->pNext);
     }
-    uint64_t cgen_var_162;
-    vkStream->handleMapping()->mapHandles_VkImage_u64(&forMarshaling->image, &cgen_var_162, 1);
-    vkStream->write((uint64_t*)&cgen_var_162, 1 * 8);
+    uint64_t cgen_var_176;
+    vkStream->handleMapping()->mapHandles_VkImage_u64(&forMarshaling->image, &cgen_var_176, 1);
+    vkStream->write((uint64_t*)&cgen_var_176, 1 * 8);
 }
 
 void unmarshal_VkImageSparseMemoryRequirementsInfo2(
@@ -4960,9 +5178,9 @@
         vkStream->read((void*)(&pNext_placeholder), sizeof(VkStructureType));
         unmarshal_extension_struct(vkStream, (void*)(forUnmarshaling->pNext));
     }
-    uint64_t cgen_var_163;
-    vkStream->read((uint64_t*)&cgen_var_163, 1 * 8);
-    vkStream->handleMapping()->mapHandles_u64_VkImage(&cgen_var_163, (VkImage*)&forUnmarshaling->image, 1);
+    uint64_t cgen_var_177;
+    vkStream->read((uint64_t*)&cgen_var_177, 1 * 8);
+    vkStream->handleMapping()->mapHandles_u64_VkImage(&cgen_var_177, (VkImage*)&forUnmarshaling->image, 1);
 }
 
 void marshal_VkMemoryRequirements2(
@@ -5799,9 +6017,9 @@
         vkStream->write((const void*)forMarshaling->pNext, sizeof(VkStructureType));
         marshal_extension_struct(vkStream, forMarshaling->pNext);
     }
-    uint64_t cgen_var_164;
-    vkStream->handleMapping()->mapHandles_VkSamplerYcbcrConversion_u64(&forMarshaling->conversion, &cgen_var_164, 1);
-    vkStream->write((uint64_t*)&cgen_var_164, 1 * 8);
+    uint64_t cgen_var_178;
+    vkStream->handleMapping()->mapHandles_VkSamplerYcbcrConversion_u64(&forMarshaling->conversion, &cgen_var_178, 1);
+    vkStream->write((uint64_t*)&cgen_var_178, 1 * 8);
 }
 
 void unmarshal_VkSamplerYcbcrConversionInfo(
@@ -5817,9 +6035,9 @@
         vkStream->read((void*)(&pNext_placeholder), sizeof(VkStructureType));
         unmarshal_extension_struct(vkStream, (void*)(forUnmarshaling->pNext));
     }
-    uint64_t cgen_var_165;
-    vkStream->read((uint64_t*)&cgen_var_165, 1 * 8);
-    vkStream->handleMapping()->mapHandles_u64_VkSamplerYcbcrConversion(&cgen_var_165, (VkSamplerYcbcrConversion*)&forUnmarshaling->conversion, 1);
+    uint64_t cgen_var_179;
+    vkStream->read((uint64_t*)&cgen_var_179, 1 * 8);
+    vkStream->handleMapping()->mapHandles_u64_VkSamplerYcbcrConversion(&cgen_var_179, (VkSamplerYcbcrConversion*)&forUnmarshaling->conversion, 1);
 }
 
 void marshal_VkBindImagePlaneMemoryInfo(
@@ -5954,10 +6172,10 @@
     vkStream->write((uint32_t*)&forMarshaling->dstArrayElement, sizeof(uint32_t));
     vkStream->write((uint32_t*)&forMarshaling->descriptorCount, sizeof(uint32_t));
     vkStream->write((VkDescriptorType*)&forMarshaling->descriptorType, sizeof(VkDescriptorType));
-    uint64_t cgen_var_166 = (uint64_t)forMarshaling->offset;
-    vkStream->putBe64(cgen_var_166);
-    uint64_t cgen_var_167 = (uint64_t)forMarshaling->stride;
-    vkStream->putBe64(cgen_var_167);
+    uint64_t cgen_var_180 = (uint64_t)forMarshaling->offset;
+    vkStream->putBe64(cgen_var_180);
+    uint64_t cgen_var_181 = (uint64_t)forMarshaling->stride;
+    vkStream->putBe64(cgen_var_181);
 }
 
 void unmarshal_VkDescriptorUpdateTemplateEntry(
@@ -5991,13 +6209,13 @@
         marshal_VkDescriptorUpdateTemplateEntry(vkStream, (const VkDescriptorUpdateTemplateEntry*)(forMarshaling->pDescriptorUpdateEntries + i));
     }
     vkStream->write((VkDescriptorUpdateTemplateType*)&forMarshaling->templateType, sizeof(VkDescriptorUpdateTemplateType));
-    uint64_t cgen_var_170;
-    vkStream->handleMapping()->mapHandles_VkDescriptorSetLayout_u64(&forMarshaling->descriptorSetLayout, &cgen_var_170, 1);
-    vkStream->write((uint64_t*)&cgen_var_170, 1 * 8);
+    uint64_t cgen_var_184;
+    vkStream->handleMapping()->mapHandles_VkDescriptorSetLayout_u64(&forMarshaling->descriptorSetLayout, &cgen_var_184, 1);
+    vkStream->write((uint64_t*)&cgen_var_184, 1 * 8);
     vkStream->write((VkPipelineBindPoint*)&forMarshaling->pipelineBindPoint, sizeof(VkPipelineBindPoint));
-    uint64_t cgen_var_171;
-    vkStream->handleMapping()->mapHandles_VkPipelineLayout_u64(&forMarshaling->pipelineLayout, &cgen_var_171, 1);
-    vkStream->write((uint64_t*)&cgen_var_171, 1 * 8);
+    uint64_t cgen_var_185;
+    vkStream->handleMapping()->mapHandles_VkPipelineLayout_u64(&forMarshaling->pipelineLayout, &cgen_var_185, 1);
+    vkStream->write((uint64_t*)&cgen_var_185, 1 * 8);
     vkStream->write((uint32_t*)&forMarshaling->set, sizeof(uint32_t));
 }
 
@@ -6021,13 +6239,13 @@
         unmarshal_VkDescriptorUpdateTemplateEntry(vkStream, (VkDescriptorUpdateTemplateEntry*)(forUnmarshaling->pDescriptorUpdateEntries + i));
     }
     vkStream->read((VkDescriptorUpdateTemplateType*)&forUnmarshaling->templateType, sizeof(VkDescriptorUpdateTemplateType));
-    uint64_t cgen_var_172;
-    vkStream->read((uint64_t*)&cgen_var_172, 1 * 8);
-    vkStream->handleMapping()->mapHandles_u64_VkDescriptorSetLayout(&cgen_var_172, (VkDescriptorSetLayout*)&forUnmarshaling->descriptorSetLayout, 1);
+    uint64_t cgen_var_186;
+    vkStream->read((uint64_t*)&cgen_var_186, 1 * 8);
+    vkStream->handleMapping()->mapHandles_u64_VkDescriptorSetLayout(&cgen_var_186, (VkDescriptorSetLayout*)&forUnmarshaling->descriptorSetLayout, 1);
     vkStream->read((VkPipelineBindPoint*)&forUnmarshaling->pipelineBindPoint, sizeof(VkPipelineBindPoint));
-    uint64_t cgen_var_173;
-    vkStream->read((uint64_t*)&cgen_var_173, 1 * 8);
-    vkStream->handleMapping()->mapHandles_u64_VkPipelineLayout(&cgen_var_173, (VkPipelineLayout*)&forUnmarshaling->pipelineLayout, 1);
+    uint64_t cgen_var_187;
+    vkStream->read((uint64_t*)&cgen_var_187, 1 * 8);
+    vkStream->handleMapping()->mapHandles_u64_VkPipelineLayout(&cgen_var_187, (VkPipelineLayout*)&forUnmarshaling->pipelineLayout, 1);
     vkStream->read((uint32_t*)&forUnmarshaling->set, sizeof(uint32_t));
 }
 
@@ -6663,9 +6881,9 @@
         marshal_extension_struct(vkStream, forMarshaling->pNext);
     }
     vkStream->write((VkSwapchainCreateFlagsKHR*)&forMarshaling->flags, sizeof(VkSwapchainCreateFlagsKHR));
-    uint64_t cgen_var_174;
-    vkStream->handleMapping()->mapHandles_VkSurfaceKHR_u64(&forMarshaling->surface, &cgen_var_174, 1);
-    vkStream->write((uint64_t*)&cgen_var_174, 1 * 8);
+    uint64_t cgen_var_188;
+    vkStream->handleMapping()->mapHandles_VkSurfaceKHR_u64(&forMarshaling->surface, &cgen_var_188, 1);
+    vkStream->write((uint64_t*)&cgen_var_188, 1 * 8);
     vkStream->write((uint32_t*)&forMarshaling->minImageCount, sizeof(uint32_t));
     vkStream->write((VkFormat*)&forMarshaling->imageFormat, sizeof(VkFormat));
     vkStream->write((VkColorSpaceKHR*)&forMarshaling->imageColorSpace, sizeof(VkColorSpaceKHR));
@@ -6675,8 +6893,8 @@
     vkStream->write((VkSharingMode*)&forMarshaling->imageSharingMode, sizeof(VkSharingMode));
     vkStream->write((uint32_t*)&forMarshaling->queueFamilyIndexCount, sizeof(uint32_t));
     // WARNING PTR CHECK
-    uint64_t cgen_var_175 = (uint64_t)(uintptr_t)forMarshaling->pQueueFamilyIndices;
-    vkStream->putBe64(cgen_var_175);
+    uint64_t cgen_var_189 = (uint64_t)(uintptr_t)forMarshaling->pQueueFamilyIndices;
+    vkStream->putBe64(cgen_var_189);
     if (forMarshaling->pQueueFamilyIndices)
     {
         vkStream->write((const uint32_t*)forMarshaling->pQueueFamilyIndices, forMarshaling->queueFamilyIndexCount * sizeof(const uint32_t));
@@ -6685,9 +6903,9 @@
     vkStream->write((VkCompositeAlphaFlagBitsKHR*)&forMarshaling->compositeAlpha, sizeof(VkCompositeAlphaFlagBitsKHR));
     vkStream->write((VkPresentModeKHR*)&forMarshaling->presentMode, sizeof(VkPresentModeKHR));
     vkStream->write((VkBool32*)&forMarshaling->clipped, sizeof(VkBool32));
-    uint64_t cgen_var_176;
-    vkStream->handleMapping()->mapHandles_VkSwapchainKHR_u64(&forMarshaling->oldSwapchain, &cgen_var_176, 1);
-    vkStream->write((uint64_t*)&cgen_var_176, 1 * 8);
+    uint64_t cgen_var_190;
+    vkStream->handleMapping()->mapHandles_VkSwapchainKHR_u64(&forMarshaling->oldSwapchain, &cgen_var_190, 1);
+    vkStream->write((uint64_t*)&cgen_var_190, 1 * 8);
 }
 
 void unmarshal_VkSwapchainCreateInfoKHR(
@@ -6704,9 +6922,9 @@
         unmarshal_extension_struct(vkStream, (void*)(forUnmarshaling->pNext));
     }
     vkStream->read((VkSwapchainCreateFlagsKHR*)&forUnmarshaling->flags, sizeof(VkSwapchainCreateFlagsKHR));
-    uint64_t cgen_var_177;
-    vkStream->read((uint64_t*)&cgen_var_177, 1 * 8);
-    vkStream->handleMapping()->mapHandles_u64_VkSurfaceKHR(&cgen_var_177, (VkSurfaceKHR*)&forUnmarshaling->surface, 1);
+    uint64_t cgen_var_191;
+    vkStream->read((uint64_t*)&cgen_var_191, 1 * 8);
+    vkStream->handleMapping()->mapHandles_u64_VkSurfaceKHR(&cgen_var_191, (VkSurfaceKHR*)&forUnmarshaling->surface, 1);
     vkStream->read((uint32_t*)&forUnmarshaling->minImageCount, sizeof(uint32_t));
     vkStream->read((VkFormat*)&forUnmarshaling->imageFormat, sizeof(VkFormat));
     vkStream->read((VkColorSpaceKHR*)&forUnmarshaling->imageColorSpace, sizeof(VkColorSpaceKHR));
@@ -6730,9 +6948,9 @@
     vkStream->read((VkCompositeAlphaFlagBitsKHR*)&forUnmarshaling->compositeAlpha, sizeof(VkCompositeAlphaFlagBitsKHR));
     vkStream->read((VkPresentModeKHR*)&forUnmarshaling->presentMode, sizeof(VkPresentModeKHR));
     vkStream->read((VkBool32*)&forUnmarshaling->clipped, sizeof(VkBool32));
-    uint64_t cgen_var_179;
-    vkStream->read((uint64_t*)&cgen_var_179, 1 * 8);
-    vkStream->handleMapping()->mapHandles_u64_VkSwapchainKHR(&cgen_var_179, (VkSwapchainKHR*)&forUnmarshaling->oldSwapchain, 1);
+    uint64_t cgen_var_193;
+    vkStream->read((uint64_t*)&cgen_var_193, 1 * 8);
+    vkStream->handleMapping()->mapHandles_u64_VkSwapchainKHR(&cgen_var_193, (VkSwapchainKHR*)&forUnmarshaling->oldSwapchain, 1);
 }
 
 void marshal_VkPresentInfoKHR(
@@ -6750,23 +6968,23 @@
     vkStream->write((uint32_t*)&forMarshaling->waitSemaphoreCount, sizeof(uint32_t));
     if (forMarshaling->waitSemaphoreCount)
     {
-        uint64_t* cgen_var_180;
-        vkStream->alloc((void**)&cgen_var_180, forMarshaling->waitSemaphoreCount * 8);
-        vkStream->handleMapping()->mapHandles_VkSemaphore_u64(forMarshaling->pWaitSemaphores, cgen_var_180, forMarshaling->waitSemaphoreCount);
-        vkStream->write((uint64_t*)cgen_var_180, forMarshaling->waitSemaphoreCount * 8);
+        uint64_t* cgen_var_194;
+        vkStream->alloc((void**)&cgen_var_194, forMarshaling->waitSemaphoreCount * 8);
+        vkStream->handleMapping()->mapHandles_VkSemaphore_u64(forMarshaling->pWaitSemaphores, cgen_var_194, forMarshaling->waitSemaphoreCount);
+        vkStream->write((uint64_t*)cgen_var_194, forMarshaling->waitSemaphoreCount * 8);
     }
     vkStream->write((uint32_t*)&forMarshaling->swapchainCount, sizeof(uint32_t));
     if (forMarshaling->swapchainCount)
     {
-        uint64_t* cgen_var_181;
-        vkStream->alloc((void**)&cgen_var_181, forMarshaling->swapchainCount * 8);
-        vkStream->handleMapping()->mapHandles_VkSwapchainKHR_u64(forMarshaling->pSwapchains, cgen_var_181, forMarshaling->swapchainCount);
-        vkStream->write((uint64_t*)cgen_var_181, forMarshaling->swapchainCount * 8);
+        uint64_t* cgen_var_195;
+        vkStream->alloc((void**)&cgen_var_195, forMarshaling->swapchainCount * 8);
+        vkStream->handleMapping()->mapHandles_VkSwapchainKHR_u64(forMarshaling->pSwapchains, cgen_var_195, forMarshaling->swapchainCount);
+        vkStream->write((uint64_t*)cgen_var_195, forMarshaling->swapchainCount * 8);
     }
     vkStream->write((const uint32_t*)forMarshaling->pImageIndices, forMarshaling->swapchainCount * sizeof(const uint32_t));
     // WARNING PTR CHECK
-    uint64_t cgen_var_182 = (uint64_t)(uintptr_t)forMarshaling->pResults;
-    vkStream->putBe64(cgen_var_182);
+    uint64_t cgen_var_196 = (uint64_t)(uintptr_t)forMarshaling->pResults;
+    vkStream->putBe64(cgen_var_196);
     if (forMarshaling->pResults)
     {
         vkStream->write((VkResult*)forMarshaling->pResults, forMarshaling->swapchainCount * sizeof(VkResult));
@@ -6789,18 +7007,18 @@
     vkStream->read((uint32_t*)&forUnmarshaling->waitSemaphoreCount, sizeof(uint32_t));
     if (forUnmarshaling->waitSemaphoreCount)
     {
-        uint64_t* cgen_var_183;
-        vkStream->alloc((void**)&cgen_var_183, forUnmarshaling->waitSemaphoreCount * 8);
-        vkStream->read((uint64_t*)cgen_var_183, forUnmarshaling->waitSemaphoreCount * 8);
-        vkStream->handleMapping()->mapHandles_u64_VkSemaphore(cgen_var_183, (VkSemaphore*)forUnmarshaling->pWaitSemaphores, forUnmarshaling->waitSemaphoreCount);
+        uint64_t* cgen_var_197;
+        vkStream->alloc((void**)&cgen_var_197, forUnmarshaling->waitSemaphoreCount * 8);
+        vkStream->read((uint64_t*)cgen_var_197, forUnmarshaling->waitSemaphoreCount * 8);
+        vkStream->handleMapping()->mapHandles_u64_VkSemaphore(cgen_var_197, (VkSemaphore*)forUnmarshaling->pWaitSemaphores, forUnmarshaling->waitSemaphoreCount);
     }
     vkStream->read((uint32_t*)&forUnmarshaling->swapchainCount, sizeof(uint32_t));
     if (forUnmarshaling->swapchainCount)
     {
-        uint64_t* cgen_var_184;
-        vkStream->alloc((void**)&cgen_var_184, forUnmarshaling->swapchainCount * 8);
-        vkStream->read((uint64_t*)cgen_var_184, forUnmarshaling->swapchainCount * 8);
-        vkStream->handleMapping()->mapHandles_u64_VkSwapchainKHR(cgen_var_184, (VkSwapchainKHR*)forUnmarshaling->pSwapchains, forUnmarshaling->swapchainCount);
+        uint64_t* cgen_var_198;
+        vkStream->alloc((void**)&cgen_var_198, forUnmarshaling->swapchainCount * 8);
+        vkStream->read((uint64_t*)cgen_var_198, forUnmarshaling->swapchainCount * 8);
+        vkStream->handleMapping()->mapHandles_u64_VkSwapchainKHR(cgen_var_198, (VkSwapchainKHR*)forUnmarshaling->pSwapchains, forUnmarshaling->swapchainCount);
     }
     vkStream->read((uint32_t*)forUnmarshaling->pImageIndices, forUnmarshaling->swapchainCount * sizeof(const uint32_t));
     // WARNING PTR CHECK
@@ -6828,9 +7046,9 @@
         vkStream->write((const void*)forMarshaling->pNext, sizeof(VkStructureType));
         marshal_extension_struct(vkStream, forMarshaling->pNext);
     }
-    uint64_t cgen_var_186;
-    vkStream->handleMapping()->mapHandles_VkSwapchainKHR_u64(&forMarshaling->swapchain, &cgen_var_186, 1);
-    vkStream->write((uint64_t*)&cgen_var_186, 1 * 8);
+    uint64_t cgen_var_200;
+    vkStream->handleMapping()->mapHandles_VkSwapchainKHR_u64(&forMarshaling->swapchain, &cgen_var_200, 1);
+    vkStream->write((uint64_t*)&cgen_var_200, 1 * 8);
 }
 
 void unmarshal_VkImageSwapchainCreateInfoKHR(
@@ -6846,9 +7064,9 @@
         vkStream->read((void*)(&pNext_placeholder), sizeof(VkStructureType));
         unmarshal_extension_struct(vkStream, (void*)(forUnmarshaling->pNext));
     }
-    uint64_t cgen_var_187;
-    vkStream->read((uint64_t*)&cgen_var_187, 1 * 8);
-    vkStream->handleMapping()->mapHandles_u64_VkSwapchainKHR(&cgen_var_187, (VkSwapchainKHR*)&forUnmarshaling->swapchain, 1);
+    uint64_t cgen_var_201;
+    vkStream->read((uint64_t*)&cgen_var_201, 1 * 8);
+    vkStream->handleMapping()->mapHandles_u64_VkSwapchainKHR(&cgen_var_201, (VkSwapchainKHR*)&forUnmarshaling->swapchain, 1);
 }
 
 void marshal_VkBindImageMemorySwapchainInfoKHR(
@@ -6863,9 +7081,9 @@
         vkStream->write((const void*)forMarshaling->pNext, sizeof(VkStructureType));
         marshal_extension_struct(vkStream, forMarshaling->pNext);
     }
-    uint64_t cgen_var_188;
-    vkStream->handleMapping()->mapHandles_VkSwapchainKHR_u64(&forMarshaling->swapchain, &cgen_var_188, 1);
-    vkStream->write((uint64_t*)&cgen_var_188, 1 * 8);
+    uint64_t cgen_var_202;
+    vkStream->handleMapping()->mapHandles_VkSwapchainKHR_u64(&forMarshaling->swapchain, &cgen_var_202, 1);
+    vkStream->write((uint64_t*)&cgen_var_202, 1 * 8);
     vkStream->write((uint32_t*)&forMarshaling->imageIndex, sizeof(uint32_t));
 }
 
@@ -6882,9 +7100,9 @@
         vkStream->read((void*)(&pNext_placeholder), sizeof(VkStructureType));
         unmarshal_extension_struct(vkStream, (void*)(forUnmarshaling->pNext));
     }
-    uint64_t cgen_var_189;
-    vkStream->read((uint64_t*)&cgen_var_189, 1 * 8);
-    vkStream->handleMapping()->mapHandles_u64_VkSwapchainKHR(&cgen_var_189, (VkSwapchainKHR*)&forUnmarshaling->swapchain, 1);
+    uint64_t cgen_var_203;
+    vkStream->read((uint64_t*)&cgen_var_203, 1 * 8);
+    vkStream->handleMapping()->mapHandles_u64_VkSwapchainKHR(&cgen_var_203, (VkSwapchainKHR*)&forUnmarshaling->swapchain, 1);
     vkStream->read((uint32_t*)&forUnmarshaling->imageIndex, sizeof(uint32_t));
 }
 
@@ -6900,16 +7118,16 @@
         vkStream->write((const void*)forMarshaling->pNext, sizeof(VkStructureType));
         marshal_extension_struct(vkStream, forMarshaling->pNext);
     }
-    uint64_t cgen_var_190;
-    vkStream->handleMapping()->mapHandles_VkSwapchainKHR_u64(&forMarshaling->swapchain, &cgen_var_190, 1);
-    vkStream->write((uint64_t*)&cgen_var_190, 1 * 8);
+    uint64_t cgen_var_204;
+    vkStream->handleMapping()->mapHandles_VkSwapchainKHR_u64(&forMarshaling->swapchain, &cgen_var_204, 1);
+    vkStream->write((uint64_t*)&cgen_var_204, 1 * 8);
     vkStream->write((uint64_t*)&forMarshaling->timeout, sizeof(uint64_t));
-    uint64_t cgen_var_191;
-    vkStream->handleMapping()->mapHandles_VkSemaphore_u64(&forMarshaling->semaphore, &cgen_var_191, 1);
-    vkStream->write((uint64_t*)&cgen_var_191, 1 * 8);
-    uint64_t cgen_var_192;
-    vkStream->handleMapping()->mapHandles_VkFence_u64(&forMarshaling->fence, &cgen_var_192, 1);
-    vkStream->write((uint64_t*)&cgen_var_192, 1 * 8);
+    uint64_t cgen_var_205;
+    vkStream->handleMapping()->mapHandles_VkSemaphore_u64(&forMarshaling->semaphore, &cgen_var_205, 1);
+    vkStream->write((uint64_t*)&cgen_var_205, 1 * 8);
+    uint64_t cgen_var_206;
+    vkStream->handleMapping()->mapHandles_VkFence_u64(&forMarshaling->fence, &cgen_var_206, 1);
+    vkStream->write((uint64_t*)&cgen_var_206, 1 * 8);
     vkStream->write((uint32_t*)&forMarshaling->deviceMask, sizeof(uint32_t));
 }
 
@@ -6926,16 +7144,16 @@
         vkStream->read((void*)(&pNext_placeholder), sizeof(VkStructureType));
         unmarshal_extension_struct(vkStream, (void*)(forUnmarshaling->pNext));
     }
-    uint64_t cgen_var_193;
-    vkStream->read((uint64_t*)&cgen_var_193, 1 * 8);
-    vkStream->handleMapping()->mapHandles_u64_VkSwapchainKHR(&cgen_var_193, (VkSwapchainKHR*)&forUnmarshaling->swapchain, 1);
+    uint64_t cgen_var_207;
+    vkStream->read((uint64_t*)&cgen_var_207, 1 * 8);
+    vkStream->handleMapping()->mapHandles_u64_VkSwapchainKHR(&cgen_var_207, (VkSwapchainKHR*)&forUnmarshaling->swapchain, 1);
     vkStream->read((uint64_t*)&forUnmarshaling->timeout, sizeof(uint64_t));
-    uint64_t cgen_var_194;
-    vkStream->read((uint64_t*)&cgen_var_194, 1 * 8);
-    vkStream->handleMapping()->mapHandles_u64_VkSemaphore(&cgen_var_194, (VkSemaphore*)&forUnmarshaling->semaphore, 1);
-    uint64_t cgen_var_195;
-    vkStream->read((uint64_t*)&cgen_var_195, 1 * 8);
-    vkStream->handleMapping()->mapHandles_u64_VkFence(&cgen_var_195, (VkFence*)&forUnmarshaling->fence, 1);
+    uint64_t cgen_var_208;
+    vkStream->read((uint64_t*)&cgen_var_208, 1 * 8);
+    vkStream->handleMapping()->mapHandles_u64_VkSemaphore(&cgen_var_208, (VkSemaphore*)&forUnmarshaling->semaphore, 1);
+    uint64_t cgen_var_209;
+    vkStream->read((uint64_t*)&cgen_var_209, 1 * 8);
+    vkStream->handleMapping()->mapHandles_u64_VkFence(&cgen_var_209, (VkFence*)&forUnmarshaling->fence, 1);
     vkStream->read((uint32_t*)&forUnmarshaling->deviceMask, sizeof(uint32_t));
 }
 
@@ -7044,9 +7262,9 @@
     VulkanStreamGuest* vkStream,
     const VkDisplayPropertiesKHR* forMarshaling)
 {
-    uint64_t cgen_var_196;
-    vkStream->handleMapping()->mapHandles_VkDisplayKHR_u64(&forMarshaling->display, &cgen_var_196, 1);
-    vkStream->write((uint64_t*)&cgen_var_196, 1 * 8);
+    uint64_t cgen_var_210;
+    vkStream->handleMapping()->mapHandles_VkDisplayKHR_u64(&forMarshaling->display, &cgen_var_210, 1);
+    vkStream->write((uint64_t*)&cgen_var_210, 1 * 8);
     vkStream->putString(forMarshaling->displayName);
     marshal_VkExtent2D(vkStream, (VkExtent2D*)(&forMarshaling->physicalDimensions));
     marshal_VkExtent2D(vkStream, (VkExtent2D*)(&forMarshaling->physicalResolution));
@@ -7059,9 +7277,9 @@
     VulkanStreamGuest* vkStream,
     VkDisplayPropertiesKHR* forUnmarshaling)
 {
-    uint64_t cgen_var_197;
-    vkStream->read((uint64_t*)&cgen_var_197, 1 * 8);
-    vkStream->handleMapping()->mapHandles_u64_VkDisplayKHR(&cgen_var_197, (VkDisplayKHR*)&forUnmarshaling->display, 1);
+    uint64_t cgen_var_211;
+    vkStream->read((uint64_t*)&cgen_var_211, 1 * 8);
+    vkStream->handleMapping()->mapHandles_u64_VkDisplayKHR(&cgen_var_211, (VkDisplayKHR*)&forUnmarshaling->display, 1);
     vkStream->loadStringInPlace((char**)&forUnmarshaling->displayName);
     unmarshal_VkExtent2D(vkStream, (VkExtent2D*)(&forUnmarshaling->physicalDimensions));
     unmarshal_VkExtent2D(vkStream, (VkExtent2D*)(&forUnmarshaling->physicalResolution));
@@ -7090,9 +7308,9 @@
     VulkanStreamGuest* vkStream,
     const VkDisplayModePropertiesKHR* forMarshaling)
 {
-    uint64_t cgen_var_198;
-    vkStream->handleMapping()->mapHandles_VkDisplayModeKHR_u64(&forMarshaling->displayMode, &cgen_var_198, 1);
-    vkStream->write((uint64_t*)&cgen_var_198, 1 * 8);
+    uint64_t cgen_var_212;
+    vkStream->handleMapping()->mapHandles_VkDisplayModeKHR_u64(&forMarshaling->displayMode, &cgen_var_212, 1);
+    vkStream->write((uint64_t*)&cgen_var_212, 1 * 8);
     marshal_VkDisplayModeParametersKHR(vkStream, (VkDisplayModeParametersKHR*)(&forMarshaling->parameters));
 }
 
@@ -7100,9 +7318,9 @@
     VulkanStreamGuest* vkStream,
     VkDisplayModePropertiesKHR* forUnmarshaling)
 {
-    uint64_t cgen_var_199;
-    vkStream->read((uint64_t*)&cgen_var_199, 1 * 8);
-    vkStream->handleMapping()->mapHandles_u64_VkDisplayModeKHR(&cgen_var_199, (VkDisplayModeKHR*)&forUnmarshaling->displayMode, 1);
+    uint64_t cgen_var_213;
+    vkStream->read((uint64_t*)&cgen_var_213, 1 * 8);
+    vkStream->handleMapping()->mapHandles_u64_VkDisplayModeKHR(&cgen_var_213, (VkDisplayModeKHR*)&forUnmarshaling->displayMode, 1);
     unmarshal_VkDisplayModeParametersKHR(vkStream, (VkDisplayModeParametersKHR*)(&forUnmarshaling->parameters));
 }
 
@@ -7173,9 +7391,9 @@
     VulkanStreamGuest* vkStream,
     const VkDisplayPlanePropertiesKHR* forMarshaling)
 {
-    uint64_t cgen_var_200;
-    vkStream->handleMapping()->mapHandles_VkDisplayKHR_u64(&forMarshaling->currentDisplay, &cgen_var_200, 1);
-    vkStream->write((uint64_t*)&cgen_var_200, 1 * 8);
+    uint64_t cgen_var_214;
+    vkStream->handleMapping()->mapHandles_VkDisplayKHR_u64(&forMarshaling->currentDisplay, &cgen_var_214, 1);
+    vkStream->write((uint64_t*)&cgen_var_214, 1 * 8);
     vkStream->write((uint32_t*)&forMarshaling->currentStackIndex, sizeof(uint32_t));
 }
 
@@ -7183,9 +7401,9 @@
     VulkanStreamGuest* vkStream,
     VkDisplayPlanePropertiesKHR* forUnmarshaling)
 {
-    uint64_t cgen_var_201;
-    vkStream->read((uint64_t*)&cgen_var_201, 1 * 8);
-    vkStream->handleMapping()->mapHandles_u64_VkDisplayKHR(&cgen_var_201, (VkDisplayKHR*)&forUnmarshaling->currentDisplay, 1);
+    uint64_t cgen_var_215;
+    vkStream->read((uint64_t*)&cgen_var_215, 1 * 8);
+    vkStream->handleMapping()->mapHandles_u64_VkDisplayKHR(&cgen_var_215, (VkDisplayKHR*)&forUnmarshaling->currentDisplay, 1);
     vkStream->read((uint32_t*)&forUnmarshaling->currentStackIndex, sizeof(uint32_t));
 }
 
@@ -7202,9 +7420,9 @@
         marshal_extension_struct(vkStream, forMarshaling->pNext);
     }
     vkStream->write((VkDisplaySurfaceCreateFlagsKHR*)&forMarshaling->flags, sizeof(VkDisplaySurfaceCreateFlagsKHR));
-    uint64_t cgen_var_202;
-    vkStream->handleMapping()->mapHandles_VkDisplayModeKHR_u64(&forMarshaling->displayMode, &cgen_var_202, 1);
-    vkStream->write((uint64_t*)&cgen_var_202, 1 * 8);
+    uint64_t cgen_var_216;
+    vkStream->handleMapping()->mapHandles_VkDisplayModeKHR_u64(&forMarshaling->displayMode, &cgen_var_216, 1);
+    vkStream->write((uint64_t*)&cgen_var_216, 1 * 8);
     vkStream->write((uint32_t*)&forMarshaling->planeIndex, sizeof(uint32_t));
     vkStream->write((uint32_t*)&forMarshaling->planeStackIndex, sizeof(uint32_t));
     vkStream->write((VkSurfaceTransformFlagBitsKHR*)&forMarshaling->transform, sizeof(VkSurfaceTransformFlagBitsKHR));
@@ -7227,9 +7445,9 @@
         unmarshal_extension_struct(vkStream, (void*)(forUnmarshaling->pNext));
     }
     vkStream->read((VkDisplaySurfaceCreateFlagsKHR*)&forUnmarshaling->flags, sizeof(VkDisplaySurfaceCreateFlagsKHR));
-    uint64_t cgen_var_203;
-    vkStream->read((uint64_t*)&cgen_var_203, 1 * 8);
-    vkStream->handleMapping()->mapHandles_u64_VkDisplayModeKHR(&cgen_var_203, (VkDisplayModeKHR*)&forUnmarshaling->displayMode, 1);
+    uint64_t cgen_var_217;
+    vkStream->read((uint64_t*)&cgen_var_217, 1 * 8);
+    vkStream->handleMapping()->mapHandles_u64_VkDisplayModeKHR(&cgen_var_217, (VkDisplayModeKHR*)&forUnmarshaling->displayMode, 1);
     vkStream->read((uint32_t*)&forUnmarshaling->planeIndex, sizeof(uint32_t));
     vkStream->read((uint32_t*)&forUnmarshaling->planeStackIndex, sizeof(uint32_t));
     vkStream->read((VkSurfaceTransformFlagBitsKHR*)&forUnmarshaling->transform, sizeof(VkSurfaceTransformFlagBitsKHR));
@@ -7291,8 +7509,8 @@
     }
     vkStream->write((VkXlibSurfaceCreateFlagsKHR*)&forMarshaling->flags, sizeof(VkXlibSurfaceCreateFlagsKHR));
     // WARNING PTR CHECK
-    uint64_t cgen_var_204 = (uint64_t)(uintptr_t)forMarshaling->dpy;
-    vkStream->putBe64(cgen_var_204);
+    uint64_t cgen_var_218 = (uint64_t)(uintptr_t)forMarshaling->dpy;
+    vkStream->putBe64(cgen_var_218);
     if (forMarshaling->dpy)
     {
         vkStream->write((Display*)forMarshaling->dpy, sizeof(Display));
@@ -7344,8 +7562,8 @@
     }
     vkStream->write((VkXcbSurfaceCreateFlagsKHR*)&forMarshaling->flags, sizeof(VkXcbSurfaceCreateFlagsKHR));
     // WARNING PTR CHECK
-    uint64_t cgen_var_206 = (uint64_t)(uintptr_t)forMarshaling->connection;
-    vkStream->putBe64(cgen_var_206);
+    uint64_t cgen_var_220 = (uint64_t)(uintptr_t)forMarshaling->connection;
+    vkStream->putBe64(cgen_var_220);
     if (forMarshaling->connection)
     {
         vkStream->write((xcb_connection_t*)forMarshaling->connection, sizeof(xcb_connection_t));
@@ -7397,15 +7615,15 @@
     }
     vkStream->write((VkWaylandSurfaceCreateFlagsKHR*)&forMarshaling->flags, sizeof(VkWaylandSurfaceCreateFlagsKHR));
     // WARNING PTR CHECK
-    uint64_t cgen_var_208 = (uint64_t)(uintptr_t)forMarshaling->display;
-    vkStream->putBe64(cgen_var_208);
+    uint64_t cgen_var_222 = (uint64_t)(uintptr_t)forMarshaling->display;
+    vkStream->putBe64(cgen_var_222);
     if (forMarshaling->display)
     {
         vkStream->write((wl_display*)forMarshaling->display, sizeof(wl_display));
     }
     // WARNING PTR CHECK
-    uint64_t cgen_var_209 = (uint64_t)(uintptr_t)forMarshaling->surface;
-    vkStream->putBe64(cgen_var_209);
+    uint64_t cgen_var_223 = (uint64_t)(uintptr_t)forMarshaling->surface;
+    vkStream->putBe64(cgen_var_223);
     if (forMarshaling->surface)
     {
         vkStream->write((wl_surface*)forMarshaling->surface, sizeof(wl_surface));
@@ -7466,15 +7684,15 @@
     }
     vkStream->write((VkMirSurfaceCreateFlagsKHR*)&forMarshaling->flags, sizeof(VkMirSurfaceCreateFlagsKHR));
     // WARNING PTR CHECK
-    uint64_t cgen_var_212 = (uint64_t)(uintptr_t)forMarshaling->connection;
-    vkStream->putBe64(cgen_var_212);
+    uint64_t cgen_var_226 = (uint64_t)(uintptr_t)forMarshaling->connection;
+    vkStream->putBe64(cgen_var_226);
     if (forMarshaling->connection)
     {
         vkStream->write((MirConnection*)forMarshaling->connection, sizeof(MirConnection));
     }
     // WARNING PTR CHECK
-    uint64_t cgen_var_213 = (uint64_t)(uintptr_t)forMarshaling->mirSurface;
-    vkStream->putBe64(cgen_var_213);
+    uint64_t cgen_var_227 = (uint64_t)(uintptr_t)forMarshaling->mirSurface;
+    vkStream->putBe64(cgen_var_227);
     if (forMarshaling->mirSurface)
     {
         vkStream->write((MirSurface*)forMarshaling->mirSurface, sizeof(MirSurface));
@@ -7535,8 +7753,8 @@
     }
     vkStream->write((VkAndroidSurfaceCreateFlagsKHR*)&forMarshaling->flags, sizeof(VkAndroidSurfaceCreateFlagsKHR));
     // WARNING PTR CHECK
-    uint64_t cgen_var_216 = (uint64_t)(uintptr_t)forMarshaling->window;
-    vkStream->putBe64(cgen_var_216);
+    uint64_t cgen_var_230 = (uint64_t)(uintptr_t)forMarshaling->window;
+    vkStream->putBe64(cgen_var_230);
     if (forMarshaling->window)
     {
         vkStream->write((ANativeWindow*)forMarshaling->window, sizeof(ANativeWindow));
@@ -7675,8 +7893,8 @@
         marshal_extension_struct(vkStream, forMarshaling->pNext);
     }
     // WARNING PTR CHECK
-    uint64_t cgen_var_218 = (uint64_t)(uintptr_t)forMarshaling->pAttributes;
-    vkStream->putBe64(cgen_var_218);
+    uint64_t cgen_var_232 = (uint64_t)(uintptr_t)forMarshaling->pAttributes;
+    vkStream->putBe64(cgen_var_232);
     if (forMarshaling->pAttributes)
     {
         vkStream->write((const SECURITY_ATTRIBUTES*)forMarshaling->pAttributes, sizeof(const SECURITY_ATTRIBUTES));
@@ -7756,9 +7974,9 @@
         vkStream->write((const void*)forMarshaling->pNext, sizeof(VkStructureType));
         marshal_extension_struct(vkStream, forMarshaling->pNext);
     }
-    uint64_t cgen_var_220;
-    vkStream->handleMapping()->mapHandles_VkDeviceMemory_u64(&forMarshaling->memory, &cgen_var_220, 1);
-    vkStream->write((uint64_t*)&cgen_var_220, 1 * 8);
+    uint64_t cgen_var_234;
+    vkStream->handleMapping()->mapHandles_VkDeviceMemory_u64(&forMarshaling->memory, &cgen_var_234, 1);
+    vkStream->write((uint64_t*)&cgen_var_234, 1 * 8);
     vkStream->write((VkExternalMemoryHandleTypeFlagBits*)&forMarshaling->handleType, sizeof(VkExternalMemoryHandleTypeFlagBits));
 }
 
@@ -7775,9 +7993,9 @@
         vkStream->read((void*)(&pNext_placeholder), sizeof(VkStructureType));
         unmarshal_extension_struct(vkStream, (void*)(forUnmarshaling->pNext));
     }
-    uint64_t cgen_var_221;
-    vkStream->read((uint64_t*)&cgen_var_221, 1 * 8);
-    vkStream->handleMapping()->mapHandles_u64_VkDeviceMemory(&cgen_var_221, (VkDeviceMemory*)&forUnmarshaling->memory, 1);
+    uint64_t cgen_var_235;
+    vkStream->read((uint64_t*)&cgen_var_235, 1 * 8);
+    vkStream->handleMapping()->mapHandles_u64_VkDeviceMemory(&cgen_var_235, (VkDeviceMemory*)&forUnmarshaling->memory, 1);
     vkStream->read((VkExternalMemoryHandleTypeFlagBits*)&forUnmarshaling->handleType, sizeof(VkExternalMemoryHandleTypeFlagBits));
 }
 
@@ -7859,9 +8077,9 @@
         vkStream->write((const void*)forMarshaling->pNext, sizeof(VkStructureType));
         marshal_extension_struct(vkStream, forMarshaling->pNext);
     }
-    uint64_t cgen_var_222;
-    vkStream->handleMapping()->mapHandles_VkDeviceMemory_u64(&forMarshaling->memory, &cgen_var_222, 1);
-    vkStream->write((uint64_t*)&cgen_var_222, 1 * 8);
+    uint64_t cgen_var_236;
+    vkStream->handleMapping()->mapHandles_VkDeviceMemory_u64(&forMarshaling->memory, &cgen_var_236, 1);
+    vkStream->write((uint64_t*)&cgen_var_236, 1 * 8);
     vkStream->write((VkExternalMemoryHandleTypeFlagBits*)&forMarshaling->handleType, sizeof(VkExternalMemoryHandleTypeFlagBits));
 }
 
@@ -7878,9 +8096,9 @@
         vkStream->read((void*)(&pNext_placeholder), sizeof(VkStructureType));
         unmarshal_extension_struct(vkStream, (void*)(forUnmarshaling->pNext));
     }
-    uint64_t cgen_var_223;
-    vkStream->read((uint64_t*)&cgen_var_223, 1 * 8);
-    vkStream->handleMapping()->mapHandles_u64_VkDeviceMemory(&cgen_var_223, (VkDeviceMemory*)&forUnmarshaling->memory, 1);
+    uint64_t cgen_var_237;
+    vkStream->read((uint64_t*)&cgen_var_237, 1 * 8);
+    vkStream->handleMapping()->mapHandles_u64_VkDeviceMemory(&cgen_var_237, (VkDeviceMemory*)&forUnmarshaling->memory, 1);
     vkStream->read((VkExternalMemoryHandleTypeFlagBits*)&forUnmarshaling->handleType, sizeof(VkExternalMemoryHandleTypeFlagBits));
 }
 
@@ -7901,20 +8119,20 @@
     vkStream->write((uint32_t*)&forMarshaling->acquireCount, sizeof(uint32_t));
     if (forMarshaling->acquireCount)
     {
-        uint64_t* cgen_var_224;
-        vkStream->alloc((void**)&cgen_var_224, forMarshaling->acquireCount * 8);
-        vkStream->handleMapping()->mapHandles_VkDeviceMemory_u64(forMarshaling->pAcquireSyncs, cgen_var_224, forMarshaling->acquireCount);
-        vkStream->write((uint64_t*)cgen_var_224, forMarshaling->acquireCount * 8);
+        uint64_t* cgen_var_238;
+        vkStream->alloc((void**)&cgen_var_238, forMarshaling->acquireCount * 8);
+        vkStream->handleMapping()->mapHandles_VkDeviceMemory_u64(forMarshaling->pAcquireSyncs, cgen_var_238, forMarshaling->acquireCount);
+        vkStream->write((uint64_t*)cgen_var_238, forMarshaling->acquireCount * 8);
     }
     vkStream->write((const uint64_t*)forMarshaling->pAcquireKeys, forMarshaling->acquireCount * sizeof(const uint64_t));
     vkStream->write((const uint32_t*)forMarshaling->pAcquireTimeouts, forMarshaling->acquireCount * sizeof(const uint32_t));
     vkStream->write((uint32_t*)&forMarshaling->releaseCount, sizeof(uint32_t));
     if (forMarshaling->releaseCount)
     {
-        uint64_t* cgen_var_225;
-        vkStream->alloc((void**)&cgen_var_225, forMarshaling->releaseCount * 8);
-        vkStream->handleMapping()->mapHandles_VkDeviceMemory_u64(forMarshaling->pReleaseSyncs, cgen_var_225, forMarshaling->releaseCount);
-        vkStream->write((uint64_t*)cgen_var_225, forMarshaling->releaseCount * 8);
+        uint64_t* cgen_var_239;
+        vkStream->alloc((void**)&cgen_var_239, forMarshaling->releaseCount * 8);
+        vkStream->handleMapping()->mapHandles_VkDeviceMemory_u64(forMarshaling->pReleaseSyncs, cgen_var_239, forMarshaling->releaseCount);
+        vkStream->write((uint64_t*)cgen_var_239, forMarshaling->releaseCount * 8);
     }
     vkStream->write((const uint64_t*)forMarshaling->pReleaseKeys, forMarshaling->releaseCount * sizeof(const uint64_t));
 }
@@ -7935,20 +8153,20 @@
     vkStream->read((uint32_t*)&forUnmarshaling->acquireCount, sizeof(uint32_t));
     if (forUnmarshaling->acquireCount)
     {
-        uint64_t* cgen_var_226;
-        vkStream->alloc((void**)&cgen_var_226, forUnmarshaling->acquireCount * 8);
-        vkStream->read((uint64_t*)cgen_var_226, forUnmarshaling->acquireCount * 8);
-        vkStream->handleMapping()->mapHandles_u64_VkDeviceMemory(cgen_var_226, (VkDeviceMemory*)forUnmarshaling->pAcquireSyncs, forUnmarshaling->acquireCount);
+        uint64_t* cgen_var_240;
+        vkStream->alloc((void**)&cgen_var_240, forUnmarshaling->acquireCount * 8);
+        vkStream->read((uint64_t*)cgen_var_240, forUnmarshaling->acquireCount * 8);
+        vkStream->handleMapping()->mapHandles_u64_VkDeviceMemory(cgen_var_240, (VkDeviceMemory*)forUnmarshaling->pAcquireSyncs, forUnmarshaling->acquireCount);
     }
     vkStream->read((uint64_t*)forUnmarshaling->pAcquireKeys, forUnmarshaling->acquireCount * sizeof(const uint64_t));
     vkStream->read((uint32_t*)forUnmarshaling->pAcquireTimeouts, forUnmarshaling->acquireCount * sizeof(const uint32_t));
     vkStream->read((uint32_t*)&forUnmarshaling->releaseCount, sizeof(uint32_t));
     if (forUnmarshaling->releaseCount)
     {
-        uint64_t* cgen_var_227;
-        vkStream->alloc((void**)&cgen_var_227, forUnmarshaling->releaseCount * 8);
-        vkStream->read((uint64_t*)cgen_var_227, forUnmarshaling->releaseCount * 8);
-        vkStream->handleMapping()->mapHandles_u64_VkDeviceMemory(cgen_var_227, (VkDeviceMemory*)forUnmarshaling->pReleaseSyncs, forUnmarshaling->releaseCount);
+        uint64_t* cgen_var_241;
+        vkStream->alloc((void**)&cgen_var_241, forUnmarshaling->releaseCount * 8);
+        vkStream->read((uint64_t*)cgen_var_241, forUnmarshaling->releaseCount * 8);
+        vkStream->handleMapping()->mapHandles_u64_VkDeviceMemory(cgen_var_241, (VkDeviceMemory*)forUnmarshaling->pReleaseSyncs, forUnmarshaling->releaseCount);
     }
     vkStream->read((uint64_t*)forUnmarshaling->pReleaseKeys, forUnmarshaling->releaseCount * sizeof(const uint64_t));
 }
@@ -7971,9 +8189,9 @@
         vkStream->write((const void*)forMarshaling->pNext, sizeof(VkStructureType));
         marshal_extension_struct(vkStream, forMarshaling->pNext);
     }
-    uint64_t cgen_var_228;
-    vkStream->handleMapping()->mapHandles_VkSemaphore_u64(&forMarshaling->semaphore, &cgen_var_228, 1);
-    vkStream->write((uint64_t*)&cgen_var_228, 1 * 8);
+    uint64_t cgen_var_242;
+    vkStream->handleMapping()->mapHandles_VkSemaphore_u64(&forMarshaling->semaphore, &cgen_var_242, 1);
+    vkStream->write((uint64_t*)&cgen_var_242, 1 * 8);
     vkStream->write((VkSemaphoreImportFlags*)&forMarshaling->flags, sizeof(VkSemaphoreImportFlags));
     vkStream->write((VkExternalSemaphoreHandleTypeFlagBits*)&forMarshaling->handleType, sizeof(VkExternalSemaphoreHandleTypeFlagBits));
     vkStream->write((HANDLE*)&forMarshaling->handle, sizeof(HANDLE));
@@ -7993,9 +8211,9 @@
         vkStream->read((void*)(&pNext_placeholder), sizeof(VkStructureType));
         unmarshal_extension_struct(vkStream, (void*)(forUnmarshaling->pNext));
     }
-    uint64_t cgen_var_229;
-    vkStream->read((uint64_t*)&cgen_var_229, 1 * 8);
-    vkStream->handleMapping()->mapHandles_u64_VkSemaphore(&cgen_var_229, (VkSemaphore*)&forUnmarshaling->semaphore, 1);
+    uint64_t cgen_var_243;
+    vkStream->read((uint64_t*)&cgen_var_243, 1 * 8);
+    vkStream->handleMapping()->mapHandles_u64_VkSemaphore(&cgen_var_243, (VkSemaphore*)&forUnmarshaling->semaphore, 1);
     vkStream->read((VkSemaphoreImportFlags*)&forUnmarshaling->flags, sizeof(VkSemaphoreImportFlags));
     vkStream->read((VkExternalSemaphoreHandleTypeFlagBits*)&forUnmarshaling->handleType, sizeof(VkExternalSemaphoreHandleTypeFlagBits));
     vkStream->read((HANDLE*)&forUnmarshaling->handle, sizeof(HANDLE));
@@ -8015,8 +8233,8 @@
         marshal_extension_struct(vkStream, forMarshaling->pNext);
     }
     // WARNING PTR CHECK
-    uint64_t cgen_var_230 = (uint64_t)(uintptr_t)forMarshaling->pAttributes;
-    vkStream->putBe64(cgen_var_230);
+    uint64_t cgen_var_244 = (uint64_t)(uintptr_t)forMarshaling->pAttributes;
+    vkStream->putBe64(cgen_var_244);
     if (forMarshaling->pAttributes)
     {
         vkStream->write((const SECURITY_ATTRIBUTES*)forMarshaling->pAttributes, sizeof(const SECURITY_ATTRIBUTES));
@@ -8067,16 +8285,16 @@
     }
     vkStream->write((uint32_t*)&forMarshaling->waitSemaphoreValuesCount, sizeof(uint32_t));
     // WARNING PTR CHECK
-    uint64_t cgen_var_232 = (uint64_t)(uintptr_t)forMarshaling->pWaitSemaphoreValues;
-    vkStream->putBe64(cgen_var_232);
+    uint64_t cgen_var_246 = (uint64_t)(uintptr_t)forMarshaling->pWaitSemaphoreValues;
+    vkStream->putBe64(cgen_var_246);
     if (forMarshaling->pWaitSemaphoreValues)
     {
         vkStream->write((const uint64_t*)forMarshaling->pWaitSemaphoreValues, forMarshaling->waitSemaphoreValuesCount * sizeof(const uint64_t));
     }
     vkStream->write((uint32_t*)&forMarshaling->signalSemaphoreValuesCount, sizeof(uint32_t));
     // WARNING PTR CHECK
-    uint64_t cgen_var_233 = (uint64_t)(uintptr_t)forMarshaling->pSignalSemaphoreValues;
-    vkStream->putBe64(cgen_var_233);
+    uint64_t cgen_var_247 = (uint64_t)(uintptr_t)forMarshaling->pSignalSemaphoreValues;
+    vkStream->putBe64(cgen_var_247);
     if (forMarshaling->pSignalSemaphoreValues)
     {
         vkStream->write((const uint64_t*)forMarshaling->pSignalSemaphoreValues, forMarshaling->signalSemaphoreValuesCount * sizeof(const uint64_t));
@@ -8134,9 +8352,9 @@
         vkStream->write((const void*)forMarshaling->pNext, sizeof(VkStructureType));
         marshal_extension_struct(vkStream, forMarshaling->pNext);
     }
-    uint64_t cgen_var_236;
-    vkStream->handleMapping()->mapHandles_VkSemaphore_u64(&forMarshaling->semaphore, &cgen_var_236, 1);
-    vkStream->write((uint64_t*)&cgen_var_236, 1 * 8);
+    uint64_t cgen_var_250;
+    vkStream->handleMapping()->mapHandles_VkSemaphore_u64(&forMarshaling->semaphore, &cgen_var_250, 1);
+    vkStream->write((uint64_t*)&cgen_var_250, 1 * 8);
     vkStream->write((VkExternalSemaphoreHandleTypeFlagBits*)&forMarshaling->handleType, sizeof(VkExternalSemaphoreHandleTypeFlagBits));
 }
 
@@ -8153,9 +8371,9 @@
         vkStream->read((void*)(&pNext_placeholder), sizeof(VkStructureType));
         unmarshal_extension_struct(vkStream, (void*)(forUnmarshaling->pNext));
     }
-    uint64_t cgen_var_237;
-    vkStream->read((uint64_t*)&cgen_var_237, 1 * 8);
-    vkStream->handleMapping()->mapHandles_u64_VkSemaphore(&cgen_var_237, (VkSemaphore*)&forUnmarshaling->semaphore, 1);
+    uint64_t cgen_var_251;
+    vkStream->read((uint64_t*)&cgen_var_251, 1 * 8);
+    vkStream->handleMapping()->mapHandles_u64_VkSemaphore(&cgen_var_251, (VkSemaphore*)&forUnmarshaling->semaphore, 1);
     vkStream->read((VkExternalSemaphoreHandleTypeFlagBits*)&forUnmarshaling->handleType, sizeof(VkExternalSemaphoreHandleTypeFlagBits));
 }
 
@@ -8173,9 +8391,9 @@
         vkStream->write((const void*)forMarshaling->pNext, sizeof(VkStructureType));
         marshal_extension_struct(vkStream, forMarshaling->pNext);
     }
-    uint64_t cgen_var_238;
-    vkStream->handleMapping()->mapHandles_VkSemaphore_u64(&forMarshaling->semaphore, &cgen_var_238, 1);
-    vkStream->write((uint64_t*)&cgen_var_238, 1 * 8);
+    uint64_t cgen_var_252;
+    vkStream->handleMapping()->mapHandles_VkSemaphore_u64(&forMarshaling->semaphore, &cgen_var_252, 1);
+    vkStream->write((uint64_t*)&cgen_var_252, 1 * 8);
     vkStream->write((VkSemaphoreImportFlags*)&forMarshaling->flags, sizeof(VkSemaphoreImportFlags));
     vkStream->write((VkExternalSemaphoreHandleTypeFlagBits*)&forMarshaling->handleType, sizeof(VkExternalSemaphoreHandleTypeFlagBits));
     vkStream->write((int*)&forMarshaling->fd, sizeof(int));
@@ -8194,9 +8412,9 @@
         vkStream->read((void*)(&pNext_placeholder), sizeof(VkStructureType));
         unmarshal_extension_struct(vkStream, (void*)(forUnmarshaling->pNext));
     }
-    uint64_t cgen_var_239;
-    vkStream->read((uint64_t*)&cgen_var_239, 1 * 8);
-    vkStream->handleMapping()->mapHandles_u64_VkSemaphore(&cgen_var_239, (VkSemaphore*)&forUnmarshaling->semaphore, 1);
+    uint64_t cgen_var_253;
+    vkStream->read((uint64_t*)&cgen_var_253, 1 * 8);
+    vkStream->handleMapping()->mapHandles_u64_VkSemaphore(&cgen_var_253, (VkSemaphore*)&forUnmarshaling->semaphore, 1);
     vkStream->read((VkSemaphoreImportFlags*)&forUnmarshaling->flags, sizeof(VkSemaphoreImportFlags));
     vkStream->read((VkExternalSemaphoreHandleTypeFlagBits*)&forUnmarshaling->handleType, sizeof(VkExternalSemaphoreHandleTypeFlagBits));
     vkStream->read((int*)&forUnmarshaling->fd, sizeof(int));
@@ -8214,9 +8432,9 @@
         vkStream->write((const void*)forMarshaling->pNext, sizeof(VkStructureType));
         marshal_extension_struct(vkStream, forMarshaling->pNext);
     }
-    uint64_t cgen_var_240;
-    vkStream->handleMapping()->mapHandles_VkSemaphore_u64(&forMarshaling->semaphore, &cgen_var_240, 1);
-    vkStream->write((uint64_t*)&cgen_var_240, 1 * 8);
+    uint64_t cgen_var_254;
+    vkStream->handleMapping()->mapHandles_VkSemaphore_u64(&forMarshaling->semaphore, &cgen_var_254, 1);
+    vkStream->write((uint64_t*)&cgen_var_254, 1 * 8);
     vkStream->write((VkExternalSemaphoreHandleTypeFlagBits*)&forMarshaling->handleType, sizeof(VkExternalSemaphoreHandleTypeFlagBits));
 }
 
@@ -8233,9 +8451,9 @@
         vkStream->read((void*)(&pNext_placeholder), sizeof(VkStructureType));
         unmarshal_extension_struct(vkStream, (void*)(forUnmarshaling->pNext));
     }
-    uint64_t cgen_var_241;
-    vkStream->read((uint64_t*)&cgen_var_241, 1 * 8);
-    vkStream->handleMapping()->mapHandles_u64_VkSemaphore(&cgen_var_241, (VkSemaphore*)&forUnmarshaling->semaphore, 1);
+    uint64_t cgen_var_255;
+    vkStream->read((uint64_t*)&cgen_var_255, 1 * 8);
+    vkStream->handleMapping()->mapHandles_u64_VkSemaphore(&cgen_var_255, (VkSemaphore*)&forUnmarshaling->semaphore, 1);
     vkStream->read((VkExternalSemaphoreHandleTypeFlagBits*)&forUnmarshaling->handleType, sizeof(VkExternalSemaphoreHandleTypeFlagBits));
 }
 
@@ -8300,8 +8518,8 @@
 {
     vkStream->write((uint32_t*)&forMarshaling->rectangleCount, sizeof(uint32_t));
     // WARNING PTR CHECK
-    uint64_t cgen_var_242 = (uint64_t)(uintptr_t)forMarshaling->pRectangles;
-    vkStream->putBe64(cgen_var_242);
+    uint64_t cgen_var_256 = (uint64_t)(uintptr_t)forMarshaling->pRectangles;
+    vkStream->putBe64(cgen_var_256);
     if (forMarshaling->pRectangles)
     {
         for (uint32_t i = 0; i < (uint32_t)forMarshaling->rectangleCount; ++i)
@@ -8346,8 +8564,8 @@
     }
     vkStream->write((uint32_t*)&forMarshaling->swapchainCount, sizeof(uint32_t));
     // WARNING PTR CHECK
-    uint64_t cgen_var_244 = (uint64_t)(uintptr_t)forMarshaling->pRegions;
-    vkStream->putBe64(cgen_var_244);
+    uint64_t cgen_var_258 = (uint64_t)(uintptr_t)forMarshaling->pRegions;
+    vkStream->putBe64(cgen_var_258);
     if (forMarshaling->pRegions)
     {
         for (uint32_t i = 0; i < (uint32_t)forMarshaling->swapchainCount; ++i)
@@ -8499,8 +8717,8 @@
         marshal_VkAttachmentReference2KHR(vkStream, (const VkAttachmentReference2KHR*)(forMarshaling->pColorAttachments + i));
     }
     // WARNING PTR CHECK
-    uint64_t cgen_var_246 = (uint64_t)(uintptr_t)forMarshaling->pResolveAttachments;
-    vkStream->putBe64(cgen_var_246);
+    uint64_t cgen_var_260 = (uint64_t)(uintptr_t)forMarshaling->pResolveAttachments;
+    vkStream->putBe64(cgen_var_260);
     if (forMarshaling->pResolveAttachments)
     {
         for (uint32_t i = 0; i < (uint32_t)forMarshaling->colorAttachmentCount; ++i)
@@ -8509,8 +8727,8 @@
         }
     }
     // WARNING PTR CHECK
-    uint64_t cgen_var_247 = (uint64_t)(uintptr_t)forMarshaling->pDepthStencilAttachment;
-    vkStream->putBe64(cgen_var_247);
+    uint64_t cgen_var_261 = (uint64_t)(uintptr_t)forMarshaling->pDepthStencilAttachment;
+    vkStream->putBe64(cgen_var_261);
     if (forMarshaling->pDepthStencilAttachment)
     {
         marshal_VkAttachmentReference2KHR(vkStream, (const VkAttachmentReference2KHR*)(forMarshaling->pDepthStencilAttachment));
@@ -8795,9 +9013,9 @@
         vkStream->write((const void*)forMarshaling->pNext, sizeof(VkStructureType));
         marshal_extension_struct(vkStream, forMarshaling->pNext);
     }
-    uint64_t cgen_var_250;
-    vkStream->handleMapping()->mapHandles_VkFence_u64(&forMarshaling->fence, &cgen_var_250, 1);
-    vkStream->write((uint64_t*)&cgen_var_250, 1 * 8);
+    uint64_t cgen_var_264;
+    vkStream->handleMapping()->mapHandles_VkFence_u64(&forMarshaling->fence, &cgen_var_264, 1);
+    vkStream->write((uint64_t*)&cgen_var_264, 1 * 8);
     vkStream->write((VkFenceImportFlags*)&forMarshaling->flags, sizeof(VkFenceImportFlags));
     vkStream->write((VkExternalFenceHandleTypeFlagBits*)&forMarshaling->handleType, sizeof(VkExternalFenceHandleTypeFlagBits));
     vkStream->write((HANDLE*)&forMarshaling->handle, sizeof(HANDLE));
@@ -8817,9 +9035,9 @@
         vkStream->read((void*)(&pNext_placeholder), sizeof(VkStructureType));
         unmarshal_extension_struct(vkStream, (void*)(forUnmarshaling->pNext));
     }
-    uint64_t cgen_var_251;
-    vkStream->read((uint64_t*)&cgen_var_251, 1 * 8);
-    vkStream->handleMapping()->mapHandles_u64_VkFence(&cgen_var_251, (VkFence*)&forUnmarshaling->fence, 1);
+    uint64_t cgen_var_265;
+    vkStream->read((uint64_t*)&cgen_var_265, 1 * 8);
+    vkStream->handleMapping()->mapHandles_u64_VkFence(&cgen_var_265, (VkFence*)&forUnmarshaling->fence, 1);
     vkStream->read((VkFenceImportFlags*)&forUnmarshaling->flags, sizeof(VkFenceImportFlags));
     vkStream->read((VkExternalFenceHandleTypeFlagBits*)&forUnmarshaling->handleType, sizeof(VkExternalFenceHandleTypeFlagBits));
     vkStream->read((HANDLE*)&forUnmarshaling->handle, sizeof(HANDLE));
@@ -8839,8 +9057,8 @@
         marshal_extension_struct(vkStream, forMarshaling->pNext);
     }
     // WARNING PTR CHECK
-    uint64_t cgen_var_252 = (uint64_t)(uintptr_t)forMarshaling->pAttributes;
-    vkStream->putBe64(cgen_var_252);
+    uint64_t cgen_var_266 = (uint64_t)(uintptr_t)forMarshaling->pAttributes;
+    vkStream->putBe64(cgen_var_266);
     if (forMarshaling->pAttributes)
     {
         vkStream->write((const SECURITY_ATTRIBUTES*)forMarshaling->pAttributes, sizeof(const SECURITY_ATTRIBUTES));
@@ -8889,9 +9107,9 @@
         vkStream->write((const void*)forMarshaling->pNext, sizeof(VkStructureType));
         marshal_extension_struct(vkStream, forMarshaling->pNext);
     }
-    uint64_t cgen_var_254;
-    vkStream->handleMapping()->mapHandles_VkFence_u64(&forMarshaling->fence, &cgen_var_254, 1);
-    vkStream->write((uint64_t*)&cgen_var_254, 1 * 8);
+    uint64_t cgen_var_268;
+    vkStream->handleMapping()->mapHandles_VkFence_u64(&forMarshaling->fence, &cgen_var_268, 1);
+    vkStream->write((uint64_t*)&cgen_var_268, 1 * 8);
     vkStream->write((VkExternalFenceHandleTypeFlagBits*)&forMarshaling->handleType, sizeof(VkExternalFenceHandleTypeFlagBits));
 }
 
@@ -8908,9 +9126,9 @@
         vkStream->read((void*)(&pNext_placeholder), sizeof(VkStructureType));
         unmarshal_extension_struct(vkStream, (void*)(forUnmarshaling->pNext));
     }
-    uint64_t cgen_var_255;
-    vkStream->read((uint64_t*)&cgen_var_255, 1 * 8);
-    vkStream->handleMapping()->mapHandles_u64_VkFence(&cgen_var_255, (VkFence*)&forUnmarshaling->fence, 1);
+    uint64_t cgen_var_269;
+    vkStream->read((uint64_t*)&cgen_var_269, 1 * 8);
+    vkStream->handleMapping()->mapHandles_u64_VkFence(&cgen_var_269, (VkFence*)&forUnmarshaling->fence, 1);
     vkStream->read((VkExternalFenceHandleTypeFlagBits*)&forUnmarshaling->handleType, sizeof(VkExternalFenceHandleTypeFlagBits));
 }
 
@@ -8928,9 +9146,9 @@
         vkStream->write((const void*)forMarshaling->pNext, sizeof(VkStructureType));
         marshal_extension_struct(vkStream, forMarshaling->pNext);
     }
-    uint64_t cgen_var_256;
-    vkStream->handleMapping()->mapHandles_VkFence_u64(&forMarshaling->fence, &cgen_var_256, 1);
-    vkStream->write((uint64_t*)&cgen_var_256, 1 * 8);
+    uint64_t cgen_var_270;
+    vkStream->handleMapping()->mapHandles_VkFence_u64(&forMarshaling->fence, &cgen_var_270, 1);
+    vkStream->write((uint64_t*)&cgen_var_270, 1 * 8);
     vkStream->write((VkFenceImportFlags*)&forMarshaling->flags, sizeof(VkFenceImportFlags));
     vkStream->write((VkExternalFenceHandleTypeFlagBits*)&forMarshaling->handleType, sizeof(VkExternalFenceHandleTypeFlagBits));
     vkStream->write((int*)&forMarshaling->fd, sizeof(int));
@@ -8949,9 +9167,9 @@
         vkStream->read((void*)(&pNext_placeholder), sizeof(VkStructureType));
         unmarshal_extension_struct(vkStream, (void*)(forUnmarshaling->pNext));
     }
-    uint64_t cgen_var_257;
-    vkStream->read((uint64_t*)&cgen_var_257, 1 * 8);
-    vkStream->handleMapping()->mapHandles_u64_VkFence(&cgen_var_257, (VkFence*)&forUnmarshaling->fence, 1);
+    uint64_t cgen_var_271;
+    vkStream->read((uint64_t*)&cgen_var_271, 1 * 8);
+    vkStream->handleMapping()->mapHandles_u64_VkFence(&cgen_var_271, (VkFence*)&forUnmarshaling->fence, 1);
     vkStream->read((VkFenceImportFlags*)&forUnmarshaling->flags, sizeof(VkFenceImportFlags));
     vkStream->read((VkExternalFenceHandleTypeFlagBits*)&forUnmarshaling->handleType, sizeof(VkExternalFenceHandleTypeFlagBits));
     vkStream->read((int*)&forUnmarshaling->fd, sizeof(int));
@@ -8969,9 +9187,9 @@
         vkStream->write((const void*)forMarshaling->pNext, sizeof(VkStructureType));
         marshal_extension_struct(vkStream, forMarshaling->pNext);
     }
-    uint64_t cgen_var_258;
-    vkStream->handleMapping()->mapHandles_VkFence_u64(&forMarshaling->fence, &cgen_var_258, 1);
-    vkStream->write((uint64_t*)&cgen_var_258, 1 * 8);
+    uint64_t cgen_var_272;
+    vkStream->handleMapping()->mapHandles_VkFence_u64(&forMarshaling->fence, &cgen_var_272, 1);
+    vkStream->write((uint64_t*)&cgen_var_272, 1 * 8);
     vkStream->write((VkExternalFenceHandleTypeFlagBits*)&forMarshaling->handleType, sizeof(VkExternalFenceHandleTypeFlagBits));
 }
 
@@ -8988,9 +9206,9 @@
         vkStream->read((void*)(&pNext_placeholder), sizeof(VkStructureType));
         unmarshal_extension_struct(vkStream, (void*)(forUnmarshaling->pNext));
     }
-    uint64_t cgen_var_259;
-    vkStream->read((uint64_t*)&cgen_var_259, 1 * 8);
-    vkStream->handleMapping()->mapHandles_u64_VkFence(&cgen_var_259, (VkFence*)&forUnmarshaling->fence, 1);
+    uint64_t cgen_var_273;
+    vkStream->read((uint64_t*)&cgen_var_273, 1 * 8);
+    vkStream->handleMapping()->mapHandles_u64_VkFence(&cgen_var_273, (VkFence*)&forUnmarshaling->fence, 1);
     vkStream->read((VkExternalFenceHandleTypeFlagBits*)&forUnmarshaling->handleType, sizeof(VkExternalFenceHandleTypeFlagBits));
 }
 
@@ -9010,9 +9228,9 @@
         vkStream->write((const void*)forMarshaling->pNext, sizeof(VkStructureType));
         marshal_extension_struct(vkStream, forMarshaling->pNext);
     }
-    uint64_t cgen_var_260;
-    vkStream->handleMapping()->mapHandles_VkSurfaceKHR_u64(&forMarshaling->surface, &cgen_var_260, 1);
-    vkStream->write((uint64_t*)&cgen_var_260, 1 * 8);
+    uint64_t cgen_var_274;
+    vkStream->handleMapping()->mapHandles_VkSurfaceKHR_u64(&forMarshaling->surface, &cgen_var_274, 1);
+    vkStream->write((uint64_t*)&cgen_var_274, 1 * 8);
 }
 
 void unmarshal_VkPhysicalDeviceSurfaceInfo2KHR(
@@ -9028,9 +9246,9 @@
         vkStream->read((void*)(&pNext_placeholder), sizeof(VkStructureType));
         unmarshal_extension_struct(vkStream, (void*)(forUnmarshaling->pNext));
     }
-    uint64_t cgen_var_261;
-    vkStream->read((uint64_t*)&cgen_var_261, 1 * 8);
-    vkStream->handleMapping()->mapHandles_u64_VkSurfaceKHR(&cgen_var_261, (VkSurfaceKHR*)&forUnmarshaling->surface, 1);
+    uint64_t cgen_var_275;
+    vkStream->read((uint64_t*)&cgen_var_275, 1 * 8);
+    vkStream->handleMapping()->mapHandles_u64_VkSurfaceKHR(&cgen_var_275, (VkSurfaceKHR*)&forUnmarshaling->surface, 1);
 }
 
 void marshal_VkSurfaceCapabilities2KHR(
@@ -9204,9 +9422,9 @@
         vkStream->write((const void*)forMarshaling->pNext, sizeof(VkStructureType));
         marshal_extension_struct(vkStream, forMarshaling->pNext);
     }
-    uint64_t cgen_var_262;
-    vkStream->handleMapping()->mapHandles_VkDisplayModeKHR_u64(&forMarshaling->mode, &cgen_var_262, 1);
-    vkStream->write((uint64_t*)&cgen_var_262, 1 * 8);
+    uint64_t cgen_var_276;
+    vkStream->handleMapping()->mapHandles_VkDisplayModeKHR_u64(&forMarshaling->mode, &cgen_var_276, 1);
+    vkStream->write((uint64_t*)&cgen_var_276, 1 * 8);
     vkStream->write((uint32_t*)&forMarshaling->planeIndex, sizeof(uint32_t));
 }
 
@@ -9223,9 +9441,9 @@
         vkStream->read((void*)(&pNext_placeholder), sizeof(VkStructureType));
         unmarshal_extension_struct(vkStream, (void*)(forUnmarshaling->pNext));
     }
-    uint64_t cgen_var_263;
-    vkStream->read((uint64_t*)&cgen_var_263, 1 * 8);
-    vkStream->handleMapping()->mapHandles_u64_VkDisplayModeKHR(&cgen_var_263, (VkDisplayModeKHR*)&forUnmarshaling->mode, 1);
+    uint64_t cgen_var_277;
+    vkStream->read((uint64_t*)&cgen_var_277, 1 * 8);
+    vkStream->handleMapping()->mapHandles_u64_VkDisplayModeKHR(&cgen_var_277, (VkDisplayModeKHR*)&forUnmarshaling->mode, 1);
     vkStream->read((uint32_t*)&forUnmarshaling->planeIndex, sizeof(uint32_t));
 }
 
@@ -9363,8 +9581,8 @@
         marshal_extension_struct(vkStream, forMarshaling->pNext);
     }
     // WARNING PTR CHECK
-    uint64_t cgen_var_264 = (uint64_t)(uintptr_t)forMarshaling->handle;
-    vkStream->putBe64(cgen_var_264);
+    uint64_t cgen_var_278 = (uint64_t)(uintptr_t)forMarshaling->handle;
+    vkStream->putBe64(cgen_var_278);
     if (forMarshaling->handle)
     {
         vkStream->write((const uint32_t*)forMarshaling->handle, sizeof(const uint32_t));
@@ -9422,11 +9640,11 @@
         marshal_extension_struct(vkStream, forMarshaling->pNext);
     }
     vkStream->write((VkDebugReportFlagsEXT*)&forMarshaling->flags, sizeof(VkDebugReportFlagsEXT));
-    uint64_t cgen_var_266 = (uint64_t)forMarshaling->pfnCallback;
-    vkStream->putBe64(cgen_var_266);
+    uint64_t cgen_var_280 = (uint64_t)forMarshaling->pfnCallback;
+    vkStream->putBe64(cgen_var_280);
     // WARNING PTR CHECK
-    uint64_t cgen_var_267 = (uint64_t)(uintptr_t)forMarshaling->pUserData;
-    vkStream->putBe64(cgen_var_267);
+    uint64_t cgen_var_281 = (uint64_t)(uintptr_t)forMarshaling->pUserData;
+    vkStream->putBe64(cgen_var_281);
     if (forMarshaling->pUserData)
     {
         vkStream->write((void*)forMarshaling->pUserData, sizeof(uint8_t));
@@ -9556,8 +9774,8 @@
     vkStream->write((VkDebugReportObjectTypeEXT*)&forMarshaling->objectType, sizeof(VkDebugReportObjectTypeEXT));
     vkStream->write((uint64_t*)&forMarshaling->object, sizeof(uint64_t));
     vkStream->write((uint64_t*)&forMarshaling->tagName, sizeof(uint64_t));
-    uint64_t cgen_var_270 = (uint64_t)forMarshaling->tagSize;
-    vkStream->putBe64(cgen_var_270);
+    uint64_t cgen_var_284 = (uint64_t)forMarshaling->tagSize;
+    vkStream->putBe64(cgen_var_284);
     vkStream->write((const void*)forMarshaling->pTag, forMarshaling->tagSize * sizeof(const uint8_t));
 }
 
@@ -9692,12 +9910,12 @@
         vkStream->write((const void*)forMarshaling->pNext, sizeof(VkStructureType));
         marshal_extension_struct(vkStream, forMarshaling->pNext);
     }
-    uint64_t cgen_var_272;
-    vkStream->handleMapping()->mapHandles_VkImage_u64(&forMarshaling->image, &cgen_var_272, 1);
-    vkStream->write((uint64_t*)&cgen_var_272, 1 * 8);
-    uint64_t cgen_var_273;
-    vkStream->handleMapping()->mapHandles_VkBuffer_u64(&forMarshaling->buffer, &cgen_var_273, 1);
-    vkStream->write((uint64_t*)&cgen_var_273, 1 * 8);
+    uint64_t cgen_var_286;
+    vkStream->handleMapping()->mapHandles_VkImage_u64(&forMarshaling->image, &cgen_var_286, 1);
+    vkStream->write((uint64_t*)&cgen_var_286, 1 * 8);
+    uint64_t cgen_var_287;
+    vkStream->handleMapping()->mapHandles_VkBuffer_u64(&forMarshaling->buffer, &cgen_var_287, 1);
+    vkStream->write((uint64_t*)&cgen_var_287, 1 * 8);
 }
 
 void unmarshal_VkDedicatedAllocationMemoryAllocateInfoNV(
@@ -9713,12 +9931,12 @@
         vkStream->read((void*)(&pNext_placeholder), sizeof(VkStructureType));
         unmarshal_extension_struct(vkStream, (void*)(forUnmarshaling->pNext));
     }
-    uint64_t cgen_var_274;
-    vkStream->read((uint64_t*)&cgen_var_274, 1 * 8);
-    vkStream->handleMapping()->mapHandles_u64_VkImage(&cgen_var_274, (VkImage*)&forUnmarshaling->image, 1);
-    uint64_t cgen_var_275;
-    vkStream->read((uint64_t*)&cgen_var_275, 1 * 8);
-    vkStream->handleMapping()->mapHandles_u64_VkBuffer(&cgen_var_275, (VkBuffer*)&forUnmarshaling->buffer, 1);
+    uint64_t cgen_var_288;
+    vkStream->read((uint64_t*)&cgen_var_288, 1 * 8);
+    vkStream->handleMapping()->mapHandles_u64_VkImage(&cgen_var_288, (VkImage*)&forUnmarshaling->image, 1);
+    uint64_t cgen_var_289;
+    vkStream->read((uint64_t*)&cgen_var_289, 1 * 8);
+    vkStream->handleMapping()->mapHandles_u64_VkBuffer(&cgen_var_289, (VkBuffer*)&forUnmarshaling->buffer, 1);
 }
 
 #endif
@@ -9771,10 +9989,10 @@
     vkStream->write((uint32_t*)&forMarshaling->numUsedVgprs, sizeof(uint32_t));
     vkStream->write((uint32_t*)&forMarshaling->numUsedSgprs, sizeof(uint32_t));
     vkStream->write((uint32_t*)&forMarshaling->ldsSizePerLocalWorkGroup, sizeof(uint32_t));
-    uint64_t cgen_var_276 = (uint64_t)forMarshaling->ldsUsageSizeInBytes;
-    vkStream->putBe64(cgen_var_276);
-    uint64_t cgen_var_277 = (uint64_t)forMarshaling->scratchMemUsageInBytes;
-    vkStream->putBe64(cgen_var_277);
+    uint64_t cgen_var_290 = (uint64_t)forMarshaling->ldsUsageSizeInBytes;
+    vkStream->putBe64(cgen_var_290);
+    uint64_t cgen_var_291 = (uint64_t)forMarshaling->scratchMemUsageInBytes;
+    vkStream->putBe64(cgen_var_291);
 }
 
 void unmarshal_VkShaderResourceUsageAMD(
@@ -9952,8 +10170,8 @@
         marshal_extension_struct(vkStream, forMarshaling->pNext);
     }
     // WARNING PTR CHECK
-    uint64_t cgen_var_280 = (uint64_t)(uintptr_t)forMarshaling->pAttributes;
-    vkStream->putBe64(cgen_var_280);
+    uint64_t cgen_var_294 = (uint64_t)(uintptr_t)forMarshaling->pAttributes;
+    vkStream->putBe64(cgen_var_294);
     if (forMarshaling->pAttributes)
     {
         vkStream->write((const SECURITY_ATTRIBUTES*)forMarshaling->pAttributes, sizeof(const SECURITY_ATTRIBUTES));
@@ -10005,20 +10223,20 @@
     vkStream->write((uint32_t*)&forMarshaling->acquireCount, sizeof(uint32_t));
     if (forMarshaling->acquireCount)
     {
-        uint64_t* cgen_var_282;
-        vkStream->alloc((void**)&cgen_var_282, forMarshaling->acquireCount * 8);
-        vkStream->handleMapping()->mapHandles_VkDeviceMemory_u64(forMarshaling->pAcquireSyncs, cgen_var_282, forMarshaling->acquireCount);
-        vkStream->write((uint64_t*)cgen_var_282, forMarshaling->acquireCount * 8);
+        uint64_t* cgen_var_296;
+        vkStream->alloc((void**)&cgen_var_296, forMarshaling->acquireCount * 8);
+        vkStream->handleMapping()->mapHandles_VkDeviceMemory_u64(forMarshaling->pAcquireSyncs, cgen_var_296, forMarshaling->acquireCount);
+        vkStream->write((uint64_t*)cgen_var_296, forMarshaling->acquireCount * 8);
     }
     vkStream->write((const uint64_t*)forMarshaling->pAcquireKeys, forMarshaling->acquireCount * sizeof(const uint64_t));
     vkStream->write((const uint32_t*)forMarshaling->pAcquireTimeoutMilliseconds, forMarshaling->acquireCount * sizeof(const uint32_t));
     vkStream->write((uint32_t*)&forMarshaling->releaseCount, sizeof(uint32_t));
     if (forMarshaling->releaseCount)
     {
-        uint64_t* cgen_var_283;
-        vkStream->alloc((void**)&cgen_var_283, forMarshaling->releaseCount * 8);
-        vkStream->handleMapping()->mapHandles_VkDeviceMemory_u64(forMarshaling->pReleaseSyncs, cgen_var_283, forMarshaling->releaseCount);
-        vkStream->write((uint64_t*)cgen_var_283, forMarshaling->releaseCount * 8);
+        uint64_t* cgen_var_297;
+        vkStream->alloc((void**)&cgen_var_297, forMarshaling->releaseCount * 8);
+        vkStream->handleMapping()->mapHandles_VkDeviceMemory_u64(forMarshaling->pReleaseSyncs, cgen_var_297, forMarshaling->releaseCount);
+        vkStream->write((uint64_t*)cgen_var_297, forMarshaling->releaseCount * 8);
     }
     vkStream->write((const uint64_t*)forMarshaling->pReleaseKeys, forMarshaling->releaseCount * sizeof(const uint64_t));
 }
@@ -10039,20 +10257,20 @@
     vkStream->read((uint32_t*)&forUnmarshaling->acquireCount, sizeof(uint32_t));
     if (forUnmarshaling->acquireCount)
     {
-        uint64_t* cgen_var_284;
-        vkStream->alloc((void**)&cgen_var_284, forUnmarshaling->acquireCount * 8);
-        vkStream->read((uint64_t*)cgen_var_284, forUnmarshaling->acquireCount * 8);
-        vkStream->handleMapping()->mapHandles_u64_VkDeviceMemory(cgen_var_284, (VkDeviceMemory*)forUnmarshaling->pAcquireSyncs, forUnmarshaling->acquireCount);
+        uint64_t* cgen_var_298;
+        vkStream->alloc((void**)&cgen_var_298, forUnmarshaling->acquireCount * 8);
+        vkStream->read((uint64_t*)cgen_var_298, forUnmarshaling->acquireCount * 8);
+        vkStream->handleMapping()->mapHandles_u64_VkDeviceMemory(cgen_var_298, (VkDeviceMemory*)forUnmarshaling->pAcquireSyncs, forUnmarshaling->acquireCount);
     }
     vkStream->read((uint64_t*)forUnmarshaling->pAcquireKeys, forUnmarshaling->acquireCount * sizeof(const uint64_t));
     vkStream->read((uint32_t*)forUnmarshaling->pAcquireTimeoutMilliseconds, forUnmarshaling->acquireCount * sizeof(const uint32_t));
     vkStream->read((uint32_t*)&forUnmarshaling->releaseCount, sizeof(uint32_t));
     if (forUnmarshaling->releaseCount)
     {
-        uint64_t* cgen_var_285;
-        vkStream->alloc((void**)&cgen_var_285, forUnmarshaling->releaseCount * 8);
-        vkStream->read((uint64_t*)cgen_var_285, forUnmarshaling->releaseCount * 8);
-        vkStream->handleMapping()->mapHandles_u64_VkDeviceMemory(cgen_var_285, (VkDeviceMemory*)forUnmarshaling->pReleaseSyncs, forUnmarshaling->releaseCount);
+        uint64_t* cgen_var_299;
+        vkStream->alloc((void**)&cgen_var_299, forUnmarshaling->releaseCount * 8);
+        vkStream->read((uint64_t*)cgen_var_299, forUnmarshaling->releaseCount * 8);
+        vkStream->handleMapping()->mapHandles_u64_VkDeviceMemory(cgen_var_299, (VkDeviceMemory*)forUnmarshaling->pReleaseSyncs, forUnmarshaling->releaseCount);
     }
     vkStream->read((uint64_t*)forUnmarshaling->pReleaseKeys, forUnmarshaling->releaseCount * sizeof(const uint64_t));
 }
@@ -10108,8 +10326,8 @@
     }
     vkStream->write((VkViSurfaceCreateFlagsNN*)&forMarshaling->flags, sizeof(VkViSurfaceCreateFlagsNN));
     // WARNING PTR CHECK
-    uint64_t cgen_var_286 = (uint64_t)(uintptr_t)forMarshaling->window;
-    vkStream->putBe64(cgen_var_286);
+    uint64_t cgen_var_300 = (uint64_t)(uintptr_t)forMarshaling->window;
+    vkStream->putBe64(cgen_var_300);
     if (forMarshaling->window)
     {
         vkStream->write((void*)forMarshaling->window, sizeof(uint8_t));
@@ -10161,9 +10379,9 @@
         vkStream->write((const void*)forMarshaling->pNext, sizeof(VkStructureType));
         marshal_extension_struct(vkStream, forMarshaling->pNext);
     }
-    uint64_t cgen_var_288;
-    vkStream->handleMapping()->mapHandles_VkBuffer_u64(&forMarshaling->buffer, &cgen_var_288, 1);
-    vkStream->write((uint64_t*)&cgen_var_288, 1 * 8);
+    uint64_t cgen_var_302;
+    vkStream->handleMapping()->mapHandles_VkBuffer_u64(&forMarshaling->buffer, &cgen_var_302, 1);
+    vkStream->write((uint64_t*)&cgen_var_302, 1 * 8);
     vkStream->write((VkDeviceSize*)&forMarshaling->offset, sizeof(VkDeviceSize));
     vkStream->write((VkConditionalRenderingFlagsEXT*)&forMarshaling->flags, sizeof(VkConditionalRenderingFlagsEXT));
 }
@@ -10181,9 +10399,9 @@
         vkStream->read((void*)(&pNext_placeholder), sizeof(VkStructureType));
         unmarshal_extension_struct(vkStream, (void*)(forUnmarshaling->pNext));
     }
-    uint64_t cgen_var_289;
-    vkStream->read((uint64_t*)&cgen_var_289, 1 * 8);
-    vkStream->handleMapping()->mapHandles_u64_VkBuffer(&cgen_var_289, (VkBuffer*)&forUnmarshaling->buffer, 1);
+    uint64_t cgen_var_303;
+    vkStream->read((uint64_t*)&cgen_var_303, 1 * 8);
+    vkStream->handleMapping()->mapHandles_u64_VkBuffer(&cgen_var_303, (VkBuffer*)&forUnmarshaling->buffer, 1);
     vkStream->read((VkDeviceSize*)&forUnmarshaling->offset, sizeof(VkDeviceSize));
     vkStream->read((VkConditionalRenderingFlagsEXT*)&forUnmarshaling->flags, sizeof(VkConditionalRenderingFlagsEXT));
 }
@@ -10329,9 +10547,9 @@
     const VkIndirectCommandsTokenNVX* forMarshaling)
 {
     vkStream->write((VkIndirectCommandsTokenTypeNVX*)&forMarshaling->tokenType, sizeof(VkIndirectCommandsTokenTypeNVX));
-    uint64_t cgen_var_290;
-    vkStream->handleMapping()->mapHandles_VkBuffer_u64(&forMarshaling->buffer, &cgen_var_290, 1);
-    vkStream->write((uint64_t*)&cgen_var_290, 1 * 8);
+    uint64_t cgen_var_304;
+    vkStream->handleMapping()->mapHandles_VkBuffer_u64(&forMarshaling->buffer, &cgen_var_304, 1);
+    vkStream->write((uint64_t*)&cgen_var_304, 1 * 8);
     vkStream->write((VkDeviceSize*)&forMarshaling->offset, sizeof(VkDeviceSize));
 }
 
@@ -10340,9 +10558,9 @@
     VkIndirectCommandsTokenNVX* forUnmarshaling)
 {
     vkStream->read((VkIndirectCommandsTokenTypeNVX*)&forUnmarshaling->tokenType, sizeof(VkIndirectCommandsTokenTypeNVX));
-    uint64_t cgen_var_291;
-    vkStream->read((uint64_t*)&cgen_var_291, 1 * 8);
-    vkStream->handleMapping()->mapHandles_u64_VkBuffer(&cgen_var_291, (VkBuffer*)&forUnmarshaling->buffer, 1);
+    uint64_t cgen_var_305;
+    vkStream->read((uint64_t*)&cgen_var_305, 1 * 8);
+    vkStream->handleMapping()->mapHandles_u64_VkBuffer(&cgen_var_305, (VkBuffer*)&forUnmarshaling->buffer, 1);
     vkStream->read((VkDeviceSize*)&forUnmarshaling->offset, sizeof(VkDeviceSize));
 }
 
@@ -10421,28 +10639,28 @@
         vkStream->write((const void*)forMarshaling->pNext, sizeof(VkStructureType));
         marshal_extension_struct(vkStream, forMarshaling->pNext);
     }
-    uint64_t cgen_var_292;
-    vkStream->handleMapping()->mapHandles_VkObjectTableNVX_u64(&forMarshaling->objectTable, &cgen_var_292, 1);
-    vkStream->write((uint64_t*)&cgen_var_292, 1 * 8);
-    uint64_t cgen_var_293;
-    vkStream->handleMapping()->mapHandles_VkIndirectCommandsLayoutNVX_u64(&forMarshaling->indirectCommandsLayout, &cgen_var_293, 1);
-    vkStream->write((uint64_t*)&cgen_var_293, 1 * 8);
+    uint64_t cgen_var_306;
+    vkStream->handleMapping()->mapHandles_VkObjectTableNVX_u64(&forMarshaling->objectTable, &cgen_var_306, 1);
+    vkStream->write((uint64_t*)&cgen_var_306, 1 * 8);
+    uint64_t cgen_var_307;
+    vkStream->handleMapping()->mapHandles_VkIndirectCommandsLayoutNVX_u64(&forMarshaling->indirectCommandsLayout, &cgen_var_307, 1);
+    vkStream->write((uint64_t*)&cgen_var_307, 1 * 8);
     vkStream->write((uint32_t*)&forMarshaling->indirectCommandsTokenCount, sizeof(uint32_t));
     for (uint32_t i = 0; i < (uint32_t)forMarshaling->indirectCommandsTokenCount; ++i)
     {
         marshal_VkIndirectCommandsTokenNVX(vkStream, (const VkIndirectCommandsTokenNVX*)(forMarshaling->pIndirectCommandsTokens + i));
     }
     vkStream->write((uint32_t*)&forMarshaling->maxSequencesCount, sizeof(uint32_t));
-    uint64_t cgen_var_294;
-    vkStream->handleMapping()->mapHandles_VkCommandBuffer_u64(&forMarshaling->targetCommandBuffer, &cgen_var_294, 1);
-    vkStream->write((uint64_t*)&cgen_var_294, 1 * 8);
-    uint64_t cgen_var_295;
-    vkStream->handleMapping()->mapHandles_VkBuffer_u64(&forMarshaling->sequencesCountBuffer, &cgen_var_295, 1);
-    vkStream->write((uint64_t*)&cgen_var_295, 1 * 8);
+    uint64_t cgen_var_308;
+    vkStream->handleMapping()->mapHandles_VkCommandBuffer_u64(&forMarshaling->targetCommandBuffer, &cgen_var_308, 1);
+    vkStream->write((uint64_t*)&cgen_var_308, 1 * 8);
+    uint64_t cgen_var_309;
+    vkStream->handleMapping()->mapHandles_VkBuffer_u64(&forMarshaling->sequencesCountBuffer, &cgen_var_309, 1);
+    vkStream->write((uint64_t*)&cgen_var_309, 1 * 8);
     vkStream->write((VkDeviceSize*)&forMarshaling->sequencesCountOffset, sizeof(VkDeviceSize));
-    uint64_t cgen_var_296;
-    vkStream->handleMapping()->mapHandles_VkBuffer_u64(&forMarshaling->sequencesIndexBuffer, &cgen_var_296, 1);
-    vkStream->write((uint64_t*)&cgen_var_296, 1 * 8);
+    uint64_t cgen_var_310;
+    vkStream->handleMapping()->mapHandles_VkBuffer_u64(&forMarshaling->sequencesIndexBuffer, &cgen_var_310, 1);
+    vkStream->write((uint64_t*)&cgen_var_310, 1 * 8);
     vkStream->write((VkDeviceSize*)&forMarshaling->sequencesIndexOffset, sizeof(VkDeviceSize));
 }
 
@@ -10459,28 +10677,28 @@
         vkStream->read((void*)(&pNext_placeholder), sizeof(VkStructureType));
         unmarshal_extension_struct(vkStream, (void*)(forUnmarshaling->pNext));
     }
-    uint64_t cgen_var_297;
-    vkStream->read((uint64_t*)&cgen_var_297, 1 * 8);
-    vkStream->handleMapping()->mapHandles_u64_VkObjectTableNVX(&cgen_var_297, (VkObjectTableNVX*)&forUnmarshaling->objectTable, 1);
-    uint64_t cgen_var_298;
-    vkStream->read((uint64_t*)&cgen_var_298, 1 * 8);
-    vkStream->handleMapping()->mapHandles_u64_VkIndirectCommandsLayoutNVX(&cgen_var_298, (VkIndirectCommandsLayoutNVX*)&forUnmarshaling->indirectCommandsLayout, 1);
+    uint64_t cgen_var_311;
+    vkStream->read((uint64_t*)&cgen_var_311, 1 * 8);
+    vkStream->handleMapping()->mapHandles_u64_VkObjectTableNVX(&cgen_var_311, (VkObjectTableNVX*)&forUnmarshaling->objectTable, 1);
+    uint64_t cgen_var_312;
+    vkStream->read((uint64_t*)&cgen_var_312, 1 * 8);
+    vkStream->handleMapping()->mapHandles_u64_VkIndirectCommandsLayoutNVX(&cgen_var_312, (VkIndirectCommandsLayoutNVX*)&forUnmarshaling->indirectCommandsLayout, 1);
     vkStream->read((uint32_t*)&forUnmarshaling->indirectCommandsTokenCount, sizeof(uint32_t));
     for (uint32_t i = 0; i < (uint32_t)forUnmarshaling->indirectCommandsTokenCount; ++i)
     {
         unmarshal_VkIndirectCommandsTokenNVX(vkStream, (VkIndirectCommandsTokenNVX*)(forUnmarshaling->pIndirectCommandsTokens + i));
     }
     vkStream->read((uint32_t*)&forUnmarshaling->maxSequencesCount, sizeof(uint32_t));
-    uint64_t cgen_var_299;
-    vkStream->read((uint64_t*)&cgen_var_299, 1 * 8);
-    vkStream->handleMapping()->mapHandles_u64_VkCommandBuffer(&cgen_var_299, (VkCommandBuffer*)&forUnmarshaling->targetCommandBuffer, 1);
-    uint64_t cgen_var_300;
-    vkStream->read((uint64_t*)&cgen_var_300, 1 * 8);
-    vkStream->handleMapping()->mapHandles_u64_VkBuffer(&cgen_var_300, (VkBuffer*)&forUnmarshaling->sequencesCountBuffer, 1);
+    uint64_t cgen_var_313;
+    vkStream->read((uint64_t*)&cgen_var_313, 1 * 8);
+    vkStream->handleMapping()->mapHandles_u64_VkCommandBuffer(&cgen_var_313, (VkCommandBuffer*)&forUnmarshaling->targetCommandBuffer, 1);
+    uint64_t cgen_var_314;
+    vkStream->read((uint64_t*)&cgen_var_314, 1 * 8);
+    vkStream->handleMapping()->mapHandles_u64_VkBuffer(&cgen_var_314, (VkBuffer*)&forUnmarshaling->sequencesCountBuffer, 1);
     vkStream->read((VkDeviceSize*)&forUnmarshaling->sequencesCountOffset, sizeof(VkDeviceSize));
-    uint64_t cgen_var_301;
-    vkStream->read((uint64_t*)&cgen_var_301, 1 * 8);
-    vkStream->handleMapping()->mapHandles_u64_VkBuffer(&cgen_var_301, (VkBuffer*)&forUnmarshaling->sequencesIndexBuffer, 1);
+    uint64_t cgen_var_315;
+    vkStream->read((uint64_t*)&cgen_var_315, 1 * 8);
+    vkStream->handleMapping()->mapHandles_u64_VkBuffer(&cgen_var_315, (VkBuffer*)&forUnmarshaling->sequencesIndexBuffer, 1);
     vkStream->read((VkDeviceSize*)&forUnmarshaling->sequencesIndexOffset, sizeof(VkDeviceSize));
 }
 
@@ -10496,12 +10714,12 @@
         vkStream->write((const void*)forMarshaling->pNext, sizeof(VkStructureType));
         marshal_extension_struct(vkStream, forMarshaling->pNext);
     }
-    uint64_t cgen_var_302;
-    vkStream->handleMapping()->mapHandles_VkObjectTableNVX_u64(&forMarshaling->objectTable, &cgen_var_302, 1);
-    vkStream->write((uint64_t*)&cgen_var_302, 1 * 8);
-    uint64_t cgen_var_303;
-    vkStream->handleMapping()->mapHandles_VkIndirectCommandsLayoutNVX_u64(&forMarshaling->indirectCommandsLayout, &cgen_var_303, 1);
-    vkStream->write((uint64_t*)&cgen_var_303, 1 * 8);
+    uint64_t cgen_var_316;
+    vkStream->handleMapping()->mapHandles_VkObjectTableNVX_u64(&forMarshaling->objectTable, &cgen_var_316, 1);
+    vkStream->write((uint64_t*)&cgen_var_316, 1 * 8);
+    uint64_t cgen_var_317;
+    vkStream->handleMapping()->mapHandles_VkIndirectCommandsLayoutNVX_u64(&forMarshaling->indirectCommandsLayout, &cgen_var_317, 1);
+    vkStream->write((uint64_t*)&cgen_var_317, 1 * 8);
     vkStream->write((uint32_t*)&forMarshaling->maxSequencesCount, sizeof(uint32_t));
 }
 
@@ -10518,12 +10736,12 @@
         vkStream->read((void*)(&pNext_placeholder), sizeof(VkStructureType));
         unmarshal_extension_struct(vkStream, (void*)(forUnmarshaling->pNext));
     }
-    uint64_t cgen_var_304;
-    vkStream->read((uint64_t*)&cgen_var_304, 1 * 8);
-    vkStream->handleMapping()->mapHandles_u64_VkObjectTableNVX(&cgen_var_304, (VkObjectTableNVX*)&forUnmarshaling->objectTable, 1);
-    uint64_t cgen_var_305;
-    vkStream->read((uint64_t*)&cgen_var_305, 1 * 8);
-    vkStream->handleMapping()->mapHandles_u64_VkIndirectCommandsLayoutNVX(&cgen_var_305, (VkIndirectCommandsLayoutNVX*)&forUnmarshaling->indirectCommandsLayout, 1);
+    uint64_t cgen_var_318;
+    vkStream->read((uint64_t*)&cgen_var_318, 1 * 8);
+    vkStream->handleMapping()->mapHandles_u64_VkObjectTableNVX(&cgen_var_318, (VkObjectTableNVX*)&forUnmarshaling->objectTable, 1);
+    uint64_t cgen_var_319;
+    vkStream->read((uint64_t*)&cgen_var_319, 1 * 8);
+    vkStream->handleMapping()->mapHandles_u64_VkIndirectCommandsLayoutNVX(&cgen_var_319, (VkIndirectCommandsLayoutNVX*)&forUnmarshaling->indirectCommandsLayout, 1);
     vkStream->read((uint32_t*)&forUnmarshaling->maxSequencesCount, sizeof(uint32_t));
 }
 
@@ -10596,9 +10814,9 @@
 {
     vkStream->write((VkObjectEntryTypeNVX*)&forMarshaling->type, sizeof(VkObjectEntryTypeNVX));
     vkStream->write((VkObjectEntryUsageFlagsNVX*)&forMarshaling->flags, sizeof(VkObjectEntryUsageFlagsNVX));
-    uint64_t cgen_var_306;
-    vkStream->handleMapping()->mapHandles_VkPipeline_u64(&forMarshaling->pipeline, &cgen_var_306, 1);
-    vkStream->write((uint64_t*)&cgen_var_306, 1 * 8);
+    uint64_t cgen_var_320;
+    vkStream->handleMapping()->mapHandles_VkPipeline_u64(&forMarshaling->pipeline, &cgen_var_320, 1);
+    vkStream->write((uint64_t*)&cgen_var_320, 1 * 8);
 }
 
 void unmarshal_VkObjectTablePipelineEntryNVX(
@@ -10607,9 +10825,9 @@
 {
     vkStream->read((VkObjectEntryTypeNVX*)&forUnmarshaling->type, sizeof(VkObjectEntryTypeNVX));
     vkStream->read((VkObjectEntryUsageFlagsNVX*)&forUnmarshaling->flags, sizeof(VkObjectEntryUsageFlagsNVX));
-    uint64_t cgen_var_307;
-    vkStream->read((uint64_t*)&cgen_var_307, 1 * 8);
-    vkStream->handleMapping()->mapHandles_u64_VkPipeline(&cgen_var_307, (VkPipeline*)&forUnmarshaling->pipeline, 1);
+    uint64_t cgen_var_321;
+    vkStream->read((uint64_t*)&cgen_var_321, 1 * 8);
+    vkStream->handleMapping()->mapHandles_u64_VkPipeline(&cgen_var_321, (VkPipeline*)&forUnmarshaling->pipeline, 1);
 }
 
 void marshal_VkObjectTableDescriptorSetEntryNVX(
@@ -10618,12 +10836,12 @@
 {
     vkStream->write((VkObjectEntryTypeNVX*)&forMarshaling->type, sizeof(VkObjectEntryTypeNVX));
     vkStream->write((VkObjectEntryUsageFlagsNVX*)&forMarshaling->flags, sizeof(VkObjectEntryUsageFlagsNVX));
-    uint64_t cgen_var_308;
-    vkStream->handleMapping()->mapHandles_VkPipelineLayout_u64(&forMarshaling->pipelineLayout, &cgen_var_308, 1);
-    vkStream->write((uint64_t*)&cgen_var_308, 1 * 8);
-    uint64_t cgen_var_309;
-    vkStream->handleMapping()->mapHandles_VkDescriptorSet_u64(&forMarshaling->descriptorSet, &cgen_var_309, 1);
-    vkStream->write((uint64_t*)&cgen_var_309, 1 * 8);
+    uint64_t cgen_var_322;
+    vkStream->handleMapping()->mapHandles_VkPipelineLayout_u64(&forMarshaling->pipelineLayout, &cgen_var_322, 1);
+    vkStream->write((uint64_t*)&cgen_var_322, 1 * 8);
+    uint64_t cgen_var_323;
+    vkStream->handleMapping()->mapHandles_VkDescriptorSet_u64(&forMarshaling->descriptorSet, &cgen_var_323, 1);
+    vkStream->write((uint64_t*)&cgen_var_323, 1 * 8);
 }
 
 void unmarshal_VkObjectTableDescriptorSetEntryNVX(
@@ -10632,12 +10850,12 @@
 {
     vkStream->read((VkObjectEntryTypeNVX*)&forUnmarshaling->type, sizeof(VkObjectEntryTypeNVX));
     vkStream->read((VkObjectEntryUsageFlagsNVX*)&forUnmarshaling->flags, sizeof(VkObjectEntryUsageFlagsNVX));
-    uint64_t cgen_var_310;
-    vkStream->read((uint64_t*)&cgen_var_310, 1 * 8);
-    vkStream->handleMapping()->mapHandles_u64_VkPipelineLayout(&cgen_var_310, (VkPipelineLayout*)&forUnmarshaling->pipelineLayout, 1);
-    uint64_t cgen_var_311;
-    vkStream->read((uint64_t*)&cgen_var_311, 1 * 8);
-    vkStream->handleMapping()->mapHandles_u64_VkDescriptorSet(&cgen_var_311, (VkDescriptorSet*)&forUnmarshaling->descriptorSet, 1);
+    uint64_t cgen_var_324;
+    vkStream->read((uint64_t*)&cgen_var_324, 1 * 8);
+    vkStream->handleMapping()->mapHandles_u64_VkPipelineLayout(&cgen_var_324, (VkPipelineLayout*)&forUnmarshaling->pipelineLayout, 1);
+    uint64_t cgen_var_325;
+    vkStream->read((uint64_t*)&cgen_var_325, 1 * 8);
+    vkStream->handleMapping()->mapHandles_u64_VkDescriptorSet(&cgen_var_325, (VkDescriptorSet*)&forUnmarshaling->descriptorSet, 1);
 }
 
 void marshal_VkObjectTableVertexBufferEntryNVX(
@@ -10646,9 +10864,9 @@
 {
     vkStream->write((VkObjectEntryTypeNVX*)&forMarshaling->type, sizeof(VkObjectEntryTypeNVX));
     vkStream->write((VkObjectEntryUsageFlagsNVX*)&forMarshaling->flags, sizeof(VkObjectEntryUsageFlagsNVX));
-    uint64_t cgen_var_312;
-    vkStream->handleMapping()->mapHandles_VkBuffer_u64(&forMarshaling->buffer, &cgen_var_312, 1);
-    vkStream->write((uint64_t*)&cgen_var_312, 1 * 8);
+    uint64_t cgen_var_326;
+    vkStream->handleMapping()->mapHandles_VkBuffer_u64(&forMarshaling->buffer, &cgen_var_326, 1);
+    vkStream->write((uint64_t*)&cgen_var_326, 1 * 8);
 }
 
 void unmarshal_VkObjectTableVertexBufferEntryNVX(
@@ -10657,9 +10875,9 @@
 {
     vkStream->read((VkObjectEntryTypeNVX*)&forUnmarshaling->type, sizeof(VkObjectEntryTypeNVX));
     vkStream->read((VkObjectEntryUsageFlagsNVX*)&forUnmarshaling->flags, sizeof(VkObjectEntryUsageFlagsNVX));
-    uint64_t cgen_var_313;
-    vkStream->read((uint64_t*)&cgen_var_313, 1 * 8);
-    vkStream->handleMapping()->mapHandles_u64_VkBuffer(&cgen_var_313, (VkBuffer*)&forUnmarshaling->buffer, 1);
+    uint64_t cgen_var_327;
+    vkStream->read((uint64_t*)&cgen_var_327, 1 * 8);
+    vkStream->handleMapping()->mapHandles_u64_VkBuffer(&cgen_var_327, (VkBuffer*)&forUnmarshaling->buffer, 1);
 }
 
 void marshal_VkObjectTableIndexBufferEntryNVX(
@@ -10668,9 +10886,9 @@
 {
     vkStream->write((VkObjectEntryTypeNVX*)&forMarshaling->type, sizeof(VkObjectEntryTypeNVX));
     vkStream->write((VkObjectEntryUsageFlagsNVX*)&forMarshaling->flags, sizeof(VkObjectEntryUsageFlagsNVX));
-    uint64_t cgen_var_314;
-    vkStream->handleMapping()->mapHandles_VkBuffer_u64(&forMarshaling->buffer, &cgen_var_314, 1);
-    vkStream->write((uint64_t*)&cgen_var_314, 1 * 8);
+    uint64_t cgen_var_328;
+    vkStream->handleMapping()->mapHandles_VkBuffer_u64(&forMarshaling->buffer, &cgen_var_328, 1);
+    vkStream->write((uint64_t*)&cgen_var_328, 1 * 8);
     vkStream->write((VkIndexType*)&forMarshaling->indexType, sizeof(VkIndexType));
 }
 
@@ -10680,9 +10898,9 @@
 {
     vkStream->read((VkObjectEntryTypeNVX*)&forUnmarshaling->type, sizeof(VkObjectEntryTypeNVX));
     vkStream->read((VkObjectEntryUsageFlagsNVX*)&forUnmarshaling->flags, sizeof(VkObjectEntryUsageFlagsNVX));
-    uint64_t cgen_var_315;
-    vkStream->read((uint64_t*)&cgen_var_315, 1 * 8);
-    vkStream->handleMapping()->mapHandles_u64_VkBuffer(&cgen_var_315, (VkBuffer*)&forUnmarshaling->buffer, 1);
+    uint64_t cgen_var_329;
+    vkStream->read((uint64_t*)&cgen_var_329, 1 * 8);
+    vkStream->handleMapping()->mapHandles_u64_VkBuffer(&cgen_var_329, (VkBuffer*)&forUnmarshaling->buffer, 1);
     vkStream->read((VkIndexType*)&forUnmarshaling->indexType, sizeof(VkIndexType));
 }
 
@@ -10692,9 +10910,9 @@
 {
     vkStream->write((VkObjectEntryTypeNVX*)&forMarshaling->type, sizeof(VkObjectEntryTypeNVX));
     vkStream->write((VkObjectEntryUsageFlagsNVX*)&forMarshaling->flags, sizeof(VkObjectEntryUsageFlagsNVX));
-    uint64_t cgen_var_316;
-    vkStream->handleMapping()->mapHandles_VkPipelineLayout_u64(&forMarshaling->pipelineLayout, &cgen_var_316, 1);
-    vkStream->write((uint64_t*)&cgen_var_316, 1 * 8);
+    uint64_t cgen_var_330;
+    vkStream->handleMapping()->mapHandles_VkPipelineLayout_u64(&forMarshaling->pipelineLayout, &cgen_var_330, 1);
+    vkStream->write((uint64_t*)&cgen_var_330, 1 * 8);
     vkStream->write((VkShaderStageFlags*)&forMarshaling->stageFlags, sizeof(VkShaderStageFlags));
 }
 
@@ -10704,9 +10922,9 @@
 {
     vkStream->read((VkObjectEntryTypeNVX*)&forUnmarshaling->type, sizeof(VkObjectEntryTypeNVX));
     vkStream->read((VkObjectEntryUsageFlagsNVX*)&forUnmarshaling->flags, sizeof(VkObjectEntryUsageFlagsNVX));
-    uint64_t cgen_var_317;
-    vkStream->read((uint64_t*)&cgen_var_317, 1 * 8);
-    vkStream->handleMapping()->mapHandles_u64_VkPipelineLayout(&cgen_var_317, (VkPipelineLayout*)&forUnmarshaling->pipelineLayout, 1);
+    uint64_t cgen_var_331;
+    vkStream->read((uint64_t*)&cgen_var_331, 1 * 8);
+    vkStream->handleMapping()->mapHandles_u64_VkPipelineLayout(&cgen_var_331, (VkPipelineLayout*)&forUnmarshaling->pipelineLayout, 1);
     vkStream->read((VkShaderStageFlags*)&forUnmarshaling->stageFlags, sizeof(VkShaderStageFlags));
 }
 
@@ -10743,8 +10961,8 @@
     vkStream->write((VkBool32*)&forMarshaling->viewportWScalingEnable, sizeof(VkBool32));
     vkStream->write((uint32_t*)&forMarshaling->viewportCount, sizeof(uint32_t));
     // WARNING PTR CHECK
-    uint64_t cgen_var_318 = (uint64_t)(uintptr_t)forMarshaling->pViewportWScalings;
-    vkStream->putBe64(cgen_var_318);
+    uint64_t cgen_var_332 = (uint64_t)(uintptr_t)forMarshaling->pViewportWScalings;
+    vkStream->putBe64(cgen_var_332);
     if (forMarshaling->pViewportWScalings)
     {
         for (uint32_t i = 0; i < (uint32_t)forMarshaling->viewportCount; ++i)
@@ -11036,8 +11254,8 @@
     }
     vkStream->write((uint32_t*)&forMarshaling->swapchainCount, sizeof(uint32_t));
     // WARNING PTR CHECK
-    uint64_t cgen_var_320 = (uint64_t)(uintptr_t)forMarshaling->pTimes;
-    vkStream->putBe64(cgen_var_320);
+    uint64_t cgen_var_334 = (uint64_t)(uintptr_t)forMarshaling->pTimes;
+    vkStream->putBe64(cgen_var_334);
     if (forMarshaling->pTimes)
     {
         for (uint32_t i = 0; i < (uint32_t)forMarshaling->swapchainCount; ++i)
@@ -11153,8 +11371,8 @@
     vkStream->write((VkPipelineViewportSwizzleStateCreateFlagsNV*)&forMarshaling->flags, sizeof(VkPipelineViewportSwizzleStateCreateFlagsNV));
     vkStream->write((uint32_t*)&forMarshaling->viewportCount, sizeof(uint32_t));
     // WARNING PTR CHECK
-    uint64_t cgen_var_322 = (uint64_t)(uintptr_t)forMarshaling->pViewportSwizzles;
-    vkStream->putBe64(cgen_var_322);
+    uint64_t cgen_var_336 = (uint64_t)(uintptr_t)forMarshaling->pViewportSwizzles;
+    vkStream->putBe64(cgen_var_336);
     if (forMarshaling->pViewportSwizzles)
     {
         for (uint32_t i = 0; i < (uint32_t)forMarshaling->viewportCount; ++i)
@@ -11244,8 +11462,8 @@
     vkStream->write((VkDiscardRectangleModeEXT*)&forMarshaling->discardRectangleMode, sizeof(VkDiscardRectangleModeEXT));
     vkStream->write((uint32_t*)&forMarshaling->discardRectangleCount, sizeof(uint32_t));
     // WARNING PTR CHECK
-    uint64_t cgen_var_324 = (uint64_t)(uintptr_t)forMarshaling->pDiscardRectangles;
-    vkStream->putBe64(cgen_var_324);
+    uint64_t cgen_var_338 = (uint64_t)(uintptr_t)forMarshaling->pDiscardRectangles;
+    vkStream->putBe64(cgen_var_338);
     if (forMarshaling->pDiscardRectangles)
     {
         for (uint32_t i = 0; i < (uint32_t)forMarshaling->discardRectangleCount; ++i)
@@ -11452,8 +11670,8 @@
     }
     vkStream->write((VkIOSSurfaceCreateFlagsMVK*)&forMarshaling->flags, sizeof(VkIOSSurfaceCreateFlagsMVK));
     // WARNING PTR CHECK
-    uint64_t cgen_var_326 = (uint64_t)(uintptr_t)forMarshaling->pView;
-    vkStream->putBe64(cgen_var_326);
+    uint64_t cgen_var_340 = (uint64_t)(uintptr_t)forMarshaling->pView;
+    vkStream->putBe64(cgen_var_340);
     if (forMarshaling->pView)
     {
         vkStream->write((const void*)forMarshaling->pView, sizeof(const uint8_t));
@@ -11503,8 +11721,8 @@
     }
     vkStream->write((VkMacOSSurfaceCreateFlagsMVK*)&forMarshaling->flags, sizeof(VkMacOSSurfaceCreateFlagsMVK));
     // WARNING PTR CHECK
-    uint64_t cgen_var_328 = (uint64_t)(uintptr_t)forMarshaling->pView;
-    vkStream->putBe64(cgen_var_328);
+    uint64_t cgen_var_342 = (uint64_t)(uintptr_t)forMarshaling->pView;
+    vkStream->putBe64(cgen_var_342);
     if (forMarshaling->pView)
     {
         vkStream->write((const void*)forMarshaling->pView, sizeof(const uint8_t));
@@ -11558,7 +11776,20 @@
     }
     vkStream->write((VkObjectType*)&forMarshaling->objectType, sizeof(VkObjectType));
     vkStream->write((uint64_t*)&forMarshaling->objectHandle, sizeof(uint64_t));
-    vkStream->putString(forMarshaling->pObjectName);
+    if (vkStream->getFeatureBits() & VULKAN_STREAM_FEATURE_NULL_OPTIONAL_STRINGS_BIT)
+    {
+        // WARNING PTR CHECK
+        uint64_t cgen_var_344 = (uint64_t)(uintptr_t)forMarshaling->pObjectName;
+        vkStream->putBe64(cgen_var_344);
+        if (forMarshaling->pObjectName)
+        {
+            vkStream->putString(forMarshaling->pObjectName);
+        }
+    }
+    else
+    {
+        vkStream->putString(forMarshaling->pObjectName);
+    }
 }
 
 void unmarshal_VkDebugUtilsObjectNameInfoEXT(
@@ -11576,7 +11807,24 @@
     }
     vkStream->read((VkObjectType*)&forUnmarshaling->objectType, sizeof(VkObjectType));
     vkStream->read((uint64_t*)&forUnmarshaling->objectHandle, sizeof(uint64_t));
-    vkStream->loadStringInPlace((char**)&forUnmarshaling->pObjectName);
+    if (vkStream->getFeatureBits() & VULKAN_STREAM_FEATURE_NULL_OPTIONAL_STRINGS_BIT)
+    {
+        // WARNING PTR CHECK
+        const char* check_pObjectName;
+        check_pObjectName = (const char*)(uintptr_t)vkStream->getBe64();
+        if (forUnmarshaling->pObjectName)
+        {
+            if (!(check_pObjectName))
+            {
+                fprintf(stderr, "fatal: forUnmarshaling->pObjectName inconsistent between guest and host\n");
+            }
+            vkStream->loadStringInPlace((char**)&forUnmarshaling->pObjectName);
+        }
+    }
+    else
+    {
+        vkStream->loadStringInPlace((char**)&forUnmarshaling->pObjectName);
+    }
 }
 
 void marshal_VkDebugUtilsObjectTagInfoEXT(
@@ -11594,8 +11842,8 @@
     vkStream->write((VkObjectType*)&forMarshaling->objectType, sizeof(VkObjectType));
     vkStream->write((uint64_t*)&forMarshaling->objectHandle, sizeof(uint64_t));
     vkStream->write((uint64_t*)&forMarshaling->tagName, sizeof(uint64_t));
-    uint64_t cgen_var_330 = (uint64_t)forMarshaling->tagSize;
-    vkStream->putBe64(cgen_var_330);
+    uint64_t cgen_var_346 = (uint64_t)forMarshaling->tagSize;
+    vkStream->putBe64(cgen_var_346);
     vkStream->write((const void*)forMarshaling->pTag, forMarshaling->tagSize * sizeof(const uint8_t));
 }
 
@@ -11665,13 +11913,26 @@
         marshal_extension_struct(vkStream, forMarshaling->pNext);
     }
     vkStream->write((VkDebugUtilsMessengerCallbackDataFlagsEXT*)&forMarshaling->flags, sizeof(VkDebugUtilsMessengerCallbackDataFlagsEXT));
-    vkStream->putString(forMarshaling->pMessageIdName);
+    if (vkStream->getFeatureBits() & VULKAN_STREAM_FEATURE_NULL_OPTIONAL_STRINGS_BIT)
+    {
+        // WARNING PTR CHECK
+        uint64_t cgen_var_348 = (uint64_t)(uintptr_t)forMarshaling->pMessageIdName;
+        vkStream->putBe64(cgen_var_348);
+        if (forMarshaling->pMessageIdName)
+        {
+            vkStream->putString(forMarshaling->pMessageIdName);
+        }
+    }
+    else
+    {
+        vkStream->putString(forMarshaling->pMessageIdName);
+    }
     vkStream->write((int32_t*)&forMarshaling->messageIdNumber, sizeof(int32_t));
     vkStream->putString(forMarshaling->pMessage);
     vkStream->write((uint32_t*)&forMarshaling->queueLabelCount, sizeof(uint32_t));
     // WARNING PTR CHECK
-    uint64_t cgen_var_332 = (uint64_t)(uintptr_t)forMarshaling->pQueueLabels;
-    vkStream->putBe64(cgen_var_332);
+    uint64_t cgen_var_349 = (uint64_t)(uintptr_t)forMarshaling->pQueueLabels;
+    vkStream->putBe64(cgen_var_349);
     if (forMarshaling->pQueueLabels)
     {
         for (uint32_t i = 0; i < (uint32_t)forMarshaling->queueLabelCount; ++i)
@@ -11681,8 +11942,8 @@
     }
     vkStream->write((uint32_t*)&forMarshaling->cmdBufLabelCount, sizeof(uint32_t));
     // WARNING PTR CHECK
-    uint64_t cgen_var_333 = (uint64_t)(uintptr_t)forMarshaling->pCmdBufLabels;
-    vkStream->putBe64(cgen_var_333);
+    uint64_t cgen_var_350 = (uint64_t)(uintptr_t)forMarshaling->pCmdBufLabels;
+    vkStream->putBe64(cgen_var_350);
     if (forMarshaling->pCmdBufLabels)
     {
         for (uint32_t i = 0; i < (uint32_t)forMarshaling->cmdBufLabelCount; ++i)
@@ -11692,8 +11953,8 @@
     }
     vkStream->write((uint32_t*)&forMarshaling->objectCount, sizeof(uint32_t));
     // WARNING PTR CHECK
-    uint64_t cgen_var_334 = (uint64_t)(uintptr_t)forMarshaling->pObjects;
-    vkStream->putBe64(cgen_var_334);
+    uint64_t cgen_var_351 = (uint64_t)(uintptr_t)forMarshaling->pObjects;
+    vkStream->putBe64(cgen_var_351);
     if (forMarshaling->pObjects)
     {
         for (uint32_t i = 0; i < (uint32_t)forMarshaling->objectCount; ++i)
@@ -11717,7 +11978,24 @@
         unmarshal_extension_struct(vkStream, (void*)(forUnmarshaling->pNext));
     }
     vkStream->read((VkDebugUtilsMessengerCallbackDataFlagsEXT*)&forUnmarshaling->flags, sizeof(VkDebugUtilsMessengerCallbackDataFlagsEXT));
-    vkStream->loadStringInPlace((char**)&forUnmarshaling->pMessageIdName);
+    if (vkStream->getFeatureBits() & VULKAN_STREAM_FEATURE_NULL_OPTIONAL_STRINGS_BIT)
+    {
+        // WARNING PTR CHECK
+        const char* check_pMessageIdName;
+        check_pMessageIdName = (const char*)(uintptr_t)vkStream->getBe64();
+        if (forUnmarshaling->pMessageIdName)
+        {
+            if (!(check_pMessageIdName))
+            {
+                fprintf(stderr, "fatal: forUnmarshaling->pMessageIdName inconsistent between guest and host\n");
+            }
+            vkStream->loadStringInPlace((char**)&forUnmarshaling->pMessageIdName);
+        }
+    }
+    else
+    {
+        vkStream->loadStringInPlace((char**)&forUnmarshaling->pMessageIdName);
+    }
     vkStream->read((int32_t*)&forUnmarshaling->messageIdNumber, sizeof(int32_t));
     vkStream->loadStringInPlace((char**)&forUnmarshaling->pMessage);
     vkStream->read((uint32_t*)&forUnmarshaling->queueLabelCount, sizeof(uint32_t));
@@ -11782,11 +12060,11 @@
     vkStream->write((VkDebugUtilsMessengerCreateFlagsEXT*)&forMarshaling->flags, sizeof(VkDebugUtilsMessengerCreateFlagsEXT));
     vkStream->write((VkDebugUtilsMessageSeverityFlagsEXT*)&forMarshaling->messageSeverity, sizeof(VkDebugUtilsMessageSeverityFlagsEXT));
     vkStream->write((VkDebugUtilsMessageTypeFlagsEXT*)&forMarshaling->messageType, sizeof(VkDebugUtilsMessageTypeFlagsEXT));
-    uint64_t cgen_var_338 = (uint64_t)forMarshaling->pfnUserCallback;
-    vkStream->putBe64(cgen_var_338);
+    uint64_t cgen_var_356 = (uint64_t)forMarshaling->pfnUserCallback;
+    vkStream->putBe64(cgen_var_356);
     // WARNING PTR CHECK
-    uint64_t cgen_var_339 = (uint64_t)(uintptr_t)forMarshaling->pUserData;
-    vkStream->putBe64(cgen_var_339);
+    uint64_t cgen_var_357 = (uint64_t)(uintptr_t)forMarshaling->pUserData;
+    vkStream->putBe64(cgen_var_357);
     if (forMarshaling->pUserData)
     {
         vkStream->write((void*)forMarshaling->pUserData, sizeof(uint8_t));
@@ -11977,9 +12255,9 @@
         vkStream->write((const void*)forMarshaling->pNext, sizeof(VkStructureType));
         marshal_extension_struct(vkStream, forMarshaling->pNext);
     }
-    uint64_t cgen_var_342;
-    vkStream->handleMapping()->mapHandles_VkDeviceMemory_u64(&forMarshaling->memory, &cgen_var_342, 1);
-    vkStream->write((uint64_t*)&cgen_var_342, 1 * 8);
+    uint64_t cgen_var_360;
+    vkStream->handleMapping()->mapHandles_VkDeviceMemory_u64(&forMarshaling->memory, &cgen_var_360, 1);
+    vkStream->write((uint64_t*)&cgen_var_360, 1 * 8);
 }
 
 void unmarshal_VkMemoryGetAndroidHardwareBufferInfoANDROID(
@@ -11995,9 +12273,9 @@
         vkStream->read((void*)(&pNext_placeholder), sizeof(VkStructureType));
         unmarshal_extension_struct(vkStream, (void*)(forUnmarshaling->pNext));
     }
-    uint64_t cgen_var_343;
-    vkStream->read((uint64_t*)&cgen_var_343, 1 * 8);
-    vkStream->handleMapping()->mapHandles_u64_VkDeviceMemory(&cgen_var_343, (VkDeviceMemory*)&forUnmarshaling->memory, 1);
+    uint64_t cgen_var_361;
+    vkStream->read((uint64_t*)&cgen_var_361, 1 * 8);
+    vkStream->handleMapping()->mapHandles_u64_VkDeviceMemory(&cgen_var_361, (VkDeviceMemory*)&forUnmarshaling->memory, 1);
 }
 
 void marshal_VkExternalFormatANDROID(
@@ -12515,8 +12793,8 @@
     vkStream->write((VkBool32*)&forMarshaling->coverageModulationTableEnable, sizeof(VkBool32));
     vkStream->write((uint32_t*)&forMarshaling->coverageModulationTableCount, sizeof(uint32_t));
     // WARNING PTR CHECK
-    uint64_t cgen_var_344 = (uint64_t)(uintptr_t)forMarshaling->pCoverageModulationTable;
-    vkStream->putBe64(cgen_var_344);
+    uint64_t cgen_var_362 = (uint64_t)(uintptr_t)forMarshaling->pCoverageModulationTable;
+    vkStream->putBe64(cgen_var_362);
     if (forMarshaling->pCoverageModulationTable)
     {
         vkStream->write((const float*)forMarshaling->pCoverageModulationTable, forMarshaling->coverageModulationTableCount * sizeof(const float));
@@ -12572,8 +12850,8 @@
         marshal_extension_struct(vkStream, forMarshaling->pNext);
     }
     vkStream->write((VkValidationCacheCreateFlagsEXT*)&forMarshaling->flags, sizeof(VkValidationCacheCreateFlagsEXT));
-    uint64_t cgen_var_346 = (uint64_t)forMarshaling->initialDataSize;
-    vkStream->putBe64(cgen_var_346);
+    uint64_t cgen_var_364 = (uint64_t)forMarshaling->initialDataSize;
+    vkStream->putBe64(cgen_var_364);
     vkStream->write((const void*)forMarshaling->pInitialData, forMarshaling->initialDataSize * sizeof(const uint8_t));
 }
 
@@ -12607,9 +12885,9 @@
         vkStream->write((const void*)forMarshaling->pNext, sizeof(VkStructureType));
         marshal_extension_struct(vkStream, forMarshaling->pNext);
     }
-    uint64_t cgen_var_348;
-    vkStream->handleMapping()->mapHandles_VkValidationCacheEXT_u64(&forMarshaling->validationCache, &cgen_var_348, 1);
-    vkStream->write((uint64_t*)&cgen_var_348, 1 * 8);
+    uint64_t cgen_var_366;
+    vkStream->handleMapping()->mapHandles_VkValidationCacheEXT_u64(&forMarshaling->validationCache, &cgen_var_366, 1);
+    vkStream->write((uint64_t*)&cgen_var_366, 1 * 8);
 }
 
 void unmarshal_VkShaderModuleValidationCacheCreateInfoEXT(
@@ -12625,9 +12903,9 @@
         vkStream->read((void*)(&pNext_placeholder), sizeof(VkStructureType));
         unmarshal_extension_struct(vkStream, (void*)(forUnmarshaling->pNext));
     }
-    uint64_t cgen_var_349;
-    vkStream->read((uint64_t*)&cgen_var_349, 1 * 8);
-    vkStream->handleMapping()->mapHandles_u64_VkValidationCacheEXT(&cgen_var_349, (VkValidationCacheEXT*)&forUnmarshaling->validationCache, 1);
+    uint64_t cgen_var_367;
+    vkStream->read((uint64_t*)&cgen_var_367, 1 * 8);
+    vkStream->handleMapping()->mapHandles_u64_VkValidationCacheEXT(&cgen_var_367, (VkValidationCacheEXT*)&forUnmarshaling->validationCache, 1);
 }
 
 #endif
@@ -12924,8 +13202,8 @@
     }
     vkStream->write((VkExternalMemoryHandleTypeFlagBits*)&forMarshaling->handleType, sizeof(VkExternalMemoryHandleTypeFlagBits));
     // WARNING PTR CHECK
-    uint64_t cgen_var_350 = (uint64_t)(uintptr_t)forMarshaling->pHostPointer;
-    vkStream->putBe64(cgen_var_350);
+    uint64_t cgen_var_368 = (uint64_t)(uintptr_t)forMarshaling->pHostPointer;
+    vkStream->putBe64(cgen_var_368);
     if (forMarshaling->pHostPointer)
     {
         vkStream->write((void*)forMarshaling->pHostPointer, sizeof(uint8_t));
@@ -13219,8 +13497,8 @@
     }
     vkStream->write((VkPipelineStageFlagBits*)&forMarshaling->stage, sizeof(VkPipelineStageFlagBits));
     // WARNING PTR CHECK
-    uint64_t cgen_var_352 = (uint64_t)(uintptr_t)forMarshaling->pCheckpointMarker;
-    vkStream->putBe64(cgen_var_352);
+    uint64_t cgen_var_370 = (uint64_t)(uintptr_t)forMarshaling->pCheckpointMarker;
+    vkStream->putBe64(cgen_var_370);
     if (forMarshaling->pCheckpointMarker)
     {
         vkStream->write((void*)forMarshaling->pCheckpointMarker, sizeof(uint8_t));
@@ -13333,6 +13611,10 @@
 #endif
 #ifdef VK_GOOGLE_async_command_buffers
 #endif
+#ifdef VK_GOOGLE_create_resources_with_requirements
+#endif
+#ifdef VK_GOOGLE_address_space_info
+#endif
 void marshal_extension_struct(
     VulkanStreamGuest* vkStream,
     const void* structExtension)
@@ -14659,5 +14941,1467 @@
     }
 }
 
+const char* api_opcode_to_string(
+    const uint32_t opcode)
+{
+    switch(opcode)
+    {
+#ifdef VK_VERSION_1_0
+        case OP_vkCreateInstance:
+        {
+            return "OP_vkCreateInstance";
+        }
+        case OP_vkDestroyInstance:
+        {
+            return "OP_vkDestroyInstance";
+        }
+        case OP_vkEnumeratePhysicalDevices:
+        {
+            return "OP_vkEnumeratePhysicalDevices";
+        }
+        case OP_vkGetPhysicalDeviceFeatures:
+        {
+            return "OP_vkGetPhysicalDeviceFeatures";
+        }
+        case OP_vkGetPhysicalDeviceFormatProperties:
+        {
+            return "OP_vkGetPhysicalDeviceFormatProperties";
+        }
+        case OP_vkGetPhysicalDeviceImageFormatProperties:
+        {
+            return "OP_vkGetPhysicalDeviceImageFormatProperties";
+        }
+        case OP_vkGetPhysicalDeviceProperties:
+        {
+            return "OP_vkGetPhysicalDeviceProperties";
+        }
+        case OP_vkGetPhysicalDeviceQueueFamilyProperties:
+        {
+            return "OP_vkGetPhysicalDeviceQueueFamilyProperties";
+        }
+        case OP_vkGetPhysicalDeviceMemoryProperties:
+        {
+            return "OP_vkGetPhysicalDeviceMemoryProperties";
+        }
+        case OP_vkGetInstanceProcAddr:
+        {
+            return "OP_vkGetInstanceProcAddr";
+        }
+        case OP_vkGetDeviceProcAddr:
+        {
+            return "OP_vkGetDeviceProcAddr";
+        }
+        case OP_vkCreateDevice:
+        {
+            return "OP_vkCreateDevice";
+        }
+        case OP_vkDestroyDevice:
+        {
+            return "OP_vkDestroyDevice";
+        }
+        case OP_vkEnumerateInstanceExtensionProperties:
+        {
+            return "OP_vkEnumerateInstanceExtensionProperties";
+        }
+        case OP_vkEnumerateDeviceExtensionProperties:
+        {
+            return "OP_vkEnumerateDeviceExtensionProperties";
+        }
+        case OP_vkEnumerateInstanceLayerProperties:
+        {
+            return "OP_vkEnumerateInstanceLayerProperties";
+        }
+        case OP_vkEnumerateDeviceLayerProperties:
+        {
+            return "OP_vkEnumerateDeviceLayerProperties";
+        }
+        case OP_vkGetDeviceQueue:
+        {
+            return "OP_vkGetDeviceQueue";
+        }
+        case OP_vkQueueSubmit:
+        {
+            return "OP_vkQueueSubmit";
+        }
+        case OP_vkQueueWaitIdle:
+        {
+            return "OP_vkQueueWaitIdle";
+        }
+        case OP_vkDeviceWaitIdle:
+        {
+            return "OP_vkDeviceWaitIdle";
+        }
+        case OP_vkAllocateMemory:
+        {
+            return "OP_vkAllocateMemory";
+        }
+        case OP_vkFreeMemory:
+        {
+            return "OP_vkFreeMemory";
+        }
+        case OP_vkMapMemory:
+        {
+            return "OP_vkMapMemory";
+        }
+        case OP_vkUnmapMemory:
+        {
+            return "OP_vkUnmapMemory";
+        }
+        case OP_vkFlushMappedMemoryRanges:
+        {
+            return "OP_vkFlushMappedMemoryRanges";
+        }
+        case OP_vkInvalidateMappedMemoryRanges:
+        {
+            return "OP_vkInvalidateMappedMemoryRanges";
+        }
+        case OP_vkGetDeviceMemoryCommitment:
+        {
+            return "OP_vkGetDeviceMemoryCommitment";
+        }
+        case OP_vkBindBufferMemory:
+        {
+            return "OP_vkBindBufferMemory";
+        }
+        case OP_vkBindImageMemory:
+        {
+            return "OP_vkBindImageMemory";
+        }
+        case OP_vkGetBufferMemoryRequirements:
+        {
+            return "OP_vkGetBufferMemoryRequirements";
+        }
+        case OP_vkGetImageMemoryRequirements:
+        {
+            return "OP_vkGetImageMemoryRequirements";
+        }
+        case OP_vkGetImageSparseMemoryRequirements:
+        {
+            return "OP_vkGetImageSparseMemoryRequirements";
+        }
+        case OP_vkGetPhysicalDeviceSparseImageFormatProperties:
+        {
+            return "OP_vkGetPhysicalDeviceSparseImageFormatProperties";
+        }
+        case OP_vkQueueBindSparse:
+        {
+            return "OP_vkQueueBindSparse";
+        }
+        case OP_vkCreateFence:
+        {
+            return "OP_vkCreateFence";
+        }
+        case OP_vkDestroyFence:
+        {
+            return "OP_vkDestroyFence";
+        }
+        case OP_vkResetFences:
+        {
+            return "OP_vkResetFences";
+        }
+        case OP_vkGetFenceStatus:
+        {
+            return "OP_vkGetFenceStatus";
+        }
+        case OP_vkWaitForFences:
+        {
+            return "OP_vkWaitForFences";
+        }
+        case OP_vkCreateSemaphore:
+        {
+            return "OP_vkCreateSemaphore";
+        }
+        case OP_vkDestroySemaphore:
+        {
+            return "OP_vkDestroySemaphore";
+        }
+        case OP_vkCreateEvent:
+        {
+            return "OP_vkCreateEvent";
+        }
+        case OP_vkDestroyEvent:
+        {
+            return "OP_vkDestroyEvent";
+        }
+        case OP_vkGetEventStatus:
+        {
+            return "OP_vkGetEventStatus";
+        }
+        case OP_vkSetEvent:
+        {
+            return "OP_vkSetEvent";
+        }
+        case OP_vkResetEvent:
+        {
+            return "OP_vkResetEvent";
+        }
+        case OP_vkCreateQueryPool:
+        {
+            return "OP_vkCreateQueryPool";
+        }
+        case OP_vkDestroyQueryPool:
+        {
+            return "OP_vkDestroyQueryPool";
+        }
+        case OP_vkGetQueryPoolResults:
+        {
+            return "OP_vkGetQueryPoolResults";
+        }
+        case OP_vkCreateBuffer:
+        {
+            return "OP_vkCreateBuffer";
+        }
+        case OP_vkDestroyBuffer:
+        {
+            return "OP_vkDestroyBuffer";
+        }
+        case OP_vkCreateBufferView:
+        {
+            return "OP_vkCreateBufferView";
+        }
+        case OP_vkDestroyBufferView:
+        {
+            return "OP_vkDestroyBufferView";
+        }
+        case OP_vkCreateImage:
+        {
+            return "OP_vkCreateImage";
+        }
+        case OP_vkDestroyImage:
+        {
+            return "OP_vkDestroyImage";
+        }
+        case OP_vkGetImageSubresourceLayout:
+        {
+            return "OP_vkGetImageSubresourceLayout";
+        }
+        case OP_vkCreateImageView:
+        {
+            return "OP_vkCreateImageView";
+        }
+        case OP_vkDestroyImageView:
+        {
+            return "OP_vkDestroyImageView";
+        }
+        case OP_vkCreateShaderModule:
+        {
+            return "OP_vkCreateShaderModule";
+        }
+        case OP_vkDestroyShaderModule:
+        {
+            return "OP_vkDestroyShaderModule";
+        }
+        case OP_vkCreatePipelineCache:
+        {
+            return "OP_vkCreatePipelineCache";
+        }
+        case OP_vkDestroyPipelineCache:
+        {
+            return "OP_vkDestroyPipelineCache";
+        }
+        case OP_vkGetPipelineCacheData:
+        {
+            return "OP_vkGetPipelineCacheData";
+        }
+        case OP_vkMergePipelineCaches:
+        {
+            return "OP_vkMergePipelineCaches";
+        }
+        case OP_vkCreateGraphicsPipelines:
+        {
+            return "OP_vkCreateGraphicsPipelines";
+        }
+        case OP_vkCreateComputePipelines:
+        {
+            return "OP_vkCreateComputePipelines";
+        }
+        case OP_vkDestroyPipeline:
+        {
+            return "OP_vkDestroyPipeline";
+        }
+        case OP_vkCreatePipelineLayout:
+        {
+            return "OP_vkCreatePipelineLayout";
+        }
+        case OP_vkDestroyPipelineLayout:
+        {
+            return "OP_vkDestroyPipelineLayout";
+        }
+        case OP_vkCreateSampler:
+        {
+            return "OP_vkCreateSampler";
+        }
+        case OP_vkDestroySampler:
+        {
+            return "OP_vkDestroySampler";
+        }
+        case OP_vkCreateDescriptorSetLayout:
+        {
+            return "OP_vkCreateDescriptorSetLayout";
+        }
+        case OP_vkDestroyDescriptorSetLayout:
+        {
+            return "OP_vkDestroyDescriptorSetLayout";
+        }
+        case OP_vkCreateDescriptorPool:
+        {
+            return "OP_vkCreateDescriptorPool";
+        }
+        case OP_vkDestroyDescriptorPool:
+        {
+            return "OP_vkDestroyDescriptorPool";
+        }
+        case OP_vkResetDescriptorPool:
+        {
+            return "OP_vkResetDescriptorPool";
+        }
+        case OP_vkAllocateDescriptorSets:
+        {
+            return "OP_vkAllocateDescriptorSets";
+        }
+        case OP_vkFreeDescriptorSets:
+        {
+            return "OP_vkFreeDescriptorSets";
+        }
+        case OP_vkUpdateDescriptorSets:
+        {
+            return "OP_vkUpdateDescriptorSets";
+        }
+        case OP_vkCreateFramebuffer:
+        {
+            return "OP_vkCreateFramebuffer";
+        }
+        case OP_vkDestroyFramebuffer:
+        {
+            return "OP_vkDestroyFramebuffer";
+        }
+        case OP_vkCreateRenderPass:
+        {
+            return "OP_vkCreateRenderPass";
+        }
+        case OP_vkDestroyRenderPass:
+        {
+            return "OP_vkDestroyRenderPass";
+        }
+        case OP_vkGetRenderAreaGranularity:
+        {
+            return "OP_vkGetRenderAreaGranularity";
+        }
+        case OP_vkCreateCommandPool:
+        {
+            return "OP_vkCreateCommandPool";
+        }
+        case OP_vkDestroyCommandPool:
+        {
+            return "OP_vkDestroyCommandPool";
+        }
+        case OP_vkResetCommandPool:
+        {
+            return "OP_vkResetCommandPool";
+        }
+        case OP_vkAllocateCommandBuffers:
+        {
+            return "OP_vkAllocateCommandBuffers";
+        }
+        case OP_vkFreeCommandBuffers:
+        {
+            return "OP_vkFreeCommandBuffers";
+        }
+        case OP_vkBeginCommandBuffer:
+        {
+            return "OP_vkBeginCommandBuffer";
+        }
+        case OP_vkEndCommandBuffer:
+        {
+            return "OP_vkEndCommandBuffer";
+        }
+        case OP_vkResetCommandBuffer:
+        {
+            return "OP_vkResetCommandBuffer";
+        }
+        case OP_vkCmdBindPipeline:
+        {
+            return "OP_vkCmdBindPipeline";
+        }
+        case OP_vkCmdSetViewport:
+        {
+            return "OP_vkCmdSetViewport";
+        }
+        case OP_vkCmdSetScissor:
+        {
+            return "OP_vkCmdSetScissor";
+        }
+        case OP_vkCmdSetLineWidth:
+        {
+            return "OP_vkCmdSetLineWidth";
+        }
+        case OP_vkCmdSetDepthBias:
+        {
+            return "OP_vkCmdSetDepthBias";
+        }
+        case OP_vkCmdSetBlendConstants:
+        {
+            return "OP_vkCmdSetBlendConstants";
+        }
+        case OP_vkCmdSetDepthBounds:
+        {
+            return "OP_vkCmdSetDepthBounds";
+        }
+        case OP_vkCmdSetStencilCompareMask:
+        {
+            return "OP_vkCmdSetStencilCompareMask";
+        }
+        case OP_vkCmdSetStencilWriteMask:
+        {
+            return "OP_vkCmdSetStencilWriteMask";
+        }
+        case OP_vkCmdSetStencilReference:
+        {
+            return "OP_vkCmdSetStencilReference";
+        }
+        case OP_vkCmdBindDescriptorSets:
+        {
+            return "OP_vkCmdBindDescriptorSets";
+        }
+        case OP_vkCmdBindIndexBuffer:
+        {
+            return "OP_vkCmdBindIndexBuffer";
+        }
+        case OP_vkCmdBindVertexBuffers:
+        {
+            return "OP_vkCmdBindVertexBuffers";
+        }
+        case OP_vkCmdDraw:
+        {
+            return "OP_vkCmdDraw";
+        }
+        case OP_vkCmdDrawIndexed:
+        {
+            return "OP_vkCmdDrawIndexed";
+        }
+        case OP_vkCmdDrawIndirect:
+        {
+            return "OP_vkCmdDrawIndirect";
+        }
+        case OP_vkCmdDrawIndexedIndirect:
+        {
+            return "OP_vkCmdDrawIndexedIndirect";
+        }
+        case OP_vkCmdDispatch:
+        {
+            return "OP_vkCmdDispatch";
+        }
+        case OP_vkCmdDispatchIndirect:
+        {
+            return "OP_vkCmdDispatchIndirect";
+        }
+        case OP_vkCmdCopyBuffer:
+        {
+            return "OP_vkCmdCopyBuffer";
+        }
+        case OP_vkCmdCopyImage:
+        {
+            return "OP_vkCmdCopyImage";
+        }
+        case OP_vkCmdBlitImage:
+        {
+            return "OP_vkCmdBlitImage";
+        }
+        case OP_vkCmdCopyBufferToImage:
+        {
+            return "OP_vkCmdCopyBufferToImage";
+        }
+        case OP_vkCmdCopyImageToBuffer:
+        {
+            return "OP_vkCmdCopyImageToBuffer";
+        }
+        case OP_vkCmdUpdateBuffer:
+        {
+            return "OP_vkCmdUpdateBuffer";
+        }
+        case OP_vkCmdFillBuffer:
+        {
+            return "OP_vkCmdFillBuffer";
+        }
+        case OP_vkCmdClearColorImage:
+        {
+            return "OP_vkCmdClearColorImage";
+        }
+        case OP_vkCmdClearDepthStencilImage:
+        {
+            return "OP_vkCmdClearDepthStencilImage";
+        }
+        case OP_vkCmdClearAttachments:
+        {
+            return "OP_vkCmdClearAttachments";
+        }
+        case OP_vkCmdResolveImage:
+        {
+            return "OP_vkCmdResolveImage";
+        }
+        case OP_vkCmdSetEvent:
+        {
+            return "OP_vkCmdSetEvent";
+        }
+        case OP_vkCmdResetEvent:
+        {
+            return "OP_vkCmdResetEvent";
+        }
+        case OP_vkCmdWaitEvents:
+        {
+            return "OP_vkCmdWaitEvents";
+        }
+        case OP_vkCmdPipelineBarrier:
+        {
+            return "OP_vkCmdPipelineBarrier";
+        }
+        case OP_vkCmdBeginQuery:
+        {
+            return "OP_vkCmdBeginQuery";
+        }
+        case OP_vkCmdEndQuery:
+        {
+            return "OP_vkCmdEndQuery";
+        }
+        case OP_vkCmdResetQueryPool:
+        {
+            return "OP_vkCmdResetQueryPool";
+        }
+        case OP_vkCmdWriteTimestamp:
+        {
+            return "OP_vkCmdWriteTimestamp";
+        }
+        case OP_vkCmdCopyQueryPoolResults:
+        {
+            return "OP_vkCmdCopyQueryPoolResults";
+        }
+        case OP_vkCmdPushConstants:
+        {
+            return "OP_vkCmdPushConstants";
+        }
+        case OP_vkCmdBeginRenderPass:
+        {
+            return "OP_vkCmdBeginRenderPass";
+        }
+        case OP_vkCmdNextSubpass:
+        {
+            return "OP_vkCmdNextSubpass";
+        }
+        case OP_vkCmdEndRenderPass:
+        {
+            return "OP_vkCmdEndRenderPass";
+        }
+        case OP_vkCmdExecuteCommands:
+        {
+            return "OP_vkCmdExecuteCommands";
+        }
+#endif
+#ifdef VK_VERSION_1_1
+        case OP_vkEnumerateInstanceVersion:
+        {
+            return "OP_vkEnumerateInstanceVersion";
+        }
+        case OP_vkBindBufferMemory2:
+        {
+            return "OP_vkBindBufferMemory2";
+        }
+        case OP_vkBindImageMemory2:
+        {
+            return "OP_vkBindImageMemory2";
+        }
+        case OP_vkGetDeviceGroupPeerMemoryFeatures:
+        {
+            return "OP_vkGetDeviceGroupPeerMemoryFeatures";
+        }
+        case OP_vkCmdSetDeviceMask:
+        {
+            return "OP_vkCmdSetDeviceMask";
+        }
+        case OP_vkCmdDispatchBase:
+        {
+            return "OP_vkCmdDispatchBase";
+        }
+        case OP_vkEnumeratePhysicalDeviceGroups:
+        {
+            return "OP_vkEnumeratePhysicalDeviceGroups";
+        }
+        case OP_vkGetImageMemoryRequirements2:
+        {
+            return "OP_vkGetImageMemoryRequirements2";
+        }
+        case OP_vkGetBufferMemoryRequirements2:
+        {
+            return "OP_vkGetBufferMemoryRequirements2";
+        }
+        case OP_vkGetImageSparseMemoryRequirements2:
+        {
+            return "OP_vkGetImageSparseMemoryRequirements2";
+        }
+        case OP_vkGetPhysicalDeviceFeatures2:
+        {
+            return "OP_vkGetPhysicalDeviceFeatures2";
+        }
+        case OP_vkGetPhysicalDeviceProperties2:
+        {
+            return "OP_vkGetPhysicalDeviceProperties2";
+        }
+        case OP_vkGetPhysicalDeviceFormatProperties2:
+        {
+            return "OP_vkGetPhysicalDeviceFormatProperties2";
+        }
+        case OP_vkGetPhysicalDeviceImageFormatProperties2:
+        {
+            return "OP_vkGetPhysicalDeviceImageFormatProperties2";
+        }
+        case OP_vkGetPhysicalDeviceQueueFamilyProperties2:
+        {
+            return "OP_vkGetPhysicalDeviceQueueFamilyProperties2";
+        }
+        case OP_vkGetPhysicalDeviceMemoryProperties2:
+        {
+            return "OP_vkGetPhysicalDeviceMemoryProperties2";
+        }
+        case OP_vkGetPhysicalDeviceSparseImageFormatProperties2:
+        {
+            return "OP_vkGetPhysicalDeviceSparseImageFormatProperties2";
+        }
+        case OP_vkTrimCommandPool:
+        {
+            return "OP_vkTrimCommandPool";
+        }
+        case OP_vkGetDeviceQueue2:
+        {
+            return "OP_vkGetDeviceQueue2";
+        }
+        case OP_vkCreateSamplerYcbcrConversion:
+        {
+            return "OP_vkCreateSamplerYcbcrConversion";
+        }
+        case OP_vkDestroySamplerYcbcrConversion:
+        {
+            return "OP_vkDestroySamplerYcbcrConversion";
+        }
+        case OP_vkCreateDescriptorUpdateTemplate:
+        {
+            return "OP_vkCreateDescriptorUpdateTemplate";
+        }
+        case OP_vkDestroyDescriptorUpdateTemplate:
+        {
+            return "OP_vkDestroyDescriptorUpdateTemplate";
+        }
+        case OP_vkUpdateDescriptorSetWithTemplate:
+        {
+            return "OP_vkUpdateDescriptorSetWithTemplate";
+        }
+        case OP_vkGetPhysicalDeviceExternalBufferProperties:
+        {
+            return "OP_vkGetPhysicalDeviceExternalBufferProperties";
+        }
+        case OP_vkGetPhysicalDeviceExternalFenceProperties:
+        {
+            return "OP_vkGetPhysicalDeviceExternalFenceProperties";
+        }
+        case OP_vkGetPhysicalDeviceExternalSemaphoreProperties:
+        {
+            return "OP_vkGetPhysicalDeviceExternalSemaphoreProperties";
+        }
+        case OP_vkGetDescriptorSetLayoutSupport:
+        {
+            return "OP_vkGetDescriptorSetLayoutSupport";
+        }
+#endif
+#ifdef VK_KHR_surface
+        case OP_vkDestroySurfaceKHR:
+        {
+            return "OP_vkDestroySurfaceKHR";
+        }
+        case OP_vkGetPhysicalDeviceSurfaceSupportKHR:
+        {
+            return "OP_vkGetPhysicalDeviceSurfaceSupportKHR";
+        }
+        case OP_vkGetPhysicalDeviceSurfaceCapabilitiesKHR:
+        {
+            return "OP_vkGetPhysicalDeviceSurfaceCapabilitiesKHR";
+        }
+        case OP_vkGetPhysicalDeviceSurfaceFormatsKHR:
+        {
+            return "OP_vkGetPhysicalDeviceSurfaceFormatsKHR";
+        }
+        case OP_vkGetPhysicalDeviceSurfacePresentModesKHR:
+        {
+            return "OP_vkGetPhysicalDeviceSurfacePresentModesKHR";
+        }
+#endif
+#ifdef VK_KHR_swapchain
+        case OP_vkCreateSwapchainKHR:
+        {
+            return "OP_vkCreateSwapchainKHR";
+        }
+        case OP_vkDestroySwapchainKHR:
+        {
+            return "OP_vkDestroySwapchainKHR";
+        }
+        case OP_vkGetSwapchainImagesKHR:
+        {
+            return "OP_vkGetSwapchainImagesKHR";
+        }
+        case OP_vkAcquireNextImageKHR:
+        {
+            return "OP_vkAcquireNextImageKHR";
+        }
+        case OP_vkQueuePresentKHR:
+        {
+            return "OP_vkQueuePresentKHR";
+        }
+        case OP_vkGetDeviceGroupPresentCapabilitiesKHR:
+        {
+            return "OP_vkGetDeviceGroupPresentCapabilitiesKHR";
+        }
+        case OP_vkGetDeviceGroupSurfacePresentModesKHR:
+        {
+            return "OP_vkGetDeviceGroupSurfacePresentModesKHR";
+        }
+        case OP_vkGetPhysicalDevicePresentRectanglesKHR:
+        {
+            return "OP_vkGetPhysicalDevicePresentRectanglesKHR";
+        }
+        case OP_vkAcquireNextImage2KHR:
+        {
+            return "OP_vkAcquireNextImage2KHR";
+        }
+#endif
+#ifdef VK_KHR_display
+        case OP_vkGetPhysicalDeviceDisplayPropertiesKHR:
+        {
+            return "OP_vkGetPhysicalDeviceDisplayPropertiesKHR";
+        }
+        case OP_vkGetPhysicalDeviceDisplayPlanePropertiesKHR:
+        {
+            return "OP_vkGetPhysicalDeviceDisplayPlanePropertiesKHR";
+        }
+        case OP_vkGetDisplayPlaneSupportedDisplaysKHR:
+        {
+            return "OP_vkGetDisplayPlaneSupportedDisplaysKHR";
+        }
+        case OP_vkGetDisplayModePropertiesKHR:
+        {
+            return "OP_vkGetDisplayModePropertiesKHR";
+        }
+        case OP_vkCreateDisplayModeKHR:
+        {
+            return "OP_vkCreateDisplayModeKHR";
+        }
+        case OP_vkGetDisplayPlaneCapabilitiesKHR:
+        {
+            return "OP_vkGetDisplayPlaneCapabilitiesKHR";
+        }
+        case OP_vkCreateDisplayPlaneSurfaceKHR:
+        {
+            return "OP_vkCreateDisplayPlaneSurfaceKHR";
+        }
+#endif
+#ifdef VK_KHR_display_swapchain
+        case OP_vkCreateSharedSwapchainsKHR:
+        {
+            return "OP_vkCreateSharedSwapchainsKHR";
+        }
+#endif
+#ifdef VK_KHR_xlib_surface
+        case OP_vkCreateXlibSurfaceKHR:
+        {
+            return "OP_vkCreateXlibSurfaceKHR";
+        }
+        case OP_vkGetPhysicalDeviceXlibPresentationSupportKHR:
+        {
+            return "OP_vkGetPhysicalDeviceXlibPresentationSupportKHR";
+        }
+#endif
+#ifdef VK_KHR_xcb_surface
+        case OP_vkCreateXcbSurfaceKHR:
+        {
+            return "OP_vkCreateXcbSurfaceKHR";
+        }
+        case OP_vkGetPhysicalDeviceXcbPresentationSupportKHR:
+        {
+            return "OP_vkGetPhysicalDeviceXcbPresentationSupportKHR";
+        }
+#endif
+#ifdef VK_KHR_wayland_surface
+        case OP_vkCreateWaylandSurfaceKHR:
+        {
+            return "OP_vkCreateWaylandSurfaceKHR";
+        }
+        case OP_vkGetPhysicalDeviceWaylandPresentationSupportKHR:
+        {
+            return "OP_vkGetPhysicalDeviceWaylandPresentationSupportKHR";
+        }
+#endif
+#ifdef VK_KHR_mir_surface
+        case OP_vkCreateMirSurfaceKHR:
+        {
+            return "OP_vkCreateMirSurfaceKHR";
+        }
+        case OP_vkGetPhysicalDeviceMirPresentationSupportKHR:
+        {
+            return "OP_vkGetPhysicalDeviceMirPresentationSupportKHR";
+        }
+#endif
+#ifdef VK_KHR_android_surface
+        case OP_vkCreateAndroidSurfaceKHR:
+        {
+            return "OP_vkCreateAndroidSurfaceKHR";
+        }
+#endif
+#ifdef VK_KHR_win32_surface
+        case OP_vkCreateWin32SurfaceKHR:
+        {
+            return "OP_vkCreateWin32SurfaceKHR";
+        }
+        case OP_vkGetPhysicalDeviceWin32PresentationSupportKHR:
+        {
+            return "OP_vkGetPhysicalDeviceWin32PresentationSupportKHR";
+        }
+#endif
+#ifdef VK_KHR_get_physical_device_properties2
+        case OP_vkGetPhysicalDeviceFeatures2KHR:
+        {
+            return "OP_vkGetPhysicalDeviceFeatures2KHR";
+        }
+        case OP_vkGetPhysicalDeviceProperties2KHR:
+        {
+            return "OP_vkGetPhysicalDeviceProperties2KHR";
+        }
+        case OP_vkGetPhysicalDeviceFormatProperties2KHR:
+        {
+            return "OP_vkGetPhysicalDeviceFormatProperties2KHR";
+        }
+        case OP_vkGetPhysicalDeviceImageFormatProperties2KHR:
+        {
+            return "OP_vkGetPhysicalDeviceImageFormatProperties2KHR";
+        }
+        case OP_vkGetPhysicalDeviceQueueFamilyProperties2KHR:
+        {
+            return "OP_vkGetPhysicalDeviceQueueFamilyProperties2KHR";
+        }
+        case OP_vkGetPhysicalDeviceMemoryProperties2KHR:
+        {
+            return "OP_vkGetPhysicalDeviceMemoryProperties2KHR";
+        }
+        case OP_vkGetPhysicalDeviceSparseImageFormatProperties2KHR:
+        {
+            return "OP_vkGetPhysicalDeviceSparseImageFormatProperties2KHR";
+        }
+#endif
+#ifdef VK_KHR_device_group
+        case OP_vkGetDeviceGroupPeerMemoryFeaturesKHR:
+        {
+            return "OP_vkGetDeviceGroupPeerMemoryFeaturesKHR";
+        }
+        case OP_vkCmdSetDeviceMaskKHR:
+        {
+            return "OP_vkCmdSetDeviceMaskKHR";
+        }
+        case OP_vkCmdDispatchBaseKHR:
+        {
+            return "OP_vkCmdDispatchBaseKHR";
+        }
+#endif
+#ifdef VK_KHR_maintenance1
+        case OP_vkTrimCommandPoolKHR:
+        {
+            return "OP_vkTrimCommandPoolKHR";
+        }
+#endif
+#ifdef VK_KHR_device_group_creation
+        case OP_vkEnumeratePhysicalDeviceGroupsKHR:
+        {
+            return "OP_vkEnumeratePhysicalDeviceGroupsKHR";
+        }
+#endif
+#ifdef VK_KHR_external_memory_capabilities
+        case OP_vkGetPhysicalDeviceExternalBufferPropertiesKHR:
+        {
+            return "OP_vkGetPhysicalDeviceExternalBufferPropertiesKHR";
+        }
+#endif
+#ifdef VK_KHR_external_memory_win32
+        case OP_vkGetMemoryWin32HandleKHR:
+        {
+            return "OP_vkGetMemoryWin32HandleKHR";
+        }
+        case OP_vkGetMemoryWin32HandlePropertiesKHR:
+        {
+            return "OP_vkGetMemoryWin32HandlePropertiesKHR";
+        }
+#endif
+#ifdef VK_KHR_external_memory_fd
+        case OP_vkGetMemoryFdKHR:
+        {
+            return "OP_vkGetMemoryFdKHR";
+        }
+        case OP_vkGetMemoryFdPropertiesKHR:
+        {
+            return "OP_vkGetMemoryFdPropertiesKHR";
+        }
+#endif
+#ifdef VK_KHR_external_semaphore_capabilities
+        case OP_vkGetPhysicalDeviceExternalSemaphorePropertiesKHR:
+        {
+            return "OP_vkGetPhysicalDeviceExternalSemaphorePropertiesKHR";
+        }
+#endif
+#ifdef VK_KHR_external_semaphore_win32
+        case OP_vkImportSemaphoreWin32HandleKHR:
+        {
+            return "OP_vkImportSemaphoreWin32HandleKHR";
+        }
+        case OP_vkGetSemaphoreWin32HandleKHR:
+        {
+            return "OP_vkGetSemaphoreWin32HandleKHR";
+        }
+#endif
+#ifdef VK_KHR_external_semaphore_fd
+        case OP_vkImportSemaphoreFdKHR:
+        {
+            return "OP_vkImportSemaphoreFdKHR";
+        }
+        case OP_vkGetSemaphoreFdKHR:
+        {
+            return "OP_vkGetSemaphoreFdKHR";
+        }
+#endif
+#ifdef VK_KHR_push_descriptor
+        case OP_vkCmdPushDescriptorSetKHR:
+        {
+            return "OP_vkCmdPushDescriptorSetKHR";
+        }
+        case OP_vkCmdPushDescriptorSetWithTemplateKHR:
+        {
+            return "OP_vkCmdPushDescriptorSetWithTemplateKHR";
+        }
+#endif
+#ifdef VK_KHR_descriptor_update_template
+        case OP_vkCreateDescriptorUpdateTemplateKHR:
+        {
+            return "OP_vkCreateDescriptorUpdateTemplateKHR";
+        }
+        case OP_vkDestroyDescriptorUpdateTemplateKHR:
+        {
+            return "OP_vkDestroyDescriptorUpdateTemplateKHR";
+        }
+        case OP_vkUpdateDescriptorSetWithTemplateKHR:
+        {
+            return "OP_vkUpdateDescriptorSetWithTemplateKHR";
+        }
+#endif
+#ifdef VK_KHR_create_renderpass2
+        case OP_vkCreateRenderPass2KHR:
+        {
+            return "OP_vkCreateRenderPass2KHR";
+        }
+        case OP_vkCmdBeginRenderPass2KHR:
+        {
+            return "OP_vkCmdBeginRenderPass2KHR";
+        }
+        case OP_vkCmdNextSubpass2KHR:
+        {
+            return "OP_vkCmdNextSubpass2KHR";
+        }
+        case OP_vkCmdEndRenderPass2KHR:
+        {
+            return "OP_vkCmdEndRenderPass2KHR";
+        }
+#endif
+#ifdef VK_KHR_shared_presentable_image
+        case OP_vkGetSwapchainStatusKHR:
+        {
+            return "OP_vkGetSwapchainStatusKHR";
+        }
+#endif
+#ifdef VK_KHR_external_fence_capabilities
+        case OP_vkGetPhysicalDeviceExternalFencePropertiesKHR:
+        {
+            return "OP_vkGetPhysicalDeviceExternalFencePropertiesKHR";
+        }
+#endif
+#ifdef VK_KHR_external_fence_win32
+        case OP_vkImportFenceWin32HandleKHR:
+        {
+            return "OP_vkImportFenceWin32HandleKHR";
+        }
+        case OP_vkGetFenceWin32HandleKHR:
+        {
+            return "OP_vkGetFenceWin32HandleKHR";
+        }
+#endif
+#ifdef VK_KHR_external_fence_fd
+        case OP_vkImportFenceFdKHR:
+        {
+            return "OP_vkImportFenceFdKHR";
+        }
+        case OP_vkGetFenceFdKHR:
+        {
+            return "OP_vkGetFenceFdKHR";
+        }
+#endif
+#ifdef VK_KHR_get_surface_capabilities2
+        case OP_vkGetPhysicalDeviceSurfaceCapabilities2KHR:
+        {
+            return "OP_vkGetPhysicalDeviceSurfaceCapabilities2KHR";
+        }
+        case OP_vkGetPhysicalDeviceSurfaceFormats2KHR:
+        {
+            return "OP_vkGetPhysicalDeviceSurfaceFormats2KHR";
+        }
+#endif
+#ifdef VK_KHR_get_display_properties2
+        case OP_vkGetPhysicalDeviceDisplayProperties2KHR:
+        {
+            return "OP_vkGetPhysicalDeviceDisplayProperties2KHR";
+        }
+        case OP_vkGetPhysicalDeviceDisplayPlaneProperties2KHR:
+        {
+            return "OP_vkGetPhysicalDeviceDisplayPlaneProperties2KHR";
+        }
+        case OP_vkGetDisplayModeProperties2KHR:
+        {
+            return "OP_vkGetDisplayModeProperties2KHR";
+        }
+        case OP_vkGetDisplayPlaneCapabilities2KHR:
+        {
+            return "OP_vkGetDisplayPlaneCapabilities2KHR";
+        }
+#endif
+#ifdef VK_KHR_get_memory_requirements2
+        case OP_vkGetImageMemoryRequirements2KHR:
+        {
+            return "OP_vkGetImageMemoryRequirements2KHR";
+        }
+        case OP_vkGetBufferMemoryRequirements2KHR:
+        {
+            return "OP_vkGetBufferMemoryRequirements2KHR";
+        }
+        case OP_vkGetImageSparseMemoryRequirements2KHR:
+        {
+            return "OP_vkGetImageSparseMemoryRequirements2KHR";
+        }
+#endif
+#ifdef VK_KHR_sampler_ycbcr_conversion
+        case OP_vkCreateSamplerYcbcrConversionKHR:
+        {
+            return "OP_vkCreateSamplerYcbcrConversionKHR";
+        }
+        case OP_vkDestroySamplerYcbcrConversionKHR:
+        {
+            return "OP_vkDestroySamplerYcbcrConversionKHR";
+        }
+#endif
+#ifdef VK_KHR_bind_memory2
+        case OP_vkBindBufferMemory2KHR:
+        {
+            return "OP_vkBindBufferMemory2KHR";
+        }
+        case OP_vkBindImageMemory2KHR:
+        {
+            return "OP_vkBindImageMemory2KHR";
+        }
+#endif
+#ifdef VK_KHR_maintenance3
+        case OP_vkGetDescriptorSetLayoutSupportKHR:
+        {
+            return "OP_vkGetDescriptorSetLayoutSupportKHR";
+        }
+#endif
+#ifdef VK_KHR_draw_indirect_count
+        case OP_vkCmdDrawIndirectCountKHR:
+        {
+            return "OP_vkCmdDrawIndirectCountKHR";
+        }
+        case OP_vkCmdDrawIndexedIndirectCountKHR:
+        {
+            return "OP_vkCmdDrawIndexedIndirectCountKHR";
+        }
+#endif
+#ifdef VK_ANDROID_native_buffer
+        case OP_vkGetSwapchainGrallocUsageANDROID:
+        {
+            return "OP_vkGetSwapchainGrallocUsageANDROID";
+        }
+        case OP_vkAcquireImageANDROID:
+        {
+            return "OP_vkAcquireImageANDROID";
+        }
+        case OP_vkQueueSignalReleaseImageANDROID:
+        {
+            return "OP_vkQueueSignalReleaseImageANDROID";
+        }
+#endif
+#ifdef VK_EXT_debug_report
+        case OP_vkCreateDebugReportCallbackEXT:
+        {
+            return "OP_vkCreateDebugReportCallbackEXT";
+        }
+        case OP_vkDestroyDebugReportCallbackEXT:
+        {
+            return "OP_vkDestroyDebugReportCallbackEXT";
+        }
+        case OP_vkDebugReportMessageEXT:
+        {
+            return "OP_vkDebugReportMessageEXT";
+        }
+#endif
+#ifdef VK_EXT_debug_marker
+        case OP_vkDebugMarkerSetObjectTagEXT:
+        {
+            return "OP_vkDebugMarkerSetObjectTagEXT";
+        }
+        case OP_vkDebugMarkerSetObjectNameEXT:
+        {
+            return "OP_vkDebugMarkerSetObjectNameEXT";
+        }
+        case OP_vkCmdDebugMarkerBeginEXT:
+        {
+            return "OP_vkCmdDebugMarkerBeginEXT";
+        }
+        case OP_vkCmdDebugMarkerEndEXT:
+        {
+            return "OP_vkCmdDebugMarkerEndEXT";
+        }
+        case OP_vkCmdDebugMarkerInsertEXT:
+        {
+            return "OP_vkCmdDebugMarkerInsertEXT";
+        }
+#endif
+#ifdef VK_AMD_draw_indirect_count
+        case OP_vkCmdDrawIndirectCountAMD:
+        {
+            return "OP_vkCmdDrawIndirectCountAMD";
+        }
+        case OP_vkCmdDrawIndexedIndirectCountAMD:
+        {
+            return "OP_vkCmdDrawIndexedIndirectCountAMD";
+        }
+#endif
+#ifdef VK_AMD_shader_info
+        case OP_vkGetShaderInfoAMD:
+        {
+            return "OP_vkGetShaderInfoAMD";
+        }
+#endif
+#ifdef VK_NV_external_memory_capabilities
+        case OP_vkGetPhysicalDeviceExternalImageFormatPropertiesNV:
+        {
+            return "OP_vkGetPhysicalDeviceExternalImageFormatPropertiesNV";
+        }
+#endif
+#ifdef VK_NV_external_memory_win32
+        case OP_vkGetMemoryWin32HandleNV:
+        {
+            return "OP_vkGetMemoryWin32HandleNV";
+        }
+#endif
+#ifdef VK_NN_vi_surface
+        case OP_vkCreateViSurfaceNN:
+        {
+            return "OP_vkCreateViSurfaceNN";
+        }
+#endif
+#ifdef VK_EXT_conditional_rendering
+        case OP_vkCmdBeginConditionalRenderingEXT:
+        {
+            return "OP_vkCmdBeginConditionalRenderingEXT";
+        }
+        case OP_vkCmdEndConditionalRenderingEXT:
+        {
+            return "OP_vkCmdEndConditionalRenderingEXT";
+        }
+#endif
+#ifdef VK_NVX_device_generated_commands
+        case OP_vkCmdProcessCommandsNVX:
+        {
+            return "OP_vkCmdProcessCommandsNVX";
+        }
+        case OP_vkCmdReserveSpaceForCommandsNVX:
+        {
+            return "OP_vkCmdReserveSpaceForCommandsNVX";
+        }
+        case OP_vkCreateIndirectCommandsLayoutNVX:
+        {
+            return "OP_vkCreateIndirectCommandsLayoutNVX";
+        }
+        case OP_vkDestroyIndirectCommandsLayoutNVX:
+        {
+            return "OP_vkDestroyIndirectCommandsLayoutNVX";
+        }
+        case OP_vkCreateObjectTableNVX:
+        {
+            return "OP_vkCreateObjectTableNVX";
+        }
+        case OP_vkDestroyObjectTableNVX:
+        {
+            return "OP_vkDestroyObjectTableNVX";
+        }
+        case OP_vkRegisterObjectsNVX:
+        {
+            return "OP_vkRegisterObjectsNVX";
+        }
+        case OP_vkUnregisterObjectsNVX:
+        {
+            return "OP_vkUnregisterObjectsNVX";
+        }
+        case OP_vkGetPhysicalDeviceGeneratedCommandsPropertiesNVX:
+        {
+            return "OP_vkGetPhysicalDeviceGeneratedCommandsPropertiesNVX";
+        }
+#endif
+#ifdef VK_NV_clip_space_w_scaling
+        case OP_vkCmdSetViewportWScalingNV:
+        {
+            return "OP_vkCmdSetViewportWScalingNV";
+        }
+#endif
+#ifdef VK_EXT_direct_mode_display
+        case OP_vkReleaseDisplayEXT:
+        {
+            return "OP_vkReleaseDisplayEXT";
+        }
+#endif
+#ifdef VK_EXT_acquire_xlib_display
+        case OP_vkAcquireXlibDisplayEXT:
+        {
+            return "OP_vkAcquireXlibDisplayEXT";
+        }
+        case OP_vkGetRandROutputDisplayEXT:
+        {
+            return "OP_vkGetRandROutputDisplayEXT";
+        }
+#endif
+#ifdef VK_EXT_display_surface_counter
+        case OP_vkGetPhysicalDeviceSurfaceCapabilities2EXT:
+        {
+            return "OP_vkGetPhysicalDeviceSurfaceCapabilities2EXT";
+        }
+#endif
+#ifdef VK_EXT_display_control
+        case OP_vkDisplayPowerControlEXT:
+        {
+            return "OP_vkDisplayPowerControlEXT";
+        }
+        case OP_vkRegisterDeviceEventEXT:
+        {
+            return "OP_vkRegisterDeviceEventEXT";
+        }
+        case OP_vkRegisterDisplayEventEXT:
+        {
+            return "OP_vkRegisterDisplayEventEXT";
+        }
+        case OP_vkGetSwapchainCounterEXT:
+        {
+            return "OP_vkGetSwapchainCounterEXT";
+        }
+#endif
+#ifdef VK_GOOGLE_display_timing
+        case OP_vkGetRefreshCycleDurationGOOGLE:
+        {
+            return "OP_vkGetRefreshCycleDurationGOOGLE";
+        }
+        case OP_vkGetPastPresentationTimingGOOGLE:
+        {
+            return "OP_vkGetPastPresentationTimingGOOGLE";
+        }
+#endif
+#ifdef VK_EXT_discard_rectangles
+        case OP_vkCmdSetDiscardRectangleEXT:
+        {
+            return "OP_vkCmdSetDiscardRectangleEXT";
+        }
+#endif
+#ifdef VK_EXT_hdr_metadata
+        case OP_vkSetHdrMetadataEXT:
+        {
+            return "OP_vkSetHdrMetadataEXT";
+        }
+#endif
+#ifdef VK_MVK_ios_surface
+        case OP_vkCreateIOSSurfaceMVK:
+        {
+            return "OP_vkCreateIOSSurfaceMVK";
+        }
+#endif
+#ifdef VK_MVK_macos_surface
+        case OP_vkCreateMacOSSurfaceMVK:
+        {
+            return "OP_vkCreateMacOSSurfaceMVK";
+        }
+#endif
+#ifdef VK_EXT_debug_utils
+        case OP_vkSetDebugUtilsObjectNameEXT:
+        {
+            return "OP_vkSetDebugUtilsObjectNameEXT";
+        }
+        case OP_vkSetDebugUtilsObjectTagEXT:
+        {
+            return "OP_vkSetDebugUtilsObjectTagEXT";
+        }
+        case OP_vkQueueBeginDebugUtilsLabelEXT:
+        {
+            return "OP_vkQueueBeginDebugUtilsLabelEXT";
+        }
+        case OP_vkQueueEndDebugUtilsLabelEXT:
+        {
+            return "OP_vkQueueEndDebugUtilsLabelEXT";
+        }
+        case OP_vkQueueInsertDebugUtilsLabelEXT:
+        {
+            return "OP_vkQueueInsertDebugUtilsLabelEXT";
+        }
+        case OP_vkCmdBeginDebugUtilsLabelEXT:
+        {
+            return "OP_vkCmdBeginDebugUtilsLabelEXT";
+        }
+        case OP_vkCmdEndDebugUtilsLabelEXT:
+        {
+            return "OP_vkCmdEndDebugUtilsLabelEXT";
+        }
+        case OP_vkCmdInsertDebugUtilsLabelEXT:
+        {
+            return "OP_vkCmdInsertDebugUtilsLabelEXT";
+        }
+        case OP_vkCreateDebugUtilsMessengerEXT:
+        {
+            return "OP_vkCreateDebugUtilsMessengerEXT";
+        }
+        case OP_vkDestroyDebugUtilsMessengerEXT:
+        {
+            return "OP_vkDestroyDebugUtilsMessengerEXT";
+        }
+        case OP_vkSubmitDebugUtilsMessageEXT:
+        {
+            return "OP_vkSubmitDebugUtilsMessageEXT";
+        }
+#endif
+#ifdef VK_ANDROID_external_memory_android_hardware_buffer
+        case OP_vkGetAndroidHardwareBufferPropertiesANDROID:
+        {
+            return "OP_vkGetAndroidHardwareBufferPropertiesANDROID";
+        }
+        case OP_vkGetMemoryAndroidHardwareBufferANDROID:
+        {
+            return "OP_vkGetMemoryAndroidHardwareBufferANDROID";
+        }
+#endif
+#ifdef VK_EXT_sample_locations
+        case OP_vkCmdSetSampleLocationsEXT:
+        {
+            return "OP_vkCmdSetSampleLocationsEXT";
+        }
+        case OP_vkGetPhysicalDeviceMultisamplePropertiesEXT:
+        {
+            return "OP_vkGetPhysicalDeviceMultisamplePropertiesEXT";
+        }
+#endif
+#ifdef VK_EXT_validation_cache
+        case OP_vkCreateValidationCacheEXT:
+        {
+            return "OP_vkCreateValidationCacheEXT";
+        }
+        case OP_vkDestroyValidationCacheEXT:
+        {
+            return "OP_vkDestroyValidationCacheEXT";
+        }
+        case OP_vkMergeValidationCachesEXT:
+        {
+            return "OP_vkMergeValidationCachesEXT";
+        }
+        case OP_vkGetValidationCacheDataEXT:
+        {
+            return "OP_vkGetValidationCacheDataEXT";
+        }
+#endif
+#ifdef VK_EXT_external_memory_host
+        case OP_vkGetMemoryHostPointerPropertiesEXT:
+        {
+            return "OP_vkGetMemoryHostPointerPropertiesEXT";
+        }
+#endif
+#ifdef VK_AMD_buffer_marker
+        case OP_vkCmdWriteBufferMarkerAMD:
+        {
+            return "OP_vkCmdWriteBufferMarkerAMD";
+        }
+#endif
+#ifdef VK_NV_device_diagnostic_checkpoints
+        case OP_vkCmdSetCheckpointNV:
+        {
+            return "OP_vkCmdSetCheckpointNV";
+        }
+        case OP_vkGetQueueCheckpointDataNV:
+        {
+            return "OP_vkGetQueueCheckpointDataNV";
+        }
+#endif
+#ifdef VK_GOOGLE_address_space
+        case OP_vkMapMemoryIntoAddressSpaceGOOGLE:
+        {
+            return "OP_vkMapMemoryIntoAddressSpaceGOOGLE";
+        }
+#endif
+#ifdef VK_GOOGLE_color_buffer
+        case OP_vkRegisterImageColorBufferGOOGLE:
+        {
+            return "OP_vkRegisterImageColorBufferGOOGLE";
+        }
+        case OP_vkRegisterBufferColorBufferGOOGLE:
+        {
+            return "OP_vkRegisterBufferColorBufferGOOGLE";
+        }
+#endif
+#ifdef VK_GOOGLE_sized_descriptor_update_template
+        case OP_vkUpdateDescriptorSetWithTemplateSizedGOOGLE:
+        {
+            return "OP_vkUpdateDescriptorSetWithTemplateSizedGOOGLE";
+        }
+#endif
+#ifdef VK_GOOGLE_async_command_buffers
+        case OP_vkBeginCommandBufferAsyncGOOGLE:
+        {
+            return "OP_vkBeginCommandBufferAsyncGOOGLE";
+        }
+        case OP_vkEndCommandBufferAsyncGOOGLE:
+        {
+            return "OP_vkEndCommandBufferAsyncGOOGLE";
+        }
+        case OP_vkResetCommandBufferAsyncGOOGLE:
+        {
+            return "OP_vkResetCommandBufferAsyncGOOGLE";
+        }
+        case OP_vkCommandBufferHostSyncGOOGLE:
+        {
+            return "OP_vkCommandBufferHostSyncGOOGLE";
+        }
+#endif
+#ifdef VK_GOOGLE_create_resources_with_requirements
+        case OP_vkCreateImageWithRequirementsGOOGLE:
+        {
+            return "OP_vkCreateImageWithRequirementsGOOGLE";
+        }
+        case OP_vkCreateBufferWithRequirementsGOOGLE:
+        {
+            return "OP_vkCreateBufferWithRequirementsGOOGLE";
+        }
+#endif
+#ifdef VK_GOOGLE_address_space_info
+        case OP_vkGetMemoryHostAddressInfoGOOGLE:
+        {
+            return "OP_vkGetMemoryHostAddressInfoGOOGLE";
+        }
+#endif
+        default:
+        {
+            return "OP_UNKNOWN_API_CALL";
+        }
+    }
+}
+
 
 } // namespace goldfish_vk
diff --git a/system/vulkan_enc/goldfish_vk_marshaling_guest.h b/system/vulkan_enc/goldfish_vk_marshaling_guest.h
index 283e0ad..da9e961 100644
--- a/system/vulkan_enc/goldfish_vk_marshaling_guest.h
+++ b/system/vulkan_enc/goldfish_vk_marshaling_guest.h
@@ -3388,6 +3388,17 @@
 #define OP_vkBeginCommandBufferAsyncGOOGLE 20321
 #define OP_vkEndCommandBufferAsyncGOOGLE 20322
 #define OP_vkResetCommandBufferAsyncGOOGLE 20323
+#define OP_vkCommandBufferHostSyncGOOGLE 20324
 #endif
+#ifdef VK_GOOGLE_create_resources_with_requirements
+#define OP_vkCreateImageWithRequirementsGOOGLE 20325
+#define OP_vkCreateBufferWithRequirementsGOOGLE 20326
+#endif
+#ifdef VK_GOOGLE_address_space_info
+#define OP_vkGetMemoryHostAddressInfoGOOGLE 20327
+#endif
+const char* api_opcode_to_string(
+    const uint32_t opcode);
+
 
 } // namespace goldfish_vk
diff --git a/system/vulkan_enc/goldfish_vk_private_defs.h b/system/vulkan_enc/goldfish_vk_private_defs.h
index 15d30e1..dd0c155 100644
--- a/system/vulkan_enc/goldfish_vk_private_defs.h
+++ b/system/vulkan_enc/goldfish_vk_private_defs.h
@@ -17,6 +17,7 @@
 #include <vulkan/vulkan.h>
 
 #ifdef __cplusplus
+#include <algorithm>
 extern "C" {
 #endif
 
@@ -114,6 +115,10 @@
 typedef VkResult (VKAPI_PTR *PFN_vkRegisterImageColorBufferGOOGLE)(VkDevice device, VkImage image, uint32_t colorBuffer);
 typedef VkResult (VKAPI_PTR *PFN_vkRegisterBufferColorBufferGOOGLE)(VkDevice device, VkBuffer image, uint32_t colorBuffer);
 
+#define VK_GOOGLE_address_space_info 1
+
+typedef VkResult (VKAPI_PTR *PFN_vkGetMemoryHostAddressInfoGOOGLE)(VkDevice device, VkDeviceMemory memory, uint64_t* pAddress, uint64_t* pSize);
+
 #define VK_ANDROID_external_memory_android_hardware_buffer 1
 struct AHardwareBuffer;
 struct VkAndroidHardwareBufferPropertiesANDROID;
@@ -424,35 +429,28 @@
 typedef void (VKAPI_PTR *PFN_vkResetCommandBufferAsyncGOOGLE)(
     VkCommandBuffer commandBuffer,
     VkCommandBufferResetFlags flags);
+typedef void (VKAPI_PTR *PFN_vkCommandBufferHostSyncGOOGLE)(
+    VkCommandBuffer commandBuffer,
+    uint32_t needHostSync,
+    uint32_t sequenceNumber);
 
-#ifdef VK_USE_PLATFORM_FUCHSIA
+#define VK_GOOGLE_create_resources_with_requirements 1
+
+typedef void (VKAPI_PTR *PFN_vkCreateImageWithRequirementsGOOGLE)(
+    VkDevice device, const VkImageCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkImage* pImage, VkMemoryRequirements* pMemoryRequirements);
+
+#ifndef VK_FUCHSIA_buffer_collection
 #define VK_FUCHSIA_buffer_collection 1
 VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkBufferCollectionFUCHSIA)
 
 #define VK_FUCHSIA_BUFFER_COLLECTION_SPEC_VERSION 1
 #define VK_FUCHSIA_BUFFER_COLLECTION_EXTENSION_NAME "VK_FUCHSIA_buffer_collection"
 
-typedef struct VkBufferCollectionImageCreateInfoFUCHSIA {
-    VkStructureType              sType;
-    const void*                  pNext;
-    VkBufferCollectionFUCHSIA    collection;
-    uint32_t                     index;
-} VkBufferCollectionImageCreateInfoFUCHSIA;
-
-#define VK_STRUCTURE_TYPE_BUFFER_COLLECTION_IMAGE_CREATE_INFO_FUCHSIA \
-    ((VkStructureType)1001004005)
-#endif  // VK_USE_PLATFORM_FUCHSIA
-
-#ifdef VK_USE_PLATFORM_ANDROID_KHR
-
-typedef struct VkImportMemoryZirconHandleInfoFUCHSIA {
-    VkStructureType                       sType;
-    const void*                           pNext;
-    VkExternalMemoryHandleTypeFlagBits    handleType;
-    uint32_t                              handle;
-} VkImportMemoryZirconHandleInfoFUCHSIA;
-
-typedef uint32_t VkBufferCollectionFUCHSIA;
+typedef struct VkBufferCollectionCreateInfoFUCHSIA {
+    VkStructureType    sType;
+    const void*        pNext;
+    uint32_t           collectionToken;
+} VkBufferCollectionCreateInfoFUCHSIA;
 
 typedef struct VkImportMemoryBufferCollectionFUCHSIA {
     VkStructureType              sType;
@@ -461,17 +459,100 @@
     uint32_t                     index;
 } VkImportMemoryBufferCollectionFUCHSIA;
 
-#define VK_STRUCTURE_TYPE_IMPORT_MEMORY_BUFFER_COLLECTION_FUCHSIA \
-    ((VkStructureType)1001000000)
-#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_TEMP_ZIRCON_EVENT_BIT_FUCHSIA \
-    ((VkStructureType)0x00000020)
+typedef struct VkBufferCollectionImageCreateInfoFUCHSIA {
+    VkStructureType              sType;
+    const void*                  pNext;
+    VkBufferCollectionFUCHSIA    collection;
+    uint32_t                     index;
+} VkBufferCollectionImageCreateInfoFUCHSIA;
 
-#endif // VK_USE_PLATFORM_ANDROID_KHR
+typedef struct VkBufferCollectionPropertiesFUCHSIA {
+    VkStructureType    sType;
+    void*              pNext;
+    uint32_t           memoryTypeBits;
+    uint32_t           count;
+} VkBufferCollectionPropertiesFUCHSIA;
+
+#define VK_STRUCTURE_TYPE_IMPORT_MEMORY_BUFFER_COLLECTION_FUCHSIA       \
+    ((VkStructureType)1001004004)
+#define VK_STRUCTURE_TYPE_BUFFER_COLLECTION_IMAGE_CREATE_INFO_FUCHSIA \
+    ((VkStructureType)1001004005)
+#endif  // VK_FUCHSIA_buffer_collection
+
+#ifndef VK_FUCHSIA_external_memory
+#define VK_FUCHSIA_external_memory 1
+#define VK_FUCHSIA_EXTERNAL_MEMORY_SPEC_VERSION 1
+#define VK_FUCHSIA_EXTERNAL_MEMORY_EXTENSION_NAME "VK_FUCHSIA_external_memory"
+
+typedef struct VkImportMemoryZirconHandleInfoFUCHSIA {
+    VkStructureType                       sType;
+    const void*                           pNext;
+    VkExternalMemoryHandleTypeFlagBits    handleType;
+    uint32_t                              handle;
+} VkImportMemoryZirconHandleInfoFUCHSIA;
+
+typedef struct VkMemoryZirconHandlePropertiesFUCHSIA {
+    VkStructureType    sType;
+    void*              pNext;
+    uint32_t           memoryTypeBits;
+} VkMemoryZirconHandlePropertiesFUCHSIA;
+
+typedef struct VkMemoryGetZirconHandleInfoFUCHSIA {
+    VkStructureType                       sType;
+    const void*                           pNext;
+    VkDeviceMemory                        memory;
+    VkExternalMemoryHandleTypeFlagBits    handleType;
+} VkMemoryGetZirconHandleInfoFUCHSIA;
+
+#define VK_STRUCTURE_TYPE_TEMP_IMPORT_MEMORY_ZIRCON_HANDLE_INFO_FUCHSIA \
+    ((VkStructureType)1001005000)
+#define VK_STRUCTURE_TYPE_TEMP_MEMORY_ZIRCON_HANDLE_PROPERTIES_FUCHSIA \
+    ((VkStructureType)1001005001)
+#define VK_EXTERNAL_MEMORY_HANDLE_TYPE_TEMP_ZIRCON_VMO_BIT_FUCHSIA \
+    ((VkExternalMemoryHandleTypeFlagBits)0x00100000)
+#endif  // VK_FUCHSIA_external_memory
+
+#ifndef VK_FUCHSIA_external_semaphore
+#define VK_FUCHSIA_external_semaphore 1
+#define VK_FUCHSIA_EXTERNAL_SEMAPHORE_SPEC_VERSION 1
+#define VK_FUCHSIA_EXTERNAL_SEMAPHORE_EXTENSION_NAME "VK_FUCHSIA_external_semaphore"
+
+typedef struct VkImportSemaphoreZirconHandleInfoFUCHSIA {
+    VkStructureType                          sType;
+    const void*                              pNext;
+    VkSemaphore                              semaphore;
+    VkSemaphoreImportFlags                   flags;
+    VkExternalSemaphoreHandleTypeFlagBits    handleType;
+    uint32_t                                 handle;
+} VkImportSemaphoreZirconHandleInfoFUCHSIA;
+
+typedef struct VkSemaphoreGetZirconHandleInfoFUCHSIA {
+    VkStructureType                          sType;
+    const void*                              pNext;
+    VkSemaphore                              semaphore;
+    VkExternalSemaphoreHandleTypeFlagBits    handleType;
+} VkSemaphoreGetZirconHandleInfoFUCHSIA;
+
+#define VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_TEMP_ZIRCON_EVENT_BIT_FUCHSIA \
+    ((VkExternalSemaphoreHandleTypeFlagBits)0x00100000)
+#endif  // VK_FUCHSIA_external_semaphore
+
+// VulkanStream features
+#define VULKAN_STREAM_FEATURE_NULL_OPTIONAL_STRINGS_BIT (1 << 0)
+#define VULKAN_STREAM_FEATURE_IGNORED_HANDLES_BIT (1 << 1)
+
+#define VK_YCBCR_CONVERSION_DO_NOTHING ((VkSamplerYcbcrConversion)0x1111111111111111)
 
 #ifdef __cplusplus
 } // extern "C"
 #endif
+
+#ifdef __cplusplus
+
+template<class T, typename F>
+bool arrayany(const T* arr, uint32_t begin, uint32_t end, const F& func) {
+    const T* e = arr + end;
+    return std::find_if(arr + begin, e, func) != e;
+}
+
+#endif
diff --git a/system/vulkan_enc/goldfish_vk_transform_guest.cpp b/system/vulkan_enc/goldfish_vk_transform_guest.cpp
index aa42af7..9e7fbf5 100644
--- a/system/vulkan_enc/goldfish_vk_transform_guest.cpp
+++ b/system/vulkan_enc/goldfish_vk_transform_guest.cpp
@@ -8945,6 +8945,10 @@
 #endif
 #ifdef VK_GOOGLE_async_command_buffers
 #endif
+#ifdef VK_GOOGLE_create_resources_with_requirements
+#endif
+#ifdef VK_GOOGLE_address_space_info
+#endif
 void transform_tohost_extension_struct(
     ResourceTracker* resourceTracker,
     void* structExtension_out)
diff --git a/system/vulkan_enc/goldfish_vk_transform_guest.h b/system/vulkan_enc/goldfish_vk_transform_guest.h
index 754c033..6511666 100644
--- a/system/vulkan_enc/goldfish_vk_transform_guest.h
+++ b/system/vulkan_enc/goldfish_vk_transform_guest.h
@@ -3067,5 +3067,9 @@
 #endif
 #ifdef VK_GOOGLE_async_command_buffers
 #endif
+#ifdef VK_GOOGLE_create_resources_with_requirements
+#endif
+#ifdef VK_GOOGLE_address_space_info
+#endif
 
 } // namespace goldfish_vk
diff --git a/system/vulkan_enc/vk_format_info.h b/system/vulkan_enc/vk_format_info.h
index c70f45f..dd9c99b 100644
--- a/system/vulkan_enc/vk_format_info.h
+++ b/system/vulkan_enc/vk_format_info.h
@@ -27,6 +27,9 @@
 #define VK_FORMAT_INFO_H
 
 #include <stdbool.h>
+#ifdef VK_USE_PLATFORM_ANDROID_KHR
+#include <system/graphics.h>
+#endif
 #include <vulkan/vulkan.h>
 #include <vndk/hardware_buffer.h>
 
@@ -51,7 +54,13 @@
       return VK_FORMAT_A2B10G10R10_UNORM_PACK32;
    case HAL_PIXEL_FORMAT_NV12_Y_TILED_INTEL:
       return VK_FORMAT_G8_B8R8_2PLANE_420_UNORM;
+#ifdef VK_USE_PLATFORM_ANDROID_KHR
+   case HAL_PIXEL_FORMAT_YV12:
+      // YUV converter will convert this format to R8G8B8A8
+      // TODO: should we use R8G8B8A8 for other YUV format as well?
+      return VK_FORMAT_R8G8B8A8_UNORM;
    case AHARDWAREBUFFER_FORMAT_BLOB:
+#endif
    default:
       return VK_FORMAT_UNDEFINED;
    }
diff --git a/system/vulkan_enc/vk_struct_id.h b/system/vulkan_enc/vk_struct_id.h
index 893389c..1a33438 100644
--- a/system/vulkan_enc/vk_struct_id.h
+++ b/system/vulkan_enc/vk_struct_id.h
@@ -43,15 +43,12 @@
 REGISTER_VK_STRUCT_ID(VkSamplerYcbcrConversionCreateInfo, VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_CREATE_INFO);
 REGISTER_VK_STRUCT_ID(VkImportColorBufferGOOGLE, VK_STRUCTURE_TYPE_IMPORT_COLOR_BUFFER_GOOGLE);
 REGISTER_VK_STRUCT_ID(VkImageViewCreateInfo, VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO);
-
-#ifdef VK_USE_PLATFORM_ANDROID_KHR
-// These two should be under Android
 REGISTER_VK_STRUCT_ID(VkImportMemoryBufferCollectionFUCHSIA, VK_STRUCTURE_TYPE_IMPORT_MEMORY_BUFFER_COLLECTION_FUCHSIA);
 REGISTER_VK_STRUCT_ID(VkImportMemoryZirconHandleInfoFUCHSIA, VK_STRUCTURE_TYPE_TEMP_IMPORT_MEMORY_ZIRCON_HANDLE_INFO_FUCHSIA);
-#endif  // VK_USE_PLATFORM_ANDROID_KHR
-
-#ifdef VK_USE_PLATFORM_FUCHSIA
 REGISTER_VK_STRUCT_ID(VkBufferCollectionImageCreateInfoFUCHSIA, VK_STRUCTURE_TYPE_BUFFER_COLLECTION_IMAGE_CREATE_INFO_FUCHSIA);
-#endif  // VK_USE_PLATFORM_FUCHSIA
+REGISTER_VK_STRUCT_ID(VkSamplerCreateInfo, VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO);
+REGISTER_VK_STRUCT_ID(VkSamplerYcbcrConversionInfo, VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_INFO);
+REGISTER_VK_STRUCT_ID(VkFenceCreateInfo, VK_STRUCTURE_TYPE_FENCE_CREATE_INFO);
+REGISTER_VK_STRUCT_ID(VkExportFenceCreateInfo, VK_STRUCTURE_TYPE_EXPORT_FENCE_CREATE_INFO);
 
 #undef REGISTER_VK_STRUCT_ID
diff --git a/system/vulkan_enc/vulkan_enc_unittests.cpp b/system/vulkan_enc/vulkan_enc_unittests.cpp
new file mode 100644
index 0000000..744ea31
--- /dev/null
+++ b/system/vulkan_enc/vulkan_enc_unittests.cpp
@@ -0,0 +1,288 @@
+// Copyright (C) 2019 The Android Open Source Project
+// Copyright (C) 2019 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+#include <gtest/gtest.h>
+
+#include "android/base/synchronization/AndroidConditionVariable.h"
+#include "android/base/synchronization/AndroidLock.h"
+#include "android/base/threads/AndroidWorkPool.h"
+
+#include <atomic>
+#include <vector>
+
+namespace android {
+namespace base {
+namespace guest {
+
+// Tests basic default construction/deconstruction.
+TEST(WorkPool, Basic) {
+    WorkPool p;
+}
+
+// Tests sending one task.
+TEST(WorkPool, One) {
+    WorkPool p;
+
+    WorkPool::Task task = [] {
+        fprintf(stderr, "do something\n");
+    };
+
+    std::vector<WorkPool::Task> tasks { task };
+
+    p.schedule(tasks);
+}
+
+// Tests sending two tasks.
+TEST(WorkPool, Two) {
+    WorkPool p;
+
+    std::vector<WorkPool::Task> tasks {
+        [] { fprintf(stderr, "do something 1\n"); },
+        [] { fprintf(stderr, "do something 2\n"); },
+    };
+
+    p.schedule(tasks);
+}
+
+// Tests sending eight tasks (can require spawning more threads)
+TEST(WorkPool, Eight) {
+    WorkPool p;
+
+    std::vector<WorkPool::Task> tasks {
+        [] { fprintf(stderr, "do something 1\n"); },
+        [] { fprintf(stderr, "do something 2\n"); },
+        [] { fprintf(stderr, "do something 3\n"); },
+        [] { fprintf(stderr, "do something 4\n"); },
+        [] { fprintf(stderr, "do something 5\n"); },
+        [] { fprintf(stderr, "do something 6\n"); },
+        [] { fprintf(stderr, "do something 7\n"); },
+        [] { fprintf(stderr, "do something 8\n"); },
+    };
+
+    p.schedule(tasks);
+}
+
+// Tests waitAny primitive; if at least one of the tasks successfully run,
+// at least one of them will read 0 and store back 1 in |x|, or more,
+// so check that x >= 1.
+TEST(WorkPool, WaitAny) {
+    WorkPool p;
+    int x = 0;
+    WorkPool::WaitGroupHandle handle = 0;
+
+    {
+        std::vector<WorkPool::Task> tasks;
+
+        for (int i = 0; i < 8; ++i) {
+            tasks.push_back([&x] { ++x; });
+        }
+
+        handle = p.schedule(tasks);
+    }
+
+
+    p.waitAny(handle, -1);
+
+    EXPECT_GE(x, 1);
+
+    // Prevent use after scope after test finish
+    p.waitAll(handle);
+}
+
+// Tests waitAll primitive; each worker increments the atomic int once,
+// so we expect it to end up at 8 (8 workers).
+TEST(WorkPool, WaitAll) {
+    WorkPool p;
+    std::atomic<int> x { 0 };
+
+    std::vector<WorkPool::Task> tasks;
+
+    for (int i = 0; i < 8; ++i) {
+        tasks.push_back([&x] { ++x; });
+    }
+
+    auto handle = p.schedule(tasks);
+
+    p.waitAll(handle, -1);
+
+    EXPECT_EQ(x, 8);
+}
+
+// Tests waitAll primitive with two concurrent wait groups in flight.
+// The second wait group is scheduled after the first, but
+// we wait on the second wait group first. This is to ensure that
+// order of submission does not enforce order of waiting / completion.
+TEST(WorkPool, WaitAllTwoWaitGroups) {
+    WorkPool p;
+    std::atomic<int> x { 0 };
+    std::atomic<int> y { 0 };
+
+    std::vector<WorkPool::Task> tasks1;
+    std::vector<WorkPool::Task> tasks2;
+
+    for (int i = 0; i < 8; ++i) {
+        tasks1.push_back([&x] { ++x; });
+        tasks2.push_back([&y] { ++y; });
+    }
+
+    auto handle1 = p.schedule(tasks1);
+    auto handle2 = p.schedule(tasks2);
+
+    p.waitAll(handle2, -1);
+    p.waitAll(handle1, -1);
+
+    EXPECT_EQ(x, 8);
+    EXPECT_EQ(y, 8);
+}
+
+// Tests waitAll primitive with two concurrent wait groups.
+// The first wait group waits on what the second wait group will signal.
+// This is to ensure that we can send blocking tasks to WorkPool
+// without causing a deadlock.
+TEST(WorkPool, WaitAllWaitSignal) {
+    WorkPool p;
+    Lock lock;
+    ConditionVariable cv;
+    // Similar to a timeline semaphore object;
+    // one process waits on a particular value to get reached,
+    // while other processes gradually increment it.
+    std::atomic<int> x { 0 };
+
+    std::vector<WorkPool::Task> tasks1 = {
+        [&lock, &cv, &x] {
+            AutoLock l(lock);
+            while (x < 8) {
+                cv.wait(&lock);
+            }
+        },
+    };
+
+    std::vector<WorkPool::Task> tasks2;
+
+    for (int i = 0; i < 8; ++i) {
+        tasks2.push_back([&lock, &cv, &x] {
+            AutoLock l(lock);
+            ++x;
+            cv.signal();
+        });
+    }
+
+    auto handle1 = p.schedule(tasks1);
+    auto handle2 = p.schedule(tasks2);
+
+    p.waitAll(handle1, -1);
+
+    EXPECT_EQ(8, x);
+}
+
+// Tests waitAll primitive with some kind of timeout.
+// We don't expect x to be anything in particular..
+TEST(WorkPool, WaitAllTimeout) {
+    WorkPool p;
+    Lock lock;
+    ConditionVariable cv;
+    std::atomic<int> x { 0 };
+
+    std::vector<WorkPool::Task> tasks1 = {
+        [&lock, &cv, &x] {
+            AutoLock l(lock);
+            while (x < 8) {
+                cv.wait(&lock);
+            }
+        },
+    };
+
+    std::vector<WorkPool::Task> tasks2;
+
+    for (int i = 0; i < 8; ++i) {
+        tasks2.push_back([&lock, &cv, &x] {
+            AutoLock l(lock);
+            ++x;
+            cv.signal();
+        });
+    }
+
+    auto handle1 = p.schedule(tasks1);
+    auto handle2 = p.schedule(tasks2);
+
+    p.waitAll(handle1, 10);
+}
+
+// Tests waitAny primitive with some kind of timeout.
+// We don't expect x to be anything in particular..
+TEST(WorkPool, WaitAnyTimeout) {
+    WorkPool p;
+    Lock lock;
+    ConditionVariable cv;
+    std::atomic<int> x { 0 };
+
+    std::vector<WorkPool::Task> tasks1 = {
+        [&lock, &cv, &x] {
+            AutoLock l(lock);
+            while (x < 8) {
+                cv.wait(&lock);
+            }
+        },
+    };
+
+    std::vector<WorkPool::Task> tasks2;
+
+    for (int i = 0; i < 8; ++i) {
+        tasks2.push_back([&lock, &cv, &x] {
+            AutoLock l(lock);
+            ++x;
+            cv.signal();
+        });
+    }
+
+    auto handle1 = p.schedule(tasks1);
+    auto handle2 = p.schedule(tasks2);
+
+    p.waitAny(handle1, 10);
+}
+
+// Nesting waitAll inside another task.
+TEST(WorkPool, NestedWaitAll) {
+    WorkPool p;
+    std::atomic<int> x { 0 };
+    std::atomic<int> y { 0 };
+
+    std::vector<WorkPool::Task> tasks1;
+
+    for (int i = 0; i < 8; ++i) {
+        tasks1.push_back([&x] {
+            ++x;
+        });
+    }
+
+    auto waitGroupHandle = p.schedule(tasks1);
+
+    std::vector<WorkPool::Task> tasks2 = {
+        [&p, waitGroupHandle, &x, &y] {
+            p.waitAll(waitGroupHandle);
+            EXPECT_EQ(8, x);
+            ++y;
+        },
+    };
+
+    auto handle2 = p.schedule(tasks2);
+
+    p.waitAll(handle2);
+
+    EXPECT_EQ(1, y);
+}
+
+} // namespace android
+} // namespace base
+} // namespace guest