Create and destroy render pass and frame buffers

This commit is contained in:
Bill Currie 2020-02-18 17:18:37 +09:00
parent 1f4c019abc
commit ba654b09f7
9 changed files with 212 additions and 89 deletions

View file

@ -62,4 +62,6 @@ qfv_instance_t *QFV_CreateInstance (struct vulkan_ctx_s *ctx,
const char **extensions);
void QFV_DestroyInstance (qfv_instance_t *instance);
VkSampleCountFlagBits QFV_GetMaxSampleCount (qfv_physdev_t *physdev);
#endif // __QF_Vulkan_instance_h

View file

@ -36,6 +36,8 @@
#include <vulkan/vulkan.h>
struct vulkan_ctx_s;
void Vulkan_DestroyFramebuffers (struct vulkan_ctx_s *ctx);
void Vulkan_CreateFramebuffers (struct vulkan_ctx_s *ctx);
void Vulkan_DestroyRenderPass (struct vulkan_ctx_s *ctx);
void Vulkan_CreateRenderPass (struct vulkan_ctx_s *ctx);
void Vulkan_CreateSwapchain (struct vulkan_ctx_s *ctx);

View file

@ -15,18 +15,8 @@ typedef struct qfv_attachmentreference_s
#define QFV_AllocAttachmentReference(num, allocator) \
DARRAY_ALLOCFIXED (qfv_attachmentreference_t, num, allocator)
typedef struct qfv_subpassparameters_s {
VkPipelineBindPoint pipelineBindPoint;
qfv_attachmentreference_t *inputAttachments;
qfv_attachmentreference_t *colorAttachments;
qfv_attachmentreference_t *resolveAttachments;
VkAttachmentReference *depthStencilAttachment;
uint32_t numPreserve;
uint32_t *preserveAttachments;
} qfv_subpassparameters_t;
typedef struct qfv_subpassparametersset_s
DARRAY_TYPE (qfv_subpassparameters_t) qfv_subpassparametersset_t;
DARRAY_TYPE (VkSubpassDescription) qfv_subpassparametersset_t;
#define QFV_AllocSubpassParametersSet(num, allocator) \
DARRAY_ALLOCFIXED (qfv_subpassparametersset_t, num, allocator)
@ -49,6 +39,6 @@ QFV_CreateFramebuffer (struct qfv_device_s *device,
VkRenderPass renderPass,
uint32_t numAttachments,
VkImageView *attachments,
uint32_t width, uint32_t height, uint32_t layers);
VkExtent2D, uint32_t layers);
#endif//__QF_Vulkan_renderpass_h

View file

