diff --git a/build.zig.zon b/build.zig.zon index 36e44d5..ad2066f 100644 --- a/build.zig.zon +++ b/build.zig.zon @@ -7,8 +7,8 @@ .hash = "pretty-0.10.6-Tm65r99UAQDEJMgZysD10qE8dinBHr064fPM6YkxVPfB", }, .NZSL = .{ // For unit tests - .url = "git+https://git.kbz8.me/kbz_8/NZigSL#0bdfc3231138b2a1d5a2c9d517df2c3e7a296dc7", - .hash = "NZSL-1.1.1-N0xSVLF6AADmN3lNOmBVu0humpmo4YRv6pd-lSygyG8o", + .url = "git+https://git.kbz8.me/kbz_8/NZigSL#5377dbdf9935b0de767f76ea4650e7aba4516b32", + .hash = "NZSL-1.1.2-N0xSVMt6AAC1ncQHA_RafnclWolDA477iTnFmZgdvxd-", .lazy = true, }, }, diff --git a/example/shader.nzsl b/example/shader.nzsl index 4c68214..d71158b 100644 --- a/example/shader.nzsl +++ b/example/shader.nzsl @@ -3,25 +3,15 @@ module; struct FragOut { - [location(0)] value: f32, - [location(1)] value2: f32 -} - -fn Half(inout color: vec3[f32], out value: f32, in inValue: f32, inValue2: f32) -{ - color *= 2.0; - value = 10.0; + [location(0)] color: vec4[i32] } [entry(frag)] fn main() -> FragOut { - let output: FragOut; - let mainColor = vec3[f32](1.0, 1.0, 1.0); - let inValue = 2.0; - let inValue2 = 1.0; - Half(inout mainColor, out output.value2, in inValue, inValue2); - output.value = mainColor.x; - - return output; + let base: i32 = 4; + let value: i32 = base << 3; + let output: FragOut; + output.color = vec4[i32](value, value, value, value); + return output; } diff --git a/example/shader.spv b/example/shader.spv index ac2a675..04ee6a5 100644 Binary files a/example/shader.spv and b/example/shader.spv differ diff --git a/example/shader.spv.txt b/example/shader.spv.txt index c5210b3..a9fdff1 100644 --- a/example/shader.spv.txt +++ b/example/shader.spv.txt @@ -1,88 +1,50 @@ Version 1.0 Generator: 2560130 -Bound: 51 +Bound: 29 Schema: 0 OpCapability Capability(Shader) OpMemoryModel AddressingModel(Logical) MemoryModel(GLSL450) - OpEntryPoint ExecutionModel(Fragment) %20 "main" %11 %12 - OpExecutionMode %20 ExecutionMode(OriginUpperLeft) + OpEntryPoint ExecutionModel(Fragment) %13 "main" %6 + OpExecutionMode %13 ExecutionMode(OriginUpperLeft) OpSource SourceLanguage(NZSL) 4198400 OpSourceExtension "Version: 1.1" - OpName %13 "FragOut" - OpMemberName %13 0 "value" - OpMemberName %13 1 "value2" - OpName %11 "value" - OpName %12 "value2" - OpName %19 "Half" - OpName %20 "main" - OpDecorate %11 Decoration(Location) 0 - OpDecorate %12 Decoration(Location) 1 - OpMemberDecorate %13 0 Decoration(Offset) 0 - OpMemberDecorate %13 1 Decoration(Offset) 4 + OpName %7 "FragOut" + OpMemberName %7 0 "color" + OpName %6 "color" + OpName %13 "main" + OpDecorate %6 Decoration(Location) 0 + OpMemberDecorate %7 0 Decoration(Offset) 0 %1 = OpTypeVoid - %2 = OpTypeFloat 32 - %3 = OpTypeVector %2 3 - %4 = OpTypePointer StorageClass(Function) %3 - %5 = OpTypePointer StorageClass(Function) %2 - %6 = OpTypeFunction %1 %4 %5 %5 %5 - %7 = OpConstant %2 f32(2) - %8 = OpConstant %2 f32(10) - %9 = OpTypeFunction %1 -%10 = OpTypePointer StorageClass(Output) %2 -%13 = OpTypeStruct %2 %2 -%14 = OpTypePointer StorageClass(Function) %13 -%15 = OpConstant %2 f32(1) -%16 = OpTypeInt 32 1 -%17 = OpConstant %16 i32(1) -%18 = OpConstant %16 i32(0) -%11 = OpVariable %10 StorageClass(Output) -%12 = OpVariable %10 StorageClass(Output) -%19 = OpFunction %1 FunctionControl(0) %6 -%21 = OpFunctionParameter %4 -%22 = OpFunctionParameter %5 -%23 = OpFunctionParameter %5 -%24 = OpFunctionParameter %5 -%25 = OpLabel -%26 = OpLoad %3 %21 -%27 = OpVectorTimesScalar %3 %26 %7 - OpStore %21 %27 - OpStore %22 %8 - OpReturn - OpFunctionEnd -%20 = OpFunction %1 FunctionControl(0) %9 -%28 = OpLabel -%29 = OpVariable %14 StorageClass(Function) -%30 = OpVariable %4 StorageClass(Function) -%31 = OpVariable %5 StorageClass(Function) -%32 = OpVariable %5 StorageClass(Function) -%33 = OpVariable %4 StorageClass(Function) -%34 = OpVariable %5 StorageClass(Function) -%35 = OpVariable %5 StorageClass(Function) -%36 = OpVariable %5 StorageClass(Function) -%37 = OpCompositeConstruct %3 %15 %15 %15 - OpStore %30 %37 - OpStore %31 %7 - OpStore %32 %15 -%38 = OpLoad %3 %30 - OpStore %33 %38 -%39 = OpLoad %2 %31 - OpStore %35 %39 -%40 = OpLoad %2 %32 - OpStore %36 %40 -%41 = OpFunctionCall %1 %19 %33 %34 %35 %36 -%42 = OpLoad %3 %33 - OpStore %30 %42 -%43 = OpLoad %2 %34 -%44 = OpAccessChain %5 %29 %17 - OpStore %44 %43 -%45 = OpLoad %3 %30 -%46 = OpCompositeExtract %2 %45 0 -%47 = OpAccessChain %5 %29 %18 - OpStore %47 %46 -%48 = OpLoad %13 %29 -%49 = OpCompositeExtract %2 %48 0 - OpStore %11 %49 -%50 = OpCompositeExtract %2 %48 1 - OpStore %12 %50 + %2 = OpTypeFunction %1 + %3 = OpTypeInt 32 1 + %4 = OpTypeVector %3 4 + %5 = OpTypePointer StorageClass(Output) %4 + %7 = OpTypeStruct %4 + %8 = OpConstant %3 i32(4) + %9 = OpTypePointer StorageClass(Function) %3 +%10 = OpConstant %3 i32(3) +%11 = OpTypePointer StorageClass(Function) %7 +%12 = OpConstant %3 i32(0) +%26 = OpTypePointer StorageClass(Function) %4 + %6 = OpVariable %5 StorageClass(Output) +%13 = OpFunction %1 FunctionControl(0) %2 +%14 = OpLabel +%15 = OpVariable %9 StorageClass(Function) +%16 = OpVariable %9 StorageClass(Function) +%17 = OpVariable %11 StorageClass(Function) + OpStore %15 %8 +%18 = OpLoad %3 %15 +%19 = OpShiftLeftLogical %3 %18 %10 + OpStore %16 %19 +%20 = OpLoad %3 %16 +%21 = OpLoad %3 %16 +%22 = OpLoad %3 %16 +%23 = OpLoad %3 %16 +%24 = OpCompositeConstruct %4 %20 %21 %22 %23 +%25 = OpAccessChain %26 %17 %12 + OpStore %25 %24 +%27 = OpLoad %7 %17 +%28 = OpCompositeExtract %4 %27 0 + OpStore %6 %28 OpReturn OpFunctionEnd diff --git a/src/opcodes.zig b/src/opcodes.zig index 713f181..bbe1d4b 100644 --- a/src/opcodes.zig +++ b/src/opcodes.zig @@ -21,19 +21,33 @@ const ValueType = enum { const MathOp = enum { Add, - Sub, - Mul, Div, Mod, + Mul, + Sub, }; const CondOp = enum { Equal, - NotEqual, Greater, GreaterEqual, Less, LessEqual, + NotEqual, +}; + +const BitOp = enum { + BitCount, + BitFieldInsert, + BitFieldSExtract, + BitFieldUExtract, + BitReverse, + BitwiseAnd, + BitwiseXor, + Not, + ShiftLeft, + ShiftRight, + ShiftRightArithmetic, }; pub const OpCodeFunc = *const fn (std.mem.Allocator, SpvWord, *Runtime) RuntimeError!void; @@ -117,6 +131,17 @@ pub const SetupDispatcher = block: { .ULessThanEqual = autoSetupConstant, .UMod = autoSetupConstant, .Variable = opVariable, + .ShiftLeftLogical = autoSetupConstant, + .ShiftRightLogical = autoSetupConstant, + .ShiftRightArithmetic = autoSetupConstant, + .BitwiseAnd = autoSetupConstant, + .BitwiseXor = autoSetupConstant, + .Not = autoSetupConstant, + .BitFieldInsert = autoSetupConstant, + .BitFieldSExtract = autoSetupConstant, + .BitFieldUExtract = autoSetupConstant, + .BitReverse = autoSetupConstant, + .BitCount = autoSetupConstant, }); }; @@ -184,6 +209,65 @@ pub const RuntimeDispatcher = block: { }); }; +fn BitEngine(comptime T: ValueType, comptime Op: BitOp) type { + return struct { + fn op(_: std.mem.Allocator, _: SpvWord, rt: *Runtime) RuntimeError!void { + _ = rt.it.skip(); + const value = try rt.results[try rt.it.next()].getValue(); + const op1_value = try rt.results[try rt.it.next()].getValue(); + const op2_value = if (Op == .Not) null else try rt.results[try rt.it.next()].getValue(); + + const size = sw: switch (target_type) { + .Vector => |v| continue :sw (try rt.results[v.components_type_word].getVariant()).Type, + .Float => |f| if (T == .Float) f.bit_length else return RuntimeError.InvalidSpirV, + .Int => |i| if (T == .SInt or T == .UInt) i.bit_length else return RuntimeError.InvalidSpirV, + else => return RuntimeError.InvalidSpirV, + }; + + const operator = struct { + fn operation(comptime TT: type, op1: TT, op2: TT) RuntimeError!TT { + return switch (Op) { + .Add => if (@typeInfo(TT) == .int) @addWithOverflow(op1, op2)[0] else op1 + op2, + .Sub => if (@typeInfo(TT) == .int) @subWithOverflow(op1, op2)[0] else op1 - op2, + .Mul => if (@typeInfo(TT) == .int) @mulWithOverflow(op1, op2)[0] else op1 * op2, + .Div => blk: { + if (op2 == 0) return RuntimeError.DivisionByZero; + break :blk if (@typeInfo(TT) == .int) @divTrunc(op1, op2) else op1 / op2; + }, + .Mod => blk: { + if (op2 == 0) return RuntimeError.DivisionByZero; + break :blk @mod(op1, op2); + }, + }; + } + + fn process(bit_count: SpvWord, v: *Result.Value, op1_v: *const Result.Value, op2_v: *const Result.Value) RuntimeError!void { + switch (bit_count) { + inline 8, 16, 32, 64 => |i| { + if (i == 8 and T == .Float) { // No f8 + return RuntimeError.InvalidSpirV; + } + (try getValuePrimitiveField(T, i, v)).* = try operation( + getValuePrimitiveFieldType(T, i), + (try getValuePrimitiveField(T, i, @constCast(op1_v))).*, + (try getValuePrimitiveField(T, i, @constCast(op2_v))).*, + ); + }, + else => return RuntimeError.InvalidSpirV, + } + } + }; + + switch (value.*) { + .Float => if (T == .Float) try operator.process(size, value, op1_value, op2_value) else return RuntimeError.InvalidSpirV, + .Int => if (T == .SInt or T == .UInt) try operator.process(size, value, op1_value, op2_value) else return RuntimeError.InvalidSpirV, + .Vector => |vec| for (vec, op1_value.Vector, op2_value.Vector) |*val, op1_v, op2_v| try operator.process(size, val, &op1_v, &op2_v), + else => return RuntimeError.InvalidSpirV, + } + } + }; +} + fn CondEngine(comptime T: ValueType, comptime Op: CondOp) type { return struct { fn op(_: std.mem.Allocator, _: SpvWord, rt: *Runtime) RuntimeError!void {