diff options
author | quou <quou@disroot.org> | 2024-12-22 22:19:36 +1100 |
---|---|---|
committer | quou <quou@disroot.org> | 2024-12-22 22:19:36 +1100 |
commit | 58245585cbe77e6c03ebe13f29e10393ff3c45b4 (patch) | |
tree | 6c3dcd8e9adcbc699318d4062bb2cf594116702e | |
parent | 82767020e84ec8c1af2e3817fc7efede5497c82d (diff) |
cute asset loading system
-rw-r--r-- | .gitignore | 2 | ||||
-rw-r--r-- | Makefile | 31 | ||||
-rw-r--r-- | asset.cpp | 101 | ||||
-rw-r--r-- | asset.hpp | 41 | ||||
-rw-r--r-- | c2.cpp | 21 | ||||
-rw-r--r-- | packer.c | 82 | ||||
-rw-r--r-- | qstd/Makefile | 7 | ||||
-rw-r--r-- | qstd/pack.c | 165 | ||||
-rw-r--r-- | qstd/pack.h | 40 | ||||
-rw-r--r-- | vid_enums.h | 26 | ||||
-rw-r--r-- | video.cpp | 179 | ||||
-rw-r--r-- | video.hpp | 18 |
12 files changed, 615 insertions, 98 deletions
@@ -7,3 +7,5 @@ tags /qstd/libqstd.a /sc/sc /c2 +/pack +/packer @@ -2,12 +2,13 @@ target = c2 data_dir = data -shaders = data/triangle.csh -tools = qstd cfg sc -objects = app.o c2.o video.o pipeline.o +shaders = $(data_dir)/triangle.csh +packed_files = $(shaders) +tools = qstd cfg sc packer +objects = app.o c2.o video.o pipeline.o asset.o includes = -Iqstd defines = -Dplat_x86 -Dplat_posix -Dplat_x11 -Dallocation_default_alignment=8 -cflags = $(includes) $(defines) $(DEBUG_COMPILE_FLAG) +cflags = -MMD -MF $(basename $@).d $(includes) $(defines) $(DEBUG_COMPILE_FLAG) libs = -lX11 -lm lflags = $(libs) $(DEBUG_LINK_FLAG) @@ -23,19 +24,28 @@ cfg: qstd sc: qstd cfg $(MAKE) -C sc +packer: packer.c | qstd + $(CC) $(cflags) packer.c $(lflags) -Lqstd -lqstd -o packer + +pack: $(packed_files) packer + ./packer pack $(data_dir) $(packed_files) + data/triangle.csh: intermediate/triangle.glsl | $(data_dir) sc - ./sc/sc intermediate/triangle.glsl data/triangle.csh + ./sc/sc intermediate/triangle.glsl $(data_dir)/triangle.csh -app.o: app.cpp app.hpp qstd/memory.h qstd/plat.h +app.o: $(CXX) -c $(cflags) app.cpp -o app.o -video.o: video.cpp video.hpp app.hpp qstd/memory.h qstd/plat.h qstd/str.h sc/sh_enums.h +video.o: $(CXX) -c $(cflags) video.cpp -o video.o -pipeline.o: pipeline.cpp video.hpp qstd/memory.h qstd/plat.h +pipeline.o: $(CXX) -c $(cflags) pipeline.cpp -o pipeline.o -c2.o: c2.cpp app.hpp video.hpp qstd/memory.h qstd/plat.h +asset.o: + $(CXX) -c $(cflags) asset.cpp -o asset.o + +c2.o: $(CXX) -c $(cflags) c2.cpp -o c2.o $(target): $(objects) qstd/libqstd.a @@ -54,3 +64,6 @@ clean: make -C qstd clean make -C cfg clean make -C sc clean + +-include $(objects:%.o=%.d) +-include packer.d diff --git a/asset.cpp b/asset.cpp new file mode 100644 index 0000000..09260e0 --- /dev/null +++ b/asset.cpp @@ -0,0 +1,101 @@ +#include "asset.hpp" + +extern "C" { +#include "memory.h" +#include "pack.h" +#include "plat.h" +#include "str.h" +} + +#define max_asset_types 32 + +struct RLoader { + char magic[4]; + Asset_Loader* loader; +}; + +struct Manager { + RLoader loaders[max_asset_types]; + + Manager() { + int i; + for (i = 0; i < max_asset_types; i++) { + loaders[i].loader = 0; + } + } + + RLoader* find_loader(const char* magic) { + uint32_t hash = hash_string(magic); + int bucket = (int)(hash % max_asset_types); + int i; + for (i = 0; i < max_asset_types; i++) { + RLoader& e = loaders[bucket]; + if (!e.loader || ( + e.magic[0] == magic[0] && + e.magic[1] == magic[1] && + e.magic[2] == magic[2] && + e.magic[3] == magic[3] + )) return &e; + bucket = (bucket + 1) % max_asset_types; + } + return 0; + } + + Asset_Loader& get_loader(const char* magic) { + RLoader* r = find_loader(magic); + assert(r != 0 && r->loader != 0); + return *r->loader; + } + + void set_loader(const char* magic, Asset_Loader* l) { + RLoader* r = find_loader(magic); + assert(r != 0 && r->loader == 0); + r->magic[0] = magic[0]; + r->magic[1] = magic[1]; + r->magic[2] = magic[2]; + r->magic[3] = magic[3]; + r->loader = l; + } +} manager; + +void register_asset_loader( + const char* magic, + Asset_Loader* loader +) { + manager.set_loader(magic, loader); +} + +void Asset_Arena::init(Arena* arena, const char* pack_name) { + p = pack_open(pack_name, arena); + a = arena; + assets = 0; +} + +void Asset_Arena::destroy() { + Asset* a; + for (a = assets; a; a = a->next) { + a->unload(a->loader); + } + pack_close(p); +} + +void Asset_Arena::claim(Asset* a) { + if (assets) { + a->next = assets; + assets = a; + } else assets = a; +} + +Asset* Asset_Arena::load(const char* name) { + char magic[4]; + Pack_File* f = pack_open_file(p, name); + if (!f) return 0; + pack_read(f, magic, 4); + pack_seek(f, 0, seek_rel_start); + Asset_Loader& loader = manager.get_loader(magic); + Asset* asset = loader.load(a, f); + asset->loader = &loader; + pack_close_file(f); + claim(asset); + return asset; +} diff --git a/asset.hpp b/asset.hpp new file mode 100644 index 0000000..27ac990 --- /dev/null +++ b/asset.hpp @@ -0,0 +1,41 @@ +#ifndef asset_hpp +#define asset_hpp + +struct Arena; +struct Asset_Loader; +struct Pack_File; +struct Pack; + +struct Asset { + Asset* next; + Asset_Loader* loader; + virtual bool load( + Asset_Loader* loader, + Arena* a, + Pack_File* f + ) = 0; + virtual void unload(Asset_Loader* loader) = 0; +}; + +struct Asset_Loader { + virtual Asset* load(Arena* a, Pack_File* f) = 0; +}; + +struct Asset_Arena { + Pack* p; + Arena* a; + Asset* assets; + + void init(Arena* arena, const char* pack_name); + void destroy(); + + Asset* load(const char* name); + void claim(Asset* a); +}; + +void register_asset_loader( + const char* magic, + Asset_Loader* loader +); + +#endif @@ -7,6 +7,7 @@ extern "C" { #include <string.h> #define video_arena_size (1024 * 1024 * 16) +#define asset_arena_size (1024 * 1024 * 4) #define per_frame_memory_size (1024 * 1024) static float verts[] = { @@ -24,8 +25,10 @@ struct C2 : public App { int main() { Arena video_arena; + Arena asset_arena; + Asset_Arena assets; Device* dev; - Shader_Id shader; + Shader* shader; Buffer_Id vbo; C2* app = App::create<C2>("c2"); void* per_frame; @@ -35,9 +38,15 @@ int main() { arena_alloc(app->arena, video_arena_size), video_arena_size ); + init_arena( + &asset_arena, + arena_alloc(app->arena, asset_arena_size), + asset_arena_size + ); + assets.init(&asset_arena, "pack"); dev = Device::create(&video_arena, app); app->dev = dev; - shader = dev->load_shader("data/triangle.csh"); + shader = (Shader*)assets.load("triangle.csh"); per_frame = heap_alloc( dev->heap, per_frame_memory_size @@ -68,14 +77,14 @@ int main() { Render_Pass& pass = pb.build_rp(); pb.begin(); - pb.shader(shader); - pb.vertex_format(dev->get_shader(shader).vf); + pb.shader(shader->id); + pb.vertex_format(shader->vf); Pipeline& pip = pb.build(); Vertex_Buffer_Binding binding[] = {{ .id = vbo, .offset = 0, - .target = dev->get_shader(shader).binding_index("verts") + .target = shader->binding_index("verts") }, {}}; Draw draw{}; @@ -90,8 +99,8 @@ int main() { dev->present(); app->end(); } + assets.destroy(); dev->destroy_buffer(vbo); - dev->destroy_shader(shader); dev->destroy(); app->destroy(); } diff --git a/packer.c b/packer.c new file mode 100644 index 0000000..ca1cb4a --- /dev/null +++ b/packer.c @@ -0,0 +1,82 @@ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "memory.h" +#include "pack.h" +#include "plat.h" + +char magic[4] = { 'P', 'A', 'C', 'K' }; +#define buffer_size 1024 + +int main(int argc, const char** argv) { + FILE* outfile; + const char* workingdir, * dsep = ""; + char buffer[buffer_size]; + int file_count = argc - 3, i; + uint32_t coff, table_size; + Pack_Entry* table; + Pack* pack; + if (file_count <= 0) return 0; + if (argc < 3) { + print_err("Usage: %s <outfile> <dir> infile...\n"); + return 3; + } + outfile = fopen(argv[1], "wb"); + if (!outfile) { + print_err("Failed to open %s\n", argv[1]); + return 6; + } + workingdir = argv[2]; + if (workingdir[strlen(workingdir) - 1] != '/') + dsep = "/"; + table_size = sizeof *table * file_count; + pack = malloc(get_pack_size(file_count)); + if (!pack) { + print_err("Out of memory.\n"); + return 1; + } + table = get_pack_table(pack); + for (i = 0; i < file_count; i++) { + table[i].name[0] = 0; + } + pack->filename = 0; + pack->file_count = file_count; + for (i = 0; i < file_count; i++) { + Pack_Entry* e; + e = pack_find_entry(pack, argv[i + 3]); + if (!e || e->name[0]) { + print_err("Hash table error.\n"); + return 5; + } + strcpy(e->name, argv[i + 3] + strlen(workingdir) + strlen(dsep)); + } + fwrite(magic, 1, 4, outfile); + fwrite(&pack->file_count, 1, 4, outfile); + fwrite(table, 1, table_size, outfile); + coff = ftell(outfile); + for (i = 0; i < file_count; i++) { + FILE* infile; + Pack_Entry* e = &table[i]; + uint32_t j; + infile = fopen(argv[i + 3], "rb"); + if (!infile) { + print_err("Failed to open %s.\n", argv[i + 3]); + return 6; + } + fseek(infile, 0, SEEK_END); + e->size = ftell(infile); + e->offset = coff; + rewind(infile); + fseek(outfile, e->offset, SEEK_SET); + for (j = 0; j < e->size; j += buffer_size) { + int read = fread(buffer, 1, buffer_size, infile); + fwrite(buffer, 1, read, outfile); + } + coff += e->size; + } + fseek(outfile, 8, SEEK_SET); + fwrite(table, 1, table_size, outfile); + fclose(outfile); + return 0; +} diff --git a/qstd/Makefile b/qstd/Makefile index 3c4b6a8..c4b088b 100644 --- a/qstd/Makefile +++ b/qstd/Makefile @@ -5,7 +5,7 @@ defines = -Dplat_x86 -Dplat_posix -Dallocation_default_alignment=8 cflags = -std=c90 -pedantic -Wall -Wextra $(DEBUG_COMPILE_FLAG) $(includes) $(defines) lflags = $(DEBUG_LINK_FLAG) -objects = plat.o memory.o str.o +objects = plat.o memory.o str.o pack.o .PHONY: all clean @@ -17,9 +17,12 @@ memory.o: memory.c memory.h plat.h plat.o: plat.c plat.h $(CC) -c $(cflags) plat.c -o plat.o -str.o: str.c str.h +str.o: str.c str.h memory.h $(CC) -c $(cflags) str.c -o str.o +pack.o: pack.c pack.h str.h plat.h memory.h + $(CC) -c $(cflags) pack.c -o pack.o + $(target): $(objects) $(AR) -rcs $(target) $(objects) diff --git a/qstd/pack.c b/qstd/pack.c new file mode 100644 index 0000000..e9ca0c3 --- /dev/null +++ b/qstd/pack.c @@ -0,0 +1,165 @@ +#include "memory.h" +#include "pack.h" +#include "plat.h" +#include "str.h" + +#include <stddef.h> +#include <stdint.h> +#include <stdio.h> + +#define pack_max_files 4 + +typedef struct Pack_File { + FILE* handle; + Pack_Entry* entry; + int offset; +} Pack_File; + +Pack_Entry* get_pack_table(Pack* p) { + return (Pack_Entry*)( + (char*)&p[1] + pack_max_files * sizeof(Pack_File) + ); +} + +int get_pack_size(int entry_count) { + return sizeof(Pack) + + pack_max_files * sizeof(Pack_File) + + entry_count * sizeof(Pack_Entry); +} + +Pack_Entry* pack_find_entry(Pack* p, const char* name) { + Pack_Entry* tab = get_pack_table(p); + uint32_t hash = hash_string(name); + int idx = (int)(hash % p->file_count), i; + int e = (int)p->file_count; + for (i = 0; i < e; i++) { + Pack_Entry* e = &tab[idx]; + if (!e->name[0] || string_equal(name, e->name)) + return e; + idx = (int)((idx + 1) % p->file_count); + } + return 0; +} + +static void insert_entry(Pack* p, const Pack_Entry* e) { + Pack_Entry* d = pack_find_entry(p, e->name); + assert(d != 0); + if (d->name[0]) + print_war("Duplicate entry in %s: %s\n", p->filename, e->name); + *d = *e; +} + +static void read_table(Pack* p, FILE* f) { + uint32_t i, e = p->file_count; + Pack_Entry* tab = get_pack_table(p); + for (i = 0; i < e; i++) + tab[i].name[0] = 0; + for (i = 0; i < e; i++) { + Pack_Entry e; + fread(&e, sizeof e, 1, f); + insert_entry(p, &e); + } +} + +static void init_files(Pack* p) { + int i; + Pack_File* files = (Pack_File*)&p[1]; + for (i = 0; i < pack_max_files; i++) { + files[i].handle = 0; + } +} + +Pack* pack_open(const char* filename, Arena* a) { + Pack* p; + char magic[4]; + uint32_t entry_count; + FILE* f = fopen(filename, "rb"); + if (!f) return 0; + fread(magic, 1, 4, f); + if ( + magic[0] != 'P' || + magic[1] != 'A' || + magic[2] != 'C' || + magic[3] != 'K' + ) { + fclose(f); + return 0; + } + fread(&entry_count, 4, 1, f); + p = arena_alloc(a, get_pack_size(entry_count)); + p->filename = dup_string(a, filename); + p->file_count = entry_count; + init_files(p); + read_table(p, f); + fclose(f); + return p; +} + +void pack_close(Pack* p) { + (void)p; +} + +Pack_Entry* pack_get_entry(Pack* p, const char* name) { + Pack_Entry* e = pack_find_entry(p, name); + if (!e || e->name[0] == 0) return 0; + return e; +} + +static Pack_File* init_handle( + Pack* p, + Pack_File* h, + const char* name +) { + FILE* f; + Pack_Entry* e = pack_find_entry(p, name); + if (!e || !e->name[0]) return 0; + f = fopen(p->filename, "rb"); + if (!f) return 0; + h->offset = 0; + h->handle = f; + h->entry = e; + return h; +} + +Pack_File* pack_open_file(Pack* p, const char* name) { + int i; + Pack_File* files = (Pack_File*)&p[1]; + for (i = 0; i < pack_max_files; i++) { + Pack_File* file = &files[i]; + if (!file->handle) + return init_handle(p, file, name); + } + return 0; +} + +void pack_close_file(Pack_File* f) { + fclose(f->handle); +} + +int pack_read(Pack_File* f, void* buf, int size) { + int diff = (f->offset + size) - f->entry->size; + int read; + if (diff > 0) size -= diff; + fseek(f->handle, f->entry->offset + f->offset, SEEK_SET); + read = fread(buf, 1, size, f->handle); + f->offset += read; + return read; +} + +void pack_seek(Pack_File* f, int offset, Seek_Rel rel) { + switch (rel) { + case seek_rel_cur: + f->offset += offset; + break; + case seek_rel_start: + f->offset = offset; + break; + case seek_rel_end: + f->offset = f->entry->size - offset; + break; + } +} + +int pack_tell(Pack_File* f) { + return f->offset; +} diff --git a/qstd/pack.h b/qstd/pack.h new file mode 100644 index 0000000..447cd5b --- /dev/null +++ b/qstd/pack.h @@ -0,0 +1,40 @@ +#ifndef pack_h +#define pack_h + +#include <stdint.h> + +struct Arena; +struct Pack_File; + +typedef struct { + char name[56]; + uint32_t offset; + uint32_t size; +} Pack_Entry; + +typedef struct Pack { + char* filename; + uint32_t file_count; +} Pack; + +Pack_Entry* pack_find_entry(Pack* p, const char* name); +Pack_Entry* get_pack_table(Pack* p); +int get_pack_size(int entry_count); + +Pack* pack_open(const char* filename, struct Arena* a); +void pack_close(Pack* p); +Pack_Entry* pack_get_entry(Pack* p, const char* name); + +typedef enum { + seek_rel_cur, + seek_rel_start, + seek_rel_end +} Seek_Rel; + +struct Pack_File* pack_open_file(Pack* p, const char* name); +void pack_close_file(struct Pack_File* h); +int pack_read(struct Pack_File* f, void* buf, int size); +void pack_seek(struct Pack_File* f, int offset, Seek_Rel rel); +int pack_tell(struct Pack_File* f); + +#endif diff --git a/vid_enums.h b/vid_enums.h new file mode 100644 index 0000000..fca4f06 --- /dev/null +++ b/vid_enums.h @@ -0,0 +1,26 @@ +#ifndef vid_enums_h +#define vid_enums_h + +#define texture_format_xmacro() \ + x(r8i) \ + x(r16f) \ + x(r32f) \ + x(rg8i) \ + x(rg16f) \ + x(rg32f) \ + x(rgb8i) \ + x(rgb16f) \ + x(rgb32f) \ + x(rgba8i) \ + x(rgba16f) \ + x(rgba32f) \ + x(bc1) + +typedef enum { +#define x(n) texture_format_ ## n, + texture_format_xmacro() +#undef x + texture_format_count +} Texture_Format; + +#endif @@ -11,9 +11,10 @@ extern "C" { #include "memory.h" +#include "pack.h" #include "plat.h" -#include "str.h" #include "sc/sh_enums.h" +#include "str.h" } #include <algorithm> @@ -337,7 +338,7 @@ struct Shader_Vk : public Shader { int attr_count; int binding_count; - bool init(Device_Vk* dev, FILE* f); + bool init(Device_Vk* dev, Pack_File* f); void destroy(Device_Vk* dev); int find_binding(const char* name); @@ -349,7 +350,7 @@ struct Shader_Vk : public Shader { char entrypoints[shader_type_count][24]; Vertex_Format vfd; - bool init(Device_Vk* dev, FILE* f); + bool init(Device_Vk* dev, Pack_File* f); bool init_module( Device_Vk* dev, int stage, @@ -596,6 +597,12 @@ struct std::hash<Render_Pass> { } }; +struct Shader_Loader : public Asset_Loader { + Device_Vk* dev; + void init(Device_Vk* d); + Asset* load(Arena* a, Pack_File* f) override; +}; + struct Device_Vk : public Device { VkAllocationCallbacks ac; VkInstance inst; @@ -611,6 +618,7 @@ struct Device_Vk : public Device { Swapchain swapchain; Context_Vk contexts[max_contexts]; Context_Vk* current_ctx; + Shader_Loader shader_loader; #ifdef DEBUG VkDebugUtilsMessengerEXT msg; #endif @@ -971,6 +979,8 @@ void Device_Vk::init_internal() { shader_count = 1; rpo_cache.init(); pso_cache.init(); + shader_loader.init(this); + register_asset_loader("CSH2", &shader_loader); find_exts(exts, ext_count); init_ac(); create_inst(exts, ext_count); @@ -1983,52 +1993,6 @@ void Vertex_Format_Vk::destroy(Device_Vk* dev) { heap_free(dev->heap, bindings); } -/* todo proper asset manager which will load this stuff */ -bool Shader_Vk::init(Device_Vk* dev, FILE* f) { - char magic[4]; - int binding_count, target_count, i; - fread(magic, 4, 1, f); - if ( - magic[0] != 'C' || - magic[1] != 'S' || - magic[2] != 'H' || - magic[3] != '2' - ) return false; - fread(&type, 4, 1, f); - fread(&binding_count, 4, 1, f); - fread(&target_count, 4, 1, f); - vfd.binding_count = binding_count; - assert(binding_count); - if (!vfd.init(dev, f)) - return false; - vf = dev->create_vf(*this); - fseek( - f, - 32 * target_count, - SEEK_CUR - ); - for (i = 0; i < shader_type_count; i++) { - int o, s; - fread(&o, 4, 1, f); - fread(&s, 4, 1, f); - if (o) { - bool r; - int before = ftell(f); - char* buf = (char*)heap_alloc(dev->heap, s); - fseek(f, o, SEEK_SET); - fread(buf, 1, s, f); - r = init_module(dev, i, buf, s); - heap_free(dev->heap, buf); - fseek(f, before, SEEK_SET); - if (!r) return false; - } else { - modules[i] = VK_NULL_HANDLE; - } - fread(entrypoints[i], 1, 24, f); - } - return true; -} - bool Shader_Vk::init_module( Device_Vk* dev, int stage, @@ -2076,27 +2040,27 @@ int Shader_Vk::Vertex_Format::find_attribute(const char* name) { bool Shader_Vk::Vertex_Format::init( Device_Vk* dev, - FILE* f + Pack_File* f ) { int i, attr_index = 0; - int start = ftell(f); + int start = pack_tell(f); attr_count = 0; for (i = 0; i < binding_count; i++) { char name[24]; int count, j; SBinding_Rate rate; - fread(name, 1, sizeof name, f); - fread(&rate, 4, 1, f); - fread(&count, 4, 1, f); + pack_read(f, name, sizeof name); + pack_read(f, &rate, 4); + pack_read(f, &count, 4); for (j = 0; j < count; j++) { char aname[28]; SVariable_Type type; - fread(aname, 1, sizeof aname, f); - fread(&type, 4, 1, f); + pack_read(f, aname, sizeof aname); + pack_read(f, &type, 4); attr_count++; } } - fseek(f, start, SEEK_SET); + pack_seek(f, start, seek_rel_start); bindings = (Binding*)heap_alloc( dev->heap, binding_count * sizeof *bindings @@ -2114,9 +2078,9 @@ bool Shader_Vk::Vertex_Format::init( char name[24]; int count, j; SBinding_Rate rate; - fread(name, 1, sizeof name, f); - fread(&rate, 4, 1, f); - fread(&count, 4, 1, f); + pack_read(f, name, sizeof name); + pack_read(f, &rate, 4); + pack_read(f, &count, 4); binding = &bindings[find_binding(name)]; strcpy(binding->name, name); binding->rate = rate; @@ -2131,8 +2095,8 @@ bool Shader_Vk::Vertex_Format::init( Attribute* attr; char aname[28]; SVariable_Type type; - fread(aname, 1, sizeof aname, f); - fread(&type, 4, 1, f); + pack_read(f, aname, sizeof aname); + pack_read(f, &type, 4); bucket = find_attribute(aname); binding->attributes[j] = bucket; attr = &attributes[bucket]; @@ -2276,27 +2240,86 @@ Shader& Device::get_shader(Shader_Id id) { return ((Device_Vk*)this)->shaders[id]; } -Shader_Id Device::load_shader(const char* fname) { - FILE* f = fopen(fname, "rb"); +bool Shader::load( + Asset_Loader* loader, + Arena* a, + Pack_File* f +) { + Device_Vk* dev = ((Shader_Loader*)loader)->dev; + Shader_Vk& sh = *(Shader_Vk*)this; + return sh.init(dev, f); +} + +void Shader::unload(Asset_Loader* loader_) { + Shader_Loader* loader = (Shader_Loader*)loader_; + Device_Vk* dev = loader->dev; + Shader_Vk& sh = *(Shader_Vk*)this; + sh.destroy(dev); + dev->shaders.remove(id); +} + +void Shader_Loader::init(Device_Vk* d) { + dev = d; +} + +Asset* Shader_Loader::load( + Arena* a, + Pack_File* f +) { Shader_Vk* s; - Device_Vk* dev = (Device_Vk*)this; Shader_Id id; - bool r; - if (!f) return Shader_Id(0); id = dev->alloc_shader(); - s = (Shader_Vk*)&get_shader(id); - r = s->init(dev, f); - fclose(f); - if (!r) { - heap_free(heap, s); + s = (Shader_Vk*)&dev->get_shader(id); + s->id = id; + if (!s->load(this, a, f)) { + dev->shaders.remove(id); return 0; } - return id; + return s; } -void Device::destroy_shader(Shader_Id id) { - Device_Vk* dev = (Device_Vk*)this; - Shader_Vk& buf = *(Shader_Vk*)&get_shader(id); - buf.destroy(dev); - dev->shaders.remove(id); +bool Shader_Vk::init(Device_Vk* dev, Pack_File* f) { + char magic[4]; + int binding_count, target_count, i; + pack_read(f, magic, 4); + if ( + magic[0] != 'C' || + magic[1] != 'S' || + magic[2] != 'H' || + magic[3] != '2' + ) return false; + pack_read(f, &type, 4); + pack_read(f, &binding_count, 4); + pack_read(f, &target_count, 4); + vfd.binding_count = binding_count; + assert(binding_count); + if (!vfd.init(dev, f)) + return false; + vf = dev->create_vf(*this); + pack_seek( + f, + 32 * target_count, + seek_rel_cur + ); + 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; + } else { + modules[i] = VK_NULL_HANDLE; + } + pack_read(f, entrypoints[i], 24); + } + return true; } + @@ -4,6 +4,12 @@ #include <stddef.h> #include <stdint.h> +extern "C" { +#include "vid_enums.h" +} + +#include "asset.hpp" + struct App; struct Arena; struct Heap; @@ -139,9 +145,7 @@ struct Device { Buffer& get_buffer(Buffer_Id id); void destroy_buffer(Buffer_Id id); - Shader_Id load_shader(const char* fname); Shader& get_shader(Shader_Id id); - void destroy_shader(Shader_Id id); }; struct Context { @@ -162,7 +166,8 @@ struct Context { void submit(Device& d, const Render_Pass& rp); }; -struct Shader { +struct Shader : public Asset { + Shader_Id id; Vertex_Format_Id vf; void destroy(Device* dev); @@ -170,6 +175,13 @@ struct Shader { int binding_index(const char* name); int attribute_index(const char* name); int target_index(const char* name); + + bool load( + Asset_Loader* loader, + Arena* a, + Pack_File* f + ) override; + void unload(Asset_Loader* loader) override; }; #endif |