From 4afaea19d621f6f552e6d51c0217863cf39aa93c Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Wed, 15 Nov 2023 21:46:07 -0800 Subject: [PATCH] pkg/glslang: shader api --- pkg/glslang/build.zig | 7 +++++ pkg/glslang/init.zig | 9 ++++++ pkg/glslang/main.zig | 21 ++----------- pkg/glslang/shader.zig | 58 ++++++++++++++++++++++++++++++++++++ pkg/glslang/test.zig | 10 +++++++ pkg/glslang/test/simple.frag | 56 ++++++++++++++++++++++++++++++++++ 6 files changed, 143 insertions(+), 18 deletions(-) create mode 100644 pkg/glslang/init.zig create mode 100644 pkg/glslang/shader.zig create mode 100644 pkg/glslang/test.zig create mode 100644 pkg/glslang/test/simple.frag diff --git a/pkg/glslang/build.zig b/pkg/glslang/build.zig index a5589e87c..8b05b357e 100644 --- a/pkg/glslang/build.zig +++ b/pkg/glslang/build.zig @@ -21,6 +21,9 @@ pub fn build(b: *std.Build) !void { const tests_run = b.addRunArtifact(test_exe); const test_step = b.step("test", "Run tests"); test_step.dependOn(&tests_run.step); + + // Uncomment this if we're debugging tests + b.installArtifact(test_exe); } } @@ -42,6 +45,10 @@ fn buildGlslang( var flags = std.ArrayList([]const u8).init(b.allocator); defer flags.deinit(); + try flags.appendSlice(&.{ + "-fno-sanitize=undefined", + "-fno-sanitize-trap=undefined", + }); lib.addCSourceFiles(.{ .dependency = upstream, diff --git a/pkg/glslang/init.zig b/pkg/glslang/init.zig new file mode 100644 index 000000000..33ddd081d --- /dev/null +++ b/pkg/glslang/init.zig @@ -0,0 +1,9 @@ +const c = @import("c.zig"); + +pub fn init() !void { + if (c.glslang_initialize_process() == 0) return error.GlslangInitFailed; +} + +pub fn finalize() void { + c.glslang_finalize_process(); +} diff --git a/pkg/glslang/main.zig b/pkg/glslang/main.zig index 253a1add1..f7dc6c2da 100644 --- a/pkg/glslang/main.zig +++ b/pkg/glslang/main.zig @@ -1,22 +1,7 @@ pub const c = @import("c.zig"); +pub usingnamespace @import("init.zig"); +pub usingnamespace @import("shader.zig"); test { - const input: c.glslang_input_t = .{ - .language = c.GLSLANG_SOURCE_GLSL, - .stage = c.GLSLANG_STAGE_VERTEX, - .client = c.GLSLANG_CLIENT_VULKAN, - .client_version = c.GLSLANG_TARGET_VULKAN_1_2, - .target_language = c.GLSLANG_TARGET_SPV, - .target_language_version = c.GLSLANG_TARGET_SPV_1_5, - .code = "", - .default_version = 100, - .default_profile = c.GLSLANG_NO_PROFILE, - .force_default_version_and_profile = 0, - .forward_compatible = 0, - .messages = c.GLSLANG_MSG_DEFAULT_BIT, - .resource = c.glslang_default_resource(), - }; - - const shader = c.glslang_shader_create(&input); - _ = shader; + @import("std").testing.refAllDecls(@This()); } diff --git a/pkg/glslang/shader.zig b/pkg/glslang/shader.zig new file mode 100644 index 000000000..90e5e192f --- /dev/null +++ b/pkg/glslang/shader.zig @@ -0,0 +1,58 @@ +const std = @import("std"); +const c = @import("c.zig"); +const testlib = @import("test.zig"); + +pub const Shader = opaque { + pub fn create(input: *const c.glslang_input_t) !*Shader { + if (c.glslang_shader_create(input)) |ptr| return @ptrCast(ptr); + return error.OutOfMemory; + } + + pub fn delete(self: *Shader) void { + c.glslang_shader_delete(@ptrCast(self)); + } + + pub fn preprocess(self: *Shader, input: *const c.glslang_input_t) !void { + if (c.glslang_shader_preprocess(@ptrCast(self), input) == 0) + return error.GlslangFailed; + } + + pub fn parse(self: *Shader, input: *const c.glslang_input_t) !void { + if (c.glslang_shader_parse(@ptrCast(self), input) == 0) + return error.GlslangFailed; + } + + pub fn getInfoLog(self: *Shader) ![:0]const u8 { + const ptr = c.glslang_shader_get_info_log(@ptrCast(self)); + return std.mem.sliceTo(ptr, 0); + } + + pub fn getDebugInfoLog(self: *Shader) ![:0]const u8 { + const ptr = c.glslang_shader_get_info_debug_log(@ptrCast(self)); + return std.mem.sliceTo(ptr, 0); + } +}; + +test { + const input: c.glslang_input_t = .{ + .language = c.GLSLANG_SOURCE_GLSL, + .stage = c.GLSLANG_STAGE_FRAGMENT, + .client = c.GLSLANG_CLIENT_VULKAN, + .client_version = c.GLSLANG_TARGET_VULKAN_1_2, + .target_language = c.GLSLANG_TARGET_SPV, + .target_language_version = c.GLSLANG_TARGET_SPV_1_5, + .code = @embedFile("test/simple.frag"), + .default_version = 100, + .default_profile = c.GLSLANG_NO_PROFILE, + .force_default_version_and_profile = 0, + .forward_compatible = 0, + .messages = c.GLSLANG_MSG_DEFAULT_BIT, + .resource = c.glslang_default_resource(), + }; + + try testlib.ensureInit(); + const shader = try Shader.create(&input); + defer shader.delete(); + try shader.preprocess(&input); + try shader.parse(&input); +} diff --git a/pkg/glslang/test.zig b/pkg/glslang/test.zig new file mode 100644 index 000000000..8cdf98f75 --- /dev/null +++ b/pkg/glslang/test.zig @@ -0,0 +1,10 @@ +const glslang = @import("main.zig"); + +var initialized: bool = false; + +/// Call this function before any other tests in this package to ensure that +/// the glslang library is initialized. +pub fn ensureInit() !void { + if (initialized) return; + try glslang.init(); +} diff --git a/pkg/glslang/test/simple.frag b/pkg/glslang/test/simple.frag new file mode 100644 index 000000000..c1cd903ce --- /dev/null +++ b/pkg/glslang/test/simple.frag @@ -0,0 +1,56 @@ +#version 430 core + +layout(binding = 0) uniform Globals { + uniform vec3 iResolution; + uniform float iTime; + uniform float iTimeDelta; + uniform float iFrameRate; + uniform int iFrame; + uniform float iChannelTime[4]; + uniform vec3 iChannelResolution[4]; + uniform vec4 iMouse; + uniform vec4 iDate; + uniform float iSampleRate; +}; + +layout(binding = 0) uniform sampler2D iChannel0; +layout(binding = 1) uniform sampler2D iChannel1; +layout(binding = 2) uniform sampler2D iChannel2; +layout(binding = 3) uniform sampler2D iChannel3; + +layout(location = 0) in vec4 gl_FragCoord; +layout(location = 0) out vec4 _fragColor; + +#define texture2D texture + +void mainImage( out vec4 fragColor, in vec2 fragCoord ); +void main() { mainImage (_fragColor, gl_FragCoord.xy); } + +#define t iTime + +void mainImage( out vec4 fragColor, in vec2 fragCoord ) +{ + // Normalized pixel coordinates (from 0 to 1) + vec2 uv = ( fragCoord - .5*iResolution.xy) / iResolution.y; + vec3 col = vec3(0.); + float a = atan(uv.y,uv.x); + float r = 0.5*length(uv); + float counter = 100.; + a = 4.*a+20.*r+50.*cos(r)*cos(.1*t)+abs(a*r); + float f = 0.02*abs(cos(a))/(r*r); + + + vec2 v = vec2(0.); + for(float i=0.;i2.){ + counter = i; + break; + } + } + + col=vec3(min(0.9,1.2*exp(-pow(f,0.45)*counter))); + + fragColor = min(0.9,1.2*exp(-pow(f,0.45)*counter) ) + * ( 0.7 + 0.3* cos(10.*r - 2.*t -vec4(.7,1.4,2.1,0) ) ); +}