[vulkan] Implement pipeline layout creation

It seems to work when parsing the layouts. They can be created in-line
(in theory) or in a "setLayouts" node and then referenced by name.
This commit is contained in:
Bill Currie 2021-01-04 17:36:11 +09:00
parent e4f75791ce
commit d919a85c8e
6 changed files with 302 additions and 1 deletions

View file

@ -45,6 +45,7 @@ typedef struct vulkan_ctx_s {
struct hashlink_s *hashlinks; //FIXME want per thread
VkSurfaceKHR surface; //FIXME surface = window, so "contains" swapchain
struct hashtab_s *shadermodules;
struct hashtab_s *setLayouts;
struct shadermodule_s *shadermodule_freelist;
VkCommandPool cmdpool;

View file

@ -14,6 +14,37 @@
file = $builtin/pushcolor.frag;
},
);
setLayouts = {
something = {
flags = 0;
bindings = (
{
binding = 0;
descriptorType = sampled_image;
descriptorCount = 1;
stageFlags = fragment;
},
{
binding = 1;
descriptorType = uniform_buffer;
descriptorCount = 1;
stageFlags = vertex;
},
);
};
};
pipelineLayouts = {
something = {
setLayouts = (something);
pushConstantRanges = (
{
stageFlags = fragment;
offset = 0;
size = "4 * 4";
},
);
};
};
renderpass = {
attachments = (
{

View file

@ -53,6 +53,7 @@
#include "QF/vid.h"
#include "QF/simd/vec4f.h"
#include "QF/Vulkan/qf_vid.h"
#include "QF/Vulkan/descriptor.h"
#include "QF/Vulkan/device.h"
#include "QF/Vulkan/command.h"
#include "QF/Vulkan/instance.h"
@ -329,6 +330,21 @@ parse_custom (const plfield_t *field, const plitem_t *item,
return custom->parse (item, offsets, messages, context);
}
static int
parse_RGBA (const plitem_t *item, void **data,
plitem_t *messages, parsectx_t *context)
{
int ret = 1;
exprctx_t ectx = *context->ectx;
exprval_t result = { &cexpr_vector, data[0] };
ectx.symtab = 0;
ectx.result = &result;
const char *valstr = PL_String (item);
Sys_Printf ("parse_RGBA: %s\n", valstr);
ret = !cexpr_eval_string (valstr, &ectx);
Sys_Printf (" "VEC4F_FMT"\n", VEC4_EXP (*(vec4f_t *)data[0]));
return ret;
}
static int
parse_VkShaderModule (const plitem_t *item, void **data,
@ -344,6 +360,79 @@ parse_VkShaderModule (const plitem_t *item, void **data,
}
return 0;
}
typedef struct setlayout_s {
char *name;
VkDescriptorSetLayout layout;
} setlayout_t;
static const char *
setLayout_getkey (const void *sl, void *unused)
{
return ((setlayout_t *)sl)->name;
}
static void
setLayout_free (void *sl, void *_ctx)
{
__auto_type setLayout = (setlayout_t *) sl;
__auto_type ctx = (vulkan_ctx_t *) _ctx;
qfv_device_t *device = ctx->device;
qfv_devfuncs_t *dfunc = device->funcs;
dfunc->vkDestroyDescriptorSetLayout (device->dev, setLayout->layout, 0);
free (setLayout->name);
free (setLayout);
}
static int
parse_VkDescriptorSetLayout (const plfield_t *field, const plitem_t *item,
void *data, plitem_t *messages, void *context)
{
__auto_type layout = (setlayout_t *) data;
vulkan_ctx_t *ctx = ((parsectx_t *) context)->vctx;
qfv_device_t *device = ctx->device;
qfv_devfuncs_t *dfunc = device->funcs;
if (PL_Type (item) == QFString) {
// accessing a named set layout
const char *name = PL_String (item);
setlayout_t *l = Hash_Find (ctx->setLayouts, name);
if (!l) {
PL_Message (messages, item, "undefined set layout %s", name);
return 0;
}
*layout = *l;
return 1;
}
VkDescriptorSetLayoutCreateInfo createInfo = {};
if (!parse_VkDescriptorSetLayoutCreateInfo (0, item, &createInfo,
messages, context)) {
return 0;
}
layout->name = strdup (field->name);
VkResult res;
res = dfunc->vkCreateDescriptorSetLayout (device->dev, &createInfo, 0,
&layout->layout);
if (res != VK_SUCCESS) {
PL_Message (messages, item, "could not create set layout");
return 0;
}
return 1;
}
static plelement_t setLayout_data = {
QFDictionary,
sizeof (setlayout_t),
malloc,
parse_VkDescriptorSetLayout,
0,
};
static plfield_t setLayout_field = { 0, 0, QFDictionary, 0, &setLayout_data };
static hashtab_t *enum_symtab;
#include "libs/video/renderer/vulkan/vkparse.cinc"
@ -440,6 +529,33 @@ QFV_ParseRenderPass (vulkan_ctx_t *ctx, plitem_t *plist)
return renderpass;
}
void
QFV_ParseDescriptorSetLayouts (vulkan_ctx_t *ctx, plitem_t *sets)
{
plitem_t *messages = PL_NewArray ();
exprctx_t exprctx = {};
parsectx_t parsectx = { &exprctx, ctx };
exprctx.memsuper = new_memsuper ();
exprctx.messages = messages;
exprctx.hashlinks = ctx->hashlinks;
if (!ctx->setLayouts) {
ctx->setLayouts = Hash_NewTable (23, setLayout_getkey, setLayout_free,
ctx, &exprctx.hashlinks);
}
int res = PL_ParseSymtab (&setLayout_field, sets, ctx->setLayouts,
messages, &parsectx);
if (!res || developer->int_val & SYS_VULKAN) {
for (int i = 0; i < PL_A_NumObjects (messages); i++) {
Sys_Printf ("%s\n", PL_String (PL_ObjectAtIndex (messages, i)));
}
}
PL_Free (messages);
delete_memsuper (exprctx.memsuper);
ctx->hashlinks = exprctx.hashlinks;
}
static const char *
enum_symtab_getkey (const void *e, void *unused)
{

View file

@ -12,6 +12,8 @@ typedef struct parsectx_s {
struct vulkan_ctx_s *vctx;
} parsectx_t;
void QFV_ParseDescriptorSetLayouts (vulkan_ctx_t *ctx, plitem_t *sets);
VkRenderPass QFV_ParseRenderPass (vulkan_ctx_t *ctx, plitem_t *plist);
void QFV_InitParse (void);
exprenum_t *QFV_GetEnum (const char *name);

View file

@ -5,6 +5,18 @@
VkSubpassDependency,
VkSpecializationInfo,
VkPipelineShaderStageCreateInfo,
VkPipelineVertexInputStateCreateInfo,
VkPipelineInputAssemblyStateCreateInfo,
VkPipelineViewportStateCreateInfo,
VkPipelineRasterizationStateCreateInfo,
VkPipelineMultisampleStateCreateInfo,
VkPipelineDepthStencilStateCreateInfo,
VkPipelineColorBlendStateCreateInfo,
VkPipelineDynamicStateCreateInfo,
VkDescriptorSetLayoutBinding,
VkDescriptorSetLayoutCreateInfo,
VkPushConstantRange,
VkPipelineLayoutCreateInfo,
qfv_swapchain_t,
);
parse = {
@ -69,5 +81,125 @@
};
};
VkShaderModuleCreateInfo = skip;
VkDescriptorSetLayoutBinding = {
binding = auto;
descriptorType = auto;
descriptorCount = auto;
stageFlags = auto;
// skip pImmutableSamplers (default to 0) until I know how it works
};
VkDescriptorSetLayoutCreateInfo = {
flags = auto;
bindings = {
type = (array, VkDescriptorSetLayoutBinding);
size = bindingCount;
values = pBindings;
};
};
VkPipelineVertexInputStateCreateInfo = {
//flags = auto; reserved for future use (Bits enum does not exist)
bindings = {
type = (array, VkVertexInputBindingDescription);
size = vertexBindingDescriptionCount;
values = pVertexBindingDescriptions;
};
attributes = {
type = (array, VkVertexInputAttributeDescription);
size = vertexAttributeDescriptionCount;
values = pVertexAttributeDescriptions;
};
};
VkPipelineInputAssemblyStateCreateInfo = {
//flags = auto; reserved for future use (Bits enum does not exist)
topology = auto;
primitiveRestartEnable = auto;
};
VkPipelineViewportStateCreateInfo = {
//flags = auto; reserved for future use (Bits enum does not exist)
//FIXME redo as one array
viewports = {
type = (array, VkViewport);
size = viewportCount;
values = pViewports;
};
scissors = {
type = (array, VkRect2D);
size = scissorCount;
values = pScissors;
};
};
VkPipelineRasterizationStateCreateInfo = {
//flags = auto; reserved for future use (Bits enum does not exist)
depthClampEnable = auto;
rasterizerDiscardEnable = auto;
polygonMode = auto;
cullMode = auto;
frontFace = auto;
depthBiasEnable = auto;
depthBiasConstantFactor = auto;
depthBiasClamp = auto;
depthBiasSlopeFactor = auto;
lineWidth = auto;
};
VkPipelineMultisampleStateCreateInfo = {
//flags = auto; reserved for future use (Bits enum does not exist)
rasterizationSamples = auto;
sampleShadingEnable = auto;
minSampleShading = auto;
//pSampleMask = auto; FIXME disabled until correct size is known
alphaToCoverageEnable = auto;
alphaToOneEnable = auto;
};
VkPipelineDepthStencilStateCreateInfo = {
//flags = auto; reserved for future use (Bits enum does not exist)
depthTestEnable = auto;
depthWriteEnable = auto;
depthCompareOp = auto;
depthBoundsTestEnable = auto;
stencilTestEnable = auto;
front = auto;
back = auto;
minDepthBounds = auto;
maxDepthBounds = auto;
};
VkPipelineColorBlendStateCreateInfo = {
//flags = auto; reserved for future use (Bits enum does not exist)
logicOpEnable = auto;
logicOp = auto;
attachments = {
type = (array, VkPipelineColorBlendAttachmentState);
size = attachmentCount;
values = pAttachments;
};
blendConstants = {
type = (custom, QFString, parse_RGBA);
fields = (blendConstants);
};
};
VkPipelineDynamicStateCreateInfo = {
//flags = auto; reserved for future use (Bits enum does not exist)
dynamicState = {
type = (array, VkDynamicState);
size = dynamicStateCount;
values = pDynamicStates;
};
};
VkPipelineLayoutCreateInfo = {
//flags = auto; reserved for future use (Bits enum does not exist)
setLayouts = {
type = (array, {
parse_type = (QFDictionary, QFString);
type = VkDescriptorSetLayout;
parser = parse_VkDescriptorSetLayout;
});
size = setLayoutCount;
values = pSetLayouts;
};
pushConstantRanges = {
type = (array, VkPushConstantRange);
size = pushConstantRangeCount;
values = pPushConstantRanges;
};
}
}
}

