From d919a85c8e63cd7757f6b9be49cb0fc59d5124d3 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Mon, 4 Jan 2021 17:36:11 +0900 Subject: [PATCH] [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. --- include/vid_vulkan.h | 1 + libs/video/renderer/vulkan/qfpipeline.plist | 31 ++++ libs/video/renderer/vulkan/vkparse.c | 116 +++++++++++++++ libs/video/renderer/vulkan/vkparse.h | 2 + libs/video/renderer/vulkan/vkparse.plist | 132 ++++++++++++++++++ .../video/renderer/vulkan/vulkan_vid_common.c | 21 ++- 6 files changed, 302 insertions(+), 1 deletion(-) diff --git a/include/vid_vulkan.h b/include/vid_vulkan.h index 5eb2dd157..29cbc8ff1 100644 --- a/include/vid_vulkan.h +++ b/include/vid_vulkan.h @@ -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; diff --git a/libs/video/renderer/vulkan/qfpipeline.plist b/libs/video/renderer/vulkan/qfpipeline.plist index 7af624b99..d619b8406 100644 --- a/libs/video/renderer/vulkan/qfpipeline.plist +++ b/libs/video/renderer/vulkan/qfpipeline.plist @@ -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 = ( { diff --git a/libs/video/renderer/vulkan/vkparse.c b/libs/video/renderer/vulkan/vkparse.c index 21e7bdf72..0931ee755 100644 --- a/libs/video/renderer/vulkan/vkparse.c +++ b/libs/video/renderer/vulkan/vkparse.c @@ -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) { diff --git a/libs/video/renderer/vulkan/vkparse.h b/libs/video/renderer/vulkan/vkparse.h index e34624dab..0f47ac16a 100644 --- a/libs/video/renderer/vulkan/vkparse.h +++ b/libs/video/renderer/vulkan/vkparse.h @@ -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); diff --git a/libs/video/renderer/vulkan/vkparse.plist b/libs/video/renderer/vulkan/vkparse.plist index 1ba7e8bb4..95ad4368e 100644 --- a/libs/video/renderer/vulkan/vkparse.plist +++ b/libs/video/renderer/vulkan/vkparse.plist @@ -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; + }; + } } } diff --git a/libs/video/renderer/vulkan/vulkan_vid_common.c b/libs/video/renderer/vulkan/vulkan_vid_common.c index 7647db9ff..f515abd83 100644 --- a/libs/video/renderer/vulkan/vulkan_vid_common.c +++ b/libs/video/renderer/vulkan/vulkan_vid_common.c @@ -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