Snap for 12231853 from 1bc8f06614fffd18c4f5392ff34f2da65e7a1c8f to emu-35-2-release

Change-Id: I4ea62e71eed8cfeca51c4071399e3a0e753a21af
diff --git a/Android.bp b/Android.bp
index 09c58d4..4f17387 100644
--- a/Android.bp
+++ b/Android.bp
@@ -100,10 +100,53 @@
     ],
 }
 
+soong_config_module_type {
+    name: "gfxstream_cc_defaults_config_for_platform",
+    module_type: "cc_defaults",
+    config_namespace: "gfxstream",
+    variables: ["mesa3d_platforms"],
+    properties: [
+        "cflags",
+        "target.android.srcs",
+    ],
+}
+
+soong_config_string_variable {
+    name: "mesa3d_platforms",
+    values: [
+        // Android surfaceless build
+        "none",
+        // The default when variable is not set is Android
+    ],
+}
+
+gfxstream_cc_defaults_config_for_platform {
+    name: "gfxstream_guest_cc_defaults_for_platform",
+    soong_config_variables: {
+        mesa3d_platforms: {
+            // Android surfaceless build
+            none: {
+                cflags: [
+                    "-UANDROID",
+                    "-U__ANDROID__",
+                    "-DLINUX_GUEST_BUILD",
+                ],
+            },
+            // The default when variable is not set is Android
+            conditions_default: {
+                cflags: [
+                    "-DVK_USE_PLATFORM_ANDROID_KHR",
+                ],
+            },
+        },
+    },
+}
+
 cc_defaults {
     name: "gfxstream_guest_cc_defaults",
     defaults: [
         "gfxstream_cc_defaults",
+        "gfxstream_guest_cc_defaults_for_platform",
     ],
 }
 
diff --git a/codegen/vulkan/vulkan-docs-next/scripts/cerealgenerator.py b/codegen/vulkan/vulkan-docs-next/scripts/cerealgenerator.py
index 6e13231..01e58bf 100644
--- a/codegen/vulkan/vulkan-docs-next/scripts/cerealgenerator.py
+++ b/codegen/vulkan/vulkan-docs-next/scripts/cerealgenerator.py
@@ -91,6 +91,7 @@
     "VK_EXT_host_image_copy",
     "VK_EXT_image_compression_control",
     "VK_EXT_image_compression_control_swapchain",
+    "VK_EXT_image_drm_format_modifier",
     # VK1.3 extensions: see b/298704840
     "VK_KHR_copy_commands2",
     "VK_KHR_dynamic_rendering",
diff --git a/common/end2end/Android.bp b/common/end2end/Android.bp
index de6086e..4ec4200 100644
--- a/common/end2end/Android.bp
+++ b/common/end2end/Android.bp
@@ -17,12 +17,15 @@
         "GfxstreamEnd2EndVkSnapshotBufferTests.cpp",
         "GfxstreamEnd2EndVkSnapshotImageTests.cpp",
         "GfxstreamEnd2EndVkSnapshotPipelineTests.cpp",
+        "KumquatInstance.cpp",
     ],
     header_libs: [
+        "virtgpu_kumquat_ffi_headers",
         "gfxstream_headers",
         "libgfxstream_guest_rendercontrol_headers",
     ],
     data: [
+        "//external/crosvm:kumquat",
         "testdata/256x256_android.png",
         "testdata/256x256_android_with_transparency.png",
         "testdata/256x256_golden_basic_composition.png",
@@ -31,21 +34,19 @@
         "libEGL_emulation_with_host",
         "libgfxstream_guest_rendercontrol_with_host",
         "libgfxstream_guest_vulkan_with_host",
-        "libgfxstream_platform_rutabaga_server",
         "libGLESv1_CM_emulation_with_host",
         "libGLESv2_emulation_with_host",
     ],
     shared_libs: [
-        "libandroidemu",
         "libOpenglSystemCommonWithHost",
         "liblog",
-        "libgfxstream_platform_rutabaga_server",
+        "libvirtgpu_kumquat_ffi",
     ],
     static_libs: [
+        "libgfxstream_androidemu_static",
         "libgfxstream_common_image",
         "libgfxstream_common_utils",
         "libgfxstream_guest_android_with_host",
-        "libgfxstream_platform_rutabaga",
         "libgfxstream_thirdparty_stb",
         "libgmock",
     ],
diff --git a/common/end2end/GfxstreamEnd2EndTests.cpp b/common/end2end/GfxstreamEnd2EndTests.cpp
index fd3212f..0ff6900 100644
--- a/common/end2end/GfxstreamEnd2EndTests.cpp
+++ b/common/end2end/GfxstreamEnd2EndTests.cpp
@@ -22,11 +22,8 @@
 
 #include <filesystem>
 
-#include "ProcessPipe.h"
-#include "RutabagaLayer.h"
 #include "aemu/base/Path.h"
 #include "gfxstream/ImageUtils.h"
-#include "gfxstream/RutabagaLayerTestUtils.h"
 #include "gfxstream/Strings.h"
 
 VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE
@@ -226,25 +223,21 @@
 
 void GfxstreamEnd2EndTest::SetUp() {
     const TestParams params = GetParam();
-
     const std::string transportValue = GfxstreamTransportToEnvVar(params.with_transport);
-    ASSERT_THAT(setenv("GFXSTREAM_TRANSPORT", transportValue.c_str(), /*overwrite=*/1), Eq(0));
-
-    ASSERT_THAT(setenv("GFXSTREAM_EMULATED_VIRTIO_GPU_WITH_GL",
-                       params.with_gl ? "Y" : "N", /*overwrite=*/1), Eq(0));
-    ASSERT_THAT(setenv("GFXSTREAM_EMULATED_VIRTIO_GPU_WITH_VK", params.with_vk ? "Y" : "N",
-                       /*overwrite=*/1),
-                Eq(0));
-
     std::vector<std::string> featureEnables;
     for (const std::string& feature : params.with_features) {
         featureEnables.push_back(feature + ":enabled");
     }
-    const std::string features = Join(featureEnables, ",");
-    ASSERT_THAT(setenv("GFXSTREAM_EMULATED_VIRTIO_GPU_RENDERER_FEATURES", features.c_str(),
-                        /*overwrite=*/1),
-                Eq(0));
 
+    ASSERT_THAT(setenv("GFXSTREAM_TRANSPORT", transportValue.c_str(), /*overwrite=*/1), Eq(0));
+
+    const std::string features = Join(featureEnables, ",");
+
+    // We probably don't need to create a Kumquat Server instance for every test.  GTest provides
+    // SetUpTestSuite + TearDownTestSuite for common resources that can be shared across a test
+    // suite.
+    mKumquatInstance = std::make_unique<KumquatInstance>();
+    mKumquatInstance->SetUp(params.with_gl, params.with_vk, features);
 
     if (params.with_gl) {
         mGl = SetupGuestGl();
@@ -279,25 +272,11 @@
     mAnwHelper.reset();
     mGralloc.reset();
     mSync.reset();
-
-    processPipeRestart();
-}
-
-void GfxstreamEnd2EndTest::TearDownHost() {
-    const uint32_t users = GetNumActiveEmulatedVirtioGpuUsers();
-    if (users != 0) {
-        ALOGE("The EmulationVirtioGpu was found to still be active by %" PRIu32
-              " after the "
-              "end of the test. Please ensure you have fully destroyed all objects created "
-              "during the test (Gralloc allocations, ANW allocations, etc).",
-              users);
-        abort();
-    }
 }
 
 void GfxstreamEnd2EndTest::TearDown() {
     TearDownGuest();
-    TearDownHost();
+    mKumquatInstance.reset();
 }
 
 void GfxstreamEnd2EndTest::SetUpEglContextAndSurface(
@@ -626,12 +605,8 @@
 }
 
 void GfxstreamEnd2EndTest::SnapshotSaveAndLoad() {
-    auto directory = testing::TempDir();
-
-    std::shared_ptr<gfxstream::EmulatedVirtioGpu> emulation = gfxstream::EmulatedVirtioGpu::Get();
-
-    emulation->SnapshotSave(directory);
-    emulation->SnapshotRestore(directory);
+    mKumquatInstance->Snapshot();
+    mKumquatInstance->Restore();
 }
 
 Result<Image> GfxstreamEnd2EndTest::LoadImage(const std::string& basename) {
diff --git a/common/end2end/GfxstreamEnd2EndTests.h b/common/end2end/GfxstreamEnd2EndTests.h
index dbcb645..bae58c2 100644
--- a/common/end2end/GfxstreamEnd2EndTests.h
+++ b/common/end2end/GfxstreamEnd2EndTests.h
@@ -44,6 +44,7 @@
 #include <vulkan/vk_android_native_buffer.h>
 // clang-format on
 
+#include "KumquatInstance.h"
 #include "Sync.h"
 #include "drm_fourcc.h"
 #include "gfxstream/Expected.h"
@@ -522,7 +523,6 @@
     void SetUp() override;
 
     void TearDownGuest();
-    void TearDownHost();
     void TearDown() override;
 
     void SetUpEglContextAndSurface(uint32_t contextVersion,
@@ -576,6 +576,8 @@
     std::unique_ptr<GuestGlDispatchTable> mGl;
     std::unique_ptr<GuestRenderControlDispatchTable> mRc;
     std::unique_ptr<vkhpp::DynamicLoader> mVk;
+
+    std::unique_ptr<KumquatInstance> mKumquatInstance = nullptr;
 };
 
 }  // namespace tests
diff --git a/common/end2end/GfxstreamEnd2EndVkSnapshotBufferTests.cpp b/common/end2end/GfxstreamEnd2EndVkSnapshotBufferTests.cpp
index c615215..941b334 100644
--- a/common/end2end/GfxstreamEnd2EndVkSnapshotBufferTests.cpp
+++ b/common/end2end/GfxstreamEnd2EndVkSnapshotBufferTests.cpp
@@ -16,7 +16,6 @@
 
 #include "GfxstreamEnd2EndTestUtils.h"
 #include "GfxstreamEnd2EndTests.h"
-#include "gfxstream/RutabagaLayerTestUtils.h"
 
 namespace gfxstream {
 namespace tests {
@@ -291,4 +290,4 @@
 
 }  // namespace
 }  // namespace tests
-}  // namespace gfxstream
\ No newline at end of file
+}  // namespace gfxstream
diff --git a/common/end2end/GfxstreamEnd2EndVkSnapshotImageTests.cpp b/common/end2end/GfxstreamEnd2EndVkSnapshotImageTests.cpp
index 3dad6d3..a32b32c 100644
--- a/common/end2end/GfxstreamEnd2EndVkSnapshotImageTests.cpp
+++ b/common/end2end/GfxstreamEnd2EndVkSnapshotImageTests.cpp
@@ -16,7 +16,6 @@
 
 #include "GfxstreamEnd2EndTestUtils.h"
 #include "GfxstreamEnd2EndTests.h"
-#include "gfxstream/RutabagaLayerTestUtils.h"
 
 namespace gfxstream {
 namespace tests {
@@ -619,4 +618,4 @@
 
 }  // namespace
 }  // namespace tests
-}  // namespace gfxstream
\ No newline at end of file
+}  // namespace gfxstream
diff --git a/common/end2end/GfxstreamEnd2EndVkSnapshotPipelineTests.cpp b/common/end2end/GfxstreamEnd2EndVkSnapshotPipelineTests.cpp
index be14641..c277447 100644
--- a/common/end2end/GfxstreamEnd2EndVkSnapshotPipelineTests.cpp
+++ b/common/end2end/GfxstreamEnd2EndVkSnapshotPipelineTests.cpp
@@ -16,7 +16,6 @@
 
 #include "GfxstreamEnd2EndTestUtils.h"
 #include "GfxstreamEnd2EndTests.h"
-#include "gfxstream/RutabagaLayerTestUtils.h"
 #include "shaders/simple_shader_frag.h"
 #include "shaders/simple_shader_vert.h"
 
@@ -1288,4 +1287,4 @@
 
 }  // namespace
 }  // namespace tests
-}  // namespace gfxstream
\ No newline at end of file
+}  // namespace gfxstream
diff --git a/common/end2end/GfxstreamEnd2EndVkTests.cpp b/common/end2end/GfxstreamEnd2EndVkTests.cpp
index c91f222..7d749a1 100644
--- a/common/end2end/GfxstreamEnd2EndVkTests.cpp
+++ b/common/end2end/GfxstreamEnd2EndVkTests.cpp
@@ -1747,12 +1747,13 @@
 
         constexpr const int kNumThreads = 5;
         for (int t = 0; t < kNumThreads; t++) {
-            threads.emplace_back([&, this](){
+            threads.emplace_back([&, this]() {
                 // Perform some work to ensure host RenderThread started.
                 auto buffer1 = device->createBufferUnique(bufferCreateInfo).value;
 
                 ++threadsReady;
-                while (threadsReady.load() != kNumThreads) {}
+                while (threadsReady.load() != kNumThreads) {
+                }
 
                 // Sleep a little which is hopefully enough time to potentially get
                 // the corresponding host ASG RenderThreads to go sleep waiting for
diff --git a/common/end2end/KumquatInstance.cpp b/common/end2end/KumquatInstance.cpp
new file mode 100644
index 0000000..e3cb966
--- /dev/null
+++ b/common/end2end/KumquatInstance.cpp
@@ -0,0 +1,90 @@
+// Copyright (C) 2024 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 <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+#include "KumquatInstance.h"
+
+#include <unistd.h>
+
+#include <filesystem>
+
+#include "aemu/base/Path.h"
+
+using testing::Eq;
+
+namespace gfxstream {
+namespace tests {
+
+KumquatInstance::KumquatInstance() {}
+
+void KumquatInstance::SetUp(bool withGl, bool withVk, std::string features) {
+    const std::filesystem::path testDirectory = gfxstream::guest::getProgramDirectory();
+    const std::string kumquatCommand = (testDirectory / "kumquat").string();
+    const std::string renderer_features = "--renderer-features=" + features;
+
+    std::string capset_names = "--capset-names=";
+    if (withGl) {
+        capset_names.append("gfxstream-gles:");
+    }
+    if (withVk) {
+        capset_names.append("gfxstream-vulkan:");
+    }
+
+    int fds[2];
+    ASSERT_THAT(pipe(fds), Eq(0));
+
+    // VirtGpuKumquatDevice.cpp by default connects to "/tmp/kumquat-gpu-0".  If this changes,
+    // the correct socket path must be plumbed through to VirtGpuKumquatDevice.cpp
+    const std::string gpu_socket_path = "/tmp/kumquat-gpu-" + std::to_string(0);
+
+    const std::string gpu_socket_cmd = "--gpu-socket-path=" + gpu_socket_path;
+
+    const std::string pipe_descriptor = "--pipe-descriptor=" + std::to_string(fds[1]);
+
+    pid_t pid = fork();
+    if (pid == 0) {
+        close(fds[0]);
+        execl(kumquatCommand.c_str(), kumquatCommand.c_str(), gpu_socket_cmd.c_str(),
+              capset_names.c_str(), renderer_features.c_str(), pipe_descriptor.c_str(), nullptr);
+        exit(0);
+    } else {
+        close(fds[1]);
+        uint64_t count = 0;
+        ssize_t bytes_read = read(fds[0], &count, sizeof(count));
+        // Kumquat writes [uint64_t](1) to the write end of the pipe..
+        ASSERT_THAT(bytes_read, Eq(8));
+        close(fds[0]);
+        ASSERT_THAT(virtgpu_kumquat_init(&mVirtGpu, gpu_socket_path.c_str()), Eq(0));
+        mKumquatPid = pid;
+    }
+}
+
+KumquatInstance::~KumquatInstance() {
+    virtgpu_kumquat_finish(&mVirtGpu);
+    kill(mKumquatPid, SIGKILL);
+    int status = 0;
+    pid_t pid = waitpid(mKumquatPid, &status, WNOHANG);
+    while (!pid) {
+        pid = waitpid(mKumquatPid, &status, WNOHANG);
+    }
+}
+
+void KumquatInstance::Snapshot() { ASSERT_THAT(virtgpu_kumquat_snapshot_save(mVirtGpu), Eq(0)); }
+
+void KumquatInstance::Restore() { ASSERT_THAT(virtgpu_kumquat_snapshot_restore(mVirtGpu), Eq(0)); }
+
+}  // namespace tests
+}  // namespace gfxstream
diff --git a/common/end2end/KumquatInstance.h b/common/end2end/KumquatInstance.h
new file mode 100644
index 0000000..ea0b7ed
--- /dev/null
+++ b/common/end2end/KumquatInstance.h
@@ -0,0 +1,40 @@
+// Copyright (C) 2024 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 <cstdint>
+#include <string>
+
+#include "virtgpu_kumquat_ffi.h"
+
+namespace gfxstream {
+namespace tests {
+
+class KumquatInstance {
+   public:
+    KumquatInstance();
+    ~KumquatInstance();
+
+    void SetUp(bool withGl, bool withVk, std::string features);
+    void Snapshot();
+    void Restore();
+
+   private:
+    pid_t mKumquatPid = 0;
+    struct virtgpu_kumquat* mVirtGpu = nullptr;
+};
+
+}  // namespace tests
+}  // namespace gfxstream
diff --git a/common/etc/BUILD.bazel b/common/etc/BUILD.bazel
index c9a9d78..3d723be 100644
--- a/common/etc/BUILD.bazel
+++ b/common/etc/BUILD.bazel
@@ -13,6 +13,7 @@
 cc_library(
     name = "gfxstream_etc",
     srcs = ["etc.cpp"],
+    copts = ["-fno-exceptions"],
     visibility = ["//visibility:public"],  # Control visibility
     deps = [":gfxstream_etc_headers"],
 )
diff --git a/common/utils/BUILD.bazel b/common/utils/BUILD.bazel
index 79599da..b6cc3ab 100644
--- a/common/utils/BUILD.bazel
+++ b/common/utils/BUILD.bazel
@@ -10,6 +10,7 @@
 cc_library(
     name = "gfxstream_common_utils",
     srcs = ["Strings.cpp"],
+    copts = ["-fno-exceptions"],
     visibility = ["//visibility:public"],
     deps = [":gfxstream_common_utils_headers"],
 )
diff --git a/guest/GLESv1/Android.bp b/guest/GLESv1/Android.bp
index 166e5bd..ac884a5 100644
--- a/guest/GLESv1/Android.bp
+++ b/guest/GLESv1/Android.bp
@@ -26,6 +26,9 @@
     defaults: [
         "libgfxstream_guest_cc_defaults",
     ],
+    header_libs: [
+        "libgfxstream_egl_headers",
+    ],
     shared_libs: [
         "liblog",
         "lib_renderControl_enc",
diff --git a/guest/GLESv1_enc/Android.bp b/guest/GLESv1_enc/Android.bp
index 2489667..ec3925e 100644
--- a/guest/GLESv1_enc/Android.bp
+++ b/guest/GLESv1_enc/Android.bp
@@ -30,8 +30,10 @@
         "libgfxstream_guest_graphics_headers",
         "libgfxstream_guest_iostream",
     ],
+    static_libs: [
+        "libgfxstream_androidemu_static",
+    ],
     shared_libs: [
-        "libandroidemu",
         "liblog",
         "libOpenglCodecCommon",
     ],
diff --git a/guest/GLESv2/Android.bp b/guest/GLESv2/Android.bp
index f4728d5..cd921dd 100644
--- a/guest/GLESv2/Android.bp
+++ b/guest/GLESv2/Android.bp
@@ -26,6 +26,12 @@
     defaults: [
         "libgfxstream_guest_cc_defaults",
     ],
+    header_libs: [
+        "libgfxstream_egl_headers",
+    ],
+    static_libs: [
+        "libgfxstream_androidemu_static",
+    ],
     shared_libs: [
         "liblog",
         "lib_renderControl_enc",
diff --git a/guest/GLESv2_enc/Android.bp b/guest/GLESv2_enc/Android.bp
index 0ea4aeb..5ed3b0f 100644
--- a/guest/GLESv2_enc/Android.bp
+++ b/guest/GLESv2_enc/Android.bp
@@ -45,7 +45,6 @@
         "libgfxstream_guest_iostream",
     ],
     shared_libs: [
-        "libandroidemu",
         "liblog",
         "libOpenglCodecCommon",
     ],
@@ -53,6 +52,7 @@
         "libOpenglCodecCommon",
     ],
     static_libs: [
+        "libgfxstream_androidemu_static",
         "libgfxstream_gles2_encoder_program_binary_proto",
         "libprotobuf-cpp-lite",
     ],
diff --git a/guest/GoldfishAddressSpace/GoldfishAddressSpaceStream.cpp b/guest/GoldfishAddressSpace/GoldfishAddressSpaceStream.cpp
index f1c8330..294db47 100644
--- a/guest/GoldfishAddressSpace/GoldfishAddressSpaceStream.cpp
+++ b/guest/GoldfishAddressSpace/GoldfishAddressSpaceStream.cpp
@@ -14,6 +14,8 @@
 
 #include "GoldfishAddressSpaceStream.h"
 
+#include <log/log.h>
+
 #include "goldfish_address_space.h"
 
 AddressSpaceStream* createGoldfishAddressSpaceStream(size_t ignored_bufSize) {
diff --git a/guest/GoldfishAddressSpace/VirtioGpuAddressSpaceStream.cpp b/guest/GoldfishAddressSpace/VirtioGpuAddressSpaceStream.cpp
index 7bd6109..62c802d 100644
--- a/guest/GoldfishAddressSpace/VirtioGpuAddressSpaceStream.cpp
+++ b/guest/GoldfishAddressSpace/VirtioGpuAddressSpaceStream.cpp
@@ -15,6 +15,7 @@
 #include "VirtioGpuAddressSpaceStream.h"
 
 #include <cutils/log.h>
+#include <errno.h>
 
 #include "util.h"
 
diff --git a/guest/OpenglSystemCommon/Android.bp b/guest/OpenglSystemCommon/Android.bp
index c5b12f2..1f867f2 100644
--- a/guest/OpenglSystemCommon/Android.bp
+++ b/guest/OpenglSystemCommon/Android.bp
@@ -116,10 +116,8 @@
     defaults: [
         "libOpenglSystemCommonDefaults",
     ],
-    shared_libs: [
-        "libandroidemu",
-    ],
     static_libs: [
+        "libgfxstream_androidemu_static",
         "libgfxstream_guest_android",
         "libmesa_util_gfxstream",
         "libmesa_util_c11_gfxstream",
@@ -146,19 +144,19 @@
         "libOpenglSystemCommonDefaults",
     ],
     shared_libs: [
-        "libandroidemu",
-        "libgfxstream_platform_rutabaga_server",
+        "libvirtgpu_kumquat_ffi",
     ],
     static_libs: [
+        "libgfxstream_androidemu_static",
         "libgfxstream_guest_android_with_host",
         "libgfxstream_guest_vulkan_encoder_with_host",
         "libmesa_util_gfxstream",
         "libmesa_util_c11_gfxstream",
-        "libgfxstream_platform_rutabaga",
+        "libgfxstream_platform_kumquat",
     ],
     export_static_lib_headers: [
         "libgfxstream_guest_android_with_host",
-        "libgfxstream_platform_rutabaga",
+        "libgfxstream_platform_kumquat",
     ],
     target: {
         host: {
@@ -197,17 +195,14 @@
     header_libs: [
         "vulkan_enc_headers",
     ],
-    shared_libs: [
-        "libgfxstream_platform_rutabaga_server",
-    ],
     static_libs: [
         "libgfxstream_androidemu_static",
         "libgfxstream_guest_android_with_host",
-        "libgfxstream_platform_rutabaga",
+        "libgfxstream_platform_kumquat",
     ],
     export_static_lib_headers: [
         "libgfxstream_guest_android_with_host",
-        "libgfxstream_platform_rutabaga",
+        "libgfxstream_platform_kumquat",
     ],
     target: {
         host: {
diff --git a/guest/OpenglSystemCommon/HostConnection.cpp b/guest/OpenglSystemCommon/HostConnection.cpp
index cbde7cb..9ce74da 100644
--- a/guest/OpenglSystemCommon/HostConnection.cpp
+++ b/guest/OpenglSystemCommon/HostConnection.cpp
@@ -69,14 +69,9 @@
 #include "VirtioGpuPipeStream.h"
 
 #if defined(__linux__) || defined(__ANDROID__)
-#include "virtgpu_drm.h"
 #include <fstream>
 #include <string>
 #include <unistd.h>
-
-static const size_t kPageSize = getpagesize();
-#else
-constexpr size_t kPageSize = PAGE_SIZE;
 #endif
 
 #undef LOG_TAG
@@ -84,7 +79,6 @@
 #include <cutils/log.h>
 
 #define STREAM_BUFFER_SIZE  (4*1024*1024)
-#define STREAM_PORT_NUM     22468
 
 constexpr const auto kEglProp = "ro.hardware.egl";
 
@@ -168,8 +162,7 @@
 }
 
 // static
-std::unique_ptr<HostConnection> HostConnection::connect(enum VirtGpuCapset capset,
-                                                        int32_t descriptor) {
+std::unique_ptr<HostConnection> HostConnection::connect(enum VirtGpuCapset capset) {
     const enum HostConnectionType connType = getConnectionTypeFromProperty(capset);
     uint32_t noRenderControlEnc = 0;
 
@@ -209,7 +202,7 @@
         }
 #endif
         case HOST_CONNECTION_VIRTIO_GPU_PIPE: {
-            auto stream = new VirtioGpuPipeStream(STREAM_BUFFER_SIZE);
+            auto stream = new VirtioGpuPipeStream(STREAM_BUFFER_SIZE, INVALID_DESCRIPTOR);
             if (!stream) {
                 ALOGE("Failed to create VirtioGpu for host connection\n");
                 return nullptr;
@@ -218,7 +211,9 @@
                 ALOGE("Failed to connect to host (VirtioGpu)\n");
                 return nullptr;
             }
+
             auto rendernodeFd = stream->getRendernodeFd();
+            auto device = VirtGpuDevice::getInstance(capset);
             con->m_stream = stream;
             con->m_rendernodeFd = rendernodeFd;
             break;
@@ -226,7 +221,7 @@
         case HOST_CONNECTION_VIRTIO_GPU_ADDRESS_SPACE: {
             // Use kCapsetGfxStreamVulkan for now, Ranchu HWC needs to be modified to pass in
             // right capset.
-            auto device = VirtGpuDevice::getInstance(kCapsetGfxStreamVulkan, descriptor);
+            auto device = VirtGpuDevice::getInstance(kCapsetGfxStreamVulkan);
             auto deviceHandle = device->getDeviceHandle();
             auto stream = createVirtioGpuAddressSpaceStream(kCapsetGfxStreamVulkan);
             if (!stream) {
@@ -272,10 +267,6 @@
     }
 
     auto handle = (connType == HOST_CONNECTION_VIRTIO_GPU_ADDRESS_SPACE) ? con->m_rendernodeFd : -1;
-    if (descriptor >= 0) {
-        handle = descriptor;
-    }
-
     processPipeInit(handle, connType, noRenderControlEnc);
     if (!noRenderControlEnc && capset == kCapsetGfxStreamVulkan) {
         con->rcEncoder();
@@ -284,27 +275,20 @@
     return con;
 }
 
-HostConnection* HostConnection::get() {
-    return getWithThreadInfo(getEGLThreadInfo(), kCapsetNone, INVALID_DESCRIPTOR);
-}
+HostConnection* HostConnection::get() { return getWithThreadInfo(getEGLThreadInfo(), kCapsetNone); }
 
 HostConnection* HostConnection::getOrCreate(enum VirtGpuCapset capset) {
-    return getWithThreadInfo(getEGLThreadInfo(), capset, INVALID_DESCRIPTOR);
+    return getWithThreadInfo(getEGLThreadInfo(), capset);
 }
 
-HostConnection* HostConnection::getWithDescriptor(enum VirtGpuCapset capset, int32_t descriptor) {
-    return getWithThreadInfo(getEGLThreadInfo(), capset, descriptor);
-}
-
-HostConnection* HostConnection::getWithThreadInfo(EGLThreadInfo* tinfo, enum VirtGpuCapset capset,
-                                                  int32_t descriptor) {
+HostConnection* HostConnection::getWithThreadInfo(EGLThreadInfo* tinfo, enum VirtGpuCapset capset) {
     // Get thread info
     if (!tinfo) {
         return NULL;
     }
 
     if (tinfo->hostConn == NULL) {
-        tinfo->hostConn = HostConnection::createUnique(capset, descriptor);
+        tinfo->hostConn = HostConnection::createUnique(capset);
     }
 
     return tinfo->hostConn.get();
@@ -316,19 +300,24 @@
         return;
     }
 
+#if defined(ANDROID)
+    if (tinfo->hostConn) {
+        tinfo->hostConn->m_grallocHelper = nullptr;
+    }
+#endif
+
     tinfo->hostConn.reset();
 }
 
 // static
-std::unique_ptr<HostConnection> HostConnection::createUnique(enum VirtGpuCapset capset,
-                                                             int32_t descriptor) {
-    return connect(capset, descriptor);
+std::unique_ptr<HostConnection> HostConnection::createUnique(enum VirtGpuCapset capset) {
+    return connect(capset);
 }
 
 GLEncoder *HostConnection::glEncoder()
 {
     if (!m_glEnc) {
-        m_glEnc = std::make_unique<GLEncoder>(m_stream, checksumHelper());
+        m_glEnc = std::make_unique<GLEncoder>(m_stream, &m_checksumHelper);
         DBG("HostConnection::glEncoder new encoder %p, tid %lu", m_glEnc, getCurrentThreadId());
         m_glEnc->setContextAccessor(s_getGLContext);
     }
@@ -338,8 +327,7 @@
 GL2Encoder *HostConnection::gl2Encoder()
 {
     if (!m_gl2Enc) {
-        m_gl2Enc =
-            std::make_unique<GL2Encoder>(m_stream, checksumHelper());
+        m_gl2Enc = std::make_unique<GL2Encoder>(m_stream, &m_checksumHelper);
         DBG("HostConnection::gl2Encoder new encoder %p, tid %lu", m_gl2Enc, getCurrentThreadId());
         m_gl2Enc->setContextAccessor(s_getGL2Context);
         m_gl2Enc->setNoHostError(m_noHostError);
@@ -361,8 +349,7 @@
 ExtendedRCEncoderContext *HostConnection::rcEncoder()
 {
     if (!m_rcEnc) {
-        m_rcEnc = std::make_unique<ExtendedRCEncoderContext>(m_stream,
-                                                             checksumHelper());
+        m_rcEnc = std::make_unique<ExtendedRCEncoderContext>(m_stream, &m_checksumHelper);
 
         ExtendedRCEncoderContext* rcEnc = m_rcEnc.get();
         setChecksumHelper(rcEnc);
diff --git a/guest/OpenglSystemCommon/HostConnection.h b/guest/OpenglSystemCommon/HostConnection.h
index 7199704..be01b18 100644
--- a/guest/OpenglSystemCommon/HostConnection.h
+++ b/guest/OpenglSystemCommon/HostConnection.h
@@ -123,15 +123,10 @@
 public:
     static HostConnection *get();
     static HostConnection* getOrCreate(enum VirtGpuCapset capset = kCapsetNone);
-    static HostConnection* getWithDescriptor(enum VirtGpuCapset capset,
-                                             int32_t descriptor);  // For testing purposes
-
-    static HostConnection* getWithThreadInfo(EGLThreadInfo* tInfo, enum VirtGpuCapset capset,
-                                             int32_t descriptor);
+    static HostConnection* getWithThreadInfo(EGLThreadInfo* tInfo, enum VirtGpuCapset capset);
     static void exit();
 
-    static std::unique_ptr<HostConnection> createUnique(enum VirtGpuCapset capset,
-                                                        int32_t descriptor);
+    static std::unique_ptr<HostConnection> createUnique(enum VirtGpuCapset capset);
     HostConnection(const HostConnection&) = delete;
 
     ~HostConnection();
@@ -141,10 +136,6 @@
     gfxstream::vk::VkEncoder *vkEncoder();
     ExtendedRCEncoderContext *rcEncoder();
 
-    int getRendernodeFd() { return m_rendernodeFd; }
-
-    gfxstream::guest::ChecksumCalculator *checksumHelper() { return &m_checksumHelper; }
-
 #if defined(ANDROID)
     gfxstream::ANativeWindowHelper* anwHelper() { return m_anwHelper.get(); }
     gfxstream::Gralloc* grallocHelper() { return m_grallocHelper.get(); }
@@ -170,7 +161,7 @@
 private:
     // If the connection failed, |conn| is deleted.
     // Returns NULL if connection failed.
- static std::unique_ptr<HostConnection> connect(enum VirtGpuCapset capset, int32_t descriptor);
+ static std::unique_ptr<HostConnection> connect(enum VirtGpuCapset capset);
 
  HostConnection();
  static gl_client_context_t* s_getGLContext();
diff --git a/guest/OpenglSystemCommon/ProcessPipe.cpp b/guest/OpenglSystemCommon/ProcessPipe.cpp
index 1c66d2a..6fea28f 100644
--- a/guest/OpenglSystemCommon/ProcessPipe.cpp
+++ b/guest/OpenglSystemCommon/ProcessPipe.cpp
@@ -148,44 +148,7 @@
 
 void processPipeRestart() {
     std::lock_guard<std::mutex> lock(sNeedInitMutex);
-
-    ALOGW("%s: restarting process pipe\n", __func__);
-    bool isPipe = false;
-
-    switch (sConnType) {
-        // TODO: Move those over too
-        case HOST_CONNECTION_QEMU_PIPE:
-        case HOST_CONNECTION_ADDRESS_SPACE:
-            isPipe = true;
-            break;
-        case HOST_CONNECTION_VIRTIO_GPU_PIPE:
-        case HOST_CONNECTION_VIRTIO_GPU_ADDRESS_SPACE: {
-            isPipe = false;
-            break;
-        }
-    }
-
-    sProcUID = 0;
-
-    if (isPipe) {
-        if (qemu_pipe_valid(sProcPipe)) {
-            qemu_pipe_close(sProcPipe);
-            sProcPipe = 0;
-        }
-    } else {
-#ifndef __Fuchsia__
-        if (sVirtioGpuPipeStream) {
-            delete sVirtioGpuPipeStream;
-            sVirtioGpuPipeStream = nullptr;
-        }
-#endif
-    }
-
-    if (sConnType == HOST_CONNECTION_VIRTIO_GPU_PIPE ||
-        sConnType == HOST_CONNECTION_VIRTIO_GPU_ADDRESS_SPACE) {
-        VirtGpuDevice::resetInstance();
-    }
-
+    VirtGpuDevice::resetInstance();
     sNeedInit = true;
 }
 
diff --git a/guest/OpenglSystemCommon/VirtioGpuPipeStream.cpp b/guest/OpenglSystemCommon/VirtioGpuPipeStream.cpp
index d628156..31f7a76 100644
--- a/guest/OpenglSystemCommon/VirtioGpuPipeStream.cpp
+++ b/guest/OpenglSystemCommon/VirtioGpuPipeStream.cpp
@@ -28,20 +28,13 @@
 static const size_t kReadSize = 512 * 1024;
 static const size_t kWriteOffset = kReadSize;
 
-VirtioGpuPipeStream::VirtioGpuPipeStream(size_t bufSize) :
-    IOStream(bufSize),
-    m_virtio_mapped(nullptr),
-    m_bufsize(bufSize),
-    m_buf(nullptr),
-    m_writtenPos(0) { }
-
-VirtioGpuPipeStream::VirtioGpuPipeStream(size_t bufSize, int fd) :
-    IOStream(bufSize),
-    m_fd(fd),
-    m_virtio_mapped(nullptr),
-    m_bufsize(bufSize),
-    m_buf(nullptr),
-    m_writtenPos(0) { }
+VirtioGpuPipeStream::VirtioGpuPipeStream(size_t bufSize, int32_t descriptor)
+    : IOStream(bufSize),
+      m_fd(descriptor),
+      m_virtio_mapped(nullptr),
+      m_bufsize(bufSize),
+      m_buf(nullptr),
+      m_writtenPos(0) {}
 
 VirtioGpuPipeStream::~VirtioGpuPipeStream()
 {
diff --git a/guest/OpenglSystemCommon/VirtioGpuPipeStream.h b/guest/OpenglSystemCommon/VirtioGpuPipeStream.h
index 7756ab9..f639ac2 100644
--- a/guest/OpenglSystemCommon/VirtioGpuPipeStream.h
+++ b/guest/OpenglSystemCommon/VirtioGpuPipeStream.h
@@ -29,8 +29,7 @@
 
 class VirtioGpuPipeStream : public gfxstream::guest::IOStream {
    public:
-    explicit VirtioGpuPipeStream(size_t bufsize = 10000);
-    explicit VirtioGpuPipeStream(size_t bufsize, int stream_handle);
+    explicit VirtioGpuPipeStream(size_t bufsize, int32_t descriptor);
     ~VirtioGpuPipeStream();
     int connect(const char* serviceName = 0);
     uint64_t initProcessPipe();
@@ -56,7 +55,7 @@
     ssize_t transferToHost(const void* buffer, size_t len);
     ssize_t transferFromHost(void* buffer, size_t len);
 
-    int m_fd = -1;
+    int32_t m_fd = -1;
     std::unique_ptr<VirtGpuDevice> m_device;
     VirtGpuResourcePtr m_resource;
     VirtGpuResourceMappingPtr m_resourceMapping;
diff --git a/guest/android-emu/aemu/base/Tracing.cpp b/guest/android-emu/aemu/base/Tracing.cpp
index c651759..c53d988 100644
--- a/guest/android-emu/aemu/base/Tracing.cpp
+++ b/guest/android-emu/aemu/base/Tracing.cpp
@@ -31,35 +31,18 @@
 namespace guest {
 
 bool isTracingEnabled() {
-#if defined(__ANDROID__)
-    return atrace_is_tag_enabled(TRACE_TAG);
-#else
     // TODO: Fuchsia + Linux
     return false;
-#endif
 }
 
 void ScopedTraceGuest::beginTraceImpl(const char* name) {
-#if defined(__ANDROID__)
-    atrace_begin(TRACE_TAG, name);
-#elif defined(__Fuchsia__) && !defined(FUCHSIA_NO_TRACE)
-    TRACE_DURATION_BEGIN(TRACE_TAG, name);
-#else
     // No-op
     (void)name;
-#endif
 }
 
 void ScopedTraceGuest::endTraceImpl(const char* name) {
-#if defined(__ANDROID__)
-    (void)name;
-    atrace_end(TRACE_TAG);
-#elif defined(__Fuchsia__) && !defined(FUCHSIA_NO_TRACE)
-    TRACE_DURATION_END(TRACE_TAG, name);
-#else
     // No-op
     (void)name;
-#endif
 }
 
 } // namespace base
diff --git a/guest/android/Android.bp b/guest/android/Android.bp
index c2d06cc..53b41ad 100644
--- a/guest/android/Android.bp
+++ b/guest/android/Android.bp
@@ -88,7 +88,7 @@
         "libgfxstream_guest_android_defaults",
     ],
     static_libs: [
-        "libgfxstream_platform_rutabaga",
+        "libgfxstream_platform_kumquat",
     ],
     target: {
         host: {
diff --git a/guest/android/Gralloc.cpp b/guest/android/Gralloc.cpp
index 500519d..c878217 100644
--- a/guest/android/Gralloc.cpp
+++ b/guest/android/Gralloc.cpp
@@ -24,11 +24,11 @@
 
 namespace gfxstream {
 
-Gralloc* createPlatformGralloc(int deviceFd) {
+Gralloc* createPlatformGralloc(int32_t descriptor) {
     const std::string value = android::base::GetProperty("ro.hardware.gralloc", "");
     if (value == "minigbm") {
         auto gralloc = new MinigbmGralloc();
-        gralloc->setFd(deviceFd);
+        gralloc->setFd(descriptor);
         return gralloc;
     }
     return new GoldfishGralloc();
@@ -36,4 +36,4 @@
 
 }  // namespace gfxstream
 
-#endif
\ No newline at end of file
+#endif
diff --git a/guest/android/GrallocEmulated.cpp b/guest/android/GrallocEmulated.cpp
index 34945a5..101a681 100644
--- a/guest/android/GrallocEmulated.cpp
+++ b/guest/android/GrallocEmulated.cpp
@@ -407,7 +407,12 @@
     return 0;
 }
 
-EmulatedGralloc::EmulatedGralloc() {}
+EmulatedGralloc::EmulatedGralloc(VirtGpuDevice* device) : mDevice(device) {}
+
+EmulatedGralloc::~EmulatedGralloc() {
+    mOwned.clear();
+    delete mDevice;
+}
 
 uint32_t EmulatedGralloc::createColorBuffer(void*, int width, int height, uint32_t glFormat) {
     auto drmFormat = GlFormatToDrmFormat(glFormat);
@@ -449,12 +454,6 @@
 AHardwareBuffer* EmulatedGralloc::allocate(uint32_t width, uint32_t height, uint32_t drmFormat) {
     ALOGE("Allocating AHB w:%u, h:%u, format %u", width, height, drmFormat);
 
-    auto device = VirtGpuDevice::getInstance();
-    if (!device) {
-        ALOGE("Failed to allocate: no virtio gpu device.");
-        return nullptr;
-    }
-
     const auto& formatInfosMap = GetDrmFormatInfoMap();
     auto formatInfoIt = formatInfosMap.find(drmFormat);
     if (formatInfoIt == formatInfosMap.end()) {
@@ -483,8 +482,8 @@
                               ? VIRGL_BIND_LINEAR
                               : VIRGL_BIND_RENDER_TARGET;
 
-    auto resource = device->createResource(width, height, stride, size, formatInfo.virglFormat,
-                                           PIPE_TEXTURE_2D, bind);
+    auto resource = mDevice->createResource(width, height, stride, size, formatInfo.virglFormat,
+                                            PIPE_TEXTURE_2D, bind);
     if (!resource) {
         ALOGE("Failed to allocate: failed to create virtio resource.");
         return nullptr;
@@ -576,8 +575,14 @@
     return 0;
 }
 
-Gralloc* createPlatformGralloc(int /*deviceFd*/) {
-    return new EmulatedGralloc();
+Gralloc* createPlatformGralloc(int32_t descriptor) {
+    auto device = createPlatformVirtGpuDevice(kCapsetNone, descriptor);
+    if (!device) {
+        ALOGE("no virtio gpu device.");
+        return nullptr;
+    }
+
+    return new EmulatedGralloc(device);
 }
 
 }  // namespace gfxstream
diff --git a/guest/android/GrallocEmulated.h b/guest/android/GrallocEmulated.h
index c5d8985..686510c 100644
--- a/guest/android/GrallocEmulated.h
+++ b/guest/android/GrallocEmulated.h
@@ -65,8 +65,8 @@
 
 class EmulatedGralloc : public Gralloc {
    public:
-    EmulatedGralloc();
-
+    EmulatedGralloc(VirtGpuDevice* device);
+    ~EmulatedGralloc();
     uint32_t createColorBuffer(void*, int width, int height, uint32_t glFormat) override;
 
     int allocate(uint32_t width, uint32_t height, uint32_t format, uint64_t usage,
@@ -100,6 +100,7 @@
     int getId(const AHardwareBuffer* ahb, uint64_t* id) override;
 
    private:
+    VirtGpuDevice* mDevice;
     std::vector<std::unique_ptr<EmulatedAHardwareBuffer>> mOwned;
 };
 
diff --git a/guest/android/GrallocStub.cpp b/guest/android/GrallocStub.cpp
index e92faff..2536f8e 100644
--- a/guest/android/GrallocStub.cpp
+++ b/guest/android/GrallocStub.cpp
@@ -16,6 +16,6 @@
 
 namespace gfxstream {
 
-Gralloc* createPlatformGralloc(int) { return nullptr; }
+Gralloc* createPlatformGralloc(int32_t) { return nullptr; }
 
-}  // namespace gfxstream
\ No newline at end of file
+}  // namespace gfxstream
diff --git a/guest/android/include/gfxstream/guest/Gralloc.h b/guest/android/include/gfxstream/guest/Gralloc.h
index 577c22e..155d03f 100644
--- a/guest/android/include/gfxstream/guest/Gralloc.h
+++ b/guest/android/include/gfxstream/guest/Gralloc.h
@@ -106,8 +106,8 @@
     virtual bool treatBlobAsImage() { return false; }
 };
 
-Gralloc* createPlatformGralloc(int deviceFd = -1);
+Gralloc* createPlatformGralloc(int32_t descriptor = -1);
 
 }  // namespace gfxstream
 
-#endif  // defined(ANDROID)
\ No newline at end of file
+#endif  // defined(ANDROID)
diff --git a/guest/egl/Android.bp b/guest/egl/Android.bp
index 3b07122..1cd8c71 100644
--- a/guest/egl/Android.bp
+++ b/guest/egl/Android.bp
@@ -19,6 +19,15 @@
     default_applicable_licenses: ["hardware_google_gfxstream_license"],
 }
 
+cc_library_headers {
+    host_supported: true,
+    vendor: true,
+    name: "libgfxstream_egl_headers",
+    export_include_dirs: [
+        ".",
+    ],
+}
+
 cc_defaults {
     name: "libgfxstream_guest_egl_defaults",
     host_supported: true,
@@ -34,13 +43,13 @@
         "libgfxstream_guest_graphics_headers",
     ],
     shared_libs: [
-        "libandroidemu",
         "libcutils",
         "libdrm",
         "liblog",
         "libOpenglCodecCommon",
     ],
     static_libs: [
+        "libgfxstream_androidemu_static",
         "libarect",
         "libqemupipe.ranchu",
     ],
diff --git a/guest/OpenglSystemCommon/EGLClientIface.h b/guest/egl/EGLClientIface.h
similarity index 100%
rename from guest/OpenglSystemCommon/EGLClientIface.h
rename to guest/egl/EGLClientIface.h
diff --git a/guest/OpenglSystemCommon/EGLImage.h b/guest/egl/EGLImage.h
similarity index 100%
rename from guest/OpenglSystemCommon/EGLImage.h
rename to guest/egl/EGLImage.h
diff --git a/guest/egl/egl.cpp b/guest/egl/egl.cpp
index 92f9337..d3f401b 100644
--- a/guest/egl/egl.cpp
+++ b/guest/egl/egl.cpp
@@ -158,27 +158,26 @@
         return ret;                                                  \
     }
 
-#define DEFINE_AND_VALIDATE_HOST_CONNECTION_FOR_TLS(ret, tls)                    \
-    HostConnection* hostCon =                                                    \
-        HostConnection::getWithThreadInfo(tls, kCapsetNone, INVALID_DESCRIPTOR); \
-    if (!hostCon) {                                                              \
-        ALOGE("egl: Failed to get host connection\n");                           \
-        return ret;                                                              \
-    }                                                                            \
-    ExtendedRCEncoderContext* rcEnc = hostCon->rcEncoder();                      \
-    if (!rcEnc) {                                                                \
-        ALOGE("egl: Failed to get renderControl encoder context\n");             \
-        return ret;                                                              \
-    }                                                                            \
-    auto const* grallocHelper = hostCon->grallocHelper();                        \
-    if (!grallocHelper) {                                                        \
-        ALOGE("egl: Failed to get grallocHelper\n");                             \
-        return ret;                                                              \
-    }                                                                            \
-    auto* anwHelper = hostCon->anwHelper();                                      \
-    if (!anwHelper) {                                                            \
-        ALOGE("egl: Failed to get anwHelper\n");                                 \
-        return ret;                                                              \
+#define DEFINE_AND_VALIDATE_HOST_CONNECTION_FOR_TLS(ret, tls)                      \
+    HostConnection* hostCon = HostConnection::getWithThreadInfo(tls, kCapsetNone); \
+    if (!hostCon) {                                                                \
+        ALOGE("egl: Failed to get host connection\n");                             \
+        return ret;                                                                \
+    }                                                                              \
+    ExtendedRCEncoderContext* rcEnc = hostCon->rcEncoder();                        \
+    if (!rcEnc) {                                                                  \
+        ALOGE("egl: Failed to get renderControl encoder context\n");               \
+        return ret;                                                                \
+    }                                                                              \
+    auto const* grallocHelper = hostCon->grallocHelper();                          \
+    if (!grallocHelper) {                                                          \
+        ALOGE("egl: Failed to get grallocHelper\n");                               \
+        return ret;                                                                \
+    }                                                                              \
+    auto* anwHelper = hostCon->anwHelper();                                        \
+    if (!anwHelper) {                                                              \
+        ALOGE("egl: Failed to get anwHelper\n");                                   \
+        return ret;                                                                \
     }
 
 #define VALIDATE_CONTEXT_RETURN(context,ret)  \
@@ -2609,13 +2608,3 @@
 
     return EGL_TRUE;
 }
-
-EGLBoolean eglInitializeKumquat(EGLint descriptor) {
-    HostConnection* hostCon = HostConnection::getWithDescriptor(kCapsetNone, descriptor);
-    if (!hostCon) {
-        ALOGE("egl: Failed to get kumquat connection");
-        return EGL_FALSE;
-    }
-
-    return EGL_TRUE;
-}
diff --git a/guest/egl/eglDisplay.h b/guest/egl/eglDisplay.h
index d1d57c2..9535027 100644
--- a/guest/egl/eglDisplay.h
+++ b/guest/egl/eglDisplay.h
@@ -128,5 +128,4 @@
     HostDriverCaps m_hostDriverCaps;
 };
 
-EGLBoolean eglInitializeKumquat(EGLint descriptor);
 #endif
diff --git a/guest/egl/egl_ftable.h b/guest/egl/egl_ftable.h
index 607ef0c..16d130c 100644
--- a/guest/egl/egl_ftable.h
+++ b/guest/egl/egl_ftable.h
@@ -58,8 +58,7 @@
     {"eglCreateSyncKHR", (void *)eglCreateSyncKHR},
     {"eglDestroySyncKHR", (void *)eglDestroySyncKHR},
     {"eglClientWaitSyncKHR", (void *)eglClientWaitSyncKHR},
-    {"eglGetSyncAttribKHR", (void *)eglGetSyncAttribKHR},
-    {"eglInitializeKumquat", (void*)eglInitializeKumquat}
+    {"eglGetSyncAttribKHR", (void *)eglGetSyncAttribKHR}
 };
 
 static const int egl_num_funcs = sizeof(egl_funcs_by_name) / sizeof(struct _egl_funcs_by_name);
diff --git a/guest/gralloc_cb/include/gralloc_cb_bp.h b/guest/gralloc_cb/include/gralloc_cb_bp.h
index 834ba4e..89b40c0 100644
--- a/guest/gralloc_cb/include/gralloc_cb_bp.h
+++ b/guest/gralloc_cb/include/gralloc_cb_bp.h
@@ -30,25 +30,24 @@
     cb_handle_t(uint32_t p_magic,
                 uint32_t p_hostHandle,
                 int32_t p_format,
-                uint32_t p_usage,
+                uint64_t p_usage,
                 uint32_t p_drmformat,
                 uint32_t p_stride,
                 uint32_t p_bufSize,
                 uint64_t p_mmapedOffset)
-        : magic(p_magic),
+        : usage(p_usage),
+          mmapedOffset(p_mmapedOffset),
+          magic(p_magic),
           hostHandle(p_hostHandle),
           format(p_format),
-          usage(p_usage),
           drmformat(p_drmformat),
           bufferSize(p_bufSize),
-          stride(p_stride),
-          mmapedOffsetLo(static_cast<uint32_t>(p_mmapedOffset)),
-          mmapedOffsetHi(static_cast<uint32_t>(p_mmapedOffset >> 32)) {
+          stride(p_stride) {
         version = sizeof(native_handle);
     }
 
     uint64_t getMmapedOffset() const {
-        return (uint64_t(mmapedOffsetHi) << 32) | mmapedOffsetLo;
+        return mmapedOffset;
     }
 
     uint32_t allocatedSize() const {
@@ -77,15 +76,14 @@
     int32_t fds[2];
 
     // ints
-    uint32_t magic;         // magic number in order to validate a pointer
-    uint32_t hostHandle;    // the host reference to this buffer
-    uint32_t format;        // real internal pixel format format
-    uint32_t usage;         // allocation usage
-    uint32_t drmformat;     // drm format
-    uint32_t bufferSize;
-    uint32_t stride;
-    uint32_t mmapedOffsetLo;
-    uint32_t mmapedOffsetHi;
+    const uint64_t usage;         // allocation usage
+    const uint64_t mmapedOffset;
+    const uint32_t magic;         // magic number in order to validate a pointer
+    const uint32_t hostHandle;    // the host reference to this buffer
+    const uint32_t format;        // real internal pixel format format
+    const uint32_t drmformat;     // drm format
+    const uint32_t bufferSize;
+    const uint32_t stride;
 };
 
 #endif //__GRALLOC_CB_H__
diff --git a/guest/magma/magma.cpp b/guest/magma/magma.cpp
index 3f1aa72..d1de58c 100644
--- a/guest/magma/magma.cpp
+++ b/guest/magma/magma.cpp
@@ -15,6 +15,7 @@
 #include <assert.h>
 #include <fcntl.h>
 #include <lib/magma/magma_common_defs.h>
+#include <log/log.h>
 #include <stdarg.h>
 #include <stdint.h>
 #include <string.h>
@@ -28,8 +29,8 @@
 #include <thread>
 #include <unordered_map>
 
-#include "VirtioGpuAddressSpaceStream.h"
 #include "EncoderDebug.h"
+#include "VirtioGpuAddressSpaceStream.h"
 #include "magma_enc.h"
 
 static uint64_t get_ns_monotonic(bool raw) {
diff --git a/guest/mesa/Android.bp b/guest/mesa/Android.bp
index 3d45a61..d803299 100644
--- a/guest/mesa/Android.bp
+++ b/guest/mesa/Android.bp
@@ -17,6 +17,10 @@
     vendor: true,
     header_libs: ["mesa_common_headers_gfxstream"],
 
+    defaults: [
+        "gfxstream_guest_cc_defaults_for_platform",
+    ],
+
     cflags: [
         "-Wno-error",
         "-Werror=incompatible-pointer-types",
@@ -60,7 +64,6 @@
         "-DHAVE_LINUX_FUTEX_H",
         "-DHAVE_ENDIAN_H",
         "-DMAJOR_IN_SYSMACROS",
-        "-DVK_USE_PLATFORM_ANDROID_KHR",
         "-fvisibility=hidden",
         "-fno-math-errno",
         "-fno-trapping-math",
diff --git a/guest/mesa/src/vulkan/runtime/Android.bp b/guest/mesa/src/vulkan/runtime/Android.bp
index 73d931d..a11b2e7 100644
--- a/guest/mesa/src/vulkan/runtime/Android.bp
+++ b/guest/mesa/src/vulkan/runtime/Android.bp
@@ -185,12 +185,36 @@
         "$(location vk_format_info.c)",
 }
 
+soong_config_module_type_import {
+    from: "hardware/google/gfxstream/Android.bp",
+    module_types: ["gfxstream_cc_defaults_config_for_platform"],
+}
+
+gfxstream_cc_defaults_config_for_platform {
+    name: "libmesa_vulkan_runtime_gfxstream_cc_defaults_for_platform",
+    soong_config_variables: {
+        mesa3d_platforms: {
+            // Android surfaceless build
+            none: {},
+            // The default when variable is not set is Android
+            conditions_default: {
+                target: {
+                    android: {
+                        srcs: ["vk_android.c"],
+                    },
+                },
+            },
+        },
+    },
+}
+
 cc_library_static {
     name: "libmesa_vulkan_runtime_gfxstream",
     host_supported: true,
     vendor: true,
     defaults: [
         "mesa_common_defaults_gfxstream",
+        "libmesa_vulkan_runtime_gfxstream_cc_defaults_for_platform",
     ],
     header_libs: [
         "mesa_common_headers_gfxstream",
@@ -279,9 +303,6 @@
                 "hwvulkan_headers",
                 "libnativewindow_headers",
             ],
-            srcs: [
-                "vk_android.c",
-            ],
         },
     },
 }
diff --git a/guest/mesa/src/vulkan/wsi/wsi_common_drm.c b/guest/mesa/src/vulkan/wsi/wsi_common_drm.c
index f04a791..b53d485 100644
--- a/guest/mesa/src/vulkan/wsi/wsi_common_drm.c
+++ b/guest/mesa/src/vulkan/wsi/wsi_common_drm.c
@@ -323,8 +323,7 @@
    if (result != VK_SUCCESS)
       return result;
 
-   /* HACK: This should be fixed as part of (b:326956485) */
-   if (true) {
+   if (num_modifier_lists == 0) {
       /* If we don't have modifiers, fall back to the legacy "scanout" flag */
       info->wsi.scanout = true;
    } else {
diff --git a/guest/platform/Android.bp b/guest/platform/Android.bp
index 7fe0b91..8a53e0d 100644
--- a/guest/platform/Android.bp
+++ b/guest/platform/Android.bp
@@ -60,62 +60,28 @@
     },
 }
 
-cc_library_shared {
-    name: "libgfxstream_platform_rutabaga_server",
-    host_supported: true,
-    vendor_available: true,
-    srcs: [
-        "rutabaga/RutabagaLayer.cpp",
-    ],
-    header_libs: [
-        "rutabaga_gfx_ffi_headers",
-    ],
-    shared_libs: [
-        "libcutils",
-        "librutabaga_gfx_ffi",
-        "libgfxstream_backend",
-        "liblog",
-        "libutils",
-    ],
-    export_include_dirs: [
-        // TODO: restrict to just RutabagaLayer.h
-        "rutabaga/include",
-        "rutabaga",
-    ],
-    target: {
-        host: {
-            compile_multilib: "64",
-        },
-        android: {
-            compile_multilib: "64",
-        },
-    },
-}
-
 cc_library_static {
-    name: "libgfxstream_platform_rutabaga",
+    name: "libgfxstream_platform_kumquat",
     host_supported: true,
     vendor_available: true,
     srcs: [
         "VirtGpu.cpp",
-        "rutabaga/RutabagaVirtGpuBlob.cpp",
-        "rutabaga/RutabagaVirtGpuBlobMapping.cpp",
-        "rutabaga/RutabagaVirtGpuDevice.cpp",
-        "rutabaga/RutabagaVirtGpuSyncHelper.cpp",
+        "kumquat/VirtGpuKumquatBlob.cpp",
+        "kumquat/VirtGpuKumquatBlobMapping.cpp",
+        "kumquat/VirtGpuKumquatDevice.cpp",
+        "kumquat/VirtGpuKumquatSync.cpp",
+    ],
+    header_libs: [
+        "virtgpu_kumquat_ffi_headers",
     ],
     shared_libs: [
         "libcutils",
-        "libdrm",
-        "libgfxstream_platform_rutabaga_server",
         "liblog",
         "libutils",
-    ],
-    export_shared_lib_headers: [
-        "libdrm",
+        "libvirtgpu_kumquat_ffi",
     ],
     export_include_dirs: [
         "include",
-        "rutabaga/include",
     ],
     cflags: [
         "-DLOG_TAG=\"platform\"",
@@ -123,10 +89,6 @@
         "-fvisibility=default",
         "-fstrict-aliasing",
     ],
-    local_include_dirs: [
-        "include",
-        "rutabaga/include",
-    ],
     target: {
         host: {
             compile_multilib: "64",
diff --git a/guest/platform/kumquat/VirtGpuKumquat.h b/guest/platform/kumquat/VirtGpuKumquat.h
index d22f210..0fa2177 100644
--- a/guest/platform/kumquat/VirtGpuKumquat.h
+++ b/guest/platform/kumquat/VirtGpuKumquat.h
@@ -85,6 +85,7 @@
     virtual int execBuffer(struct VirtGpuExecBuffer& execbuffer, const VirtGpuResource* blob);
 
    private:
+    int32_t mDescriptor = 0;
     struct virtgpu_kumquat* mVirtGpu = nullptr;
     struct VirtGpuCaps mCaps;
 };
diff --git a/guest/platform/kumquat/VirtGpuKumquatDevice.cpp b/guest/platform/kumquat/VirtGpuKumquatDevice.cpp
index 0b7263e..3566b10 100644
--- a/guest/platform/kumquat/VirtGpuKumquatDevice.cpp
+++ b/guest/platform/kumquat/VirtGpuKumquatDevice.cpp
@@ -62,6 +62,7 @@
 
     if (descriptor >= 0) {
         gpu_socket_path.append(std::to_string(descriptor));
+        mDescriptor = descriptor;
     } else {
         gpu_socket_path.append("0");
     }
@@ -148,7 +149,7 @@
 
 struct VirtGpuCaps VirtGpuKumquatDevice::getCaps(void) { return mCaps; }
 
-int64_t VirtGpuKumquatDevice::getDeviceHandle(void) { return -1; }
+int64_t VirtGpuKumquatDevice::getDeviceHandle(void) { return mDescriptor; }
 
 VirtGpuResourcePtr VirtGpuKumquatDevice::createResource(uint32_t width, uint32_t height,
                                                         uint32_t stride, uint32_t size,
diff --git a/guest/platform/rutabaga/RutabagaLayer.cpp b/guest/platform/rutabaga/RutabagaLayer.cpp
deleted file mode 100644
index 8519020..0000000
--- a/guest/platform/rutabaga/RutabagaLayer.cpp
+++ /dev/null
@@ -1,1170 +0,0 @@
-/*
- * Copyright 2023 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 "RutabagaLayer.h"
-
-#include <inttypes.h>
-#include <log/log.h>
-#include <string.h>
-
-#include <algorithm>
-#include <cstdlib>
-#include <future>
-#include <memory>
-#include <optional>
-#include <queue>
-#include <sstream>
-#include <string>
-#include <thread>
-#include <unordered_map>
-#include <variant>
-
-// Blueprint and Meson builds place things differently
-#if defined(ANDROID)
-#include "rutabaga_gfx_ffi.h"
-#else
-#include "rutabaga_gfx/rutabaga_gfx_ffi.h"
-#endif
-
-namespace gfxstream {
-namespace {
-
-constexpr const uint32_t kInvalidContextId = 0;
-
-std::vector<std::string> Split(const std::string& s, const std::string& delimiters) {
-    if (delimiters.empty()) {
-        return {};
-    }
-
-    std::vector<std::string> result;
-
-    size_t base = 0;
-    size_t found;
-    while (true) {
-        found = s.find_first_of(delimiters, base);
-        result.push_back(s.substr(base, found - base));
-        if (found == s.npos) break;
-        base = found + 1;
-    }
-
-    return result;
-}
-
-std::string Join(const std::vector<std::string>& things, const std::string& separator) {
-    if (things.empty()) {
-        return "";
-    }
-
-    std::ostringstream result;
-    result << *things.begin();
-    for (auto it = std::next(things.begin()); it != things.end(); ++it) {
-        result << separator << *it;
-    }
-    return result.str();
-}
-
-}  // namespace
-
-class EmulatedVirtioGpu::EmulatedVirtioGpuImpl {
-   public:
-    EmulatedVirtioGpuImpl();
-    ~EmulatedVirtioGpuImpl();
-
-    bool Init(bool withGl, bool withVk, const std::string& features, EmulatedVirtioGpu* parent);
-
-    bool GetCaps(uint32_t capsetId, uint32_t guestCapsSize, uint8_t* capset);
-
-    std::optional<uint32_t> CreateContext(uint32_t contextInit);
-    void DestroyContext(uint32_t contextId);
-
-    uint8_t* Map(uint32_t resourceId);
-    void Unmap(uint32_t resourceId);
-
-    int SubmitCmd(uint32_t contextId, uint32_t cmdSize, void* cmd, uint32_t ringIdx,
-                  VirtioGpuFenceFlags fenceFlags, uint32_t& fenceId,
-                  std::optional<uint32_t> blobResourceId);
-
-    int Wait(uint32_t resourceId);
-
-    int TransferFromHost(uint32_t contextId, uint32_t resourceId, uint32_t transferOffset,
-                         uint32_t transferSize);
-    int TransferFromHost(uint32_t contextId, uint32_t resourceId, uint32_t x, uint32_t y,
-                         uint32_t w, uint32_t h);
-
-    int TransferToHost(uint32_t contextId, uint32_t resourceId, uint32_t transferOffset,
-                       uint32_t transferSize);
-    int TransferToHost(uint32_t contextId, uint32_t resourceId, uint32_t x, uint32_t y, uint32_t w,
-                       uint32_t h);
-
-    std::optional<uint32_t> CreateBlob(uint32_t contextId, uint32_t blobMem, uint32_t blobFlags,
-                                       uint64_t blobId, uint64_t blobSize);
-    std::optional<uint32_t> CreateVirglBlob(uint32_t contextId, uint32_t width, uint32_t height,
-                                            uint32_t virglFormat, uint32_t target, uint32_t bind,
-                                            uint32_t size);
-
-    void DestroyResource(uint32_t contextId, uint32_t resourceId);
-    void SnapshotSave(const std::string& directory);
-    void SnapshotRestore(const std::string& directory);
-
-    uint32_t CreateEmulatedFence();
-
-    void SignalEmulatedFence(uint32_t fenceId);
-
-    int WaitOnEmulatedFence(int fenceAsFileDescriptor, int timeoutMilliseconds);
-
-   private:
-    struct VirtioGpuTaskContextAttachResource {
-        uint32_t contextId;
-        uint32_t resourceId;
-    };
-    struct VirtioGpuTaskContextDetachResource {
-        uint32_t contextId;
-        uint32_t resourceId;
-    };
-    struct VirtioGpuTaskCreateContext {
-        uint32_t contextId;
-        uint32_t contextInit;
-        std::string contextName;
-    };
-    struct VirtioGpuTaskCreateBlob {
-        uint32_t contextId;
-        uint32_t resourceId;
-        struct rutabaga_create_blob params;
-    };
-    struct VirtioGpuTaskCreateResource {
-        uint32_t contextId;
-        uint32_t resourceId;
-        uint8_t* resourceBytes;
-        struct rutabaga_create_3d params;
-    };
-    struct VirtioGpuTaskDestroyContext {
-        uint32_t contextId;
-    };
-    struct VirtioGpuTaskMap {
-        uint32_t resourceId;
-        std::promise<uint8_t*> resourceMappedPromise;
-    };
-    struct VirtioGpuTaskUnmap {
-        uint32_t resourceId;
-    };
-    struct VirtioGpuTaskSubmitCmd {
-        uint32_t contextId;
-        std::vector<std::byte> commandBuffer;
-    };
-    struct VirtioGpuTaskTransferToHost {
-        uint32_t contextId;
-        uint32_t resourceId;
-        uint32_t x;
-        uint32_t y;
-        uint32_t w;
-        uint32_t h;
-    };
-    struct VirtioGpuTaskTransferFromHost {
-        uint32_t contextId;
-        uint32_t resourceId;
-        uint32_t x;
-        uint32_t y;
-        uint32_t w;
-        uint32_t h;
-    };
-    struct VirtioGpuTaskUnrefResource {
-        uint32_t resourceId;
-    };
-    struct VirtioGpuTaskSnapshotSave {
-        std::string directory;
-    };
-    struct VirtioGpuTaskSnapshotRestore {
-        std::string directory;
-    };
-    using VirtioGpuTask =
-        std::variant<VirtioGpuTaskContextAttachResource, VirtioGpuTaskContextDetachResource,
-                     VirtioGpuTaskCreateBlob, VirtioGpuTaskCreateContext,
-                     VirtioGpuTaskCreateResource, VirtioGpuTaskDestroyContext, VirtioGpuTaskMap,
-                     VirtioGpuTaskUnmap, VirtioGpuTaskSubmitCmd, VirtioGpuTaskTransferFromHost,
-                     VirtioGpuTaskTransferToHost, VirtioGpuTaskUnrefResource,
-                     VirtioGpuTaskSnapshotSave, VirtioGpuTaskSnapshotRestore>;
-
-    struct VirtioGpuFence {
-        uint32_t fenceId;
-        uint32_t ringIdx;
-    };
-
-    struct VirtioGpuTaskWithWaitable {
-        uint32_t contextId;
-        VirtioGpuTask task;
-        std::promise<void> taskCompletedSignaler;
-        std::optional<VirtioGpuFence> fence;
-    };
-
-    std::shared_future<void> EnqueueVirtioGpuTask(
-        uint32_t contextId, VirtioGpuTask task, std::optional<VirtioGpuFence> fence = std::nullopt);
-    void DoTask(VirtioGpuTaskContextAttachResource task);
-    void DoTask(VirtioGpuTaskContextDetachResource task);
-    void DoTask(VirtioGpuTaskCreateContext task);
-    void DoTask(VirtioGpuTaskCreateBlob task);
-    void DoTask(VirtioGpuTaskCreateResource task);
-    void DoTask(VirtioGpuTaskDestroyContext task);
-    void DoTask(VirtioGpuTaskMap task);
-    void DoTask(VirtioGpuTaskUnmap task);
-    void DoTask(VirtioGpuTaskSubmitCmd task);
-    void DoTask(VirtioGpuTaskTransferFromHost task);
-    void DoTask(VirtioGpuTaskTransferToHost task);
-    void DoTask(VirtioGpuTaskWithWaitable task);
-    void DoTask(VirtioGpuTaskUnrefResource task);
-    void DoTask(VirtioGpuTaskSnapshotSave task);
-    void DoTask(VirtioGpuTaskSnapshotRestore task);
-
-    void RunVirtioGpuTaskProcessingLoop();
-
-    std::atomic<uint32_t> mNextContextId{1};
-    std::atomic<uint32_t> mNextVirtioGpuResourceId{1};
-    std::atomic<uint32_t> mNextVirtioGpuFenceId{1};
-
-    std::atomic_bool mShuttingDown{false};
-
-    std::mutex mTasksMutex;
-    std::queue<VirtioGpuTaskWithWaitable> mTasks;
-
-    enum class EmulatedResourceType {
-        kBlob,
-        kPipe,
-    };
-    struct EmulatedResource {
-        EmulatedResourceType type;
-
-        std::mutex pendingWaitablesMutex;
-        std::vector<std::shared_future<void>> pendingWaitables;
-
-        // For non-blob resources, the guest shadow memory.
-        std::unique_ptr<uint8_t[]> guestBytes;
-
-        // For mappable blob resources, the host memory once it is mapped.
-        std::shared_future<uint8_t*> mappedHostBytes;
-
-        // For resources with iovecs.  Test layer just needs 1.
-        struct iovec iovec;
-    };
-    std::mutex mResourcesMutex;
-    std::unordered_map<uint32_t, EmulatedResource> mResources;
-
-    EmulatedResource* CreateResource(uint32_t resourceId, EmulatedResourceType resourceType) {
-        std::lock_guard<std::mutex> lock(mResourcesMutex);
-
-        auto [it, created] = mResources.emplace(
-            std::piecewise_construct, std::forward_as_tuple(resourceId), std::forward_as_tuple());
-        if (!created) {
-            ALOGE("Created resource %" PRIu32 " twice?", resourceId);
-        }
-
-        EmulatedResource* resource = &it->second;
-        resource->type = resourceType;
-        return resource;
-    }
-
-    EmulatedResource* GetResource(uint32_t resourceId) {
-        std::lock_guard<std::mutex> lock(mResourcesMutex);
-
-        auto it = mResources.find(resourceId);
-        if (it == mResources.end()) {
-            return nullptr;
-        }
-
-        return &it->second;
-    }
-
-    void DeleteResource(uint32_t resourceId) {
-        std::lock_guard<std::mutex> lock(mResourcesMutex);
-        mResources.erase(resourceId);
-    }
-
-    struct EmulatedFence {
-        std::promise<void> signaler;
-        std::shared_future<void> waitable;
-    };
-    std::mutex mVirtioGpuFencesMutex;
-    std::unordered_map<uint32_t, EmulatedFence> mVirtioGpuFences;
-
-    std::thread mWorkerThread;
-    struct rutabaga* mRutabaga = nullptr;
-    std::unordered_map<uint32_t, std::vector<uint8_t>> mCapsets;
-};
-
-EmulatedVirtioGpu::EmulatedVirtioGpuImpl::EmulatedVirtioGpuImpl()
-    : mWorkerThread([this]() { RunVirtioGpuTaskProcessingLoop(); }) {}
-
-EmulatedVirtioGpu::EmulatedVirtioGpuImpl::~EmulatedVirtioGpuImpl() {
-    mShuttingDown = true;
-    mWorkerThread.join();
-
-    if (mRutabaga) {
-        rutabaga_finish(&mRutabaga);
-        mRutabaga = nullptr;
-    }
-}
-
-namespace {
-
-void WriteFenceTrampoline(uint64_t cookie, const struct rutabaga_fence* fence) {
-    auto* gpu = reinterpret_cast<EmulatedVirtioGpu*>(cookie);
-    gpu->SignalEmulatedFence(fence->fence_id);
-}
-
-}  // namespace
-
-bool EmulatedVirtioGpu::EmulatedVirtioGpuImpl::Init(bool withGl, bool withVk,
-                                                    const std::string& features,
-                                                    EmulatedVirtioGpu* parent) {
-    int32_t ret;
-    uint64_t capsetMask = 0;
-    uint32_t numCapsets = 0;
-    struct rutabaga_builder builder = {0};
-
-    if (withGl) {
-        capsetMask |= (1 << RUTABAGA_CAPSET_GFXSTREAM_GLES);
-    }
-
-    if (withVk) {
-        capsetMask |= (1 << RUTABAGA_CAPSET_GFXSTREAM_VULKAN);
-    }
-
-    builder.user_data = static_cast<uint64_t>(reinterpret_cast<uintptr_t>(parent)),
-    builder.fence_cb = WriteFenceTrampoline;
-    builder.capset_mask = capsetMask;
-    builder.wsi = RUTABAGA_WSI_SURFACELESS;
-    if (!features.empty()) {
-        builder.renderer_features = features.c_str();
-    }
-
-    ret = rutabaga_init(&builder, &mRutabaga);
-    if (ret) {
-        ALOGE("Failed to initialize rutabaga");
-        return false;
-    }
-
-    ret = rutabaga_get_num_capsets(mRutabaga, &numCapsets);
-    if (ret) {
-        ALOGE("Failed to get number of capsets");
-        return false;
-    }
-
-    for (uint32_t i = 0; i < numCapsets; i++) {
-        uint32_t capsetId, capsetVersion, capsetSize;
-        std::vector<uint8_t> capsetData;
-
-        ret = rutabaga_get_capset_info(mRutabaga, i, &capsetId, &capsetVersion, &capsetSize);
-        if (ret) {
-            ALOGE("Failed to get capset info");
-            return false;
-        }
-
-        capsetData.resize(capsetSize);
-
-        ret = rutabaga_get_capset(mRutabaga, capsetId, capsetVersion, (uint8_t*)capsetData.data(),
-                                  capsetSize);
-
-        if (ret) {
-            ALOGE("Failed to get capset");
-            return false;
-        }
-
-        mCapsets[capsetId] = capsetData;
-    }
-
-    return true;
-}
-
-bool EmulatedVirtioGpu::EmulatedVirtioGpuImpl::GetCaps(uint32_t capsetId, uint32_t guestCapsSize,
-                                                       uint8_t* capset) {
-    if (mCapsets.count(capsetId) == 0) return false;
-
-    auto capsetData = mCapsets[capsetId];
-    auto copySize = std::min(static_cast<size_t>(guestCapsSize), capsetData.size());
-    memcpy(capset, capsetData.data(), copySize);
-
-    return true;
-}
-
-std::optional<uint32_t> EmulatedVirtioGpu::EmulatedVirtioGpuImpl::CreateContext(
-    uint32_t contextInit) {
-    const uint32_t contextId = mNextContextId++;
-
-    VirtioGpuTaskCreateContext task = {
-        .contextId = contextId,
-        .contextInit = contextInit,
-        .contextName = "EmulatedVirtioGpu Context " + std::to_string(contextId),
-    };
-    EnqueueVirtioGpuTask(contextId, std::move(task));
-    return contextId;
-}
-
-void EmulatedVirtioGpu::EmulatedVirtioGpuImpl::DestroyContext(uint32_t contextId) {
-    VirtioGpuTaskDestroyContext task = {
-        .contextId = contextId,
-    };
-    EnqueueVirtioGpuTask(contextId, std::move(task));
-}
-
-uint8_t* EmulatedVirtioGpu::EmulatedVirtioGpuImpl::Map(uint32_t resourceId) {
-    EmulatedResource* resource = GetResource(resourceId);
-    if (resource == nullptr) {
-        ALOGE("Failed to Map() resource %" PRIu32 ": not found.", resourceId);
-        return nullptr;
-    }
-
-    uint8_t* mapped = nullptr;
-    if (resource->type == EmulatedResourceType::kBlob) {
-        if (!resource->mappedHostBytes.valid()) {
-            ALOGE("Failed to Map() resource %" PRIu32
-                  ": attempting to map blob "
-                  "without mappable flag?",
-                  resourceId);
-            return nullptr;
-        }
-        mapped = resource->mappedHostBytes.get();
-    } else if (resource->type == EmulatedResourceType::kPipe) {
-        mapped = resource->guestBytes.get();
-    }
-    return mapped;
-}
-
-void EmulatedVirtioGpu::EmulatedVirtioGpuImpl::Unmap(uint32_t resourceId) {
-    VirtioGpuTaskUnmap task = {
-        .resourceId = resourceId,
-    };
-    EnqueueVirtioGpuTask(0, std::move(task));
-}
-
-int EmulatedVirtioGpu::EmulatedVirtioGpuImpl::Wait(uint32_t resourceId) {
-    EmulatedResource* resource = GetResource(resourceId);
-    if (resource == nullptr) {
-        ALOGE("Failed to Wait() on resource %" PRIu32 ": not found.", resourceId);
-        return -1;
-    }
-
-    std::vector<std::shared_future<void>> pendingWaitables;
-    {
-        std::lock_guard<std::mutex> lock(resource->pendingWaitablesMutex);
-        pendingWaitables = resource->pendingWaitables;
-        resource->pendingWaitables.clear();
-    }
-    for (auto& waitable : pendingWaitables) {
-        waitable.wait();
-    }
-
-    return 0;
-}
-
-int EmulatedVirtioGpu::EmulatedVirtioGpuImpl::TransferFromHost(uint32_t contextId,
-                                                               uint32_t resourceId,
-                                                               uint32_t transferOffset,
-                                                               uint32_t transferSize) {
-    return TransferFromHost(contextId, resourceId, transferOffset, 0, transferSize, 1);
-}
-
-int EmulatedVirtioGpu::EmulatedVirtioGpuImpl::TransferFromHost(uint32_t contextId,
-                                                               uint32_t resourceId, uint32_t x,
-                                                               uint32_t y, uint32_t w, uint32_t h) {
-    EmulatedResource* resource = GetResource(resourceId);
-    if (resource == nullptr) {
-        ALOGE("Failed to TransferFromHost() on resource %" PRIu32 ": not found.", resourceId);
-        return -1;
-    }
-
-    VirtioGpuTaskTransferFromHost task = {
-        .contextId = contextId,
-        .resourceId = resourceId,
-        .x = x,
-        .y = y,
-        .w = w,
-        .h = h,
-    };
-    auto waitable = EnqueueVirtioGpuTask(contextId, std::move(task));
-
-    {
-        std::lock_guard<std::mutex> lock(resource->pendingWaitablesMutex);
-        resource->pendingWaitables.push_back(std::move(waitable));
-    }
-
-    return 0;
-}
-
-int EmulatedVirtioGpu::EmulatedVirtioGpuImpl::TransferToHost(uint32_t contextId,
-                                                             uint32_t resourceId,
-                                                             uint32_t transferOffset,
-                                                             uint32_t transferSize) {
-    return TransferToHost(contextId, resourceId, transferOffset, 0, transferSize, 1);
-}
-
-int EmulatedVirtioGpu::EmulatedVirtioGpuImpl::TransferToHost(uint32_t contextId,
-                                                             uint32_t resourceId, uint32_t x,
-                                                             uint32_t y, uint32_t w, uint32_t h) {
-    EmulatedResource* resource = GetResource(resourceId);
-    if (resource == nullptr) {
-        ALOGE("Failed to TransferFromHost() on resource %" PRIu32 ": not found.", resourceId);
-        return -1;
-    }
-
-    VirtioGpuTaskTransferToHost task = {
-        .contextId = contextId,
-        .resourceId = resourceId,
-        .x = x,
-        .y = y,
-        .w = w,
-        .h = h,
-    };
-    auto waitable = EnqueueVirtioGpuTask(contextId, std::move(task));
-
-    {
-        std::lock_guard<std::mutex> lock(resource->pendingWaitablesMutex);
-        resource->pendingWaitables.push_back(std::move(waitable));
-    }
-
-    return 0;
-}
-
-std::optional<uint32_t> EmulatedVirtioGpu::EmulatedVirtioGpuImpl::CreateBlob(
-    uint32_t contextId, uint32_t blobMem, uint32_t blobFlags, uint64_t blobId, uint64_t blobSize) {
-    const uint32_t resourceId = mNextVirtioGpuResourceId++;
-
-    ALOGV("Enquing task to create blob resource-id:%d size:%" PRIu64, resourceId, blobSize);
-
-    EmulatedResource* resource = CreateResource(resourceId, EmulatedResourceType::kBlob);
-
-    VirtioGpuTaskCreateBlob createTask{
-        .contextId = contextId,
-        .resourceId = resourceId,
-        .params =
-            {
-                .blob_mem = blobMem,
-                .blob_flags = blobFlags,
-                .blob_id = blobId,
-                .size = blobSize,
-            },
-    };
-    auto createBlobCompletedWaitable = EnqueueVirtioGpuTask(contextId, std::move(createTask));
-    resource->pendingWaitables.push_back(std::move(createBlobCompletedWaitable));
-
-    if (blobFlags & 0x001 /*kBlobFlagMappable*/) {
-        std::promise<uint8_t*> mappedBytesPromise;
-        std::shared_future<uint8_t*> mappedBytesWaitable = mappedBytesPromise.get_future();
-
-        VirtioGpuTaskMap mapTask{
-            .resourceId = resourceId,
-            .resourceMappedPromise = std::move(mappedBytesPromise),
-        };
-        EnqueueVirtioGpuTask(contextId, std::move(mapTask));
-        resource->mappedHostBytes = std::move(mappedBytesWaitable);
-    }
-
-    VirtioGpuTaskContextAttachResource attachTask{
-        .contextId = contextId,
-        .resourceId = resourceId,
-    };
-    EnqueueVirtioGpuTask(contextId, std::move(attachTask));
-
-    return resourceId;
-}
-
-std::optional<uint32_t> EmulatedVirtioGpu::EmulatedVirtioGpuImpl::CreateVirglBlob(
-    uint32_t contextId, uint32_t width, uint32_t height, uint32_t virglFormat, uint32_t target,
-    uint32_t bind, uint32_t size) {
-    const uint32_t resourceId = mNextVirtioGpuResourceId++;
-
-    EmulatedResource* resource = CreateResource(resourceId, EmulatedResourceType::kPipe);
-
-    resource->guestBytes = std::make_unique<uint8_t[]>(size);
-
-    VirtioGpuTaskCreateResource task{
-        .contextId = contextId,
-        .resourceId = resourceId,
-        .resourceBytes = resource->guestBytes.get(),
-        .params =
-            {
-                .target = target,
-                .format = virglFormat,
-                .bind = bind,
-                .width = width,
-                .height = height,
-                .depth = 1,
-                .array_size = 1,
-                .last_level = 0,
-                .nr_samples = 0,
-                .flags = 0,
-            },
-    };
-    auto taskCompletedWaitable = EnqueueVirtioGpuTask(contextId, std::move(task));
-    resource->pendingWaitables.push_back(std::move(taskCompletedWaitable));
-
-    VirtioGpuTaskContextAttachResource attachTask{
-        .contextId = contextId,
-        .resourceId = resourceId,
-    };
-    EnqueueVirtioGpuTask(contextId, std::move(attachTask));
-
-    return resourceId;
-}
-
-void EmulatedVirtioGpu::EmulatedVirtioGpuImpl::DestroyResource(uint32_t contextId,
-                                                               uint32_t resourceId) {
-    DeleteResource(resourceId);
-
-    VirtioGpuTaskUnrefResource unrefTask{
-        .resourceId = resourceId,
-    };
-    EnqueueVirtioGpuTask(contextId, std::move(unrefTask));
-
-    VirtioGpuTaskContextDetachResource detachTask{
-        .contextId = contextId,
-        .resourceId = resourceId,
-    };
-    EnqueueVirtioGpuTask(contextId, std::move(detachTask));
-}
-
-void EmulatedVirtioGpu::EmulatedVirtioGpuImpl::SnapshotSave(const std::string& directory) {
-    uint32_t contextId = 0;
-
-    VirtioGpuTaskSnapshotSave saveTask{
-        .directory = directory,
-    };
-    EnqueueVirtioGpuTask(contextId, std::move(saveTask)).wait();
-}
-
-void EmulatedVirtioGpu::EmulatedVirtioGpuImpl::SnapshotRestore(const std::string& directory) {
-    uint32_t contextId = 0;
-
-    VirtioGpuTaskSnapshotRestore restoreTask{
-        .directory = directory,
-    };
-
-    EnqueueVirtioGpuTask(contextId, std::move(restoreTask)).wait();
-}
-
-int EmulatedVirtioGpu::EmulatedVirtioGpuImpl::SubmitCmd(uint32_t contextId, uint32_t cmdSize,
-                                                        void* cmd, uint32_t ringIdx,
-                                                        VirtioGpuFenceFlags fenceFlags,
-                                                        uint32_t& fenceId,
-                                                        std::optional<uint32_t> blobResourceId) {
-    std::optional<VirtioGpuFence> fence;
-    if (fenceFlags & kFlagFence) {
-        fence = VirtioGpuFence{.fenceId = CreateEmulatedFence(), .ringIdx = ringIdx};
-    }
-
-    const VirtioGpuTaskSubmitCmd task = {
-        .contextId = contextId,
-        .commandBuffer = std::vector<std::byte>(reinterpret_cast<std::byte*>(cmd),
-                                                reinterpret_cast<std::byte*>(cmd) + cmdSize),
-    };
-    auto taskCompletedWaitable = EnqueueVirtioGpuTask(contextId, std::move(task), fence);
-
-    if (blobResourceId) {
-        EmulatedResource* resource = GetResource(*blobResourceId);
-        if (resource == nullptr) {
-            ALOGE("Failed to SubmitCmd() with resource %" PRIu32 ": not found.", *blobResourceId);
-            return -1;
-        }
-
-        {
-            std::lock_guard<std::mutex> lock(resource->pendingWaitablesMutex);
-            resource->pendingWaitables.push_back(std::move(taskCompletedWaitable));
-        }
-    }
-
-    if (fenceFlags & kFlagFence) {
-        fenceId = (*fence).fenceId;
-    }
-
-    return 0;
-}
-
-int EmulatedVirtioGpu::EmulatedVirtioGpuImpl::WaitOnEmulatedFence(int fenceAsFileDescriptor,
-                                                                  int timeoutMilliseconds) {
-    uint32_t fenceId = static_cast<uint32_t>(fenceAsFileDescriptor);
-    ALOGV("Waiting on fence:%d", (int)fenceId);
-
-    std::shared_future<void> waitable;
-
-    {
-        std::lock_guard<std::mutex> lock(mVirtioGpuFencesMutex);
-
-        auto fenceIt = mVirtioGpuFences.find(fenceId);
-        if (fenceIt == mVirtioGpuFences.end()) {
-            ALOGE("Fence:%d already signaled", (int)fenceId);
-            return 0;
-        }
-        auto& fence = fenceIt->second;
-
-        waitable = fence.waitable;
-    }
-
-    auto status = waitable.wait_for(std::chrono::milliseconds(timeoutMilliseconds));
-    if (status == std::future_status::ready) {
-        ALOGV("Finished waiting for fence:%d", (int)fenceId);
-        return 0;
-    } else {
-        ALOGE("Timed out waiting for fence:%d", (int)fenceId);
-        return -1;
-    }
-}
-
-void EmulatedVirtioGpu::EmulatedVirtioGpuImpl::SignalEmulatedFence(uint32_t fenceId) {
-    ALOGV("Signaling fence:%d", (int)fenceId);
-
-    std::lock_guard<std::mutex> lock(mVirtioGpuFencesMutex);
-
-    auto fenceIt = mVirtioGpuFences.find(fenceId);
-    if (fenceIt == mVirtioGpuFences.end()) {
-        ALOGE("Failed to find fence %" PRIu32, fenceId);
-        return;
-    }
-    auto& fenceInfo = fenceIt->second;
-    fenceInfo.signaler.set_value();
-}
-
-uint32_t EmulatedVirtioGpu::EmulatedVirtioGpuImpl::CreateEmulatedFence() {
-    const uint32_t fenceId = mNextVirtioGpuFenceId++;
-
-    ALOGV("Creating fence:%d", (int)fenceId);
-
-    std::lock_guard<std::mutex> lock(mVirtioGpuFencesMutex);
-
-    auto [fenceIt, fenceCreated] = mVirtioGpuFences.emplace(fenceId, EmulatedFence{});
-    if (!fenceCreated) {
-        ALOGE("Attempting to recreate fence %" PRIu32, fenceId);
-    }
-
-    auto& fenceInfo = fenceIt->second;
-    fenceInfo.waitable = fenceInfo.signaler.get_future();
-
-    return fenceId;
-}
-
-std::shared_future<void> EmulatedVirtioGpu::EmulatedVirtioGpuImpl::EnqueueVirtioGpuTask(
-    uint32_t contextId, VirtioGpuTask task, std::optional<VirtioGpuFence> fence) {
-    std::promise<void> taskCompletedSignaler;
-    std::shared_future<void> taskCompletedWaitable(taskCompletedSignaler.get_future());
-
-    std::lock_guard<std::mutex> lock(mTasksMutex);
-    mTasks.push(VirtioGpuTaskWithWaitable{
-        .contextId = contextId,
-        .task = std::move(task),
-        .taskCompletedSignaler = std::move(taskCompletedSignaler),
-        .fence = fence,
-    });
-
-    return taskCompletedWaitable;
-}
-
-void EmulatedVirtioGpu::EmulatedVirtioGpuImpl::DoTask(VirtioGpuTaskContextAttachResource task) {
-    ALOGV("Performing task to attach resource-id:%d to context-id:%d", task.resourceId,
-          task.contextId);
-
-    rutabaga_context_attach_resource(mRutabaga, task.contextId, task.resourceId);
-
-    ALOGV("Performing task to attach resource-id:%d to context-id:%d - done", task.resourceId,
-          task.contextId);
-}
-
-void EmulatedVirtioGpu::EmulatedVirtioGpuImpl::DoTask(VirtioGpuTaskContextDetachResource task) {
-    ALOGV("Performing task to detach resource-id:%d to context-id:%d", task.resourceId,
-          task.contextId);
-
-    rutabaga_context_detach_resource(mRutabaga, task.contextId, task.resourceId);
-
-    ALOGV("Performing task to detach resource-id:%d to context-id:%d - done", task.resourceId,
-          task.contextId);
-}
-
-void EmulatedVirtioGpu::EmulatedVirtioGpuImpl::DoTask(VirtioGpuTaskCreateBlob task) {
-    ALOGV("Performing task to create blob resource-id:%d", task.resourceId);
-
-    int ret =
-        rutabaga_resource_create_blob(mRutabaga, task.contextId, task.resourceId, &task.params,
-                                      /*iovecs=*/nullptr,
-                                      /*handle=*/nullptr);
-    if (ret) {
-        ALOGE("Failed to create blob.");
-    }
-
-    ALOGV("Performing task to create blob resource-id:%d - done", task.resourceId);
-}
-
-void EmulatedVirtioGpu::EmulatedVirtioGpuImpl::DoTask(VirtioGpuTaskCreateContext task) {
-    ALOGV("Performing task to create context-id:%" PRIu32 " context-init:%" PRIu32
-          " context-name:%s",
-          task.contextId, task.contextInit, task.contextName.c_str());
-
-    int ret = rutabaga_context_create(mRutabaga, task.contextId, task.contextName.size(),
-                                      task.contextName.data(), task.contextInit);
-    if (ret) {
-        ALOGE("Failed to create context-id:%" PRIu32 ".", task.contextId);
-        return;
-    }
-
-    ALOGV("Performing task to create context-id:%" PRIu32 " context-init:%" PRIu32
-          " context-name:%s - done",
-          task.contextId, task.contextInit, task.contextName.c_str());
-}
-
-void EmulatedVirtioGpu::EmulatedVirtioGpuImpl::DoTask(VirtioGpuTaskCreateResource task) {
-    ALOGV("Performing task to create resource resource:%d", task.resourceId);
-
-    EmulatedResource* resource = GetResource(task.resourceId);
-
-    int ret = rutabaga_resource_create_3d(mRutabaga, task.resourceId, &task.params);
-    if (ret) {
-        ALOGE("Failed to create resource:%d", task.resourceId);
-    }
-
-    resource->iovec.iov_base = task.resourceBytes;
-    resource->iovec.iov_len = task.params.width * task.params.height * 4;
-
-    struct rutabaga_iovecs vecs = {0};
-    vecs.iovecs = &resource->iovec;
-    vecs.num_iovecs = 1;
-
-    ret = rutabaga_resource_attach_backing(mRutabaga, task.resourceId, &vecs);
-    if (ret) {
-        ALOGE("Failed to attach iov to resource:%d", task.resourceId);
-    }
-
-    ALOGV("Performing task to create resource resource:%d - done", task.resourceId);
-
-    rutabaga_context_attach_resource(mRutabaga, task.contextId, task.resourceId);
-}
-
-void EmulatedVirtioGpu::EmulatedVirtioGpuImpl::DoTask(VirtioGpuTaskDestroyContext task) {
-    ALOGV("Performing task to destroy context-id:%" PRIu32, task.contextId);
-
-    rutabaga_context_destroy(mRutabaga, task.contextId);
-
-    ALOGV("Performing task to destroy context-id:%" PRIu32 " - done", task.contextId);
-}
-
-void EmulatedVirtioGpu::EmulatedVirtioGpuImpl::DoTask(VirtioGpuTaskMap task) {
-    ALOGV("Performing task to map resource resource:%d", task.resourceId);
-
-    struct rutabaga_mapping mapping;
-    int ret = rutabaga_resource_map(mRutabaga, task.resourceId, &mapping);
-    if (ret) {
-        ALOGE("Failed to map resource:%d", task.resourceId);
-        return;
-    }
-
-    task.resourceMappedPromise.set_value(reinterpret_cast<uint8_t*>(mapping.ptr));
-    ALOGV("Performing task to map resource resource:%d - done", task.resourceId);
-}
-
-void EmulatedVirtioGpu::EmulatedVirtioGpuImpl::DoTask(VirtioGpuTaskUnmap task) {
-    ALOGV("Performing task to unmap resource resource:%d", task.resourceId);
-    rutabaga_resource_unmap(mRutabaga, task.resourceId);
-    ALOGV("Performing task to unmap resource:%d - done", task.resourceId);
-}
-
-void EmulatedVirtioGpu::EmulatedVirtioGpuImpl::DoTask(VirtioGpuTaskSubmitCmd task) {
-    ALOGV("Performing task to execbuffer");
-
-    if (task.commandBuffer.size() % 4 != 0) {
-        ALOGE("Unaligned command buffer?");
-        return;
-    }
-
-    struct rutabaga_command cmd = {
-        .ctx_id = task.contextId,
-        .cmd_size = static_cast<uint32_t>(task.commandBuffer.size()),
-        .cmd = reinterpret_cast<uint8_t*>(task.commandBuffer.data()),
-        .num_in_fences = 0,
-        .fence_ids = nullptr,
-    };
-
-    int ret = rutabaga_submit_command(mRutabaga, &cmd);
-    if (ret) {
-        ALOGE("Failed to execbuffer.");
-    }
-
-    ALOGV("Performing task to execbuffer - done");
-}
-
-void EmulatedVirtioGpu::EmulatedVirtioGpuImpl::DoTask(VirtioGpuTaskTransferFromHost task) {
-    struct rutabaga_transfer transfer = {0};
-    transfer.x = task.x;
-    transfer.y = task.y;
-    transfer.z = 0;
-    transfer.w = task.w;
-    transfer.h = task.h;
-    transfer.d = 1;
-
-    int ret = rutabaga_resource_transfer_read(mRutabaga, task.contextId, task.resourceId, &transfer,
-                                              nullptr);
-    if (ret) {
-        ALOGE("Failed to transferFromHost() for resource:%" PRIu32, task.resourceId);
-    }
-}
-
-void EmulatedVirtioGpu::EmulatedVirtioGpuImpl::DoTask(VirtioGpuTaskTransferToHost task) {
-    struct rutabaga_transfer transfer = {0};
-    transfer.x = task.x;
-    transfer.y = task.y;
-    transfer.z = 0;
-    transfer.w = task.w;
-    transfer.h = task.h;
-    transfer.d = 1;
-
-    int ret =
-        rutabaga_resource_transfer_write(mRutabaga, task.contextId, task.resourceId, &transfer);
-    if (ret) {
-        ALOGE("Failed to transferToHost() for resource:%" PRIu32, task.resourceId);
-    }
-}
-
-void EmulatedVirtioGpu::EmulatedVirtioGpuImpl::DoTask(VirtioGpuTaskUnrefResource task) {
-    rutabaga_resource_unref(mRutabaga, task.resourceId);
-}
-
-void EmulatedVirtioGpu::EmulatedVirtioGpuImpl::DoTask(VirtioGpuTaskSnapshotSave task) {
-    int ret = rutabaga_snapshot(mRutabaga, task.directory.c_str());
-    if (ret) {
-        ALOGE("snapshotting failed");
-    }
-}
-
-void EmulatedVirtioGpu::EmulatedVirtioGpuImpl::DoTask(VirtioGpuTaskSnapshotRestore task) {
-    int ret = rutabaga_restore(mRutabaga, task.directory.c_str());
-    if (ret) {
-        ALOGE("snapshot restore failed");
-    }
-}
-
-void EmulatedVirtioGpu::EmulatedVirtioGpuImpl::DoTask(VirtioGpuTaskWithWaitable task) {
-    std::visit(
-        [this](auto&& work) {
-            using T = std::decay_t<decltype(work)>;
-            if constexpr (std::is_same_v<T, VirtioGpuTaskContextAttachResource>) {
-                DoTask(std::move(work));
-            } else if constexpr (std::is_same_v<T, VirtioGpuTaskContextDetachResource>) {
-                DoTask(std::move(work));
-            } else if constexpr (std::is_same_v<T, VirtioGpuTaskCreateBlob>) {
-                DoTask(std::move(work));
-            } else if constexpr (std::is_same_v<T, VirtioGpuTaskCreateContext>) {
-                DoTask(std::move(work));
-            } else if constexpr (std::is_same_v<T, VirtioGpuTaskCreateResource>) {
-                DoTask(std::move(work));
-            } else if constexpr (std::is_same_v<T, VirtioGpuTaskDestroyContext>) {
-                DoTask(std::move(work));
-            } else if constexpr (std::is_same_v<T, VirtioGpuTaskMap>) {
-                DoTask(std::move(work));
-            } else if constexpr (std::is_same_v<T, VirtioGpuTaskUnmap>) {
-                DoTask(std::move(work));
-            } else if constexpr (std::is_same_v<T, VirtioGpuTaskSubmitCmd>) {
-                DoTask(std::move(work));
-            } else if constexpr (std::is_same_v<T, VirtioGpuTaskTransferFromHost>) {
-                DoTask(std::move(work));
-            } else if constexpr (std::is_same_v<T, VirtioGpuTaskTransferToHost>) {
-                DoTask(std::move(work));
-            } else if constexpr (std::is_same_v<T, VirtioGpuTaskUnrefResource>) {
-                DoTask(std::move(work));
-            } else if constexpr (std::is_same_v<T, VirtioGpuTaskSnapshotSave>) {
-                DoTask(std::move(work));
-            } else if constexpr (std::is_same_v<T, VirtioGpuTaskSnapshotRestore>) {
-                DoTask(std::move(work));
-            }
-        },
-        task.task);
-
-    if (task.fence) {
-        const struct rutabaga_fence fenceInfo = {
-            .flags = RUTABAGA_FLAG_INFO_RING_IDX,
-            .fence_id = (*task.fence).fenceId,
-            .ctx_id = task.contextId,
-            .ring_idx = (*task.fence).ringIdx,
-        };
-        int ret = rutabaga_create_fence(mRutabaga, &fenceInfo);
-        if (ret) {
-            ALOGE("Failed to create fence.");
-        }
-    }
-
-    task.taskCompletedSignaler.set_value();
-}
-
-void EmulatedVirtioGpu::EmulatedVirtioGpuImpl::RunVirtioGpuTaskProcessingLoop() {
-    while (!mShuttingDown.load()) {
-        std::optional<VirtioGpuTaskWithWaitable> task;
-
-        {
-            std::lock_guard<std::mutex> lock(mTasksMutex);
-            if (!mTasks.empty()) {
-                task = std::move(mTasks.front());
-                mTasks.pop();
-            }
-        }
-
-        if (task) {
-            DoTask(std::move(*task));
-        }
-    }
-}
-
-EmulatedVirtioGpu::EmulatedVirtioGpu()
-    : mImpl{std::make_unique<EmulatedVirtioGpu::EmulatedVirtioGpuImpl>()} {}
-
-namespace {
-
-static std::mutex sInstanceMutex;
-static std::weak_ptr<EmulatedVirtioGpu> sInstance;
-
-}  // namespace
-
-/*static*/
-std::shared_ptr<EmulatedVirtioGpu> EmulatedVirtioGpu::Get() {
-    std::lock_guard<std::mutex> lock(sInstanceMutex);
-
-    std::shared_ptr<EmulatedVirtioGpu> instance = sInstance.lock();
-    if (instance != nullptr) {
-        return instance;
-    }
-
-    instance = std::shared_ptr<EmulatedVirtioGpu>(new EmulatedVirtioGpu());
-
-    bool withGl = false;
-    bool withVk = false;
-    std::string features;
-
-    struct BoolOption {
-        std::string env;
-        bool* val;
-    };
-    const std::vector<BoolOption> options = {
-        {"GFXSTREAM_EMULATED_VIRTIO_GPU_WITH_GL", &withGl},
-        {"GFXSTREAM_EMULATED_VIRTIO_GPU_WITH_VK", &withVk},
-    };
-    for (const BoolOption& option : options) {
-        const char* val = std::getenv(option.env.c_str());
-        if (val != nullptr && (val[0] == 'Y' || val[0] == 'y')) {
-            *option.val = true;
-        }
-    }
-
-    struct StringOption {
-        std::string env;
-        std::string* val;
-    };
-    const std::vector<StringOption> stringOptions = {
-        {"GFXSTREAM_EMULATED_VIRTIO_GPU_RENDERER_FEATURES", &features},
-    };
-    for (const StringOption& option : stringOptions) {
-        const char* val = std::getenv(option.env.c_str());
-        if (val != nullptr) {
-            *option.val = std::string(val);
-        }
-    }
-
-    ALOGE("Initializing withGl:%d withVk:%d features:%s", withGl, withVk, features.c_str());
-    if (!instance->Init(withGl, withVk, features)) {
-        ALOGE("Failed to initialize EmulatedVirtioGpu.");
-        return nullptr;
-    }
-    ALOGE("Successfully initialized EmulatedVirtioGpu.");
-    sInstance = instance;
-    return instance;
-}
-
-/*static*/
-uint32_t EmulatedVirtioGpu::GetNumActiveUsers() {
-    std::lock_guard<std::mutex> lock(sInstanceMutex);
-    std::shared_ptr<EmulatedVirtioGpu> instance = sInstance.lock();
-    return instance.use_count();
-}
-
-bool EmulatedVirtioGpu::Init(bool withGl, bool withVk, const std::string& features) {
-    return mImpl->Init(withGl, withVk, features, this);
-}
-
-std::optional<uint32_t> EmulatedVirtioGpu::CreateContext(uint32_t contextInit) {
-    return mImpl->CreateContext(contextInit);
-}
-
-void EmulatedVirtioGpu::DestroyContext(uint32_t contextId) { mImpl->DestroyContext(contextId); }
-
-bool EmulatedVirtioGpu::GetCaps(uint32_t capsetId, uint32_t guestCapsSize, uint8_t* capset) {
-    return mImpl->GetCaps(capsetId, guestCapsSize, capset);
-}
-
-uint8_t* EmulatedVirtioGpu::Map(uint32_t resourceId) { return mImpl->Map(resourceId); }
-
-void EmulatedVirtioGpu::Unmap(uint32_t resourceId) { mImpl->Unmap(resourceId); }
-
-int EmulatedVirtioGpu::SubmitCmd(uint32_t contextId, uint32_t cmdSize, void* cmd, uint32_t ringIdx,
-                                 VirtioGpuFenceFlags fenceFlags, uint32_t& fenceId,
-                                 std::optional<uint32_t> blobResourceId) {
-    return mImpl->SubmitCmd(contextId, cmdSize, cmd, ringIdx, fenceFlags, fenceId, blobResourceId);
-}
-
-int EmulatedVirtioGpu::Wait(uint32_t resourceId) { return mImpl->Wait(resourceId); }
-
-int EmulatedVirtioGpu::TransferFromHost(uint32_t contextId, uint32_t resourceId, uint32_t offset,
-                                        uint32_t size) {
-    return mImpl->TransferFromHost(contextId, resourceId, offset, size);
-}
-
-int EmulatedVirtioGpu::TransferFromHost(uint32_t contextId, uint32_t resourceId, uint32_t x,
-                                        uint32_t y, uint32_t w, uint32_t h) {
-    return mImpl->TransferFromHost(contextId, resourceId, x, y, w, h);
-}
-
-int EmulatedVirtioGpu::TransferToHost(uint32_t contextId, uint32_t resourceId, uint32_t offset,
-                                      uint32_t size) {
-    return mImpl->TransferToHost(contextId, resourceId, offset, size);
-}
-
-int EmulatedVirtioGpu::TransferToHost(uint32_t contextId, uint32_t resourceId, uint32_t x,
-                                      uint32_t y, uint32_t w, uint32_t h) {
-    return mImpl->TransferToHost(contextId, resourceId, x, y, w, h);
-}
-
-std::optional<uint32_t> EmulatedVirtioGpu::CreateBlob(uint32_t contextId, uint32_t blobMem,
-                                                      uint32_t blobFlags, uint64_t blobId,
-                                                      uint64_t blobSize) {
-    return mImpl->CreateBlob(contextId, blobMem, blobFlags, blobId, blobSize);
-}
-
-std::optional<uint32_t> EmulatedVirtioGpu::CreateVirglBlob(uint32_t contextId, uint32_t width,
-                                                           uint32_t height, uint32_t virglFormat,
-                                                           uint32_t target, uint32_t bind,
-                                                           uint32_t size) {
-    return mImpl->CreateVirglBlob(contextId, width, height, virglFormat, target, bind, size);
-}
-
-void EmulatedVirtioGpu::DestroyResource(uint32_t contextId, uint32_t resourceId) {
-    mImpl->DestroyResource(contextId, resourceId);
-}
-
-void EmulatedVirtioGpu::SnapshotSave(const std::string& directory) {
-    mImpl->SnapshotSave(directory);
-}
-
-void EmulatedVirtioGpu::SnapshotRestore(const std::string& directory) {
-    mImpl->SnapshotRestore(directory);
-}
-
-int EmulatedVirtioGpu::WaitOnEmulatedFence(int fenceAsFileDescriptor, int timeoutMilliseconds) {
-    return mImpl->WaitOnEmulatedFence(fenceAsFileDescriptor, timeoutMilliseconds);
-}
-
-void EmulatedVirtioGpu::SignalEmulatedFence(int fenceId) { mImpl->SignalEmulatedFence(fenceId); }
-
-bool GetNumActiveEmulatedVirtioGpuUsers() { return EmulatedVirtioGpu::GetNumActiveUsers(); }
-
-}  // namespace gfxstream
diff --git a/guest/platform/rutabaga/RutabagaLayer.h b/guest/platform/rutabaga/RutabagaLayer.h
deleted file mode 100644
index 10c65bb..0000000
--- a/guest/platform/rutabaga/RutabagaLayer.h
+++ /dev/null
@@ -1,93 +0,0 @@
-/*
- * Copyright 2023 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 <memory>
-#include <optional>
-
-// see protocol.rs in crosvm
-enum VirtioGpuFenceFlags : uint32_t {
-    kFlagNone = 0x0000,
-    kFlagFence = 0x0001,
-    kFlagRingIdx = 0x0002,
-    kFlagFenceShareable = 0x0004,
-};
-
-constexpr enum VirtioGpuFenceFlags operator|(const enum VirtioGpuFenceFlags self,
-                                             const enum VirtioGpuFenceFlags other) {
-    return (enum VirtioGpuFenceFlags)(uint32_t(self) | uint32_t(other));
-}
-
-namespace gfxstream {
-
-// Emulates parts of the Linux Virtio GPU kernel module and parts of
-// a virtual machine manager to allow speaking directly to the Gfxstream
-// host server via rutabaga.
-class EmulatedVirtioGpu {
-  public:
-   static std::shared_ptr<EmulatedVirtioGpu> Get();
-   static uint32_t GetNumActiveUsers();
-
-   bool Init(bool withGl, bool withVk, const std::string& features);
-
-   bool GetCaps(uint32_t capsetId, uint32_t guestCapsSize, uint8_t* capset);
-
-   std::optional<uint32_t> CreateContext(uint32_t contextInit);
-   void DestroyContext(uint32_t contextId);
-
-   std::optional<uint32_t> CreateBlob(uint32_t contextId, uint32_t blobMem, uint32_t blobFlags,
-                                      uint64_t blobId, uint64_t blobSize);
-   std::optional<uint32_t> CreateVirglBlob(uint32_t contextId, uint32_t width, uint32_t height,
-                                           uint32_t virglFormat, uint32_t target, uint32_t bind,
-                                           uint32_t size);
-
-   void DestroyResource(uint32_t contextId, uint32_t resourceId);
-
-   uint8_t* Map(uint32_t resourceId);
-   void Unmap(uint32_t resourceId);
-
-   int SubmitCmd(uint32_t contextId, uint32_t cmdSize, void* cmd, uint32_t ringIdx,
-                 VirtioGpuFenceFlags fenceFlags, uint32_t& fenceId,
-                 std::optional<uint32_t> blobResourceId);
-
-   int Wait(uint32_t resourceId);
-
-   int TransferFromHost(uint32_t contextId, uint32_t resourceId, uint32_t transferOffset,
-                        uint32_t transferSize);
-   int TransferFromHost(uint32_t contextId, uint32_t resourceId, uint32_t x, uint32_t y, uint32_t w,
-                        uint32_t h);
-
-   int TransferToHost(uint32_t contextId, uint32_t resourceId, uint32_t transferOffset,
-                      uint32_t transferSize);
-   int TransferToHost(uint32_t contextId, uint32_t resourceId, uint32_t x, uint32_t y, uint32_t w,
-                      uint32_t h);
-
-   void SignalEmulatedFence(int fenceId);
-
-   int WaitOnEmulatedFence(int fenceAsFileDescriptor, int timeoutMilliseconds);
-
-   void SnapshotSave(const std::string& directory);
-   void SnapshotRestore(const std::string& directory);
-
-  private:
-    EmulatedVirtioGpu();
-
-    class EmulatedVirtioGpuImpl;
-    std::unique_ptr<EmulatedVirtioGpuImpl> mImpl;
-};
-
-}  // namespace gfxstream
diff --git a/guest/platform/rutabaga/RutabagaVirtGpu.h b/guest/platform/rutabaga/RutabagaVirtGpu.h
deleted file mode 100644
index e56369b..0000000
--- a/guest/platform/rutabaga/RutabagaVirtGpu.h
+++ /dev/null
@@ -1,110 +0,0 @@
-/*
- * Copyright 2023 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 <memory>
-
-#include "VirtGpu.h"
-
-namespace gfxstream {
-
-// Virtio GPU abstraction that directly runs a host render server.
-
-class RutabagaVirtGpuDevice;
-
-class RutabagaVirtGpuResourceMapping : public VirtGpuResourceMapping {
-   public:
-    RutabagaVirtGpuResourceMapping(std::shared_ptr<EmulatedVirtioGpu> emulation,
-                                   VirtGpuResourcePtr blob, uint8_t* mapped);
-    ~RutabagaVirtGpuResourceMapping();
-
-    uint8_t* asRawPtr(void) override;
-
-   private:
-    const std::shared_ptr<EmulatedVirtioGpu> mEmulation;
-    const VirtGpuResourcePtr mBlob;
-    uint8_t* mMapped = nullptr;
-};
-
-class RutabagaVirtGpuResource : public std::enable_shared_from_this<RutabagaVirtGpuResource>,
-                                public VirtGpuResource {
-   public:
-    ~RutabagaVirtGpuResource();
-
-    VirtGpuResourceMappingPtr createMapping(void) override;
-
-    uint32_t getResourceHandle() const override;
-    uint32_t getBlobHandle() const override;
-
-    int exportBlob(VirtGpuExternalHandle& handle) override;
-    int wait() override;
-
-    int transferFromHost(uint32_t offset, uint32_t size) override;
-    int transferFromHost(uint32_t x, uint32_t y, uint32_t w, uint32_t h) override;
-
-    int transferToHost(uint32_t offset, uint32_t size) override;
-    int transferToHost(uint32_t x, uint32_t y, uint32_t w, uint32_t h) override;
-
-   private:
-    friend class RutabagaVirtGpuDevice;
-
-    enum class ResourceType {
-        kBlob,
-        kPipe,
-    };
-
-    RutabagaVirtGpuResource(std::shared_ptr<EmulatedVirtioGpu> emulation, uint32_t resourceId,
-                            ResourceType resourceType, uint32_t contextId);
-
-    const std::shared_ptr<EmulatedVirtioGpu> mEmulation;
-    const uint32_t mContextId;
-    const uint32_t mResourceId;
-    const ResourceType mResourceType;
-};
-
-class RutabagaVirtGpuDevice : public std::enable_shared_from_this<RutabagaVirtGpuDevice>, public VirtGpuDevice {
-  public:
-   RutabagaVirtGpuDevice(std::shared_ptr<EmulatedVirtioGpu> emulation, VirtGpuCapset capset);
-   ~RutabagaVirtGpuDevice();
-
-   bool Init();
-
-   int64_t getDeviceHandle() override;
-
-   VirtGpuCaps getCaps() override;
-
-   VirtGpuResourcePtr createBlob(const struct VirtGpuCreateBlob& blobCreate) override;
-
-   VirtGpuResourcePtr createResource(uint32_t width, uint32_t height, uint32_t stride,
-                                     uint32_t size, uint32_t virglFormat, uint32_t target,
-                                     uint32_t bind) override;
-
-   VirtGpuResourcePtr importBlob(const struct VirtGpuExternalHandle& handle) override;
-
-   int execBuffer(struct VirtGpuExecBuffer& execbuffer, const VirtGpuResource* blob) override;
-
-  private:
-   const std::shared_ptr<EmulatedVirtioGpu> mEmulation;
-   uint32_t mContextId;
-   VirtGpuCapset mCapset;
-   struct VirtGpuCaps mCaps;
-
-   friend class RutabagaVirtGpuResource;
-   uint32_t GetContextId() const { return mContextId; }
-};
-
-}  // namespace gfxstream
diff --git a/guest/platform/rutabaga/RutabagaVirtGpuBlob.cpp b/guest/platform/rutabaga/RutabagaVirtGpuBlob.cpp
deleted file mode 100644
index e2a5310..0000000
--- a/guest/platform/rutabaga/RutabagaVirtGpuBlob.cpp
+++ /dev/null
@@ -1,101 +0,0 @@
-/*
- * Copyright 2023 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 <log/log.h>
-
-#include "RutabagaLayer.h"
-#include "RutabagaVirtGpu.h"
-
-namespace gfxstream {
-
-RutabagaVirtGpuResource::RutabagaVirtGpuResource(std::shared_ptr<EmulatedVirtioGpu> emulation,
-                                                 uint32_t resourceId, ResourceType resourceType,
-                                                 uint32_t contextId)
-    : mEmulation(emulation),
-      mContextId(contextId),
-      mResourceId(resourceId),
-      mResourceType(resourceType) {}
-
-RutabagaVirtGpuResource::~RutabagaVirtGpuResource() {
-    mEmulation->DestroyResource(mContextId, mResourceId);
-}
-
-VirtGpuResourceMappingPtr RutabagaVirtGpuResource::createMapping(void) {
-    uint8_t* mapped = mEmulation->Map(mResourceId);
-    return std::make_shared<RutabagaVirtGpuResourceMapping>(mEmulation, shared_from_this(), mapped);
-}
-
-uint32_t RutabagaVirtGpuResource::getResourceHandle() const { return mResourceId; }
-
-uint32_t RutabagaVirtGpuResource::getBlobHandle() const {
-    if (mResourceType != ResourceType::kBlob) {
-        ALOGE("Attempting to get blob handle for non-blob resource");
-        return -1;
-    }
-
-    ALOGE("Unimplemented: %s", __FUNCTION__);
-    return -1;
-}
-
-int RutabagaVirtGpuResource::exportBlob(VirtGpuExternalHandle&) {
-    if (mResourceType != ResourceType::kBlob) {
-        ALOGE("Attempting to export blob for non-blob resource");
-        return -1;
-    }
-
-    ALOGE("Unimplemented: %s", __FUNCTION__);
-    return -1;
-}
-
-int RutabagaVirtGpuResource::wait() { return mEmulation->Wait(mResourceId); }
-
-int RutabagaVirtGpuResource::transferFromHost(uint32_t offset, uint32_t size) {
-    if (mResourceType != ResourceType::kPipe) {
-        ALOGE("Unexpected transferFromHost() called on non-pipe resource.");
-        return -1;
-    }
-
-    return mEmulation->TransferFromHost(mContextId, mResourceId, offset, size);
-}
-
-int RutabagaVirtGpuResource::transferFromHost(uint32_t x, uint32_t y, uint32_t w, uint32_t h) {
-    if (mResourceType != ResourceType::kPipe) {
-        ALOGE("Unexpected transferFromHost() called on non-pipe resource.");
-        return -1;
-    }
-
-    return mEmulation->TransferFromHost(mContextId, mResourceId, x, y, w, h);
-}
-
-int RutabagaVirtGpuResource::transferToHost(uint32_t offset, uint32_t size) {
-    if (mResourceType != ResourceType::kPipe) {
-        ALOGE("Unexpected transferToHost() called on non-pipe resource.");
-        return -1;
-    }
-
-    return mEmulation->TransferToHost(mContextId, mResourceId, offset, size);
-}
-
-int RutabagaVirtGpuResource::transferToHost(uint32_t x, uint32_t y, uint32_t w, uint32_t h) {
-    if (mResourceType != ResourceType::kPipe) {
-        ALOGE("Unexpected transferToHost() called on non-pipe resource.");
-        return -1;
-    }
-
-    return mEmulation->TransferToHost(mContextId, mResourceId, x, y, w, h);
-}
-
-}  // namespace gfxstream
diff --git a/guest/platform/rutabaga/RutabagaVirtGpuBlobMapping.cpp b/guest/platform/rutabaga/RutabagaVirtGpuBlobMapping.cpp
deleted file mode 100644
index 928532b..0000000
--- a/guest/platform/rutabaga/RutabagaVirtGpuBlobMapping.cpp
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * Copyright 2023 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 "RutabagaLayer.h"
-#include "RutabagaVirtGpu.h"
-
-namespace gfxstream {
-
-RutabagaVirtGpuResourceMapping::RutabagaVirtGpuResourceMapping(
-    std::shared_ptr<EmulatedVirtioGpu> emulation, VirtGpuResourcePtr blob, uint8_t* mapped)
-    : mEmulation(emulation), mBlob(blob), mMapped(mapped) {}
-
-RutabagaVirtGpuResourceMapping::~RutabagaVirtGpuResourceMapping(void) {
-    mEmulation->Unmap(mBlob->getResourceHandle());
-}
-
-uint8_t* RutabagaVirtGpuResourceMapping::asRawPtr(void) { return mMapped; }
-
-}  // namespace gfxstream
diff --git a/guest/platform/rutabaga/RutabagaVirtGpuDevice.cpp b/guest/platform/rutabaga/RutabagaVirtGpuDevice.cpp
deleted file mode 100644
index 3e24190..0000000
--- a/guest/platform/rutabaga/RutabagaVirtGpuDevice.cpp
+++ /dev/null
@@ -1,169 +0,0 @@
-/*
- * Copyright 2023 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 <log/log.h>
-
-#include "RutabagaLayer.h"
-#include "RutabagaVirtGpu.h"
-
-namespace gfxstream {
-
-RutabagaVirtGpuDevice::RutabagaVirtGpuDevice(std::shared_ptr<EmulatedVirtioGpu> emulation,
-                                             VirtGpuCapset capset)
-    : VirtGpuDevice(capset), mEmulation(emulation), mCapset(capset) {}
-
-RutabagaVirtGpuDevice::~RutabagaVirtGpuDevice() { mEmulation->DestroyContext(mContextId); }
-
-bool RutabagaVirtGpuDevice::Init() {
-    uint32_t capsetId = 0;
-    uint32_t capsetSize = 0;
-    uint32_t contextInit = 0;
-    uint8_t* capsetPtr = nullptr;
-
-    mCaps = {
-        .params =
-            {
-                [kParam3D] = 1,
-                [kParamCapsetFix] = 1,
-                [kParamResourceBlob] = 1,
-                [kParamHostVisible] = 1,
-                [kParamCrossDevice] = 0,
-                [kParamContextInit] = 1,
-                [kParamSupportedCapsetIds] = 0,
-                [kParamExplicitDebugName] = 0,
-                [kParamCreateGuestHandle] = 0,
-            },
-    };
-
-    capsetId = static_cast<uint32_t>(mCapset);
-    switch (mCapset) {
-        case kCapsetGfxStreamVulkan:
-            capsetSize = sizeof(struct vulkanCapset);
-            capsetPtr = reinterpret_cast<uint8_t*>(&mCaps.vulkanCapset);
-            break;
-        case kCapsetGfxStreamMagma:
-            capsetSize = sizeof(struct magmaCapset);
-            capsetPtr = reinterpret_cast<uint8_t*>(&mCaps.magmaCapset);
-            break;
-        case kCapsetGfxStreamGles:
-            capsetSize = sizeof(struct vulkanCapset);
-            capsetPtr = reinterpret_cast<uint8_t*>(&mCaps.glesCapset);
-            break;
-        case kCapsetGfxStreamComposer:
-            capsetSize = sizeof(struct vulkanCapset);
-            capsetPtr = reinterpret_cast<uint8_t*>(&mCaps.composerCapset);
-            break;
-        default:
-            capsetSize = 0;
-    }
-
-    if (capsetId != 0) {
-        bool success = mEmulation->GetCaps(capsetId, capsetSize, capsetPtr);
-        if (!success) {
-            ALOGE("Failed to capability set");
-            return false;
-        }
-    }
-
-    const auto contextIdOp = mEmulation->CreateContext(capsetId);
-    if (!contextIdOp) {
-        ALOGE("Failed to create RutabagaVirtGpuDevice: failed to create context.");
-        return false;
-    }
-
-    mContextId = *contextIdOp;
-    return true;
-}
-
-int64_t RutabagaVirtGpuDevice::getDeviceHandle() { return -1; }
-
-VirtGpuCaps RutabagaVirtGpuDevice::getCaps() { return mCaps; }
-
-VirtGpuResourcePtr RutabagaVirtGpuDevice::createBlob(const struct VirtGpuCreateBlob& blobCreate) {
-    const auto resourceIdOpt = mEmulation->CreateBlob(
-        mContextId, static_cast<uint32_t>(blobCreate.blobMem),
-        static_cast<uint32_t>(blobCreate.flags), blobCreate.blobId, blobCreate.size);
-    if (!resourceIdOpt) {
-        return nullptr;
-    }
-
-    return VirtGpuResourcePtr(new RutabagaVirtGpuResource(
-        mEmulation, *resourceIdOpt, RutabagaVirtGpuResource::ResourceType::kBlob, mContextId));
-}
-
-VirtGpuResourcePtr RutabagaVirtGpuDevice::createResource(uint32_t width, uint32_t height,
-                                                         uint32_t /*stride*/, uint32_t size,
-                                                         uint32_t virglFormat, uint32_t target,
-                                                         uint32_t bind) {
-    const auto resourceIdOpt =
-        mEmulation->CreateVirglBlob(mContextId, width, height, virglFormat, target, bind, size);
-    if (!resourceIdOpt) {
-        return nullptr;
-    }
-
-    return VirtGpuResourcePtr(new RutabagaVirtGpuResource(
-        mEmulation, *resourceIdOpt, RutabagaVirtGpuResource::ResourceType::kPipe, mContextId));
-}
-
-int RutabagaVirtGpuDevice::execBuffer(struct VirtGpuExecBuffer& execbuffer,
-                                      const VirtGpuResource* blob) {
-    std::optional<uint32_t> blobResourceId;
-    uint32_t fenceId = 0;
-    VirtioGpuFenceFlags fenceFlags = kFlagNone;
-
-    if (blob) {
-        blobResourceId = blob->getResourceHandle();
-    }
-
-    if (execbuffer.flags & kFenceOut) {
-        fenceFlags = kFlagFence;
-    }
-
-    int ret = mEmulation->SubmitCmd(mContextId, execbuffer.command_size, execbuffer.command,
-                                    execbuffer.ring_idx, fenceFlags, fenceId, blobResourceId);
-
-    if (execbuffer.flags & kFenceOut) {
-        execbuffer.handle.osHandle = fenceId;
-        execbuffer.handle.type = kFenceHandleSyncFd;
-    }
-
-    return ret;
-}
-
-VirtGpuResourcePtr RutabagaVirtGpuDevice::importBlob(const struct VirtGpuExternalHandle&) {
-    ALOGE("Unimplemented %s", __FUNCTION__);
-    return nullptr;
-}
-
-}  // namespace gfxstream
-
-VirtGpuDevice* createPlatformVirtGpuDevice(enum VirtGpuCapset capset, int32_t) {
-    std::shared_ptr<gfxstream::EmulatedVirtioGpu> emulation = gfxstream::EmulatedVirtioGpu::Get();
-    if (!emulation) {
-        ALOGE("Failed to create RutabagaVirtGpuDevice: failed to get emulation layer.");
-        return nullptr;
-    }
-
-    auto device = new gfxstream::RutabagaVirtGpuDevice(emulation, capset);
-    bool success = device->Init();
-    if (!success) {
-        ALOGE("Failed to create RutabagaVirtGpuDevice: Init failed.");
-        delete device;
-        return nullptr;
-    }
-
-    return device;
-}
diff --git a/guest/platform/rutabaga/RutabagaVirtGpuSyncHelper.cpp b/guest/platform/rutabaga/RutabagaVirtGpuSyncHelper.cpp
deleted file mode 100644
index 2f97ea8..0000000
--- a/guest/platform/rutabaga/RutabagaVirtGpuSyncHelper.cpp
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * Copyright 2023 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 "RutabagaVirtGpuSyncHelper.h"
-
-#include <log/log.h>
-
-#include "RutabagaLayer.h"
-
-namespace gfxstream {
-
-RutabagaVirtGpuSyncHelper::RutabagaVirtGpuSyncHelper() {}
-
-bool RutabagaVirtGpuSyncHelper::Init() {
-    mEmulation = EmulatedVirtioGpu::Get();
-    return mEmulation != nullptr;
-}
-
-int RutabagaVirtGpuSyncHelper::wait(int syncFd, int timeoutMilliseconds) {
-    return mEmulation->WaitOnEmulatedFence(syncFd, timeoutMilliseconds);
-}
-
-int RutabagaVirtGpuSyncHelper::dup(int syncFd) {
-    // TODO update reference count
-    return syncFd;
-}
-
-int RutabagaVirtGpuSyncHelper::close(int) { return 0; }
-
-SyncHelper* createPlatformSyncHelper() {
-    RutabagaVirtGpuSyncHelper* sync = new RutabagaVirtGpuSyncHelper();
-    if (!sync->Init()) {
-        ALOGE("Failed to initialize RutabagaVirtGpuSyncHelper: Failed to get emulation layer.");
-        return nullptr;
-    }
-    return sync;
-}
-
-}  // namespace gfxstream
diff --git a/guest/platform/rutabaga/RutabagaVirtGpuSyncHelper.h b/guest/platform/rutabaga/RutabagaVirtGpuSyncHelper.h
deleted file mode 100644
index 6b50e71..0000000
--- a/guest/platform/rutabaga/RutabagaVirtGpuSyncHelper.h
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * Copyright 2023 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 <memory>
-
-#include "RutabagaLayer.h"
-#include "Sync.h"
-
-namespace gfxstream {
-
-class RutabagaVirtGpuSyncHelper : public SyncHelper {
-  public:
-    RutabagaVirtGpuSyncHelper();
-
-    bool Init();
-
-    int wait(int syncFd, int timeoutMilliseconds) override;
-
-    int dup(int syncFd) override;
-
-    int close(int) override;
-
-   private:
-    std::shared_ptr<EmulatedVirtioGpu> mEmulation;
-};
-
-SyncHelper* createPlatformSyncHelper();
-
-}  // namespace gfxstream
diff --git a/guest/platform/rutabaga/include/gfxstream/RutabagaLayerTestUtils.h b/guest/platform/rutabaga/include/gfxstream/RutabagaLayerTestUtils.h
deleted file mode 100644
index 8f4536d..0000000
--- a/guest/platform/rutabaga/include/gfxstream/RutabagaLayerTestUtils.h
+++ /dev/null
@@ -1,23 +0,0 @@
-/*
- * Copyright 2023 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
-
-namespace gfxstream {
-
-uint32_t GetNumActiveEmulatedVirtioGpuUsers();
-
-}  // namespace gfxstream
diff --git a/guest/qemupipe/Android.bp b/guest/qemupipe/Android.bp
index b199e34..4fbd9e5 100644
--- a/guest/qemupipe/Android.bp
+++ b/guest/qemupipe/Android.bp
@@ -32,21 +32,10 @@
     vendor_available: true,
     srcs: [
         "qemu_pipe_common.cpp",
+        "qemu_pipe_guest.cpp",
     ],
     header_libs: ["libqemupipe-types.ranchu"],
     export_header_lib_headers: ["libqemupipe-types.ranchu"],
     shared_libs: ["liblog"],
     export_include_dirs: ["include"],
-    target: {
-        android: {
-            srcs: [
-                "qemu_pipe_guest.cpp",
-            ],
-        },
-        host: {
-            srcs: [
-                "qemu_pipe_stub.cpp",
-            ],
-        },
-    },
 }
diff --git a/guest/qemupipe/qemu_pipe_stub.cpp b/guest/qemupipe/qemu_pipe_stub.cpp
deleted file mode 100644
index 0e1c14d..0000000
--- a/guest/qemupipe/qemu_pipe_stub.cpp
+++ /dev/null
@@ -1,43 +0,0 @@
-// Copyright (C) 2023 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.
-
-extern "C" {
-
-int qemu_pipe_open_ns(const char*, const char*, int) {
-    return -1;
-}
-
-int qemu_pipe_open(const char*) {
-    return -1;
-}
-
-void qemu_pipe_close(int) {
-}
-
-int qemu_pipe_read(int, void*, int) {
-    return -1;
-}
-
-int qemu_pipe_write(int, const void*, int) {
-    return -1;
-}
-
-int qemu_pipe_try_again(int) {
-    return -1;
-}
-
-void qemu_pipe_print_error(int) {
-}
-
-}  // extern "C"
\ No newline at end of file
diff --git a/guest/renderControl_enc/Android.bp b/guest/renderControl_enc/Android.bp
index 5f346a3..c58a292 100644
--- a/guest/renderControl_enc/Android.bp
+++ b/guest/renderControl_enc/Android.bp
@@ -46,8 +46,10 @@
         "libgfxstream_guest_graphics_headers",
         "libgfxstream_guest_iostream",
     ],
+    static_libs: [
+        "libgfxstream_androidemu_static",
+    ],
     shared_libs: [
-        "libandroidemu",
         "liblog",
         "libOpenglCodecCommon",
     ],
diff --git a/guest/rendercontrol/RenderControl.cpp b/guest/rendercontrol/RenderControl.cpp
index ee2598a..339060e 100644
--- a/guest/rendercontrol/RenderControl.cpp
+++ b/guest/rendercontrol/RenderControl.cpp
@@ -48,8 +48,7 @@
 
 class RenderControlDeviceImpl {
    public:
-    RenderControlDeviceImpl()
-        : mHostConnection(HostConnection::createUnique(kCapsetNone, INVALID_DESCRIPTOR)) {}
+    RenderControlDeviceImpl() : mHostConnection(HostConnection::createUnique(kCapsetNone)) {}
 
     RenderControlDeviceImpl(const RenderControlDeviceImpl& rhs) = delete;
     RenderControlDeviceImpl& operator=(const RenderControlDeviceImpl& rhs) = delete;
diff --git a/guest/vulkan/Android.bp b/guest/vulkan/Android.bp
index 806a77c..975d4ec 100644
--- a/guest/vulkan/Android.bp
+++ b/guest/vulkan/Android.bp
@@ -65,7 +65,6 @@
     cflags: [
         "-DLOG_TAG=\"goldfish_vulkan\"",
         "-DVK_NO_PROTOTYPES",
-        "-DVK_USE_PLATFORM_ANDROID_KHR",
         "-fstrict-aliasing",
         "-fvisibility=hidden",
         "-Wno-missing-field-initializers",
@@ -124,12 +123,12 @@
         "libgfxstream_guest_vulkan_defaults",
     ],
     shared_libs: [
-        "libgfxstream_platform_rutabaga_server",
+        "libvirtgpu_kumquat_ffi",
     ],
     static_libs: [
         "libgfxstream_guest_android_with_host",
         "libgfxstream_guest_system_common_with_host",
-        "libgfxstream_platform_rutabaga",
+        "libgfxstream_platform_kumquat",
     ],
     cflags: [
         "-DEND2END_TESTS",
diff --git a/guest/vulkan/gfxstream_vk_cmd.cpp b/guest/vulkan/gfxstream_vk_cmd.cpp
index 2039e08..f233571 100644
--- a/guest/vulkan/gfxstream_vk_cmd.cpp
+++ b/guest/vulkan/gfxstream_vk_cmd.cpp
@@ -126,6 +126,9 @@
     VK_FROM_HANDLE(gfxstream_vk_device, gfxstream_device, device);
     VK_FROM_HANDLE(gfxstream_vk_command_pool, gfxstream_commandPool, pAllocateInfo->commandPool);
     VkResult result = (VkResult)0;
+    for (uint32_t i = 0; i < pAllocateInfo->commandBufferCount; i++) {
+        pCommandBuffers[i] = VK_NULL_HANDLE;
+    }
     std::vector<gfxstream_vk_command_buffer*> gfxstream_commandBuffers(
         pAllocateInfo->commandBufferCount);
     for (uint32_t i = 0; i < pAllocateInfo->commandBufferCount; i++) {
@@ -171,20 +174,26 @@
     VK_FROM_HANDLE(gfxstream_vk_command_pool, gfxstream_commandPool, commandPool);
     {
         // Set up internal commandBuffer array for gfxstream-internal call
-        std::vector<VkCommandBuffer> internal_objects(commandBufferCount);
+        std::vector<VkCommandBuffer> internal_objects;
+        internal_objects.reserve(commandBufferCount);
         for (uint32_t i = 0; i < commandBufferCount; i++) {
             VK_FROM_HANDLE(gfxstream_vk_command_buffer, gfxstream_commandBuffer,
                            pCommandBuffers[i]);
-            internal_objects[i] = gfxstream_commandBuffer->internal_object;
+            if (gfxstream_commandBuffer) {
+                internal_objects.push_back(gfxstream_commandBuffer->internal_object);
+            }
         }
         auto vkEnc = gfxstream::vk::ResourceTracker::getThreadLocalEncoder();
         vkEnc->vkFreeCommandBuffers(gfxstream_device->internal_object,
-                                    gfxstream_commandPool->internal_object, commandBufferCount,
+                                    gfxstream_commandPool->internal_object,
+                                    internal_objects.size(),
                                     internal_objects.data(), true /* do lock */);
     }
     for (uint32_t i = 0; i < commandBufferCount; i++) {
         VK_FROM_HANDLE(gfxstream_vk_command_buffer, gfxstream_commandBuffer, pCommandBuffers[i]);
-        vk_command_buffer_destroyOp(&gfxstream_commandBuffer->vk);
+        if (gfxstream_commandBuffer) {
+            vk_command_buffer_destroyOp(&gfxstream_commandBuffer->vk);
+        }
     }
 }
 
diff --git a/guest/vulkan/gfxstream_vk_device.cpp b/guest/vulkan/gfxstream_vk_device.cpp
index 5b51e50..4c022e8 100644
--- a/guest/vulkan/gfxstream_vk_device.cpp
+++ b/guest/vulkan/gfxstream_vk_device.cpp
@@ -99,18 +99,6 @@
     return VK_SUCCESS;
 }
 
-#if defined(END2END_TESTS)
-static VkResult vkInitializeKumquat(uint32_t descriptor) {
-    HostConnection* hostCon = HostConnection::getWithDescriptor(kCapsetGfxStreamVulkan, descriptor);
-    if (!hostCon) {
-        mesa_loge("failed to get kumquat connection");
-        return VK_ERROR_INITIALIZATION_FAILED;
-    }
-
-    return VK_SUCCESS;
-}
-#endif
-
 static bool isMesaOnlyInstanceExtension(const char* name) {
     for (auto mesaExt : kMesaOnlyInstanceExtension) {
         if (!strncmp(mesaExt, name, VK_MAX_EXTENSION_NAME_SIZE)) return true;
@@ -646,13 +634,6 @@
 
 PFN_vkVoidFunction gfxstream_vk_GetInstanceProcAddr(VkInstance _instance, const char* pName) {
     VK_FROM_HANDLE(gfxstream_vk_instance, instance, _instance);
-
-#if defined(END2END_TESTS)
-    if (strcmp(pName, "vkInitializeKumquat") == 0) {
-        return (PFN_vkVoidFunction)vkInitializeKumquat;
-    }
-#endif
-
     return vk_instance_get_proc_addr(&instance->vk, &gfxstream_vk_instance_entrypoints, pName);
 }
 
diff --git a/guest/vulkan_enc/Android.bp b/guest/vulkan_enc/Android.bp
index f06d7b8..b9906b6 100644
--- a/guest/vulkan_enc/Android.bp
+++ b/guest/vulkan_enc/Android.bp
@@ -110,6 +110,7 @@
     vendor: true,
     defaults: [
         "libgfxstream_guest_cc_defaults",
+        "gfxstream_guest_cc_defaults_for_platform",
     ],
     header_libs: [
         "libgfxstream_vulkan_headers",
@@ -148,7 +149,6 @@
         "-DVK_EXT_device_memory_report",
         "-DVK_GOOGLE_gfxstream",
         "-DVK_NO_PROTOTYPES",
-        "-DVK_USE_PLATFORM_ANDROID_KHR",
         "-fstrict-aliasing",
         "-Werror",
         "-Wno-missing-field-initializers",
@@ -198,10 +198,10 @@
         "libgfxstream_guest_vulkan_encoder_defaults",
     ],
     static_libs: [
-        "libgfxstream_platform_rutabaga",
+        "libgfxstream_platform_kumquat",
     ],
     export_static_lib_headers: [
-        "libgfxstream_platform_rutabaga",
+        "libgfxstream_platform_kumquat",
     ],
     target: {
         host: {
diff --git a/guest/vulkan_enc/AndroidHardwareBuffer.cpp b/guest/vulkan_enc/AndroidHardwareBuffer.cpp
index 1a5d93a..4ac0bdf 100644
--- a/guest/vulkan_enc/AndroidHardwareBuffer.cpp
+++ b/guest/vulkan_enc/AndroidHardwareBuffer.cpp
@@ -25,6 +25,8 @@
 #define DRM_FORMAT_S8_UINT fourcc_code('9', '9', '9', '1')
 #endif
 
+#if defined(ANDROID)
+
 #include <assert.h>
 
 #include "gfxstream/guest/Gralloc.h"
@@ -331,3 +333,5 @@
 
 }  // namespace vk
 }  // namespace gfxstream
+
+#endif  // ANDROID
diff --git a/guest/vulkan_enc/AndroidHardwareBuffer.h b/guest/vulkan_enc/AndroidHardwareBuffer.h
index 5b2bef5..72c5118 100644
--- a/guest/vulkan_enc/AndroidHardwareBuffer.h
+++ b/guest/vulkan_enc/AndroidHardwareBuffer.h
@@ -14,6 +14,8 @@
 // limitations under the License.
 #pragma once
 
+#if defined(ANDROID)
+
 #include <vulkan/vulkan.h>
 
 #include "gfxstream/guest/Gralloc.h"
@@ -51,3 +53,5 @@
 
 }  // namespace vk
 }  // namespace gfxstream
+
+#endif  // ANDROID
diff --git a/guest/vulkan_enc/ResourceTracker.cpp b/guest/vulkan_enc/ResourceTracker.cpp
index 4aca2fe..e6ab971 100644
--- a/guest/vulkan_enc/ResourceTracker.cpp
+++ b/guest/vulkan_enc/ResourceTracker.cpp
@@ -33,9 +33,9 @@
 
 #ifdef VK_USE_PLATFORM_ANDROID_KHR
 #include "vk_format_info.h"
+#include <vndk/hardware_buffer.h>
 #endif
 #include <stdlib.h>
-#include <vndk/hardware_buffer.h>
 
 #include <algorithm>
 #include <set>
@@ -46,6 +46,10 @@
 #include "vk_struct_id.h"
 #include "vk_util.h"
 
+#if defined(__linux__)
+#include <drm_fourcc.h>
+#endif
+
 #if defined(__ANDROID__) || defined(__linux__) || defined(__APPLE__)
 
 #include <sys/mman.h>
@@ -1893,6 +1897,9 @@
 #if !defined(VK_USE_PLATFORM_ANDROID_KHR) && defined(__linux__)
         filteredExts.push_back(VkExtensionProperties{"VK_KHR_external_memory_fd", 1});
         filteredExts.push_back(VkExtensionProperties{"VK_EXT_external_memory_dma_buf", 1});
+        // In case the host doesn't support format modifiers, they are emulated
+        // on guest side.
+        filteredExts.push_back(VkExtensionProperties{"VK_EXT_image_drm_format_modifier", 1});
 #endif
     }
 
@@ -3801,11 +3808,12 @@
                 isDmaBufImage = imageInfo.isDmaBufImage;
             }
 
-            // TODO (b/326956485): Support DRM format modifiers for dmabuf memory
-            // For now, can only externalize memory for linear images
             if (isDmaBufImage) {
                 const VkImageSubresource imageSubresource = {
-                    .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
+                    .aspectMask = exportAllocateInfoPtr->handleTypes &
+                                          VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT
+                                      ? VK_IMAGE_ASPECT_MEMORY_PLANE_0_BIT_EXT
+                                      : VK_IMAGE_ASPECT_COLOR_BIT,
                     .mipLevel = 0,
                     .arrayLayer = 0,
                 };
@@ -4224,28 +4232,55 @@
 
 #if defined(LINUX_GUEST_BUILD)
     bool isDmaBufImage = false;
+    VkImageDrmFormatModifierExplicitCreateInfoEXT localDrmFormatModifierInfo;
+    VkImageDrmFormatModifierListCreateInfoEXT localDrmFormatModifierList;
+
     if (extImgCiPtr &&
         (extImgCiPtr->handleTypes & VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT)) {
         const wsi_image_create_info* wsiImageCi =
             vk_find_struct<wsi_image_create_info>(pCreateInfo);
-        if (wsiImageCi) {
-            if (!wsiImageCi->scanout) {
-                mesa_logd(
-                    "gfxstream only supports native DRM image scanout path for Linux WSI "
-                    "(wsi_image_create_info::scanout)");
-                return VK_ERROR_INITIALIZATION_FAILED;
-            }
+        if (wsiImageCi && wsiImageCi->scanout) {
             // Linux WSI creates swapchain images with VK_IMAGE_CREATE_ALIAS_BIT. Vulkan spec
             // states: "If the pNext chain includes a VkExternalMemoryImageCreateInfo or
             // VkExternalMemoryImageCreateInfoNV structure whose handleTypes member is not 0, it is
             // as if VK_IMAGE_CREATE_ALIAS_BIT is set." To avoid flag mismatches on host driver,
             // remove the VK_IMAGE_CREATE_ALIAS_BIT here.
             localCreateInfo.flags &= ~VK_IMAGE_CREATE_ALIAS_BIT;
-            // TODO (b/326956485): DRM format modifiers to support client/compositor awareness
-            // For now, override WSI images to use linear tiling, as compositor will default to
-            // DRM_FORMAT_MOD_LINEAR.
-            localCreateInfo.tiling = VK_IMAGE_TILING_LINEAR;
         }
+
+        const VkImageDrmFormatModifierExplicitCreateInfoEXT* drmFmtMod =
+            vk_find_struct<VkImageDrmFormatModifierExplicitCreateInfoEXT>(pCreateInfo);
+        const VkImageDrmFormatModifierListCreateInfoEXT* drmFmtModList =
+            vk_find_struct<VkImageDrmFormatModifierListCreateInfoEXT>(pCreateInfo);
+        if (drmFmtMod || drmFmtModList) {
+            if (getHostDeviceExtensionIndex(VK_EXT_IMAGE_DRM_FORMAT_MODIFIER_EXTENSION_NAME) !=
+                -1) {
+                // host supports DRM format modifiers => forward the struct
+                if (drmFmtMod) {
+                    localDrmFormatModifierInfo = vk_make_orphan_copy(*drmFmtMod);
+                    vk_append_struct(&structChainIter, &localDrmFormatModifierInfo);
+                }
+                if (drmFmtModList) {
+                    localDrmFormatModifierList = vk_make_orphan_copy(*drmFmtModList);
+                    vk_append_struct(&structChainIter, &localDrmFormatModifierList);
+                }
+            } else {
+                bool canUseLinearModifier =
+                    (drmFmtMod && drmFmtMod->drmFormatModifier == DRM_FORMAT_MOD_LINEAR) ||
+                    std::any_of(
+                        drmFmtModList->pDrmFormatModifiers,
+                        drmFmtModList->pDrmFormatModifiers + drmFmtModList->drmFormatModifierCount,
+                        [](const uint64_t mod) { return mod == DRM_FORMAT_MOD_LINEAR; });
+                // host doesn't support DRM format modifiers, try emulating
+                if (canUseLinearModifier) {
+                    mesa_logd("emulating DRM_FORMAT_MOD_LINEAR with VK_IMAGE_TILING_LINEAR");
+                    localCreateInfo.tiling = VK_IMAGE_TILING_LINEAR;
+                } else {
+                    return VK_ERROR_VALIDATION_FAILED_EXT;
+                }
+            }
+        }
+
         isDmaBufImage = true;
     }
 #endif
@@ -6680,6 +6715,8 @@
     VkEncoder* enc = (VkEncoder*)context;
     (void)input_result;
 
+    VkPhysicalDeviceImageFormatInfo2 localImageFormatInfo = *pImageFormatInfo;
+
     uint32_t supportedHandleType = 0;
     VkExternalImageFormatProperties* ext_img_properties =
         vk_find_struct<VkExternalImageFormatProperties>(pImageFormatProperties);
@@ -6723,18 +6760,64 @@
         }
     }
 
+#ifdef LINUX_GUEST_BUILD
+    VkImageDrmFormatModifierExplicitCreateInfoEXT localDrmFormatModifierInfo;
+
+    const VkPhysicalDeviceImageDrmFormatModifierInfoEXT* drmFmtMod =
+        vk_find_struct<VkPhysicalDeviceImageDrmFormatModifierInfoEXT>(pImageFormatInfo);
+    VkDrmFormatModifierPropertiesListEXT* emulatedDrmFmtModPropsList = nullptr;
+    if (drmFmtMod) {
+        if (getHostDeviceExtensionIndex(VK_EXT_IMAGE_DRM_FORMAT_MODIFIER_EXTENSION_NAME) != -1) {
+            // Host supports DRM format modifiers => leave the input unchanged.
+        } else {
+            mesa_logd("emulating DRM_FORMAT_MOD_LINEAR with VK_IMAGE_TILING_LINEAR");
+            emulatedDrmFmtModPropsList =
+                vk_find_struct<VkDrmFormatModifierPropertiesListEXT>(pImageFormatProperties);
+
+            // Host doesn't support DRM format modifiers, try emulating.
+            if (drmFmtMod) {
+                if (drmFmtMod->drmFormatModifier == DRM_FORMAT_MOD_LINEAR) {
+                    localImageFormatInfo.tiling = VK_IMAGE_TILING_LINEAR;
+                    pImageFormatInfo = &localImageFormatInfo;
+                    // Leave drmFormatMod in the input; it should be ignored when
+                    // tiling is not VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT
+                } else {
+                    return VK_ERROR_FORMAT_NOT_SUPPORTED;
+                }
+            }
+        }
+    }
+#endif  // LINUX_GUEST_BUILD
+
     VkResult hostRes;
 
     if (isKhr) {
         hostRes = enc->vkGetPhysicalDeviceImageFormatProperties2KHR(
-            physicalDevice, pImageFormatInfo, pImageFormatProperties, true /* do lock */);
+            physicalDevice, &localImageFormatInfo, pImageFormatProperties, true /* do lock */);
     } else {
         hostRes = enc->vkGetPhysicalDeviceImageFormatProperties2(
-            physicalDevice, pImageFormatInfo, pImageFormatProperties, true /* do lock */);
+            physicalDevice, &localImageFormatInfo, pImageFormatProperties, true /* do lock */);
     }
 
     if (hostRes != VK_SUCCESS) return hostRes;
 
+#ifdef LINUX_GUEST_BUILD
+    if (emulatedDrmFmtModPropsList) {
+        VkFormatProperties formatProperties;
+        enc->vkGetPhysicalDeviceFormatProperties(physicalDevice, localImageFormatInfo.format,
+                                                 &formatProperties, true /* do lock */);
+
+        emulatedDrmFmtModPropsList->drmFormatModifierCount = 1;
+        if (emulatedDrmFmtModPropsList->pDrmFormatModifierProperties) {
+            emulatedDrmFmtModPropsList->pDrmFormatModifierProperties[0] = {
+                .drmFormatModifier = DRM_FORMAT_MOD_LINEAR,
+                .drmFormatModifierPlaneCount = 1,
+                .drmFormatModifierTilingFeatures = formatProperties.linearTilingFeatures,
+            };
+        }
+    }
+#endif  // LINUX_GUEST_BUILD
+
 #ifdef VK_USE_PLATFORM_FUCHSIA
     if (ext_img_properties) {
         if (ext_img_info) {
diff --git a/guest/vulkan_enc/VkEncoder.cpp b/guest/vulkan_enc/VkEncoder.cpp
index a178049..89be61c 100644
--- a/guest/vulkan_enc/VkEncoder.cpp
+++ b/guest/vulkan_enc/VkEncoder.cpp
@@ -22888,6 +22888,80 @@
 }
 
 #endif
+#ifdef VK_EXT_image_drm_format_modifier
+VkResult VkEncoder::vkGetImageDrmFormatModifierPropertiesEXT(
+    VkDevice device, VkImage image, VkImageDrmFormatModifierPropertiesEXT* pProperties,
+    uint32_t doLock) {
+    ENCODER_DEBUG_LOG(
+        "vkGetImageDrmFormatModifierPropertiesEXT(device:%p, image:%p, pProperties:%p)", device,
+        image, pProperties);
+    (void)doLock;
+    bool queueSubmitWithCommandsEnabled =
+        sFeatureBits & VULKAN_STREAM_FEATURE_QUEUE_SUBMIT_WITH_COMMANDS_BIT;
+    if (!queueSubmitWithCommandsEnabled && doLock) this->lock();
+    auto stream = mImpl->stream();
+    auto pool = mImpl->pool();
+    VkDevice local_device;
+    VkImage local_image;
+    local_device = device;
+    local_image = image;
+    size_t count = 0;
+    size_t* countPtr = &count;
+    {
+        uint64_t cgen_var_0;
+        *countPtr += 1 * 8;
+        uint64_t cgen_var_1;
+        *countPtr += 1 * 8;
+        count_VkImageDrmFormatModifierPropertiesEXT(
+            sFeatureBits, VK_STRUCTURE_TYPE_MAX_ENUM,
+            (VkImageDrmFormatModifierPropertiesEXT*)(pProperties), countPtr);
+    }
+    uint32_t packetSize_vkGetImageDrmFormatModifierPropertiesEXT =
+        4 + 4 + (queueSubmitWithCommandsEnabled ? 4 : 0) + count;
+    uint8_t* streamPtr = stream->reserve(packetSize_vkGetImageDrmFormatModifierPropertiesEXT);
+    uint8_t* packetBeginPtr = streamPtr;
+    uint8_t** streamPtrPtr = &streamPtr;
+    uint32_t opcode_vkGetImageDrmFormatModifierPropertiesEXT =
+        OP_vkGetImageDrmFormatModifierPropertiesEXT;
+    uint32_t seqno;
+    if (queueSubmitWithCommandsEnabled) seqno = ResourceTracker::nextSeqno();
+    memcpy(streamPtr, &opcode_vkGetImageDrmFormatModifierPropertiesEXT, sizeof(uint32_t));
+    streamPtr += sizeof(uint32_t);
+    memcpy(streamPtr, &packetSize_vkGetImageDrmFormatModifierPropertiesEXT, sizeof(uint32_t));
+    streamPtr += sizeof(uint32_t);
+    if (queueSubmitWithCommandsEnabled) {
+        memcpy(streamPtr, &seqno, sizeof(uint32_t));
+        streamPtr += sizeof(uint32_t);
+    }
+    uint64_t cgen_var_0;
+    *&cgen_var_0 = get_host_u64_VkDevice((*&local_device));
+    memcpy(*streamPtrPtr, (uint64_t*)&cgen_var_0, 1 * 8);
+    *streamPtrPtr += 1 * 8;
+    uint64_t cgen_var_1;
+    *&cgen_var_1 = get_host_u64_VkImage((*&local_image));
+    memcpy(*streamPtrPtr, (uint64_t*)&cgen_var_1, 1 * 8);
+    *streamPtrPtr += 1 * 8;
+    reservedmarshal_VkImageDrmFormatModifierPropertiesEXT(
+        stream, VK_STRUCTURE_TYPE_MAX_ENUM, (VkImageDrmFormatModifierPropertiesEXT*)(pProperties),
+        streamPtrPtr);
+    unmarshal_VkImageDrmFormatModifierPropertiesEXT(
+        stream, VK_STRUCTURE_TYPE_MAX_ENUM, (VkImageDrmFormatModifierPropertiesEXT*)(pProperties));
+    if (pProperties) {
+        transform_fromhost_VkImageDrmFormatModifierPropertiesEXT(
+            sResourceTracker, (VkImageDrmFormatModifierPropertiesEXT*)(pProperties));
+    }
+    VkResult vkGetImageDrmFormatModifierPropertiesEXT_VkResult_return = (VkResult)0;
+    stream->read(&vkGetImageDrmFormatModifierPropertiesEXT_VkResult_return, sizeof(VkResult));
+    ++encodeCount;
+    if (0 == encodeCount % POOL_CLEAR_INTERVAL) {
+        pool->freeAll();
+        stream->clearPool();
+    }
+    if (!queueSubmitWithCommandsEnabled && doLock) this->unlock();
+    return vkGetImageDrmFormatModifierPropertiesEXT_VkResult_return;
+}
+
+#endif
 #ifdef VK_EXT_tooling_info
 VkResult VkEncoder::vkGetPhysicalDeviceToolPropertiesEXT(
     VkPhysicalDevice physicalDevice, uint32_t* pToolCount,
diff --git a/guest/vulkan_enc/VkEncoder.h b/guest/vulkan_enc/VkEncoder.h
index d40042a..e21eea7 100644
--- a/guest/vulkan_enc/VkEncoder.h
+++ b/guest/vulkan_enc/VkEncoder.h
@@ -863,6 +863,11 @@
                                        VkDeviceSize counterBufferOffset, uint32_t counterOffset,
                                        uint32_t vertexStride, uint32_t doLock);
 #endif
+#ifdef VK_EXT_image_drm_format_modifier
+    VkResult vkGetImageDrmFormatModifierPropertiesEXT(
+        VkDevice device, VkImage image, VkImageDrmFormatModifierPropertiesEXT* pProperties,
+        uint32_t doLock);
+#endif
 #ifdef VK_EXT_tooling_info
     VkResult vkGetPhysicalDeviceToolPropertiesEXT(VkPhysicalDevice physicalDevice,
                                                   uint32_t* pToolCount,
diff --git a/guest/vulkan_enc/func_table.cpp b/guest/vulkan_enc/func_table.cpp
index c7f0004..c9dd53b 100644
--- a/guest/vulkan_enc/func_table.cpp
+++ b/guest/vulkan_enc/func_table.cpp
@@ -4045,6 +4045,21 @@
     return vkGetMemoryAndroidHardwareBufferANDROID_VkResult_return;
 }
 #endif
+#ifdef VK_EXT_image_drm_format_modifier
+VkResult gfxstream_vk_GetImageDrmFormatModifierPropertiesEXT(
+    VkDevice device, VkImage image, VkImageDrmFormatModifierPropertiesEXT* pProperties) {
+    MESA_TRACE_SCOPE("vkGetImageDrmFormatModifierPropertiesEXT");
+    VkResult vkGetImageDrmFormatModifierPropertiesEXT_VkResult_return = (VkResult)0;
+    VK_FROM_HANDLE(gfxstream_vk_device, gfxstream_device, device);
+    {
+        auto vkEnc = gfxstream::vk::ResourceTracker::getThreadLocalEncoder();
+        vkGetImageDrmFormatModifierPropertiesEXT_VkResult_return =
+            vkEnc->vkGetImageDrmFormatModifierPropertiesEXT(gfxstream_device->internal_object,
+                                                            image, pProperties, true /* do lock */);
+    }
+    return vkGetImageDrmFormatModifierPropertiesEXT_VkResult_return;
+}
+#endif
 #ifdef VK_EXT_tooling_info
 VkResult gfxstream_vk_GetPhysicalDeviceToolPropertiesEXT(
     VkPhysicalDevice physicalDevice, uint32_t* pToolCount,
diff --git a/guest/vulkan_enc/goldfish_vk_counting_guest.cpp b/guest/vulkan_enc/goldfish_vk_counting_guest.cpp
index 4731014..014d9ed 100644
--- a/guest/vulkan_enc/goldfish_vk_counting_guest.cpp
+++ b/guest/vulkan_enc/goldfish_vk_counting_guest.cpp
@@ -6364,6 +6364,166 @@
 }
 
 #endif
+#ifdef VK_EXT_image_drm_format_modifier
+void count_VkDrmFormatModifierPropertiesEXT(uint32_t featureBits, VkStructureType rootType,
+                                            const VkDrmFormatModifierPropertiesEXT* toCount,
+                                            size_t* count) {
+    (void)featureBits;
+    (void)rootType;
+    (void)toCount;
+    (void)count;
+    *count += sizeof(uint64_t);
+    *count += sizeof(uint32_t);
+    *count += sizeof(VkFormatFeatureFlags);
+}
+
+void count_VkDrmFormatModifierPropertiesListEXT(uint32_t featureBits, VkStructureType rootType,
+                                                const VkDrmFormatModifierPropertiesListEXT* toCount,
+                                                size_t* count) {
+    (void)featureBits;
+    (void)rootType;
+    (void)toCount;
+    (void)count;
+    *count += sizeof(VkStructureType);
+    if (rootType == VK_STRUCTURE_TYPE_MAX_ENUM) {
+        rootType = toCount->sType;
+    }
+    count_extension_struct(featureBits, rootType, toCount->pNext, count);
+    *count += sizeof(uint32_t);
+    // WARNING PTR CHECK
+    *count += 8;
+    if (toCount->pDrmFormatModifierProperties) {
+        if (toCount) {
+            for (uint32_t i = 0; i < (uint32_t)toCount->drmFormatModifierCount; ++i) {
+                count_VkDrmFormatModifierPropertiesEXT(
+                    featureBits, rootType,
+                    (VkDrmFormatModifierPropertiesEXT*)(toCount->pDrmFormatModifierProperties + i),
+                    count);
+            }
+        }
+    }
+}
+
+void count_VkPhysicalDeviceImageDrmFormatModifierInfoEXT(
+    uint32_t featureBits, VkStructureType rootType,
+    const VkPhysicalDeviceImageDrmFormatModifierInfoEXT* toCount, size_t* count) {
+    (void)featureBits;
+    (void)rootType;
+    (void)toCount;
+    (void)count;
+    *count += sizeof(VkStructureType);
+    if (rootType == VK_STRUCTURE_TYPE_MAX_ENUM) {
+        rootType = toCount->sType;
+    }
+    count_extension_struct(featureBits, rootType, toCount->pNext, count);
+    *count += sizeof(uint64_t);
+    *count += sizeof(VkSharingMode);
+    *count += sizeof(uint32_t);
+    // WARNING PTR CHECK
+    *count += 8;
+    if (toCount->pQueueFamilyIndices) {
+        if (toCount) {
+            *count += toCount->queueFamilyIndexCount * sizeof(const uint32_t);
+        }
+    }
+}
+
+void count_VkImageDrmFormatModifierListCreateInfoEXT(
+    uint32_t featureBits, VkStructureType rootType,
+    const VkImageDrmFormatModifierListCreateInfoEXT* toCount, size_t* count) {
+    (void)featureBits;
+    (void)rootType;
+    (void)toCount;
+    (void)count;
+    *count += sizeof(VkStructureType);
+    if (rootType == VK_STRUCTURE_TYPE_MAX_ENUM) {
+        rootType = toCount->sType;
+    }
+    count_extension_struct(featureBits, rootType, toCount->pNext, count);
+    *count += sizeof(uint32_t);
+    if (toCount) {
+        *count += toCount->drmFormatModifierCount * sizeof(const uint64_t);
+    }
+}
+
+void count_VkImageDrmFormatModifierExplicitCreateInfoEXT(
+    uint32_t featureBits, VkStructureType rootType,
+    const VkImageDrmFormatModifierExplicitCreateInfoEXT* toCount, size_t* count) {
+    (void)featureBits;
+    (void)rootType;
+    (void)toCount;
+    (void)count;
+    *count += sizeof(VkStructureType);
+    if (rootType == VK_STRUCTURE_TYPE_MAX_ENUM) {
+        rootType = toCount->sType;
+    }
+    count_extension_struct(featureBits, rootType, toCount->pNext, count);
+    *count += sizeof(uint64_t);
+    *count += sizeof(uint32_t);
+    if (toCount) {
+        for (uint32_t i = 0; i < (uint32_t)toCount->drmFormatModifierPlaneCount; ++i) {
+            count_VkSubresourceLayout(featureBits, rootType,
+                                      (const VkSubresourceLayout*)(toCount->pPlaneLayouts + i),
+                                      count);
+        }
+    }
+}
+
+void count_VkImageDrmFormatModifierPropertiesEXT(
+    uint32_t featureBits, VkStructureType rootType,
+    const VkImageDrmFormatModifierPropertiesEXT* toCount, size_t* count) {
+    (void)featureBits;
+    (void)rootType;
+    (void)toCount;
+    (void)count;
+    *count += sizeof(VkStructureType);
+    if (rootType == VK_STRUCTURE_TYPE_MAX_ENUM) {
+        rootType = toCount->sType;
+    }
+    count_extension_struct(featureBits, rootType, toCount->pNext, count);
+    *count += sizeof(uint64_t);
+}
+
+void count_VkDrmFormatModifierProperties2EXT(uint32_t featureBits, VkStructureType rootType,
+                                             const VkDrmFormatModifierProperties2EXT* toCount,
+                                             size_t* count) {
+    (void)featureBits;
+    (void)rootType;
+    (void)toCount;
+    (void)count;
+    *count += sizeof(uint64_t);
+    *count += sizeof(uint32_t);
+    *count += sizeof(VkFormatFeatureFlags2);
+}
+
+void count_VkDrmFormatModifierPropertiesList2EXT(
+    uint32_t featureBits, VkStructureType rootType,
+    const VkDrmFormatModifierPropertiesList2EXT* toCount, size_t* count) {
+    (void)featureBits;
+    (void)rootType;
+    (void)toCount;
+    (void)count;
+    *count += sizeof(VkStructureType);
+    if (rootType == VK_STRUCTURE_TYPE_MAX_ENUM) {
+        rootType = toCount->sType;
+    }
+    count_extension_struct(featureBits, rootType, toCount->pNext, count);
+    *count += sizeof(uint32_t);
+    // WARNING PTR CHECK
+    *count += 8;
+    if (toCount->pDrmFormatModifierProperties) {
+        if (toCount) {
+            for (uint32_t i = 0; i < (uint32_t)toCount->drmFormatModifierCount; ++i) {
+                count_VkDrmFormatModifierProperties2EXT(
+                    featureBits, rootType,
+                    (VkDrmFormatModifierProperties2EXT*)(toCount->pDrmFormatModifierProperties + i),
+                    count);
+            }
+        }
+    }
+}
+
+#endif
 #ifdef VK_EXT_vertex_attribute_divisor
 void count_VkPhysicalDeviceVertexAttributeDivisorPropertiesEXT(
     uint32_t featureBits, VkStructureType rootType,
@@ -8187,6 +8347,45 @@
             break;
         }
 #endif
+#ifdef VK_EXT_image_drm_format_modifier
+        case VK_STRUCTURE_TYPE_DRM_FORMAT_MODIFIER_PROPERTIES_LIST_EXT: {
+            count_VkDrmFormatModifierPropertiesListEXT(
+                featureBits, rootType,
+                reinterpret_cast<const VkDrmFormatModifierPropertiesListEXT*>(structExtension),
+                count);
+            break;
+        }
+        case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_DRM_FORMAT_MODIFIER_INFO_EXT: {
+            count_VkPhysicalDeviceImageDrmFormatModifierInfoEXT(
+                featureBits, rootType,
+                reinterpret_cast<const VkPhysicalDeviceImageDrmFormatModifierInfoEXT*>(
+                    structExtension),
+                count);
+            break;
+        }
+        case VK_STRUCTURE_TYPE_IMAGE_DRM_FORMAT_MODIFIER_LIST_CREATE_INFO_EXT: {
+            count_VkImageDrmFormatModifierListCreateInfoEXT(
+                featureBits, rootType,
+                reinterpret_cast<const VkImageDrmFormatModifierListCreateInfoEXT*>(structExtension),
+                count);
+            break;
+        }
+        case VK_STRUCTURE_TYPE_IMAGE_DRM_FORMAT_MODIFIER_EXPLICIT_CREATE_INFO_EXT: {
+            count_VkImageDrmFormatModifierExplicitCreateInfoEXT(
+                featureBits, rootType,
+                reinterpret_cast<const VkImageDrmFormatModifierExplicitCreateInfoEXT*>(
+                    structExtension),
+                count);
+            break;
+        }
+        case VK_STRUCTURE_TYPE_DRM_FORMAT_MODIFIER_PROPERTIES_LIST_2_EXT: {
+            count_VkDrmFormatModifierPropertiesList2EXT(
+                featureBits, rootType,
+                reinterpret_cast<const VkDrmFormatModifierPropertiesList2EXT*>(structExtension),
+                count);
+            break;
+        }
+#endif
 #ifdef VK_EXT_vertex_attribute_divisor
         case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VERTEX_ATTRIBUTE_DIVISOR_PROPERTIES_EXT: {
             count_VkPhysicalDeviceVertexAttributeDivisorPropertiesEXT(
diff --git a/guest/vulkan_enc/goldfish_vk_counting_guest.h b/guest/vulkan_enc/goldfish_vk_counting_guest.h
index 2573d47..d61169c 100644
--- a/guest/vulkan_enc/goldfish_vk_counting_guest.h
+++ b/guest/vulkan_enc/goldfish_vk_counting_guest.h
@@ -1512,6 +1512,40 @@
                       count_VkDescriptorPoolInlineUniformBlockCreateInfoEXT)
 
 #endif
+#ifdef VK_EXT_image_drm_format_modifier
+void count_VkDrmFormatModifierPropertiesEXT(uint32_t featureBits, VkStructureType rootType,
+                                            const VkDrmFormatModifierPropertiesEXT* toCount,
+                                            size_t* count);
+
+void count_VkDrmFormatModifierPropertiesListEXT(uint32_t featureBits, VkStructureType rootType,
+                                                const VkDrmFormatModifierPropertiesListEXT* toCount,
+                                                size_t* count);
+
+void count_VkPhysicalDeviceImageDrmFormatModifierInfoEXT(
+    uint32_t featureBits, VkStructureType rootType,
+    const VkPhysicalDeviceImageDrmFormatModifierInfoEXT* toCount, size_t* count);
+
+void count_VkImageDrmFormatModifierListCreateInfoEXT(
+    uint32_t featureBits, VkStructureType rootType,
+    const VkImageDrmFormatModifierListCreateInfoEXT* toCount, size_t* count);
+
+void count_VkImageDrmFormatModifierExplicitCreateInfoEXT(
+    uint32_t featureBits, VkStructureType rootType,
+    const VkImageDrmFormatModifierExplicitCreateInfoEXT* toCount, size_t* count);
+
+void count_VkImageDrmFormatModifierPropertiesEXT(
+    uint32_t featureBits, VkStructureType rootType,
+    const VkImageDrmFormatModifierPropertiesEXT* toCount, size_t* count);
+
+void count_VkDrmFormatModifierProperties2EXT(uint32_t featureBits, VkStructureType rootType,
+                                             const VkDrmFormatModifierProperties2EXT* toCount,
+                                             size_t* count);
+
+void count_VkDrmFormatModifierPropertiesList2EXT(
+    uint32_t featureBits, VkStructureType rootType,
+    const VkDrmFormatModifierPropertiesList2EXT* toCount, size_t* count);
+
+#endif
 #ifdef VK_EXT_vertex_attribute_divisor
 void count_VkPhysicalDeviceVertexAttributeDivisorPropertiesEXT(
     uint32_t featureBits, VkStructureType rootType,
diff --git a/guest/vulkan_enc/goldfish_vk_deepcopy_guest.cpp b/guest/vulkan_enc/goldfish_vk_deepcopy_guest.cpp
index 2cdab19..e82dea7 100644
--- a/guest/vulkan_enc/goldfish_vk_deepcopy_guest.cpp
+++ b/guest/vulkan_enc/goldfish_vk_deepcopy_guest.cpp
@@ -7363,6 +7363,207 @@
 }
 
 #endif
+#ifdef VK_EXT_image_drm_format_modifier
+void deepcopy_VkDrmFormatModifierPropertiesEXT(Allocator* alloc, VkStructureType rootType,
+                                               const VkDrmFormatModifierPropertiesEXT* from,
+                                               VkDrmFormatModifierPropertiesEXT* to) {
+    (void)alloc;
+    (void)rootType;
+    *to = *from;
+}
+
+void deepcopy_VkDrmFormatModifierPropertiesListEXT(Allocator* alloc, VkStructureType rootType,
+                                                   const VkDrmFormatModifierPropertiesListEXT* from,
+                                                   VkDrmFormatModifierPropertiesListEXT* to) {
+    (void)alloc;
+    (void)rootType;
+    *to = *from;
+    if (rootType == VK_STRUCTURE_TYPE_MAX_ENUM) {
+        rootType = from->sType;
+    }
+    const void* from_pNext = from;
+    size_t pNext_size = 0u;
+    while (!pNext_size && from_pNext) {
+        from_pNext = static_cast<const vk_struct_common*>(from_pNext)->pNext;
+        pNext_size = goldfish_vk_extension_struct_size(rootType, from_pNext);
+    }
+    to->pNext = nullptr;
+    if (pNext_size) {
+        to->pNext = (void*)alloc->alloc(pNext_size);
+        deepcopy_extension_struct(alloc, rootType, from_pNext, (void*)(to->pNext));
+    }
+    if (from) {
+        to->pDrmFormatModifierProperties = nullptr;
+        if (from->pDrmFormatModifierProperties) {
+            to->pDrmFormatModifierProperties = (VkDrmFormatModifierPropertiesEXT*)alloc->alloc(
+                from->drmFormatModifierCount * sizeof(VkDrmFormatModifierPropertiesEXT));
+            to->drmFormatModifierCount = from->drmFormatModifierCount;
+            for (uint32_t i = 0; i < (uint32_t)from->drmFormatModifierCount; ++i) {
+                deepcopy_VkDrmFormatModifierPropertiesEXT(
+                    alloc, rootType, from->pDrmFormatModifierProperties + i,
+                    (VkDrmFormatModifierPropertiesEXT*)(to->pDrmFormatModifierProperties + i));
+            }
+        }
+    }
+}
+
+void deepcopy_VkPhysicalDeviceImageDrmFormatModifierInfoEXT(
+    Allocator* alloc, VkStructureType rootType,
+    const VkPhysicalDeviceImageDrmFormatModifierInfoEXT* from,
+    VkPhysicalDeviceImageDrmFormatModifierInfoEXT* to) {
+    (void)alloc;
+    (void)rootType;
+    *to = *from;
+    if (rootType == VK_STRUCTURE_TYPE_MAX_ENUM) {
+        rootType = from->sType;
+    }
+    const void* from_pNext = from;
+    size_t pNext_size = 0u;
+    while (!pNext_size && from_pNext) {
+        from_pNext = static_cast<const vk_struct_common*>(from_pNext)->pNext;
+        pNext_size = goldfish_vk_extension_struct_size(rootType, from_pNext);
+    }
+    to->pNext = nullptr;
+    if (pNext_size) {
+        to->pNext = (void*)alloc->alloc(pNext_size);
+        deepcopy_extension_struct(alloc, rootType, from_pNext, (void*)(to->pNext));
+    }
+    to->pQueueFamilyIndices = nullptr;
+    if (from->pQueueFamilyIndices) {
+        to->pQueueFamilyIndices = (uint32_t*)alloc->dupArray(
+            from->pQueueFamilyIndices, from->queueFamilyIndexCount * sizeof(const uint32_t));
+    }
+}
+
+void deepcopy_VkImageDrmFormatModifierListCreateInfoEXT(
+    Allocator* alloc, VkStructureType rootType,
+    const VkImageDrmFormatModifierListCreateInfoEXT* from,
+    VkImageDrmFormatModifierListCreateInfoEXT* to) {
+    (void)alloc;
+    (void)rootType;
+    *to = *from;
+    if (rootType == VK_STRUCTURE_TYPE_MAX_ENUM) {
+        rootType = from->sType;
+    }
+    const void* from_pNext = from;
+    size_t pNext_size = 0u;
+    while (!pNext_size && from_pNext) {
+        from_pNext = static_cast<const vk_struct_common*>(from_pNext)->pNext;
+        pNext_size = goldfish_vk_extension_struct_size(rootType, from_pNext);
+    }
+    to->pNext = nullptr;
+    if (pNext_size) {
+        to->pNext = (void*)alloc->alloc(pNext_size);
+        deepcopy_extension_struct(alloc, rootType, from_pNext, (void*)(to->pNext));
+    }
+    to->pDrmFormatModifiers = nullptr;
+    if (from->pDrmFormatModifiers) {
+        to->pDrmFormatModifiers = (uint64_t*)alloc->dupArray(
+            from->pDrmFormatModifiers, from->drmFormatModifierCount * sizeof(const uint64_t));
+    }
+}
+
+void deepcopy_VkImageDrmFormatModifierExplicitCreateInfoEXT(
+    Allocator* alloc, VkStructureType rootType,
+    const VkImageDrmFormatModifierExplicitCreateInfoEXT* from,
+    VkImageDrmFormatModifierExplicitCreateInfoEXT* to) {
+    (void)alloc;
+    (void)rootType;
+    *to = *from;
+    if (rootType == VK_STRUCTURE_TYPE_MAX_ENUM) {
+        rootType = from->sType;
+    }
+    const void* from_pNext = from;
+    size_t pNext_size = 0u;
+    while (!pNext_size && from_pNext) {
+        from_pNext = static_cast<const vk_struct_common*>(from_pNext)->pNext;
+        pNext_size = goldfish_vk_extension_struct_size(rootType, from_pNext);
+    }
+    to->pNext = nullptr;
+    if (pNext_size) {
+        to->pNext = (void*)alloc->alloc(pNext_size);
+        deepcopy_extension_struct(alloc, rootType, from_pNext, (void*)(to->pNext));
+    }
+    if (from) {
+        to->pPlaneLayouts = nullptr;
+        if (from->pPlaneLayouts) {
+            to->pPlaneLayouts = (VkSubresourceLayout*)alloc->alloc(
+                from->drmFormatModifierPlaneCount * sizeof(const VkSubresourceLayout));
+            to->drmFormatModifierPlaneCount = from->drmFormatModifierPlaneCount;
+            for (uint32_t i = 0; i < (uint32_t)from->drmFormatModifierPlaneCount; ++i) {
+                deepcopy_VkSubresourceLayout(alloc, rootType, from->pPlaneLayouts + i,
+                                             (VkSubresourceLayout*)(to->pPlaneLayouts + i));
+            }
+        }
+    }
+}
+
+void deepcopy_VkImageDrmFormatModifierPropertiesEXT(
+    Allocator* alloc, VkStructureType rootType, const VkImageDrmFormatModifierPropertiesEXT* from,
+    VkImageDrmFormatModifierPropertiesEXT* to) {
+    (void)alloc;
+    (void)rootType;
+    *to = *from;
+    if (rootType == VK_STRUCTURE_TYPE_MAX_ENUM) {
+        rootType = from->sType;
+    }
+    const void* from_pNext = from;
+    size_t pNext_size = 0u;
+    while (!pNext_size && from_pNext) {
+        from_pNext = static_cast<const vk_struct_common*>(from_pNext)->pNext;
+        pNext_size = goldfish_vk_extension_struct_size(rootType, from_pNext);
+    }
+    to->pNext = nullptr;
+    if (pNext_size) {
+        to->pNext = (void*)alloc->alloc(pNext_size);
+        deepcopy_extension_struct(alloc, rootType, from_pNext, (void*)(to->pNext));
+    }
+}
+
+void deepcopy_VkDrmFormatModifierProperties2EXT(Allocator* alloc, VkStructureType rootType,
+                                                const VkDrmFormatModifierProperties2EXT* from,
+                                                VkDrmFormatModifierProperties2EXT* to) {
+    (void)alloc;
+    (void)rootType;
+    *to = *from;
+}
+
+void deepcopy_VkDrmFormatModifierPropertiesList2EXT(
+    Allocator* alloc, VkStructureType rootType, const VkDrmFormatModifierPropertiesList2EXT* from,
+    VkDrmFormatModifierPropertiesList2EXT* to) {
+    (void)alloc;
+    (void)rootType;
+    *to = *from;
+    if (rootType == VK_STRUCTURE_TYPE_MAX_ENUM) {
+        rootType = from->sType;
+    }
+    const void* from_pNext = from;
+    size_t pNext_size = 0u;
+    while (!pNext_size && from_pNext) {
+        from_pNext = static_cast<const vk_struct_common*>(from_pNext)->pNext;
+        pNext_size = goldfish_vk_extension_struct_size(rootType, from_pNext);
+    }
+    to->pNext = nullptr;
+    if (pNext_size) {
+        to->pNext = (void*)alloc->alloc(pNext_size);
+        deepcopy_extension_struct(alloc, rootType, from_pNext, (void*)(to->pNext));
+    }
+    if (from) {
+        to->pDrmFormatModifierProperties = nullptr;
+        if (from->pDrmFormatModifierProperties) {
+            to->pDrmFormatModifierProperties = (VkDrmFormatModifierProperties2EXT*)alloc->alloc(
+                from->drmFormatModifierCount * sizeof(VkDrmFormatModifierProperties2EXT));
+            to->drmFormatModifierCount = from->drmFormatModifierCount;
+            for (uint32_t i = 0; i < (uint32_t)from->drmFormatModifierCount; ++i) {
+                deepcopy_VkDrmFormatModifierProperties2EXT(
+                    alloc, rootType, from->pDrmFormatModifierProperties + i,
+                    (VkDrmFormatModifierProperties2EXT*)(to->pDrmFormatModifierProperties + i));
+            }
+        }
+    }
+}
+
+#endif
 #ifdef VK_EXT_vertex_attribute_divisor
 void deepcopy_VkPhysicalDeviceVertexAttributeDivisorPropertiesEXT(
     Allocator* alloc, VkStructureType rootType,
@@ -9589,6 +9790,47 @@
             break;
         }
 #endif
+#ifdef VK_EXT_image_drm_format_modifier
+        case VK_STRUCTURE_TYPE_DRM_FORMAT_MODIFIER_PROPERTIES_LIST_EXT: {
+            deepcopy_VkDrmFormatModifierPropertiesListEXT(
+                alloc, rootType,
+                reinterpret_cast<const VkDrmFormatModifierPropertiesListEXT*>(structExtension),
+                reinterpret_cast<VkDrmFormatModifierPropertiesListEXT*>(structExtension_out));
+            break;
+        }
+        case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_DRM_FORMAT_MODIFIER_INFO_EXT: {
+            deepcopy_VkPhysicalDeviceImageDrmFormatModifierInfoEXT(
+                alloc, rootType,
+                reinterpret_cast<const VkPhysicalDeviceImageDrmFormatModifierInfoEXT*>(
+                    structExtension),
+                reinterpret_cast<VkPhysicalDeviceImageDrmFormatModifierInfoEXT*>(
+                    structExtension_out));
+            break;
+        }
+        case VK_STRUCTURE_TYPE_IMAGE_DRM_FORMAT_MODIFIER_LIST_CREATE_INFO_EXT: {
+            deepcopy_VkImageDrmFormatModifierListCreateInfoEXT(
+                alloc, rootType,
+                reinterpret_cast<const VkImageDrmFormatModifierListCreateInfoEXT*>(structExtension),
+                reinterpret_cast<VkImageDrmFormatModifierListCreateInfoEXT*>(structExtension_out));
+            break;
+        }
+        case VK_STRUCTURE_TYPE_IMAGE_DRM_FORMAT_MODIFIER_EXPLICIT_CREATE_INFO_EXT: {
+            deepcopy_VkImageDrmFormatModifierExplicitCreateInfoEXT(
+                alloc, rootType,
+                reinterpret_cast<const VkImageDrmFormatModifierExplicitCreateInfoEXT*>(
+                    structExtension),
+                reinterpret_cast<VkImageDrmFormatModifierExplicitCreateInfoEXT*>(
+                    structExtension_out));
+            break;
+        }
+        case VK_STRUCTURE_TYPE_DRM_FORMAT_MODIFIER_PROPERTIES_LIST_2_EXT: {
+            deepcopy_VkDrmFormatModifierPropertiesList2EXT(
+                alloc, rootType,
+                reinterpret_cast<const VkDrmFormatModifierPropertiesList2EXT*>(structExtension),
+                reinterpret_cast<VkDrmFormatModifierPropertiesList2EXT*>(structExtension_out));
+            break;
+        }
+#endif
 #ifdef VK_EXT_vertex_attribute_divisor
         case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VERTEX_ATTRIBUTE_DIVISOR_PROPERTIES_EXT: {
             deepcopy_VkPhysicalDeviceVertexAttributeDivisorPropertiesEXT(
diff --git a/guest/vulkan_enc/goldfish_vk_deepcopy_guest.h b/guest/vulkan_enc/goldfish_vk_deepcopy_guest.h
index 98f1696..b4f906f 100644
--- a/guest/vulkan_enc/goldfish_vk_deepcopy_guest.h
+++ b/guest/vulkan_enc/goldfish_vk_deepcopy_guest.h
@@ -1655,6 +1655,43 @@
                       deepcopy_VkDescriptorPoolInlineUniformBlockCreateInfoEXT)
 
 #endif
+#ifdef VK_EXT_image_drm_format_modifier
+void deepcopy_VkDrmFormatModifierPropertiesEXT(Allocator* alloc, VkStructureType rootType,
+                                               const VkDrmFormatModifierPropertiesEXT* from,
+                                               VkDrmFormatModifierPropertiesEXT* to);
+
+void deepcopy_VkDrmFormatModifierPropertiesListEXT(Allocator* alloc, VkStructureType rootType,
+                                                   const VkDrmFormatModifierPropertiesListEXT* from,
+                                                   VkDrmFormatModifierPropertiesListEXT* to);
+
+void deepcopy_VkPhysicalDeviceImageDrmFormatModifierInfoEXT(
+    Allocator* alloc, VkStructureType rootType,
+    const VkPhysicalDeviceImageDrmFormatModifierInfoEXT* from,
+    VkPhysicalDeviceImageDrmFormatModifierInfoEXT* to);
+
+void deepcopy_VkImageDrmFormatModifierListCreateInfoEXT(
+    Allocator* alloc, VkStructureType rootType,
+    const VkImageDrmFormatModifierListCreateInfoEXT* from,
+    VkImageDrmFormatModifierListCreateInfoEXT* to);
+
+void deepcopy_VkImageDrmFormatModifierExplicitCreateInfoEXT(
+    Allocator* alloc, VkStructureType rootType,
+    const VkImageDrmFormatModifierExplicitCreateInfoEXT* from,
+    VkImageDrmFormatModifierExplicitCreateInfoEXT* to);
+
+void deepcopy_VkImageDrmFormatModifierPropertiesEXT(
+    Allocator* alloc, VkStructureType rootType, const VkImageDrmFormatModifierPropertiesEXT* from,
+    VkImageDrmFormatModifierPropertiesEXT* to);
+
+void deepcopy_VkDrmFormatModifierProperties2EXT(Allocator* alloc, VkStructureType rootType,
+                                                const VkDrmFormatModifierProperties2EXT* from,
+                                                VkDrmFormatModifierProperties2EXT* to);
+
+void deepcopy_VkDrmFormatModifierPropertiesList2EXT(
+    Allocator* alloc, VkStructureType rootType, const VkDrmFormatModifierPropertiesList2EXT* from,
+    VkDrmFormatModifierPropertiesList2EXT* to);
+
+#endif
 #ifdef VK_EXT_vertex_attribute_divisor
 void deepcopy_VkPhysicalDeviceVertexAttributeDivisorPropertiesEXT(
     Allocator* alloc, VkStructureType rootType,
diff --git a/guest/vulkan_enc/goldfish_vk_extension_structs_guest.cpp b/guest/vulkan_enc/goldfish_vk_extension_structs_guest.cpp
index 27a7c47..448c2dd 100644
--- a/guest/vulkan_enc/goldfish_vk_extension_structs_guest.cpp
+++ b/guest/vulkan_enc/goldfish_vk_extension_structs_guest.cpp
@@ -441,6 +441,23 @@
             return sizeof(VkPipelineRasterizationDepthClipStateCreateInfoEXT);
         }
 #endif
+#ifdef VK_EXT_image_drm_format_modifier
+        case VK_STRUCTURE_TYPE_DRM_FORMAT_MODIFIER_PROPERTIES_LIST_EXT: {
+            return sizeof(VkDrmFormatModifierPropertiesListEXT);
+        }
+        case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_DRM_FORMAT_MODIFIER_INFO_EXT: {
+            return sizeof(VkPhysicalDeviceImageDrmFormatModifierInfoEXT);
+        }
+        case VK_STRUCTURE_TYPE_IMAGE_DRM_FORMAT_MODIFIER_LIST_CREATE_INFO_EXT: {
+            return sizeof(VkImageDrmFormatModifierListCreateInfoEXT);
+        }
+        case VK_STRUCTURE_TYPE_IMAGE_DRM_FORMAT_MODIFIER_EXPLICIT_CREATE_INFO_EXT: {
+            return sizeof(VkImageDrmFormatModifierExplicitCreateInfoEXT);
+        }
+        case VK_STRUCTURE_TYPE_DRM_FORMAT_MODIFIER_PROPERTIES_LIST_2_EXT: {
+            return sizeof(VkDrmFormatModifierPropertiesList2EXT);
+        }
+#endif
 #ifdef VK_EXT_vertex_attribute_divisor
         case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VERTEX_ATTRIBUTE_DIVISOR_PROPERTIES_EXT: {
             return sizeof(VkPhysicalDeviceVertexAttributeDivisorPropertiesEXT);
@@ -1068,6 +1085,23 @@
             return sizeof(VkPipelineRasterizationDepthClipStateCreateInfoEXT);
         }
 #endif
+#ifdef VK_EXT_image_drm_format_modifier
+        case VK_STRUCTURE_TYPE_DRM_FORMAT_MODIFIER_PROPERTIES_LIST_EXT: {
+            return sizeof(VkDrmFormatModifierPropertiesListEXT);
+        }
+        case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_DRM_FORMAT_MODIFIER_INFO_EXT: {
+            return sizeof(VkPhysicalDeviceImageDrmFormatModifierInfoEXT);
+        }
+        case VK_STRUCTURE_TYPE_IMAGE_DRM_FORMAT_MODIFIER_LIST_CREATE_INFO_EXT: {
+            return sizeof(VkImageDrmFormatModifierListCreateInfoEXT);
+        }
+        case VK_STRUCTURE_TYPE_IMAGE_DRM_FORMAT_MODIFIER_EXPLICIT_CREATE_INFO_EXT: {
+            return sizeof(VkImageDrmFormatModifierExplicitCreateInfoEXT);
+        }
+        case VK_STRUCTURE_TYPE_DRM_FORMAT_MODIFIER_PROPERTIES_LIST_2_EXT: {
+            return sizeof(VkDrmFormatModifierPropertiesList2EXT);
+        }
+#endif
 #ifdef VK_EXT_vertex_attribute_divisor
         case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VERTEX_ATTRIBUTE_DIVISOR_PROPERTIES_EXT: {
             return sizeof(VkPhysicalDeviceVertexAttributeDivisorPropertiesEXT);
diff --git a/guest/vulkan_enc/goldfish_vk_marshaling_guest.cpp b/guest/vulkan_enc/goldfish_vk_marshaling_guest.cpp
index 43f1037..8d595bb 100644
--- a/guest/vulkan_enc/goldfish_vk_marshaling_guest.cpp
+++ b/guest/vulkan_enc/goldfish_vk_marshaling_guest.cpp
@@ -11982,6 +11982,301 @@
 }
 
 #endif
+#ifdef VK_EXT_image_drm_format_modifier
+void marshal_VkDrmFormatModifierPropertiesEXT(
+    VulkanStreamGuest* vkStream, VkStructureType rootType,
+    const VkDrmFormatModifierPropertiesEXT* forMarshaling) {
+    (void)rootType;
+    vkStream->write((uint64_t*)&forMarshaling->drmFormatModifier, sizeof(uint64_t));
+    vkStream->write((uint32_t*)&forMarshaling->drmFormatModifierPlaneCount, sizeof(uint32_t));
+    vkStream->write((VkFormatFeatureFlags*)&forMarshaling->drmFormatModifierTilingFeatures,
+                    sizeof(VkFormatFeatureFlags));
+}
+
+void unmarshal_VkDrmFormatModifierPropertiesEXT(VulkanStreamGuest* vkStream,
+                                                VkStructureType rootType,
+                                                VkDrmFormatModifierPropertiesEXT* forUnmarshaling) {
+    (void)rootType;
+    vkStream->read((uint64_t*)&forUnmarshaling->drmFormatModifier, sizeof(uint64_t));
+    vkStream->read((uint32_t*)&forUnmarshaling->drmFormatModifierPlaneCount, sizeof(uint32_t));
+    vkStream->read((VkFormatFeatureFlags*)&forUnmarshaling->drmFormatModifierTilingFeatures,
+                   sizeof(VkFormatFeatureFlags));
+}
+
+void marshal_VkDrmFormatModifierPropertiesListEXT(
+    VulkanStreamGuest* vkStream, VkStructureType rootType,
+    const VkDrmFormatModifierPropertiesListEXT* forMarshaling) {
+    (void)rootType;
+    vkStream->write((VkStructureType*)&forMarshaling->sType, sizeof(VkStructureType));
+    if (rootType == VK_STRUCTURE_TYPE_MAX_ENUM) {
+        rootType = forMarshaling->sType;
+    }
+    marshal_extension_struct(vkStream, rootType, forMarshaling->pNext);
+    vkStream->write((uint32_t*)&forMarshaling->drmFormatModifierCount, sizeof(uint32_t));
+    // WARNING PTR CHECK
+    uint64_t cgen_var_0 = (uint64_t)(uintptr_t)forMarshaling->pDrmFormatModifierProperties;
+    vkStream->putBe64(cgen_var_0);
+    if (forMarshaling->pDrmFormatModifierProperties) {
+        if (forMarshaling) {
+            for (uint32_t i = 0; i < (uint32_t)forMarshaling->drmFormatModifierCount; ++i) {
+                marshal_VkDrmFormatModifierPropertiesEXT(
+                    vkStream, rootType,
+                    (VkDrmFormatModifierPropertiesEXT*)(forMarshaling
+                                                            ->pDrmFormatModifierProperties +
+                                                        i));
+            }
+        }
+    }
+}
+
+void unmarshal_VkDrmFormatModifierPropertiesListEXT(
+    VulkanStreamGuest* vkStream, VkStructureType rootType,
+    VkDrmFormatModifierPropertiesListEXT* forUnmarshaling) {
+    (void)rootType;
+    vkStream->read((VkStructureType*)&forUnmarshaling->sType, sizeof(VkStructureType));
+    if (rootType == VK_STRUCTURE_TYPE_MAX_ENUM) {
+        rootType = forUnmarshaling->sType;
+    }
+    unmarshal_extension_struct(vkStream, rootType, (void*)(forUnmarshaling->pNext));
+    vkStream->read((uint32_t*)&forUnmarshaling->drmFormatModifierCount, sizeof(uint32_t));
+    // WARNING PTR CHECK
+    VkDrmFormatModifierPropertiesEXT* check_pDrmFormatModifierProperties;
+    check_pDrmFormatModifierProperties =
+        (VkDrmFormatModifierPropertiesEXT*)(uintptr_t)vkStream->getBe64();
+    if (forUnmarshaling->pDrmFormatModifierProperties) {
+        if (!(check_pDrmFormatModifierProperties)) {
+            fprintf(stderr,
+                    "fatal: forUnmarshaling->pDrmFormatModifierProperties inconsistent between "
+                    "guest and host\n");
+        }
+        if (forUnmarshaling) {
+            for (uint32_t i = 0; i < (uint32_t)forUnmarshaling->drmFormatModifierCount; ++i) {
+                unmarshal_VkDrmFormatModifierPropertiesEXT(
+                    vkStream, rootType,
+                    (VkDrmFormatModifierPropertiesEXT*)(forUnmarshaling
+                                                            ->pDrmFormatModifierProperties +
+                                                        i));
+            }
+        }
+    }
+}
+
+void marshal_VkPhysicalDeviceImageDrmFormatModifierInfoEXT(
+    VulkanStreamGuest* vkStream, VkStructureType rootType,
+    const VkPhysicalDeviceImageDrmFormatModifierInfoEXT* forMarshaling) {
+    (void)rootType;
+    vkStream->write((VkStructureType*)&forMarshaling->sType, sizeof(VkStructureType));
+    if (rootType == VK_STRUCTURE_TYPE_MAX_ENUM) {
+        rootType = forMarshaling->sType;
+    }
+    marshal_extension_struct(vkStream, rootType, forMarshaling->pNext);
+    vkStream->write((uint64_t*)&forMarshaling->drmFormatModifier, sizeof(uint64_t));
+    vkStream->write((VkSharingMode*)&forMarshaling->sharingMode, sizeof(VkSharingMode));
+    vkStream->write((uint32_t*)&forMarshaling->queueFamilyIndexCount, sizeof(uint32_t));
+    // WARNING PTR CHECK
+    uint64_t cgen_var_0 = (uint64_t)(uintptr_t)forMarshaling->pQueueFamilyIndices;
+    vkStream->putBe64(cgen_var_0);
+    if (forMarshaling->pQueueFamilyIndices) {
+        vkStream->write((const uint32_t*)forMarshaling->pQueueFamilyIndices,
+                        forMarshaling->queueFamilyIndexCount * sizeof(const uint32_t));
+    }
+}
+
+void unmarshal_VkPhysicalDeviceImageDrmFormatModifierInfoEXT(
+    VulkanStreamGuest* vkStream, VkStructureType rootType,
+    VkPhysicalDeviceImageDrmFormatModifierInfoEXT* forUnmarshaling) {
+    (void)rootType;
+    vkStream->read((VkStructureType*)&forUnmarshaling->sType, sizeof(VkStructureType));
+    if (rootType == VK_STRUCTURE_TYPE_MAX_ENUM) {
+        rootType = forUnmarshaling->sType;
+    }
+    unmarshal_extension_struct(vkStream, rootType, (void*)(forUnmarshaling->pNext));
+    vkStream->read((uint64_t*)&forUnmarshaling->drmFormatModifier, sizeof(uint64_t));
+    vkStream->read((VkSharingMode*)&forUnmarshaling->sharingMode, sizeof(VkSharingMode));
+    vkStream->read((uint32_t*)&forUnmarshaling->queueFamilyIndexCount, sizeof(uint32_t));
+    // WARNING PTR CHECK
+    const uint32_t* check_pQueueFamilyIndices;
+    check_pQueueFamilyIndices = (const uint32_t*)(uintptr_t)vkStream->getBe64();
+    if (forUnmarshaling->pQueueFamilyIndices) {
+        if (!(check_pQueueFamilyIndices)) {
+            fprintf(stderr,
+                    "fatal: forUnmarshaling->pQueueFamilyIndices inconsistent between guest and "
+                    "host\n");
+        }
+        vkStream->read((uint32_t*)forUnmarshaling->pQueueFamilyIndices,
+                       forUnmarshaling->queueFamilyIndexCount * sizeof(const uint32_t));
+    }
+}
+
+void marshal_VkImageDrmFormatModifierListCreateInfoEXT(
+    VulkanStreamGuest* vkStream, VkStructureType rootType,
+    const VkImageDrmFormatModifierListCreateInfoEXT* forMarshaling) {
+    (void)rootType;
+    vkStream->write((VkStructureType*)&forMarshaling->sType, sizeof(VkStructureType));
+    if (rootType == VK_STRUCTURE_TYPE_MAX_ENUM) {
+        rootType = forMarshaling->sType;
+    }
+    marshal_extension_struct(vkStream, rootType, forMarshaling->pNext);
+    vkStream->write((uint32_t*)&forMarshaling->drmFormatModifierCount, sizeof(uint32_t));
+    vkStream->write((const uint64_t*)forMarshaling->pDrmFormatModifiers,
+                    forMarshaling->drmFormatModifierCount * sizeof(const uint64_t));
+}
+
+void unmarshal_VkImageDrmFormatModifierListCreateInfoEXT(
+    VulkanStreamGuest* vkStream, VkStructureType rootType,
+    VkImageDrmFormatModifierListCreateInfoEXT* forUnmarshaling) {
+    (void)rootType;
+    vkStream->read((VkStructureType*)&forUnmarshaling->sType, sizeof(VkStructureType));
+    if (rootType == VK_STRUCTURE_TYPE_MAX_ENUM) {
+        rootType = forUnmarshaling->sType;
+    }
+    unmarshal_extension_struct(vkStream, rootType, (void*)(forUnmarshaling->pNext));
+    vkStream->read((uint32_t*)&forUnmarshaling->drmFormatModifierCount, sizeof(uint32_t));
+    vkStream->read((uint64_t*)forUnmarshaling->pDrmFormatModifiers,
+                   forUnmarshaling->drmFormatModifierCount * sizeof(const uint64_t));
+}
+
+void marshal_VkImageDrmFormatModifierExplicitCreateInfoEXT(
+    VulkanStreamGuest* vkStream, VkStructureType rootType,
+    const VkImageDrmFormatModifierExplicitCreateInfoEXT* forMarshaling) {
+    (void)rootType;
+    vkStream->write((VkStructureType*)&forMarshaling->sType, sizeof(VkStructureType));
+    if (rootType == VK_STRUCTURE_TYPE_MAX_ENUM) {
+        rootType = forMarshaling->sType;
+    }
+    marshal_extension_struct(vkStream, rootType, forMarshaling->pNext);
+    vkStream->write((uint64_t*)&forMarshaling->drmFormatModifier, sizeof(uint64_t));
+    vkStream->write((uint32_t*)&forMarshaling->drmFormatModifierPlaneCount, sizeof(uint32_t));
+    if (forMarshaling) {
+        for (uint32_t i = 0; i < (uint32_t)forMarshaling->drmFormatModifierPlaneCount; ++i) {
+            marshal_VkSubresourceLayout(
+                vkStream, rootType, (const VkSubresourceLayout*)(forMarshaling->pPlaneLayouts + i));
+        }
+    }
+}
+
+void unmarshal_VkImageDrmFormatModifierExplicitCreateInfoEXT(
+    VulkanStreamGuest* vkStream, VkStructureType rootType,
+    VkImageDrmFormatModifierExplicitCreateInfoEXT* forUnmarshaling) {
+    (void)rootType;
+    vkStream->read((VkStructureType*)&forUnmarshaling->sType, sizeof(VkStructureType));
+    if (rootType == VK_STRUCTURE_TYPE_MAX_ENUM) {
+        rootType = forUnmarshaling->sType;
+    }
+    unmarshal_extension_struct(vkStream, rootType, (void*)(forUnmarshaling->pNext));
+    vkStream->read((uint64_t*)&forUnmarshaling->drmFormatModifier, sizeof(uint64_t));
+    vkStream->read((uint32_t*)&forUnmarshaling->drmFormatModifierPlaneCount, sizeof(uint32_t));
+    if (forUnmarshaling) {
+        for (uint32_t i = 0; i < (uint32_t)forUnmarshaling->drmFormatModifierPlaneCount; ++i) {
+            unmarshal_VkSubresourceLayout(
+                vkStream, rootType, (VkSubresourceLayout*)(forUnmarshaling->pPlaneLayouts + i));
+        }
+    }
+}
+
+void marshal_VkImageDrmFormatModifierPropertiesEXT(
+    VulkanStreamGuest* vkStream, VkStructureType rootType,
+    const VkImageDrmFormatModifierPropertiesEXT* forMarshaling) {
+    (void)rootType;
+    vkStream->write((VkStructureType*)&forMarshaling->sType, sizeof(VkStructureType));
+    if (rootType == VK_STRUCTURE_TYPE_MAX_ENUM) {
+        rootType = forMarshaling->sType;
+    }
+    marshal_extension_struct(vkStream, rootType, forMarshaling->pNext);
+    vkStream->write((uint64_t*)&forMarshaling->drmFormatModifier, sizeof(uint64_t));
+}
+
+void unmarshal_VkImageDrmFormatModifierPropertiesEXT(
+    VulkanStreamGuest* vkStream, VkStructureType rootType,
+    VkImageDrmFormatModifierPropertiesEXT* forUnmarshaling) {
+    (void)rootType;
+    vkStream->read((VkStructureType*)&forUnmarshaling->sType, sizeof(VkStructureType));
+    if (rootType == VK_STRUCTURE_TYPE_MAX_ENUM) {
+        rootType = forUnmarshaling->sType;
+    }
+    unmarshal_extension_struct(vkStream, rootType, (void*)(forUnmarshaling->pNext));
+    vkStream->read((uint64_t*)&forUnmarshaling->drmFormatModifier, sizeof(uint64_t));
+}
+
+void marshal_VkDrmFormatModifierProperties2EXT(
+    VulkanStreamGuest* vkStream, VkStructureType rootType,
+    const VkDrmFormatModifierProperties2EXT* forMarshaling) {
+    (void)rootType;
+    vkStream->write((uint64_t*)&forMarshaling->drmFormatModifier, sizeof(uint64_t));
+    vkStream->write((uint32_t*)&forMarshaling->drmFormatModifierPlaneCount, sizeof(uint32_t));
+    vkStream->write((VkFormatFeatureFlags2*)&forMarshaling->drmFormatModifierTilingFeatures,
+                    sizeof(VkFormatFeatureFlags2));
+}
+
+void unmarshal_VkDrmFormatModifierProperties2EXT(
+    VulkanStreamGuest* vkStream, VkStructureType rootType,
+    VkDrmFormatModifierProperties2EXT* forUnmarshaling) {
+    (void)rootType;
+    vkStream->read((uint64_t*)&forUnmarshaling->drmFormatModifier, sizeof(uint64_t));
+    vkStream->read((uint32_t*)&forUnmarshaling->drmFormatModifierPlaneCount, sizeof(uint32_t));
+    vkStream->read((VkFormatFeatureFlags2*)&forUnmarshaling->drmFormatModifierTilingFeatures,
+                   sizeof(VkFormatFeatureFlags2));
+}
+
+void marshal_VkDrmFormatModifierPropertiesList2EXT(
+    VulkanStreamGuest* vkStream, VkStructureType rootType,
+    const VkDrmFormatModifierPropertiesList2EXT* forMarshaling) {
+    (void)rootType;
+    vkStream->write((VkStructureType*)&forMarshaling->sType, sizeof(VkStructureType));
+    if (rootType == VK_STRUCTURE_TYPE_MAX_ENUM) {
+        rootType = forMarshaling->sType;
+    }
+    marshal_extension_struct(vkStream, rootType, forMarshaling->pNext);
+    vkStream->write((uint32_t*)&forMarshaling->drmFormatModifierCount, sizeof(uint32_t));
+    // WARNING PTR CHECK
+    uint64_t cgen_var_0 = (uint64_t)(uintptr_t)forMarshaling->pDrmFormatModifierProperties;
+    vkStream->putBe64(cgen_var_0);
+    if (forMarshaling->pDrmFormatModifierProperties) {
+        if (forMarshaling) {
+            for (uint32_t i = 0; i < (uint32_t)forMarshaling->drmFormatModifierCount; ++i) {
+                marshal_VkDrmFormatModifierProperties2EXT(
+                    vkStream, rootType,
+                    (VkDrmFormatModifierProperties2EXT*)(forMarshaling
+                                                             ->pDrmFormatModifierProperties +
+                                                         i));
+            }
+        }
+    }
+}
+
+void unmarshal_VkDrmFormatModifierPropertiesList2EXT(
+    VulkanStreamGuest* vkStream, VkStructureType rootType,
+    VkDrmFormatModifierPropertiesList2EXT* forUnmarshaling) {
+    (void)rootType;
+    vkStream->read((VkStructureType*)&forUnmarshaling->sType, sizeof(VkStructureType));
+    if (rootType == VK_STRUCTURE_TYPE_MAX_ENUM) {
+        rootType = forUnmarshaling->sType;
+    }
+    unmarshal_extension_struct(vkStream, rootType, (void*)(forUnmarshaling->pNext));
+    vkStream->read((uint32_t*)&forUnmarshaling->drmFormatModifierCount, sizeof(uint32_t));
+    // WARNING PTR CHECK
+    VkDrmFormatModifierProperties2EXT* check_pDrmFormatModifierProperties;
+    check_pDrmFormatModifierProperties =
+        (VkDrmFormatModifierProperties2EXT*)(uintptr_t)vkStream->getBe64();
+    if (forUnmarshaling->pDrmFormatModifierProperties) {
+        if (!(check_pDrmFormatModifierProperties)) {
+            fprintf(stderr,
+                    "fatal: forUnmarshaling->pDrmFormatModifierProperties inconsistent between "
+                    "guest and host\n");
+        }
+        if (forUnmarshaling) {
+            for (uint32_t i = 0; i < (uint32_t)forUnmarshaling->drmFormatModifierCount; ++i) {
+                unmarshal_VkDrmFormatModifierProperties2EXT(
+                    vkStream, rootType,
+                    (VkDrmFormatModifierProperties2EXT*)(forUnmarshaling
+                                                             ->pDrmFormatModifierProperties +
+                                                         i));
+            }
+        }
+    }
+}
+
+#endif
 #ifdef VK_EXT_vertex_attribute_divisor
 void marshal_VkPhysicalDeviceVertexAttributeDivisorPropertiesEXT(
     VulkanStreamGuest* vkStream, VkStructureType rootType,
@@ -14374,6 +14669,41 @@
             break;
         }
 #endif
+#ifdef VK_EXT_image_drm_format_modifier
+        case VK_STRUCTURE_TYPE_DRM_FORMAT_MODIFIER_PROPERTIES_LIST_EXT: {
+            marshal_VkDrmFormatModifierPropertiesListEXT(
+                vkStream, rootType,
+                reinterpret_cast<const VkDrmFormatModifierPropertiesListEXT*>(structExtension));
+            break;
+        }
+        case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_DRM_FORMAT_MODIFIER_INFO_EXT: {
+            marshal_VkPhysicalDeviceImageDrmFormatModifierInfoEXT(
+                vkStream, rootType,
+                reinterpret_cast<const VkPhysicalDeviceImageDrmFormatModifierInfoEXT*>(
+                    structExtension));
+            break;
+        }
+        case VK_STRUCTURE_TYPE_IMAGE_DRM_FORMAT_MODIFIER_LIST_CREATE_INFO_EXT: {
+            marshal_VkImageDrmFormatModifierListCreateInfoEXT(
+                vkStream, rootType,
+                reinterpret_cast<const VkImageDrmFormatModifierListCreateInfoEXT*>(
+                    structExtension));
+            break;
+        }
+        case VK_STRUCTURE_TYPE_IMAGE_DRM_FORMAT_MODIFIER_EXPLICIT_CREATE_INFO_EXT: {
+            marshal_VkImageDrmFormatModifierExplicitCreateInfoEXT(
+                vkStream, rootType,
+                reinterpret_cast<const VkImageDrmFormatModifierExplicitCreateInfoEXT*>(
+                    structExtension));
+            break;
+        }
+        case VK_STRUCTURE_TYPE_DRM_FORMAT_MODIFIER_PROPERTIES_LIST_2_EXT: {
+            marshal_VkDrmFormatModifierPropertiesList2EXT(
+                vkStream, rootType,
+                reinterpret_cast<const VkDrmFormatModifierPropertiesList2EXT*>(structExtension));
+            break;
+        }
+#endif
 #ifdef VK_EXT_vertex_attribute_divisor
         case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VERTEX_ATTRIBUTE_DIVISOR_PROPERTIES_EXT: {
             marshal_VkPhysicalDeviceVertexAttributeDivisorPropertiesEXT(
@@ -15592,6 +15922,40 @@
             break;
         }
 #endif
+#ifdef VK_EXT_image_drm_format_modifier
+        case VK_STRUCTURE_TYPE_DRM_FORMAT_MODIFIER_PROPERTIES_LIST_EXT: {
+            unmarshal_VkDrmFormatModifierPropertiesListEXT(
+                vkStream, rootType,
+                reinterpret_cast<VkDrmFormatModifierPropertiesListEXT*>(structExtension_out));
+            break;
+        }
+        case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_DRM_FORMAT_MODIFIER_INFO_EXT: {
+            unmarshal_VkPhysicalDeviceImageDrmFormatModifierInfoEXT(
+                vkStream, rootType,
+                reinterpret_cast<VkPhysicalDeviceImageDrmFormatModifierInfoEXT*>(
+                    structExtension_out));
+            break;
+        }
+        case VK_STRUCTURE_TYPE_IMAGE_DRM_FORMAT_MODIFIER_LIST_CREATE_INFO_EXT: {
+            unmarshal_VkImageDrmFormatModifierListCreateInfoEXT(
+                vkStream, rootType,
+                reinterpret_cast<VkImageDrmFormatModifierListCreateInfoEXT*>(structExtension_out));
+            break;
+        }
+        case VK_STRUCTURE_TYPE_IMAGE_DRM_FORMAT_MODIFIER_EXPLICIT_CREATE_INFO_EXT: {
+            unmarshal_VkImageDrmFormatModifierExplicitCreateInfoEXT(
+                vkStream, rootType,
+                reinterpret_cast<VkImageDrmFormatModifierExplicitCreateInfoEXT*>(
+                    structExtension_out));
+            break;
+        }
+        case VK_STRUCTURE_TYPE_DRM_FORMAT_MODIFIER_PROPERTIES_LIST_2_EXT: {
+            unmarshal_VkDrmFormatModifierPropertiesList2EXT(
+                vkStream, rootType,
+                reinterpret_cast<VkDrmFormatModifierPropertiesList2EXT*>(structExtension_out));
+            break;
+        }
+#endif
 #ifdef VK_EXT_vertex_attribute_divisor
         case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VERTEX_ATTRIBUTE_DIVISOR_PROPERTIES_EXT: {
             unmarshal_VkPhysicalDeviceVertexAttributeDivisorPropertiesEXT(
@@ -16943,6 +17307,11 @@
             return "OP_vkCmdCopyBufferToImage2KHR";
         }
 #endif
+#ifdef VK_EXT_image_drm_format_modifier
+        case OP_vkGetImageDrmFormatModifierPropertiesEXT: {
+            return "OP_vkGetImageDrmFormatModifierPropertiesEXT";
+        }
+#endif
 #ifdef VK_VERSION_1_2
         case OP_vkResetQueryPool: {
             return "OP_vkResetQueryPool";
diff --git a/guest/vulkan_enc/goldfish_vk_marshaling_guest.h b/guest/vulkan_enc/goldfish_vk_marshaling_guest.h
index c48c4c6..3fd79df 100644
--- a/guest/vulkan_enc/goldfish_vk_marshaling_guest.h
+++ b/guest/vulkan_enc/goldfish_vk_marshaling_guest.h
@@ -3170,6 +3170,73 @@
                       unmarshal_VkDescriptorPoolInlineUniformBlockCreateInfoEXT)
 
 #endif
+#ifdef VK_EXT_image_drm_format_modifier
+void marshal_VkDrmFormatModifierPropertiesEXT(
+    VulkanStreamGuest* vkStream, VkStructureType rootType,
+    const VkDrmFormatModifierPropertiesEXT* forMarshaling);
+
+void unmarshal_VkDrmFormatModifierPropertiesEXT(VulkanStreamGuest* vkStream,
+                                                VkStructureType rootType,
+                                                VkDrmFormatModifierPropertiesEXT* forUnmarshaling);
+
+void marshal_VkDrmFormatModifierPropertiesListEXT(
+    VulkanStreamGuest* vkStream, VkStructureType rootType,
+    const VkDrmFormatModifierPropertiesListEXT* forMarshaling);
+
+void unmarshal_VkDrmFormatModifierPropertiesListEXT(
+    VulkanStreamGuest* vkStream, VkStructureType rootType,
+    VkDrmFormatModifierPropertiesListEXT* forUnmarshaling);
+
+void marshal_VkPhysicalDeviceImageDrmFormatModifierInfoEXT(
+    VulkanStreamGuest* vkStream, VkStructureType rootType,
+    const VkPhysicalDeviceImageDrmFormatModifierInfoEXT* forMarshaling);
+
+void unmarshal_VkPhysicalDeviceImageDrmFormatModifierInfoEXT(
+    VulkanStreamGuest* vkStream, VkStructureType rootType,
+    VkPhysicalDeviceImageDrmFormatModifierInfoEXT* forUnmarshaling);
+
+void marshal_VkImageDrmFormatModifierListCreateInfoEXT(
+    VulkanStreamGuest* vkStream, VkStructureType rootType,
+    const VkImageDrmFormatModifierListCreateInfoEXT* forMarshaling);
+
+void unmarshal_VkImageDrmFormatModifierListCreateInfoEXT(
+    VulkanStreamGuest* vkStream, VkStructureType rootType,
+    VkImageDrmFormatModifierListCreateInfoEXT* forUnmarshaling);
+
+void marshal_VkImageDrmFormatModifierExplicitCreateInfoEXT(
+    VulkanStreamGuest* vkStream, VkStructureType rootType,
+    const VkImageDrmFormatModifierExplicitCreateInfoEXT* forMarshaling);
+
+void unmarshal_VkImageDrmFormatModifierExplicitCreateInfoEXT(
+    VulkanStreamGuest* vkStream, VkStructureType rootType,
+    VkImageDrmFormatModifierExplicitCreateInfoEXT* forUnmarshaling);
+
+void marshal_VkImageDrmFormatModifierPropertiesEXT(
+    VulkanStreamGuest* vkStream, VkStructureType rootType,
+    const VkImageDrmFormatModifierPropertiesEXT* forMarshaling);
+
+void unmarshal_VkImageDrmFormatModifierPropertiesEXT(
+    VulkanStreamGuest* vkStream, VkStructureType rootType,
+    VkImageDrmFormatModifierPropertiesEXT* forUnmarshaling);
+
+#define OP_vkGetImageDrmFormatModifierPropertiesEXT 251301237
+void marshal_VkDrmFormatModifierProperties2EXT(
+    VulkanStreamGuest* vkStream, VkStructureType rootType,
+    const VkDrmFormatModifierProperties2EXT* forMarshaling);
+
+void unmarshal_VkDrmFormatModifierProperties2EXT(
+    VulkanStreamGuest* vkStream, VkStructureType rootType,
+    VkDrmFormatModifierProperties2EXT* forUnmarshaling);
+
+void marshal_VkDrmFormatModifierPropertiesList2EXT(
+    VulkanStreamGuest* vkStream, VkStructureType rootType,
+    const VkDrmFormatModifierPropertiesList2EXT* forMarshaling);
+
+void unmarshal_VkDrmFormatModifierPropertiesList2EXT(
+    VulkanStreamGuest* vkStream, VkStructureType rootType,
+    VkDrmFormatModifierPropertiesList2EXT* forUnmarshaling);
+
+#endif
 #ifdef VK_EXT_vertex_attribute_divisor
 void marshal_VkPhysicalDeviceVertexAttributeDivisorPropertiesEXT(
     VulkanStreamGuest* vkStream, VkStructureType rootType,
diff --git a/guest/vulkan_enc/goldfish_vk_reserved_marshaling_guest.cpp b/guest/vulkan_enc/goldfish_vk_reserved_marshaling_guest.cpp
index db59101..6266220 100644
--- a/guest/vulkan_enc/goldfish_vk_reserved_marshaling_guest.cpp
+++ b/guest/vulkan_enc/goldfish_vk_reserved_marshaling_guest.cpp
@@ -8041,6 +8041,178 @@
 }
 
 #endif
+#ifdef VK_EXT_image_drm_format_modifier
+void reservedmarshal_VkDrmFormatModifierPropertiesEXT(
+    VulkanStreamGuest* vkStream, VkStructureType rootType,
+    const VkDrmFormatModifierPropertiesEXT* forMarshaling, uint8_t** ptr) {
+    (void)vkStream;
+    (void)rootType;
+    memcpy(*ptr, (uint64_t*)&forMarshaling->drmFormatModifier, sizeof(uint64_t));
+    *ptr += sizeof(uint64_t);
+    memcpy(*ptr, (uint32_t*)&forMarshaling->drmFormatModifierPlaneCount, sizeof(uint32_t));
+    *ptr += sizeof(uint32_t);
+    memcpy(*ptr, (VkFormatFeatureFlags*)&forMarshaling->drmFormatModifierTilingFeatures,
+           sizeof(VkFormatFeatureFlags));
+    *ptr += sizeof(VkFormatFeatureFlags);
+}
+
+void reservedmarshal_VkDrmFormatModifierPropertiesListEXT(
+    VulkanStreamGuest* vkStream, VkStructureType rootType,
+    const VkDrmFormatModifierPropertiesListEXT* forMarshaling, uint8_t** ptr) {
+    (void)vkStream;
+    (void)rootType;
+    memcpy(*ptr, (VkStructureType*)&forMarshaling->sType, sizeof(VkStructureType));
+    *ptr += sizeof(VkStructureType);
+    if (rootType == VK_STRUCTURE_TYPE_MAX_ENUM) {
+        rootType = forMarshaling->sType;
+    }
+    reservedmarshal_extension_struct(vkStream, rootType, forMarshaling->pNext, ptr);
+    memcpy(*ptr, (uint32_t*)&forMarshaling->drmFormatModifierCount, sizeof(uint32_t));
+    *ptr += sizeof(uint32_t);
+    // WARNING PTR CHECK
+    uint64_t cgen_var_0 = (uint64_t)(uintptr_t)forMarshaling->pDrmFormatModifierProperties;
+    memcpy((*ptr), &cgen_var_0, 8);
+    gfxstream::guest::Stream::toBe64((uint8_t*)(*ptr));
+    *ptr += 8;
+    if (forMarshaling->pDrmFormatModifierProperties) {
+        for (uint32_t i = 0; i < (uint32_t)forMarshaling->drmFormatModifierCount; ++i) {
+            reservedmarshal_VkDrmFormatModifierPropertiesEXT(
+                vkStream, rootType,
+                (VkDrmFormatModifierPropertiesEXT*)(forMarshaling->pDrmFormatModifierProperties +
+                                                    i),
+                ptr);
+        }
+    }
+}
+
+void reservedmarshal_VkPhysicalDeviceImageDrmFormatModifierInfoEXT(
+    VulkanStreamGuest* vkStream, VkStructureType rootType,
+    const VkPhysicalDeviceImageDrmFormatModifierInfoEXT* forMarshaling, uint8_t** ptr) {
+    (void)vkStream;
+    (void)rootType;
+    memcpy(*ptr, (VkStructureType*)&forMarshaling->sType, sizeof(VkStructureType));
+    *ptr += sizeof(VkStructureType);
+    if (rootType == VK_STRUCTURE_TYPE_MAX_ENUM) {
+        rootType = forMarshaling->sType;
+    }
+    reservedmarshal_extension_struct(vkStream, rootType, forMarshaling->pNext, ptr);
+    memcpy(*ptr, (uint64_t*)&forMarshaling->drmFormatModifier, sizeof(uint64_t));
+    *ptr += sizeof(uint64_t);
+    memcpy(*ptr, (VkSharingMode*)&forMarshaling->sharingMode, sizeof(VkSharingMode));
+    *ptr += sizeof(VkSharingMode);
+    memcpy(*ptr, (uint32_t*)&forMarshaling->queueFamilyIndexCount, sizeof(uint32_t));
+    *ptr += sizeof(uint32_t);
+    // WARNING PTR CHECK
+    uint64_t cgen_var_0 = (uint64_t)(uintptr_t)forMarshaling->pQueueFamilyIndices;
+    memcpy((*ptr), &cgen_var_0, 8);
+    gfxstream::guest::Stream::toBe64((uint8_t*)(*ptr));
+    *ptr += 8;
+    if (forMarshaling->pQueueFamilyIndices) {
+        memcpy(*ptr, (const uint32_t*)forMarshaling->pQueueFamilyIndices,
+               forMarshaling->queueFamilyIndexCount * sizeof(const uint32_t));
+        *ptr += forMarshaling->queueFamilyIndexCount * sizeof(const uint32_t);
+    }
+}
+
+void reservedmarshal_VkImageDrmFormatModifierListCreateInfoEXT(
+    VulkanStreamGuest* vkStream, VkStructureType rootType,
+    const VkImageDrmFormatModifierListCreateInfoEXT* forMarshaling, uint8_t** ptr) {
+    (void)vkStream;
+    (void)rootType;
+    memcpy(*ptr, (VkStructureType*)&forMarshaling->sType, sizeof(VkStructureType));
+    *ptr += sizeof(VkStructureType);
+    if (rootType == VK_STRUCTURE_TYPE_MAX_ENUM) {
+        rootType = forMarshaling->sType;
+    }
+    reservedmarshal_extension_struct(vkStream, rootType, forMarshaling->pNext, ptr);
+    memcpy(*ptr, (uint32_t*)&forMarshaling->drmFormatModifierCount, sizeof(uint32_t));
+    *ptr += sizeof(uint32_t);
+    memcpy(*ptr, (const uint64_t*)forMarshaling->pDrmFormatModifiers,
+           forMarshaling->drmFormatModifierCount * sizeof(const uint64_t));
+    *ptr += forMarshaling->drmFormatModifierCount * sizeof(const uint64_t);
+}
+
+void reservedmarshal_VkImageDrmFormatModifierExplicitCreateInfoEXT(
+    VulkanStreamGuest* vkStream, VkStructureType rootType,
+    const VkImageDrmFormatModifierExplicitCreateInfoEXT* forMarshaling, uint8_t** ptr) {
+    (void)vkStream;
+    (void)rootType;
+    memcpy(*ptr, (VkStructureType*)&forMarshaling->sType, sizeof(VkStructureType));
+    *ptr += sizeof(VkStructureType);
+    if (rootType == VK_STRUCTURE_TYPE_MAX_ENUM) {
+        rootType = forMarshaling->sType;
+    }
+    reservedmarshal_extension_struct(vkStream, rootType, forMarshaling->pNext, ptr);
+    memcpy(*ptr, (uint64_t*)&forMarshaling->drmFormatModifier, sizeof(uint64_t));
+    *ptr += sizeof(uint64_t);
+    memcpy(*ptr, (uint32_t*)&forMarshaling->drmFormatModifierPlaneCount, sizeof(uint32_t));
+    *ptr += sizeof(uint32_t);
+    for (uint32_t i = 0; i < (uint32_t)forMarshaling->drmFormatModifierPlaneCount; ++i) {
+        reservedmarshal_VkSubresourceLayout(
+            vkStream, rootType, (const VkSubresourceLayout*)(forMarshaling->pPlaneLayouts + i),
+            ptr);
+    }
+}
+
+void reservedmarshal_VkImageDrmFormatModifierPropertiesEXT(
+    VulkanStreamGuest* vkStream, VkStructureType rootType,
+    const VkImageDrmFormatModifierPropertiesEXT* forMarshaling, uint8_t** ptr) {
+    (void)vkStream;
+    (void)rootType;
+    memcpy(*ptr, (VkStructureType*)&forMarshaling->sType, sizeof(VkStructureType));
+    *ptr += sizeof(VkStructureType);
+    if (rootType == VK_STRUCTURE_TYPE_MAX_ENUM) {
+        rootType = forMarshaling->sType;
+    }
+    reservedmarshal_extension_struct(vkStream, rootType, forMarshaling->pNext, ptr);
+    memcpy(*ptr, (uint64_t*)&forMarshaling->drmFormatModifier, sizeof(uint64_t));
+    *ptr += sizeof(uint64_t);
+}
+
+void reservedmarshal_VkDrmFormatModifierProperties2EXT(
+    VulkanStreamGuest* vkStream, VkStructureType rootType,
+    const VkDrmFormatModifierProperties2EXT* forMarshaling, uint8_t** ptr) {
+    (void)vkStream;
+    (void)rootType;
+    memcpy(*ptr, (uint64_t*)&forMarshaling->drmFormatModifier, sizeof(uint64_t));
+    *ptr += sizeof(uint64_t);
+    memcpy(*ptr, (uint32_t*)&forMarshaling->drmFormatModifierPlaneCount, sizeof(uint32_t));
+    *ptr += sizeof(uint32_t);
+    memcpy(*ptr, (VkFormatFeatureFlags2*)&forMarshaling->drmFormatModifierTilingFeatures,
+           sizeof(VkFormatFeatureFlags2));
+    *ptr += sizeof(VkFormatFeatureFlags2);
+}
+
+void reservedmarshal_VkDrmFormatModifierPropertiesList2EXT(
+    VulkanStreamGuest* vkStream, VkStructureType rootType,
+    const VkDrmFormatModifierPropertiesList2EXT* forMarshaling, uint8_t** ptr) {
+    (void)vkStream;
+    (void)rootType;
+    memcpy(*ptr, (VkStructureType*)&forMarshaling->sType, sizeof(VkStructureType));
+    *ptr += sizeof(VkStructureType);
+    if (rootType == VK_STRUCTURE_TYPE_MAX_ENUM) {
+        rootType = forMarshaling->sType;
+    }
+    reservedmarshal_extension_struct(vkStream, rootType, forMarshaling->pNext, ptr);
+    memcpy(*ptr, (uint32_t*)&forMarshaling->drmFormatModifierCount, sizeof(uint32_t));
+    *ptr += sizeof(uint32_t);
+    // WARNING PTR CHECK
+    uint64_t cgen_var_0 = (uint64_t)(uintptr_t)forMarshaling->pDrmFormatModifierProperties;
+    memcpy((*ptr), &cgen_var_0, 8);
+    gfxstream::guest::Stream::toBe64((uint8_t*)(*ptr));
+    *ptr += 8;
+    if (forMarshaling->pDrmFormatModifierProperties) {
+        for (uint32_t i = 0; i < (uint32_t)forMarshaling->drmFormatModifierCount; ++i) {
+            reservedmarshal_VkDrmFormatModifierProperties2EXT(
+                vkStream, rootType,
+                (VkDrmFormatModifierProperties2EXT*)(forMarshaling->pDrmFormatModifierProperties +
+                                                     i),
+                ptr);
+        }
+    }
+}
+
+#endif
 #ifdef VK_EXT_vertex_attribute_divisor
 void reservedmarshal_VkPhysicalDeviceVertexAttributeDivisorPropertiesEXT(
     VulkanStreamGuest* vkStream, VkStructureType rootType,
@@ -9949,6 +10121,45 @@
             break;
         }
 #endif
+#ifdef VK_EXT_image_drm_format_modifier
+        case VK_STRUCTURE_TYPE_DRM_FORMAT_MODIFIER_PROPERTIES_LIST_EXT: {
+            reservedmarshal_VkDrmFormatModifierPropertiesListEXT(
+                vkStream, rootType,
+                reinterpret_cast<const VkDrmFormatModifierPropertiesListEXT*>(structExtension),
+                ptr);
+            break;
+        }
+        case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_DRM_FORMAT_MODIFIER_INFO_EXT: {
+            reservedmarshal_VkPhysicalDeviceImageDrmFormatModifierInfoEXT(
+                vkStream, rootType,
+                reinterpret_cast<const VkPhysicalDeviceImageDrmFormatModifierInfoEXT*>(
+                    structExtension),
+                ptr);
+            break;
+        }
+        case VK_STRUCTURE_TYPE_IMAGE_DRM_FORMAT_MODIFIER_LIST_CREATE_INFO_EXT: {
+            reservedmarshal_VkImageDrmFormatModifierListCreateInfoEXT(
+                vkStream, rootType,
+                reinterpret_cast<const VkImageDrmFormatModifierListCreateInfoEXT*>(structExtension),
+                ptr);
+            break;
+        }
+        case VK_STRUCTURE_TYPE_IMAGE_DRM_FORMAT_MODIFIER_EXPLICIT_CREATE_INFO_EXT: {
+            reservedmarshal_VkImageDrmFormatModifierExplicitCreateInfoEXT(
+                vkStream, rootType,
+                reinterpret_cast<const VkImageDrmFormatModifierExplicitCreateInfoEXT*>(
+                    structExtension),
+                ptr);
+            break;
+        }
+        case VK_STRUCTURE_TYPE_DRM_FORMAT_MODIFIER_PROPERTIES_LIST_2_EXT: {
+            reservedmarshal_VkDrmFormatModifierPropertiesList2EXT(
+                vkStream, rootType,
+                reinterpret_cast<const VkDrmFormatModifierPropertiesList2EXT*>(structExtension),
+                ptr);
+            break;
+        }
+#endif
 #ifdef VK_EXT_vertex_attribute_divisor
         case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VERTEX_ATTRIBUTE_DIVISOR_PROPERTIES_EXT: {
             reservedmarshal_VkPhysicalDeviceVertexAttributeDivisorPropertiesEXT(
diff --git a/guest/vulkan_enc/goldfish_vk_reserved_marshaling_guest.h b/guest/vulkan_enc/goldfish_vk_reserved_marshaling_guest.h
index 092c55a..623253f 100644
--- a/guest/vulkan_enc/goldfish_vk_reserved_marshaling_guest.h
+++ b/guest/vulkan_enc/goldfish_vk_reserved_marshaling_guest.h
@@ -1685,6 +1685,40 @@
                       reservedmarshal_VkDescriptorPoolInlineUniformBlockCreateInfoEXT)
 
 #endif
+#ifdef VK_EXT_image_drm_format_modifier
+void reservedmarshal_VkDrmFormatModifierPropertiesEXT(
+    VulkanStreamGuest* vkStream, VkStructureType rootType,
+    const VkDrmFormatModifierPropertiesEXT* forMarshaling, uint8_t** ptr);
+
+void reservedmarshal_VkDrmFormatModifierPropertiesListEXT(
+    VulkanStreamGuest* vkStream, VkStructureType rootType,
+    const VkDrmFormatModifierPropertiesListEXT* forMarshaling, uint8_t** ptr);
+
+void reservedmarshal_VkPhysicalDeviceImageDrmFormatModifierInfoEXT(
+    VulkanStreamGuest* vkStream, VkStructureType rootType,
+    const VkPhysicalDeviceImageDrmFormatModifierInfoEXT* forMarshaling, uint8_t** ptr);
+
+void reservedmarshal_VkImageDrmFormatModifierListCreateInfoEXT(
+    VulkanStreamGuest* vkStream, VkStructureType rootType,
+    const VkImageDrmFormatModifierListCreateInfoEXT* forMarshaling, uint8_t** ptr);
+
+void reservedmarshal_VkImageDrmFormatModifierExplicitCreateInfoEXT(
+    VulkanStreamGuest* vkStream, VkStructureType rootType,
+    const VkImageDrmFormatModifierExplicitCreateInfoEXT* forMarshaling, uint8_t** ptr);
+
+void reservedmarshal_VkImageDrmFormatModifierPropertiesEXT(
+    VulkanStreamGuest* vkStream, VkStructureType rootType,
+    const VkImageDrmFormatModifierPropertiesEXT* forMarshaling, uint8_t** ptr);
+
+void reservedmarshal_VkDrmFormatModifierProperties2EXT(
+    VulkanStreamGuest* vkStream, VkStructureType rootType,
+    const VkDrmFormatModifierProperties2EXT* forMarshaling, uint8_t** ptr);
+
+void reservedmarshal_VkDrmFormatModifierPropertiesList2EXT(
+    VulkanStreamGuest* vkStream, VkStructureType rootType,
+    const VkDrmFormatModifierPropertiesList2EXT* forMarshaling, uint8_t** ptr);
+
+#endif
 #ifdef VK_EXT_vertex_attribute_divisor
 void reservedmarshal_VkPhysicalDeviceVertexAttributeDivisorPropertiesEXT(
     VulkanStreamGuest* vkStream, VkStructureType rootType,
diff --git a/guest/vulkan_enc/goldfish_vk_transform_guest.cpp b/guest/vulkan_enc/goldfish_vk_transform_guest.cpp
index 7ef53d1..03eacb7 100644
--- a/guest/vulkan_enc/goldfish_vk_transform_guest.cpp
+++ b/guest/vulkan_enc/goldfish_vk_transform_guest.cpp
@@ -6830,6 +6830,196 @@
 }
 
 #endif
+#ifdef VK_EXT_image_drm_format_modifier
+void transform_tohost_VkDrmFormatModifierPropertiesEXT(
+    ResourceTracker* resourceTracker, VkDrmFormatModifierPropertiesEXT* toTransform) {
+    (void)resourceTracker;
+    (void)toTransform;
+}
+
+void transform_fromhost_VkDrmFormatModifierPropertiesEXT(
+    ResourceTracker* resourceTracker, VkDrmFormatModifierPropertiesEXT* toTransform) {
+    (void)resourceTracker;
+    (void)toTransform;
+}
+
+void transform_tohost_VkDrmFormatModifierPropertiesListEXT(
+    ResourceTracker* resourceTracker, VkDrmFormatModifierPropertiesListEXT* toTransform) {
+    (void)resourceTracker;
+    (void)toTransform;
+    if (toTransform->pNext) {
+        transform_tohost_extension_struct(resourceTracker, (void*)(toTransform->pNext));
+    }
+    if (toTransform) {
+        if (toTransform->pDrmFormatModifierProperties) {
+            for (uint32_t i = 0; i < (uint32_t)toTransform->drmFormatModifierCount; ++i) {
+                transform_tohost_VkDrmFormatModifierPropertiesEXT(
+                    resourceTracker,
+                    (VkDrmFormatModifierPropertiesEXT*)(toTransform->pDrmFormatModifierProperties +
+                                                        i));
+            }
+        }
+    }
+}
+
+void transform_fromhost_VkDrmFormatModifierPropertiesListEXT(
+    ResourceTracker* resourceTracker, VkDrmFormatModifierPropertiesListEXT* toTransform) {
+    (void)resourceTracker;
+    (void)toTransform;
+    if (toTransform->pNext) {
+        transform_fromhost_extension_struct(resourceTracker, (void*)(toTransform->pNext));
+    }
+    if (toTransform) {
+        if (toTransform->pDrmFormatModifierProperties) {
+            for (uint32_t i = 0; i < (uint32_t)toTransform->drmFormatModifierCount; ++i) {
+                transform_fromhost_VkDrmFormatModifierPropertiesEXT(
+                    resourceTracker,
+                    (VkDrmFormatModifierPropertiesEXT*)(toTransform->pDrmFormatModifierProperties +
+                                                        i));
+            }
+        }
+    }
+}
+
+void transform_tohost_VkPhysicalDeviceImageDrmFormatModifierInfoEXT(
+    ResourceTracker* resourceTracker, VkPhysicalDeviceImageDrmFormatModifierInfoEXT* toTransform) {
+    (void)resourceTracker;
+    (void)toTransform;
+    if (toTransform->pNext) {
+        transform_tohost_extension_struct(resourceTracker, (void*)(toTransform->pNext));
+    }
+}
+
+void transform_fromhost_VkPhysicalDeviceImageDrmFormatModifierInfoEXT(
+    ResourceTracker* resourceTracker, VkPhysicalDeviceImageDrmFormatModifierInfoEXT* toTransform) {
+    (void)resourceTracker;
+    (void)toTransform;
+    if (toTransform->pNext) {
+        transform_fromhost_extension_struct(resourceTracker, (void*)(toTransform->pNext));
+    }
+}
+
+void transform_tohost_VkImageDrmFormatModifierListCreateInfoEXT(
+    ResourceTracker* resourceTracker, VkImageDrmFormatModifierListCreateInfoEXT* toTransform) {
+    (void)resourceTracker;
+    (void)toTransform;
+    if (toTransform->pNext) {
+        transform_tohost_extension_struct(resourceTracker, (void*)(toTransform->pNext));
+    }
+}
+
+void transform_fromhost_VkImageDrmFormatModifierListCreateInfoEXT(
+    ResourceTracker* resourceTracker, VkImageDrmFormatModifierListCreateInfoEXT* toTransform) {
+    (void)resourceTracker;
+    (void)toTransform;
+    if (toTransform->pNext) {
+        transform_fromhost_extension_struct(resourceTracker, (void*)(toTransform->pNext));
+    }
+}
+
+void transform_tohost_VkImageDrmFormatModifierExplicitCreateInfoEXT(
+    ResourceTracker* resourceTracker, VkImageDrmFormatModifierExplicitCreateInfoEXT* toTransform) {
+    (void)resourceTracker;
+    (void)toTransform;
+    if (toTransform->pNext) {
+        transform_tohost_extension_struct(resourceTracker, (void*)(toTransform->pNext));
+    }
+    if (toTransform) {
+        if (toTransform->pPlaneLayouts) {
+            for (uint32_t i = 0; i < (uint32_t)toTransform->drmFormatModifierPlaneCount; ++i) {
+                transform_tohost_VkSubresourceLayout(
+                    resourceTracker, (VkSubresourceLayout*)(toTransform->pPlaneLayouts + i));
+            }
+        }
+    }
+}
+
+void transform_fromhost_VkImageDrmFormatModifierExplicitCreateInfoEXT(
+    ResourceTracker* resourceTracker, VkImageDrmFormatModifierExplicitCreateInfoEXT* toTransform) {
+    (void)resourceTracker;
+    (void)toTransform;
+    if (toTransform->pNext) {
+        transform_fromhost_extension_struct(resourceTracker, (void*)(toTransform->pNext));
+    }
+    if (toTransform) {
+        if (toTransform->pPlaneLayouts) {
+            for (uint32_t i = 0; i < (uint32_t)toTransform->drmFormatModifierPlaneCount; ++i) {
+                transform_fromhost_VkSubresourceLayout(
+                    resourceTracker, (VkSubresourceLayout*)(toTransform->pPlaneLayouts + i));
+            }
+        }
+    }
+}
+
+void transform_tohost_VkImageDrmFormatModifierPropertiesEXT(
+    ResourceTracker* resourceTracker, VkImageDrmFormatModifierPropertiesEXT* toTransform) {
+    (void)resourceTracker;
+    (void)toTransform;
+    if (toTransform->pNext) {
+        transform_tohost_extension_struct(resourceTracker, (void*)(toTransform->pNext));
+    }
+}
+
+void transform_fromhost_VkImageDrmFormatModifierPropertiesEXT(
+    ResourceTracker* resourceTracker, VkImageDrmFormatModifierPropertiesEXT* toTransform) {
+    (void)resourceTracker;
+    (void)toTransform;
+    if (toTransform->pNext) {
+        transform_fromhost_extension_struct(resourceTracker, (void*)(toTransform->pNext));
+    }
+}
+
+void transform_tohost_VkDrmFormatModifierProperties2EXT(
+    ResourceTracker* resourceTracker, VkDrmFormatModifierProperties2EXT* toTransform) {
+    (void)resourceTracker;
+    (void)toTransform;
+}
+
+void transform_fromhost_VkDrmFormatModifierProperties2EXT(
+    ResourceTracker* resourceTracker, VkDrmFormatModifierProperties2EXT* toTransform) {
+    (void)resourceTracker;
+    (void)toTransform;
+}
+
+void transform_tohost_VkDrmFormatModifierPropertiesList2EXT(
+    ResourceTracker* resourceTracker, VkDrmFormatModifierPropertiesList2EXT* toTransform) {
+    (void)resourceTracker;
+    (void)toTransform;
+    if (toTransform->pNext) {
+        transform_tohost_extension_struct(resourceTracker, (void*)(toTransform->pNext));
+    }
+    if (toTransform) {
+        if (toTransform->pDrmFormatModifierProperties) {
+            for (uint32_t i = 0; i < (uint32_t)toTransform->drmFormatModifierCount; ++i) {
+                transform_tohost_VkDrmFormatModifierProperties2EXT(
+                    resourceTracker,
+                    (VkDrmFormatModifierProperties2EXT*)(toTransform->pDrmFormatModifierProperties +
+                                                         i));
+            }
+        }
+    }
+}
+
+void transform_fromhost_VkDrmFormatModifierPropertiesList2EXT(
+    ResourceTracker* resourceTracker, VkDrmFormatModifierPropertiesList2EXT* toTransform) {
+    (void)resourceTracker;
+    (void)toTransform;
+    if (toTransform->pNext) {
+        transform_fromhost_extension_struct(resourceTracker, (void*)(toTransform->pNext));
+    }
+    if (toTransform) {
+        if (toTransform->pDrmFormatModifierProperties) {
+            for (uint32_t i = 0; i < (uint32_t)toTransform->drmFormatModifierCount; ++i) {
+                transform_fromhost_VkDrmFormatModifierProperties2EXT(
+                    resourceTracker,
+                    (VkDrmFormatModifierProperties2EXT*)(toTransform->pDrmFormatModifierProperties +
+                                                         i));
+            }
+        }
+    }
+}
+
+#endif
 #ifdef VK_EXT_vertex_attribute_divisor
 void transform_tohost_VkPhysicalDeviceVertexAttributeDivisorPropertiesEXT(
     ResourceTracker* resourceTracker,
@@ -8685,6 +8875,38 @@
             break;
         }
 #endif
+#ifdef VK_EXT_image_drm_format_modifier
+        case VK_STRUCTURE_TYPE_DRM_FORMAT_MODIFIER_PROPERTIES_LIST_EXT: {
+            transform_tohost_VkDrmFormatModifierPropertiesListEXT(
+                resourceTracker,
+                reinterpret_cast<VkDrmFormatModifierPropertiesListEXT*>(structExtension_out));
+            break;
+        }
+        case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_DRM_FORMAT_MODIFIER_INFO_EXT: {
+            transform_tohost_VkPhysicalDeviceImageDrmFormatModifierInfoEXT(
+                resourceTracker, reinterpret_cast<VkPhysicalDeviceImageDrmFormatModifierInfoEXT*>(
+                                     structExtension_out));
+            break;
+        }
+        case VK_STRUCTURE_TYPE_IMAGE_DRM_FORMAT_MODIFIER_LIST_CREATE_INFO_EXT: {
+            transform_tohost_VkImageDrmFormatModifierListCreateInfoEXT(
+                resourceTracker,
+                reinterpret_cast<VkImageDrmFormatModifierListCreateInfoEXT*>(structExtension_out));
+            break;
+        }
+        case VK_STRUCTURE_TYPE_IMAGE_DRM_FORMAT_MODIFIER_EXPLICIT_CREATE_INFO_EXT: {
+            transform_tohost_VkImageDrmFormatModifierExplicitCreateInfoEXT(
+                resourceTracker, reinterpret_cast<VkImageDrmFormatModifierExplicitCreateInfoEXT*>(
+                                     structExtension_out));
+            break;
+        }
+        case VK_STRUCTURE_TYPE_DRM_FORMAT_MODIFIER_PROPERTIES_LIST_2_EXT: {
+            transform_tohost_VkDrmFormatModifierPropertiesList2EXT(
+                resourceTracker,
+                reinterpret_cast<VkDrmFormatModifierPropertiesList2EXT*>(structExtension_out));
+            break;
+        }
+#endif
 #ifdef VK_EXT_vertex_attribute_divisor
         case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VERTEX_ATTRIBUTE_DIVISOR_PROPERTIES_EXT: {
             transform_tohost_VkPhysicalDeviceVertexAttributeDivisorPropertiesEXT(
@@ -9779,6 +10001,38 @@
             break;
         }
 #endif
+#ifdef VK_EXT_image_drm_format_modifier
+        case VK_STRUCTURE_TYPE_DRM_FORMAT_MODIFIER_PROPERTIES_LIST_EXT: {
+            transform_fromhost_VkDrmFormatModifierPropertiesListEXT(
+                resourceTracker,
+                reinterpret_cast<VkDrmFormatModifierPropertiesListEXT*>(structExtension_out));
+            break;
+        }
+        case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_DRM_FORMAT_MODIFIER_INFO_EXT: {
+            transform_fromhost_VkPhysicalDeviceImageDrmFormatModifierInfoEXT(
+                resourceTracker, reinterpret_cast<VkPhysicalDeviceImageDrmFormatModifierInfoEXT*>(
+                                     structExtension_out));
+            break;
+        }
+        case VK_STRUCTURE_TYPE_IMAGE_DRM_FORMAT_MODIFIER_LIST_CREATE_INFO_EXT: {
+            transform_fromhost_VkImageDrmFormatModifierListCreateInfoEXT(
+                resourceTracker,
+                reinterpret_cast<VkImageDrmFormatModifierListCreateInfoEXT*>(structExtension_out));
+            break;
+        }
+        case VK_STRUCTURE_TYPE_IMAGE_DRM_FORMAT_MODIFIER_EXPLICIT_CREATE_INFO_EXT: {
+            transform_fromhost_VkImageDrmFormatModifierExplicitCreateInfoEXT(
+                resourceTracker, reinterpret_cast<VkImageDrmFormatModifierExplicitCreateInfoEXT*>(
+                                     structExtension_out));
+            break;
+        }
+        case VK_STRUCTURE_TYPE_DRM_FORMAT_MODIFIER_PROPERTIES_LIST_2_EXT: {
+            transform_fromhost_VkDrmFormatModifierPropertiesList2EXT(
+                resourceTracker,
+                reinterpret_cast<VkDrmFormatModifierPropertiesList2EXT*>(structExtension_out));
+            break;
+        }
+#endif
 #ifdef VK_EXT_vertex_attribute_divisor
         case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VERTEX_ATTRIBUTE_DIVISOR_PROPERTIES_EXT: {
             transform_fromhost_VkPhysicalDeviceVertexAttributeDivisorPropertiesEXT(
diff --git a/guest/vulkan_enc/goldfish_vk_transform_guest.h b/guest/vulkan_enc/goldfish_vk_transform_guest.h
index 0616180..4a1f98a 100644
--- a/guest/vulkan_enc/goldfish_vk_transform_guest.h
+++ b/guest/vulkan_enc/goldfish_vk_transform_guest.h
@@ -2681,6 +2681,56 @@
                       transform_fromhost_VkDescriptorPoolInlineUniformBlockCreateInfoEXT)
 
 #endif
+#ifdef VK_EXT_image_drm_format_modifier
+void transform_tohost_VkDrmFormatModifierPropertiesEXT(
+    ResourceTracker* resourceTracker, VkDrmFormatModifierPropertiesEXT* toTransform);
+
+void transform_fromhost_VkDrmFormatModifierPropertiesEXT(
+    ResourceTracker* resourceTracker, VkDrmFormatModifierPropertiesEXT* toTransform);
+
+void transform_tohost_VkDrmFormatModifierPropertiesListEXT(
+    ResourceTracker* resourceTracker, VkDrmFormatModifierPropertiesListEXT* toTransform);
+
+void transform_fromhost_VkDrmFormatModifierPropertiesListEXT(
+    ResourceTracker* resourceTracker, VkDrmFormatModifierPropertiesListEXT* toTransform);
+
+void transform_tohost_VkPhysicalDeviceImageDrmFormatModifierInfoEXT(
+    ResourceTracker* resourceTracker, VkPhysicalDeviceImageDrmFormatModifierInfoEXT* toTransform);
+
+void transform_fromhost_VkPhysicalDeviceImageDrmFormatModifierInfoEXT(
+    ResourceTracker* resourceTracker, VkPhysicalDeviceImageDrmFormatModifierInfoEXT* toTransform);
+
+void transform_tohost_VkImageDrmFormatModifierListCreateInfoEXT(
+    ResourceTracker* resourceTracker, VkImageDrmFormatModifierListCreateInfoEXT* toTransform);
+
+void transform_fromhost_VkImageDrmFormatModifierListCreateInfoEXT(
+    ResourceTracker* resourceTracker, VkImageDrmFormatModifierListCreateInfoEXT* toTransform);
+
+void transform_tohost_VkImageDrmFormatModifierExplicitCreateInfoEXT(
+    ResourceTracker* resourceTracker, VkImageDrmFormatModifierExplicitCreateInfoEXT* toTransform);
+
+void transform_fromhost_VkImageDrmFormatModifierExplicitCreateInfoEXT(
+    ResourceTracker* resourceTracker, VkImageDrmFormatModifierExplicitCreateInfoEXT* toTransform);
+
+void transform_tohost_VkImageDrmFormatModifierPropertiesEXT(
+    ResourceTracker* resourceTracker, VkImageDrmFormatModifierPropertiesEXT* toTransform);
+
+void transform_fromhost_VkImageDrmFormatModifierPropertiesEXT(
+    ResourceTracker* resourceTracker, VkImageDrmFormatModifierPropertiesEXT* toTransform);
+
+void transform_tohost_VkDrmFormatModifierProperties2EXT(
+    ResourceTracker* resourceTracker, VkDrmFormatModifierProperties2EXT* toTransform);
+
+void transform_fromhost_VkDrmFormatModifierProperties2EXT(
+    ResourceTracker* resourceTracker, VkDrmFormatModifierProperties2EXT* toTransform);
+
+void transform_tohost_VkDrmFormatModifierPropertiesList2EXT(
+    ResourceTracker* resourceTracker, VkDrmFormatModifierPropertiesList2EXT* toTransform);
+
+void transform_fromhost_VkDrmFormatModifierPropertiesList2EXT(
+    ResourceTracker* resourceTracker, VkDrmFormatModifierPropertiesList2EXT* toTransform);
+
+#endif
 #ifdef VK_EXT_vertex_attribute_divisor
 void transform_tohost_VkPhysicalDeviceVertexAttributeDivisorPropertiesEXT(
     ResourceTracker* resourceTracker,
diff --git a/guest/vulkan_enc/vk_struct_id.h b/guest/vulkan_enc/vk_struct_id.h
index e7a6e60..9bcca28 100644
--- a/guest/vulkan_enc/vk_struct_id.h
+++ b/guest/vulkan_enc/vk_struct_id.h
@@ -135,6 +135,15 @@
 #if defined(LINUX_GUEST_BUILD)
 REGISTER_VK_STRUCT_ID(wsi_image_create_info, VK_STRUCTURE_TYPE_WSI_IMAGE_CREATE_INFO_MESA);
 #endif
+REGISTER_VK_STRUCT_ID(VkImageDrmFormatModifierExplicitCreateInfoEXT,
+                      VK_STRUCTURE_TYPE_IMAGE_DRM_FORMAT_MODIFIER_EXPLICIT_CREATE_INFO_EXT);
+REGISTER_VK_STRUCT_ID(VkFormatProperties2, VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_2);
+REGISTER_VK_STRUCT_ID(VkPhysicalDeviceImageDrmFormatModifierInfoEXT,
+                      VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_DRM_FORMAT_MODIFIER_INFO_EXT);
+REGISTER_VK_STRUCT_ID(VkDrmFormatModifierPropertiesListEXT,
+                      VK_STRUCTURE_TYPE_DRM_FORMAT_MODIFIER_PROPERTIES_LIST_EXT);
+REGISTER_VK_STRUCT_ID(VkImageDrmFormatModifierListCreateInfoEXT,
+                      VK_STRUCTURE_TYPE_IMAGE_DRM_FORMAT_MODIFIER_LIST_CREATE_INFO_EXT);
 
 #undef REGISTER_VK_STRUCT_ID
 
diff --git a/host/BUILD.bazel b/host/BUILD.bazel
index df5dde8..c218f34 100644
--- a/host/BUILD.bazel
+++ b/host/BUILD.bazel
@@ -1,6 +1,7 @@
 cc_library(
     name = "gfxstream_backend_headers",
     hdrs = glob(["include/**/*.h"]),
+    copts = ["-fno-exceptions"],
     includes = ["include"],
     visibility = ["//visibility:public"],
 )
@@ -13,6 +14,7 @@
         "*.h",
         "gl/*.h",
     ]),
+    copts = ["-fno-exceptions"],
     includes = ["."],
     visibility = [":__subpackages__"],
 )
@@ -23,6 +25,7 @@
     hdrs = [
         "compressedTextureFormats/AstcCpuDecompressor.h",
     ],
+    copts = ["-fno-exceptions"],
     includes = ["."],
     visibility = ["//visibility:public"],
     deps = [
@@ -33,6 +36,7 @@
 cc_test(
     name = "gfxstream-compressedTextures_unittests",
     srcs = ["compressedTextureFormats/AstcCpuDecompressor_unittest.cpp"],
+    copts = ["-fno-exceptions"],
     deps = [
         ":gfxstream-compressedTextures",
         "//hardware/google/aemu/base:aemu-base",
@@ -48,6 +52,10 @@
         "NativeSubWindow.h",
         "NativeSubWindow_cocoa.mm",
     ],
+    copts = [
+        "-fno-exceptions",
+        "-Wno-deprecated-declarations",
+    ],
     defines = [
         "EMUGL_BUILD",
         "GFXSTREAM_ENABLE_HOST_GLES=1",
@@ -103,6 +111,7 @@
     copts = [
         "-Wno-return-type-c-linkage",
         "-Wno-extern-c-compat",
+        "-fno-exceptions",
     ],
     defines = [
         "EMUGL_BUILD",
@@ -157,6 +166,7 @@
         "virtio-gpu-gfxstream-renderer.cpp",
     ],
     copts = [
+        "-fno-exceptions",
         "-Wno-extern-c-compat",
         "-Wno-return-type-c-linkage",
     ],
@@ -184,6 +194,7 @@
         "render_api.cpp",
         "virtio-gpu-gfxstream-renderer.cpp",
     ],
+    copts = ["-fno-exceptions"],
     linkshared = True,
     visibility = ["//visibility:public"],
     deps = [
diff --git a/host/apigen-codec-common/BUILD.bazel b/host/apigen-codec-common/BUILD.bazel
index 3e7d6fa..1172ba7 100644
--- a/host/apigen-codec-common/BUILD.bazel
+++ b/host/apigen-codec-common/BUILD.bazel
@@ -24,6 +24,7 @@
         "ProtocolUtils.h",
         "gl_base_types.h",
     ],
+    copts = ["-fno-exceptions"],
     defines = [
         "EMUGL_BUILD",
         "BUILDING_EMUGL_COMMON_SHARED",
diff --git a/host/features/BUILD.bazel b/host/features/BUILD.bazel
index c2877a2..2eb71dc 100644
--- a/host/features/BUILD.bazel
+++ b/host/features/BUILD.bazel
@@ -1,6 +1,7 @@
 cc_library(
     name = "gfxstream_features",
     srcs = ["Features.cpp"] + glob(["include/**/*.h"]),
+    copts = ["-fno-exceptions"],
     includes = ["include"],
     visibility = ["//visibility:public"],
 )
diff --git a/host/gl/BUILD.bazel b/host/gl/BUILD.bazel
index d48ffe1..88420f7 100644
--- a/host/gl/BUILD.bazel
+++ b/host/gl/BUILD.bazel
@@ -5,6 +5,7 @@
         "gles1_dec/gles1_dec.cpp",
         "gles1_dec/gles1_server_context.cpp",
     ] + glob(["gles1_dec/*.h"]),
+    copts = ["-fno-exceptions"],
     defines = ["EMUGL_BUILD"],
     visibility = ["//visibility:public"],
     deps = [
@@ -30,6 +31,7 @@
 cc_library(
     name = "gl-common-headers",
     hdrs = glob(["glestranslator/include/**/*.h"]),
+    copts = ["-fno-exceptions"],
     includes = ["glestranslator/include"],
     visibility = ["//visibility:public"],
     deps = ["//hardware/google/gfxstream/host/apigen-codec-common"],
@@ -46,6 +48,8 @@
     sdk_frameworks = [
         "IOSurface",
         "AppKit",
+        "CoreGraphics",
+        "OpenGL",
     ],
     visibility = ["//visibility:public"],
     deps = [
@@ -89,6 +93,7 @@
     hdrs =
         ["glestranslator/EGL/ClientAPIExts.in"],
     copts = [
+        "-fno-exceptions",
         "-Wno-extern-c-compat",
         "-Wno-inconsistent-missing-override",
         "-Wno-return-type-c-linkage",
@@ -137,7 +142,10 @@
         "glestranslator/GLcommon/TextureUtils.cpp",
         "glestranslator/GLcommon/rgtc.cpp",
     ],
-    copts = ["-Wno-extern-c-compat"],
+    copts = [
+        "-Wno-extern-c-compat",
+        "-fno-exceptions",
+    ],
     defines = [
         "EMUGL_BUILD",
         "BUILDING_EMUGL_COMMON_SHARED",
@@ -175,6 +183,7 @@
     }) + glob(["gl-host-common/include/**/*.h"]),
     copts = [
         "-Wno-return-type-c-linkage",
+        "-fno-exceptions",
         "-Wno-extern-c-compat",
     ],
     defines = ["EMUGL_BUILD"],
@@ -205,6 +214,7 @@
         "gles2_dec/gles2_dec.cpp",
         "gles2_dec/gles2_server_context.cpp",
     ] + glob(["gles2_dec/*.h"]),
+    copts = ["-fno-exceptions"],
     defines = ["EMUGL_BUILD"],
     visibility = ["//visibility:public"],
     deps = [
@@ -219,7 +229,10 @@
     name = "GLSnapshot",
     srcs = ["glsnapshot/GLSnapshot.cpp"],
     hdrs = ["glsnapshot/GLSnapshot.h"],
-    copts = ["-Wno-extern-c-compat"],
+    copts = [
+        "-fno-exceptions",
+        "-Wno-extern-c-compat",
+    ],
     defines = ["EMUGL_BUILD"],
     includes = ["glsnapshot"],
     visibility = ["//visibility:public"],
@@ -237,7 +250,10 @@
         "OpenGLESDispatch/gles1_stubbed_in_translator_namespace.cpp",
         "OpenGLESDispatch/gles2_stubbed_in_translator_namespace.cpp",
     ] + glob(["OpenGLESDispatch/*.h"]),
-    copts = ["-Wno-extern-c-compat"],
+    copts = [
+        "-fno-exceptions",
+        "-Wno-extern-c-compat",
+    ],
     defines = ["EMUGL_BUILD"],
     visibility = ["//visibility:public"],
     deps = [
@@ -275,7 +291,10 @@
         "glestranslator/include/**/*.h",
     ]),
     hdrs = [],
-    copts = ["-Wno-extern-c-compat"],
+    copts = [
+        "-fno-exceptions",
+        "-Wno-extern-c-compat",
+    ],
     defines = [
         "GFXSTREAM_ENABLE_HOST_GLES=1",
         "EMUGL_BUILD",
diff --git a/host/gl/EmulationGl.cpp b/host/gl/EmulationGl.cpp
index 664695a..db36352 100644
--- a/host/gl/EmulationGl.cpp
+++ b/host/gl/EmulationGl.cpp
@@ -529,8 +529,8 @@
 std::unique_ptr<gfxstream::DisplaySurface> EmulationGl::createFakeWindowSurface() {
     return std::make_unique<gfxstream::DisplaySurface>(
         mWidth, mHeight,
-        std::move(DisplaySurfaceGl::createPbufferSurface(
-            mEglDisplay, mEglConfig, mEglContext, getGlesMaxContextAttribs(), mWidth, mHeight)));
+        DisplaySurfaceGl::createPbufferSurface(
+            mEglDisplay, mEglConfig, mEglContext, getGlesMaxContextAttribs(), mWidth, mHeight));
 }
 
 /*static*/ const GLint* EmulationGl::getGlesMaxContextAttribs() {
diff --git a/host/vulkan/VkDecoder.cpp b/host/vulkan/VkDecoder.cpp
index 99974a9..b52d841 100644
--- a/host/vulkan/VkDecoder.cpp
+++ b/host/vulkan/VkDecoder.cpp
@@ -18970,6 +18970,78 @@
                 break;
             }
 #endif
+#ifdef VK_EXT_image_drm_format_modifier
+            case OP_vkGetImageDrmFormatModifierPropertiesEXT: {
+                android::base::beginTrace("vkGetImageDrmFormatModifierPropertiesEXT decode");
+                VkDevice device;
+                VkImage image;
+                VkImageDrmFormatModifierPropertiesEXT* pProperties;
+                // Begin non wrapped dispatchable handle unboxing for device;
+                uint64_t cgen_var_0;
+                memcpy((uint64_t*)&cgen_var_0, *readStreamPtrPtr, 1 * 8);
+                *readStreamPtrPtr += 1 * 8;
+                *(VkDevice*)&device = (VkDevice)(VkDevice)((VkDevice)(*&cgen_var_0));
+                auto unboxed_device = unbox_VkDevice(device);
+                auto vk = dispatch_VkDevice(device);
+                // End manual dispatchable handle unboxing for device;
+                uint64_t cgen_var_1;
+                memcpy((uint64_t*)&cgen_var_1, *readStreamPtrPtr, 1 * 8);
+                *readStreamPtrPtr += 1 * 8;
+                *(VkImage*)&image = (VkImage)unbox_VkImage((VkImage)(*&cgen_var_1));
+                // Begin manual dispatchable handle unboxing for pProperties;
+                vkReadStream->unsetHandleMapping();
+                vkReadStream->alloc((void**)&pProperties,
+                                    sizeof(VkImageDrmFormatModifierPropertiesEXT));
+                reservedunmarshal_VkImageDrmFormatModifierPropertiesEXT(
+                    vkReadStream, VK_STRUCTURE_TYPE_MAX_ENUM,
+                    (VkImageDrmFormatModifierPropertiesEXT*)(pProperties), readStreamPtrPtr);
+                if (pProperties) {
+                    transform_tohost_VkImageDrmFormatModifierPropertiesEXT(
+                        m_state, (VkImageDrmFormatModifierPropertiesEXT*)(pProperties));
+                }
+                if (m_logCalls) {
+                    fprintf(stderr,
+                            "stream %p: call vkGetImageDrmFormatModifierPropertiesEXT 0x%llx "
+                            "0x%llx 0x%llx \n",
+                            ioStream, (unsigned long long)device, (unsigned long long)image,
+                            (unsigned long long)pProperties);
+                }
+                VkResult vkGetImageDrmFormatModifierPropertiesEXT_VkResult_return = (VkResult)0;
+                vkGetImageDrmFormatModifierPropertiesEXT_VkResult_return =
+                    vk->vkGetImageDrmFormatModifierPropertiesEXT(unboxed_device, image,
+                                                                 pProperties);
+                if ((vkGetImageDrmFormatModifierPropertiesEXT_VkResult_return) ==
+                    VK_ERROR_DEVICE_LOST)
+                    m_state->on_DeviceLost();
+                m_state->on_CheckOutOfMemory(
+                    vkGetImageDrmFormatModifierPropertiesEXT_VkResult_return, opcode, context);
+                vkStream->unsetHandleMapping();
+                if (pProperties) {
+                    transform_fromhost_VkImageDrmFormatModifierPropertiesEXT(
+                        m_state, (VkImageDrmFormatModifierPropertiesEXT*)(pProperties));
+                }
+                marshal_VkImageDrmFormatModifierPropertiesEXT(
+                    vkStream, VK_STRUCTURE_TYPE_MAX_ENUM,
+                    (VkImageDrmFormatModifierPropertiesEXT*)(pProperties));
+                vkStream->write(&vkGetImageDrmFormatModifierPropertiesEXT_VkResult_return,
+                                sizeof(VkResult));
+                vkStream->commitWrite();
+                vkReadStream->setReadPos((uintptr_t)(*readStreamPtrPtr) -
+                                         (uintptr_t)snapshotTraceBegin);
+                size_t snapshotTraceBytes = vkReadStream->endTrace();
+                if (m_state->snapshotsEnabled()) {
+                    m_state->snapshot()->vkGetImageDrmFormatModifierPropertiesEXT(
+                        snapshotTraceBegin, snapshotTraceBytes, &m_pool,
+                        vkGetImageDrmFormatModifierPropertiesEXT_VkResult_return, device, image,
+                        pProperties);
+                }
+                vkReadStream->clearPool();
+                if (m_queueSubmitWithCommandsEnabled)
+                    seqnoPtr->fetch_add(1, std::memory_order_seq_cst);
+                android::base::endTrace();
+                break;
+            }
+#endif
 #ifdef VK_EXT_external_memory_host
             case OP_vkGetMemoryHostPointerPropertiesEXT: {
                 android::base::beginTrace("vkGetMemoryHostPointerPropertiesEXT decode");
diff --git a/host/vulkan/VkDecoderGlobalState.cpp b/host/vulkan/VkDecoderGlobalState.cpp
index b056460..2b514be 100644
--- a/host/vulkan/VkDecoderGlobalState.cpp
+++ b/host/vulkan/VkDecoderGlobalState.cpp
@@ -1696,6 +1696,7 @@
                                          pCreateInfo->ppEnabledExtensionNames);
 
         m_emu->deviceLostHelper.addNeededDeviceExtensions(&updatedDeviceExtensions);
+
         uint32_t supportedFenceHandleTypes = 0;
         uint32_t supportedBinarySemaphoreHandleTypes = 0;
         // Run the underlying API call, filtering extensions.
@@ -5327,6 +5328,7 @@
         } else if (m_emu->features.ExternalBlob.enabled) {
             VkResult result;
             auto device = unbox_VkDevice(boxed_device);
+            auto vk = dispatch_VkDevice(boxed_device);
             DescriptorType handle;
             uint32_t handleType;
             struct VulkanInfo vulkanInfo = {
@@ -5337,6 +5339,15 @@
             memcpy(vulkanInfo.driverUUID, m_emu->deviceInfo.idProps.driverUUID,
                    sizeof(vulkanInfo.driverUUID));
 
+            if (snapshotsEnabled()) {
+                VkResult mapResult = vk->vkMapMemory(device, memory, 0, info->size, 0, &info->ptr);
+                if (mapResult != VK_SUCCESS) {
+                    return VK_ERROR_OUT_OF_HOST_MEMORY;
+                }
+
+                info->needUnmap = true;
+            }
+
 #ifdef __unix__
             VkMemoryGetFdInfoKHR getFd = {
                 .sType = VK_STRUCTURE_TYPE_MEMORY_GET_FD_INFO_KHR,
@@ -7473,6 +7484,17 @@
             hasDeviceExtension(properties, VK_EXT_EXTERNAL_MEMORY_DMA_BUF_EXTENSION_NAME)) {
             res.push_back(VK_EXT_EXTERNAL_MEMORY_DMA_BUF_EXTENSION_NAME);
         }
+
+        if (hasDeviceExtension(properties, VK_EXT_IMAGE_DRM_FORMAT_MODIFIER_EXTENSION_NAME)) {
+            // Mesa Vulkan Wayland WSI needs vkGetImageDrmFormatModifierPropertiesEXT. On some Intel
+            // GPUs, this extension is exposed by the driver only if
+            // VK_EXT_image_drm_format_modifier extension is requested via
+            // VkDeviceCreateInfo::ppEnabledExtensionNames. vkcube-wayland does not request it,
+            // which makes the host attempt to call a null function pointer unless we force-enable
+            // it regardless of the client's wishes.
+            res.push_back(VK_EXT_IMAGE_DRM_FORMAT_MODIFIER_EXTENSION_NAME);
+        }
+
 #endif
         return res;
     }
diff --git a/host/vulkan/VkDecoderSnapshot.cpp b/host/vulkan/VkDecoderSnapshot.cpp
index 6543722..654c053 100644
--- a/host/vulkan/VkDecoderSnapshot.cpp
+++ b/host/vulkan/VkDecoderSnapshot.cpp
@@ -3233,6 +3233,12 @@
                                       VkDebugUtilsMessageTypeFlagsEXT messageTypes,
                                       const VkDebugUtilsMessengerCallbackDataEXT* pCallbackData) {}
 #endif
+#ifdef VK_EXT_image_drm_format_modifier
+    void vkGetImageDrmFormatModifierPropertiesEXT(
+        const uint8_t* snapshotTraceBegin, size_t snapshotTraceBytes, android::base::BumpPool* pool,
+        VkResult input_result, VkDevice device, VkImage image,
+        VkImageDrmFormatModifierPropertiesEXT* pProperties) {}
+#endif
 #ifdef VK_EXT_external_memory_host
     void vkGetMemoryHostPointerPropertiesEXT(
         const uint8_t* snapshotTraceBegin, size_t snapshotTraceBytes, android::base::BumpPool* pool,
@@ -6805,6 +6811,15 @@
                                         messageSeverity, messageTypes, pCallbackData);
 }
 #endif
+#ifdef VK_EXT_image_drm_format_modifier
+void VkDecoderSnapshot::vkGetImageDrmFormatModifierPropertiesEXT(
+    const uint8_t* snapshotTraceBegin, size_t snapshotTraceBytes, android::base::BumpPool* pool,
+    VkResult input_result, VkDevice device, VkImage image,
+    VkImageDrmFormatModifierPropertiesEXT* pProperties) {
+    mImpl->vkGetImageDrmFormatModifierPropertiesEXT(snapshotTraceBegin, snapshotTraceBytes, pool,
+                                                    input_result, device, image, pProperties);
+}
+#endif
 #ifdef VK_EXT_external_memory_host
 void VkDecoderSnapshot::vkGetMemoryHostPointerPropertiesEXT(
     const uint8_t* snapshotTraceBegin, size_t snapshotTraceBytes, android::base::BumpPool* pool,
diff --git a/host/vulkan/VkDecoderSnapshot.h b/host/vulkan/VkDecoderSnapshot.h
index 0072da1..8f6170d 100644
--- a/host/vulkan/VkDecoderSnapshot.h
+++ b/host/vulkan/VkDecoderSnapshot.h
@@ -1321,6 +1321,12 @@
                                       VkDebugUtilsMessageTypeFlagsEXT messageTypes,
                                       const VkDebugUtilsMessengerCallbackDataEXT* pCallbackData);
 #endif
+#ifdef VK_EXT_image_drm_format_modifier
+    void vkGetImageDrmFormatModifierPropertiesEXT(
+        const uint8_t* snapshotTraceBegin, size_t snapshotTraceBytes, android::base::BumpPool* pool,
+        VkResult input_result, VkDevice device, VkImage image,
+        VkImageDrmFormatModifierPropertiesEXT* pProperties);
+#endif
 #ifdef VK_EXT_external_memory_host
     void vkGetMemoryHostPointerPropertiesEXT(
         const uint8_t* snapshotTraceBegin, size_t snapshotTraceBytes, android::base::BumpPool* pool,
diff --git a/host/vulkan/cereal/common/goldfish_vk_deepcopy.cpp b/host/vulkan/cereal/common/goldfish_vk_deepcopy.cpp
index b1402aa..988913c 100644
--- a/host/vulkan/cereal/common/goldfish_vk_deepcopy.cpp
+++ b/host/vulkan/cereal/common/goldfish_vk_deepcopy.cpp
@@ -7802,6 +7802,207 @@
 }
 
 #endif
+#ifdef VK_EXT_image_drm_format_modifier
+void deepcopy_VkDrmFormatModifierPropertiesEXT(Allocator* alloc, VkStructureType rootType,
+                                               const VkDrmFormatModifierPropertiesEXT* from,
+                                               VkDrmFormatModifierPropertiesEXT* to) {
+    (void)alloc;
+    (void)rootType;
+    *to = *from;
+}
+
+void deepcopy_VkDrmFormatModifierPropertiesListEXT(Allocator* alloc, VkStructureType rootType,
+                                                   const VkDrmFormatModifierPropertiesListEXT* from,
+                                                   VkDrmFormatModifierPropertiesListEXT* to) {
+    (void)alloc;
+    (void)rootType;
+    *to = *from;
+    if (rootType == VK_STRUCTURE_TYPE_MAX_ENUM) {
+        rootType = from->sType;
+    }
+    const void* from_pNext = from;
+    size_t pNext_size = 0u;
+    while (!pNext_size && from_pNext) {
+        from_pNext = static_cast<const vk_struct_common*>(from_pNext)->pNext;
+        pNext_size = goldfish_vk_extension_struct_size(rootType, from_pNext);
+    }
+    to->pNext = nullptr;
+    if (pNext_size) {
+        to->pNext = (void*)alloc->alloc(pNext_size);
+        deepcopy_extension_struct(alloc, rootType, from_pNext, (void*)(to->pNext));
+    }
+    if (from) {
+        to->pDrmFormatModifierProperties = nullptr;
+        if (from->pDrmFormatModifierProperties) {
+            to->pDrmFormatModifierProperties = (VkDrmFormatModifierPropertiesEXT*)alloc->alloc(
+                from->drmFormatModifierCount * sizeof(VkDrmFormatModifierPropertiesEXT));
+            to->drmFormatModifierCount = from->drmFormatModifierCount;
+            for (uint32_t i = 0; i < (uint32_t)from->drmFormatModifierCount; ++i) {
+                deepcopy_VkDrmFormatModifierPropertiesEXT(
+                    alloc, rootType, from->pDrmFormatModifierProperties + i,
+                    (VkDrmFormatModifierPropertiesEXT*)(to->pDrmFormatModifierProperties + i));
+            }
+        }
+    }
+}
+
+void deepcopy_VkPhysicalDeviceImageDrmFormatModifierInfoEXT(
+    Allocator* alloc, VkStructureType rootType,
+    const VkPhysicalDeviceImageDrmFormatModifierInfoEXT* from,
+    VkPhysicalDeviceImageDrmFormatModifierInfoEXT* to) {
+    (void)alloc;
+    (void)rootType;
+    *to = *from;
+    if (rootType == VK_STRUCTURE_TYPE_MAX_ENUM) {
+        rootType = from->sType;
+    }
+    const void* from_pNext = from;
+    size_t pNext_size = 0u;
+    while (!pNext_size && from_pNext) {
+        from_pNext = static_cast<const vk_struct_common*>(from_pNext)->pNext;
+        pNext_size = goldfish_vk_extension_struct_size(rootType, from_pNext);
+    }
+    to->pNext = nullptr;
+    if (pNext_size) {
+        to->pNext = (void*)alloc->alloc(pNext_size);
+        deepcopy_extension_struct(alloc, rootType, from_pNext, (void*)(to->pNext));
+    }
+    to->pQueueFamilyIndices = nullptr;
+    if (from->pQueueFamilyIndices) {
+        to->pQueueFamilyIndices = (uint32_t*)alloc->dupArray(
+            from->pQueueFamilyIndices, from->queueFamilyIndexCount * sizeof(const uint32_t));
+    }
+}
+
+void deepcopy_VkImageDrmFormatModifierListCreateInfoEXT(
+    Allocator* alloc, VkStructureType rootType,
+    const VkImageDrmFormatModifierListCreateInfoEXT* from,
+    VkImageDrmFormatModifierListCreateInfoEXT* to) {
+    (void)alloc;
+    (void)rootType;
+    *to = *from;
+    if (rootType == VK_STRUCTURE_TYPE_MAX_ENUM) {
+        rootType = from->sType;
+    }
+    const void* from_pNext = from;
+    size_t pNext_size = 0u;
+    while (!pNext_size && from_pNext) {
+        from_pNext = static_cast<const vk_struct_common*>(from_pNext)->pNext;
+        pNext_size = goldfish_vk_extension_struct_size(rootType, from_pNext);
+    }
+    to->pNext = nullptr;
+    if (pNext_size) {
+        to->pNext = (void*)alloc->alloc(pNext_size);
+        deepcopy_extension_struct(alloc, rootType, from_pNext, (void*)(to->pNext));
+    }
+    to->pDrmFormatModifiers = nullptr;
+    if (from->pDrmFormatModifiers) {
+        to->pDrmFormatModifiers = (uint64_t*)alloc->dupArray(
+            from->pDrmFormatModifiers, from->drmFormatModifierCount * sizeof(const uint64_t));
+    }
+}
+
+void deepcopy_VkImageDrmFormatModifierExplicitCreateInfoEXT(
+    Allocator* alloc, VkStructureType rootType,
+    const VkImageDrmFormatModifierExplicitCreateInfoEXT* from,
+    VkImageDrmFormatModifierExplicitCreateInfoEXT* to) {
+    (void)alloc;
+    (void)rootType;
+    *to = *from;
+    if (rootType == VK_STRUCTURE_TYPE_MAX_ENUM) {
+        rootType = from->sType;
+    }
+    const void* from_pNext = from;
+    size_t pNext_size = 0u;
+    while (!pNext_size && from_pNext) {
+        from_pNext = static_cast<const vk_struct_common*>(from_pNext)->pNext;
+        pNext_size = goldfish_vk_extension_struct_size(rootType, from_pNext);
+    }
+    to->pNext = nullptr;
+    if (pNext_size) {
+        to->pNext = (void*)alloc->alloc(pNext_size);
+        deepcopy_extension_struct(alloc, rootType, from_pNext, (void*)(to->pNext));
+    }
+    if (from) {
+        to->pPlaneLayouts = nullptr;
+        if (from->pPlaneLayouts) {
+            to->pPlaneLayouts = (VkSubresourceLayout*)alloc->alloc(
+                from->drmFormatModifierPlaneCount * sizeof(const VkSubresourceLayout));
+            to->drmFormatModifierPlaneCount = from->drmFormatModifierPlaneCount;
+            for (uint32_t i = 0; i < (uint32_t)from->drmFormatModifierPlaneCount; ++i) {
+                deepcopy_VkSubresourceLayout(alloc, rootType, from->pPlaneLayouts + i,
+                                             (VkSubresourceLayout*)(to->pPlaneLayouts + i));
+            }
+        }
+    }
+}
+
+void deepcopy_VkImageDrmFormatModifierPropertiesEXT(
+    Allocator* alloc, VkStructureType rootType, const VkImageDrmFormatModifierPropertiesEXT* from,
+    VkImageDrmFormatModifierPropertiesEXT* to) {
+    (void)alloc;
+    (void)rootType;
+    *to = *from;
+    if (rootType == VK_STRUCTURE_TYPE_MAX_ENUM) {
+        rootType = from->sType;
+    }
+    const void* from_pNext = from;
+    size_t pNext_size = 0u;
+    while (!pNext_size && from_pNext) {
+        from_pNext = static_cast<const vk_struct_common*>(from_pNext)->pNext;
+        pNext_size = goldfish_vk_extension_struct_size(rootType, from_pNext);
+    }
+    to->pNext = nullptr;
+    if (pNext_size) {
+        to->pNext = (void*)alloc->alloc(pNext_size);
+        deepcopy_extension_struct(alloc, rootType, from_pNext, (void*)(to->pNext));
+    }
+}
+
+void deepcopy_VkDrmFormatModifierProperties2EXT(Allocator* alloc, VkStructureType rootType,
+                                                const VkDrmFormatModifierProperties2EXT* from,
+                                                VkDrmFormatModifierProperties2EXT* to) {
+    (void)alloc;
+    (void)rootType;
+    *to = *from;
+}
+
+void deepcopy_VkDrmFormatModifierPropertiesList2EXT(
+    Allocator* alloc, VkStructureType rootType, const VkDrmFormatModifierPropertiesList2EXT* from,
+    VkDrmFormatModifierPropertiesList2EXT* to) {
+    (void)alloc;
+    (void)rootType;
+    *to = *from;
+    if (rootType == VK_STRUCTURE_TYPE_MAX_ENUM) {
+        rootType = from->sType;
+    }
+    const void* from_pNext = from;
+    size_t pNext_size = 0u;
+    while (!pNext_size && from_pNext) {
+        from_pNext = static_cast<const vk_struct_common*>(from_pNext)->pNext;
+        pNext_size = goldfish_vk_extension_struct_size(rootType, from_pNext);
+    }
+    to->pNext = nullptr;
+    if (pNext_size) {
+        to->pNext = (void*)alloc->alloc(pNext_size);
+        deepcopy_extension_struct(alloc, rootType, from_pNext, (void*)(to->pNext));
+    }
+    if (from) {
+        to->pDrmFormatModifierProperties = nullptr;
+        if (from->pDrmFormatModifierProperties) {
+            to->pDrmFormatModifierProperties = (VkDrmFormatModifierProperties2EXT*)alloc->alloc(
+                from->drmFormatModifierCount * sizeof(VkDrmFormatModifierProperties2EXT));
+            to->drmFormatModifierCount = from->drmFormatModifierCount;
+            for (uint32_t i = 0; i < (uint32_t)from->drmFormatModifierCount; ++i) {
+                deepcopy_VkDrmFormatModifierProperties2EXT(
+                    alloc, rootType, from->pDrmFormatModifierProperties + i,
+                    (VkDrmFormatModifierProperties2EXT*)(to->pDrmFormatModifierProperties + i));
+            }
+        }
+    }
+}
+
+#endif
 #ifdef VK_EXT_external_memory_host
 void deepcopy_VkImportMemoryHostPointerInfoEXT(Allocator* alloc, VkStructureType rootType,
                                                const VkImportMemoryHostPointerInfoEXT* from,
@@ -10542,6 +10743,47 @@
             break;
         }
 #endif
+#ifdef VK_EXT_image_drm_format_modifier
+        case VK_STRUCTURE_TYPE_DRM_FORMAT_MODIFIER_PROPERTIES_LIST_EXT: {
+            deepcopy_VkDrmFormatModifierPropertiesListEXT(
+                alloc, rootType,
+                reinterpret_cast<const VkDrmFormatModifierPropertiesListEXT*>(structExtension),
+                reinterpret_cast<VkDrmFormatModifierPropertiesListEXT*>(structExtension_out));
+            break;
+        }
+        case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_DRM_FORMAT_MODIFIER_INFO_EXT: {
+            deepcopy_VkPhysicalDeviceImageDrmFormatModifierInfoEXT(
+                alloc, rootType,
+                reinterpret_cast<const VkPhysicalDeviceImageDrmFormatModifierInfoEXT*>(
+                    structExtension),
+                reinterpret_cast<VkPhysicalDeviceImageDrmFormatModifierInfoEXT*>(
+                    structExtension_out));
+            break;
+        }
+        case VK_STRUCTURE_TYPE_IMAGE_DRM_FORMAT_MODIFIER_LIST_CREATE_INFO_EXT: {
+            deepcopy_VkImageDrmFormatModifierListCreateInfoEXT(
+                alloc, rootType,
+                reinterpret_cast<const VkImageDrmFormatModifierListCreateInfoEXT*>(structExtension),
+                reinterpret_cast<VkImageDrmFormatModifierListCreateInfoEXT*>(structExtension_out));
+            break;
+        }
+        case VK_STRUCTURE_TYPE_IMAGE_DRM_FORMAT_MODIFIER_EXPLICIT_CREATE_INFO_EXT: {
+            deepcopy_VkImageDrmFormatModifierExplicitCreateInfoEXT(
+                alloc, rootType,
+                reinterpret_cast<const VkImageDrmFormatModifierExplicitCreateInfoEXT*>(
+                    structExtension),
+                reinterpret_cast<VkImageDrmFormatModifierExplicitCreateInfoEXT*>(
+                    structExtension_out));
+            break;
+        }
+        case VK_STRUCTURE_TYPE_DRM_FORMAT_MODIFIER_PROPERTIES_LIST_2_EXT: {
+            deepcopy_VkDrmFormatModifierPropertiesList2EXT(
+                alloc, rootType,
+                reinterpret_cast<const VkDrmFormatModifierPropertiesList2EXT*>(structExtension),
+                reinterpret_cast<VkDrmFormatModifierPropertiesList2EXT*>(structExtension_out));
+            break;
+        }
+#endif
 #ifdef VK_EXT_external_memory_host
         case VK_STRUCTURE_TYPE_IMPORT_MEMORY_HOST_POINTER_INFO_EXT: {
             deepcopy_VkImportMemoryHostPointerInfoEXT(
diff --git a/host/vulkan/cereal/common/goldfish_vk_deepcopy.h b/host/vulkan/cereal/common/goldfish_vk_deepcopy.h
index 86caae3..5b0ca70 100644
--- a/host/vulkan/cereal/common/goldfish_vk_deepcopy.h
+++ b/host/vulkan/cereal/common/goldfish_vk_deepcopy.h
@@ -1714,6 +1714,43 @@
                       deepcopy_VkDescriptorPoolInlineUniformBlockCreateInfoEXT)
 
 #endif
+#ifdef VK_EXT_image_drm_format_modifier
+void deepcopy_VkDrmFormatModifierPropertiesEXT(Allocator* alloc, VkStructureType rootType,
+                                               const VkDrmFormatModifierPropertiesEXT* from,
+                                               VkDrmFormatModifierPropertiesEXT* to);
+
+void deepcopy_VkDrmFormatModifierPropertiesListEXT(Allocator* alloc, VkStructureType rootType,
+                                                   const VkDrmFormatModifierPropertiesListEXT* from,
+                                                   VkDrmFormatModifierPropertiesListEXT* to);
+
+void deepcopy_VkPhysicalDeviceImageDrmFormatModifierInfoEXT(
+    Allocator* alloc, VkStructureType rootType,
+    const VkPhysicalDeviceImageDrmFormatModifierInfoEXT* from,
+    VkPhysicalDeviceImageDrmFormatModifierInfoEXT* to);
+
+void deepcopy_VkImageDrmFormatModifierListCreateInfoEXT(
+    Allocator* alloc, VkStructureType rootType,
+    const VkImageDrmFormatModifierListCreateInfoEXT* from,
+    VkImageDrmFormatModifierListCreateInfoEXT* to);
+
+void deepcopy_VkImageDrmFormatModifierExplicitCreateInfoEXT(
+    Allocator* alloc, VkStructureType rootType,
+    const VkImageDrmFormatModifierExplicitCreateInfoEXT* from,
+    VkImageDrmFormatModifierExplicitCreateInfoEXT* to);
+
+void deepcopy_VkImageDrmFormatModifierPropertiesEXT(
+    Allocator* alloc, VkStructureType rootType, const VkImageDrmFormatModifierPropertiesEXT* from,
+    VkImageDrmFormatModifierPropertiesEXT* to);
+
+void deepcopy_VkDrmFormatModifierProperties2EXT(Allocator* alloc, VkStructureType rootType,
+                                                const VkDrmFormatModifierProperties2EXT* from,
+                                                VkDrmFormatModifierProperties2EXT* to);
+
+void deepcopy_VkDrmFormatModifierPropertiesList2EXT(
+    Allocator* alloc, VkStructureType rootType, const VkDrmFormatModifierPropertiesList2EXT* from,
+    VkDrmFormatModifierPropertiesList2EXT* to);
+
+#endif
 #ifdef VK_EXT_external_memory_host
 void deepcopy_VkImportMemoryHostPointerInfoEXT(Allocator* alloc, VkStructureType rootType,
                                                const VkImportMemoryHostPointerInfoEXT* from,
diff --git a/host/vulkan/cereal/common/goldfish_vk_dispatch.cpp b/host/vulkan/cereal/common/goldfish_vk_dispatch.cpp
index 1f1ea67..7b1a434 100644
--- a/host/vulkan/cereal/common/goldfish_vk_dispatch.cpp
+++ b/host/vulkan/cereal/common/goldfish_vk_dispatch.cpp
@@ -659,6 +659,11 @@
     out->vkCmdInsertDebugUtilsLabelEXT =
         (PFN_vkCmdInsertDebugUtilsLabelEXT)dlSymFunc(lib, "vkCmdInsertDebugUtilsLabelEXT");
 #endif
+#ifdef VK_EXT_image_drm_format_modifier
+    out->vkGetImageDrmFormatModifierPropertiesEXT =
+        (PFN_vkGetImageDrmFormatModifierPropertiesEXT)dlSymFunc(
+            lib, "vkGetImageDrmFormatModifierPropertiesEXT");
+#endif
 #ifdef VK_EXT_external_memory_host
     out->vkGetMemoryHostPointerPropertiesEXT = (PFN_vkGetMemoryHostPointerPropertiesEXT)dlSymFunc(
         lib, "vkGetMemoryHostPointerPropertiesEXT");
@@ -1622,6 +1627,11 @@
         (PFN_vkCmdInsertDebugUtilsLabelEXT)vk->vkGetInstanceProcAddr(
             instance, "vkCmdInsertDebugUtilsLabelEXT");
 #endif
+#ifdef VK_EXT_image_drm_format_modifier
+    out->vkGetImageDrmFormatModifierPropertiesEXT =
+        (PFN_vkGetImageDrmFormatModifierPropertiesEXT)vk->vkGetInstanceProcAddr(
+            instance, "vkGetImageDrmFormatModifierPropertiesEXT");
+#endif
 #ifdef VK_EXT_external_memory_host
     out->vkGetMemoryHostPointerPropertiesEXT =
         (PFN_vkGetMemoryHostPointerPropertiesEXT)vk->vkGetInstanceProcAddr(
@@ -2594,6 +2604,11 @@
     out->vkCmdInsertDebugUtilsLabelEXT = (PFN_vkCmdInsertDebugUtilsLabelEXT)vk->vkGetDeviceProcAddr(
         device, "vkCmdInsertDebugUtilsLabelEXT");
 #endif
+#ifdef VK_EXT_image_drm_format_modifier
+    out->vkGetImageDrmFormatModifierPropertiesEXT =
+        (PFN_vkGetImageDrmFormatModifierPropertiesEXT)vk->vkGetDeviceProcAddr(
+            device, "vkGetImageDrmFormatModifierPropertiesEXT");
+#endif
 #ifdef VK_EXT_external_memory_host
     out->vkGetMemoryHostPointerPropertiesEXT =
         (PFN_vkGetMemoryHostPointerPropertiesEXT)vk->vkGetDeviceProcAddr(
diff --git a/host/vulkan/cereal/common/goldfish_vk_dispatch.h b/host/vulkan/cereal/common/goldfish_vk_dispatch.h
index 797f64d..34976fc 100644
--- a/host/vulkan/cereal/common/goldfish_vk_dispatch.h
+++ b/host/vulkan/cereal/common/goldfish_vk_dispatch.h
@@ -466,6 +466,9 @@
     PFN_vkDestroyDebugUtilsMessengerEXT vkDestroyDebugUtilsMessengerEXT;
     PFN_vkSubmitDebugUtilsMessageEXT vkSubmitDebugUtilsMessageEXT;
 #endif
+#ifdef VK_EXT_image_drm_format_modifier
+    PFN_vkGetImageDrmFormatModifierPropertiesEXT vkGetImageDrmFormatModifierPropertiesEXT;
+#endif
 #ifdef VK_EXT_external_memory_host
     PFN_vkGetMemoryHostPointerPropertiesEXT vkGetMemoryHostPointerPropertiesEXT;
 #endif
diff --git a/host/vulkan/cereal/common/goldfish_vk_marshaling.cpp b/host/vulkan/cereal/common/goldfish_vk_marshaling.cpp
index 08d09a6..11af645 100644
--- a/host/vulkan/cereal/common/goldfish_vk_marshaling.cpp
+++ b/host/vulkan/cereal/common/goldfish_vk_marshaling.cpp
@@ -15849,6 +15849,367 @@
 }
 
 #endif
+#ifdef VK_EXT_image_drm_format_modifier
+void marshal_VkDrmFormatModifierPropertiesEXT(
+    VulkanStream* vkStream, VkStructureType rootType,
+    const VkDrmFormatModifierPropertiesEXT* forMarshaling) {
+    (void)rootType;
+    vkStream->write((uint64_t*)&forMarshaling->drmFormatModifier, sizeof(uint64_t));
+    vkStream->write((uint32_t*)&forMarshaling->drmFormatModifierPlaneCount, sizeof(uint32_t));
+    vkStream->write((VkFormatFeatureFlags*)&forMarshaling->drmFormatModifierTilingFeatures,
+                    sizeof(VkFormatFeatureFlags));
+}
+
+void unmarshal_VkDrmFormatModifierPropertiesEXT(VulkanStream* vkStream, VkStructureType rootType,
+                                                VkDrmFormatModifierPropertiesEXT* forUnmarshaling) {
+    (void)rootType;
+    vkStream->read((uint64_t*)&forUnmarshaling->drmFormatModifier, sizeof(uint64_t));
+    vkStream->read((uint32_t*)&forUnmarshaling->drmFormatModifierPlaneCount, sizeof(uint32_t));
+    vkStream->read((VkFormatFeatureFlags*)&forUnmarshaling->drmFormatModifierTilingFeatures,
+                   sizeof(VkFormatFeatureFlags));
+}
+
+void marshal_VkDrmFormatModifierPropertiesListEXT(
+    VulkanStream* vkStream, VkStructureType rootType,
+    const VkDrmFormatModifierPropertiesListEXT* forMarshaling) {
+    (void)rootType;
+    vkStream->write((VkStructureType*)&forMarshaling->sType, sizeof(VkStructureType));
+    if (rootType == VK_STRUCTURE_TYPE_MAX_ENUM) {
+        rootType = forMarshaling->sType;
+    }
+    marshal_extension_struct(vkStream, rootType, forMarshaling->pNext);
+    vkStream->write((uint32_t*)&forMarshaling->drmFormatModifierCount, sizeof(uint32_t));
+    // WARNING PTR CHECK
+    uint64_t cgen_var_0 = (uint64_t)(uintptr_t)forMarshaling->pDrmFormatModifierProperties;
+    vkStream->putBe64(cgen_var_0);
+    if (forMarshaling->pDrmFormatModifierProperties) {
+        if (forMarshaling) {
+            for (uint32_t i = 0; i < (uint32_t)forMarshaling->drmFormatModifierCount; ++i) {
+                marshal_VkDrmFormatModifierPropertiesEXT(
+                    vkStream, rootType,
+                    (VkDrmFormatModifierPropertiesEXT*)(forMarshaling
+                                                            ->pDrmFormatModifierProperties +
+                                                        i));
+            }
+        }
+    }
+}
+
+void unmarshal_VkDrmFormatModifierPropertiesListEXT(
+    VulkanStream* vkStream, VkStructureType rootType,
+    VkDrmFormatModifierPropertiesListEXT* forUnmarshaling) {
+    (void)rootType;
+    vkStream->read((VkStructureType*)&forUnmarshaling->sType, sizeof(VkStructureType));
+    if (rootType == VK_STRUCTURE_TYPE_MAX_ENUM) {
+        rootType = forUnmarshaling->sType;
+    }
+    size_t pNext_size;
+    pNext_size = vkStream->getBe32();
+    forUnmarshaling->pNext = nullptr;
+    if (pNext_size) {
+        vkStream->alloc((void**)&forUnmarshaling->pNext, sizeof(VkStructureType));
+        vkStream->read((void*)forUnmarshaling->pNext, sizeof(VkStructureType));
+        VkStructureType extType = *(VkStructureType*)(forUnmarshaling->pNext);
+        vkStream->alloc((void**)&forUnmarshaling->pNext,
+                        goldfish_vk_extension_struct_size_with_stream_features(
+                            vkStream->getFeatureBits(), rootType, forUnmarshaling->pNext));
+        *(VkStructureType*)forUnmarshaling->pNext = extType;
+        unmarshal_extension_struct(vkStream, rootType, (void*)(forUnmarshaling->pNext));
+    }
+    vkStream->read((uint32_t*)&forUnmarshaling->drmFormatModifierCount, sizeof(uint32_t));
+    // WARNING PTR CHECK
+    forUnmarshaling->pDrmFormatModifierProperties =
+        (VkDrmFormatModifierPropertiesEXT*)(uintptr_t)vkStream->getBe64();
+    if (forUnmarshaling->pDrmFormatModifierProperties) {
+        vkStream->alloc(
+            (void**)&forUnmarshaling->pDrmFormatModifierProperties,
+            forUnmarshaling->drmFormatModifierCount * sizeof(VkDrmFormatModifierPropertiesEXT));
+        if (forUnmarshaling) {
+            for (uint32_t i = 0; i < (uint32_t)forUnmarshaling->drmFormatModifierCount; ++i) {
+                unmarshal_VkDrmFormatModifierPropertiesEXT(
+                    vkStream, rootType,
+                    (VkDrmFormatModifierPropertiesEXT*)(forUnmarshaling
+                                                            ->pDrmFormatModifierProperties +
+                                                        i));
+            }
+        }
+    }
+}
+
+void marshal_VkPhysicalDeviceImageDrmFormatModifierInfoEXT(
+    VulkanStream* vkStream, VkStructureType rootType,
+    const VkPhysicalDeviceImageDrmFormatModifierInfoEXT* forMarshaling) {
+    (void)rootType;
+    vkStream->write((VkStructureType*)&forMarshaling->sType, sizeof(VkStructureType));
+    if (rootType == VK_STRUCTURE_TYPE_MAX_ENUM) {
+        rootType = forMarshaling->sType;
+    }
+    marshal_extension_struct(vkStream, rootType, forMarshaling->pNext);
+    vkStream->write((uint64_t*)&forMarshaling->drmFormatModifier, sizeof(uint64_t));
+    vkStream->write((VkSharingMode*)&forMarshaling->sharingMode, sizeof(VkSharingMode));
+    vkStream->write((uint32_t*)&forMarshaling->queueFamilyIndexCount, sizeof(uint32_t));
+    // WARNING PTR CHECK
+    uint64_t cgen_var_0 = (uint64_t)(uintptr_t)forMarshaling->pQueueFamilyIndices;
+    vkStream->putBe64(cgen_var_0);
+    if (forMarshaling->pQueueFamilyIndices) {
+        vkStream->write((const uint32_t*)forMarshaling->pQueueFamilyIndices,
+                        forMarshaling->queueFamilyIndexCount * sizeof(const uint32_t));
+    }
+}
+
+void unmarshal_VkPhysicalDeviceImageDrmFormatModifierInfoEXT(
+    VulkanStream* vkStream, VkStructureType rootType,
+    VkPhysicalDeviceImageDrmFormatModifierInfoEXT* forUnmarshaling) {
+    (void)rootType;
+    vkStream->read((VkStructureType*)&forUnmarshaling->sType, sizeof(VkStructureType));
+    if (rootType == VK_STRUCTURE_TYPE_MAX_ENUM) {
+        rootType = forUnmarshaling->sType;
+    }
+    size_t pNext_size;
+    pNext_size = vkStream->getBe32();
+    forUnmarshaling->pNext = nullptr;
+    if (pNext_size) {
+        vkStream->alloc((void**)&forUnmarshaling->pNext, sizeof(VkStructureType));
+        vkStream->read((void*)forUnmarshaling->pNext, sizeof(VkStructureType));
+        VkStructureType extType = *(VkStructureType*)(forUnmarshaling->pNext);
+        vkStream->alloc((void**)&forUnmarshaling->pNext,
+                        goldfish_vk_extension_struct_size_with_stream_features(
+                            vkStream->getFeatureBits(), rootType, forUnmarshaling->pNext));
+        *(VkStructureType*)forUnmarshaling->pNext = extType;
+        unmarshal_extension_struct(vkStream, rootType, (void*)(forUnmarshaling->pNext));
+    }
+    vkStream->read((uint64_t*)&forUnmarshaling->drmFormatModifier, sizeof(uint64_t));
+    vkStream->read((VkSharingMode*)&forUnmarshaling->sharingMode, sizeof(VkSharingMode));
+    vkStream->read((uint32_t*)&forUnmarshaling->queueFamilyIndexCount, sizeof(uint32_t));
+    // WARNING PTR CHECK
+    forUnmarshaling->pQueueFamilyIndices = (const uint32_t*)(uintptr_t)vkStream->getBe64();
+    if (forUnmarshaling->pQueueFamilyIndices) {
+        vkStream->alloc((void**)&forUnmarshaling->pQueueFamilyIndices,
+                        forUnmarshaling->queueFamilyIndexCount * sizeof(const uint32_t));
+        vkStream->read((uint32_t*)forUnmarshaling->pQueueFamilyIndices,
+                       forUnmarshaling->queueFamilyIndexCount * sizeof(const uint32_t));
+    }
+}
+
+void marshal_VkImageDrmFormatModifierListCreateInfoEXT(
+    VulkanStream* vkStream, VkStructureType rootType,
+    const VkImageDrmFormatModifierListCreateInfoEXT* forMarshaling) {
+    (void)rootType;
+    vkStream->write((VkStructureType*)&forMarshaling->sType, sizeof(VkStructureType));
+    if (rootType == VK_STRUCTURE_TYPE_MAX_ENUM) {
+        rootType = forMarshaling->sType;
+    }
+    marshal_extension_struct(vkStream, rootType, forMarshaling->pNext);
+    vkStream->write((uint32_t*)&forMarshaling->drmFormatModifierCount, sizeof(uint32_t));
+    vkStream->write((const uint64_t*)forMarshaling->pDrmFormatModifiers,
+                    forMarshaling->drmFormatModifierCount * sizeof(const uint64_t));
+}
+
+void unmarshal_VkImageDrmFormatModifierListCreateInfoEXT(
+    VulkanStream* vkStream, VkStructureType rootType,
+    VkImageDrmFormatModifierListCreateInfoEXT* forUnmarshaling) {
+    (void)rootType;
+    vkStream->read((VkStructureType*)&forUnmarshaling->sType, sizeof(VkStructureType));
+    if (rootType == VK_STRUCTURE_TYPE_MAX_ENUM) {
+        rootType = forUnmarshaling->sType;
+    }
+    size_t pNext_size;
+    pNext_size = vkStream->getBe32();
+    forUnmarshaling->pNext = nullptr;
+    if (pNext_size) {
+        vkStream->alloc((void**)&forUnmarshaling->pNext, sizeof(VkStructureType));
+        vkStream->read((void*)forUnmarshaling->pNext, sizeof(VkStructureType));
+        VkStructureType extType = *(VkStructureType*)(forUnmarshaling->pNext);
+        vkStream->alloc((void**)&forUnmarshaling->pNext,
+                        goldfish_vk_extension_struct_size_with_stream_features(
+                            vkStream->getFeatureBits(), rootType, forUnmarshaling->pNext));
+        *(VkStructureType*)forUnmarshaling->pNext = extType;
+        unmarshal_extension_struct(vkStream, rootType, (void*)(forUnmarshaling->pNext));
+    }
+    vkStream->read((uint32_t*)&forUnmarshaling->drmFormatModifierCount, sizeof(uint32_t));
+    vkStream->alloc((void**)&forUnmarshaling->pDrmFormatModifiers,
+                    forUnmarshaling->drmFormatModifierCount * sizeof(const uint64_t));
+    vkStream->read((uint64_t*)forUnmarshaling->pDrmFormatModifiers,
+                   forUnmarshaling->drmFormatModifierCount * sizeof(const uint64_t));
+}
+
+void marshal_VkImageDrmFormatModifierExplicitCreateInfoEXT(
+    VulkanStream* vkStream, VkStructureType rootType,
+    const VkImageDrmFormatModifierExplicitCreateInfoEXT* forMarshaling) {
+    (void)rootType;
+    vkStream->write((VkStructureType*)&forMarshaling->sType, sizeof(VkStructureType));
+    if (rootType == VK_STRUCTURE_TYPE_MAX_ENUM) {
+        rootType = forMarshaling->sType;
+    }
+    marshal_extension_struct(vkStream, rootType, forMarshaling->pNext);
+    vkStream->write((uint64_t*)&forMarshaling->drmFormatModifier, sizeof(uint64_t));
+    vkStream->write((uint32_t*)&forMarshaling->drmFormatModifierPlaneCount, sizeof(uint32_t));
+    if (forMarshaling) {
+        for (uint32_t i = 0; i < (uint32_t)forMarshaling->drmFormatModifierPlaneCount; ++i) {
+            marshal_VkSubresourceLayout(
+                vkStream, rootType, (const VkSubresourceLayout*)(forMarshaling->pPlaneLayouts + i));
+        }
+    }
+}
+
+void unmarshal_VkImageDrmFormatModifierExplicitCreateInfoEXT(
+    VulkanStream* vkStream, VkStructureType rootType,
+    VkImageDrmFormatModifierExplicitCreateInfoEXT* forUnmarshaling) {
+    (void)rootType;
+    vkStream->read((VkStructureType*)&forUnmarshaling->sType, sizeof(VkStructureType));
+    if (rootType == VK_STRUCTURE_TYPE_MAX_ENUM) {
+        rootType = forUnmarshaling->sType;
+    }
+    size_t pNext_size;
+    pNext_size = vkStream->getBe32();
+    forUnmarshaling->pNext = nullptr;
+    if (pNext_size) {
+        vkStream->alloc((void**)&forUnmarshaling->pNext, sizeof(VkStructureType));
+        vkStream->read((void*)forUnmarshaling->pNext, sizeof(VkStructureType));
+        VkStructureType extType = *(VkStructureType*)(forUnmarshaling->pNext);
+        vkStream->alloc((void**)&forUnmarshaling->pNext,
+                        goldfish_vk_extension_struct_size_with_stream_features(
+                            vkStream->getFeatureBits(), rootType, forUnmarshaling->pNext));
+        *(VkStructureType*)forUnmarshaling->pNext = extType;
+        unmarshal_extension_struct(vkStream, rootType, (void*)(forUnmarshaling->pNext));
+    }
+    vkStream->read((uint64_t*)&forUnmarshaling->drmFormatModifier, sizeof(uint64_t));
+    vkStream->read((uint32_t*)&forUnmarshaling->drmFormatModifierPlaneCount, sizeof(uint32_t));
+    vkStream->alloc(
+        (void**)&forUnmarshaling->pPlaneLayouts,
+        forUnmarshaling->drmFormatModifierPlaneCount * sizeof(const VkSubresourceLayout));
+    if (forUnmarshaling) {
+        for (uint32_t i = 0; i < (uint32_t)forUnmarshaling->drmFormatModifierPlaneCount; ++i) {
+            unmarshal_VkSubresourceLayout(
+                vkStream, rootType, (VkSubresourceLayout*)(forUnmarshaling->pPlaneLayouts + i));
+        }
+    }
+}
+
+void marshal_VkImageDrmFormatModifierPropertiesEXT(
+    VulkanStream* vkStream, VkStructureType rootType,
+    const VkImageDrmFormatModifierPropertiesEXT* forMarshaling) {
+    (void)rootType;
+    vkStream->write((VkStructureType*)&forMarshaling->sType, sizeof(VkStructureType));
+    if (rootType == VK_STRUCTURE_TYPE_MAX_ENUM) {
+        rootType = forMarshaling->sType;
+    }
+    marshal_extension_struct(vkStream, rootType, forMarshaling->pNext);
+    vkStream->write((uint64_t*)&forMarshaling->drmFormatModifier, sizeof(uint64_t));
+}
+
+void unmarshal_VkImageDrmFormatModifierPropertiesEXT(
+    VulkanStream* vkStream, VkStructureType rootType,
+    VkImageDrmFormatModifierPropertiesEXT* forUnmarshaling) {
+    (void)rootType;
+    vkStream->read((VkStructureType*)&forUnmarshaling->sType, sizeof(VkStructureType));
+    if (rootType == VK_STRUCTURE_TYPE_MAX_ENUM) {
+        rootType = forUnmarshaling->sType;
+    }
+    size_t pNext_size;
+    pNext_size = vkStream->getBe32();
+    forUnmarshaling->pNext = nullptr;
+    if (pNext_size) {
+        vkStream->alloc((void**)&forUnmarshaling->pNext, sizeof(VkStructureType));
+        vkStream->read((void*)forUnmarshaling->pNext, sizeof(VkStructureType));
+        VkStructureType extType = *(VkStructureType*)(forUnmarshaling->pNext);
+        vkStream->alloc((void**)&forUnmarshaling->pNext,
+                        goldfish_vk_extension_struct_size_with_stream_features(
+                            vkStream->getFeatureBits(), rootType, forUnmarshaling->pNext));
+        *(VkStructureType*)forUnmarshaling->pNext = extType;
+        unmarshal_extension_struct(vkStream, rootType, (void*)(forUnmarshaling->pNext));
+    }
+    vkStream->read((uint64_t*)&forUnmarshaling->drmFormatModifier, sizeof(uint64_t));
+}
+
+void marshal_VkDrmFormatModifierProperties2EXT(
+    VulkanStream* vkStream, VkStructureType rootType,
+    const VkDrmFormatModifierProperties2EXT* forMarshaling) {
+    (void)rootType;
+    vkStream->write((uint64_t*)&forMarshaling->drmFormatModifier, sizeof(uint64_t));
+    vkStream->write((uint32_t*)&forMarshaling->drmFormatModifierPlaneCount, sizeof(uint32_t));
+    vkStream->write((VkFormatFeatureFlags2*)&forMarshaling->drmFormatModifierTilingFeatures,
+                    sizeof(VkFormatFeatureFlags2));
+}
+
+void unmarshal_VkDrmFormatModifierProperties2EXT(
+    VulkanStream* vkStream, VkStructureType rootType,
+    VkDrmFormatModifierProperties2EXT* forUnmarshaling) {
+    (void)rootType;
+    vkStream->read((uint64_t*)&forUnmarshaling->drmFormatModifier, sizeof(uint64_t));
+    vkStream->read((uint32_t*)&forUnmarshaling->drmFormatModifierPlaneCount, sizeof(uint32_t));
+    vkStream->read((VkFormatFeatureFlags2*)&forUnmarshaling->drmFormatModifierTilingFeatures,
+                   sizeof(VkFormatFeatureFlags2));
+}
+
+void marshal_VkDrmFormatModifierPropertiesList2EXT(
+    VulkanStream* vkStream, VkStructureType rootType,
+    const VkDrmFormatModifierPropertiesList2EXT* forMarshaling) {
+    (void)rootType;
+    vkStream->write((VkStructureType*)&forMarshaling->sType, sizeof(VkStructureType));
+    if (rootType == VK_STRUCTURE_TYPE_MAX_ENUM) {
+        rootType = forMarshaling->sType;
+    }
+    marshal_extension_struct(vkStream, rootType, forMarshaling->pNext);
+    vkStream->write((uint32_t*)&forMarshaling->drmFormatModifierCount, sizeof(uint32_t));
+    // WARNING PTR CHECK
+    uint64_t cgen_var_0 = (uint64_t)(uintptr_t)forMarshaling->pDrmFormatModifierProperties;
+    vkStream->putBe64(cgen_var_0);
+    if (forMarshaling->pDrmFormatModifierProperties) {
+        if (forMarshaling) {
+            for (uint32_t i = 0; i < (uint32_t)forMarshaling->drmFormatModifierCount; ++i) {
+                marshal_VkDrmFormatModifierProperties2EXT(
+                    vkStream, rootType,
+                    (VkDrmFormatModifierProperties2EXT*)(forMarshaling
+                                                             ->pDrmFormatModifierProperties +
+                                                         i));
+            }
+        }
+    }
+}
+
+void unmarshal_VkDrmFormatModifierPropertiesList2EXT(
+    VulkanStream* vkStream, VkStructureType rootType,
+    VkDrmFormatModifierPropertiesList2EXT* forUnmarshaling) {
+    (void)rootType;
+    vkStream->read((VkStructureType*)&forUnmarshaling->sType, sizeof(VkStructureType));
+    if (rootType == VK_STRUCTURE_TYPE_MAX_ENUM) {
+        rootType = forUnmarshaling->sType;
+    }
+    size_t pNext_size;
+    pNext_size = vkStream->getBe32();
+    forUnmarshaling->pNext = nullptr;
+    if (pNext_size) {
+        vkStream->alloc((void**)&forUnmarshaling->pNext, sizeof(VkStructureType));
+        vkStream->read((void*)forUnmarshaling->pNext, sizeof(VkStructureType));
+        VkStructureType extType = *(VkStructureType*)(forUnmarshaling->pNext);
+        vkStream->alloc((void**)&forUnmarshaling->pNext,
+                        goldfish_vk_extension_struct_size_with_stream_features(
+                            vkStream->getFeatureBits(), rootType, forUnmarshaling->pNext));
+        *(VkStructureType*)forUnmarshaling->pNext = extType;
+        unmarshal_extension_struct(vkStream, rootType, (void*)(forUnmarshaling->pNext));
+    }
+    vkStream->read((uint32_t*)&forUnmarshaling->drmFormatModifierCount, sizeof(uint32_t));
+    // WARNING PTR CHECK
+    forUnmarshaling->pDrmFormatModifierProperties =
+        (VkDrmFormatModifierProperties2EXT*)(uintptr_t)vkStream->getBe64();
+    if (forUnmarshaling->pDrmFormatModifierProperties) {
+        vkStream->alloc(
+            (void**)&forUnmarshaling->pDrmFormatModifierProperties,
+            forUnmarshaling->drmFormatModifierCount * sizeof(VkDrmFormatModifierProperties2EXT));
+        if (forUnmarshaling) {
+            for (uint32_t i = 0; i < (uint32_t)forUnmarshaling->drmFormatModifierCount; ++i) {
+                unmarshal_VkDrmFormatModifierProperties2EXT(
+                    vkStream, rootType,
+                    (VkDrmFormatModifierProperties2EXT*)(forUnmarshaling
+                                                             ->pDrmFormatModifierProperties +
+                                                         i));
+            }
+        }
+    }
+}
+
+#endif
 #ifdef VK_EXT_external_memory_host
 void marshal_VkImportMemoryHostPointerInfoEXT(
     VulkanStream* vkStream, VkStructureType rootType,
@@ -19707,6 +20068,41 @@
             break;
         }
 #endif
+#ifdef VK_EXT_image_drm_format_modifier
+        case VK_STRUCTURE_TYPE_DRM_FORMAT_MODIFIER_PROPERTIES_LIST_EXT: {
+            marshal_VkDrmFormatModifierPropertiesListEXT(
+                vkStream, rootType,
+                reinterpret_cast<const VkDrmFormatModifierPropertiesListEXT*>(structExtension));
+            break;
+        }
+        case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_DRM_FORMAT_MODIFIER_INFO_EXT: {
+            marshal_VkPhysicalDeviceImageDrmFormatModifierInfoEXT(
+                vkStream, rootType,
+                reinterpret_cast<const VkPhysicalDeviceImageDrmFormatModifierInfoEXT*>(
+                    structExtension));
+            break;
+        }
+        case VK_STRUCTURE_TYPE_IMAGE_DRM_FORMAT_MODIFIER_LIST_CREATE_INFO_EXT: {
+            marshal_VkImageDrmFormatModifierListCreateInfoEXT(
+                vkStream, rootType,
+                reinterpret_cast<const VkImageDrmFormatModifierListCreateInfoEXT*>(
+                    structExtension));
+            break;
+        }
+        case VK_STRUCTURE_TYPE_IMAGE_DRM_FORMAT_MODIFIER_EXPLICIT_CREATE_INFO_EXT: {
+            marshal_VkImageDrmFormatModifierExplicitCreateInfoEXT(
+                vkStream, rootType,
+                reinterpret_cast<const VkImageDrmFormatModifierExplicitCreateInfoEXT*>(
+                    structExtension));
+            break;
+        }
+        case VK_STRUCTURE_TYPE_DRM_FORMAT_MODIFIER_PROPERTIES_LIST_2_EXT: {
+            marshal_VkDrmFormatModifierPropertiesList2EXT(
+                vkStream, rootType,
+                reinterpret_cast<const VkDrmFormatModifierPropertiesList2EXT*>(structExtension));
+            break;
+        }
+#endif
 #ifdef VK_EXT_external_memory_host
         case VK_STRUCTURE_TYPE_IMPORT_MEMORY_HOST_POINTER_INFO_EXT: {
             marshal_VkImportMemoryHostPointerInfoEXT(
@@ -21051,6 +21447,40 @@
             break;
         }
 #endif
+#ifdef VK_EXT_image_drm_format_modifier
+        case VK_STRUCTURE_TYPE_DRM_FORMAT_MODIFIER_PROPERTIES_LIST_EXT: {
+            unmarshal_VkDrmFormatModifierPropertiesListEXT(
+                vkStream, rootType,
+                reinterpret_cast<VkDrmFormatModifierPropertiesListEXT*>(structExtension_out));
+            break;
+        }
+        case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_DRM_FORMAT_MODIFIER_INFO_EXT: {
+            unmarshal_VkPhysicalDeviceImageDrmFormatModifierInfoEXT(
+                vkStream, rootType,
+                reinterpret_cast<VkPhysicalDeviceImageDrmFormatModifierInfoEXT*>(
+                    structExtension_out));
+            break;
+        }
+        case VK_STRUCTURE_TYPE_IMAGE_DRM_FORMAT_MODIFIER_LIST_CREATE_INFO_EXT: {
+            unmarshal_VkImageDrmFormatModifierListCreateInfoEXT(
+                vkStream, rootType,
+                reinterpret_cast<VkImageDrmFormatModifierListCreateInfoEXT*>(structExtension_out));
+            break;
+        }
+        case VK_STRUCTURE_TYPE_IMAGE_DRM_FORMAT_MODIFIER_EXPLICIT_CREATE_INFO_EXT: {
+            unmarshal_VkImageDrmFormatModifierExplicitCreateInfoEXT(
+                vkStream, rootType,
+                reinterpret_cast<VkImageDrmFormatModifierExplicitCreateInfoEXT*>(
+                    structExtension_out));
+            break;
+        }
+        case VK_STRUCTURE_TYPE_DRM_FORMAT_MODIFIER_PROPERTIES_LIST_2_EXT: {
+            unmarshal_VkDrmFormatModifierPropertiesList2EXT(
+                vkStream, rootType,
+                reinterpret_cast<VkDrmFormatModifierPropertiesList2EXT*>(structExtension_out));
+            break;
+        }
+#endif
 #ifdef VK_EXT_external_memory_host
         case VK_STRUCTURE_TYPE_IMPORT_MEMORY_HOST_POINTER_INFO_EXT: {
             unmarshal_VkImportMemoryHostPointerInfoEXT(
@@ -22590,6 +23020,11 @@
             return "OP_vkCmdCopyBufferToImage2KHR";
         }
 #endif
+#ifdef VK_EXT_image_drm_format_modifier
+        case OP_vkGetImageDrmFormatModifierPropertiesEXT: {
+            return "OP_vkGetImageDrmFormatModifierPropertiesEXT";
+        }
+#endif
 #ifdef VK_VERSION_1_2
         case OP_vkResetQueryPool: {
             return "OP_vkResetQueryPool";
diff --git a/host/vulkan/cereal/common/goldfish_vk_marshaling.h b/host/vulkan/cereal/common/goldfish_vk_marshaling.h
index a8ccf33..43e016b 100644
--- a/host/vulkan/cereal/common/goldfish_vk_marshaling.h
+++ b/host/vulkan/cereal/common/goldfish_vk_marshaling.h
@@ -3263,6 +3263,72 @@
                       unmarshal_VkDescriptorPoolInlineUniformBlockCreateInfoEXT)
 
 #endif
+#ifdef VK_EXT_image_drm_format_modifier
+void marshal_VkDrmFormatModifierPropertiesEXT(
+    VulkanStream* vkStream, VkStructureType rootType,
+    const VkDrmFormatModifierPropertiesEXT* forMarshaling);
+
+void unmarshal_VkDrmFormatModifierPropertiesEXT(VulkanStream* vkStream, VkStructureType rootType,
+                                                VkDrmFormatModifierPropertiesEXT* forUnmarshaling);
+
+void marshal_VkDrmFormatModifierPropertiesListEXT(
+    VulkanStream* vkStream, VkStructureType rootType,
+    const VkDrmFormatModifierPropertiesListEXT* forMarshaling);
+
+void unmarshal_VkDrmFormatModifierPropertiesListEXT(
+    VulkanStream* vkStream, VkStructureType rootType,
+    VkDrmFormatModifierPropertiesListEXT* forUnmarshaling);
+
+void marshal_VkPhysicalDeviceImageDrmFormatModifierInfoEXT(
+    VulkanStream* vkStream, VkStructureType rootType,
+    const VkPhysicalDeviceImageDrmFormatModifierInfoEXT* forMarshaling);
+
+void unmarshal_VkPhysicalDeviceImageDrmFormatModifierInfoEXT(
+    VulkanStream* vkStream, VkStructureType rootType,
+    VkPhysicalDeviceImageDrmFormatModifierInfoEXT* forUnmarshaling);
+
+void marshal_VkImageDrmFormatModifierListCreateInfoEXT(
+    VulkanStream* vkStream, VkStructureType rootType,
+    const VkImageDrmFormatModifierListCreateInfoEXT* forMarshaling);
+
+void unmarshal_VkImageDrmFormatModifierListCreateInfoEXT(
+    VulkanStream* vkStream, VkStructureType rootType,
+    VkImageDrmFormatModifierListCreateInfoEXT* forUnmarshaling);
+
+void marshal_VkImageDrmFormatModifierExplicitCreateInfoEXT(
+    VulkanStream* vkStream, VkStructureType rootType,
+    const VkImageDrmFormatModifierExplicitCreateInfoEXT* forMarshaling);
+
+void unmarshal_VkImageDrmFormatModifierExplicitCreateInfoEXT(
+    VulkanStream* vkStream, VkStructureType rootType,
+    VkImageDrmFormatModifierExplicitCreateInfoEXT* forUnmarshaling);
+
+void marshal_VkImageDrmFormatModifierPropertiesEXT(
+    VulkanStream* vkStream, VkStructureType rootType,
+    const VkImageDrmFormatModifierPropertiesEXT* forMarshaling);
+
+void unmarshal_VkImageDrmFormatModifierPropertiesEXT(
+    VulkanStream* vkStream, VkStructureType rootType,
+    VkImageDrmFormatModifierPropertiesEXT* forUnmarshaling);
+
+#define OP_vkGetImageDrmFormatModifierPropertiesEXT 251301237
+void marshal_VkDrmFormatModifierProperties2EXT(
+    VulkanStream* vkStream, VkStructureType rootType,
+    const VkDrmFormatModifierProperties2EXT* forMarshaling);
+
+void unmarshal_VkDrmFormatModifierProperties2EXT(
+    VulkanStream* vkStream, VkStructureType rootType,
+    VkDrmFormatModifierProperties2EXT* forUnmarshaling);
+
+void marshal_VkDrmFormatModifierPropertiesList2EXT(
+    VulkanStream* vkStream, VkStructureType rootType,
+    const VkDrmFormatModifierPropertiesList2EXT* forMarshaling);
+
+void unmarshal_VkDrmFormatModifierPropertiesList2EXT(
+    VulkanStream* vkStream, VkStructureType rootType,
+    VkDrmFormatModifierPropertiesList2EXT* forUnmarshaling);
+
+#endif
 #ifdef VK_EXT_external_memory_host
 void marshal_VkImportMemoryHostPointerInfoEXT(
     VulkanStream* vkStream, VkStructureType rootType,
diff --git a/host/vulkan/cereal/common/goldfish_vk_reserved_marshaling.cpp b/host/vulkan/cereal/common/goldfish_vk_reserved_marshaling.cpp
index 1c32f0c..ec3c954 100644
--- a/host/vulkan/cereal/common/goldfish_vk_reserved_marshaling.cpp
+++ b/host/vulkan/cereal/common/goldfish_vk_reserved_marshaling.cpp
@@ -12217,6 +12217,269 @@
 }
 
 #endif
+#ifdef VK_EXT_image_drm_format_modifier
+void reservedunmarshal_VkDrmFormatModifierPropertiesEXT(
+    VulkanStream* vkStream, VkStructureType rootType,
+    VkDrmFormatModifierPropertiesEXT* forUnmarshaling, uint8_t** ptr) {
+    memcpy((uint64_t*)&forUnmarshaling->drmFormatModifier, *ptr, sizeof(uint64_t));
+    *ptr += sizeof(uint64_t);
+    memcpy((uint32_t*)&forUnmarshaling->drmFormatModifierPlaneCount, *ptr, sizeof(uint32_t));
+    *ptr += sizeof(uint32_t);
+    memcpy((VkFormatFeatureFlags*)&forUnmarshaling->drmFormatModifierTilingFeatures, *ptr,
+           sizeof(VkFormatFeatureFlags));
+    *ptr += sizeof(VkFormatFeatureFlags);
+}
+
+void reservedunmarshal_VkDrmFormatModifierPropertiesListEXT(
+    VulkanStream* vkStream, VkStructureType rootType,
+    VkDrmFormatModifierPropertiesListEXT* forUnmarshaling, uint8_t** ptr) {
+    memcpy((VkStructureType*)&forUnmarshaling->sType, *ptr, sizeof(VkStructureType));
+    *ptr += sizeof(VkStructureType);
+    if (rootType == VK_STRUCTURE_TYPE_MAX_ENUM) {
+        rootType = forUnmarshaling->sType;
+    }
+    uint32_t pNext_size;
+    memcpy((uint32_t*)&pNext_size, *ptr, sizeof(uint32_t));
+    android::base::Stream::fromBe32((uint8_t*)&pNext_size);
+    *ptr += sizeof(uint32_t);
+    forUnmarshaling->pNext = nullptr;
+    if (pNext_size) {
+        vkStream->alloc((void**)&forUnmarshaling->pNext, sizeof(VkStructureType));
+        memcpy((void*)forUnmarshaling->pNext, *ptr, sizeof(VkStructureType));
+        *ptr += sizeof(VkStructureType);
+        VkStructureType extType = *(VkStructureType*)(forUnmarshaling->pNext);
+        vkStream->alloc((void**)&forUnmarshaling->pNext,
+                        goldfish_vk_extension_struct_size_with_stream_features(
+                            vkStream->getFeatureBits(), rootType, forUnmarshaling->pNext));
+        *(VkStructureType*)forUnmarshaling->pNext = extType;
+        reservedunmarshal_extension_struct(vkStream, rootType, (void*)(forUnmarshaling->pNext),
+                                           ptr);
+    }
+    memcpy((uint32_t*)&forUnmarshaling->drmFormatModifierCount, *ptr, sizeof(uint32_t));
+    *ptr += sizeof(uint32_t);
+    // WARNING PTR CHECK
+    memcpy((VkDrmFormatModifierPropertiesEXT**)&forUnmarshaling->pDrmFormatModifierProperties,
+           (*ptr), 8);
+    android::base::Stream::fromBe64((uint8_t*)&forUnmarshaling->pDrmFormatModifierProperties);
+    *ptr += 8;
+    if (forUnmarshaling->pDrmFormatModifierProperties) {
+        vkStream->alloc(
+            (void**)&forUnmarshaling->pDrmFormatModifierProperties,
+            forUnmarshaling->drmFormatModifierCount * sizeof(VkDrmFormatModifierPropertiesEXT));
+        for (uint32_t i = 0; i < (uint32_t)forUnmarshaling->drmFormatModifierCount; ++i) {
+            reservedunmarshal_VkDrmFormatModifierPropertiesEXT(
+                vkStream, rootType,
+                (VkDrmFormatModifierPropertiesEXT*)(forUnmarshaling->pDrmFormatModifierProperties +
+                                                    i),
+                ptr);
+        }
+    }
+}
+
+void reservedunmarshal_VkPhysicalDeviceImageDrmFormatModifierInfoEXT(
+    VulkanStream* vkStream, VkStructureType rootType,
+    VkPhysicalDeviceImageDrmFormatModifierInfoEXT* forUnmarshaling, uint8_t** ptr) {
+    memcpy((VkStructureType*)&forUnmarshaling->sType, *ptr, sizeof(VkStructureType));
+    *ptr += sizeof(VkStructureType);
+    if (rootType == VK_STRUCTURE_TYPE_MAX_ENUM) {
+        rootType = forUnmarshaling->sType;
+    }
+    uint32_t pNext_size;
+    memcpy((uint32_t*)&pNext_size, *ptr, sizeof(uint32_t));
+    android::base::Stream::fromBe32((uint8_t*)&pNext_size);
+    *ptr += sizeof(uint32_t);
+    forUnmarshaling->pNext = nullptr;
+    if (pNext_size) {
+        vkStream->alloc((void**)&forUnmarshaling->pNext, sizeof(VkStructureType));
+        memcpy((void*)forUnmarshaling->pNext, *ptr, sizeof(VkStructureType));
+        *ptr += sizeof(VkStructureType);
+        VkStructureType extType = *(VkStructureType*)(forUnmarshaling->pNext);
+        vkStream->alloc((void**)&forUnmarshaling->pNext,
+                        goldfish_vk_extension_struct_size_with_stream_features(
+                            vkStream->getFeatureBits(), rootType, forUnmarshaling->pNext));
+        *(VkStructureType*)forUnmarshaling->pNext = extType;
+        reservedunmarshal_extension_struct(vkStream, rootType, (void*)(forUnmarshaling->pNext),
+                                           ptr);
+    }
+    memcpy((uint64_t*)&forUnmarshaling->drmFormatModifier, *ptr, sizeof(uint64_t));
+    *ptr += sizeof(uint64_t);
+    memcpy((VkSharingMode*)&forUnmarshaling->sharingMode, *ptr, sizeof(VkSharingMode));
+    *ptr += sizeof(VkSharingMode);
+    memcpy((uint32_t*)&forUnmarshaling->queueFamilyIndexCount, *ptr, sizeof(uint32_t));
+    *ptr += sizeof(uint32_t);
+    // WARNING PTR CHECK
+    memcpy((uint32_t**)&forUnmarshaling->pQueueFamilyIndices, (*ptr), 8);
+    android::base::Stream::fromBe64((uint8_t*)&forUnmarshaling->pQueueFamilyIndices);
+    *ptr += 8;
+    if (forUnmarshaling->pQueueFamilyIndices) {
+        vkStream->alloc((void**)&forUnmarshaling->pQueueFamilyIndices,
+                        forUnmarshaling->queueFamilyIndexCount * sizeof(const uint32_t));
+        memcpy((uint32_t*)forUnmarshaling->pQueueFamilyIndices, *ptr,
+               forUnmarshaling->queueFamilyIndexCount * sizeof(const uint32_t));
+        *ptr += forUnmarshaling->queueFamilyIndexCount * sizeof(const uint32_t);
+    }
+}
+
+void reservedunmarshal_VkImageDrmFormatModifierListCreateInfoEXT(
+    VulkanStream* vkStream, VkStructureType rootType,
+    VkImageDrmFormatModifierListCreateInfoEXT* forUnmarshaling, uint8_t** ptr) {
+    memcpy((VkStructureType*)&forUnmarshaling->sType, *ptr, sizeof(VkStructureType));
+    *ptr += sizeof(VkStructureType);
+    if (rootType == VK_STRUCTURE_TYPE_MAX_ENUM) {
+        rootType = forUnmarshaling->sType;
+    }
+    uint32_t pNext_size;
+    memcpy((uint32_t*)&pNext_size, *ptr, sizeof(uint32_t));
+    android::base::Stream::fromBe32((uint8_t*)&pNext_size);
+    *ptr += sizeof(uint32_t);
+    forUnmarshaling->pNext = nullptr;
+    if (pNext_size) {
+        vkStream->alloc((void**)&forUnmarshaling->pNext, sizeof(VkStructureType));
+        memcpy((void*)forUnmarshaling->pNext, *ptr, sizeof(VkStructureType));
+        *ptr += sizeof(VkStructureType);
+        VkStructureType extType = *(VkStructureType*)(forUnmarshaling->pNext);
+        vkStream->alloc((void**)&forUnmarshaling->pNext,
+                        goldfish_vk_extension_struct_size_with_stream_features(
+                            vkStream->getFeatureBits(), rootType, forUnmarshaling->pNext));
+        *(VkStructureType*)forUnmarshaling->pNext = extType;
+        reservedunmarshal_extension_struct(vkStream, rootType, (void*)(forUnmarshaling->pNext),
+                                           ptr);
+    }
+    memcpy((uint32_t*)&forUnmarshaling->drmFormatModifierCount, *ptr, sizeof(uint32_t));
+    *ptr += sizeof(uint32_t);
+    vkStream->alloc((void**)&forUnmarshaling->pDrmFormatModifiers,
+                    forUnmarshaling->drmFormatModifierCount * sizeof(const uint64_t));
+    memcpy((uint64_t*)forUnmarshaling->pDrmFormatModifiers, *ptr,
+           forUnmarshaling->drmFormatModifierCount * sizeof(const uint64_t));
+    *ptr += forUnmarshaling->drmFormatModifierCount * sizeof(const uint64_t);
+}
+
+void reservedunmarshal_VkImageDrmFormatModifierExplicitCreateInfoEXT(
+    VulkanStream* vkStream, VkStructureType rootType,
+    VkImageDrmFormatModifierExplicitCreateInfoEXT* forUnmarshaling, uint8_t** ptr) {
+    memcpy((VkStructureType*)&forUnmarshaling->sType, *ptr, sizeof(VkStructureType));
+    *ptr += sizeof(VkStructureType);
+    if (rootType == VK_STRUCTURE_TYPE_MAX_ENUM) {
+        rootType = forUnmarshaling->sType;
+    }
+    uint32_t pNext_size;
+    memcpy((uint32_t*)&pNext_size, *ptr, sizeof(uint32_t));
+    android::base::Stream::fromBe32((uint8_t*)&pNext_size);
+    *ptr += sizeof(uint32_t);
+    forUnmarshaling->pNext = nullptr;
+    if (pNext_size) {
+        vkStream->alloc((void**)&forUnmarshaling->pNext, sizeof(VkStructureType));
+        memcpy((void*)forUnmarshaling->pNext, *ptr, sizeof(VkStructureType));
+        *ptr += sizeof(VkStructureType);
+        VkStructureType extType = *(VkStructureType*)(forUnmarshaling->pNext);
+        vkStream->alloc((void**)&forUnmarshaling->pNext,
+                        goldfish_vk_extension_struct_size_with_stream_features(
+                            vkStream->getFeatureBits(), rootType, forUnmarshaling->pNext));
+        *(VkStructureType*)forUnmarshaling->pNext = extType;
+        reservedunmarshal_extension_struct(vkStream, rootType, (void*)(forUnmarshaling->pNext),
+                                           ptr);
+    }
+    memcpy((uint64_t*)&forUnmarshaling->drmFormatModifier, *ptr, sizeof(uint64_t));
+    *ptr += sizeof(uint64_t);
+    memcpy((uint32_t*)&forUnmarshaling->drmFormatModifierPlaneCount, *ptr, sizeof(uint32_t));
+    *ptr += sizeof(uint32_t);
+    vkStream->alloc(
+        (void**)&forUnmarshaling->pPlaneLayouts,
+        forUnmarshaling->drmFormatModifierPlaneCount * sizeof(const VkSubresourceLayout));
+    for (uint32_t i = 0; i < (uint32_t)forUnmarshaling->drmFormatModifierPlaneCount; ++i) {
+        reservedunmarshal_VkSubresourceLayout(
+            vkStream, rootType, (VkSubresourceLayout*)(forUnmarshaling->pPlaneLayouts + i), ptr);
+    }
+}
+
+void reservedunmarshal_VkImageDrmFormatModifierPropertiesEXT(
+    VulkanStream* vkStream, VkStructureType rootType,
+    VkImageDrmFormatModifierPropertiesEXT* forUnmarshaling, uint8_t** ptr) {
+    memcpy((VkStructureType*)&forUnmarshaling->sType, *ptr, sizeof(VkStructureType));
+    *ptr += sizeof(VkStructureType);
+    if (rootType == VK_STRUCTURE_TYPE_MAX_ENUM) {
+        rootType = forUnmarshaling->sType;
+    }
+    uint32_t pNext_size;
+    memcpy((uint32_t*)&pNext_size, *ptr, sizeof(uint32_t));
+    android::base::Stream::fromBe32((uint8_t*)&pNext_size);
+    *ptr += sizeof(uint32_t);
+    forUnmarshaling->pNext = nullptr;
+    if (pNext_size) {
+        vkStream->alloc((void**)&forUnmarshaling->pNext, sizeof(VkStructureType));
+        memcpy((void*)forUnmarshaling->pNext, *ptr, sizeof(VkStructureType));
+        *ptr += sizeof(VkStructureType);
+        VkStructureType extType = *(VkStructureType*)(forUnmarshaling->pNext);
+        vkStream->alloc((void**)&forUnmarshaling->pNext,
+                        goldfish_vk_extension_struct_size_with_stream_features(
+                            vkStream->getFeatureBits(), rootType, forUnmarshaling->pNext));
+        *(VkStructureType*)forUnmarshaling->pNext = extType;
+        reservedunmarshal_extension_struct(vkStream, rootType, (void*)(forUnmarshaling->pNext),
+                                           ptr);
+    }
+    memcpy((uint64_t*)&forUnmarshaling->drmFormatModifier, *ptr, sizeof(uint64_t));
+    *ptr += sizeof(uint64_t);
+}
+
+void reservedunmarshal_VkDrmFormatModifierProperties2EXT(
+    VulkanStream* vkStream, VkStructureType rootType,
+    VkDrmFormatModifierProperties2EXT* forUnmarshaling, uint8_t** ptr) {
+    memcpy((uint64_t*)&forUnmarshaling->drmFormatModifier, *ptr, sizeof(uint64_t));
+    *ptr += sizeof(uint64_t);
+    memcpy((uint32_t*)&forUnmarshaling->drmFormatModifierPlaneCount, *ptr, sizeof(uint32_t));
+    *ptr += sizeof(uint32_t);
+    memcpy((VkFormatFeatureFlags2*)&forUnmarshaling->drmFormatModifierTilingFeatures, *ptr,
+           sizeof(VkFormatFeatureFlags2));
+    *ptr += sizeof(VkFormatFeatureFlags2);
+}
+
+void reservedunmarshal_VkDrmFormatModifierPropertiesList2EXT(
+    VulkanStream* vkStream, VkStructureType rootType,
+    VkDrmFormatModifierPropertiesList2EXT* forUnmarshaling, uint8_t** ptr) {
+    memcpy((VkStructureType*)&forUnmarshaling->sType, *ptr, sizeof(VkStructureType));
+    *ptr += sizeof(VkStructureType);
+    if (rootType == VK_STRUCTURE_TYPE_MAX_ENUM) {
+        rootType = forUnmarshaling->sType;
+    }
+    uint32_t pNext_size;
+    memcpy((uint32_t*)&pNext_size, *ptr, sizeof(uint32_t));
+    android::base::Stream::fromBe32((uint8_t*)&pNext_size);
+    *ptr += sizeof(uint32_t);
+    forUnmarshaling->pNext = nullptr;
+    if (pNext_size) {
+        vkStream->alloc((void**)&forUnmarshaling->pNext, sizeof(VkStructureType));
+        memcpy((void*)forUnmarshaling->pNext, *ptr, sizeof(VkStructureType));
+        *ptr += sizeof(VkStructureType);
+        VkStructureType extType = *(VkStructureType*)(forUnmarshaling->pNext);
+        vkStream->alloc((void**)&forUnmarshaling->pNext,
+                        goldfish_vk_extension_struct_size_with_stream_features(
+                            vkStream->getFeatureBits(), rootType, forUnmarshaling->pNext));
+        *(VkStructureType*)forUnmarshaling->pNext = extType;
+        reservedunmarshal_extension_struct(vkStream, rootType, (void*)(forUnmarshaling->pNext),
+                                           ptr);
+    }
+    memcpy((uint32_t*)&forUnmarshaling->drmFormatModifierCount, *ptr, sizeof(uint32_t));
+    *ptr += sizeof(uint32_t);
+    // WARNING PTR CHECK
+    memcpy((VkDrmFormatModifierProperties2EXT**)&forUnmarshaling->pDrmFormatModifierProperties,
+           (*ptr), 8);
+    android::base::Stream::fromBe64((uint8_t*)&forUnmarshaling->pDrmFormatModifierProperties);
+    *ptr += 8;
+    if (forUnmarshaling->pDrmFormatModifierProperties) {
+        vkStream->alloc(
+            (void**)&forUnmarshaling->pDrmFormatModifierProperties,
+            forUnmarshaling->drmFormatModifierCount * sizeof(VkDrmFormatModifierProperties2EXT));
+        for (uint32_t i = 0; i < (uint32_t)forUnmarshaling->drmFormatModifierCount; ++i) {
+            reservedunmarshal_VkDrmFormatModifierProperties2EXT(
+                vkStream, rootType,
+                (VkDrmFormatModifierProperties2EXT*)(forUnmarshaling->pDrmFormatModifierProperties +
+                                                     i),
+                ptr);
+        }
+    }
+}
+
+#endif
 #ifdef VK_EXT_external_memory_host
 void reservedunmarshal_VkImportMemoryHostPointerInfoEXT(
     VulkanStream* vkStream, VkStructureType rootType,
@@ -15512,6 +15775,43 @@
             break;
         }
 #endif
+#ifdef VK_EXT_image_drm_format_modifier
+        case VK_STRUCTURE_TYPE_DRM_FORMAT_MODIFIER_PROPERTIES_LIST_EXT: {
+            reservedunmarshal_VkDrmFormatModifierPropertiesListEXT(
+                vkStream, rootType,
+                reinterpret_cast<VkDrmFormatModifierPropertiesListEXT*>(structExtension_out), ptr);
+            break;
+        }
+        case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_DRM_FORMAT_MODIFIER_INFO_EXT: {
+            reservedunmarshal_VkPhysicalDeviceImageDrmFormatModifierInfoEXT(
+                vkStream, rootType,
+                reinterpret_cast<VkPhysicalDeviceImageDrmFormatModifierInfoEXT*>(
+                    structExtension_out),
+                ptr);
+            break;
+        }
+        case VK_STRUCTURE_TYPE_IMAGE_DRM_FORMAT_MODIFIER_LIST_CREATE_INFO_EXT: {
+            reservedunmarshal_VkImageDrmFormatModifierListCreateInfoEXT(
+                vkStream, rootType,
+                reinterpret_cast<VkImageDrmFormatModifierListCreateInfoEXT*>(structExtension_out),
+                ptr);
+            break;
+        }
+        case VK_STRUCTURE_TYPE_IMAGE_DRM_FORMAT_MODIFIER_EXPLICIT_CREATE_INFO_EXT: {
+            reservedunmarshal_VkImageDrmFormatModifierExplicitCreateInfoEXT(
+                vkStream, rootType,
+                reinterpret_cast<VkImageDrmFormatModifierExplicitCreateInfoEXT*>(
+                    structExtension_out),
+                ptr);
+            break;
+        }
+        case VK_STRUCTURE_TYPE_DRM_FORMAT_MODIFIER_PROPERTIES_LIST_2_EXT: {
+            reservedunmarshal_VkDrmFormatModifierPropertiesList2EXT(
+                vkStream, rootType,
+                reinterpret_cast<VkDrmFormatModifierPropertiesList2EXT*>(structExtension_out), ptr);
+            break;
+        }
+#endif
 #ifdef VK_EXT_external_memory_host
         case VK_STRUCTURE_TYPE_IMPORT_MEMORY_HOST_POINTER_INFO_EXT: {
             reservedunmarshal_VkImportMemoryHostPointerInfoEXT(
diff --git a/host/vulkan/cereal/common/goldfish_vk_reserved_marshaling.h b/host/vulkan/cereal/common/goldfish_vk_reserved_marshaling.h
index 1bc9728..ddb8801 100644
--- a/host/vulkan/cereal/common/goldfish_vk_reserved_marshaling.h
+++ b/host/vulkan/cereal/common/goldfish_vk_reserved_marshaling.h
@@ -1711,6 +1711,40 @@
                       reservedunmarshal_VkDescriptorPoolInlineUniformBlockCreateInfoEXT)
 
 #endif
+#ifdef VK_EXT_image_drm_format_modifier
+void reservedunmarshal_VkDrmFormatModifierPropertiesEXT(
+    VulkanStream* vkStream, VkStructureType rootType,
+    VkDrmFormatModifierPropertiesEXT* forUnmarshaling, uint8_t** ptr);
+
+void reservedunmarshal_VkDrmFormatModifierPropertiesListEXT(
+    VulkanStream* vkStream, VkStructureType rootType,
+    VkDrmFormatModifierPropertiesListEXT* forUnmarshaling, uint8_t** ptr);
+
+void reservedunmarshal_VkPhysicalDeviceImageDrmFormatModifierInfoEXT(
+    VulkanStream* vkStream, VkStructureType rootType,
+    VkPhysicalDeviceImageDrmFormatModifierInfoEXT* forUnmarshaling, uint8_t** ptr);
+
+void reservedunmarshal_VkImageDrmFormatModifierListCreateInfoEXT(
+    VulkanStream* vkStream, VkStructureType rootType,
+    VkImageDrmFormatModifierListCreateInfoEXT* forUnmarshaling, uint8_t** ptr);
+
+void reservedunmarshal_VkImageDrmFormatModifierExplicitCreateInfoEXT(
+    VulkanStream* vkStream, VkStructureType rootType,
+    VkImageDrmFormatModifierExplicitCreateInfoEXT* forUnmarshaling, uint8_t** ptr);
+
+void reservedunmarshal_VkImageDrmFormatModifierPropertiesEXT(
+    VulkanStream* vkStream, VkStructureType rootType,
+    VkImageDrmFormatModifierPropertiesEXT* forUnmarshaling, uint8_t** ptr);
+
+void reservedunmarshal_VkDrmFormatModifierProperties2EXT(
+    VulkanStream* vkStream, VkStructureType rootType,
+    VkDrmFormatModifierProperties2EXT* forUnmarshaling, uint8_t** ptr);
+
+void reservedunmarshal_VkDrmFormatModifierPropertiesList2EXT(
+    VulkanStream* vkStream, VkStructureType rootType,
+    VkDrmFormatModifierPropertiesList2EXT* forUnmarshaling, uint8_t** ptr);
+
+#endif
 #ifdef VK_EXT_external_memory_host
 void reservedunmarshal_VkImportMemoryHostPointerInfoEXT(
     VulkanStream* vkStream, VkStructureType rootType,
diff --git a/host/vulkan/cereal/common/goldfish_vk_transform.cpp b/host/vulkan/cereal/common/goldfish_vk_transform.cpp
index eb4d2e7..28ed4b6 100644
--- a/host/vulkan/cereal/common/goldfish_vk_transform.cpp
+++ b/host/vulkan/cereal/common/goldfish_vk_transform.cpp
@@ -7222,6 +7222,200 @@
 }
 
 #endif
+#ifdef VK_EXT_image_drm_format_modifier
+void transform_tohost_VkDrmFormatModifierPropertiesEXT(
+    VkDecoderGlobalState* resourceTracker, VkDrmFormatModifierPropertiesEXT* toTransform) {
+    (void)resourceTracker;
+    (void)toTransform;
+}
+
+void transform_fromhost_VkDrmFormatModifierPropertiesEXT(
+    VkDecoderGlobalState* resourceTracker, VkDrmFormatModifierPropertiesEXT* toTransform) {
+    (void)resourceTracker;
+    (void)toTransform;
+}
+
+void transform_tohost_VkDrmFormatModifierPropertiesListEXT(
+    VkDecoderGlobalState* resourceTracker, VkDrmFormatModifierPropertiesListEXT* toTransform) {
+    (void)resourceTracker;
+    (void)toTransform;
+    if (toTransform->pNext) {
+        transform_tohost_extension_struct(resourceTracker, (void*)(toTransform->pNext));
+    }
+    if (toTransform) {
+        if (toTransform->pDrmFormatModifierProperties) {
+            for (uint32_t i = 0; i < (uint32_t)toTransform->drmFormatModifierCount; ++i) {
+                transform_tohost_VkDrmFormatModifierPropertiesEXT(
+                    resourceTracker,
+                    (VkDrmFormatModifierPropertiesEXT*)(toTransform->pDrmFormatModifierProperties +
+                                                        i));
+            }
+        }
+    }
+}
+
+void transform_fromhost_VkDrmFormatModifierPropertiesListEXT(
+    VkDecoderGlobalState* resourceTracker, VkDrmFormatModifierPropertiesListEXT* toTransform) {
+    (void)resourceTracker;
+    (void)toTransform;
+    if (toTransform->pNext) {
+        transform_fromhost_extension_struct(resourceTracker, (void*)(toTransform->pNext));
+    }
+    if (toTransform) {
+        if (toTransform->pDrmFormatModifierProperties) {
+            for (uint32_t i = 0; i < (uint32_t)toTransform->drmFormatModifierCount; ++i) {
+                transform_fromhost_VkDrmFormatModifierPropertiesEXT(
+                    resourceTracker,
+                    (VkDrmFormatModifierPropertiesEXT*)(toTransform->pDrmFormatModifierProperties +
+                                                        i));
+            }
+        }
+    }
+}
+
+void transform_tohost_VkPhysicalDeviceImageDrmFormatModifierInfoEXT(
+    VkDecoderGlobalState* resourceTracker,
+    VkPhysicalDeviceImageDrmFormatModifierInfoEXT* toTransform) {
+    (void)resourceTracker;
+    (void)toTransform;
+    if (toTransform->pNext) {
+        transform_tohost_extension_struct(resourceTracker, (void*)(toTransform->pNext));
+    }
+}
+
+void transform_fromhost_VkPhysicalDeviceImageDrmFormatModifierInfoEXT(
+    VkDecoderGlobalState* resourceTracker,
+    VkPhysicalDeviceImageDrmFormatModifierInfoEXT* toTransform) {
+    (void)resourceTracker;
+    (void)toTransform;
+    if (toTransform->pNext) {
+        transform_fromhost_extension_struct(resourceTracker, (void*)(toTransform->pNext));
+    }
+}
+
+void transform_tohost_VkImageDrmFormatModifierListCreateInfoEXT(
+    VkDecoderGlobalState* resourceTracker, VkImageDrmFormatModifierListCreateInfoEXT* toTransform) {
+    (void)resourceTracker;
+    (void)toTransform;
+    if (toTransform->pNext) {
+        transform_tohost_extension_struct(resourceTracker, (void*)(toTransform->pNext));
+    }
+}
+
+void transform_fromhost_VkImageDrmFormatModifierListCreateInfoEXT(
+    VkDecoderGlobalState* resourceTracker, VkImageDrmFormatModifierListCreateInfoEXT* toTransform) {
+    (void)resourceTracker;
+    (void)toTransform;
+    if (toTransform->pNext) {
+        transform_fromhost_extension_struct(resourceTracker, (void*)(toTransform->pNext));
+    }
+}
+
+void transform_tohost_VkImageDrmFormatModifierExplicitCreateInfoEXT(
+    VkDecoderGlobalState* resourceTracker,
+    VkImageDrmFormatModifierExplicitCreateInfoEXT* toTransform) {
+    (void)resourceTracker;
+    (void)toTransform;
+    if (toTransform->pNext) {
+        transform_tohost_extension_struct(resourceTracker, (void*)(toTransform->pNext));
+    }
+    if (toTransform) {
+        if (toTransform->pPlaneLayouts) {
+            for (uint32_t i = 0; i < (uint32_t)toTransform->drmFormatModifierPlaneCount; ++i) {
+                transform_tohost_VkSubresourceLayout(
+                    resourceTracker, (VkSubresourceLayout*)(toTransform->pPlaneLayouts + i));
+            }
+        }
+    }
+}
+
+void transform_fromhost_VkImageDrmFormatModifierExplicitCreateInfoEXT(
+    VkDecoderGlobalState* resourceTracker,
+    VkImageDrmFormatModifierExplicitCreateInfoEXT* toTransform) {
+    (void)resourceTracker;
+    (void)toTransform;
+    if (toTransform->pNext) {
+        transform_fromhost_extension_struct(resourceTracker, (void*)(toTransform->pNext));
+    }
+    if (toTransform) {
+        if (toTransform->pPlaneLayouts) {
+            for (uint32_t i = 0; i < (uint32_t)toTransform->drmFormatModifierPlaneCount; ++i) {
+                transform_fromhost_VkSubresourceLayout(
+                    resourceTracker, (VkSubresourceLayout*)(toTransform->pPlaneLayouts + i));
+            }
+        }
+    }
+}
+
+void transform_tohost_VkImageDrmFormatModifierPropertiesEXT(
+    VkDecoderGlobalState* resourceTracker, VkImageDrmFormatModifierPropertiesEXT* toTransform) {
+    (void)resourceTracker;
+    (void)toTransform;
+    if (toTransform->pNext) {
+        transform_tohost_extension_struct(resourceTracker, (void*)(toTransform->pNext));
+    }
+}
+
+void transform_fromhost_VkImageDrmFormatModifierPropertiesEXT(
+    VkDecoderGlobalState* resourceTracker, VkImageDrmFormatModifierPropertiesEXT* toTransform) {
+    (void)resourceTracker;
+    (void)toTransform;
+    if (toTransform->pNext) {
+        transform_fromhost_extension_struct(resourceTracker, (void*)(toTransform->pNext));
+    }
+}
+
+void transform_tohost_VkDrmFormatModifierProperties2EXT(
+    VkDecoderGlobalState* resourceTracker, VkDrmFormatModifierProperties2EXT* toTransform) {
+    (void)resourceTracker;
+    (void)toTransform;
+}
+
+void transform_fromhost_VkDrmFormatModifierProperties2EXT(
+    VkDecoderGlobalState* resourceTracker, VkDrmFormatModifierProperties2EXT* toTransform) {
+    (void)resourceTracker;
+    (void)toTransform;
+}
+
+void transform_tohost_VkDrmFormatModifierPropertiesList2EXT(
+    VkDecoderGlobalState* resourceTracker, VkDrmFormatModifierPropertiesList2EXT* toTransform) {
+    (void)resourceTracker;
+    (void)toTransform;
+    if (toTransform->pNext) {
+        transform_tohost_extension_struct(resourceTracker, (void*)(toTransform->pNext));
+    }
+    if (toTransform) {
+        if (toTransform->pDrmFormatModifierProperties) {
+            for (uint32_t i = 0; i < (uint32_t)toTransform->drmFormatModifierCount; ++i) {
+                transform_tohost_VkDrmFormatModifierProperties2EXT(
+                    resourceTracker,
+                    (VkDrmFormatModifierProperties2EXT*)(toTransform->pDrmFormatModifierProperties +
+                                                         i));
+            }
+        }
+    }
+}
+
+void transform_fromhost_VkDrmFormatModifierPropertiesList2EXT(
+    VkDecoderGlobalState* resourceTracker, VkDrmFormatModifierPropertiesList2EXT* toTransform) {
+    (void)resourceTracker;
+    (void)toTransform;
+    if (toTransform->pNext) {
+        transform_fromhost_extension_struct(resourceTracker, (void*)(toTransform->pNext));
+    }
+    if (toTransform) {
+        if (toTransform->pDrmFormatModifierProperties) {
+            for (uint32_t i = 0; i < (uint32_t)toTransform->drmFormatModifierCount; ++i) {
+                transform_fromhost_VkDrmFormatModifierProperties2EXT(
+                    resourceTracker,
+                    (VkDrmFormatModifierProperties2EXT*)(toTransform->pDrmFormatModifierProperties +
+                                                         i));
+            }
+        }
+    }
+}
+
+#endif
 #ifdef VK_EXT_external_memory_host
 void transform_tohost_VkImportMemoryHostPointerInfoEXT(
     VkDecoderGlobalState* resourceTracker, VkImportMemoryHostPointerInfoEXT* toTransform) {
@@ -9537,6 +9731,38 @@
             break;
         }
 #endif
+#ifdef VK_EXT_image_drm_format_modifier
+        case VK_STRUCTURE_TYPE_DRM_FORMAT_MODIFIER_PROPERTIES_LIST_EXT: {
+            transform_tohost_VkDrmFormatModifierPropertiesListEXT(
+                resourceTracker,
+                reinterpret_cast<VkDrmFormatModifierPropertiesListEXT*>(structExtension_out));
+            break;
+        }
+        case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_DRM_FORMAT_MODIFIER_INFO_EXT: {
+            transform_tohost_VkPhysicalDeviceImageDrmFormatModifierInfoEXT(
+                resourceTracker, reinterpret_cast<VkPhysicalDeviceImageDrmFormatModifierInfoEXT*>(
+                                     structExtension_out));
+            break;
+        }
+        case VK_STRUCTURE_TYPE_IMAGE_DRM_FORMAT_MODIFIER_LIST_CREATE_INFO_EXT: {
+            transform_tohost_VkImageDrmFormatModifierListCreateInfoEXT(
+                resourceTracker,
+                reinterpret_cast<VkImageDrmFormatModifierListCreateInfoEXT*>(structExtension_out));
+            break;
+        }
+        case VK_STRUCTURE_TYPE_IMAGE_DRM_FORMAT_MODIFIER_EXPLICIT_CREATE_INFO_EXT: {
+            transform_tohost_VkImageDrmFormatModifierExplicitCreateInfoEXT(
+                resourceTracker, reinterpret_cast<VkImageDrmFormatModifierExplicitCreateInfoEXT*>(
+                                     structExtension_out));
+            break;
+        }
+        case VK_STRUCTURE_TYPE_DRM_FORMAT_MODIFIER_PROPERTIES_LIST_2_EXT: {
+            transform_tohost_VkDrmFormatModifierPropertiesList2EXT(
+                resourceTracker,
+                reinterpret_cast<VkDrmFormatModifierPropertiesList2EXT*>(structExtension_out));
+            break;
+        }
+#endif
 #ifdef VK_EXT_external_memory_host
         case VK_STRUCTURE_TYPE_IMPORT_MEMORY_HOST_POINTER_INFO_EXT: {
             transform_tohost_VkImportMemoryHostPointerInfoEXT(
@@ -10755,6 +10981,38 @@
             break;
         }
 #endif
+#ifdef VK_EXT_image_drm_format_modifier
+        case VK_STRUCTURE_TYPE_DRM_FORMAT_MODIFIER_PROPERTIES_LIST_EXT: {
+            transform_fromhost_VkDrmFormatModifierPropertiesListEXT(
+                resourceTracker,
+                reinterpret_cast<VkDrmFormatModifierPropertiesListEXT*>(structExtension_out));
+            break;
+        }
+        case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_DRM_FORMAT_MODIFIER_INFO_EXT: {
+            transform_fromhost_VkPhysicalDeviceImageDrmFormatModifierInfoEXT(
+                resourceTracker, reinterpret_cast<VkPhysicalDeviceImageDrmFormatModifierInfoEXT*>(
+                                     structExtension_out));
+            break;
+        }
+        case VK_STRUCTURE_TYPE_IMAGE_DRM_FORMAT_MODIFIER_LIST_CREATE_INFO_EXT: {
+            transform_fromhost_VkImageDrmFormatModifierListCreateInfoEXT(
+                resourceTracker,
+                reinterpret_cast<VkImageDrmFormatModifierListCreateInfoEXT*>(structExtension_out));
+            break;
+        }
+        case VK_STRUCTURE_TYPE_IMAGE_DRM_FORMAT_MODIFIER_EXPLICIT_CREATE_INFO_EXT: {
+            transform_fromhost_VkImageDrmFormatModifierExplicitCreateInfoEXT(
+                resourceTracker, reinterpret_cast<VkImageDrmFormatModifierExplicitCreateInfoEXT*>(
+                                     structExtension_out));
+            break;
+        }
+        case VK_STRUCTURE_TYPE_DRM_FORMAT_MODIFIER_PROPERTIES_LIST_2_EXT: {
+            transform_fromhost_VkDrmFormatModifierPropertiesList2EXT(
+                resourceTracker,
+                reinterpret_cast<VkDrmFormatModifierPropertiesList2EXT*>(structExtension_out));
+            break;
+        }
+#endif
 #ifdef VK_EXT_external_memory_host
         case VK_STRUCTURE_TYPE_IMPORT_MEMORY_HOST_POINTER_INFO_EXT: {
             transform_fromhost_VkImportMemoryHostPointerInfoEXT(
diff --git a/host/vulkan/cereal/common/goldfish_vk_transform.h b/host/vulkan/cereal/common/goldfish_vk_transform.h
index 9024dc4..ddabb77 100644
--- a/host/vulkan/cereal/common/goldfish_vk_transform.h
+++ b/host/vulkan/cereal/common/goldfish_vk_transform.h
@@ -2850,6 +2850,60 @@
                       transform_fromhost_VkDescriptorPoolInlineUniformBlockCreateInfoEXT)
 
 #endif
+#ifdef VK_EXT_image_drm_format_modifier
+void transform_tohost_VkDrmFormatModifierPropertiesEXT(
+    VkDecoderGlobalState* resourceTracker, VkDrmFormatModifierPropertiesEXT* toTransform);
+
+void transform_fromhost_VkDrmFormatModifierPropertiesEXT(
+    VkDecoderGlobalState* resourceTracker, VkDrmFormatModifierPropertiesEXT* toTransform);
+
+void transform_tohost_VkDrmFormatModifierPropertiesListEXT(
+    VkDecoderGlobalState* resourceTracker, VkDrmFormatModifierPropertiesListEXT* toTransform);
+
+void transform_fromhost_VkDrmFormatModifierPropertiesListEXT(
+    VkDecoderGlobalState* resourceTracker, VkDrmFormatModifierPropertiesListEXT* toTransform);
+
+void transform_tohost_VkPhysicalDeviceImageDrmFormatModifierInfoEXT(
+    VkDecoderGlobalState* resourceTracker,
+    VkPhysicalDeviceImageDrmFormatModifierInfoEXT* toTransform);
+
+void transform_fromhost_VkPhysicalDeviceImageDrmFormatModifierInfoEXT(
+    VkDecoderGlobalState* resourceTracker,
+    VkPhysicalDeviceImageDrmFormatModifierInfoEXT* toTransform);
+
+void transform_tohost_VkImageDrmFormatModifierListCreateInfoEXT(
+    VkDecoderGlobalState* resourceTracker, VkImageDrmFormatModifierListCreateInfoEXT* toTransform);
+
+void transform_fromhost_VkImageDrmFormatModifierListCreateInfoEXT(
+    VkDecoderGlobalState* resourceTracker, VkImageDrmFormatModifierListCreateInfoEXT* toTransform);
+
+void transform_tohost_VkImageDrmFormatModifierExplicitCreateInfoEXT(
+    VkDecoderGlobalState* resourceTracker,
+    VkImageDrmFormatModifierExplicitCreateInfoEXT* toTransform);
+
+void transform_fromhost_VkImageDrmFormatModifierExplicitCreateInfoEXT(
+    VkDecoderGlobalState* resourceTracker,
+    VkImageDrmFormatModifierExplicitCreateInfoEXT* toTransform);
+
+void transform_tohost_VkImageDrmFormatModifierPropertiesEXT(
+    VkDecoderGlobalState* resourceTracker, VkImageDrmFormatModifierPropertiesEXT* toTransform);
+
+void transform_fromhost_VkImageDrmFormatModifierPropertiesEXT(
+    VkDecoderGlobalState* resourceTracker, VkImageDrmFormatModifierPropertiesEXT* toTransform);
+
+void transform_tohost_VkDrmFormatModifierProperties2EXT(
+    VkDecoderGlobalState* resourceTracker, VkDrmFormatModifierProperties2EXT* toTransform);
+
+void transform_fromhost_VkDrmFormatModifierProperties2EXT(
+    VkDecoderGlobalState* resourceTracker, VkDrmFormatModifierProperties2EXT* toTransform);
+
+void transform_tohost_VkDrmFormatModifierPropertiesList2EXT(
+    VkDecoderGlobalState* resourceTracker, VkDrmFormatModifierPropertiesList2EXT* toTransform);
+
+void transform_fromhost_VkDrmFormatModifierPropertiesList2EXT(
+    VkDecoderGlobalState* resourceTracker, VkDrmFormatModifierPropertiesList2EXT* toTransform);
+
+#endif
 #ifdef VK_EXT_external_memory_host
 void transform_tohost_VkImportMemoryHostPointerInfoEXT(
     VkDecoderGlobalState* resourceTracker, VkImportMemoryHostPointerInfoEXT* toTransform);
diff --git a/utils/BUILD.bazel b/utils/BUILD.bazel
index b9275ff..f042524 100644
--- a/utils/BUILD.bazel
+++ b/utils/BUILD.bazel
@@ -17,6 +17,7 @@
 cc_library(
     name = "gfxstream_utils",
     srcs = ["GfxApiLogger.cpp"],
+    copts = ["-fno-exceptions"],
     visibility = ["//visibility:public"],
     deps = [":gfxstream_utils_headers"],
 )