Merge "Implement metal_objects for MoltenVK" into main
diff --git a/codegen/vulkan/vulkan-docs-next/scripts/cerealgenerator.py b/codegen/vulkan/vulkan-docs-next/scripts/cerealgenerator.py
index cb23590..59db4fa 100644
--- a/codegen/vulkan/vulkan-docs-next/scripts/cerealgenerator.py
+++ b/codegen/vulkan/vulkan-docs-next/scripts/cerealgenerator.py
@@ -140,6 +140,8 @@
     "VK_QNX_external_memory_screen_buffer",
     # b/320855472 Chrome
     "VK_EXT_fragment_density_map",
+    # b/349122558 Zink
+    "VK_EXT_color_write_enable",
 ]
 
 HOST_MODULES = ["goldfish_vk_extension_structs", "goldfish_vk_marshaling",
diff --git a/guest/vulkan/gfxstream_vk_device.cpp b/guest/vulkan/gfxstream_vk_device.cpp
index 617f902..2ccf87e 100644
--- a/guest/vulkan/gfxstream_vk_device.cpp
+++ b/guest/vulkan/gfxstream_vk_device.cpp
@@ -43,9 +43,12 @@
 // Provided by Mesa components only; never encoded/decoded through gfxstream
 static const char* const kMesaOnlyInstanceExtension[] = {
     VK_KHR_SURFACE_EXTENSION_NAME,
-#if defined(LINUX_GUEST_BUILD)
+#if defined(GFXSTREAM_VK_WAYLAND)
     VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME,
 #endif
+#if defined(GFXSTREAM_VK_X11)
+    VK_KHR_XCB_SURFACE_EXTENSION_NAME,
+#endif
     VK_EXT_DEBUG_UTILS_EXTENSION_NAME,
 };
 
diff --git a/guest/vulkan/meson.build b/guest/vulkan/meson.build
index 84a8bec..9055a9c 100644
--- a/guest/vulkan/meson.build
+++ b/guest/vulkan/meson.build
@@ -7,10 +7,19 @@
   'gfxstream_vk_wsi.cpp'
 )
 
+gfxstream_vk_wsi_args = []
+if with_platform_x11
+   gfxstream_vk_wsi_args += '-DGFXSTREAM_VK_X11'
+endif
+
+if with_platform_wayland
+   gfxstream_vk_wsi_args += '-DGFXSTREAM_VK_WAYLAND'
+endif
+
 lib_vulkan_gfxstream = shared_library(
    'vulkan_gfxstream',
    files_lib_vulkan_gfxstream + files_lib_vulkan_enc + gfxstream_vk_entrypoints,
-   cpp_args: gfxstream_guest_args,
+   cpp_args: gfxstream_guest_args + gfxstream_vk_wsi_args,
    include_directories: [inc_vulkan_headers, inc_opengl_headers, inc_android_emu,
                          inc_android_compat, inc_opengl_system, inc_guest_iostream,
                          inc_opengl_codec, inc_render_enc, inc_vulkan_enc, inc_platform,
diff --git a/guest/vulkan_enc/ResourceTracker.cpp b/guest/vulkan_enc/ResourceTracker.cpp
index 056fe1e..a197dc3 100644
--- a/guest/vulkan_enc/ResourceTracker.cpp
+++ b/guest/vulkan_enc/ResourceTracker.cpp
@@ -1776,6 +1776,7 @@
         // Vulkan 1.3
         "VK_KHR_synchronization2",
         "VK_EXT_private_data",
+        "VK_EXT_color_write_enable",
     };
 
     VkEncoder* enc = (VkEncoder*)context;
diff --git a/guest/vulkan_enc/VkEncoder.cpp b/guest/vulkan_enc/VkEncoder.cpp
index 65cf8d2..38a4c6f 100644
--- a/guest/vulkan_enc/VkEncoder.cpp
+++ b/guest/vulkan_enc/VkEncoder.cpp
@@ -35764,6 +35764,97 @@
 }
 
 #endif
+#ifdef VK_EXT_color_write_enable
+void VkEncoder::vkCmdSetColorWriteEnableEXT(VkCommandBuffer commandBuffer, uint32_t attachmentCount,
+                                            const VkBool32* pColorWriteEnables, uint32_t doLock) {
+    std::optional<uint32_t> healthMonitorAnnotation_seqno = std::nullopt;
+    std::optional<uint32_t> healthMonitorAnnotation_packetSize = std::nullopt;
+    std::vector<uint8_t> healthMonitorAnnotation_packetContents;
+
+    auto watchdog =
+        WATCHDOG_BUILDER(mHealthMonitor, "vkCmdSetColorWriteEnableEXT in VkEncoder")
+            .setOnHangCallback([&]() {
+                auto annotations = std::make_unique<EventHangMetadata::HangAnnotations>();
+                if (healthMonitorAnnotation_seqno) {
+                    annotations->insert(
+                        {{"seqno", std::to_string(healthMonitorAnnotation_seqno.value())}});
+                }
+                if (healthMonitorAnnotation_packetSize) {
+                    annotations->insert(
+                        {{"packetSize",
+                          std::to_string(healthMonitorAnnotation_packetSize.value())}});
+                }
+                if (!healthMonitorAnnotation_packetContents.empty()) {
+                    annotations->insert(
+                        {{"packetContents",
+                          getPacketContents(&healthMonitorAnnotation_packetContents[0],
+                                            healthMonitorAnnotation_packetContents.size())}});
+                }
+                return std::move(annotations);
+            })
+            .build();
+
+    ENCODER_DEBUG_LOG(
+        "vkCmdSetColorWriteEnableEXT(commandBuffer:%p, attachmentCount:%d, pColorWriteEnables:%p)",
+        commandBuffer, attachmentCount, pColorWriteEnables);
+    (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();
+    VkCommandBuffer local_commandBuffer;
+    uint32_t local_attachmentCount;
+    VkBool32* local_pColorWriteEnables;
+    local_commandBuffer = commandBuffer;
+    local_attachmentCount = attachmentCount;
+    // Avoiding deepcopy for pColorWriteEnables
+    local_pColorWriteEnables = (VkBool32*)pColorWriteEnables;
+    size_t count = 0;
+    size_t* countPtr = &count;
+    {
+        uint64_t cgen_var_0;
+        *countPtr += 1 * 8;
+        *countPtr += sizeof(uint32_t);
+        *countPtr += ((attachmentCount)) * sizeof(VkBool32);
+    }
+    uint32_t packetSize_vkCmdSetColorWriteEnableEXT = 4 + 4 + count;
+    healthMonitorAnnotation_packetSize = std::make_optional(packetSize_vkCmdSetColorWriteEnableEXT);
+    if (queueSubmitWithCommandsEnabled) packetSize_vkCmdSetColorWriteEnableEXT -= 8;
+    uint8_t* streamPtr = stream->reserve(packetSize_vkCmdSetColorWriteEnableEXT);
+    uint8_t* packetBeginPtr = streamPtr;
+    uint8_t** streamPtrPtr = &streamPtr;
+    uint32_t opcode_vkCmdSetColorWriteEnableEXT = OP_vkCmdSetColorWriteEnableEXT;
+    memcpy(streamPtr, &opcode_vkCmdSetColorWriteEnableEXT, sizeof(uint32_t));
+    streamPtr += sizeof(uint32_t);
+    memcpy(streamPtr, &packetSize_vkCmdSetColorWriteEnableEXT, sizeof(uint32_t));
+    streamPtr += sizeof(uint32_t);
+    if (!queueSubmitWithCommandsEnabled) {
+        uint64_t cgen_var_0;
+        *&cgen_var_0 = get_host_u64_VkCommandBuffer((*&local_commandBuffer));
+        memcpy(*streamPtrPtr, (uint64_t*)&cgen_var_0, 1 * 8);
+        *streamPtrPtr += 1 * 8;
+    }
+    memcpy(*streamPtrPtr, (uint32_t*)&local_attachmentCount, sizeof(uint32_t));
+    *streamPtrPtr += sizeof(uint32_t);
+    memcpy(*streamPtrPtr, (VkBool32*)local_pColorWriteEnables,
+           ((attachmentCount)) * sizeof(VkBool32));
+    *streamPtrPtr += ((attachmentCount)) * sizeof(VkBool32);
+    if (watchdog) {
+        size_t watchdogBufSize = std::min<size_t>(
+            static_cast<size_t>(packetSize_vkCmdSetColorWriteEnableEXT), kWatchdogBufferMax);
+        healthMonitorAnnotation_packetContents.resize(watchdogBufSize);
+        memcpy(&healthMonitorAnnotation_packetContents[0], packetBeginPtr, watchdogBufSize);
+    }
+    ++encodeCount;
+    if (0 == encodeCount % POOL_CLEAR_INTERVAL) {
+        pool->freeAll();
+        stream->clearPool();
+    }
+    if (!queueSubmitWithCommandsEnabled && doLock) this->unlock();
+}
+
+#endif
 #ifdef VK_GOOGLE_gfxstream
 VkResult VkEncoder::vkMapMemoryIntoAddressSpaceGOOGLE(VkDevice device, VkDeviceMemory memory,
                                                       uint64_t* pAddress, uint32_t doLock) {
diff --git a/guest/vulkan_enc/VkEncoder.h b/guest/vulkan_enc/VkEncoder.h
index 4f630c9..c7f9524 100644
--- a/guest/vulkan_enc/VkEncoder.h
+++ b/guest/vulkan_enc/VkEncoder.h
@@ -1064,6 +1064,10 @@
     void vkCmdSetPrimitiveRestartEnableEXT(VkCommandBuffer commandBuffer,
                                            VkBool32 primitiveRestartEnable, uint32_t doLock);
 #endif
+#ifdef VK_EXT_color_write_enable
+    void vkCmdSetColorWriteEnableEXT(VkCommandBuffer commandBuffer, uint32_t attachmentCount,
+                                     const VkBool32* pColorWriteEnables, uint32_t doLock);
+#endif
 #ifdef VK_GOOGLE_gfxstream
     VkResult vkMapMemoryIntoAddressSpaceGOOGLE(VkDevice device, VkDeviceMemory memory,
                                                uint64_t* pAddress, uint32_t doLock);
diff --git a/guest/vulkan_enc/func_table.cpp b/guest/vulkan_enc/func_table.cpp
index 9d23f88..aae06c0 100644
--- a/guest/vulkan_enc/func_table.cpp
+++ b/guest/vulkan_enc/func_table.cpp
@@ -4550,6 +4550,19 @@
     }
 }
 #endif