@ -88,6 +88,25 @@
ar; \
})
/** Initialized the array.
The array will be initialized to be empty but with grow set to the
specifed value.
\param array *Address* of the array to be modified (ie, pointer to the
array struct instance, not the instance itself: use & for
static instances of the array struct).
\param growSize Number of elements by which the array is to grow when
required.
\hideinitializer
*/
#define DARRAY_INIT(array, growSize) \
do { \
__auto_type ar = (array); \
ar->size = ar->maxSize = 0; \
ar->grow = (growSize); \
} while (0)
/** Clear the array.
If the array can grow, its backing will be freed and maxSize and a reset,

View file

@ -6,19 +6,25 @@
#endif
#include <vulkan/vulkan.h>
typedef struct vulkan_frameset_s {
int curFrame; // index into fences
struct qfv_fenceset_s *fences;
struct qfv_cmdbufferset_s *cmdBuffers;
struct qfv_semaphoreset_s *imageSemaphores;
struct qfv_semaphoreset_s *renderDoneSemaphores;
} vulkan_frameset_t;
#include "QF/darray.h"
typedef struct vulkan_renderpass_s {
VkRenderPass renderpass;
struct qfv_imageresource_s *colorImage;
struct qfv_imageresource_s *depthImage;
} vulkan_renderpass_t;
typedef struct vulkan_framebuffer_s {
VkFramebuffer framebuffer;
VkFence fence;
VkSemaphore imageAvailableSemaphore;
VkSemaphore renderDoneSemaphore;
VkCommandBuffer cmdBuffer;
} vulkan_framebuffer_t;
typedef struct vulkan_framebufferset_s
DARRAY_TYPE (vulkan_framebuffer_t) vulkan_framebufferset_t;
typedef struct vulkan_ctx_s {
void (*load_vulkan) (struct vulkan_ctx_s *ctx);
void (*unload_vulkan) (struct vulkan_ctx_s *ctx);
@ -40,8 +46,9 @@ typedef struct vulkan_ctx_s {
VkCommandPool cmdpool;
VkCommandBuffer cmdbuffer;
VkFence fence; // for ctx->cmdbuffer only
vulkan_frameset_t frameset;
vulkan_renderpass_t renderpass;
size_t curFrame;
vulkan_framebufferset_t framebuffers;
#define EXPORTED_VULKAN_FUNCTION(fname) PFN_##fname fname;
#define GLOBAL_LEVEL_VULKAN_FUNCTION(fname) PFN_##fname fname;

View file

@ -60,13 +60,11 @@ vulkan_R_Init (void)
{
qfv_device_t *device = vulkan_ctx->device;
qfv_devfuncs_t *dfunc = device->funcs;
qfv_cmdbufferset_t *cmdBuffers;
Vulkan_CreateSwapchain (vulkan_ctx);
Vulkan_CreateRenderPass (vulkan_ctx);
cmdBuffers = QFV_AllocateCommandBuffers (device, vulkan_ctx->cmdpool, 0,
vulkan_ctx->swapchain->numImages);
vulkan_ctx->frameset.cmdBuffers = cmdBuffers;
Vulkan_CreateFramebuffers (vulkan_ctx);
VkCommandBufferBeginInfo beginInfo
= { VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO };
VkClearColorValue clearColor = { {0.7294, 0.8549, 0.3333, 1.0} };
@ -96,29 +94,30 @@ vulkan_R_Init (void)
0, // filled in later
image_subresource_range
};
for (size_t i = 0; i < cmdBuffers->size; i++) {
for (size_t i = 0; i < vulkan_ctx->framebuffers.size; i++) {
__auto_type framebuffer = &vulkan_ctx->framebuffers.a[i];
pc_barrier.image = vulkan_ctx->swapchain->images->a[i];
cp_barrier.image = vulkan_ctx->swapchain->images->a[i];
dfunc->vkBeginCommandBuffer (cmdBuffers->a[i], &beginInfo);
dfunc->vkCmdPipelineBarrier (cmdBuffers->a[i],
dfunc->vkBeginCommandBuffer (framebuffer->cmdBuffer, &beginInfo);
dfunc->vkCmdPipelineBarrier (framebuffer->cmdBuffer,
VK_PIPELINE_STAGE_TRANSFER_BIT,
VK_PIPELINE_STAGE_TRANSFER_BIT,
0,
0, 0, // memory barriers
0, 0, // buffer barriers
1, &pc_barrier);
dfunc->vkCmdClearColorImage (cmdBuffers->a[i], pc_barrier.image,
dfunc->vkCmdClearColorImage (framebuffer->cmdBuffer, pc_barrier.image,
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
&clearColor, 1,
&image_subresource_range);
dfunc->vkCmdPipelineBarrier (cmdBuffers->a[i],
dfunc->vkCmdPipelineBarrier (framebuffer->cmdBuffer,
VK_PIPELINE_STAGE_TRANSFER_BIT,
VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT,
0,
0, 0,
0, 0,
1, &cp_barrier);
dfunc->vkEndCommandBuffer (cmdBuffers->a[i]);
dfunc->vkEndCommandBuffer (framebuffer->cmdBuffer);
}
Sys_Printf ("R_Init %p %d", vulkan_ctx->swapchain->swapchain,
vulkan_ctx->swapchain->numImages);
@ -138,38 +137,38 @@ vulkan_SCR_UpdateScreen (double time, void (*f)(void), void (**g)(void))
qfv_devfuncs_t *dfunc = device->funcs;
VkDevice dev = device->dev;
qfv_queue_t *queue = &vulkan_ctx->device->queue;
vulkan_frameset_t *frameset = &vulkan_ctx->frameset;
dfunc->vkWaitForFences (dev, 1, &frameset->fences->a[frameset->curFrame],
VK_TRUE, 2000000000);
__auto_type framebuffer
= &vulkan_ctx->framebuffers.a[vulkan_ctx->curFrame];
dfunc->vkWaitForFences (dev, 1, &framebuffer->fence, VK_TRUE, 2000000000);
QFV_AcquireNextImage (vulkan_ctx->swapchain,
frameset->imageSemaphores->a[frameset->curFrame],
0, &imageIndex);
framebuffer->imageAvailableSemaphore,
0, &imageIndex);
VkPipelineStageFlags waitStage
= VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
VkSubmitInfo submitInfo = {
VK_STRUCTURE_TYPE_SUBMIT_INFO, 0,
1,
&frameset->imageSemaphores->a[frameset->curFrame],
&framebuffer->imageAvailableSemaphore,
&waitStage,
1, &frameset->cmdBuffers->a[imageIndex],
1, &frameset->renderDoneSemaphores->a[frameset->curFrame],
1, &framebuffer->cmdBuffer,
1, &framebuffer->renderDoneSemaphore,
};
dfunc->vkResetFences (dev, 1, &frameset->fences->a[frameset->curFrame]);
dfunc->vkQueueSubmit (queue->queue, 1, &submitInfo,
frameset->fences->a[frameset->curFrame]);
dfunc->vkResetFences (dev, 1, &framebuffer->fence);
dfunc->vkQueueSubmit (queue->queue, 1, &submitInfo, framebuffer->fence);
VkPresentInfoKHR presentInfo = {
VK_STRUCTURE_TYPE_PRESENT_INFO_KHR, 0,
1, &frameset->renderDoneSemaphores->a[frameset->curFrame],
1, &framebuffer->renderDoneSemaphore,
1, &vulkan_ctx->swapchain->swapchain, &imageIndex,
0
};
dfunc->vkQueuePresentKHR (queue->queue, &presentInfo);
frameset->curFrame++;
frameset->curFrame %= frameset->fences->size;
vulkan_ctx->curFrame++;
vulkan_ctx->curFrame %= vulkan_ctx->framebuffers.size;
if (++count >= 100) {
double currenTime = Sys_DoubleTime ();
@ -311,19 +310,6 @@ vulkan_vid_render_create_context (void)
{
vulkan_ctx->create_window (vulkan_ctx);
vulkan_ctx->surface = vulkan_ctx->create_surface (vulkan_ctx);
vulkan_ctx->frameset.curFrame = 0;
qfv_fenceset_t *fences = DARRAY_ALLOCFIXED (*fences, 2, malloc);
qfv_semaphoreset_t *imageSems = DARRAY_ALLOCFIXED (*imageSems, 2, malloc);
qfv_semaphoreset_t *renderDoneSems = DARRAY_ALLOCFIXED (*renderDoneSems, 2,
malloc);
for (int i = 0; i < 2; i++) {
fences->a[i] = QFV_CreateFence (vulkan_ctx->device, 1);
imageSems->a[i] = QFV_CreateSemaphore (vulkan_ctx->device);
renderDoneSems->a[i] = QFV_CreateSemaphore (vulkan_ctx->device);
}
vulkan_ctx->frameset.fences = fences;
vulkan_ctx->frameset.imageSemaphores = imageSems;
vulkan_ctx->frameset.renderDoneSemaphores = renderDoneSems;
Sys_Printf ("vk create context %p\n", vulkan_ctx->surface);
}
@ -350,12 +336,6 @@ vulkan_vid_render_shutdown (void)
qfv_devfuncs_t *df = device->funcs;
VkDevice dev = device->dev;
QFV_DeviceWaitIdle (device);
vulkan_frameset_t *frameset = &vulkan_ctx->frameset;
for (size_t i = 0; i < frameset->fences->size; i++) {
df->vkDestroyFence (dev, frameset->fences->a[i], 0);
df->vkDestroySemaphore (dev, frameset->imageSemaphores->a[i], 0);
df->vkDestroySemaphore (dev, frameset->renderDoneSemaphores->a[i], 0);
}
df->vkDestroyFence (dev, vulkan_ctx->fence, 0);
df->vkDestroyCommandPool (dev, vulkan_ctx->cmdpool, 0);
Vulkan_Shutdown_Common (vulkan_ctx);

View file

@ -36,6 +36,7 @@
#include "QF/cvar.h"
#include "QF/dstring.h"
#include "QF/input.h"
#include "QF/mathlib.h"
#include "QF/qargs.h"
#include "QF/quakefs.h"
#include "QF/sys.h"
@ -284,3 +285,17 @@ QFV_DestroyInstance (qfv_instance_t *instance)
instance->funcs->vkDestroyInstance (instance->instance, 0);
free (instance);
}
VkSampleCountFlagBits
QFV_GetMaxSampleCount (qfv_physdev_t *physdev)
{
VkSampleCountFlagBits maxSamples = VK_SAMPLE_COUNT_64_BIT;
VkSampleCountFlagBits counts;
counts = min (physdev->properties.limits.framebufferColorSampleCounts,
physdev->properties.limits.framebufferDepthSampleCounts);
while (maxSamples && maxSamples > counts) {
maxSamples >>= 1;
}
Sys_MaskPrintf (SYS_VULKAN, "Max samples: %x\n", maxSamples);
return maxSamples;
}

View file

@ -71,29 +71,10 @@ QFV_CreateRenderPass (qfv_device_t *device,
VkDevice dev = device->dev;
qfv_devfuncs_t *dfunc = device->funcs;
VkSubpassDescription *subpasses = alloca (subpassparams->size
* sizeof (*subpasses));
for (uint32_t i = 0; i < subpassparams->size; i++) {
qfv_subpassparameters_t *params = &subpassparams->a[i];
subpasses[i].flags = 0;
subpasses[i].pipelineBindPoint = params->pipelineBindPoint;
subpasses[i].inputAttachmentCount = params->inputAttachments->size;
subpasses[i].pInputAttachments = params->inputAttachments->a;
subpasses[i].colorAttachmentCount = params->colorAttachments->size;
subpasses[i].pColorAttachments = params->colorAttachments->a;
if (params->resolveAttachments) {
subpasses[i].pResolveAttachments = params->resolveAttachments->a;
}
subpasses[i].pDepthStencilAttachment = params->depthStencilAttachment;
subpasses[i].preserveAttachmentCount = params->numPreserve;
subpasses[i].pPreserveAttachments = params->preserveAttachments;
}
VkRenderPassCreateInfo createInfo = {
VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO, 0, 0,
attachments->size, attachments->a,
subpassparams->size, subpasses,
subpassparams->size, subpassparams->a,
dependencies->size, dependencies->a,
};
@ -105,7 +86,7 @@ QFV_CreateRenderPass (qfv_device_t *device,
VkFramebuffer
QFV_CreateFramebuffer (qfv_device_t *device, VkRenderPass renderPass,
uint32_t numAttachments, VkImageView *attachments,
uint32_t width, uint32_t height, uint32_t layers)
VkExtent2D extent, uint32_t layers)
{
VkDevice dev = device->dev;
qfv_devfuncs_t *dfunc = device->funcs;
@ -113,7 +94,7 @@ QFV_CreateFramebuffer (qfv_device_t *device, VkRenderPass renderPass,
VkFramebufferCreateInfo createInfo = {
VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO, 0, 0,
renderPass, numAttachments, attachments,
width, height, layers,
extent.width, extent.height, layers,
};
VkFramebuffer framebuffer;

View file

@ -50,8 +50,10 @@
#include "QF/vid.h"
#include "QF/Vulkan/qf_vid.h"
#include "QF/Vulkan/device.h"
#include "QF/Vulkan/command.h"
#include "QF/Vulkan/instance.h"
#include "QF/Vulkan/image.h"
#include "QF/Vulkan/renderpass.h"
#include "QF/Vulkan/swapchain.h"
#include "compat.h"
@ -117,6 +119,9 @@ Vulkan_Init_Common (vulkan_ctx_t *ctx)
void
Vulkan_Shutdown_Common (vulkan_ctx_t *ctx)
{
if (ctx->framebuffers.size) {
Vulkan_DestroyFramebuffers (ctx);
}
if (ctx->renderpass.colorImage) {
Vulkan_DestroyRenderPass (ctx);
}
@ -241,11 +246,13 @@ Vulkan_CreateRenderPass (vulkan_ctx_t *ctx)
VkExtent3D extent = {sc->extent.width, sc->extent.height, 1};
VkSampleCountFlagBits msaaSamples
= QFV_GetMaxSampleCount (device->physDev);
Sys_MaskPrintf (SYS_VULKAN, "color resource\n");
colorImage->image
= QFV_CreateImage (device, 0, VK_IMAGE_TYPE_2D,
sc->format, extent, 1, 1,
VK_SAMPLE_COUNT_1_BIT, // FIXME
sc->format, extent, 1, 1, msaaSamples,
VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT
| VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT);
colorImage->object
@ -263,8 +270,7 @@ Vulkan_CreateRenderPass (vulkan_ctx_t *ctx)
VkFormat depthFormat = VK_FORMAT_D32_SFLOAT;
depthImage->image
= QFV_CreateImage (device, 0, VK_IMAGE_TYPE_2D,
depthFormat, extent, 1, 1,
VK_SAMPLE_COUNT_1_BIT, // FIXME (for depth?!?)
depthFormat, extent, 1, 1, msaaSamples,
VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT);
depthImage->object
= QFV_AllocImageMemory (device, depthImage->image,
@ -322,6 +328,72 @@ Vulkan_CreateRenderPass (vulkan_ctx_t *ctx)
ctx->renderpass.colorImage = colorImage;
ctx->renderpass.depthImage = depthImage;
__auto_type attachments = QFV_AllocAttachmentDescription (3, alloca);
__auto_type attachmentRefs = QFV_AllocAttachmentReference (3, alloca);
// color attachment
attachments->a[0].flags = 0;
attachments->a[0].format = sc->format;
attachments->a[0].samples = msaaSamples;
attachments->a[0].loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
attachments->a[0].storeOp = VK_ATTACHMENT_STORE_OP_STORE;
attachments->a[0].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
attachments->a[0].stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
attachments->a[0].initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
attachments->a[0].finalLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
attachmentRefs->a[0].attachment = 0;
attachmentRefs->a[0].layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
// depth attachment
attachments->a[1].flags = 0;
attachments->a[1].format = depthFormat;
attachments->a[1].samples = msaaSamples;
attachments->a[1].loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
attachments->a[1].storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
attachments->a[1].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
attachments->a[1].stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
attachments->a[1].initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
attachments->a[1].finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
attachmentRefs->a[1].attachment = 1;
attachmentRefs->a[1].layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
// resolve attachment
attachments->a[2].flags = 0;
attachments->a[2].format = sc->format;
attachments->a[2].samples = VK_SAMPLE_COUNT_1_BIT;
attachments->a[2].loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
attachments->a[2].storeOp = VK_ATTACHMENT_STORE_OP_STORE;
attachments->a[2].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
attachments->a[2].stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
attachments->a[2].initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
attachments->a[2].finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
attachmentRefs->a[2].attachment = 2;
attachmentRefs->a[2].layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
__auto_type subpasses = QFV_AllocSubpassParametersSet (1, alloca);
subpasses->a[0].flags = 0;
subpasses->a[0].pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
subpasses->a[0].inputAttachmentCount = 0;
subpasses->a[0].pInputAttachments = 0;
subpasses->a[0].colorAttachmentCount = 1;
subpasses->a[0].pColorAttachments = &attachmentRefs->a[0];
subpasses->a[0].pResolveAttachments = &attachmentRefs->a[2];
subpasses->a[0].pDepthStencilAttachment = &attachmentRefs->a[1];
subpasses->a[0].preserveAttachmentCount = 0;
subpasses->a[0].pPreserveAttachments = 0;
__auto_type depenencies = QFV_AllocSubpassDependencies (1, alloca);
depenencies->a[0].srcSubpass = VK_SUBPASS_EXTERNAL;
depenencies->a[0].dstSubpass = 0;
depenencies->a[0].srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
depenencies->a[0].dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
depenencies->a[0].srcAccessMask = 0;
depenencies->a[0].dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
depenencies->a[0].dependencyFlags = 0;
ctx->renderpass.renderpass = QFV_CreateRenderPass (device, attachments,
subpasses, depenencies);
}
void
@ -331,6 +403,8 @@ Vulkan_DestroyRenderPass (vulkan_ctx_t *ctx)
VkDevice dev = device->dev;
qfv_devfuncs_t *df = device->funcs;
df->vkDestroyRenderPass (dev, ctx->renderpass.renderpass, 0);
df->vkDestroyImageView (dev, ctx->renderpass.colorImage->view, 0);
df->vkDestroyImage (dev, ctx->renderpass.colorImage->image, 0);
df->vkFreeMemory (dev, ctx->renderpass.colorImage->object, 0);
@ -343,3 +417,56 @@ Vulkan_DestroyRenderPass (vulkan_ctx_t *ctx)
free (ctx->renderpass.depthImage);
ctx->renderpass.depthImage = 0;
}
void
Vulkan_CreateFramebuffers (vulkan_ctx_t *ctx)
{
qfv_device_t *device = ctx->device;
VkCommandPool cmdpool = ctx->cmdpool;
qfv_swapchain_t *sc = ctx->swapchain;
VkRenderPass renderpass = ctx->renderpass.renderpass;
if (!ctx->framebuffers.grow) {
DARRAY_INIT (&ctx->framebuffers, 4);
}
DARRAY_RESIZE (&ctx->framebuffers, sc->numImages);
__auto_type attachments = DARRAY_ALLOCFIXED (qfv_imageviewset_t, 3,
alloca);
attachments->a[0] = ctx->renderpass.colorImage->view;
attachments->a[1] = ctx->renderpass.depthImage->view;
__auto_type cmdBuffers
= QFV_AllocateCommandBuffers (device, cmdpool, 0,
ctx->framebuffers.size);
for (size_t i = 0; i < ctx->framebuffers.size; i++) {
attachments->a[2] = sc->imageViews->a[i];
__auto_type frame = &ctx->framebuffers.a[i];
frame->framebuffer = QFV_CreateFramebuffer (device, renderpass,
attachments->size,
attachments->a,
sc->extent, 1);
frame->fence = QFV_CreateFence (device, 1);
frame->imageAvailableSemaphore = QFV_CreateSemaphore (device);
frame->renderDoneSemaphore = QFV_CreateSemaphore (device);
frame->cmdBuffer = cmdBuffers->a[i];
}
}
void
Vulkan_DestroyFramebuffers (vulkan_ctx_t *ctx)
{
qfv_device_t *device = ctx->device;
qfv_devfuncs_t *df = device->funcs;
VkDevice dev = device->dev;
for (size_t i = 0; i < ctx->framebuffers.size; i++) {
__auto_type frame = &ctx->framebuffers.a[i];
df->vkDestroyFence (dev, frame->fence, 0);
df->vkDestroySemaphore (dev, frame->imageAvailableSemaphore, 0);
df->vkDestroySemaphore (dev, frame->renderDoneSemaphore, 0);
df->vkDestroyFramebuffer (dev, frame->framebuffer, 0);
}
}