summaryrefslogtreecommitdiff
path: root/video.cpp
diff options
context:
space:
mode:
authorquou <quou@disroot.org>2025-03-14 21:23:41 +1100
committerquou <quou@disroot.org>2025-03-14 21:23:41 +1100
commit750b192a0229ecf401fbe4dd727725a6ef5350d9 (patch)
tree7b08bc8d891ea1b6c6c097d4f55b089adbd58ca6 /video.cpp
parentdae6866161ca59a6b23b41ae7008411116127f76 (diff)
implementing shader variants
Diffstat (limited to 'video.cpp')
-rw-r--r--video.cpp173
1 files changed, 141 insertions, 32 deletions
diff --git a/video.cpp b/video.cpp
index 9e2699e..b4c5897 100644
--- a/video.cpp
+++ b/video.cpp
@@ -430,6 +430,12 @@ enum {
context_state_init = 1 << 1
};
+
+struct Shader_Module {
+ int mask;
+ VkShaderModule mod;
+};
+
struct Shader_Vk : public Shader, public Late_Terminated {
struct Attribute {
char name[28];
@@ -464,23 +470,31 @@ struct Shader_Vk : public Shader, public Late_Terminated {
int stage;
};
+ struct Option {
+ char name[24];
+ int mask;
+ int stage;
+ };
+
SProgram_Type type;
- VkShaderModule modules[shader_type_count];
- char entrypoints[shader_type_count][24];
Vertex_Format vfd;
Desc* descs;
- int desc_count;
+ Shader_Module* modules[shader_type_count];
+ Option* options;
+ int desc_count, opt_count;
+ int module_count[shader_type_count];
- bool init(Device_Vk* dev, Pack_File* f);
- bool init_module(
+ bool init(Device_Vk* dev, Arena* a, Pack_File* f);
+ VkShaderModule make_module(
Device_Vk* dev,
- int stage,
char* buf,
int size
);
void destroy(Device_Vk* dev) override;
int find_descriptor(const char* name);
+ int find_module(Shader_Type type, int mask);
+ int find_opt(Shader_Type, const char* name);
static VkShaderStageFlagBits stage(Shader_Type type) {
switch (type) {
@@ -2811,12 +2825,24 @@ void Pipeline_Vk::init_stages(
zero(sis, sizeof *sis * count);
for (i = 0, count = 0; i < shader_type_count; i++) {
if (shader.modules[i]) {
+ int idx = shader.find_module(
+ (Shader_Type)i,
+ desc.shader_masks[i]
+ );
+ VkShaderModule mod;
+ if (idx < 0) {
+ mod = shader.modules[i][0].mod;
+ print_war("Shader variant not found; using the default >~<\n");
+ print(" ^ mask was 0x%x\n", desc.shader_masks[i]);
+ } else
+ mod = shader.modules[i][idx].mod;
+ assert(idx >= 0);
auto& si = sis[i];
si.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
si.flags = 0;
si.stage = Shader_Vk::stage((Shader_Type)i);
- si.module = shader.modules[i];
- si.pName = shader.entrypoints[i];
+ si.module = mod;
+ si.pName = "main";
count++;
}
}
@@ -3396,9 +3422,8 @@ void Vertex_Format_Vk::optimise(const Vertex_Format_Vk* shadervf) {
}
}
-bool Shader_Vk::init_module(
+VkShaderModule Shader_Vk::make_module(
Device_Vk* dev,
- int stage,
char* buf,
int size
) {
@@ -3409,8 +3434,9 @@ bool Shader_Vk::init_module(
mi.codeSize = size;
mi.pCode = (uint32_t*)buf;
r = vkCreateShaderModule(dev->dev, &mi, &dev->ac, &m);
- modules[stage] = m;
- return r == VK_SUCCESS;
+ if (r == VK_SUCCESS)
+ return m;
+ return 0;
}
int Shader_Vk::Vertex_Format::find_binding(const char* name) {
@@ -3522,8 +3548,11 @@ void Shader_Vk::Vertex_Format::destroy(Device_Vk* dev) {
void Shader_Vk::destroy(Device_Vk* dev) {
int i;
for (i = 0; i < shader_type_count; i++)
- if (modules[i])
- vkDestroyShaderModule(dev->dev, modules[i], &dev->ac);
+ if (modules[i]) {
+ int j, e = module_count[i];
+ for (j = 0; j < e; j++)
+ vkDestroyShaderModule(dev->dev, modules[i][j].mod, &dev->ac);
+ }
vfd.destroy(dev);
heap_free(dev->heap, descs);
dev->destroy_vertex_format(vf);
@@ -3554,6 +3583,11 @@ int Shader::descriptor_binding(const char* name) {
return sh->descs[idx].slot;
}
+int Shader::opt_mask(Shader_Type type, const char* name) {
+ Shader_Vk* sh = (Shader_Vk*)this;
+ return sh->find_opt(type, name);
+}
+
int Shader::descriptor_stage(int slot) {
Shader_Vk* sh = (Shader_Vk*)this;
int i;
@@ -3909,11 +3943,10 @@ Asset* Shader_Loader::load(
Shader_Vk* shader;
Shader_Id id;
(void)s;
- (void)a;
(void)filename;
id = dev->alloc_shader();
shader = (Shader_Vk*)&dev->get_shader(id);
- if (!shader->init(dev, f)) {
+ if (!shader->init(dev, a, f)) {
dev->shaders.remove(id);
return 0;
}
@@ -3939,7 +3972,46 @@ int Shader_Vk::find_descriptor(const char* name) {
return -1;
}
-bool Shader_Vk::init(Device_Vk* dev, Pack_File* f) {
+int Shader_Vk::find_module(
+ Shader_Type type,
+ int mask
+) {
+ int i;
+ int count = module_count[type];
+ Shader_Module* arr = modules[type];
+ int bucket = (int)(
+ fnv1a64((uint8_t*)&mask, sizeof mask) %
+ count
+ );
+ for (i = 0; i < count; i++) {
+ Shader_Module& mod = arr[bucket];
+ if (mod.mask == mask)
+ return bucket;
+ bucket = (bucket + 1) % count;
+ }
+ return -1;
+}
+
+int Shader_Vk::find_opt(
+ Shader_Type type,
+ const char* name
+) {
+ int count = module_count[type], i;
+ int bucket = (int)(
+ hash_string(name) %
+ count
+ );
+ int stage = 1 << type;
+ for (i = 0; i < count; i++) {
+ Option& o = options[bucket];
+ if (string_equal(name, o.name) && (o.stage & stage))
+ return o.mask;
+ bucket = (bucket + 1) % count;
+ }
+ return 0;
+}
+
+bool Shader_Vk::init(Device_Vk* dev, Arena* a, Pack_File* f) {
char magic[4];
int binding_count, target_count, i;
pack_read(f, magic, 4);
@@ -3953,6 +4025,7 @@ bool Shader_Vk::init(Device_Vk* dev, Pack_File* f) {
pack_read(f, &binding_count, 4);
pack_read(f, &target_count, 4);
pack_read(f, &desc_count, 4);
+ pack_read(f, &opt_count, 4);
assert(binding_count);
vfd.binding_count = binding_count;
if (!vfd.init(dev, f))
@@ -4000,24 +4073,60 @@ bool Shader_Vk::init(Device_Vk* dev, Pack_File* f) {
desc_count * sizeof *descs
);
pack_read(f, descs, desc_count * sizeof *descs);
+ options = (Option*)arena_alloc(
+ a,
+ opt_count * sizeof *options
+ );
+ pack_read(f, options, opt_count * sizeof *options);
for (i = 0; i < shader_type_count; i++) {
- int o, s;
- pack_read(f, &o, 4);
- pack_read(f, &s, 4);
- if (o) {
- bool r;
- int before = pack_tell(f);
- char* buf = (char*)heap_alloc(dev->heap, s);
- pack_seek(f, o, seek_rel_start);
- pack_read(f, buf, s);
- r = init_module(dev, i, buf, s);
- heap_free(dev->heap, buf);
- pack_seek(f, before, seek_rel_start);
- if (!r) return false;
+ int c;
+ pack_read(f, &c, 4);
+ module_count[i] = c;
+ if (c) {
+ int o, s, mask;
+ int bucket, j;
+ Shader_Module* m = (Shader_Module*)arena_alloc(
+ a,
+ c * sizeof *m
+ );
+ for (j = 0; j < c; j++) {
+ m[j].mask = -1;
+ }
+ for (j = 0; j < c; j++) {
+ int k;
+ pack_read(f, &o, 4); /* H_Variant */
+ pack_read(f, &s, 4);
+ pack_read(f, &mask, 4);
+ pack_seek(f, 4, seek_rel_cur);
+ bucket = (int)(
+ fnv1a64((uint8_t*)&m, sizeof m) %
+ c
+ );
+ for (k = 0; k < c; k++) {
+ Shader_Module& mod = m[bucket];
+ if (mod.mask == -1)
+ goto found;
+ bucket = (bucket + 1) % c;
+ }
+ assert(0);
+ {
+ found:
+ char* buf = (char*)heap_alloc(dev->heap, s);
+ VkShaderModule r;
+ int before = pack_tell(f);
+ pack_seek(f, o, seek_rel_start);
+ pack_read(f, buf, s);
+ r = make_module(dev, buf, s);
+ heap_free(dev->heap, buf);
+ pack_seek(f, before, seek_rel_start);
+ if (!r) return false;
+ m[bucket] = Shader_Module { mask, r };
+ }
+ }
+ modules[i] = m;
} else {
- modules[i] = VK_NULL_HANDLE;
+ modules[i] = 0;
}
- pack_read(f, entrypoints[i], 24);
}
return true;
}