+#ifdef VK_EXT_color_write_enable
+void gfxstream_vk_CmdSetColorWriteEnableEXT(VkCommandBuffer commandBuffer, uint32_t attachmentCount,
+                                            const VkBool32* pColorWriteEnables) {
+    AEMU_SCOPED_TRACE("vkCmdSetColorWriteEnableEXT");
+    VK_FROM_HANDLE(gfxstream_vk_command_buffer, gfxstream_commandBuffer, commandBuffer);
+    {
+        auto vkEnc = gfxstream::vk::ResourceTracker::getCommandBufferEncoder(
+            gfxstream_commandBuffer->internal_object);
+        vkEnc->vkCmdSetColorWriteEnableEXT(gfxstream_commandBuffer->internal_object,
+                                           attachmentCount, pColorWriteEnables, true /* do lock */);
+    }
+}
+#endif
 #ifdef VK_GOOGLE_gfxstream
 VkResult gfxstream_vk_MapMemoryIntoAddressSpaceGOOGLE(VkDevice device, VkDeviceMemory memory,
                                                       uint64_t* pAddress) {
diff --git a/guest/vulkan_enc/goldfish_vk_counting_guest.cpp b/guest/vulkan_enc/goldfish_vk_counting_guest.cpp
index aba8793..d7388f4 100644
--- a/guest/vulkan_enc/goldfish_vk_counting_guest.cpp
+++ b/guest/vulkan_enc/goldfish_vk_counting_guest.cpp
@@ -7298,6 +7298,41 @@
 }
 
 #endif
+#ifdef VK_EXT_color_write_enable
+void count_VkPhysicalDeviceColorWriteEnableFeaturesEXT(
+    uint32_t featureBits, VkStructureType rootType,
+    const VkPhysicalDeviceColorWriteEnableFeaturesEXT* 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(VkBool32);
+}
+
+void count_VkPipelineColorWriteCreateInfoEXT(uint32_t featureBits, VkStructureType rootType,
+                                             const VkPipelineColorWriteCreateInfoEXT* 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->attachmentCount * sizeof(const VkBool32);
+    }
+}
+
+#endif
 #ifdef VK_GOOGLE_gfxstream
 void count_VkImportColorBufferGOOGLE(uint32_t featureBits, VkStructureType rootType,
                                      const VkImportColorBufferGOOGLE* toCount, size_t* count) {
@@ -8658,6 +8693,22 @@
             break;
         }
 #endif
+#ifdef VK_EXT_color_write_enable
+        case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COLOR_WRITE_ENABLE_FEATURES_EXT: {
+            count_VkPhysicalDeviceColorWriteEnableFeaturesEXT(
+                featureBits, rootType,
+                reinterpret_cast<const VkPhysicalDeviceColorWriteEnableFeaturesEXT*>(
+                    structExtension),
+                count);
+            break;
+        }
+        case VK_STRUCTURE_TYPE_PIPELINE_COLOR_WRITE_CREATE_INFO_EXT: {
+            count_VkPipelineColorWriteCreateInfoEXT(
+                featureBits, rootType,
+                reinterpret_cast<const VkPipelineColorWriteCreateInfoEXT*>(structExtension), count);
+            break;
+        }
+#endif
 #ifdef VK_GOOGLE_gfxstream
         case VK_STRUCTURE_TYPE_IMPORT_COLOR_BUFFER_GOOGLE: {
             count_VkImportColorBufferGOOGLE(
diff --git a/guest/vulkan_enc/goldfish_vk_counting_guest.h b/guest/vulkan_enc/goldfish_vk_counting_guest.h
index a2ca5af..2154e09 100644
--- a/guest/vulkan_enc/goldfish_vk_counting_guest.h
+++ b/guest/vulkan_enc/goldfish_vk_counting_guest.h
@@ -1822,6 +1822,16 @@
     const VkPhysicalDeviceExtendedDynamicState2FeaturesEXT* toCount, size_t* count);
 
 #endif
+#ifdef VK_EXT_color_write_enable
+void count_VkPhysicalDeviceColorWriteEnableFeaturesEXT(
+    uint32_t featureBits, VkStructureType rootType,
+    const VkPhysicalDeviceColorWriteEnableFeaturesEXT* toCount, size_t* count);
+
+void count_VkPipelineColorWriteCreateInfoEXT(uint32_t featureBits, VkStructureType rootType,
+                                             const VkPipelineColorWriteCreateInfoEXT* toCount,
+                                             size_t* count);
+
+#endif
 #ifdef VK_GOOGLE_gfxstream
 void count_VkImportColorBufferGOOGLE(uint32_t featureBits, VkStructureType rootType,
                                      const VkImportColorBufferGOOGLE* toCount, size_t* count);
diff --git a/guest/vulkan_enc/goldfish_vk_deepcopy_guest.cpp b/guest/vulkan_enc/goldfish_vk_deepcopy_guest.cpp
index 53c8085..9e7e9ba 100644
--- a/guest/vulkan_enc/goldfish_vk_deepcopy_guest.cpp
+++ b/guest/vulkan_enc/goldfish_vk_deepcopy_guest.cpp
@@ -8600,6 +8600,58 @@
 }
 
 #endif
+#ifdef VK_EXT_color_write_enable
+void deepcopy_VkPhysicalDeviceColorWriteEnableFeaturesEXT(
+    Allocator* alloc, VkStructureType rootType,
+    const VkPhysicalDeviceColorWriteEnableFeaturesEXT* from,
+    VkPhysicalDeviceColorWriteEnableFeaturesEXT* 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_VkPipelineColorWriteCreateInfoEXT(Allocator* alloc, VkStructureType rootType,
+                                                const VkPipelineColorWriteCreateInfoEXT* from,
+                                                VkPipelineColorWriteCreateInfoEXT* 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->pColorWriteEnables = nullptr;
+    if (from->pColorWriteEnables) {
+        to->pColorWriteEnables = (VkBool32*)alloc->dupArray(
+            from->pColorWriteEnables, from->attachmentCount * sizeof(const VkBool32));
+    }
+}
+
+#endif
 #ifdef VK_GOOGLE_gfxstream
 void deepcopy_VkImportColorBufferGOOGLE(Allocator* alloc, VkStructureType rootType,
                                         const VkImportColorBufferGOOGLE* from,
@@ -10076,6 +10128,24 @@
             break;
         }
 #endif
+#ifdef VK_EXT_color_write_enable
+        case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COLOR_WRITE_ENABLE_FEATURES_EXT: {
+            deepcopy_VkPhysicalDeviceColorWriteEnableFeaturesEXT(
+                alloc, rootType,
+                reinterpret_cast<const VkPhysicalDeviceColorWriteEnableFeaturesEXT*>(
+                    structExtension),
+                reinterpret_cast<VkPhysicalDeviceColorWriteEnableFeaturesEXT*>(
+                    structExtension_out));
+            break;
+        }
+        case VK_STRUCTURE_TYPE_PIPELINE_COLOR_WRITE_CREATE_INFO_EXT: {
+            deepcopy_VkPipelineColorWriteCreateInfoEXT(
+                alloc, rootType,
+                reinterpret_cast<const VkPipelineColorWriteCreateInfoEXT*>(structExtension),
+                reinterpret_cast<VkPipelineColorWriteCreateInfoEXT*>(structExtension_out));
+            break;
+        }
+#endif
 #ifdef VK_GOOGLE_gfxstream
         case VK_STRUCTURE_TYPE_IMPORT_COLOR_BUFFER_GOOGLE: {
             deepcopy_VkImportColorBufferGOOGLE(
diff --git a/guest/vulkan_enc/goldfish_vk_deepcopy_guest.h b/guest/vulkan_enc/goldfish_vk_deepcopy_guest.h
index 9eff7bc..e168f11 100644
--- a/guest/vulkan_enc/goldfish_vk_deepcopy_guest.h
+++ b/guest/vulkan_enc/goldfish_vk_deepcopy_guest.h
@@ -2002,6 +2002,17 @@
     VkPhysicalDeviceExtendedDynamicState2FeaturesEXT* to);
 
 #endif
+#ifdef VK_EXT_color_write_enable
+void deepcopy_VkPhysicalDeviceColorWriteEnableFeaturesEXT(
+    Allocator* alloc, VkStructureType rootType,
+    const VkPhysicalDeviceColorWriteEnableFeaturesEXT* from,
+    VkPhysicalDeviceColorWriteEnableFeaturesEXT* to);
+
+void deepcopy_VkPipelineColorWriteCreateInfoEXT(Allocator* alloc, VkStructureType rootType,
+                                                const VkPipelineColorWriteCreateInfoEXT* from,
+                                                VkPipelineColorWriteCreateInfoEXT* to);
+
+#endif
 #ifdef VK_GOOGLE_gfxstream
 void deepcopy_VkImportColorBufferGOOGLE(Allocator* alloc, VkStructureType rootType,
                                         const VkImportColorBufferGOOGLE* from,
diff --git a/guest/vulkan_enc/goldfish_vk_extension_structs_guest.cpp b/guest/vulkan_enc/goldfish_vk_extension_structs_guest.cpp
index 5f6422d..747fcaf 100644
--- a/guest/vulkan_enc/goldfish_vk_extension_structs_guest.cpp
+++ b/guest/vulkan_enc/goldfish_vk_extension_structs_guest.cpp
@@ -218,6 +218,8 @@
 #endif
 #ifdef VK_EXT_extended_dynamic_state2
 #endif
+#ifdef VK_EXT_color_write_enable
+#endif
 #ifdef VK_GOOGLE_gfxstream
 #endif
 #ifdef VK_EXT_load_store_op_none
@@ -822,6 +824,14 @@
             return sizeof(VkPhysicalDeviceExtendedDynamicState2FeaturesEXT);
         }
 #endif
+#ifdef VK_EXT_color_write_enable
+        case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COLOR_WRITE_ENABLE_FEATURES_EXT: {
+            return sizeof(VkPhysicalDeviceColorWriteEnableFeaturesEXT);
+        }
+        case VK_STRUCTURE_TYPE_PIPELINE_COLOR_WRITE_CREATE_INFO_EXT: {
+            return sizeof(VkPipelineColorWriteCreateInfoEXT);
+        }
+#endif
 #ifdef VK_GOOGLE_gfxstream
         case VK_STRUCTURE_TYPE_IMPORT_COLOR_BUFFER_GOOGLE: {
             return sizeof(VkImportColorBufferGOOGLE);
@@ -1441,6 +1451,14 @@
             return sizeof(VkPhysicalDeviceExtendedDynamicState2FeaturesEXT);
         }
 #endif
+#ifdef VK_EXT_color_write_enable
+        case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COLOR_WRITE_ENABLE_FEATURES_EXT: {
+            return sizeof(VkPhysicalDeviceColorWriteEnableFeaturesEXT);
+        }
+        case VK_STRUCTURE_TYPE_PIPELINE_COLOR_WRITE_CREATE_INFO_EXT: {
+            return sizeof(VkPipelineColorWriteCreateInfoEXT);
+        }
+#endif
 #ifdef VK_GOOGLE_gfxstream
         case VK_STRUCTURE_TYPE_IMPORT_COLOR_BUFFER_GOOGLE: {
             return sizeof(VkImportColorBufferGOOGLE);
diff --git a/guest/vulkan_enc/goldfish_vk_extension_structs_guest.h b/guest/vulkan_enc/goldfish_vk_extension_structs_guest.h
index 495e3e7..76b873c 100644
--- a/guest/vulkan_enc/goldfish_vk_extension_structs_guest.h
+++ b/guest/vulkan_enc/goldfish_vk_extension_structs_guest.h
@@ -238,6 +238,8 @@
 #endif
 #ifdef VK_EXT_extended_dynamic_state2
 #endif
+#ifdef VK_EXT_color_write_enable
+#endif
 #ifdef VK_GOOGLE_gfxstream
 #endif
 #ifdef VK_EXT_load_store_op_none
diff --git a/guest/vulkan_enc/goldfish_vk_marshaling_guest.cpp b/guest/vulkan_enc/goldfish_vk_marshaling_guest.cpp
index 0f3d2d3..c6f0875 100644
--- a/guest/vulkan_enc/goldfish_vk_marshaling_guest.cpp
+++ b/guest/vulkan_enc/goldfish_vk_marshaling_guest.cpp
@@ -13506,6 +13506,60 @@
 }
 
 #endif
+#ifdef VK_EXT_color_write_enable
+void marshal_VkPhysicalDeviceColorWriteEnableFeaturesEXT(
+    VulkanStreamGuest* vkStream, VkStructureType rootType,
+    const VkPhysicalDeviceColorWriteEnableFeaturesEXT* 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((VkBool32*)&forMarshaling->colorWriteEnable, sizeof(VkBool32));
+}
+
+void unmarshal_VkPhysicalDeviceColorWriteEnableFeaturesEXT(
+    VulkanStreamGuest* vkStream, VkStructureType rootType,
+    VkPhysicalDeviceColorWriteEnableFeaturesEXT* 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((VkBool32*)&forUnmarshaling->colorWriteEnable, sizeof(VkBool32));
+}
+
+void marshal_VkPipelineColorWriteCreateInfoEXT(
+    VulkanStreamGuest* vkStream, VkStructureType rootType,
+    const VkPipelineColorWriteCreateInfoEXT* 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->attachmentCount, sizeof(uint32_t));
+    vkStream->write((const VkBool32*)forMarshaling->pColorWriteEnables,
+                    forMarshaling->attachmentCount * sizeof(const VkBool32));
+}
+
+void unmarshal_VkPipelineColorWriteCreateInfoEXT(
+    VulkanStreamGuest* vkStream, VkStructureType rootType,
+    VkPipelineColorWriteCreateInfoEXT* 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->attachmentCount, sizeof(uint32_t));
+    vkStream->read((VkBool32*)forUnmarshaling->pColorWriteEnables,
+                   forUnmarshaling->attachmentCount * sizeof(const VkBool32));
+}
+
+#endif
 #ifdef VK_GOOGLE_gfxstream
 void marshal_VkImportColorBufferGOOGLE(VulkanStreamGuest* vkStream, VkStructureType rootType,
                                        const VkImportColorBufferGOOGLE* forMarshaling) {
@@ -14789,6 +14843,21 @@
             break;
         }
 #endif
