Commit | Line | Data |
---|---|---|
3719602c PC |
1 | /* Copyright (C) 2010-2020 The RetroArch team |
2 | * | |
3 | * --------------------------------------------------------------------------------------------- | |
4 | * The following license statement only applies to this libretro API header (libretro_vulkan.h) | |
5 | * --------------------------------------------------------------------------------------------- | |
6 | * | |
7 | * Permission is hereby granted, free of charge, | |
8 | * to any person obtaining a copy of this software and associated documentation files (the "Software"), | |
9 | * to deal in the Software without restriction, including without limitation the rights to | |
10 | * 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 following conditions: | |
12 | * | |
13 | * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. | |
14 | * | |
15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, | |
16 | * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
17 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. | |
18 | * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, | |
19 | * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |
20 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | |
21 | */ | |
22 | ||
23 | #ifndef LIBRETRO_VULKAN_H__ | |
24 | #define LIBRETRO_VULKAN_H__ | |
25 | ||
26 | #include <libretro.h> | |
27 | #include <vulkan/vulkan.h> | |
28 | ||
29 | #define RETRO_HW_RENDER_INTERFACE_VULKAN_VERSION 5 | |
30 | #define RETRO_HW_RENDER_CONTEXT_NEGOTIATION_INTERFACE_VULKAN_VERSION 2 | |
31 | ||
32 | struct retro_vulkan_image | |
33 | { | |
34 | VkImageView image_view; | |
35 | VkImageLayout image_layout; | |
36 | VkImageViewCreateInfo create_info; | |
37 | }; | |
38 | ||
39 | typedef void (*retro_vulkan_set_image_t)(void *handle, | |
40 | const struct retro_vulkan_image *image, | |
41 | uint32_t num_semaphores, | |
42 | const VkSemaphore *semaphores, | |
43 | uint32_t src_queue_family); | |
44 | ||
45 | typedef uint32_t (*retro_vulkan_get_sync_index_t)(void *handle); | |
46 | typedef uint32_t (*retro_vulkan_get_sync_index_mask_t)(void *handle); | |
47 | typedef void (*retro_vulkan_set_command_buffers_t)(void *handle, | |
48 | uint32_t num_cmd, | |
49 | const VkCommandBuffer *cmd); | |
50 | typedef void (*retro_vulkan_wait_sync_index_t)(void *handle); | |
51 | typedef void (*retro_vulkan_lock_queue_t)(void *handle); | |
52 | typedef void (*retro_vulkan_unlock_queue_t)(void *handle); | |
53 | typedef void (*retro_vulkan_set_signal_semaphore_t)(void *handle, VkSemaphore semaphore); | |
54 | ||
55 | typedef const VkApplicationInfo *(*retro_vulkan_get_application_info_t)(void); | |
56 | ||
57 | struct retro_vulkan_context | |
58 | { | |
59 | VkPhysicalDevice gpu; | |
60 | VkDevice device; | |
61 | VkQueue queue; | |
62 | uint32_t queue_family_index; | |
63 | VkQueue presentation_queue; | |
64 | uint32_t presentation_queue_family_index; | |
65 | }; | |
66 | ||
67 | /* This is only used in v1 of the negotiation interface. | |
68 | * It is deprecated since it cannot express PDF2 features or optional extensions. */ | |
69 | typedef bool (*retro_vulkan_create_device_t)( | |
70 | struct retro_vulkan_context *context, | |
71 | VkInstance instance, | |
72 | VkPhysicalDevice gpu, | |
73 | VkSurfaceKHR surface, | |
74 | PFN_vkGetInstanceProcAddr get_instance_proc_addr, | |
75 | const char **required_device_extensions, | |
76 | unsigned num_required_device_extensions, | |
77 | const char **required_device_layers, | |
78 | unsigned num_required_device_layers, | |
79 | const VkPhysicalDeviceFeatures *required_features); | |
80 | ||
81 | typedef void (*retro_vulkan_destroy_device_t)(void); | |
82 | ||
83 | /* v2 CONTEXT_NEGOTIATION_INTERFACE only. */ | |
84 | typedef VkInstance (*retro_vulkan_create_instance_wrapper_t)( | |
85 | void *opaque, const VkInstanceCreateInfo *create_info); | |
86 | ||
87 | /* v2 CONTEXT_NEGOTIATION_INTERFACE only. */ | |
88 | typedef VkInstance (*retro_vulkan_create_instance_t)( | |
89 | PFN_vkGetInstanceProcAddr get_instance_proc_addr, | |
90 | const VkApplicationInfo *app, | |
91 | retro_vulkan_create_instance_wrapper_t create_instance_wrapper, | |
92 | void *opaque); | |
93 | ||
94 | /* v2 CONTEXT_NEGOTIATION_INTERFACE only. */ | |
95 | typedef VkDevice (*retro_vulkan_create_device_wrapper_t)( | |
96 | VkPhysicalDevice gpu, void *opaque, | |
97 | const VkDeviceCreateInfo *create_info); | |
98 | ||
99 | /* v2 CONTEXT_NEGOTIATION_INTERFACE only. */ | |
100 | typedef bool (*retro_vulkan_create_device2_t)( | |
101 | struct retro_vulkan_context *context, | |
102 | VkInstance instance, | |
103 | VkPhysicalDevice gpu, | |
104 | VkSurfaceKHR surface, | |
105 | PFN_vkGetInstanceProcAddr get_instance_proc_addr, | |
106 | retro_vulkan_create_device_wrapper_t create_device_wrapper, | |
107 | void *opaque); | |
108 | ||
109 | /* Note on thread safety: | |
110 | * The Vulkan API is heavily designed around multi-threading, and | |
111 | * the libretro interface for it should also be threading friendly. | |
112 | * A core should be able to build command buffers and submit | |
113 | * command buffers to the GPU from any thread. | |
114 | */ | |
115 | ||
116 | struct retro_hw_render_context_negotiation_interface_vulkan | |
117 | { | |
118 | /* Must be set to RETRO_HW_RENDER_CONTEXT_NEGOTIATION_INTERFACE_VULKAN. */ | |
119 | enum retro_hw_render_context_negotiation_interface_type interface_type; | |
120 | /* Usually set to RETRO_HW_RENDER_CONTEXT_NEGOTIATION_INTERFACE_VULKAN_VERSION, | |
121 | * but can be lower depending on GET_HW_RENDER_CONTEXT_NEGOTIATION_INTERFACE_SUPPORT. */ | |
122 | unsigned interface_version; | |
123 | ||
124 | /* If non-NULL, returns a VkApplicationInfo struct that the frontend can use instead of | |
125 | * its "default" application info. | |
126 | * VkApplicationInfo::apiVersion also controls the target core Vulkan version for instance level functionality. | |
127 | * Lifetime of the returned pointer must remain until the retro_vulkan_context is initialized. | |
128 | * | |
129 | * NOTE: For optimal compatibility with e.g. Android which is very slow to update its loader, | |
130 | * a core version of 1.1 should be requested. Features beyond that can be requested with extensions. | |
131 | * Vulkan 1.0 is only appropriate for legacy cores, but is still supported. | |
132 | * A frontend is free to bump the instance creation apiVersion as necessary if the frontend requires more advanced core features. | |
133 | * | |
134 | * v2: This function must not be NULL, and must not return NULL. | |
135 | * v1: It was not clearly defined if this function could return NULL. | |
136 | * Frontends should be defensive and provide a default VkApplicationInfo | |
137 | * if this function returns NULL or if this function is NULL. | |
138 | */ | |
139 | retro_vulkan_get_application_info_t get_application_info; | |
140 | ||
141 | /* If non-NULL, the libretro core will choose one or more physical devices, | |
142 | * create one or more logical devices and create one or more queues. | |
143 | * The core must prepare a designated PhysicalDevice, Device, Queue and queue family index | |
144 | * which the frontend will use for its internal operation. | |
145 | * | |
146 | * If gpu is not VK_NULL_HANDLE, the physical device provided to the frontend must be this PhysicalDevice if the call succeeds. | |
147 | * The core is still free to use other physical devices for other purposes that are private to the core. | |
148 | * | |
149 | * The frontend will request certain extensions and layers for a device which is created. | |
150 | * The core must ensure that the queue and queue_family_index support GRAPHICS and COMPUTE. | |
151 | * | |
152 | * If surface is not VK_NULL_HANDLE, the core must consider presentation when creating the queues. | |
153 | * If presentation to "surface" is supported on the queue, presentation_queue must be equal to queue. | |
154 | * If not, a second queue must be provided in presentation_queue and presentation_queue_index. | |
155 | * If surface is not VK_NULL_HANDLE, the instance from frontend will have been created with supported for | |
156 | * VK_KHR_surface extension. | |
157 | * | |
158 | * The core is free to set its own queue priorities. | |
159 | * Device provided to frontend is owned by the frontend, but any additional device resources must be freed by core | |
160 | * in destroy_device callback. | |
161 | * | |
162 | * If this function returns true, a PhysicalDevice, Device and Queues are initialized. | |
163 | * If false, none of the above have been initialized and the frontend will attempt | |
164 | * to fallback to "default" device creation, as if this function was never called. | |
165 | */ | |
166 | retro_vulkan_create_device_t create_device; | |
167 | ||
168 | /* If non-NULL, this callback is called similar to context_destroy for HW_RENDER_INTERFACE. | |
169 | * However, it will be called even if context_reset was not called. | |
170 | * This can happen if the context never succeeds in being created. | |
171 | * destroy_device will always be called before the VkInstance | |
172 | * of the frontend is destroyed if create_device was called successfully so that the core has a chance of | |
173 | * tearing down its own device resources. | |
174 | * | |
175 | * Only auxillary resources should be freed here, i.e. resources which are not part of retro_vulkan_context. | |
176 | * v2: Auxillary instance resources created during create_instance can also be freed here. | |
177 | */ | |
178 | retro_vulkan_destroy_device_t destroy_device; | |
179 | ||
180 | /* v2 API: If interface_version is < 2, fields below must be ignored. | |
181 | * If the frontend does not support interface version 2, the v1 entry points will be used instead. */ | |
182 | ||
183 | /* If non-NULL, this is called to create an instance, otherwise a VkInstance is created by the frontend. | |
184 | * v1 interface bug: The only way to enable instance features is through core versions signalled in VkApplicationInfo. | |
185 | * The frontend may request that certain extensions and layers | |
186 | * are enabled on the VkInstance. Application may add additional features. | |
187 | * If app is non-NULL, apiVersion controls the minimum core version required by the application. | |
188 | * Return a VkInstance or VK_NULL_HANDLE. The VkInstance is owned by the frontend. | |
189 | * | |
190 | * Rather than call vkCreateInstance directly, a core must call the CreateInstance wrapper provided with: | |
191 | * VkInstance instance = create_instance_wrapper(opaque, &create_info); | |
192 | * If the core wishes to create a private instance for whatever reason (relying on shared memory for example), | |
193 | * it may call vkCreateInstance directly. */ | |
194 | retro_vulkan_create_instance_t create_instance; | |
195 | ||
196 | /* If non-NULL and frontend recognizes negotiation interface >= 2, create_device2 takes precedence over create_device. | |
197 | * Similar to create_device, but is extended to better understand new core versions and PDF2 feature enablement. | |
198 | * Requirements for create_device2 are the same as create_device unless a difference is mentioned. | |
199 | * | |
200 | * v2 consideration: | |
201 | * If the chosen gpu by frontend cannot be supported, a core must return false. | |
202 | * | |
203 | * NOTE: "Cannot be supported" is intentionally vaguely defined. | |
204 | * Refusing to run on an iGPU for a very intensive core with desktop GPU as a minimum spec may be in the gray area. | |
205 | * Not supporting optional features is not a good reason to reject a physical device, however. | |
206 | * | |
207 | * On device creation feature with explicit gpu, a frontend should fall back create_device2 with gpu == VK_NULL_HANDLE and let core | |
208 | * decide on a supported device if possible. | |
209 | * | |
210 | * A core must assume that the explicitly provided GPU is the only guaranteed attempt it has to create a device. | |
211 | * A fallback may not be attempted if there are particular reasons why only a specific physical device can work, | |
212 | * but these situations should be esoteric and rare in nature, e.g. a libretro frontend is implemented with external memory | |
213 | * and only LUID matching would work. | |
214 | * Cores and frontends should ensure "best effort" when negotiating like this and appropriate logging is encouraged. | |
215 | * | |
216 | * v1 note: In the v1 version of create_device, it was never expected that create_device would fail like this, | |
217 | * and frontends are not expected to attempt fall backs. | |
218 | * | |
219 | * Rather than call vkCreateDevice directly, a core must call the CreateDevice wrapper provided with: | |
220 | * VkDevice device = create_device_wrapper(gpu, opaque, &create_info); | |
221 | * If the core wishes to create a private device for whatever reason (relying on shared memory for example), | |
222 | * it may call vkCreateDevice directly. | |
223 | * | |
224 | * This allows the frontend to add additional extensions that it requires as well as adjust the PDF2 pNext as required. | |
225 | * It is also possible adjust the queue create infos in case the frontend desires to allocate some private queues. | |
226 | * | |
227 | * The get_instance_proc_addr provided in create_device2 must be the same as create_instance. | |
228 | * | |
229 | * NOTE: The frontend must not disable features requested by application. | |
230 | * NOTE: The frontend must not add any robustness features as some API behavior may change (VK_EXT_descriptor_buffer comes to mind). | |
231 | * I.e. robustBufferAccess and the like. (nullDescriptor from robustness2 is allowed to be enabled). | |
232 | */ | |
233 | retro_vulkan_create_device2_t create_device2; | |
234 | }; | |
235 | ||
236 | struct retro_hw_render_interface_vulkan | |
237 | { | |
238 | /* Must be set to RETRO_HW_RENDER_INTERFACE_VULKAN. */ | |
239 | enum retro_hw_render_interface_type interface_type; | |
240 | /* Must be set to RETRO_HW_RENDER_INTERFACE_VULKAN_VERSION. */ | |
241 | unsigned interface_version; | |
242 | ||
243 | /* Opaque handle to the Vulkan backend in the frontend | |
244 | * which must be passed along to all function pointers | |
245 | * in this interface. | |
246 | * | |
247 | * The rationale for including a handle here (which libretro v1 | |
248 | * doesn't currently do in general) is: | |
249 | * | |
250 | * - Vulkan cores should be able to be freely threaded without lots of fuzz. | |
251 | * This would break frontends which currently rely on TLS | |
252 | * to deal with multiple cores loaded at the same time. | |
253 | * - Fixing this in general is TODO for an eventual libretro v2. | |
254 | */ | |
255 | void *handle; | |
256 | ||
257 | /* The Vulkan instance the context is using. */ | |
258 | VkInstance instance; | |
259 | /* The physical device used. */ | |
260 | VkPhysicalDevice gpu; | |
261 | /* The logical device used. */ | |
262 | VkDevice device; | |
263 | ||
264 | /* Allows a core to fetch all its needed symbols without having to link | |
265 | * against the loader itself. */ | |
266 | PFN_vkGetDeviceProcAddr get_device_proc_addr; | |
267 | PFN_vkGetInstanceProcAddr get_instance_proc_addr; | |
268 | ||
269 | /* The queue the core must use to submit data. | |
270 | * This queue and index must remain constant throughout the lifetime | |
271 | * of the context. | |
272 | * | |
273 | * This queue will be the queue that supports graphics and compute | |
274 | * if the device supports compute. | |
275 | */ | |
276 | VkQueue queue; | |
277 | unsigned queue_index; | |
278 | ||
279 | /* Before calling retro_video_refresh_t with RETRO_HW_FRAME_BUFFER_VALID, | |
280 | * set which image to use for this frame. | |
281 | * | |
282 | * If num_semaphores is non-zero, the frontend will wait for the | |
283 | * semaphores provided to be signaled before using the results further | |
284 | * in the pipeline. | |
285 | * | |
286 | * Semaphores provided by a single call to set_image will only be | |
287 | * waited for once (waiting for a semaphore resets it). | |
288 | * E.g. set_image, video_refresh, and then another | |
289 | * video_refresh without set_image, | |
290 | * but same image will only wait for semaphores once. | |
291 | * | |
292 | * For this reason, ownership transfer will only occur if semaphores | |
293 | * are waited on for a particular frame in the frontend. | |
294 | * | |
295 | * Using semaphores is optional for synchronization purposes, | |
296 | * but if not using | |
297 | * semaphores, an image memory barrier in vkCmdPipelineBarrier | |
298 | * should be used in the graphics_queue. | |
299 | * Example: | |
300 | * | |
301 | * vkCmdPipelineBarrier(cmd, | |
302 | * srcStageMask = VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT, | |
303 | * dstStageMask = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, | |
304 | * image_memory_barrier = { | |
305 | * srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, | |
306 | * dstAccessMask = VK_ACCESS_SHADER_READ_BIT, | |
307 | * }); | |
308 | * | |
309 | * The use of pipeline barriers instead of semaphores is encouraged | |
310 | * as it is simpler and more fine-grained. A layout transition | |
311 | * must generally happen anyways which requires a | |
312 | * pipeline barrier. | |
313 | * | |
314 | * The image passed to set_image must have imageUsage flags set to at least | |
315 | * VK_IMAGE_USAGE_TRANSFER_SRC_BIT and VK_IMAGE_USAGE_SAMPLED_BIT. | |
316 | * The core will naturally want to use flags such as | |
317 | * VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT and/or | |
318 | * VK_IMAGE_USAGE_TRANSFER_DST_BIT depending | |
319 | * on how the final image is created. | |
320 | * | |
321 | * The image must also have been created with MUTABLE_FORMAT bit set if | |
322 | * 8-bit formats are used, so that the frontend can reinterpret sRGB | |
323 | * formats as it sees fit. | |
324 | * | |
325 | * Images passed to set_image should be created with TILING_OPTIMAL. | |
326 | * The image layout should be transitioned to either | |
327 | * VK_IMAGE_LAYOUT_GENERIC or VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL. | |
328 | * The actual image layout used must be set in image_layout. | |
329 | * | |
330 | * The image must be a 2D texture which may or not be layered | |
331 | * and/or mipmapped. | |
332 | * | |
333 | * The image must be suitable for linear sampling. | |
334 | * While the image_view is typically the only field used, | |
335 | * the frontend may want to reinterpret the texture as sRGB vs. | |
336 | * non-sRGB for example so the VkImageViewCreateInfo used to | |
337 | * create the image view must also be passed in. | |
338 | * | |
339 | * The data in the pointer to the image struct will not be copied | |
340 | * as the pNext field in create_info cannot be reliably deep-copied. | |
341 | * The image pointer passed to set_image must be valid until | |
342 | * retro_video_refresh_t has returned. | |
343 | * | |
344 | * If frame duping is used when passing NULL to retro_video_refresh_t, | |
345 | * the frontend is free to either use the latest image passed to | |
346 | * set_image or reuse the older pointer passed to set_image the | |
347 | * frame RETRO_HW_FRAME_BUFFER_VALID was last used. | |
348 | * | |
349 | * Essentially, the lifetime of the pointer passed to | |
350 | * retro_video_refresh_t should be extended if frame duping is used | |
351 | * so that the frontend can reuse the older pointer. | |
352 | * | |
353 | * The image itself however, must not be touched by the core until | |
354 | * wait_sync_index has been completed later. The frontend may perform | |
355 | * layout transitions on the image, so even read-only access is not defined. | |
356 | * The exception to read-only rule is if GENERAL layout is used for the image. | |
357 | * In this case, the frontend is not allowed to perform any layout transitions, | |
358 | * so concurrent reads from core and frontend are allowed. | |
359 | * | |
360 | * If frame duping is used, or if set_command_buffers is used, | |
361 | * the frontend will not wait for any semaphores. | |
362 | * | |
363 | * The src_queue_family is used to specify which queue family | |
364 | * the image is currently owned by. If using multiple queue families | |
365 | * (e.g. async compute), the frontend will need to acquire ownership of the | |
366 | * image before rendering with it and release the image afterwards. | |
367 | * | |
368 | * If src_queue_family is equal to the queue family (queue_index), | |
369 | * no ownership transfer will occur. | |
370 | * Similarly, if src_queue_family is VK_QUEUE_FAMILY_IGNORED, | |
371 | * no ownership transfer will occur. | |
372 | * | |
373 | * The frontend will always release ownership back to src_queue_family. | |
374 | * Waiting for frontend to complete with wait_sync_index() ensures that | |
375 | * the frontend has released ownership back to the application. | |
376 | * Note that in Vulkan, transfering ownership is a two-part process. | |
377 | * | |
378 | * Example frame: | |
379 | * - core releases ownership from src_queue_index to queue_index with VkImageMemoryBarrier. | |
380 | * - core calls set_image with src_queue_index. | |
381 | * - Frontend will acquire the image with src_queue_index -> queue_index as well, completing the ownership transfer. | |
382 | * - Frontend renders the frame. | |
383 | * - Frontend releases ownership with queue_index -> src_queue_index. | |
384 | * - Next time image is used, core must acquire ownership from queue_index ... | |
385 | * | |
386 | * Since the frontend releases ownership, we cannot necessarily dupe the frame because | |
387 | * the core needs to make the roundtrip of ownership transfer. | |
388 | */ | |
389 | retro_vulkan_set_image_t set_image; | |
390 | ||
391 | /* Get the current sync index for this frame which is obtained in | |
392 | * frontend by calling e.g. vkAcquireNextImageKHR before calling | |
393 | * retro_run(). | |
394 | * | |
395 | * This index will correspond to which swapchain buffer is currently | |
396 | * the active one. | |
397 | * | |
398 | * Knowing this index is very useful for maintaining safe asynchronous CPU | |
399 | * and GPU operation without stalling. | |
400 | * | |
401 | * The common pattern for synchronization is to receive fences when | |
402 | * submitting command buffers to Vulkan (vkQueueSubmit) and add this fence | |
403 | * to a list of fences for frame number get_sync_index(). | |
404 | * | |
405 | * Next time we receive the same get_sync_index(), we can wait for the | |
406 | * fences from before, which will usually return immediately as the | |
407 | * frontend will generally also avoid letting the GPU run ahead too much. | |
408 | * | |
409 | * After the fence has signaled, we know that the GPU has completed all | |
410 | * GPU work related to work submitted in the frame we last saw get_sync_index(). | |
411 | * | |
412 | * This means we can safely reuse or free resources allocated in this frame. | |
413 | * | |
414 | * In theory, even if we wait for the fences correctly, it is not technically | |
415 | * safe to write to the image we earlier passed to the frontend since we're | |
416 | * not waiting for the frontend GPU jobs to complete. | |
417 | * | |
418 | * The frontend will guarantee that the appropriate pipeline barrier | |
419 | * in graphics_queue has been used such that | |
420 | * VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT cannot | |
421 | * start until the frontend is done with the image. | |
422 | */ | |
423 | retro_vulkan_get_sync_index_t get_sync_index; | |
424 | ||
425 | /* Returns a bitmask of how many swapchain images we currently have | |
426 | * in the frontend. | |
427 | * | |
428 | * If bit #N is set in the return value, get_sync_index can return N. | |
429 | * Knowing this value is useful for preallocating per-frame management | |
430 | * structures ahead of time. | |
431 | * | |
432 | * While this value will typically remain constant throughout the | |
433 | * applications lifecycle, it may for example change if the frontend | |
434 | * suddently changes fullscreen state and/or latency. | |
435 | * | |
436 | * If this value ever changes, it is safe to assume that the device | |
437 | * is completely idle and all synchronization objects can be deleted | |
438 | * right away as desired. | |
439 | */ | |
440 | retro_vulkan_get_sync_index_mask_t get_sync_index_mask; | |
441 | ||
442 | /* Instead of submitting the command buffer to the queue first, the core | |
443 | * can pass along its command buffer to the frontend, and the frontend | |
444 | * will submit the command buffer together with the frontends command buffers. | |
445 | * | |
446 | * This has the advantage that the overhead of vkQueueSubmit can be | |
447 | * amortized into a single call. For this mode, semaphores in set_image | |
448 | * will be ignored, so vkCmdPipelineBarrier must be used to synchronize | |
449 | * the core and frontend. | |
450 | * | |
451 | * The command buffers in set_command_buffers are only executed once, | |
452 | * even if frame duping is used. | |
453 | * | |
454 | * If frame duping is used, set_image should be used for the frames | |
455 | * which should be duped instead. | |
456 | * | |
457 | * Command buffers passed to the frontend with set_command_buffers | |
458 | * must not actually be submitted to the GPU until retro_video_refresh_t | |
459 | * is called. | |
460 | * | |
461 | * The frontend must submit the command buffer before submitting any | |
462 | * other command buffers provided by set_command_buffers. */ | |
463 | retro_vulkan_set_command_buffers_t set_command_buffers; | |
464 | ||
465 | /* Waits on CPU for device activity for the current sync index to complete. | |
466 | * This is useful since the core will not have a relevant fence to sync with | |
467 | * when the frontend is submitting the command buffers. */ | |
468 | retro_vulkan_wait_sync_index_t wait_sync_index; | |
469 | ||
470 | /* If the core submits command buffers itself to any of the queues provided | |
471 | * in this interface, the core must lock and unlock the frontend from | |
472 | * racing on the VkQueue. | |
473 | * | |
474 | * Queue submission can happen on any thread. | |
475 | * Even if queue submission happens on the same thread as retro_run(), | |
476 | * the lock/unlock functions must still be called. | |
477 | * | |
478 | * NOTE: Queue submissions are heavy-weight. */ | |
479 | retro_vulkan_lock_queue_t lock_queue; | |
480 | retro_vulkan_unlock_queue_t unlock_queue; | |
481 | ||
482 | /* Sets a semaphore which is signaled when the image in set_image can safely be reused. | |
483 | * The semaphore is consumed next call to retro_video_refresh_t. | |
484 | * The semaphore will be signalled even for duped frames. | |
485 | * The semaphore will be signalled only once, so set_signal_semaphore should be called every frame. | |
486 | * The semaphore may be VK_NULL_HANDLE, which disables semaphore signalling for next call to retro_video_refresh_t. | |
487 | * | |
488 | * This is mostly useful to support use cases where you're rendering to a single image that | |
489 | * is recycled in a ping-pong fashion with the frontend to save memory (but potentially less throughput). | |
490 | */ | |
491 | retro_vulkan_set_signal_semaphore_t set_signal_semaphore; | |
492 | }; | |
493 | ||
494 | #endif |