Merge "vulkan: Remove unused variable"
diff --git a/system/OpenglSystemCommon/HostConnection.cpp b/system/OpenglSystemCommon/HostConnection.cpp
index f308475..7829545 100644
--- a/system/OpenglSystemCommon/HostConnection.cpp
+++ b/system/OpenglSystemCommon/HostConnection.cpp
@@ -352,11 +352,6 @@
 static GoldfishProcessPipe m_goldfishProcessPipe;
 
 HostConnection::HostConnection() :
-    m_stream(NULL),
-    m_glEnc(NULL),
-    m_gl2Enc(NULL),
-    m_vkEnc(NULL),
-    m_rcEnc(NULL),
     m_checksumHelper(),
     m_glExtensions(),
     m_grallocOnly(true),
@@ -369,15 +364,11 @@
     // round-trip to ensure that queued commands have been processed
     // before process pipe closure is detected.
     if (m_rcEnc) {
-        (void) m_rcEnc->rcGetRendererVersion(m_rcEnc);
+        (void)m_rcEnc->rcGetRendererVersion(m_rcEnc.get());
     }
     if (m_grallocType == GRALLOC_TYPE_MINIGBM) {
         delete m_grallocHelper;
     }
-    delete m_stream;
-    delete m_glEnc;
-    delete m_gl2Enc;
-    delete m_rcEnc;
 
     if (m_rendernodeFdOwned) {
         close(m_rendernodeFd);
@@ -385,43 +376,40 @@
 }
 
 // static
