diff --git a/include/QF/Vulkan/pipeline.h b/include/QF/Vulkan/pipeline.h index f77585217..c7d5013de 100644 --- a/include/QF/Vulkan/pipeline.h +++ b/include/QF/Vulkan/pipeline.h @@ -128,9 +128,6 @@ typedef struct qfv_pipelinecacheset_s #define QFV_AllocPipelineCacheSet(num, allocator) \ DARRAY_ALLOCFIXED (qfv_pipelinecacheset_t, num, allocator) -VkShaderModule QFV_CreateShaderModule (struct qfv_device_s *device, - size_t size, const uint32_t *code); - struct dstring_s; VkPipelineCache QFV_CreatePipelineCache (struct qfv_device_s *device, struct dstring_s *cacheData); diff --git a/include/QF/Vulkan/qf_vid.h b/include/QF/Vulkan/qf_vid.h index d7ef64a97..d380d1236 100644 --- a/include/QF/Vulkan/qf_vid.h +++ b/include/QF/Vulkan/qf_vid.h @@ -38,8 +38,9 @@ struct vulkan_ctx_s; void Vulkan_DestroyFramebuffers (struct vulkan_ctx_s *ctx); void Vulkan_CreateFramebuffers (struct vulkan_ctx_s *ctx); -void Vulkan_DestroyRenderPass (struct vulkan_ctx_s *ctx); void Vulkan_CreateRenderPass (struct vulkan_ctx_s *ctx); +void Vulkan_DestroyRenderPass (struct vulkan_ctx_s *ctx); +void Vulkan_CreatePipelines (struct vulkan_ctx_s *ctx); void Vulkan_CreateSwapchain (struct vulkan_ctx_s *ctx); void Vulkan_CreateDevice (struct vulkan_ctx_s *ctx); void Vulkan_Init_Common (struct vulkan_ctx_s *ctx); diff --git a/include/QF/Vulkan/shader.h b/include/QF/Vulkan/shader.h index 6b8321cdd..b13f6a618 100644 --- a/include/QF/Vulkan/shader.h +++ b/include/QF/Vulkan/shader.h @@ -3,11 +3,20 @@ struct qfv_device_s; struct vulkan_ctx_s; +struct plitem_s; +struct parsectx_s; VkShaderModule QFV_CreateShaderModule (struct qfv_device_s *device, const char *path); +void QFV_DestroyShaderModule (struct qfv_device_s *device, + VkShaderModule module); +VkShaderModule QFV_FindShaderModule (struct vulkan_ctx_s *ctx, + const char *name); void QFV_RegisterShaderModule (struct vulkan_ctx_s *ctx, const char *name, VkShaderModule module); void QFV_DeregisterShaderModule (struct vulkan_ctx_s *ctx, const char *name); +int parse_VkShaderModule (const struct plitem_s *item, void **data, + struct plitem_s *messages, + struct parsectx_s *context); #endif//__QF_Vulkan_shader_h diff --git a/libs/video/renderer/vid_render_vulkan.c b/libs/video/renderer/vid_render_vulkan.c index 85181547c..52246162b 100644 --- a/libs/video/renderer/vid_render_vulkan.c +++ b/libs/video/renderer/vid_render_vulkan.c @@ -64,6 +64,9 @@ vulkan_R_Init (void) Vulkan_CreateSwapchain (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_CreatePipelines (vulkan_ctx); qfv_swapchain_t *sc = vulkan_ctx->swapchain; diff --git a/libs/video/renderer/vulkan/pipeline.c b/libs/video/renderer/vulkan/pipeline.c index 119fbf303..bfe48ce9f 100644 --- a/libs/video/renderer/vulkan/pipeline.c +++ b/libs/video/renderer/vulkan/pipeline.c @@ -64,23 +64,6 @@ #include "util.h" -VkShaderModule -QFV_CreateShaderModule (qfv_device_t *device, - size_t size, const uint32_t *code) -{ - VkDevice dev = device->dev; - qfv_devfuncs_t *dfunc = device->funcs; - - VkShaderModuleCreateInfo createInfo = { - VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO, 0, 0, - size, code, - }; - - VkShaderModule module; - dfunc->vkCreateShaderModule (dev, &createInfo, 0, &module); - return module; -} - VkPipelineCache QFV_CreatePipelineCache (qfv_device_t *device, dstring_t *cacheData) { diff --git a/libs/video/renderer/vulkan/qfpipeline.plist b/libs/video/renderer/vulkan/qfpipeline.plist index 66c9e0adb..7af624b99 100644 --- a/libs/video/renderer/vulkan/qfpipeline.plist +++ b/libs/video/renderer/vulkan/qfpipeline.plist @@ -1,4 +1,19 @@ { + modules = ( + // specify shader modules to load into memory + { + // the name of the module for referecy by the pipeline + name = passthrough; + // the path to the spv file to load + // $shader refers to the shader install path + // $builtin refers to compiled-in shaders + file = $builtin/passthrough.vert; + }, + { + name = pushcolor; + file = $builtin/pushcolor.frag; + }, + ); renderpass = { attachments = ( { diff --git a/libs/video/renderer/vulkan/shader.c b/libs/video/renderer/vulkan/shader.c index 704e01996..5ee89ca25 100644 --- a/libs/video/renderer/vulkan/shader.c +++ b/libs/video/renderer/vulkan/shader.c @@ -42,6 +42,7 @@ #include "QF/cvar.h" #include "QF/dstring.h" #include "QF/hash.h" +#include "QF/qfplist.h" #include "QF/quakefs.h" #include "QF/sys.h" #include "QF/Vulkan/qf_vid.h" @@ -52,6 +53,7 @@ #include "QF/Vulkan/shader.h" #include "vid_vulkan.h" +#include "vkparse.h" static #include "libs/video/renderer/vulkan/passthrough.vert.spvc" @@ -92,7 +94,7 @@ QFV_CreateShaderModule (qfv_device_t *device, const char *shader_path) shaderdata_t _data = {}; shaderdata_t *data = 0; dstring_t *path = 0; - QFile *file; + QFile *file = 0; VkShaderModule shader = 0; if (strncmp (shader_path, BUILTIN, BUILTIN_SIZE) == 0) { @@ -142,6 +144,15 @@ QFV_CreateShaderModule (qfv_device_t *device, const char *shader_path) return shader; } +void +QFV_DestroyShaderModule (qfv_device_t *device, VkShaderModule module) +{ + VkDevice dev = device->dev; + qfv_devfuncs_t *dfunc = device->funcs; + + dfunc->vkDestroyShaderModule (dev, module, 0); +} + static shadermodule_t * new_module (vulkan_ctx_t *ctx) { @@ -169,10 +180,21 @@ sm_free (void *sm, void *ctx) del_module (sm, ctx); } +VkShaderModule +QFV_FindShaderModule (vulkan_ctx_t *ctx, const char *name) +{ + //FIXME + if (!ctx->shadermodules) { + ctx->shadermodules = Hash_NewTable (127, sm_getkey, sm_free, ctx, 0); + } + return Hash_Find (ctx->shadermodules, name); +} + void QFV_RegisterShaderModule (vulkan_ctx_t *ctx, const char *name, VkShaderModule module) { + //FIXME if (!ctx->shadermodules) { ctx->shadermodules = Hash_NewTable (127, sm_getkey, sm_free, ctx, 0); } @@ -190,3 +212,18 @@ QFV_DeregisterShaderModule (vulkan_ctx_t *ctx, const char *name) } Hash_Free (ctx->shadermodules, Hash_Del (ctx->shadermodules, name)); } + +int +parse_VkShaderModule (const plitem_t *item, void **data, + plitem_t *messages, parsectx_t *context) +{ + vulkan_ctx_t *ctx = context->vctx; + const char *name = PL_String (item); + __auto_type mptr = (VkShaderModule *)data[0]; + VkShaderModule module = QFV_FindShaderModule (ctx, name); + if (module) { + *mptr = module; + return 1; + } + return 0; +} diff --git a/libs/video/renderer/vulkan/vkgen/Makemodule.am b/libs/video/renderer/vulkan/vkgen/Makemodule.am index 31c22d936..4847bf6fd 100644 --- a/libs/video/renderer/vulkan/vkgen/Makemodule.am +++ b/libs/video/renderer/vulkan/vkgen/Makemodule.am @@ -6,6 +6,7 @@ vkgen_dat_src= \ libs/video/renderer/vulkan/vkgen/vkenum.r \ libs/video/renderer/vulkan/vkgen/vkfieldarray.r \ libs/video/renderer/vulkan/vkgen/vkfieldauto.r \ + libs/video/renderer/vulkan/vkgen/vkfieldcustom.r \ libs/video/renderer/vulkan/vkgen/vkfielddata.r \ libs/video/renderer/vulkan/vkgen/vkfielddef.r \ libs/video/renderer/vulkan/vkgen/vkfieldsingle.r \ diff --git a/libs/video/renderer/vulkan/vkgen/vkfieldcustom.h b/libs/video/renderer/vulkan/vkgen/vkfieldcustom.h new file mode 100644 index 000000000..4b7672a9e --- /dev/null +++ b/libs/video/renderer/vulkan/vkgen/vkfieldcustom.h @@ -0,0 +1,14 @@ +#ifndef __renderer_vulkan_vkgen_vkfieldcustom_h +#define __renderer_vulkan_vkgen_vkfieldcustom_h + +#include "vkfielddef.h" + +@interface CustomField: FieldDef +{ + string pltype; + string parser; + PLItem *fields; +} +@end + +#endif//__renderer_vulkan_vkgen_vkfieldcustom_h diff --git a/libs/video/renderer/vulkan/vkgen/vkfieldcustom.r b/libs/video/renderer/vulkan/vkgen/vkfieldcustom.r new file mode 100644 index 000000000..e00085ac1 --- /dev/null +++ b/libs/video/renderer/vulkan/vkgen/vkfieldcustom.r @@ -0,0 +1,60 @@ +#include + +#include "vkfieldcustom.h" +#include "vkgen.h" +#include "vktype.h" + +@implementation CustomField + +-init:(PLItem *) item struct:(Struct *)strct field:(string)fname +{ + self = [super init:item struct:strct field:fname]; + if (!self) { + return self; + } + + PLItem *desc = [item getObjectForKey:"type"]; + pltype = [[desc getObjectAtIndex:1] string]; + parser = [[desc getObjectAtIndex:2] string]; + + fields = [item getObjectForKey:"fields"]; + return self; +} + +-writeParseData +{ + fprintf (output_file, "static size_t parse_%s_%s_offsets = {\n", + struct_name, field_name); + for (int i = 0, count = [fields count]; i < count; i++) { + string field = [[fields getObjectAtIndex:i] string]; + fprintf (output_file, "\tfield_offset (%s, %s),\n", + struct_name, field); + } + fprintf (output_file, "};\n"); + + fprintf (output_file, "static parse_custom_t parse_%s_%s_data = {\n", + struct_name, field_name); + fprintf (output_file, "\t%s,\n", parser); + fprintf (output_file, "\t&parse_%s_%s_offsets,\n", + struct_name, field_name); + fprintf (output_file, "\t%d,\n", [fields count]); + fprintf (output_file, "};\n"); + return self; +} + +-writeField +{ + fprintf (output_file, "\t{\"%s\", 0, %s, parse_%s, &parse_%s_%s_data},\n", + field_name, pltype, "custom", struct_name, field_name); + return self; +} + +-writeSymbol +{ + fprintf (output_file, + "\t{\"%s\", 0/*FIXME*/, 0/*(void *) field_offset (%s, %s)*/},\n", + field_name, struct_name, "FIXME"); + return self; +} + +@end diff --git a/libs/video/renderer/vulkan/vkgen/vkfielddef.r b/libs/video/renderer/vulkan/vkgen/vkfielddef.r index 9cc35c13a..6aba1df05 100644 --- a/libs/video/renderer/vulkan/vkgen/vkfielddef.r +++ b/libs/video/renderer/vulkan/vkgen/vkfielddef.r @@ -3,6 +3,7 @@ #include "vkfieldarray.h" #include "vkfieldauto.h" +#include "vkfieldcustom.h" #include "vkfielddata.h" #include "vkfielddef.h" #include "vkfieldsingle.h" @@ -31,6 +32,8 @@ switch (record) { case "auto": return [[[AutoField alloc] init:item struct:strct field:fname] autorelease]; + case "custom": + return [[[CustomField alloc] init:item struct:strct field:fname] autorelease]; case "string": return [[[StringField alloc] init:item struct:strct field:fname] autorelease]; case "data": diff --git a/libs/video/renderer/vulkan/vkparse.c b/libs/video/renderer/vulkan/vkparse.c index fbfbdf226..5b198a807 100644 --- a/libs/video/renderer/vulkan/vkparse.c +++ b/libs/video/renderer/vulkan/vkparse.c @@ -56,6 +56,7 @@ #include "QF/Vulkan/instance.h" #include "QF/Vulkan/image.h" #include "QF/Vulkan/renderpass.h" +#include "QF/Vulkan/shader.h" #include "QF/Vulkan/swapchain.h" #include "compat.h" @@ -126,8 +127,16 @@ typedef struct parse_string_s { size_t value_offset; } parse_string_t; -static int parse_uint32_t (const plfield_t *field, const plitem_t *item, - void *data, plitem_t *messages, void *context) +typedef struct parse_custom_s { + int (*parse) (const plitem_t *item, void **data, + plitem_t *messages, parsectx_t *context); + size_t *offsets; + size_t num_offsets; +} parse_custom_t; + +static int +parse_uint32_t (const plfield_t *field, const plitem_t *item, + void *data, plitem_t *messages, void *context) { int ret = 1; const char *valstr = PL_String (item); @@ -154,12 +163,13 @@ static int parse_uint32_t (const plfield_t *field, const plitem_t *item, return ret; } -static int parse_enum (const plfield_t *field, const plitem_t *item, - void *data, plitem_t *messages, void *context) +static int +parse_enum (const plfield_t *field, const plitem_t *item, + void *data, plitem_t *messages, void *context) { int ret = 1; __auto_type enm = (exprenum_t *) field->data; - exprctx_t ectx = *(exprctx_t *)context; + exprctx_t ectx = *((parsectx_t *)context)->ectx; exprval_t result = { enm->type, data }; ectx.symtab = enm->symtab; ectx.result = &result; @@ -172,8 +182,9 @@ static int parse_enum (const plfield_t *field, const plitem_t *item, return ret; } -static int parse_single (const plfield_t *field, const plitem_t *item, - void *data, plitem_t *messages, void *context) +static int +parse_single (const plfield_t *field, const plitem_t *item, + void *data, plitem_t *messages, void *context) { __auto_type single = (parse_single_t *) field->data; void *flddata = (byte *)data + single->value_offset; @@ -197,8 +208,9 @@ static int parse_single (const plfield_t *field, const plitem_t *item, return 1; } -static int parse_array (const plfield_t *field, const plitem_t *item, - void *data, plitem_t *messages, void *context) +static int +parse_array (const plfield_t *field, const plitem_t *item, + void *data, plitem_t *messages, void *context) { __auto_type array = (parse_array_t *) field->data; __auto_type value = (void **) ((byte *)data + array->value_offset); @@ -233,8 +245,9 @@ static int parse_array (const plfield_t *field, const plitem_t *item, return 1; } -static int parse_data (const plfield_t *field, const plitem_t *item, - void *data, plitem_t *messages, void *context) +static int +parse_data (const plfield_t *field, const plitem_t *item, + void *data, plitem_t *messages, void *context) { __auto_type datad = (parse_data_t *) field->data; __auto_type value = (void **) ((byte *)data + datad->value_offset); @@ -257,8 +270,9 @@ static int parse_data (const plfield_t *field, const plitem_t *item, return 1; } -static int parse_string (const plfield_t *field, const plitem_t *item, - void *data, plitem_t *messages, void *context) +static int +parse_string (const plfield_t *field, const plitem_t *item, + void *data, plitem_t *messages, void *context) { __auto_type string = (parse_string_t *) field->data; __auto_type value = (char **) ((byte *)data + string->value_offset); @@ -275,6 +289,18 @@ static int parse_string (const plfield_t *field, const plitem_t *item, return 1; } +static int +parse_custom (const plfield_t *field, const plitem_t *item, + void *data, plitem_t *messages, void *context) +{ + __auto_type custom = (parse_custom_t *) field->data; + void **offsets = alloca (custom->num_offsets * sizeof (void *)); + for (size_t i = 0; i < custom->num_offsets; i++) { + offsets[i] = data + custom->offsets[i]; + } + return custom->parse (item, offsets, messages, context); +} + #include "libs/video/renderer/vulkan/vkparse.cinc" typedef struct qfv_renderpass_s { @@ -331,6 +357,7 @@ QFV_ParseRenderPass (vulkan_ctx_t *ctx, plitem_t *plist) }; exprtab_t vars_tab = { var_syms, 0 }; exprctx_t exprctx = {}; + parsectx_t parsectx = { &exprctx, ctx }; exprctx.external_variables = &vars_tab; exprctx.memsuper = new_memsuper (); @@ -340,7 +367,7 @@ QFV_ParseRenderPass (vulkan_ctx_t *ctx, plitem_t *plist) cexpr_init_symtab (&vars_tab, &exprctx); if (!PL_ParseDictionary (renderpass_fields, plist, - &renderpass_data, messages, &exprctx)) { + &renderpass_data, messages, &parsectx)) { for (int i = 0; i < PL_A_NumObjects (messages); i++) { Sys_Printf ("%s\n", PL_String (PL_ObjectAtIndex (messages, i))); } diff --git a/libs/video/renderer/vulkan/vkparse.h b/libs/video/renderer/vulkan/vkparse.h index ae8a30af9..b95475bda 100644 --- a/libs/video/renderer/vulkan/vkparse.h +++ b/libs/video/renderer/vulkan/vkparse.h @@ -1,9 +1,15 @@ #ifndef __vkparse_h #define __vkparse_h +#include "QF/cexpr.h" #include "QF/Vulkan/renderpass.h" #include "libs/video/renderer/vulkan/vkparse.hinc" +typedef struct parsectx_s { + struct exprctx_s *ectx; + struct vulkan_ctx_s *vctx; +} parsectx_t; + VkRenderPass QFV_ParseRenderPass (vulkan_ctx_t *ctx, plitem_t *plist); void QFV_InitParse (void); diff --git a/libs/video/renderer/vulkan/vkparse.plist b/libs/video/renderer/vulkan/vkparse.plist index 1441a0267..1ba7e8bb4 100644 --- a/libs/video/renderer/vulkan/vkparse.plist +++ b/libs/video/renderer/vulkan/vkparse.plist @@ -3,6 +3,8 @@ VkAttachmentDescription, VkSubpassDescription, VkSubpassDependency, + VkSpecializationInfo, + VkPipelineShaderStageCreateInfo, qfv_swapchain_t, ); parse = { @@ -37,6 +39,35 @@ size = preserveAttachmentCount; values = pPreserveAttachments; }; - } + }; + VkSpecializationInfo = { + mapEntries = { + type = (array, VkSpecializationMapEntry); + size = mapEntryCount; + values = pMapEntries; + }; + data = { + type = data; + size = dataSize; + data = pData; + }; + }; + VkPipelineShaderStageCreateInfo = { + flags = auto; + stage = auto; + name = { + type = string; + string = pName; + }; + module = { + type = (custom, QFString, parse_VkShaderModule); + fields = (module); + }; + specializationInfo = { + type = (single, VkSpecializationInfo); + value = pSpecializationInfo; + }; + }; + VkShaderModuleCreateInfo = skip; } } diff --git a/libs/video/renderer/vulkan/vulkan_vid_common.c b/libs/video/renderer/vulkan/vulkan_vid_common.c index 9c2b021f4..78c4e9add 100644 --- a/libs/video/renderer/vulkan/vulkan_vid_common.c +++ b/libs/video/renderer/vulkan/vulkan_vid_common.c @@ -57,6 +57,7 @@ #include "QF/Vulkan/instance.h" #include "QF/Vulkan/image.h" #include "QF/Vulkan/renderpass.h" +#include "QF/Vulkan/shader.h" #include "QF/Vulkan/swapchain.h" #include "compat.h" @@ -260,7 +261,12 @@ static qfv_pipelinestagepair_t imageLayoutTransitionStages[] = { static plitem_t * qfv_load_pipeline (void) { - return PL_GetPropertyList (quakeforge_pipeline); + static plitem_t *pipeline; + + if (!pipeline) { + pipeline = PL_GetPropertyList (quakeforge_pipeline); + } + return pipeline; } void @@ -269,9 +275,9 @@ Vulkan_CreateRenderPass (vulkan_ctx_t *ctx) plitem_t *item = qfv_load_pipeline (); if (!item || !(item = PL_ObjectForKey (item, "renderpass"))) { - Sys_Printf ("error loading pipeline\n"); + Sys_Printf ("error loading renderpass\n"); } else { - Sys_Printf ("Found renderer def\n"); + Sys_Printf ("Found renderpass def\n"); } qfv_device_t *device = ctx->device; VkDevice dev = device->dev; @@ -391,6 +397,34 @@ Vulkan_DestroyRenderPass (vulkan_ctx_t *ctx) ctx->renderpass.depthImage = 0; } +void +Vulkan_CreatePipelines (vulkan_ctx_t *ctx) +{ + plitem_t *item = qfv_load_pipeline (); + + if (!item || !(item = PL_ObjectForKey (item, "modules"))) { + Sys_Printf ("error loading modules\n"); + } else { + Sys_Printf ("Found modules def\n"); + } + for (int i = PL_A_NumObjects (item); i-- > 0; ) { + plitem_t *mod = PL_ObjectAtIndex (item, i); + const char *name = PL_String (PL_ObjectForKey (mod, "name")); + const char *file = PL_String (PL_ObjectForKey (mod, "file")); + if (!name || !file) { + continue; + } + if (QFV_FindShaderModule (ctx, name)) { + continue; + } + VkShaderModule module = QFV_CreateShaderModule (ctx->device, file); + if (module) { + Sys_Printf ("registering shader %s %p\n", name, module); + QFV_RegisterShaderModule (ctx, name, module); + } + } +} + void Vulkan_CreateFramebuffers (vulkan_ctx_t *ctx) {