[vulkan] Start moving towards a deferred renderer

After getting lights even vaguely working for alias models, I realized
that it just wasn't going to be feasible to do nice lighting with
forward rendering. This gets the bulk of the work done for deferred
rendering, but still need to sort out the shaders before any real
testing can be done.
This commit is contained in:
Bill Currie 2021-02-14 11:35:06 +09:00
parent 121425a75b
commit a94949c009
17 changed files with 1347 additions and 551 deletions

View file

@ -3,8 +3,17 @@
#include "QF/darray.h"
typedef struct qfv_imageset_s DARRAY_TYPE (VkImage) qfv_imageset_t;
typedef struct qfv_imageviewset_s DARRAY_TYPE (VkImageView) qfv_imageviewset_t;
typedef struct qfv_imageset_s
DARRAY_TYPE (VkImage) qfv_imageset_t;
#define QFV_AllocImages(num, allocator) \
DARRAY_ALLOCFIXED (qfv_imageset_t, num, allocator)
typedef struct qfv_imageviewset_s
DARRAY_TYPE (VkImageView) qfv_imageviewset_t;
#define QFV_AllocImageViews(num, allocator) \
DARRAY_ALLOCFIXED (qfv_imageviewset_t, num, allocator)
typedef struct qfv_imageresource_s {
struct qfv_device_s *device;

View file

@ -36,6 +36,7 @@
#include "QF/model.h"
#include "QF/modelgen.h"
#include "QF/Vulkan/qf_vid.h"
#include "QF/Vulkan/command.h"
typedef struct aliasvrt_s {
float vertex[4];
@ -61,32 +62,22 @@ typedef struct qfv_alias_skin_s {
byte colorb[4];
} qfv_alias_skin_t;
typedef struct qfv_light_s {
vec3_t color;
float dist;
vec3_t position;
int type;
vec3_t direction;
float cone;
} qfv_light_t;
#define ALIAS_LIGHTS 8
typedef struct qfv_light_buffer_s {
int light_count;
qfv_light_t lights[ALIAS_LIGHTS] __attribute__((aligned(16)));
} qfv_light_buffer_t;
#define ALIAS_BUFFER_INFOS 2
#define ALIAS_BUFFER_INFOS 1
#define ALIAS_IMAGE_INFOS 1
enum {
QFV_aliasDepth,
QFV_aliasGBuffer,
//QFV_aliasTranslucent,
QFV_aliasNumPasses
};
typedef struct aliasframe_s {
VkCommandBuffer cmd;
qfv_cmdbufferset_t cmdSet;
VkDescriptorBufferInfo bufferInfo[ALIAS_BUFFER_INFOS];
VkDescriptorImageInfo imageInfo[ALIAS_IMAGE_INFOS];
VkWriteDescriptorSet descriptors[ALIAS_BUFFER_INFOS + ALIAS_IMAGE_INFOS];
qfv_light_buffer_t *lights;
VkBuffer light_buffer;
} aliasframe_t;
typedef struct aliasframeset_s
@ -94,11 +85,10 @@ typedef struct aliasframeset_s
typedef struct aliasctx_s {
aliasframeset_t frames;
VkPipeline pipeline;
VkPipeline depth;
VkPipeline gbuf;
VkPipelineLayout layout;
VkSampler sampler;
VkDeviceMemory light_memory;
} aliasctx_t;
struct vulkan_ctx_s;

View file

@ -35,6 +35,7 @@
#include "QF/darray.h"
#include "QF/model.h"
#include "QF/Vulkan/qf_vid.h"
#include "QF/Vulkan/command.h"
typedef struct bspvert_s {
quat_t vertex;
@ -69,13 +70,19 @@ typedef enum {
// Texture, GlowMap, LightMap, SkySheet, SkyCube
#define BSP_IMAGE_INFOS 5
enum {
QFV_bspDepth,
QFV_bspGBuffer,
QFV_bspTranslucent,
QFV_bspNumPasses
};
typedef struct bspframe_s {
uint32_t *index_data; // pointer into mega-buffer for this frame (c)
uint32_t index_offset; // offset of index_data within mega-buffer (c)
uint32_t index_count; // number if indices queued (d)
VkCommandBuffer bsp_cmd;
VkCommandBuffer turb_cmd;
VkCommandBuffer sky_cmd;
qfv_cmdbufferset_t cmdSet;
VkDescriptorBufferInfo bufferInfo[BSP_BUFFER_INFOS];
VkDescriptorImageInfo imageInfo[BSP_IMAGE_INFOS];
VkWriteDescriptorSet descriptors[BSP_BUFFER_INFOS + BSP_IMAGE_INFOS];

View file

@ -35,9 +35,22 @@
#endif
#include <vulkan/vulkan.h>
//FIXME location
enum {
QFV_passDepth, // geometry
QFV_passGBuffer, // geometry
QFV_passTranslucent, // geometry
QFV_passLighting, // single quad
QFV_passCompose, // single quad
QFV_NumPasses
};
struct vulkan_ctx_s;
void Vulkan_DestroyFramebuffers (struct vulkan_ctx_s *ctx);
void Vulkan_DestroyFrames (struct vulkan_ctx_s *ctx);
void Vulkan_CreateFrames (struct vulkan_ctx_s *ctx);
void Vulkan_CreateFramebuffers (struct vulkan_ctx_s *ctx);
void Vulkan_DestroyFramebuffers (struct vulkan_ctx_s *ctx);
void Vulkan_CreateRenderPass (struct vulkan_ctx_s *ctx);
void Vulkan_DestroyRenderPass (struct vulkan_ctx_s *ctx);
void Vulkan_CreateMatrices (struct vulkan_ctx_s *ctx);

View file

@ -27,6 +27,12 @@ typedef struct qfv_subpassdependency_s
#define QFV_AllocSubpassDependencies(num, allocator) \
DARRAY_ALLOCFIXED (qfv_subpassdependency_t, num, allocator)
typedef struct qfv_framebufferset_s
DARRAY_TYPE (VkFramebuffer) qfv_framebufferset_t;
#define QFV_AllocFrameBuffers(num, allocator) \
DARRAY_ALLOCFIXED (qfv_framebufferset_t, num, allocator)
struct qfv_device_s;
struct qfv_imageviewset_s;
VkRenderPass

View file

@ -8,20 +8,15 @@
#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 {
typedef struct vulkan_frame_s {
VkFramebuffer framebuffer;
VkFence fence;
VkSemaphore imageAvailableSemaphore;
VkSemaphore renderDoneSemaphore;
VkCommandBuffer cmdBuffer;
struct qfv_cmdbufferset_s *subCommand;
int cmdSetCount;
struct qfv_cmdbufferset_s *cmdSets;
} vulkan_frame_t;
typedef struct vulkan_matrices_s {
@ -59,11 +54,22 @@ typedef struct vulkan_ctx_s {
VkSurfaceKHR surface; //FIXME surface = window, so "contains" swapchain
struct plitem_s *pipelineDef;
struct plitem_s *renderpassDef;
VkRenderPass renderpass;
struct qfv_imageset_s *attachment_images;
struct qfv_imageviewset_s *attachment_views;
VkDeviceMemory attachmentMemory;
uint32_t swapImageIndex;
struct qfv_framebufferset_s *framebuffers;
struct hashtab_s *shaderModules;
struct hashtab_s *setLayouts;
struct hashtab_s *pipelineLayouts;
struct hashtab_s *descriptorPools;
struct hashtab_s *samplers;
struct hashtab_s *images;
struct hashtab_s *imageViews;
struct aliasctx_s *alias_context;
struct bspctx_s *bsp_context;
@ -72,7 +78,6 @@ typedef struct vulkan_ctx_s {
VkCommandPool cmdpool;
VkCommandBuffer cmdbuffer;
VkFence fence; // for ctx->cmdbuffer only
vulkan_renderpass_t renderpass;
struct qfv_stagebuf_s *staging;
VkPipeline pipeline;
size_t curFrame;

View file

@ -209,6 +209,8 @@ libs_video_renderer_vid_render_sw32_la_SOURCES=\
pipeline_src = libs/video/renderer/vulkan/qfpipeline.plist
pipeline_gen = libs/video/renderer/vulkan/qfpipeline.plc
renderpass_src = libs/video/renderer/vulkan/deferred.plist
renderpass_gen = libs/video/renderer/vulkan/deferred.plc
video_renderer_vulkan_libs = \
libs/models/libmodels_vulkan.la
@ -250,7 +252,7 @@ libs/video/renderer/vulkan/vkparse.lo: libs/video/renderer/vulkan/vkparse.c $(vk
libs/video/renderer/vulkan/shader.lo: libs/video/renderer/vulkan/shader.c $(vkshader_c)
libs/video/renderer/vulkan/vulkan_vid_common.lo: libs/video/renderer/vulkan/vulkan_vid_common.c $(vkparse_src) $(pipeline_gen)
libs/video/renderer/vulkan/vulkan_vid_common.lo: libs/video/renderer/vulkan/vulkan_vid_common.c $(vkparse_src) $(pipeline_gen) ${renderpass_gen}
qwaq_curses = ruamoko/qwaq/qwaq-curses$(EXEEXT)

View file

@ -87,8 +87,9 @@ vulkan_R_Init (void)
Vulkan_CreateStagingBuffers (vulkan_ctx);
Vulkan_CreateMatrices (vulkan_ctx);
Vulkan_CreateSwapchain (vulkan_ctx);
Vulkan_CreateFramebuffers (vulkan_ctx);
Vulkan_CreateFrames (vulkan_ctx);
Vulkan_CreateRenderPass (vulkan_ctx);
Vulkan_CreateFramebuffers (vulkan_ctx);
// FIXME this should be staged so screen updates can begin while pipelines
// are being built
vulkan_ctx->pipeline = Vulkan_CreatePipeline (vulkan_ctx, "pipeline");
@ -111,6 +112,8 @@ vulkan_R_Init (void)
static void
vulkan_R_RenderFrame (SCR_Func scr_3dfunc, SCR_Func *scr_funcs)
{
const VkSubpassContents subpassContents
= VK_SUBPASS_CONTENTS_SECONDARY_COMMAND_BUFFERS;
static int count = 0;
static double startTime;
uint32_t imageIndex = 0;
@ -128,20 +131,9 @@ vulkan_R_RenderFrame (SCR_Func scr_3dfunc, SCR_Func *scr_funcs)
QFV_AcquireNextImage (vulkan_ctx->swapchain,
frame->imageAvailableSemaphore,
0, &imageIndex);
vulkan_ctx->swapImageIndex = imageIndex;
int attachCount = vulkan_ctx->msaaSamples > 1 ? 3 : 2;
__auto_type attachments = DARRAY_ALLOCFIXED (qfv_imageviewset_t,
attachCount, alloca);
qfv_swapchain_t *sc = vulkan_ctx->swapchain;
attachments->a[0] = sc->imageViews->a[imageIndex];
attachments->a[1] = vulkan_ctx->renderpass.depthImage->view;
if (attachCount > 2) {
attachments->a[2] = vulkan_ctx->renderpass.colorImage->view;
}
VkRenderPass renderpass = vulkan_ctx->renderpass.renderpass;
frame->framebuffer = QFV_CreateFramebuffer (device, renderpass,
attachments, sc->extent, 1);
frame->framebuffer = vulkan_ctx->framebuffers->a[imageIndex];
scr_3dfunc ();
while (*scr_funcs) {
@ -160,20 +152,26 @@ vulkan_R_RenderFrame (SCR_Func scr_3dfunc, SCR_Func *scr_funcs)
};
VkRenderPassBeginInfo renderPassInfo = {
VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO, 0,
vulkan_ctx->renderpass.renderpass, 0,
{ {0, 0}, sc->extent },
vulkan_ctx->renderpass, 0,
{ {0, 0}, vulkan_ctx->swapchain->extent },
3, clearValues
};
dfunc->vkBeginCommandBuffer (frame->cmdBuffer, &beginInfo);
renderPassInfo.framebuffer = frame->framebuffer;
dfunc->vkCmdBeginRenderPass (frame->cmdBuffer, &renderPassInfo,
VK_SUBPASS_CONTENTS_SECONDARY_COMMAND_BUFFERS);
subpassContents);
dfunc->vkCmdExecuteCommands (frame->cmdBuffer, frame->subCommand->size,
frame->subCommand->a);
// reset for next time around
frame->subCommand->size = 0;
for (int i = 0; i < frame->cmdSetCount; i++) {
dfunc->vkCmdExecuteCommands (frame->cmdBuffer, frame->cmdSets[i].size,
frame->cmdSets[i].a);
// reset for next time around
frame->cmdSets[i].size = 0;
if (i < frame->cmdSetCount) {
dfunc->vkCmdNextSubpass (frame->cmdBuffer, subpassContents);
}
}
dfunc->vkCmdEndRenderPass (frame->cmdBuffer);
dfunc->vkEndCommandBuffer (frame->cmdBuffer);

View file

@ -0,0 +1,342 @@
{
images = {
depth = {
imageType = VK_IMAGE_TYPE_2D; //FIXME short form is 2d...
format = x8_d24_unorm_pack32;
samples = 1;
extent = {
width = $swapchain.extent.width;
height = $swapchain.extent.height;
depth = 1;
};
mipLevels = 1;
arrayLayers = 1;
tiling = optimal;
usage = depth_stencil_attachment|input_attachment;
};
color = {
imageType = VK_IMAGE_TYPE_2D;
format = r8g8b8a8_unorm;
samples = 1;
extent = {
width = $swapchain.extent.width;
height = $swapchain.extent.height;
depth = 1;
};
mipLevels = 1;
arrayLayers = 1;
tiling = optimal;
usage = color_attachment|input_attachment;
};
normals = {
imageType = VK_IMAGE_TYPE_2D;
format = r16g16b16a16_sfloat;
samples = 1;
extent = {
width = $swapchain.extent.width;
height = $swapchain.extent.height;
depth = 1;
};
mipLevels = 1;
arrayLayers = 1;
tiling = optimal;
usage = color_attachment|input_attachment;
};
opaque = {
imageType = VK_IMAGE_TYPE_2D;
format = r8g8b8a8_unorm;
samples = 1;
extent = {
width = $swapchain.extent.width;
height = $swapchain.extent.height;
depth = 1;
};
mipLevels = 1;
arrayLayers = 1;
tiling = optimal;
usage = color_attachment|input_attachment;
};
translucent = {
imageType = VK_IMAGE_TYPE_2D;
format = r8g8b8a8_unorm;
samples = 1;
extent = {
width = $swapchain.extent.width;
height = $swapchain.extent.height;
depth = 1;
};
mipLevels = 1;
arrayLayers = 1;
tiling = optimal;
usage = color_attachment|input_attachment;
};
};
imageViews = {
depth = {
image = depth;
viewType = VK_IMAGE_VIEW_TYPE_2D;
format = $properties.images.depth.format;
components = {
r = identity;
g = identity;
b = identity;
a = identity;
};
subresourceRange = {
aspectMask = depth;
levelCount = 1;
layerCount = 1;
};
};
color = {
image = color;
viewType = VK_IMAGE_VIEW_TYPE_2D;
format = $properties.images.color.format;
components = {
r = identity;
g = identity;
b = identity;
a = identity;
};
subresourceRange = {
aspectMask = color;
levelCount = 1;
layerCount = 1;
};
};
normals = {
image = normals;
viewType = VK_IMAGE_VIEW_TYPE_2D;
format = $properties.images.normals.format;
components = {
r = identity;
g = identity;
b = identity;
a = identity;
};
subresourceRange = {
aspectMask = color;
levelCount = 1;
layerCount = 1;
};
};
opaque = {
image = opaque;
viewType = VK_IMAGE_VIEW_TYPE_2D;
format = $properties.images.opaque.format;
components = {
r = identity;
g = identity;
b = identity;
a = identity;
};
subresourceRange = {
aspectMask = color;
levelCount = 1;
layerCount = 1;
};
};
translucent = {
image = translucent;
viewType = VK_IMAGE_VIEW_TYPE_2D;
format = $properties.images.translucent.format;
components = {
r = identity;
g = identity;
b = identity;
a = identity;
};
subresourceRange = {
aspectMask = color;
levelCount = 1;
layerCount = 1;
};
};
};
framebuffer = {
renderPass = renderpass;
attachments = (depth, color, normals, opaque, translucent,
"$swapchain.views[$swapImageIndex]");
width = $swapchain.extent.width;
height = $swapchain.extent.height;
};
renderpass = {
attachments = (
{
format = $properties.images.depth.format;
samples = 1;
loadOp = dont_care;
storeOp = dont_care;
stencilLoadOp = dont_care;
stencilStoreOp = dont_care;
initialLayout = undefined;
finalLayout = depth_stencil_attachment_optimal;
},
{
format = $properties.images.color.format;
samples = 1;
loadOp = dont_care;
storeOp = dont_care;
stencilLoadOp = dont_care;
stencilStoreOp = dont_care;
initialLayout = undefined;
finalLayout = color_attachment_optimal;
},
{
format = $properties.images.normals.format;
samples = 1;
loadOp = dont_care;
storeOp = dont_care;
stencilLoadOp = dont_care;
stencilStoreOp = dont_care;
initialLayout = undefined;
finalLayout = color_attachment_optimal;
},
{
format = $properties.images.opaque.format;
samples = 1;
loadOp = dont_care;
storeOp = dont_care;
stencilLoadOp = dont_care;
stencilStoreOp = dont_care;
initialLayout = undefined;
finalLayout = color_attachment_optimal;
},
{
format = $properties.images.translucent.format;
samples = 1;
loadOp = dont_care;
storeOp = dont_care;
stencilLoadOp = dont_care;
stencilStoreOp = dont_care;
initialLayout = undefined;
finalLayout = color_attachment_optimal;
},
{
format = $swapchain.format;
samples = 1;
loadOp = clear;
storeOp = store;
stencilLoadOp = dont_care;
stencilStoreOp = dont_care;
initialLayout = undefined;
finalLayout = present_src_khr;
},
);
subpasses = (
{ // depth
pipelineBindPoint = graphics;
depthStencilAttachment = {
attachment = 0;
layout = depth_stencil_attachment_optimal;
};
},
{ // g-buffer generation
pipelineBindPoint = graphics;
colorAttachments = (
{ // color
attachment = 1;
layout = color_attachment_optimal;
},
{ // normals
attachment = 2;
layout = color_attachment_optimal;
},
);
depthStencilAttachment = {
attachment = 0;
layout = depth_stencil_attachment_optimal;
};
},
{ // lighting
pipelineBindPoint = graphics;
inputAttachments = (
{ // depth
attachment = 0;
layout = shader_read_only_optimal;
},
{ // color
attachment = 1;
layout = shader_read_only_optimal;
},
{ // normals
attachment = 2;
layout = shader_read_only_optimal;
},
);
colorAttachments = (
{ // opaque
attachment = 3;
layout = color_attachment_optimal;
},
);
},
{ // translucent
pipelineBindPoint = graphics;
colorAttachments = (
{ // translucent
attachment = 4;
layout = color_attachment_optimal;
},
);
},
{ // compose
pipelineBindPoint = graphics;
inputAttachments = (
{ // opaque
attachment = 3;
layout = shader_read_only_optimal;
},
{ // translucent
attachment = 4;
layout = shader_read_only_optimal;
},
);
colorAttachments = (
{ // swapchain
attachment = 5;
layout = color_attachment_optimal;
},
);
},
);
dependencies = (
{
srcSubpass = 0;
dstSubpass = 1;
srcStageMask = color_attachment_output;
dstStageMask = fragment_shader;
srcAccessMask = color_attachment_write;
dstAccessMask = shader_read;
dependencyFlags = by_region;
},
{
srcSubpass = 1;
dstSubpass = 2;
srcStageMask = color_attachment_output;
dstStageMask = fragment_shader;
srcAccessMask = color_attachment_write;
dstAccessMask = shader_read;
dependencyFlags = by_region;
},
{
srcSubpass = 2;
dstSubpass = 4;
srcStageMask = color_attachment_output;
dstStageMask = fragment_shader;
srcAccessMask = color_attachment_write;
dstAccessMask = shader_read;
dependencyFlags = by_region;
},
{
srcSubpass = 3;
dstSubpass = 4;
srcStageMask = color_attachment_output;
dstStageMask = fragment_shader;
srcAccessMask = color_attachment_write;
dstAccessMask = shader_read;
dependencyFlags = by_region;
},
);
};
}

View file

@ -273,7 +273,45 @@
};
};
pipelines = {
alias = {
alias_depth = {
stages = (
{
stage = vertex;
name = main;
module = $builtin/alias.vert;
},
);
vertexInput = {
bindings = (
"$properties.pipelines.alias_gbuf.vertexInput.bindings[0]",
"$properties.pipelines.alias_gbuf.vertexInput.bindings[1]",
);
attributes = (
"$properties.pipelines.alias_gbuf.vertexInput.attributes[0]",
"$properties.pipelines.alias_gbuf.vertexInput.attributes[1]",
"$properties.pipelines.alias_gbuf.vertexInput.attributes[2]",
"$properties.pipelines.alias_gbuf.vertexInput.attributes[3]",
);
};
inputAssembly = $properties.pipelines.alias_gbuf.inputAssembly;
viewport = $properties.pipelines.alias_gbuf.viewport;
rasterization = $properties.pipelines.alias_gbuf.rasterization;
multisample = $properties.pipelines.alias_gbuf.multisample;
depthStencil = {
depthTestEnable = true;
depthWriteEnable = true;
depthCompareOp = less_or_equal;
depthBoundsTestEnable = false;
stencilTestEnable = false;
};
colorBlend = $properties.pipelines.alias_gbuf.colorBlend;
dynamic = {
dynamicState = ( viewport, scissor );
};
layout = alias_layout;
//renderPass = renderpass;
};
alias_gbuf = {
stages = (
{
stage = vertex;
@ -404,7 +442,41 @@
layout = alias_layout;
//renderPass = renderpass;
};
quakebsp_main = {
bsp_depth = {
stages = (
{
stage = vertex;
name = main;
module = $builtin/quakebsp.vert;
},
);
vertexInput = {
bindings = (
"$properties.pipelines.bsp_gbuf.vertexInput.bindings[0]",
);
attributes = (
"$properties.pipelines.bsp_gbuf.vertexInput.attributes[0]",
);
};
inputAssembly = $properties.pipelines.bsp_main.inputAssembly;
viewport = $properties.pipelines.bsp_main.viewport;
rasterization = $properties.pipelines.bsp_main.rasterization;
multisample = $properties.pipelines.bsp_main.multisample;
depthStencil = {
depthTestEnable = true;
depthWriteEnable = true;
depthCompareOp = less_or_equal;
depthBoundsTestEnable = false;
stencilTestEnable = false;
};
colorBlend = $properties.pipelines.bsp_gbuf.colorBlend;
dynamic = {
dynamicState = ( viewport, scissor );
};
layout = quakebsp_layout;
//renderPass = renderpass;
};
bsp_gbuf = {
stages = (
{
stage = vertex;
@ -523,86 +595,15 @@
};
},
);
vertexInput = {
bindings = (
{
binding = 0;
stride = "2 * 4 * 4";
inputRate = vertex;
},
);
attributes = (
{
location = 0;
binding = 0;
format = r32g32b32a32_sfloat;
offset = 0;
},
{
location = 1;
binding = 0;
format = r32g32b32a32_sfloat;
offset = 16;
},
);
};
inputAssembly = {
topology = triangle_fan;
primitiveRestartEnable = true;
};
viewport = {
viewports = (
{
x = 0; y = 0;
width = 640; height = 480;
minDepth = 0; maxDepth = 1;
}
);
scissors = (
{
offset = { x = 0; y = 0 };
extent = { width = 640; height = 480; };
},
);
};
rasterization = {
depthClampEnable = false;
rasterizerDiscardEnable = false;
polygonMode = fill;
cullMode = back;
frontFace = clockwise;
depthBiasEnable = false;
lineWidth = 1;
};
multisample = {
rasterizationSamples = $msaaSamples;
sampleShadingEnable = false;
minSampleShading = 0.5f;
alphaToCoverageEnable = false;
alphaToOneEnable = false;
};
depthStencil = {
depthTestEnable = true;
depthWriteEnable = true;
depthCompareOp = less_or_equal;
depthBoundsTestEnable = false;
stencilTestEnable = false;
};
colorBlend = {
logicOpEnable = false;
attachments = ({
blendEnable = true;
srcColorBlendFactor = src_alpha;
dstColorBlendFactor = one_minus_src_alpha;
colorBlendOp = add;
srcAlphaBlendFactor = src_alpha;
dstAlphaBlendFactor = one_minus_src_alpha;
alphaBlendOp = add;
colorWriteMask = r|g|b|a;
});
};
vertexInput = $properties.pipelines.bsp_gbuf.vertexInput;
inputAssembly = $properties.pipelines.bsp_gbuf.inputAssembly;
viewport = $properties.pipelines.bsp_gbuf.viewport;
rasterization = $properties.pipelines.bsp_gbuf.rasterization;
multisample = $properties.pipelines.bsp_gbuf.multisample;
depthStencil = $properties.pipelines.bsp_gbuf.depthStencil;
colorBlend = $properties.pipelines.bsp_gbuf.colorBlend;
dynamic = {
dynamicState = ( viewport, scissor, blend_constants );
dynamicState = ( viewport, scissor );
};
layout = quakebsp_layout;
//renderPass = renderpass;

View file

@ -460,7 +460,8 @@ parse_VkDescriptorSetLayout (const plfield_t *field, const plitem_t *item,
ret = !cexpr_eval_string (name, &ectx);
if (ret) {
VkDescriptorSetLayout setLayout;
setLayout = QFV_ParseDescriptorSetLayout (ctx, setItem);
setLayout = QFV_ParseDescriptorSetLayout (ctx, setItem,
pctx->properties);
*handle = (VkDescriptorSetLayout) setLayout;
QFV_AddHandle (ctx->setLayouts, name, (uint64_t) setLayout);
@ -495,7 +496,7 @@ parse_VkPipelineLayout (const plitem_t *item, void **data,
ret = !cexpr_eval_string (name, &ectx);
if (ret) {
VkPipelineLayout layout;
layout = QFV_ParsePipelineLayout (ctx, setItem);
layout = QFV_ParsePipelineLayout (ctx, setItem, context->properties);
*handle = (VkPipelineLayout) layout;
QFV_AddHandle (ctx->pipelineLayouts, name, (uint64_t) layout);
@ -503,6 +504,92 @@ parse_VkPipelineLayout (const plitem_t *item, void **data,
return ret;
}
static int
parse_VkImage (const plitem_t *item, void **data, plitem_t *messages,
parsectx_t *context)
{
__auto_type handle = (VkImage *) data[0];
int ret = 1;
exprctx_t ectx = *context->ectx;
vulkan_ctx_t *ctx = context->vctx;
const char *name = PL_String (item);
Sys_Printf ("parse_VkImage: %s\n", name);
if (name[0] != '$') {
name = va (ctx->va_ctx, "$"QFV_PROPERTIES".images.%s", name);
}
*handle = (VkImage) QFV_GetHandle (ctx->images, name);
if (*handle) {
return 1;
}
plitem_t *imageItem = 0;
exprval_t result = { &cexpr_plitem, &imageItem };
ectx.symtab = 0;
ectx.result = &result;
ret = !cexpr_eval_string (name, &ectx);
if (ret) {
VkImage image;
image = QFV_ParseImage (ctx, imageItem, context->properties);
*handle = (VkImage) image;
QFV_AddHandle (ctx->images, name, (uint64_t) image);
}
return ret;
}
static exprtype_t imageview_type = {
"VkImageView",
sizeof (VkImageView),
0, 0, 0
};
static int
parse_VkImageView (const plfield_t *field, const plitem_t *item, void *data,
plitem_t *messages, void *_context)
{
parsectx_t *context = _context;
__auto_type handle = (VkImageView *) data;
int ret = 1;
exprctx_t ectx = *context->ectx;
vulkan_ctx_t *ctx = context->vctx;
const char *name = PL_String (item);
Sys_Printf ("parse_VkImageView: %s\n", name);
if (name[0] != '$') {
name = va (ctx->va_ctx, "$"QFV_PROPERTIES".imageViews.%s", name);
}
*handle = (VkImageView) QFV_GetHandle (ctx->imageViews, name);
if (*handle) {
return 1;
}
exprval_t *value = 0;
exprval_t result = { &cexpr_exprval, &value };
ectx.symtab = 0;
ectx.result = &result;
ret = !cexpr_eval_string (name, &ectx);
plitem_t *imageViewItem = 0;
if (ret) {
VkImageView imageView;
if (value->type == &imageview_type) {
imageView = *(VkImageView *) value->value;
} else if (value->type == &cexpr_plitem) {
imageView = QFV_ParseImageView (ctx, imageViewItem,
context->properties);
QFV_AddHandle (ctx->imageViews, name, (uint64_t) imageView);
} else {
PL_Message (messages, item, "not a VkImageView");
return 0;
}
*handle = (VkImageView) imageView;
}
return ret;
}
static const char *
handleref_getkey (const void *hr, void *unused)
{
@ -592,6 +679,36 @@ sampler_free (void *hr, void *_ctx)
handleref_free (handleref, ctx);
}
static void
image_free (void *hr, void *_ctx)
{
__auto_type handleref = (handleref_t *) hr;
__auto_type image = (VkImage) handleref->handle;
__auto_type ctx = (vulkan_ctx_t *) _ctx;
qfv_device_t *device = ctx->device;
qfv_devfuncs_t *dfunc = device->funcs;
if (image) {
dfunc->vkDestroyImage (device->dev, image, 0);
};
handleref_free (handleref, ctx);
}
static void
imageView_free (void *hr, void *_ctx)
{
__auto_type handleref = (handleref_t *) hr;
__auto_type imageView = (VkImageView) handleref->handle;
__auto_type ctx = (vulkan_ctx_t *) _ctx;
qfv_device_t *device = ctx->device;
qfv_devfuncs_t *dfunc = device->funcs;
if (imageView) {
dfunc->vkDestroyImageView (device->dev, imageView, 0);
};
handleref_free (handleref, ctx);
}
static hashtab_t *enum_symtab;
static int
@ -605,23 +722,71 @@ parse_BasePipeline (const plitem_t *item, void **data,
#include "libs/video/renderer/vulkan/vkparse.cinc"
static exprsym_t imageset_symbols[] = {
{"size", &cexpr_size_t, (void *)field_offset (qfv_imageset_t, size)},
static void
imageviewset_index (const exprval_t *a, size_t index, exprval_t *c,
exprctx_t *ctx)
{
__auto_type set = *(qfv_imageviewset_t **) a->value;
exprval_t *val = 0;
if (index >= set->size) {
cexpr_error (ctx, "invalid index: %zd", index);
} else {
val = cexpr_value (&imageview_type, ctx);
*(VkImageView *) val->value = set->a[index];
}
*(exprval_t **) c->value = val;
}
static void
imageviewset_int (const exprval_t *a, const exprval_t *b, exprval_t *c,
exprctx_t *ctx)
{
size_t index = *(int *) b->value;
imageviewset_index (a, index, c, ctx);
}
static void
imageviewset_uint (const exprval_t *a, const exprval_t *b, exprval_t *c,
exprctx_t *ctx)
{
size_t index = *(unsigned *) b->value;
imageviewset_index (a, index, c, ctx);
}
static void
imageviewset_size_t (const exprval_t *a, const exprval_t *b, exprval_t *c,
exprctx_t *ctx)
{
size_t index = *(size_t *) b->value;
imageviewset_index (a, index, c, ctx);
}
binop_t imageviewset_binops[] = {
{ '.', &cexpr_field, &cexpr_exprval, cexpr_struct_pointer_getfield },
{ '[', &cexpr_int, &imageview_type, imageviewset_int },
{ '[', &cexpr_uint, &imageview_type, imageviewset_uint },
{ '[', &cexpr_size_t, &imageview_type, imageviewset_size_t },
{}
};
static exprsym_t imageviewset_symbols[] = {
{"size", &cexpr_size_t, (void *)field_offset (qfv_imageviewset_t, size)},
{ }
};
static exprtab_t imageset_symtab = {
imageset_symbols,
static exprtab_t imageviewset_symtab = {
imageviewset_symbols,
};
exprtype_t imageset_type = {
"imageset",
sizeof (qfv_imageset_t *),
cexpr_struct_pointer_binops,
exprtype_t imageviewset_type = {
"imageviewset",
sizeof (qfv_imageviewset_t *),
imageviewset_binops,
0,
&imageset_symtab,
&imageviewset_symtab,
};
static exprsym_t qfv_swapchain_t_symbols[] = {
{"format", &VkFormat_type, (void *)field_offset (qfv_swapchain_t, format)},
{"images", &imageset_type, (void *)field_offset (qfv_swapchain_t, images)},
{"extent", &VkExtent2D_type, (void *)field_offset (qfv_swapchain_t, extent)},
{"views", &imageviewset_type, (void *)field_offset (qfv_swapchain_t, imageViews)},
{ }
};
static exprtab_t qfv_swapchain_t_symtab = {
@ -714,7 +879,7 @@ QFV_InitParse (vulkan_ctx_t *ctx)
vkgen_init_symtabs (&context);
cexpr_init_symtab (&qfv_swapchain_t_symtab, &context);
cexpr_init_symtab (&vulkan_frameset_t_symtab, &context);
cexpr_init_symtab (&imageset_symtab, &context);
cexpr_init_symtab (&imageviewset_symtab, &context);
if (!ctx->setLayouts) {
ctx->shaderModules = handlref_symtab (shaderModule_free, ctx);
@ -722,6 +887,8 @@ QFV_InitParse (vulkan_ctx_t *ctx)
ctx->pipelineLayouts = handlref_symtab (pipelineLayout_free, ctx);
ctx->descriptorPools = handlref_symtab (descriptorPool_free, ctx);
ctx->samplers = handlref_symtab (sampler_free, ctx);
ctx->images = handlref_symtab (image_free, ctx);
ctx->imageViews = handlref_symtab (imageView_free, ctx);
}
}
@ -733,16 +900,17 @@ QFV_GetEnum (const char *name)
static int
parse_object (vulkan_ctx_t *ctx, plitem_t *plist,
plparser_t parser, void *object)
plparser_t parser, void *object, plitem_t *properties)
{
plitem_t *messages = PL_NewArray ();
exprctx_t exprctx = {};
parsectx_t parsectx = { &exprctx, ctx };
parsectx_t parsectx = { &exprctx, ctx, properties };
exprsym_t var_syms[] = {
{"swapchain", &qfv_swapchain_t_type, ctx->swapchain},
{"frames", &vulkan_frameset_t_type, &ctx->frames},
{"msaaSamples", &VkSampleCountFlagBits_type, &ctx->msaaSamples},
{QFV_PROPERTIES, &cexpr_plitem, &ctx->pipelineDef},
{"swapImageIndex", &cexpr_uint, &ctx->swapImageIndex},
{QFV_PROPERTIES, &cexpr_plitem, &parsectx.properties},
{}
};
exprtab_t vars_tab = { var_syms, 0 };
@ -775,13 +943,14 @@ parse_qfv_renderpass (const plfield_t *field, const plitem_t *item, void *data,
}
VkRenderPass
QFV_ParseRenderPass (vulkan_ctx_t *ctx, plitem_t *plist)
QFV_ParseRenderPass (vulkan_ctx_t *ctx, plitem_t *plist, plitem_t *properties)
{
qfv_device_t *device = ctx->device;
qfv_renderpass_t renderpass_data = {};
if (!parse_object (ctx, plist, parse_qfv_renderpass, &renderpass_data)) {
if (!parse_object (ctx, plist, parse_qfv_renderpass, &renderpass_data,
properties)) {
return 0;
}
@ -805,7 +974,7 @@ QFV_ParseRenderPass (vulkan_ctx_t *ctx, plitem_t *plist)
}
VkPipeline
QFV_ParsePipeline (vulkan_ctx_t *ctx, plitem_t *plist)
QFV_ParsePipeline (vulkan_ctx_t *ctx, plitem_t *plist, plitem_t *properties)
{
qfv_device_t *device = ctx->device;
@ -813,11 +982,11 @@ QFV_ParsePipeline (vulkan_ctx_t *ctx, plitem_t *plist)
memset (&cInfo->a[0], 0, sizeof (cInfo->a[0]));
if (!parse_object (ctx, plist, parse_VkGraphicsPipelineCreateInfo,
&cInfo->a[0])) {
&cInfo->a[0], properties)) {
return 0;
}
cInfo->a[0].renderPass = ctx->renderpass.renderpass;
cInfo->a[0].renderPass = ctx->renderpass;
__auto_type plSet = QFV_CreateGraphicsPipelines (device, 0, cInfo);
VkPipeline pipeline = plSet->a[0];
free (plSet);
@ -825,14 +994,16 @@ QFV_ParsePipeline (vulkan_ctx_t *ctx, plitem_t *plist)
}
VkDescriptorPool
QFV_ParseDescriptorPool (vulkan_ctx_t *ctx, plitem_t *plist)
QFV_ParseDescriptorPool (vulkan_ctx_t *ctx, plitem_t *plist,
plitem_t *properties)
{
qfv_device_t *device = ctx->device;
qfv_devfuncs_t *dfunc = device->funcs;
VkDescriptorPoolCreateInfo cInfo = {};
if (!parse_object (ctx, plist, parse_VkDescriptorPoolCreateInfo, &cInfo)) {
if (!parse_object (ctx, plist, parse_VkDescriptorPoolCreateInfo, &cInfo,
properties)) {
return 0;
}
@ -843,7 +1014,8 @@ QFV_ParseDescriptorPool (vulkan_ctx_t *ctx, plitem_t *plist)
}
VkDescriptorSetLayout
QFV_ParseDescriptorSetLayout (vulkan_ctx_t *ctx, plitem_t *plist)
QFV_ParseDescriptorSetLayout (vulkan_ctx_t *ctx, plitem_t *plist,
plitem_t *properties)
{
qfv_device_t *device = ctx->device;
qfv_devfuncs_t *dfunc = device->funcs;
@ -851,7 +1023,7 @@ QFV_ParseDescriptorSetLayout (vulkan_ctx_t *ctx, plitem_t *plist)
VkDescriptorSetLayoutCreateInfo cInfo = {};
if (!parse_object (ctx, plist, parse_VkDescriptorSetLayoutCreateInfo,
&cInfo)) {
&cInfo, properties)) {
return 0;
}
@ -862,7 +1034,8 @@ QFV_ParseDescriptorSetLayout (vulkan_ctx_t *ctx, plitem_t *plist)
}
VkPipelineLayout
QFV_ParsePipelineLayout (vulkan_ctx_t *ctx, plitem_t *plist)
QFV_ParsePipelineLayout (vulkan_ctx_t *ctx, plitem_t *plist,
plitem_t *properties)
{
qfv_device_t *device = ctx->device;
qfv_devfuncs_t *dfunc = device->funcs;
@ -870,7 +1043,7 @@ QFV_ParsePipelineLayout (vulkan_ctx_t *ctx, plitem_t *plist)
VkPipelineLayoutCreateInfo cInfo = {};
if (!parse_object (ctx, plist, parse_VkPipelineLayoutCreateInfo,
&cInfo)) {
&cInfo, properties)) {
return 0;
}
@ -881,14 +1054,15 @@ QFV_ParsePipelineLayout (vulkan_ctx_t *ctx, plitem_t *plist)
}
VkSampler
QFV_ParseSampler (vulkan_ctx_t *ctx, plitem_t *plist)
QFV_ParseSampler (vulkan_ctx_t *ctx, plitem_t *plist, plitem_t *properties)
{
qfv_device_t *device = ctx->device;
qfv_devfuncs_t *dfunc = device->funcs;
VkSamplerCreateInfo cInfo = {};
if (!parse_object (ctx, plist, parse_VkSamplerCreateInfo, &cInfo)) {
if (!parse_object (ctx, plist, parse_VkSamplerCreateInfo, &cInfo,
properties)) {
return 0;
}
@ -897,3 +1071,195 @@ QFV_ParseSampler (vulkan_ctx_t *ctx, plitem_t *plist)
return sampler;
}
VkImage
QFV_ParseImage (vulkan_ctx_t *ctx, plitem_t *plist, plitem_t *properties)
{
qfv_device_t *device = ctx->device;
qfv_devfuncs_t *dfunc = device->funcs;
VkImageCreateInfo cInfo = {};
if (!parse_object (ctx, plist, parse_VkImageCreateInfo, &cInfo,
properties)) {
return 0;
}
VkImage image;
dfunc->vkCreateImage (device->dev, &cInfo, 0, &image);
return image;
}
VkImageView
QFV_ParseImageView (vulkan_ctx_t *ctx, plitem_t *plist, plitem_t *properties)
{
qfv_device_t *device = ctx->device;
qfv_devfuncs_t *dfunc = device->funcs;
VkImageViewCreateInfo cInfo = {};
if (!parse_object (ctx, plist, parse_VkImageViewCreateInfo, &cInfo,
properties)) {
return 0;
}
VkImageView imageView;
dfunc->vkCreateImageView (device->dev, &cInfo, 0, &imageView);
return imageView;
}
typedef struct {
uint32_t count;
VkImageCreateInfo *info;
} imagecreate_t;
typedef struct {
uint32_t count;
VkImageViewCreateInfo *info;
} imageviewcreate_t;
static plelement_t qfv_imagecreate_dict = {
QFDictionary,
sizeof (VkImageCreateInfo),
array_alloc,
parse_VkImageCreateInfo,
};
static plelement_t qfv_imageviewcreate_dict = {
QFDictionary,
sizeof (VkImageViewCreateInfo),
array_alloc,
parse_VkImageViewCreateInfo,
};
static int
parse_imagecreate_dict (const plfield_t *field, const plitem_t *item,
void *data, plitem_t *messages, void *context)
{
plfield_t f = { "images", 0, QFArray, parse_array,
&qfv_imagecreate_dict };
typedef struct arr_s DARRAY_TYPE(byte) arr_t;
arr_t *arr = 0;
int ret;
if ((ret = PL_ParseLabeledArray (&f, item, &arr, messages, context))) {
imagecreate_t *imagecreate = data;
imagecreate->count = arr->size;
imagecreate->info = (VkImageCreateInfo *) arr->a;
} else {
//FIXME leaky boat when succeeds
if (arr) {
free (arr);
}
}
return ret;
}
static int
parse_imageviewcreate_dict (const plfield_t *field, const plitem_t *item,
void *data, plitem_t *messages, void *context)
{
plfield_t f = { "images", 0, QFArray, parse_array,
&qfv_imageviewcreate_dict };
typedef struct arr_s DARRAY_TYPE(byte) arr_t;
arr_t *arr = 0;
int ret;
if ((ret = PL_ParseLabeledArray (&f, item, &arr, messages, context))) {
imageviewcreate_t *imageviewcreate = data;
imageviewcreate->count = arr->size;
imageviewcreate->info = (VkImageViewCreateInfo *) arr->a;
} else {
//FIXME leaky boat when succeeds
if (arr) {
free (arr);
}
}
return ret;
}
qfv_imageset_t *
QFV_ParseImageSet (vulkan_ctx_t *ctx, plitem_t *item, plitem_t *properties)
{
qfv_device_t *device = ctx->device;
qfv_devfuncs_t *dfunc = device->funcs;
imagecreate_t create = {};
pltype_t type = PL_Type (item);
if (type == QFDictionary) {
if (!parse_object (ctx, item, parse_imagecreate_dict, &create,
properties)) {
return 0;
}
} else {
Sys_Printf ("Neither array nor dictionary: %d\n", PL_Line (item));
return 0;
}
__auto_type set = QFV_AllocImages (create.count, malloc);
for (uint32_t i = 0; i < create.count; i++) {
dfunc->vkCreateImage (device->dev, &create.info[i], 0, &set->a[i]);
const char *name = PL_KeyAtIndex (item, i);
name = va (ctx->va_ctx, "$"QFV_PROPERTIES".images.%s", name);
QFV_AddHandle (ctx->images, name, (uint64_t) set->a[i]);
}
return set;
}
qfv_imageviewset_t *
QFV_ParseImageViewSet (vulkan_ctx_t *ctx, plitem_t *item,
plitem_t *properties)
{
qfv_device_t *device = ctx->device;
qfv_devfuncs_t *dfunc = device->funcs;
imageviewcreate_t create = {};
pltype_t type = PL_Type (item);
if (type == QFDictionary) {
if (!parse_object (ctx, item, parse_imageviewcreate_dict, &create,
properties)) {
return 0;
}
} else {
Sys_Printf ("Neither array nor dictionary: %d\n", PL_Line (item));
return 0;
}
__auto_type set = QFV_AllocImageViews (create.count, malloc);
for (uint32_t i = 0; i < create.count; i++) {
dfunc->vkCreateImageView (device->dev, &create.info[i], 0, &set->a[i]);
const char *name = PL_KeyAtIndex (item, i);
name = va (ctx->va_ctx, "$"QFV_PROPERTIES".imageViews.%s", name);
QFV_AddHandle (ctx->imageViews, name, (uint64_t) set->a[i]);
}
return set;
}
VkFramebuffer
QFV_ParseFramebuffer (vulkan_ctx_t *ctx, plitem_t *plist, plitem_t *properties)
{
qfv_device_t *device = ctx->device;
qfv_devfuncs_t *dfunc = device->funcs;
VkFramebufferCreateInfo cInfo = {};
if (!parse_object (ctx, plist, parse_VkFramebufferCreateInfo, &cInfo,
properties)) {
return 0;
}
VkFramebuffer framebuffer;
dfunc->vkCreateFramebuffer (device->dev, &cInfo, 0, &framebuffer);
return framebuffer;
}

View file

@ -4,6 +4,8 @@
typedef struct parsectx_s {
struct exprctx_s *ectx;
struct vulkan_ctx_s *vctx;
struct plitem_s *properties;
void *data;
} parsectx_t;
#include "QF/cexpr.h"
@ -32,12 +34,29 @@ exprenum_t *QFV_GetEnum (const char *name);
uint64_t QFV_GetHandle (struct hashtab_s *tab, const char *name);
void QFV_AddHandle (struct hashtab_s *tab, const char *name, uint64_t handle);
VkRenderPass QFV_ParseRenderPass (vulkan_ctx_t *ctx, plitem_t *plist);
VkPipeline QFV_ParsePipeline (vulkan_ctx_t *ctx, plitem_t *plist);
VkDescriptorPool QFV_ParseDescriptorPool (vulkan_ctx_t *ctx, plitem_t *plist);
VkRenderPass QFV_ParseRenderPass (vulkan_ctx_t *ctx, plitem_t *plist,
plitem_t *properties);
VkPipeline QFV_ParsePipeline (vulkan_ctx_t *ctx, plitem_t *plist,
plitem_t *properties);
VkDescriptorPool QFV_ParseDescriptorPool (vulkan_ctx_t *ctx, plitem_t *plist,
plitem_t *properties);
VkDescriptorSetLayout QFV_ParseDescriptorSetLayout (vulkan_ctx_t *ctx,
plitem_t *plist);
VkPipelineLayout QFV_ParsePipelineLayout (vulkan_ctx_t *ctx, plitem_t *plist);
VkSampler QFV_ParseSampler (vulkan_ctx_t *ctx, plitem_t *plist);
plitem_t *plist,
plitem_t *properties);
VkPipelineLayout QFV_ParsePipelineLayout (vulkan_ctx_t *ctx, plitem_t *plist,
plitem_t *properties);
VkSampler QFV_ParseSampler (vulkan_ctx_t *ctx, plitem_t *plist,
plitem_t *properties);
VkImage QFV_ParseImage (vulkan_ctx_t *ctx, plitem_t *plist,
plitem_t *properties);
VkImageView QFV_ParseImageView (vulkan_ctx_t *ctx, plitem_t *plist,
plitem_t *properties);
struct qfv_imageset_s *QFV_ParseImageSet (vulkan_ctx_t *ctx, plitem_t *plist,
plitem_t *properties);
struct qfv_imageviewset_s *QFV_ParseImageViewSet (vulkan_ctx_t *ctx,
plitem_t *plist,
plitem_t *properties);
VkFramebuffer QFV_ParseFramebuffer (vulkan_ctx_t *ctx, plitem_t *plist,
plitem_t *properties);
#endif//__vkparse_h

View file

@ -20,6 +20,9 @@
VkGraphicsPipelineCreateInfo,
VkDescriptorPoolCreateInfo,
VkSamplerCreateInfo,
VkImageCreateInfo,
VkImageViewCreateInfo,
VkFramebufferCreateInfo,
);
parse = {
VkSubpassDescription = {
@ -282,6 +285,48 @@
fields = (basePipelineHandle);
};
basePipelineIndex = auto;
};
VkImageCreateInfo = {
flags = auto;
imageType = auto;
format = auto;
extent = auto;
mipLevels = auto;
arrayLayers = auto;
samples = auto;
tiling = auto;
usage = auto;
sharingMode = skip; // FIXME for now
queueFamilyIndexCount = skip; // FIXME for now
pQueueFamilyIndices = skip; // FIXME for now
initialLayout = auto;
};
VkImageViewCreateInfo = {
flags = auto;
image = {
type = (custom, (QFDictionary, QFString),
parse_VkImage);
fields = (image);
};
viewType = auto;
format = auto;
components = auto;
subresourceRange = auto;
};
VkFramebufferCreateInfo = {
//flags = auto; reserved for future use (Bits enum does not exist)
renderPass = {
type = (custom, QFString, parse_VkShaderModule);
fields = (renderPass);
};
attachments = {
type = (array, VkImageView);
size = attachmentCount;
values = pAttachments;
};
width = auto;
height = auto;
layers = auto;
}
}
}

View file

@ -64,16 +64,65 @@
#include "r_internal.h"
#include "vid_vulkan.h"
void
Vulkan_DrawAlias (entity_t *ent, struct vulkan_ctx_s *ctx)
static const char *alias_pass_names[] = {
"depth",
"g-buffer",
"translucent",
};
static void
emit_commands (VkCommandBuffer cmd, int pose1, int pose2,
qfv_alias_skin_t *skin,
void *vert_constants, int vert_size,
void *frag_constants, int frag_size,
aliashdr_t *hdr, vulkan_ctx_t *ctx)
{
qfv_device_t *device = ctx->device;
qfv_devfuncs_t *dfunc = device->funcs;
aliasctx_t *actx = ctx->alias_context;
aliasframe_t *aframe = &actx->frames.a[ctx->curFrame];
__auto_type mesh = (qfv_alias_mesh_t *) ((byte *) hdr + hdr->commands);
VkDeviceSize offsets[] = {
pose1 * hdr->poseverts * sizeof (aliasvrt_t),
pose2 * hdr->poseverts * sizeof (aliasvrt_t),
0,
};
VkBuffer buffers[] = {
mesh->vertex_buffer,
mesh->vertex_buffer,
mesh->uv_buffer,
};
int bindingCount = skin ? 3 : 2;
dfunc->vkCmdBindVertexBuffers (cmd, 0, bindingCount, buffers, offsets);
dfunc->vkCmdBindIndexBuffer (cmd, mesh->index_buffer, 0,
VK_INDEX_TYPE_UINT32);
dfunc->vkCmdPushConstants (cmd, actx->layout, VK_SHADER_STAGE_VERTEX_BIT,
0, vert_size, vert_constants);
if (skin) {
dfunc->vkCmdPushConstants (cmd, actx->layout,
VK_SHADER_STAGE_FRAGMENT_BIT,
68, frag_size, frag_constants);
aframe->imageInfo[0].imageView = skin->view;
dfunc->vkCmdPushDescriptorSetKHR (cmd,
VK_PIPELINE_BIND_POINT_GRAPHICS,
actx->layout,
0, ALIAS_IMAGE_INFOS,
aframe->descriptors
+ ALIAS_BUFFER_INFOS);
}
dfunc->vkCmdDrawIndexed (cmd, 3 * hdr->mdl.numtris, 1, 0, 0, 0);
}
void
Vulkan_DrawAlias (entity_t *ent, vulkan_ctx_t *ctx)
{
aliasctx_t *actx = ctx->alias_context;
aliasframe_t *aframe = &actx->frames.a[ctx->curFrame];
model_t *model = ent->model;
aliashdr_t *hdr;
qfv_alias_mesh_t *mesh;
qfv_alias_skin_t *skin;
float vertex_constants[17];
byte fragment_constants[3][4];
@ -81,7 +130,6 @@ Vulkan_DrawAlias (entity_t *ent, struct vulkan_ctx_s *ctx)
if (!(hdr = model->aliashdr)) {
hdr = Cache_Get (&model->cache);
}
mesh = (qfv_alias_mesh_t *) ((byte *) hdr + hdr->commands);
memcpy (vertex_constants, ent->transform, sizeof (ent->transform));
vertex_constants[16] = R_AliasGetLerpedFrames (ent, hdr);
@ -97,90 +145,26 @@ Vulkan_DrawAlias (entity_t *ent, struct vulkan_ctx_s *ctx)
QuatCopy (skin->colora, fragment_constants[1]);
QuatCopy (skin->colorb, fragment_constants[2]);
VkDeviceSize offsets[] = {
ent->pose1 * hdr->poseverts * sizeof (aliasvrt_t),
ent->pose2 * hdr->poseverts * sizeof (aliasvrt_t),
0,
};
VkBuffer buffers[] = {
mesh->vertex_buffer,
mesh->vertex_buffer,
mesh->uv_buffer,
};
dfunc->vkCmdBindVertexBuffers (aframe->cmd, 0, 3, buffers, offsets);
dfunc->vkCmdBindIndexBuffer (aframe->cmd, mesh->index_buffer, 0,
VK_INDEX_TYPE_UINT32);
dfunc->vkCmdPushConstants (aframe->cmd, actx->layout,
VK_SHADER_STAGE_VERTEX_BIT,
0, sizeof (vertex_constants), vertex_constants);
dfunc->vkCmdPushConstants (aframe->cmd, actx->layout,
VK_SHADER_STAGE_FRAGMENT_BIT,
68, sizeof (fragment_constants),
fragment_constants);
aframe->imageInfo[0].imageView = skin->view;
dfunc->vkCmdPushDescriptorSetKHR (aframe->cmd,
VK_PIPELINE_BIND_POINT_GRAPHICS,
actx->layout,
0, ALIAS_IMAGE_INFOS,
aframe->descriptors
+ ALIAS_BUFFER_INFOS);
dfunc->vkCmdDrawIndexed (aframe->cmd, 3 * hdr->mdl.numtris, 1, 0, 0, 0);
emit_commands (aframe->cmdSet.a[QFV_aliasDepth], ent->pose1, ent->pose2,
0, vertex_constants, sizeof (vertex_constants),
fragment_constants, sizeof (fragment_constants),
hdr, ctx);
}
static void
calc_lighting (qfv_light_t *light, entity_t *ent)
{
vec3_t ambient_color;
//FIXME should be ent->position
float l = R_LightPoint (&r_worldentity.model->brush, r_origin) / 128.0;
//XXX l = max (light, max (ent->model->min_light, ent->min_light));
light->type = 2;
VectorSet (1, 1, 1, ambient_color); //FIXME
// position doubles as ambient light
VectorScale (ambient_color, l, light->position);
VectorSet (-1, 0, 0, light->direction); //FIXME
VectorCopy (light->position, light->color);
}
void
Vulkan_AliasBegin (vulkan_ctx_t *ctx)
alias_begin_subpass (VkCommandBuffer cmd, VkPipeline pipeline,
vulkan_ctx_t *ctx)
{
qfv_device_t *device = ctx->device;
qfv_devfuncs_t *dfunc = device->funcs;
aliasctx_t *actx = ctx->alias_context;
dlight_t *lights[ALIAS_LIGHTS];
//XXX quat_t fog;
__auto_type cframe = &ctx->frames.a[ctx->curFrame];
aliasframe_t *aframe = &actx->frames.a[ctx->curFrame];
VkCommandBuffer cmd = aframe->cmd;
DARRAY_APPEND (cframe->subCommand, cmd);
//FIXME ambient needs to be per entity
aframe->lights->light_count = 1;
calc_lighting (&aframe->lights->lights[0], 0);
R_FindNearLights (r_origin, ALIAS_LIGHTS - 1, lights);
for (int i = 0; i < ALIAS_LIGHTS - 1; i++) {
if (!lights[i]) {
break;
}
aframe->lights->light_count++;
VectorCopy (lights[i]->color, aframe->lights->lights[i + 1].color);
VectorCopy (lights[i]->origin, aframe->lights->lights[i + 1].position);
aframe->lights->lights[i + 1].dist = lights[i]->radius;
aframe->lights->lights[i + 1].type = 0;
}
//FIXME need per frame matrices
aframe->bufferInfo[0].buffer = ctx->matrices.buffer_3d;
aframe->bufferInfo[1].buffer = aframe->light_buffer;
dfunc->vkResetCommandBuffer (cmd, 0);
VkCommandBufferInheritanceInfo inherit = {
VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_INFO, 0,
ctx->renderpass.renderpass, 0,
ctx->renderpass, 0,
cframe->framebuffer,
0, 0, 0,
};
@ -192,7 +176,7 @@ Vulkan_AliasBegin (vulkan_ctx_t *ctx)
dfunc->vkBeginCommandBuffer (cmd, &beginInfo);
dfunc->vkCmdBindPipeline (cmd, VK_PIPELINE_BIND_POINT_GRAPHICS,
actx->pipeline);
pipeline);
//VkDescriptorSet sets[] = {
// aframe->descriptors[0].dstSet,
// aframe->descriptors[1].dstSet,
@ -213,15 +197,43 @@ Vulkan_AliasBegin (vulkan_ctx_t *ctx)
//XXX fog[3] = glsl_Fog_GetDensity () / 64.0;
}
void
Vulkan_AliasEnd (vulkan_ctx_t *ctx)
static void
alias_end_subpass (VkCommandBuffer cmd, vulkan_ctx_t *ctx)
{
qfv_device_t *device = ctx->device;
qfv_devfuncs_t *dfunc = device->funcs;
aliasctx_t *actx = ctx->alias_context;
dfunc->vkEndCommandBuffer (cmd);
}
void
Vulkan_AliasBegin (vulkan_ctx_t *ctx)
{
aliasctx_t *actx = ctx->alias_context;
__auto_type cframe = &ctx->frames.a[ctx->curFrame];
aliasframe_t *aframe = &actx->frames.a[ctx->curFrame];
dfunc->vkEndCommandBuffer (aframe->cmd);
//XXX quat_t fog;
DARRAY_APPEND (&cframe->cmdSets[QFV_passDepth],
aframe->cmdSet.a[QFV_aliasDepth]);
DARRAY_APPEND (&cframe->cmdSets[QFV_passGBuffer],
aframe->cmdSet.a[QFV_aliasGBuffer]);
//FIXME need per frame matrices
aframe->bufferInfo[0].buffer = ctx->matrices.buffer_3d;
alias_begin_subpass (aframe->cmdSet.a[QFV_aliasDepth], actx->depth, ctx);
alias_begin_subpass (aframe->cmdSet.a[QFV_aliasGBuffer], actx->gbuf, ctx);
}
void
Vulkan_AliasEnd (vulkan_ctx_t *ctx)
{
aliasctx_t *actx = ctx->alias_context;
aliasframe_t *aframe = &actx->frames.a[ctx->curFrame];
alias_end_subpass (aframe->cmdSet.a[QFV_aliasDepth], ctx);
alias_end_subpass (aframe->cmdSet.a[QFV_aliasGBuffer], ctx);
}
static VkDescriptorBufferInfo base_buffer_info = {
@ -247,7 +259,6 @@ void
Vulkan_Alias_Init (vulkan_ctx_t *ctx)
{
qfv_device_t *device = ctx->device;
qfv_devfuncs_t *dfunc = device->funcs;
aliasctx_t *actx = calloc (1, sizeof (aliasctx_t));
ctx->alias_context = actx;
@ -257,7 +268,8 @@ Vulkan_Alias_Init (vulkan_ctx_t *ctx)
DARRAY_RESIZE (&actx->frames, frames);
actx->frames.grow = 0;
actx->pipeline = Vulkan_CreatePipeline (ctx, "alias");
actx->depth = Vulkan_CreatePipeline (ctx, "alias_depth");
actx->gbuf = Vulkan_CreatePipeline (ctx, "alias_gbuf");
actx->layout = Vulkan_CreatePipelineLayout (ctx, "alias_layout");
actx->sampler = Vulkan_CreateSampler (ctx, "alias_sampler");
@ -276,43 +288,22 @@ Vulkan_Alias_Init (vulkan_ctx_t *ctx)
}*/
//__auto_type pool = QFV_GetDescriptorPool (ctx, "alias.pool");
__auto_type cmdBuffers = QFV_AllocCommandBufferSet (frames, alloca);
QFV_AllocateCommandBuffers (device, ctx->cmdpool, 1, cmdBuffers);
__auto_type lbuffers = QFV_AllocBufferSet (frames, alloca);
for (size_t i = 0; i < frames; i++) {
lbuffers->a[i] = QFV_CreateBuffer (device, sizeof (qfv_light_buffer_t),
VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT);
QFV_duSetObjectName (device, VK_OBJECT_TYPE_BUFFER,
lbuffers->a[i],
va (ctx->va_ctx, "buffer:alias:%s:%zd",
"lights", i));
}
VkMemoryRequirements requirements;
dfunc->vkGetBufferMemoryRequirements (device->dev, lbuffers->a[0],
&requirements);
actx->light_memory = QFV_AllocBufferMemory (device, lbuffers->a[0],
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT,
frames * requirements.size, 0);
QFV_duSetObjectName (device, VK_OBJECT_TYPE_DEVICE_MEMORY,
actx->light_memory, va (ctx->va_ctx,
"memory:alias:%s", "lights"));
byte *light_data;
dfunc->vkMapMemory (device->dev, actx->light_memory, 0,
frames * requirements.size, 0, (void **) &light_data);
//__auto_type sets = QFV_AllocateDescriptorSet (device, pool, layouts);
for (size_t i = 0; i < frames; i++) {
__auto_type aframe = &actx->frames.a[i];
aframe->cmd = cmdBuffers->a[i];
QFV_duSetObjectName (device, VK_OBJECT_TYPE_COMMAND_BUFFER,
aframe->cmd,
va (ctx->va_ctx, "cmd:alias:%zd", i));
aframe->light_buffer = lbuffers->a[i];
aframe->lights = (qfv_light_buffer_t *) (light_data + i * requirements.size);
QFV_BindBufferMemory (device, lbuffers->a[i], actx->light_memory,
i * requirements.size);
DARRAY_INIT (&aframe->cmdSet, QFV_aliasNumPasses);
DARRAY_RESIZE (&aframe->cmdSet, QFV_aliasNumPasses);
aframe->cmdSet.grow = 0;
QFV_AllocateCommandBuffers (device, ctx->cmdpool, 1, &aframe->cmdSet);
for (int j = 0; j < QFV_aliasNumPasses; j++) {
QFV_duSetObjectName (device, VK_OBJECT_TYPE_COMMAND_BUFFER,
aframe->cmdSet.a[j],
va (ctx->va_ctx, "cmd:alias:%zd:%s", i,
alias_pass_names[j]));
}
for (int j = 0; j < ALIAS_BUFFER_INFOS; j++) {
aframe->bufferInfo[j] = base_buffer_info;
aframe->descriptors[j] = base_buffer_write;
@ -333,7 +324,7 @@ Vulkan_Alias_Init (vulkan_ctx_t *ctx)
}
void
Vulkan_Alias_Shutdown (struct vulkan_ctx_s *ctx)
Vulkan_Alias_Shutdown (vulkan_ctx_t *ctx)
{
qfv_device_t *device = ctx->device;
qfv_devfuncs_t *dfunc = device->funcs;
@ -341,11 +332,11 @@ Vulkan_Alias_Shutdown (struct vulkan_ctx_s *ctx)
for (size_t i = 0; i < actx->frames.size; i++) {
__auto_type aframe = &actx->frames.a[i];
dfunc->vkDestroyBuffer (device->dev, aframe->light_buffer, 0);
free (aframe->cmdSet.a);
}
dfunc->vkFreeMemory (device->dev, actx->light_memory, 0);
dfunc->vkDestroyPipeline (device->dev, actx->pipeline, 0);
DARRAY_CLEAR (&actx->frames);
dfunc->vkDestroyPipeline (device->dev, actx->depth, 0);
dfunc->vkDestroyPipeline (device->dev, actx->gbuf, 0);
free (actx->frames.a);
free (actx);
}

View file

@ -69,6 +69,12 @@
#include "r_internal.h"
#include "vid_vulkan.h"
static const char *bsp_pass_names[] = {
"depth",
"g-buffer",
"translucent",
};
static float identity[] = {
1, 0, 0, 0,
0, 1, 0, 0,
@ -779,33 +785,44 @@ bind_view (qfv_bsp_tex tex, VkImageView view, bspframe_t *bframe,
+ BSP_BUFFER_INFOS);
}
static void
push_transform (vec_t *transform, VkPipelineLayout layout,
qfv_devfuncs_t *dfunc, VkCommandBuffer cmd)
{
dfunc->vkCmdPushConstants (cmd, layout, VK_SHADER_STAGE_VERTEX_BIT,
0, 16 * sizeof (float), transform);
}
static void
push_fragconst (fragconst_t *fragconst, VkPipelineLayout layout,
qfv_devfuncs_t *dfunc, VkCommandBuffer cmd)
{
dfunc->vkCmdPushConstants (cmd, layout, VK_SHADER_STAGE_FRAGMENT_BIT,
0, sizeof (fragconst_t), fragconst);
}
static void
push_descriptors (int count, VkWriteDescriptorSet *descriptors,
VkPipelineLayout layout, qfv_devfuncs_t *dfunc,
VkCommandBuffer cmd)
{
dfunc->vkCmdPushDescriptorSetKHR (cmd, VK_PIPELINE_BIND_POINT_GRAPHICS,
layout, 0, count, descriptors);
}
static void
draw_elechain (elechain_t *ec, VkPipelineLayout layout, qfv_devfuncs_t *dfunc,
VkCommandBuffer cmd)
{
elements_t *el;
/*if (colloc >= 0) {
float *color;
color = ec->color;
if (!color)
color = bctx->default_color;
if (!QuatCompare (color, bctx->last_color)) {
QuatCopy (color, bctx->last_color);
qfeglVertexAttrib4fv (quake_bsp.color.location, color);
}
}*/
if (ec->transform) {
dfunc->vkCmdPushConstants (cmd, layout, VK_SHADER_STAGE_VERTEX_BIT,
0, 16 * sizeof (float), ec->transform);
push_transform (ec->transform, layout, dfunc, cmd);
} else {
//FIXME should cache current transform
dfunc->vkCmdPushConstants (cmd, layout, VK_SHADER_STAGE_VERTEX_BIT,
0, 16 * sizeof (float), identity);
push_transform (identity, layout, dfunc, cmd);
}
for (el = ec->elements; el; el = el->next) {
//FIXME check if these are contiguous and if so merge into one
//command
if (!el->index_count)
continue;
dfunc->vkCmdDrawIndexed (cmd, el->index_count, 1, el->first_index,
@ -828,35 +845,18 @@ get_view (qfv_tex_t *tex, qfv_tex_t *default_tex)
}
static void
bsp_begin (vulkan_ctx_t *ctx)
bsp_begin_subpass (VkCommandBuffer cmd, VkPipeline pipeline, vulkan_ctx_t *ctx)
{
qfv_device_t *device = ctx->device;
qfv_devfuncs_t *dfunc = device->funcs;
bspctx_t *bctx = ctx->bsp_context;
//XXX quat_t fog;
bctx->default_color[3] = 1;
QuatCopy (bctx->default_color, bctx->last_color);
__auto_type cframe = &ctx->frames.a[ctx->curFrame];
bspframe_t *bframe = &bctx->frames.a[ctx->curFrame];
VkCommandBuffer cmd = bframe->bsp_cmd;
DARRAY_APPEND (cframe->subCommand, cmd);
//FIXME need per frame matrices
bframe->bufferInfo[0].buffer = ctx->matrices.buffer_3d;
bframe->imageInfo[0].imageView = 0; // set by tex chain loop
bframe->imageInfo[1].imageView = 0; // set by tex chain loop
bframe->imageInfo[2].imageView = QFV_ScrapImageView (bctx->light_scrap);
bframe->imageInfo[3].imageView = get_view (bctx->skysheet_tex,
bctx->default_skysheet);
bframe->imageInfo[4].imageView = get_view (bctx->skybox_tex,
bctx->default_skybox);
dfunc->vkResetCommandBuffer (cmd, 0);
VkCommandBufferInheritanceInfo inherit = {
VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_INFO, 0,
ctx->renderpass.renderpass, 0,
ctx->renderpass, 0,
cframe->framebuffer,
0, 0, 0,
};
@ -868,7 +868,7 @@ bsp_begin (vulkan_ctx_t *ctx)
dfunc->vkBeginCommandBuffer (cmd, &beginInfo);
dfunc->vkCmdBindPipeline (cmd, VK_PIPELINE_BIND_POINT_GRAPHICS,
bctx->main);
pipeline);
VkViewport viewport = {0, 0, vid.width, vid.height, 0, 1};
VkRect2D scissor = { {0, 0}, {vid.width, vid.height} };
dfunc->vkCmdSetViewport (cmd, 0, 1, &viewport);
@ -893,14 +893,54 @@ bsp_begin (vulkan_ctx_t *ctx)
}
static void
bsp_end (vulkan_ctx_t *ctx)
bsp_end_subpass (VkCommandBuffer cmd, vulkan_ctx_t *ctx)
{
qfv_device_t *device = ctx->device;
qfv_devfuncs_t *dfunc = device->funcs;
bspctx_t *bctx = ctx->bsp_context;
dfunc->vkEndCommandBuffer (cmd);
}
static void
bsp_begin (vulkan_ctx_t *ctx)
{
bspctx_t *bctx = ctx->bsp_context;
//XXX quat_t fog;
bctx->default_color[3] = 1;
QuatCopy (bctx->default_color, bctx->last_color);
__auto_type cframe = &ctx->frames.a[ctx->curFrame];
bspframe_t *bframe = &bctx->frames.a[ctx->curFrame];
dfunc->vkEndCommandBuffer (bframe->bsp_cmd);
DARRAY_APPEND (&cframe->cmdSets[QFV_passDepth],
bframe->cmdSet.a[QFV_bspDepth]);
DARRAY_APPEND (&cframe->cmdSets[QFV_passGBuffer],
bframe->cmdSet.a[QFV_bspGBuffer]);
//FIXME need per frame matrices
bframe->bufferInfo[0].buffer = ctx->matrices.buffer_3d;
bframe->imageInfo[0].imageView = 0; // set by tex chain loop
bframe->imageInfo[1].imageView = 0; // set by tex chain loop
bframe->imageInfo[2].imageView = QFV_ScrapImageView (bctx->light_scrap);
bframe->imageInfo[3].imageView = get_view (bctx->skysheet_tex,
bctx->default_skysheet);
bframe->imageInfo[4].imageView = get_view (bctx->skybox_tex,
bctx->default_skybox);
//FIXME pipeline
bsp_begin_subpass (bframe->cmdSet.a[QFV_bspDepth], bctx->main, ctx);
bsp_begin_subpass (bframe->cmdSet.a[QFV_bspGBuffer], bctx->main, ctx);
}
static void
bsp_end (vulkan_ctx_t *ctx)
{
bspctx_t *bctx = ctx->bsp_context;
bspframe_t *bframe = &bctx->frames.a[ctx->curFrame];
bsp_end_subpass (bframe->cmdSet.a[QFV_bspDepth], ctx);
bsp_end_subpass (bframe->cmdSet.a[QFV_bspGBuffer], ctx);
}
/*static void
@ -982,8 +1022,6 @@ spin (mat4_t mat, bspctx_t *bctx)
static void
sky_begin (vulkan_ctx_t *ctx)
{
qfv_device_t *device = ctx->device;
qfv_devfuncs_t *dfunc = device->funcs;
bspctx_t *bctx = ctx->bsp_context;
bctx->default_color[3] = 1;
@ -993,8 +1031,10 @@ sky_begin (vulkan_ctx_t *ctx)
__auto_type cframe = &ctx->frames.a[ctx->curFrame];
bspframe_t *bframe = &bctx->frames.a[ctx->curFrame];
VkCommandBuffer cmd = bframe->sky_cmd;
DARRAY_APPEND (cframe->subCommand, cmd);
//FIXME where should skys go? g-buffer is overkill. Translucent pre-pass?
DARRAY_APPEND (&cframe->cmdSets[QFV_passTranslucent],
bframe->cmdSet.a[QFV_bspTranslucent]);
//FIXME need per frame matrices
bframe->bufferInfo[0].buffer = ctx->matrices.buffer_3d;
@ -1006,54 +1046,18 @@ sky_begin (vulkan_ctx_t *ctx)
bframe->imageInfo[4].imageView = get_view (bctx->skybox_tex,
bctx->default_skybox);
dfunc->vkResetCommandBuffer (cmd, 0);
VkCommandBufferInheritanceInfo inherit = {
VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_INFO, 0,
ctx->renderpass.renderpass, 0,
cframe->framebuffer,
0, 0, 0,
};
VkCommandBufferBeginInfo beginInfo = {
VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, 0,
VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT
| VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT, &inherit,
};
dfunc->vkBeginCommandBuffer (cmd, &beginInfo);
dfunc->vkCmdBindPipeline (cmd, VK_PIPELINE_BIND_POINT_GRAPHICS,
bctx->sky);
VkViewport viewport = {0, 0, vid.width, vid.height, 0, 1};
VkRect2D scissor = { {0, 0}, {vid.width, vid.height} };
dfunc->vkCmdSetViewport (cmd, 0, 1, &viewport);
dfunc->vkCmdSetScissor (cmd, 0, 1, &scissor);
VkDeviceSize offsets[] = { 0 };
dfunc->vkCmdBindVertexBuffers (cmd, 0, 1, &bctx->vertex_buffer, offsets);
dfunc->vkCmdBindIndexBuffer (cmd, bctx->index_buffer, bframe->index_offset,
VK_INDEX_TYPE_UINT32);
// push VP matrices
dfunc->vkCmdPushDescriptorSetKHR (cmd, VK_PIPELINE_BIND_POINT_GRAPHICS,
bctx->layout,
0, 1, bframe->descriptors + 0);
// push static images
dfunc->vkCmdPushDescriptorSetKHR (cmd, VK_PIPELINE_BIND_POINT_GRAPHICS,
bctx->layout,
0, 5, bframe->descriptors + 1);
//XXX glsl_Fog_GetColor (fog);
//XXX fog[3] = glsl_Fog_GetDensity () / 64.0;
//FIXME sky pass
bsp_begin_subpass (bframe->cmdSet.a[QFV_bspTranslucent], bctx->sky, ctx);
}
static void
sky_end (vulkan_ctx_t *ctx)
{
qfv_device_t *device = ctx->device;
qfv_devfuncs_t *dfunc = device->funcs;
bspctx_t *bctx = ctx->bsp_context;
bspframe_t *bframe = &bctx->frames.a[ctx->curFrame];
dfunc->vkEndCommandBuffer (bframe->sky_cmd);
//FIXME sky pass
bsp_end_subpass (bframe->cmdSet.a[QFV_bspTranslucent], ctx);
}
static inline void
@ -1133,13 +1137,13 @@ Vulkan_DrawWorld (vulkan_ctx_t *ctx)
Vulkan_FlushLightmaps (ctx);
bsp_begin (ctx);
dfunc->vkCmdPushConstants (bframe->bsp_cmd, bctx->layout,
VK_SHADER_STAGE_VERTEX_BIT,
0, 16 * sizeof (float), identity);
push_transform (identity, bctx->layout, dfunc,
bframe->cmdSet.a[QFV_bspDepth]);
push_transform (identity, bctx->layout, dfunc,
bframe->cmdSet.a[QFV_bspGBuffer]);
fragconst_t frag_constants = { time: vr_data.realtime };
dfunc->vkCmdPushConstants (bframe->bsp_cmd, bctx->layout,
VK_SHADER_STAGE_FRAGMENT_BIT,
64, sizeof (fragconst_t), &frag_constants);
push_fragconst (&frag_constants, bctx->layout, dfunc,
bframe->cmdSet.a[QFV_bspGBuffer]);
//XXX qfeglActiveTexture (GL_TEXTURE0 + 0);
for (size_t i = 0; i < bctx->texture_chains.size; i++) {
vulktex_t *tex;
@ -1153,13 +1157,15 @@ Vulkan_DrawWorld (vulkan_ctx_t *ctx)
ctx->default_white);
bframe->imageInfo[1].imageView = get_view (tex->glow,
ctx->default_black);
dfunc->vkCmdPushDescriptorSetKHR (bframe->bsp_cmd,
VK_PIPELINE_BIND_POINT_GRAPHICS,
bctx->layout,
0, 2, bframe->descriptors + 1);
push_descriptors (2, bframe->descriptors + 1, bctx->layout, dfunc,
bframe->cmdSet.a[QFV_bspGBuffer]);
for (ec = tex->elechain; ec; ec = ec->next) {
draw_elechain (ec, bctx->layout, dfunc, bframe->bsp_cmd);
draw_elechain (ec, bctx->layout, dfunc,
bframe->cmdSet.a[QFV_bspDepth]);
draw_elechain (ec, bctx->layout, dfunc,
bframe->cmdSet.a[QFV_bspGBuffer]);
}
tex->elechain = 0;
tex->elechain_tail = &tex->elechain;
@ -1246,22 +1252,24 @@ Vulkan_DrawSky (vulkan_ctx_t *ctx)
return;
sky_begin (ctx);
dfunc->vkCmdPushConstants (bframe->sky_cmd, bctx->layout,
VK_SHADER_STAGE_VERTEX_BIT,
0, 16 * sizeof (float), identity);
//FIXME sky pass
push_transform (identity, bctx->layout, dfunc,
bframe->cmdSet.a[QFV_bspTranslucent]);
fragconst_t frag_constants = { time: vr_data.realtime };
dfunc->vkCmdPushConstants (bframe->sky_cmd, bctx->layout,
VK_SHADER_STAGE_FRAGMENT_BIT,
64, sizeof (fragconst_t), &frag_constants);
push_fragconst (&frag_constants, bctx->layout, dfunc,
bframe->cmdSet.a[QFV_bspTranslucent]);
for (is = bctx->sky_chain; is; is = is->tex_chain) {
surf = is->surface;
if (tex != surf->texinfo->texture->render) {
if (tex) {
bind_view (qfv_bsp_skysheet,
get_view (tex->tex, ctx->default_black),
bframe, bframe->sky_cmd, bctx->layout, dfunc);
bframe,
bframe->cmdSet.a[QFV_bspTranslucent],//FIXME
bctx->layout, dfunc);
for (ec = tex->elechain; ec; ec = ec->next) {
draw_elechain (ec, bctx->layout, dfunc, bframe->sky_cmd);
draw_elechain (ec, bctx->layout, dfunc,//FIXME
bframe->cmdSet.a[QFV_bspTranslucent]);
}
tex->elechain = 0;
tex->elechain_tail = &tex->elechain;
@ -1271,11 +1279,12 @@ Vulkan_DrawSky (vulkan_ctx_t *ctx)
add_surf_elements (tex, is, &ec, &el, bctx, bframe);
}
if (tex) {
bind_view (qfv_bsp_skysheet,
get_view (tex->tex, ctx->default_black),
bframe, bframe->sky_cmd, bctx->layout, dfunc);
bind_view (qfv_bsp_skysheet, get_view (tex->tex, ctx->default_black),
bframe, bframe->cmdSet.a[QFV_bspTranslucent],//FIXME
bctx->layout, dfunc);
for (ec = tex->elechain; ec; ec = ec->next) {
draw_elechain (ec, bctx->layout, dfunc, bframe->sky_cmd);
draw_elechain (ec, bctx->layout, dfunc,//FIXME
bframe->cmdSet.a[QFV_bspTranslucent]);
}
tex->elechain = 0;
tex->elechain_tail = &tex->elechain;
@ -1453,23 +1462,21 @@ Vulkan_Bsp_Init (vulkan_ctx_t *ctx)
bctx->layout = Vulkan_CreatePipelineLayout (ctx, "quakebsp_layout");
bctx->sampler = Vulkan_CreateSampler (ctx, "quakebsp_sampler");
__auto_type cmdBuffers = QFV_AllocCommandBufferSet (3 * frames, alloca);
QFV_AllocateCommandBuffers (device, ctx->cmdpool, 1, cmdBuffers);
for (size_t i = 0; i < frames; i++) {
__auto_type bframe = &bctx->frames.a[i];
bframe->bsp_cmd = cmdBuffers->a[i * 3 + 0];
bframe->turb_cmd = cmdBuffers->a[i * 3 + 1];
bframe->sky_cmd = cmdBuffers->a[i * 3 + 2];
QFV_duSetObjectName (device, VK_OBJECT_TYPE_COMMAND_BUFFER,
bframe->bsp_cmd,
va (ctx->va_ctx, "cmd:bsp:%zd", i));
QFV_duSetObjectName (device, VK_OBJECT_TYPE_COMMAND_BUFFER,
bframe->turb_cmd,
va (ctx->va_ctx, "cmd:turb:%zd", i));
QFV_duSetObjectName (device, VK_OBJECT_TYPE_COMMAND_BUFFER,
bframe->sky_cmd,
va (ctx->va_ctx, "cmd:sky:%zd", i));
DARRAY_INIT (&bframe->cmdSet, QFV_bspNumPasses);
DARRAY_RESIZE (&bframe->cmdSet, QFV_bspNumPasses);
bframe->cmdSet.grow = 0;
QFV_AllocateCommandBuffers (device, ctx->cmdpool, 1, &bframe->cmdSet);
for (int j = 0; j < QFV_bspNumPasses; j++) {
QFV_duSetObjectName (device, VK_OBJECT_TYPE_COMMAND_BUFFER,
bframe->cmdSet.a[i],
va (ctx->va_ctx, "cmd:bsp:%zd:%s", i,
bsp_pass_names[j]));
}
for (int j = 0; j < BSP_BUFFER_INFOS; j++) {
bframe->bufferInfo[j] = base_buffer_info;
@ -1495,6 +1502,11 @@ Vulkan_Bsp_Shutdown (struct vulkan_ctx_s *ctx)
qfv_devfuncs_t *dfunc = device->funcs;
bspctx_t *bctx = ctx->bsp_context;
for (size_t i = 0; i < bctx->frames.size; i++) {
__auto_type bframe = &bctx->frames.a[i];
free (bframe->cmdSet.a);
}
dfunc->vkDestroyPipeline (device->dev, bctx->main, 0);
dfunc->vkDestroyPipeline (device->dev, bctx->sky, 0);
DARRAY_CLEAR (&bctx->texture_chains);

View file

@ -696,7 +696,8 @@ Vulkan_FlushText (vulkan_ctx_t *ctx)
drawframe_t *dframe = &dctx->frames.a[ctx->curFrame];
VkCommandBuffer cmd = dframe->cmd;
DARRAY_APPEND (cframe->subCommand, cmd);
//FIXME which pass?
DARRAY_APPEND (&cframe->cmdSets[QFV_passTranslucent], cmd);
VkMappedMemoryRange range = {
VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE, 0,
@ -708,7 +709,7 @@ Vulkan_FlushText (vulkan_ctx_t *ctx)
dfunc->vkResetCommandBuffer (cmd, 0);
VkCommandBufferInheritanceInfo inherit = {
VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_INFO, 0,
ctx->renderpass.renderpass, 0,
ctx->renderpass, 0,
cframe->framebuffer,
0, 0, 0
};

View file

@ -78,6 +78,10 @@ static const char quakeforge_pipeline[] =
#include "libs/video/renderer/vulkan/qfpipeline.plc"
;
static const char quakeforge_renderpass[] =
#include "libs/video/renderer/vulkan/deferred.plc"
;
cvar_t *vulkan_frame_count;
cvar_t *vulkan_presentation_mode;
cvar_t *msaaSamples;
@ -163,6 +167,7 @@ void
Vulkan_Init_Common (vulkan_ctx_t *ctx)
{
Sys_Printf ("Vulkan_Init_Common\n");
QFV_InitParse (ctx);
Vulkan_Init_Cvars ();
ctx->instance = QFV_CreateInstance (ctx, PACKAGE_STRING, 0x000702ff, 0, instance_extensions);//FIXME version
@ -185,9 +190,9 @@ Vulkan_Shutdown_Common (vulkan_ctx_t *ctx)
QFV_DestroyPipeline (ctx->device, ctx->pipeline);
}
if (ctx->frames.size) {
Vulkan_DestroyFramebuffers (ctx);
Vulkan_DestroyFrames (ctx);
}
if (ctx->renderpass.colorImage) {
if (ctx->renderpass) {
Vulkan_DestroyRenderPass (ctx);
}
if (ctx->swapchain) {
@ -216,6 +221,15 @@ void
Vulkan_CreateDevice (vulkan_ctx_t *ctx)
{
ctx->device = QFV_CreateDevice (ctx, device_extensions);
//FIXME msaa and deferred rendering...
//also, location
ctx->msaaSamples = 1;
/*ctx->msaaSamples = min ((VkSampleCountFlagBits) msaaSamples->int_val,
QFV_GetMaxSampleCount (device->physDev));
if (ctx->msaaSamples > 1) {
name = "renderpass_msaa";
}*/
}
void
@ -257,138 +271,54 @@ qfv_load_pipeline (vulkan_ctx_t *ctx, const char *name)
return item;
}
static plitem_t *
qfv_load_renderpass (vulkan_ctx_t *ctx, const char *name)
{
if (!ctx->renderpassDef) {
ctx->renderpassDef = PL_GetPropertyList (quakeforge_renderpass,
&ctx->hashlinks);
}
plitem_t *item = ctx->renderpassDef;
if (!item || !(item = PL_ObjectForKey (item, name))) {
Sys_Printf ("error loading %s\n", name);
} else {
Sys_Printf ("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;
}
void
Vulkan_CreateRenderPass (vulkan_ctx_t *ctx)
{
const char *name = "renderpass";//FIXME
qfv_device_t *device = ctx->device;
VkDevice dev = device->dev;
qfv_devfuncs_t *df = device->funcs;
VkCommandBuffer cmd = ctx->cmdbuffer;
qfv_swapchain_t *sc = ctx->swapchain;
ctx->msaaSamples = min ((VkSampleCountFlagBits) msaaSamples->int_val,
QFV_GetMaxSampleCount (device->physDev));
if (ctx->msaaSamples > 1) {
name = "renderpass_msaa";
}
plitem_t *item = qfv_load_renderpass (ctx, name);
//FIXME a tad inconsistent
plitem_t *item = qfv_load_pipeline (ctx, name);
if (!item) {
return;
}
qfv_imageresource_t *colorImage = malloc (sizeof (*colorImage));
qfv_imageresource_t *depthImage = malloc (sizeof (*depthImage));
VkExtent3D extent = {sc->extent.width, sc->extent.height, 1};
Sys_MaskPrintf (SYS_VULKAN, "color resource\n");
colorImage->image
= QFV_CreateImage (device, 0, VK_IMAGE_TYPE_2D,
sc->format, extent, 1, 1, ctx->msaaSamples,
VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT
| VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT);
colorImage->object
= QFV_AllocImageMemory (device, colorImage->image,
VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, 0, 0);
QFV_BindImageMemory (device, colorImage->image, colorImage->object, 0);
colorImage->view
= QFV_CreateImageView (device, colorImage->image,
VK_IMAGE_VIEW_TYPE_2D,
sc->format, VK_IMAGE_ASPECT_COLOR_BIT);
Sys_MaskPrintf (SYS_VULKAN, " image: %p object: %p view:%p\n",
colorImage->image, colorImage->object, colorImage->view);
Sys_MaskPrintf (SYS_VULKAN, "depth resource\n");
VkFormat depthFormat = VK_FORMAT_D32_SFLOAT;
depthImage->image
= QFV_CreateImage (device, 0, VK_IMAGE_TYPE_2D,
depthFormat, extent, 1, 1, ctx->msaaSamples,
VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT);
depthImage->object
= QFV_AllocImageMemory (device, depthImage->image,
VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, 0, 0);
QFV_BindImageMemory (device, depthImage->image, depthImage->object, 0);
depthImage->view
= QFV_CreateImageView (device, depthImage->image,
VK_IMAGE_VIEW_TYPE_2D,
depthFormat, VK_IMAGE_ASPECT_DEPTH_BIT);
Sys_MaskPrintf (SYS_VULKAN, " image: %p object: %p view:%p\n",
depthImage->image, depthImage->object, depthImage->view);
VkImageMemoryBarrier barrier;
qfv_pipelinestagepair_t stages;
df->vkWaitForFences (dev, 1, &ctx->fence, VK_TRUE, ~0ull);
df->vkResetCommandBuffer (cmd, 0);
VkCommandBufferBeginInfo beginInfo = {
VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, 0,
VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT, 0,
};
df->vkBeginCommandBuffer (cmd, &beginInfo);
stages = imageLayoutTransitionStages[qfv_LT_Undefined_to_Color];
barrier = imageLayoutTransitionBarriers[qfv_LT_Undefined_to_Color];
barrier.image = colorImage->image;
df->vkCmdPipelineBarrier (cmd, stages.src, stages.dst, 0,
0, 0,
0, 0,
1, &barrier);
stages = imageLayoutTransitionStages[qfv_LT_Undefined_to_DepthStencil];
barrier = imageLayoutTransitionBarriers[qfv_LT_Undefined_to_DepthStencil];
barrier.image = depthImage->image;
if (depthFormat == VK_FORMAT_D32_SFLOAT_S8_UINT
|| depthFormat == VK_FORMAT_D24_UNORM_S8_UINT) {
barrier.subresourceRange.aspectMask |= VK_IMAGE_ASPECT_STENCIL_BIT;
}
df->vkCmdPipelineBarrier (cmd, stages.src, stages.dst, 0,
0, 0,
0, 0,
1, &barrier);
df->vkEndCommandBuffer (cmd);
VkSubmitInfo submitInfo = {
VK_STRUCTURE_TYPE_SUBMIT_INFO, 0,
0, 0, 0,
1, &cmd,
0, 0
};
df->vkResetFences (dev, 1, &ctx->fence);
df->vkQueueSubmit (device->queue.queue, 1, &submitInfo, ctx->fence);
ctx->renderpass.colorImage = colorImage;
ctx->renderpass.depthImage = depthImage;
ctx->renderpass.renderpass = QFV_ParseRenderPass (ctx, item);
ctx->renderpass = QFV_ParseRenderPass (ctx, item, ctx->renderpassDef);
QFV_duSetObjectName (ctx->device, VK_OBJECT_TYPE_RENDER_PASS,
ctx->renderpass.renderpass,
va (ctx->va_ctx, "pipeline:%s", name));
ctx->renderpass, va (ctx->va_ctx, "renderpass:%s",
name));
}
void
Vulkan_DestroyRenderPass (vulkan_ctx_t *ctx)
{
qfv_device_t *device = ctx->device;
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);
free (ctx->renderpass.colorImage);
ctx->renderpass.colorImage = 0;
df->vkDestroyImageView (dev, ctx->renderpass.depthImage->view, 0);
df->vkDestroyImage (dev, ctx->renderpass.depthImage->image, 0);
df->vkFreeMemory (dev, ctx->renderpass.depthImage->object, 0);
free (ctx->renderpass.depthImage);
ctx->renderpass.depthImage = 0;
}
VkPipeline
@ -401,7 +331,7 @@ Vulkan_CreatePipeline (vulkan_ctx_t *ctx, const char *name)
} else {
Sys_Printf ("Found pipeline def %s\n", name);
}
VkPipeline pipeline = QFV_ParsePipeline (ctx, item);
VkPipeline pipeline = QFV_ParsePipeline (ctx, item, ctx->pipelineDef);
QFV_duSetObjectName (ctx->device, VK_OBJECT_TYPE_PIPELINE, pipeline,
va (ctx->va_ctx, "pipeline:%s", name));
return pipeline;
@ -425,7 +355,7 @@ Vulkan_CreateDescriptorPool (vulkan_ctx_t *ctx, const char *name)
} else {
Sys_Printf ("Found descriptor pool def %s\n", name);
}
pool = QFV_ParseDescriptorPool (ctx, item);
pool = QFV_ParseDescriptorPool (ctx, item, ctx->pipelineDef);
QFV_AddHandle (tab, path, (uint64_t) pool);
QFV_duSetObjectName (ctx->device, VK_OBJECT_TYPE_DESCRIPTOR_POOL, pool,
va (ctx->va_ctx, "descriptor_pool:%s", name));
@ -450,7 +380,7 @@ Vulkan_CreatePipelineLayout (vulkan_ctx_t *ctx, const char *name)
} else {
Sys_Printf ("Found pipeline layout def %s\n", name);
}
layout = QFV_ParsePipelineLayout (ctx, item);
layout = QFV_ParsePipelineLayout (ctx, item, ctx->pipelineDef);
QFV_AddHandle (tab, path, (uint64_t) layout);
QFV_duSetObjectName (ctx->device, VK_OBJECT_TYPE_PIPELINE_LAYOUT, layout,
va (ctx->va_ctx, "pipeline_layout:%s", name));
@ -475,7 +405,7 @@ Vulkan_CreateSampler (vulkan_ctx_t *ctx, const char *name)
} else {
Sys_Printf ("Found sampler def %s\n", name);
}
sampler = QFV_ParseSampler (ctx, item);
sampler = QFV_ParseSampler (ctx, item, ctx->pipelineDef);
QFV_AddHandle (tab, path, (uint64_t) sampler);
QFV_duSetObjectName (ctx->device, VK_OBJECT_TYPE_SAMPLER, sampler,
va (ctx->va_ctx, "sampler:%s", name));
@ -500,7 +430,7 @@ Vulkan_CreateDescriptorSetLayout(vulkan_ctx_t *ctx, const char *name)
} else {
Sys_Printf ("Found descriptor set def %s\n", name);
}
set = QFV_ParseDescriptorSetLayout (ctx, item);
set = QFV_ParseDescriptorSetLayout (ctx, item, ctx->pipelineDef);
QFV_AddHandle (tab, path, (uint64_t) set);
QFV_duSetObjectName (ctx->device, VK_OBJECT_TYPE_DESCRIPTOR_SET_LAYOUT,
set, va (ctx->va_ctx, "descriptor_set:%s", name));
@ -508,7 +438,7 @@ Vulkan_CreateDescriptorSetLayout(vulkan_ctx_t *ctx, const char *name)
}
void
Vulkan_CreateFramebuffers (vulkan_ctx_t *ctx)
Vulkan_CreateFrames (vulkan_ctx_t *ctx)
{
qfv_device_t *device = ctx->device;
VkCommandPool cmdpool = ctx->cmdpool;
@ -531,13 +461,16 @@ Vulkan_CreateFramebuffers (vulkan_ctx_t *ctx)
frame->renderDoneSemaphore = QFV_CreateSemaphore (device);
frame->cmdBuffer = cmdBuffers->a[i];
frame->subCommand = malloc (sizeof (qfv_cmdbufferset_t));
DARRAY_INIT (frame->subCommand, 4);
frame->cmdSetCount = QFV_NumPasses;
frame->cmdSets = malloc (QFV_NumPasses * sizeof (qfv_cmdbufferset_t));
for (int j = 0; j < QFV_NumPasses; j++) {
DARRAY_INIT (&frame->cmdSets[j], 4);
}
}
}
void
Vulkan_DestroyFramebuffers (vulkan_ctx_t *ctx)
Vulkan_DestroyFrames (vulkan_ctx_t *ctx)
{
qfv_device_t *device = ctx->device;
qfv_devfuncs_t *df = device->funcs;
@ -553,3 +486,59 @@ Vulkan_DestroyFramebuffers (vulkan_ctx_t *ctx)
DARRAY_CLEAR (&ctx->frames);
}
void
Vulkan_CreateFramebuffers (vulkan_ctx_t *ctx)
{
qfv_device_t *device = ctx->device;
plitem_t *item = qfv_load_renderpass (ctx, "images");
if (!item) {
return;
}
__auto_type images = QFV_ParseImageSet (ctx, item, ctx->renderpassDef);
ctx->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);
ctx->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, "imageViews");
if (!item) {
return;
}
__auto_type views = QFV_ParseImageViewSet (ctx, item, ctx->renderpassDef);
ctx->attachment_views = views;
item = qfv_load_renderpass (ctx, "framebuffer");
if (!item) {
return;
}
ctx->framebuffers = QFV_AllocFrameBuffers (ctx->swapchain->numImages,
malloc);
for (size_t i = 0; i < ctx->framebuffers->size; i++) {
ctx->swapImageIndex = i;
ctx->framebuffers->a[i] = QFV_ParseFramebuffer (ctx, item,
ctx->renderpassDef);
}
}
void
Vulkan_DestroyFramebuffers (vulkan_ctx_t *ctx)
{
}