Move the ownership of DisplayVk to VkEmulation am: 4ddffd9a1d

Original change: https://android-review.googlesource.com/c/device/generic/vulkan-cereal/+/1955444

Change-Id: I66fc4cb47d8d000d49d3b7e4ecfeef32ee54a0c9
diff --git a/stream-servers/FrameBuffer.cpp b/stream-servers/FrameBuffer.cpp
index dc088ef..f39b3e1 100644
--- a/stream-servers/FrameBuffer.cpp
+++ b/stream-servers/FrameBuffer.cpp
@@ -342,7 +342,6 @@
     }
 
     m_readbackThread.enqueue({ReadbackCmd::Exit});
-    m_displayVk.reset();
     if (m_vkSurface != VK_NULL_HANDLE) {
         emugl::vkDispatch(false /* not for testing */)
             ->vkDestroySurfaceKHR(m_vkInstance, m_vkSurface, nullptr);
@@ -380,22 +379,13 @@
     goldfish_vk::VulkanDispatch* vkDispatch = nullptr;
     if (feature_is_enabled(kFeature_Vulkan)) {
         vkDispatch = emugl::vkDispatch(false /* not for testing */);
-        vkEmu = goldfish_vk::createOrGetGlobalVkEmulation(vkDispatch);
+        vkEmu = goldfish_vk::createGlobalVkEmulation(vkDispatch);
         if (!vkEmu) {
             ERR("Failed to initialize global Vulkan emulation. Disable the Vulkan support.");
         }
     }
     if (vkEmu) {
-        bool useDeferredCommands =
-            android::base::getEnvironmentVariable("ANDROID_EMU_VK_DISABLE_DEFERRED_COMMANDS").empty();
-        bool useCreateResourcesWithRequirements =
-            android::base::getEnvironmentVariable("ANDROID_EMU_VK_DISABLE_USE_CREATE_RESOURCES_WITH_REQUIREMENTS").empty();
-        goldfish_vk::setUseDeferredCommands(vkEmu, useDeferredCommands);
-        goldfish_vk::setUseCreateResourcesWithRequirements(vkEmu, useCreateResourcesWithRequirements);
         if (feature_is_enabled(kFeature_VulkanNativeSwapchain)) {
-            fb->m_displayVk = std::make_shared<DisplayVk>(
-                *vkEmu->ivk, vkEmu->physdev, vkEmu->queueFamilyIndex, vkEmu->queueFamilyIndex,
-                vkEmu->device, vkEmu->queue, vkEmu->queueLock, vkEmu->queue, vkEmu->queueLock);
             fb->m_vkInstance = vkEmu->instance;
         }
         if (vkEmu->deviceInfo.supportsIdProperties) {
@@ -500,6 +490,18 @@
         feature_is_enabled(
             kFeature_GuestUsesAngle);
 
+    goldfish_vk::VkEmulationFeatures vkEmulationFeatures = {
+        .glInteropSupported = false,  // Set later.
+        .deferredCommands =
+            android::base::getEnvironmentVariable("ANDROID_EMU_VK_DISABLE_DEFERRED_COMMANDS")
+                .empty(),
+        .createResourceWithRequirements =
+            android::base::getEnvironmentVariable(
+                "ANDROID_EMU_VK_DISABLE_USE_CREATE_RESOURCES_WITH_REQUIREMENTS")
+                .empty(),
+        .useVulkanNativeSwapchain = feature_is_enabled(kFeature_VulkanNativeSwapchain),
+    };
+
     //
     // if GLES2 plugin has loaded - try to make GLES2 context and
     // get GLES2 extension string
@@ -802,7 +804,13 @@
     }
 
     GL_LOG("glvk interop final: %d", fb->m_vulkanInteropSupported);
-    goldfish_vk::setGlInteropSupported(fb->m_vulkanInteropSupported);
+    vkEmulationFeatures.glInteropSupported = fb->m_vulkanInteropSupported;
+    if (feature_is_enabled(kFeature_Vulkan)) {
+        goldfish_vk::initVkEmulationFeatures(vkEmulationFeatures);
+        if (vkEmu->displayVk) {
+            fb->m_displayVk = vkEmu->displayVk.get();
+        }
+    }
 
     // Start up the single sync thread. If we are using Vulkan native
     // swapchain, then don't initialize SyncThread worker threads with EGL
@@ -844,8 +852,12 @@
 
     auto& cb = *c->second.cb;
     std::shared_ptr<DisplayVk::DisplayBufferInfo> db = nullptr;
-    if (m_displayVk != nullptr) {
+    if (m_displayVk) {
         db = m_displayVk->createDisplayBuffer(image, imageCi);
+        if (!db) {
+            ERR("Fail to create display buffer for ColorBuffer %" PRIu64 ".",
+                static_cast<uint64_t>(colorBufferHandle));
+        }
     }
     return cb.importMemory(handle, size, dedicated, imageCi.tiling == VK_IMAGE_TILING_LINEAR,
                            vulkanOnly, std::move(db));
@@ -1045,9 +1057,8 @@
                         return false;
                     }
                     INFO("Recreating swapchain...");
-                    m_displayVk->bindToSurface(
-                        m_vkSurface, static_cast<uint32_t>(m_windowWidth),
-                        static_cast<uint32_t>(m_windowHeight));
+                    m_displayVk->bindToSurface(m_vkSurface, static_cast<uint32_t>(m_windowWidth),
+                                             static_cast<uint32_t>(m_windowHeight));
                     INFO("Recreating swapchain completes.");
                     return true;
                 }
diff --git a/stream-servers/FrameBuffer.h b/stream-servers/FrameBuffer.h
index 4f7640d..b960c30 100644
--- a/stream-servers/FrameBuffer.h
+++ b/stream-servers/FrameBuffer.h
@@ -24,6 +24,7 @@
 #include <functional>
 #include <map>
 #include <memory>
+#include <optional>
 #include <unordered_map>
 #include <unordered_set>
 
@@ -46,8 +47,8 @@
 #include "base/WorkerThread.h"
 #include "render_api.h"
 #include "snapshot/common.h"
-#include "vulkan/vk_util.h"
 #include "virtio_gpu_ops.h"
+#include "vulkan/vk_util.h"
 
 struct ColorBufferRef {
     ColorBufferPtr cb;
@@ -786,9 +787,9 @@
     android::base::MessageChannel<HandleType, 1024>
         mOutstandingColorBufferDestroys;
 
-    // The implementation for Vulkan native swapchain. Only initialized when
-    // useVulkan is set when calling FrameBuffer::initialize().
-    std::shared_ptr<DisplayVk> m_displayVk;
+    // The implementation for Vulkan native swapchain. Only initialized when useVulkan is set when
+    // calling FrameBuffer::initialize(). DisplayVk is actually owned by VkEmulation.
+    DisplayVk *m_displayVk;
     VkInstance m_vkInstance = VK_NULL_HANDLE;
     VkSurfaceKHR m_vkSurface = VK_NULL_HANDLE;
 
diff --git a/stream-servers/PostWorker.cpp b/stream-servers/PostWorker.cpp
index b9ac93c..d8cb380 100644
--- a/stream-servers/PostWorker.cpp
+++ b/stream-servers/PostWorker.cpp
@@ -53,17 +53,16 @@
     (void)wait;
 }
 
-PostWorker::PostWorker(PostWorker::BindSubwinCallback&& cb,
-                       bool mainThreadPostingOnly, EGLContext eglContext,
-                       EGLSurface, std::shared_ptr<DisplayVk> displayVk)
+PostWorker::PostWorker(PostWorker::BindSubwinCallback&& cb, bool mainThreadPostingOnly,
+                       EGLContext eglContext, EGLSurface,
+                       DisplayVk* displayVk)
     : mFb(FrameBuffer::getFB()),
       mBindSubwin(cb),
       m_mainThreadPostingOnly(mainThreadPostingOnly),
-      m_runOnUiThread(m_mainThreadPostingOnly
-                          ? emugl::get_emugl_window_operations().runOnUiThread
-                          : sDefaultRunOnUiThread),
+      m_runOnUiThread(m_mainThreadPostingOnly ? emugl::get_emugl_window_operations().runOnUiThread
+                                              : sDefaultRunOnUiThread),
       mContext(eglContext),
-      m_displayVk(std::move(displayVk)) {}
+      m_displayVk(displayVk) {}
 
 void PostWorker::fillMultiDisplayPostStruct(ComposeLayer* l,
                                             hwc_rect_t displayArea,
diff --git a/stream-servers/PostWorker.h b/stream-servers/PostWorker.h
index 3fe8097..ccbb3cf 100644
--- a/stream-servers/PostWorker.h
+++ b/stream-servers/PostWorker.h
@@ -41,9 +41,8 @@
    public:
     using BindSubwinCallback = std::function<bool(void)>;
 
-    PostWorker(BindSubwinCallback&& cb, bool mainThreadPostingOnly,
-               EGLContext eglContext, EGLSurface eglSurface,
-               std::shared_ptr<DisplayVk>);
+    PostWorker(BindSubwinCallback&& cb, bool mainThreadPostingOnly, EGLContext eglContext,
+               EGLSurface eglSurface, DisplayVk*);
     ~PostWorker();
 
     // post: posts the next color buffer.
@@ -120,8 +119,9 @@
     EGLContext mContext = EGL_NO_CONTEXT;
 
     // The implementation for Vulkan native swapchain. Only initialized when
-    // useVulkan is set when calling FrameBuffer::initialize().
-    std::shared_ptr<DisplayVk> m_displayVk;
+    // useVulkan is set when calling FrameBuffer::initialize(). PostWorker
+    // doesn't take the ownership of this DisplayVk object.
+    DisplayVk* const m_displayVk;
     // With Vulkan swapchain, compose also means to post to the WSI surface.
     // In this case, don't do anything in the subsequent resource flush.
     std::optional<uint32_t> m_lastVkComposeColorBuffer = std::nullopt;
diff --git a/stream-servers/vulkan/VkCommonOperations.cpp b/stream-servers/vulkan/VkCommonOperations.cpp
index 2e955fa..e1d4e29 100644
--- a/stream-servers/vulkan/VkCommonOperations.cpp
+++ b/stream-servers/vulkan/VkCommonOperations.cpp
@@ -445,7 +445,7 @@
     return res;
 }
 
-VkEmulation* createOrGetGlobalVkEmulation(VulkanDispatch* vk) {
+VkEmulation* createGlobalVkEmulation(VulkanDispatch* vk) {
 #define VK_EMU_INIT_RETURN_ON_ERROR(...) \
     do {                                 \
         ERR(__VA_ARGS__);                \
@@ -1060,30 +1060,32 @@
     return sVkEmulation;
 }
 
-void setGlInteropSupported(bool supported) {
-    if (!sVkEmulation) {
-        // LOG(VERBOSE) << "Not setting vk/gl interop support, Vulkan not enabled";
+void initVkEmulationFeatures(const VkEmulationFeatures& features) {
+    if (!sVkEmulation || !sVkEmulation->live) {
+        ERR("VkEmulation is either not initialized or destroyed.");
         return;
     }
 
-    // LOG(VERBOSE) << "Setting gl interop support for Vk to: " << supported;
-    sVkEmulation->deviceInfo.glInteropSupported = supported;
-}
+    AutoLock lock(sVkEmulationLock);
+    INFO("Initializing VkEmulation features:");
+    INFO("    glInteropSupported: %s", features.glInteropSupported ? "true" : "false");
+    INFO("    useDeferredCommands: %s", features.deferredCommands ? "true" : "false");
+    INFO("    createResourceWithRequirements: %s",
+         features.createResourceWithRequirements ? "true" : "false");
+    INFO("    useVulkanNativeSwapchain: %s", features.useVulkanNativeSwapchain ? "true" : "false");
+    sVkEmulation->deviceInfo.glInteropSupported = features.glInteropSupported;
+    sVkEmulation->useDeferredCommands = features.deferredCommands;
+    sVkEmulation->useCreateResourcesWithRequirements = features.createResourceWithRequirements;
 
-void setUseDeferredCommands(VkEmulation* emu, bool useDeferredCommands) {
-    if (!emu) return;
-    if (!emu->live) return;
-
-    // LOG(VERBOSE) << "Using deferred Vulkan commands: " << useDeferredCommands;
-    emu->useDeferredCommands = useDeferredCommands;
-}
-
-void setUseCreateResourcesWithRequirements(VkEmulation* emu, bool useCreateResourcesWithRequirements) {
-    if (!emu) return;
-    if (!emu->live) return;
-
-    /// LOG(VERBOSE) << "Using deferred Vulkan commands: " << useCreateResourcesWithRequirements;
-    emu->useCreateResourcesWithRequirements = useCreateResourcesWithRequirements;
+    if (features.useVulkanNativeSwapchain) {
+        if (sVkEmulation->displayVk) {
+            ERR("Reset VkEmulation::displayVk.");
+        }
+        sVkEmulation->displayVk = std::make_unique<DisplayVk>(
+            *sVkEmulation->ivk, sVkEmulation->physdev, sVkEmulation->queueFamilyIndex,
+            sVkEmulation->queueFamilyIndex, sVkEmulation->device, sVkEmulation->queue,
+            sVkEmulation->queueLock, sVkEmulation->queue, sVkEmulation->queueLock);
+    }
 }
 
 VkEmulation* getGlobalVkEmulation() {
@@ -1097,6 +1099,8 @@
     // Don't try to tear down something that did not set up completely; too risky
     if (!sVkEmulation->live) return;
 
+    sVkEmulation->displayVk.reset();
+
     freeExternalMemoryLocked(sVkEmulation->dvk, &sVkEmulation->staging.memory);
 
     sVkEmulation->ivk->vkDestroyDevice(sVkEmulation->device, nullptr);
diff --git a/stream-servers/vulkan/VkCommonOperations.h b/stream-servers/vulkan/VkCommonOperations.h
index 5f2d2d4..3150c6e 100644
--- a/stream-servers/vulkan/VkCommonOperations.h
+++ b/stream-servers/vulkan/VkCommonOperations.h
@@ -22,6 +22,7 @@
 #include <unordered_set>
 #include <vector>
 
+#include "DisplayVk.h"
 #include "base/Lock.h"
 #include "base/Optional.h"
 #include "cereal/common/goldfish_vk_private_defs.h"
@@ -336,12 +337,20 @@
     // Every command buffer in the pool is associated with a VkFence which is
     // signaled only if the command buffer completes.
     std::vector<std::tuple<VkCommandBuffer, VkFence>> transferQueueCommandBufferPool;
+
+    // The implementation for Vulkan native swapchain. Only initialized in initVkEmulationFeatures
+    // if useVulkanNativeSwapchain is set.
+    std::unique_ptr<DisplayVk> displayVk;
 };
 
-VkEmulation* createOrGetGlobalVkEmulation(VulkanDispatch* vk);
-void setGlInteropSupported(bool supported);
-void setUseDeferredCommands(VkEmulation* emu, bool useDeferred);
-void setUseCreateResourcesWithRequirements(VkEmulation* emu, bool useCreateResourcesWithRequirements);
+VkEmulation* createGlobalVkEmulation(VulkanDispatch* vk);
+struct VkEmulationFeatures {
+    bool glInteropSupported = false;
+    bool deferredCommands = false;
+    bool createResourceWithRequirements = false;
+    bool useVulkanNativeSwapchain = false;
+};
+void initVkEmulationFeatures(const VkEmulationFeatures&);
 
 VkEmulation* getGlobalVkEmulation();
 void teardownGlobalVkEmulation();