View file

@ -52,6 +52,7 @@
#include "QF/va.h"
#include "QF/vid.h"
#include "QF/Vulkan/qf_vid.h"
#include "QF/Vulkan/descriptor.h"
#include "QF/Vulkan/device.h"
#include "QF/Vulkan/command.h"
#include "QF/Vulkan/instance.h"
@ -401,8 +402,10 @@ Vulkan_DestroyRenderPass (vulkan_ctx_t *ctx)
void
Vulkan_CreatePipelines (vulkan_ctx_t *ctx)
{
plitem_t *item = qfv_load_pipeline ();
plitem_t *pipeline_def = qfv_load_pipeline ();
plitem_t *item;
item = pipeline_def;
if (!item || !(item = PL_ObjectForKey (item, "modules"))) {
Sys_Printf ("error loading modules\n");
} else {
@ -424,6 +427,22 @@ Vulkan_CreatePipelines (vulkan_ctx_t *ctx)
QFV_RegisterShaderModule (ctx, name, module);
}
}
item = pipeline_def;
if (!item || !(item = PL_ObjectForKey (item, "setLayouts"))) {
Sys_Printf ("error loading setLayouts\n");
} else {
Sys_Printf ("Found setLayouts\n");
QFV_ParseDescriptorSetLayouts (ctx, item);
}
/*item = pipeline_def;
if (!item || !(item = PL_ObjectForKey (item, "pipelineLayouts"))) {
Sys_Printf ("error loading pipelineLayouts\n");
} else {
Sys_Printf ("Found pipelineLayouts\n");
QFV_ParsePipelineLayouts (ctx, item);
}*/
}
void