From 32806def90a68f5f0514405d0ff8c1b0cb16772e Mon Sep 17 00:00:00 2001 From: Kbz-8 Date: Sat, 4 Jul 2026 01:48:29 +0200 Subject: [PATCH] adding per invocation derivative signs --- src/Runtime.zig | 9 +++++++++ src/opcodes.zig | 23 ++++++++++++++++++++++- 2 files changed, 31 insertions(+), 1 deletion(-) diff --git a/src/Runtime.zig b/src/Runtime.zig index 7884b4d..5b0d25b 100644 --- a/src/Runtime.zig +++ b/src/Runtime.zig @@ -128,6 +128,8 @@ specialization_constants: std.AutoHashMapUnmanaged(u32, []const u8), derivatives: std.AutoHashMapUnmanaged(SpvWord, Derivative), phi_values: std.AutoHashMapUnmanaged(SpvWord, Value), helper_invocation: bool, +derivative_sign_x: f32, +derivative_sign_y: f32, image_api: ImageAPI, @@ -162,6 +164,8 @@ pub fn init(allocator: std.mem.Allocator, module: *Module, image_api: ImageAPI) .derivatives = .empty, .phi_values = .empty, .helper_invocation = false, + .derivative_sign_x = 1.0, + .derivative_sign_y = 1.0, .image_api = image_api, }; errdefer self.deinit(allocator); @@ -198,6 +202,8 @@ pub fn initFrom(allocator: std.mem.Allocator, other: *const Self, image_api: Ima .derivatives = .empty, .phi_values = .empty, .helper_invocation = other.helper_invocation, + .derivative_sign_x = other.derivative_sign_x, + .derivative_sign_y = other.derivative_sign_y, .image_api = image_api, }; errdefer self.deinit(allocator); @@ -1305,6 +1311,9 @@ pub fn hasResultOrMemberDecoration(self: *const Self, result: SpvWord, decoratio } pub fn resetInvocation(self: *Self, allocator: std.mem.Allocator) void { + self.derivative_sign_x = 1.0; + self.derivative_sign_y = 1.0; + var derivatives = self.derivatives.iterator(); while (derivatives.next()) |entry| { entry.value_ptr.deinit(allocator); diff --git a/src/opcodes.zig b/src/opcodes.zig index 3631c63..27fc5ee 100644 --- a/src/opcodes.zig +++ b/src/opcodes.zig @@ -5783,7 +5783,28 @@ fn DerivativeEngine(comptime axis: enum { x, y }) type { .x => &derivative.dx, .y => &derivative.dy, }; - try copyValue(try rt.results[id].getValue(), src); + const dst = try rt.results[id].getValue(); + try copyValue(dst, src); + const sign = switch (axis) { + .x => rt.derivative_sign_x, + .y => rt.derivative_sign_y, + }; + if (sign != 1.0) { + const target_type = (try rt.results[result_type_word].getVariant()).Type; + const lane_bits = try Result.resolveLaneBitWidth(target_type, rt); + const lane_count = try Result.resolveLaneCount(target_type); + switch (lane_bits) { + inline 16, 32, 64 => |bits| { + const FloatT = Value.getPrimitiveFieldType(.Float, bits); + const sign_t: FloatT = @floatCast(sign); + for (0..lane_count) |lane_index| { + const lane = try Value.readLane(.Float, bits, dst, lane_index); + try Value.writeLane(.Float, bits, dst, lane_index, lane * sign_t); + } + }, + else => return RuntimeError.InvalidSpirV, + } + } try rt.copyDerivative(allocator, id, operand); } };