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          &region); \
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