diff --git a/BUILD.gn b/BUILD.gn
index 5e63b1923eb2a8a361aaca626eab448197d8031b..348ab87c46af21a98e704da82ad1a25b67b92f33 100644
--- a/BUILD.gn
+++ b/BUILD.gn
@@ -1,4 +1,4 @@
-source_set("goldfish_vulkan") {
+shared_library("vulkan_goldfish") {
   sources = [
     "android-emu/android/base/AlignedBuf.cpp",
     "android-emu/android/base/AlignedBuf.h",
@@ -84,8 +84,14 @@ source_set("goldfish_vulkan") {
     "-Wno-missing-field-initializers",
   ]
 
+  ldflags = [ "-static-libstdc++" ]
+
   if (target_os == "fuchsia") {
-    sources += [ "fuchsia/port.cc" ]
+    sources -= [ "system/OpenglSystemCommon/QemuPipeStream.cpp" ]
+    sources += [
+      "fuchsia/port.cc",
+      "system/OpenglSystemCommon/QemuPipeStreamFuchsia.cpp",
+    ]
 
     include_dirs += [
       "//third_party/vulkan_loader_and_validation_layers/include",
@@ -97,16 +103,17 @@ source_set("goldfish_vulkan") {
     ]
 
     deps = [
-      "//zircon/public/fidl/fuchsia-hardware-goldfish:fuchsia-hardware-goldfish_c",
+      "//zircon/public/fidl/fuchsia-hardware-goldfish-address-space:fuchsia-hardware-goldfish-address-space_c",
+      "//zircon/public/fidl/fuchsia-hardware-goldfish-control:fuchsia-hardware-goldfish-control_c",
+      "//zircon/public/fidl/fuchsia-hardware-goldfish-pipe:fuchsia-hardware-goldfish-pipe_c",
       "//zircon/public/fidl/fuchsia-sysmem",
       "//zircon/public/lib/fdio",
-      "//zircon/public/lib/fzl",
       "//zircon/public/lib/trace",
     ]
 
     defines += [
-      "QEMU_PIPE_PATH=\"/dev/sys/platform/acpi/goldfish/goldfish-pipe\"",
-      "GOLDFISH_ADDRESS_SPACE_DEVICE_NAME=\"/dev/sys/platform/acpi/goldfish/goldfish-pipe\"",
+      "QEMU_PIPE_PATH=\"/dev/class/goldfish-pipe/000\"",
+      "GOLDFISH_ADDRESS_SPACE_DEVICE_NAME=\"/dev/class/goldfish-address-space/000\"",
     ]
   }
 }
diff --git a/shared/OpenglCodecCommon/goldfish_address_space.cpp b/shared/OpenglCodecCommon/goldfish_address_space.cpp
index afa6b85dcf158e1b6f90614ac650333abc7d4d24..bbc59c618d539949dc5769805ab3bc9d446d9f52 100644
--- a/shared/OpenglCodecCommon/goldfish_address_space.cpp
+++ b/shared/OpenglCodecCommon/goldfish_address_space.cpp
@@ -127,8 +127,9 @@ void GoldfishAddressSpaceBlock::replace(GoldfishAddressSpaceBlock *other)
 }
 #elif __Fuchsia__
 #include <fcntl.h>
-#include <fuchsia/hardware/goldfish/c/fidl.h>
-#include <lib/fzl/fdio.h>
+#include <fuchsia/hardware/goldfish/address/space/c/fidl.h>
+#include <lib/fdio/fdio.h>
+#include <stdlib.h>
 #include <sys/stat.h>
 #include <sys/types.h>
 #include <unistd.h>
@@ -136,22 +137,23 @@ void GoldfishAddressSpaceBlock::replace(GoldfishAddressSpaceBlock *other)
 #include <zircon/syscalls.h>
 #include <zircon/syscalls/object.h>
 
-GoldfishAddressSpaceBlockProvider::GoldfishAddressSpaceBlockProvider()
-    : m_fd(::open(GOLDFISH_ADDRESS_SPACE_DEVICE_NAME, O_RDWR)) {}
+GoldfishAddressSpaceBlockProvider::GoldfishAddressSpaceBlockProvider() {
+    fdio_get_service_handle(::open(GOLDFISH_ADDRESS_SPACE_DEVICE_NAME, O_RDWR), &m_channel);
+}
 
 GoldfishAddressSpaceBlockProvider::~GoldfishAddressSpaceBlockProvider()
 {
-    ::close(m_fd);
+    zx_handle_close(m_channel);
 }
 
 GoldfishAddressSpaceBlock::GoldfishAddressSpaceBlock()
     : m_vmo(ZX_HANDLE_INVALID)
+    , m_channel(ZX_HANDLE_INVALID)
     , m_mmaped_ptr(NULL)
     , m_phys_addr(0)
     , m_host_addr(0)
     , m_offset(0)
-    , m_size(0)
-    , m_fd(-1) {}
+    , m_size(0) {}
 
 GoldfishAddressSpaceBlock::~GoldfishAddressSpaceBlock()
 {
@@ -166,7 +168,7 @@ GoldfishAddressSpaceBlock &GoldfishAddressSpaceBlock::operator=(const GoldfishAd
     m_host_addr = rhs.m_host_addr;
     m_offset = rhs.m_offset;
     m_size = rhs.m_size;
-    m_fd = rhs.m_fd;
+    m_channel = rhs.m_channel;
 
     return *this;
 }
@@ -182,36 +184,13 @@ bool GoldfishAddressSpaceBlock::allocate(GoldfishAddressSpaceBlockProvider *prov
         return false;
     }
 
-    {
-        fzl::FdioCaller caller{fbl::unique_fd(provider->m_fd)};
-
-        int32_t res = ZX_OK;
-        zx_status_t status =
-            fuchsia_hardware_goldfish_DeviceAllocateVmo(caller.borrow_channel(),
-                                                        size, &res, &m_vmo);
-        if (status != ZX_OK || res != ZX_OK) {
-            ALOGE("%s: allocate vmo failed: %d:%d", __func__, status, res);
-            provider->m_fd = caller.release().release();
-            return false;
-        }
-
-        zx_handle_t vmo_out;
-        status = zx_handle_duplicate(m_vmo, ZX_DEFAULT_VMO_RIGHTS, &vmo_out);
-        if (status != ZX_OK) {
-            ALOGE("%s: vmo dup failed: %d:%d", __func__, status);
-            provider->m_fd = caller.release().release();
-            return false;
-        }
-
-        status = fuchsia_hardware_goldfish_DeviceGetPhysicalAddress(
-            caller.borrow_channel(),
-            vmo_out, &res, &m_phys_addr);
-        provider->m_fd = caller.release().release();
-
-        if (status != ZX_OK || res != ZX_OK) {
-            ALOGE("%s: pin vmo failed: %d:%d", __func__, status, res);
-            return false;
-        }
+    int32_t res = ZX_OK;
+    zx_status_t status =
+        fuchsia_hardware_goldfish_address_space_DeviceAllocateBlock(
+            provider->m_channel, size, &res, &m_phys_addr, &m_vmo);
+    if (status != ZX_OK || res != ZX_OK) {
+        ALOGE("%s: allocate block failed: %d:%d", __func__, status, res);
+        return false;
     }
 
     m_offset = 0;
@@ -221,7 +200,7 @@ bool GoldfishAddressSpaceBlock::allocate(GoldfishAddressSpaceBlockProvider *prov
           (unsigned long long)m_offset,
           (unsigned long long)m_size);
 
-    m_fd = provider->m_fd;
+    m_channel = provider->m_channel;
     return true;
 }
 
@@ -284,6 +263,14 @@ void GoldfishAddressSpaceBlock::destroy()
     if (m_size) {
         zx_handle_close(m_vmo);
         m_vmo = ZX_HANDLE_INVALID;
+        int32_t res = ZX_OK;
+        zx_status_t status =
+            fuchsia_hardware_goldfish_address_space_DeviceDeallocateBlock(
+                m_channel, m_phys_addr, &res);
+        if (status != ZX_OK || res != ZX_OK) {
+            ALOGE("%s: deallocate block failed: %d:%d", __func__, status, res);
+        }
+        m_channel = ZX_HANDLE_INVALID;
         m_phys_addr = 0;
         m_host_addr = 0;
         m_offset = 0;
@@ -303,7 +290,7 @@ void GoldfishAddressSpaceBlock::replace(GoldfishAddressSpaceBlock *other)
 
 bool GoldfishAddressSpaceBlockProvider::is_opened()
 {
-    return m_fd >= 0;
+    return m_channel != ZX_HANDLE_INVALID;
 }
 #else
 #include <linux/types.h>
diff --git a/shared/OpenglCodecCommon/goldfish_address_space.h b/shared/OpenglCodecCommon/goldfish_address_space.h
index 637e20dfe38921dc5a48a1f82a4688532b1f015e..7ebb4517b5d65a66ceab03a3347b13e4750129d7 100644
--- a/shared/OpenglCodecCommon/goldfish_address_space.h
+++ b/shared/OpenglCodecCommon/goldfish_address_space.h
@@ -45,7 +45,11 @@ private:
    GoldfishAddressSpaceBlockProvider &operator=(const GoldfishAddressSpaceBlockProvider &rhs);
 
    bool is_opened();
+#ifdef __Fuchsia__
+   uint32_t m_channel;
+#else
    int m_fd;
+#endif
 
    friend class GoldfishAddressSpaceBlock;
 };
@@ -75,13 +79,15 @@ private:
 #else
 #ifdef __Fuchsia__
     uint32_t  m_vmo;
+    uint32_t  m_channel;
+#else
+    int       m_fd;
 #endif
     void     *m_mmaped_ptr;
     uint64_t  m_phys_addr;
     uint64_t  m_host_addr;
     uint64_t  m_offset;
     size_t    m_size;
-    int       m_fd;
 #endif
 };
 
diff --git a/system/OpenglSystemCommon/QemuPipeStream.h b/system/OpenglSystemCommon/QemuPipeStream.h
index 0884d5740eff21f5a633ee305df52e6f3efe0ad6..8d64ab8419aa90c7845b9cfefe7342add9715ca7 100644
--- a/system/OpenglSystemCommon/QemuPipeStream.h
+++ b/system/OpenglSystemCommon/QemuPipeStream.h
@@ -25,6 +25,12 @@
 
 #include "qemu_pipe.h"
 
+#ifdef __Fuchsia__
+#include <lib/zx/channel.h>
+#include <lib/zx/event.h>
+#include <lib/zx/vmo.h>
+#endif
+
 class QemuPipeStream : public IOStream {
 public:
     typedef enum { ERR_INVALID_SOCKET = -1000 } QemuPipeStreamError;
@@ -48,6 +54,11 @@ private:
     QEMU_PIPE_HANDLE m_sock;
     size_t m_bufsize;
     unsigned char *m_buf;
+#ifdef __Fuchsia__
+    zx::channel m_channel;
+    zx::event m_event;
+    zx::vmo m_vmo;
+#endif
     QemuPipeStream(QEMU_PIPE_HANDLE sock, size_t bufSize);
 };
 
diff --git a/system/OpenglSystemCommon/QemuPipeStreamFuchsia.cpp b/system/OpenglSystemCommon/QemuPipeStreamFuchsia.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..f4ee61c5e332b1fc04e4e342560ecaa707c802ed
--- /dev/null
+++ b/system/OpenglSystemCommon/QemuPipeStreamFuchsia.cpp
@@ -0,0 +1,296 @@
+/*
+* Copyright (C) 2019 The Android Open Source Project
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+#include "QemuPipeStream.h"
+
+#include <cutils/log.h>
+#include <errno.h>
+#include <fuchsia/hardware/goldfish/pipe/c/fidl.h>
+#include <lib/fdio/fdio.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <zircon/process.h>
+
+#include <utility>
+
+QemuPipeStream::QemuPipeStream(size_t bufSize) :
+    IOStream(bufSize),
+    m_sock(-1),
+    m_bufsize(bufSize),
+    m_buf(nullptr)
+{
+}
+
+QemuPipeStream::QemuPipeStream(QEMU_PIPE_HANDLE sock, size_t bufSize) :
+    IOStream(bufSize),
+    m_sock(sock),
+    m_bufsize(bufSize),
+    m_buf(nullptr)
+{
+}
+
+QemuPipeStream::~QemuPipeStream()
+{
+    if (m_channel.is_valid()) {
+        flush();
+    }
+    if (m_buf) {
+        zx_status_t status = zx_vmar_unmap(zx_vmar_root_self(),
+                                           reinterpret_cast<zx_vaddr_t>(m_buf),
+                                           m_bufsize);
+        if (status != ZX_OK) {
+            ALOGE("zx_vmar_unmap failed: %d\n", status);
+            abort();
+        }
+    }
+}
+
+int QemuPipeStream::connect(void)
+{
+    int fd = TEMP_FAILURE_RETRY(open(QEMU_PIPE_PATH, O_RDWR));
+    if (fd < 0) {
+        ALOGE("%s: failed to open " QEMU_PIPE_PATH ": %s",
+              __FUNCTION__, strerror(errno));
+        return -1;
+    }
+
+    zx::channel channel;
+    zx_status_t status = fdio_get_service_handle(
+        fd, channel.reset_and_get_address());
+    if (status != ZX_OK) {
+        ALOGE("%s: failed to get service handle for " QEMU_PIPE_PATH ": %d",
+              __FUNCTION__, status);
+        close(fd);
+        return -1;
+    }
+
+    zx::event event;
+    status = zx::event::create(0, &event);
+    if (status != ZX_OK) {
+        ALOGE("%s: failed to create event: %d", __FUNCTION__, status);
+        return -1;
+    }
+    zx::event event_copy;
+    status = event.duplicate(ZX_RIGHT_SAME_RIGHTS, &event_copy);
+    if (status != ZX_OK) {
+        ALOGE("%s: failed to duplicate event: %d", __FUNCTION__, status);
+        return -1;
+    }
+
+    status = fuchsia_hardware_goldfish_pipe_DeviceSetEvent(
+        channel.get(), event_copy.release());
+    if (status != ZX_OK) {
+        ALOGE("%s: failed to set event: %d:%d", __FUNCTION__, status);
+        return -1;
+    }
+
+    zx_status_t status2 = ZX_OK;
+    zx::vmo vmo;
+    status = fuchsia_hardware_goldfish_pipe_DeviceGetBuffer(
+        channel.get(), &status2, vmo.reset_and_get_address());
+    if (status != ZX_OK || status2 != ZX_OK) {
+        ALOGE("%s: failed to get buffer: %d:%d", __FUNCTION__, status, status2);
+        return -1;
+    }
+
+    size_t len = strlen("pipe:opengles");
+    status = vmo.write("pipe:opengles", 0, len + 1);
+    if (status != ZX_OK) {
+        ALOGE("%s: failed write pipe name", __FUNCTION__);
+        return -1;
+    }
+
+    uint64_t actual;
+    status = fuchsia_hardware_goldfish_pipe_DeviceWrite(
+        channel.get(), len + 1, 0, &status2, &actual);
+    if (status != ZX_OK || status2 != ZX_OK) {
+        ALOGD("%s: connecting to pipe service failed: %d:%d", __FUNCTION__,
+              status, status2);
+        return -1;
+    }
+
+    m_channel = std::move(channel);
+    m_event = std::move(event);
+    m_vmo = std::move(vmo);
+    return 0;
+}
+
+void *QemuPipeStream::allocBuffer(size_t minSize)
+{
+    zx_status_t status;
+    if (m_buf) {
+        if (minSize <= m_bufsize) {
+            return m_buf;
+        }
+        status = zx_vmar_unmap(zx_vmar_root_self(),
+                               reinterpret_cast<zx_vaddr_t>(m_buf),
+                               m_bufsize);
+        if (status != ZX_OK) {
+          ALOGE("zx_vmar_unmap failed: %d\n", status);
+          abort();
+        }
+        m_buf = nullptr;
+    }
+
+    size_t allocSize = m_bufsize < minSize ? minSize : m_bufsize;
+
+    zx_status_t status2 = ZX_OK;
+    status = fuchsia_hardware_goldfish_pipe_DeviceSetBufferSize(
+        m_channel.get(), allocSize, &status2);
+    if (status != ZX_OK || status2 != ZX_OK) {
+        ALOGE("%s: failed to get buffer: %d:%d", __FUNCTION__, status, status2);
+        return nullptr;
+    }
+
+    zx::vmo vmo;
+    status = fuchsia_hardware_goldfish_pipe_DeviceGetBuffer(
+        m_channel.get(), &status2, vmo.reset_and_get_address());
+    if (status != ZX_OK || status2 != ZX_OK) {
+        ALOGE("%s: failed to get buffer: %d:%d", __FUNCTION__, status, status2);
+        return nullptr;
+    }
+
+    zx_vaddr_t mapped_addr;
+    status = zx_vmar_map(zx_vmar_root_self(),
+                         ZX_VM_PERM_READ | ZX_VM_PERM_WRITE,
+                         0, vmo.get(), 0, allocSize, &mapped_addr);
+    if (status != ZX_OK) {
+        ALOGE("%s: failed to map buffer: %d:%d", __FUNCTION__, status);
+        return nullptr;
+    }
+
+    m_buf = reinterpret_cast<unsigned char*>(mapped_addr);
+    m_bufsize = allocSize;
+    m_vmo = std::move(vmo);
+    return m_buf;
+}
+
+int QemuPipeStream::commitBuffer(size_t size)
+{
+    if (size == 0) return 0;
+
+    size_t remaining = size;
+    while (remaining) {
+        zx_status_t status2 = ZX_OK;
+        uint64_t actual = 0;
+        zx_status_t status = fuchsia_hardware_goldfish_pipe_DeviceWrite(
+            m_channel.get(), remaining, size - remaining, &status2, &actual);
+        if (status != ZX_OK) {
+            ALOGD("%s: Failed writing to pipe: %d", __FUNCTION__, status);
+            return -1;
+        }
+        if (actual) {
+            remaining -= actual;
+            continue;
+        }
+        if (status2 != ZX_ERR_SHOULD_WAIT) {
+            ALOGD("%s: Error writing to pipe: %d", __FUNCTION__, status2);
+            return -1;
+        }
+        zx_signals_t observed = ZX_SIGNAL_NONE;
+        status = m_event.wait_one(
+            fuchsia_hardware_goldfish_pipe_SIGNAL_WRITABLE |
+            fuchsia_hardware_goldfish_pipe_SIGNAL_HANGUP,
+            zx::time::infinite(), &observed);
+        if (status != ZX_OK) {
+            ALOGD("%s: wait_one failed: %d", __FUNCTION__, status);
+            return -1;
+        }
+        if (observed & fuchsia_hardware_goldfish_pipe_SIGNAL_HANGUP) {
+            ALOGD("%s: Remote end hungup", __FUNCTION__);
+            return -1;
+        }
+    }
+
+    return 0;
+}
+
+int QemuPipeStream::writeFully(const void *buf, size_t len)
+{
+    ALOGE("%s: unsupported", __FUNCTION__);
+    abort();
+    return -1;
+}
+
+QEMU_PIPE_HANDLE QemuPipeStream::getSocket() const {
+    return m_sock;
+}
+
+const unsigned char *QemuPipeStream::readFully(void *buf, size_t len)
+{
+    if (!m_channel.is_valid()) return nullptr;
+
+    if (!buf) {
+        if (len > 0) {
+            ALOGE("QemuPipeStream::readFully failed, buf=NULL, len %zu, lethal"
+                    " error, exiting.", len);
+            abort();
+        }
+        return nullptr;
+    }
+
+    size_t remaining = len;
+    while (remaining) {
+        size_t readSize = m_bufsize < remaining ? m_bufsize : remaining;
+        zx_status_t status2 = ZX_OK;
+        uint64_t actual = 0;
+        zx_status_t status = fuchsia_hardware_goldfish_pipe_DeviceRead(
+            m_channel.get(), readSize, 0, &status2, &actual);
+        if (status != ZX_OK) {
+            ALOGD("%s: Failed reading from pipe: %d", __FUNCTION__, status);
+            return nullptr;
+        }
+        if (actual) {
+            m_vmo.read(static_cast<char *>(buf) + (len - remaining), 0, actual);
+            remaining -= actual;
+            continue;
+        }
+        if (status2 != ZX_ERR_SHOULD_WAIT) {
+            ALOGD("%s: Error reading from pipe: %d", __FUNCTION__, status2);
+            return nullptr;
+        }
+        zx_signals_t observed = ZX_SIGNAL_NONE;
+        status = m_event.wait_one(
+            fuchsia_hardware_goldfish_pipe_SIGNAL_READABLE |
+            fuchsia_hardware_goldfish_pipe_SIGNAL_HANGUP,
+            zx::time::infinite(), &observed);
+        if (status != ZX_OK) {
+            ALOGD("%s: wait_one failed: %d", __FUNCTION__, status);
+            return nullptr;
+        }
+        if (observed & fuchsia_hardware_goldfish_pipe_SIGNAL_HANGUP) {
+            ALOGD("%s: Remote end hungup", __FUNCTION__);
+            return nullptr;
+        }
+    }
+
+    return static_cast<const unsigned char *>(buf);
+}
+
+const unsigned char *QemuPipeStream::read(void *buf, size_t *inout_len)
+{
+    ALOGE("%s: unsupported", __FUNCTION__);
+    abort();
+    return nullptr;
+}
+
+int QemuPipeStream::recv(void *buf, size_t len)
+{
+    ALOGE("%s: unsupported", __FUNCTION__);
+    abort();
+    return -1;
+}
diff --git a/system/gralloc/gralloc.cpp b/system/gralloc/gralloc.cpp
index aace8e3f3c8fab8138d03d63146c7c949c281fae..d39d99ab807dcfa29d2ec17f493fd14a197f1e5d 100644
--- a/system/gralloc/gralloc.cpp
+++ b/system/gralloc/gralloc.cpp
@@ -506,10 +506,6 @@ static int gralloc_alloc(alloc_device_t* dev,
             } else if (usage & GRALLOC_USAGE_HW_VIDEO_ENCODER) {
                 // Camera-to-encoder is NV21
                 format = HAL_PIXEL_FORMAT_YCrCb_420_SP;
-            } else if ((usage & GRALLOC_USAGE_HW_CAMERA_MASK) ==
-                    GRALLOC_USAGE_HW_CAMERA_ZSL) {
-                // Camera-to-ZSL-queue is RGB_888
-                format = HAL_PIXEL_FORMAT_RGB_888;
             }
         }
 
@@ -545,11 +541,6 @@ static int gralloc_alloc(alloc_device_t* dev,
             glFormat = GL_RGBA;
             glType = GL_UNSIGNED_BYTE;
             break;
-        case HAL_PIXEL_FORMAT_RGB_888:
-            bpp = 3;
-            glFormat = GL_RGB;
-            glType = GL_UNSIGNED_BYTE;
-            break;
         case HAL_PIXEL_FORMAT_RGB_565:
             bpp = 2;
             // Workaround: distinguish vs the RGB8/RGBA8
diff --git a/system/vulkan/Android.mk b/system/vulkan/Android.mk
index 30037a243b33c598c5e45637bacd46edaa420388..ebaa3c0cb8c8b6264b6a7c6eb36f39472ae84032 100644
--- a/system/vulkan/Android.mk
+++ b/system/vulkan/Android.mk
@@ -20,6 +20,7 @@ ifneq (true,$(GOLDFISH_OPENGL_BUILD_FOR_HOST))
 $(call emugl-import,libandroidemu)
 
 LOCAL_HEADER_LIBRARIES += \
+    hwvulkan_headers \
     vulkan_headers \
 
 endif
diff --git a/system/vulkan/CMakeLists.txt b/system/vulkan/CMakeLists.txt
index e7fd9bb4271b007d165f96d83ab8044ec9125649..68a62d670b49e25e780a29a3cee4b58f649078c6 100644
--- a/system/vulkan/CMakeLists.txt
+++ b/system/vulkan/CMakeLists.txt
@@ -1,7 +1,7 @@
 # This is an autogenerated file! Do not edit!
 # instead run make from .../device/generic/goldfish-opengl
 # which will re-generate this file.
-android_validate_sha256("${GOLDFISH_DEVICE_ROOT}/system/vulkan/Android.mk" "dbe5f184561a1505d6ed26216fe645508b64bf2f3800f67946428077045c8166")
+android_validate_sha256("${GOLDFISH_DEVICE_ROOT}/system/vulkan/Android.mk" "7ec8946bc369a60407913f2257120f701fa2c6e2ce30e3f7148a8e7b0abca46a")
 set(vulkan.ranchu_src func_table.cpp goldfish_vulkan.cpp)
 android_add_shared_library(vulkan.ranchu)
 target_include_directories(vulkan.ranchu PRIVATE ${GOLDFISH_DEVICE_ROOT}/system/OpenglSystemCommon ${GOLDFISH_DEVICE_ROOT}/bionic/libc/private ${GOLDFISH_DEVICE_ROOT}/system/vulkan_enc ${GOLDFISH_DEVICE_ROOT}/android-emu ${GOLDFISH_DEVICE_ROOT}/system/renderControl_enc ${GOLDFISH_DEVICE_ROOT}/system/GLESv2_enc ${GOLDFISH_DEVICE_ROOT}/system/GLESv1_enc ${GOLDFISH_DEVICE_ROOT}/shared/OpenglCodecCommon ${GOLDFISH_DEVICE_ROOT}/system/vulkan ${GOLDFISH_DEVICE_ROOT}/./host/include/libOpenglRender ${GOLDFISH_DEVICE_ROOT}/./system/include ${GOLDFISH_DEVICE_ROOT}/./../../../external/qemu/android/android-emugl/guest ${GOLDFISH_DEVICE_ROOT}/./../../../external/qemu/android/android-emugl/host/include)
diff --git a/system/vulkan/func_table.cpp b/system/vulkan/func_table.cpp
index 14c8c323930fa65077df9a967f225108e52eab8f..f5b380e23c6df69a7ddf52a9c4b1ffa71f9299cf 100644
--- a/system/vulkan/func_table.cpp
+++ b/system/vulkan/func_table.cpp
@@ -666,7 +666,8 @@ static VkResult entry_vkCreateImageView(
     AEMU_SCOPED_TRACE("vkCreateImageView");
     auto vkEnc = HostConnection::get()->vkEncoder();
     VkResult vkCreateImageView_VkResult_return = (VkResult)0;
-    vkCreateImageView_VkResult_return = vkEnc->vkCreateImageView(device, pCreateInfo, pAllocator, pView);
+    auto resources = ResourceTracker::get();
+    vkCreateImageView_VkResult_return = resources->on_vkCreateImageView(vkEnc, VK_SUCCESS, device, pCreateInfo, pAllocator, pView);
     return vkCreateImageView_VkResult_return;
 }
 static void entry_vkDestroyImageView(
@@ -1095,7 +1096,7 @@ static void entry_vkCmdSetDepthBias(
 }
 static void entry_vkCmdSetBlendConstants(
     VkCommandBuffer commandBuffer,
-    const float blendConstants)
+    const float blendConstants[4])
 {
     AEMU_SCOPED_TRACE("vkCmdSetBlendConstants");
     auto vkEnc = HostConnection::get()->vkEncoder();
diff --git a/system/vulkan/goldfish_vulkan.cpp b/system/vulkan/goldfish_vulkan.cpp
index 18a9424580b0ec4f5c0580063822eef1e49b2b87..bf170e1cd9390b075884d32e48bbbb23fc37c8c4 100644
--- a/system/vulkan/goldfish_vulkan.cpp
+++ b/system/vulkan/goldfish_vulkan.cpp
@@ -161,6 +161,14 @@ SetBufferCollectionConstraintsFUCHSIA(VkDevice /*device*/,
     AEMU_SCOPED_TRACE("vkstubhal::SetBufferCollectionConstraintsFUCHSIA");
     return VK_SUCCESS;
 }
+
+VkResult
+GetBufferCollectionPropertiesFUCHSIA(VkDevice /*device*/,
+                                     VkBufferCollectionFUCHSIA /*collection*/,
+                                     VkBufferCollectionPropertiesFUCHSIA* /*pProperties*/) {
+    AEMU_SCOPED_TRACE("vkstubhal::GetBufferCollectionPropertiesFUCHSIA");
+    return VK_SUCCESS;
+}
 #endif
 
 PFN_vkVoidFunction GetInstanceProcAddr(VkInstance instance,
@@ -195,6 +203,8 @@ PFN_vkVoidFunction GetInstanceProcAddr(VkInstance instance,
         return reinterpret_cast<PFN_vkVoidFunction>(DestroyBufferCollectionFUCHSIA);
     if (strcmp(name, "vkSetBufferCollectionConstraintsFUCHSIA") == 0)
         return reinterpret_cast<PFN_vkVoidFunction>(SetBufferCollectionConstraintsFUCHSIA);
+    if (strcmp(name, "vkGetBufferCollectionPropertiesFUCHSIA") == 0)
+        return reinterpret_cast<PFN_vkVoidFunction>(GetBufferCollectionPropertiesFUCHSIA);
 #endif
     // Per the spec, return NULL if instance is NULL.
     if (!instance)
@@ -208,6 +218,8 @@ PFN_vkVoidFunction GetInstanceProcAddr(VkInstance instance,
 
 namespace {
 
+#ifdef VK_USE_PLATFORM_ANDROID_KHR
+
 int OpenDevice(const hw_module_t* module, const char* id, hw_device_t** device);
 
 hw_module_methods_t goldfish_vulkan_module_methods = {
@@ -232,6 +244,8 @@ int CloseDevice(struct hw_device_t* /*device*/) {
     return 0;
 }
 
+#endif
+
 #define VK_HOST_CONNECTION(ret) \
     HostConnection *hostCon = HostConnection::get(); \
     if (!hostCon) { \
@@ -436,6 +450,26 @@ VkResult SetBufferCollectionConstraintsFUCHSIA(
 
     return res;
 }
+
+VKAPI_ATTR
+VkResult GetBufferCollectionPropertiesFUCHSIA(
+    VkDevice device,
+    VkBufferCollectionFUCHSIA collection,
+    VkBufferCollectionPropertiesFUCHSIA* pProperties) {
+    AEMU_SCOPED_TRACE("goldfish_vulkan::GetBufferCollectionPropertiesFUCHSIA");
+
+    VK_HOST_CONNECTION(VK_ERROR_DEVICE_LOST)
+
+    if (!hostSupportsVulkan) {
+        return vkstubhal::GetBufferCollectionPropertiesFUCHSIA(device, collection, pProperties);
+    }
+
+    VkResult res = goldfish_vk::ResourceTracker::get()->
+        on_vkGetBufferCollectionPropertiesFUCHSIA(
+            vkEnc, VK_SUCCESS, device, collection, pProperties);
+
+    return res;
+}
 #endif
 
 static PFN_vkVoidFunction GetDeviceProcAddr(VkDevice device, const char* name) {
@@ -469,6 +503,9 @@ static PFN_vkVoidFunction GetDeviceProcAddr(VkDevice device, const char* name) {
     if (!strcmp(name, "vkSetBufferCollectionConstraintsFUCHSIA")) {
         return (PFN_vkVoidFunction)SetBufferCollectionConstraintsFUCHSIA;
     }
+    if (!strcmp(name, "vkGetBufferCollectionPropertiesFUCHSIA")) {
+        return (PFN_vkVoidFunction)GetBufferCollectionPropertiesFUCHSIA;
+    }
 #endif
     if (!strcmp(name, "vkGetDeviceProcAddr")) {
         return (PFN_vkVoidFunction)(GetDeviceProcAddr);
@@ -498,6 +535,8 @@ PFN_vkVoidFunction GetInstanceProcAddr(VkInstance instance, const char* name) {
     return (PFN_vkVoidFunction)(goldfish_vk::goldfish_vulkan_get_instance_proc_address(instance, name));
 }
 
+#ifdef VK_USE_PLATFORM_ANDROID_KHR
+
 hwvulkan_device_t goldfish_vulkan_device = {
     .common = {
         .tag = HARDWARE_DEVICE_TAG,
@@ -517,27 +556,43 @@ int OpenDevice(const hw_module_t* /*module*/,
 
     if (strcmp(id, HWVULKAN_DEVICE_0) == 0) {
         *device = &goldfish_vulkan_device.common;
-#ifdef VK_USE_PLATFORM_FUCHSIA
-        goldfish_vk::ResourceTracker::get()->setColorBufferFunctions(
-            [](uint32_t width, uint32_t height, uint32_t format) {
-                VK_HOST_CONNECTION((uint32_t)0)
-                uint32_t r = rcEnc->rcCreateColorBuffer(rcEnc, width, height, format);
-                return r;
-            },
-            [](uint32_t id) {
-                VK_HOST_CONNECTION()
-                rcEnc->rcOpenColorBuffer(rcEnc, id);
-            },
-            [](uint32_t id){
-                VK_HOST_CONNECTION()
-                rcEnc->rcCloseColorBuffer(rcEnc, id);
-            });
-#else
         goldfish_vk::ResourceTracker::get();
-#endif
         return 0;
     }
     return -ENOENT;
 }
 
+#endif
+
+#ifdef VK_USE_PLATFORM_FUCHSIA
+
+class VulkanDevice {
+public:
+    VulkanDevice() {
+        goldfish_vk::ResourceTracker::get();
+    }
+
+    static VulkanDevice& GetInstance() {
+        static VulkanDevice g_instance;
+        return g_instance;
+    }
+
+    PFN_vkVoidFunction GetInstanceProcAddr(VkInstance instance, const char* name) {
+        return ::GetInstanceProcAddr(instance, name);
+    }
+};
+
+extern "C" __attribute__((visibility("default"))) PFN_vkVoidFunction
+vk_icdGetInstanceProcAddr(VkInstance instance, const char* name) {
+    return VulkanDevice::GetInstance().GetInstanceProcAddr(instance, name);
+}
+
+extern "C" __attribute__((visibility("default"))) VkResult
+vk_icdNegotiateLoaderICDInterfaceVersion(uint32_t* pSupportedVersion) {
+    *pSupportedVersion = std::min(*pSupportedVersion, 3u);
+    return VK_SUCCESS;
+}
+
+#endif
+
 } // namespace
diff --git a/system/vulkan_enc/Android.mk b/system/vulkan_enc/Android.mk
index 86d9a4ca90cf5584fa2c1fb059187e044b1d9780..c51aa7eb679fb5d52cda6c8aba39f8d7a114c7c1 100644
--- a/system/vulkan_enc/Android.mk
+++ b/system/vulkan_enc/Android.mk
@@ -28,6 +28,7 @@ LOCAL_C_INCLUDES += \
     $(LOCAL_PATH)/../vulkan_enc \
 
 LOCAL_HEADER_LIBRARIES += \
+    hwvulkan_headers \
     vulkan_headers \
 
 endif
diff --git a/system/vulkan_enc/AndroidHardwareBuffer.cpp b/system/vulkan_enc/AndroidHardwareBuffer.cpp
index a4478306863e15006d8e578f92edce2a8a7cbe59..5cebdc28ebad9881024a9afa30a149bd401ed2d1 100644
--- a/system/vulkan_enc/AndroidHardwareBuffer.cpp
+++ b/system/vulkan_enc/AndroidHardwareBuffer.cpp
@@ -59,15 +59,13 @@ VkResult getAndroidHardwareBufferPropertiesANDROID(
     VkAndroidHardwareBufferPropertiesANDROID* pProperties) {
 
     VkAndroidHardwareBufferFormatPropertiesANDROID* ahbFormatProps =
-        (VkAndroidHardwareBufferFormatPropertiesANDROID*)vk_find_struct(
-            (vk_struct_common*)pProperties->pNext,
-            VK_STRUCTURE_TYPE_ANDROID_HARDWARE_BUFFER_FORMAT_PROPERTIES_ANDROID);
+        vk_find_struct<VkAndroidHardwareBufferFormatPropertiesANDROID>(pProperties);
 
     if (ahbFormatProps) {
         AHardwareBuffer_Desc desc;
         AHardwareBuffer_describe(buffer, &desc);
 
-       uint64_t gpu_usage =
+       const uint64_t gpu_usage =
           AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE |
           AHARDWAREBUFFER_USAGE_GPU_COLOR_OUTPUT |
           AHARDWAREBUFFER_USAGE_GPU_DATA_BUFFER;
@@ -76,10 +74,8 @@ VkResult getAndroidHardwareBufferPropertiesANDROID(
             return VK_ERROR_INVALID_EXTERNAL_HANDLE;
         }
 
-        ahbFormatProps->format =
-            vk_format_from_android(desc.format);
-
-        ahbFormatProps->externalFormat = VK_FORMAT_G8B8G8R8_422_UNORM;
+        ahbFormatProps->format = vk_format_from_android(desc.format);
+        ahbFormatProps->externalFormat = desc.format;
 
         // The formatFeatures member must include
         // VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT and at least one of
@@ -103,7 +99,10 @@ VkResult getAndroidHardwareBufferPropertiesANDROID(
         ahbFormatProps->samplerYcbcrConversionComponents.b = VK_COMPONENT_SWIZZLE_IDENTITY;
         ahbFormatProps->samplerYcbcrConversionComponents.a = VK_COMPONENT_SWIZZLE_IDENTITY;
 
-        ahbFormatProps->suggestedYcbcrModel = VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_601;
+        ahbFormatProps->suggestedYcbcrModel =
+            android_format_is_yuv(desc.format) ?
+                VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_601 :
+                VK_SAMPLER_YCBCR_MODEL_CONVERSION_RGB_IDENTITY;
         ahbFormatProps->suggestedYcbcrRange = VK_SAMPLER_YCBCR_RANGE_ITU_FULL;
 
         ahbFormatProps->suggestedXChromaOffset = VK_CHROMA_LOCATION_MIDPOINT;
diff --git a/system/vulkan_enc/CMakeLists.txt b/system/vulkan_enc/CMakeLists.txt
index 9d98562c964450501b724b95e1a70a666ccefe1f..9d4e7e952b4a294ef76f1eff22248ba52023899e 100644
--- a/system/vulkan_enc/CMakeLists.txt
+++ b/system/vulkan_enc/CMakeLists.txt
@@ -1,7 +1,7 @@
 # This is an autogenerated file! Do not edit!
 # instead run make from .../device/generic/goldfish-opengl
 # which will re-generate this file.
-android_validate_sha256("${GOLDFISH_DEVICE_ROOT}/system/vulkan_enc/Android.mk" "694b4f97bb916f16f52b9b2f2287d248de5271e6113ae367cf8bf360637659c5")
+android_validate_sha256("${GOLDFISH_DEVICE_ROOT}/system/vulkan_enc/Android.mk" "4e4982fe274cdee96492d57f444a19d3a979720f17df5d289961d77cbdb4054b")
 set(vulkan_enc_src AndroidHardwareBuffer.cpp HostVisibleMemoryVirtualization.cpp Resources.cpp Validation.cpp VulkanStreamGuest.cpp VulkanHandleMapping.cpp ResourceTracker.cpp VkEncoder.cpp goldfish_vk_extension_structs_guest.cpp goldfish_vk_marshaling_guest.cpp goldfish_vk_deepcopy_guest.cpp goldfish_vk_handlemap_guest.cpp goldfish_vk_transform_guest.cpp)
 android_add_shared_library(vulkan_enc)
 target_include_directories(vulkan_enc PRIVATE ${GOLDFISH_DEVICE_ROOT}/android-emu ${GOLDFISH_DEVICE_ROOT}/shared/OpenglCodecCommon ${GOLDFISH_DEVICE_ROOT}/system/vulkan_enc ${GOLDFISH_DEVICE_ROOT}/./host/include/libOpenglRender ${GOLDFISH_DEVICE_ROOT}/./system/include ${GOLDFISH_DEVICE_ROOT}/./../../../external/qemu/android/android-emugl/guest ${GOLDFISH_DEVICE_ROOT}/./../../../external/qemu/android/android-emugl/host/include ${GOLDFISH_DEVICE_ROOT}/./../../../external/qemu/android/android-emugl/host/include/vulkan)
diff --git a/system/vulkan_enc/ResourceTracker.cpp b/system/vulkan_enc/ResourceTracker.cpp
index 01ad42b77cd9831a324bef06c3733eedf81ed255..4e86c20adb518da9c8ab150e029f2070d6239a1b 100644
--- a/system/vulkan_enc/ResourceTracker.cpp
+++ b/system/vulkan_enc/ResourceTracker.cpp
@@ -14,6 +14,7 @@
 // limitations under the License.
 
 #include "ResourceTracker.h"
+#include "goldfish_vk_private_defs.h"
 
 #include "../OpenglSystemCommon/EmulatorFeatureInfo.h"
 
@@ -26,31 +27,6 @@ typedef uint32_t zx_handle_t;
 void zx_handle_close(zx_handle_t) { }
 void zx_event_create(int, zx_handle_t*) { }
 
-typedef struct VkImportMemoryZirconHandleInfoFUCHSIA {
-    VkStructureType                       sType;
-    const void*                           pNext;
-    VkExternalMemoryHandleTypeFlagBits    handleType;
-    uint32_t                              handle;
-} VkImportMemoryZirconHandleInfoFUCHSIA;
-
-typedef uint32_t VkBufferCollectionFUCHSIA;
-
-typedef struct VkImportMemoryBufferCollectionFUCHSIA {
-    VkStructureType              sType;
-    const void*                  pNext;
-    VkBufferCollectionFUCHSIA    collection;
-    uint32_t                     index;
-} VkImportMemoryBufferCollectionFUCHSIA;
-
-#define VK_STRUCTURE_TYPE_IMPORT_MEMORY_BUFFER_COLLECTION_FUCHSIA \
-    ((VkStructureType)1001000000)
-#define VK_STRUCTURE_TYPE_TEMP_IMPORT_MEMORY_ZIRCON_HANDLE_INFO_FUCHSIA \
-    ((VkStructureType)1001000000)
-#define VK_EXTERNAL_MEMORY_HANDLE_TYPE_TEMP_ZIRCON_VMO_BIT_FUCHSIA \
-    ((VkStructureType)0x00000800)
-#define VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_TEMP_ZIRCON_EVENT_BIT_FUCHSIA \
-    ((VkStructureType)0x00000020)
-
 #include "AndroidHardwareBuffer.h"
 
 #endif // VK_USE_PLATFORM_ANDROID_KHR
@@ -58,7 +34,7 @@ typedef struct VkImportMemoryBufferCollectionFUCHSIA {
 #ifdef VK_USE_PLATFORM_FUCHSIA
 
 #include <cutils/native_handle.h>
-#include <fuchsia/hardware/goldfish/c/fidl.h>
+#include <fuchsia/hardware/goldfish/control/c/fidl.h>
 #include <fuchsia/sysmem/cpp/fidl.h>
 #include <lib/fdio/directory.h>
 #include <lib/fdio/fd.h>
@@ -273,7 +249,6 @@ public:
         SubAlloc subAlloc;
         AHardwareBuffer* ahw = nullptr;
         zx_handle_t vmoHandle = ZX_HANDLE_INVALID;
-        uint32_t cbHandle = 0;
     };
 
     // custom guest-side structs for images/buffers because of AHardwareBuffer :((
@@ -285,7 +260,6 @@ public:
         VkDeviceMemory currentBacking = VK_NULL_HANDLE;
         VkDeviceSize currentBackingOffset = 0;
         VkDeviceSize currentBackingSize = 0;
-        uint32_t cbHandle = 0;
     };
 
     struct VkBuffer_Info {
@@ -364,10 +338,6 @@ public:
             AHardwareBuffer_release(memInfo.ahw);
         }
 
-        if (memInfo.cbHandle) {
-            (*mCloseColorBuffer)(memInfo.cbHandle);
-        }
-
         if (memInfo.vmoHandle != ZX_HANDLE_INVALID) {
             zx_handle_close(memInfo.vmoHandle);
         }
@@ -394,9 +364,6 @@ public:
         if (it == info_VkImage.end()) return;
 
         auto& imageInfo = it->second;
-        if (imageInfo.cbHandle) {
-            (*mCloseColorBuffer)(imageInfo.cbHandle);
-        }
 
         info_VkImage.erase(img);
     }
@@ -479,8 +446,7 @@ public:
                              uint8_t* ptr,
                              uint32_t memoryTypeIndex,
                              AHardwareBuffer* ahw = nullptr,
-                             zx_handle_t vmoHandle = ZX_HANDLE_INVALID,
-                             uint32_t cbHandle = 0) {
+                             zx_handle_t vmoHandle = ZX_HANDLE_INVALID) {
         AutoLock lock(mLock);
         auto& deviceInfo = info_VkDevice[device];
         auto& info = info_VkDeviceMemory[memory];
@@ -491,7 +457,6 @@ public:
         info.memoryTypeIndex = memoryTypeIndex;
         info.ahw = ahw;
         info.vmoHandle = vmoHandle;
-        info.cbHandle = cbHandle;
     }
 
     void setImageInfo(VkImage image,
@@ -575,11 +540,24 @@ public:
         }
 
 #ifdef VK_USE_PLATFORM_FUCHSIA
-        zx_status_t status = fdio_service_connect(
-            "/svc/fuchsia.sysmem.Allocator",
-            mSysmemAllocator.NewRequest().TakeChannel().release());
-        if (status != ZX_OK) {
-            ALOGE("failed to connect to sysmem service, status %d", status);
+        if (mFeatureInfo->hasVulkan) {
+            int fd = open("/dev/class/goldfish-control/000", O_RDWR);
+            if (fd < 0) {
+                ALOGE("failed to open control device");
+                abort();
+            }
+            zx_status_t status = fdio_get_service_handle(fd, &mControlDevice);
+            if (status != ZX_OK) {
+                ALOGE("failed to get control service handle, status %d", status);
+                abort();
+            }
+            status = fuchsia_hardware_goldfish_control_DeviceConnectSysmem(
+                mControlDevice,
+                mSysmemAllocator.NewRequest().TakeChannel().release());
+            if (status != ZX_OK) {
+                ALOGE("failed to get sysmem connection, status %d", status);
+                abort();
+            }
         }
 #endif
     }
@@ -621,14 +599,6 @@ public:
         return -1;
     }
 
-    void setColorBufferFunctions(PFN_CreateColorBuffer create,
-                                 PFN_OpenColorBuffer open,
-                                 PFN_CloseColorBuffer close) {
-        mCreateColorBuffer = create;
-        mOpenColorBuffer = open;
-        mCloseColorBuffer = close;
-    }
-
     void deviceMemoryTransform_tohost(
         VkDeviceMemory* memory, uint32_t memoryCount,
         VkDeviceSize* offset, uint32_t offsetCount,
@@ -1210,7 +1180,7 @@ public:
         for (uint32_t i = 0; i < info.memProps.memoryTypeCount; ++i) {
             if (info.memProps.memoryTypes[i].propertyFlags &
                 VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT) {
-                pProperties->memoryTypeBits = 1ull << i;
+                pProperties->memoryTypeBits |= 1ull << i;
             }
         }
         return VK_SUCCESS;
@@ -1319,10 +1289,9 @@ public:
         delete sysmem_collection;
     }
 
-    VkResult on_vkSetBufferCollectionConstraintsFUCHSIA(
-        void*, VkResult, VkDevice,
-        VkBufferCollectionFUCHSIA collection,
-        const VkImageCreateInfo* pImageInfo) {
+    void setBufferCollectionConstraints(fuchsia::sysmem::BufferCollectionSyncPtr* collection,
+                                        const VkImageCreateInfo* pImageInfo,
+                                        size_t min_size_bytes) {
         fuchsia::sysmem::BufferCollectionConstraints constraints = {};
         constraints.usage.vulkan = fuchsia::sysmem::vulkanUsageColorAttachment |
                                    fuchsia::sysmem::vulkanUsageTransferSrc |
@@ -1332,13 +1301,14 @@ public:
         constraints.has_buffer_memory_constraints = true;
         fuchsia::sysmem::BufferMemoryConstraints& buffer_constraints =
             constraints.buffer_memory_constraints;
-        buffer_constraints.min_size_bytes = pImageInfo->extent.width * pImageInfo->extent.height * 4;
+        buffer_constraints.min_size_bytes = min_size_bytes;
         buffer_constraints.max_size_bytes = 0xffffffff;
         buffer_constraints.physically_contiguous_required = false;
         buffer_constraints.secure_required = false;
         buffer_constraints.secure_permitted = false;
-        buffer_constraints.ram_domain_supported = true;
+        buffer_constraints.ram_domain_supported = false;
         buffer_constraints.cpu_domain_supported = false;
+        buffer_constraints.gpu_domain_supported = true;
         constraints.image_format_constraints_count = 1;
         fuchsia::sysmem::ImageFormatConstraints& image_constraints =
             constraints.image_format_constraints[0];
@@ -1360,8 +1330,57 @@ public:
         image_constraints.display_width_divisor = 1;
         image_constraints.display_height_divisor = 1;
 
+        (*collection)->SetConstraints(true, constraints);
+    }
+
+    VkResult on_vkSetBufferCollectionConstraintsFUCHSIA(
+        void*, VkResult, VkDevice,
+        VkBufferCollectionFUCHSIA collection,
+        const VkImageCreateInfo* pImageInfo) {
+        auto sysmem_collection =
+            reinterpret_cast<fuchsia::sysmem::BufferCollectionSyncPtr*>(collection);
+        setBufferCollectionConstraints(
+            sysmem_collection, pImageInfo,
+            pImageInfo->extent.width * pImageInfo->extent.height * 4);
+        return VK_SUCCESS;
+    }
+
+    VkResult on_vkGetBufferCollectionPropertiesFUCHSIA(
+        void*, VkResult,
+        VkDevice device,
+        VkBufferCollectionFUCHSIA collection,
+        VkBufferCollectionPropertiesFUCHSIA* pProperties) {
         auto sysmem_collection = reinterpret_cast<fuchsia::sysmem::BufferCollectionSyncPtr*>(collection);
-        (*sysmem_collection)->SetConstraints(true, constraints);
+        fuchsia::sysmem::BufferCollectionInfo_2 info;
+        zx_status_t status2;
+        zx_status_t status = (*sysmem_collection)->WaitForBuffersAllocated(&status2, &info);
+        if (status != ZX_OK || status2 != ZX_OK) {
+            ALOGE("Failed wait for allocation: %d %d", status, status2);
+            return VK_ERROR_INITIALIZATION_FAILED;
+        }
+        if (!info.settings.has_image_format_constraints) {
+            return VK_ERROR_INITIALIZATION_FAILED;
+        }
+        pProperties->count = info.buffer_count;
+
+        AutoLock lock(mLock);
+
+        auto deviceIt = info_VkDevice.find(device);
+
+        if (deviceIt == info_VkDevice.end()) {
+            return VK_ERROR_INITIALIZATION_FAILED;
+        }
+
+        auto& deviceInfo = deviceIt->second;
+
+        // Device local memory type supported.
+        pProperties->memoryTypeBits = 0;
+        for (uint32_t i = 0; i < deviceInfo.memProps.memoryTypeCount; ++i) {
+            if (deviceInfo.memProps.memoryTypes[i].propertyFlags &
+                VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT) {
+                pProperties->memoryTypeBits |= 1ull << i;
+            }
+        }
         return VK_SUCCESS;
     }
 #endif
@@ -1493,7 +1512,9 @@ public:
 
         VkEncoder* enc = (VkEncoder*)context;
 
-        VkMemoryAllocateInfo finalAllocInfo = *pAllocateInfo;
+        VkMemoryAllocateInfo finalAllocInfo = vk_make_orphan_copy(*pAllocateInfo);
+        vk_struct_chain_iterator structChainIter = vk_make_chain_iterator(&finalAllocInfo);
+
         VkMemoryDedicatedAllocateInfo dedicatedAllocInfo;
         VkImportColorBufferGOOGLE importCbInfo = {
             VK_STRUCTURE_TYPE_IMPORT_COLOR_BUFFER_GOOGLE, 0,
@@ -1502,30 +1523,20 @@ public:
         //     VK_STRUCTURE_TYPE_IMPORT_PHYSICAL_ADDRESS_GOOGLE, 0,
         // };
 
-        vk_struct_common* structChain =
-        structChain = vk_init_struct_chain(
-            (vk_struct_common*)(&finalAllocInfo));
-        structChain->pNext = nullptr;
-
-        VkExportMemoryAllocateInfo* exportAllocateInfoPtr =
-            (VkExportMemoryAllocateInfo*)vk_find_struct((vk_struct_common*)pAllocateInfo,
-                VK_STRUCTURE_TYPE_EXPORT_MEMORY_ALLOCATE_INFO);
+        const VkExportMemoryAllocateInfo* exportAllocateInfoPtr =
+            vk_find_struct<VkExportMemoryAllocateInfo>(pAllocateInfo);
 
-        VkImportAndroidHardwareBufferInfoANDROID* importAhbInfoPtr =
-            (VkImportAndroidHardwareBufferInfoANDROID*)vk_find_struct((vk_struct_common*)pAllocateInfo,
-                VK_STRUCTURE_TYPE_IMPORT_ANDROID_HARDWARE_BUFFER_INFO_ANDROID);
+        const VkImportAndroidHardwareBufferInfoANDROID* importAhbInfoPtr =
+            vk_find_struct<VkImportAndroidHardwareBufferInfoANDROID>(pAllocateInfo);
 
-        VkImportMemoryBufferCollectionFUCHSIA* importBufferCollectionInfoPtr =
-            (VkImportMemoryBufferCollectionFUCHSIA*)vk_find_struct((vk_struct_common*)pAllocateInfo,
-                VK_STRUCTURE_TYPE_IMPORT_MEMORY_BUFFER_COLLECTION_FUCHSIA);
+        const VkImportMemoryBufferCollectionFUCHSIA* importBufferCollectionInfoPtr =
+            vk_find_struct<VkImportMemoryBufferCollectionFUCHSIA>(pAllocateInfo);
 
-        VkImportMemoryZirconHandleInfoFUCHSIA* importVmoInfoPtr =
-            (VkImportMemoryZirconHandleInfoFUCHSIA*)vk_find_struct((vk_struct_common*)pAllocateInfo,
-                VK_STRUCTURE_TYPE_TEMP_IMPORT_MEMORY_ZIRCON_HANDLE_INFO_FUCHSIA);
+        const VkImportMemoryZirconHandleInfoFUCHSIA* importVmoInfoPtr =
+            vk_find_struct<VkImportMemoryZirconHandleInfoFUCHSIA>(pAllocateInfo);
 
-        VkMemoryDedicatedAllocateInfo* dedicatedAllocInfoPtr =
-            (VkMemoryDedicatedAllocateInfo*)vk_find_struct((vk_struct_common*)pAllocateInfo,
-                VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO);
+        const VkMemoryDedicatedAllocateInfo* dedicatedAllocInfoPtr =
+            vk_find_struct<VkMemoryDedicatedAllocateInfo>(pAllocateInfo);
 
         bool shouldPassThroughDedicatedAllocInfo =
             !exportAllocateInfoPtr &&
@@ -1549,12 +1560,8 @@ public:
 
         if (shouldPassThroughDedicatedAllocInfo &&
             dedicatedAllocInfoPtr) {
-            dedicatedAllocInfo = *dedicatedAllocInfoPtr;
-            structChain->pNext =
-                (vk_struct_common*)(&dedicatedAllocInfo);
-            structChain =
-                (vk_struct_common*)(&dedicatedAllocInfo);
-            structChain->pNext = nullptr;
+            dedicatedAllocInfo = vk_make_orphan_copy(*dedicatedAllocInfoPtr);
+            vk_append_struct(&structChainIter, &dedicatedAllocInfo);
         }
 
         // State needed for import/export.
@@ -1575,8 +1582,6 @@ public:
         // and then we attach a new VkDeviceMemory
         // to the AHardwareBuffer on the host via an "import" operation.
         AHardwareBuffer* ahw = nullptr;
-        zx_handle_t vmo_handle = ZX_HANDLE_INVALID;
-        uint32_t cbHandle = 0;
 
         if (exportAllocateInfoPtr) {
             exportAhb =
@@ -1667,10 +1672,11 @@ public:
             const cb_handle_t* cb_handle =
                 reinterpret_cast<const cb_handle_t*>(handle);
             importCbInfo.colorBuffer = cb_handle->hostHandle;
-            structChain =
-                vk_append_struct(structChain, (vk_struct_common*)(&importCbInfo));
+            vk_append_struct(&structChainIter, &importCbInfo);
         }
 
+        zx_handle_t vmo_handle = ZX_HANDLE_INVALID;
+
         if (importBufferCollection) {
 
 #ifdef VK_USE_PLATFORM_FUCHSIA
@@ -1697,28 +1703,104 @@ public:
             vmo_handle = importVmoInfoPtr->handle;
         }
 
-        if (vmo_handle != ZX_HANDLE_INVALID) {
-            uint64_t cb = 0;
-
 #ifdef VK_USE_PLATFORM_FUCHSIA
-            zx_object_get_cookie(vmo_handle, vmo_handle, &cb);
-#endif
+        if (vmo_handle == ZX_HANDLE_INVALID &&
+            !isHostVisibleMemoryTypeIndexForGuest(
+                &mHostVisibleMemoryVirtInfo, finalAllocInfo.memoryTypeIndex)) {
+            bool hasDedicatedImage = dedicatedAllocInfoPtr &&
+                (dedicatedAllocInfoPtr->image != VK_NULL_HANDLE);
+            VkImageCreateInfo imageCreateInfo = {};
+
+            if (hasDedicatedImage) {
+                AutoLock lock(mLock);
+
+                auto it = info_VkImage.find(dedicatedAllocInfoPtr->image);
+                if (it == info_VkImage.end()) return VK_ERROR_INITIALIZATION_FAILED;
+                const auto& imageInfo = it->second;
+
+                imageCreateInfo = imageInfo.createInfo;
+            }
+
+            if (imageCreateInfo.usage & VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT) {
+                fuchsia::sysmem::BufferCollectionTokenSyncPtr token;
+                zx_status_t status = mSysmemAllocator->AllocateSharedCollection(
+                    token.NewRequest());
+                if (status != ZX_OK) {
+                    ALOGE("AllocateSharedCollection failed: %d", status);
+                    abort();
+                }
+
+                fuchsia::sysmem::BufferCollectionSyncPtr collection;
+                status = mSysmemAllocator->BindSharedCollection(
+                    std::move(token), collection.NewRequest());
+                if (status != ZX_OK) {
+                    ALOGE("BindSharedCollection failed: %d", status);
+                    abort();
+                }
+                setBufferCollectionConstraints(&collection,
+                                               &imageCreateInfo,
+                                               finalAllocInfo.allocationSize);
+
+                fuchsia::sysmem::BufferCollectionInfo_2 info;
+                zx_status_t status2;
+                status = collection->WaitForBuffersAllocated(&status2, &info);
+                if (status == ZX_OK && status2 == ZX_OK) {
+                    if (!info.buffer_count) {
+                      ALOGE("WaitForBuffersAllocated returned invalid count: %d", status);
+                      abort();
+                    }
+                    vmo_handle = info.buffers[0].vmo.release();
+                } else {
+                    ALOGE("WaitForBuffersAllocated failed: %d %d", status, status2);
+                    abort();
+                }
+
+                collection->Close();
 
-            if (cb) {
-                cbHandle = importCbInfo.colorBuffer = cb;
-                structChain =
-                    vk_append_struct(structChain, (vk_struct_common*)(&importCbInfo));
+                zx_handle_t vmo_copy;
+                status = zx_handle_duplicate(vmo_handle, ZX_RIGHT_SAME_RIGHTS, &vmo_copy);
+                if (status != ZX_OK) {
+                    ALOGE("Failed to duplicate VMO: %d", status);
+                    abort();
+                }
+                status = fuchsia_hardware_goldfish_control_DeviceCreateColorBuffer(
+                    mControlDevice,
+                    vmo_copy,
+                    imageCreateInfo.extent.width,
+                    imageCreateInfo.extent.height,
+                    fuchsia_hardware_goldfish_control_FormatType_BGRA,
+                    &status2);
+                if (status != ZX_OK || status2 != ZX_OK) {
+                    ALOGE("CreateColorBuffer failed: %d:%d", status, status2);
+                    abort();
+                }
             }
         }
 
+        if (vmo_handle != ZX_HANDLE_INVALID) {
+            zx_handle_t vmo_copy;
+            zx_status_t status = zx_handle_duplicate(vmo_handle,
+                                                     ZX_RIGHT_SAME_RIGHTS,
+                                                     &vmo_copy);
+            if (status != ZX_OK) {
+                ALOGE("Failed to duplicate VMO: %d", status);
+                abort();
+            }
+            zx_status_t status2 = ZX_OK;
+            status = fuchsia_hardware_goldfish_control_DeviceGetColorBuffer(
+                mControlDevice, vmo_copy, &status2, &importCbInfo.colorBuffer);
+            if (status != ZX_OK || status2 != ZX_OK) {
+                ALOGE("GetColorBuffer failed: %d:%d", status, status2);
+            }
+            vk_append_struct(&structChainIter, &importCbInfo);
+        }
+#endif
+
         // TODO if (exportVmo) { }
 
         if (!isHostVisibleMemoryTypeIndexForGuest(
                 &mHostVisibleMemoryVirtInfo,
                 finalAllocInfo.memoryTypeIndex)) {
-            if (cbHandle) {
-                (*mOpenColorBuffer)(cbHandle);
-            }
             input_result =
                 enc->vkAllocateMemory(
                     device, &finalAllocInfo, pAllocator, pMemory);
@@ -1732,8 +1814,7 @@ public:
                 0, nullptr,
                 finalAllocInfo.memoryTypeIndex,
                 ahw,
-                vmo_handle,
-                cbHandle);
+                vmo_handle);
 
             return VK_SUCCESS;
         }
@@ -2006,10 +2087,7 @@ public:
         transformExternalResourceMemoryRequirementsForGuest(&reqs2->memoryRequirements);
 
         VkMemoryDedicatedRequirements* dedicatedReqs =
-            (VkMemoryDedicatedRequirements*)
-            vk_find_struct(
-                (vk_struct_common*)reqs2,
-                VK_STRUCTURE_TYPE_MEMORY_DEDICATED_REQUIREMENTS);
+            vk_find_struct<VkMemoryDedicatedRequirements>(reqs2);
 
         if (!dedicatedReqs) return;
 
@@ -2038,10 +2116,7 @@ public:
         transformExternalResourceMemoryRequirementsForGuest(&reqs2->memoryRequirements);
 
         VkMemoryDedicatedRequirements* dedicatedReqs =
-            (VkMemoryDedicatedRequirements*)
-            vk_find_struct(
-                (vk_struct_common*)reqs2,
-                VK_STRUCTURE_TYPE_MEMORY_DEDICATED_REQUIREMENTS);
+            vk_find_struct<VkMemoryDedicatedRequirements>(reqs2);
 
         if (!dedicatedReqs) return;
 
@@ -2056,164 +2131,91 @@ public:
         VkImage *pImage) {
         VkEncoder* enc = (VkEncoder*)context;
 
-        uint32_t cbHandle = 0;
-
-        VkImageCreateInfo localCreateInfo = *pCreateInfo;
-        VkNativeBufferANDROID localAnb;
+        VkImageCreateInfo localCreateInfo = vk_make_orphan_copy(*pCreateInfo);
+        vk_struct_chain_iterator structChainIter = vk_make_chain_iterator(&localCreateInfo);
         VkExternalMemoryImageCreateInfo localExtImgCi;
 
-        VkImageCreateInfo* pCreateInfo_mut = &localCreateInfo;
-
-        VkNativeBufferANDROID* anbInfoPtr =
-            (VkNativeBufferANDROID*)
-            vk_find_struct(
-                (vk_struct_common*)pCreateInfo_mut,
-                VK_STRUCTURE_TYPE_NATIVE_BUFFER_ANDROID);
-
-        if (anbInfoPtr) {
-            localAnb = *anbInfoPtr;
-        }
-
-        VkExternalMemoryImageCreateInfo* extImgCiPtr =
-            (VkExternalMemoryImageCreateInfo*)
-            vk_find_struct(
-                (vk_struct_common*)pCreateInfo_mut,
-                VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO);
-
+        const VkExternalMemoryImageCreateInfo* extImgCiPtr =
+            vk_find_struct<VkExternalMemoryImageCreateInfo>(pCreateInfo);
         if (extImgCiPtr) {
-            localExtImgCi = *extImgCiPtr;
-        }
-
-#ifdef VK_USE_PLATFORM_ANDROID_KHR
-        VkExternalFormatANDROID localExtFormatAndroid;
-        VkExternalFormatANDROID* extFormatAndroidPtr =
-        (VkExternalFormatANDROID*)
-        vk_find_struct(
-            (vk_struct_common*)pCreateInfo_mut,
-            VK_STRUCTURE_TYPE_EXTERNAL_FORMAT_ANDROID);
-        if (extFormatAndroidPtr) {
-            localExtFormatAndroid = *extFormatAndroidPtr;
-        }
-#endif
-
-#ifdef VK_USE_PLATFORM_FUCHSIA
-        VkFuchsiaImageFormatFUCHSIA* extFuchsiaImageFormatPtr =
-        (VkFuchsiaImageFormatFUCHSIA*)
-        vk_find_struct(
-            (vk_struct_common*)pCreateInfo_mut,
-            VK_STRUCTURE_TYPE_FUCHSIA_IMAGE_FORMAT_FUCHSIA);
-
-        VkBufferCollectionImageCreateInfoFUCHSIA* extBufferCollectionPtr =
-        (VkBufferCollectionImageCreateInfoFUCHSIA*)
-        vk_find_struct(
-            (vk_struct_common*)pCreateInfo_mut,
-            VK_STRUCTURE_TYPE_BUFFER_COLLECTION_IMAGE_CREATE_INFO_FUCHSIA);
-#endif
-
-        vk_struct_common* structChain =
-            vk_init_struct_chain((vk_struct_common*)pCreateInfo_mut);
-
-        if (extImgCiPtr) {
-            structChain =
-                vk_append_struct(
-                    structChain, (vk_struct_common*)(&localExtImgCi));
+            localExtImgCi = vk_make_orphan_copy(*extImgCiPtr);
+            vk_append_struct(&structChainIter, &localExtImgCi);
         }
 
 #ifdef VK_USE_PLATFORM_ANDROID_KHR
+        VkNativeBufferANDROID localAnb;
+        const VkNativeBufferANDROID* anbInfoPtr =
+            vk_find_struct<VkNativeBufferANDROID>(pCreateInfo);
         if (anbInfoPtr) {
-            structChain =
-                vk_append_struct(
-                    structChain, (vk_struct_common*)(&localAnb));
+            localAnb = vk_make_orphan_copy(*anbInfoPtr);
+            vk_append_struct(&structChainIter, &localAnb);
         }
 
+        VkExternalFormatANDROID localExtFormatAndroid;
+        const VkExternalFormatANDROID* extFormatAndroidPtr =
+            vk_find_struct<VkExternalFormatANDROID>(pCreateInfo);
         if (extFormatAndroidPtr) {
+            localExtFormatAndroid = vk_make_orphan_copy(*extFormatAndroidPtr);
+
             // Do not append external format android;
-            // instead, replace the local image pCreateInfo_mut format
+            // instead, replace the local image localCreateInfo format
             // with the corresponding Vulkan format
             if (extFormatAndroidPtr->externalFormat) {
-                pCreateInfo_mut->format =
+                localCreateInfo.format =
                     vk_format_from_android(extFormatAndroidPtr->externalFormat);
+                if (localCreateInfo.format == VK_FORMAT_UNDEFINED)
+                    return VK_ERROR_VALIDATION_FAILED_EXT;
             }
         }
 #endif
 
-
 #ifdef VK_USE_PLATFORM_FUCHSIA
-        VkNativeBufferANDROID native_info = {
-            .sType = VK_STRUCTURE_TYPE_NATIVE_BUFFER_ANDROID,
-            .pNext = NULL,
-        };
-        cb_handle_t native_handle(
-            0, 0, 0, 0, 0, 0, 0, 0, 0, FRAMEWORK_FORMAT_GL_COMPATIBLE);
-
-        if (pCreateInfo->usage & VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT) {
-            // Create color buffer.
-            cbHandle = (*mCreateColorBuffer)(pCreateInfo_mut->extent.width,
-                                             pCreateInfo_mut->extent.height,
-                                             0x1908 /*GL_RGBA*/);
-            native_handle.hostHandle = cbHandle;
-            native_info.handle = (uint32_t*)&native_handle;
-            native_info.stride = 0;
-            native_info.format = 1; // RGBA
-            native_info.usage = GRALLOC_USAGE_HW_FB;
-            if (pCreateInfo_mut->pNext) {
-                abort();
+        const VkBufferCollectionImageCreateInfoFUCHSIA* extBufferCollectionPtr =
+            vk_find_struct<VkBufferCollectionImageCreateInfoFUCHSIA>(pCreateInfo);
+        if (extBufferCollectionPtr) {
+            auto collection = reinterpret_cast<fuchsia::sysmem::BufferCollectionSyncPtr*>(
+                extBufferCollectionPtr->collection);
+            uint32_t index = extBufferCollectionPtr->index;
+            zx_handle_t vmo_handle = ZX_HANDLE_INVALID;
+
+            fuchsia::sysmem::BufferCollectionInfo_2 info;
+            zx_status_t status2;
+            zx_status_t status = (*collection)->WaitForBuffersAllocated(&status2, &info);
+            if (status == ZX_OK && status2 == ZX_OK) {
+                if (index < info.buffer_count) {
+                    vmo_handle = info.buffers[index].vmo.release();
+                }
+            } else {
+                ALOGE("WaitForBuffersAllocated failed: %d %d", status, status2);
             }
-            pCreateInfo_mut->pNext = &native_info;
-
-            bool is_physically_contiguous = false;
-            if (extBufferCollectionPtr) {
-               auto collection = reinterpret_cast<fuchsia::sysmem::BufferCollectionSyncPtr*>(
-                   extBufferCollectionPtr->collection);
-               fuchsia::sysmem::BufferCollectionInfo_2 info;
-               zx_status_t status2;
-               zx_status_t status = (*collection)->WaitForBuffersAllocated(&status2, &info);
-               if (status == ZX_OK && status2 == ZX_OK) {
-                   is_physically_contiguous =
-                       info.settings.has_image_format_constraints &&
-                       info.settings.buffer_settings.is_physically_contiguous;
-               } else {
-                   ALOGE("WaitForBuffersAllocated failed: %d %d", status, status2);
-               }
-            } else if (extFuchsiaImageFormatPtr) {
-                auto imageFormat = static_cast<const uint8_t*>(
-                    extFuchsiaImageFormatPtr->imageFormat);
-                size_t imageFormatSize =
-                    extFuchsiaImageFormatPtr->imageFormatSize;
-                std::vector<uint8_t> message(
-                    imageFormat, imageFormat + imageFormatSize);
-                fidl::Message msg(fidl::BytePart(message.data(),
-                                                 imageFormatSize,
-                                                 imageFormatSize),
-                                  fidl::HandlePart());
-                const char* err_msg = nullptr;
-                zx_status_t status = msg.Decode(
-                    fuchsia::sysmem::SingleBufferSettings::FidlType, &err_msg);
-                if (status != ZX_OK) {
-                    ALOGE("Invalid SingleBufferSettings: %d %s", status,
-                          err_msg);
-                    abort();
+
+            if (vmo_handle != ZX_HANDLE_INVALID) {
+                zx_status_t status2 = ZX_OK;
+                status = fuchsia_hardware_goldfish_control_DeviceCreateColorBuffer(
+                    mControlDevice,
+                    vmo_handle,
+                    localCreateInfo.extent.width,
+                    localCreateInfo.extent.height,
+                    fuchsia_hardware_goldfish_control_FormatType_BGRA,
+                    &status2);
+                if (status != ZX_OK || status2 != ZX_OK) {
+                    ALOGE("CreateColorBuffer failed: %d:%d", status, status2);
                 }
-                fidl::Decoder decoder(std::move(msg));
-                fuchsia::sysmem::SingleBufferSettings settings;
-                fuchsia::sysmem::SingleBufferSettings::Decode(
-                    &decoder, &settings, 0);
-                is_physically_contiguous =
-                    settings.buffer_settings.is_physically_contiguous;
             }
+        }
 
-            if (is_physically_contiguous) {
-                // Replace the local image pCreateInfo_mut format
-                // with the color buffer format if physically contiguous
-                // and a potential display layer candidate.
-                // TODO(reveman): Remove this after adding BGRA color
-                // buffer support.
-                pCreateInfo_mut->format = VK_FORMAT_R8G8B8A8_UNORM;
+        // Allow external memory for all color attachments on fuchsia.
+        if (localCreateInfo.usage & VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT) {
+            if (!extImgCiPtr) {
+                localExtImgCi.sType = VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO;
+                localExtImgCi.pNext = nullptr;
+                localExtImgCi.handleTypes = ~0; // handle type just needs to be non-zero
+                extImgCiPtr = &localExtImgCi;   // no vk_append_struct required
             }
         }
 #endif
 
-        VkResult res = enc->vkCreateImage(device, pCreateInfo_mut, pAllocator, pImage);
+        VkResult res = enc->vkCreateImage(device, &localCreateInfo, pAllocator, pImage);
 
         if (res != VK_SUCCESS) return res;
 
@@ -2225,9 +2227,8 @@ public:
         auto& info = it->second;
 
         info.device = device;
-        info.createInfo = *pCreateInfo_mut;
+        info.createInfo = *pCreateInfo;
         info.createInfo.pNext = nullptr;
-        info.cbHandle = cbHandle;
 
         if (!extImgCiPtr) return res;
 
@@ -2244,28 +2245,14 @@ public:
         const VkAllocationCallbacks* pAllocator,
         VkSamplerYcbcrConversion* pYcbcrConversion) {
 
-        VkSamplerYcbcrConversionCreateInfo localCreateInfo = *pCreateInfo;
-        VkSamplerYcbcrConversionCreateInfo* pCreateInfo_mut = &localCreateInfo;
-
-#ifdef VK_USE_PLATFORM_ANDROID_KHR
-        VkExternalFormatANDROID localExtFormatAndroid;
-        VkExternalFormatANDROID* extFormatAndroidPtr =
-        (VkExternalFormatANDROID*)
-        vk_find_struct(
-            (vk_struct_common*)pCreateInfo_mut,
-            VK_STRUCTURE_TYPE_EXTERNAL_FORMAT_ANDROID);
-        if (extFormatAndroidPtr) {
-            localExtFormatAndroid = *extFormatAndroidPtr;
-        }
-#endif
-
-        vk_struct_common* structChain =
-            vk_init_struct_chain((vk_struct_common*)pCreateInfo_mut);
+        VkSamplerYcbcrConversionCreateInfo localCreateInfo = vk_make_orphan_copy(*pCreateInfo);
 
 #ifdef VK_USE_PLATFORM_ANDROID_KHR
+        const VkExternalFormatANDROID* extFormatAndroidPtr =
+            vk_find_struct<VkExternalFormatANDROID>(pCreateInfo);
         if (extFormatAndroidPtr) {
             if (extFormatAndroidPtr->externalFormat) {
-                pCreateInfo_mut->format =
+                localCreateInfo.format =
                     vk_format_from_android(extFormatAndroidPtr->externalFormat);
             }
         }
@@ -2273,7 +2260,7 @@ public:
 
         VkEncoder* enc = (VkEncoder*)context;
         return enc->vkCreateSamplerYcbcrConversion(
-            device, pCreateInfo, pAllocator, pYcbcrConversion);
+            device, &localCreateInfo, pAllocator, pYcbcrConversion);
     }
 
     VkResult on_vkCreateSamplerYcbcrConversionKHR(
@@ -2283,34 +2270,22 @@ public:
         const VkAllocationCallbacks* pAllocator,
         VkSamplerYcbcrConversion* pYcbcrConversion) {
 
-        VkSamplerYcbcrConversionCreateInfo localCreateInfo = *pCreateInfo;
-        VkSamplerYcbcrConversionCreateInfo* pCreateInfo_mut = &localCreateInfo;
-
-#ifdef VK_USE_PLATFORM_ANDROID_KHR
-        VkExternalFormatANDROID localExtFormatAndroid;
-        VkExternalFormatANDROID* extFormatAndroidPtr =
-        (VkExternalFormatANDROID*)
-        vk_find_struct(
-            (vk_struct_common*)pCreateInfo_mut,
-            VK_STRUCTURE_TYPE_EXTERNAL_FORMAT_ANDROID);
-        if (extFormatAndroidPtr) {
-            localExtFormatAndroid = *extFormatAndroidPtr;
-        }
-#endif
-
-        vk_struct_common* structChain =
-            vk_init_struct_chain((vk_struct_common*)pCreateInfo_mut);
+        VkSamplerYcbcrConversionCreateInfo localCreateInfo = vk_make_orphan_copy(*pCreateInfo);
 
 #ifdef VK_USE_PLATFORM_ANDROID_KHR
+        const VkExternalFormatANDROID* extFormatAndroidPtr =
+            vk_find_struct<VkExternalFormatANDROID>(pCreateInfo);
         if (extFormatAndroidPtr) {
-            pCreateInfo_mut->format =
-                vk_format_from_android(extFormatAndroidPtr->externalFormat);
+            if (extFormatAndroidPtr->externalFormat) {
+                localCreateInfo.format =
+                    vk_format_from_android(extFormatAndroidPtr->externalFormat);
+            }
         }
 #endif
 
         VkEncoder* enc = (VkEncoder*)context;
         return enc->vkCreateSamplerYcbcrConversionKHR(
-            device, pCreateInfo, pAllocator, pYcbcrConversion);
+            device, &localCreateInfo, pAllocator, pYcbcrConversion);
     }
 
     void on_vkDestroyImage(
@@ -2354,41 +2329,6 @@ public:
         void* context, VkResult,
         VkDevice device, VkImage image, VkDeviceMemory memory,
         VkDeviceSize memoryOffset) {
-#ifdef VK_USE_PLATFORM_FUCHSIA
-        auto imageIt = info_VkImage.find(image);
-        if (imageIt == info_VkImage.end()) {
-            return VK_ERROR_INITIALIZATION_FAILED;
-        }
-        auto& imageInfo = imageIt->second;
-
-        if (imageInfo.cbHandle) {
-            auto memoryIt = info_VkDeviceMemory.find(memory);
-            if (memoryIt == info_VkDeviceMemory.end()) {
-                return VK_ERROR_INITIALIZATION_FAILED;
-            }
-            auto& memoryInfo = memoryIt->second;
-
-            zx_status_t status;
-            if (memoryInfo.vmoHandle == ZX_HANDLE_INVALID) {
-                status = zx_vmo_create(memoryInfo.allocationSize, 0,
-                                       &memoryInfo.vmoHandle);
-                if (status != ZX_OK) {
-                    ALOGE("%s: failed to alloc vmo", __func__);
-                    abort();
-                }
-            }
-            status = zx_object_set_cookie(memoryInfo.vmoHandle,
-                                          memoryInfo.vmoHandle,
-                                          imageInfo.cbHandle);
-            if (status != ZX_OK) {
-                ALOGE("%s: failed to set color buffer cookie", __func__);
-                abort();
-            }
-            // Color buffer backed images are already bound.
-            return VK_SUCCESS;
-        }
-#endif
-
         VkEncoder* enc = (VkEncoder*)context;
         return enc->vkBindImageMemory(device, image, memory, memoryOffset);
     }
@@ -2428,9 +2368,8 @@ public:
         info.createInfo = *pCreateInfo;
         info.createInfo.pNext = nullptr;
 
-        VkExternalMemoryBufferCreateInfo* extBufCi =
-            (VkExternalMemoryBufferCreateInfo*)vk_find_struct((vk_struct_common*)pCreateInfo,
-                VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_BUFFER_CREATE_INFO);
+        const VkExternalMemoryBufferCreateInfo* extBufCi =
+            vk_find_struct<VkExternalMemoryBufferCreateInfo>(pCreateInfo);
 
         if (!extBufCi) return res;
 
@@ -2520,10 +2459,8 @@ public:
 
         VkSemaphoreCreateInfo finalCreateInfo = *pCreateInfo;
 
-        VkExportSemaphoreCreateInfoKHR* exportSemaphoreInfoPtr =
-            (VkExportSemaphoreCreateInfoKHR*)vk_find_struct(
-                (vk_struct_common*)pCreateInfo,
-                VK_STRUCTURE_TYPE_EXPORT_SEMAPHORE_CREATE_INFO_KHR);
+        const VkExportSemaphoreCreateInfoKHR* exportSemaphoreInfoPtr =
+            vk_find_struct<VkExportSemaphoreCreateInfoKHR>(pCreateInfo);
 
 #ifdef VK_USE_PLATFORM_FUCHSIA
         bool exportEvent = exportSemaphoreInfoPtr &&
@@ -3092,9 +3029,7 @@ public:
         (void)input_result;
 
         VkAndroidHardwareBufferUsageANDROID* output_ahw_usage =
-            (VkAndroidHardwareBufferUsageANDROID*)vk_find_struct(
-                (vk_struct_common*)pImageFormatProperties,
-                VK_STRUCTURE_TYPE_ANDROID_HARDWARE_BUFFER_USAGE_ANDROID);
+            vk_find_struct<VkAndroidHardwareBufferUsageANDROID>(pImageFormatProperties);
 
         VkResult hostRes;
 
@@ -3187,6 +3122,32 @@ public:
         return VK_SUCCESS;
     }
 
+    VkResult on_vkCreateImageView(
+        void* context, VkResult input_result,
+        VkDevice device,
+        const VkImageViewCreateInfo* pCreateInfo,
+        const VkAllocationCallbacks* pAllocator,
+        VkImageView* pView) {
+
+        VkEncoder* enc = (VkEncoder*)context;
+        (void)input_result;
+
+        VkImageViewCreateInfo localCreateInfo = vk_make_orphan_copy(*pCreateInfo);
+
+#ifdef VK_USE_PLATFORM_ANDROID_KHR
+        const VkExternalFormatANDROID* extFormatAndroidPtr =
+            vk_find_struct<VkExternalFormatANDROID>(pCreateInfo);
+        if (extFormatAndroidPtr) {
+            if (extFormatAndroidPtr->externalFormat) {
+                localCreateInfo.format =
+                    vk_format_from_android(extFormatAndroidPtr->externalFormat);
+            }
+        }
+#endif
+
+        return enc->vkCreateImageView(device, &localCreateInfo, pAllocator, pView);
+    }
+
     uint32_t getApiVersionFromInstance(VkInstance instance) const {
         AutoLock lock(mLock);
         uint32_t api = kMinApiVersion;
@@ -3237,9 +3198,6 @@ private:
     HostVisibleMemoryVirtualizationInfo mHostVisibleMemoryVirtInfo;
     std::unique_ptr<EmulatorFeatureInfo> mFeatureInfo;
     std::unique_ptr<GoldfishAddressSpaceBlockProvider> mGoldfishAddressSpaceBlockProvider;
-    PFN_CreateColorBuffer mCreateColorBuffer;
-    PFN_OpenColorBuffer mOpenColorBuffer;
-    PFN_CloseColorBuffer mCloseColorBuffer;
 
     std::vector<VkExtensionProperties> mHostInstanceExtensions;
     std::vector<VkExtensionProperties> mHostDeviceExtensions;
@@ -3247,6 +3205,7 @@ private:
     int mSyncDeviceFd = -1;
 
 #ifdef VK_USE_PLATFORM_FUCHSIA
+    zx_handle_t mControlDevice = ZX_HANDLE_INVALID;
     fuchsia::sysmem::AllocatorSyncPtr mSysmemAllocator;
 #endif
 };
@@ -3332,13 +3291,6 @@ bool ResourceTracker::hasDeviceExtension(VkDevice device, const std::string &nam
     return mImpl->hasDeviceExtension(device, name);
 }
 
-void ResourceTracker::setColorBufferFunctions(
-    PFN_CreateColorBuffer create,
-    PFN_OpenColorBuffer open,
-    PFN_CloseColorBuffer close) {
-    mImpl->setColorBufferFunctions(create, open, close);
-}
-
 VkResult ResourceTracker::on_vkEnumerateInstanceExtensionProperties(
     void* context,
     VkResult input_result,
@@ -3692,6 +3644,15 @@ VkResult ResourceTracker::on_vkSetBufferCollectionConstraintsFUCHSIA(
     return mImpl->on_vkSetBufferCollectionConstraintsFUCHSIA(
         context, input_result, device, collection, pImageInfo);
 }
+
+VkResult ResourceTracker::on_vkGetBufferCollectionPropertiesFUCHSIA(
+        void* context, VkResult input_result,
+        VkDevice device,
+        VkBufferCollectionFUCHSIA collection,
+        VkBufferCollectionPropertiesFUCHSIA* pProperties) {
+    return mImpl->on_vkGetBufferCollectionPropertiesFUCHSIA(
+        context, input_result, device, collection, pProperties);
+}
 #endif
 
 VkResult ResourceTracker::on_vkGetAndroidHardwareBufferPropertiesANDROID(
@@ -3828,6 +3789,16 @@ VkResult ResourceTracker::on_vkResetCommandBuffer(
         context, input_result, commandBuffer, flags);
 }
 
+VkResult ResourceTracker::on_vkCreateImageView(
+    void* context, VkResult input_result,
+    VkDevice device,
+    const VkImageViewCreateInfo* pCreateInfo,
+    const VkAllocationCallbacks* pAllocator,
+    VkImageView* pView) {
+    return mImpl->on_vkCreateImageView(
+        context, input_result, device, pCreateInfo, pAllocator, pView);
+}
+
 void ResourceTracker::deviceMemoryTransform_tohost(
     VkDeviceMemory* memory, uint32_t memoryCount,
     VkDeviceSize* offset, uint32_t offsetCount,
diff --git a/system/vulkan_enc/ResourceTracker.h b/system/vulkan_enc/ResourceTracker.h
index 200bfb6870dcb756d280eff4dfd080173ff822c8..6429d6f4be713e016c22df07eb3b16d339ab0836 100644
--- a/system/vulkan_enc/ResourceTracker.h
+++ b/system/vulkan_enc/ResourceTracker.h
@@ -28,10 +28,6 @@ struct EmulatorFeatureInfo;
 
 namespace goldfish_vk {
 
-typedef uint32_t (*PFN_CreateColorBuffer)(uint32_t width, uint32_t height, uint32_t format);
-typedef void (*PFN_OpenColorBuffer)(uint32_t id);
-typedef void (*PFN_CloseColorBuffer)(uint32_t id);
-
 class ResourceTracker {
 public:
     ResourceTracker();
@@ -249,6 +245,11 @@ public:
         VkDevice device,
         VkBufferCollectionFUCHSIA collection,
         const VkImageCreateInfo* pImageInfo);
+    VkResult on_vkGetBufferCollectionPropertiesFUCHSIA(
+        void* context, VkResult input_result,
+        VkDevice device,
+        VkBufferCollectionFUCHSIA collection,
+        VkBufferCollectionPropertiesFUCHSIA* pProperties);
 #endif
 
     VkResult on_vkGetAndroidHardwareBufferPropertiesANDROID(
@@ -333,6 +334,13 @@ public:
         VkCommandBuffer commandBuffer,
         VkCommandBufferResetFlags flags);
 
+    VkResult on_vkCreateImageView(
+        void* context, VkResult input_result,
+        VkDevice device,
+        const VkImageViewCreateInfo* pCreateInfo,
+        const VkAllocationCallbacks* pAllocator,
+        VkImageView* pView);
+
     bool isMemoryTypeHostVisible(VkDevice device, uint32_t typeIndex) const;
     uint8_t* getMappedPointer(VkDeviceMemory memory);
     VkDeviceSize getMappedSize(VkDeviceMemory memory);
@@ -345,9 +353,6 @@ public:
     uint32_t getApiVersionFromDevice(VkDevice device) const;
     bool hasInstanceExtension(VkInstance instance, const std::string& name) const;
     bool hasDeviceExtension(VkDevice instance, const std::string& name) const;
-    void setColorBufferFunctions(PFN_CreateColorBuffer create,
-                                 PFN_OpenColorBuffer open,
-                                 PFN_CloseColorBuffer close);
 
     // Transforms
     void deviceMemoryTransform_tohost(
diff --git a/system/vulkan_enc/VkEncoder.cpp b/system/vulkan_enc/VkEncoder.cpp
index b97f120e8650c9c3f4a5231c4b3a5654d5ed84bf..42487ea1b686672b86fdb0023b40e4cb9d02db0a 100644
--- a/system/vulkan_enc/VkEncoder.cpp
+++ b/system/vulkan_enc/VkEncoder.cpp
@@ -7137,7 +7137,7 @@ void VkEncoder::vkCmdSetDepthBias(
 
 void VkEncoder::vkCmdSetBlendConstants(
     VkCommandBuffer commandBuffer,
-    const float blendConstants)
+    const float blendConstants[4])
 {
     AEMU_SCOPED_TRACE("vkCmdSetBlendConstants encode");
     mImpl->log("start vkCmdSetBlendConstants");
diff --git a/system/vulkan_enc/VkEncoder.h b/system/vulkan_enc/VkEncoder.h
index 16df497f6f881c0a8e609e93f6770cbb1be6b5e7..8328b321edb5f431bf3e411d8c50134318cf58ca 100644
--- a/system/vulkan_enc/VkEncoder.h
+++ b/system/vulkan_enc/VkEncoder.h
@@ -473,7 +473,7 @@ public:
         float depthBiasSlopeFactor);
     void vkCmdSetBlendConstants(
     VkCommandBuffer commandBuffer,
-        const float blendConstants);
+        const float blendConstants[4]);
     void vkCmdSetDepthBounds(
     VkCommandBuffer commandBuffer,
         float minDepthBounds,
diff --git a/system/vulkan_enc/goldfish_vk_private_defs.h b/system/vulkan_enc/goldfish_vk_private_defs.h
index 3eed2442ed3805998e3dc53e7c1f42bfce6a99bd..15d30e141cd6f187ad28fd793a61f1acc4c169a7 100644
--- a/system/vulkan_enc/goldfish_vk_private_defs.h
+++ b/system/vulkan_enc/goldfish_vk_private_defs.h
@@ -425,6 +425,53 @@ typedef void (VKAPI_PTR *PFN_vkResetCommandBufferAsyncGOOGLE)(
     VkCommandBuffer commandBuffer,
     VkCommandBufferResetFlags flags);
 
+#ifdef VK_USE_PLATFORM_FUCHSIA
+#define VK_FUCHSIA_buffer_collection 1
+VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkBufferCollectionFUCHSIA)
+
+#define VK_FUCHSIA_BUFFER_COLLECTION_SPEC_VERSION 1
+#define VK_FUCHSIA_BUFFER_COLLECTION_EXTENSION_NAME "VK_FUCHSIA_buffer_collection"
+
+typedef struct VkBufferCollectionImageCreateInfoFUCHSIA {
+    VkStructureType              sType;
+    const void*                  pNext;
+    VkBufferCollectionFUCHSIA    collection;
+    uint32_t                     index;
+} VkBufferCollectionImageCreateInfoFUCHSIA;
+
+#define VK_STRUCTURE_TYPE_BUFFER_COLLECTION_IMAGE_CREATE_INFO_FUCHSIA \
+    ((VkStructureType)1001004005)
+#endif  // VK_USE_PLATFORM_FUCHSIA
+
+#ifdef VK_USE_PLATFORM_ANDROID_KHR
+
+typedef struct VkImportMemoryZirconHandleInfoFUCHSIA {
+    VkStructureType                       sType;
+    const void*                           pNext;
+    VkExternalMemoryHandleTypeFlagBits    handleType;
+    uint32_t                              handle;
+} VkImportMemoryZirconHandleInfoFUCHSIA;
+
+typedef uint32_t VkBufferCollectionFUCHSIA;
+
+typedef struct VkImportMemoryBufferCollectionFUCHSIA {
+    VkStructureType              sType;
+    const void*                  pNext;
+    VkBufferCollectionFUCHSIA    collection;
+    uint32_t                     index;
+} VkImportMemoryBufferCollectionFUCHSIA;
+
+#define VK_STRUCTURE_TYPE_IMPORT_MEMORY_BUFFER_COLLECTION_FUCHSIA \
+    ((VkStructureType)1001000000)
+#define VK_STRUCTURE_TYPE_TEMP_IMPORT_MEMORY_ZIRCON_HANDLE_INFO_FUCHSIA \
+    ((VkStructureType)1001000000)
+#define VK_EXTERNAL_MEMORY_HANDLE_TYPE_TEMP_ZIRCON_VMO_BIT_FUCHSIA \
+    ((VkStructureType)0x00000800)
+#define VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_TEMP_ZIRCON_EVENT_BIT_FUCHSIA \
+    ((VkStructureType)0x00000020)
+
+#endif // VK_USE_PLATFORM_ANDROID_KHR
+
 #ifdef __cplusplus
 } // extern "C"
 #endif
diff --git a/system/vulkan_enc/vk_format_info.h b/system/vulkan_enc/vk_format_info.h
index 3bac828aab8089d82e9bd112d96a5f0225921991..c70f45ff72a5651d3811433eafdb235ab836f345 100644
--- a/system/vulkan_enc/vk_format_info.h
+++ b/system/vulkan_enc/vk_format_info.h
@@ -58,7 +58,7 @@ vk_format_from_android(unsigned android_format)
 }
 
 static inline unsigned
-android_format_from_vk(unsigned vk_format)
+android_format_from_vk(VkFormat vk_format)
 {
    switch (vk_format) {
    case VK_FORMAT_R8G8B8A8_UNORM:
@@ -78,6 +78,18 @@ android_format_from_vk(unsigned vk_format)
    }
 }
 
+static inline bool
+android_format_is_yuv(unsigned android_format)
+{
+   switch (android_format) {
+   case HAL_PIXEL_FORMAT_NV12_Y_TILED_INTEL:
+      return true;
+
+   default:
+      return false;
+   }
+}
+
 static inline VkImageAspectFlags
 vk_format_aspects(VkFormat format)
 {
diff --git a/system/vulkan_enc/vk_struct_id.h b/system/vulkan_enc/vk_struct_id.h
new file mode 100644
index 0000000000000000000000000000000000000000..893389c7e064ed616081237a970b5d8d61124c33
--- /dev/null
+++ b/system/vulkan_enc/vk_struct_id.h
@@ -0,0 +1,57 @@
+// Copyright (C) 2018 The Android Open Source Project
+// Copyright (C) 2018 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+#pragma once
+
+#include <vulkan/vulkan.h>
+#include "goldfish_vk_private_defs.h"
+
+template <class T> struct vk_get_vk_struct_id;
+
+#define REGISTER_VK_STRUCT_ID(T, ID) \
+    template <> struct vk_get_vk_struct_id<T> { static constexpr VkStructureType id = ID; };
+
+REGISTER_VK_STRUCT_ID(VkAndroidHardwareBufferPropertiesANDROID, VK_STRUCTURE_TYPE_ANDROID_HARDWARE_BUFFER_PROPERTIES_ANDROID);
+REGISTER_VK_STRUCT_ID(VkAndroidHardwareBufferFormatPropertiesANDROID, VK_STRUCTURE_TYPE_ANDROID_HARDWARE_BUFFER_FORMAT_PROPERTIES_ANDROID);
+REGISTER_VK_STRUCT_ID(VkAndroidHardwareBufferUsageANDROID, VK_STRUCTURE_TYPE_ANDROID_HARDWARE_BUFFER_USAGE_ANDROID);
+REGISTER_VK_STRUCT_ID(VkBufferCreateInfo, VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO);
+REGISTER_VK_STRUCT_ID(VkImageCreateInfo, VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_CREATE_INFO);
+REGISTER_VK_STRUCT_ID(VkImageFormatProperties2, VK_STRUCTURE_TYPE_IMAGE_FORMAT_PROPERTIES_2);
+REGISTER_VK_STRUCT_ID(VkNativeBufferANDROID, VK_STRUCTURE_TYPE_NATIVE_BUFFER_ANDROID);
+REGISTER_VK_STRUCT_ID(VkExternalFormatANDROID, VK_STRUCTURE_TYPE_EXTERNAL_FORMAT_ANDROID);
+REGISTER_VK_STRUCT_ID(VkExternalMemoryBufferCreateInfo, VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_BUFFER_CREATE_INFO);
+REGISTER_VK_STRUCT_ID(VkExternalMemoryImageCreateInfo, VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO);
+REGISTER_VK_STRUCT_ID(VkMemoryAllocateInfo, VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO);
+REGISTER_VK_STRUCT_ID(VkMemoryDedicatedAllocateInfo, VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO);
+REGISTER_VK_STRUCT_ID(VkMemoryDedicatedRequirements, VK_STRUCTURE_TYPE_MEMORY_DEDICATED_REQUIREMENTS);
+REGISTER_VK_STRUCT_ID(VkImportAndroidHardwareBufferInfoANDROID, VK_STRUCTURE_TYPE_IMPORT_ANDROID_HARDWARE_BUFFER_INFO_ANDROID);
+REGISTER_VK_STRUCT_ID(VkExportMemoryAllocateInfo, VK_STRUCTURE_TYPE_EXPORT_MEMORY_ALLOCATE_INFO);
+REGISTER_VK_STRUCT_ID(VkMemoryRequirements2, VK_STRUCTURE_TYPE_MEMORY_REQUIREMENTS_2);
+REGISTER_VK_STRUCT_ID(VkSemaphoreCreateInfo, VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO);
+REGISTER_VK_STRUCT_ID(VkExportSemaphoreCreateInfoKHR, VK_STRUCTURE_TYPE_EXPORT_SEMAPHORE_CREATE_INFO_KHR);
+REGISTER_VK_STRUCT_ID(VkSamplerYcbcrConversionCreateInfo, VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_CREATE_INFO);
+REGISTER_VK_STRUCT_ID(VkImportColorBufferGOOGLE, VK_STRUCTURE_TYPE_IMPORT_COLOR_BUFFER_GOOGLE);
+REGISTER_VK_STRUCT_ID(VkImageViewCreateInfo, VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO);
+
+#ifdef VK_USE_PLATFORM_ANDROID_KHR
+// These two should be under Android
+REGISTER_VK_STRUCT_ID(VkImportMemoryBufferCollectionFUCHSIA, VK_STRUCTURE_TYPE_IMPORT_MEMORY_BUFFER_COLLECTION_FUCHSIA);
+REGISTER_VK_STRUCT_ID(VkImportMemoryZirconHandleInfoFUCHSIA, VK_STRUCTURE_TYPE_TEMP_IMPORT_MEMORY_ZIRCON_HANDLE_INFO_FUCHSIA);
+#endif  // VK_USE_PLATFORM_ANDROID_KHR
+
+#ifdef VK_USE_PLATFORM_FUCHSIA
+REGISTER_VK_STRUCT_ID(VkBufferCollectionImageCreateInfoFUCHSIA, VK_STRUCTURE_TYPE_BUFFER_COLLECTION_IMAGE_CREATE_INFO_FUCHSIA);
+#endif  // VK_USE_PLATFORM_FUCHSIA
+
+#undef REGISTER_VK_STRUCT_ID
diff --git a/system/vulkan_enc/vk_util.h b/system/vulkan_enc/vk_util.h
index 0c7f4b9823c13dcd645d74da6557608a7fe4ea36..39de99189d6fd696f230a44c0a9e881efb2da872 100644
--- a/system/vulkan_enc/vk_util.h
+++ b/system/vulkan_enc/vk_util.h
@@ -26,12 +26,18 @@
 /* common inlines and macros for vulkan drivers */
 
 #include <vulkan/vulkan.h>
+#include <stdlib.h>
+#include "vk_struct_id.h"
 
 struct vk_struct_common {
     VkStructureType sType;
     struct vk_struct_common *pNext;
 };
 
+struct vk_struct_chain_iterator {
+    vk_struct_common* value;
+};
+
 #define vk_foreach_struct(__iter, __start) \
    for (struct vk_struct_common *__iter = (struct vk_struct_common *)(__start); \
         __iter; __iter = __iter->pNext)
@@ -191,11 +197,18 @@ __vk_find_struct(void *start, VkStructureType sType)
    return NULL;
 }
 
-#define vk_find_struct(__start, __sType) \
-   __vk_find_struct((__start), __sType)
+template <class T, class H> T* vk_find_struct(H* head)
+{
+    vk_get_vk_struct_id<H>::id;
+    return static_cast<T*>(__vk_find_struct(static_cast<void*>(head), vk_get_vk_struct_id<T>::id));
+}
 
-#define vk_find_struct_const(__start, __sType) \
-   (const void *)__vk_find_struct((void *)(__start), __sType)
+template <class T, class H> const T* vk_find_struct(const H* head)
+{
+    vk_get_vk_struct_id<H>::id;
+    return static_cast<const T*>(__vk_find_struct(const_cast<void*>(static_cast<const void*>(head)),
+                                 vk_get_vk_struct_id<T>::id));
+}
 
 uint32_t vk_get_driver_version(void);
 
@@ -207,19 +220,32 @@ uint32_t vk_get_version_override(void);
 #define VK_ENUM_OFFSET(__enum) \
    ((__enum) >= VK_EXT_OFFSET ? ((__enum) % 1000) : (__enum))
 
-static inline vk_struct_common*
-vk_init_struct_chain(vk_struct_common* start)
+template <class T> T vk_make_orphan_copy(const T& vk_struct) {
+    T copy = vk_struct;
+    copy.pNext = NULL;
+    return copy;
+}
+
+template <class T> vk_struct_chain_iterator vk_make_chain_iterator(T* vk_struct)
 {
-   start->pNext = nullptr;
-   return start;
+    vk_get_vk_struct_id<T>::id;
+    vk_struct_chain_iterator result = { reinterpret_cast<vk_struct_common*>(vk_struct) };
+    return result;
 }
 
-static inline vk_struct_common*
-vk_append_struct(vk_struct_common* current, vk_struct_common* next)
+template <class T> void vk_append_struct(vk_struct_chain_iterator* i, T* vk_struct)
 {
-   current->pNext = next;
-   next->pNext = nullptr;
-   return next;
+    vk_get_vk_struct_id<T>::id;
+
+    vk_struct_common* p = i->value;
+    if (p->pNext) {
+        ::abort();
+    }
+
+    p->pNext = reinterpret_cast<vk_struct_common *>(vk_struct);
+    vk_struct->pNext = NULL;
+
+    *i = vk_make_chain_iterator(vk_struct);
 }
 
 #endif /* VK_UTIL_H */