1 /* RetroArch - A frontend for libretro.
2 * Copyright (C) 2016-2017 - Hans-Kristian Arntzen
3 *
4 * RetroArch is free software: you can redistribute it and/or modify it under the terms
5 * of the GNU General Public License as published by the Free Software Found-
6 * ation, either version 3 of the License, or (at your option) any later version.
7 *
8 * RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
9 * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
10 * PURPOSE. See the GNU General Public License for more details.
11 *
12 * You should have received a copy of the GNU General Public License along with RetroArch.
13 * If not, see <http://www.gnu.org/licenses/>.
14 */
15
16 #ifndef VULKAN_COMMON_H__
17 #define VULKAN_COMMON_H__
18
19 #ifdef HAVE_CONFIG_H
20 #include "../../config.h"
21 #endif
22
23 #include <lists/string_list.h>
24
25
26 #define VULKAN_DESCRIPTOR_MANAGER_BLOCK_SETS 16
27 #define VULKAN_MAX_DESCRIPTOR_POOL_SIZES 16
28 #define VULKAN_BUFFER_BLOCK_SIZE (64 * 1024)
29
30 #define VULKAN_MAX_SWAPCHAIN_IMAGES 8
31
32 #define VULKAN_DIRTY_DYNAMIC_BIT 0x0001
33
34 #include "vksym.h"
35
36 #include <boolean.h>
37 #include <retro_inline.h>
38 #include <retro_common_api.h>
39 #include <retro_miscellaneous.h>
40 #include <gfx/math/matrix_4x4.h>
41 #include <gfx/scaler/scaler.h>
42 #include <rthreads/rthreads.h>
43 #include <formats/image.h>
44
45 #include <libretro.h>
46 #include <libretro_vulkan.h>
47
48 #include "../video_defines.h"
49 #include "../../driver.h"
50 #include "../../retroarch.h"
51 #include "../../verbosity.h"
52 #include "../font_driver.h"
53 #include "../drivers_shader/shader_vulkan.h"
54 #include "../include/vulkan/vulkan.h"
55
56 RETRO_BEGIN_DECLS
57
58 enum vk_texture_type
59 {
60 /* We will use the texture as a sampled linear texture. */
61 VULKAN_TEXTURE_STREAMED = 0,
62
63 /* We will use the texture as a linear texture, but only
64 * for copying to a DYNAMIC texture. */
65 VULKAN_TEXTURE_STAGING,
66
67 /* We will use the texture as an optimally tiled texture,
68 * and we will update the texture by copying from STAGING
69 * textures. */
70 VULKAN_TEXTURE_DYNAMIC,
71
72 /* We will upload content once. */
73 VULKAN_TEXTURE_STATIC,
74
75 /* We will use the texture for reading back transfers from GPU. */
76 VULKAN_TEXTURE_READBACK
77 };
78
79 enum vulkan_wsi_type
80 {
81 VULKAN_WSI_NONE = 0,
82 VULKAN_WSI_WAYLAND,
83 VULKAN_WSI_MIR,
84 VULKAN_WSI_ANDROID,
85 VULKAN_WSI_WIN32,
86 VULKAN_WSI_XCB,
87 VULKAN_WSI_XLIB,
88 VULKAN_WSI_DISPLAY,
89 VULKAN_WSI_MVK_MACOS,
90 VULKAN_WSI_MVK_IOS,
91 };
92
93 typedef struct vulkan_context
94 {
95 slock_t *queue_lock;
96 retro_vulkan_destroy_device_t destroy_device; /* ptr alignment */
97
98 VkInstance instance;
99 VkPhysicalDevice gpu;
100 VkDevice device;
101 VkQueue queue;
102
103 VkPhysicalDeviceProperties gpu_properties;
104 VkPhysicalDeviceMemoryProperties memory_properties;
105
106 VkImage swapchain_images[VULKAN_MAX_SWAPCHAIN_IMAGES];
107 VkFence swapchain_fences[VULKAN_MAX_SWAPCHAIN_IMAGES];
108 VkFormat swapchain_format;
109
110 VkSemaphore swapchain_semaphores[VULKAN_MAX_SWAPCHAIN_IMAGES];
111 VkSemaphore swapchain_acquire_semaphore;
112 VkSemaphore swapchain_recycled_semaphores[VULKAN_MAX_SWAPCHAIN_IMAGES];
113 VkSemaphore swapchain_wait_semaphores[VULKAN_MAX_SWAPCHAIN_IMAGES];
114
115 #ifdef VULKAN_DEBUG
116 VkDebugReportCallbackEXT debug_callback;
117 #endif
118 uint32_t graphics_queue_index;
119 uint32_t num_swapchain_images;
120 uint32_t current_swapchain_index;
121 uint32_t current_frame_index;
122
123 unsigned swapchain_width;
124 unsigned swapchain_height;
125 unsigned swap_interval;
126 unsigned num_recycled_acquire_semaphores;
127
128 bool swapchain_fences_signalled[VULKAN_MAX_SWAPCHAIN_IMAGES];
129 bool invalid_swapchain;
130 /* Used by screenshot to get blits with correct colorspace. */
131 bool swapchain_is_srgb;
132 bool swap_interval_emulation_lock;
133 bool has_acquired_swapchain;
134 } vulkan_context_t;
135
136 struct vulkan_emulated_mailbox
137 {
138 sthread_t *thread;
139 slock_t *lock;
140 scond_t *cond;
141 VkDevice device; /* ptr alignment */
142 VkSwapchainKHR swapchain; /* ptr alignment */
143
144 unsigned index;
145 VkResult result; /* enum alignment */
146 bool acquired;
147 bool request_acquire;
148 bool dead;
149 bool has_pending_request;
150 };
151
152 typedef struct gfx_ctx_vulkan_data
153 {
154 struct string_list *gpu_list;
155
156 vulkan_context_t context;
157 VkSurfaceKHR vk_surface; /* ptr alignment */
158 VkSwapchainKHR swapchain; /* ptr alignment */
159
160 struct vulkan_emulated_mailbox mailbox;
161
162 /* Used to check if we need to use mailbox emulation or not.
163 * Only relevant on Windows for now. */
164 bool fullscreen;
165
166 bool need_new_swapchain;
167 bool created_new_swapchain;
168 bool emulate_mailbox;
169 bool emulating_mailbox;
170 /* If set, prefer a path where we use
171 * semaphores instead of fences for vkAcquireNextImageKHR.
172 * Helps workaround certain performance issues on some drivers. */
173 bool use_wsi_semaphore;
174 } gfx_ctx_vulkan_data_t;
175
176 struct vulkan_display_surface_info
177 {
178 unsigned width;
179 unsigned height;
180 unsigned monitor_index;
181 };
182
183 struct vk_color
184 {
185 float r, g, b, a;
186 };
187
188 struct vk_vertex
189 {
190 float x, y;
191 float tex_x, tex_y;
192 struct vk_color color; /* float alignment */
193 };
194
195 struct vk_image
196 {
197 VkImage image; /* ptr alignment */
198 VkImageView view; /* ptr alignment */
199 VkFramebuffer framebuffer; /* ptr alignment */
200 };
201
202 struct vk_texture
203 {
204 VkDeviceSize memory_size; /* uint64_t alignment */
205
206 void *mapped;
207 VkImage image; /* ptr alignment */
208 VkImageView view; /* ptr alignment */
209 VkBuffer buffer; /* ptr alignment */
210 VkDeviceMemory memory; /* ptr alignment */
211
212 size_t offset;
213 size_t stride;
214 size_t size;
215 uint32_t memory_type;
216 unsigned width, height;
217
218 VkImageLayout layout; /* enum alignment */
219 VkFormat format; /* enum alignment */
220 enum vk_texture_type type;
221 bool default_smooth;
222 bool need_manual_cache_management;
223 bool mipmap;
224 };
225
226 struct vk_buffer
227 {
228 VkDeviceSize size; /* uint64_t alignment */
229 void *mapped;
230 VkBuffer buffer; /* ptr alignment */
231 VkDeviceMemory memory; /* ptr alignment */
232 };
233
234 struct vk_buffer_node
235 {
236 struct vk_buffer buffer; /* uint64_t alignment */
237 struct vk_buffer_node *next;
238 };
239
240 struct vk_buffer_chain
241 {
242 VkDeviceSize block_size; /* uint64_t alignment */
243 VkDeviceSize alignment; /* uint64_t alignment */
244 VkDeviceSize offset; /* uint64_t alignment */
245 struct vk_buffer_node *head;
246 struct vk_buffer_node *current;
247 VkBufferUsageFlags usage; /* uint32_t alignment */
248 };
249
250 struct vk_buffer_range
251 {
252 VkDeviceSize offset; /* uint64_t alignment */
253 uint8_t *data;
254 VkBuffer buffer; /* ptr alignment */
255 };
256
257 struct vk_descriptor_pool
258 {
259 struct vk_descriptor_pool *next;
260 VkDescriptorPool pool; /* ptr alignment */
261 VkDescriptorSet sets[VULKAN_DESCRIPTOR_MANAGER_BLOCK_SETS]; /* ptr alignment */
262 };
263
264 struct vk_descriptor_manager
265 {
266 struct vk_descriptor_pool *head;
267 struct vk_descriptor_pool *current;
268 VkDescriptorSetLayout set_layout; /* ptr alignment */
269 VkDescriptorPoolSize sizes[VULKAN_MAX_DESCRIPTOR_POOL_SIZES]; /* uint32_t alignment */
270 unsigned count;
271 unsigned num_sizes;
272 };
273
274 struct vk_per_frame
275 {
276 struct vk_texture texture; /* uint64_t alignment */
277 struct vk_texture texture_optimal;
278 struct vk_buffer_chain vbo; /* uint64_t alignment */
279 struct vk_buffer_chain ubo;
280 struct vk_descriptor_manager descriptor_manager;
281
282 VkCommandPool cmd_pool; /* ptr alignment */
283 VkCommandBuffer cmd; /* ptr alignment */
284 };
285
286 struct vk_draw_quad
287 {
288 struct vk_texture *texture;
289 const math_matrix_4x4 *mvp;
290 VkPipeline pipeline; /* ptr alignment */
291 VkSampler sampler; /* ptr alignment */
292 struct vk_color color; /* float alignment */
293 };
294
295 struct vk_draw_triangles
296 {
297 const void *uniform;
298 const struct vk_buffer_range *vbo;
299 struct vk_texture *texture;
300 VkPipeline pipeline; /* ptr alignment */
301 VkSampler sampler; /* ptr alignment */
302 size_t uniform_size;
303 unsigned vertices;
304 };
305
306 typedef struct vk
307 {
308 void *filter_chain;
309 vulkan_context_t *context;
310 void *ctx_data;
311 const gfx_ctx_driver_t *ctx_driver;
312 struct vk_per_frame *chain;
313 struct vk_image *backbuffer;
314
315 unsigned video_width;
316 unsigned video_height;
317
318 unsigned tex_w, tex_h;
319 unsigned vp_out_width, vp_out_height;
320 unsigned rotation;
321 unsigned num_swapchain_images;
322 unsigned last_valid_index;
323
324 video_info_t video;
325
326 VkFormat tex_fmt;
327 math_matrix_4x4 mvp, mvp_no_rot; /* float alignment */
328 VkViewport vk_vp;
329 VkRenderPass render_pass;
330 struct video_viewport vp;
331 struct vk_per_frame swapchain[VULKAN_MAX_SWAPCHAIN_IMAGES];
332 struct vk_image backbuffers[VULKAN_MAX_SWAPCHAIN_IMAGES];
333 struct vk_texture default_texture;
334
335 /* Currently active command buffer. */
336 VkCommandBuffer cmd;
337 /* Staging pool for doing buffer transfers on GPU. */
338 VkCommandPool staging_pool;
339
340 struct
341 {
342 struct scaler_ctx scaler_bgr;
343 struct scaler_ctx scaler_rgb;
344 struct vk_texture staging[VULKAN_MAX_SWAPCHAIN_IMAGES];
345 bool pending;
346 bool streamed;
347 } readback;
348
349 struct
350 {
351 struct vk_texture *images;
352 struct vk_vertex *vertex;
353 unsigned count;
354 bool enable;
355 bool full_screen;
356 } overlay;
357
358 struct
359 {
360 VkPipeline alpha_blend;
361 VkPipeline font;
362 VkDescriptorSetLayout set_layout;
363 VkPipelineLayout layout;
364 VkPipelineCache cache;
365 } pipelines;
366
367 struct
368 {
369 VkPipeline pipelines[7 * 2];
370 struct vk_texture blank_texture;
371 bool blend;
372 } display;
373
374 struct
375 {
376 struct vk_texture textures[VULKAN_MAX_SWAPCHAIN_IMAGES];
377 struct vk_texture textures_optimal[VULKAN_MAX_SWAPCHAIN_IMAGES];
378 unsigned last_index;
379 float alpha;
380 bool dirty[VULKAN_MAX_SWAPCHAIN_IMAGES];
381 bool enable;
382 bool full_screen;
383 } menu;
384
385 struct
386 {
387 VkSampler linear;
388 VkSampler nearest;
389 VkSampler mipmap_nearest;
390 VkSampler mipmap_linear;
391 } samplers;
392
393 struct
394 {
395 const struct retro_vulkan_image *image;
396 VkPipelineStageFlags *wait_dst_stages;
397 VkCommandBuffer *cmd;
398 VkSemaphore *semaphores;
399 VkSemaphore signal_semaphore; /* ptr alignment */
400
401 struct retro_hw_render_interface_vulkan iface;
402
403 unsigned capacity_cmd;
404 unsigned last_width;
405 unsigned last_height;
406 uint32_t num_semaphores;
407 uint32_t num_cmd;
408 uint32_t src_queue_family;
409
410 bool enable;
411 bool valid_semaphore;
412 } hw;
413
414 struct
415 {
416 uint64_t dirty;
417 VkPipeline pipeline; /* ptr alignment */
418 VkImageView view; /* ptr alignment */
419 VkSampler sampler; /* ptr alignment */
420 math_matrix_4x4 mvp;
421 VkRect2D scissor; /* int32_t alignment */
422 bool use_scissor;
423 } tracker;
424
425 bool vsync;
426 bool keep_aspect;
427 bool fullscreen;
428 bool quitting;
429 bool should_resize;
430
431 } vk_t;
432
433 #define VK_BUFFER_CHAIN_DISCARD(chain) \
434 { \
435 chain->current = chain->head; \
436 chain->offset = 0; \
437 }
438
439 #define VULKAN_SYNC_TEXTURE_TO_GPU(device, tex_memory) \
440 { \
441 VkMappedMemoryRange range; \
442 range.sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE; \
443 range.pNext = NULL; \
444 range.memory = tex_memory; \
445 range.offset = 0; \
446 range.size = VK_WHOLE_SIZE; \
447 vkFlushMappedMemoryRanges(device, 1, &range); \
448 }
449
450 #define VULKAN_SYNC_TEXTURE_TO_CPU(device, tex_memory) \
451 { \
452 VkMappedMemoryRange range; \
453 range.sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE; \
454 range.pNext = NULL; \
455 range.memory = tex_memory; \
456 range.offset = 0; \
457 range.size = VK_WHOLE_SIZE; \
458 vkInvalidateMappedMemoryRanges(device, 1, &range); \
459 }
460
461 #define VULKAN_IMAGE_LAYOUT_TRANSITION_LEVELS(cmd, img, levels, old_layout, new_layout, src_access, dst_access, src_stages, dst_stages, src_queue_family_idx, dst_queue_family_idx) \
462 { \
463 VkImageMemoryBarrier barrier; \
464 barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; \
465 barrier.pNext = NULL; \
466 barrier.srcAccessMask = src_access; \
467 barrier.dstAccessMask = dst_access; \
468 barrier.oldLayout = old_layout; \
469 barrier.newLayout = new_layout; \
470 barrier.srcQueueFamilyIndex = src_queue_family_idx; \
471 barrier.dstQueueFamilyIndex = dst_queue_family_idx; \
472 barrier.image = img; \
473 barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; \
474 barrier.subresourceRange.baseMipLevel = 0; \
475 barrier.subresourceRange.levelCount = levels; \
476 barrier.subresourceRange.baseArrayLayer = 0; \
477 barrier.subresourceRange.layerCount = VK_REMAINING_ARRAY_LAYERS; \
478 vkCmdPipelineBarrier(cmd, src_stages, dst_stages, 0, 0, NULL, 0, NULL, 1, &barrier); \
479 }
480
481 #define VULKAN_TRANSFER_IMAGE_OWNERSHIP(cmd, img, layout, src_stages, dst_stages, src_queue_family, dst_queue_family) VULKAN_IMAGE_LAYOUT_TRANSITION_LEVELS(cmd, img, VK_REMAINING_MIP_LEVELS, layout, layout, 0, 0, src_stages, dst_stages, src_queue_family, dst_queue_family)
482
483 #define VULKAN_IMAGE_LAYOUT_TRANSITION(cmd, img, old_layout, new_layout, src_access, dst_access, src_stages, dst_stages) VULKAN_IMAGE_LAYOUT_TRANSITION_LEVELS(cmd, img, VK_REMAINING_MIP_LEVELS, old_layout, new_layout, src_access, dst_access, src_stages, dst_stages, VK_QUEUE_FAMILY_IGNORED, VK_QUEUE_FAMILY_IGNORED)
484
485 #define VK_DESCRIPTOR_MANAGER_RESTART(manager) \
486 { \
487 manager->current = manager->head; \
488 manager->count = 0; \
489 }
490
491 #define VK_MAP_PERSISTENT_TEXTURE(device, texture) \
492 { \
493 vkMapMemory(device, texture->memory, texture->offset, texture->size, 0, &texture->mapped); \
494 }
495
496 #define VULKAN_PASS_SET_TEXTURE(device, set, _sampler, binding, image_view, image_layout) \
497 { \
498 VkDescriptorImageInfo image_info; \
499 VkWriteDescriptorSet write; \
500 image_info.sampler = _sampler; \
501 image_info.imageView = image_view; \
502 image_info.imageLayout = image_layout; \
503 write.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; \
504 write.pNext = NULL; \
505 write.dstSet = set; \
506 write.dstBinding = binding; \
507 write.dstArrayElement = 0; \
508 write.descriptorCount = 1; \
509 write.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; \
510 write.pImageInfo = &image_info; \
511 write.pBufferInfo = NULL; \
512 write.pTexelBufferView = NULL; \
513 vkUpdateDescriptorSets(device, 1, &write, 0, NULL); \
514 }
515
516 #define VULKAN_WRITE_QUAD_VBO(pv, _x, _y, _width, _height, _tex_x, _tex_y, _tex_width, _tex_height, vulkan_color) \
517 { \
518 float r = (vulkan_color)->r; \
519 float g = (vulkan_color)->g; \
520 float b = (vulkan_color)->b; \
521 float a = (vulkan_color)->a; \
522 pv[0].x = (_x) + 0.0f * (_width); \
523 pv[0].y = (_y) + 0.0f * (_height); \
524 pv[0].tex_x = (_tex_x) + 0.0f * (_tex_width); \
525 pv[0].tex_y = (_tex_y) + 0.0f * (_tex_height); \
526 pv[0].color.r = r; \
527 pv[0].color.g = g; \
528 pv[0].color.b = b; \
529 pv[0].color.a = a; \
530 pv[1].x = (_x) + 0.0f * (_width); \
531 pv[1].y = (_y) + 1.0f * (_height); \
532 pv[1].tex_x = (_tex_x) + 0.0f * (_tex_width); \
533 pv[1].tex_y = (_tex_y) + 1.0f * (_tex_height); \
534 pv[1].color.r = r; \
535 pv[1].color.g = g; \
536 pv[1].color.b = b; \
537 pv[1].color.a = a; \
538 pv[2].x = (_x) + 1.0f * (_width); \
539 pv[2].y = (_y) + 0.0f * (_height); \
540 pv[2].tex_x = (_tex_x) + 1.0f * (_tex_width); \
541 pv[2].tex_y = (_tex_y) + 0.0f * (_tex_height); \
542 pv[2].color.r = r; \
543 pv[2].color.g = g; \
544 pv[2].color.b = b; \
545 pv[2].color.a = a; \
546 pv[3].x = (_x) + 1.0f * (_width); \
547 pv[3].y = (_y) + 1.0f * (_height); \
548 pv[3].tex_x = (_tex_x) + 1.0f * (_tex_width); \
549 pv[3].tex_y = (_tex_y) + 1.0f * (_tex_height); \
550 pv[3].color.r = r; \
551 pv[3].color.g = g; \
552 pv[3].color.b = b; \
553 pv[3].color.a = a; \
554 pv[4].x = (_x) + 1.0f * (_width); \
555 pv[4].y = (_y) + 0.0f * (_height); \
556 pv[4].tex_x = (_tex_x) + 1.0f * (_tex_width); \
557 pv[4].tex_y = (_tex_y) + 0.0f * (_tex_height); \
558 pv[4].color.r = r; \
559 pv[4].color.g = g; \
560 pv[4].color.b = b; \
561 pv[4].color.a = a; \
562 pv[5].x = (_x) + 0.0f * (_width); \
563 pv[5].y = (_y) + 1.0f * (_height); \
564 pv[5].tex_x = (_tex_x) + 0.0f * (_tex_width); \
565 pv[5].tex_y = (_tex_y) + 1.0f * (_tex_height); \
566 pv[5].color.r = r; \
567 pv[5].color.g = g; \
568 pv[5].color.b = b; \
569 pv[5].color.a = a; \
570 }
571
572
573 struct vk_buffer_chain vulkan_buffer_chain_init(
574 VkDeviceSize block_size,
575 VkDeviceSize alignment,
576 VkBufferUsageFlags usage);
577
578 bool vulkan_buffer_chain_alloc(const struct vulkan_context *context,
579 struct vk_buffer_chain *chain, size_t size,
580 struct vk_buffer_range *range);
581
582 void vulkan_buffer_chain_free(
583 VkDevice device,
584 struct vk_buffer_chain *chain);
585
586 uint32_t vulkan_find_memory_type(
587 const VkPhysicalDeviceMemoryProperties *mem_props,
588 uint32_t device_reqs, uint32_t host_reqs);
589
590 uint32_t vulkan_find_memory_type_fallback(
591 const VkPhysicalDeviceMemoryProperties *mem_props,
592 uint32_t device_reqs, uint32_t host_reqs_first,
593 uint32_t host_reqs_second);
594
595 struct vk_texture vulkan_create_texture(vk_t *vk,
596 struct vk_texture *old,
597 unsigned width, unsigned height,
598 VkFormat format,
599 const void *initial, const VkComponentMapping *swizzle,
600 enum vk_texture_type type);
601
602 void vulkan_transition_texture(vk_t *vk, VkCommandBuffer cmd, struct vk_texture *texture);
603
604 void vulkan_destroy_texture(
605 VkDevice device,
606 struct vk_texture *tex);
607
608 /* Dynamic texture type should be set to : VULKAN_TEXTURE_DYNAMIC
609 * Staging texture type should be set to : VULKAN_TEXTURE_STAGING
610 */
611 #define VULKAN_COPY_STAGING_TO_DYNAMIC(vk, cmd, dynamic, staging) \
612 { \
613 VkBufferImageCopy region; \
614 VULKAN_IMAGE_LAYOUT_TRANSITION( \
615 cmd, \
616 dynamic->image, \
617 VK_IMAGE_LAYOUT_UNDEFINED, \
618 VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, \
619 0, \
620 VK_ACCESS_TRANSFER_WRITE_BIT, \
621 VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, \
622 VK_PIPELINE_STAGE_TRANSFER_BIT); \
623 region.bufferOffset = 0; \
624 region.bufferRowLength = 0; \
625 region.bufferImageHeight = 0; \
626 region.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; \
627 region.imageSubresource.mipLevel = 0; \
628 region.imageSubresource.baseArrayLayer = 0; \
629 region.imageSubresource.layerCount = 1; \
630 region.imageOffset.x = 0; \
631 region.imageOffset.y = 0; \
632 region.imageOffset.z = 0; \
633 region.imageExtent.width = dynamic->width; \
634 region.imageExtent.height = dynamic->height; \
635 region.imageExtent.depth = 1; \
636 vkCmdCopyBufferToImage( \
637 cmd, \
638 staging->buffer, \
639 dynamic->image, \
640 VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, \
641 1, \
642 ®ion); \
643 VULKAN_IMAGE_LAYOUT_TRANSITION( \
644 cmd, \
645 dynamic->image, \
646 VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, \
647 VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, \
648 VK_ACCESS_TRANSFER_WRITE_BIT, \
649 VK_ACCESS_SHADER_READ_BIT, \
650 VK_PIPELINE_STAGE_TRANSFER_BIT, \
651 VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT); \
652 dynamic->layout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; \
653 }
654
655 /* We don't have to sync against previous TRANSFER,
656 * since we observed the completion by fences.
657 *
658 * If we have a single texture_optimal, we would need to sync against
659 * previous transfers to avoid races.
660 *
661 * We would also need to optionally maintain extra textures due to
662 * changes in resolution, so this seems like the sanest and
663 * simplest solution. */
664 #define VULKAN_SYNC_TEXTURE_TO_GPU_COND_PTR(vk, tex) \
665 if ((tex)->need_manual_cache_management && (tex)->memory != VK_NULL_HANDLE) \
666 VULKAN_SYNC_TEXTURE_TO_GPU(vk->context->device, (tex)->memory) \
667
668 #define VULKAN_SYNC_TEXTURE_TO_GPU_COND_OBJ(vk, tex) \
669 if ((tex).need_manual_cache_management && (tex).memory != VK_NULL_HANDLE) \
670 VULKAN_SYNC_TEXTURE_TO_GPU(vk->context->device, (tex).memory) \
671
672 /* VBO will be written to here. */
673 void vulkan_draw_quad(vk_t *vk, const struct vk_draw_quad *quad);
674
675 /* The VBO needs to be written to before calling this.
676 * Use vulkan_buffer_chain_alloc.
677 */
678 void vulkan_draw_triangles(vk_t *vk, const struct vk_draw_triangles *call);
679
vulkan_format_to_bpp(VkFormat format)680 static INLINE unsigned vulkan_format_to_bpp(VkFormat format)
681 {
682 switch (format)
683 {
684 case VK_FORMAT_B8G8R8A8_UNORM:
685 return 4;
686
687 case VK_FORMAT_R4G4B4A4_UNORM_PACK16:
688 case VK_FORMAT_B4G4R4A4_UNORM_PACK16:
689 case VK_FORMAT_R5G6B5_UNORM_PACK16:
690 return 2;
691
692 case VK_FORMAT_R8_UNORM:
693 return 1;
694
695 default:
696 RARCH_ERR("[Vulkan]: Unknown format.\n");
697 abort();
698 }
699 }
700
701 struct vk_buffer vulkan_create_buffer(
702 const struct vulkan_context *context,
703 size_t size, VkBufferUsageFlags usage);
704
705 void vulkan_destroy_buffer(
706 VkDevice device,
707 struct vk_buffer *buffer);
708
709 VkDescriptorSet vulkan_descriptor_manager_alloc(
710 VkDevice device,
711 struct vk_descriptor_manager *manager);
712
713 struct vk_descriptor_manager vulkan_create_descriptor_manager(
714 VkDevice device,
715 const VkDescriptorPoolSize *sizes, unsigned num_sizes,
716 VkDescriptorSetLayout set_layout);
717
718 void vulkan_destroy_descriptor_manager(
719 VkDevice device,
720 struct vk_descriptor_manager *manager);
721
722 bool vulkan_context_init(gfx_ctx_vulkan_data_t *vk,
723 enum vulkan_wsi_type type);
724
725 void vulkan_context_destroy(gfx_ctx_vulkan_data_t *vk,
726 bool destroy_surface);
727
728 bool vulkan_surface_create(gfx_ctx_vulkan_data_t *vk,
729 enum vulkan_wsi_type type,
730 void *display, void *surface,
731 unsigned width, unsigned height,
732 unsigned swap_interval);
733
734 void vulkan_present(gfx_ctx_vulkan_data_t *vk, unsigned index);
735
736 void vulkan_acquire_next_image(gfx_ctx_vulkan_data_t *vk);
737
738 bool vulkan_create_swapchain(gfx_ctx_vulkan_data_t *vk,
739 unsigned width, unsigned height,
740 unsigned swap_interval);
741
742 void vulkan_set_uniform_buffer(
743 VkDevice device,
744 VkDescriptorSet set,
745 unsigned binding,
746 VkBuffer buffer,
747 VkDeviceSize offset,
748 VkDeviceSize range);
749
750 void vulkan_framebuffer_generate_mips(
751 VkFramebuffer framebuffer,
752 VkImage image,
753 struct Size2D size,
754 VkCommandBuffer cmd,
755 unsigned levels
756 );
757
758 void vulkan_framebuffer_copy(VkImage image,
759 struct Size2D size,
760 VkCommandBuffer cmd,
761 VkImage src_image, VkImageLayout src_layout);
762
763 void vulkan_framebuffer_clear(VkImage image, VkCommandBuffer cmd);
764
765 void vulkan_initialize_render_pass(VkDevice device,
766 VkFormat format, VkRenderPass *render_pass);
767
768 RETRO_END_DECLS
769
770 #endif
771