+#ifdef VK_EXT_color_write_enable
+        case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COLOR_WRITE_ENABLE_FEATURES_EXT: {
+            marshal_VkPhysicalDeviceColorWriteEnableFeaturesEXT(
+                vkStream, rootType,
+                reinterpret_cast<const VkPhysicalDeviceColorWriteEnableFeaturesEXT*>(
+                    structExtension));
+            break;
+        }
+        case VK_STRUCTURE_TYPE_PIPELINE_COLOR_WRITE_CREATE_INFO_EXT: {
+            marshal_VkPipelineColorWriteCreateInfoEXT(
+                vkStream, rootType,
+                reinterpret_cast<const VkPipelineColorWriteCreateInfoEXT*>(structExtension));
+            break;
+        }
+#endif
 #ifdef VK_GOOGLE_gfxstream
         case VK_STRUCTURE_TYPE_IMPORT_COLOR_BUFFER_GOOGLE: {
             marshal_VkImportColorBufferGOOGLE(
@@ -15989,6 +16058,21 @@
             break;
         }
 #endif
+#ifdef VK_EXT_color_write_enable
+        case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COLOR_WRITE_ENABLE_FEATURES_EXT: {
+            unmarshal_VkPhysicalDeviceColorWriteEnableFeaturesEXT(
+                vkStream, rootType,
+                reinterpret_cast<VkPhysicalDeviceColorWriteEnableFeaturesEXT*>(
+                    structExtension_out));
+            break;
+        }
+        case VK_STRUCTURE_TYPE_PIPELINE_COLOR_WRITE_CREATE_INFO_EXT: {
+            unmarshal_VkPipelineColorWriteCreateInfoEXT(
+                vkStream, rootType,
+                reinterpret_cast<VkPipelineColorWriteCreateInfoEXT*>(structExtension_out));
+            break;
+        }
+#endif
 #ifdef VK_GOOGLE_gfxstream
         case VK_STRUCTURE_TYPE_IMPORT_COLOR_BUFFER_GOOGLE: {
             unmarshal_VkImportColorBufferGOOGLE(
@@ -16719,6 +16803,11 @@
             return "OP_vkGetDeviceBufferMemoryRequirementsKHR";
         }
 #endif
+#ifdef VK_EXT_color_write_enable
+        case OP_vkCmdSetColorWriteEnableEXT: {
+            return "OP_vkCmdSetColorWriteEnableEXT";
+        }
+#endif
 #ifdef VK_KHR_maintenance5
         case OP_vkCmdBindIndexBuffer2KHR: {
             return "OP_vkCmdBindIndexBuffer2KHR";
diff --git a/guest/vulkan_enc/goldfish_vk_marshaling_guest.h b/guest/vulkan_enc/goldfish_vk_marshaling_guest.h
index c66ddbe..72d33f9 100644
--- a/guest/vulkan_enc/goldfish_vk_marshaling_guest.h
+++ b/guest/vulkan_enc/goldfish_vk_marshaling_guest.h
@@ -3720,6 +3720,25 @@
 #define OP_vkCmdSetLogicOpEXT 267481927
 #define OP_vkCmdSetPrimitiveRestartEnableEXT 299567883
 #endif
+#ifdef VK_EXT_color_write_enable
+void marshal_VkPhysicalDeviceColorWriteEnableFeaturesEXT(
+    VulkanStreamGuest* vkStream, VkStructureType rootType,
+    const VkPhysicalDeviceColorWriteEnableFeaturesEXT* forMarshaling);
+
+void unmarshal_VkPhysicalDeviceColorWriteEnableFeaturesEXT(
+    VulkanStreamGuest* vkStream, VkStructureType rootType,
+    VkPhysicalDeviceColorWriteEnableFeaturesEXT* forUnmarshaling);
+
+void marshal_VkPipelineColorWriteCreateInfoEXT(
+    VulkanStreamGuest* vkStream, VkStructureType rootType,
+    const VkPipelineColorWriteCreateInfoEXT* forMarshaling);
+
+void unmarshal_VkPipelineColorWriteCreateInfoEXT(
+    VulkanStreamGuest* vkStream, VkStructureType rootType,
+    VkPipelineColorWriteCreateInfoEXT* forUnmarshaling);
+
+#define OP_vkCmdSetColorWriteEnableEXT 202223297
+#endif
 #ifdef VK_GOOGLE_gfxstream
 void marshal_VkImportColorBufferGOOGLE(VulkanStreamGuest* vkStream, VkStructureType rootType,
                                        const VkImportColorBufferGOOGLE* forMarshaling);
diff --git a/guest/vulkan_enc/goldfish_vk_reserved_marshaling_guest.cpp b/guest/vulkan_enc/goldfish_vk_reserved_marshaling_guest.cpp
index bce85a5..b96b79c 100644
--- a/guest/vulkan_enc/goldfish_vk_reserved_marshaling_guest.cpp
+++ b/guest/vulkan_enc/goldfish_vk_reserved_marshaling_guest.cpp
@@ -9063,6 +9063,41 @@
 }
 
 #endif
+#ifdef VK_EXT_color_write_enable
+void reservedmarshal_VkPhysicalDeviceColorWriteEnableFeaturesEXT(
+    VulkanStreamGuest* vkStream, VkStructureType rootType,
+    const VkPhysicalDeviceColorWriteEnableFeaturesEXT* 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, (VkBool32*)&forMarshaling->colorWriteEnable, sizeof(VkBool32));
+    *ptr += sizeof(VkBool32);
+}
+
+void reservedmarshal_VkPipelineColorWriteCreateInfoEXT(
+    VulkanStreamGuest* vkStream, VkStructureType rootType,
+    const VkPipelineColorWriteCreateInfoEXT* 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->attachmentCount, sizeof(uint32_t));
+    *ptr += sizeof(uint32_t);
+    memcpy(*ptr, (const VkBool32*)forMarshaling->pColorWriteEnables,
+           forMarshaling->attachmentCount * sizeof(const VkBool32));
+    *ptr += forMarshaling->attachmentCount * sizeof(const VkBool32);
+}
+
+#endif
 #ifdef VK_GOOGLE_gfxstream
 void reservedmarshal_VkImportColorBufferGOOGLE(VulkanStreamGuest* vkStream,
                                                VkStructureType rootType,
@@ -10420,6 +10455,22 @@
             break;
         }
 #endif
