[vulkan] Add support for custom parsers

And provisionally parse shader stage defs.
This commit is contained in:
Bill Currie 2020-12-24 01:36:17 +09:00
parent 017d2c1f44
commit 25ade4c0f3
15 changed files with 261 additions and 40 deletions

View file

@ -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);

View file

@ -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);

View file

@ -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

View file

@ -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;

View file

@ -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)
{

View file

@ -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 = (
{

View file

@ -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;
}

View file

@ -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 \

View file

@ -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

View file

@ -0,0 +1,60 @@
#include <PropertyList.h>
#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

View file

@ -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":

View file

@ -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)));
}

View file

@ -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);

View file

@ -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;
}
}

View file

@ -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)
{