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.h
Views: 1401
/* Copyright (C) 2010-2016 The RetroArch team1*2* ---------------------------------------------------------------------------------------------3* The following license statement only applies to this libretro API header (libretro_vulkan.h)4* ---------------------------------------------------------------------------------------------5*6* Permission is hereby granted, free of charge,7* to any person obtaining a copy of this software and associated documentation files (the8* "Software"),9* to deal in the Software without restriction, including without limitation the rights to10* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,11* and to permit persons to whom the Software is furnished to do so, subject to the following12* conditions:13*14* The above copyright notice and this permission notice shall be included in all copies or15* substantial portions of the Software.16*17* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,18* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,19* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.20* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER21* LIABILITY,22* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,23* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.24*/2526#ifndef LIBRETRO_VULKAN_H__27#define LIBRETRO_VULKAN_H__2829#include "ext/vulkan/vulkan.h"30#include "libretro.h"31#include "LibretroGraphicsContext.h"3233#define RETRO_HW_RENDER_INTERFACE_VULKAN_VERSION 534#define RETRO_HW_RENDER_CONTEXT_NEGOTIATION_INTERFACE_VULKAN_VERSION 13536struct retro_vulkan_image37{38VkImageView image_view;39VkImageLayout image_layout;40VkImageViewCreateInfo create_info;41};4243typedef void (*retro_vulkan_set_image_t)(void* handle, const struct retro_vulkan_image* image,44uint32_t num_semaphores, const VkSemaphore* semaphores,45uint32_t src_queue_family);4647typedef uint32_t (*retro_vulkan_get_sync_index_t)(void* handle);48typedef uint32_t (*retro_vulkan_get_sync_index_mask_t)(void* handle);49typedef void (*retro_vulkan_set_command_buffers_t)(void* handle, uint32_t num_cmd,50const VkCommandBuffer* cmd);51typedef void (*retro_vulkan_wait_sync_index_t)(void* handle);52typedef void (*retro_vulkan_lock_queue_t)(void* handle);53typedef void (*retro_vulkan_unlock_queue_t)(void* handle);54typedef void (*retro_vulkan_set_signal_semaphore_t)(void* handle, VkSemaphore semaphore);5556typedef const VkApplicationInfo* (*retro_vulkan_get_application_info_t)(void);5758struct retro_vulkan_context59{60VkPhysicalDevice gpu;61VkDevice device;62VkQueue queue;63uint32_t queue_family_index;64VkQueue presentation_queue;65uint32_t presentation_queue_family_index;66};6768typedef bool (*retro_vulkan_create_device_t)(69struct retro_vulkan_context* context, VkInstance instance, VkPhysicalDevice gpu,70VkSurfaceKHR surface, PFN_vkGetInstanceProcAddr get_instance_proc_addr,71const char** required_device_extensions, unsigned num_required_device_extensions,72const char** required_device_layers, unsigned num_required_device_layers,73const VkPhysicalDeviceFeatures* required_features);7475typedef void (*retro_vulkan_destroy_device_t)(void);7677/* Note on thread safety:78* The Vulkan API is heavily designed around multi-threading, and79* the libretro interface for it should also be threading friendly.80* A core should be able to build command buffers and submit81* command buffers to the GPU from any thread.82*/8384struct retro_hw_render_context_negotiation_interface_vulkan85{86/* Must be set to RETRO_HW_RENDER_CONTEXT_NEGOTIATION_INTERFACE_VULKAN. */87enum retro_hw_render_context_negotiation_interface_type interface_type;88/* Must be set to RETRO_HW_RENDER_CONTEXT_NEGOTIATION_INTERFACE_VULKAN_VERSION. */89unsigned interface_version;9091/* If non-NULL, returns a VkApplicationInfo struct that the frontend can use instead of92* its "default" application info.93*/94retro_vulkan_get_application_info_t get_application_info;9596/* If non-NULL, the libretro core will choose one or more physical devices,97* create one or more logical devices and create one or more queues.98* The core must prepare a designated PhysicalDevice, Device, Queue and queue family index99* which the frontend will use for its internal operation.100*101* If gpu is not VK_NULL_HANDLE, the physical device provided to the frontend must be this102* PhysicalDevice.103* The core is still free to use other physical devices.104*105* The frontend will request certain extensions and layers for a device which is created.106* The core must ensure that the queue and queue_family_index support GRAPHICS and COMPUTE.107*108* If surface is not VK_NULL_HANDLE, the core must consider presentation when creating the queues.109* If presentation to "surface" is supported on the queue, presentation_queue must be equal to110* queue.111* If not, a second queue must be provided in presentation_queue and presentation_queue_index.112* If surface is not VK_NULL_HANDLE, the instance from frontend will have been created with113* supported for114* VK_KHR_surface extension.115*116* The core is free to set its own queue priorities.117* Device provided to frontend is owned by the frontend, but any additional device resources must118* be freed by core119* in destroy_device callback.120*121* If this function returns true, a PhysicalDevice, Device and Queues are initialized.122* If false, none of the above have been initialized and the frontend will attempt123* to fallback to "default" device creation, as if this function was never called.124*/125retro_vulkan_create_device_t create_device;126127/* If non-NULL, this callback is called similar to context_destroy for HW_RENDER_INTERFACE.128* However, it will be called even if context_reset was not called.129* This can happen if the context never succeeds in being created.130* destroy_device will always be called before the VkInstance131* of the frontend is destroyed if create_device was called successfully so that the core has a132* chance of133* tearing down its own device resources.134*135* Only auxillary resources should be freed here, i.e. resources which are not part of136* retro_vulkan_context.137*/138retro_vulkan_destroy_device_t destroy_device;139};140141struct retro_hw_render_interface_vulkan142{143/* Must be set to RETRO_HW_RENDER_INTERFACE_VULKAN. */144enum retro_hw_render_interface_type interface_type;145/* Must be set to RETRO_HW_RENDER_INTERFACE_VULKAN_VERSION. */146unsigned interface_version;147148/* Opaque handle to the Vulkan backend in the frontend149* which must be passed along to all function pointers150* in this interface.151*152* The rationale for including a handle here (which libretro v1153* doesn't currently do in general) is:154*155* - Vulkan cores should be able to be freely threaded without lots of fuzz.156* This would break frontends which currently rely on TLS157* to deal with multiple cores loaded at the same time.158* - Fixing this in general is TODO for an eventual libretro v2.159*/160void* handle;161162/* The Vulkan instance the context is using. */163VkInstance instance;164/* The physical device used. */165VkPhysicalDevice gpu;166/* The logical device used. */167VkDevice device;168169/* Allows a core to fetch all its needed symbols without having to link170* against the loader itself. */171PFN_vkGetDeviceProcAddr get_device_proc_addr;172PFN_vkGetInstanceProcAddr get_instance_proc_addr;173174/* The queue the core must use to submit data.175* This queue and index must remain constant throughout the lifetime176* of the context.177*178* This queue will be the queue that supports graphics and compute179* if the device supports compute.180*/181VkQueue queue;182unsigned queue_index;183184/* Before calling retro_video_refresh_t with RETRO_HW_FRAME_BUFFER_VALID,185* set which image to use for this frame.186*187* If num_semaphores is non-zero, the frontend will wait for the188* semaphores provided to be signaled before using the results further189* in the pipeline.190*191* Semaphores provided by a single call to set_image will only be192* waited for once (waiting for a semaphore resets it).193* E.g. set_image, video_refresh, and then another194* video_refresh without set_image,195* but same image will only wait for semaphores once.196*197* For this reason, ownership transfer will only occur if semaphores198* are waited on for a particular frame in the frontend.199*200* Using semaphores is optional for synchronization purposes,201* but if not using202* semaphores, an image memory barrier in vkCmdPipelineBarrier203* should be used in the graphics_queue.204* Example:205*206* vkCmdPipelineBarrier(cmd,207* srcStageMask = VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT,208* dstStageMask = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,209* image_memory_barrier = {210* srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,211* dstAccessMask = VK_ACCESS_SHADER_READ_BIT,212* });213*214* The use of pipeline barriers instead of semaphores is encouraged215* as it is simpler and more fine-grained. A layout transition216* must generally happen anyways which requires a217* pipeline barrier.218*219* The image passed to set_image must have imageUsage flags set to at least220* VK_IMAGE_USAGE_TRANSFER_SRC_BIT and VK_IMAGE_USAGE_SAMPLED_BIT.221* The core will naturally want to use flags such as222* VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT and/or223* VK_IMAGE_USAGE_TRANSFER_DST_BIT depending224* on how the final image is created.225*226* The image must also have been created with MUTABLE_FORMAT bit set if227* 8-bit formats are used, so that the frontend can reinterpret sRGB228* formats as it sees fit.229*230* Images passed to set_image should be created with TILING_OPTIMAL.231* The image layout should be transitioned to either232* VK_IMAGE_LAYOUT_GENERIC or VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL.233* The actual image layout used must be set in image_layout.234*235* The image must be a 2D texture which may or not be layered236* and/or mipmapped.237*238* The image must be suitable for linear sampling.239* While the image_view is typically the only field used,240* the frontend may want to reinterpret the texture as sRGB vs.241* non-sRGB for example so the VkImageViewCreateInfo used to242* create the image view must also be passed in.243*244* The data in the pointer to the image struct will not be copied245* as the pNext field in create_info cannot be reliably deep-copied.246* The image pointer passed to set_image must be valid until247* retro_video_refresh_t has returned.248*249* If frame duping is used when passing NULL to retro_video_refresh_t,250* the frontend is free to either use the latest image passed to251* set_image or reuse the older pointer passed to set_image the252* frame RETRO_HW_FRAME_BUFFER_VALID was last used.253*254* Essentially, the lifetime of the pointer passed to255* set_image should be extended if frame duping is used256* so that the frontend can reuse the older pointer.257*258* The image itself however, must not be touched by the core until259* wait_sync_index has been completed later. The frontend may perform260* layout transitions on the image, so even read-only access is not defined.261* The exception to read-only rule is if GENERAL layout is used for the image.262* In this case, the frontend is not allowed to perform any layout transitions,263* so concurrent reads from core and frontend are allowed.264*265* If frame duping is used, or if set_command_buffers is used,266* the frontend will not wait for any semaphores.267*268* The src_queue_family is used to specify which queue family269* the image is currently owned by. If using multiple queue families270* (e.g. async compute), the frontend will need to acquire ownership of the271* image before rendering with it and release the image afterwards.272*273* If src_queue_family is equal to the queue family (queue_index),274* no ownership transfer will occur.275* Similarly, if src_queue_family is VK_QUEUE_FAMILY_IGNORED,276* no ownership transfer will occur.277*278* The frontend will always release ownership back to src_queue_family.279* Waiting for frontend to complete with wait_sync_index() ensures that280* the frontend has released ownership back to the application.281* Note that in Vulkan, transfering ownership is a two-part process.282*283* Example frame:284* - core releases ownership from src_queue_index to queue_index with VkImageMemoryBarrier.285* - core calls set_image with src_queue_index.286* - Frontend will acquire the image with src_queue_index -> queue_index as well, completing the287* ownership transfer.288* - Frontend renders the frame.289* - Frontend releases ownership with queue_index -> src_queue_index.290* - Next time image is used, core must acquire ownership from queue_index ...291*292* Since the frontend releases ownership, we cannot necessarily dupe the frame because293* the core needs to make the roundtrip of ownership transfer.294*/295retro_vulkan_set_image_t set_image;296297/* Get the current sync index for this frame which is obtained in298* frontend by calling e.g. vkAcquireNextImageKHR before calling299* retro_run().300*301* This index will correspond to which swapchain buffer is currently302* the active one.303*304* Knowing this index is very useful for maintaining safe asynchronous CPU305* and GPU operation without stalling.306*307* The common pattern for synchronization is to receive fences when308* submitting command buffers to Vulkan (vkQueueSubmit) and add this fence309* to a list of fences for frame number get_sync_index().310*311* Next time we receive the same get_sync_index(), we can wait for the312* fences from before, which will usually return immediately as the313* frontend will generally also avoid letting the GPU run ahead too much.314*315* After the fence has signaled, we know that the GPU has completed all316* GPU work related to work submitted in the frame we last saw get_sync_index().317*318* This means we can safely reuse or free resources allocated in this frame.319*320* In theory, even if we wait for the fences correctly, it is not technically321* safe to write to the image we earlier passed to the frontend since we're322* not waiting for the frontend GPU jobs to complete.323*324* The frontend will guarantee that the appropriate pipeline barrier325* in graphics_queue has been used such that326* VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT cannot327* start until the frontend is done with the image.328*/329retro_vulkan_get_sync_index_t get_sync_index;330331/* Returns a bitmask of how many swapchain images we currently have332* in the frontend.333*334* If bit #N is set in the return value, get_sync_index can return N.335* Knowing this value is useful for preallocating per-frame management336* structures ahead of time.337*338* While this value will typically remain constant throughout the339* applications lifecycle, it may for example change if the frontend340* suddently changes fullscreen state and/or latency.341*342* If this value ever changes, it is safe to assume that the device343* is completely idle and all synchronization objects can be deleted344* right away as desired.345*/346retro_vulkan_get_sync_index_mask_t get_sync_index_mask;347348/* Instead of submitting the command buffer to the queue first, the core349* can pass along its command buffer to the frontend, and the frontend350* will submit the command buffer together with the frontends command buffers.351*352* This has the advantage that the overhead of vkQueueSubmit can be353* amortized into a single call. For this mode, semaphores in set_image354* will be ignored, so vkCmdPipelineBarrier must be used to synchronize355* the core and frontend.356*357* The command buffers in set_command_buffers are only executed once,358* even if frame duping is used.359*360* If frame duping is used, set_image should be used for the frames361* which should be duped instead.362*363* Command buffers passed to the frontend with set_command_buffers364* must not actually be submitted to the GPU until retro_video_refresh_t365* is called.366*367* The frontend must submit the command buffer before submitting any368* other command buffers provided by set_command_buffers. */369retro_vulkan_set_command_buffers_t set_command_buffers;370371/* Waits on CPU for device activity for the current sync index to complete.372* This is useful since the core will not have a relevant fence to sync with373* when the frontend is submitting the command buffers. */374retro_vulkan_wait_sync_index_t wait_sync_index;375376/* If the core submits command buffers itself to any of the queues provided377* in this interface, the core must lock and unlock the frontend from378* racing on the VkQueue.379*380* Queue submission can happen on any thread.381* Even if queue submission happens on the same thread as retro_run(),382* the lock/unlock functions must still be called.383*384* NOTE: Queue submissions are heavy-weight. */385retro_vulkan_lock_queue_t lock_queue;386retro_vulkan_unlock_queue_t unlock_queue;387388/* Sets a semaphore which is signaled when the image in set_image can safely be reused.389* The semaphore is consumed next call to retro_video_refresh_t.390* The semaphore will be signalled even for duped frames.391* The semaphore will be signalled only once, so set_signal_semaphore should be called every392* frame.393* The semaphore may be VK_NULL_HANDLE, which disables semaphore signalling for next call to394* retro_video_refresh_t.395*396* This is mostly useful to support use cases where you're rendering to a single image that397* is recycled in a ping-pong fashion with the frontend to save memory (but potentially less398* throughput).399*/400retro_vulkan_set_signal_semaphore_t set_signal_semaphore;401};402403#endif404405406