|  | /* | 
|  | * Copyright 2016 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. | 
|  | */ | 
|  |  | 
|  | /* NOTE: | 
|  | * This stub HAL is only used internally by the loader when a real HAL | 
|  | * implementation is not present, in order to avoid needing "null HAL" checks | 
|  | * throughout the loader. It does not enumerate any physical devices, and is | 
|  | * only as conformant to the Vulkan and Android HAL interfaces as the loader | 
|  | * needs it to be. Do not use it as an example of a correct implementation; the | 
|  | * code in ../null_driver is better for that. | 
|  | */ | 
|  |  | 
|  | #undef LOG_TAG | 
|  | #define LOG_TAG "vkstub" | 
|  |  | 
|  | #include <array> | 
|  | #include <bitset> | 
|  | #include <mutex> | 
|  |  | 
|  | #include <log/log.h> | 
|  | #include <hardware/hwvulkan.h> | 
|  |  | 
|  | #include "stubhal.h" | 
|  |  | 
|  | namespace vulkan { | 
|  | namespace stubhal { | 
|  |  | 
|  | namespace { | 
|  |  | 
|  | 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"); | 
|  | } | 
|  |  | 
|  | VKAPI_ATTR VkResult | 
|  | EnumerateInstanceExtensionProperties(const char* /*layer_name*/, | 
|  | uint32_t* count, | 
|  | VkExtensionProperties* /*properties*/) { | 
|  | *count = 0; | 
|  | return VK_SUCCESS; | 
|  | } | 
|  |  | 
|  | VKAPI_ATTR VkResult | 
|  | EnumerateInstanceLayerProperties(uint32_t* count, | 
|  | VkLayerProperties* /*properties*/) { | 
|  | *count = 0; | 
|  | return VK_SUCCESS; | 
|  | } | 
|  |  | 
|  | VKAPI_ATTR 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; | 
|  | } | 
|  |  | 
|  | VKAPI_ATTR 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; | 
|  | } | 
|  |  | 
|  | VKAPI_ATTR VkResult EnumeratePhysicalDevices(VkInstance /*instance*/, | 
|  | uint32_t* count, | 
|  | VkPhysicalDevice* /*gpus*/) { | 
|  | *count = 0; | 
|  | return VK_SUCCESS; | 
|  | } | 
|  |  | 
|  | VKAPI_ATTR 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, "vkGetInstanceProcAddr") == 0) | 
|  | return reinterpret_cast<PFN_vkVoidFunction>(GetInstanceProcAddr); | 
|  |  | 
|  | // 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); | 
|  | } | 
|  |  | 
|  | }  // anonymous namespace | 
|  |  | 
|  | const hwvulkan_device_t kDevice = { | 
|  | .common = | 
|  | { | 
|  | .tag = HARDWARE_DEVICE_TAG, | 
|  | .version = HWVULKAN_DEVICE_API_VERSION_0_1, | 
|  | .module = nullptr, | 
|  | .close = nullptr, | 
|  | }, | 
|  | .EnumerateInstanceExtensionProperties = | 
|  | EnumerateInstanceExtensionProperties, | 
|  | .CreateInstance = CreateInstance, | 
|  | .GetInstanceProcAddr = GetInstanceProcAddr, | 
|  | }; | 
|  |  | 
|  | }  // namespace stubhal | 
|  | }  // namespace vulkan |