blob: 7404b94df4c89835486d51d6b971daff0eb8d524 [file] [log] [blame]
/*
* 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 VkResult
EnumeratePhysicalDeviceGroups(VkInstance /*instance*/,
uint32_t* count,
VkPhysicalDeviceGroupProperties* /*properties*/) {
*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, "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);
}
} // 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