Add runtime shader reflection support
continuous-integration/drone/push Build is passing Details

This commit is contained in:
kayomn 2024-07-06 03:25:09 +01:00
parent 2ba249f4bf
commit 842dbd56cf
6 changed files with 385 additions and 174 deletions

2
.vscode/launch.json vendored
View File

@ -7,7 +7,7 @@
"request": "launch",
"target": "${workspaceRoot}/zig-out/bin/main",
"cwd": "${workspaceRoot}/debug/",
"valuesFormatting": "parseText",
"valuesFormatting": "prettyPrinters",
"preLaunchTask": "Build All"
},
]

View File

@ -115,7 +115,7 @@ pub const DecimalFormat = struct {
}
}
pub fn print(self: DecimalFormat, writer: io.Writer, value: anytype) io.PrintError!void {
pub fn format(self: DecimalFormat, writer: io.Writer, value: anytype) io.PrintError!void {
if (value == 0) {
return io.print(writer, switch (self.positive_prefix) {
.none => "0",
@ -178,13 +178,13 @@ pub const HexadecimalFormat = struct {
positive_prefix: enum {none, plus, space} = .none,
casing: enum {lower, upper} = .lower,
const default = HexadecimalFormat{
pub const default = HexadecimalFormat{
.delimiter = "",
.positive_prefix = .none,
.casing = .lower,
};
pub fn print(self: HexadecimalFormat, writer: io.Writer, value: anytype) ?usize {
pub fn format(self: HexadecimalFormat, writer: io.Writer, value: anytype) io.Error!void {
// TODO: Implement.
_ = self;
_ = writer;

View File

@ -108,13 +108,23 @@ pub fn Generator(comptime Output: type, comptime input_types: []const type) type
};
}
pub const PrintError = Error || error {
IncompleteWrite,
pub const NullWritable = struct {
written: usize = 0,
pub fn write(self: *NullWritable, buffer: []const Byte) Error!usize {
self.written += buffer.len;
return buffer.len;
}
pub fn writer(self: *NullWritable) Writer {
return Writer.bind(NullWritable, self, write);
}
};
pub const Reader = Generator(Error!usize, &.{[]coral.Byte});
pub const Reader = Generator(Error!usize, &.{[]Byte});
pub const Writer = Generator(Error!usize, &.{[]const coral.Byte});
pub const Writer = Generator(Error!usize, &.{[]const Byte});
pub fn alloc_read(input: coral.io.Reader, allocator: std.mem.Allocator) []coral.Byte {
const buffer = coral.Stack(coral.Byte){.allocator = allocator};
@ -138,12 +148,6 @@ pub fn bytes_of(value: anytype) []const Byte {
};
}
pub fn print(writer: Writer, utf8: []const u8) PrintError!void {
if (try writer.yield(.{utf8}) != utf8.len) {
return error.IncompleteWrite;
}
}
pub fn skip_n(input: Reader, distance: u64) Error!void {
var buffer = @as([512]coral.Byte, undefined);
var remaining = distance;
@ -159,7 +163,7 @@ pub fn skip_n(input: Reader, distance: u64) Error!void {
}
}
pub fn slice_sentineled(comptime sen: anytype, ptr: [*:sen]const @TypeOf(sen)) [:sen]const @TypeOf(sen) {
pub fn slice_sentineled(comptime Sentinel: type, comptime sen: Sentinel, ptr: [*:sen]const Sentinel) [:sen]const Sentinel {
var len = @as(usize, 0);
while (ptr[len] != sen) {
@ -206,3 +210,9 @@ pub fn stream_n(input: Reader, output: Writer, limit: usize) Error!usize {
remaining -= read;
}
}
pub fn write_all(writer: Writer, utf8: []const u8) Error!void {
if (try writer.yield(.{utf8}) != utf8.len) {
return error.UnavailableResource;
}
}

View File

@ -19,15 +19,54 @@ pub fn alloc_formatted(allocator: std.mem.Allocator, comptime format: []const u8
return buffer.to_allocation(formatted_len, 0);
}
fn count_formatted(comptime format: []const u8, args: anytype) usize {
var count = io.defaultWritable{};
pub fn count_formatted(comptime format: []const u8, args: anytype) usize {
var count = io.NullWritable{};
print_formatted(count.writer(), format, args) catch unreachable;
write_formatted(count.writer(), format, args) catch unreachable;
return count.written;
}
pub fn print_formatted(writer: io.Writer, comptime format: []const u8, args: anytype) io.PrintError!void {
pub fn print_formatted(buffer: [:0]coral.io.Byte, comptime format: []const u8, args: anytype) io.Error![:0]u8 {
const Seekable = struct {
buffer: []coral.io.Byte,
cursor: usize,
const Self = @This();
fn write(self: *Self, input: []const coral.io.Byte) io.Error!usize {
const range = @min(input.len, self.buffer.len - self.cursor);
const tail = self.cursor + range;
@memcpy(self.buffer[self.cursor .. tail], input);
self.cursor = tail;
return range;
}
};
const len = count_formatted(format, args);
if (len > buffer.len) {
return error.UnavailableResource;
}
var seekable = Seekable{
.buffer = buffer,
.cursor = 0,
};
try write_formatted(coral.io.Writer.bind(Seekable, &seekable, Seekable.write), format, args);
if (buffer.len < len) {
buffer[len] = 0;
}
return buffer[0 .. len:0];
}
pub fn write_formatted(writer: io.Writer, comptime format: []const u8, args: anytype) io.Error!void {
switch (@typeInfo(@TypeOf(args))) {
.Struct => |arguments_struct| {
comptime var arg_index = 0;
@ -67,7 +106,7 @@ pub fn print_formatted(writer: io.Writer, comptime format: []const u8, args: any
@compileError("format specifiers cannot be named when using a tuple struct");
}
try io.print(writer, format[head .. (tail - 1)]);
try io.write_all(writer, format[head .. (tail - 1)]);
head = tail;
tail += 1;
@ -93,14 +132,14 @@ pub fn print_formatted(writer: io.Writer, comptime format: []const u8, args: any
}
}
try io.print(writer, format[head .. ]);
try io.write_all(writer, format[head .. ]);
},
else => @compileError("`arguments` must be a struct type"),
}
}
noinline fn print_formatted_value(writer: io.Writer, value: anytype) io.PrintError!void {
noinline fn print_formatted_value(writer: io.Writer, value: anytype) io.Error!void {
const Value = @TypeOf(value);
return switch (@typeInfo(Value)) {
@ -109,9 +148,9 @@ noinline fn print_formatted_value(writer: io.Writer, value: anytype) io.PrintErr
.Enum => io.print(writer, @tagName(value)),
.Pointer => |pointer| switch (pointer.size) {
.Many, .C => ascii.HexadecimalFormat.default.print(writer, @intFromPtr(value)),
.One => if (pointer.child == []const u8) io.print(writer, *value) else ascii.HexadecimalFormat.default.print(writer, @intFromPtr(value)),
.Slice => if (pointer.child == u8) io.print(writer, value) else @compileError(unformattableMessage(Value)),
.Many, .C => ascii.HexadecimalFormat.default.format(writer, @intFromPtr(value)),
.One => if (pointer.child == []const u8) io.write_all(writer, *value) else ascii.HexadecimalFormat.default.print(writer, @intFromPtr(value)),
.Slice => if (pointer.child == u8) io.write_all(writer, value) else @compileError(unformattableMessage(Value)),
},
else => @compileError(unformattableMessage(Value)),

View File

@ -380,7 +380,7 @@ const Loop = struct {
ext.SDL_GL_DeleteContext(context);
}
var rendering_2d = try Rendering2D.init(coral.heap.allocator);
var rendering_2d = try Rendering2D.init();
defer rendering_2d.deinit();
@ -535,6 +535,12 @@ const Rendering2D = struct {
const mesh_2d = resource_cast(frame.mesh.?).payload.mesh_2d;
const texture_image, const texture_sampler = switch (resource_cast(frame.texture.?).payload) {
.texture => |texture| .{texture.image, texture.sampler},
.render_target => |render_target| .{render_target.color_image, render_target.sampler},
else => unreachable,
};
var bindings = sokol.gfx.Bindings{
.vertex_buffers = get: {
var buffers = [_]sokol.gfx.Buffer{.{}} ** 8;
@ -546,44 +552,40 @@ const Rendering2D = struct {
.index_buffer = mesh_2d.index_buffer,
.fs = switch (resource_cast(frame.texture.?).payload) {
.texture => |texture| .{
.images = get: {
var images = [_]sokol.gfx.Image{.{}} ** 12;
.fs = .{
.images = get: {
var images = [_]sokol.gfx.Image{.{}} ** 12;
images[0] = texture.image;
images[0] = texture_image;
break: get images;
},
.samplers = get: {
var samplers = [_]sokol.gfx.Sampler{.{}} ** 8;
samplers[0] = texture.sampler;
break: get samplers;
},
break: get images;
},
.render_target => |render_target| .{
.images = get: {
var images = [_]sokol.gfx.Image{.{}} ** 12;
.samplers = get: {
var samplers = [_]sokol.gfx.Sampler{.{}} ** 8;
images[0] = render_target.color_image;
samplers[0] = texture_sampler;
break: get images;
},
break: get samplers;
},
},
.samplers = get: {
var samplers = [_]sokol.gfx.Sampler{.{}} ** 8;
.vs = .{
.images = get: {
var images = [_]sokol.gfx.Image{.{}} ** 12;
samplers[0] = render_target.sampler;
images[0] = texture_image;
break: get samplers;
},
break: get images;
},
else => unreachable,
.samplers = get: {
var samplers = [_]sokol.gfx.Sampler{.{}} ** 8;
samplers[0] = texture_sampler;
break: get samplers;
},
},
};
@ -602,7 +604,7 @@ const Rendering2D = struct {
}
}
fn init(allocator: std.mem.Allocator) spirv.CompileError!Rendering2D {
fn init() spirv.Error!Rendering2D {
sokol.gfx.setup(.{
.environment = .{
.defaults = .{
@ -617,17 +619,15 @@ const Rendering2D = struct {
},
});
var arena = std.heap.ArenaAllocator.init(allocator);
var spirv_unit = try spirv.Unit.init();
defer arena.deinit();
defer spirv_unit.deinit();
const shader_desc = try spirv.compile(&arena, .{
.fragment_spirv = shader_spirv[0 ..],
.vertex_spirv = shader_spirv[0 ..],
});
try spirv_unit.compile(shader_spirv[0 ..], .vertex);
try spirv_unit.compile(shader_spirv[0 ..], .fragment);
std.log.info("{s}\n", .{shader_desc.fs.source});
std.log.info("{s}", .{shader_desc.vs.source});
std.log.info("{s}\n", .{spirv_unit.shader_desc.fs.source});
std.log.info("{s}", .{spirv_unit.shader_desc.vs.source});
return .{
.batching_pipeline = sokol.gfx.makePipeline(.{
@ -689,7 +689,7 @@ const Rendering2D = struct {
},
},
.shader = sokol.gfx.makeShader(shader_desc),
.shader = sokol.gfx.makeShader(spirv_unit.shader_desc),
.index_type = .UINT16,
}),

View File

@ -8,123 +8,285 @@ const sokol = @import("sokol");
const std = @import("std");
pub const CompileError = std.mem.Allocator.Error || error {
pub const Error = std.mem.Allocator.Error || error {
UnsupportedTarget,
InvalidSpirV,
UnsupportedSpirv,
UnknownFailure,
InvalidSPIRV,
UnsupportedSPIRV,
};
pub const Sources = struct {
vertex_spirv: []const u32,
fragment_spirv: []const u32,
pub const Unit = struct {
context: ext.spvc_context,
shader_desc: sokol.gfx.ShaderDesc,
attrs_used: u32 = 0,
pub fn compile(self: *Unit, spirv: []const u32, stage: Stage) Error!void {
const execution_model, const stage_desc = switch (stage) {
.vertex => .{ext.SpvExecutionModelVertex, &self.shader_desc.vs},
.fragment => .{ext.SpvExecutionModelFragment, &self.shader_desc.fs},
};
const Backend = struct {
target: ext.spvc_backend,
option_values: []const struct {ext.spvc_compiler_option, c_uint},
};
const backend: Backend = switch (sokol.gfx.queryBackend()) {
.GLCORE => .{
.target = ext.SPVC_BACKEND_GLSL,
.option_values = &.{
.{ext.SPVC_COMPILER_OPTION_GLSL_VERSION, 430},
.{ext.SPVC_COMPILER_OPTION_GLSL_ES, @intFromBool(false)},
.{ext.SPVC_COMPILER_OPTION_GLSL_VULKAN_SEMANTICS, @intFromBool(false)},
.{ext.SPVC_COMPILER_OPTION_GLSL_EMIT_UNIFORM_BUFFER_AS_PLAIN_UNIFORMS, @intFromBool(true)},
},
},
else => @panic("Unimplemented"),
};
const compiler = parse_and_configure: {
var parsed_ir: ext.spvc_parsed_ir = null;
try to_error(ext.spvc_context_parse_spirv(self.context, spirv.ptr, spirv.len, &parsed_ir));
var compiler: ext.spvc_compiler = null;
try to_error(ext.spvc_context_create_compiler(self.context, backend.target, parsed_ir, ext.SPVC_CAPTURE_MODE_TAKE_OWNERSHIP, &compiler));
try to_error(ext.spvc_compiler_build_combined_image_samplers(compiler));
var combined_image_samplers: []const ext.spvc_combined_image_sampler = &.{};
try to_error(ext.spvc_compiler_get_combined_image_samplers(compiler, @ptrCast(&combined_image_samplers.ptr), &combined_image_samplers.len));
var binding: u32 = 0;
for (combined_image_samplers) |combined_image_sampler| {
var name_buffer = [_:0]u8{0} ** 255;
const name = coral.utf8.print_formatted(&name_buffer, "{image_name}_{sampler_name}", .{
.image_name = coral.io.slice_sentineled(u8, 0, ext.spvc_compiler_get_name(compiler, combined_image_sampler.image_id)),
.sampler_name = coral.io.slice_sentineled(u8, 0, ext.spvc_compiler_get_name(compiler, combined_image_sampler.sampler_id)),
}) catch {
return error.InvalidSPIRV;
};
ext.spvc_compiler_set_name(compiler, combined_image_sampler.combined_id, name);
ext.spvc_compiler_set_decoration(compiler, combined_image_sampler.combined_id, ext.SpvDecorationBinding, binding);
binding += 1;
}
break: parse_and_configure compiler;
};
try to_error(ext.spvc_compiler_set_entry_point(compiler, stage_desc.entry, @intCast(execution_model)));
const resources = create: {
var resources: ext.spvc_resources = null;
try to_error(ext.spvc_compiler_create_shader_resources(compiler, &resources));
break: create resources;
};
try reflect_uniform_blocks(compiler, resources, stage_desc);
try reflect_image_samplers(compiler, resources, stage_desc);
try to_error(ext.spvc_compiler_install_compiler_options(compiler, create: {
var options: ext.spvc_compiler_options = null;
try to_error(ext.spvc_compiler_create_compiler_options(compiler, &options));
for (backend.option_values) |option_value| {
const entry, const value = option_value;
try to_error(ext.spvc_compiler_options_set_uint(options, entry, value));
}
break: create options;
}));
try to_error(ext.spvc_compiler_compile(compiler, @ptrCast(&stage_desc.source)));
}
pub fn deinit(self: *Unit) void {
ext.spvc_context_destroy(self.context);
self.* = undefined;
}
pub fn init() std.mem.Allocator.Error!Unit {
var context: ext.spvc_context = null;
if (ext.spvc_context_create(&context) != ext.SPVC_SUCCESS) {
return error.OutOfMemory;
}
errdefer ext.spvc_context_destroy(context);
ext.spvc_context_set_error_callback(context, log_context_errors, null);
return .{
.context = context,
.shader_desc = .{
.vs = .{.entry = "main"},
.fs = .{.entry = "main"},
},
};
}
};
pub fn compile(arena: *std.heap.ArenaAllocator, sources: Sources) CompileError!sokol.gfx.ShaderDesc {
var context = @as(ext.spvc_context, null);
pub const Stage = enum {
fragment,
vertex,
};
try switch (ext.spvc_context_create(&context)) {
ext.SPVC_ERROR_OUT_OF_MEMORY => error.OutOfMemory,
ext.SPVC_SUCCESS => {},
else => error.UnknownFailure,
};
ext.spvc_context_set_error_callback(context, log_errors, null);
defer ext.spvc_context_destroy(context);
const arena_allocator = arena.allocator();
const shader_source_sentinel = @as(u8, 0);
return .{
.vs = .{
.source = try arena_allocator.dupeZ(u8, coral.io.slice_sentineled(
shader_source_sentinel,
@ptrCast(try compile_shader(context, ext.SpvExecutionModelVertex, sources.vertex_spirv)))),
},
.fs = .{
.source = try arena_allocator.dupeZ(u8, coral.io.slice_sentineled(
shader_source_sentinel,
@ptrCast(try compile_shader(context, ext.SpvExecutionModelFragment, sources.fragment_spirv)))),
},
};
}
fn compile_shader(context: ext.spvc_context, model: ext.SpvExecutionModel, spirv: []const u32) CompileError![*]const u8 {
var parsed_ir = @as(ext.spvc_parsed_ir, null);
try switch (ext.spvc_context_parse_spirv(context, spirv.ptr, spirv.len, &parsed_ir)) {
ext.SPVC_ERROR_OUT_OF_MEMORY => error.OutOfMemory,
ext.SPVC_ERROR_INVALID_SPIRV => error.InvalidSpirV,
ext.SPVC_SUCCESS => {},
else => error.UnknownFailure,
};
var compiler = @as(ext.spvc_compiler, null);
try switch (ext.spvc_context_create_compiler(context, ext.SPVC_BACKEND_GLSL, parsed_ir, ext.SPVC_CAPTURE_MODE_TAKE_OWNERSHIP, &compiler)) {
ext.SPVC_ERROR_OUT_OF_MEMORY => error.OutOfMemory,
ext.SPVC_ERROR_INVALID_ARGUMENT => error.UnsupportedTarget,
ext.SPVC_SUCCESS => {},
else => error.UnknownFailure,
};
try switch (ext.spvc_compiler_build_combined_image_samplers(compiler)) {
ext.SPVC_ERROR_UNSUPPORTED_SPIRV => error.UnsupportedSpirv,
ext.SPVC_SUCCESS => {},
else => error.UnknownFailure,
};
try switch (ext.spvc_compiler_set_entry_point(compiler, "main", model)) {
ext.SPVC_SUCCESS => {},
else => error.UnknownFailure,
};
var options = @as(ext.spvc_compiler_options, null);
try switch (ext.spvc_compiler_create_compiler_options(compiler, &options)) {
ext.SPVC_ERROR_OUT_OF_MEMORY => error.OutOfMemory,
ext.SPVC_SUCCESS => {},
else => error.UnknownFailure,
};
try switch (ext.spvc_compiler_options_set_uint(options, ext.SPVC_COMPILER_OPTION_GLSL_VERSION, 430)) {
ext.SPVC_ERROR_INVALID_ARGUMENT => error.InvalidSpirV,
ext.SPVC_SUCCESS => {},
else => error.UnknownFailure,
};
try switch (ext.spvc_compiler_options_set_bool(options, ext.SPVC_COMPILER_OPTION_GLSL_ES, @intFromBool(false))) {
ext.SPVC_ERROR_INVALID_ARGUMENT => error.InvalidSpirV,
ext.SPVC_SUCCESS => {},
else => error.UnknownFailure,
};
try switch (ext.spvc_compiler_options_set_bool(options, ext.SPVC_COMPILER_OPTION_GLSL_VULKAN_SEMANTICS, @intFromBool(false))) {
ext.SPVC_ERROR_INVALID_ARGUMENT => error.InvalidSpirV,
ext.SPVC_SUCCESS => {},
else => error.UnknownFailure,
};
try switch (ext.spvc_compiler_install_compiler_options(compiler, options)) {
ext.SPVC_SUCCESS => {},
else => error.UnknownFailure,
};
var source = @as([*]const u8, undefined);
try switch (ext.spvc_compiler_compile(compiler, @ptrCast(&source))) {
ext.SPVC_ERROR_OUT_OF_MEMORY => error.OutOfMemory,
ext.SPVC_ERROR_UNSUPPORTED_SPIRV => error.UnsupportedSpirv,
ext.SPVC_SUCCESS => {},
else => error.UnknownFailure,
};
return source;
}
fn log_errors(userdata: ?*anyopaque, error_message: [*c]const u8) callconv(.C) void {
fn log_context_errors(userdata: ?*anyopaque, error_message: [*c]const u8) callconv(.C) void {
std.debug.assert(userdata == null);
std.log.err("{s}", .{error_message});
}
fn reflect_image_samplers(compiler: ext.spvc_compiler, resources: ext.spvc_resources, stage: *sokol.gfx.ShaderStageDesc) Error!void {
var reflected_sampled_images: []const ext.spvc_reflected_resource = &.{};
try to_error(ext.spvc_resources_get_resource_list_for_type(
resources,
ext.SPVC_RESOURCE_TYPE_SAMPLED_IMAGE,
@ptrCast(&reflected_sampled_images.ptr),
&reflected_sampled_images.len,
));
if (reflected_sampled_images.len > stage.image_sampler_pairs.len) {
return error.UnsupportedSPIRV;
}
for (0 .. reflected_sampled_images.len, reflected_sampled_images) |i, reflected_sampled_image| {
const sampled_image_type = ext.spvc_compiler_get_type_handle(compiler, reflected_sampled_image.type_id);
if (ext.spvc_type_get_basetype(sampled_image_type) != ext.SPVC_BASETYPE_SAMPLED_IMAGE) {
return error.InvalidSPIRV;
}
stage.images[i] = .{
.multisampled = ext.spvc_type_get_image_multisampled(sampled_image_type) != 0,
.image_type = try switch (ext.spvc_type_get_image_dimension(sampled_image_type)) {
ext.SpvDim2D => sokol.gfx.ImageType._2D,
else => error.InvalidSPIRV,
},
.sample_type = try switch (ext.spvc_type_get_basetype(ext.spvc_compiler_get_type_handle(compiler, ext.spvc_type_get_image_sampled_type(sampled_image_type)))) {
ext.SPVC_BASETYPE_FP32 => sokol.gfx.ImageSampleType.FLOAT,
else => error.InvalidSPIRV,
},
.used = true,
};
stage.samplers[i] = .{
.sampler_type = .DEFAULT,
.used = true,
};
stage.image_sampler_pairs[i] = .{
.glsl_name = ext.spvc_compiler_get_name(compiler, reflected_sampled_image.id),
.image_slot = @intCast(i),
.sampler_slot = @intCast(i),
.used = true,
};
}
}
fn reflect_uniform_blocks(compiler: ext.spvc_compiler, resources: ext.spvc_resources, stage: *sokol.gfx.ShaderStageDesc) Error!void {
var reflected_uniform_buffers: []const ext.spvc_reflected_resource = &.{};
try to_error(ext.spvc_resources_get_resource_list_for_type(
resources,
ext.SPVC_RESOURCE_TYPE_UNIFORM_BUFFER,
@ptrCast(&reflected_uniform_buffers.ptr),
&reflected_uniform_buffers.len,
));
if (reflected_uniform_buffers.len > stage.uniform_blocks.len) {
return error.UnsupportedSPIRV;
}
for (stage.uniform_blocks[0 .. reflected_uniform_buffers.len], reflected_uniform_buffers) |*uniform_block, reflected_uniform_buffer| {
const uniform_buffer_type = ext.spvc_compiler_get_type_handle(compiler, reflected_uniform_buffer.type_id);
if (ext.spvc_type_get_basetype(uniform_buffer_type) != ext.SPVC_BASETYPE_STRUCT) {
return error.InvalidSPIRV;
}
const member_count = ext.spvc_type_get_num_member_types(uniform_buffer_type);
if (member_count > uniform_block.uniforms.len) {
return error.UnsupportedSPIRV;
}
try to_error(ext.spvc_compiler_get_declared_struct_size(compiler, uniform_buffer_type, &uniform_block.size));
var uniform_blocks_used: u32 = 0;
while (uniform_blocks_used < member_count) : (uniform_blocks_used += 1) {
const member_type_id = ext.spvc_type_get_member_type(uniform_buffer_type, uniform_blocks_used);
const member_type = ext.spvc_compiler_get_type_handle(compiler, member_type_id);
uniform_block.uniforms[uniform_blocks_used] = .{
// .name = ext.spvc_compiler_get_member_name(compiler, ext.spvc_type_get_base_type_id(uniform_buffer_type), uniform_blocks_used),
.array_count = @intCast(try switch (ext.spvc_type_get_num_array_dimensions(member_type)) {
0 => 0,
1 => switch (ext.spvc_type_array_dimension_is_literal(member_type, 1) != 0) {
true => ext.spvc_type_get_array_dimension(member_type, 1),
false => error.InvalidSPIRV,
},
else => error.InvalidSPIRV,
}),
.type = try switch (ext.spvc_type_get_basetype(member_type)) {
ext.SPVC_BASETYPE_INT32 => switch (ext.spvc_type_get_vector_size(member_type)) {
1 => if (ext.spvc_type_get_columns(member_type) == 1) sokol.gfx.UniformType.INT else error.InvalidSPIRV,
2 => if (ext.spvc_type_get_columns(member_type) == 1) sokol.gfx.UniformType.INT2 else error.InvalidSPIRV,
3 => if (ext.spvc_type_get_columns(member_type) == 1) sokol.gfx.UniformType.INT3 else error.InvalidSPIRV,
4 => if (ext.spvc_type_get_columns(member_type) == 1) sokol.gfx.UniformType.INT4 else error.InvalidSPIRV,
else => error.InvalidSPIRV,
},
ext.SPVC_BASETYPE_FP32 => switch (ext.spvc_type_get_vector_size(member_type)) {
1 => if (ext.spvc_type_get_columns(member_type) == 1) sokol.gfx.UniformType.FLOAT else error.InvalidSPIRV,
2 => if (ext.spvc_type_get_columns(member_type) == 1) sokol.gfx.UniformType.FLOAT2 else error.InvalidSPIRV,
3 => if (ext.spvc_type_get_columns(member_type) == 1) sokol.gfx.UniformType.FLOAT3 else error.InvalidSPIRV,
4 => switch (ext.spvc_type_get_columns(member_type)) {
1 => sokol.gfx.UniformType.FLOAT4,
4 => sokol.gfx.UniformType.MAT4,
else => error.InvalidSPIRV,
},
else => error.InvalidSPIRV,
},
else => error.InvalidSPIRV,
},
};
// uniform_block.uniforms[uniform_blocks_used].name = ext.spvc_compiler_get_member_name(compiler, ext.spvc_type_get_base_type_id(uniform_buffer_type), uniform_blocks_used);
}
}
}
fn to_error(result: ext.spvc_result) Error!void {
return switch (result) {
ext.SPVC_SUCCESS => {},
ext.SPVC_ERROR_INVALID_SPIRV => error.InvalidSPIRV,
ext.SPVC_ERROR_UNSUPPORTED_SPIRV => error.UnsupportedSPIRV,
ext.SPVC_ERROR_OUT_OF_MEMORY => error.OutOfMemory,
ext.SPVC_ERROR_INVALID_ARGUMENT, ext.SPVC_ERROR_INT_MAX => unreachable,
else => unreachable,
};
}