CoCalc provides the best real-time collaborative environment for Jupyter Notebooks, LaTeX documents, and SageMath, scalable from individual users to large groups and classes!
CoCalc provides the best real-time collaborative environment for Jupyter Notebooks, LaTeX documents, and SageMath, scalable from individual users to large groups and classes!
Path: blob/master/libretro/libretro_vulkan.cpp
Views: 1401
// Debugging notes1// The crash happens when we try to call vkGetPhysicalDeviceProperties2KHR which seems to be null.2//3// Apparently we don't manage to specify the extensions we want. Still something reports that this one4// is present?5// Failed to load : vkGetPhysicalDeviceProperties2KHR6// Failed to load : vkGetPhysicalDeviceFeatures2KHR78#include <cstring>9#include <cassert>10#include <vector>11#include <mutex>12#include <condition_variable>1314#include "Common/GPU/Vulkan/VulkanLoader.h"15#include "Common/Log.h"16#include "Core/Config.h"1718#define VK_NO_PROTOTYPES19#include "libretro/libretro_vulkan.h"2021using namespace PPSSPP_VK;2223static retro_hw_render_interface_vulkan *vulkan;2425static struct {26VkInstance instance;27VkPhysicalDevice gpu;28VkSurfaceKHR surface;29PFN_vkGetInstanceProcAddr get_instance_proc_addr;30const char **required_device_extensions;31unsigned num_required_device_extensions;32const char **required_device_layers;33unsigned num_required_device_layers;34const VkPhysicalDeviceFeatures *required_features;35} vk_init_info;36static bool DEDICATED_ALLOCATION;3738#define VULKAN_MAX_SWAPCHAIN_IMAGES 839struct VkSwapchainKHR_T {40uint32_t count;41struct {42VkImage handle;43VkDeviceMemory memory;44retro_vulkan_image retro_image;45} images[VULKAN_MAX_SWAPCHAIN_IMAGES];46std::mutex mutex;47std::condition_variable condVar;48int current_index;49};50static VkSwapchainKHR_T chain;5152#define LIBRETRO_VK_WARP_LIST() \53LIBRETRO_VK_WARP_FUNC(vkCreateInstance); \54LIBRETRO_VK_WARP_FUNC(vkDestroyInstance); \55LIBRETRO_VK_WARP_FUNC(vkCreateDevice); \56LIBRETRO_VK_WARP_FUNC(vkDestroyDevice); \57LIBRETRO_VK_WARP_FUNC(vkGetPhysicalDeviceSurfaceCapabilitiesKHR); \58LIBRETRO_VK_WARP_FUNC(vkDestroySurfaceKHR); \59LIBRETRO_VK_WARP_FUNC(vkCreateSwapchainKHR); \60LIBRETRO_VK_WARP_FUNC(vkGetSwapchainImagesKHR); \61LIBRETRO_VK_WARP_FUNC(vkAcquireNextImageKHR); \62LIBRETRO_VK_WARP_FUNC(vkQueuePresentKHR); \63LIBRETRO_VK_WARP_FUNC(vkDestroySwapchainKHR); \64LIBRETRO_VK_WARP_FUNC(vkQueueSubmit); \65LIBRETRO_VK_WARP_FUNC(vkQueueWaitIdle); \66LIBRETRO_VK_WARP_FUNC(vkCmdPipelineBarrier); \67LIBRETRO_VK_WARP_FUNC(vkCreateRenderPass);6869#define LIBRETRO_VK_WARP_FUNC(x) \70PFN_##x x##_org7172LIBRETRO_VK_WARP_FUNC(vkGetInstanceProcAddr);73LIBRETRO_VK_WARP_FUNC(vkGetDeviceProcAddr);74LIBRETRO_VK_WARP_LIST();7576static VKAPI_ATTR VkResult VKAPI_CALL vkCreateInstance_libretro(const VkInstanceCreateInfo *pCreateInfo, const VkAllocationCallbacks *pAllocator, VkInstance *pInstance) {77*pInstance = vk_init_info.instance;78return VK_SUCCESS;79}8081static void add_name_unique(std::vector<const char *> &list, const char *value) {82for (const char *name : list)83if (!strcmp(value, name))84return;8586list.push_back(value);87}88static VKAPI_ATTR VkResult VKAPI_CALL vkCreateDevice_libretro(VkPhysicalDevice physicalDevice, const VkDeviceCreateInfo *pCreateInfo, const VkAllocationCallbacks *pAllocator, VkDevice *pDevice) {89VkDeviceCreateInfo info = *pCreateInfo;90std::vector<const char *> EnabledLayerNames(info.ppEnabledLayerNames, info.ppEnabledLayerNames + info.enabledLayerCount);91std::vector<const char *> EnabledExtensionNames(info.ppEnabledExtensionNames, info.ppEnabledExtensionNames + info.enabledExtensionCount);92VkPhysicalDeviceFeatures EnabledFeatures = *info.pEnabledFeatures;9394for (unsigned i = 0; i < vk_init_info.num_required_device_layers; i++)95add_name_unique(EnabledLayerNames, vk_init_info.required_device_layers[i]);9697for (unsigned i = 0; i < vk_init_info.num_required_device_extensions; i++)98add_name_unique(EnabledExtensionNames, vk_init_info.required_device_extensions[i]);99100for (unsigned i = 0; i < sizeof(VkPhysicalDeviceFeatures) / sizeof(VkBool32); i++) {101if (((VkBool32 *)vk_init_info.required_features)[i])102((VkBool32 *)&EnabledFeatures)[i] = VK_TRUE;103}104105for (auto extension_name : EnabledExtensionNames) {106if (!strcmp(extension_name, VK_KHR_DEDICATED_ALLOCATION_EXTENSION_NAME))107DEDICATED_ALLOCATION = true;108}109110info.enabledLayerCount = (uint32_t)EnabledLayerNames.size();111info.ppEnabledLayerNames = info.enabledLayerCount ? EnabledLayerNames.data() : nullptr;112info.enabledExtensionCount = (uint32_t)EnabledExtensionNames.size();113info.ppEnabledExtensionNames = info.enabledExtensionCount ? EnabledExtensionNames.data() : nullptr;114info.pEnabledFeatures = &EnabledFeatures;115116return vkCreateDevice_org(physicalDevice, &info, pAllocator, pDevice);117}118119static VKAPI_ATTR VkResult VKAPI_CALL vkCreateLibretroSurfaceKHR(VkInstance instance, const void *pCreateInfo, const VkAllocationCallbacks *pAllocator, VkSurfaceKHR *pSurface) {120*pSurface = vk_init_info.surface;121return VK_SUCCESS;122}123124VKAPI_ATTR VkResult VKAPI_CALL vkGetPhysicalDeviceSurfaceCapabilitiesKHR_libretro(VkPhysicalDevice physicalDevice, VkSurfaceKHR surface, VkSurfaceCapabilitiesKHR *pSurfaceCapabilities) {125VkResult res = vkGetPhysicalDeviceSurfaceCapabilitiesKHR_org(physicalDevice, surface, pSurfaceCapabilities);126if (res == VK_SUCCESS) {127int w = g_Config.iInternalResolution * NATIVEWIDTH;128int h = g_Config.iInternalResolution * NATIVEHEIGHT;129130if (g_Config.bDisplayCropTo16x9)131h -= g_Config.iInternalResolution * 2;132133pSurfaceCapabilities->minImageExtent.width = w;134pSurfaceCapabilities->minImageExtent.height = h;135pSurfaceCapabilities->maxImageExtent.width = w;136pSurfaceCapabilities->maxImageExtent.height = h;137pSurfaceCapabilities->currentExtent.width = w;138pSurfaceCapabilities->currentExtent.height = h;139}140return res;141}142143static bool MemoryTypeFromProperties(uint32_t typeBits, VkFlags requirements_mask, uint32_t *typeIndex) {144VkPhysicalDeviceMemoryProperties memory_properties;145vkGetPhysicalDeviceMemoryProperties(vulkan->gpu, &memory_properties);146// Search memtypes to find first index with those properties147for (uint32_t i = 0; i < 32; i++) {148if ((typeBits & 1) == 1) {149// Type is available, does it match user properties?150if ((memory_properties.memoryTypes[i].propertyFlags & requirements_mask) == requirements_mask) {151*typeIndex = i;152return true;153}154}155typeBits >>= 1;156}157// No memory types matched, return failure158return false;159}160161static VKAPI_ATTR VkResult VKAPI_CALL vkCreateSwapchainKHR_libretro(VkDevice device, const VkSwapchainCreateInfoKHR *pCreateInfo, const VkAllocationCallbacks *pAllocator, VkSwapchainKHR *pSwapchain) {162uint32_t swapchain_mask = vulkan->get_sync_index_mask(vulkan->handle);163164chain.count = 0;165while (swapchain_mask) {166chain.count++;167swapchain_mask >>= 1;168}169assert(chain.count <= VULKAN_MAX_SWAPCHAIN_IMAGES);170171for (uint32_t i = 0; i < chain.count; i++) {172{173VkImageCreateInfo info{ VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO };174info.flags = VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT;175info.imageType = VK_IMAGE_TYPE_2D;176info.format = pCreateInfo->imageFormat;177info.extent.width = pCreateInfo->imageExtent.width;178info.extent.height = pCreateInfo->imageExtent.height;179info.extent.depth = 1;180info.mipLevels = 1;181info.arrayLayers = 1;182info.samples = VK_SAMPLE_COUNT_1_BIT;183info.tiling = VK_IMAGE_TILING_OPTIMAL;184info.usage = VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;185info.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;186187vkCreateImage(device, &info, pAllocator, &chain.images[i].handle);188}189190VkMemoryRequirements memreq;191vkGetImageMemoryRequirements(device, chain.images[i].handle, &memreq);192193VkMemoryAllocateInfo alloc{ VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO };194alloc.allocationSize = memreq.size;195196VkMemoryDedicatedAllocateInfoKHR dedicated{ VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO_KHR };197if (DEDICATED_ALLOCATION) {198alloc.pNext = &dedicated;199dedicated.image = chain.images[i].handle;200}201202MemoryTypeFromProperties(memreq.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, &alloc.memoryTypeIndex);203VkResult res = vkAllocateMemory(device, &alloc, pAllocator, &chain.images[i].memory);204assert(res == VK_SUCCESS);205res = vkBindImageMemory(device, chain.images[i].handle, chain.images[i].memory, 0);206assert(res == VK_SUCCESS);207208chain.images[i].retro_image.create_info.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;209chain.images[i].retro_image.create_info.image = chain.images[i].handle;210chain.images[i].retro_image.create_info.viewType = VK_IMAGE_VIEW_TYPE_2D;211chain.images[i].retro_image.create_info.format = pCreateInfo->imageFormat;212chain.images[i].retro_image.create_info.components = { VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY };213chain.images[i].retro_image.create_info.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;214chain.images[i].retro_image.create_info.subresourceRange.layerCount = 1;215chain.images[i].retro_image.create_info.subresourceRange.levelCount = 1;216res = vkCreateImageView(device, &chain.images[i].retro_image.create_info, pAllocator, &chain.images[i].retro_image.image_view);217assert(res == VK_SUCCESS);218219chain.images[i].retro_image.image_layout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;220}221222chain.current_index = -1;223*pSwapchain = (VkSwapchainKHR)&chain;224225return VK_SUCCESS;226}227static VKAPI_ATTR VkResult VKAPI_CALL vkGetSwapchainImagesKHR_libretro(VkDevice device, VkSwapchainKHR swapchain_, uint32_t *pSwapchainImageCount, VkImage *pSwapchainImages) {228VkSwapchainKHR_T *swapchain = (VkSwapchainKHR_T *)swapchain_;229if (pSwapchainImages) {230assert(*pSwapchainImageCount <= swapchain->count);231for (int i = 0; i < *pSwapchainImageCount; i++)232pSwapchainImages[i] = swapchain->images[i].handle;233} else234*pSwapchainImageCount = swapchain->count;235236return VK_SUCCESS;237}238239static VKAPI_ATTR VkResult VKAPI_CALL vkAcquireNextImageKHR_libretro(VkDevice device, VkSwapchainKHR swapchain, uint64_t timeout, VkSemaphore semaphore, VkFence fence, uint32_t *pImageIndex) {240vulkan->wait_sync_index(vulkan->handle);241*pImageIndex = vulkan->get_sync_index(vulkan->handle);242#if 0243vulkan->set_signal_semaphore(vulkan->handle, semaphore);244#endif245return VK_SUCCESS;246}247248static VKAPI_ATTR VkResult VKAPI_CALL vkQueuePresentKHR_libretro(VkQueue queue, const VkPresentInfoKHR *pPresentInfo) {249VkSwapchainKHR_T *swapchain = (VkSwapchainKHR_T *)pPresentInfo->pSwapchains[0];250std::unique_lock<std::mutex> lock(swapchain->mutex);251#if 0252if(chain.current_index >= 0)253chain.condVar.wait(lock);254#endif255256chain.current_index = pPresentInfo->pImageIndices[0];257#if 0258vulkan->set_image(vulkan->handle, &swapchain->images[pPresentInfo->pImageIndices[0]].retro_image, pPresentInfo->waitSemaphoreCount, pPresentInfo->pWaitSemaphores, vulkan->queue_index);259#else260vulkan->set_image(vulkan->handle, &swapchain->images[pPresentInfo->pImageIndices[0]].retro_image, 0, nullptr, vulkan->queue_index);261#endif262swapchain->condVar.notify_all();263264return VK_SUCCESS;265}266267void vk_libretro_wait_for_presentation() {268std::unique_lock<std::mutex> lock(chain.mutex);269if (chain.current_index < 0)270chain.condVar.wait(lock);271#if 0272chain.current_index = -1;273chain.condVar.notify_all();274#endif275}276277static VKAPI_ATTR void VKAPI_CALL vkDestroyInstance_libretro(VkInstance instance, const VkAllocationCallbacks *pAllocator) {}278static VKAPI_ATTR void VKAPI_CALL vkDestroyDevice_libretro(VkDevice device, const VkAllocationCallbacks *pAllocator) {}279static VKAPI_ATTR void VKAPI_CALL vkDestroySurfaceKHR_libretro(VkInstance instance, VkSurfaceKHR surface, const VkAllocationCallbacks *pAllocator) {}280static VKAPI_ATTR void VKAPI_CALL vkDestroySwapchainKHR_libretro(VkDevice device, VkSwapchainKHR swapchain, const VkAllocationCallbacks *pAllocator) {281for (int i = 0; i < chain.count; i++) {282vkDestroyImage(device, chain.images[i].handle, pAllocator);283vkDestroyImageView(device, chain.images[i].retro_image.image_view, pAllocator);284vkFreeMemory(device, chain.images[i].memory, pAllocator);285}286287memset(&chain.images, 0x00, sizeof(chain.images));288chain.count = 0;289chain.current_index = -1;290}291292VKAPI_ATTR VkResult VKAPI_CALL vkQueueSubmit_libretro(VkQueue queue, uint32_t submitCount, const VkSubmitInfo *pSubmits, VkFence fence) {293VkResult res = VK_SUCCESS;294295#if 0296for(int i = 0; i < submitCount; i++)297vulkan->set_command_buffers(vulkan->handle, pSubmits[i].commandBufferCount, pSubmits[i].pCommandBuffers);298#else299#if 1300for (int i = 0; i < submitCount; i++) {301((VkSubmitInfo *)pSubmits)[i].waitSemaphoreCount = 0;302((VkSubmitInfo *)pSubmits)[i].pWaitSemaphores = nullptr;303((VkSubmitInfo *)pSubmits)[i].signalSemaphoreCount = 0;304((VkSubmitInfo *)pSubmits)[i].pSignalSemaphores = nullptr;305}306#endif307vulkan->lock_queue(vulkan->handle);308res = vkQueueSubmit_org(queue, submitCount, pSubmits, fence);309vulkan->unlock_queue(vulkan->handle);310#endif311312return res;313}314315VKAPI_ATTR VkResult VKAPI_CALL vkQueueWaitIdle_libretro(VkQueue queue) {316vulkan->lock_queue(vulkan->handle);317VkResult res = vkQueueWaitIdle_org(queue);318vulkan->unlock_queue(vulkan->handle);319return res;320}321322VKAPI_ATTR void VKAPI_CALL vkCmdPipelineBarrier_libretro(VkCommandBuffer commandBuffer, VkPipelineStageFlags srcStageMask, VkPipelineStageFlags dstStageMask, VkDependencyFlags dependencyFlags, uint32_t memoryBarrierCount, const VkMemoryBarrier *pMemoryBarriers, uint32_t bufferMemoryBarrierCount, const VkBufferMemoryBarrier *pBufferMemoryBarriers, uint32_t imageMemoryBarrierCount, const VkImageMemoryBarrier *pImageMemoryBarriers) {323VkImageMemoryBarrier *barriers = (VkImageMemoryBarrier *)pImageMemoryBarriers;324for (int i = 0; i < imageMemoryBarrierCount; i++) {325if (pImageMemoryBarriers[i].oldLayout == VK_IMAGE_LAYOUT_PRESENT_SRC_KHR) {326barriers[i].oldLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;327barriers[i].srcAccessMask = VK_ACCESS_SHADER_READ_BIT;328}329if (pImageMemoryBarriers[i].newLayout == VK_IMAGE_LAYOUT_PRESENT_SRC_KHR) {330barriers[i].newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;331barriers[i].dstAccessMask = VK_ACCESS_SHADER_READ_BIT;332}333}334return vkCmdPipelineBarrier_org(commandBuffer, srcStageMask, dstStageMask, dependencyFlags, memoryBarrierCount, pMemoryBarriers, bufferMemoryBarrierCount, pBufferMemoryBarriers, imageMemoryBarrierCount, barriers);335}336337VKAPI_ATTR VkResult VKAPI_CALL vkCreateRenderPass_libretro(VkDevice device, const VkRenderPassCreateInfo *pCreateInfo, const VkAllocationCallbacks *pAllocator, VkRenderPass *pRenderPass) {338if (pCreateInfo->pAttachments[0].finalLayout == VK_IMAGE_LAYOUT_PRESENT_SRC_KHR)339((VkAttachmentDescription *)pCreateInfo->pAttachments)[0].finalLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;340341return vkCreateRenderPass_org(device, pCreateInfo, pAllocator, pRenderPass);342}343344#undef LIBRETRO_VK_WARP_FUNC345#define LIBRETRO_VK_WARP_FUNC(x) \346if (!strcmp(pName, #x)) { \347x##_org = (PFN_##x)fptr; \348return (PFN_vkVoidFunction)x##_libretro; \349}350351VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL vkGetInstanceProcAddr_libretro(VkInstance instance, const char *pName) {352if (false353#ifdef _WIN32354|| !strcmp(pName, "vkCreateWin32SurfaceKHR")355#endif356#ifdef __ANDROID__357|| !strcmp(pName, "vkCreateAndroidSurfaceKHR")358#endif359#ifdef VK_USE_PLATFORM_METAL_EXT360|| !strcmp(pName, "vkCreateMetalSurfaceEXT")361#endif362#ifdef VK_USE_PLATFORM_XLIB_KHR363|| !strcmp(pName, "vkCreateXlibSurfaceKHR")364#endif365#ifdef VK_USE_PLATFORM_XCB_KHR366|| !strcmp(pName, "vkCreateXcbSurfaceKHR")367#endif368#ifdef VK_USE_PLATFORM_WAYLAND_KHR369|| !strcmp(pName, "vkCreateWaylandSurfaceKHR")370#endif371#ifdef VK_USE_PLATFORM_DISPLAY_KHR372|| !strcmp(pName, "vkCreateDisplayPlaneSurfaceKHR")373#endif374) {375return (PFN_vkVoidFunction)vkCreateLibretroSurfaceKHR;376}377378PFN_vkVoidFunction fptr = vk_init_info.get_instance_proc_addr(instance, pName);379if (!fptr) {380ERROR_LOG(Log::G3D, "Failed to load VK instance function: %s", pName);381return fptr;382}383384LIBRETRO_VK_WARP_LIST();385386return fptr;387}388389VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL vkGetDeviceProcAddr_libretro(VkDevice device, const char *pName) {390PFN_vkVoidFunction fptr = vkGetDeviceProcAddr_org(device, pName);391if (!fptr)392return fptr;393394LIBRETRO_VK_WARP_LIST();395396return fptr;397}398399void vk_libretro_init(VkInstance instance, VkPhysicalDevice gpu, VkSurfaceKHR surface, PFN_vkGetInstanceProcAddr get_instance_proc_addr, const char **required_device_extensions, unsigned num_required_device_extensions, const char **required_device_layers, unsigned num_required_device_layers, const VkPhysicalDeviceFeatures *required_features) {400assert(surface);401402vk_init_info.instance = instance;403vk_init_info.gpu = gpu;404vk_init_info.surface = surface;405vk_init_info.get_instance_proc_addr = get_instance_proc_addr;406vk_init_info.required_device_extensions = required_device_extensions;407vk_init_info.num_required_device_extensions = num_required_device_extensions;408vk_init_info.required_device_layers = required_device_layers;409vk_init_info.num_required_device_layers = num_required_device_layers;410vk_init_info.required_features = required_features;411412vkGetInstanceProcAddr_org = vkGetInstanceProcAddr;413vkGetInstanceProcAddr = vkGetInstanceProcAddr_libretro;414vkGetDeviceProcAddr_org = (PFN_vkGetDeviceProcAddr)vkGetInstanceProcAddr(instance, "vkGetDeviceProcAddr");;415vkGetDeviceProcAddr = vkGetDeviceProcAddr_libretro;416vkCreateInstance = vkCreateInstance_libretro;417418vkEnumerateInstanceVersion = (PFN_vkEnumerateInstanceVersion)vkGetInstanceProcAddr(NULL, "vkEnumerateInstanceVersion");419vkEnumerateInstanceExtensionProperties = (PFN_vkEnumerateInstanceExtensionProperties)vkGetInstanceProcAddr(NULL, "vkEnumerateInstanceExtensionProperties");420vkEnumerateInstanceLayerProperties = (PFN_vkEnumerateInstanceLayerProperties)vkGetInstanceProcAddr(NULL, "vkEnumerateInstanceLayerProperties");421}422423void vk_libretro_set_hwrender_interface(retro_hw_render_interface *hw_render_interface) {424vulkan = (retro_hw_render_interface_vulkan *)hw_render_interface;425}426427void vk_libretro_shutdown() {428memset(&vk_init_info, 0, sizeof(vk_init_info));429vulkan = nullptr;430DEDICATED_ALLOCATION = false;431}432433434