/* * Copyright 2015 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. */ // module header #include "loader.h" #include "driver.h" // standard C headers #include #include #include #include #include #include #include // standard C++ headers #include #include #include #include #include #include // platform/library headers #include #include #include #include #include // #define ENABLE_ALLOC_CALLSTACKS 1 #if ENABLE_ALLOC_CALLSTACKS #include #define ALOGD_CALLSTACK(...) \ do { \ ALOGD(__VA_ARGS__); \ android::CallStack callstack; \ callstack.update(); \ callstack.log(LOG_TAG, ANDROID_LOG_DEBUG, " "); \ } while (false) #else #define ALOGD_CALLSTACK(...) \ do { \ } while (false) #endif using namespace vulkan; static const uint32_t kMaxPhysicalDevices = 4; namespace { // ---------------------------------------------------------------------------- // Standard-library allocator that delegates to VkAllocationCallbacks. // // TODO(jessehall): This class currently always uses // VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE. The scope to use could be a template // parameter or a constructor parameter. The former would help catch bugs // where we use the wrong scope, e.g. adding a command-scope string to an // instance-scope vector. But that might also be pretty annoying to deal with. template class CallbackAllocator { public: typedef T value_type; CallbackAllocator(const VkAllocationCallbacks* alloc_input) : alloc(alloc_input) {} template CallbackAllocator(const CallbackAllocator& other) : alloc(other.alloc) {} T* allocate(std::size_t n) { void* mem = alloc->pfnAllocation(alloc->pUserData, n * sizeof(T), alignof(T), VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE); if (!mem) throw std::bad_alloc(); return static_cast(mem); } void deallocate(T* array, std::size_t /*n*/) noexcept { alloc->pfnFree(alloc->pUserData, array); } const VkAllocationCallbacks* alloc; }; // These are needed in order to move Strings template bool operator==(const CallbackAllocator& alloc1, const CallbackAllocator& alloc2) { return alloc1.alloc == alloc2.alloc; } template bool operator!=(const CallbackAllocator& alloc1, const CallbackAllocator& alloc2) { return !(alloc1 == alloc2); } template using Vector = std::vector>; typedef std::basic_string, CallbackAllocator> String; // ---------------------------------------------------------------------------- VKAPI_ATTR void* DefaultAllocate(void*, size_t size, size_t alignment, VkSystemAllocationScope) { void* ptr = nullptr; // Vulkan requires 'alignment' to be a power of two, but posix_memalign // additionally requires that it be at least sizeof(void*). int ret = posix_memalign(&ptr, std::max(alignment, sizeof(void*)), size); ALOGD_CALLSTACK("Allocate: size=%zu align=%zu => (%d) %p", size, alignment, ret, ptr); return ret == 0 ? ptr : nullptr; } VKAPI_ATTR void* DefaultReallocate(void*, void* ptr, size_t size, size_t alignment, VkSystemAllocationScope) { if (size == 0) { free(ptr); return nullptr; } // TODO(jessehall): Right now we never shrink allocations; if the new // request is smaller than the existing chunk, we just continue using it. // Right now the loader never reallocs, so this doesn't matter. If that // changes, or if this code is copied into some other project, this should // probably have a heuristic to allocate-copy-free when doing so will save // "enough" space. size_t old_size = ptr ? malloc_usable_size(ptr) : 0; if (size <= old_size) return ptr; void* new_ptr = nullptr; if (posix_memalign(&new_ptr, std::max(alignment, sizeof(void*)), size) != 0) return nullptr; if (ptr) { memcpy(new_ptr, ptr, std::min(old_size, size)); free(ptr); } return new_ptr; } VKAPI_ATTR void DefaultFree(void*, void* ptr) { ALOGD_CALLSTACK("Free: %p", ptr); free(ptr); } const VkAllocationCallbacks kDefaultAllocCallbacks = { .pUserData = nullptr, .pfnAllocation = DefaultAllocate, .pfnReallocation = DefaultReallocate, .pfnFree = DefaultFree, }; // ---------------------------------------------------------------------------- // Global Data and Initialization hwvulkan_device_t* g_hwdevice = nullptr; InstanceExtensionSet g_driver_instance_extensions; void LoadVulkanHAL() { static const hwvulkan_module_t* module; int result = hw_get_module("vulkan", reinterpret_cast(&module)); if (result != 0) { ALOGE("failed to load vulkan hal: %s (%d)", strerror(-result), result); return; } result = module->common.methods->open( &module->common, HWVULKAN_DEVICE_0, reinterpret_cast(&g_hwdevice)); if (result != 0) { ALOGE("failed to open vulkan driver: %s (%d)", strerror(-result), result); module = nullptr; return; } VkResult vkresult; uint32_t count; if ((vkresult = g_hwdevice->EnumerateInstanceExtensionProperties( nullptr, &count, nullptr)) != VK_SUCCESS) { ALOGE("driver EnumerateInstanceExtensionProperties failed: %d", vkresult); g_hwdevice->common.close(&g_hwdevice->common); g_hwdevice = nullptr; module = nullptr; return; } VkExtensionProperties* extensions = static_cast( alloca(count * sizeof(VkExtensionProperties))); if ((vkresult = g_hwdevice->EnumerateInstanceExtensionProperties( nullptr, &count, extensions)) != VK_SUCCESS) { ALOGE("driver EnumerateInstanceExtensionProperties failed: %d", vkresult); g_hwdevice->common.close(&g_hwdevice->common); g_hwdevice = nullptr; module = nullptr; return; } ALOGV_IF(count > 0, "Driver-supported instance extensions:"); for (uint32_t i = 0; i < count; i++) { ALOGV(" %s (v%u)", extensions[i].extensionName, extensions[i].specVersion); InstanceExtension id = InstanceExtensionFromName(extensions[i].extensionName); if (id != kInstanceExtensionCount) g_driver_instance_extensions.set(id); } // Ignore driver attempts to support loader extensions g_driver_instance_extensions.reset(kKHR_surface); g_driver_instance_extensions.reset(kKHR_android_surface); } // ----------------------------------------------------------------------------- struct Instance { Instance(const VkAllocationCallbacks* alloc_callbacks) : base{{}, *alloc_callbacks}, alloc(&base.allocator), num_physical_devices(0) { memset(physical_devices, 0, sizeof(physical_devices)); enabled_extensions.reset(); memset(&drv.dispatch, 0, sizeof(drv.dispatch)); } ~Instance() {} driver::InstanceData base; const VkAllocationCallbacks* alloc; uint32_t num_physical_devices; VkPhysicalDevice physical_devices_top[kMaxPhysicalDevices]; VkPhysicalDevice physical_devices[kMaxPhysicalDevices]; DeviceExtensionSet physical_device_driver_extensions[kMaxPhysicalDevices]; DebugReportCallbackList debug_report_callbacks; InstanceExtensionSet enabled_extensions; struct { DriverDispatchTable dispatch; } drv; // may eventually be an array }; struct Device { Device(Instance* instance_) : base{{}, *instance_->alloc}, instance(instance_) { enabled_extensions.reset(); } driver::DeviceData base; Instance* instance; PFN_vkGetDeviceProcAddr get_device_proc_addr; DeviceExtensionSet enabled_extensions; }; template struct HandleTraits {}; template <> struct HandleTraits { typedef Instance LoaderObjectType; }; template <> struct HandleTraits { typedef Instance LoaderObjectType; }; template <> struct HandleTraits { typedef Device LoaderObjectType; }; template <> struct HandleTraits { typedef Device LoaderObjectType; }; template <> struct HandleTraits { typedef Device LoaderObjectType; }; template typename HandleTraits::LoaderObjectType& GetDispatchParent( THandle handle) { // TODO(jessehall): Make Instance and Device POD types (by removing the // non-default constructors), so that offsetof is actually legal to use. // The specific case we're using here is safe in gcc/clang (and probably // most other C++ compilers), but isn't guaranteed by C++. typedef typename HandleTraits::LoaderObjectType ObjectType; #pragma clang diagnostic push #pragma clang diagnostic ignored "-Winvalid-offsetof" const size_t kBaseOffset = offsetof(ObjectType, base); #pragma clang diagnostic pop const auto& base = driver::GetData(handle); uintptr_t base_addr = reinterpret_cast(&base); uintptr_t object_addr = base_addr - kBaseOffset; return *reinterpret_cast(object_addr); } // ----------------------------------------------------------------------------- void DestroyDevice(Device* device, VkDevice vkdevice) { const auto& instance = *device->instance; if (vkdevice != VK_NULL_HANDLE) instance.drv.dispatch.DestroyDevice(vkdevice, instance.alloc); device->~Device(); instance.alloc->pfnFree(instance.alloc->pUserData, device); } /* * This function will return the pNext pointer of any * CreateInfo extensions that are not loader extensions. * This is used to skip past the loader extensions prepended * to the list during CreateInstance and CreateDevice. */ void* StripCreateExtensions(const void* pNext) { VkLayerInstanceCreateInfo* create_info = const_cast( static_cast(pNext)); while ( create_info && (create_info->sType == VK_STRUCTURE_TYPE_LOADER_INSTANCE_CREATE_INFO || create_info->sType == VK_STRUCTURE_TYPE_LOADER_DEVICE_CREATE_INFO)) { create_info = const_cast( static_cast(create_info->pNext)); } return create_info; } // Clean up and deallocate an Instance; called from both the failure paths in // CreateInstance_Top as well as from DestroyInstance_Top. This function does // not call down the dispatch chain; that should be done before calling this // function, iff the lower vkCreateInstance call has been made and returned // successfully. void DestroyInstance(Instance* instance, const VkAllocationCallbacks* allocator, VkInstance vkinstance) { if (vkinstance != VK_NULL_HANDLE && instance->drv.dispatch.DestroyInstance) instance->drv.dispatch.DestroyInstance(vkinstance, allocator); instance->~Instance(); allocator->pfnFree(allocator->pUserData, instance); } } // anonymous namespace namespace vulkan { // ----------------------------------------------------------------------------- // "Bottom" functions. These are called at the end of the instance dispatch // chain. VkResult CreateInstance_Bottom(const VkInstanceCreateInfo* create_info, const VkAllocationCallbacks* allocator, VkInstance* vkinstance) { VkResult result; if (!allocator) allocator = &kDefaultAllocCallbacks; void* instance_mem = allocator->pfnAllocation( allocator->pUserData, sizeof(Instance), alignof(Instance), VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE); if (!instance_mem) return VK_ERROR_OUT_OF_HOST_MEMORY; Instance& instance = *new (instance_mem) Instance(allocator); // Check that all enabled extensions are supported uint32_t num_driver_extensions = 0; for (uint32_t i = 0; i < create_info->enabledExtensionCount; i++) { const char* name = create_info->ppEnabledExtensionNames[i]; InstanceExtension id = InstanceExtensionFromName(name); if (id != kInstanceExtensionCount) { if (g_driver_instance_extensions[id]) { num_driver_extensions++; instance.enabled_extensions.set(id); continue; } if (id == kKHR_surface || id == kKHR_android_surface) { instance.enabled_extensions.set(id); continue; } // The loader natively supports debug report. if (id == kEXT_debug_report) { continue; } } } VkInstanceCreateInfo driver_create_info = *create_info; driver_create_info.pNext = StripCreateExtensions(create_info->pNext); driver_create_info.enabledLayerCount = 0; driver_create_info.ppEnabledLayerNames = nullptr; driver_create_info.enabledExtensionCount = 0; driver_create_info.ppEnabledExtensionNames = nullptr; if (num_driver_extensions > 0) { const char** names = static_cast( alloca(num_driver_extensions * sizeof(char*))); for (uint32_t i = 0; i < create_info->enabledExtensionCount; i++) { const char* name = create_info->ppEnabledExtensionNames[i]; InstanceExtension id = InstanceExtensionFromName(name); if (id != kInstanceExtensionCount) { if (g_driver_instance_extensions[id]) { names[driver_create_info.enabledExtensionCount++] = name; continue; } } } driver_create_info.ppEnabledExtensionNames = names; ALOG_ASSERT( driver_create_info.enabledExtensionCount == num_driver_extensions, "counted enabled driver instance extensions twice and got " "different answers!"); } VkInstance drv_instance; result = g_hwdevice->CreateInstance(&driver_create_info, instance.alloc, &drv_instance); if (result != VK_SUCCESS) { DestroyInstance(&instance, allocator, VK_NULL_HANDLE); return result; } if (!driver::SetData(drv_instance, instance.base)) { DestroyInstance(&instance, allocator, drv_instance); return VK_ERROR_INITIALIZATION_FAILED; } if (!LoadDriverDispatchTable(drv_instance, g_hwdevice->GetInstanceProcAddr, instance.enabled_extensions, instance.drv.dispatch)) { DestroyInstance(&instance, allocator, drv_instance); return VK_ERROR_INITIALIZATION_FAILED; } uint32_t num_physical_devices = 0; result = instance.drv.dispatch.EnumeratePhysicalDevices( drv_instance, &num_physical_devices, nullptr); if (result != VK_SUCCESS) { DestroyInstance(&instance, allocator, drv_instance); return VK_ERROR_INITIALIZATION_FAILED; } num_physical_devices = std::min(num_physical_devices, kMaxPhysicalDevices); result = instance.drv.dispatch.EnumeratePhysicalDevices( drv_instance, &num_physical_devices, instance.physical_devices); if (result != VK_SUCCESS) { DestroyInstance(&instance, allocator, drv_instance); return VK_ERROR_INITIALIZATION_FAILED; } Vector extensions( Vector::allocator_type(instance.alloc)); for (uint32_t i = 0; i < num_physical_devices; i++) { if (!driver::SetData(instance.physical_devices[i], instance.base)) { DestroyInstance(&instance, allocator, drv_instance); return VK_ERROR_INITIALIZATION_FAILED; } uint32_t count; if ((result = instance.drv.dispatch.EnumerateDeviceExtensionProperties( instance.physical_devices[i], nullptr, &count, nullptr)) != VK_SUCCESS) { ALOGW("driver EnumerateDeviceExtensionProperties(%u) failed: %d", i, result); continue; } try { extensions.resize(count); } catch (std::bad_alloc&) { ALOGE("instance creation failed: out of memory"); DestroyInstance(&instance, allocator, drv_instance); return VK_ERROR_OUT_OF_HOST_MEMORY; } if ((result = instance.drv.dispatch.EnumerateDeviceExtensionProperties( instance.physical_devices[i], nullptr, &count, extensions.data())) != VK_SUCCESS) { ALOGW("driver EnumerateDeviceExtensionProperties(%u) failed: %d", i, result); continue; } ALOGV_IF(count > 0, "driver gpu[%u] supports extensions:", i); for (const auto& extension : extensions) { ALOGV(" %s (v%u)", extension.extensionName, extension.specVersion); DeviceExtension id = DeviceExtensionFromName(extension.extensionName); if (id == kDeviceExtensionCount) { ALOGW("driver gpu[%u] extension '%s' unknown to loader", i, extension.extensionName); } else { instance.physical_device_driver_extensions[i].set(id); } } // Ignore driver attempts to support loader extensions instance.physical_device_driver_extensions[i].reset(kKHR_swapchain); } instance.num_physical_devices = num_physical_devices; *vkinstance = drv_instance; return VK_SUCCESS; } VkResult CreateAndroidSurfaceKHR_Disabled(VkInstance, const VkAndroidSurfaceCreateInfoKHR*, const VkAllocationCallbacks*, VkSurfaceKHR*) { ALOGE( "VK_KHR_android_surface not enabled. vkCreateAndroidSurfaceKHR not " "executed."); return VK_SUCCESS; } void DestroySurfaceKHR_Disabled(VkInstance, VkSurfaceKHR, const VkAllocationCallbacks*) { ALOGE("VK_KHR_surface not enabled. vkDestroySurfaceKHR not executed."); } VkResult GetPhysicalDeviceSurfaceSupportKHR_Disabled(VkPhysicalDevice, uint32_t, VkSurfaceKHR, VkBool32*) { ALOGE( "VK_KHR_surface not enabled. vkGetPhysicalDeviceSurfaceSupportKHR not " "executed."); return VK_SUCCESS; } VkResult GetPhysicalDeviceSurfaceCapabilitiesKHR_Disabled( VkPhysicalDevice, VkSurfaceKHR, VkSurfaceCapabilitiesKHR*) { ALOGE( "VK_KHR_surface not enabled. vkGetPhysicalDeviceSurfaceapabilitiesKHR " "not executed."); return VK_SUCCESS; } VkResult GetPhysicalDeviceSurfaceFormatsKHR_Disabled(VkPhysicalDevice, VkSurfaceKHR, uint32_t*, VkSurfaceFormatKHR*) { ALOGE( "VK_KHR_surface not enabled. vkGetPhysicalDeviceSurfaceFormatsKHR not " "executed."); return VK_SUCCESS; } VkResult GetPhysicalDeviceSurfacePresentModesKHR_Disabled(VkPhysicalDevice, VkSurfaceKHR, uint32_t*, VkPresentModeKHR*) { ALOGE( "VK_KHR_surface not enabled. vkGetPhysicalDeviceSurfacePresentModesKHR " "not executed."); return VK_SUCCESS; } PFN_vkVoidFunction GetInstanceProcAddr_Bottom(VkInstance vkinstance, const char* name) { PFN_vkVoidFunction pfn; if (vkinstance) { Instance& instance = GetDispatchParent(vkinstance); if (!instance.enabled_extensions[kKHR_android_surface]) { // KHR_android_surface is not enabled, use error stubs instead if (strcmp(name, "vkCreateAndroidSurfaceKHR") == 0) { return reinterpret_cast( CreateAndroidSurfaceKHR_Disabled); } } if (!instance.enabled_extensions[kKHR_surface]) { // KHR_surface is not enabled, use error stubs instead if (strcmp(name, "vkDestroySurfaceKHR") == 0) { return reinterpret_cast( DestroySurfaceKHR_Disabled); } if (strcmp(name, "vkGetPhysicalDeviceSurfaceSupportKHR") == 0) { return reinterpret_cast( GetPhysicalDeviceSurfaceSupportKHR_Disabled); } if (strcmp(name, "vkGetPhysicalDeviceSurfaceCapabilitiesKHR") == 0) { return reinterpret_cast( GetPhysicalDeviceSurfaceCapabilitiesKHR_Disabled); } if (strcmp(name, "vkGetPhysicalDeviceSurfaceFormatsKHR") == 0) { return reinterpret_cast( GetPhysicalDeviceSurfaceFormatsKHR_Disabled); } if (strcmp(name, "vkGetPhysicalDeviceSurfacePresentModesKHR") == 0) { return reinterpret_cast( GetPhysicalDeviceSurfacePresentModesKHR_Disabled); } } } if ((pfn = GetLoaderBottomProcAddr(name))) return pfn; return g_hwdevice->GetInstanceProcAddr(vkinstance, name); } VkResult EnumeratePhysicalDevices_Bottom(VkInstance vkinstance, uint32_t* pdev_count, VkPhysicalDevice* pdevs) { Instance& instance = GetDispatchParent(vkinstance); uint32_t count = instance.num_physical_devices; if (pdevs) { count = std::min(count, *pdev_count); std::copy(instance.physical_devices, instance.physical_devices + count, pdevs); } *pdev_count = count; return VK_SUCCESS; } void GetPhysicalDeviceProperties_Bottom( VkPhysicalDevice pdev, VkPhysicalDeviceProperties* properties) { GetDispatchParent(pdev).drv.dispatch.GetPhysicalDeviceProperties( pdev, properties); } void GetPhysicalDeviceFeatures_Bottom(VkPhysicalDevice pdev, VkPhysicalDeviceFeatures* features) { GetDispatchParent(pdev).drv.dispatch.GetPhysicalDeviceFeatures(pdev, features); } void GetPhysicalDeviceMemoryProperties_Bottom( VkPhysicalDevice pdev, VkPhysicalDeviceMemoryProperties* properties) { GetDispatchParent(pdev).drv.dispatch.GetPhysicalDeviceMemoryProperties( pdev, properties); } void GetPhysicalDeviceQueueFamilyProperties_Bottom( VkPhysicalDevice pdev, uint32_t* pCount, VkQueueFamilyProperties* properties) { GetDispatchParent(pdev).drv.dispatch.GetPhysicalDeviceQueueFamilyProperties( pdev, pCount, properties); } void GetPhysicalDeviceFormatProperties_Bottom(VkPhysicalDevice pdev, VkFormat format, VkFormatProperties* properties) { GetDispatchParent(pdev).drv.dispatch.GetPhysicalDeviceFormatProperties( pdev, format, properties); } VkResult GetPhysicalDeviceImageFormatProperties_Bottom( VkPhysicalDevice pdev, VkFormat format, VkImageType type, VkImageTiling tiling, VkImageUsageFlags usage, VkImageCreateFlags flags, VkImageFormatProperties* properties) { return GetDispatchParent(pdev) .drv.dispatch.GetPhysicalDeviceImageFormatProperties( pdev, format, type, tiling, usage, flags, properties); } void GetPhysicalDeviceSparseImageFormatProperties_Bottom( VkPhysicalDevice pdev, VkFormat format, VkImageType type, VkSampleCountFlagBits samples, VkImageUsageFlags usage, VkImageTiling tiling, uint32_t* properties_count, VkSparseImageFormatProperties* properties) { GetDispatchParent(pdev) .drv.dispatch.GetPhysicalDeviceSparseImageFormatProperties( pdev, format, type, samples, usage, tiling, properties_count, properties); } VKAPI_ATTR VkResult EnumerateDeviceExtensionProperties_Bottom( VkPhysicalDevice pdev, const char* layer_name, uint32_t* properties_count, VkExtensionProperties* properties) { (void)layer_name; Instance& instance = GetDispatchParent(pdev); size_t gpu_idx = 0; while (instance.physical_devices[gpu_idx] != pdev) gpu_idx++; const DeviceExtensionSet driver_extensions = instance.physical_device_driver_extensions[gpu_idx]; // We only support VK_KHR_swapchain if the GPU supports // VK_ANDROID_native_buffer VkExtensionProperties* available = static_cast( alloca(kDeviceExtensionCount * sizeof(VkExtensionProperties))); uint32_t num_extensions = 0; if (driver_extensions[kANDROID_native_buffer]) { available[num_extensions++] = VkExtensionProperties{ VK_KHR_SWAPCHAIN_EXTENSION_NAME, VK_KHR_SWAPCHAIN_SPEC_VERSION}; } if (!properties || *properties_count > num_extensions) *properties_count = num_extensions; if (properties) std::copy(available, available + *properties_count, properties); return *properties_count < num_extensions ? VK_INCOMPLETE : VK_SUCCESS; } // This is a no-op, the Top function returns the aggregate layer property // data. This is to keep the dispatch generator happy. VKAPI_ATTR VkResult EnumerateDeviceLayerProperties_Bottom( VkPhysicalDevice /*pdev*/, uint32_t* /*properties_count*/, VkLayerProperties* /*properties*/) { return VK_SUCCESS; } VKAPI_ATTR VkResult CreateDevice_Bottom(VkPhysicalDevice gpu, const VkDeviceCreateInfo* create_info, const VkAllocationCallbacks* allocator, VkDevice* device_out) { Instance& instance = GetDispatchParent(gpu); // FIXME(jessehall): We don't have good conventions or infrastructure yet to // do better than just using the instance allocator and scope for // everything. See b/26732122. if (true /*!allocator*/) allocator = instance.alloc; void* mem = allocator->pfnAllocation(allocator->pUserData, sizeof(Device), alignof(Device), VK_SYSTEM_ALLOCATION_SCOPE_DEVICE); if (!mem) return VK_ERROR_OUT_OF_HOST_MEMORY; Device* device = new (mem) Device(&instance); size_t gpu_idx = 0; while (instance.physical_devices[gpu_idx] != gpu) gpu_idx++; VkDeviceCreateInfo driver_create_info = *create_info; driver_create_info.pNext = StripCreateExtensions(create_info->pNext); driver_create_info.enabledLayerCount = 0; driver_create_info.ppEnabledLayerNames = nullptr; uint32_t num_driver_extensions = 0; const char** driver_extensions = static_cast( alloca(create_info->enabledExtensionCount * sizeof(const char*))); for (uint32_t i = 0; i < create_info->enabledExtensionCount; i++) { const char* name = create_info->ppEnabledExtensionNames[i]; DeviceExtension id = DeviceExtensionFromName(name); if (id != kDeviceExtensionCount) { if (instance.physical_device_driver_extensions[gpu_idx][id]) { driver_extensions[num_driver_extensions++] = name; device->enabled_extensions.set(id); continue; } // Add the VK_ANDROID_native_buffer extension to the list iff // the VK_KHR_swapchain extension was requested if (id == kKHR_swapchain && instance.physical_device_driver_extensions [gpu_idx][kANDROID_native_buffer]) { driver_extensions[num_driver_extensions++] = VK_ANDROID_NATIVE_BUFFER_EXTENSION_NAME; device->enabled_extensions.set(id); continue; } } } driver_create_info.enabledExtensionCount = num_driver_extensions; driver_create_info.ppEnabledExtensionNames = driver_extensions; VkDevice drv_device; VkResult result = instance.drv.dispatch.CreateDevice( gpu, &driver_create_info, allocator, &drv_device); if (result != VK_SUCCESS) { DestroyDevice(device, VK_NULL_HANDLE); return VK_ERROR_INITIALIZATION_FAILED; } if (!driver::SetData(drv_device, device->base)) { DestroyDevice(device, drv_device); return VK_ERROR_INITIALIZATION_FAILED; } device->get_device_proc_addr = reinterpret_cast( instance.drv.dispatch.GetDeviceProcAddr(drv_device, "vkGetDeviceProcAddr")); *device_out = drv_device; return VK_SUCCESS; } void DestroyInstance_Bottom(VkInstance vkinstance, const VkAllocationCallbacks* allocator) { Instance& instance = GetDispatchParent(vkinstance); VkAllocationCallbacks local_allocator; if (!allocator) { local_allocator = *instance.alloc; allocator = &local_allocator; } DestroyInstance(&instance, allocator, vkinstance); } VkResult CreateSwapchainKHR_Disabled(VkDevice, const VkSwapchainCreateInfoKHR*, const VkAllocationCallbacks*, VkSwapchainKHR*) { ALOGE("VK_KHR_swapchain not enabled. vkCreateSwapchainKHR not executed."); return VK_SUCCESS; } void DestroySwapchainKHR_Disabled(VkDevice, VkSwapchainKHR, const VkAllocationCallbacks*) { ALOGE("VK_KHR_swapchain not enabled. vkDestroySwapchainKHR not executed."); } VkResult GetSwapchainImagesKHR_Disabled(VkDevice, VkSwapchainKHR, uint32_t*, VkImage*) { ALOGE( "VK_KHR_swapchain not enabled. vkGetSwapchainImagesKHR not executed."); return VK_SUCCESS; } VkResult AcquireNextImageKHR_Disabled(VkDevice, VkSwapchainKHR, uint64_t, VkSemaphore, VkFence, uint32_t*) { ALOGE("VK_KHR_swapchain not enabled. vkAcquireNextImageKHR not executed."); return VK_SUCCESS; } VkResult QueuePresentKHR_Disabled(VkQueue, const VkPresentInfoKHR*) { ALOGE("VK_KHR_swapchain not enabled. vkQueuePresentKHR not executed."); return VK_SUCCESS; } PFN_vkVoidFunction GetDeviceProcAddr_Bottom(VkDevice vkdevice, const char* name) { if (strcmp(name, "vkCreateDevice") == 0) { return reinterpret_cast(CreateDevice_Bottom); } Device& device = GetDispatchParent(vkdevice); if (!device.enabled_extensions[kKHR_swapchain]) { if (strcmp(name, "vkCreateSwapchainKHR") == 0) { return reinterpret_cast( CreateSwapchainKHR_Disabled); } if (strcmp(name, "vkDestroySwapchainKHR") == 0) { return reinterpret_cast( DestroySwapchainKHR_Disabled); } if (strcmp(name, "vkGetSwapchainImagesKHR") == 0) { return reinterpret_cast( GetSwapchainImagesKHR_Disabled); } if (strcmp(name, "vkAcquireNextSwapchainImageKHR") == 0) { return reinterpret_cast( AcquireNextImageKHR_Disabled); } if (strcmp(name, "vkQueuePresentKHR") == 0) { return reinterpret_cast( QueuePresentKHR_Disabled); } } // VK_ANDROID_native_buffer should be hidden from applications and layers. // TODO(jessehall): Generate this as part of GetLoaderBottomProcAddr. PFN_vkVoidFunction pfn; if (strcmp(name, "vkGetSwapchainGrallocUsageANDROID") == 0 || strcmp(name, "vkAcquireImageANDROID") == 0 || strcmp(name, "vkQueueSignalReleaseImageANDROID") == 0) { return nullptr; } if ((pfn = GetLoaderBottomProcAddr(name))) return pfn; return GetDispatchParent(vkdevice).get_device_proc_addr(vkdevice, name); } void DestroyDevice_Bottom(VkDevice vkdevice, const VkAllocationCallbacks*) { DestroyDevice(&GetDispatchParent(vkdevice), vkdevice); } void GetDeviceQueue_Bottom(VkDevice vkdevice, uint32_t family, uint32_t index, VkQueue* queue_out) { const auto& device = GetDispatchParent(vkdevice); const auto& instance = *device.instance; instance.drv.dispatch.GetDeviceQueue(vkdevice, family, index, queue_out); driver::SetData(*queue_out, device.base); } VkResult AllocateCommandBuffers_Bottom( VkDevice vkdevice, const VkCommandBufferAllocateInfo* alloc_info, VkCommandBuffer* cmdbufs) { const auto& device = GetDispatchParent(vkdevice); const auto& instance = *device.instance; VkResult result = instance.drv.dispatch.AllocateCommandBuffers( vkdevice, alloc_info, cmdbufs); if (result == VK_SUCCESS) { for (uint32_t i = 0; i < alloc_info->commandBufferCount; i++) driver::SetData(cmdbufs[i], device.base); } return result; } // ----------------------------------------------------------------------------- const VkAllocationCallbacks* GetAllocator(VkInstance vkinstance) { return GetDispatchParent(vkinstance).alloc; } const VkAllocationCallbacks* GetAllocator(VkDevice vkdevice) { return GetDispatchParent(vkdevice).instance->alloc; } VkInstance GetDriverInstance(VkInstance instance) { return instance; } const DriverDispatchTable& GetDriverDispatch(VkInstance instance) { return GetDispatchParent(instance).drv.dispatch; } const DriverDispatchTable& GetDriverDispatch(VkDevice device) { return GetDispatchParent(device).instance->drv.dispatch; } const DriverDispatchTable& GetDriverDispatch(VkQueue queue) { return GetDispatchParent(queue).instance->drv.dispatch; } DebugReportCallbackList& GetDebugReportCallbacks(VkInstance instance) { return GetDispatchParent(instance).debug_report_callbacks; } namespace driver { bool Debuggable() { return (prctl(PR_GET_DUMPABLE, 0, 0, 0, 0) >= 0); } bool OpenHAL() { if (!g_hwdevice) LoadVulkanHAL(); return (g_hwdevice != nullptr); } const VkAllocationCallbacks& GetDefaultAllocator() { return kDefaultAllocCallbacks; } PFN_vkVoidFunction GetInstanceProcAddr(VkInstance instance, const char* pName) { return GetInstanceProcAddr_Bottom(instance, pName); } PFN_vkVoidFunction GetDeviceProcAddr(VkDevice device, const char* pName) { return GetDeviceProcAddr_Bottom(device, pName); } VkResult EnumerateInstanceExtensionProperties( const char* pLayerName, uint32_t* pPropertyCount, VkExtensionProperties* pProperties) { (void)pLayerName; VkExtensionProperties* available = static_cast( alloca(kInstanceExtensionCount * sizeof(VkExtensionProperties))); uint32_t num_extensions = 0; available[num_extensions++] = VkExtensionProperties{ VK_KHR_SURFACE_EXTENSION_NAME, VK_KHR_SURFACE_SPEC_VERSION}; available[num_extensions++] = VkExtensionProperties{VK_KHR_ANDROID_SURFACE_EXTENSION_NAME, VK_KHR_ANDROID_SURFACE_SPEC_VERSION}; if (g_driver_instance_extensions[kEXT_debug_report]) { available[num_extensions++] = VkExtensionProperties{VK_EXT_DEBUG_REPORT_EXTENSION_NAME, VK_EXT_DEBUG_REPORT_SPEC_VERSION}; } if (!pProperties || *pPropertyCount > num_extensions) *pPropertyCount = num_extensions; if (pProperties) std::copy(available, available + *pPropertyCount, pProperties); return *pPropertyCount < num_extensions ? VK_INCOMPLETE : VK_SUCCESS; } } // namespace driver } // namespace vulkan