1 /* 2 * Copyright 2016 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 /* NOTE: 18 * This stub HAL is only used internally by the loader when a real HAL 19 * implementation is not present, in order to avoid needing "null HAL" checks 20 * throughout the loader. It does not enumerate any physical devices, and is 21 * only as conformant to the Vulkan and Android HAL interfaces as the loader 22 * needs it to be. Do not use it as an example of a correct implementation; the 23 * code in ../null_driver is better for that. 24 */ 25 26 #undef LOG_TAG 27 #define LOG_TAG "vkstub" 28 29 #include <array> 30 #include <bitset> 31 #include <mutex> 32 33 #include <log/log.h> 34 #include <hardware/hwvulkan.h> 35 36 #include "stubhal.h" 37 38 namespace vulkan { 39 namespace stubhal { 40 41 namespace { 42 43 const size_t kMaxInstances = 32; 44 static std::mutex g_instance_mutex; 45 static std::bitset<kMaxInstances> g_instance_used(false); 46 static std::array<hwvulkan_dispatch_t, kMaxInstances> g_instances; 47 48 [[noreturn]] VKAPI_ATTR void NoOp() { 49 LOG_ALWAYS_FATAL("invalid stub function called"); 50 } 51 52 VKAPI_ATTR VkResult 53 EnumerateInstanceExtensionProperties(const char* /*layer_name*/, 54 uint32_t* count, 55 VkExtensionProperties* /*properties*/) { 56 *count = 0; 57 return VK_SUCCESS; 58 } 59 60 VKAPI_ATTR VkResult 61 EnumerateInstanceLayerProperties(uint32_t* count, 62 VkLayerProperties* /*properties*/) { 63 *count = 0; 64 return VK_SUCCESS; 65 } 66 67 VKAPI_ATTR VkResult CreateInstance(const VkInstanceCreateInfo* /*create_info*/, 68 const VkAllocationCallbacks* /*allocator*/, 69 VkInstance* instance) { 70 std::lock_guard<std::mutex> lock(g_instance_mutex); 71 for (size_t i = 0; i < kMaxInstances; i++) { 72 if (!g_instance_used[i]) { 73 g_instance_used[i] = true; 74 g_instances[i].magic = HWVULKAN_DISPATCH_MAGIC; 75 *instance = reinterpret_cast<VkInstance>(&g_instances[i]); 76 return VK_SUCCESS; 77 } 78 } 79 ALOGE("no more instances available (max=%zu)", kMaxInstances); 80 return VK_ERROR_INITIALIZATION_FAILED; 81 } 82 83 VKAPI_ATTR void DestroyInstance(VkInstance instance, 84 const VkAllocationCallbacks* /*allocator*/) { 85 std::lock_guard<std::mutex> lock(g_instance_mutex); 86 ssize_t idx = 87 reinterpret_cast<hwvulkan_dispatch_t*>(instance) - &g_instances[0]; 88 ALOG_ASSERT(idx >= 0 && static_cast<size_t>(idx) < g_instance_used.size(), 89 "DestroyInstance: invalid instance handle"); 90 g_instance_used[static_cast<size_t>(idx)] = false; 91 } 92 93 VKAPI_ATTR VkResult EnumeratePhysicalDevices(VkInstance /*instance*/, 94 uint32_t* count, 95 VkPhysicalDevice* /*gpus*/) { 96 *count = 0; 97 return VK_SUCCESS; 98 } 99 100 VKAPI_ATTR VkResult 101 EnumeratePhysicalDeviceGroups(VkInstance /*instance*/, 102 uint32_t* count, 103 VkPhysicalDeviceGroupProperties* /*properties*/) { 104 *count = 0; 105 return VK_SUCCESS; 106 } 107 108 VKAPI_ATTR PFN_vkVoidFunction GetInstanceProcAddr(VkInstance instance, 109 const char* name) { 110 if (strcmp(name, "vkCreateInstance") == 0) 111 return reinterpret_cast<PFN_vkVoidFunction>(CreateInstance); 112 if (strcmp(name, "vkDestroyInstance") == 0) 113 return reinterpret_cast<PFN_vkVoidFunction>(DestroyInstance); 114 if (strcmp(name, "vkEnumerateInstanceExtensionProperties") == 0) 115 return reinterpret_cast<PFN_vkVoidFunction>( 116 EnumerateInstanceExtensionProperties); 117 if (strcmp(name, "vkEnumeratePhysicalDevices") == 0) 118 return reinterpret_cast<PFN_vkVoidFunction>(EnumeratePhysicalDevices); 119 if (strcmp(name, "vkEnumeratePhysicalDeviceGroups") == 0) 120 return reinterpret_cast<PFN_vkVoidFunction>( 121 EnumeratePhysicalDeviceGroups); 122 if (strcmp(name, "vkGetInstanceProcAddr") == 0) 123 return reinterpret_cast<PFN_vkVoidFunction>(GetInstanceProcAddr); 124 // Per the spec, return NULL if instance is NULL. 125 if (!instance) 126 return nullptr; 127 // None of the other Vulkan functions should ever be called, as they all 128 // take a VkPhysicalDevice or other object obtained from a physical device. 129 return reinterpret_cast<PFN_vkVoidFunction>(NoOp); 130 } 131 132 } // anonymous namespace 133 134 const hwvulkan_device_t kDevice = { 135 .common = 136 { 137 .tag = HARDWARE_DEVICE_TAG, 138 .version = HWVULKAN_DEVICE_API_VERSION_0_1, 139 .module = nullptr, 140 .close = nullptr, 141 }, 142 .EnumerateInstanceExtensionProperties = 143 EnumerateInstanceExtensionProperties, 144 .CreateInstance = CreateInstance, 145 .GetInstanceProcAddr = GetInstanceProcAddr, 146 }; 147 148 } // namespace stubhal 149 } // namespace vulkan 150