[vulkan] Add feature flag

bug: 111137294

This allows us to build the HAL, but not activate it unless a
feature flag is enabled.

If the feature flag is not enabled, the stub hal is used.

Change-Id: I678a1eea0f36fd1574c78a400676f7189a8fc53c
diff --git a/system/vulkan/goldfish_vulkan.cpp b/system/vulkan/goldfish_vulkan.cpp
index 0fc48e0..4e80c45 100644
--- a/system/vulkan/goldfish_vulkan.cpp
+++ b/system/vulkan/goldfish_vulkan.cpp
@@ -24,6 +24,105 @@
 
 #include "func_table.h"
 
+#include <array>
+#include <bitset>
+#include <mutex>
+
+// Used when there is no Vulkan support on the host.
+// Copied from frameworks/native/vulkan/libvulkan/stubhal.cpp
+namespace vkstubhal {
+
+const size_t kMaxInstances = 32;
+static std::mutex g_instance_mutex;
+static std::bitset<kMaxInstances> g_instance_used(false);
+static std::array<hwvulkan_dispatch_t, kMaxInstances> g_instances;
+
+[[noreturn]] VKAPI_ATTR void NoOp() {
+    LOG_ALWAYS_FATAL("invalid stub function called");
+}
+
+VkResult
+EnumerateInstanceExtensionProperties(const char* /*layer_name*/,
+                                     uint32_t* count,
+                                     VkExtensionProperties* /*properties*/) {
+    *count = 0;
+    return VK_SUCCESS;
+}
+
+VkResult
+EnumerateInstanceLayerProperties(uint32_t* count,
+                                 VkLayerProperties* /*properties*/) {
+    *count = 0;
+    return VK_SUCCESS;
+}
+
+VkResult CreateInstance(const VkInstanceCreateInfo* /*create_info*/,
+                        const VkAllocationCallbacks* /*allocator*/,
+                        VkInstance* instance) {
+    std::lock_guard<std::mutex> lock(g_instance_mutex);
+    for (size_t i = 0; i < kMaxInstances; i++) {
+        if (!g_instance_used[i]) {
+            g_instance_used[i] = true;
+            g_instances[i].magic = HWVULKAN_DISPATCH_MAGIC;
+            *instance = reinterpret_cast<VkInstance>(&g_instances[i]);
+            return VK_SUCCESS;
+        }
+    }
+    ALOGE("no more instances available (max=%zu)", kMaxInstances);
+    return VK_ERROR_INITIALIZATION_FAILED;
+}
+
+void DestroyInstance(VkInstance instance,
+                     const VkAllocationCallbacks* /*allocator*/) {
+    std::lock_guard<std::mutex> lock(g_instance_mutex);
+    ssize_t idx =
+        reinterpret_cast<hwvulkan_dispatch_t*>(instance) - &g_instances[0];
+    ALOG_ASSERT(idx >= 0 && static_cast<size_t>(idx) < g_instance_used.size(),
+                "DestroyInstance: invalid instance handle");
+    g_instance_used[static_cast<size_t>(idx)] = false;
+}
+
+VkResult EnumeratePhysicalDevices(VkInstance /*instance*/,
+                                  uint32_t* count,
+                                  VkPhysicalDevice* /*gpus*/) {
+    *count = 0;
+    return VK_SUCCESS;
+}
+
+VkResult
+EnumeratePhysicalDeviceGroups(VkInstance /*instance*/,
+                              uint32_t* count,
+                              VkPhysicalDeviceGroupProperties* /*properties*/) {
+    *count = 0;
+    return VK_SUCCESS;
+}
+
+PFN_vkVoidFunction GetInstanceProcAddr(VkInstance instance,
+                                       const char* name) {
+    if (strcmp(name, "vkCreateInstance") == 0)
+        return reinterpret_cast<PFN_vkVoidFunction>(CreateInstance);
+    if (strcmp(name, "vkDestroyInstance") == 0)
+        return reinterpret_cast<PFN_vkVoidFunction>(DestroyInstance);
+    if (strcmp(name, "vkEnumerateInstanceExtensionProperties") == 0)
+        return reinterpret_cast<PFN_vkVoidFunction>(
+            EnumerateInstanceExtensionProperties);
+    if (strcmp(name, "vkEnumeratePhysicalDevices") == 0)
+        return reinterpret_cast<PFN_vkVoidFunction>(EnumeratePhysicalDevices);
+    if (strcmp(name, "vkEnumeratePhysicalDeviceGroups") == 0)
+        return reinterpret_cast<PFN_vkVoidFunction>(
+            EnumeratePhysicalDeviceGroups);
+    if (strcmp(name, "vkGetInstanceProcAddr") == 0)
+        return reinterpret_cast<PFN_vkVoidFunction>(GetInstanceProcAddr);
+    // Per the spec, return NULL if instance is NULL.
+    if (!instance)
+        return nullptr;
+    // None of the other Vulkan functions should ever be called, as they all
+    // take a VkPhysicalDevice or other object obtained from a physical device.
+    return reinterpret_cast<PFN_vkVoidFunction>(NoOp);
+}
+
+} // namespace vkstubhal
+
 namespace {
 
 int OpenDevice(const hw_module_t* module, const char* id, hw_device_t** device);
@@ -49,23 +148,24 @@
     return 0;
 }
 