+#ifdef VK_EXT_color_write_enable
+        case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COLOR_WRITE_ENABLE_FEATURES_EXT: {
+            reservedmarshal_VkPhysicalDeviceColorWriteEnableFeaturesEXT(
+                vkStream, rootType,
+                reinterpret_cast<const VkPhysicalDeviceColorWriteEnableFeaturesEXT*>(
+                    structExtension),
+                ptr);
+            break;
+        }
+        case VK_STRUCTURE_TYPE_PIPELINE_COLOR_WRITE_CREATE_INFO_EXT: {
+            reservedmarshal_VkPipelineColorWriteCreateInfoEXT(
+                vkStream, rootType,
+                reinterpret_cast<const VkPipelineColorWriteCreateInfoEXT*>(structExtension), ptr);
+            break;
+        }
+#endif
 #ifdef VK_GOOGLE_gfxstream
         case VK_STRUCTURE_TYPE_IMPORT_COLOR_BUFFER_GOOGLE: {
             reservedmarshal_VkImportColorBufferGOOGLE(
diff --git a/guest/vulkan_enc/goldfish_vk_reserved_marshaling_guest.h b/guest/vulkan_enc/goldfish_vk_reserved_marshaling_guest.h
index dcf5fbe..21203b6 100644
--- a/guest/vulkan_enc/goldfish_vk_reserved_marshaling_guest.h
+++ b/guest/vulkan_enc/goldfish_vk_reserved_marshaling_guest.h
@@ -2011,6 +2011,16 @@
     const VkPhysicalDeviceExtendedDynamicState2FeaturesEXT* forMarshaling, uint8_t** ptr);
 
 #endif
+#ifdef VK_EXT_color_write_enable
+void reservedmarshal_VkPhysicalDeviceColorWriteEnableFeaturesEXT(
+    VulkanStreamGuest* vkStream, VkStructureType rootType,
+    const VkPhysicalDeviceColorWriteEnableFeaturesEXT* forMarshaling, uint8_t** ptr);
+
+void reservedmarshal_VkPipelineColorWriteCreateInfoEXT(
+    VulkanStreamGuest* vkStream, VkStructureType rootType,
+    const VkPipelineColorWriteCreateInfoEXT* forMarshaling, uint8_t** ptr);
+
+#endif
 #ifdef VK_GOOGLE_gfxstream
 void reservedmarshal_VkImportColorBufferGOOGLE(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 1c8eb59..cd80dc3 100644
--- a/guest/vulkan_enc/goldfish_vk_transform_guest.cpp
+++ b/guest/vulkan_enc/goldfish_vk_transform_guest.cpp
@@ -7902,6 +7902,44 @@
 }
 
 #endif
+#ifdef VK_EXT_color_write_enable
+void transform_tohost_VkPhysicalDeviceColorWriteEnableFeaturesEXT(
+    ResourceTracker* resourceTracker, VkPhysicalDeviceColorWriteEnableFeaturesEXT* toTransform) {
+    (void)resourceTracker;
+    (void)toTransform;
+    if (toTransform->pNext) {
+        transform_tohost_extension_struct(resourceTracker, (void*)(toTransform->pNext));
+    }
+}
+
+void transform_fromhost_VkPhysicalDeviceColorWriteEnableFeaturesEXT(
+    ResourceTracker* resourceTracker, VkPhysicalDeviceColorWriteEnableFeaturesEXT* toTransform) {
+    (void)resourceTracker;
+    (void)toTransform;
+    if (toTransform->pNext) {
+        transform_fromhost_extension_struct(resourceTracker, (void*)(toTransform->pNext));
+    }
+}
+
+void transform_tohost_VkPipelineColorWriteCreateInfoEXT(
+    ResourceTracker* resourceTracker, VkPipelineColorWriteCreateInfoEXT* toTransform) {
+    (void)resourceTracker;
+    (void)toTransform;
+    if (toTransform->pNext) {
+        transform_tohost_extension_struct(resourceTracker, (void*)(toTransform->pNext));
+    }
+}
+
+void transform_fromhost_VkPipelineColorWriteCreateInfoEXT(
+    ResourceTracker* resourceTracker, VkPipelineColorWriteCreateInfoEXT* toTransform) {
+    (void)resourceTracker;
+    (void)toTransform;
+    if (toTransform->pNext) {
+        transform_fromhost_extension_struct(resourceTracker, (void*)(toTransform->pNext));
+    }
+}
+
+#endif
 #ifdef VK_GOOGLE_gfxstream
 void transform_tohost_VkImportColorBufferGOOGLE(ResourceTracker* resourceTracker,
                                                 VkImportColorBufferGOOGLE* toTransform) {
@@ -9032,6 +9070,20 @@
             break;
         }
 #endif
+#ifdef VK_EXT_color_write_enable
+        case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COLOR_WRITE_ENABLE_FEATURES_EXT: {
+            transform_tohost_VkPhysicalDeviceColorWriteEnableFeaturesEXT(
+                resourceTracker, reinterpret_cast<VkPhysicalDeviceColorWriteEnableFeaturesEXT*>(
+                                     structExtension_out));
+            break;
+        }
+        case VK_STRUCTURE_TYPE_PIPELINE_COLOR_WRITE_CREATE_INFO_EXT: {
+            transform_tohost_VkPipelineColorWriteCreateInfoEXT(
+                resourceTracker,
+                reinterpret_cast<VkPipelineColorWriteCreateInfoEXT*>(structExtension_out));
+            break;
+        }
+#endif
 #ifdef VK_GOOGLE_gfxstream
         case VK_STRUCTURE_TYPE_IMPORT_COLOR_BUFFER_GOOGLE: {
             transform_tohost_VkImportColorBufferGOOGLE(
@@ -10112,6 +10164,20 @@
             break;
         }
 #endif
+#ifdef VK_EXT_color_write_enable
+        case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COLOR_WRITE_ENABLE_FEATURES_EXT: {
+            transform_fromhost_VkPhysicalDeviceColorWriteEnableFeaturesEXT(
+                resourceTracker, reinterpret_cast<VkPhysicalDeviceColorWriteEnableFeaturesEXT*>(
+                                     structExtension_out));
+            break;
+        }
+        case VK_STRUCTURE_TYPE_PIPELINE_COLOR_WRITE_CREATE_INFO_EXT: {
+            transform_fromhost_VkPipelineColorWriteCreateInfoEXT(
+                resourceTracker,
+                reinterpret_cast<VkPipelineColorWriteCreateInfoEXT*>(structExtension_out));
+            break;
+        }
+#endif
 #ifdef VK_GOOGLE_gfxstream
         case VK_STRUCTURE_TYPE_IMPORT_COLOR_BUFFER_GOOGLE: {
             transform_fromhost_VkImportColorBufferGOOGLE(
diff --git a/guest/vulkan_enc/goldfish_vk_transform_guest.h b/guest/vulkan_enc/goldfish_vk_transform_guest.h
index 7b1ca80..8897aa6 100644
--- a/guest/vulkan_enc/goldfish_vk_transform_guest.h
+++ b/guest/vulkan_enc/goldfish_vk_transform_guest.h
@@ -3157,6 +3157,20 @@
     VkPhysicalDeviceExtendedDynamicState2FeaturesEXT* toTransform);
 
 #endif
+#ifdef VK_EXT_color_write_enable
+void transform_tohost_VkPhysicalDeviceColorWriteEnableFeaturesEXT(
+    ResourceTracker* resourceTracker, VkPhysicalDeviceColorWriteEnableFeaturesEXT* toTransform);
+
+void transform_fromhost_VkPhysicalDeviceColorWriteEnableFeaturesEXT(
+    ResourceTracker* resourceTracker, VkPhysicalDeviceColorWriteEnableFeaturesEXT* toTransform);
+
+void transform_tohost_VkPipelineColorWriteCreateInfoEXT(
+    ResourceTracker* resourceTracker, VkPipelineColorWriteCreateInfoEXT* toTransform);
+
+void transform_fromhost_VkPipelineColorWriteCreateInfoEXT(
+    ResourceTracker* resourceTracker, VkPipelineColorWriteCreateInfoEXT* toTransform);
+
+#endif
 #ifdef VK_GOOGLE_gfxstream
 void transform_tohost_VkImportColorBufferGOOGLE(ResourceTracker* resourceTracker,
                                                 VkImportColorBufferGOOGLE* toTransform);
diff --git a/host/virtio-gpu-gfxstream-renderer.cpp b/host/virtio-gpu-gfxstream-renderer.cpp
index 19d911a..e572a90 100644
--- a/host/virtio-gpu-gfxstream-renderer.cpp
+++ b/host/virtio-gpu-gfxstream-renderer.cpp
@@ -710,11 +710,6 @@
         mCookie = cookie;
         mFeatures = features;
         mFenceCallback = fence_callback;
-        mVirtioGpuOps = android_getVirtioGpuOps();
-        if (!mVirtioGpuOps) {
-            stream_renderer_error("Could not get virtio gpu ops!");
-            return -EINVAL;
-        }
         mAddressSpaceDeviceControlOps = get_address_space_device_control_ops();
         if (!mAddressSpaceDeviceControlOps) {
             stream_renderer_error("Could not get address space device control ops!");
@@ -972,9 +967,11 @@
 
                 stream_renderer_debug("wait for gpu ring %s", to_string(ring).c_str());
                 auto taskId = mVirtioGpuTimelines->enqueueTask(ring);
-                mVirtioGpuOps->async_wait_for_gpu_with_cb(sync_handle, [this, taskId] {
+#if GFXSTREAM_ENABLE_HOST_GLES
+                gfxstream::FrameBuffer::getFB()->asyncWaitForGpuWithCb(sync_handle, [this, taskId] {
                     mVirtioGpuTimelines->notifyTaskCompletion(taskId);
                 });
+#endif
                 break;
             }
             case GFXSTREAM_CREATE_EXPORT_SYNC_VK:
@@ -998,7 +995,7 @@
 
                 stream_renderer_debug("wait for gpu ring %s", to_string(ring).c_str());
                 auto taskId = mVirtioGpuTimelines->enqueueTask(ring);
-                mVirtioGpuOps->async_wait_for_gpu_vulkan_with_cb(
+                gfxstream::FrameBuffer::getFB()->asyncWaitForGpuVulkanWithCb(
                     device_handle, fence_handle,
                     [this, taskId] { mVirtioGpuTimelines->notifyTaskCompletion(taskId); });
                 break;
@@ -1021,9 +1018,9 @@
                 stream_renderer_debug("wait for gpu vk qsri ring %u image 0x%llx",
                                       to_string(ring).c_str(), (unsigned long long)image_handle);
                 auto taskId = mVirtioGpuTimelines->enqueueTask(ring);
-                mVirtioGpuOps->async_wait_for_gpu_vulkan_qsri_with_cb(image_handle, [this, taskId] {
-                    mVirtioGpuTimelines->notifyTaskCompletion(taskId);
-                });
+                gfxstream::FrameBuffer::getFB()->asyncWaitForGpuVulkanQsriWithCb(
+                    image_handle,
+                    [this, taskId] { mVirtioGpuTimelines->notifyTaskCompletion(taskId); });
                 break;
             }
             case GFXSTREAM_PLACEHOLDER_COMMAND_VK: {
@@ -1143,7 +1140,8 @@
 
     void handleCreateResourceBuffer(struct stream_renderer_resource_create_args* args) {
         stream_renderer_debug("w:%u h:%u handle:%u", args->handle, args->width, args->height);
-        mVirtioGpuOps->create_buffer_with_handle(args->width * args->height, args->handle);
+        gfxstream::FrameBuffer::getFB()->createBufferWithHandle(args->width * args->height,
+                                                                args->handle);
     }
 
     void handleCreateResourceColorBuffer(struct stream_renderer_resource_create_args* args) {
@@ -1153,10 +1151,12 @@
         const uint32_t glformat = virgl_format_to_gl(args->format);
         const uint32_t fwkformat = virgl_format_to_fwk_format(args->format);
         const bool linear = !!(args->bind & VIRGL_BIND_LINEAR);
-        mVirtioGpuOps->create_color_buffer_with_handle(args->width, args->height, glformat,
-                                                       fwkformat, args->handle, linear);
-        mVirtioGpuOps->set_guest_managed_color_buffer_lifetime(true /* guest manages lifetime */);
-        mVirtioGpuOps->open_color_buffer(args->handle);
+        gfxstream::FrameBuffer::getFB()->createColorBufferWithHandle(
+            args->width, args->height, glformat, (gfxstream::FrameworkFormat)fwkformat,
+            args->handle, linear);
+        gfxstream::FrameBuffer::getFB()->setGuestManagedColorBufferLifetime(
+            true /* guest manages lifetime */);
+        gfxstream::FrameBuffer::getFB()->openColorBuffer(args->handle);
     }
 
     int createResource(struct stream_renderer_resource_create_args* args, struct iovec* iov,
@@ -1210,10 +1210,10 @@
             case ResType::PIPE:
                 break;
             case ResType::BUFFER:
-                mVirtioGpuOps->close_buffer(toUnrefId);
+                gfxstream::FrameBuffer::getFB()->closeBuffer(toUnrefId);
                 break;
             case ResType::COLOR_BUFFER:
-                mVirtioGpuOps->close_color_buffer(toUnrefId);
+                gfxstream::FrameBuffer::getFB()->closeColorBuffer(toUnrefId);
                 break;
         }
 
@@ -1366,8 +1366,8 @@
             return -EINVAL;
         }
 
-        mVirtioGpuOps->read_buffer(res->args.handle, 0, res->args.width * res->args.height,
-                                   res->linear);
+        gfxstream::FrameBuffer::getFB()->readBuffer(
+            res->args.handle, 0, res->args.width * res->args.height, res->linear);
         return 0;
     }
 
@@ -1377,8 +1377,8 @@
             return -EINVAL;
         }
 
-        mVirtioGpuOps->update_buffer(res->args.handle, 0, res->args.width * res->args.height,
-                                     res->linear);
+        gfxstream::FrameBuffer::getFB()->updateBuffer(
+            res->args.handle, 0, res->args.width * res->args.height, res->linear);
         return 0;
     }
 
@@ -1395,11 +1395,13 @@
         // We always xfer the whole thing again from GL
         // since it's fiddly to calc / copy-out subregions
         if (virgl_format_is_yuv(res->args.format)) {
-            mVirtioGpuOps->read_color_buffer_yuv(res->args.handle, 0, 0, res->args.width,
-                                                 res->args.height, res->linear, res->linearSize);
+            gfxstream::FrameBuffer::getFB()->readColorBufferYUV(res->args.handle, 0, 0,
+                                                                res->args.width, res->args.height,
+                                                                res->linear, res->linearSize);
         } else {
-            mVirtioGpuOps->read_color_buffer(res->args.handle, 0, 0, res->args.width,
-                                             res->args.height, glformat, gltype, res->linear);
+            gfxstream::FrameBuffer::getFB()->readColorBuffer(res->args.handle, 0, 0,
+                                                             res->args.width, res->args.height,
+                                                             glformat, gltype, res->linear);
         }
 
         return 0;
@@ -1417,8 +1419,9 @@
 
         // We always xfer the whole thing again to GL
         // since it's fiddly to calc / copy-out subregions
-        mVirtioGpuOps->update_color_buffer(res->args.handle, 0, 0, res->args.width,
-                                           res->args.height, glformat, gltype, res->linear);
+        gfxstream::FrameBuffer::getFB()->updateColorBuffer(res->args.handle, 0, 0, res->args.width,
+                                                           res->args.height, glformat, gltype,
+                                                           res->linear);
         return 0;
     }
 
@@ -1666,7 +1669,7 @@
 
     void flushResource(uint32_t res_handle) {
         auto taskId = mVirtioGpuTimelines->enqueueTask(VirtioGpuRingGlobal{});
-        mVirtioGpuOps->async_post_color_buffer(
+        gfxstream::FrameBuffer::getFB()->postWithCallback(
             res_handle, [this, taskId](std::shared_future<void> waitForGpu) {
                 waitForGpu.wait();
                 mVirtioGpuTimelines->notifyTaskCompletion(taskId);
@@ -1801,24 +1804,35 @@
     int platformImportResource(int res_handle, int res_info, void* resource) {
         auto it = mResources.find(res_handle);
         if (it == mResources.end()) return -EINVAL;
-        bool success = mVirtioGpuOps->platform_import_resource(res_handle, res_info, resource);
+        bool success =
+            gfxstream::FrameBuffer::getFB()->platformImportResource(res_handle, res_info, resource);
         return success ? 0 : -1;
     }
 
     int platformResourceInfo(int res_handle, int* width, int* height, int* internal_format) {
+        bool success = false;
         auto it = mResources.find(res_handle);
         if (it == mResources.end()) return -EINVAL;
-        bool success =
-            mVirtioGpuOps->platform_resource_info(res_handle, width, height, internal_format);
+#if GFXSTREAM_ENABLE_HOST_GLES
+        success = gfxstream::FrameBuffer::getFB()->getColorBufferInfo(res_handle, width, height,
+                                                                      internal_format);
+#endif
         return success ? 0 : -1;
     }
 
     void* platformCreateSharedEglContext() {
-        return mVirtioGpuOps->platform_create_shared_egl_context();
+        void* ptr = nullptr;
+#if GFXSTREAM_ENABLE_HOST_GLES
+        ptr = gfxstream::FrameBuffer::getFB()->platformCreateSharedEglContext();
+#endif
+        return ptr;
     }
 
     int platformDestroySharedEglContext(void* context) {
-        bool success = mVirtioGpuOps->platform_destroy_shared_egl_context(context);
+        bool success = false;
+#if GFXSTREAM_ENABLE_HOST_GLES
+        success = gfxstream::FrameBuffer::getFB()->platformDestroySharedEglContext(context);
+#endif
         return success ? 0 : -1;
     }
 
@@ -1834,7 +1848,7 @@
             return -EINVAL;
         }
 
-        return mVirtioGpuOps->wait_sync_color_buffer(res_handle);
+        return gfxstream::FrameBuffer::getFB()->waitSyncColorBuffer(res_handle);
     }
 
     int resourceMapInfo(uint32_t res_handle, uint32_t* map_info) {
@@ -1991,7 +2005,6 @@
     void* mCookie = nullptr;
     gfxstream::host::FeatureSet mFeatures;
     stream_renderer_fence_callback mFenceCallback;
-    AndroidVirtioGpuOps* mVirtioGpuOps = nullptr;
     uint32_t mPageSize = 4096;
     struct address_space_device_control_ops* mAddressSpaceDeviceControlOps = nullptr;
 
diff --git a/host/vulkan/VkDecoder.cpp b/host/vulkan/VkDecoder.cpp
index d01db9c..e36069c 100644
--- a/host/vulkan/VkDecoder.cpp
+++ b/host/vulkan/VkDecoder.cpp
@@ -20508,6 +20508,53 @@
                 break;
             }
 #endif
+#ifdef VK_EXT_color_write_enable
+            case OP_vkCmdSetColorWriteEnableEXT: {
+                android::base::beginTrace("vkCmdSetColorWriteEnableEXT decode");
+                VkCommandBuffer commandBuffer;
+                uint32_t attachmentCount;
+                const VkBool32* pColorWriteEnables;
+                // Begin non wrapped dispatchable handle unboxing for commandBuffer;
+                uint64_t cgen_var_0;
+                memcpy((uint64_t*)&cgen_var_0, *readStreamPtrPtr, 1 * 8);
+                *readStreamPtrPtr += 1 * 8;
+                *(VkCommandBuffer*)&commandBuffer =
+                    (VkCommandBuffer)(VkCommandBuffer)((VkCommandBuffer)(*&cgen_var_0));
+                auto unboxed_commandBuffer = unbox_VkCommandBuffer(commandBuffer);
+                auto vk = dispatch_VkCommandBuffer(commandBuffer);
+                // End manual dispatchable handle unboxing for commandBuffer;
+                memcpy((uint32_t*)&attachmentCount, *readStreamPtrPtr, sizeof(uint32_t));
+                *readStreamPtrPtr += sizeof(uint32_t);
+                vkReadStream->alloc((void**)&pColorWriteEnables,
+                                    ((attachmentCount)) * sizeof(const VkBool32));
+                memcpy((VkBool32*)pColorWriteEnables, *readStreamPtrPtr,
+                       ((attachmentCount)) * sizeof(const VkBool32));
+                *readStreamPtrPtr += ((attachmentCount)) * sizeof(const VkBool32);
+                if (m_logCalls) {
+                    fprintf(stderr,
+                            "stream %p: call vkCmdSetColorWriteEnableEXT 0x%llx 0x%llx 0x%llx \n",
+                            ioStream, (unsigned long long)commandBuffer,
+                            (unsigned long long)attachmentCount,
+                            (unsigned long long)pColorWriteEnables);
+                }
+                vk->vkCmdSetColorWriteEnableEXT(unboxed_commandBuffer, attachmentCount,
+                                                pColorWriteEnables);
+                vkStream->unsetHandleMapping();
+                vkReadStream->setReadPos((uintptr_t)(*readStreamPtrPtr) -
+                                         (uintptr_t)snapshotTraceBegin);
+                size_t snapshotTraceBytes = vkReadStream->endTrace();
+                if (m_state->snapshotsEnabled()) {
+                    m_state->snapshot()->vkCmdSetColorWriteEnableEXT(
+                        snapshotTraceBegin, snapshotTraceBytes, &m_pool, commandBuffer,
+                        attachmentCount, pColorWriteEnables);
+                }
+                vkReadStream->clearPool();
+                if (m_queueSubmitWithCommandsEnabled)
+                    seqnoPtr->fetch_add(1, std::memory_order_seq_cst);
+                android::base::endTrace();
+                break;
+            }
+#endif
 #ifdef VK_GOOGLE_gfxstream
             case OP_vkMapMemoryIntoAddressSpaceGOOGLE: {
                 android::base::beginTrace("vkMapMemoryIntoAddressSpaceGOOGLE decode");
diff --git a/host/vulkan/VkDecoder.h b/host/vulkan/VkDecoder.h
index 80d41ed..b1087e1 100644
--- a/host/vulkan/VkDecoder.h
+++ b/host/vulkan/VkDecoder.h
@@ -252,6 +252,8 @@
 #endif
 #ifdef VK_EXT_extended_dynamic_state2
 #endif
+#ifdef VK_EXT_color_write_enable
+#endif
 #ifdef VK_GOOGLE_gfxstream
 #endif
 #ifdef VK_EXT_load_store_op_none
diff --git a/host/vulkan/VkDecoderSnapshot.cpp b/host/vulkan/VkDecoderSnapshot.cpp
index 448c8b6..a406dcb 100644
--- a/host/vulkan/VkDecoderSnapshot.cpp
+++ b/host/vulkan/VkDecoderSnapshot.cpp
@@ -3616,6 +3616,22 @@
         }
     }
 #endif
+#ifdef VK_EXT_color_write_enable
+    void vkCmdSetColorWriteEnableEXT(const uint8_t* snapshotTraceBegin, size_t snapshotTraceBytes,
+                                     android::base::BumpPool* pool, VkCommandBuffer commandBuffer,
+                                     uint32_t attachmentCount, const VkBool32* pColorWriteEnables) {
+        android::base::AutoLock lock(mLock);
+        // commandBuffer modify
+        auto apiHandle = mReconstruction.createApiInfo();
+        auto apiInfo = mReconstruction.getApiInfo(apiHandle);
+        mReconstruction.setApiTrace(apiInfo, OP_vkCmdSetColorWriteEnableEXT, snapshotTraceBegin,
+                                    snapshotTraceBytes);
+        for (uint32_t i = 0; i < 1; ++i) {
+            VkCommandBuffer boxed = unboxed_to_boxed_VkCommandBuffer((&commandBuffer)[i]);
+            mReconstruction.forEachHandleAddModifyApi((const uint64_t*)(&boxed), 1, apiHandle);
+        }
+    }
+#endif
 #ifdef VK_GOOGLE_gfxstream
     void vkMapMemoryIntoAddressSpaceGOOGLE(const uint8_t* snapshotTraceBegin,
                                            size_t snapshotTraceBytes, android::base::BumpPool* pool,
@@ -7052,6 +7068,14 @@
                                              commandBuffer, primitiveRestartEnable);
 }
 #endif
+#ifdef VK_EXT_color_write_enable
+void VkDecoderSnapshot::vkCmdSetColorWriteEnableEXT(
+    const uint8_t* snapshotTraceBegin, size_t snapshotTraceBytes, android::base::BumpPool* pool,
+    VkCommandBuffer commandBuffer, uint32_t attachmentCount, const VkBool32* pColorWriteEnables) {
+    mImpl->vkCmdSetColorWriteEnableEXT(snapshotTraceBegin, snapshotTraceBytes, pool, commandBuffer,
+                                       attachmentCount, pColorWriteEnables);
+}
+#endif
 #ifdef VK_GOOGLE_gfxstream
 void VkDecoderSnapshot::vkMapMemoryIntoAddressSpaceGOOGLE(
     const uint8_t* snapshotTraceBegin, size_t snapshotTraceBytes, android::base::BumpPool* pool,
diff --git a/host/vulkan/VkDecoderSnapshot.h b/host/vulkan/VkDecoderSnapshot.h
index 337d151..723d72e 100644
--- a/host/vulkan/VkDecoderSnapshot.h
+++ b/host/vulkan/VkDecoderSnapshot.h
@@ -1555,6 +1555,11 @@
                                            VkCommandBuffer commandBuffer,
                                            VkBool32 primitiveRestartEnable);
 #endif
+#ifdef VK_EXT_color_write_enable
+    void vkCmdSetColorWriteEnableEXT(const uint8_t* snapshotTraceBegin, size_t snapshotTraceBytes,
+                                     android::base::BumpPool* pool, VkCommandBuffer commandBuffer,
+                                     uint32_t attachmentCount, const VkBool32* pColorWriteEnables);
+#endif
 #ifdef VK_GOOGLE_gfxstream
     void vkMapMemoryIntoAddressSpaceGOOGLE(const uint8_t* snapshotTraceBegin,
                                            size_t snapshotTraceBytes, android::base::BumpPool* pool,
diff --git a/host/vulkan/VkSubDecoder.cpp b/host/vulkan/VkSubDecoder.cpp
index 215fc80..b204f42 100644
--- a/host/vulkan/VkSubDecoder.cpp
+++ b/host/vulkan/VkSubDecoder.cpp
@@ -3137,6 +3137,29 @@
                 break;
             }
 #endif
+#ifdef VK_EXT_color_write_enable
+            case OP_vkCmdSetColorWriteEnableEXT: {
+                android::base::beginTrace("vkCmdSetColorWriteEnableEXT subdecode");
+                uint32_t attachmentCount;
+                const VkBool32* pColorWriteEnables;
+                VkBool32 stack_pColorWriteEnables[MAX_STACK_ITEMS];
+                memcpy((uint32_t*)&attachmentCount, *readStreamPtrPtr, sizeof(uint32_t));
+                *readStreamPtrPtr += sizeof(uint32_t);
+                if (((attachmentCount)) <= MAX_STACK_ITEMS) {
+                    pColorWriteEnables = (VkBool32*)stack_pColorWriteEnables;
+                } else {
+                    readStream->alloc((void**)&pColorWriteEnables,
+                                      ((attachmentCount)) * sizeof(const VkBool32));
+                }
+                memcpy((VkBool32*)pColorWriteEnables, *readStreamPtrPtr,
+                       ((attachmentCount)) * sizeof(const VkBool32));
+                *readStreamPtrPtr += ((attachmentCount)) * sizeof(const VkBool32);
+                vk->vkCmdSetColorWriteEnableEXT((VkCommandBuffer)dispatchHandle, attachmentCount,
+                                                pColorWriteEnables);
+                android::base::endTrace();
+                break;
+            }
+#endif
 #ifdef VK_GOOGLE_gfxstream
             case OP_vkBeginCommandBufferAsyncGOOGLE: {
                 android::base::beginTrace("vkBeginCommandBufferAsyncGOOGLE subdecode");
diff --git a/host/vulkan/cereal/common/goldfish_vk_deepcopy.cpp b/host/vulkan/cereal/common/goldfish_vk_deepcopy.cpp
index fb5072e..ce7ba9e 100644
--- a/host/vulkan/cereal/common/goldfish_vk_deepcopy.cpp
+++ b/host/vulkan/cereal/common/goldfish_vk_deepcopy.cpp
@@ -9191,6 +9191,58 @@
 }
 
 #endif
+#ifdef VK_EXT_color_write_enable
+void deepcopy_VkPhysicalDeviceColorWriteEnableFeaturesEXT(
+    Allocator* alloc, VkStructureType rootType,
+    const VkPhysicalDeviceColorWriteEnableFeaturesEXT* from,
+    VkPhysicalDeviceColorWriteEnableFeaturesEXT* 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_VkPipelineColorWriteCreateInfoEXT(Allocator* alloc, VkStructureType rootType,
+                                                const VkPipelineColorWriteCreateInfoEXT* from,
+                                                VkPipelineColorWriteCreateInfoEXT* 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->pColorWriteEnables = nullptr;
+    if (from->pColorWriteEnables) {
+        to->pColorWriteEnables = (VkBool32*)alloc->dupArray(
+            from->pColorWriteEnables, from->attachmentCount * sizeof(const VkBool32));
+    }
+}
+
+#endif
 #ifdef VK_GOOGLE_gfxstream
 void deepcopy_VkImportColorBufferGOOGLE(Allocator* alloc, VkStructureType rootType,
                                         const VkImportColorBufferGOOGLE* from,
@@ -10769,6 +10821,24 @@
             break;
         }
 #endif
+#ifdef VK_EXT_color_write_enable
+        case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COLOR_WRITE_ENABLE_FEATURES_EXT: {
+            deepcopy_VkPhysicalDeviceColorWriteEnableFeaturesEXT(
+                alloc, rootType,
+                reinterpret_cast<const VkPhysicalDeviceColorWriteEnableFeaturesEXT*>(
+                    structExtension),
+                reinterpret_cast<VkPhysicalDeviceColorWriteEnableFeaturesEXT*>(
+                    structExtension_out));
+            break;
+        }
+        case VK_STRUCTURE_TYPE_PIPELINE_COLOR_WRITE_CREATE_INFO_EXT: {
+            deepcopy_VkPipelineColorWriteCreateInfoEXT(
+                alloc, rootType,
+                reinterpret_cast<const VkPipelineColorWriteCreateInfoEXT*>(structExtension),
+                reinterpret_cast<VkPipelineColorWriteCreateInfoEXT*>(structExtension_out));
+            break;
+        }
+#endif
 #ifdef VK_GOOGLE_gfxstream
         case VK_STRUCTURE_TYPE_IMPORT_COLOR_BUFFER_GOOGLE: {
             deepcopy_VkImportColorBufferGOOGLE(
diff --git a/host/vulkan/cereal/common/goldfish_vk_deepcopy.h b/host/vulkan/cereal/common/goldfish_vk_deepcopy.h
index 74ffcb3..1ab18b3 100644
--- a/host/vulkan/cereal/common/goldfish_vk_deepcopy.h
+++ b/host/vulkan/cereal/common/goldfish_vk_deepcopy.h
@@ -2078,6 +2078,17 @@
     VkPhysicalDeviceExtendedDynamicState2FeaturesEXT* to);
 
 #endif
+#ifdef VK_EXT_color_write_enable
+void deepcopy_VkPhysicalDeviceColorWriteEnableFeaturesEXT(
+    Allocator* alloc, VkStructureType rootType,
+    const VkPhysicalDeviceColorWriteEnableFeaturesEXT* from,
+    VkPhysicalDeviceColorWriteEnableFeaturesEXT* to);
+
+void deepcopy_VkPipelineColorWriteCreateInfoEXT(Allocator* alloc, VkStructureType rootType,
+                                                const VkPipelineColorWriteCreateInfoEXT* from,
+                                                VkPipelineColorWriteCreateInfoEXT* to);
+
+#endif
 #ifdef VK_GOOGLE_gfxstream
 void deepcopy_VkImportColorBufferGOOGLE(Allocator* alloc, VkStructureType rootType,
                                         const VkImportColorBufferGOOGLE* from,
diff --git a/host/vulkan/cereal/common/goldfish_vk_dispatch.cpp b/host/vulkan/cereal/common/goldfish_vk_dispatch.cpp
index d225e29..acf2ae9 100644
--- a/host/vulkan/cereal/common/goldfish_vk_dispatch.cpp
+++ b/host/vulkan/cereal/common/goldfish_vk_dispatch.cpp
@@ -223,6 +223,8 @@
 #endif
 #ifdef VK_EXT_extended_dynamic_state2
 #endif
+#ifdef VK_EXT_color_write_enable
+#endif
 #ifdef VK_GOOGLE_gfxstream
 #endif
 #ifdef VK_EXT_load_store_op_none
@@ -921,6 +923,10 @@
     out->vkCmdSetPrimitiveRestartEnableEXT =
         (PFN_vkCmdSetPrimitiveRestartEnableEXT)dlSymFunc(lib, "vkCmdSetPrimitiveRestartEnableEXT");
 #endif
+#ifdef VK_EXT_color_write_enable
+    out->vkCmdSetColorWriteEnableEXT =
+        (PFN_vkCmdSetColorWriteEnableEXT)dlSymFunc(lib, "vkCmdSetColorWriteEnableEXT");
+#endif
 #ifdef VK_GOOGLE_gfxstream
     out->vkMapMemoryIntoAddressSpaceGOOGLE =
         (PFN_vkMapMemoryIntoAddressSpaceGOOGLE)dlSymFunc(lib, "vkMapMemoryIntoAddressSpaceGOOGLE");
@@ -1875,6 +1881,10 @@
         (PFN_vkCmdSetPrimitiveRestartEnableEXT)vk->vkGetInstanceProcAddr(
             instance, "vkCmdSetPrimitiveRestartEnableEXT");
 #endif
+#ifdef VK_EXT_color_write_enable
+    out->vkCmdSetColorWriteEnableEXT = (PFN_vkCmdSetColorWriteEnableEXT)vk->vkGetInstanceProcAddr(
+        instance, "vkCmdSetColorWriteEnableEXT");
+#endif
 #ifdef VK_GOOGLE_gfxstream
     out->vkMapMemoryIntoAddressSpaceGOOGLE =
         (PFN_vkMapMemoryIntoAddressSpaceGOOGLE)vk->vkGetInstanceProcAddr(
@@ -2811,6 +2821,10 @@
         (PFN_vkCmdSetPrimitiveRestartEnableEXT)vk->vkGetDeviceProcAddr(
             device, "vkCmdSetPrimitiveRestartEnableEXT");
 #endif
+#ifdef VK_EXT_color_write_enable
+    out->vkCmdSetColorWriteEnableEXT = (PFN_vkCmdSetColorWriteEnableEXT)vk->vkGetDeviceProcAddr(
+        device, "vkCmdSetColorWriteEnableEXT");
+#endif
 #ifdef VK_GOOGLE_gfxstream
     out->vkMapMemoryIntoAddressSpaceGOOGLE =
         (PFN_vkMapMemoryIntoAddressSpaceGOOGLE)vk->vkGetDeviceProcAddr(
diff --git a/host/vulkan/cereal/common/goldfish_vk_dispatch.h b/host/vulkan/cereal/common/goldfish_vk_dispatch.h
index b54a8b1..bb57b78 100644
--- a/host/vulkan/cereal/common/goldfish_vk_dispatch.h
+++ b/host/vulkan/cereal/common/goldfish_vk_dispatch.h
@@ -617,6 +617,9 @@
     PFN_vkCmdSetLogicOpEXT vkCmdSetLogicOpEXT;
     PFN_vkCmdSetPrimitiveRestartEnableEXT vkCmdSetPrimitiveRestartEnableEXT;
 #endif
+#ifdef VK_EXT_color_write_enable
+    PFN_vkCmdSetColorWriteEnableEXT vkCmdSetColorWriteEnableEXT;
+#endif
 #ifdef VK_GOOGLE_gfxstream
     PFN_vkMapMemoryIntoAddressSpaceGOOGLE vkMapMemoryIntoAddressSpaceGOOGLE;
     PFN_vkUpdateDescriptorSetWithTemplateSizedGOOGLE vkUpdateDescriptorSetWithTemplateSizedGOOGLE;
diff --git a/host/vulkan/cereal/common/goldfish_vk_extension_structs.cpp b/host/vulkan/cereal/common/goldfish_vk_extension_structs.cpp
index 34c17e6..d1be96b 100644
--- a/host/vulkan/cereal/common/goldfish_vk_extension_structs.cpp
+++ b/host/vulkan/cereal/common/goldfish_vk_extension_structs.cpp
@@ -218,6 +218,8 @@
 #endif
 #ifdef VK_EXT_extended_dynamic_state2
 #endif
+#ifdef VK_EXT_color_write_enable
+#endif
 #ifdef VK_GOOGLE_gfxstream
 #endif
 #ifdef VK_EXT_load_store_op_none
@@ -871,6 +873,14 @@
             return sizeof(VkPhysicalDeviceExtendedDynamicState2FeaturesEXT);
         }
 #endif
+#ifdef VK_EXT_color_write_enable
+        case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COLOR_WRITE_ENABLE_FEATURES_EXT: {
+            return sizeof(VkPhysicalDeviceColorWriteEnableFeaturesEXT);
+        }
+        case VK_STRUCTURE_TYPE_PIPELINE_COLOR_WRITE_CREATE_INFO_EXT: {
+            return sizeof(VkPipelineColorWriteCreateInfoEXT);
+        }
+#endif
 #ifdef VK_GOOGLE_gfxstream
         case VK_STRUCTURE_TYPE_IMPORT_COLOR_BUFFER_GOOGLE: {
             return sizeof(VkImportColorBufferGOOGLE);
@@ -1541,6 +1551,14 @@
             return sizeof(VkPhysicalDeviceExtendedDynamicState2FeaturesEXT);
         }
 #endif
+#ifdef VK_EXT_color_write_enable
+        case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COLOR_WRITE_ENABLE_FEATURES_EXT: {
+            return sizeof(VkPhysicalDeviceColorWriteEnableFeaturesEXT);
+        }
+        case VK_STRUCTURE_TYPE_PIPELINE_COLOR_WRITE_CREATE_INFO_EXT: {
+            return sizeof(VkPipelineColorWriteCreateInfoEXT);
+        }
+#endif
 #ifdef VK_GOOGLE_gfxstream
         case VK_STRUCTURE_TYPE_IMPORT_COLOR_BUFFER_GOOGLE: {
             return sizeof(VkImportColorBufferGOOGLE);
diff --git a/host/vulkan/cereal/common/goldfish_vk_extension_structs.h b/host/vulkan/cereal/common/goldfish_vk_extension_structs.h
index 092fc41..80cd508 100644
--- a/host/vulkan/cereal/common/goldfish_vk_extension_structs.h
+++ b/host/vulkan/cereal/common/goldfish_vk_extension_structs.h
@@ -232,6 +232,8 @@
 #endif
 #ifdef VK_EXT_extended_dynamic_state2
 #endif
+#ifdef VK_EXT_color_write_enable
+#endif
 #ifdef VK_GOOGLE_gfxstream
 #endif
 #ifdef VK_EXT_load_store_op_none
diff --git a/host/vulkan/cereal/common/goldfish_vk_marshaling.cpp b/host/vulkan/cereal/common/goldfish_vk_marshaling.cpp
index b077246..3465068 100644
--- a/host/vulkan/cereal/common/goldfish_vk_marshaling.cpp
+++ b/host/vulkan/cereal/common/goldfish_vk_marshaling.cpp
@@ -18149,6 +18149,86 @@
 }
 
 #endif
+#ifdef VK_EXT_color_write_enable
+void marshal_VkPhysicalDeviceColorWriteEnableFeaturesEXT(
+    VulkanStream* vkStream, VkStructureType rootType,
+    const VkPhysicalDeviceColorWriteEnableFeaturesEXT* 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((VkBool32*)&forMarshaling->colorWriteEnable, sizeof(VkBool32));
+}
+
+void unmarshal_VkPhysicalDeviceColorWriteEnableFeaturesEXT(
+    VulkanStream* vkStream, VkStructureType rootType,
+    VkPhysicalDeviceColorWriteEnableFeaturesEXT* 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((VkBool32*)&forUnmarshaling->colorWriteEnable, sizeof(VkBool32));
+}
+
+void marshal_VkPipelineColorWriteCreateInfoEXT(
+    VulkanStream* vkStream, VkStructureType rootType,
+    const VkPipelineColorWriteCreateInfoEXT* 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->attachmentCount, sizeof(uint32_t));
+    vkStream->write((const VkBool32*)forMarshaling->pColorWriteEnables,
+                    forMarshaling->attachmentCount * sizeof(const VkBool32));
+}
+
+void unmarshal_VkPipelineColorWriteCreateInfoEXT(
+    VulkanStream* vkStream, VkStructureType rootType,
+    VkPipelineColorWriteCreateInfoEXT* 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->attachmentCount, sizeof(uint32_t));
+    vkStream->alloc((void**)&forUnmarshaling->pColorWriteEnables,
+                    forUnmarshaling->attachmentCount * sizeof(const VkBool32));
+    vkStream->read((VkBool32*)forUnmarshaling->pColorWriteEnables,
+                   forUnmarshaling->attachmentCount * sizeof(const VkBool32));
+}
+
+#endif
 #ifdef VK_GOOGLE_gfxstream
 void marshal_VkImportColorBufferGOOGLE(VulkanStream* vkStream, VkStructureType rootType,
                                        const VkImportColorBufferGOOGLE* forMarshaling) {
@@ -19569,6 +19649,21 @@
             break;
         }
 #endif
+#ifdef VK_EXT_color_write_enable
+        case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COLOR_WRITE_ENABLE_FEATURES_EXT: {
+            marshal_VkPhysicalDeviceColorWriteEnableFeaturesEXT(
+                vkStream, rootType,
+                reinterpret_cast<const VkPhysicalDeviceColorWriteEnableFeaturesEXT*>(
+                    structExtension));
+            break;
+        }
+        case VK_STRUCTURE_TYPE_PIPELINE_COLOR_WRITE_CREATE_INFO_EXT: {
+            marshal_VkPipelineColorWriteCreateInfoEXT(
+                vkStream, rootType,
+                reinterpret_cast<const VkPipelineColorWriteCreateInfoEXT*>(structExtension));
+            break;
+        }
+#endif
 #ifdef VK_GOOGLE_gfxstream
         case VK_STRUCTURE_TYPE_IMPORT_COLOR_BUFFER_GOOGLE: {
             marshal_VkImportColorBufferGOOGLE(
@@ -20854,6 +20949,21 @@
             break;
         }
 #endif
+#ifdef VK_EXT_color_write_enable
+        case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COLOR_WRITE_ENABLE_FEATURES_EXT: {
+            unmarshal_VkPhysicalDeviceColorWriteEnableFeaturesEXT(
+                vkStream, rootType,
+                reinterpret_cast<VkPhysicalDeviceColorWriteEnableFeaturesEXT*>(
+                    structExtension_out));
+            break;
+        }
+        case VK_STRUCTURE_TYPE_PIPELINE_COLOR_WRITE_CREATE_INFO_EXT: {
+            unmarshal_VkPipelineColorWriteCreateInfoEXT(
+                vkStream, rootType,
+                reinterpret_cast<VkPipelineColorWriteCreateInfoEXT*>(structExtension_out));
+            break;
+        }
+#endif
 #ifdef VK_GOOGLE_gfxstream
         case VK_STRUCTURE_TYPE_IMPORT_COLOR_BUFFER_GOOGLE: {
             unmarshal_VkImportColorBufferGOOGLE(
@@ -21659,6 +21769,11 @@
             return "OP_vkGetDeviceBufferMemoryRequirementsKHR";
         }
 #endif
+#ifdef VK_EXT_color_write_enable
+        case OP_vkCmdSetColorWriteEnableEXT: {
+            return "OP_vkCmdSetColorWriteEnableEXT";
+        }
+#endif
 #ifdef VK_KHR_maintenance5
         case OP_vkCmdBindIndexBuffer2KHR: {
             return "OP_vkCmdBindIndexBuffer2KHR";
diff --git a/host/vulkan/cereal/common/goldfish_vk_marshaling.h b/host/vulkan/cereal/common/goldfish_vk_marshaling.h
index 66897c2..96b368e 100644
--- a/host/vulkan/cereal/common/goldfish_vk_marshaling.h
+++ b/host/vulkan/cereal/common/goldfish_vk_marshaling.h
@@ -3847,6 +3847,25 @@
 #define OP_vkCmdSetLogicOpEXT 267481927
 #define OP_vkCmdSetPrimitiveRestartEnableEXT 299567883
 #endif
+#ifdef VK_EXT_color_write_enable
+void marshal_VkPhysicalDeviceColorWriteEnableFeaturesEXT(
+    VulkanStream* vkStream, VkStructureType rootType,
+    const VkPhysicalDeviceColorWriteEnableFeaturesEXT* forMarshaling);
+
+void unmarshal_VkPhysicalDeviceColorWriteEnableFeaturesEXT(
+    VulkanStream* vkStream, VkStructureType rootType,
+    VkPhysicalDeviceColorWriteEnableFeaturesEXT* forUnmarshaling);
+
+void marshal_VkPipelineColorWriteCreateInfoEXT(
+    VulkanStream* vkStream, VkStructureType rootType,
+    const VkPipelineColorWriteCreateInfoEXT* forMarshaling);
+
+void unmarshal_VkPipelineColorWriteCreateInfoEXT(
+    VulkanStream* vkStream, VkStructureType rootType,
+    VkPipelineColorWriteCreateInfoEXT* forUnmarshaling);
+
+#define OP_vkCmdSetColorWriteEnableEXT 202223297
+#endif
 #ifdef VK_GOOGLE_gfxstream
 void marshal_VkImportColorBufferGOOGLE(VulkanStream* vkStream, VkStructureType rootType,
                                        const VkImportColorBufferGOOGLE* forMarshaling);
diff --git a/host/vulkan/cereal/common/goldfish_vk_reserved_marshaling.cpp b/host/vulkan/cereal/common/goldfish_vk_reserved_marshaling.cpp
index 5dee122..20c4c86 100644
--- a/host/vulkan/cereal/common/goldfish_vk_reserved_marshaling.cpp
+++ b/host/vulkan/cereal/common/goldfish_vk_reserved_marshaling.cpp
@@ -14064,6 +14064,71 @@
 }
 
 #endif
+#ifdef VK_EXT_color_write_enable
+void reservedunmarshal_VkPhysicalDeviceColorWriteEnableFeaturesEXT(
+    VulkanStream* vkStream, VkStructureType rootType,
+    VkPhysicalDeviceColorWriteEnableFeaturesEXT* 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((VkBool32*)&forUnmarshaling->colorWriteEnable, *ptr, sizeof(VkBool32));
+    *ptr += sizeof(VkBool32);
+}
+
+void reservedunmarshal_VkPipelineColorWriteCreateInfoEXT(
+    VulkanStream* vkStream, VkStructureType rootType,
+    VkPipelineColorWriteCreateInfoEXT* 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->attachmentCount, *ptr, sizeof(uint32_t));
+    *ptr += sizeof(uint32_t);
+    vkStream->alloc((void**)&forUnmarshaling->pColorWriteEnables,
+                    forUnmarshaling->attachmentCount * sizeof(const VkBool32));
+    memcpy((VkBool32*)forUnmarshaling->pColorWriteEnables, *ptr,
+           forUnmarshaling->attachmentCount * sizeof(const VkBool32));
+    *ptr += forUnmarshaling->attachmentCount * sizeof(const VkBool32);
+}
+
+#endif
 #ifdef VK_GOOGLE_gfxstream
 void reservedunmarshal_VkImportColorBufferGOOGLE(VulkanStream* vkStream, VkStructureType rootType,
                                                  VkImportColorBufferGOOGLE* forUnmarshaling,
@@ -15546,6 +15611,21 @@
             break;
         }
 #endif
+#ifdef VK_EXT_color_write_enable
+        case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COLOR_WRITE_ENABLE_FEATURES_EXT: {
+            reservedunmarshal_VkPhysicalDeviceColorWriteEnableFeaturesEXT(
+                vkStream, rootType,
+                reinterpret_cast<VkPhysicalDeviceColorWriteEnableFeaturesEXT*>(structExtension_out),
+                ptr);
+            break;
+        }
+        case VK_STRUCTURE_TYPE_PIPELINE_COLOR_WRITE_CREATE_INFO_EXT: {
+            reservedunmarshal_VkPipelineColorWriteCreateInfoEXT(
+                vkStream, rootType,
+                reinterpret_cast<VkPipelineColorWriteCreateInfoEXT*>(structExtension_out), ptr);
+            break;
+        }
+#endif
 #ifdef VK_GOOGLE_gfxstream
         case VK_STRUCTURE_TYPE_IMPORT_COLOR_BUFFER_GOOGLE: {
             reservedunmarshal_VkImportColorBufferGOOGLE(
diff --git a/host/vulkan/cereal/common/goldfish_vk_reserved_marshaling.h b/host/vulkan/cereal/common/goldfish_vk_reserved_marshaling.h
index cc6d7aa..8571822 100644
--- a/host/vulkan/cereal/common/goldfish_vk_reserved_marshaling.h
+++ b/host/vulkan/cereal/common/goldfish_vk_reserved_marshaling.h
@@ -2051,6 +2051,16 @@
     VkPhysicalDeviceExtendedDynamicState2FeaturesEXT* forUnmarshaling, uint8_t** ptr);
 
 #endif
+#ifdef VK_EXT_color_write_enable
+void reservedunmarshal_VkPhysicalDeviceColorWriteEnableFeaturesEXT(
+    VulkanStream* vkStream, VkStructureType rootType,
+    VkPhysicalDeviceColorWriteEnableFeaturesEXT* forUnmarshaling, uint8_t** ptr);
+
+void reservedunmarshal_VkPipelineColorWriteCreateInfoEXT(
+    VulkanStream* vkStream, VkStructureType rootType,
+    VkPipelineColorWriteCreateInfoEXT* forUnmarshaling, uint8_t** ptr);
+
+#endif
 #ifdef VK_GOOGLE_gfxstream
 void reservedunmarshal_VkImportColorBufferGOOGLE(VulkanStream* vkStream, VkStructureType rootType,
                                                  VkImportColorBufferGOOGLE* forUnmarshaling,
diff --git a/host/vulkan/cereal/common/goldfish_vk_transform.cpp b/host/vulkan/cereal/common/goldfish_vk_transform.cpp
index 4974e11..d22c383 100644
--- a/host/vulkan/cereal/common/goldfish_vk_transform.cpp
+++ b/host/vulkan/cereal/common/goldfish_vk_transform.cpp
@@ -8420,6 +8420,46 @@
 }
 
 #endif
+#ifdef VK_EXT_color_write_enable
+void transform_tohost_VkPhysicalDeviceColorWriteEnableFeaturesEXT(
+    VkDecoderGlobalState* resourceTracker,
+    VkPhysicalDeviceColorWriteEnableFeaturesEXT* toTransform) {
+    (void)resourceTracker;
+    (void)toTransform;
+    if (toTransform->pNext) {
+        transform_tohost_extension_struct(resourceTracker, (void*)(toTransform->pNext));
+    }
+}
+
+void transform_fromhost_VkPhysicalDeviceColorWriteEnableFeaturesEXT(
+    VkDecoderGlobalState* resourceTracker,
+    VkPhysicalDeviceColorWriteEnableFeaturesEXT* toTransform) {
+    (void)resourceTracker;
+    (void)toTransform;
+    if (toTransform->pNext) {
+        transform_fromhost_extension_struct(resourceTracker, (void*)(toTransform->pNext));
+    }
+}
+
+void transform_tohost_VkPipelineColorWriteCreateInfoEXT(
+    VkDecoderGlobalState* resourceTracker, VkPipelineColorWriteCreateInfoEXT* toTransform) {
+    (void)resourceTracker;
+    (void)toTransform;
+    if (toTransform->pNext) {
+        transform_tohost_extension_struct(resourceTracker, (void*)(toTransform->pNext));
+    }
+}
+
+void transform_fromhost_VkPipelineColorWriteCreateInfoEXT(
+    VkDecoderGlobalState* resourceTracker, VkPipelineColorWriteCreateInfoEXT* toTransform) {
+    (void)resourceTracker;
+    (void)toTransform;
+    if (toTransform->pNext) {
+        transform_fromhost_extension_struct(resourceTracker, (void*)(toTransform->pNext));
+    }
+}
+
+#endif
 #ifdef VK_GOOGLE_gfxstream
 void transform_tohost_VkImportColorBufferGOOGLE(VkDecoderGlobalState* resourceTracker,
                                                 VkImportColorBufferGOOGLE* toTransform) {
@@ -9638,6 +9678,20 @@
             break;
         }
 #endif
+#ifdef VK_EXT_color_write_enable
+        case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COLOR_WRITE_ENABLE_FEATURES_EXT: {
+            transform_tohost_VkPhysicalDeviceColorWriteEnableFeaturesEXT(
+                resourceTracker, reinterpret_cast<VkPhysicalDeviceColorWriteEnableFeaturesEXT*>(
+                                     structExtension_out));
+            break;
+        }
+        case VK_STRUCTURE_TYPE_PIPELINE_COLOR_WRITE_CREATE_INFO_EXT: {
+            transform_tohost_VkPipelineColorWriteCreateInfoEXT(
+                resourceTracker,
+                reinterpret_cast<VkPipelineColorWriteCreateInfoEXT*>(structExtension_out));
+            break;
+        }
+#endif
 #ifdef VK_GOOGLE_gfxstream
         case VK_STRUCTURE_TYPE_IMPORT_COLOR_BUFFER_GOOGLE: {
             transform_tohost_VkImportColorBufferGOOGLE(
@@ -10806,6 +10860,20 @@
             break;
         }
 #endif
+#ifdef VK_EXT_color_write_enable
+        case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COLOR_WRITE_ENABLE_FEATURES_EXT: {
+            transform_fromhost_VkPhysicalDeviceColorWriteEnableFeaturesEXT(
+                resourceTracker, reinterpret_cast<VkPhysicalDeviceColorWriteEnableFeaturesEXT*>(
+                                     structExtension_out));
+            break;
+        }
+        case VK_STRUCTURE_TYPE_PIPELINE_COLOR_WRITE_CREATE_INFO_EXT: {
+            transform_fromhost_VkPipelineColorWriteCreateInfoEXT(
+                resourceTracker,
+                reinterpret_cast<VkPipelineColorWriteCreateInfoEXT*>(structExtension_out));
+            break;
+        }
+#endif
 #ifdef VK_GOOGLE_gfxstream
         case VK_STRUCTURE_TYPE_IMPORT_COLOR_BUFFER_GOOGLE: {
             transform_fromhost_VkImportColorBufferGOOGLE(
diff --git a/host/vulkan/cereal/common/goldfish_vk_transform.h b/host/vulkan/cereal/common/goldfish_vk_transform.h
index bfe011c..360d734 100644
--- a/host/vulkan/cereal/common/goldfish_vk_transform.h
+++ b/host/vulkan/cereal/common/goldfish_vk_transform.h
@@ -3382,6 +3382,22 @@
     VkPhysicalDeviceExtendedDynamicState2FeaturesEXT* toTransform);
 
 #endif
+#ifdef VK_EXT_color_write_enable
+void transform_tohost_VkPhysicalDeviceColorWriteEnableFeaturesEXT(
+    VkDecoderGlobalState* resourceTracker,
+    VkPhysicalDeviceColorWriteEnableFeaturesEXT* toTransform);
+
+void transform_fromhost_VkPhysicalDeviceColorWriteEnableFeaturesEXT(
+    VkDecoderGlobalState* resourceTracker,
+    VkPhysicalDeviceColorWriteEnableFeaturesEXT* toTransform);
+
+void transform_tohost_VkPipelineColorWriteCreateInfoEXT(
+    VkDecoderGlobalState* resourceTracker, VkPipelineColorWriteCreateInfoEXT* toTransform);
+
+void transform_fromhost_VkPipelineColorWriteCreateInfoEXT(
+    VkDecoderGlobalState* resourceTracker, VkPipelineColorWriteCreateInfoEXT* toTransform);
+
+#endif
 #ifdef VK_GOOGLE_gfxstream
 void transform_tohost_VkImportColorBufferGOOGLE(VkDecoderGlobalState* resourceTracker,
                                                 VkImportColorBufferGOOGLE* toTransform);