vkQuake2 doxygen  1.0 dev
vk_common.c
Go to the documentation of this file.
1 /*
2 Copyright (C) 1997-2001 Id Software, Inc.
3 Copyright (C) 2018-2019 Krzysztof Kondrak
4 
5 This program is free software; you can redistribute it and/or
6 modify it under the terms of the GNU General Public License
7 as published by the Free Software Foundation; either version 2
8 of the License, or (at your option) any later version.
9 
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
13 
14 See the GNU General Public License for more details.
15 
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
19 
20 */
21 /*
22 ** VK_COMMON.C
23 **
24 ** This file implements the operating system binding of Vk to QVk function
25 ** pointers. When doing a port of Quake2 you must implement the following
26 ** two functions:
27 **
28 ** QVk_Init() - loads libraries, assigns function pointers, etc.
29 ** QVk_Shutdown() - unloads libraries, NULLs function pointers
30 */
31 #include <float.h>
32 #include "../ref_vk/vk_local.h"
33 #ifdef _WIN32
34 #include "../win32/vk_win.h"
35 #endif
36 #ifdef __linux__
37 #include "../linux/vk_linux.h"
38 #endif
39 #ifdef __APPLE__
40 #include "../macos/vk_macos.h"
41 #endif
42 
43 FILE *vk_logfp = NULL;
44 
45 // Vulkan instance, surface and memory allocator
46 VkInstance vk_instance = VK_NULL_HANDLE;
47 VkSurfaceKHR vk_surface = VK_NULL_HANDLE;
48 VmaAllocator vk_malloc = VK_NULL_HANDLE;
49 
50 // Vulkan device
52  .physical = VK_NULL_HANDLE,
53  .logical = VK_NULL_HANDLE,
54  .gfxQueue = VK_NULL_HANDLE,
55  .presentQueue = VK_NULL_HANDLE,
56  .transferQueue = VK_NULL_HANDLE,
57  .gfxFamilyIndex = -1,
58  .presentFamilyIndex = -1,
59  .transferFamilyIndex = -1
60 };
61 
62 // Vulkan swapchain
64  .sc = VK_NULL_HANDLE,
65  .format = VK_FORMAT_UNDEFINED,
66  .presentMode = VK_PRESENT_MODE_MAILBOX_KHR,
67  .extent = { 0, 0 },
68  .images = NULL,
69  .imageCount = 0
70 };
71 
72 // Vulkan renderpasses
74  // RP_WORLD
75  {
76  .rp = VK_NULL_HANDLE,
77  .colorLoadOp = VK_ATTACHMENT_LOAD_OP_CLEAR,
78  .sampleCount = VK_SAMPLE_COUNT_1_BIT
79  },
80  // RP_UI
81  {
82  .rp = VK_NULL_HANDLE,
83  .colorLoadOp = VK_ATTACHMENT_LOAD_OP_LOAD,
84  .sampleCount = VK_SAMPLE_COUNT_1_BIT
85  },
86  // RP_WORLD_WARP
87  {
88  .rp = VK_NULL_HANDLE,
89  .colorLoadOp = VK_ATTACHMENT_LOAD_OP_LOAD,
90  .sampleCount = VK_SAMPLE_COUNT_1_BIT
91  }
92 };
93 
94 // Vulkan pools
95 VkCommandPool vk_commandPool = VK_NULL_HANDLE;
96 VkCommandPool vk_transferCommandPool = VK_NULL_HANDLE;
97 VkDescriptorPool vk_descriptorPool = VK_NULL_HANDLE;
98 static VkCommandPool vk_stagingCommandPool = VK_NULL_HANDLE;
99 // Vulkan image views
100 VkImageView *vk_imageviews = NULL;
101 // Vulkan framebuffers
102 VkFramebuffer *vk_framebuffers[RP_COUNT];
103 // color buffer containing main game/world view
105 // color buffer with postprocessed game view
107 // depth buffer
109 // depth buffer for UI renderpass
111 // render target for MSAA resolve
113 // viewport and scissor
114 VkViewport vk_viewport = { .0f, .0f, .0f, .0f, .0f, .0f };
115 VkRect2D vk_scissor = { { 0, 0 }, { 0, 0 } };
116 
117 #define NUM_CMDBUFFERS 2
118 // Vulkan command buffers
119 VkCommandBuffer *vk_commandbuffers = NULL;
120 // command buffer double buffering fences
122 // semaphore: signal when next image is available for rendering
124 // semaphore: signal when rendering to current command buffer is complete
126 // tracker variables
127 VkCommandBuffer vk_activeCmdbuffer = VK_NULL_HANDLE;
128 // index of active command buffer
130 // index of currently acquired image
131 uint32_t vk_imageIndex = 0;
132 // index of currently used staging buffer
134 // started rendering frame?
136 
137 // render pipelines
161 
162 // samplers
163 static VkSampler vk_samplers[S_SAMPLER_CNT];
164 
165 // Vulkan function pointers
166 PFN_vkCreateDebugUtilsMessengerEXT qvkCreateDebugUtilsMessengerEXT;
167 PFN_vkDestroyDebugUtilsMessengerEXT qvkDestroyDebugUtilsMessengerEXT;
168 PFN_vkSetDebugUtilsObjectNameEXT qvkSetDebugUtilsObjectNameEXT;
169 PFN_vkSetDebugUtilsObjectTagEXT qvkSetDebugUtilsObjectTagEXT;
170 PFN_vkCmdBeginDebugUtilsLabelEXT qvkCmdBeginDebugUtilsLabelEXT;
171 PFN_vkCmdEndDebugUtilsLabelEXT qvkCmdEndDebugUtilsLabelEXT;
172 PFN_vkCmdInsertDebugUtilsLabelEXT qvkInsertDebugUtilsLabelEXT;
173 
174 #define VK_INPUTBIND_DESC(s) { \
175  .binding = 0, \
176  .stride = s, \
177  .inputRate = VK_VERTEX_INPUT_RATE_VERTEX \
178 };
179 
180 #define VK_INPUTATTR_DESC(l, f, o) { \
181  .binding = 0, \
182  .location = l, \
183  .format = f, \
184  .offset = o \
185 }
186 
187 #define VK_VERTEXINPUT_CINF(b, a) { \
188  .sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, \
189  .pNext = NULL, \
190  .flags = 0, \
191  .vertexBindingDescriptionCount = 1, \
192  .pVertexBindingDescriptions = &b, \
193  .vertexAttributeDescriptionCount = sizeof(a) / sizeof(a[0]), \
194  .pVertexAttributeDescriptions = a \
195 }
196 
197 #define VK_VERTINFO(name, bindSize, ...) \
198  VkVertexInputAttributeDescription attrDesc##name[] = { __VA_ARGS__ }; \
199  VkVertexInputBindingDescription name##bindingDesc = VK_INPUTBIND_DESC(bindSize); \
200  VkPipelineVertexInputStateCreateInfo vertInfo##name = VK_VERTEXINPUT_CINF(name##bindingDesc, attrDesc##name);
201 
202 #define VK_NULL_VERTEXINPUT_CINF { \
203  .sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, \
204  .pNext = NULL, \
205  .flags = 0, \
206  .vertexBindingDescriptionCount = 0, \
207  .pVertexBindingDescriptions = NULL, \
208  .vertexAttributeDescriptionCount = 0, \
209  .pVertexAttributeDescriptions = NULL \
210 }
211 
212 #define VK_LOAD_VERTFRAG_SHADERS(shaders, namevert, namefrag) \
213  vkDestroyShaderModule(vk_device.logical, shaders[0].module, NULL); \
214  vkDestroyShaderModule(vk_device.logical, shaders[1].module, NULL); \
215  shaders[0] = QVk_CreateShader(namevert##_vert_spv, namevert##_vert_size, VK_SHADER_STAGE_VERTEX_BIT); \
216  shaders[1] = QVk_CreateShader(namefrag##_frag_spv, namefrag##_frag_size, VK_SHADER_STAGE_FRAGMENT_BIT); \
217  QVk_DebugSetObjectName((uint64_t)shaders[0].module, VK_OBJECT_TYPE_SHADER_MODULE, "Shader Module: "#namevert".vert"); \
218  QVk_DebugSetObjectName((uint64_t)shaders[1].module, VK_OBJECT_TYPE_SHADER_MODULE, "Shader Module: "#namefrag".frag");
219 
220 // global static buffers (reused, never changing)
224 
225 // global dynamic buffers (double buffered)
226 #define NUM_DYNBUFFERS 2
230 static VkDescriptorSet vk_uboDescriptorSets[NUM_DYNBUFFERS];
232 static int vk_activeDynBufferIdx = 0;
233 static int vk_activeSwapBufferIdx = 0;
234 
235 // index buffer for triangle fan emulation - all because Metal/MoltenVK don't support them
236 static VkBuffer *vk_triangleFanIbo = NULL;
237 static uint32_t vk_triangleFanIboUsage = 0;
238 
239 // swap buffers used if primary dynamic buffers get full
240 #define NUM_SWAPBUFFER_SLOTS 4
245 
246 // by how much will the dynamic buffers be resized if we run out of space?
247 #define BUFFER_RESIZE_FACTOR 2.f
248 // size in bytes used for uniform descriptor update
249 #define UNIFORM_ALLOC_SIZE 1024
250 // start values for dynamic buffer sizes - bound to change if the application runs out of space (sizes in bytes)
251 #define VERTEX_BUFFER_SIZE (1024 * 1024)
252 #define INDEX_BUFFER_SIZE (2 * 1024)
253 #define UNIFORM_BUFFER_SIZE (2048 * 1024)
254 // staging buffer is constant in size but has a max limit beyond which it will be submitted
255 #define STAGING_BUFFER_MAXSIZE (8192 * 1024)
256 // initial index count in triangle fan buffer - assuming 200 indices (200*3 = 600 triangles) per object
257 #define TRIANGLE_FAN_INDEX_CNT 200
258 
259 // Vulkan common descriptor sets for UBO, primary texture sampler and optional lightmap texture
260 VkDescriptorSetLayout vk_uboDescSetLayout;
261 VkDescriptorSetLayout vk_samplerDescSetLayout;
262 VkDescriptorSetLayout vk_samplerLightmapDescSetLayout;
263 
264 extern cvar_t *vk_msaa;
265 extern cvar_t *vid_ref;
266 
268 {
269  VkFormat depthFormats[] = {
270  VK_FORMAT_D32_SFLOAT_S8_UINT,
271  VK_FORMAT_D32_SFLOAT,
272  VK_FORMAT_D24_UNORM_S8_UINT,
273  VK_FORMAT_D16_UNORM_S8_UINT,
274  VK_FORMAT_D16_UNORM
275  };
276 
277  for (int i = 0; i < 5; ++i)
278  {
279  VkFormatProperties formatProps;
280  vkGetPhysicalDeviceFormatProperties(vk_device.physical, depthFormats[i], &formatProps);
281 
282  if (formatProps.optimalTilingFeatures & VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT)
283  return depthFormats[i];
284  }
285 
286  return VK_FORMAT_D16_UNORM;
287 }
288 
289 // internal helper
290 static VkSampleCountFlagBits GetSampleCount()
291 {
292  static VkSampleCountFlagBits msaaModes[] = {
293  VK_SAMPLE_COUNT_1_BIT,
294  VK_SAMPLE_COUNT_2_BIT,
295  VK_SAMPLE_COUNT_4_BIT,
296  VK_SAMPLE_COUNT_8_BIT,
297  VK_SAMPLE_COUNT_16_BIT
298  };
299 
300  return msaaModes[(int)vk_msaa->value];
301 }
302 
303 // internal helper
304 static void DestroyImageViews()
305 {
306  if(!vk_imageviews)
307  return;
308 
309  for (int i = 0; i < vk_swapchain.imageCount; i++)
310  {
311  vkDestroyImageView(vk_device.logical, vk_imageviews[i], NULL);
312  }
313  free(vk_imageviews);
315 }
316 
317 // internal helper
318 static VkResult CreateImageViews()
319 {
320  VkResult res = VK_SUCCESS;
321  vk_imageviews = (VkImageView *)malloc(vk_swapchain.imageCount * sizeof(VkImageView));
322 
323  for (size_t i = 0; i < vk_swapchain.imageCount; ++i)
324  {
325  res = QVk_CreateImageView(&vk_swapchain.images[i], VK_IMAGE_ASPECT_COLOR_BIT, &vk_imageviews[i], vk_swapchain.format, 1);
326  QVk_DebugSetObjectName((uint64_t)vk_swapchain.images[i], VK_OBJECT_TYPE_IMAGE, va("Swap Chain Image #%d", i));
327  QVk_DebugSetObjectName((uint64_t)vk_imageviews[i], VK_OBJECT_TYPE_IMAGE_VIEW, va("Swap Chain Image View #%d", i));
328 
329  if (res != VK_SUCCESS)
330  {
332  return res;
333  }
334  }
335 
336  return res;
337 }
338 
339 // internal helper
340 static void DestroyFramebuffers()
341 {
342  for (int f = 0; f < RP_COUNT; f++)
343  {
344  if (vk_framebuffers[f])
345  {
346  for (int i = 0; i < vk_swapchain.imageCount; ++i)
347  {
348  vkDestroyFramebuffer(vk_device.logical, vk_framebuffers[f][i], NULL);
349  }
350 
351  free(vk_framebuffers[f]);
352  vk_framebuffers[f] = NULL;
353  }
354  }
355 }
356 
357 // internal helper
358 static VkResult CreateFramebuffers()
359 {
360  for(int i = 0; i < RP_COUNT; ++i)
361  vk_framebuffers[i] = (VkFramebuffer *)malloc(vk_swapchain.imageCount * sizeof(VkFramebuffer));
362 
363  VkFramebufferCreateInfo fbCreateInfos[] = {
364  // main world view framebuffer
365  {
366  .sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO,
367  .pNext = NULL,
368  .flags = 0,
369  .renderPass = vk_renderpasses[RP_WORLD].rp,
370  .attachmentCount = (vk_renderpasses[RP_WORLD].sampleCount != VK_SAMPLE_COUNT_1_BIT) ? 3 : 2,
371  .width = vk_swapchain.extent.width,
372  .height = vk_swapchain.extent.height,
373  .layers = 1
374  },
375  // UI framebuffer
376  {
377  .sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO,
378  .pNext = NULL,
379  .flags = 0,
380  .renderPass = vk_renderpasses[RP_UI].rp,
381  .attachmentCount = 3,
382  .width = vk_swapchain.extent.width,
383  .height = vk_swapchain.extent.height,
384  .layers = 1
385  },
386  // warped main world view (postprocessing) framebuffer
387  {
388  .sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO,
389  .pNext = NULL,
390  .flags = 0,
391  .renderPass = vk_renderpasses[RP_WORLD_WARP].rp,
392  .attachmentCount = 2,
393  .width = vk_swapchain.extent.width,
394  .height = vk_swapchain.extent.height,
395  .layers = 1
396  }
397  };
398 
399  VkImageView worldAttachments[] = { vk_colorbuffer.imageView, vk_depthbuffer.imageView, vk_msaaColorbuffer.imageView };
400  VkImageView warpAttachments[] = { vk_colorbuffer.imageView, vk_colorbufferWarp.imageView };
401 
402  fbCreateInfos[RP_WORLD].pAttachments = worldAttachments;
403  fbCreateInfos[RP_WORLD_WARP].pAttachments = warpAttachments;
404 
405  for (size_t i = 0; i < vk_swapchain.imageCount; ++i)
406  {
407  VkImageView uiAttachments[] = { vk_colorbufferWarp.imageView, vk_ui_depthbuffer.imageView, vk_imageviews[i] };
408  fbCreateInfos[RP_UI].pAttachments = uiAttachments;
409 
410  for (int j = 0; j < RP_COUNT; ++j)
411  {
412  VkResult res = vkCreateFramebuffer(vk_device.logical, &fbCreateInfos[j], NULL, &vk_framebuffers[j][i]);
413  QVk_DebugSetObjectName((uint64_t)vk_framebuffers[j][i], VK_OBJECT_TYPE_FRAMEBUFFER, va("Framebuffer #%d for Render Pass %s", i, j == RP_WORLD ? "RP_WORLD" : j == RP_UI ? "RP_UI" : "RP_WORLD_WARP"));
414 
415  if (res != VK_SUCCESS)
416  {
417  ri.Con_Printf(PRINT_ALL, "CreateFramebuffers(): framebuffer #%d create error: %s\n", j, QVk_GetError(res));
419  return res;
420  }
421  }
422  }
423 
424  return VK_SUCCESS;
425 }
426 
427 // internal helper
428 static VkResult CreateRenderpasses()
429 {
430  qboolean msaaEnabled = vk_renderpasses[RP_WORLD].sampleCount != VK_SAMPLE_COUNT_1_BIT;
431 
432  /*
433  * world view setup
434  */
435  VkAttachmentDescription worldAttachments[] = {
436  // color attachment
437  {
438  .flags = 0,
439  .format = vk_swapchain.format,
440  .samples = VK_SAMPLE_COUNT_1_BIT,
441  .loadOp = msaaEnabled ? VK_ATTACHMENT_LOAD_OP_DONT_CARE : vk_renderpasses[RP_WORLD].colorLoadOp,
442  // if MSAA is enabled, we don't need to preserve rendered texture data since it's kept by MSAA resolve attachment
443  .storeOp = msaaEnabled ? VK_ATTACHMENT_STORE_OP_DONT_CARE : VK_ATTACHMENT_STORE_OP_STORE,
444  .stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE,
445  .stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE,
446  .initialLayout = VK_IMAGE_LAYOUT_UNDEFINED,
447  .finalLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL
448  },
449  // depth attachment
450  {
451  .flags = 0,
452  .format = QVk_FindDepthFormat(),
454  .loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR,
455  .storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE,
456  .stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE,
457  .stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE,
458  .initialLayout = VK_IMAGE_LAYOUT_UNDEFINED,
459  .finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL
460  },
461  // MSAA resolve attachment
462  {
463  .flags = 0,
464  .format = vk_swapchain.format,
466  .loadOp = msaaEnabled ? vk_renderpasses[RP_WORLD].colorLoadOp : VK_ATTACHMENT_LOAD_OP_DONT_CARE,
467  .storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE,
468  .stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE,
469  .stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE,
470  .initialLayout = VK_IMAGE_LAYOUT_UNDEFINED,
471  .finalLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL
472  }
473  };
474 
475  VkAttachmentReference worldAttachmentRefs[] = {
476  // color
477  {
478  .attachment = msaaEnabled ? 2 : 0,
479  .layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
480  },
481  // depth
482  {
483  .attachment = 1,
484  .layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL
485  },
486  // MSAA resolve
487  {
488  .attachment = 0,
489  .layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL
490  }
491  };
492 
493  // primary renderpass writes to color, depth and optional MSAA resolve
494  VkSubpassDescription worldSubpassDesc = {
495  .flags = 0,
496  .pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS,
497  .inputAttachmentCount = 0,
498  .pInputAttachments = NULL,
499  .colorAttachmentCount = 1,
500  .pColorAttachments = &worldAttachmentRefs[0],
501  .pResolveAttachments = msaaEnabled ? &worldAttachmentRefs[2] : NULL,
502  .pDepthStencilAttachment = &worldAttachmentRefs[1],
503  .preserveAttachmentCount = 0,
504  .pPreserveAttachments = NULL
505  };
506 
507  /*
508  * world warp setup
509  */
510  VkAttachmentDescription warpAttachments[] = {
511  // color attachment - input from RP_WORLD renderpass
512  {
513  .flags = 0,
514  .format = vk_swapchain.format,
515  .samples = VK_SAMPLE_COUNT_1_BIT,
516  .loadOp = VK_ATTACHMENT_LOAD_OP_LOAD,
517  .storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE,
518  .stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE,
519  .stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE,
520  .initialLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
521  .finalLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL
522  },
523  // color attachment output - warped/postprocessed image that ends up in RP_UI
524  {
525  .flags = 0,
526  .format = vk_swapchain.format,
527  .samples = VK_SAMPLE_COUNT_1_BIT,
528  .loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE,
529  .storeOp = VK_ATTACHMENT_STORE_OP_STORE,
530  .stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE,
531  .stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE,
532  .initialLayout = VK_IMAGE_LAYOUT_UNDEFINED,
533  .finalLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL
534  }
535  };
536 
537  VkAttachmentReference warpAttachmentRef = {
538  // output color
539  .attachment = 1,
540  .layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL
541  };
542 
543  // world view postprocess writes to a separate color buffer
544  VkSubpassDescription warpSubpassDesc = {
545  .flags = 0,
546  .pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS,
547  .inputAttachmentCount = 0,
548  .pInputAttachments = NULL,
549  .colorAttachmentCount = 1,
550  .pColorAttachments = &warpAttachmentRef,
551  .pResolveAttachments = NULL,
552  .pDepthStencilAttachment = NULL,
553  .preserveAttachmentCount = 0,
554  .pPreserveAttachments = NULL
555  };
556 
557  /*
558  * UI setup
559  */
560  VkAttachmentDescription uiAttachments[] = {
561  // color attachment
562  {
563  .flags = 0,
564  .format = vk_swapchain.format,
565  .samples = VK_SAMPLE_COUNT_1_BIT,
566  .loadOp = VK_ATTACHMENT_LOAD_OP_LOAD,
567  .storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE,
568  .stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE,
569  .stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE,
570  .initialLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
571  .finalLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL
572  },
573  // depth attachment - because of player model preview in settings screen
574  {
575  .flags = 0,
576  .format = QVk_FindDepthFormat(),
577  .samples = VK_SAMPLE_COUNT_1_BIT,
578  .loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR,
579  .storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE,
580  .stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE,
581  .stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE,
582  .initialLayout = VK_IMAGE_LAYOUT_UNDEFINED,
583  .finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL
584  },
585  // swapchain presentation
586  {
587  .flags = 0,
588  .format = vk_swapchain.format,
589  .samples = VK_SAMPLE_COUNT_1_BIT,
590  .loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE,
591  .storeOp = VK_ATTACHMENT_STORE_OP_STORE,
592  .stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE,
593  .stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE,
594  .initialLayout = VK_IMAGE_LAYOUT_UNDEFINED,
595  .finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR
596  }
597  };
598 
599  // UI renderpass writes to depth (for player model in setup screen) and outputs to swapchain
600  VkAttachmentReference uiAttachmentRefs[] = {
601  // depth
602  {
603  .attachment = 1,
604  .layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL
605  },
606  // swapchain output
607  {
608  .attachment = 2,
609  .layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL
610  }
611  };
612 
613  VkSubpassDescription uiSubpassDesc = {
614  .flags = 0,
615  .pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS,
616  .inputAttachmentCount = 0,
617  .pInputAttachments = NULL,
618  .colorAttachmentCount = 1,
619  .pColorAttachments = &uiAttachmentRefs[1],
620  .pResolveAttachments = NULL,
621  .pDepthStencilAttachment = &uiAttachmentRefs[0],
622  .preserveAttachmentCount = 0,
623  .pPreserveAttachments = NULL
624  };
625 
626  /*
627  * create the render passes
628  */
629  // we're using 3 render passes which depend on each other (main color -> warp/postprocessing -> ui)
630  VkSubpassDependency subpassDeps[2] = {
631  {
632  .srcSubpass = VK_SUBPASS_EXTERNAL,
633  .dstSubpass = 0,
634  .srcStageMask = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
635  .dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
636  .srcAccessMask = VK_ACCESS_SHADER_READ_BIT,
637  .dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
638  .dependencyFlags = VK_DEPENDENCY_BY_REGION_BIT
639  },
640  {
641  .srcSubpass = 0,
642  .dstSubpass = VK_SUBPASS_EXTERNAL,
643  .srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
644  .dstStageMask = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
645  .srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
646  .dstAccessMask = VK_ACCESS_SHADER_READ_BIT,
647  .dependencyFlags = VK_DEPENDENCY_BY_REGION_BIT
648  }
649  };
650 
651  VkRenderPassCreateInfo rpCreateInfos[] = {
652  // offscreen world rendering to color buffer (RP_WORLD)
653  {
654  .sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO,
655  .pNext = NULL,
656  .flags = 0,
657  .attachmentCount = msaaEnabled ? 3 : 2,
658  .pAttachments = worldAttachments,
659  .subpassCount = 1,
660  .pSubpasses = &worldSubpassDesc,
661  .dependencyCount = 2,
662  .pDependencies = subpassDeps
663  },
664  // UI rendering (RP_UI)
665  {
666  .sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO,
667  .pNext = NULL,
668  .flags = 0,
669  .attachmentCount = 3,
670  .pAttachments = uiAttachments,
671  .subpassCount = 1,
672  .pSubpasses = &uiSubpassDesc,
673  .dependencyCount = 2,
674  .pDependencies = subpassDeps
675  },
676  // world warp/postprocessing render pass (RP_WORLD_WARP)
677  {
678  .sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO,
679  .pNext = NULL,
680  .flags = 0,
681  .attachmentCount = 2,
682  .pAttachments = warpAttachments,
683  .subpassCount = 1,
684  .pSubpasses = &warpSubpassDesc,
685  .dependencyCount = 2,
686  .pDependencies = subpassDeps
687  }
688  };
689 
690  for (int i = 0; i < RP_COUNT; ++i)
691  {
692  VkResult res = vkCreateRenderPass(vk_device.logical, &rpCreateInfos[i], NULL, &vk_renderpasses[i].rp);
693  if (res != VK_SUCCESS)
694  {
695  ri.Con_Printf(PRINT_ALL, "CreateRenderpasses(): renderpass #%d create error: %s\n", i, QVk_GetError(res));
696  return res;
697  }
698  }
699 
700  QVk_DebugSetObjectName((uint64_t)vk_renderpasses[RP_WORLD].rp, VK_OBJECT_TYPE_RENDER_PASS, "Render Pass: World");
701  QVk_DebugSetObjectName((uint64_t)vk_renderpasses[RP_WORLD_WARP].rp, VK_OBJECT_TYPE_RENDER_PASS, "Render Pass: UI");
702  QVk_DebugSetObjectName((uint64_t)vk_renderpasses[RP_UI].rp, VK_OBJECT_TYPE_RENDER_PASS, "Render Pass: Warp Postprocess");
703 
704  return VK_SUCCESS;
705 }
706 
707 // internal helper
708 static void CreateDrawBuffers()
709 {
711  ri.Con_Printf(PRINT_ALL, "...created world depth buffer\n");
712  QVk_CreateDepthBuffer(VK_SAMPLE_COUNT_1_BIT, &vk_ui_depthbuffer);
713  ri.Con_Printf(PRINT_ALL, "...created UI depth buffer\n");
714  QVk_CreateColorBuffer(VK_SAMPLE_COUNT_1_BIT, &vk_colorbuffer, VK_IMAGE_USAGE_SAMPLED_BIT);
715  ri.Con_Printf(PRINT_ALL, "...created world color buffer\n");
716  QVk_CreateColorBuffer(VK_SAMPLE_COUNT_1_BIT, &vk_colorbufferWarp, VK_IMAGE_USAGE_SAMPLED_BIT);
717  ri.Con_Printf(PRINT_ALL, "...created world postpocess color buffer\n");
719  ri.Con_Printf(PRINT_ALL, "...created MSAAx%d color buffer\n", vk_renderpasses[RP_WORLD].sampleCount);
720 
721  QVk_DebugSetObjectName((uint64_t)vk_depthbuffer.image, VK_OBJECT_TYPE_IMAGE, "Depth Buffer: World");
722  QVk_DebugSetObjectName((uint64_t)vk_depthbuffer.imageView, VK_OBJECT_TYPE_IMAGE_VIEW, "Image View: World Depth Buffer");
723  QVk_DebugSetObjectName((uint64_t)vk_depthbuffer.allocInfo.deviceMemory, VK_OBJECT_TYPE_DEVICE_MEMORY, "Memory: World Depth Buffer");
724  QVk_DebugSetObjectName((uint64_t)vk_ui_depthbuffer.image, VK_OBJECT_TYPE_IMAGE, "Depth Buffer: UI");
725  QVk_DebugSetObjectName((uint64_t)vk_ui_depthbuffer.imageView, VK_OBJECT_TYPE_IMAGE_VIEW, "Image View: UI Depth Buffer");
726  QVk_DebugSetObjectName((uint64_t)vk_ui_depthbuffer.allocInfo.deviceMemory, VK_OBJECT_TYPE_DEVICE_MEMORY, "Memory: UI Depth Buffer");
727  QVk_DebugSetObjectName((uint64_t)vk_colorbuffer.image, VK_OBJECT_TYPE_IMAGE, "Color Buffer: World");
728  QVk_DebugSetObjectName((uint64_t)vk_colorbuffer.imageView, VK_OBJECT_TYPE_IMAGE_VIEW, "Image View: World Color Buffer");
729  QVk_DebugSetObjectName((uint64_t)vk_colorbuffer.allocInfo.deviceMemory, VK_OBJECT_TYPE_DEVICE_MEMORY, "Memory: World Color Buffer");
730  QVk_DebugSetObjectName((uint64_t)vk_colorbufferWarp.image, VK_OBJECT_TYPE_IMAGE, "Color Buffer: Warp Postprocess");
731  QVk_DebugSetObjectName((uint64_t)vk_colorbufferWarp.imageView, VK_OBJECT_TYPE_IMAGE_VIEW, "Image View: Warp Postprocess Color Buffer");
732  QVk_DebugSetObjectName((uint64_t)vk_colorbufferWarp.allocInfo.deviceMemory, VK_OBJECT_TYPE_DEVICE_MEMORY, "Memory: Warp Postprocess Color Buffer");
733  QVk_DebugSetObjectName((uint64_t)vk_msaaColorbuffer.image, VK_OBJECT_TYPE_IMAGE, "Color Buffer: MSAA");
734  QVk_DebugSetObjectName((uint64_t)vk_msaaColorbuffer.imageView, VK_OBJECT_TYPE_IMAGE_VIEW, "Image View: MSAA Color Buffer");
735  QVk_DebugSetObjectName((uint64_t)vk_msaaColorbuffer.allocInfo.deviceMemory, VK_OBJECT_TYPE_DEVICE_MEMORY, "Memory: MSAA Color Buffer");
736 }
737 
738 // internal helper
739 static void DestroyDrawBuffer(qvktexture_t *drawBuffer)
740 {
741  if (drawBuffer->image != VK_NULL_HANDLE)
742  {
743  vmaDestroyImage(vk_malloc, drawBuffer->image, drawBuffer->allocation);
744  vkDestroyImageView(vk_device.logical, drawBuffer->imageView, NULL);
745  drawBuffer->image = VK_NULL_HANDLE;
746  drawBuffer->imageView = VK_NULL_HANDLE;
747  }
748 }
749 
750 // internal helper
751 static void DestroyDrawBuffers()
752 {
758 }
759 
760 // internal helper
762 {
763  VkDescriptorSetLayoutBinding layoutBinding = {
764  .binding = 0,
765  .descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC,
766  .descriptorCount = 1,
767  .stageFlags = VK_SHADER_STAGE_VERTEX_BIT,
768  .pImmutableSamplers = NULL
769  };
770 
771  VkDescriptorSetLayoutCreateInfo layoutInfo = {
772  .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO,
773  .pNext = NULL,
774  .flags = 0,
775  .bindingCount = 1,
776  .pBindings = &layoutBinding
777  };
778 
779  // uniform buffer object layout
780  VK_VERIFY(vkCreateDescriptorSetLayout(vk_device.logical, &layoutInfo, NULL, &vk_uboDescSetLayout));
781  // sampler layout
782  layoutBinding.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
783  layoutBinding.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT;
784  VK_VERIFY(vkCreateDescriptorSetLayout(vk_device.logical, &layoutInfo, NULL, &vk_samplerDescSetLayout));
785  // secondary sampler: lightmaps
786  VK_VERIFY(vkCreateDescriptorSetLayout(vk_device.logical, &layoutInfo, NULL, &vk_samplerLightmapDescSetLayout));
787 
788  QVk_DebugSetObjectName((uint64_t)vk_uboDescSetLayout, VK_OBJECT_TYPE_DESCRIPTOR_SET_LAYOUT, "Descriptor Set Layout: UBO");
789  QVk_DebugSetObjectName((uint64_t)vk_samplerDescSetLayout, VK_OBJECT_TYPE_DESCRIPTOR_SET_LAYOUT, "Descriptor Set Layout: Sampler");
790  QVk_DebugSetObjectName((uint64_t)vk_samplerLightmapDescSetLayout, VK_OBJECT_TYPE_DESCRIPTOR_SET_LAYOUT, "Descriptor Set Layout: Sampler + Lightmap");
791 }
792 
793 // internal helper
794 static void CreateSamplers()
795 {
796  VkSamplerCreateInfo samplerInfo = {
797  .sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO,
798  .pNext = NULL,
799  .flags = 0,
800  .magFilter = VK_FILTER_NEAREST,
801  .minFilter = VK_FILTER_NEAREST,
802  .mipmapMode = VK_SAMPLER_MIPMAP_MODE_NEAREST,
803  .addressModeU = VK_SAMPLER_ADDRESS_MODE_REPEAT,
804  .addressModeV = VK_SAMPLER_ADDRESS_MODE_REPEAT,
805  .addressModeW = VK_SAMPLER_ADDRESS_MODE_REPEAT,
806  .mipLodBias = 0.f,
807  .anisotropyEnable = VK_FALSE,
808  .maxAnisotropy = 1.f,
809  .compareEnable = VK_FALSE,
810  .compareOp = VK_COMPARE_OP_ALWAYS,
811  .minLod = 0.f,
812  .maxLod = 1.f,
813  .borderColor = VK_BORDER_COLOR_INT_OPAQUE_BLACK,
814  .unnormalizedCoordinates = VK_FALSE
815  };
816 
817  VK_VERIFY(vkCreateSampler(vk_device.logical, &samplerInfo, NULL, &vk_samplers[S_NEAREST]));
818  QVk_DebugSetObjectName((uint64_t)vk_samplers[S_NEAREST], VK_OBJECT_TYPE_SAMPLER, "Sampler: S_NEAREST");
819 
820  samplerInfo.maxLod = FLT_MAX;
821  VK_VERIFY(vkCreateSampler(vk_device.logical, &samplerInfo, NULL, &vk_samplers[S_MIPMAP_NEAREST]));
822  QVk_DebugSetObjectName((uint64_t)vk_samplers[S_MIPMAP_NEAREST], VK_OBJECT_TYPE_SAMPLER, "Sampler: S_MIPMAP_NEAREST");
823 
824  samplerInfo.magFilter = VK_FILTER_LINEAR;
825  samplerInfo.minFilter = VK_FILTER_LINEAR;
826  samplerInfo.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR;
827  VK_VERIFY(vkCreateSampler(vk_device.logical, &samplerInfo, NULL, &vk_samplers[S_MIPMAP_LINEAR]));
828  QVk_DebugSetObjectName((uint64_t)vk_samplers[S_MIPMAP_LINEAR], VK_OBJECT_TYPE_SAMPLER, "Sampler: S_MIPMAP_LINEAR");
829 
830  samplerInfo.maxLod = 1.f;
831  VK_VERIFY(vkCreateSampler(vk_device.logical, &samplerInfo, NULL, &vk_samplers[S_LINEAR]));
832  QVk_DebugSetObjectName((uint64_t)vk_samplers[S_LINEAR], VK_OBJECT_TYPE_SAMPLER, "Sampler: S_LINEAR");
833 
834  // aniso samplers
835  assert((vk_device.properties.limits.maxSamplerAnisotropy > 1.f) && "maxSamplerAnisotropy is 1");
836 
837  samplerInfo.magFilter = VK_FILTER_NEAREST;
838  samplerInfo.minFilter = VK_FILTER_NEAREST;
839  samplerInfo.mipmapMode = VK_SAMPLER_MIPMAP_MODE_NEAREST;
840  samplerInfo.anisotropyEnable = VK_TRUE;
841  samplerInfo.maxAnisotropy = vk_device.properties.limits.maxSamplerAnisotropy;
842  samplerInfo.maxLod = 1.f;
843 
844  VK_VERIFY(vkCreateSampler(vk_device.logical, &samplerInfo, NULL, &vk_samplers[S_ANISO_NEAREST]));
845  QVk_DebugSetObjectName((uint64_t)vk_samplers[S_ANISO_NEAREST], VK_OBJECT_TYPE_SAMPLER, "Sampler: S_ANISO_NEAREST");
846 
847  samplerInfo.maxLod = FLT_MAX;
848  VK_VERIFY(vkCreateSampler(vk_device.logical, &samplerInfo, NULL, &vk_samplers[S_ANISO_MIPMAP_NEAREST]));
849  QVk_DebugSetObjectName((uint64_t)vk_samplers[S_ANISO_MIPMAP_NEAREST], VK_OBJECT_TYPE_SAMPLER, "Sampler: S_ANISO_MIPMAP_NEAREST");
850 
851  samplerInfo.magFilter = VK_FILTER_LINEAR;
852  samplerInfo.minFilter = VK_FILTER_LINEAR;
853  samplerInfo.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR;
854  VK_VERIFY(vkCreateSampler(vk_device.logical, &samplerInfo, NULL, &vk_samplers[S_ANISO_MIPMAP_LINEAR]));
855  QVk_DebugSetObjectName((uint64_t)vk_samplers[S_ANISO_MIPMAP_LINEAR], VK_OBJECT_TYPE_SAMPLER, "Sampler: S_ANISO_MIPMAP_LINEAR");
856 
857  samplerInfo.maxLod = 1.f;
858  VK_VERIFY(vkCreateSampler(vk_device.logical, &samplerInfo, NULL, &vk_samplers[S_ANISO_LINEAR]));
859  QVk_DebugSetObjectName((uint64_t)vk_samplers[S_ANISO_LINEAR], VK_OBJECT_TYPE_SAMPLER, "Sampler: S_ANISO_LINEAR");
860 }
861 
862 // internal helper
863 static void DestroySamplers()
864 {
865  int i;
866  for (i = 0; i < S_SAMPLER_CNT; ++i)
867  {
868  if (vk_samplers[i] != VK_NULL_HANDLE)
869  vkDestroySampler(vk_device.logical, vk_samplers[i], NULL);
870 
871  vk_samplers[i] = VK_NULL_HANDLE;
872  }
873 }
874 
875 // internal helper
876 static void CreateDescriptorPool()
877 {
878  VkDescriptorPoolSize poolSizes[] = {
879  // UBO
880  {
881  .type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC,
882  .descriptorCount = 16
883  },
884  // sampler
885  {
886  .type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
887  .descriptorCount = MAX_VKTEXTURES + 1
888  }
889  };
890 
891  VkDescriptorPoolCreateInfo poolInfo = {
892  .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO,
893  .pNext = NULL,
894  .flags = VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT,
895  .maxSets = MAX_VKTEXTURES + 32,
896  .poolSizeCount = sizeof(poolSizes) / sizeof(poolSizes[0]),
897  .pPoolSizes = poolSizes,
898  };
899 
900  VK_VERIFY(vkCreateDescriptorPool(vk_device.logical, &poolInfo, NULL, &vk_descriptorPool));
901  QVk_DebugSetObjectName((uint64_t)vk_descriptorPool, VK_OBJECT_TYPE_DESCRIPTOR_POOL, "Descriptor Pool: Sampler + UBO");
902 }
903 
904 // internal helper
905 static void CreateUboDescriptorSet(VkDescriptorSet *descSet, VkBuffer buffer)
906 {
907  VkDescriptorSetAllocateInfo dsAllocInfo = {
908  .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO,
909  .pNext = NULL,
910  .descriptorPool = vk_descriptorPool,
911  .descriptorSetCount = 1,
912  .pSetLayouts = &vk_uboDescSetLayout
913  };
914 
915  VK_VERIFY(vkAllocateDescriptorSets(vk_device.logical, &dsAllocInfo, descSet));
916 
917  VkDescriptorBufferInfo bufferInfo = {
918  .buffer = buffer,
919  .offset = 0,
920  .range = UNIFORM_ALLOC_SIZE
921  };
922 
923  VkWriteDescriptorSet descriptorWrite = {
924  .sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
925  .pNext = NULL,
926  .dstSet = *descSet,
927  .dstBinding = 0,
928  .dstArrayElement = 0,
929  .descriptorCount = 1,
930  .descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC,
931  .pImageInfo = NULL,
932  .pBufferInfo = &bufferInfo,
933  .pTexelBufferView = NULL,
934  };
935 
936  vkUpdateDescriptorSets(vk_device.logical, 1, &descriptorWrite, 0, NULL);
937 }
938 
939 // internal helper
940 static void CreateDynamicBuffers()
941 {
942  for (int i = 0; i < NUM_DYNBUFFERS; ++i)
943  {
944  QVk_CreateVertexBuffer(NULL, vk_config.vertex_buffer_size, &vk_dynVertexBuffers[i], NULL, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, VK_MEMORY_PROPERTY_HOST_CACHED_BIT);
945  QVk_CreateIndexBuffer(NULL, vk_config.index_buffer_size, &vk_dynIndexBuffers[i], NULL, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, VK_MEMORY_PROPERTY_HOST_CACHED_BIT);
946  VK_VERIFY(QVk_CreateUniformBuffer(vk_config.uniform_buffer_size, &vk_dynUniformBuffers[i], VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, VK_MEMORY_PROPERTY_HOST_CACHED_BIT));
947  // keep dynamic buffers persistently mapped
948  VK_VERIFY(vmaMapMemory(vk_malloc, vk_dynVertexBuffers[i].allocation, &vk_dynVertexBuffers[i].allocInfo.pMappedData));
949  VK_VERIFY(vmaMapMemory(vk_malloc, vk_dynIndexBuffers[i].allocation, &vk_dynIndexBuffers[i].allocInfo.pMappedData));
950  VK_VERIFY(vmaMapMemory(vk_malloc, vk_dynUniformBuffers[i].allocation, &vk_dynUniformBuffers[i].allocInfo.pMappedData));
951  // create descriptor set for the uniform buffer
953 
954  QVk_DebugSetObjectName((uint64_t)vk_uboDescriptorSets[i], VK_OBJECT_TYPE_DESCRIPTOR_SET, va("Dynamic UBO Descriptor Set #%d", i));
955  QVk_DebugSetObjectName((uint64_t)vk_dynVertexBuffers[i].buffer, VK_OBJECT_TYPE_BUFFER, va("Dynamic Vertex Buffer #%d", i));
956  QVk_DebugSetObjectName((uint64_t)vk_dynVertexBuffers[i].allocInfo.deviceMemory, VK_OBJECT_TYPE_DEVICE_MEMORY, va("Memory: Dynamic Vertex Buffer #%d", i));
957  QVk_DebugSetObjectName((uint64_t)vk_dynIndexBuffers[i].buffer, VK_OBJECT_TYPE_BUFFER, va("Dynamic Index Buffer #%d", i));
958  QVk_DebugSetObjectName((uint64_t)vk_dynIndexBuffers[i].allocInfo.deviceMemory, VK_OBJECT_TYPE_DEVICE_MEMORY, va("Memory: Dynamic Index Buffer #%d", i));
959  QVk_DebugSetObjectName((uint64_t)vk_dynUniformBuffers[i].buffer, VK_OBJECT_TYPE_BUFFER, va("Dynamic Uniform Buffer #%d", i));
960  QVk_DebugSetObjectName((uint64_t)vk_dynUniformBuffers[i].allocInfo.deviceMemory, VK_OBJECT_TYPE_DEVICE_MEMORY, va("Memory: Dynamic Uniform Buffer #%d", i));
961  }
962 }
963 
964 // internal helper
965 static void ReleaseSwapBuffers()
966 {
968  int releaseBufferIdx = (vk_activeSwapBufferIdx + 1) % NUM_SWAPBUFFER_SLOTS;
969 
970  if (vk_swapBuffersCnt[releaseBufferIdx] > 0)
971  {
972  for (int i = 0; i < vk_swapBuffersCnt[releaseBufferIdx]; i++)
973  QVk_FreeBuffer(&vk_swapBuffers[releaseBufferIdx][i]);
974 
975  free(vk_swapBuffers[releaseBufferIdx]);
976  vk_swapBuffers[releaseBufferIdx] = NULL;
977  vk_swapBuffersCnt[releaseBufferIdx] = 0;
978  }
979 
980  if (vk_swapDescSetsCnt[releaseBufferIdx] > 0)
981  {
982  vkFreeDescriptorSets(vk_device.logical, vk_descriptorPool, vk_swapDescSetsCnt[releaseBufferIdx], vk_swapDescriptorSets[releaseBufferIdx]);
983 
984  free(vk_swapDescriptorSets[releaseBufferIdx]);
985  vk_swapDescriptorSets[releaseBufferIdx] = NULL;
986  vk_swapDescSetsCnt[releaseBufferIdx] = 0;
987  }
988 }
989 
990 // internal helper
991 static int NextPow2(int v)
992 {
993  v--;
994  v |= v >> 1;
995  v |= v >> 2;
996  v |= v >> 4;
997  v |= v >> 8;
998  v |= v >> 16;
999  v++;
1000  return v;
1001 }
1002 
1003 // internal helper
1005 {
1006  int idx = 0;
1007  VkDeviceSize dstOffset = 0;
1008  VkDeviceSize bufferSize = 3 * vk_config.triangle_fan_index_count * sizeof(uint16_t);
1009  uint16_t *iboData = NULL;
1010  uint16_t *fanData = malloc(bufferSize);
1011 
1012  // fill the index buffer so that we can emulate triangle fans via triangle lists
1013  for (int i = 0; i < vk_config.triangle_fan_index_count; ++i)
1014  {
1015  fanData[idx++] = 0;
1016  fanData[idx++] = i + 1;
1017  fanData[idx++] = i + 2;
1018  }
1019 
1020  for (int i = 0; i < NUM_DYNBUFFERS; ++i)
1021  {
1023  vmaInvalidateAllocation(vk_malloc, vk_dynIndexBuffers[i].allocation, 0, VK_WHOLE_SIZE);
1024 
1025  iboData = (uint16_t *)QVk_GetIndexBuffer(bufferSize, &dstOffset);
1026  memcpy(iboData, fanData, bufferSize);
1027 
1028  vmaFlushAllocation(vk_malloc, vk_dynIndexBuffers[i].allocation, 0, VK_WHOLE_SIZE);
1029  }
1030 
1032  vk_triangleFanIboUsage = ((bufferSize % 4) == 0) ? bufferSize : (bufferSize + 4 - (bufferSize % 4));
1033  free(fanData);
1034 }
1035 
1036 // internal helper
1038 {
1040  QVk_DebugSetObjectName((uint64_t)vk_stagingCommandPool, VK_OBJECT_TYPE_COMMAND_POOL, "Command Pool: Staging Buffers");
1041 
1042  VkFenceCreateInfo fCreateInfo = {
1043  .sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO,
1044  .flags = 0
1045  };
1046 
1047  for (int i = 0; i < NUM_DYNBUFFERS; ++i)
1048  {
1049  VK_VERIFY(QVk_CreateStagingBuffer(STAGING_BUFFER_MAXSIZE, &vk_stagingBuffers[i].buffer, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, VK_MEMORY_PROPERTY_HOST_CACHED_BIT));
1051  vk_stagingBuffers[i].submitted = false;
1052 
1053  VK_VERIFY(vkCreateFence(vk_device.logical, &fCreateInfo, NULL, &vk_stagingBuffers[i].fence));
1054 
1055  vk_stagingBuffers[i].cmdBuffer = QVk_CreateCommandBuffer(&vk_stagingCommandPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY);
1057 
1058  QVk_DebugSetObjectName((uint64_t)vk_stagingBuffers[i].fence, VK_OBJECT_TYPE_FENCE, va("Fence: Staging Buffer #%d", i));
1059  QVk_DebugSetObjectName((uint64_t)vk_stagingBuffers[i].buffer.buffer, VK_OBJECT_TYPE_BUFFER, va("Staging Buffer #%d", i));
1060  QVk_DebugSetObjectName((uint64_t)vk_stagingBuffers[i].buffer.allocInfo.deviceMemory, VK_OBJECT_TYPE_DEVICE_MEMORY, va("Memory: Staging Buffer #%d", i));
1061  QVk_DebugSetObjectName((uint64_t)vk_stagingBuffers[i].cmdBuffer, VK_OBJECT_TYPE_COMMAND_BUFFER, va("Command Buffer: Staging Buffer #%d", i));
1062  }
1063 }
1064 
1065 // internal helper
1066 static void SubmitStagingBuffer(int index)
1067 {
1068  VkMemoryBarrier memBarrier = {
1069  .sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER,
1070  .pNext = NULL,
1071  .srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT,
1072  .dstAccessMask = VK_ACCESS_INDEX_READ_BIT | VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT
1073  };
1074 
1075  vkCmdPipelineBarrier(vk_stagingBuffers[index].cmdBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_VERTEX_INPUT_BIT, 0, 1, &memBarrier, 0, NULL, 0, NULL);
1076  VK_VERIFY(vkEndCommandBuffer(vk_stagingBuffers[index].cmdBuffer));
1077 
1078  VkSubmitInfo submitInfo = {
1079  .sType = VK_STRUCTURE_TYPE_SUBMIT_INFO,
1080  .waitSemaphoreCount = 0,
1081  .pWaitSemaphores = NULL,
1082  .signalSemaphoreCount = 0,
1083  .pSignalSemaphores = NULL,
1084  .pWaitDstStageMask = NULL,
1085  .commandBufferCount = 1,
1086  .pCommandBuffers = &vk_stagingBuffers[index].cmdBuffer
1087  };
1088 
1089  VK_VERIFY(vkQueueSubmit(vk_device.gfxQueue, 1, &submitInfo, vk_stagingBuffers[index].fence));
1090 
1091  vk_stagingBuffers[index].submitted = true;
1093 }
1094 
1095 // internal helper
1096 static void CreateStaticBuffers()
1097 {
1098  const float texVerts[] = { -1., -1., 0., 0.,
1099  1., 1., 1., 1.,
1100  -1., 1., 0., 1.,
1101  1., -1., 1., 0. };
1102 
1103  const float colorVerts[] = { -1., -1.,
1104  1., 1.,
1105  -1., 1.,
1106  1., -1. };
1107 
1108  const uint32_t indices[] = { 0, 1, 2, 0, 3, 1 };
1109 
1110  QVk_CreateVertexBuffer(texVerts, sizeof(texVerts), &vk_texRectVbo, NULL, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, 0);
1111  QVk_CreateVertexBuffer(colorVerts, sizeof(colorVerts), &vk_colorRectVbo, NULL, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, 0);
1112  QVk_CreateIndexBuffer(indices, sizeof(indices), &vk_rectIbo, NULL, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, 0);
1113 
1114  QVk_DebugSetObjectName((uint64_t)vk_texRectVbo.buffer, VK_OBJECT_TYPE_BUFFER, "Static Buffer: Textured Rectangle VBO");
1115  QVk_DebugSetObjectName((uint64_t)vk_texRectVbo.allocInfo.deviceMemory, VK_OBJECT_TYPE_DEVICE_MEMORY, "Memory: Textured Rectangle VBO");
1116  QVk_DebugSetObjectName((uint64_t)vk_colorRectVbo.buffer, VK_OBJECT_TYPE_BUFFER, "Static Buffer: Colored Rectangle VBO");
1117  QVk_DebugSetObjectName((uint64_t)vk_colorRectVbo.allocInfo.deviceMemory, VK_OBJECT_TYPE_DEVICE_MEMORY, "Memory: Colored Rectangle VBO");
1118  QVk_DebugSetObjectName((uint64_t)vk_rectIbo.buffer, VK_OBJECT_TYPE_BUFFER, "Static Buffer: Rectangle IBO");
1119  QVk_DebugSetObjectName((uint64_t)vk_rectIbo.allocInfo.deviceMemory, VK_OBJECT_TYPE_DEVICE_MEMORY, "Memory: Rectangle IBO");
1120 }
1121 
1122 // internal helper
1123 static void CreatePipelines()
1124 {
1125  // shared pipeline vertex input state create infos
1126  VK_VERTINFO(RG, sizeof(float) * 2, VK_INPUTATTR_DESC(0, VK_FORMAT_R32G32_SFLOAT, 0));
1127 
1128  VK_VERTINFO(RGB, sizeof(float) * 3, VK_INPUTATTR_DESC(0, VK_FORMAT_R32G32B32_SFLOAT, 0));
1129 
1130  VK_VERTINFO(RG_RG, sizeof(float) * 4, VK_INPUTATTR_DESC(0, VK_FORMAT_R32G32_SFLOAT, 0),
1131  VK_INPUTATTR_DESC(1, VK_FORMAT_R32G32_SFLOAT, sizeof(float) * 2));
1132 
1133  VK_VERTINFO(RGB_RG, sizeof(float) * 5, VK_INPUTATTR_DESC(0, VK_FORMAT_R32G32B32_SFLOAT, 0),
1134  VK_INPUTATTR_DESC(1, VK_FORMAT_R32G32_SFLOAT, sizeof(float) * 3));
1135 
1136  VK_VERTINFO(RGB_RGB, sizeof(float) * 6, VK_INPUTATTR_DESC(0, VK_FORMAT_R32G32B32_SFLOAT, 0),
1137  VK_INPUTATTR_DESC(1, VK_FORMAT_R32G32B32_SFLOAT, sizeof(float) * 3));
1138 
1139  VK_VERTINFO(RGB_RGBA, sizeof(float) * 7, VK_INPUTATTR_DESC(0, VK_FORMAT_R32G32B32_SFLOAT, 0),
1140  VK_INPUTATTR_DESC(1, VK_FORMAT_R32G32B32A32_SFLOAT, sizeof(float) * 3));
1141 
1142  VK_VERTINFO(RGB_RG_RG, sizeof(float) * 7, VK_INPUTATTR_DESC(0, VK_FORMAT_R32G32B32_SFLOAT, 0),
1143  VK_INPUTATTR_DESC(1, VK_FORMAT_R32G32_SFLOAT, sizeof(float) * 3),
1144  VK_INPUTATTR_DESC(2, VK_FORMAT_R32G32_SFLOAT, sizeof(float) * 5));
1145 
1146  VK_VERTINFO(RGB_RGBA_RG, sizeof(float) * 9, VK_INPUTATTR_DESC(0, VK_FORMAT_R32G32B32_SFLOAT, 0),
1147  VK_INPUTATTR_DESC(1, VK_FORMAT_R32G32B32A32_SFLOAT, sizeof(float) * 3),
1148  VK_INPUTATTR_DESC(2, VK_FORMAT_R32G32_SFLOAT, sizeof(float) * 7));
1149  // no vertices passed to the pipeline (postprocessing)
1150  VkPipelineVertexInputStateCreateInfo vertInfoNull = VK_NULL_VERTEXINPUT_CINF;
1151 
1152  // shared descriptor set layouts
1153  VkDescriptorSetLayout samplerUboDsLayouts[] = { vk_samplerDescSetLayout, vk_uboDescSetLayout };
1154  VkDescriptorSetLayout samplerUboLmapDsLayouts[] = { vk_samplerDescSetLayout, vk_uboDescSetLayout, vk_samplerLightmapDescSetLayout };
1155 
1156  // shader array (vertex and fragment, no compute... yet)
1157  qvkshader_t shaders[2] = { VK_NULL_HANDLE, VK_NULL_HANDLE };
1158 
1159  // push constant sizes accomodate for maximum number of uploaded elements (should probably be checked against the hardware's maximum supported value)
1160  VkPushConstantRange pushConstantRangeVert = {
1161  .stageFlags = VK_SHADER_STAGE_VERTEX_BIT,
1162  .offset = 0,
1163  .size = 32 * sizeof(float)
1164  };
1165  VkPushConstantRange pushConstantRangeFrag = {
1166  .stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT,
1167  .offset = 0,
1168  .size = 4 * sizeof(float)
1169  };
1170 
1171  // textured quad pipeline
1172  VK_LOAD_VERTFRAG_SHADERS(shaders, basic, basic);
1174  QVk_CreatePipeline(samplerUboDsLayouts, 2, &vertInfoRG_RG, &vk_drawTexQuadPipeline, &vk_renderpasses[RP_UI], shaders, 2, &pushConstantRangeVert);
1175  QVk_DebugSetObjectName((uint64_t)vk_drawTexQuadPipeline.layout, VK_OBJECT_TYPE_PIPELINE_LAYOUT, "Pipeline Layout: textured quad");
1176  QVk_DebugSetObjectName((uint64_t)vk_drawTexQuadPipeline.pl, VK_OBJECT_TYPE_PIPELINE, "Pipeline: textured quad");
1177 
1178  // draw particles pipeline (using a texture)
1179  VK_LOAD_VERTFRAG_SHADERS(shaders, particle, basic);
1181  vk_drawParticlesPipeline.blendOpts.blendEnable = VK_TRUE;
1182  QVk_CreatePipeline(&vk_samplerDescSetLayout, 1, &vertInfoRGB_RGBA_RG, &vk_drawParticlesPipeline, &vk_renderpasses[RP_WORLD], shaders, 2, &pushConstantRangeVert);
1183  QVk_DebugSetObjectName((uint64_t)vk_drawParticlesPipeline.layout, VK_OBJECT_TYPE_PIPELINE_LAYOUT, "Pipeline Layout: textured particles");
1184  QVk_DebugSetObjectName((uint64_t)vk_drawParticlesPipeline.pl, VK_OBJECT_TYPE_PIPELINE, "Pipeline: textured particles");
1185 
1186  // draw particles pipeline (using point list)
1187  VK_LOAD_VERTFRAG_SHADERS(shaders, point_particle, point_particle);
1188  vk_drawPointParticlesPipeline.topology = VK_PRIMITIVE_TOPOLOGY_POINT_LIST;
1190  vk_drawPointParticlesPipeline.blendOpts.blendEnable = VK_TRUE;
1191  QVk_CreatePipeline(&vk_uboDescSetLayout, 1, &vertInfoRGB_RGBA, &vk_drawPointParticlesPipeline, &vk_renderpasses[RP_WORLD], shaders, 2, &pushConstantRangeVert);
1192  QVk_DebugSetObjectName((uint64_t)vk_drawPointParticlesPipeline.layout, VK_OBJECT_TYPE_PIPELINE_LAYOUT, "Pipeline Layout: point particles");
1193  QVk_DebugSetObjectName((uint64_t)vk_drawPointParticlesPipeline.pl, VK_OBJECT_TYPE_PIPELINE, "Pipeline: point particles");
1194 
1195  // colored quad pipeline
1196  VK_LOAD_VERTFRAG_SHADERS(shaders, basic_color_quad, basic_color_quad);
1197  for (int i = 0; i < 2; ++i)
1198  {
1200  vk_drawColorQuadPipeline[i].blendOpts.blendEnable = VK_TRUE;
1201  QVk_CreatePipeline(&vk_uboDescSetLayout, 1, &vertInfoRG, &vk_drawColorQuadPipeline[i], &vk_renderpasses[i], shaders, 2, &pushConstantRangeVert);
1202  }
1203  QVk_DebugSetObjectName((uint64_t)vk_drawColorQuadPipeline[0].layout, VK_OBJECT_TYPE_PIPELINE_LAYOUT, "Pipeline Layout: colored quad (RP_WORLD)");
1204  QVk_DebugSetObjectName((uint64_t)vk_drawColorQuadPipeline[0].pl, VK_OBJECT_TYPE_PIPELINE, "Pipeline: colored quad (RP_WORLD)");
1205  QVk_DebugSetObjectName((uint64_t)vk_drawColorQuadPipeline[1].layout, VK_OBJECT_TYPE_PIPELINE_LAYOUT, "Pipeline Layout: colored quad (RP_UI)");
1206  QVk_DebugSetObjectName((uint64_t)vk_drawColorQuadPipeline[1].pl, VK_OBJECT_TYPE_PIPELINE, "Pipeline: colored quad (RP_UI)");
1207 
1208  // untextured null model
1209  VK_LOAD_VERTFRAG_SHADERS(shaders, nullmodel, basic_color_quad);
1210  vk_drawNullModelPipeline.cullMode = VK_CULL_MODE_NONE;
1211  vk_drawNullModelPipeline.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
1212  QVk_CreatePipeline(&vk_uboDescSetLayout, 1, &vertInfoRGB_RGB, &vk_drawNullModelPipeline, &vk_renderpasses[RP_WORLD], shaders, 2, &pushConstantRangeVert);
1213  QVk_DebugSetObjectName((uint64_t)vk_drawNullModelPipeline.layout, VK_OBJECT_TYPE_PIPELINE_LAYOUT, "Pipeline Layout: null model");
1214  QVk_DebugSetObjectName((uint64_t)vk_drawNullModelPipeline.pl, VK_OBJECT_TYPE_PIPELINE, "Pipeline: null model");
1215 
1216  // textured model
1217  VK_LOAD_VERTFRAG_SHADERS(shaders, model, model);
1218  for (int i = 0; i < 2; ++i)
1219  {
1220  vk_drawModelPipelineStrip[i].topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP;
1221  vk_drawModelPipelineStrip[i].blendOpts.blendEnable = VK_TRUE;
1222  QVk_CreatePipeline(samplerUboDsLayouts, 2, &vertInfoRGB_RGBA_RG, &vk_drawModelPipelineStrip[i], &vk_renderpasses[i], shaders, 2, &pushConstantRangeVert);
1223 
1224  vk_drawModelPipelineFan[i].topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
1225  vk_drawModelPipelineFan[i].blendOpts.blendEnable = VK_TRUE;
1226  QVk_CreatePipeline(samplerUboDsLayouts, 2, &vertInfoRGB_RGBA_RG, &vk_drawModelPipelineFan[i], &vk_renderpasses[i], shaders, 2, &pushConstantRangeVert);
1227  }
1228  QVk_DebugSetObjectName((uint64_t)vk_drawModelPipelineStrip[0].layout, VK_OBJECT_TYPE_PIPELINE_LAYOUT, "Pipeline Layout: draw model: strip (RP_WORLD)");
1229  QVk_DebugSetObjectName((uint64_t)vk_drawModelPipelineStrip[0].pl, VK_OBJECT_TYPE_PIPELINE, "Pipeline: draw model: strip (RP_WORLD)");
1230  QVk_DebugSetObjectName((uint64_t)vk_drawModelPipelineStrip[1].layout, VK_OBJECT_TYPE_PIPELINE_LAYOUT, "Pipeline Layout: draw model: strip (RP_UI)");
1231  QVk_DebugSetObjectName((uint64_t)vk_drawModelPipelineStrip[1].pl, VK_OBJECT_TYPE_PIPELINE, "Pipeline: draw model: strip (RP_UI)");
1232  QVk_DebugSetObjectName((uint64_t)vk_drawModelPipelineFan[0].layout, VK_OBJECT_TYPE_PIPELINE_LAYOUT, "Pipeline Layout: draw model: fan (RP_WORLD)");
1233  QVk_DebugSetObjectName((uint64_t)vk_drawModelPipelineFan[0].pl, VK_OBJECT_TYPE_PIPELINE, "Pipeline: draw model: fan (RP_WORLD)");
1234  QVk_DebugSetObjectName((uint64_t)vk_drawModelPipelineFan[1].layout, VK_OBJECT_TYPE_PIPELINE_LAYOUT, "Pipeline Layout: draw model: fan (RP_UI)");
1235  QVk_DebugSetObjectName((uint64_t)vk_drawModelPipelineFan[1].pl, VK_OBJECT_TYPE_PIPELINE, "Pipeline: draw model: fan (RP_UI)");
1236 
1237  // dedicated model pipelines for translucent objects with depth write disabled
1238  vk_drawNoDepthModelPipelineStrip.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP;
1240  vk_drawNoDepthModelPipelineStrip.blendOpts.blendEnable = VK_TRUE;
1241  QVk_CreatePipeline(samplerUboDsLayouts, 2, &vertInfoRGB_RGBA_RG, &vk_drawNoDepthModelPipelineStrip, &vk_renderpasses[RP_WORLD], shaders, 2, &pushConstantRangeVert);
1242  QVk_DebugSetObjectName((uint64_t)vk_drawNoDepthModelPipelineStrip.layout, VK_OBJECT_TYPE_PIPELINE_LAYOUT, "Pipeline Layout: translucent model: strip");
1243  QVk_DebugSetObjectName((uint64_t)vk_drawNoDepthModelPipelineStrip.pl, VK_OBJECT_TYPE_PIPELINE, "Pipeline: translucent model: strip");
1244 
1245  vk_drawNoDepthModelPipelineFan.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
1247  vk_drawNoDepthModelPipelineFan.blendOpts.blendEnable = VK_TRUE;
1248  QVk_CreatePipeline(samplerUboDsLayouts, 2, &vertInfoRGB_RGBA_RG, &vk_drawNoDepthModelPipelineFan, &vk_renderpasses[RP_WORLD], shaders, 2, &pushConstantRangeVert);
1249  QVk_DebugSetObjectName((uint64_t)vk_drawNoDepthModelPipelineFan.layout, VK_OBJECT_TYPE_PIPELINE_LAYOUT, "Pipeline Layout: translucent model: fan");
1250  QVk_DebugSetObjectName((uint64_t)vk_drawNoDepthModelPipelineFan.pl, VK_OBJECT_TYPE_PIPELINE, "Pipeline: translucent model: fan");
1251 
1252  // dedicated model pipelines for when left-handed weapon model is drawn
1253  vk_drawLefthandModelPipelineStrip.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP;
1254  vk_drawLefthandModelPipelineStrip.cullMode = VK_CULL_MODE_FRONT_BIT;
1255  QVk_CreatePipeline(samplerUboDsLayouts, 2, &vertInfoRGB_RGBA_RG, &vk_drawLefthandModelPipelineStrip, &vk_renderpasses[RP_WORLD], shaders, 2, &pushConstantRangeVert);
1256  QVk_DebugSetObjectName((uint64_t)vk_drawLefthandModelPipelineStrip.layout, VK_OBJECT_TYPE_PIPELINE_LAYOUT, "Pipeline Layout: left-handed model: strip");
1257  QVk_DebugSetObjectName((uint64_t)vk_drawLefthandModelPipelineStrip.pl, VK_OBJECT_TYPE_PIPELINE, "Pipeline: left-handed model: strip");
1258 
1259  vk_drawLefthandModelPipelineFan.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
1260  vk_drawLefthandModelPipelineFan.cullMode = VK_CULL_MODE_FRONT_BIT;
1261  QVk_CreatePipeline(samplerUboDsLayouts, 2, &vertInfoRGB_RGBA_RG, &vk_drawLefthandModelPipelineFan, &vk_renderpasses[RP_WORLD], shaders, 2, &pushConstantRangeVert);
1262  QVk_DebugSetObjectName((uint64_t)vk_drawLefthandModelPipelineFan.layout, VK_OBJECT_TYPE_PIPELINE_LAYOUT, "Pipeline Layout: left-handed model: fan");
1263  QVk_DebugSetObjectName((uint64_t)vk_drawLefthandModelPipelineFan.pl, VK_OBJECT_TYPE_PIPELINE, "Pipeline: left-handed model: fan");
1264 
1265  // draw sprite pipeline
1266  VK_LOAD_VERTFRAG_SHADERS(shaders, sprite, basic);
1267  vk_drawSpritePipeline.blendOpts.blendEnable = VK_TRUE;
1268  QVk_CreatePipeline(&vk_samplerDescSetLayout, 1, &vertInfoRGB_RG, &vk_drawSpritePipeline, &vk_renderpasses[RP_WORLD], shaders, 2, &pushConstantRangeVert);
1269  QVk_DebugSetObjectName((uint64_t)vk_drawSpritePipeline.layout, VK_OBJECT_TYPE_PIPELINE_LAYOUT, "Pipeline Layout: sprite");
1270  QVk_DebugSetObjectName((uint64_t)vk_drawSpritePipeline.pl, VK_OBJECT_TYPE_PIPELINE, "Pipeline: sprite");
1271 
1272  // draw polygon pipeline
1273  VK_LOAD_VERTFRAG_SHADERS(shaders, polygon, basic);
1274  vk_drawPolyPipeline.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
1275  vk_drawPolyPipeline.blendOpts.blendEnable = VK_TRUE;
1276  QVk_CreatePipeline(samplerUboDsLayouts, 2, &vertInfoRGB_RG, &vk_drawPolyPipeline, &vk_renderpasses[RP_WORLD], shaders, 2, &pushConstantRangeVert);
1277  QVk_DebugSetObjectName((uint64_t)vk_drawPolyPipeline.layout, VK_OBJECT_TYPE_PIPELINE_LAYOUT, "Pipeline Layout: polygon");
1278  QVk_DebugSetObjectName((uint64_t)vk_drawPolyPipeline.pl, VK_OBJECT_TYPE_PIPELINE, "Pipeline: polygon");
1279 
1280  // draw lightmapped polygon
1281  VK_LOAD_VERTFRAG_SHADERS(shaders, polygon_lmap, polygon_lmap);
1282  vk_drawPolyLmapPipeline.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
1283  QVk_CreatePipeline(samplerUboLmapDsLayouts, 3, &vertInfoRGB_RG_RG, &vk_drawPolyLmapPipeline, &vk_renderpasses[RP_WORLD], shaders, 2, &pushConstantRangeVert);
1284  QVk_DebugSetObjectName((uint64_t)vk_drawPolyLmapPipeline.layout, VK_OBJECT_TYPE_PIPELINE_LAYOUT, "Pipeline Layout: lightmapped polygon");
1285  QVk_DebugSetObjectName((uint64_t)vk_drawPolyLmapPipeline.pl, VK_OBJECT_TYPE_PIPELINE, "Pipeline: lightmapped polygon");
1286 
1287  // draw polygon with warp effect (liquid) pipeline
1288  VK_LOAD_VERTFRAG_SHADERS(shaders, polygon_warp, basic);
1289  vk_drawPolyWarpPipeline.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
1290  vk_drawPolyWarpPipeline.blendOpts.blendEnable = VK_TRUE;
1291  QVk_CreatePipeline(samplerUboLmapDsLayouts, 2, &vertInfoRGB_RG, &vk_drawPolyWarpPipeline, &vk_renderpasses[RP_WORLD], shaders, 2, &pushConstantRangeVert);
1292  QVk_DebugSetObjectName((uint64_t)vk_drawPolyWarpPipeline.layout, VK_OBJECT_TYPE_PIPELINE_LAYOUT, "Pipeline Layout: warped polygon (liquids)");
1293  QVk_DebugSetObjectName((uint64_t)vk_drawPolyWarpPipeline.pl, VK_OBJECT_TYPE_PIPELINE, "Pipeline: warped polygon (liquids)");
1294 
1295  // draw beam pipeline
1296  VK_LOAD_VERTFRAG_SHADERS(shaders, beam, basic_color_quad);
1297  vk_drawBeamPipeline.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP;
1299  vk_drawBeamPipeline.blendOpts.blendEnable = VK_TRUE;
1300  QVk_CreatePipeline(&vk_uboDescSetLayout, 1, &vertInfoRGB, &vk_drawBeamPipeline, &vk_renderpasses[RP_WORLD], shaders, 2, &pushConstantRangeVert);
1301  QVk_DebugSetObjectName((uint64_t)vk_drawBeamPipeline.layout, VK_OBJECT_TYPE_PIPELINE_LAYOUT, "Pipeline Layout: beam");
1302  QVk_DebugSetObjectName((uint64_t)vk_drawBeamPipeline.pl, VK_OBJECT_TYPE_PIPELINE, "Pipeline: beam");
1303 
1304  // draw skybox pipeline
1305  VK_LOAD_VERTFRAG_SHADERS(shaders, skybox, basic);
1306  QVk_CreatePipeline(samplerUboDsLayouts, 2, &vertInfoRGB_RG, &vk_drawSkyboxPipeline, &vk_renderpasses[RP_WORLD], shaders, 2, &pushConstantRangeVert);
1307  QVk_DebugSetObjectName((uint64_t)vk_drawSkyboxPipeline.layout, VK_OBJECT_TYPE_PIPELINE_LAYOUT, "Pipeline Layout: skybox");
1308  QVk_DebugSetObjectName((uint64_t)vk_drawSkyboxPipeline.pl, VK_OBJECT_TYPE_PIPELINE, "Pipeline: skybox");
1309 
1310  // draw dynamic light pipeline
1311  VK_LOAD_VERTFRAG_SHADERS(shaders, d_light, basic_color_quad);
1312  vk_drawDLightPipeline.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
1314  vk_drawDLightPipeline.cullMode = VK_CULL_MODE_FRONT_BIT;
1315  vk_drawDLightPipeline.blendOpts.blendEnable = VK_TRUE;
1316  vk_drawDLightPipeline.blendOpts.srcColorBlendFactor = VK_BLEND_FACTOR_ONE;
1317  vk_drawDLightPipeline.blendOpts.dstColorBlendFactor = VK_BLEND_FACTOR_ONE;
1318  vk_drawDLightPipeline.blendOpts.srcAlphaBlendFactor = VK_BLEND_FACTOR_ONE;
1319  vk_drawDLightPipeline.blendOpts.dstAlphaBlendFactor = VK_BLEND_FACTOR_ONE;
1320  QVk_CreatePipeline(&vk_uboDescSetLayout, 1, &vertInfoRGB_RGB, &vk_drawDLightPipeline, &vk_renderpasses[RP_WORLD], shaders, 2, &pushConstantRangeVert);
1321  QVk_DebugSetObjectName((uint64_t)vk_drawDLightPipeline.layout, VK_OBJECT_TYPE_PIPELINE_LAYOUT, "Pipeline Layout: dynamic light");
1322  QVk_DebugSetObjectName((uint64_t)vk_drawDLightPipeline.pl, VK_OBJECT_TYPE_PIPELINE, "Pipeline: dynamic light");
1323 
1324  // vk_showtris render pipeline
1325  VK_LOAD_VERTFRAG_SHADERS(shaders, d_light, basic_color_quad);
1326  vk_showTrisPipeline.cullMode = VK_CULL_MODE_NONE;
1329  vk_showTrisPipeline.topology = VK_PRIMITIVE_TOPOLOGY_LINE_STRIP;
1330  QVk_CreatePipeline(&vk_uboDescSetLayout, 1, &vertInfoRGB_RGB, &vk_showTrisPipeline, &vk_renderpasses[RP_WORLD], shaders, 2, &pushConstantRangeVert);
1331  QVk_DebugSetObjectName((uint64_t)vk_showTrisPipeline.layout, VK_OBJECT_TYPE_PIPELINE_LAYOUT, "Pipeline Layout: show triangles");
1332  QVk_DebugSetObjectName((uint64_t)vk_showTrisPipeline.pl, VK_OBJECT_TYPE_PIPELINE, "Pipeline: show triangles");
1333 
1334  //vk_shadows render pipeline
1335  VK_LOAD_VERTFRAG_SHADERS(shaders, shadows, basic_color_quad);
1336  vk_shadowsPipelineStrip.blendOpts.blendEnable = VK_TRUE;
1337  vk_shadowsPipelineStrip.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP;
1338  QVk_CreatePipeline(&vk_uboDescSetLayout, 1, &vertInfoRGB, &vk_shadowsPipelineStrip, &vk_renderpasses[RP_WORLD], shaders, 2, &pushConstantRangeVert);
1339  QVk_DebugSetObjectName((uint64_t)vk_shadowsPipelineStrip.layout, VK_OBJECT_TYPE_PIPELINE_LAYOUT, "Pipeline Layout: draw shadows: strip");
1340  QVk_DebugSetObjectName((uint64_t)vk_shadowsPipelineStrip.pl, VK_OBJECT_TYPE_PIPELINE, "Pipeline: draw shadows: strip");
1341 
1342  vk_shadowsPipelineFan.blendOpts.blendEnable = VK_TRUE;
1343  vk_shadowsPipelineFan.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
1344  QVk_CreatePipeline(&vk_uboDescSetLayout, 1, &vertInfoRGB, &vk_shadowsPipelineFan, &vk_renderpasses[RP_WORLD], shaders, 2, &pushConstantRangeVert);
1345  QVk_DebugSetObjectName((uint64_t)vk_shadowsPipelineFan.layout, VK_OBJECT_TYPE_PIPELINE_LAYOUT, "Pipeline Layout: draw shadows: fan");
1346  QVk_DebugSetObjectName((uint64_t)vk_shadowsPipelineFan.pl, VK_OBJECT_TYPE_PIPELINE, "Pipeline: draw shadows: fan");
1347 
1348  // underwater world warp pipeline (postprocess)
1349  VK_LOAD_VERTFRAG_SHADERS(shaders, world_warp, world_warp);
1352  vk_worldWarpPipeline.cullMode = VK_CULL_MODE_NONE;
1353  QVk_CreatePipeline(&vk_samplerDescSetLayout, 1, &vertInfoNull, &vk_worldWarpPipeline, &vk_renderpasses[RP_WORLD_WARP], shaders, 2, &pushConstantRangeFrag);
1354  QVk_DebugSetObjectName((uint64_t)vk_worldWarpPipeline.layout, VK_OBJECT_TYPE_PIPELINE_LAYOUT, "Pipeline Layout: underwater view warp");
1355  QVk_DebugSetObjectName((uint64_t)vk_worldWarpPipeline.pl, VK_OBJECT_TYPE_PIPELINE, "Pipeline: underwater view warp");
1356 
1357  // postprocessing pipeline
1358  VK_LOAD_VERTFRAG_SHADERS(shaders, postprocess, postprocess);
1361  vk_postprocessPipeline.cullMode = VK_CULL_MODE_NONE;
1362  QVk_CreatePipeline(&vk_samplerDescSetLayout, 1, &vertInfoNull, &vk_postprocessPipeline, &vk_renderpasses[RP_UI], shaders, 2, &pushConstantRangeFrag);
1363  QVk_DebugSetObjectName((uint64_t)vk_postprocessPipeline.layout, VK_OBJECT_TYPE_PIPELINE_LAYOUT, "Pipeline Layout: world postprocess");
1364  QVk_DebugSetObjectName((uint64_t)vk_postprocessPipeline.pl, VK_OBJECT_TYPE_PIPELINE, "Pipeline: world postprocess");
1365 
1366  // final shader cleanup
1367  vkDestroyShaderModule(vk_device.logical, shaders[0].module, NULL);
1368  vkDestroyShaderModule(vk_device.logical, shaders[1].module, NULL);
1369 }
1370 
1371 /*
1372 ** QVk_Shutdown
1373 **
1374 ** Destroy all Vulkan related resources.
1375 */
1376 void QVk_Shutdown( void )
1377 {
1378  if (vk_instance != VK_NULL_HANDLE)
1379  {
1380  ri.Con_Printf(PRINT_ALL, "Shutting down Vulkan\n");
1381 
1382  for (int i = 0; i < 2; ++i)
1383  {
1387  }
1411  for (int i = 0; i < NUM_DYNBUFFERS; ++i)
1412  {
1413  if (vk_dynUniformBuffers[i].buffer != VK_NULL_HANDLE)
1414  {
1417  }
1418  if (vk_dynIndexBuffers[i].buffer != VK_NULL_HANDLE)
1419  {
1422  }
1423  if (vk_dynVertexBuffers[i].buffer != VK_NULL_HANDLE)
1424  {
1427  }
1428  if (vk_stagingBuffers[i].buffer.buffer != VK_NULL_HANDLE)
1429  {
1432  vkDestroyFence(vk_device.logical, vk_stagingBuffers[i].fence, NULL);
1433  }
1434  }
1435  if (vk_descriptorPool != VK_NULL_HANDLE)
1436  vkDestroyDescriptorPool(vk_device.logical, vk_descriptorPool, NULL);
1437  if (vk_uboDescSetLayout != VK_NULL_HANDLE)
1438  vkDestroyDescriptorSetLayout(vk_device.logical, vk_uboDescSetLayout, NULL);
1439  if (vk_samplerDescSetLayout != VK_NULL_HANDLE)
1440  vkDestroyDescriptorSetLayout(vk_device.logical, vk_samplerDescSetLayout, NULL);
1441  if (vk_samplerLightmapDescSetLayout != VK_NULL_HANDLE)
1442  vkDestroyDescriptorSetLayout(vk_device.logical, vk_samplerLightmapDescSetLayout, NULL);
1443  for (int i = 0; i < RP_COUNT; i++)
1444  {
1445  if (vk_renderpasses[i].rp != VK_NULL_HANDLE)
1446  vkDestroyRenderPass(vk_device.logical, vk_renderpasses[i].rp, NULL);
1447  vk_renderpasses[i].rp = VK_NULL_HANDLE;
1448  }
1449  if (vk_commandbuffers)
1450  {
1452  free(vk_commandbuffers);
1454  }
1455  if (vk_commandPool != VK_NULL_HANDLE)
1456  vkDestroyCommandPool(vk_device.logical, vk_commandPool, NULL);
1457  if (vk_transferCommandPool != VK_NULL_HANDLE)
1458  vkDestroyCommandPool(vk_device.logical, vk_transferCommandPool, NULL);
1459  if (vk_stagingCommandPool != VK_NULL_HANDLE)
1460  vkDestroyCommandPool(vk_device.logical, vk_stagingCommandPool, NULL);
1461  DestroySamplers();
1465  if (vk_swapchain.sc != VK_NULL_HANDLE)
1466  {
1467  vkDestroySwapchainKHR(vk_device.logical, vk_swapchain.sc, NULL);
1468  free(vk_swapchain.images);
1469  vk_swapchain.sc = VK_NULL_HANDLE;
1472  }
1473  for (int i = 0; i < NUM_CMDBUFFERS; ++i)
1474  {
1475  vkDestroySemaphore(vk_device.logical, vk_imageAvailableSemaphores[i], NULL);
1476  vkDestroySemaphore(vk_device.logical, vk_renderFinishedSemaphores[i], NULL);
1477  vkDestroyFence(vk_device.logical, vk_fences[i], NULL);
1478  }
1479  if (vk_malloc != VK_NULL_HANDLE)
1481  if (vk_device.logical != VK_NULL_HANDLE)
1482  vkDestroyDevice(vk_device.logical, NULL);
1483  if(vk_surface != VK_NULL_HANDLE)
1484  vkDestroySurfaceKHR(vk_instance, vk_surface, NULL);
1486 
1487  vkDestroyInstance(vk_instance, NULL);
1488  vk_instance = VK_NULL_HANDLE;
1489  vk_activeCmdbuffer = VK_NULL_HANDLE;
1490  vk_descriptorPool = VK_NULL_HANDLE;
1491  vk_uboDescSetLayout = VK_NULL_HANDLE;
1492  vk_samplerDescSetLayout = VK_NULL_HANDLE;
1493  vk_samplerLightmapDescSetLayout = VK_NULL_HANDLE;
1494  vk_commandPool = VK_NULL_HANDLE;
1495  vk_transferCommandPool = VK_NULL_HANDLE;
1496  vk_stagingCommandPool = VK_NULL_HANDLE;
1497  vk_activeBufferIdx = 0;
1498  vk_imageIndex = 0;
1499  }
1500 }
1501 
1502 # pragma warning (disable : 4113 4133 4047 )
1503 
1504 /*
1505 ** QVk_Init
1506 **
1507 ** This is responsible for initializing Vulkan.
1508 **
1509 */
1511 {
1512  PFN_vkEnumerateInstanceVersion vkEnumerateInstanceVersion = (PFN_vkEnumerateInstanceVersion)vkGetInstanceProcAddr(NULL, "vkEnumerateInstanceVersion");
1513  uint32_t instanceVersion = VK_API_VERSION_1_0;
1514 
1515  if (vkEnumerateInstanceVersion)
1516  {
1517  VK_VERIFY(vkEnumerateInstanceVersion(&instanceVersion));
1518  }
1519 
1520  VkApplicationInfo appInfo = {
1521  .sType = VK_STRUCTURE_TYPE_APPLICATION_INFO,
1522  .pNext = NULL,
1523  .pApplicationName = "Quake 2",
1524  .applicationVersion = VK_MAKE_VERSION(3, 21, 0),
1525  .pEngineName = "id Tech 2",
1526  .engineVersion = VK_MAKE_VERSION(2, 0, 0),
1527  .apiVersion = instanceVersion
1528  };
1529 
1530  uint32_t extCount;
1531  char **wantedExtensions;
1532  memset((char*)vk_config.supported_present_modes, 0, 256);
1533  memset((char*)vk_config.extensions, 0, 256);
1534  memset((char*)vk_config.layers, 0, 256);
1535  vk_config.vk_version = instanceVersion;
1548 
1549  Vkimp_GetSurfaceExtensions(NULL, &extCount);
1550 
1551  if (vk_validation->value)
1552  extCount++;
1553 #if defined(_DEBUG) || defined(ENABLE_DEBUG_LABELS)
1554  else
1555  extCount++;
1556 #endif
1557 
1558  wantedExtensions = (char **)malloc(extCount * sizeof(const char *));
1559  Vkimp_GetSurfaceExtensions(wantedExtensions, NULL);
1560 
1561  if (vk_validation->value)
1562  wantedExtensions[extCount - 1] = VK_EXT_DEBUG_UTILS_EXTENSION_NAME;
1563 #if defined(_DEBUG) || defined(ENABLE_DEBUG_LABELS)
1564  else
1565  wantedExtensions[extCount - 1] = VK_EXT_DEBUG_UTILS_EXTENSION_NAME;
1566 #endif
1567 
1568  ri.Con_Printf(PRINT_ALL, "Enabled extensions: ");
1569  for (int i = 0; i < extCount; i++)
1570  {
1571  ri.Con_Printf(PRINT_ALL, "%s ", wantedExtensions[i]);
1572  vk_config.extensions[i] = wantedExtensions[i];
1573  }
1574  ri.Con_Printf(PRINT_ALL, "\n");
1575 
1576  VkInstanceCreateInfo createInfo = {
1577  .sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO,
1578  .pNext = NULL,
1579  .pApplicationInfo = &appInfo,
1580  .enabledLayerCount = 0,
1581  .ppEnabledLayerNames = NULL,
1582  .enabledExtensionCount = extCount,
1583  .ppEnabledExtensionNames = (const char* const*)wantedExtensions
1584  };
1585 
1586 #if VK_HEADER_VERSION > 101
1587  const char *validationLayers[] = { "VK_LAYER_KHRONOS_validation" };
1588 #else
1589  const char *validationLayers[] = { "VK_LAYER_LUNARG_standard_validation" };
1590 #endif
1591 
1592  if (vk_validation->value)
1593  {
1594  createInfo.enabledLayerCount = sizeof(validationLayers) / sizeof(validationLayers[0]);
1595  createInfo.ppEnabledLayerNames = validationLayers;
1596  for (int i = 0; i < createInfo.enabledLayerCount; i++)
1597  {
1598  vk_config.layers[i] = validationLayers[i];
1599  }
1600  }
1601 
1602  VkResult res = vkCreateInstance(&createInfo, NULL, &vk_instance);
1603  free(wantedExtensions);
1604 
1605  if (res != VK_SUCCESS)
1606  {
1607  ri.Con_Printf(PRINT_ALL, "QVk_Init(): Could not create Vulkan instance: %s\n", QVk_GetError(res));
1608  return false;
1609  }
1610  ri.Con_Printf(PRINT_ALL, "...created Vulkan instance\n");
1611 
1612  // initialize function pointers
1613  qvkCreateDebugUtilsMessengerEXT = (PFN_vkCreateDebugUtilsMessengerEXT)vkGetInstanceProcAddr(vk_instance, "vkCreateDebugUtilsMessengerEXT");
1614  qvkDestroyDebugUtilsMessengerEXT = (PFN_vkDestroyDebugUtilsMessengerEXT)vkGetInstanceProcAddr(vk_instance, "vkDestroyDebugUtilsMessengerEXT");
1615  qvkSetDebugUtilsObjectNameEXT = (PFN_vkSetDebugUtilsObjectNameEXT)vkGetInstanceProcAddr(vk_instance, "vkSetDebugUtilsObjectNameEXT");
1616  qvkSetDebugUtilsObjectTagEXT = (PFN_vkSetDebugUtilsObjectTagEXT)vkGetInstanceProcAddr(vk_instance, "vkSetDebugUtilsObjectTagEXT");
1617  qvkCmdBeginDebugUtilsLabelEXT = (PFN_vkCmdBeginDebugUtilsLabelEXT)vkGetInstanceProcAddr(vk_instance, "vkCmdBeginDebugUtilsLabelEXT");
1618  qvkCmdEndDebugUtilsLabelEXT = (PFN_vkCmdEndDebugUtilsLabelEXT)vkGetInstanceProcAddr(vk_instance, "vkCmdEndDebugUtilsLabelEXT");
1619  qvkInsertDebugUtilsLabelEXT = (PFN_vkCmdInsertDebugUtilsLabelEXT)vkGetInstanceProcAddr(vk_instance, "vkCmdInsertDebugUtilsLabelEXT");
1620 
1621  if (vk_validation->value)
1623 
1624  res = Vkimp_CreateSurface();
1625  if (res != VK_SUCCESS)
1626  {
1627  ri.Con_Printf(PRINT_ALL, "QVk_Init(): Could not create Vulkan surface: %s\n", QVk_GetError(res));
1628  return false;
1629  }
1630  ri.Con_Printf(PRINT_ALL, "...created Vulkan surface\n");
1631 
1632  // create Vulkan device - see if the user prefers any specific device if there's more than one GPU in the system
1634  QVk_DebugSetObjectName((uint64_t)vk_device.physical, VK_OBJECT_TYPE_PHYSICAL_DEVICE, va("Physical Device: %s", vk_config.vendor_name));
1635 
1636  // create memory allocator
1637  VmaAllocatorCreateInfo allocInfo = {
1638  .flags = 0,
1639  .physicalDevice = vk_device.physical,
1640  .device = vk_device.logical,
1641  .preferredLargeHeapBlockSize = 0,
1642  .pAllocationCallbacks = NULL,
1643  .pDeviceMemoryCallbacks = NULL,
1644  .frameInUseCount = 0,
1645  .pHeapSizeLimit = NULL,
1646  .pVulkanFunctions = NULL,
1647  .pRecordSettings = NULL
1648  };
1649 
1650  res = vmaCreateAllocator(&allocInfo, &vk_malloc);
1651  if (res != VK_SUCCESS)
1652  {
1653  ri.Con_Printf(PRINT_ALL, "QVk_Init(): Could not create Vulkan memory allocator: %s\n", QVk_GetError(res));
1654  return false;
1655  }
1656  ri.Con_Printf(PRINT_ALL, "...created Vulkan memory allocator\n");
1657 
1658  // setup swapchain
1659  res = QVk_CreateSwapchain();
1660  if (res != VK_SUCCESS)
1661  {
1662  ri.Con_Printf(PRINT_ALL, "QVk_Init(): Could not create Vulkan swapchain: %s\n", QVk_GetError(res));
1663  return false;
1664  }
1665  ri.Con_Printf(PRINT_ALL, "...created Vulkan swapchain\n");
1666 
1667  // set viewport and scissor
1668  vk_viewport.x = 0.f;
1669  vk_viewport.y = 0.f;
1670  vk_viewport.minDepth = 0.f;
1671  vk_viewport.maxDepth = 1.f;
1672  vk_viewport.width = (float)vid.width;
1673  vk_viewport.height = (float)vid.height;
1674  vk_scissor.offset.x = 0;
1675  vk_scissor.offset.y = 0;
1676  vk_scissor.extent = vk_swapchain.extent;
1677 
1678  // setup fences and semaphores
1679  VkFenceCreateInfo fCreateInfo = {
1680  .sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO,
1681  .pNext = NULL,
1682  .flags = VK_FENCE_CREATE_SIGNALED_BIT
1683  };
1684  VkSemaphoreCreateInfo sCreateInfo = {
1685  .sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO,
1686  .pNext = NULL,
1687  .flags = 0
1688  };
1689  for (int i = 0; i < NUM_CMDBUFFERS; ++i)
1690  {
1691  VK_VERIFY(vkCreateFence(vk_device.logical, &fCreateInfo, NULL, &vk_fences[i]));
1692  VK_VERIFY(vkCreateSemaphore(vk_device.logical, &sCreateInfo, NULL, &vk_imageAvailableSemaphores[i]));
1693  VK_VERIFY(vkCreateSemaphore(vk_device.logical, &sCreateInfo, NULL, &vk_renderFinishedSemaphores[i]));
1694 
1695  QVk_DebugSetObjectName((uint64_t)vk_fences[i], VK_OBJECT_TYPE_FENCE, va("Fence #%d", i));
1696  QVk_DebugSetObjectName((uint64_t)vk_imageAvailableSemaphores[i], VK_OBJECT_TYPE_SEMAPHORE, va("Semaphore: image available #%d", i));
1697  QVk_DebugSetObjectName((uint64_t)vk_renderFinishedSemaphores[i], VK_OBJECT_TYPE_SEMAPHORE, va("Semaphore: render finished #%d", i));
1698  }
1699  ri.Con_Printf(PRINT_ALL, "...created synchronization objects\n");
1700 
1701  // setup render passes
1702  for (int i = 0; i < RP_COUNT; ++i)
1703  {
1704  vk_renderpasses[i].colorLoadOp = vk_clear->value ? VK_ATTACHMENT_LOAD_OP_CLEAR : VK_ATTACHMENT_LOAD_OP_DONT_CARE;
1705  }
1706 
1707  VkSampleCountFlagBits msaaMode = GetSampleCount();
1708  VkSampleCountFlagBits supportedMsaa = vk_device.properties.limits.framebufferColorSampleCounts;
1709  if (!(supportedMsaa & msaaMode))
1710  {
1711  ri.Con_Printf(PRINT_ALL, "MSAAx%d mode not supported, aborting...\n", msaaMode);
1712  ri.Cvar_Set("vk_msaa", "0");
1713  msaaMode = VK_SAMPLE_COUNT_1_BIT;
1714  // avoid secondary video reload
1715  vk_msaa->modified = false;
1716  }
1717 
1718  // MSAA setting will be only relevant for the primary world render pass
1719  vk_renderpasses[RP_WORLD].sampleCount = msaaMode;
1720 
1721  res = CreateRenderpasses();
1722  if (res != VK_SUCCESS)
1723  {
1724  ri.Con_Printf(PRINT_ALL, "QVk_Init(): Could not create Vulkan render passes: %s\n", QVk_GetError(res));
1725  return false;
1726  }
1727  ri.Con_Printf(PRINT_ALL, "...created %d Vulkan render passes\n", RP_COUNT);
1728 
1729  // setup command pools
1731  if (res != VK_SUCCESS)
1732  {
1733  ri.Con_Printf(PRINT_ALL, "QVk_Init(): Could not create Vulkan command pool for graphics: %s\n", QVk_GetError(res));
1734  return false;
1735  }
1737  if (res != VK_SUCCESS)
1738  {
1739  ri.Con_Printf(PRINT_ALL, "QVk_Init(): Could not create Vulkan command pool for transfer: %s\n", QVk_GetError(res));
1740  return false;
1741  }
1742 
1743  QVk_DebugSetObjectName((uint64_t)vk_commandPool, VK_OBJECT_TYPE_COMMAND_POOL, "Command Pool: Graphics");
1744  QVk_DebugSetObjectName((uint64_t)vk_transferCommandPool, VK_OBJECT_TYPE_COMMAND_POOL, "Command Pool: Transfer");
1745  ri.Con_Printf(PRINT_ALL, "...created Vulkan command pools\n");
1746 
1747  // setup draw buffers
1749 
1750  // setup image views
1751  res = CreateImageViews();
1752  if (res != VK_SUCCESS)
1753  {
1754  ri.Con_Printf(PRINT_ALL, "QVk_Init(): Could not create Vulkan image views: %s\n", QVk_GetError(res));
1755  return false;
1756  }
1757  ri.Con_Printf(PRINT_ALL, "...created %d Vulkan image view(s)\n", vk_swapchain.imageCount);
1758 
1759  // setup framebuffers
1760  res = CreateFramebuffers();
1761  if (res != VK_SUCCESS)
1762  {
1763  ri.Con_Printf(PRINT_ALL, "QVk_Init(): Could not create Vulkan framebuffers: %s\n", QVk_GetError(res));
1764  return false;
1765  }
1766  ri.Con_Printf(PRINT_ALL, "...created %d Vulkan framebuffers\n", vk_swapchain.imageCount);
1767 
1768  // setup command buffers (double buffering)
1769  vk_commandbuffers = (VkCommandBuffer *)malloc(NUM_CMDBUFFERS * sizeof(VkCommandBuffer));
1770 
1771  VkCommandBufferAllocateInfo cbInfo = {
1772  .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,
1773  .pNext = NULL,
1774  .commandPool = vk_commandPool,
1775  .level = VK_COMMAND_BUFFER_LEVEL_PRIMARY,
1776  .commandBufferCount = NUM_CMDBUFFERS
1777  };
1778 
1779  res = vkAllocateCommandBuffers(vk_device.logical, &cbInfo, vk_commandbuffers);
1780  if (res != VK_SUCCESS)
1781  {
1782  ri.Con_Printf(PRINT_ALL, "QVk_Init(): Could not create Vulkan commandbuffers: %s\n", QVk_GetError(res));
1783  free(vk_commandbuffers);
1785  return false;
1786  }
1787  ri.Con_Printf(PRINT_ALL, "...created %d Vulkan commandbuffers\n", NUM_CMDBUFFERS);
1788 
1789  // initialize tracker variables
1791 
1794  // create static vertex/index buffers reused in the games
1796  // create vertex, index and uniform buffer pools
1798  // create staging buffers
1800  // assign a dynamic index buffer for triangle fan emulation
1802  CreatePipelines();
1803  CreateSamplers();
1804 
1805  // main and world warp color buffers will be sampled for postprocessing effects, so they need descriptors and samplers
1806  VkDescriptorSetAllocateInfo dsAllocInfo = {
1807  .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO,
1808  .pNext = NULL,
1809  .descriptorPool = vk_descriptorPool,
1810  .descriptorSetCount = 1,
1811  .pSetLayouts = &vk_samplerDescSetLayout
1812  };
1813 
1814  VK_VERIFY(vkAllocateDescriptorSets(vk_device.logical, &dsAllocInfo, &vk_colorbuffer.descriptorSet));
1816  VK_VERIFY(vkAllocateDescriptorSets(vk_device.logical, &dsAllocInfo, &vk_colorbufferWarp.descriptorSet));
1818 
1819  QVk_DebugSetObjectName((uint64_t)vk_colorbuffer.descriptorSet, VK_OBJECT_TYPE_DESCRIPTOR_SET, "Descriptor Set: World Color Buffer");
1820  QVk_DebugSetObjectName((uint64_t)vk_colorbufferWarp.descriptorSet, VK_OBJECT_TYPE_DESCRIPTOR_SET, "Descriptor Set: Warp Postprocess Color Buffer");
1821  return true;
1822 }
1823 
1824 VkResult QVk_BeginFrame()
1825 {
1826  // reset tracking variables
1827  vk_state.current_pipeline = VK_NULL_HANDLE;
1829  // triangle fan index buffer data will not be cleared between frames unless the buffer itself is too small
1833 
1835 
1836  VkResult result = vkAcquireNextImageKHR(vk_device.logical, vk_swapchain.sc, UINT32_MAX, vk_imageAvailableSemaphores[vk_activeBufferIdx], VK_NULL_HANDLE, &vk_imageIndex);
1838 
1839  // swap dynamic buffers
1843  // triangle fan index data is placed in the beginning of the buffer
1848 
1849  // for VK_OUT_OF_DATE_KHR and VK_SUBOPTIMAL_KHR it'd be fine to just rebuild the swapchain but let's take the easy way out and restart video system
1850  if (result == VK_ERROR_OUT_OF_DATE_KHR || result == VK_SUBOPTIMAL_KHR || result == VK_ERROR_SURFACE_LOST_KHR)
1851  {
1852  ri.Con_Printf(PRINT_ALL, "QVk_BeginFrame(): received %s after vkAcquireNextImageKHR - restarting video!\n", QVk_GetError(result));
1853  return result;
1854  }
1855  else if (result != VK_SUCCESS)
1856  {
1857  Sys_Error("QVk_BeginFrame(): unexpected error after vkAcquireNextImageKHR: %s", QVk_GetError(result));
1858  }
1859 
1860  VK_VERIFY(vkWaitForFences(vk_device.logical, 1, &vk_fences[vk_activeBufferIdx], VK_TRUE, UINT32_MAX));
1861  VK_VERIFY(vkResetFences(vk_device.logical, 1, &vk_fences[vk_activeBufferIdx]));
1862 
1863  // setup command buffers and render pass for drawing
1864  VkCommandBufferBeginInfo beginInfo = {
1865  .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
1866  .pNext = NULL,
1867  .flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT,
1868  .pInheritanceInfo = NULL
1869  };
1870 
1871  VK_VERIFY(vkBeginCommandBuffer(vk_commandbuffers[vk_activeBufferIdx], &beginInfo));
1872 
1873  vkCmdSetViewport(vk_commandbuffers[vk_activeBufferIdx], 0, 1, &vk_viewport);
1874  vkCmdSetScissor(vk_commandbuffers[vk_activeBufferIdx], 0, 1, &vk_scissor);
1875 
1876  vk_frameStarted = true;
1877  return VK_SUCCESS;
1878 }
1879 
1880 VkResult QVk_EndFrame(qboolean force)
1881 {
1882  // continue only if QVk_BeginFrame() had been previously issued
1883  if (!vk_frameStarted)
1884  return VK_NOT_READY;
1885  // this may happen if Sys_Error is issued mid-frame, so we need to properly advance the draw pipeline
1886  if (force)
1887  {
1888  extern void R_EndWorldRenderpass(void);
1890  }
1891 
1892  // submit
1896  vmaFlushAllocation(vk_malloc, vk_dynIndexBuffers[vk_activeDynBufferIdx].allocation, 0, VK_WHOLE_SIZE);
1897 
1898  vkCmdEndRenderPass(vk_commandbuffers[vk_activeBufferIdx]);
1900  VK_VERIFY(vkEndCommandBuffer(vk_commandbuffers[vk_activeBufferIdx]));
1901 
1902  VkPipelineStageFlags waitStages = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
1903  VkSubmitInfo submitInfo = {
1904  .sType = VK_STRUCTURE_TYPE_SUBMIT_INFO,
1905  .waitSemaphoreCount = 1,
1906  .pWaitSemaphores = &vk_imageAvailableSemaphores[vk_activeBufferIdx],
1907  .signalSemaphoreCount = 1,
1908  .pSignalSemaphores = &vk_renderFinishedSemaphores[vk_activeBufferIdx],
1909  .pWaitDstStageMask = &waitStages,
1910  .commandBufferCount = 1,
1911  .pCommandBuffers = &vk_commandbuffers[vk_activeBufferIdx]
1912  };
1913 
1914  VK_VERIFY(vkQueueSubmit(vk_device.gfxQueue, 1, &submitInfo, vk_fences[vk_activeBufferIdx]));
1915 
1916  // present
1917  VkPresentInfoKHR presentInfo = {
1918  .sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR,
1919  .waitSemaphoreCount = 1,
1920  .pWaitSemaphores = &vk_renderFinishedSemaphores[vk_activeBufferIdx],
1921  .swapchainCount = 1,
1922  .pSwapchains = &vk_swapchain.sc,
1923  .pImageIndices = &vk_imageIndex,
1924  .pResults = NULL
1925  };
1926 
1927  VkResult renderResult = vkQueuePresentKHR(vk_device.presentQueue, &presentInfo);
1928 
1929  // for VK_OUT_OF_DATE_KHR and VK_SUBOPTIMAL_KHR it'd be fine to just rebuild the swapchain but let's take the easy way out and restart video system
1930  if (renderResult == VK_ERROR_OUT_OF_DATE_KHR || renderResult == VK_SUBOPTIMAL_KHR || renderResult == VK_ERROR_SURFACE_LOST_KHR)
1931  {
1932  ri.Con_Printf(PRINT_ALL, "QVk_EndFrame(): received %s after vkQueuePresentKHR - restarting video!\n", QVk_GetError(renderResult));
1933  vid_ref->modified = true;
1934  }
1935  else if (renderResult != VK_SUCCESS)
1936  {
1937  Sys_Error("QVk_EndFrame(): unexpected error after vkQueuePresentKHR: %s", QVk_GetError(renderResult));
1938  }
1939 
1941 
1942  vk_frameStarted = false;
1943  return renderResult;
1944 }
1945 
1947 {
1948  VkClearValue clearColors[3] = {
1949  {.color = { 1.f, .0f, .5f, 1.f } },
1950  {.depthStencil = { 1.f, 0 } },
1951  {.color = { 1.f, .0f, .5f, 1.f } },
1952  };
1953 
1954  VkRenderPassBeginInfo renderBeginInfo[] = {
1955  // RP_WORLD
1956  {
1957  .sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO,
1958  .renderPass = vk_renderpasses[RP_WORLD].rp,
1959  .framebuffer = vk_framebuffers[RP_WORLD][vk_imageIndex],
1960  .renderArea.offset = { 0, 0 },
1961  .renderArea.extent = vk_swapchain.extent,
1962  .clearValueCount = vk_renderpasses[RP_WORLD].sampleCount != VK_SAMPLE_COUNT_1_BIT ? 3 : 2,
1963  .pClearValues = clearColors
1964  },
1965  // RP_UI
1966  {
1967  .sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO,
1968  .renderPass = vk_renderpasses[RP_UI].rp,
1969  .framebuffer = vk_framebuffers[RP_UI][vk_imageIndex],
1970  .renderArea.offset = { 0, 0 },
1971  .renderArea.extent = vk_swapchain.extent,
1972  .clearValueCount = 2,
1973  .pClearValues = clearColors
1974  },
1975  // RP_WORLD_WARP
1976  {
1977  .sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO,
1978  .renderPass = vk_renderpasses[RP_WORLD_WARP].rp,
1979  .framebuffer = vk_framebuffers[RP_WORLD_WARP][vk_imageIndex],
1980  .renderArea.offset = { 0, 0 },
1981  .renderArea.extent = vk_swapchain.extent,
1982  .clearValueCount = 1,
1983  .pClearValues = clearColors
1984  }
1985  };
1986 
1987 #if defined(_DEBUG) || defined(ENABLE_DEBUG_LABELS)
1988  if (rpType == RP_WORLD) {
1989  QVk_DebugLabelBegin(&vk_commandbuffers[vk_activeBufferIdx], "Draw World", 0.f, 1.f, 0.f);
1990  }
1991  if (rpType == RP_UI) {
1993  QVk_DebugLabelBegin(&vk_commandbuffers[vk_activeBufferIdx], "Draw UI", 1.f, 1.f, 0.f);
1994  }
1995  if (rpType == RP_WORLD_WARP) {
1997  QVk_DebugLabelBegin(&vk_commandbuffers[vk_activeBufferIdx], "Draw View Warp", 1.f, 0.f, .5f);
1998  }
1999 #endif
2000 
2001  vkCmdBeginRenderPass(vk_commandbuffers[vk_activeBufferIdx], &renderBeginInfo[rpType], VK_SUBPASS_CONTENTS_INLINE);
2002 }
2003 
2005 {
2006  vkDeviceWaitIdle( vk_device.logical );
2010  vk_viewport.width = (float)vid.width;
2011  vk_viewport.height = (float)vid.height;
2012  vk_scissor.extent = vk_swapchain.extent;
2017 }
2018 
2019 uint8_t *QVk_GetVertexBuffer(VkDeviceSize size, VkBuffer *dstBuffer, VkDeviceSize *dstOffset)
2020 {
2022  {
2024 
2025  ri.Con_Printf(PRINT_ALL, "Resizing dynamic vertex buffer to %ukB\n", vk_config.vertex_buffer_size / 1024);
2026  int swapBufferOffset = vk_swapBuffersCnt[vk_activeSwapBufferIdx];
2028 
2031  else
2033 
2034  for (int i = 0; i < NUM_DYNBUFFERS; ++i)
2035  {
2038 
2039  QVk_CreateVertexBuffer(NULL, vk_config.vertex_buffer_size, &vk_dynVertexBuffers[i], NULL, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, VK_MEMORY_PROPERTY_HOST_CACHED_BIT);
2040  VK_VERIFY(vmaMapMemory(vk_malloc, vk_dynVertexBuffers[i].allocation, &vk_dynVertexBuffers[i].allocInfo.pMappedData));
2041 
2042  QVk_DebugSetObjectName((uint64_t)vk_dynVertexBuffers[i].buffer, VK_OBJECT_TYPE_BUFFER, va("Dynamic Vertex Buffer #%d", i));
2043  QVk_DebugSetObjectName((uint64_t)vk_dynVertexBuffers[i].allocInfo.deviceMemory, VK_OBJECT_TYPE_DEVICE_MEMORY, va("Memory: Dynamic Vertex Buffer #%d", i));
2044  }
2045  }
2046 
2050 
2054 
2055  return (uint8_t *)vk_dynVertexBuffers[vk_activeDynBufferIdx].allocInfo.pMappedData + (*dstOffset);
2056 }
2057 
2058 uint8_t *QVk_GetIndexBuffer(VkDeviceSize size, VkDeviceSize *dstOffset)
2059 {
2060  // align to 4 bytes, so that we can reuse the buffer for both VK_INDEX_TYPE_UINT16 and VK_INDEX_TYPE_UINT32
2061  const int align_mod = size % 4;
2062  const uint32_t aligned_size = ((size % 4) == 0) ? size : (size + 4 - align_mod);
2063 
2064  if (vk_dynIndexBuffers[vk_activeDynBufferIdx].currentOffset + aligned_size > vk_config.index_buffer_size)
2065  {
2067 
2068  ri.Con_Printf(PRINT_ALL, "Resizing dynamic index buffer to %ukB\n", vk_config.index_buffer_size / 1024);
2069  int swapBufferOffset = vk_swapBuffersCnt[vk_activeSwapBufferIdx];
2071 
2074  else
2076 
2077  for (int i = 0; i < NUM_DYNBUFFERS; ++i)
2078  {
2081 
2082  QVk_CreateIndexBuffer(NULL, vk_config.index_buffer_size, &vk_dynIndexBuffers[i], NULL, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, VK_MEMORY_PROPERTY_HOST_CACHED_BIT);
2083  VK_VERIFY(vmaMapMemory(vk_malloc, vk_dynIndexBuffers[i].allocation, &vk_dynIndexBuffers[i].allocInfo.pMappedData));
2084 
2085  QVk_DebugSetObjectName((uint64_t)vk_dynIndexBuffers[i].buffer, VK_OBJECT_TYPE_BUFFER, va("Dynamic Index Buffer #%d", i));
2086  QVk_DebugSetObjectName((uint64_t)vk_dynIndexBuffers[i].allocInfo.deviceMemory, VK_OBJECT_TYPE_DEVICE_MEMORY, va("Memory: Dynamic Index Buffer #%d", i));
2087  }
2088  }
2089 
2092 
2096 
2097  return (uint8_t *)vk_dynIndexBuffers[vk_activeDynBufferIdx].allocInfo.pMappedData + (*dstOffset);
2098 }
2099 
2100 uint8_t *QVk_GetUniformBuffer(VkDeviceSize size, uint32_t *dstOffset, VkDescriptorSet *dstUboDescriptorSet)
2101 {
2102  // 0x100 alignment is required by Vulkan spec
2103  const int align_mod = size % 256;
2104  const uint32_t aligned_size = ((size % 256) == 0) ? size : (size + 256 - align_mod);
2105 
2107  {
2109 
2110  ri.Con_Printf(PRINT_ALL, "Resizing dynamic uniform buffer to %ukB\n", vk_config.uniform_buffer_size / 1024);
2111  int swapBufferOffset = vk_swapBuffersCnt[vk_activeSwapBufferIdx];
2112  int swapDescSetsOffset = vk_swapDescSetsCnt[vk_activeSwapBufferIdx];
2115 
2118  else
2120 
2123  else
2125 
2126  for (int i = 0; i < NUM_DYNBUFFERS; ++i)
2127  {
2131 
2132  VK_VERIFY(QVk_CreateUniformBuffer(vk_config.uniform_buffer_size, &vk_dynUniformBuffers[i], VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, VK_MEMORY_PROPERTY_HOST_CACHED_BIT));
2133  VK_VERIFY(vmaMapMemory(vk_malloc, vk_dynUniformBuffers[i].allocation, &vk_dynUniformBuffers[i].allocInfo.pMappedData));
2135 
2136  QVk_DebugSetObjectName((uint64_t)vk_uboDescriptorSets[i], VK_OBJECT_TYPE_DESCRIPTOR_SET, va("Dynamic UBO Descriptor Set #%d", i));
2137  QVk_DebugSetObjectName((uint64_t)vk_dynUniformBuffers[i].buffer, VK_OBJECT_TYPE_BUFFER, va("Dynamic Uniform Buffer #%d", i));
2138  QVk_DebugSetObjectName((uint64_t)vk_dynUniformBuffers[i].allocInfo.deviceMemory, VK_OBJECT_TYPE_DEVICE_MEMORY, va("Memory: Dynamic Uniform Buffer #%d", i));
2139  }
2140  }
2141 
2143  *dstUboDescriptorSet = vk_uboDescriptorSets[vk_activeDynBufferIdx];
2145 
2149 
2150  return (uint8_t *)vk_dynUniformBuffers[vk_activeDynBufferIdx].allocInfo.pMappedData + (*dstOffset);
2151 }
2152 
2153 uint8_t *QVk_GetStagingBuffer(VkDeviceSize size, int alignment, VkCommandBuffer *cmdBuffer, VkBuffer *buffer, uint32_t *dstOffset)
2154 {
2156  const int align_mod = stagingBuffer->buffer.currentOffset % alignment;
2157  stagingBuffer->buffer.currentOffset = ((stagingBuffer->buffer.currentOffset % alignment) == 0)
2158  ? stagingBuffer->buffer.currentOffset : (stagingBuffer->buffer.currentOffset + alignment - align_mod);
2159 
2160  if (size > STAGING_BUFFER_MAXSIZE)
2161  Sys_Error("QVk_GetStagingBuffer(): Cannot allocate staging buffer space!");
2162 
2163  if ((stagingBuffer->buffer.currentOffset + size) >= STAGING_BUFFER_MAXSIZE && !stagingBuffer->submitted)
2165 
2166  stagingBuffer = &vk_stagingBuffers[vk_activeStagingBuffer];
2167  if (stagingBuffer->submitted)
2168  {
2169  VK_VERIFY(vkWaitForFences(vk_device.logical, 1, &stagingBuffer->fence, VK_TRUE, UINT64_MAX));
2170  VK_VERIFY(vkResetFences(vk_device.logical, 1, &stagingBuffer->fence));
2171 
2172  stagingBuffer->buffer.currentOffset = 0;
2173  stagingBuffer->submitted = false;
2174 
2175  VkCommandBufferBeginInfo beginInfo = {
2176  .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
2177  .pNext = NULL,
2178  .flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT,
2179  .pInheritanceInfo = NULL
2180  };
2181 
2182  VK_VERIFY(vkBeginCommandBuffer(stagingBuffer->cmdBuffer, &beginInfo));
2183  }
2184 
2185  if (cmdBuffer)
2186  *cmdBuffer = stagingBuffer->cmdBuffer;
2187  if (buffer)
2188  *buffer = stagingBuffer->buffer.buffer;
2189  if (dstOffset)
2190  *dstOffset = stagingBuffer->buffer.currentOffset;
2191 
2192  unsigned char *data = (uint8_t *)stagingBuffer->buffer.allocInfo.pMappedData + stagingBuffer->buffer.currentOffset;
2193  stagingBuffer->buffer.currentOffset += size;
2194 
2195  return data;
2196 }
2197 
2198 VkBuffer QVk_GetTriangleFanIbo(VkDeviceSize indexCount)
2199 {
2200  if (indexCount > vk_config.triangle_fan_index_usage)
2201  vk_config.triangle_fan_index_usage = indexCount;
2202 
2205 
2206  if (indexCount > vk_config.triangle_fan_index_count)
2207  {
2209  ri.Con_Printf(PRINT_ALL, "Resizing triangle fan index buffer to %u indices.\n", vk_config.triangle_fan_index_count);
2211  }
2212 
2213  return *vk_triangleFanIbo;
2214 }
2215 
2217 {
2218  for (int i = 0; i < NUM_DYNBUFFERS; ++i)
2219  {
2220  if (!vk_stagingBuffers[i].submitted && vk_stagingBuffers[i].buffer.currentOffset > 0)
2222  }
2223 }
2224 
2226 {
2227  assert((vk_samplers[samplerType] != VK_NULL_HANDLE) && "Sampler is VK_NULL_HANDLE!");
2228 
2229  VkDescriptorImageInfo dImgInfo = {
2230  .sampler = vk_samplers[samplerType],
2231  .imageView = texture->imageView,
2232  .imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL
2233  };
2234 
2235  VkWriteDescriptorSet writeSet = {
2236  .sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
2237  .pNext = NULL,
2238  .dstSet = texture->descriptorSet,
2239  .dstBinding = 0,
2240  .dstArrayElement = 0,
2241  .descriptorCount = 1,
2242  .descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
2243  .pImageInfo = &dImgInfo,
2244  .pBufferInfo = NULL,
2245  .pTexelBufferView = NULL
2246  };
2247 
2248  vkUpdateDescriptorSets(vk_device.logical, 1, &writeSet, 0, NULL);
2249 
2250  return vk_samplers[samplerType];
2251 }
2252 
2253 void QVk_DrawColorRect(float *ubo, VkDeviceSize uboSize, qvkrenderpasstype_t rpType)
2254 {
2255  uint32_t uboOffset;
2256  VkDescriptorSet uboDescriptorSet;
2257  uint8_t *vertData = QVk_GetUniformBuffer(uboSize, &uboOffset, &uboDescriptorSet);
2258  memcpy(vertData, ubo, uboSize);
2259 
2261  VkDeviceSize offsets = 0;
2262  vkCmdBindDescriptorSets(vk_activeCmdbuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, vk_drawColorQuadPipeline[rpType].layout, 0, 1, &uboDescriptorSet, 1, &uboOffset);
2263  vkCmdBindVertexBuffers(vk_activeCmdbuffer, 0, 1, &vk_colorRectVbo.buffer, &offsets);
2264  vkCmdBindIndexBuffer(vk_activeCmdbuffer, vk_rectIbo.buffer, 0, VK_INDEX_TYPE_UINT32);
2265  vkCmdDrawIndexed(vk_activeCmdbuffer, 6, 1, 0, 0, 0);
2266 }
2267 
2268 void QVk_DrawTexRect(float *ubo, VkDeviceSize uboSize, qvktexture_t *texture)
2269 {
2270  uint32_t uboOffset;
2271  VkDescriptorSet uboDescriptorSet;
2272  uint8_t *uboData = QVk_GetUniformBuffer(uboSize, &uboOffset, &uboDescriptorSet);
2273  memcpy(uboData, ubo, uboSize);
2274 
2276  VkDeviceSize offsets = 0;
2277  VkDescriptorSet descriptorSets[] = { texture->descriptorSet, uboDescriptorSet };
2278  vkCmdBindDescriptorSets(vk_activeCmdbuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, vk_drawTexQuadPipeline.layout, 0, 2, descriptorSets, 1, &uboOffset);
2279  vkCmdBindVertexBuffers(vk_activeCmdbuffer, 0, 1, &vk_texRectVbo.buffer, &offsets);
2280  vkCmdBindIndexBuffer(vk_activeCmdbuffer, vk_rectIbo.buffer, 0, VK_INDEX_TYPE_UINT32);
2281  vkCmdDrawIndexed(vk_activeCmdbuffer, 6, 1, 0, 0, 0);
2282 }
2283 
2285 {
2286  if (vk_state.current_pipeline != pipeline->pl)
2287  {
2288  vkCmdBindPipeline(vk_activeCmdbuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline->pl);
2289  vk_state.current_pipeline = pipeline->pl;
2290  }
2291 }
2292 
2293 const char *QVk_GetError(VkResult errorCode)
2294 {
2295 #define ERRSTR(r) case VK_ ##r: return "VK_"#r
2296  switch (errorCode)
2297  {
2298  ERRSTR(SUCCESS);
2299  ERRSTR(NOT_READY);
2300  ERRSTR(TIMEOUT);
2301  ERRSTR(EVENT_SET);
2302  ERRSTR(EVENT_RESET);
2303  ERRSTR(INCOMPLETE);
2304  ERRSTR(ERROR_OUT_OF_HOST_MEMORY);
2305  ERRSTR(ERROR_OUT_OF_DEVICE_MEMORY);
2306  ERRSTR(ERROR_INITIALIZATION_FAILED);
2307  ERRSTR(ERROR_DEVICE_LOST);
2308  ERRSTR(ERROR_MEMORY_MAP_FAILED);
2309  ERRSTR(ERROR_LAYER_NOT_PRESENT);
2310  ERRSTR(ERROR_EXTENSION_NOT_PRESENT);
2311  ERRSTR(ERROR_FEATURE_NOT_PRESENT);
2312  ERRSTR(ERROR_INCOMPATIBLE_DRIVER);
2313  ERRSTR(ERROR_TOO_MANY_OBJECTS);
2314  ERRSTR(ERROR_FORMAT_NOT_SUPPORTED);
2315  ERRSTR(ERROR_SURFACE_LOST_KHR);
2316  ERRSTR(ERROR_NATIVE_WINDOW_IN_USE_KHR);
2317  ERRSTR(SUBOPTIMAL_KHR);
2318  ERRSTR(ERROR_OUT_OF_DATE_KHR);
2319  ERRSTR(ERROR_INCOMPATIBLE_DISPLAY_KHR);
2320  ERRSTR(ERROR_VALIDATION_FAILED_EXT);
2321  ERRSTR(ERROR_INVALID_SHADER_NV);
2322  default: return "<unknown>";
2323  }
2324 #undef ERRSTR
2325  return "UNKNOWN ERROR";
2326 }
2327 
2329 {
2330  if (enable)
2331  {
2332  if (!vkw_state.log_fp)
2333  {
2334  struct tm *newtime;
2335  time_t aclock;
2336  char buffer[1024];
2337 
2338  time(&aclock);
2339  newtime = localtime(&aclock);
2340 
2341  asctime(newtime);
2342 
2343  Com_sprintf(buffer, sizeof(buffer), "%s/vk.log", ri.FS_Gamedir());
2344  vkw_state.log_fp = fopen(buffer, "wt");
2345 
2346  fprintf(vkw_state.log_fp, "%s\n", asctime(newtime));
2347  }
2349  }
2350  else
2351  {
2352  vk_logfp = NULL;
2353  }
2354 }
2355 
2356 void Vkimp_LogNewFrame( void )
2357 {
2358  fprintf( vkw_state.log_fp, "*** R_BeginFrame ***\n" );
2359 }
QVk_GetUniformBuffer
uint8_t * QVk_GetUniformBuffer(VkDeviceSize size, uint32_t *dstOffset, VkDescriptorSet *dstUboDescriptorSet)
Definition: vk_common.c:2100
vk_activeCmdbuffer
VkCommandBuffer vk_activeCmdbuffer
Definition: vk_common.c:127
MAX_VKTEXTURES
#define MAX_VKTEXTURES
Definition: vk_local.h:122
QVk_DebugSetObjectName
#define QVk_DebugSetObjectName(a, b, c)
Definition: qvk.h:317
qvkshader_t
Definition: qvk.h:166
qvkdevice_t::gfxQueue
VkQueue gfxQueue
Definition: qvk.h:43
qvkstagingbuffer_t::cmdBuffer
VkCommandBuffer cmdBuffer
Definition: qvk.h:136
vk_dynVertexBuffers
static qvkbuffer_t vk_dynVertexBuffers[NUM_DYNBUFFERS]
Definition: vk_common.c:227
qvkstagingbuffer_t::fence
VkFence fence
Definition: qvk.h:137
qvkdevice_t::logical
VkDevice logical
Definition: qvk.h:40
qvkbuffer_t::buffer
VkBuffer buffer
Definition: qvk.h:126
vk_activeBufferIdx
int vk_activeBufferIdx
Definition: vk_common.c:129
QVk_DebugLabelBegin
#define QVk_DebugLabelBegin(a, b, c, d, e)
Definition: qvk.h:319
CreateDescriptorSetLayouts
static void CreateDescriptorSetLayouts()
Definition: vk_common.c:761
int
CONST PIXELFORMATDESCRIPTOR int
Definition: qgl_win.c:35
QVk_DrawColorRect
void QVk_DrawColorRect(float *ubo, VkDeviceSize uboSize, qvkrenderpasstype_t rpType)
Definition: vk_common.c:2253
vmaInvalidateAllocation
void vmaInvalidateAllocation(VmaAllocator allocator, VmaAllocation allocation, VkDeviceSize offset, VkDeviceSize size)
Invalidates memory of given allocation.
vk_drawDLightPipeline
qvkpipeline_t vk_drawDLightPipeline
Definition: vk_common.c:155
qvkrenderpass_t::rp
VkRenderPass rp
Definition: qvk.h:118
QVVKTEXTURE_INIT
#define QVVKTEXTURE_INIT
Definition: qvk.h:91
qvkstagingbuffer_t::submitted
qboolean submitted
Definition: qvk.h:138
vk_logfp
FILE * vk_logfp
Definition: vk_common.c:43
VK_INPUTATTR_DESC
#define VK_INPUTATTR_DESC(l, f, o)
Definition: vk_common.c:180
NUM_CMDBUFFERS
#define NUM_CMDBUFFERS
Definition: vk_common.c:117
vkstate_t::current_pipeline
VkPipeline current_pipeline
Definition: vk_local.h:347
Vkimp_LogNewFrame
void Vkimp_LogNewFrame(void)
Definition: vk_common.c:2356
ri
refimport_t ri
Definition: r_main.c:25
qvkpipeline_t
Definition: qvk.h:152
vk_fences
VkFence vk_fences[NUM_CMDBUFFERS]
Definition: vk_common.c:121
vk_viewport
VkViewport vk_viewport
Definition: vk_common.c:114
DestroyDrawBuffer
static void DestroyDrawBuffer(qvktexture_t *drawBuffer)
Definition: vk_common.c:739
vk_depthbuffer
qvktexture_t vk_depthbuffer
Definition: vk_common.c:108
vk_renderFinishedSemaphores
VkSemaphore vk_renderFinishedSemaphores[NUM_CMDBUFFERS]
Definition: vk_common.c:125
v
GLdouble v
Definition: qgl_win.c:143
vk_swapBuffersCnt
static int vk_swapBuffersCnt[NUM_SWAPBUFFER_SLOTS]
Definition: vk_common.c:241
QVk_CreateVertexBuffer
void QVk_CreateVertexBuffer(const void *data, VkDeviceSize size, qvkbuffer_t *dstBuffer, qvkbuffer_t *stagingBuffer, VkMemoryPropertyFlags reqMemFlags, VkMemoryPropertyFlags prefMemFlags)
Definition: vk_buffer.c:145
cvar_s::modified
qboolean modified
Definition: q_shared.h:330
S_MIPMAP_NEAREST
@ S_MIPMAP_NEAREST
Definition: qvk.h:67
VmaAllocationInfo::deviceMemory
VkDeviceMemory deviceMemory
Handle to Vulkan memory object.
Definition: vk_mem_alloc.h:2545
vk_texRectVbo
qvkbuffer_t vk_texRectVbo
Definition: vk_common.c:221
QVk_CreateColorBuffer
void QVk_CreateColorBuffer(VkSampleCountFlagBits sampleCount, qvktexture_t *colorBuffer, int extraFlags)
Definition: vk_image.c:367
qvkdevice_t
Definition: qvk.h:37
qvkdevice_t::properties
VkPhysicalDeviceProperties properties
Definition: qvk.h:41
vk_drawPolyPipeline
qvkpipeline_t vk_drawPolyPipeline
Definition: vk_common.c:150
vk_drawPolyWarpPipeline
qvkpipeline_t vk_drawPolyWarpPipeline
Definition: vk_common.c:152
BUFFER_RESIZE_FACTOR
#define BUFFER_RESIZE_FACTOR
Definition: vk_common.c:247
Sys_Error
void Sys_Error(char *error,...)
Definition: sys_win.c:68
qboolean
qboolean
Definition: q_shared.h:63
QVk_CreateValidationLayers
void QVk_CreateValidationLayers(void)
Definition: vk_validation.c:74
QVk_BindPipeline
void QVk_BindPipeline(qvkpipeline_t *pipeline)
Definition: vk_common.c:2284
vmaUnmapMemory
void vmaUnmapMemory(VmaAllocator allocator, VmaAllocation allocation)
Unmaps memory represented by given allocation, mapped previously using vmaMapMemory().
i
int i
Definition: q_shared.c:305
STAGING_BUFFER_MAXSIZE
#define STAGING_BUFFER_MAXSIZE
Definition: vk_common.c:255
vkconfig_t::uniform_buffer_max_usage
uint32_t uniform_buffer_max_usage
Definition: vk_local.h:320
vk_instance
VkInstance vk_instance
Definition: vk_common.c:46
QVk_CreateSwapchain
VkResult QVk_CreateSwapchain(void)
Definition: vk_swapchain.c:117
vkconfig_t::uniform_buffer_usage
uint32_t uniform_buffer_usage
Definition: vk_local.h:319
VmaAllocator
Represents main object of this library initialized.
qvkstagingbuffer_t
Definition: qvk.h:133
VmaAllocatorCreateInfo
Description of a Allocator to be created.
Definition: vk_mem_alloc.h:1866
RP_WORLD_WARP
@ RP_WORLD_WARP
Definition: qvk.h:198
buffer
GLenum GLfloat * buffer
Definition: qgl_win.c:151
CreateFramebuffers
static VkResult CreateFramebuffers()
Definition: vk_common.c:358
vkconfig_t::layers
const char * layers[256]
Definition: vk_local.h:312
qvkdevice_t::gfxFamilyIndex
int gfxFamilyIndex
Definition: qvk.h:46
QVk_CreateUniformBuffer
VkResult QVk_CreateUniformBuffer(VkDeviceSize size, qvkbuffer_t *dstBuffer, VkMemoryPropertyFlags reqMemFlags, VkMemoryPropertyFlags prefMemFlags)
Definition: vk_buffer.c:127
refimport_t::Cvar_Set
cvar_t *(* Cvar_Set)(char *name, char *value)
Definition: ref.h:217
vk_swapBuffers
static qvkbuffer_t * vk_swapBuffers[NUM_SWAPBUFFER_SLOTS]
Definition: vk_common.c:243
vkw_state
vkwstate_t vkw_state
Definition: vk_imp.c:39
qvkrenderpass_t
Definition: qvk.h:116
DestroyFramebuffers
static void DestroyFramebuffers()
Definition: vk_common.c:340
width
GLint GLsizei width
Definition: qgl_win.c:115
qvkpipeline_t::pl
VkPipeline pl
Definition: qvk.h:155
qvkshader_t::module
VkShaderModule module
Definition: qvk.h:169
vk_device_idx
cvar_t * vk_device_idx
Definition: vk_rmain.c:122
QVKPIPELINE_INIT
#define QVKPIPELINE_INIT
Definition: qvk.h:172
vk_stagingBuffers
static qvkstagingbuffer_t vk_stagingBuffers[NUM_DYNBUFFERS]
Definition: vk_common.c:231
vk_transferCommandPool
VkCommandPool vk_transferCommandPool
Definition: vk_common.c:96
qvkSetDebugUtilsObjectNameEXT
PFN_vkSetDebugUtilsObjectNameEXT qvkSetDebugUtilsObjectNameEXT
Definition: vk_common.c:168
cvar_s
Definition: q_shared.h:324
vk_surface
VkSurfaceKHR vk_surface
Definition: vk_common.c:47
vk_swapchain
qvkswapchain_t vk_swapchain
Definition: vk_common.c:63
vk_swapDescriptorSets
static VkDescriptorSet * vk_swapDescriptorSets[NUM_SWAPBUFFER_SLOTS]
Definition: vk_common.c:244
vk_scissor
VkRect2D vk_scissor
Definition: vk_common.c:115
vk_clear
cvar_t * vk_clear
Definition: vk_rmain.c:99
QVk_CreatePipeline
void QVk_CreatePipeline(const VkDescriptorSetLayout *descriptorLayout, const uint32_t desLayoutCount, const VkPipelineVertexInputStateCreateInfo *vertexInputInfo, qvkpipeline_t *pipeline, const qvkrenderpass_t *renderpass, const qvkshader_t *shaders, uint32_t shaderCount, VkPushConstantRange *pcRange)
Definition: vk_pipeline.c:51
vk_imageAvailableSemaphores
VkSemaphore vk_imageAvailableSemaphores[NUM_CMDBUFFERS]
Definition: vk_common.c:123
vkconfig_t::triangle_fan_index_count
uint32_t triangle_fan_index_count
Definition: vk_local.h:324
vk_drawNoDepthModelPipelineStrip
qvkpipeline_t vk_drawNoDepthModelPipelineStrip
Definition: vk_common.c:142
vkconfig_t::index_buffer_size
uint32_t index_buffer_size
Definition: vk_local.h:318
qvkpipeline_t::topology
VkPrimitiveTopology topology
Definition: qvk.h:159
VERTEX_BUFFER_SIZE
#define VERTEX_BUFFER_SIZE
Definition: vk_common.c:251
j
GLint j
Definition: qgl_win.c:150
va
char * va(char *format,...)
Definition: q_shared.c:1050
CreateDrawBuffers
static void CreateDrawBuffers()
Definition: vk_common.c:708
vk_framebuffers
VkFramebuffer * vk_framebuffers[RP_COUNT]
Definition: vk_common.c:102
indices
GLsizei GLenum const GLvoid * indices
Definition: qgl_win.c:130
qvkInsertDebugUtilsLabelEXT
PFN_vkCmdInsertDebugUtilsLabelEXT qvkInsertDebugUtilsLabelEXT
Definition: vk_common.c:172
qvktexture_t::descriptorSet
VkDescriptorSet descriptorSet
Definition: qvk.h:87
vk_drawTexQuadPipeline
qvkpipeline_t vk_drawTexQuadPipeline
Definition: vk_common.c:138
vkconfig_t::index_buffer_usage
uint32_t index_buffer_usage
Definition: vk_local.h:316
refimport_t::Con_Printf
void(* Con_Printf)(int print_level, char *str,...)
Definition: ref.h:202
PRINT_ALL
#define PRINT_ALL
Definition: qcommon.h:751
RP_COUNT
@ RP_COUNT
Definition: qvk.h:199
qvkrenderpass_t::colorLoadOp
VkAttachmentLoadOp colorLoadOp
Definition: qvk.h:119
NUM_SWAPBUFFER_SLOTS
#define NUM_SWAPBUFFER_SLOTS
Definition: vk_common.c:240
Vkimp_GetSurfaceExtensions
void Vkimp_GetSurfaceExtensions(char **extensions, uint32_t *extCount)
Definition: vk_imp.c:158
CreateRenderpasses
static VkResult CreateRenderpasses()
Definition: vk_common.c:428
QVk_CreateDevice
qboolean QVk_CreateDevice(int preferredDeviceIdx)
Definition: vk_device.c:264
CreateDynamicBuffers
static void CreateDynamicBuffers()
Definition: vk_common.c:940
vkconfig_t::extensions
const char * extensions[256]
Definition: vk_local.h:311
QVk_CreateImageView
VkResult QVk_CreateImageView(const VkImage *image, VkImageAspectFlags aspectFlags, VkImageView *imageView, VkFormat format, uint32_t mipLevels)
Definition: vk_image.c:293
qvktexture_t::image
VkImage image
Definition: qvk.h:79
qvkswapchain_t::format
VkFormat format
Definition: qvk.h:55
qvkswapchain_t::extent
VkExtent2D extent
Definition: qvk.h:57
qvktexture_t::allocInfo
VmaAllocationInfo allocInfo
Definition: qvk.h:81
qvkrenderpasstype_t
qvkrenderpasstype_t
Definition: qvk.h:194
S_ANISO_MIPMAP_NEAREST
@ S_ANISO_MIPMAP_NEAREST
Definition: qvk.h:71
ERRSTR
#define ERRSTR(r)
vk_malloc
VmaAllocator vk_malloc
Definition: vk_common.c:48
UNIFORM_ALLOC_SIZE
#define UNIFORM_ALLOC_SIZE
Definition: vk_common.c:249
QVk_BeginRenderpass
void QVk_BeginRenderpass(qvkrenderpasstype_t rpType)
Definition: vk_common.c:1946
viddef_t::width
unsigned width
Definition: vid.h:29
UNIFORM_BUFFER_SIZE
#define UNIFORM_BUFFER_SIZE
Definition: vk_common.c:253
DestroySamplers
static void DestroySamplers()
Definition: vk_common.c:863
qvksampler_t
qvksampler_t
Definition: qvk.h:63
Vkimp_EnableLogging
void Vkimp_EnableLogging(qboolean enable)
Definition: vk_common.c:2328
qvkpipeline_t::depthTestEnable
VkBool32 depthTestEnable
Definition: qvk.h:161
vk_colorbufferWarp
qvktexture_t vk_colorbufferWarp
Definition: vk_common.c:106
S_ANISO_NEAREST
@ S_ANISO_NEAREST
Definition: qvk.h:69
vkconfig_t::index_buffer_max_usage
uint32_t index_buffer_max_usage
Definition: vk_local.h:317
qvkbuffer_t
Definition: qvk.h:124
qvkpipeline_t::cullMode
VkCullModeFlags cullMode
Definition: qvk.h:158
vk_msaaColorbuffer
qvktexture_t vk_msaaColorbuffer
Definition: vk_common.c:112
QVk_GetError
const char * QVk_GetError(VkResult errorCode)
Definition: vk_common.c:2293
vk_triangleFanIbo
static VkBuffer * vk_triangleFanIbo
Definition: vk_common.c:236
CreateDescriptorPool
static void CreateDescriptorPool()
Definition: vk_common.c:876
qvkpipeline_t::blendOpts
VkPipelineColorBlendAttachmentState blendOpts
Definition: qvk.h:160
DestroyDrawBuffers
static void DestroyDrawBuffers()
Definition: vk_common.c:751
vk_drawPolyLmapPipeline
qvkpipeline_t vk_drawPolyLmapPipeline
Definition: vk_common.c:151
CreatePipelines
static void CreatePipelines()
Definition: vk_common.c:1123
viddef_t::height
unsigned height
Definition: vid.h:29
QVk_SubmitStagingBuffers
void QVk_SubmitStagingBuffers()
Definition: vk_common.c:2216
vkconfig_t::vk_version
uint32_t vk_version
Definition: vk_local.h:306
vkconfig_t::vertex_buffer_usage
uint32_t vertex_buffer_usage
Definition: vk_local.h:313
QVk_DebugLabelEnd
#define QVk_DebugLabelEnd(a)
Definition: qvk.h:320
cvar_s::value
float value
Definition: q_shared.h:331
qvkswapchain_t::imageCount
int imageCount
Definition: qvk.h:59
vk_validation
cvar_t * vk_validation
Definition: vk_rmain.c:90
vk_stagingCommandPool
static VkCommandPool vk_stagingCommandPool
Definition: vk_common.c:98
vk_state
vkstate_t vk_state
Definition: vk_rmain.c:31
qvkbuffer_t::currentOffset
VkDeviceSize currentOffset
Definition: qvk.h:129
SubmitStagingBuffer
static void SubmitStagingBuffer(int index)
Definition: vk_common.c:1066
refimport_t::FS_Gamedir
char *(* FS_Gamedir)(void)
Definition: ref.h:214
vk_shadowsPipelineFan
qvkpipeline_t vk_shadowsPipelineFan
Definition: vk_common.c:158
qvkCmdBeginDebugUtilsLabelEXT
PFN_vkCmdBeginDebugUtilsLabelEXT qvkCmdBeginDebugUtilsLabelEXT
Definition: vk_common.c:170
CreateSamplers
static void CreateSamplers()
Definition: vk_common.c:794
NULL
#define NULL
Definition: q_shared.h:67
vk_commandPool
VkCommandPool vk_commandPool
Definition: vk_common.c:95
S_MIPMAP_LINEAR
@ S_MIPMAP_LINEAR
Definition: qvk.h:68
vk_colorbuffer
qvktexture_t vk_colorbuffer
Definition: vk_common.c:104
vk_drawParticlesPipeline
qvkpipeline_t vk_drawParticlesPipeline
Definition: vk_common.c:147
GetSampleCount
static VkSampleCountFlagBits GetSampleCount()
Definition: vk_common.c:290
QVk_Init
qboolean QVk_Init()
Definition: vk_common.c:1510
vid_ref
cvar_t * vid_ref
Definition: vid_dll.c:44
QVk_GetVertexBuffer
uint8_t * QVk_GetVertexBuffer(VkDeviceSize size, VkBuffer *dstBuffer, VkDeviceSize *dstOffset)
Definition: vk_common.c:2019
vk_showTrisPipeline
qvkpipeline_t vk_showTrisPipeline
Definition: vk_common.c:156
vk_device
qvkdevice_t vk_device
Definition: vk_common.c:51
vk_config
vkconfig_t vk_config
Definition: vk_rmain.c:30
vk_drawLefthandModelPipelineStrip
qvkpipeline_t vk_drawLefthandModelPipelineStrip
Definition: vk_common.c:144
QVk_GetTriangleFanIbo
VkBuffer QVk_GetTriangleFanIbo(VkDeviceSize indexCount)
Definition: vk_common.c:2198
qvktexture_t::imageView
VkImageView imageView
Definition: qvk.h:83
Vkimp_CreateSurface
VkResult Vkimp_CreateSurface()
Definition: vk_imp.c:170
qvkstagingbuffer_t::buffer
qvkbuffer_t buffer
Definition: qvk.h:135
qvkpipeline_t::depthWriteEnable
VkBool32 depthWriteEnable
Definition: qvk.h:162
TRIANGLE_FAN_INDEX_CNT
#define TRIANGLE_FAN_INDEX_CNT
Definition: vk_common.c:257
R_EndWorldRenderpass
void R_EndWorldRenderpass(void)
Definition: r_main.c:1249
QVk_BeginCommand
VkResult QVk_BeginCommand(const VkCommandBuffer *commandBuffer)
Definition: vk_cmd.c:23
qvkbuffer_t::allocInfo
VmaAllocationInfo allocInfo
Definition: qvk.h:128
QVk_FreeBuffer
void QVk_FreeBuffer(qvkbuffer_t *buffer)
Definition: vk_buffer.c:106
vk_activeDynBufferIdx
static int vk_activeDynBufferIdx
Definition: vk_common.c:232
QVk_CreateCommandBuffer
VkCommandBuffer QVk_CreateCommandBuffer(const VkCommandPool *commandPool, VkCommandBufferLevel level)
Definition: vk_cmd.c:78
qvkpipeline_t::layout
VkPipelineLayout layout
Definition: qvk.h:154
QVk_DrawTexRect
void QVk_DrawTexRect(float *ubo, VkDeviceSize uboSize, qvktexture_t *texture)
Definition: vk_common.c:2268
S_ANISO_MIPMAP_LINEAR
@ S_ANISO_MIPMAP_LINEAR
Definition: qvk.h:72
QVk_EndFrame
VkResult QVk_EndFrame(qboolean force)
Definition: vk_common.c:1880
VK_VERIFY
#define VK_VERIFY(x)
Definition: vk_local.h:59
vk_ui_depthbuffer
qvktexture_t vk_ui_depthbuffer
Definition: vk_common.c:110
VK_LOAD_VERTFRAG_SHADERS
#define VK_LOAD_VERTFRAG_SHADERS(shaders, namevert, namefrag)
Definition: vk_common.c:212
qvkdevice_t::presentQueue
VkQueue presentQueue
Definition: qvk.h:44
vk_imageIndex
uint32_t vk_imageIndex
Definition: vk_common.c:131
vmaDestroyAllocator
void vmaDestroyAllocator(VmaAllocator allocator)
Destroys allocator object.
QVk_CreateStagingBuffer
VkResult QVk_CreateStagingBuffer(VkDeviceSize size, qvkbuffer_t *dstBuffer, VkMemoryPropertyFlags reqMemFlags, VkMemoryPropertyFlags prefMemFlags)
Definition: vk_buffer.c:114
INDEX_BUFFER_SIZE
#define INDEX_BUFFER_SIZE
Definition: vk_common.c:252
qvkswapchain_t::sc
VkSwapchainKHR sc
Definition: qvk.h:54
QVk_RecreateSwapchain
void QVk_RecreateSwapchain()
Definition: vk_common.c:2004
vk_uboDescSetLayout
VkDescriptorSetLayout vk_uboDescSetLayout
Definition: vk_common.c:260
vmaMapMemory
VkResult vmaMapMemory(VmaAllocator allocator, VmaAllocation allocation, void **ppData)
Maps memory represented by given allocation and returns pointer to it.
S_NEAREST
@ S_NEAREST
Definition: qvk.h:65
vk_drawNoDepthModelPipelineFan
qvkpipeline_t vk_drawNoDepthModelPipelineFan
Definition: vk_common.c:143
qvkDestroyDebugUtilsMessengerEXT
PFN_vkDestroyDebugUtilsMessengerEXT qvkDestroyDebugUtilsMessengerEXT
Definition: vk_common.c:167
CreateStaticBuffers
static void CreateStaticBuffers()
Definition: vk_common.c:1096
CreateImageViews
static VkResult CreateImageViews()
Definition: vk_common.c:318
vkconfig_t::vertex_buffer_max_usage
uint32_t vertex_buffer_max_usage
Definition: vk_local.h:314
vkconfig_t::uniform_buffer_size
uint32_t uniform_buffer_size
Definition: vk_local.h:321
QVk_UpdateTextureSampler
VkSampler QVk_UpdateTextureSampler(qvktexture_t *texture, qvksampler_t samplerType)
Definition: vk_common.c:2225
qvkrenderpass_t::sampleCount
VkSampleCountFlagBits sampleCount
Definition: qvk.h:120
qvkswapchain_t::images
VkImage * images
Definition: qvk.h:58
vk_rectIbo
qvkbuffer_t vk_rectIbo
Definition: vk_common.c:223
vk_drawSkyboxPipeline
qvkpipeline_t vk_drawSkyboxPipeline
Definition: vk_common.c:154
VmaAllocationInfo::pMappedData
void * pMappedData
Pointer to the beginning of this allocation as mapped data.
Definition: vk_mem_alloc.h:2564
vk_colorRectVbo
qvkbuffer_t vk_colorRectVbo
Definition: vk_common.c:222
VmaAllocatorCreateInfo::flags
VmaAllocatorCreateFlags flags
Flags for created allocator. Use VmaAllocatorCreateFlagBits enum.
Definition: vk_mem_alloc.h:1869
S_ANISO_LINEAR
@ S_ANISO_LINEAR
Definition: qvk.h:70
vkconfig_t::vendor_name
const char * vendor_name
Definition: vk_local.h:307
RP_UI
@ RP_UI
Definition: qvk.h:197
vk_drawSpritePipeline
qvkpipeline_t vk_drawSpritePipeline
Definition: vk_common.c:149
QVk_CreateDepthBuffer
void QVk_CreateDepthBuffer(VkSampleCountFlagBits sampleCount, qvktexture_t *depthBuffer)
Definition: vk_image.c:352
vk_worldWarpPipeline
qvkpipeline_t vk_worldWarpPipeline
Definition: vk_common.c:159
QVk_DestroyPipeline
void QVk_DestroyPipeline(qvkpipeline_t *pipeline)
Definition: vk_pipeline.c:198
RebuildTriangleFanIndexBuffer
static void RebuildTriangleFanIndexBuffer()
Definition: vk_common.c:1004
qvkSetDebugUtilsObjectTagEXT
PFN_vkSetDebugUtilsObjectTagEXT qvkSetDebugUtilsObjectTagEXT
Definition: vk_common.c:169
S_SAMPLER_CNT
@ S_SAMPLER_CNT
Definition: qvk.h:73
vk_triangleFanIboUsage
static uint32_t vk_triangleFanIboUsage
Definition: vk_common.c:237
vk_drawModelPipelineFan
qvkpipeline_t vk_drawModelPipelineFan[2]
Definition: vk_common.c:141
vk_swapDescSetsCnt
static int vk_swapDescSetsCnt[NUM_SWAPBUFFER_SLOTS]
Definition: vk_common.c:242
vkconfig_t::triangle_fan_index_usage
uint32_t triangle_fan_index_usage
Definition: vk_local.h:322
vk_msaa
cvar_t * vk_msaa
Definition: vk_rmain.c:113
QVk_CreateCommandPool
VkResult QVk_CreateCommandPool(VkCommandPool *commandPool, uint32_t queueFamilyIndex)
Definition: vk_cmd.c:65
qvkswapchain_t
Definition: qvk.h:52
qvkCreateDebugUtilsMessengerEXT
PFN_vkCreateDebugUtilsMessengerEXT qvkCreateDebugUtilsMessengerEXT
Definition: vk_common.c:166
vmaCreateAllocator
VkResult vmaCreateAllocator(const VmaAllocatorCreateInfo *pCreateInfo, VmaAllocator *pAllocator)
Creates Allocator object.
S_LINEAR
@ S_LINEAR
Definition: qvk.h:66
vkwstate_t::log_fp
FILE * log_fp
Definition: vk_win.h:36
vk_descriptorPool
VkDescriptorPool vk_descriptorPool
Definition: vk_common.c:97
vk_postprocessPipeline
qvkpipeline_t vk_postprocessPipeline
Definition: vk_common.c:160
vk_drawBeamPipeline
qvkpipeline_t vk_drawBeamPipeline
Definition: vk_common.c:153
vk_frameStarted
qboolean vk_frameStarted
Definition: vk_common.c:135
vmaFlushAllocation
void vmaFlushAllocation(VmaAllocator allocator, VmaAllocation allocation, VkDeviceSize offset, VkDeviceSize size)
Flushes memory of given allocation.
vk_shadowsPipelineStrip
qvkpipeline_t vk_shadowsPipelineStrip
Definition: vk_common.c:157
ReleaseSwapBuffers
static void ReleaseSwapBuffers()
Definition: vk_common.c:965
CreateUboDescriptorSet
static void CreateUboDescriptorSet(VkDescriptorSet *descSet, VkBuffer buffer)
Definition: vk_common.c:905
vk_drawColorQuadPipeline
qvkpipeline_t vk_drawColorQuadPipeline[2]
Definition: vk_common.c:139
vk_commandbuffers
VkCommandBuffer * vk_commandbuffers
Definition: vk_common.c:119
d_light
int d_light
Definition: r_polyse.c:102
QVk_GetStagingBuffer
uint8_t * QVk_GetStagingBuffer(VkDeviceSize size, int alignment, VkCommandBuffer *cmdBuffer, VkBuffer *buffer, uint32_t *dstOffset)
Definition: vk_common.c:2153
vmaDestroyImage
void vmaDestroyImage(VmaAllocator allocator, VkImage image, VmaAllocation allocation)
Destroys Vulkan image and frees allocated memory.
texture
GLuint texture
Definition: qgl_win.c:68
QVk_BeginFrame
VkResult QVk_BeginFrame()
Definition: vk_common.c:1824
vk_imageviews
VkImageView * vk_imageviews
Definition: vk_common.c:100
vk_uboDescriptorSets
static VkDescriptorSet vk_uboDescriptorSets[NUM_DYNBUFFERS]
Definition: vk_common.c:230
CreateStagingBuffers
static void CreateStagingBuffers()
Definition: vk_common.c:1037
NUM_DYNBUFFERS
#define NUM_DYNBUFFERS
Definition: vk_common.c:226
qvkdevice_t::transferFamilyIndex
int transferFamilyIndex
Definition: qvk.h:48
vk_drawPointParticlesPipeline
qvkpipeline_t vk_drawPointParticlesPipeline
Definition: vk_common.c:148
vk_dynUniformBuffers
static qvkbuffer_t vk_dynUniformBuffers[NUM_DYNBUFFERS]
Definition: vk_common.c:229
qvktexture_t::allocation
VmaAllocation allocation
Definition: qvk.h:80
qvkCmdEndDebugUtilsLabelEXT
PFN_vkCmdEndDebugUtilsLabelEXT qvkCmdEndDebugUtilsLabelEXT
Definition: vk_common.c:171
vk_drawModelPipelineStrip
qvkpipeline_t vk_drawModelPipelineStrip[2]
Definition: vk_common.c:140
QVk_GetIndexBuffer
uint8_t * QVk_GetIndexBuffer(VkDeviceSize size, VkDeviceSize *dstOffset)
Definition: vk_common.c:2058
vk_dynIndexBuffers
static qvkbuffer_t vk_dynIndexBuffers[NUM_DYNBUFFERS]
Definition: vk_common.c:228
vkconfig_t::vertex_buffer_size
uint32_t vertex_buffer_size
Definition: vk_local.h:315
vk_renderpasses
qvkrenderpass_t vk_renderpasses[RP_COUNT]
Definition: vk_common.c:73
qvktexture_t
Definition: qvk.h:77
vk_samplers
static VkSampler vk_samplers[S_SAMPLER_CNT]
Definition: vk_common.c:163
VK_NULL_VERTEXINPUT_CINF
#define VK_NULL_VERTEXINPUT_CINF
Definition: vk_common.c:202
RP_WORLD
@ RP_WORLD
Definition: qvk.h:196
QVk_CreateIndexBuffer
void QVk_CreateIndexBuffer(const void *data, VkDeviceSize size, qvkbuffer_t *dstBuffer, qvkbuffer_t *stagingBuffer, VkMemoryPropertyFlags reqMemFlags, VkMemoryPropertyFlags prefMemFlags)
Definition: vk_buffer.c:158
vk_samplerDescSetLayout
VkDescriptorSetLayout vk_samplerDescSetLayout
Definition: vk_common.c:261
QVk_FindDepthFormat
VkFormat QVk_FindDepthFormat()
Definition: vk_common.c:267
max
#define max(a, b)
Definition: vk_local.h:75
DestroyImageViews
static void DestroyImageViews()
Definition: vk_common.c:304
Com_sprintf
void Com_sprintf(char *dest, int size, char *fmt,...)
Definition: q_shared.c:1223
vk_drawLefthandModelPipelineFan
qvkpipeline_t vk_drawLefthandModelPipelineFan
Definition: vk_common.c:145
vk_activeSwapBufferIdx
static int vk_activeSwapBufferIdx
Definition: vk_common.c:233
vk_activeStagingBuffer
int vk_activeStagingBuffer
Definition: vk_common.c:133
QVk_DestroyValidationLayers
void QVk_DestroyValidationLayers(void)
Definition: vk_validation.c:99
qvkdevice_t::physical
VkPhysicalDevice physical
Definition: qvk.h:39
NextPow2
static int NextPow2(int v)
Definition: vk_common.c:991
vkconfig_t::triangle_fan_index_max_usage
uint32_t triangle_fan_index_max_usage
Definition: vk_local.h:323
VK_VERTINFO
#define VK_VERTINFO(name, bindSize,...)
Definition: vk_common.c:197
vkconfig_t::supported_present_modes
const char * supported_present_modes[256]
Definition: vk_local.h:310
vk_drawNullModelPipeline
qvkpipeline_t vk_drawNullModelPipeline
Definition: vk_common.c:146
vk_samplerLightmapDescSetLayout
VkDescriptorSetLayout vk_samplerLightmapDescSetLayout
Definition: vk_common.c:262
QVk_Shutdown
void QVk_Shutdown(void)
Definition: vk_common.c:1376
vid
viddef_t vid
Definition: r_main.c:24