-#define VK_HOST_CONNECTION \
+#define VK_HOST_CONNECTION(ret) \
     HostConnection *hostCon = HostConnection::get(); \
     if (!hostCon) { \
         ALOGE("vulkan: Failed to get host connection\n"); \
-        return VK_ERROR_DEVICE_LOST; \
+        return ret; \
     } \
     ExtendedRCEncoderContext *rcEnc = hostCon->rcEncoder(); \
     if (!rcEnc) { \
         ALOGE("vulkan: Failed to get renderControl encoder context\n"); \
-        return VK_ERROR_DEVICE_LOST; \
+        return ret; \
     } \
     goldfish_vk::VkEncoder *vkEnc = hostCon->vkEncoder(); \
     if (!vkEnc) { \
         ALOGE("vulkan: Failed to get Vulkan encoder\n"); \
-        return VK_ERROR_DEVICE_LOST; \
+        return ret; \
     } \
     goldfish_vk::ResourceTracker::get()->setupFeatures(rcEnc->featureInfo_const()); \
+    auto hostSupportsVulkan = goldfish_vk::ResourceTracker::get()->hostSupportsVulkan(); \
 
 VKAPI_ATTR
 VkResult EnumerateInstanceExtensionProperties(
@@ -73,7 +173,11 @@
     uint32_t* count,
     VkExtensionProperties* properties) {
 
-    VK_HOST_CONNECTION;
+    VK_HOST_CONNECTION(VK_ERROR_DEVICE_LOST)
+
+    if (!hostSupportsVulkan) {
+        return vkstubhal::EnumerateInstanceExtensionProperties(layer_name, count, properties);
+    }
 
     if (layer_name) {
         ALOGW(
@@ -92,8 +196,11 @@
 VkResult CreateInstance(const VkInstanceCreateInfo* create_info,
                         const VkAllocationCallbacks* allocator,
                         VkInstance* out_instance) {
-    ALOGD("%s: goldfish vkCreateInstance\n", __func__);
-    VK_HOST_CONNECTION;
+    VK_HOST_CONNECTION(VK_ERROR_DEVICE_LOST)
+
+    if (!hostSupportsVulkan) {
+        return vkstubhal::CreateInstance(create_info, allocator, out_instance);
+    }
 
     VkResult res = vkEnc->vkCreateInstance(create_info, nullptr, out_instance);
 
@@ -101,6 +208,12 @@
 }
 
 static PFN_vkVoidFunction GetDeviceProcAddr(VkDevice device, const char* name) {
+    VK_HOST_CONNECTION(nullptr)
+
+    if (!hostSupportsVulkan) {
+        return nullptr;
+    }
+
     if (!strcmp(name, "vkGetDeviceProcAddr")) {
         return (PFN_vkVoidFunction)(GetDeviceProcAddr);
     }
@@ -109,6 +222,12 @@
 
 VKAPI_ATTR
 PFN_vkVoidFunction GetInstanceProcAddr(VkInstance instance, const char* name) {
+    VK_HOST_CONNECTION(nullptr)
+
+    if (!hostSupportsVulkan) {
+        return vkstubhal::GetInstanceProcAddr(instance, name);
+    }
+
     if (!strcmp(name, "vkEnumerateInstanceExtensionProperties")) {
         return (PFN_vkVoidFunction)EnumerateInstanceExtensionProperties;
     }
@@ -144,4 +263,4 @@
     return -ENOENT;
 }
 
-} // namespace
\ No newline at end of file
+} // namespace
diff --git a/system/vulkan_enc/ResourceTracker.cpp b/system/vulkan_enc/ResourceTracker.cpp
index a693ebd..3cacf39 100644
--- a/system/vulkan_enc/ResourceTracker.cpp
+++ b/system/vulkan_enc/ResourceTracker.cpp
@@ -328,6 +328,12 @@
         }
     }
 
+    bool hostSupportsVulkan() const {
+        if (!mFeatureInfo) return false;
+
+        return mFeatureInfo->hasVulkan;
+    }
+
     bool usingDirectMapping() const {
         return mHostVisibleMemoryVirtInfo.virtualizationSupported;
     }
@@ -1136,6 +1142,10 @@
     mImpl->setupFeatures(features);
 }
 
+bool ResourceTracker::hostSupportsVulkan() const {
+    return mImpl->hostSupportsVulkan();
+}
+
 bool ResourceTracker::usingDirectMapping() const {
     return mImpl->usingDirectMapping();
 }
diff --git a/system/vulkan_enc/ResourceTracker.h b/system/vulkan_enc/ResourceTracker.h
index cdbb54d..c63dfc0 100644
--- a/system/vulkan_enc/ResourceTracker.h
+++ b/system/vulkan_enc/ResourceTracker.h
@@ -143,6 +143,7 @@
     VkDeviceSize getNonCoherentExtendedSize(VkDevice device, VkDeviceSize basicSize) const;
     bool isValidMemoryRange(const VkMappedMemoryRange& range) const;
     void setupFeatures(const EmulatorFeatureInfo* features);
+    bool hostSupportsVulkan() const;
     bool usingDirectMapping() const;
     void deviceMemoryTransform_tohost(
         VkDeviceMemory* memory, uint32_t memoryCount,
@@ -167,4 +168,4 @@
     std::unique_ptr<Impl> mImpl;
 };
 
-} // namespace goldfish_vk
\ No newline at end of file
+} // namespace goldfish_vk