[vulkan] Make Vulkan_CreateRenderPass more generally useful

It now lives in vulkan_renderpass.c and takes most of its parameters
from plist configs (just the name (which is used to find the config),
output spec, and draw function from C). Even the debug colors and names
are taken from the config.
This commit is contained in:
Bill Currie 2022-05-30 15:58:22 +09:00
parent e14e8050dc
commit 3603fa75cd
12 changed files with 374 additions and 229 deletions

View file

@ -15,6 +15,9 @@ typedef struct qfv_subpass_s {
const char *name;
} qfv_subpass_t;
typedef struct qfv_subpassset_s
DARRAY_TYPE (qfv_subpass_t) qfv_subpassset_t;
typedef struct qfv_renderframe_s {
struct vulkan_ctx_s *vulkan_ctx;
struct qfv_renderpass_s *renderpass;
@ -30,6 +33,8 @@ typedef struct qfv_renderframeset_s
typedef struct clearvalueset_s
DARRAY_TYPE (VkClearValue) clearvalueset_t;
typedef void (*qfv_draw_t) (qfv_renderframe_t *rFrame);
typedef struct qfv_renderpass_s {
vec4f_t color; // for debugging
const char *name; // for debugging
@ -44,9 +49,19 @@ typedef struct qfv_renderpass_s {
VkViewport viewport;
VkRect2D scissor;
size_t subpassCount;
qfv_subpassset_t *subpass_info;
qfv_renderframeset_t frames;
void (*draw) (qfv_renderframe_t *rFrame);
qfv_draw_t draw;
} qfv_renderpass_t;
struct qfv_output_s;
qfv_renderpass_t *Vulkan_CreateRenderPass (struct vulkan_ctx_s *ctx,
const char *name,
struct qfv_output_s *output,
qfv_draw_t draw);
void Vulkan_DestroyRenderPass (struct vulkan_ctx_s *ctx,
qfv_renderpass_t *renderpass);
#endif//__QF_Vulkan_renderpass_h

View file

@ -61,7 +61,7 @@ struct vulkan_ctx_s;
void Vulkan_DestroyFrames (struct vulkan_ctx_s *ctx);
void Vulkan_CreateFrames (struct vulkan_ctx_s *ctx);
void Vulkan_CreateCapture (struct vulkan_ctx_s *ctx);
void Vulkan_CreateRenderPass (struct vulkan_ctx_s *ctx);
void Vulkan_CreateRenderPasses (struct vulkan_ctx_s *ctx);
void Vulkan_DestroyRenderPasses (struct vulkan_ctx_s *ctx);
void Vulkan_CreateSwapchain (struct vulkan_ctx_s *ctx);
void Vulkan_CreateDevice (struct vulkan_ctx_s *ctx);
@ -85,4 +85,6 @@ struct entity_s;
void Vulkan_BeginEntityLabel (struct vulkan_ctx_s *ctx, VkCommandBuffer cmd,
struct entity_s *ent);
struct plitem_s *Vulkan_GetConfig (struct vulkan_ctx_s *ctx, const char *name);
#endif // __QF_Vulkan_vid_h

View file

@ -98,7 +98,7 @@ typedef struct vulkan_ctx_s {
int window_width;
int window_height;
//FIXME not sure I like it being here (also, type name)
//FIXME this is for the parser
qfv_output_t output;
#define EXPORTED_VULKAN_FUNCTION(fname) PFN_##fname fname;

View file

@ -89,7 +89,7 @@ vulkan_R_Init (void)
Vulkan_CreateSwapchain (vulkan_ctx);
Vulkan_CreateFrames (vulkan_ctx);
Vulkan_CreateCapture (vulkan_ctx);
Vulkan_CreateRenderPass (vulkan_ctx);
Vulkan_CreateRenderPasses (vulkan_ctx);
Vulkan_Texture_Init (vulkan_ctx);
Vulkan_Matrix_Init (vulkan_ctx);

View file

@ -99,7 +99,7 @@
};
};
framebuffer = {
renderPass = $properties.renderpass;
renderPass = deferred;
attachments = (depth, color, emission, normal, position, opaque,
translucent, $output.view);
width = $output.extent.width;
@ -125,6 +125,16 @@
initialLayout = undefined;
finalLayout = color_attachment_optimal;
};
info = {
color = "[0, 1, 0, 1]";
subpass_info = (
{ name = depth; color = "[ 0.5, 0.5, 0.5, 1]" },
{ name = translucent; color = "[ 0.25, 0.25, 0.6, 1]" },
{ name = g-buffef; color = "[ 0.3, 0.7, 0.3, 1]" },
{ name = lighting; color = "[ 0.8, 0.8, 0.8, 1]" },
{ name = compose; color = "[ 0.7, 0.3, 0.3, 1]" },
);
};
renderpass = {
attachments = (
{

View file

@ -672,7 +672,7 @@
dynamic = {
dynamicState = ( viewport, scissor );
};
renderPass = renderpass;
renderPass = deferred;
};
depth_base = {
@inherit = $properties.pipelines.base;

View file

@ -1,3 +1,9 @@
#define __x86_64__
#include <vulkan/vulkan.h>
#include "QF/Vulkan/swapchain.h"
//FIXME copy of qfv_subpass_t in qf_renderpass.h
//except it doesn't really matter because a custom spec is used
typedef struct qfv_subpass_s {
vec4 color;
string name;
} qfv_subpass_t;

View file

@ -531,7 +531,7 @@ parse_VkRenderPass (const plitem_t *item, void **data,
// path not guaranteed to survive cexpr_eval_string due to va
path = resource_path (ctx, 0, name);
QFV_AddHandle (ctx->setLayouts, path, (uint64_t) setLayout);
QFV_AddHandle (ctx->renderpasses, path, (uint64_t) setLayout);
}
return ret;
}
@ -1516,3 +1516,65 @@ QFV_ParseClearValues (vulkan_ctx_t *ctx, plitem_t *plist, plitem_t *properties)
delete_memsuper (memsuper);
return cv;
}
static int
parse_subpassset (const plfield_t *field, const plitem_t *item, void *data,
plitem_t *messages, void *context)
{
plelement_t element = {
QFDictionary,
sizeof (qfv_subpass_t),
vkparse_alloc,
parse_qfv_subpass_t,
0,
};
plfield_t f = { 0, 0, 0, 0, &element };
if (!PL_ParseArray (&f, item, data, messages, context)) {
return 0;
}
return 1;
}
qfv_subpassset_t *
QFV_ParseSubpasses (vulkan_ctx_t *ctx, plitem_t *plist, plitem_t *properties)
{
qfv_subpassset_t *sp = 0;
memsuper_t *memsuper = new_memsuper ();
qfv_subpassset_t *subpasses = 0;
if (parse_object (ctx, memsuper, plist, parse_subpassset, &subpasses,
properties)) {
sp = DARRAY_ALLOCFIXED (qfv_subpassset_t, subpasses->size, malloc);
memcpy (sp->a, subpasses->a, sp->size * sizeof (sp->a[0]));
// the name is in memsuper which is about to be freed
for (size_t i = 0; i < sp->size; i++) {
sp->a[i].name = strdup (sp->a[i].name);
}
}
delete_memsuper (memsuper);
return sp;
}
static int
parse_rgba (const plfield_t *field, const plitem_t *item, void *data,
plitem_t *messages, void *context)
{
return parse_RGBA (item, &data, messages, context);
}
int
QFV_ParseRGBA (vulkan_ctx_t *ctx, float *rgba, plitem_t *plist,
plitem_t *properties)
{
memsuper_t *memsuper = new_memsuper ();
int ret = 0;
vec4f_t color;
if (parse_object (ctx, memsuper, plist, parse_rgba, &color, properties)) {
memcpy (rgba, &color, sizeof (color));
ret = 1;
}
delete_memsuper (memsuper);
return ret;
}

View file

@ -49,5 +49,9 @@ struct clearvalueset_s *QFV_ParseClearValues (vulkan_ctx_t *ctx,
plitem_t *plist,
plitem_t *properties);
struct qfv_subpassset_s *QFV_ParseSubpasses (vulkan_ctx_t *ctx,
plitem_t *plist,
plitem_t *properties);
int QFV_ParseRGBA (vulkan_ctx_t *ctx, float *rgba, plitem_t *plist,
plitem_t *properties);
#endif//__vkparse_h

View file

@ -30,6 +30,8 @@
VkPhysicalDeviceLimits,
VkRenderPassCreateInfo,
VkRenderPassMultiviewCreateInfo,
qfv_subpass_t,
);
parse = {
VkSubpassDescription = {
@ -377,6 +379,18 @@
size = correlationMaskCount;
values = pCorrelationMasks;
};
}
}
};
qfv_subpass_s = {
.name = qfv_subpass_t;
color = {
type = (custom, QFString, parse_RGBA);
fields = (color);
};
name = {
type = string;
string = name;
};
};
};
}

