| // Copyright 2017 The Fuchsia Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #define FUCHSIA_LAYER 1 |
| |
| #if USE_SWAPCHAIN_SURFACE_COPY |
| |
| #include "swapchain_copy_surface.h" // nogncheck |
| |
| #if defined(VK_USE_PLATFORM_FUCHSIA) |
| #define SWAPCHAIN_SURFACE_NAME "VK_LAYER_FUCHSIA_imagepipe_swapchain_copy" |
| #elif defined(VK_USE_PLATFORM_WAYLAND_KHR) |
| #define SWAPCHAIN_SURFACE_NAME "VK_LAYER_wayland_swapchain_copy" |
| #else |
| #error Unsupported |
| #endif |
| |
| #elif USE_IMAGEPIPE_SURFACE_FB |
| |
| #include "image_pipe_surface_display.h" // nogncheck |
| |
| #if SKIP_PRESENT |
| #define SWAPCHAIN_SURFACE_NAME "VK_LAYER_FUCHSIA_imagepipe_swapchain_fb_skip_present" |
| #else |
| #define SWAPCHAIN_SURFACE_NAME "VK_LAYER_FUCHSIA_imagepipe_swapchain_fb" |
| #endif |
| |
| #else |
| |
| #include "image_pipe_surface_async.h" // nogncheck |
| |
| #define SWAPCHAIN_SURFACE_NAME "VK_LAYER_FUCHSIA_imagepipe_swapchain" |
| |
| #endif |
| |
| // Useful for testing app performance without external restriction |
| // (due to composition, vsync, etc.) |
| #if SKIP_PRESENT |
| constexpr bool kSkipPresent = true; |
| #else |
| constexpr bool kSkipPresent = false; |
| #endif |
| |
| #include <assert.h> |
| #if defined(__Fuchsia__) |
| #include <lib/trace/event.h> |
| #endif |
| |
| #include <vk_dispatch_table_helper.h> |
| #include <vk_layer_extension_utils.h> |
| |
| #include <limits> |
| #include <thread> |
| #include <unordered_map> |
| #include <vector> |
| |
| #include "vk_layer_dispatch_table.h" |
| |
| // Older headers defined this for us |
| #ifndef VK_LAYER_EXPORT |
| #define VK_LAYER_EXPORT __attribute__((visibility("default"))) |
| #endif |
| |
| namespace { |
| // The loader dispatch table may be a different version from the layer's, and can't be used |
| // directly. |
| struct LoaderVkLayerDispatchTable; |
| typedef void* dispatch_key; |
| |
| // The first value in a dispatchable object should be a pointer to a VkLayerDispatchTable. |
| // According to the layer documentation: "the layer should use the dispatch table |
| // pointer within the VkDevice or VkInstance [as the hash table key] since that |
| // will be unique for a given VkInstance or VkDevice". |
| inline dispatch_key get_dispatch_key(const VkDevice object) { |
| return static_cast<dispatch_key>(*reinterpret_cast<LoaderVkLayerDispatchTable* const*>(object)); |
| } |
| inline dispatch_key get_dispatch_key(const VkInstance object) { |
| return static_cast<dispatch_key>(*reinterpret_cast<LoaderVkLayerDispatchTable* const*>(object)); |
| } |
| inline dispatch_key get_dispatch_key(const VkPhysicalDevice object) { |
| return static_cast<dispatch_key>(*reinterpret_cast<LoaderVkLayerDispatchTable* const*>(object)); |
| } |
| inline dispatch_key get_dispatch_key(const VkQueue object) { |
| return static_cast<dispatch_key>(*reinterpret_cast<LoaderVkLayerDispatchTable* const*>(object)); |
| } |
| |
| VkLayerInstanceCreateInfo* get_chain_info(const VkInstanceCreateInfo* pCreateInfo, |
| VkLayerFunction func) { |
| auto chain_info = static_cast<const VkLayerInstanceCreateInfo*>(pCreateInfo->pNext); |
| while (chain_info) { |
| if (chain_info->sType == VK_STRUCTURE_TYPE_LOADER_INSTANCE_CREATE_INFO && |
| chain_info->function == func) { |
| return const_cast<VkLayerInstanceCreateInfo*>(chain_info); |
| } |
| chain_info = static_cast<const VkLayerInstanceCreateInfo*>(chain_info->pNext); |
| } |
| assert(false && "Failed to find VkLayerInstanceCreateInfo"); |
| return nullptr; |
| } |
| |
| VkLayerDeviceCreateInfo* get_chain_info(const VkDeviceCreateInfo* pCreateInfo, |
| VkLayerFunction func) { |
| auto chain_info = static_cast<const VkLayerDeviceCreateInfo*>(pCreateInfo->pNext); |
| while (chain_info) { |
| if (chain_info->sType == VK_STRUCTURE_TYPE_LOADER_DEVICE_CREATE_INFO && |
| chain_info->function == func) { |
| return const_cast<VkLayerDeviceCreateInfo*>(chain_info); |
| } |
| chain_info = static_cast<const VkLayerDeviceCreateInfo*>(chain_info->pNext); |
| } |
| assert(false && "Failed to find VkLayerDeviceCreateInfo"); |
| return nullptr; |
| } |
| |
| } // namespace |
| |
| #define VK_LAYER_API_VERSION VK_MAKE_VERSION(1, 1, VK_HEADER_VERSION) |
| |
| static inline uint32_t to_uint32(uint64_t val) { |
| assert(val <= std::numeric_limits<uint32_t>::max()); |
| return static_cast<uint32_t>(val); |
| } |
| |
| namespace image_pipe_swapchain { |
| |
| // Global because thats how the layer code in the loader works and I dont know |
| // how to make it work otherwise |
| std::unordered_map<void*, LayerData*> layer_data_map; |
| |
| static const VkExtensionProperties instance_extensions[] = { |
| { |
| .extensionName = VK_KHR_SURFACE_EXTENSION_NAME, |
| .specVersion = 25, |
| }, |
| { |
| .extensionName = VK_KHR_GET_SURFACE_CAPABILITIES_2_EXTENSION_NAME, |
| .specVersion = 1, |
| }, |
| { |
| .extensionName = VK_KHR_SURFACE_PROTECTED_CAPABILITIES_EXTENSION_NAME, |
| .specVersion = 1, |
| }, |
| { |
| #if defined(VK_USE_PLATFOM_FUCHSIA) |
| .extensionName = VK_FUCHSIA_IMAGEPIPE_SURFACE_EXTENSION_NAME, |
| #elif defined(VK_USE_PLATFORM_WAYLAND_KHR) |
| .extensionName = VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME, |
| #endif |
| .specVersion = 1, |
| }, |
| }; |
| |
| static const VkExtensionProperties device_extensions[] = { |
| { |
| .extensionName = VK_KHR_SWAPCHAIN_EXTENSION_NAME, |
| .specVersion = 68, |
| }, |
| }; |
| |
| constexpr VkLayerProperties swapchain_layer = { |
| SWAPCHAIN_SURFACE_NAME, |
| VK_LAYER_API_VERSION, |
| 1, |
| "Image Pipe Swapchain", |
| }; |
| |
| struct ImagePipeImage { |
| VkImage image = VK_NULL_HANDLE; |
| uint32_t id = 0; |
| }; |
| |
| struct PendingImageInfo { |
| std::unique_ptr<PlatformEvent> release_fence; |
| uint32_t image_index; |
| }; |
| |
| class ImagePipeSwapchain { |
| public: |
| ImagePipeSwapchain(ImagePipeSurface* surface) |
| : surface_(surface), is_protected_(false), device_(VK_NULL_HANDLE) {} |
| |
| VkResult Initialize(VkDevice device, const VkSwapchainCreateInfoKHR* pCreateInfo, |
| const VkAllocationCallbacks* pAllocator); |
| |
| void Cleanup(VkDevice device, const VkAllocationCallbacks* pAllocator); |
| |
| VkResult GetSwapchainImages(uint32_t* pCount, VkImage* pSwapchainImages); |
| VkResult AcquireNextImage(uint64_t timeout_ns, VkSemaphore semaphore, uint32_t* pImageIndex); |
| VkResult Present(VkQueue queue, uint32_t index, uint32_t waitSemaphoreCount, |
| const VkSemaphore* pWaitSemaphores); |
| |
| void DebugMessage(VkDebugUtilsMessageSeverityFlagBitsEXT severity, const char* message); |
| |
| ImagePipeSurface* surface() { return surface_; } |
| |
| private: |
| struct PerImageData { |
| ImagePipeImage image; |
| VkDeviceMemory memory = VK_NULL_HANDLE; |
| VkSemaphore semaphore = VK_NULL_HANDLE; |
| // A fence that keeps track of the status of the previous presentation using a semaphore. |
| VkFence last_presentation_fence = VK_NULL_HANDLE; |
| }; |
| |
| ImagePipeSurface* surface_; |
| std::vector<PerImageData> per_image_data_; |
| std::vector<uint32_t> acquired_ids_; |
| std::vector<PendingImageInfo> pending_images_; |
| bool is_protected_; |
| VkDevice device_; |
| }; |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| |
| void ImagePipeSwapchain::DebugMessage(VkDebugUtilsMessageSeverityFlagBitsEXT severity, |
| const char* message) { |
| LayerData* device_data = GetLayerDataPtr(get_dispatch_key(device_), layer_data_map); |
| LayerData* instance_data = |
| GetLayerDataPtr(get_dispatch_key(device_data->instance), layer_data_map); |
| |
| VkDebugUtilsMessengerCallbackDataEXT callback_data = {}; |
| callback_data.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CALLBACK_DATA_EXT; |
| callback_data.pMessage = message; |
| |
| for (auto& callback : instance_data->debug_callbacks) { |
| if (!(severity & callback.second.messageSeverity)) |
| continue; |
| if (!(VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT & callback.second.messageType)) |
| continue; |
| callback.second.pfnUserCallback(severity, VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT, |
| &callback_data, callback.second.pUserData); |
| } |
| } |
| |
| VkResult ImagePipeSwapchain::Initialize(VkDevice device, |
| const VkSwapchainCreateInfoKHR* pCreateInfo, |
| const VkAllocationCallbacks* pAllocator) { |
| is_protected_ = pCreateInfo->flags & VK_SWAPCHAIN_CREATE_PROTECTED_BIT_KHR; |
| VkResult result; |
| VkLayerDispatchTable* pDisp = |
| GetLayerDataPtr(get_dispatch_key(device), layer_data_map)->device_dispatch_table.get(); |
| uint32_t num_images = pCreateInfo->minImageCount; |
| VkFlags usage = pCreateInfo->imageUsage & surface_->SupportedUsage(); |
| assert(pCreateInfo->sType == VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR); |
| std::vector<ImagePipeSurface::ImageInfo> image_infos; |
| |
| if (!surface_->CreateImage(device, pDisp, pCreateInfo->imageFormat, usage, pCreateInfo->flags, |
| pCreateInfo->imageExtent, num_images, pAllocator, &image_infos)) { |
| return VK_ERROR_OUT_OF_DEVICE_MEMORY; |
| } |
| for (uint32_t i = 0; i < num_images; i++) { |
| per_image_data_.push_back({}); |
| PerImageData& per_image_data = per_image_data_.back(); |
| per_image_data.image = ImagePipeImage{image_infos[i].image, image_infos[i].image_id}; |
| per_image_data.memory = image_infos[i].memory; |
| |
| VkSemaphoreCreateInfo create_semaphore_info{ |
| .sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO, .pNext = nullptr, .flags = 0}; |
| VkSemaphore semaphore; |
| result = pDisp->CreateSemaphore(device, &create_semaphore_info, pAllocator, &semaphore); |
| if (result != VK_SUCCESS) { |
| fprintf(stderr, "vkCreateSemaphore failed: %d", result); |
| return result; |
| } |
| per_image_data.semaphore = semaphore; |
| |
| VkFenceCreateInfo create_fence_info{.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO, |
| .pNext = nullptr, |
| .flags = VK_FENCE_CREATE_SIGNALED_BIT}; |
| VkFence fence; |
| result = pDisp->CreateFence(device, &create_fence_info, pAllocator, &fence); |
| if (result != VK_SUCCESS) { |
| fprintf(stderr, "vkCreateFence failed: %d", result); |
| return result; |
| } |
| per_image_data.last_presentation_fence = fence; |
| |
| auto release_fence = PlatformEvent::Create(device, pDisp, |
| true // signaled |
| ); |
| if (!release_fence) { |
| fprintf(stderr, "PlatformEvent::Create failed\n"); |
| return VK_ERROR_DEVICE_LOST; |
| } |
| |
| pending_images_.push_back({std::move(release_fence), i}); |
| } |
| |
| device_ = device; |
| return VK_SUCCESS; |
| } |
| |
| VKAPI_ATTR VkResult VKAPI_CALL CreateSwapchainKHR(VkDevice device, |
| const VkSwapchainCreateInfoKHR* pCreateInfo, |
| const VkAllocationCallbacks* pAllocator, |
| VkSwapchainKHR* pSwapchain) { |
| VkResult ret = VK_ERROR_INITIALIZATION_FAILED; |
| |
| auto surface = reinterpret_cast<ImagePipeSurface*>(pCreateInfo->surface); |
| |
| LayerData* layer_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map); |
| |
| if (!surface->OnCreateSwapchain(device, layer_data, pCreateInfo, pAllocator)) { |
| fprintf(stderr, "OnCreateSwapchain failed\n"); |
| return ret; |
| } |
| |
| auto swapchain = std::make_unique<ImagePipeSwapchain>(surface); |
| |
| ret = swapchain->Initialize(device, pCreateInfo, pAllocator); |
| if (ret != VK_SUCCESS) { |
| swapchain->Cleanup(device, pAllocator); |
| fprintf(stderr, "failed to create swapchain: %d", ret); |
| return ret; |
| } |
| |
| *pSwapchain = reinterpret_cast<VkSwapchainKHR>(swapchain.release()); |
| |
| return VK_SUCCESS; |
| } |
| |
| void ImagePipeSwapchain::Cleanup(VkDevice device, const VkAllocationCallbacks* pAllocator) { |
| VkLayerDispatchTable* pDisp = |
| GetLayerDataPtr(get_dispatch_key(device), layer_data_map)->device_dispatch_table.get(); |
| |
| // Wait for device to be idle to ensure no QueueSubmit operations caused by Present are pending. |
| pDisp->DeviceWaitIdle(device); |
| |
| for (auto& per_image_data : per_image_data_) { |
| if (per_image_data.image.image) { |
| surface()->RemoveImage(per_image_data.image.id); |
| pDisp->DestroyImage(device, per_image_data.image.image, pAllocator); |
| } |
| if (per_image_data.memory) { |
| pDisp->FreeMemory(device, per_image_data.memory, pAllocator); |
| } |
| if (per_image_data.semaphore) { |
| pDisp->DestroySemaphore(device, per_image_data.semaphore, pAllocator); |
| } |
| if (per_image_data.last_presentation_fence) { |
| pDisp->DestroyFence(device, per_image_data.last_presentation_fence, pAllocator); |
| } |
| } |
| per_image_data_.clear(); |
| } |
| |
| VKAPI_ATTR void VKAPI_CALL DestroySwapchainKHR(VkDevice device, VkSwapchainKHR vk_swapchain, |
| const VkAllocationCallbacks* pAllocator) { |
| auto swapchain = reinterpret_cast<ImagePipeSwapchain*>(vk_swapchain); |
| |
| swapchain->surface()->OnDestroySwapchain(device, pAllocator); |
| |
| swapchain->Cleanup(device, pAllocator); |
| delete reinterpret_cast<ImagePipeSwapchain*>(swapchain); |
| } |
| |
| VkResult ImagePipeSwapchain::GetSwapchainImages(uint32_t* pCount, VkImage* pSwapchainImages) { |
| if (pSwapchainImages == NULL) { |
| *pCount = to_uint32(per_image_data_.size()); |
| return VK_SUCCESS; |
| } |
| |
| assert(per_image_data_.size() <= *pCount); |
| |
| for (uint32_t i = 0; i < per_image_data_.size(); i++) |
| pSwapchainImages[i] = per_image_data_[i].image.image; |
| |
| *pCount = to_uint32(per_image_data_.size()); |
| return VK_SUCCESS; |
| } |
| |
| VKAPI_ATTR VkResult VKAPI_CALL GetSwapchainImagesKHR(VkDevice device, VkSwapchainKHR vk_swapchain, |
| uint32_t* pCount, VkImage* pSwapchainImages) { |
| auto swapchain = reinterpret_cast<ImagePipeSwapchain*>(vk_swapchain); |
| return swapchain->GetSwapchainImages(pCount, pSwapchainImages); |
| } |
| |
| static void CrashDueToOutOfImages() { abort(); } |
| |
| VkResult ImagePipeSwapchain::AcquireNextImage(uint64_t timeout_ns, VkSemaphore semaphore, |
| uint32_t* pImageIndex) { |
| if (surface_->IsLost()) |
| return VK_ERROR_SURFACE_LOST_KHR; |
| if (pending_images_.empty()) { |
| // All images acquired and none presented. We will never acquire anything. |
| if (timeout_ns == 0) |
| return VK_NOT_READY; |
| if (timeout_ns == UINT64_MAX) { |
| // This goes against the VU, so we can crash to help detect bugs: |
| // |
| // If the number of currently acquired images is greater than the difference between the |
| // number of images in swapchain and the value of VkSurfaceCapabilitiesKHR::minImageCount as |
| // returned by a call to vkGetPhysicalDeviceSurfaceCapabilities2KHR with the surface used to |
| // create swapchain, timeout must not be UINT64_MAX |
| DebugMessage(VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT, |
| "Currently all images are pending. Crashing program."); |
| CrashDueToOutOfImages(); |
| } |
| |
| std::this_thread::sleep_for(std::chrono::nanoseconds(timeout_ns)); |
| return VK_TIMEOUT; |
| } |
| |
| bool wait_for_release_fence = false; |
| |
| LayerData* layer_data = GetLayerDataPtr(get_dispatch_key(device_), layer_data_map); |
| |
| if (semaphore == VK_NULL_HANDLE) { |
| wait_for_release_fence = true; |
| } else { |
| std::unique_ptr<PlatformEvent> event; |
| |
| if (surface()->CanPresentPendingImage()) { |
| event = std::move(pending_images_[0].release_fence); |
| } else { |
| event = PlatformEvent::Create(device_, layer_data->device_dispatch_table.get(), |
| true // signaled |
| ); |
| if (!event) { |
| fprintf(stderr, "PlatformEvent::Create failed"); |
| return VK_SUCCESS; |
| } |
| wait_for_release_fence = true; |
| } |
| |
| VkResult result = |
| event->ImportToSemaphore(device_, layer_data->device_dispatch_table.get(), semaphore); |
| if (result != VK_SUCCESS) { |
| fprintf(stderr, "ImportToSemaphore failed: %d\n", result); |
| return VK_SUCCESS; |
| } |
| } |
| |
| if (wait_for_release_fence) { |
| // Wait for image to become available. |
| PlatformEvent::WaitResult result = pending_images_[0].release_fence->Wait( |
| device_, layer_data->device_dispatch_table.get(), timeout_ns); |
| |
| if (surface_->IsLost()) |
| return VK_ERROR_SURFACE_LOST_KHR; |
| |
| if (result == PlatformEvent::WaitResult::TimedOut) |
| return timeout_ns == 0ul ? VK_NOT_READY : VK_TIMEOUT; |
| |
| if (result != PlatformEvent::WaitResult::Ok) { |
| fprintf(stderr, "PlatformEvent::WaitResult failed %d\n", static_cast<int>(result)); |
| return VK_ERROR_DEVICE_LOST; |
| } |
| } |
| |
| *pImageIndex = pending_images_[0].image_index; |
| pending_images_.erase(pending_images_.begin()); |
| acquired_ids_.push_back(*pImageIndex); |
| |
| return VK_SUCCESS; |
| } |
| |
| VKAPI_ATTR VkResult VKAPI_CALL AcquireNextImageKHR(VkDevice device, VkSwapchainKHR vk_swapchain, |
| uint64_t timeout, VkSemaphore semaphore, |
| VkFence fence, uint32_t* pImageIndex) { |
| auto swapchain = reinterpret_cast<ImagePipeSwapchain*>(vk_swapchain); |
| if (fence) { |
| // TODO(https://fxbug.dev/42079241) handle this correctly |
| swapchain->DebugMessage(VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT, |
| "Image pipe swapchain doesn't support fences."); |
| return VK_ERROR_DEVICE_LOST; |
| } |
| return swapchain->AcquireNextImage(timeout, semaphore, pImageIndex); |
| } |
| |
| VkResult ImagePipeSwapchain::Present(VkQueue queue, uint32_t index, uint32_t waitSemaphoreCount, |
| const VkSemaphore* pWaitSemaphores) { |
| if (surface_->IsLost()) |
| return VK_ERROR_SURFACE_LOST_KHR; |
| |
| VkLayerDispatchTable* pDisp = |
| GetLayerDataPtr(get_dispatch_key(queue), layer_data_map)->device_dispatch_table.get(); |
| |
| PerImageData& per_image_data = per_image_data_[index]; |
| |
| // Wait for the previous present to complete before attempting to do |
| // vkImportSemaphoreZirconHandleFUCHSIA on the semaphore it used. The previous present is |
| // guaranteed to have completed by this point but the validation layers aren't aware of this |
| // because the synchronization goes through external semaphores. As a result, the validation |
| // layers generate a warning." |
| VkResult result = pDisp->WaitForFences(device_, 1, &per_image_data.last_presentation_fence, |
| VK_TRUE, UINT64_MAX); |
| if (result != VK_SUCCESS) { |
| return VK_ERROR_DEVICE_LOST; |
| } |
| |
| result = pDisp->ResetFences(device_, 1, &per_image_data.last_presentation_fence); |
| if (result != VK_SUCCESS) { |
| return VK_ERROR_DEVICE_LOST; |
| } |
| |
| auto acquire_fence = PlatformEvent::Create(device_, pDisp, false); |
| if (!acquire_fence) { |
| fprintf(stderr, "PlatformEvent::Create failed\n"); |
| return VK_ERROR_DEVICE_LOST; |
| } |
| |
| auto image_acquire_fence = acquire_fence->Duplicate(device_, pDisp); |
| if (!image_acquire_fence) { |
| fprintf(stderr, "failed to duplicate acquire fence"); |
| return VK_ERROR_DEVICE_LOST; |
| } |
| |
| result = image_acquire_fence->ImportToSemaphore(device_, pDisp, per_image_data.semaphore); |
| if (result != VK_SUCCESS) { |
| fprintf(stderr, "ImportToSemaphore failed: %d\n", result); |
| return VK_ERROR_SURFACE_LOST_KHR; |
| } |
| |
| std::vector<VkPipelineStageFlags> flag_bits(waitSemaphoreCount, |
| VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT); |
| VkProtectedSubmitInfo protected_submit_info = { |
| .sType = VK_STRUCTURE_TYPE_PROTECTED_SUBMIT_INFO, |
| .pNext = nullptr, |
| .protectedSubmit = VK_TRUE, |
| }; |
| VkSubmitInfo submit_info = {.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO, |
| .pNext = is_protected_ ? &protected_submit_info : nullptr, |
| .waitSemaphoreCount = waitSemaphoreCount, |
| .pWaitSemaphores = pWaitSemaphores, |
| .pWaitDstStageMask = flag_bits.data(), |
| .signalSemaphoreCount = 1, |
| .pSignalSemaphores = &per_image_data.semaphore}; |
| result = pDisp->QueueSubmit(queue, 1, &submit_info, per_image_data.last_presentation_fence); |
| if (result != VK_SUCCESS) { |
| fprintf(stderr, "vkQueueSubmit failed with result %d", result); |
| return VK_ERROR_SURFACE_LOST_KHR; |
| } |
| |
| auto iter = std::find(acquired_ids_.begin(), acquired_ids_.end(), index); |
| assert(iter != acquired_ids_.end()); |
| acquired_ids_.erase(iter); |
| |
| if (kSkipPresent) { |
| pending_images_.push_back({std::move(acquire_fence), index}); |
| } else { |
| auto release_fence = PlatformEvent::Create(device_, pDisp, false); |
| if (!release_fence) { |
| fprintf(stderr, "PlatformEvent::Create failed\n"); |
| return VK_ERROR_DEVICE_LOST; |
| } |
| |
| auto image_release_fence = release_fence->Duplicate(device_, pDisp); |
| if (!image_release_fence) { |
| fprintf(stderr, "failed to duplicate release fence"); |
| return VK_ERROR_DEVICE_LOST; |
| } |
| |
| pending_images_.push_back({std::move(image_release_fence), index}); |
| |
| std::vector<std::unique_ptr<PlatformEvent>> acquire_fences; |
| acquire_fences.push_back(std::move(acquire_fence)); |
| |
| std::vector<std::unique_ptr<PlatformEvent>> release_fences; |
| release_fences.push_back(std::move(release_fence)); |
| |
| #if defined(__Fuchsia__) |
| TRACE_DURATION("gfx", "ImagePipeSwapchain::Present", "swapchain_image_index", index, "image_id", |
| per_image_data_[index].image.id); |
| #endif |
| surface()->PresentImage(per_image_data_[index].image.id, std::move(acquire_fences), |
| std::move(release_fences), queue); |
| } |
| |
| return VK_SUCCESS; |
| } |
| |
| VKAPI_ATTR VkResult VKAPI_CALL QueuePresentKHR(VkQueue queue, |
| const VkPresentInfoKHR* pPresentInfo) { |
| for (uint32_t i = 0; i < pPresentInfo->swapchainCount; i++) { |
| auto swapchain = reinterpret_cast<ImagePipeSwapchain*>(pPresentInfo->pSwapchains[i]); |
| VkResult result = |
| swapchain->Present(queue, pPresentInfo->pImageIndices[i], pPresentInfo->waitSemaphoreCount, |
| pPresentInfo->pWaitSemaphores); |
| if (pPresentInfo->pResults) { |
| pPresentInfo->pResults[i] = result; |
| } else if (result != VK_SUCCESS) { |
| return result; |
| } |
| } |
| return VK_SUCCESS; |
| } |
| |
| VKAPI_ATTR VkResult VKAPI_CALL GetPhysicalDeviceSurfaceSupportKHR(VkPhysicalDevice physicalDevice, |
| uint32_t queueFamilyIndex, |
| const VkSurfaceKHR surface, |
| VkBool32* pSupported) { |
| *pSupported = surface != nullptr ? VK_TRUE : VK_FALSE; |
| return VK_SUCCESS; |
| } |
| |
| #if defined(VK_USE_PLATFORM_FUCHSIA) |
| VKAPI_ATTR VkResult VKAPI_CALL CreateImagePipeSurfaceFUCHSIA( |
| VkInstance instance, const VkImagePipeSurfaceCreateInfoFUCHSIA* pCreateInfo, |
| const VkAllocationCallbacks* pAllocator, VkSurfaceKHR* pSurface) { |
| #elif defined(VK_USE_PLATFORM_WAYLAND_KHR) |
| VKAPI_ATTR VkResult VKAPI_CALL |
| CreateWaylandSurfaceKHR(VkInstance instance, const VkWaylandSurfaceCreateInfoKHR* pCreateInfo, |
| const VkAllocationCallbacks* pAllocator, VkSurfaceKHR* pSurface) { |
| |
| #else |
| #error Unsupported |
| #endif |
| |
| #if USE_SWAPCHAIN_SURFACE_COPY |
| auto out_surface = std::make_unique<SwapchainCopySurface>(); |
| #elif USE_IMAGEPIPE_SURFACE_FB |
| auto out_surface = std::make_unique<ImagePipeSurfaceDisplay>(); |
| #else |
| auto out_surface = std::make_unique<ImagePipeSurfaceAsync>(pCreateInfo->imagePipeHandle); |
| #endif |
| |
| if (!out_surface->Init()) { |
| return VK_ERROR_DEVICE_LOST; |
| } |
| |
| LayerData* layer_data = GetLayerDataPtr(get_dispatch_key(instance), layer_data_map); |
| |
| if (!out_surface->OnCreateSurface(instance, layer_data->instance_dispatch_table.get(), |
| pCreateInfo, pAllocator)) { |
| return VK_ERROR_DEVICE_LOST; |
| } |
| |
| *pSurface = reinterpret_cast<VkSurfaceKHR>(out_surface.release()); |
| |
| return VK_SUCCESS; |
| } |
| |
| VKAPI_ATTR void VKAPI_CALL DestroySurfaceKHR(VkInstance instance, VkSurfaceKHR vk_surface, |
| const VkAllocationCallbacks* pAllocator) { |
| auto surface = reinterpret_cast<ImagePipeSurface*>(vk_surface); |
| LayerData* layer_data = GetLayerDataPtr(get_dispatch_key(instance), layer_data_map); |
| |
| surface->OnDestroySurface(instance, layer_data->instance_dispatch_table.get(), pAllocator); |
| |
| delete surface; |
| } |
| |
| VKAPI_ATTR VkResult VKAPI_CALL |
| GetPhysicalDeviceSurfaceCapabilitiesKHR(VkPhysicalDevice physicalDevice, VkSurfaceKHR surface, |
| VkSurfaceCapabilitiesKHR* pSurfaceCapabilities) { |
| VkLayerInstanceDispatchTable* instance_dispatch_table = |
| GetLayerDataPtr(get_dispatch_key(physicalDevice), layer_data_map) |
| ->instance_dispatch_table.get(); |
| |
| VkPhysicalDeviceProperties props; |
| instance_dispatch_table->GetPhysicalDeviceProperties(physicalDevice, &props); |
| |
| pSurfaceCapabilities->minImageCount = 2; |
| pSurfaceCapabilities->maxImageCount = 0; |
| pSurfaceCapabilities->minImageExtent = {1, 1}; |
| |
| auto image_pipe_surface = reinterpret_cast<ImagePipeSurface*>(surface); |
| |
| uint32_t width = 0; |
| uint32_t height = 0; |
| if (image_pipe_surface->GetSize(&width, &height)) { |
| pSurfaceCapabilities->maxImageExtent = {width, height}; |
| pSurfaceCapabilities->currentExtent = pSurfaceCapabilities->maxImageExtent; |
| } else { |
| pSurfaceCapabilities->currentExtent = {0xFFFFFFFF, 0xFFFFFFFF}; |
| pSurfaceCapabilities->maxImageExtent = {props.limits.maxImageDimension2D, |
| props.limits.maxImageDimension2D}; |
| } |
| |
| pSurfaceCapabilities->supportedTransforms = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR; |
| pSurfaceCapabilities->currentTransform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR; |
| pSurfaceCapabilities->maxImageArrayLayers = 1; |
| pSurfaceCapabilities->supportedUsageFlags = image_pipe_surface->SupportedUsage(); |
| pSurfaceCapabilities->supportedCompositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR; |
| return VK_SUCCESS; |
| } |
| |
| VKAPI_ATTR VkResult VKAPI_CALL GetPhysicalDeviceSurfaceCapabilities2KHR( |
| VkPhysicalDevice physicalDevice, const VkPhysicalDeviceSurfaceInfo2KHR* pSurfaceInfo, |
| VkSurfaceCapabilities2KHR* pSurfaceCapabilities) { |
| auto protected_caps = |
| static_cast<VkSurfaceProtectedCapabilitiesKHR*>(pSurfaceCapabilities->pNext); |
| if (protected_caps && |
| protected_caps->sType == VK_STRUCTURE_TYPE_SURFACE_PROTECTED_CAPABILITIES_KHR) { |
| protected_caps->supportsProtected = VK_TRUE; |
| } |
| |
| return GetPhysicalDeviceSurfaceCapabilitiesKHR(physicalDevice, pSurfaceInfo->surface, |
| &pSurfaceCapabilities->surfaceCapabilities); |
| } |
| |
| VKAPI_ATTR VkResult VKAPI_CALL |
| GetPhysicalDeviceSurfaceFormatsKHR(VkPhysicalDevice physicalDevice, const VkSurfaceKHR surface, |
| uint32_t* pCount, VkSurfaceFormatKHR* pSurfaceFormats) { |
| SupportedImageProperties& supported_properties = |
| reinterpret_cast<ImagePipeSurface*>(surface)->GetSupportedImageProperties(); |
| if (pSurfaceFormats == nullptr) { |
| *pCount = to_uint32(supported_properties.formats.size()); |
| return VK_SUCCESS; |
| } |
| |
| assert(*pCount >= supported_properties.formats.size()); |
| memcpy(pSurfaceFormats, supported_properties.formats.data(), |
| supported_properties.formats.size() * sizeof(VkSurfaceFormatKHR)); |
| *pCount = to_uint32(supported_properties.formats.size()); |
| return VK_SUCCESS; |
| } |
| |
| VKAPI_ATTR VkResult VKAPI_CALL GetPhysicalDeviceSurfaceFormats2KHR( |
| VkPhysicalDevice physicalDevice, const VkPhysicalDeviceSurfaceInfo2KHR* pSurfaceInfo, |
| uint32_t* pSurfaceFormatCount, VkSurfaceFormat2KHR* pSurfaceFormats) { |
| SupportedImageProperties& supported_properties = |
| reinterpret_cast<ImagePipeSurface*>(pSurfaceInfo->surface)->GetSupportedImageProperties(); |
| if (pSurfaceFormats == nullptr) { |
| *pSurfaceFormatCount = to_uint32(supported_properties.formats.size()); |
| return VK_SUCCESS; |
| } |
| |
| assert(*pSurfaceFormatCount >= supported_properties.formats.size()); |
| |
| for (size_t i = 0; i < supported_properties.formats.size(); i++) { |
| pSurfaceFormats[i] = { |
| .sType = VK_STRUCTURE_TYPE_SURFACE_FORMAT_2_KHR, |
| .pNext = nullptr, |
| .surfaceFormat = supported_properties.formats[i], |
| }; |
| } |
| *pSurfaceFormatCount = to_uint32(supported_properties.formats.size()); |
| return VK_SUCCESS; |
| } |
| |
| VKAPI_ATTR VkResult VKAPI_CALL |
| GetPhysicalDeviceSurfacePresentModesKHR(VkPhysicalDevice physicalDevice, const VkSurfaceKHR surface, |
| uint32_t* pCount, VkPresentModeKHR* pPresentModes) { |
| LayerData* layer_data = GetLayerDataPtr(get_dispatch_key(physicalDevice), layer_data_map); |
| return reinterpret_cast<ImagePipeSurface*>(surface)->GetPresentModes( |
| physicalDevice, layer_data->instance_dispatch_table.get(), pCount, pPresentModes); |
| } |
| |
| VKAPI_ATTR VkResult VKAPI_CALL CreateInstance(const VkInstanceCreateInfo* pCreateInfo, |
| const VkAllocationCallbacks* pAllocator, |
| VkInstance* pInstance) { |
| VkLayerInstanceCreateInfo* chain_info = get_chain_info(pCreateInfo, VK_LAYER_LINK_INFO); |
| |
| assert(chain_info->u.pLayerInfo); |
| PFN_vkGetInstanceProcAddr fpGetInstanceProcAddr = |
| chain_info->u.pLayerInfo->pfnNextGetInstanceProcAddr; |
| PFN_vkCreateInstance fpCreateInstance = |
| (PFN_vkCreateInstance)fpGetInstanceProcAddr(NULL, "vkCreateInstance"); |
| if (fpCreateInstance == NULL) { |
| return VK_ERROR_INITIALIZATION_FAILED; |
| } |
| |
| // Advance the link info for the next element on the chain |
| chain_info->u.pLayerInfo = chain_info->u.pLayerInfo->pNext; |
| |
| VkResult result = fpCreateInstance(pCreateInfo, pAllocator, pInstance); |
| if (result != VK_SUCCESS) |
| return result; |
| |
| LayerData* instance_layer_data = GetLayerDataPtr(get_dispatch_key(*pInstance), layer_data_map); |
| instance_layer_data->instance = *pInstance; |
| instance_layer_data->instance_dispatch_table = std::make_unique<VkLayerInstanceDispatchTable>(); |
| layer_init_instance_dispatch_table(*pInstance, instance_layer_data->instance_dispatch_table.get(), |
| fpGetInstanceProcAddr); |
| |
| return result; |
| } |
| |
| VKAPI_ATTR void VKAPI_CALL DestroyInstance(VkInstance instance, |
| const VkAllocationCallbacks* pAllocator) { |
| dispatch_key instance_key = get_dispatch_key(instance); |
| LayerData* my_data = GetLayerDataPtr(instance_key, layer_data_map); |
| |
| my_data->instance_dispatch_table->DestroyInstance(instance, pAllocator); |
| |
| // Remove from |layer_data_map| and free LayerData struct. |
| FreeLayerDataPtr(instance_key, layer_data_map); |
| } |
| |
| VKAPI_ATTR VkResult VKAPI_CALL CreateDevice(VkPhysicalDevice gpu, |
| const VkDeviceCreateInfo* pCreateInfo, |
| const VkAllocationCallbacks* pAllocator, |
| VkDevice* pDevice) { |
| void* gpu_key = get_dispatch_key(gpu); |
| LayerData* gpu_layer_data = GetLayerDataPtr(gpu_key, layer_data_map); |
| |
| bool external_semaphore_extension_available = false; |
| #if defined(VK_USE_PLATFORM_FUCHSIA) |
| bool external_memory_extension_available = false; |
| bool fuchsia_buffer_collection_extension_available = false; |
| bool dedicated_allocation_extension_available = false; |
| #elif defined(VK_USE_PLATFORM_WAYLAND_KHR) |
| bool external_fence_extension_available = false; |
| #endif |
| uint32_t device_extension_count; |
| VkResult result = gpu_layer_data->instance_dispatch_table->EnumerateDeviceExtensionProperties( |
| gpu, nullptr, &device_extension_count, nullptr); |
| if (result == VK_SUCCESS && device_extension_count > 0) { |
| std::vector<VkExtensionProperties> device_extensions(device_extension_count); |
| result = gpu_layer_data->instance_dispatch_table->EnumerateDeviceExtensionProperties( |
| gpu, nullptr, &device_extension_count, device_extensions.data()); |
| if (result == VK_SUCCESS) { |
| for (uint32_t i = 0; i < device_extension_count; i++) { |
| #if defined(VK_USE_PLATFORM_FUCHSIA) |
| if (!strcmp(VK_FUCHSIA_EXTERNAL_MEMORY_EXTENSION_NAME, |
| device_extensions[i].extensionName)) { |
| external_memory_extension_available = true; |
| } |
| if (!strcmp(VK_FUCHSIA_EXTERNAL_SEMAPHORE_EXTENSION_NAME, |
| device_extensions[i].extensionName)) { |
| external_semaphore_extension_available = true; |
| } |
| if (!strcmp(VK_FUCHSIA_BUFFER_COLLECTION_EXTENSION_NAME, |
| device_extensions[i].extensionName)) { |
| fuchsia_buffer_collection_extension_available = true; |
| } |
| if (!strcmp(VK_KHR_DEDICATED_ALLOCATION_EXTENSION_NAME, |
| device_extensions[i].extensionName)) { |
| dedicated_allocation_extension_available = true; |
| } |
| #elif defined(VK_USE_PLATFORM_WAYLAND_KHR) |
| if (!strcmp(VK_KHR_EXTERNAL_SEMAPHORE_FD_EXTENSION_NAME, |
| device_extensions[i].extensionName)) { |
| external_semaphore_extension_available = true; |
| } |
| if (!strcmp(VK_KHR_EXTERNAL_FENCE_FD_EXTENSION_NAME, device_extensions[i].extensionName)) { |
| external_fence_extension_available = true; |
| } |
| #endif |
| } |
| } |
| } |
| if (!external_semaphore_extension_available) { |
| fprintf(stderr, "External semaphore extension not available\n"); |
| } |
| #if defined(VK_USE_PLATFORM_FUCHSIA) |
| if (!external_memory_extension_available) { |
| fprintf(stderr, "External memory extension not available\n"); |
| } |
| if (!fuchsia_buffer_collection_extension_available) { |
| fprintf(stderr, "Device extension not available: %s\n", |
| VK_FUCHSIA_BUFFER_COLLECTION_EXTENSION_NAME); |
| } |
| if (!dedicated_allocation_extension_available) { |
| fprintf(stderr, "Device extension not available: %s\n", |
| VK_KHR_DEDICATED_ALLOCATION_EXTENSION_NAME); |
| } |
| if (!external_memory_extension_available || !external_semaphore_extension_available || |
| !fuchsia_buffer_collection_extension_available || !dedicated_allocation_extension_available) { |
| return VK_ERROR_INITIALIZATION_FAILED; |
| } |
| #elif defined(VK_USE_PLATFORM_WAYLAND_KHR) |
| if (!external_fence_extension_available) { |
| fprintf(stderr, "External fence extension not available\n"); |
| } |
| if (!external_semaphore_extension_available || !external_fence_extension_available) |
| return VK_ERROR_INITIALIZATION_FAILED; |
| #endif |
| |
| VkDeviceCreateInfo create_info = *pCreateInfo; |
| std::vector<const char*> enabled_extensions; |
| for (uint32_t i = 0; i < create_info.enabledExtensionCount; i++) { |
| enabled_extensions.push_back(create_info.ppEnabledExtensionNames[i]); |
| } |
| #if defined(VK_USE_PLATFORM_FUCHSIA) |
| enabled_extensions.push_back(VK_FUCHSIA_EXTERNAL_MEMORY_EXTENSION_NAME); |
| enabled_extensions.push_back(VK_FUCHSIA_EXTERNAL_SEMAPHORE_EXTENSION_NAME); |
| enabled_extensions.push_back(VK_FUCHSIA_BUFFER_COLLECTION_EXTENSION_NAME); |
| enabled_extensions.push_back(VK_KHR_DEDICATED_ALLOCATION_EXTENSION_NAME); |
| #elif defined(VK_USE_PLATFORM_WAYLAND_KHR) |
| enabled_extensions.push_back(VK_KHR_EXTERNAL_SEMAPHORE_FD_EXTENSION_NAME); |
| enabled_extensions.push_back(VK_KHR_EXTERNAL_FENCE_FD_EXTENSION_NAME); |
| #endif |
| create_info.enabledExtensionCount = to_uint32(enabled_extensions.size()); |
| create_info.ppEnabledExtensionNames = enabled_extensions.data(); |
| |
| VkLayerDeviceCreateInfo* link_info = get_chain_info(pCreateInfo, VK_LAYER_LINK_INFO); |
| |
| assert(link_info->u.pLayerInfo); |
| PFN_vkGetInstanceProcAddr fpGetInstanceProcAddr = |
| link_info->u.pLayerInfo->pfnNextGetInstanceProcAddr; |
| PFN_vkGetDeviceProcAddr fpGetDeviceProcAddr = link_info->u.pLayerInfo->pfnNextGetDeviceProcAddr; |
| PFN_vkCreateDevice fpCreateDevice = |
| (PFN_vkCreateDevice)fpGetInstanceProcAddr(gpu_layer_data->instance, "vkCreateDevice"); |
| if (fpCreateDevice == NULL) { |
| return VK_ERROR_INITIALIZATION_FAILED; |
| } |
| |
| // Advance the link info for the next element on the chain |
| link_info->u.pLayerInfo = link_info->u.pLayerInfo->pNext; |
| |
| result = fpCreateDevice(gpu, &create_info, pAllocator, pDevice); |
| if (result != VK_SUCCESS) { |
| return result; |
| } |
| |
| LayerData* device_layer_data = GetLayerDataPtr(get_dispatch_key(*pDevice), layer_data_map); |
| |
| // Setup device dispatch table |
| device_layer_data->device_dispatch_table = std::make_unique<VkLayerDispatchTable>(); |
| device_layer_data->instance = gpu_layer_data->instance; |
| layer_init_device_dispatch_table(*pDevice, device_layer_data->device_dispatch_table.get(), |
| fpGetDeviceProcAddr); |
| |
| VkLayerDeviceCreateInfo* callback_info = get_chain_info(pCreateInfo, VK_LOADER_DATA_CALLBACK); |
| assert(callback_info->u.pfnSetDeviceLoaderData); |
| device_layer_data->fpSetDeviceLoaderData = callback_info->u.pfnSetDeviceLoaderData; |
| |
| return VK_SUCCESS; |
| } |
| |
| VKAPI_ATTR void VKAPI_CALL DestroyDevice(VkDevice device, const VkAllocationCallbacks* pAllocator) { |
| dispatch_key device_key = get_dispatch_key(device); |
| LayerData* device_data = GetLayerDataPtr(device_key, layer_data_map); |
| device_data->device_dispatch_table->DestroyDevice(device, pAllocator); |
| |
| // Remove from |layer_data_map| and free LayerData struct. |
| FreeLayerDataPtr(device_key, layer_data_map); |
| } |
| |
| VKAPI_ATTR VkResult VKAPI_CALL EnumerateInstanceLayerProperties(uint32_t* pCount, |
| VkLayerProperties* pProperties) { |
| return util_GetLayerProperties(1, &swapchain_layer, pCount, pProperties); |
| } |
| |
| VKAPI_ATTR VkResult VKAPI_CALL EnumerateDeviceLayerProperties(VkPhysicalDevice physicalDevice, |
| uint32_t* pCount, |
| VkLayerProperties* pProperties) { |
| return util_GetLayerProperties(1, &swapchain_layer, pCount, pProperties); |
| } |
| |
| VKAPI_ATTR VkResult VKAPI_CALL EnumerateInstanceExtensionProperties( |
| const char* pLayerName, uint32_t* pCount, VkExtensionProperties* pProperties) { |
| if (pLayerName && !strcmp(pLayerName, swapchain_layer.layerName)) |
| return util_GetExtensionProperties(std::size(instance_extensions), instance_extensions, pCount, |
| pProperties); |
| |
| return VK_ERROR_LAYER_NOT_PRESENT; |
| } |
| |
| VKAPI_ATTR VkResult VKAPI_CALL |
| EnumerateDeviceExtensionProperties(VkPhysicalDevice physicalDevice, const char* pLayerName, |
| uint32_t* pCount, VkExtensionProperties* pProperties) { |
| if (pLayerName && !strcmp(pLayerName, swapchain_layer.layerName)) |
| return util_GetExtensionProperties(std::size(device_extensions), device_extensions, pCount, |
| pProperties); |
| |
| assert(physicalDevice); |
| |
| dispatch_key key = get_dispatch_key(physicalDevice); |
| LayerData* my_data = GetLayerDataPtr(key, layer_data_map); |
| return my_data->instance_dispatch_table->EnumerateDeviceExtensionProperties(physicalDevice, NULL, |
| pCount, pProperties); |
| } |
| |
| VKAPI_ATTR VkResult VKAPI_CALL CreateDebugUtilsMessengerEXT( |
| VkInstance instance, const VkDebugUtilsMessengerCreateInfoEXT* pCreateInfo, |
| const VkAllocationCallbacks* pAllocator, VkDebugUtilsMessengerEXT* pMessenger) { |
| dispatch_key key = get_dispatch_key(instance); |
| LayerData* my_data = GetLayerDataPtr(key, layer_data_map); |
| VkResult res = my_data->instance_dispatch_table->CreateDebugUtilsMessengerEXT( |
| instance, pCreateInfo, pAllocator, pMessenger); |
| if (res == VK_SUCCESS) { |
| my_data->debug_callbacks[*pMessenger] = *pCreateInfo; |
| } |
| return res; |
| } |
| |
| VKAPI_ATTR void VKAPI_CALL DestroyDebugUtilsMessengerEXT(VkInstance instance, |
| VkDebugUtilsMessengerEXT messenger, |
| const VkAllocationCallbacks* pAllocator) { |
| dispatch_key key = get_dispatch_key(instance); |
| LayerData* my_data = GetLayerDataPtr(key, layer_data_map); |
| my_data->debug_callbacks.erase(messenger); |
| my_data->instance_dispatch_table->DestroyDebugUtilsMessengerEXT(instance, messenger, pAllocator); |
| } |
| |
| VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL GetDeviceProcAddr(VkDevice device, const char* funcName); |
| VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL GetInstanceProcAddr(VkInstance instance, |
| const char* funcName); |
| |
| static inline PFN_vkVoidFunction layer_intercept_proc(const char* name) { |
| if (!name || name[0] != 'v' || name[1] != 'k') |
| return NULL; |
| name += 2; |
| if (!strcmp(name, "GetDeviceProcAddr")) |
| return reinterpret_cast<PFN_vkVoidFunction>(GetDeviceProcAddr); |
| if (!strcmp(name, "CreateInstance")) |
| return reinterpret_cast<PFN_vkVoidFunction>(CreateInstance); |
| if (!strcmp(name, "DestroyInstance")) |
| return reinterpret_cast<PFN_vkVoidFunction>(DestroyInstance); |
| if (!strcmp(name, "CreateDevice")) |
| return reinterpret_cast<PFN_vkVoidFunction>(CreateDevice); |
| if (!strcmp(name, "DestroyDevice")) |
| return reinterpret_cast<PFN_vkVoidFunction>(DestroyDevice); |
| if (!strcmp("CreateSwapchainKHR", name)) |
| return reinterpret_cast<PFN_vkVoidFunction>(CreateSwapchainKHR); |
| if (!strcmp("DestroySwapchainKHR", name)) |
| return reinterpret_cast<PFN_vkVoidFunction>(DestroySwapchainKHR); |
| if (!strcmp("GetSwapchainImagesKHR", name)) |
| return reinterpret_cast<PFN_vkVoidFunction>(GetSwapchainImagesKHR); |
| if (!strcmp("AcquireNextImageKHR", name)) |
| return reinterpret_cast<PFN_vkVoidFunction>(AcquireNextImageKHR); |
| if (!strcmp("QueuePresentKHR", name)) |
| return reinterpret_cast<PFN_vkVoidFunction>(QueuePresentKHR); |
| if (!strcmp("EnumerateDeviceExtensionProperties", name)) |
| return reinterpret_cast<PFN_vkVoidFunction>(EnumerateDeviceExtensionProperties); |
| if (!strcmp("EnumerateInstanceExtensionProperties", name)) |
| return reinterpret_cast<PFN_vkVoidFunction>(EnumerateInstanceExtensionProperties); |
| if (!strcmp("EnumerateDeviceLayerProperties", name)) |
| return reinterpret_cast<PFN_vkVoidFunction>(EnumerateDeviceLayerProperties); |
| if (!strcmp("EnumerateInstanceLayerProperties", name)) |
| return reinterpret_cast<PFN_vkVoidFunction>(EnumerateInstanceLayerProperties); |
| if (!strcmp(name, "CreateDebugUtilsMessengerEXT")) |
| return reinterpret_cast<PFN_vkVoidFunction>(CreateDebugUtilsMessengerEXT); |
| if (!strcmp(name, "DestroyDebugUtilsMessengerEXT")) |
| return reinterpret_cast<PFN_vkVoidFunction>(DestroyDebugUtilsMessengerEXT); |
| return NULL; |
| } |
| |
| static inline PFN_vkVoidFunction layer_intercept_instance_proc(const char* name) { |
| if (!name || name[0] != 'v' || name[1] != 'k') |
| return NULL; |
| name += 2; |
| if (!strcmp(name, "GetInstanceProcAddr")) |
| return reinterpret_cast<PFN_vkVoidFunction>(GetInstanceProcAddr); |
| if (!strcmp(name, "CreateInstance")) |
| return reinterpret_cast<PFN_vkVoidFunction>(CreateInstance); |
| if (!strcmp(name, "DestroyInstance")) |
| return reinterpret_cast<PFN_vkVoidFunction>(DestroyInstance); |
| if (!strcmp("GetPhysicalDeviceSurfaceSupportKHR", name)) |
| return reinterpret_cast<PFN_vkVoidFunction>(GetPhysicalDeviceSurfaceSupportKHR); |
| if (!strcmp("GetPhysicalDeviceSurfaceCapabilitiesKHR", name)) |
| return reinterpret_cast<PFN_vkVoidFunction>(GetPhysicalDeviceSurfaceCapabilitiesKHR); |
| if (!strcmp("GetPhysicalDeviceSurfaceFormatsKHR", name)) |
| return reinterpret_cast<PFN_vkVoidFunction>(GetPhysicalDeviceSurfaceFormatsKHR); |
| if (!strcmp("GetPhysicalDeviceSurfaceFormats2KHR", name)) |
| return reinterpret_cast<PFN_vkVoidFunction>(GetPhysicalDeviceSurfaceFormats2KHR); |
| if (!strcmp("GetPhysicalDeviceSurfacePresentModesKHR", name)) |
| return reinterpret_cast<PFN_vkVoidFunction>(GetPhysicalDeviceSurfacePresentModesKHR); |
| if (!strcmp("GetPhysicalDeviceSurfaceCapabilities2KHR", name)) |
| return reinterpret_cast<PFN_vkVoidFunction>(GetPhysicalDeviceSurfaceCapabilities2KHR); |
| #if defined(VK_USE_PLATFORM_FUCHSIA) |
| if (!strcmp("CreateImagePipeSurfaceFUCHSIA", name)) |
| return reinterpret_cast<PFN_vkVoidFunction>(CreateImagePipeSurfaceFUCHSIA); |
| #elif defined(VK_USE_PLATFORM_WAYLAND_KHR) |
| if (!strcmp("CreateWaylandSurfaceKHR", name)) |
| return reinterpret_cast<PFN_vkVoidFunction>(CreateWaylandSurfaceKHR); |
| #endif |
| if (!strcmp("DestroySurfaceKHR", name)) |
| return reinterpret_cast<PFN_vkVoidFunction>(DestroySurfaceKHR); |
| if (!strcmp(name, "CreateDebugUtilsMessengerEXT")) |
| return reinterpret_cast<PFN_vkVoidFunction>(CreateDebugUtilsMessengerEXT); |
| if (!strcmp(name, "DestroyDebugUtilsMessengerEXT")) |
| return reinterpret_cast<PFN_vkVoidFunction>(DestroyDebugUtilsMessengerEXT); |
| return NULL; |
| } |
| |
| VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL GetDeviceProcAddr(VkDevice device, const char* funcName) { |
| PFN_vkVoidFunction addr; |
| LayerData* dev_data; |
| |
| assert(device); |
| |
| addr = layer_intercept_proc(funcName); |
| if (addr) { |
| return addr; |
| } |
| |
| dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map); |
| |
| VkLayerDispatchTable* pTable = dev_data->device_dispatch_table.get(); |
| |
| if (pTable->GetDeviceProcAddr == NULL) |
| return NULL; |
| return pTable->GetDeviceProcAddr(device, funcName); |
| } |
| |
| VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL GetInstanceProcAddr(VkInstance instance, |
| const char* funcName) { |
| PFN_vkVoidFunction addr; |
| LayerData* my_data; |
| |
| addr = layer_intercept_instance_proc(funcName); |
| if (!addr) |
| addr = layer_intercept_proc(funcName); |
| if (addr) { |
| return addr; |
| } |
| |
| if (!instance) { |
| return nullptr; |
| } |
| |
| my_data = GetLayerDataPtr(get_dispatch_key(instance), layer_data_map); |
| |
| VkLayerInstanceDispatchTable* pTable = my_data->instance_dispatch_table.get(); |
| if (pTable->GetInstanceProcAddr == NULL) { |
| return NULL; |
| } |
| addr = pTable->GetInstanceProcAddr(instance, funcName); |
| return addr; |
| } |
| |
| VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL GetPhysicalDeviceProcAddr(VkInstance instance, |
| const char* funcName) { |
| assert(instance); |
| |
| LayerData* my_data; |
| my_data = GetLayerDataPtr(get_dispatch_key(instance), layer_data_map); |
| VkLayerInstanceDispatchTable* pTable = my_data->instance_dispatch_table.get(); |
| |
| if (pTable->GetPhysicalDeviceProcAddr == NULL) |
| return NULL; |
| return pTable->GetPhysicalDeviceProcAddr(instance, funcName); |
| } |
| |
| } // namespace image_pipe_swapchain |
| |
| VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkEnumerateInstanceExtensionProperties( |
| const char* pLayerName, uint32_t* pCount, VkExtensionProperties* pProperties) { |
| return image_pipe_swapchain::EnumerateInstanceExtensionProperties(pLayerName, pCount, |
| pProperties); |
| } |
| |
| VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL |
| vkEnumerateInstanceLayerProperties(uint32_t* pCount, VkLayerProperties* pProperties) { |
| return image_pipe_swapchain::EnumerateInstanceLayerProperties(pCount, pProperties); |
| } |
| |
| VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkEnumerateDeviceLayerProperties( |
| VkPhysicalDevice physicalDevice, uint32_t* pCount, VkLayerProperties* pProperties) { |
| assert(physicalDevice == VK_NULL_HANDLE); |
| return image_pipe_swapchain::EnumerateDeviceLayerProperties(VK_NULL_HANDLE, pCount, pProperties); |
| } |
| |
| VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL |
| vkEnumerateDeviceExtensionProperties(VkPhysicalDevice physicalDevice, const char* pLayerName, |
| uint32_t* pCount, VkExtensionProperties* pProperties) { |
| assert(physicalDevice == VK_NULL_HANDLE); |
| return image_pipe_swapchain::EnumerateDeviceExtensionProperties(VK_NULL_HANDLE, pLayerName, |
| pCount, pProperties); |
| } |
| |
| VK_LAYER_EXPORT VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL vkGetDeviceProcAddr(VkDevice dev, |
| const char* funcName) { |
| return image_pipe_swapchain::GetDeviceProcAddr(dev, funcName); |
| } |
| |
| VK_LAYER_EXPORT VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL |
| vkGetInstanceProcAddr(VkInstance instance, const char* funcName) { |
| return image_pipe_swapchain::GetInstanceProcAddr(instance, funcName); |
| } |