-HostConnection* HostConnection::connect(HostConnection* con) {
-    if (!con) return con;
-
+std::unique_ptr<HostConnection> HostConnection::connect() {
     const enum HostConnectionType connType = getConnectionTypeFromProperty();
     // const enum HostConnectionType connType = HOST_CONNECTION_VIRTIO_GPU;
 
+    // Use "new" to access a non-public constructor.
+    auto con = std::unique_ptr<HostConnection>(new HostConnection);
     switch (connType) {
         case HOST_CONNECTION_ADDRESS_SPACE: {
-            AddressSpaceStream *stream = createAddressSpaceStream(STREAM_BUFFER_SIZE);
+            auto stream = std::unique_ptr<AddressSpaceStream>(
+                createAddressSpaceStream(STREAM_BUFFER_SIZE));
             if (!stream) {
                 ALOGE("Failed to create AddressSpaceStream for host connection!!!\n");
-                delete con;
-                return NULL;
+                return nullptr;
             }
             con->m_connectionType = HOST_CONNECTION_ADDRESS_SPACE;
             con->m_grallocType = GRALLOC_TYPE_RANCHU;
-            con->m_stream = stream;
+            con->m_stream = std::move(stream);
             con->m_grallocHelper = &m_goldfishGralloc;
             con->m_processPipe = &m_goldfishProcessPipe;
             break;
         }
         case HOST_CONNECTION_QEMU_PIPE: {
-            QemuPipeStream *stream = new QemuPipeStream(STREAM_BUFFER_SIZE);
+            auto stream = std::make_unique<QemuPipeStream>(STREAM_BUFFER_SIZE);
             if (!stream) {
                 ALOGE("Failed to create QemuPipeStream for host connection!!!\n");
-                delete con;
-                return NULL;
+                return nullptr;
             }
             if (stream->connect() < 0) {
                 ALOGE("Failed to connect to host (QemuPipeStream)!!!\n");
-                delete stream;
-                delete con;
-                return NULL;
+                return nullptr;
             }
             con->m_connectionType = HOST_CONNECTION_QEMU_PIPE;
             con->m_grallocType = GRALLOC_TYPE_RANCHU;
-            con->m_stream = stream;
+            con->m_stream = std::move(stream);
             con->m_grallocHelper = &m_goldfishGralloc;
             con->m_processPipe = &m_goldfishProcessPipe;
             break;
@@ -429,26 +417,22 @@
         case HOST_CONNECTION_TCP: {
 #ifdef __Fuchsia__
             ALOGE("Fuchsia doesn't support HOST_CONNECTION_TCP!!!\n");
-            delete con;
-            return NULL;
+            return nullptr;
             break;
 #else
-            TcpStream *stream = new TcpStream(STREAM_BUFFER_SIZE);
+            auto stream = std::make_unique<TcpStream>(STREAM_BUFFER_SIZE);
             if (!stream) {
                 ALOGE("Failed to create TcpStream for host connection!!!\n");
-                delete con;
-                return NULL;
+                return nullptr;
             }
 
             if (stream->connect("10.0.2.2", STREAM_PORT_NUM) < 0) {
                 ALOGE("Failed to connect to host (TcpStream)!!!\n");
-                delete stream;
-                delete con;
-                return NULL;
+                return nullptr;
             }
             con->m_connectionType = HOST_CONNECTION_TCP;
             con->m_grallocType = GRALLOC_TYPE_RANCHU;
-            con->m_stream = stream;
+            con->m_stream = std::move(stream);
             con->m_grallocHelper = &m_goldfishGralloc;
             con->m_processPipe = &m_goldfishProcessPipe;
             break;
@@ -456,21 +440,18 @@
         }
 #ifdef VIRTIO_GPU
         case HOST_CONNECTION_VIRTIO_GPU: {
-            VirtioGpuStream *stream = new VirtioGpuStream(STREAM_BUFFER_SIZE);
+            auto stream = std::make_unique<VirtioGpuStream>(STREAM_BUFFER_SIZE);
             if (!stream) {
                 ALOGE("Failed to create VirtioGpu for host connection!!!\n");
-                delete con;
-                return NULL;
+                return nullptr;
             }
             if (stream->connect() < 0) {
                 ALOGE("Failed to connect to host (VirtioGpu)!!!\n");
-                delete stream;
-                delete con;
-                return NULL;
+                return nullptr;
             }
             con->m_connectionType = HOST_CONNECTION_VIRTIO_GPU;
             con->m_grallocType = GRALLOC_TYPE_MINIGBM;
-            con->m_stream = stream;
+            con->m_stream = std::move(stream);
             con->m_rendernodeFdOwned = false;
             con->m_rendernodeFdOwned = stream->getRendernodeFd();
             MinigbmGralloc* m = new MinigbmGralloc;
@@ -480,21 +461,19 @@
             break;
         }
         case HOST_CONNECTION_VIRTIO_GPU_PIPE: {
-            VirtioGpuPipeStream *stream = new VirtioGpuPipeStream(STREAM_BUFFER_SIZE);
+            auto stream =
+                std::make_unique<VirtioGpuPipeStream>(STREAM_BUFFER_SIZE);
             if (!stream) {
                 ALOGE("Failed to create VirtioGpu for host connection!!!\n");
-                delete con;
-                return NULL;
+                return nullptr;
             }
             if (stream->connect() < 0) {
                 ALOGE("Failed to connect to host (VirtioGpu)!!!\n");
-                delete stream;
-                delete con;
-                return NULL;
+                return nullptr;
             }
             con->m_connectionType = HOST_CONNECTION_VIRTIO_GPU_PIPE;
             con->m_grallocType = getGrallocTypeFromProperty();
-            con->m_stream = stream;
+            con->m_stream = std::move(stream);
             con->m_rendernodeFdOwned = false;
             con->m_rendernodeFd = stream->getRendernodeFd();
             switch (con->m_grallocType) {
@@ -516,15 +495,15 @@
         }
 #ifndef HOST_BUILD
         case HOST_CONNECTION_VIRTIO_GPU_ADDRESS_SPACE: {
-            AddressSpaceStream *stream = createVirtioGpuAddressSpaceStream(STREAM_BUFFER_SIZE);
+            auto stream = std::unique_ptr<AddressSpaceStream>(
+                createVirtioGpuAddressSpaceStream(STREAM_BUFFER_SIZE));
             if (!stream) {
                 ALOGE("Failed to create virtgpu AddressSpaceStream for host connection!!!\n");
-                delete con;
-                return NULL;
+                return nullptr;
             }
             con->m_connectionType = HOST_CONNECTION_VIRTIO_GPU_ADDRESS_SPACE;
             con->m_grallocType = getGrallocTypeFromProperty();
-            con->m_stream = stream;
+            con->m_stream = std::move(stream);
             con->m_rendernodeFdOwned = false;
             con->m_rendernodeFd = stream->getRendernodeFd();
             switch (con->m_grallocType) {
@@ -558,7 +537,7 @@
     con->m_stream->commitBuffer(sizeof(unsigned int));
 
     ALOGD("HostConnection::get() New Host Connection established %p, tid %d\n",
-          con, getCurrentThreadId());
+          con.get(), getCurrentThreadId());
 
     // ALOGD("Address space echo latency check done\n");
     return con;
@@ -575,13 +554,10 @@
     }
 
     if (tinfo->hostConn == NULL) {
-        HostConnection *con = new HostConnection();
-        con = connect(con);
-
-        tinfo->hostConn = con;
+        tinfo->hostConn = HostConnection::createUnique();
     }
 
-    return tinfo->hostConn;
+    return tinfo->hostConn.get();
 }
 
 void HostConnection::exit() {
@@ -590,38 +566,31 @@
         return;
     }
 
-    if (tinfo->hostConn) {
-        delete tinfo->hostConn;
-        tinfo->hostConn = NULL;
-    }
+    tinfo->hostConn.reset();
 }
 
 // static
-HostConnection *HostConnection::createUnique() {
+std::unique_ptr<HostConnection> HostConnection::createUnique() {
     ALOGD("%s: call\n", __func__);
-    return connect(new HostConnection());
-}
-
-// static
-void HostConnection::teardownUnique(HostConnection* con) {
-    delete con;
+    return connect();
 }
 
 GLEncoder *HostConnection::glEncoder()
 {
     if (!m_glEnc) {
-        m_glEnc = new GLEncoder(m_stream, checksumHelper());
+        m_glEnc = std::make_unique<GLEncoder>(m_stream.get(), checksumHelper());
         DBG("HostConnection::glEncoder new encoder %p, tid %d",
             m_glEnc, getCurrentThreadId());
         m_glEnc->setContextAccessor(s_getGLContext);
     }
-    return m_glEnc;
+    return m_glEnc.get();
 }
 
 GL2Encoder *HostConnection::gl2Encoder()
 {
     if (!m_gl2Enc) {
-        m_gl2Enc = new GL2Encoder(m_stream, checksumHelper());
+        m_gl2Enc =
+            std::make_unique<GL2Encoder>(m_stream.get(), checksumHelper());
         DBG("HostConnection::gl2Encoder new encoder %p, tid %d",
             m_gl2Enc, getCurrentThreadId());
         m_gl2Enc->setContextAccessor(s_getGL2Context);
@@ -630,45 +599,48 @@
             getDrawCallFlushIntervalFromProperty());
         m_gl2Enc->setHasAsyncUnmapBuffer(m_rcEnc->hasAsyncUnmapBuffer());
     }
-    return m_gl2Enc;
+    return m_gl2Enc.get();
 }
 
 VkEncoder *HostConnection::vkEncoder()
 {
     if (!m_vkEnc) {
-        m_vkEnc = new VkEncoder(m_stream);
+        m_vkEnc = std::make_unique<VkEncoder>(m_stream.get());
     }
-    return m_vkEnc;
+    return m_vkEnc.get();
 }
 
 ExtendedRCEncoderContext *HostConnection::rcEncoder()
 {
     if (!m_rcEnc) {
-        m_rcEnc = new ExtendedRCEncoderContext(m_stream, checksumHelper());
-        setChecksumHelper(m_rcEnc);
-        queryAndSetSyncImpl(m_rcEnc);
-        queryAndSetDmaImpl(m_rcEnc);
-        queryAndSetGLESMaxVersion(m_rcEnc);
-        queryAndSetNoErrorState(m_rcEnc);
-        queryAndSetHostCompositionImpl(m_rcEnc);
-        queryAndSetDirectMemSupport(m_rcEnc);
-        queryAndSetVulkanSupport(m_rcEnc);
-        queryAndSetDeferredVulkanCommandsSupport(m_rcEnc);
-        queryAndSetVulkanNullOptionalStringsSupport(m_rcEnc);
-        queryAndSetVulkanCreateResourcesWithRequirementsSupport(m_rcEnc);
-        queryAndSetVulkanIgnoredHandles(m_rcEnc);
-        queryAndSetYUVCache(m_rcEnc);
-        queryAndSetAsyncUnmapBuffer(m_rcEnc);
-        queryAndSetVirtioGpuNext(m_rcEnc);
-        queryHasSharedSlotsHostMemoryAllocator(m_rcEnc);
-        queryAndSetVulkanFreeMemorySync(m_rcEnc);
-        queryAndSetVirtioGpuNativeSync(m_rcEnc);
-        queryAndSetVulkanShaderFloat16Int8Support(m_rcEnc);
+        m_rcEnc = std::make_unique<ExtendedRCEncoderContext>(m_stream.get(),
+                                                             checksumHelper());
+
+        ExtendedRCEncoderContext* rcEnc = m_rcEnc.get();
+        setChecksumHelper(rcEnc);
+        queryAndSetSyncImpl(rcEnc);
+        queryAndSetDmaImpl(rcEnc);
+        queryAndSetGLESMaxVersion(rcEnc);
+        queryAndSetNoErrorState(rcEnc);
+        queryAndSetHostCompositionImpl(rcEnc);
+        queryAndSetDirectMemSupport(rcEnc);
+        queryAndSetVulkanSupport(rcEnc);
+        queryAndSetDeferredVulkanCommandsSupport(rcEnc);
+        queryAndSetVulkanNullOptionalStringsSupport(rcEnc);
+        queryAndSetVulkanCreateResourcesWithRequirementsSupport(rcEnc);
+        queryAndSetVulkanIgnoredHandles(rcEnc);
+        queryAndSetYUVCache(rcEnc);
+        queryAndSetAsyncUnmapBuffer(rcEnc);
+        queryAndSetVirtioGpuNext(rcEnc);
+        queryHasSharedSlotsHostMemoryAllocator(rcEnc);
+        queryAndSetVulkanFreeMemorySync(rcEnc);
+        queryAndSetVirtioGpuNativeSync(rcEnc);
+        queryAndSetVulkanShaderFloat16Int8Support(rcEnc);
         if (m_processPipe) {
-            m_processPipe->processPipeInit(m_connectionType, m_rcEnc);
+            m_processPipe->processPipeInit(m_connectionType, rcEnc);
         }
     }
-    return m_rcEnc;
+    return m_rcEnc.get();
 }
 
 int HostConnection::getOrCreateRendernodeFd() {
@@ -699,7 +671,7 @@
 {
     EGLThreadInfo *ti = getEGLThreadInfo();
     if (ti->hostConn) {
-        return ti->hostConn->m_glEnc;
+        return ti->hostConn->m_glEnc.get();
     }
     return NULL;
 }
@@ -708,7 +680,7 @@
 {
     EGLThreadInfo *ti = getEGLThreadInfo();
     if (ti->hostConn) {
-        return ti->hostConn->m_gl2Enc;
+        return ti->hostConn->m_gl2Enc.get();
     }
     return NULL;
 }
diff --git a/system/OpenglSystemCommon/HostConnection.h b/system/OpenglSystemCommon/HostConnection.h
index 3b4772a..4ccd5a7 100644
--- a/system/OpenglSystemCommon/HostConnection.h
+++ b/system/OpenglSystemCommon/HostConnection.h
@@ -30,6 +30,7 @@
 #include <utils/threads.h>
 #endif
 
+#include <memory>
 #include <string>
 
 class GLEncoder;
@@ -140,8 +141,8 @@
     static HostConnection *getWithThreadInfo(EGLThreadInfo* tInfo);
     static void exit();
 
-    static HostConnection *createUnique();
-    static void teardownUnique(HostConnection* con);
+    static std::unique_ptr<HostConnection> createUnique();
+    HostConnection(const HostConnection&) = delete;
 
     ~HostConnection();
 
@@ -187,7 +188,7 @@
 private:
     // If the connection failed, |conn| is deleted.
     // Returns NULL if connection failed.
-    static HostConnection* connect(HostConnection* con);
+    static std::unique_ptr<HostConnection> connect();
 
     HostConnection();
     static gl_client_context_t  *s_getGLContext();
@@ -219,14 +220,16 @@
 private:
     HostConnectionType m_connectionType;
     GrallocType m_grallocType;
-    IOStream *m_stream;
-    GLEncoder   *m_glEnc;
-    GL2Encoder  *m_gl2Enc;
-    goldfish_vk::VkEncoder  *m_vkEnc;
-    ExtendedRCEncoderContext *m_rcEnc;
+
+    std::unique_ptr<IOStream> m_stream;
+    std::unique_ptr<GLEncoder> m_glEnc;
+    std::unique_ptr<GL2Encoder> m_gl2Enc;
+    std::unique_ptr<goldfish_vk::VkEncoder> m_vkEnc;
+    std::unique_ptr<ExtendedRCEncoderContext> m_rcEnc;
+
     ChecksumCalculator m_checksumHelper;
-    Gralloc *m_grallocHelper;
-    ProcessPipe *m_processPipe;
+    Gralloc* m_grallocHelper = nullptr;
+    ProcessPipe* m_processPipe = nullptr;
     std::string m_glExtensions;
     bool m_grallocOnly;
     bool m_noHostError;
diff --git a/system/OpenglSystemCommon/ThreadInfo.cpp b/system/OpenglSystemCommon/ThreadInfo.cpp
index fea6cb7..99b0b9b 100644
--- a/system/OpenglSystemCommon/ThreadInfo.cpp
+++ b/system/OpenglSystemCommon/ThreadInfo.cpp
@@ -45,7 +45,6 @@
 #endif
         ) {
         EGLThreadInfo *ti = (EGLThreadInfo *)ptr;
-        delete ti->hostConn;
         delete ti;
 #ifdef __ANDROID__
         ((void **)__get_tls())[TLS_SLOT_OPENGL] = NULL;
diff --git a/system/OpenglSystemCommon/ThreadInfo.h b/system/OpenglSystemCommon/ThreadInfo.h
index 7d2260a..fa6b44b 100644
--- a/system/OpenglSystemCommon/ThreadInfo.h
+++ b/system/OpenglSystemCommon/ThreadInfo.h
@@ -24,10 +24,10 @@
 
 struct EGLThreadInfo
 {
-    EGLThreadInfo() : currentContext(NULL), hostConn(NULL), eglError(EGL_SUCCESS) { }
+    EGLThreadInfo() : currentContext(NULL), eglError(EGL_SUCCESS) {}
 
     EGLContext_t *currentContext;
-    HostConnection *hostConn;
+    std::unique_ptr<HostConnection> hostConn;
     int           eglError;
 };
 
diff --git a/system/OpenglSystemCommon/VirtioGpuStream.cpp b/system/OpenglSystemCommon/VirtioGpuStream.cpp
index a0876dc..1b49244 100644
--- a/system/OpenglSystemCommon/VirtioGpuStream.cpp
+++ b/system/OpenglSystemCommon/VirtioGpuStream.cpp
@@ -282,7 +282,7 @@
 
     if (m_flushPos + len > cmd->cmdSize) {
         ERR("%s: writeFully len %zu would overflow the command bounds, "
-            "cmd_pos=%zu, flush_pos=%zu, cmdsize=%zu, lethal error, exiting",
+            "cmd_pos=%zu, flush_pos=%zu, cmdsize=%" PRIu32 ", lethal error, exiting",
             __func__, len, m_cmdPos, m_flushPos, cmd->cmdSize);
         abort();
     }
@@ -344,7 +344,7 @@
 
     // Most likely a protocol implementation error
     if (m_cmdResp->cmdSize - sizeof(*m_cmdResp) < m_cmdRespPos + len) {
-        ERR("%s: failed, op %zu, len %zu, cmdSize %zu, pos %zu, lethal "
+        ERR("%s: failed, op %" PRIu32 ", len %zu, cmdSize %" PRIu32 ", pos %zu, lethal "
             "error, exiting.", __func__, m_cmdResp->op, len,
             m_cmdResp->cmdSize, m_cmdRespPos);
         abort();
@@ -380,7 +380,7 @@
 
         // Should never happen
         if (pos + cmd->cmdSize > m_bufSize) {
-            ERR("%s: failed, pos %zu, cmdSize %zu, bufSize %zu, lethal "
+            ERR("%s: failed, pos %zu, cmdSize %" PRIu32 ", bufSize %zu, lethal "
                 "error, exiting.", __func__, pos, cmd->cmdSize, m_bufSize);
             abort();
         }
diff --git a/system/gralloc/gralloc_30.cpp b/system/gralloc/gralloc_30.cpp
index b67f4c5..c012908 100644
--- a/system/gralloc/gralloc_30.cpp
+++ b/system/gralloc/gralloc_30.cpp
@@ -149,7 +149,9 @@
 
 class goldfish_gralloc30_module_t {
 public:
-    goldfish_gralloc30_module_t(): m_hostConn(HostConnection::createUnique()) {
+    // TODO(b/142677230): Use unique pointers instead.
+    goldfish_gralloc30_module_t()
+        : m_hostConn(HostConnection::createUnique().release()) {
         CRASH_IF(!m_hostConn, "m_hostConn cannot be nullptr");
         m_bufferManager = create_buffer_manager(this);
         CRASH_IF(!m_bufferManager, "m_bufferManager cannot be nullptr");
diff --git a/system/gralloc/gralloc_old.cpp b/system/gralloc/gralloc_old.cpp
index 7af9dfe..40f6b6c 100644
--- a/system/gralloc/gralloc_old.cpp
+++ b/system/gralloc/gralloc_old.cpp
@@ -446,7 +446,7 @@
 
 static HostConnection* createOrGetHostConnection() {
     if (!sHostCon) {
-        sHostCon = HostConnection::createUnique();
+        sHostCon = HostConnection::createUnique().release();
     }
     return sHostCon;
 }
diff --git a/system/hwc2/EmuHWC2.cpp b/system/hwc2/EmuHWC2.cpp
index e77e27d..7cdbd60 100644
--- a/system/hwc2/EmuHWC2.cpp
+++ b/system/hwc2/EmuHWC2.cpp
@@ -47,13 +47,13 @@
     return reinterpret_cast<hwc2_function_pointer_t>(function);
 }
 
-static HostConnection *sHostCon = nullptr;
+static std::unique_ptr<HostConnection> sHostCon;
 
 static HostConnection* createOrGetHostConnection() {
     if (!sHostCon) {
         sHostCon = HostConnection::createUnique();
     }
-    return sHostCon;
+    return sHostCon.get();
 }
 
 #define DEFINE_AND_VALIDATE_HOST_CONNECTION \
diff --git a/system/vulkan/goldfish_vulkan.cpp b/system/vulkan/goldfish_vulkan.cpp
index 720300d..821a68a 100644
--- a/system/vulkan/goldfish_vulkan.cpp
+++ b/system/vulkan/goldfish_vulkan.cpp
@@ -221,6 +221,14 @@
     return VK_SUCCESS;
 }
 
+VkResult SetBufferCollectionBufferConstraintsFUCHSIA(
+    VkDevice /*device*/,
+    VkBufferCollectionFUCHSIA /*collection*/,
+    const VkBufferConstraintsInfoFUCHSIA* /*pBufferConstraintsInfo*/) {
+    AEMU_SCOPED_TRACE("vkstubhal::SetBufferCollectionBufferConstraintsFUCHSIA");
+    return VK_SUCCESS;
+}
+
 VkResult
 GetBufferCollectionPropertiesFUCHSIA(VkDevice /*device*/,
                                      VkBufferCollectionFUCHSIA /*collection*/,
@@ -279,6 +287,8 @@
         return reinterpret_cast<PFN_vkVoidFunction>(DestroyBufferCollectionFUCHSIA);
     if (strcmp(name, "vkSetBufferCollectionConstraintsFUCHSIA") == 0)
         return reinterpret_cast<PFN_vkVoidFunction>(SetBufferCollectionConstraintsFUCHSIA);
+    if (strcmp(name, "vkSetBufferCollectionBufferConstraintsFUCHSIA") == 0)
+        return reinterpret_cast<PFN_vkVoidFunction>(SetBufferCollectionBufferConstraintsFUCHSIA);
     if (strcmp(name, "vkGetBufferCollectionPropertiesFUCHSIA") == 0)
         return reinterpret_cast<PFN_vkVoidFunction>(GetBufferCollectionPropertiesFUCHSIA);
 #endif
@@ -556,6 +566,27 @@
 }
 
 VKAPI_ATTR
+VkResult SetBufferCollectionBufferConstraintsFUCHSIA(
+    VkDevice device,
+    VkBufferCollectionFUCHSIA collection,
+    const VkBufferConstraintsInfoFUCHSIA* pBufferConstraintsInfo) {
+    AEMU_SCOPED_TRACE("goldfish_vulkan::SetBufferCollectionBufferConstraintsFUCHSIA");
+
+    VK_HOST_CONNECTION(VK_ERROR_DEVICE_LOST)
+
+    if (!hostSupportsVulkan) {
+        return vkstubhal::SetBufferCollectionBufferConstraintsFUCHSIA(device, collection,
+                                                                      pBufferConstraintsInfo);
+    }
+
+    VkResult res =
+        goldfish_vk::ResourceTracker::get()->on_vkSetBufferCollectionBufferConstraintsFUCHSIA(
+            vkEnc, VK_SUCCESS, device, collection, pBufferConstraintsInfo);
+
+    return res;
+}
+
+VKAPI_ATTR
 VkResult GetBufferCollectionPropertiesFUCHSIA(
     VkDevice device,
     VkBufferCollectionFUCHSIA collection,
@@ -607,6 +638,9 @@
     if (!strcmp(name, "vkSetBufferCollectionConstraintsFUCHSIA")) {
         return (PFN_vkVoidFunction)SetBufferCollectionConstraintsFUCHSIA;
     }
+    if (!strcmp(name, "vkSetBufferCollectionBufferConstraintsFUCHSIA")) {
+        return (PFN_vkVoidFunction)SetBufferCollectionBufferConstraintsFUCHSIA;
+    }
     if (!strcmp(name, "vkGetBufferCollectionPropertiesFUCHSIA")) {
         return (PFN_vkVoidFunction)GetBufferCollectionPropertiesFUCHSIA;
     }
diff --git a/system/vulkan_enc/ResourceTracker.cpp b/system/vulkan_enc/ResourceTracker.cpp
index 44da142..e7ff088 100644
--- a/system/vulkan_enc/ResourceTracker.cpp
+++ b/system/vulkan_enc/ResourceTracker.cpp
@@ -1680,18 +1680,15 @@
         delete sysmem_collection;
     }
 
-    VkResult setBufferCollectionConstraints(fuchsia::sysmem::BufferCollectionSyncPtr* collection,
-                                            const VkImageCreateInfo* pImageInfo,
-                                            size_t min_size_bytes) {
+    inline fuchsia::sysmem::BufferCollectionConstraints
+    defaultBufferCollectionConstraints(size_t min_size_bytes,
+                                       size_t buffer_count) {
         fuchsia::sysmem::BufferCollectionConstraints constraints = {};
-        constraints.usage.vulkan = fuchsia::sysmem::vulkanUsageColorAttachment |
-                                   fuchsia::sysmem::vulkanUsageTransferSrc |
-                                   fuchsia::sysmem::vulkanUsageTransferDst |
-                                   fuchsia::sysmem::vulkanUsageSampled;
-        constraints.min_buffer_count = 1;
+        constraints.min_buffer_count = buffer_count;
         constraints.has_buffer_memory_constraints = true;
         fuchsia::sysmem::BufferMemoryConstraints& buffer_constraints =
             constraints.buffer_memory_constraints;
+
         buffer_constraints.min_size_bytes = min_size_bytes;
         buffer_constraints.max_size_bytes = 0xffffffff;
         buffer_constraints.physically_contiguous_required = false;
@@ -1703,6 +1700,72 @@
         buffer_constraints.heap_permitted[0] =
             fuchsia::sysmem::HeapType::GOLDFISH_DEVICE_LOCAL;
 
+        return constraints;
+    }
+
+    uint32_t getBufferCollectionConstraintsVulkanImageUsage(
+        const VkImageCreateInfo* pImageInfo) {
+        uint32_t usage = 0u;
+        VkImageUsageFlags imageUsage = pImageInfo->usage;
+
+#define SetUsageBit(USAGE)                                    \
+    if (imageUsage & VK_IMAGE_USAGE_##USAGE##_BIT) {          \
+        usage |= fuchsia::sysmem::VULKAN_IMAGE_USAGE_##USAGE; \
+    }
+
+        SetUsageBit(COLOR_ATTACHMENT);
+        SetUsageBit(TRANSFER_SRC);
+        SetUsageBit(TRANSFER_DST);
+        SetUsageBit(SAMPLED);
+
+#undef SetUsageBit
+        return usage;
+    }
+
+    uint32_t getBufferCollectionConstraintsVulkanBufferUsage(
+        const VkBufferConstraintsInfoFUCHSIA* pBufferConstraintsInfo) {
+        uint32_t usage = 0u;
+        VkBufferUsageFlags bufferUsage =
+            pBufferConstraintsInfo->pBufferCreateInfo->usage;
+
+#define SetUsageBit(USAGE)                                     \
+    if (bufferUsage & VK_BUFFER_USAGE_##USAGE##_BIT) {         \
+        usage |= fuchsia::sysmem::VULKAN_BUFFER_USAGE_##USAGE; \
+    }
+
+        SetUsageBit(TRANSFER_SRC);
+        SetUsageBit(TRANSFER_DST);
+        SetUsageBit(UNIFORM_TEXEL_BUFFER);
+        SetUsageBit(STORAGE_TEXEL_BUFFER);
+        SetUsageBit(UNIFORM_BUFFER);
+        SetUsageBit(STORAGE_BUFFER);
+        SetUsageBit(INDEX_BUFFER);
+        SetUsageBit(VERTEX_BUFFER);
+        SetUsageBit(INDIRECT_BUFFER);
+
+#undef SetUsageBit
+        return usage;
+    }
+
+    VkResult setBufferCollectionConstraints(
+        fuchsia::sysmem::BufferCollectionSyncPtr* collection,
+        const VkImageCreateInfo* pImageInfo) {
+        if (pImageInfo == nullptr) {
+            ALOGE("setBufferCollectionConstraints: pImageInfo cannot be null.");
+            return VK_ERROR_OUT_OF_DEVICE_MEMORY;
+        }
+
+        // TODO(liyl): Currently the size only works for RGBA8 and BGRA8 images.
+        // We should set the size based on its actual format.
+        fuchsia::sysmem::BufferCollectionConstraints constraints =
+            defaultBufferCollectionConstraints(
+                /* min_size_bytes */ pImageInfo->extent.width *
+                    pImageInfo->extent.height * 4,
+                /* buffer_count */ 1u);
+
+        constraints.usage.vulkan =
+            getBufferCollectionConstraintsVulkanImageUsage(pImageInfo);
+
         // Set image format constraints for VkImage allocation.
         if (pImageInfo) {
             std::vector<VkFormat> formats{pImageInfo->format};
@@ -1768,17 +1831,49 @@
         return VK_SUCCESS;
     }
 
+    VkResult setBufferCollectionBufferConstraints(
+        fuchsia::sysmem::BufferCollectionSyncPtr* collection,
+        const VkBufferConstraintsInfoFUCHSIA* pBufferConstraintsInfo) {
+        if (pBufferConstraintsInfo == nullptr) {
+            ALOGE(
+                "setBufferCollectionBufferConstraints: "
+                "pBufferConstraintsInfo cannot be null.");
+            return VK_ERROR_OUT_OF_DEVICE_MEMORY;
+        }
+
+        fuchsia::sysmem::BufferCollectionConstraints constraints =
+            defaultBufferCollectionConstraints(
+                /* min_size_bytes */ pBufferConstraintsInfo->pBufferCreateInfo
+                    ->size,
+                /* buffer_count */ pBufferConstraintsInfo->minCount);
+        constraints.usage.vulkan =
+            getBufferCollectionConstraintsVulkanBufferUsage(
+                pBufferConstraintsInfo);
+
+        (*collection)->SetConstraints(true, constraints);
+        return VK_SUCCESS;
+    }
+
     VkResult on_vkSetBufferCollectionConstraintsFUCHSIA(
         void*, VkResult, VkDevice,
         VkBufferCollectionFUCHSIA collection,
         const VkImageCreateInfo* pImageInfo) {
         auto sysmem_collection =
             reinterpret_cast<fuchsia::sysmem::BufferCollectionSyncPtr*>(collection);
-        size_t minSizeBytes = pImageInfo ? pImageInfo->extent.width *
-                                                   pImageInfo->extent.height * 4
-                                         : 0u;
-        return setBufferCollectionConstraints(sysmem_collection, pImageInfo,
-                                              minSizeBytes);
+        return setBufferCollectionConstraints(sysmem_collection, pImageInfo);
+    }
+
+    VkResult on_vkSetBufferCollectionBufferConstraintsFUCHSIA(
+        void*,
+        VkResult,
+        VkDevice,
+        VkBufferCollectionFUCHSIA collection,
+        const VkBufferConstraintsInfoFUCHSIA* pBufferConstraintsInfo) {
+        auto sysmem_collection =
+            reinterpret_cast<fuchsia::sysmem::BufferCollectionSyncPtr*>(
+                collection);
+        return setBufferCollectionBufferConstraints(sysmem_collection,
+                                                    pBufferConstraintsInfo);
     }
 
     VkResult on_vkGetBufferCollectionPropertiesFUCHSIA(
@@ -2202,9 +2297,30 @@
         if (exportVmo) {
             bool hasDedicatedImage = dedicatedAllocInfoPtr &&
                 (dedicatedAllocInfoPtr->image != VK_NULL_HANDLE);
-            VkImageCreateInfo imageCreateInfo = {};
+            bool hasDedicatedBuffer =
+                dedicatedAllocInfoPtr &&
+                (dedicatedAllocInfoPtr->buffer != VK_NULL_HANDLE);
 
-            // TODO(liyl): Handle dedicated buffer allocation as well.
+            if (hasDedicatedImage && hasDedicatedBuffer) {
+                ALOGE(
+                    "Invalid VkMemoryDedicatedAllocationInfo: At least one "
+                    "of image and buffer must be VK_NULL_HANDLE.");
+                return VK_ERROR_OUT_OF_DEVICE_MEMORY;
+            }
+
+            const VkImageCreateInfo* pImageCreateInfo = nullptr;
+
+            VkBufferConstraintsInfoFUCHSIA bufferConstraintsInfo = {
+                .sType =
+                    VK_STRUCTURE_TYPE_BUFFER_COLLECTION_CREATE_INFO_FUCHSIA,
+                .pNext = nullptr,
+                .pBufferCreateInfo = nullptr,
+                .requiredFormatFeatures = 0,
+                .minCount = 1,
+            };
+            const VkBufferConstraintsInfoFUCHSIA* pBufferConstraintsInfo =
+                nullptr;
+
             if (hasDedicatedImage) {
                 AutoLock lock(mLock);
 
@@ -2212,13 +2328,31 @@
                 if (it == info_VkImage.end()) return VK_ERROR_INITIALIZATION_FAILED;
                 const auto& imageInfo = it->second;
 
-                imageCreateInfo = imageInfo.createInfo;
+                pImageCreateInfo = &imageInfo.createInfo;
             }
 
-            if (imageCreateInfo.usage & (VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT |
-                                         VK_IMAGE_USAGE_TRANSFER_DST_BIT |
-                                         VK_IMAGE_USAGE_TRANSFER_SRC_BIT |
-                                         VK_IMAGE_USAGE_SAMPLED_BIT)) {
+            if (hasDedicatedBuffer) {
+                AutoLock lock(mLock);
+
+                auto it = info_VkBuffer.find(dedicatedAllocInfoPtr->buffer);
+                if (it == info_VkBuffer.end())
+                    return VK_ERROR_INITIALIZATION_FAILED;
+                const auto& bufferInfo = it->second;
+
+                bufferConstraintsInfo.pBufferCreateInfo =
+                    &bufferInfo.createInfo;
+                pBufferConstraintsInfo = &bufferConstraintsInfo;
+            }
+
+            hasDedicatedImage = hasDedicatedImage &&
+                                getBufferCollectionConstraintsVulkanImageUsage(
+                                    pImageCreateInfo);
+            hasDedicatedBuffer =
+                hasDedicatedBuffer &&
+                getBufferCollectionConstraintsVulkanBufferUsage(
+                    pBufferConstraintsInfo);
+
+            if (hasDedicatedImage || hasDedicatedBuffer) {
                 fuchsia::sysmem::BufferCollectionTokenSyncPtr token;
                 zx_status_t status = mSysmemAllocator->AllocateSharedCollection(
                     token.NewRequest());
@@ -2234,12 +2368,24 @@
                     ALOGE("BindSharedCollection failed: %d", status);
                     abort();
                 }
-                VkResult res = setBufferCollectionConstraints(&collection,
-                                                              &imageCreateInfo,
-                                                              finalAllocInfo.allocationSize);
-                if (res != VK_SUCCESS) {
-                    ALOGE("setBufferCollectionConstraints failed: %d", res);
-                    abort();
+
+                if (hasDedicatedImage) {
+                    VkResult res = setBufferCollectionConstraints(
+                        &collection, pImageCreateInfo);
+                    if (res != VK_SUCCESS) {
+                        ALOGE("setBufferCollectionConstraints failed: %d", res);
+                        abort();
+                    }
+                }
+
+                if (hasDedicatedBuffer) {
+                    VkResult res = setBufferCollectionBufferConstraints(
+                        &collection, pBufferConstraintsInfo);
+                    if (res != VK_SUCCESS) {
+                        ALOGE("setBufferCollectionBufferConstraints failed: %d",
+                              res);
+                        abort();
+                    }
                 }
 
                 fuchsia::sysmem::BufferCollectionInfo_2 info;
@@ -2267,38 +2413,52 @@
                     abort();
                 }
 
-                fuchsia::hardware::goldfish::ColorBufferFormatType format;
-                switch (imageCreateInfo.format) {
-                case VK_FORMAT_B8G8R8A8_SINT:
-                case VK_FORMAT_B8G8R8A8_UNORM:
-                case VK_FORMAT_B8G8R8A8_SRGB:
-                case VK_FORMAT_B8G8R8A8_SNORM:
-                case VK_FORMAT_B8G8R8A8_SSCALED:
-                case VK_FORMAT_B8G8R8A8_USCALED:
-                    format = fuchsia::hardware::goldfish::ColorBufferFormatType::BGRA;
-                    break;
-                case VK_FORMAT_R8G8B8A8_SINT:
-                case VK_FORMAT_R8G8B8A8_UNORM:
-                case VK_FORMAT_R8G8B8A8_SRGB:
-                case VK_FORMAT_R8G8B8A8_SNORM:
-                case VK_FORMAT_R8G8B8A8_SSCALED:
-                case VK_FORMAT_R8G8B8A8_USCALED:
-                    format = fuchsia::hardware::goldfish::ColorBufferFormatType::RGBA;
-                    break;
-                default:
-                    ALOGE("Unsupported format: %d", imageCreateInfo.format);
-                    abort();
+                if (pImageCreateInfo) {
+                    fuchsia::hardware::goldfish::ColorBufferFormatType format;
+                    switch (pImageCreateInfo->format) {
+                        case VK_FORMAT_B8G8R8A8_SINT:
+                        case VK_FORMAT_B8G8R8A8_UNORM:
+                        case VK_FORMAT_B8G8R8A8_SRGB:
+                        case VK_FORMAT_B8G8R8A8_SNORM:
+                        case VK_FORMAT_B8G8R8A8_SSCALED:
+                        case VK_FORMAT_B8G8R8A8_USCALED:
+                            format = fuchsia::hardware::goldfish::
+                                ColorBufferFormatType::BGRA;
+                            break;
+                        case VK_FORMAT_R8G8B8A8_SINT:
+                        case VK_FORMAT_R8G8B8A8_UNORM:
+                        case VK_FORMAT_R8G8B8A8_SRGB:
+                        case VK_FORMAT_R8G8B8A8_SNORM:
+                        case VK_FORMAT_R8G8B8A8_SSCALED:
+                        case VK_FORMAT_R8G8B8A8_USCALED:
+                            format = fuchsia::hardware::goldfish::
+                                ColorBufferFormatType::RGBA;
+                            break;
+                        default:
+                            ALOGE("Unsupported format: %d",
+                                  pImageCreateInfo->format);
+                            abort();
+                    }
+
+                    status = mControlDevice->CreateColorBuffer(
+                        std::move(vmo_copy), pImageCreateInfo->extent.width,
+                        pImageCreateInfo->extent.height, format, &status2);
+                    if (status != ZX_OK || status2 != ZX_OK) {
+                        ALOGE("CreateColorBuffer failed: %d:%d", status,
+                              status2);
+                        abort();
+                    }
                 }
 
-                status = mControlDevice->CreateColorBuffer(
-                    std::move(vmo_copy),
-                    imageCreateInfo.extent.width,
-                    imageCreateInfo.extent.height,
-                    format,
-                    &status2);
-                if (status != ZX_OK || status2 != ZX_OK) {
-                    ALOGE("CreateColorBuffer failed: %d:%d", status, status2);
-                    abort();
+                if (pBufferConstraintsInfo) {
+                    status = mControlDevice->CreateBuffer(
+                        std::move(vmo_copy),
+                        pBufferConstraintsInfo->pBufferCreateInfo->size,
+                        &status2);
+                    if (status != ZX_OK || status2 != ZX_OK) {
+                        ALOGE("CreateBuffer failed: %d:%d", status, status2);
+                        abort();
+                    }
                 }
             }
         }
@@ -5088,6 +5248,15 @@
         context, input_result, device, collection, pImageInfo);
 }
 
+VkResult ResourceTracker::on_vkSetBufferCollectionBufferConstraintsFUCHSIA(
+        void* context, VkResult input_result,
+        VkDevice device,
+        VkBufferCollectionFUCHSIA collection,
+        const VkBufferConstraintsInfoFUCHSIA* pBufferDConstraintsInfo) {
+    return mImpl->on_vkSetBufferCollectionBufferConstraintsFUCHSIA(
+        context, input_result, device, collection, pBufferDConstraintsInfo);
+}
+
 VkResult ResourceTracker::on_vkGetBufferCollectionPropertiesFUCHSIA(
         void* context, VkResult input_result,
         VkDevice device,
diff --git a/system/vulkan_enc/ResourceTracker.h b/system/vulkan_enc/ResourceTracker.h
index 63cfc41..db33285 100644
--- a/system/vulkan_enc/ResourceTracker.h
+++ b/system/vulkan_enc/ResourceTracker.h
@@ -274,6 +274,12 @@
         VkDevice device,
         VkBufferCollectionFUCHSIA collection,
         const VkImageCreateInfo* pImageInfo);
+    VkResult on_vkSetBufferCollectionBufferConstraintsFUCHSIA(
+        void* context,
+        VkResult input_result,
+        VkDevice device,
+        VkBufferCollectionFUCHSIA collection,
+        const VkBufferConstraintsInfoFUCHSIA* pBufferConstraintsInfo);
     VkResult on_vkGetBufferCollectionPropertiesFUCHSIA(
         void* context, VkResult input_result,
         VkDevice device,
diff --git a/system/vulkan_enc/VkEncoder.cpp b/system/vulkan_enc/VkEncoder.cpp
index 9fdbe84..8a76c92 100644
--- a/system/vulkan_enc/VkEncoder.cpp
+++ b/system/vulkan_enc/VkEncoder.cpp
@@ -121,6 +121,8 @@
 VkEncoder::VkEncoder(IOStream *stream) :
     mImpl(new VkEncoder::Impl(stream)) { }
 
+VkEncoder::~VkEncoder() = default;
+
 void VkEncoder::flush() {
     mImpl->flush();
 }
diff --git a/system/vulkan_enc/goldfish_vk_private_defs.h b/system/vulkan_enc/goldfish_vk_private_defs.h
index b95517d..e7b0622 100644
--- a/system/vulkan_enc/goldfish_vk_private_defs.h
+++ b/system/vulkan_enc/goldfish_vk_private_defs.h
@@ -504,6 +504,14 @@
 #define VK_FUCHSIA_EXTERNAL_MEMORY_SPEC_VERSION 1
 #define VK_FUCHSIA_EXTERNAL_MEMORY_EXTENSION_NAME "VK_FUCHSIA_external_memory"
 
+typedef struct VkBufferConstraintsInfoFUCHSIA {
+    VkStructureType sType;
+    const void* pNext;
+    const VkBufferCreateInfo* pBufferCreateInfo;
+    VkFormatFeatureFlags requiredFormatFeatures;
+    uint32_t minCount;
+} VkBufferConstraintsInfoFUCHSIA;
+
 typedef struct VkImportMemoryZirconHandleInfoFUCHSIA {
     VkStructureType                       sType;
     const void*                           pNext;
@@ -524,6 +532,8 @@
     VkExternalMemoryHandleTypeFlagBits    handleType;
 } VkMemoryGetZirconHandleInfoFUCHSIA;
 
+#define VK_STRUCTURE_TYPE_BUFFER_COLLECTION_BUFFER_CREATE_INFO_FUCHSIA \
+    ((VkStructureType)1001004008)
 #define VK_STRUCTURE_TYPE_TEMP_IMPORT_MEMORY_ZIRCON_HANDLE_INFO_FUCHSIA \
     ((VkStructureType)1001005000)
 #define VK_STRUCTURE_TYPE_TEMP_MEMORY_ZIRCON_HANDLE_PROPERTIES_FUCHSIA \