View file

@ -29,7 +29,245 @@
#endif
#include "QF/cvar.h"
#include "QF/hash.h"
#include "QF/plist.h"
#include "QF/va.h"
#include "QF/Vulkan/command.h"
#include "QF/Vulkan/debug.h"
#include "QF/Vulkan/device.h"
#include "QF/Vulkan/image.h"
#include "QF/Vulkan/swapchain.h"
#include "QF/Vulkan/qf_renderpass.h"
#include "vid_vulkan.h"
#include "vkparse.h"
static plitem_t *
get_rp_item (vulkan_ctx_t *ctx, qfv_renderpass_t *rp, const char *name)
{
if (!rp->renderpassDef) {
rp->renderpassDef = Vulkan_GetConfig (ctx, rp->name);
}
plitem_t *item = rp->renderpassDef;
if (!item || !(item = PL_ObjectForKey (item, name))) {
Sys_Printf ("error loading %s\n", name);
} else {
Sys_MaskPrintf (SYS_vulkan_parse, "Found %s def\n", name);
}
return item;
}
static size_t
get_image_size (VkImage image, qfv_device_t *device)
{
qfv_devfuncs_t *dfunc = device->funcs;
size_t size;
size_t align;
VkMemoryRequirements requirements;
dfunc->vkGetImageMemoryRequirements (device->dev, image, &requirements);
size = requirements.size;
align = requirements.alignment - 1;
size = (size + align) & ~(align);
return size;
}
static void
create_attachements (vulkan_ctx_t *ctx, qfv_renderpass_t *rp)
{
qfv_device_t *device = ctx->device;
plitem_t *item = get_rp_item (ctx, rp, "images");
if (!item) {
return;
}
__auto_type images = QFV_ParseImageSet (ctx, item, rp->renderpassDef);
rp->attachment_images = images;
size_t memSize = 0;
for (size_t i = 0; i < images->size; i++) {
memSize += get_image_size (images->a[i], device);
}
VkDeviceMemory mem;
mem = QFV_AllocImageMemory (device, images->a[0],
VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT,
memSize, 0);
rp->attachmentMemory = mem;
QFV_duSetObjectName (device, VK_OBJECT_TYPE_DEVICE_MEMORY,
mem, "memory:framebuffers");
size_t offset = 0;
for (size_t i = 0; i < images->size; i++) {
QFV_BindImageMemory (device, images->a[i], mem, offset);
offset += get_image_size (images->a[i], device);
}
item = get_rp_item (ctx, rp, "imageViews");
if (!item) {
return;
}
__auto_type views = QFV_ParseImageViewSet (ctx, item, rp->renderpassDef);
rp->attachment_views = views;
item = get_rp_item (ctx, rp, "framebuffer");
if (!item) {
return;
}
rp->framebuffers = QFV_AllocFrameBuffers (ctx->swapchain->numImages,
malloc);
for (size_t i = 0; i < rp->framebuffers->size; i++) {
ctx->output = (qfv_output_t) {
.extent = ctx->swapchain->extent,
.view = ctx->swapchain->imageViews->a[i],
.format = ctx->swapchain->format,
};
rp->framebuffers->a[i] = QFV_ParseFramebuffer (ctx, item,
rp->renderpassDef);
}
}
static void
init_renderframe (vulkan_ctx_t *ctx, qfv_renderpass_t *rp,
qfv_renderframe_t *rFrame)
{
rFrame->subpassContents = VK_SUBPASS_CONTENTS_SECONDARY_COMMAND_BUFFERS;
rFrame->vulkan_ctx = ctx;
rFrame->renderpass = rp;
rFrame->subpassCount = rp->subpassCount;
if (rp->subpass_info) {
rFrame->subpassInfo = rp->subpass_info->a;
}
rFrame->subpassCmdSets = malloc (rp->subpassCount
* sizeof (qfv_cmdbufferset_t));
for (size_t j = 0; j < rp->subpassCount; j++) {
DARRAY_INIT (&rFrame->subpassCmdSets[j], 4);
}
}
static void
destroy_attachments (vulkan_ctx_t *ctx, qfv_renderpass_t *rp)
{
qfv_device_t *device = ctx->device;
qfv_devfuncs_t *dfunc = device->funcs;
for (size_t i = 0; i < rp->attachment_views->size; i++) {
dfunc->vkDestroyImageView (device->dev, rp->attachment_views->a[i], 0);
}
for (size_t i = 0; i < rp->attachment_images->size; i++) {
dfunc->vkDestroyImage (device->dev, rp->attachment_images->a[i], 0);
}
dfunc->vkFreeMemory (device->dev, rp->attachmentMemory, 0);
free (rp->attachment_images);
free (rp->attachment_views);
}
static void
destroy_renderframes (vulkan_ctx_t *ctx, qfv_renderpass_t *rp)
{
for (size_t i = 0; i < rp->frames.size; i++) {
__auto_type rFrame = &rp->frames.a[i];
for (int j = 0; j < rFrame->subpassCount; j++) {
DARRAY_CLEAR (&rFrame->subpassCmdSets[j]);
}
free (rFrame->subpassCmdSets);
}
}
static void
destroy_framebuffers (vulkan_ctx_t *ctx, qfv_renderpass_t *rp)
{
qfv_device_t *device = ctx->device;
qfv_devfuncs_t *dfunc = device->funcs;
for (size_t i = 0; i < rp->framebuffers->size; i++) {
dfunc->vkDestroyFramebuffer (device->dev, rp->framebuffers->a[i], 0);
}
free (rp->framebuffers);
}
qfv_renderpass_t *
Vulkan_CreateRenderPass (vulkan_ctx_t *ctx, const char *name,
qfv_output_t *output, qfv_draw_t draw)
{
plitem_t *item;
qfv_renderpass_t *rp = calloc (1, sizeof (qfv_renderpass_t));
rp->name = name;
plitem_t *rp_cfg = get_rp_item (ctx, rp, "renderpass");
hashtab_t *tab = ctx->renderpasses;
const char *path;
path = va (ctx->va_ctx, "$"QFV_PROPERTIES".%s", name);
__auto_type renderpass = (VkRenderPass) QFV_GetHandle (tab, path);
if (renderpass) {
rp->renderpass = renderpass;
} else {
ctx->output = *output;
rp->renderpass = QFV_ParseRenderPass (ctx, rp_cfg, rp->renderpassDef);
QFV_AddHandle (tab, path, (uint64_t) rp->renderpass);
QFV_duSetObjectName (ctx->device, VK_OBJECT_TYPE_RENDER_PASS,
rp->renderpass, va (ctx->va_ctx, "renderpass:%s",
name));
}
rp->subpassCount = PL_A_NumObjects (PL_ObjectForKey (rp_cfg, "subpasses"));
plitem_t *rp_info = get_rp_item (ctx, rp, "info");
if (rp_info) {
plitem_t *subpass_info = PL_ObjectForKey (rp_info, "subpass_info");
if (subpass_info) {
rp->subpass_info = QFV_ParseSubpasses (ctx, subpass_info,
rp->renderpassDef);
if (rp->subpass_info->size > rp->subpassCount) {
Sys_Printf ("warning:%s:%d: insufficient entries in "
"subpass_info\n", name, PL_Line (subpass_info));
}
}
plitem_t *color = PL_ObjectForKey (rp_info, "color");
if (color) {
QFV_ParseRGBA (ctx, (float *)&rp->color, color, rp->renderpassDef);
}
}
int width = output->extent.width;
int height = output->extent.height;
rp->viewport = (VkViewport) { 0, 0, width, height, 0, 1 };
rp->scissor = (VkRect2D) { {0, 0}, {width, height} };
DARRAY_INIT (&rp->frames, 4);
DARRAY_RESIZE (&rp->frames, ctx->frames.size);
for (size_t i = 0; i < rp->frames.size; i++) {
init_renderframe (ctx, rp, &rp->frames.a[i]);
}
create_attachements (ctx, rp);
item = get_rp_item (ctx, rp, "clearValues");
rp->clearValues = QFV_ParseClearValues (ctx, item, rp->renderpassDef);
rp->draw = draw;
return rp;
}
void
Vulkan_DestroyRenderPass (vulkan_ctx_t *ctx, qfv_renderpass_t *renderpass)
{
qfv_device_t *device = ctx->device;
qfv_devfuncs_t *dfunc = device->funcs;
PL_Free (renderpass->renderpassDef);
destroy_attachments (ctx, renderpass);
dfunc->vkDestroyRenderPass (device->dev, renderpass->renderpass, 0);
destroy_renderframes (ctx, renderpass);
destroy_framebuffers (ctx, renderpass);
DARRAY_CLEAR (&renderpass->frames);
free (renderpass->clearValues);
free (renderpass);
}

