From 719e9a06aea113ce5c11216ed1340914869da517 Mon Sep 17 00:00:00 2001 From: Interrupt Date: Mon, 23 Sep 2024 21:30:28 -0700 Subject: [PATCH 1/2] Loading shaders returns an error instead of null now --- .../platform/backends/sokol/graphics.zig | 68 +++++++------------ src/framework/platform/graphics.zig | 22 +++--- 2 files changed, 34 insertions(+), 56 deletions(-) diff --git a/src/framework/platform/backends/sokol/graphics.zig b/src/framework/platform/backends/sokol/graphics.zig index 53a7fe10..6af6a294 100644 --- a/src/framework/platform/backends/sokol/graphics.zig +++ b/src/framework/platform/backends/sokol/graphics.zig @@ -21,6 +21,10 @@ pub const Shader = graphics.Shader; // the list of layouts to automatically create Pipelines for const common_vertex_layouts = graphics.getCommonVertexLayouts(); +const ShaderInitError = error{ + ShaderNotFound, +}; + pub const BindingsImpl = struct { sokol_bindings: ?sg.Bindings, default_sokol_sampler: sg.Sampler = undefined, @@ -238,17 +242,17 @@ pub const ShaderImpl = struct { sokol_pipelines: *std.ArrayList(PipelineBinding), /// Create a new shader using the default - pub fn initDefault(cfg: graphics.ShaderConfig) Shader { - return initFromBuiltin(cfg, shader_default).?; + pub fn initDefault(cfg: graphics.ShaderConfig) !Shader { + return try initFromBuiltin(cfg, shader_default); } /// Creates a shader from a shader built in as a zig file - pub fn initFromBuiltin(cfg: graphics.ShaderConfig, comptime builtin: anytype) ?Shader { + pub fn initFromBuiltin(cfg: graphics.ShaderConfig, comptime builtin: anytype) !Shader { const shader_desc_fn = getBuiltinSokolCreateFunction(builtin); if (shader_desc_fn == null) - return null; + return ShaderInitError.ShaderNotFound; - return initSokolShader(cfg, shader_desc_fn.?(sg.queryBackend())); + return try initSokolShader(cfg, shader_desc_fn.?(sg.queryBackend())); } fn terminateString(allocator: std.mem.Allocator, in_string: []const u8) ![:0]const u8 { @@ -327,7 +331,7 @@ pub const ShaderImpl = struct { } /// Creates a shader from a ShaderDefinition struct - pub fn initFromShaderInfo(cfg: graphics.ShaderConfig, shader_info: shaders.ShaderInfo) ?Shader { + pub fn initFromShaderInfo(cfg: graphics.ShaderConfig, shader_info: shaders.ShaderInfo) !Shader { var arena = std.heap.ArenaAllocator.init(mem.getAllocator()); defer arena.deinit(); const allocator = arena.allocator(); @@ -343,13 +347,8 @@ pub const ShaderImpl = struct { // Assume there is only one shader program for now, that appears to be true. const shader_program = shader_info.shader_def.programs[0]; - const vs_entry = terminateString(allocator, shader_program.vs.entry_point) catch { - return null; - }; - - const fs_entry = terminateString(allocator, shader_program.fs.entry_point) catch { - return null; - }; + const vs_entry = try terminateString(allocator, shader_program.vs.entry_point); + const fs_entry = try terminateString(allocator, shader_program.fs.entry_point); var desc: sg.ShaderDesc = .{}; desc.label = "shader"; // does this matter? @@ -365,10 +364,7 @@ pub const ShaderImpl = struct { desc.vs.uniform_blocks[block.slot].layout = .STD140; for (block.uniforms, 0..) |uniform, i| { - const uniform_name = terminateString(allocator, uniform.name) catch { - return null; - }; - + const uniform_name = try terminateString(allocator, uniform.name); desc.vs.uniform_blocks[block.slot].uniforms[i].name = uniform_name.ptr; desc.vs.uniform_blocks[block.slot].uniforms[i].type = stringUniformTypeToSokolType(uniform.type); desc.vs.uniform_blocks[block.slot].uniforms[i].array_count = uniform.array_count; @@ -383,10 +379,7 @@ pub const ShaderImpl = struct { desc.vs.images[img.slot].multisampled = stringBool(img.multisampled); desc.vs.images[img.slot].image_type = stringImageTypeToSokolType(img.type); desc.vs.images[img.slot].sample_type = stringImageSampleTypeToSokolType(img.sample_type); - - vs_images_hashmap.put(img.name, img.slot) catch { - return null; - }; + try vs_images_hashmap.put(img.name, img.slot); } } @@ -395,10 +388,7 @@ pub const ShaderImpl = struct { for (samplers) |sample| { desc.vs.samplers[sample.slot].used = true; desc.vs.samplers[sample.slot].sampler_type = stringSampleTypeToSokolType(sample.sampler_type); - - vs_samplers_hashmap.put(sample.name, sample.slot) catch { - return null; - }; + try vs_samplers_hashmap.put(sample.name, sample.slot); } } @@ -422,10 +412,7 @@ pub const ShaderImpl = struct { desc.fs.uniform_blocks[block.slot].layout = .STD140; for (block.uniforms, 0..) |uniform, i| { - const uniform_name = terminateString(allocator, uniform.name) catch { - return null; - }; - + const uniform_name = try terminateString(allocator, uniform.name); desc.fs.uniform_blocks[block.slot].uniforms[i].name = uniform_name.ptr; desc.fs.uniform_blocks[block.slot].uniforms[i].type = stringUniformTypeToSokolType(uniform.type); desc.fs.uniform_blocks[block.slot].uniforms[i].array_count = uniform.array_count; @@ -440,10 +427,7 @@ pub const ShaderImpl = struct { desc.fs.images[img.slot].multisampled = stringBool(img.multisampled); desc.fs.images[img.slot].image_type = stringImageTypeToSokolType(img.type); desc.fs.images[img.slot].sample_type = stringImageSampleTypeToSokolType(img.sample_type); - - fs_images_hashmap.put(img.name, img.slot) catch { - return null; - }; + try fs_images_hashmap.put(img.name, img.slot); } } @@ -452,10 +436,7 @@ pub const ShaderImpl = struct { for (samplers) |sample| { desc.fs.samplers[sample.slot].used = true; desc.fs.samplers[sample.slot].sampler_type = stringSampleTypeToSokolType(sample.sampler_type); - - fs_samplers_hashmap.put(sample.name, sample.slot) catch { - return null; - }; + try fs_samplers_hashmap.put(sample.name, sample.slot); } } @@ -481,10 +462,10 @@ pub const ShaderImpl = struct { var updated_cfg = cfg; updated_cfg.shader_program_def = shader_program; - return initSokolShader(updated_cfg, desc); + return try initSokolShader(updated_cfg, desc); } - pub fn makeNewInstance(cfg: graphics.ShaderConfig, shader: ?Shader) Shader { + pub fn makeNewInstance(cfg: graphics.ShaderConfig, shader: ?Shader) !Shader { if (shader) |*s| { const pipeline_list = graphics.allocator.create(std.ArrayList(PipelineBinding)) catch { debug.err("Could not create new shader instance!", .{}); @@ -502,7 +483,7 @@ pub const ShaderImpl = struct { // fallback shader! // TODO: Should we return null instead? - return initDefault(cfg); + return try initDefault(cfg); } /// Find the shader function in the builtin that can actually make the ShaderDesc @@ -567,7 +548,7 @@ pub const ShaderImpl = struct { } /// Create a shader from a Sokol Shader Description - useful for loading built-in shaders - pub fn initSokolShader(cfg: graphics.ShaderConfig, shader_desc: sg.ShaderDesc) ?Shader { + pub fn initSokolShader(cfg: graphics.ShaderConfig, shader_desc: sg.ShaderDesc) !Shader { debug.info("Creating shader: {d}", .{graphics.next_shader_handle}); const shader = sg.makeShader(shader_desc); @@ -580,10 +561,7 @@ pub const ShaderImpl = struct { } } - const pipeline_list = graphics.allocator.create(std.ArrayList(PipelineBinding)) catch { - debug.err("Error creating new Sokol shader!", .{}); - return null; - }; + const pipeline_list = try graphics.allocator.create(std.ArrayList(PipelineBinding)); pipeline_list.* = std.ArrayList(PipelineBinding).init(graphics.allocator); defer graphics.next_shader_handle += 1; diff --git a/src/framework/platform/graphics.zig b/src/framework/platform/graphics.zig index 3c5c4851..468008fb 100644 --- a/src/framework/platform/graphics.zig +++ b/src/framework/platform/graphics.zig @@ -366,25 +366,25 @@ pub const Shader = struct { impl: ShaderImpl, /// Create a new shader using the default - pub fn initDefault(cfg: ShaderConfig) Shader { - return ShaderImpl.initDefault(cfg); + pub fn initDefault(cfg: ShaderConfig) !Shader { + return try ShaderImpl.initDefault(cfg); } /// Creates a shader from a shader built in as a zig file - pub fn initFromBuiltin(cfg: ShaderConfig, comptime builtin: anytype) ?Shader { - return ShaderImpl.initFromBuiltin(cfg, builtin); + pub fn initFromBuiltin(cfg: ShaderConfig, comptime builtin: anytype) !Shader { + return try ShaderImpl.initFromBuiltin(cfg, builtin); } - pub fn initFromShaderInfo(cfg: ShaderConfig, shader_info: shaders.ShaderInfo) ?Shader { - return ShaderImpl.initFromShaderInfo(cfg, shader_info); + pub fn initFromShaderInfo(cfg: ShaderConfig, shader_info: shaders.ShaderInfo) !Shader { + return try ShaderImpl.initFromShaderInfo(cfg, shader_info); } /// Returns a new instance of this shader - pub fn makeNewInstance(cfg: ShaderConfig, shader: ?Shader) Shader { + pub fn makeNewInstance(cfg: ShaderConfig, shader: ?Shader) !Shader { if (shader != null) { - return ShaderImpl.makeNewInstance(cfg, shader.?); + return try ShaderImpl.makeNewInstance(cfg, shader.?); } - return initDefault(cfg); + return try initDefault(cfg); } /// Updates the graphics state to draw using this shader @@ -884,7 +884,7 @@ pub const Material = struct { if (cfg.shader != null and cfg.own_shader) { material.state.shader = cfg.shader.?; } else { - material.state.shader = Shader.makeNewInstance(shader_config, cfg.shader); + material.state.shader = try Shader.makeNewInstance(shader_config, cfg.shader); } return material; @@ -1057,7 +1057,7 @@ pub fn init() !void { state.debug_draw_bindings.set(debug_vertices, debug_indices, &[_]u32{}, &[_]u32{}, 6); // Use the default shader for debug drawing - state.default_shader = Shader.initDefault(.{ .cull_mode = .NONE }); + state.default_shader = try Shader.initDefault(.{ .cull_mode = .NONE }); state.debug_material = try Material.init(.{ .shader = state.default_shader, .texture_0 = tex_white, From c5941773852e172a9759362db04da191bff15474 Mon Sep 17 00:00:00 2001 From: Interrupt Date: Mon, 23 Sep 2024 23:14:30 -0700 Subject: [PATCH 2/2] Fixing up examples, fixing bug when making common pipelines --- src/examples/collision.zig | 5 +- src/examples/fonts.zig | 2 +- src/examples/forest.zig | 2 +- src/examples/frustums.zig | 2 +- src/examples/lighting.zig | 4 +- src/examples/meshbuilder.zig | 4 +- src/examples/meshes.zig | 8 +- src/examples/quakemap.zig | 2 +- src/examples/rays.zig | 2 +- src/examples/skinned-meshes.zig | 10 +-- src/examples/sprites.zig | 4 +- src/framework/graphics/shaders.zig | 2 +- .../platform/backends/sokol/graphics.zig | 77 ++++++++++--------- src/framework/platform/graphics.zig | 22 ++++-- src/framework/utils/quakemdl.zig | 2 +- 15 files changed, 77 insertions(+), 71 deletions(-) diff --git a/src/examples/collision.zig b/src/examples/collision.zig index babcb934..1baa0fc4 100644 --- a/src/examples/collision.zig +++ b/src/examples/collision.zig @@ -18,6 +18,8 @@ const Vec2 = math.Vec2; const Rect = delve.spatial.Rect; const TextureRegion = delve.graphics.sprites.TextureRegion; +const def_shader = delve.shaders.default; + var shader_default: graphics.Shader = undefined; var sprite_batch: batcher.SpriteBatcher = undefined; @@ -58,14 +60,13 @@ pub fn registerModule() !void { fn on_init() !void { debug.log("Collision example module initializing", .{}); + shader_default = try graphics.Shader.initDefault(.{}); sprite_batch = batcher.SpriteBatcher.init(.{}) catch { debug.showErrorScreen("Fatal error during batch init!"); return; }; - shader_default = graphics.Shader.initDefault(.{}); - graphics.setClearColor(colors.examples_bg_light); } diff --git a/src/examples/fonts.zig b/src/examples/fonts.zig index 19ebb678..9c85d0c6 100644 --- a/src/examples/fonts.zig +++ b/src/examples/fonts.zig @@ -67,7 +67,7 @@ fn on_init() !void { _ = try delve.fonts.loadFont("IBMPlexSerif", "assets/fonts/IBMPlexSerif-Regular.ttf", 1024, 200); // make a shader with alpha blending - shader_blend = graphics.Shader.initDefault(.{ .blend_mode = graphics.BlendMode.BLEND }); + shader_blend = try graphics.Shader.initDefault(.{ .blend_mode = graphics.BlendMode.BLEND }); } fn on_tick(delta: f32) void { diff --git a/src/examples/forest.zig b/src/examples/forest.zig index 17b77d63..444c0627 100644 --- a/src/examples/forest.zig +++ b/src/examples/forest.zig @@ -192,7 +192,7 @@ fn on_init() !void { tex_treesheet = graphics.Texture.init(&treesheet_img); // make our default shader - shader_blend = graphics.Shader.initDefault(.{ .blend_mode = .NONE, .cull_mode = .NONE }); + shader_blend = try graphics.Shader.initDefault(.{ .blend_mode = .NONE, .cull_mode = .NONE }); // set the sky color graphics.setClearColor(sky_color); diff --git a/src/examples/frustums.zig b/src/examples/frustums.zig index 75adf3ca..70de216d 100644 --- a/src/examples/frustums.zig +++ b/src/examples/frustums.zig @@ -45,7 +45,7 @@ pub fn main() !void { } pub fn on_init() !void { - shader = delve.platform.graphics.Shader.initFromBuiltin(.{ .vertex_attributes = delve.graphics.mesh.getShaderAttributes() }, delve.shaders.default_mesh).?; + shader = try delve.platform.graphics.Shader.initFromBuiltin(.{ .vertex_attributes = delve.graphics.mesh.getShaderAttributes() }, delve.shaders.default_mesh); // Create some materials material_frustum = try delve.platform.graphics.Material.init(.{ diff --git a/src/examples/lighting.zig b/src/examples/lighting.zig index 98654bdf..d12b8852 100644 --- a/src/examples/lighting.zig +++ b/src/examples/lighting.zig @@ -85,8 +85,8 @@ fn on_init() !void { camera.direction = Vec3.new(0.0, 0.0, 1.0); // make shaders for skinned and unskinned meshes - skinned_shader = graphics.Shader.initFromBuiltin(.{ .vertex_attributes = skinned_mesh.getSkinnedShaderAttributes() }, skinned_lit_shader).?; - static_shader = graphics.Shader.initFromBuiltin(.{ .vertex_attributes = delve.graphics.mesh.getShaderAttributes() }, lit_shader).?; + skinned_shader = try graphics.Shader.initFromBuiltin(.{ .vertex_attributes = skinned_mesh.getSkinnedShaderAttributes() }, skinned_lit_shader); + static_shader = try graphics.Shader.initFromBuiltin(.{ .vertex_attributes = delve.graphics.mesh.getShaderAttributes() }, lit_shader); var base_img: images.Image = try images.loadFile(mesh_texture_file); defer base_img.deinit(); diff --git a/src/examples/meshbuilder.zig b/src/examples/meshbuilder.zig index f01f6151..3a242894 100644 --- a/src/examples/meshbuilder.zig +++ b/src/examples/meshbuilder.zig @@ -51,11 +51,11 @@ pub fn on_init() !void { defer img.deinit(); const tex = graphics.Texture.init(&img); - const shader = graphics.Shader.initFromBuiltin(.{ .vertex_attributes = delve.graphics.mesh.getShaderAttributes() }, delve.shaders.default_mesh); + const shader = try graphics.Shader.initFromBuiltin(.{ .vertex_attributes = delve.graphics.mesh.getShaderAttributes() }, delve.shaders.default_mesh); // Create a material out of the texture material = try graphics.Material.init(.{ - .shader = shader.?, + .shader = shader, .own_shader = true, .texture_0 = tex, .samplers = &[_]graphics.FilterMode{.NEAREST}, diff --git a/src/examples/meshes.zig b/src/examples/meshes.zig index f6cec0fb..53184736 100644 --- a/src/examples/meshes.zig +++ b/src/examples/meshes.zig @@ -90,13 +90,7 @@ fn on_init() !void { const tex_emissive = graphics.Texture.init(&emissive_img); // Make our emissive shader from one that is pre-compiled - const loaded_shader = graphics.Shader.initFromBuiltin(.{ .vertex_attributes = mesh.getShaderAttributes() }, emissive_shader_builtin); - - if (loaded_shader == null) { - debug.log("Could not get emissive shader", .{}); - return; - } - shader = loaded_shader.?; + shader = try graphics.Shader.initFromBuiltin(.{ .vertex_attributes = mesh.getShaderAttributes() }, emissive_shader_builtin); // Create a material out of our shader and textures material = try graphics.Material.init(.{ diff --git a/src/examples/quakemap.zig b/src/examples/quakemap.zig index 11f29148..b85a2675 100644 --- a/src/examples/quakemap.zig +++ b/src/examples/quakemap.zig @@ -149,7 +149,7 @@ pub fn on_init() !void { var err: delve.utils.quakemap.ErrorInfo = undefined; quake_map = try delve.utils.quakemap.QuakeMap.read(allocator, test_map_file, map_transform, &err); - shader = graphics.Shader.initDefault(.{ .vertex_attributes = delve.graphics.mesh.getShaderAttributes() }); + shader = try graphics.Shader.initDefault(.{ .vertex_attributes = delve.graphics.mesh.getShaderAttributes() }); // Create a material out of the texture fallback_material = try graphics.Material.init(.{ diff --git a/src/examples/rays.zig b/src/examples/rays.zig index cd4ed4ff..a1b28268 100644 --- a/src/examples/rays.zig +++ b/src/examples/rays.zig @@ -45,7 +45,7 @@ pub fn main() !void { } pub fn on_init() !void { - const shader = delve.platform.graphics.Shader.initFromBuiltin(.{ .vertex_attributes = delve.graphics.mesh.getShaderAttributes() }, delve.shaders.default_mesh); + const shader = try delve.platform.graphics.Shader.initFromBuiltin(.{ .vertex_attributes = delve.graphics.mesh.getShaderAttributes() }, delve.shaders.default_mesh); // Create some materials material_frustum = try delve.platform.graphics.Material.init(.{ diff --git a/src/examples/skinned-meshes.zig b/src/examples/skinned-meshes.zig index fd0bf6d0..2a721d7c 100644 --- a/src/examples/skinned-meshes.zig +++ b/src/examples/skinned-meshes.zig @@ -78,23 +78,19 @@ fn on_init() !void { camera.direction = Vec3.new(0.0, 0.0, 1.0); // Make our emissive shader from one that is pre-compiled - const shader = graphics.Shader.initFromBuiltin(.{ .vertex_attributes = skinned_mesh.getSkinnedShaderAttributes() }, shader_builtin); - - if (shader == null) { - debug.log("Could not get shader", .{}); - return; - } + const shader = try graphics.Shader.initFromBuiltin(.{ .vertex_attributes = skinned_mesh.getSkinnedShaderAttributes() }, shader_builtin); var base_img: images.Image = images.loadFile(mesh_texture_file) catch { debug.log("Assets: Error loading image asset: {s}", .{mesh_texture_file}); return; }; defer base_img.deinit(); + const tex_base = graphics.Texture.init(&base_img); // Create a material out of our shader and textures material = try delve.platform.graphics.Material.init(.{ - .shader = shader.?, + .shader = shader, .own_shader = true, .texture_0 = tex_base, .texture_1 = delve.platform.graphics.createSolidTexture(0x00000000), diff --git a/src/examples/sprites.zig b/src/examples/sprites.zig index 1d098bac..44190ab1 100644 --- a/src/examples/sprites.zig +++ b/src/examples/sprites.zig @@ -91,8 +91,8 @@ fn on_init() !void { texture_2 = graphics.Texture.init(&test_image_2); // make some shaders for testing - shader_opaque = graphics.Shader.initDefault(.{}); - shader_blend = graphics.Shader.initDefault(.{ .blend_mode = graphics.BlendMode.BLEND }); + shader_opaque = try graphics.Shader.initDefault(.{}); + shader_blend = try graphics.Shader.initDefault(.{ .blend_mode = graphics.BlendMode.BLEND }); // Create some test materials out of our shader and textures test_material_1 = try graphics.Material.init(.{ diff --git a/src/framework/graphics/shaders.zig b/src/framework/graphics/shaders.zig index 798f8ee3..fd40d89c 100644 --- a/src/framework/graphics/shaders.zig +++ b/src/framework/graphics/shaders.zig @@ -34,7 +34,7 @@ pub fn loadFromYaml(cfg: graphics.ShaderConfig, file_path: []const u8) !?graphic break; } - return graphics.Shader.initFromShaderInfo(cfg, shader_info); + return try graphics.Shader.initFromShaderInfo(cfg, shader_info); } fn loadShaderSource(allocator: std.mem.Allocator, shader_path: []const u8) ![:0]const u8 { diff --git a/src/framework/platform/backends/sokol/graphics.zig b/src/framework/platform/backends/sokol/graphics.zig index 6af6a294..837d575f 100644 --- a/src/framework/platform/backends/sokol/graphics.zig +++ b/src/framework/platform/backends/sokol/graphics.zig @@ -239,20 +239,22 @@ pub const ShaderImpl = struct { is_instance: bool = false, // One shader can have many pipelines, so different VertexLayouts can apply it - sokol_pipelines: *std.ArrayList(PipelineBinding), + sokol_pipelines: std.ArrayList(PipelineBinding), /// Create a new shader using the default pub fn initDefault(cfg: graphics.ShaderConfig) !Shader { - return try initFromBuiltin(cfg, shader_default); + return initFromBuiltin(cfg, shader_default); } /// Creates a shader from a shader built in as a zig file pub fn initFromBuiltin(cfg: graphics.ShaderConfig, comptime builtin: anytype) !Shader { const shader_desc_fn = getBuiltinSokolCreateFunction(builtin); - if (shader_desc_fn == null) + if (shader_desc_fn == null) { + debug.log("Shader builtin not found!", .{}); return ShaderInitError.ShaderNotFound; + } - return try initSokolShader(cfg, shader_desc_fn.?(sg.queryBackend())); + return initSokolShader(cfg, shader_desc_fn.?(sg.queryBackend())); } fn terminateString(allocator: std.mem.Allocator, in_string: []const u8) ![:0]const u8 { @@ -462,28 +464,26 @@ pub const ShaderImpl = struct { var updated_cfg = cfg; updated_cfg.shader_program_def = shader_program; - return try initSokolShader(updated_cfg, desc); + return initSokolShader(updated_cfg, desc); } - pub fn makeNewInstance(cfg: graphics.ShaderConfig, shader: ?Shader) !Shader { - if (shader) |*s| { - const pipeline_list = graphics.allocator.create(std.ArrayList(PipelineBinding)) catch { - debug.err("Could not create new shader instance!", .{}); - return s.*; - }; - pipeline_list.* = std.ArrayList(PipelineBinding).init(graphics.allocator); + pub fn makeNewInstance(cfg: graphics.ShaderConfig, shader: Shader) !Shader { + const impl = try graphics.allocator.create(ShaderImpl); - // Return a copy of our shader, but mark that this is a clone so that we don't free the sokol shader twice - var newShader = s.*; - newShader.impl.sokol_pipelines = pipeline_list; - newShader.impl.cfg = cfg; - newShader.impl.is_instance = true; - return newShader; - } + // Make a new implementation that uses our existing loaded shader, but a fresh pipeline list + // Mark it as being an instance, so we don't clean up our parent shader on destroy + impl.* = .{ + .sokol_pipelines = std.ArrayList(PipelineBinding).init(graphics.allocator), + .sokol_shader = shader.impl.sokol_shader, + .sokol_shader_desc = shader.impl.sokol_shader_desc, + .cfg = cfg, + .is_instance = true, + }; - // fallback shader! - // TODO: Should we return null instead? - return try initDefault(cfg); + // Copy the shader, but switch out its guts with our new one + var newShader = shader; + newShader.impl = impl; + return newShader; } /// Find the shader function in the builtin that can actually make the ShaderDesc @@ -561,17 +561,18 @@ pub const ShaderImpl = struct { } } - const pipeline_list = try graphics.allocator.create(std.ArrayList(PipelineBinding)); - pipeline_list.* = std.ArrayList(PipelineBinding).init(graphics.allocator); + const impl = try graphics.allocator.create(ShaderImpl); + errdefer graphics.allocator.destroy(impl); + impl.* = .{ + .sokol_pipelines = std.ArrayList(PipelineBinding).init(graphics.allocator), + .sokol_shader = shader, + .sokol_shader_desc = shader_desc, + .cfg = cfg, + }; defer graphics.next_shader_handle += 1; var built_shader = Shader{ - .impl = .{ - .sokol_pipelines = pipeline_list, - .sokol_shader = shader, - .sokol_shader_desc = shader_desc, - .cfg = cfg, - }, + .impl = impl, .handle = graphics.next_shader_handle, .cfg = cfg, .fs_texture_slots = num_fs_images, @@ -579,11 +580,6 @@ pub const ShaderImpl = struct { .shader_program_def = cfg.shader_program_def, }; - // Cache some common pipelines - for (common_vertex_layouts) |l| { - _ = built_shader.impl.makePipeline(l); - } - // Set the uniformblocks to use for this shader for (cfg.vs_uniformblocks, 0..) |block, i| { built_shader.vs_uniformblocks[i] = block; @@ -595,6 +591,13 @@ pub const ShaderImpl = struct { return built_shader; } + /// Cache our common pipelines, as an optimization step + pub fn makeCommonPipelines(self: *Shader) void { + for (graphics.getCommonVertexLayouts()) |l| { + _ = self.impl.makePipeline(l); + } + } + pub fn apply(self: *Shader, layout: graphics.VertexLayout) bool { // Find the pipeline that matches our vertex layout var pipeline: ?sg.Pipeline = null; @@ -639,12 +642,14 @@ pub const ShaderImpl = struct { for (self.impl.sokol_pipelines.items) |p| { sg.destroyPipeline(p.sokol_pipeline); } + self.impl.sokol_pipelines.deinit(); - graphics.allocator.destroy(self.impl.sokol_pipelines); if (!self.impl.is_instance) { sg.destroyShader(self.impl.sokol_shader); } + + graphics.allocator.destroy(self.impl); } }; diff --git a/src/framework/platform/graphics.zig b/src/framework/platform/graphics.zig index 468008fb..3658809a 100644 --- a/src/framework/platform/graphics.zig +++ b/src/framework/platform/graphics.zig @@ -363,28 +363,32 @@ pub const Shader = struct { shader_program_def: ?shaders.ShaderProgram = null, - impl: ShaderImpl, + impl: *ShaderImpl, /// Create a new shader using the default pub fn initDefault(cfg: ShaderConfig) !Shader { - return try ShaderImpl.initDefault(cfg); + return ShaderImpl.initDefault(cfg); } /// Creates a shader from a shader built in as a zig file pub fn initFromBuiltin(cfg: ShaderConfig, comptime builtin: anytype) !Shader { - return try ShaderImpl.initFromBuiltin(cfg, builtin); + var shader = try ShaderImpl.initFromBuiltin(cfg, builtin); + shader.makeCommonPipelines(); + return shader; } pub fn initFromShaderInfo(cfg: ShaderConfig, shader_info: shaders.ShaderInfo) !Shader { - return try ShaderImpl.initFromShaderInfo(cfg, shader_info); + var shader = try ShaderImpl.initFromShaderInfo(cfg, shader_info); + shader.makeCommonPipelines(); + return shader; } /// Returns a new instance of this shader pub fn makeNewInstance(cfg: ShaderConfig, shader: ?Shader) !Shader { if (shader != null) { - return try ShaderImpl.makeNewInstance(cfg, shader.?); + return ShaderImpl.makeNewInstance(cfg, shader.?); } - return try initDefault(cfg); + return initDefault(cfg); } /// Updates the graphics state to draw using this shader @@ -422,6 +426,10 @@ pub const Shader = struct { } } + pub fn makeCommonPipelines(self: *Shader) void { + ShaderImpl.makeCommonPipelines(self); + } + pub fn destroy(self: *Shader) void { return ShaderImpl.destroy(self); } @@ -1058,6 +1066,8 @@ pub fn init() !void { // Use the default shader for debug drawing state.default_shader = try Shader.initDefault(.{ .cull_mode = .NONE }); + state.default_shader.makeCommonPipelines(); + state.debug_material = try Material.init(.{ .shader = state.default_shader, .texture_0 = tex_white, diff --git a/src/framework/utils/quakemdl.zig b/src/framework/utils/quakemdl.zig index 85c92237..5958278d 100644 --- a/src/framework/utils/quakemdl.zig +++ b/src/framework/utils/quakemdl.zig @@ -465,7 +465,7 @@ pub fn open(in_allocator: Allocator, path: []const u8) !MDL { // Material const default_material = try graphics.Material.init(.{ - .shader = graphics.Shader.initFromBuiltin(.{ .vertex_attributes = mesh.getShaderAttributes() }, default_mesh), + .shader = try graphics.Shader.initFromBuiltin(.{ .vertex_attributes = mesh.getShaderAttributes() }, default_mesh), .own_shader = true, .texture_0 = skins[0].single.texture, .samplers = &[_]graphics.FilterMode{.NEAREST},