mirror of
https://git.code.sf.net/p/quake/quakeforge
synced 2025-01-18 15:01:41 +00:00
[vulkan] Add support for custom parsers
And provisionally parse shader stage defs.
This commit is contained in:
parent
017d2c1f44
commit
25ade4c0f3
15 changed files with 261 additions and 40 deletions
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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 = (
|
||||
{
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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 \
|
||||
|
|
14
libs/video/renderer/vulkan/vkgen/vkfieldcustom.h
Normal file
14
libs/video/renderer/vulkan/vkgen/vkfieldcustom.h
Normal 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
|
60
libs/video/renderer/vulkan/vkgen/vkfieldcustom.r
Normal file
60
libs/video/renderer/vulkan/vkgen/vkfieldcustom.r
Normal 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
|
|
@ -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":
|
||||
|
|
|
@ -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)));
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
Loading…
Reference in a new issue