View file

@ -317,8 +317,8 @@ build_configs (vulkan_ctx_t *ctx)
cexpr_init_symtab (&builtin_configs, &ectx);
}
static plitem_t *
get_builtin_config (vulkan_ctx_t *ctx, const char *name)
plitem_t *
Vulkan_GetConfig (vulkan_ctx_t *ctx, const char *name)
{
if (!builtin_configs.tab) {
build_configs (ctx);
@ -353,7 +353,7 @@ static plitem_t *
qfv_load_pipeline (vulkan_ctx_t *ctx, const char *name)
{
if (!ctx->pipelineDef) {
ctx->pipelineDef = get_builtin_config (ctx, "qfpipeline");
ctx->pipelineDef = Vulkan_GetConfig (ctx, "qfpipeline");
}
plitem_t *item = ctx->pipelineDef;
@ -365,37 +365,6 @@ qfv_load_pipeline (vulkan_ctx_t *ctx, const char *name)
return item;
}
static plitem_t *
qfv_load_renderpass (vulkan_ctx_t *ctx, qfv_renderpass_t *rp, const char *name)
{
if (!rp->renderpassDef) {
rp->renderpassDef = get_builtin_config (ctx, "deferred");
}
plitem_t *item = rp->renderpassDef;
if (!item || !(item = PL_ObjectForKey (item, name))) {
Sys_Printf ("error loading %s\n", name);
} else {
Sys_MaskPrintf (SYS_vulkan_parse, "Found %s def\n", name);
}
return item;
}
static size_t
get_image_size (VkImage image, qfv_device_t *device)
{
qfv_devfuncs_t *dfunc = device->funcs;
size_t size;
size_t align;
VkMemoryRequirements requirements;
dfunc->vkGetImageMemoryRequirements (device->dev, image, &requirements);
size = requirements.size;
align = requirements.alignment - 1;
size = (size + align) & ~(align);
return size;
}
static void
renderpass_draw (qfv_renderframe_t *rFrame)
{
@ -406,199 +375,24 @@ renderpass_draw (qfv_renderframe_t *rFrame)
Vulkan_Compose_Draw (rFrame);
}
static void
create_attachements (vulkan_ctx_t *ctx, qfv_renderpass_t *rp)
{
qfv_device_t *device = ctx->device;
plitem_t *item = qfv_load_renderpass (ctx, rp, "images");
if (!item) {
return;
}
__auto_type images = QFV_ParseImageSet (ctx, item, rp->renderpassDef);
rp->attachment_images = images;
size_t memSize = 0;
for (size_t i = 0; i < images->size; i++) {
memSize += get_image_size (images->a[i], device);
}
VkDeviceMemory mem;
mem = QFV_AllocImageMemory (device, images->a[0],
VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT,
memSize, 0);
rp->attachmentMemory = mem;
QFV_duSetObjectName (device, VK_OBJECT_TYPE_DEVICE_MEMORY,
mem, "memory:framebuffers");
size_t offset = 0;
for (size_t i = 0; i < images->size; i++) {
QFV_BindImageMemory (device, images->a[i], mem, offset);
offset += get_image_size (images->a[i], device);
}
item = qfv_load_renderpass (ctx, rp, "imageViews");
if (!item) {
return;
}
__auto_type views = QFV_ParseImageViewSet (ctx, item, rp->renderpassDef);
rp->attachment_views = views;
item = qfv_load_renderpass (ctx, rp, "framebuffer");
if (!item) {
return;
}
rp->framebuffers = QFV_AllocFrameBuffers (ctx->swapchain->numImages,
malloc);
for (size_t i = 0; i < rp->framebuffers->size; i++) {
ctx->output = (qfv_output_t) {
.extent = ctx->swapchain->extent,
.view = ctx->swapchain->imageViews->a[i],
.format = ctx->swapchain->format,
};
rp->framebuffers->a[i] = QFV_ParseFramebuffer (ctx, item,
rp->renderpassDef);
}
}
static void
init_renderframe (vulkan_ctx_t *ctx, qfv_renderpass_t *rp,
qfv_renderframe_t *rFrame)
{
// FIXME should not be hard-coded
static qfv_subpass_t subpass_info[] = {
{ .name = "depth", .color = { 0.5, 0.5, 0.5, 1} },
{ .name = "translucent", .color = { 0.25, 0.25, 0.6, 1} },
{ .name = "g-buffef", .color = { 0.3, 0.7, 0.3, 1} },
{ .name = "lighting", .color = { 0.8, 0.8, 0.8, 1} },
{ .name = "compose", .color = { 0.7, 0.3, 0.3, 1} },
};
rFrame->subpassContents = VK_SUBPASS_CONTENTS_SECONDARY_COMMAND_BUFFERS;
rFrame->vulkan_ctx = ctx;
rFrame->renderpass = rp;
rFrame->subpassCount = QFV_NumPasses;
rFrame->subpassInfo = subpass_info; //FIXME
rFrame->subpassCmdSets = malloc (QFV_NumPasses
* sizeof (qfv_cmdbufferset_t));
for (int j = 0; j < QFV_NumPasses; j++) {
DARRAY_INIT (&rFrame->subpassCmdSets[j], 4);
}
}
void
Vulkan_CreateRenderPass (vulkan_ctx_t *ctx)
Vulkan_CreateRenderPasses (vulkan_ctx_t *ctx)
{
const char *name = "renderpass";//FIXME
plitem_t *item;
qfv_renderpass_t *rp = calloc (1, sizeof (qfv_renderpass_t));
rp->name = name;
rp->color = (vec4f_t) { 0, 1, 0, 1 }; //FIXME
hashtab_t *tab = ctx->renderpasses;
const char *path;
path = va (ctx->va_ctx, "$"QFV_PROPERTIES".%s", name);
__auto_type renderpass = (VkRenderPass) QFV_GetHandle (tab, path);
if (renderpass) {
rp->renderpass = renderpass;
} else {
ctx->output = (qfv_output_t) {
.extent = ctx->swapchain->extent,
.view = ctx->swapchain->imageViews->a[0],
.format = ctx->swapchain->format,
};
item = qfv_load_renderpass (ctx, rp, name);
rp->renderpass = QFV_ParseRenderPass (ctx, item, rp->renderpassDef);
QFV_AddHandle (tab, path, (uint64_t) rp->renderpass);
QFV_duSetObjectName (ctx->device, VK_OBJECT_TYPE_RENDER_PASS,
rp->renderpass, va (ctx->va_ctx, "renderpass:%s",
name));
}
int width = ctx->window_width;
int height = ctx->window_height;
rp->viewport = (VkViewport) { 0, 0, width, height, 0, 1 };
rp->scissor = (VkRect2D) { {0, 0}, {width, height} };
DARRAY_INIT (&rp->frames, 4);
DARRAY_RESIZE (&rp->frames, ctx->frames.size);
for (size_t i = 0; i < rp->frames.size; i++) {
init_renderframe (ctx, rp, &rp->frames.a[i]);
}
create_attachements (ctx, rp);
item = qfv_load_renderpass (ctx, rp, "clearValues");
rp->clearValues = QFV_ParseClearValues (ctx, item, rp->renderpassDef);
rp->draw = renderpass_draw;
qfv_output_t output = {
.extent = ctx->swapchain->extent,
.view = ctx->swapchain->imageViews->a[0],
.format = ctx->swapchain->format,
};
__auto_type rp = Vulkan_CreateRenderPass (ctx, "deferred",
&output, renderpass_draw);
DARRAY_APPEND (&ctx->renderPasses, rp);
}
static void
destroy_attachments (vulkan_ctx_t *ctx, qfv_renderpass_t *rp)
{
qfv_device_t *device = ctx->device;
qfv_devfuncs_t *dfunc = device->funcs;
for (size_t i = 0; i < rp->attachment_views->size; i++) {
dfunc->vkDestroyImageView (device->dev, rp->attachment_views->a[i], 0);
}
for (size_t i = 0; i < rp->attachment_images->size; i++) {
dfunc->vkDestroyImage (device->dev, rp->attachment_images->a[i], 0);
}
dfunc->vkFreeMemory (device->dev, rp->attachmentMemory, 0);
free (rp->attachment_images);
free (rp->attachment_views);
}
static void
destroy_renderframes (vulkan_ctx_t *ctx, qfv_renderpass_t *rp)
{
for (size_t i = 0; i < rp->frames.size; i++) {
__auto_type rFrame = &rp->frames.a[i];
for (int j = 0; j < rFrame->subpassCount; j++) {
DARRAY_CLEAR (&rFrame->subpassCmdSets[j]);
}
free (rFrame->subpassCmdSets);
}
}
static void
destroy_framebuffers (vulkan_ctx_t *ctx, qfv_renderpass_t *rp)
{
qfv_device_t *device = ctx->device;
qfv_devfuncs_t *dfunc = device->funcs;
for (size_t i = 0; i < rp->framebuffers->size; i++) {
dfunc->vkDestroyFramebuffer (device->dev, rp->framebuffers->a[i], 0);
}
free (rp->framebuffers);
}
void
Vulkan_DestroyRenderPasses (vulkan_ctx_t *ctx)
{
qfv_device_t *device = ctx->device;
qfv_devfuncs_t *dfunc = device->funcs;
for (size_t i = 0; i < ctx->renderPasses.size; i++) {
__auto_type rp = ctx->renderPasses.a[i];
PL_Free (rp->renderpassDef);
destroy_attachments (ctx, rp);
dfunc->vkDestroyRenderPass (device->dev, rp->renderpass, 0);
destroy_renderframes (ctx, rp);
destroy_framebuffers (ctx, rp);
DARRAY_CLEAR (&rp->frames);
free (rp->clearValues);
free (rp);
Vulkan_DestroyRenderPass (ctx, ctx->renderPasses.a[i]);
}
}