improving spec constant support
This commit is contained in:
@@ -87,8 +87,10 @@ pub fn initRuntimeDispatcher() void {
|
|||||||
runtime_dispatcher[@intFromEnum(ext.GLSLOp.FClamp)] = MathEngine(.Float, .FClamp).opTripleOperators;
|
runtime_dispatcher[@intFromEnum(ext.GLSLOp.FClamp)] = MathEngine(.Float, .FClamp).opTripleOperators;
|
||||||
runtime_dispatcher[@intFromEnum(ext.GLSLOp.FMax)] = MathEngine(.Float, .FMax).opDoubleOperators;
|
runtime_dispatcher[@intFromEnum(ext.GLSLOp.FMax)] = MathEngine(.Float, .FMax).opDoubleOperators;
|
||||||
runtime_dispatcher[@intFromEnum(ext.GLSLOp.FMin)] = MathEngine(.Float, .FMin).opDoubleOperators;
|
runtime_dispatcher[@intFromEnum(ext.GLSLOp.FMin)] = MathEngine(.Float, .FMin).opDoubleOperators;
|
||||||
|
runtime_dispatcher[@intFromEnum(ext.GLSLOp.FMix)] = opFMix;
|
||||||
runtime_dispatcher[@intFromEnum(ext.GLSLOp.FSign)] = MathEngine(.Float, .FSign).opSingleOperator;
|
runtime_dispatcher[@intFromEnum(ext.GLSLOp.FSign)] = MathEngine(.Float, .FSign).opSingleOperator;
|
||||||
runtime_dispatcher[@intFromEnum(ext.GLSLOp.Floor)] = MathEngine(.Float, .Floor).opSingleOperator;
|
runtime_dispatcher[@intFromEnum(ext.GLSLOp.Floor)] = MathEngine(.Float, .Floor).opSingleOperator;
|
||||||
|
runtime_dispatcher[@intFromEnum(ext.GLSLOp.Fract)] = MathEngine(.Float, .Fract).opSingleOperator;
|
||||||
runtime_dispatcher[@intFromEnum(ext.GLSLOp.Length)] = opLength;
|
runtime_dispatcher[@intFromEnum(ext.GLSLOp.Length)] = opLength;
|
||||||
runtime_dispatcher[@intFromEnum(ext.GLSLOp.Log)] = MathEngine(.Float, .Log).opSingleOperator;
|
runtime_dispatcher[@intFromEnum(ext.GLSLOp.Log)] = MathEngine(.Float, .Log).opSingleOperator;
|
||||||
runtime_dispatcher[@intFromEnum(ext.GLSLOp.Log2)] = MathEngine(.Float, .Log2).opSingleOperator;
|
runtime_dispatcher[@intFromEnum(ext.GLSLOp.Log2)] = MathEngine(.Float, .Log2).opSingleOperator;
|
||||||
@@ -138,6 +140,7 @@ fn MathEngine(comptime T: PrimitiveType, comptime Op: MathOp) type {
|
|||||||
.FAbs => @abs(x),
|
.FAbs => @abs(x),
|
||||||
.FSign => std.math.sign(x),
|
.FSign => std.math.sign(x),
|
||||||
.Floor => @floor(x),
|
.Floor => @floor(x),
|
||||||
|
.Fract => x - @floor(x),
|
||||||
.Log => @log(x),
|
.Log => @log(x),
|
||||||
.Log2 => @log2(x),
|
.Log2 => @log2(x),
|
||||||
.Round => @round(x),
|
.Round => @round(x),
|
||||||
@@ -310,6 +313,37 @@ fn MathEngine(comptime T: PrimitiveType, comptime Op: MathOp) type {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
fn opFMix(
|
||||||
|
_: std.mem.Allocator,
|
||||||
|
target_type_id: SpvWord,
|
||||||
|
id: SpvWord,
|
||||||
|
_: SpvWord,
|
||||||
|
rt: *Runtime,
|
||||||
|
) RuntimeError!void {
|
||||||
|
const target_type = (try rt.results[target_type_id].getVariant()).Type;
|
||||||
|
const dst = try rt.results[id].getValue();
|
||||||
|
const x = try rt.results[try rt.it.next()].getValue();
|
||||||
|
const y = try rt.results[try rt.it.next()].getValue();
|
||||||
|
const a = try rt.results[try rt.it.next()].getValue();
|
||||||
|
|
||||||
|
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);
|
||||||
|
for (0..lane_count) |lane_index| {
|
||||||
|
const xv = try Value.readLane(.Float, bits, x, lane_index);
|
||||||
|
const yv = try Value.readLane(.Float, bits, y, lane_index);
|
||||||
|
const av = try Value.readLane(.Float, bits, a, lane_index);
|
||||||
|
try Value.writeLane(.Float, bits, dst, lane_index, @as(FloatT, xv * (1 - av) + yv * av));
|
||||||
|
}
|
||||||
|
},
|
||||||
|
else => return RuntimeError.InvalidSpirV,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn IntBitEngine(comptime op_kind: IntBitOp) type {
|
fn IntBitEngine(comptime op_kind: IntBitOp) type {
|
||||||
return struct {
|
return struct {
|
||||||
inline fn findILsb32(x: u32) i32 {
|
inline fn findILsb32(x: u32) i32 {
|
||||||
|
|||||||
+6
-7
@@ -149,13 +149,6 @@ fn checkEndiannessFromSpvMagic(magic: SpvWord) bool {
|
|||||||
|
|
||||||
fn pass(self: *Self, allocator: std.mem.Allocator) ModuleError!void {
|
fn pass(self: *Self, allocator: std.mem.Allocator) ModuleError!void {
|
||||||
var rt = Runtime.init(allocator, self, undefined) catch return ModuleError.OutOfMemory;
|
var rt = Runtime.init(allocator, self, undefined) catch return ModuleError.OutOfMemory;
|
||||||
defer {
|
|
||||||
for (self.results, rt.results) |*result, new_result| {
|
|
||||||
result.deinit(allocator);
|
|
||||||
result.* = new_result.dupe(allocator) catch unreachable; // OutOfMemory if unreachable
|
|
||||||
}
|
|
||||||
rt.deinit(allocator);
|
|
||||||
}
|
|
||||||
|
|
||||||
while (rt.it.nextOrNull()) |opcode_data| {
|
while (rt.it.nextOrNull()) |opcode_data| {
|
||||||
const word_count = ((opcode_data & (~spv.SpvOpCodeMask)) >> spv.SpvWordCountShift) - 1;
|
const word_count = ((opcode_data & (~spv.SpvOpCodeMask)) >> spv.SpvWordCountShift) - 1;
|
||||||
@@ -170,6 +163,12 @@ fn pass(self: *Self, allocator: std.mem.Allocator) ModuleError!void {
|
|||||||
_ = it_tmp.skipN(word_count);
|
_ = it_tmp.skipN(word_count);
|
||||||
rt.it = it_tmp;
|
rt.it = it_tmp;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (self.results, rt.results) |*result, new_result| {
|
||||||
|
result.deinit(allocator);
|
||||||
|
result.* = new_result.dupe(allocator) catch return ModuleError.OutOfMemory;
|
||||||
|
}
|
||||||
|
rt.deinit(allocator);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn resolveConstantWord(self: *const Self, id: SpvWord) ?SpvWord {
|
fn resolveConstantWord(self: *const Self, id: SpvWord) ?SpvWord {
|
||||||
|
|||||||
+6
-4
@@ -301,12 +301,14 @@ pub inline fn getConstValue(self: *Self) RuntimeError!*const Value {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
pub inline fn getVariant(self: *Self) RuntimeError!*VariantData {
|
pub fn getVariant(self: *Self) RuntimeError!*VariantData {
|
||||||
return &(self.variant orelse return RuntimeError.InvalidSpirV);
|
if (self.variant) |*variant| return variant;
|
||||||
|
return RuntimeError.InvalidSpirV;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub inline fn getConstVariant(self: *const Self) RuntimeError!*const VariantData {
|
pub fn getConstVariant(self: *const Self) RuntimeError!*const VariantData {
|
||||||
return &(self.variant orelse return RuntimeError.InvalidSpirV);
|
if (self.variant) |variant| return &variant;
|
||||||
|
return RuntimeError.InvalidSpirV;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Performs a deep copy
|
/// Performs a deep copy
|
||||||
|
|||||||
@@ -165,6 +165,7 @@ pub const Value = union(Type) {
|
|||||||
.Structure => |*s| s.values,
|
.Structure => |*s| s.values,
|
||||||
.Array => |*a| a.values,
|
.Array => |*a| a.values,
|
||||||
.Vector => |v| v,
|
.Vector => |v| v,
|
||||||
|
.Matrix => |m| m,
|
||||||
else => null,
|
else => null,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
+373
-54
@@ -71,6 +71,7 @@ const BitOp = enum {
|
|||||||
const ImageOp = enum {
|
const ImageOp = enum {
|
||||||
Fetch,
|
Fetch,
|
||||||
QuerySize,
|
QuerySize,
|
||||||
|
QuerySizeLod,
|
||||||
Read,
|
Read,
|
||||||
Resolve,
|
Resolve,
|
||||||
SampleExplicitLod,
|
SampleExplicitLod,
|
||||||
@@ -100,6 +101,7 @@ pub const OpCodeExtFunc = *const fn (std.mem.Allocator, SpvWord, SpvWord, SpvWor
|
|||||||
pub const SetupDispatcher = block: {
|
pub const SetupDispatcher = block: {
|
||||||
@setEvalBranchQuota(65535);
|
@setEvalBranchQuota(65535);
|
||||||
break :block std.EnumMap(spv.SpvOp, OpCodeFunc).init(.{
|
break :block std.EnumMap(spv.SpvOp, OpCodeFunc).init(.{
|
||||||
|
.AccessChain = setupAccessChain,
|
||||||
.All = autoSetupConstant,
|
.All = autoSetupConstant,
|
||||||
.Any = autoSetupConstant,
|
.Any = autoSetupConstant,
|
||||||
.AtomicAnd = autoSetupConstant,
|
.AtomicAnd = autoSetupConstant,
|
||||||
@@ -109,15 +111,14 @@ pub const SetupDispatcher = block: {
|
|||||||
.AtomicIDecrement = autoSetupConstant,
|
.AtomicIDecrement = autoSetupConstant,
|
||||||
.AtomicIIncrement = autoSetupConstant,
|
.AtomicIIncrement = autoSetupConstant,
|
||||||
.AtomicISub = autoSetupConstant,
|
.AtomicISub = autoSetupConstant,
|
||||||
.AtomicStore = autoSetupConstant,
|
|
||||||
.AtomicLoad = autoSetupConstant,
|
.AtomicLoad = autoSetupConstant,
|
||||||
.AtomicOr = autoSetupConstant,
|
.AtomicOr = autoSetupConstant,
|
||||||
.AtomicSMax = autoSetupConstant,
|
.AtomicSMax = autoSetupConstant,
|
||||||
.AtomicSMin = autoSetupConstant,
|
.AtomicSMin = autoSetupConstant,
|
||||||
|
.AtomicStore = autoSetupConstant,
|
||||||
.AtomicUMax = autoSetupConstant,
|
.AtomicUMax = autoSetupConstant,
|
||||||
.AtomicUMin = autoSetupConstant,
|
.AtomicUMin = autoSetupConstant,
|
||||||
.AtomicXor = autoSetupConstant,
|
.AtomicXor = autoSetupConstant,
|
||||||
.AccessChain = setupAccessChain,
|
|
||||||
.BitCount = autoSetupConstant,
|
.BitCount = autoSetupConstant,
|
||||||
.BitFieldInsert = autoSetupConstant,
|
.BitFieldInsert = autoSetupConstant,
|
||||||
.BitFieldSExtract = autoSetupConstant,
|
.BitFieldSExtract = autoSetupConstant,
|
||||||
@@ -132,21 +133,26 @@ pub const SetupDispatcher = block: {
|
|||||||
.CompositeInsert = autoSetupConstant,
|
.CompositeInsert = autoSetupConstant,
|
||||||
.Constant = opConstant,
|
.Constant = opConstant,
|
||||||
.ConstantComposite = opConstantComposite,
|
.ConstantComposite = opConstantComposite,
|
||||||
|
.ConstantFalse = opConstantFalse,
|
||||||
|
.ConstantTrue = opConstantTrue,
|
||||||
.ConvertFToS = autoSetupConstant,
|
.ConvertFToS = autoSetupConstant,
|
||||||
.ConvertFToU = autoSetupConstant,
|
.ConvertFToU = autoSetupConstant,
|
||||||
.ConvertPtrToU = autoSetupConstant,
|
.ConvertPtrToU = autoSetupConstant,
|
||||||
.ConvertSToF = autoSetupConstant,
|
.ConvertSToF = autoSetupConstant,
|
||||||
.ConvertUToF = autoSetupConstant,
|
.ConvertUToF = autoSetupConstant,
|
||||||
.ConvertUToPtr = autoSetupConstant,
|
.ConvertUToPtr = autoSetupConstant,
|
||||||
.Decorate = opDecorate,
|
|
||||||
.DecorationGroup = opDecorationGroup,
|
|
||||||
.Dot = autoSetupConstant,
|
|
||||||
.DPdx = autoSetupConstant,
|
.DPdx = autoSetupConstant,
|
||||||
.DPdxCoarse = autoSetupConstant,
|
.DPdxCoarse = autoSetupConstant,
|
||||||
.DPdxFine = autoSetupConstant,
|
.DPdxFine = autoSetupConstant,
|
||||||
.DPdy = autoSetupConstant,
|
.DPdy = autoSetupConstant,
|
||||||
.DPdyCoarse = autoSetupConstant,
|
.DPdyCoarse = autoSetupConstant,
|
||||||
.DPdyFine = autoSetupConstant,
|
.DPdyFine = autoSetupConstant,
|
||||||
|
.Fwidth = autoSetupConstant,
|
||||||
|
.FwidthCoarse = autoSetupConstant,
|
||||||
|
.FwidthFine = autoSetupConstant,
|
||||||
|
.Decorate = opDecorate,
|
||||||
|
.DecorationGroup = opDecorationGroup,
|
||||||
|
.Dot = autoSetupConstant,
|
||||||
.EntryPoint = opEntryPoint,
|
.EntryPoint = opEntryPoint,
|
||||||
.ExecutionMode = opExecutionMode,
|
.ExecutionMode = opExecutionMode,
|
||||||
.ExtInst = autoSetupConstant,
|
.ExtInst = autoSetupConstant,
|
||||||
@@ -187,6 +193,7 @@ pub const SetupDispatcher = block: {
|
|||||||
.Image = autoSetupConstant,
|
.Image = autoSetupConstant,
|
||||||
.ImageFetch = autoSetupConstant,
|
.ImageFetch = autoSetupConstant,
|
||||||
.ImageQuerySize = autoSetupConstant,
|
.ImageQuerySize = autoSetupConstant,
|
||||||
|
.ImageQuerySizeLod = autoSetupConstant,
|
||||||
.ImageRead = autoSetupConstant,
|
.ImageRead = autoSetupConstant,
|
||||||
.ImageSampleExplicitLod = autoSetupConstant,
|
.ImageSampleExplicitLod = autoSetupConstant,
|
||||||
.ImageSampleImplicitLod = autoSetupConstant,
|
.ImageSampleImplicitLod = autoSetupConstant,
|
||||||
@@ -230,23 +237,23 @@ pub const SetupDispatcher = block: {
|
|||||||
.ShiftLeftLogical = autoSetupConstant,
|
.ShiftLeftLogical = autoSetupConstant,
|
||||||
.ShiftRightArithmetic = autoSetupConstant,
|
.ShiftRightArithmetic = autoSetupConstant,
|
||||||
.ShiftRightLogical = autoSetupConstant,
|
.ShiftRightLogical = autoSetupConstant,
|
||||||
|
.SourceExtension = opSourceExtension,
|
||||||
.SpecConstant = opSpecConstant,
|
.SpecConstant = opSpecConstant,
|
||||||
.SpecConstantComposite = opConstantComposite,
|
.SpecConstantComposite = opConstantComposite,
|
||||||
.SpecConstantFalse = opSpecConstantFalse,
|
.SpecConstantFalse = opSpecConstantFalse,
|
||||||
.SpecConstantOp = opSpecConstantOp,
|
.SpecConstantOp = opSpecConstantOp,
|
||||||
.SpecConstantTrue = opSpecConstantTrue,
|
.SpecConstantTrue = opSpecConstantTrue,
|
||||||
.SourceExtension = opSourceExtension,
|
|
||||||
.TypeArray = opTypeArray,
|
.TypeArray = opTypeArray,
|
||||||
.TypeBool = opTypeBool,
|
.TypeBool = opTypeBool,
|
||||||
.TypeFloat = opTypeFloat,
|
.TypeFloat = opTypeFloat,
|
||||||
.TypeFunction = opTypeFunction,
|
.TypeFunction = opTypeFunction,
|
||||||
.TypeImage = opTypeImage,
|
.TypeImage = opTypeImage,
|
||||||
.TypeSampler = opTypeSampler,
|
|
||||||
.TypeSampledImage = opTypeSampledImage,
|
|
||||||
.TypeInt = opTypeInt,
|
.TypeInt = opTypeInt,
|
||||||
.TypeMatrix = opTypeMatrix,
|
.TypeMatrix = opTypeMatrix,
|
||||||
.TypePointer = opTypePointer,
|
.TypePointer = opTypePointer,
|
||||||
.TypeRuntimeArray = opTypeRuntimeArray,
|
.TypeRuntimeArray = opTypeRuntimeArray,
|
||||||
|
.TypeSampledImage = opTypeSampledImage,
|
||||||
|
.TypeSampler = opTypeSampler,
|
||||||
.TypeStruct = opTypeStruct,
|
.TypeStruct = opTypeStruct,
|
||||||
.TypeVector = opTypeVector,
|
.TypeVector = opTypeVector,
|
||||||
.TypeVoid = opTypeVoid,
|
.TypeVoid = opTypeVoid,
|
||||||
@@ -260,6 +267,7 @@ pub const SetupDispatcher = block: {
|
|||||||
.UMulExtended = autoSetupConstant,
|
.UMulExtended = autoSetupConstant,
|
||||||
.Undef = autoSetupConstant,
|
.Undef = autoSetupConstant,
|
||||||
.Variable = opVariable,
|
.Variable = opVariable,
|
||||||
|
.VectorExtractDynamic = autoSetupConstant,
|
||||||
.VectorShuffle = autoSetupConstant,
|
.VectorShuffle = autoSetupConstant,
|
||||||
.VectorTimesMatrix = autoSetupConstant,
|
.VectorTimesMatrix = autoSetupConstant,
|
||||||
.VectorTimesScalar = autoSetupConstant,
|
.VectorTimesScalar = autoSetupConstant,
|
||||||
@@ -315,6 +323,9 @@ pub fn initRuntimeDispatcher() void {
|
|||||||
runtime_dispatcher[@intFromEnum(spv.SpvOp.DPdy)] = DerivativeEngine(.y).op;
|
runtime_dispatcher[@intFromEnum(spv.SpvOp.DPdy)] = DerivativeEngine(.y).op;
|
||||||
runtime_dispatcher[@intFromEnum(spv.SpvOp.DPdyCoarse)] = DerivativeEngine(.y).op;
|
runtime_dispatcher[@intFromEnum(spv.SpvOp.DPdyCoarse)] = DerivativeEngine(.y).op;
|
||||||
runtime_dispatcher[@intFromEnum(spv.SpvOp.DPdyFine)] = DerivativeEngine(.y).op;
|
runtime_dispatcher[@intFromEnum(spv.SpvOp.DPdyFine)] = DerivativeEngine(.y).op;
|
||||||
|
runtime_dispatcher[@intFromEnum(spv.SpvOp.Fwidth)] = opFwidth;
|
||||||
|
runtime_dispatcher[@intFromEnum(spv.SpvOp.FwidthCoarse)] = opFwidth;
|
||||||
|
runtime_dispatcher[@intFromEnum(spv.SpvOp.FwidthFine)] = opFwidth;
|
||||||
runtime_dispatcher[@intFromEnum(spv.SpvOp.Dot)] = opDot;
|
runtime_dispatcher[@intFromEnum(spv.SpvOp.Dot)] = opDot;
|
||||||
runtime_dispatcher[@intFromEnum(spv.SpvOp.ExtInst)] = opExtInst;
|
runtime_dispatcher[@intFromEnum(spv.SpvOp.ExtInst)] = opExtInst;
|
||||||
runtime_dispatcher[@intFromEnum(spv.SpvOp.FAdd)] = MathEngine(.Float, .Add, false).op;
|
runtime_dispatcher[@intFromEnum(spv.SpvOp.FAdd)] = MathEngine(.Float, .Add, false).op;
|
||||||
@@ -348,6 +359,7 @@ pub fn initRuntimeDispatcher() void {
|
|||||||
runtime_dispatcher[@intFromEnum(spv.SpvOp.Image)] = ImageEngine(.Resolve).op;
|
runtime_dispatcher[@intFromEnum(spv.SpvOp.Image)] = ImageEngine(.Resolve).op;
|
||||||
runtime_dispatcher[@intFromEnum(spv.SpvOp.ImageFetch)] = ImageEngine(.Fetch).op;
|
runtime_dispatcher[@intFromEnum(spv.SpvOp.ImageFetch)] = ImageEngine(.Fetch).op;
|
||||||
runtime_dispatcher[@intFromEnum(spv.SpvOp.ImageQuerySize)] = ImageEngine(.QuerySize).op;
|
runtime_dispatcher[@intFromEnum(spv.SpvOp.ImageQuerySize)] = ImageEngine(.QuerySize).op;
|
||||||
|
runtime_dispatcher[@intFromEnum(spv.SpvOp.ImageQuerySizeLod)] = ImageEngine(.QuerySizeLod).op;
|
||||||
runtime_dispatcher[@intFromEnum(spv.SpvOp.ImageRead)] = ImageEngine(.Read).op;
|
runtime_dispatcher[@intFromEnum(spv.SpvOp.ImageRead)] = ImageEngine(.Read).op;
|
||||||
runtime_dispatcher[@intFromEnum(spv.SpvOp.ImageSampleExplicitLod)] = ImageEngine(.SampleExplicitLod).op;
|
runtime_dispatcher[@intFromEnum(spv.SpvOp.ImageSampleExplicitLod)] = ImageEngine(.SampleExplicitLod).op;
|
||||||
runtime_dispatcher[@intFromEnum(spv.SpvOp.ImageSampleImplicitLod)] = ImageEngine(.SampleImplicitLod).op;
|
runtime_dispatcher[@intFromEnum(spv.SpvOp.ImageSampleImplicitLod)] = ImageEngine(.SampleImplicitLod).op;
|
||||||
@@ -406,6 +418,7 @@ pub fn initRuntimeDispatcher() void {
|
|||||||
runtime_dispatcher[@intFromEnum(spv.SpvOp.UMod)] = MathEngine(.UInt, .Mod, false).op;
|
runtime_dispatcher[@intFromEnum(spv.SpvOp.UMod)] = MathEngine(.UInt, .Mod, false).op;
|
||||||
runtime_dispatcher[@intFromEnum(spv.SpvOp.UMulExtended)] = opUMulExtended;
|
runtime_dispatcher[@intFromEnum(spv.SpvOp.UMulExtended)] = opUMulExtended;
|
||||||
runtime_dispatcher[@intFromEnum(spv.SpvOp.Unreachable)] = opUnreachable;
|
runtime_dispatcher[@intFromEnum(spv.SpvOp.Unreachable)] = opUnreachable;
|
||||||
|
runtime_dispatcher[@intFromEnum(spv.SpvOp.VectorExtractDynamic)] = opVectorExtractDynamic;
|
||||||
runtime_dispatcher[@intFromEnum(spv.SpvOp.VectorShuffle)] = opVectorShuffle;
|
runtime_dispatcher[@intFromEnum(spv.SpvOp.VectorShuffle)] = opVectorShuffle;
|
||||||
runtime_dispatcher[@intFromEnum(spv.SpvOp.VectorTimesMatrix)] = MathEngine(.Float, .VectorTimesMatrix, false).op; // TODO
|
runtime_dispatcher[@intFromEnum(spv.SpvOp.VectorTimesMatrix)] = MathEngine(.Float, .VectorTimesMatrix, false).op; // TODO
|
||||||
runtime_dispatcher[@intFromEnum(spv.SpvOp.VectorTimesScalar)] = MathEngine(.Float, .VectorTimesScalar, false).op;
|
runtime_dispatcher[@intFromEnum(spv.SpvOp.VectorTimesScalar)] = MathEngine(.Float, .VectorTimesScalar, false).op;
|
||||||
@@ -1117,6 +1130,29 @@ fn ImageEngine(comptime Op: ImageOp) type {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn resolveImageForQuery(image: *Result, rt: *Runtime) RuntimeError!ImageOperand {
|
||||||
|
return switch ((try image.getValue()).*) {
|
||||||
|
.Image => try resolveImage(image, rt),
|
||||||
|
.SampledImage => |img| blk: {
|
||||||
|
const sampled_image_type = switch ((try rt.results[img.type_word].getConstVariant()).*) {
|
||||||
|
.Type => |t| switch (t) {
|
||||||
|
.SampledImage => |sampled_image| sampled_image,
|
||||||
|
else => return RuntimeError.InvalidSpirV,
|
||||||
|
},
|
||||||
|
else => return RuntimeError.InvalidSpirV,
|
||||||
|
};
|
||||||
|
|
||||||
|
break :blk .{
|
||||||
|
.type_word = sampled_image_type.image_type,
|
||||||
|
.driver_image = img.driver_image,
|
||||||
|
.dim = try resolveImageDim(rt, sampled_image_type.image_type),
|
||||||
|
.arrayed = try resolveImageArrayed(rt, sampled_image_type.image_type),
|
||||||
|
};
|
||||||
|
},
|
||||||
|
else => return RuntimeError.InvalidSpirV,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
fn readStorageCoordLane(coord: *const Value, lane_index: usize) RuntimeError!i32 {
|
fn readStorageCoordLane(coord: *const Value, lane_index: usize) RuntimeError!i32 {
|
||||||
return switch (coord.*) {
|
return switch (coord.*) {
|
||||||
.Int => |i| {
|
.Int => |i| {
|
||||||
@@ -1504,8 +1540,11 @@ fn ImageEngine(comptime Op: ImageOp) type {
|
|||||||
_ = try rt.it.next(); // result type
|
_ = try rt.it.next(); // result type
|
||||||
const result_id = try rt.it.next();
|
const result_id = try rt.it.next();
|
||||||
const image = &rt.results[try rt.it.next()];
|
const image = &rt.results[try rt.it.next()];
|
||||||
if (comptime Op == .QuerySize) {
|
if (comptime Op == .QuerySize or Op == .QuerySizeLod) {
|
||||||
const image_operand = try resolveImage(image, rt);
|
const image_operand = try resolveImageForQuery(image, rt);
|
||||||
|
if (comptime Op == .QuerySizeLod) {
|
||||||
|
_ = try rt.it.next(); // LOD operand; ImageAPI currently exposes base size only.
|
||||||
|
}
|
||||||
const dst = try rt.results[result_id].getValue();
|
const dst = try rt.results[result_id].getValue();
|
||||||
return try queryImageSize(rt, dst, image_operand);
|
return try queryImageSize(rt, dst, image_operand);
|
||||||
}
|
}
|
||||||
@@ -2710,22 +2749,6 @@ fn opCompositeConstruct(_: std.mem.Allocator, word_count: SpvWord, rt: *Runtime)
|
|||||||
}.routines;
|
}.routines;
|
||||||
|
|
||||||
switch (value.*) {
|
switch (value.*) {
|
||||||
.Matrix => |*m| {
|
|
||||||
var index: SpvWord = 0;
|
|
||||||
for (m.*[0..]) |*mat_elem| {
|
|
||||||
if (mat_elem.getCompositeDataOrNull()) |vec| {
|
|
||||||
for (vec[0..]) |*elem| {
|
|
||||||
const elem_value = (try rt.results[try rt.it.next()].getVariant()).Constant.value;
|
|
||||||
elem.* = elem_value;
|
|
||||||
index += 1;
|
|
||||||
if (index == index_count)
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
try vectorRoutines(mat_elem, rt);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
.RuntimeArray => |arr| {
|
.RuntimeArray => |arr| {
|
||||||
_ = arr;
|
_ = arr;
|
||||||
return RuntimeError.ToDo;
|
return RuntimeError.ToDo;
|
||||||
@@ -2915,6 +2938,22 @@ fn opCompositeInsert(allocator: std.mem.Allocator, word_count: SpvWord, rt: *Run
|
|||||||
try helpers.insertAt(arena.allocator(), rt.results, target, object, indices);
|
try helpers.insertAt(arena.allocator(), rt.results, target, object, indices);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn opConstantFalse(allocator: std.mem.Allocator, _: SpvWord, rt: *Runtime) RuntimeError!void {
|
||||||
|
const target = try setupConstant(allocator, rt);
|
||||||
|
switch (target.variant.?.Constant.value) {
|
||||||
|
.Bool => |*b| b.* = false,
|
||||||
|
else => return RuntimeError.InvalidSpirV,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn opConstantTrue(allocator: std.mem.Allocator, _: SpvWord, rt: *Runtime) RuntimeError!void {
|
||||||
|
const target = try setupConstant(allocator, rt);
|
||||||
|
switch (target.variant.?.Constant.value) {
|
||||||
|
.Bool => |*b| b.* = true,
|
||||||
|
else => return RuntimeError.InvalidSpirV,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn opConstant(allocator: std.mem.Allocator, word_count: SpvWord, rt: *Runtime) RuntimeError!void {
|
fn opConstant(allocator: std.mem.Allocator, word_count: SpvWord, rt: *Runtime) RuntimeError!void {
|
||||||
const target = try setupConstant(allocator, rt);
|
const target = try setupConstant(allocator, rt);
|
||||||
switch (target.variant.?.Constant.value) {
|
switch (target.variant.?.Constant.value) {
|
||||||
@@ -3320,38 +3359,213 @@ fn opSpecConstantOp(allocator: std.mem.Allocator, word_count: SpvWord, rt: *Runt
|
|||||||
if (word_count < 3)
|
if (word_count < 3)
|
||||||
return RuntimeError.InvalidSpirV;
|
return RuntimeError.InvalidSpirV;
|
||||||
|
|
||||||
|
const helpers = struct {
|
||||||
|
fn readUInt(value: *const Value) RuntimeError!u64 {
|
||||||
|
return switch (value.*) {
|
||||||
|
.Int => |i| switch (i.bit_count) {
|
||||||
|
8 => i.value.uint8,
|
||||||
|
16 => i.value.uint16,
|
||||||
|
32 => i.value.uint32,
|
||||||
|
64 => i.value.uint64,
|
||||||
|
else => return RuntimeError.InvalidSpirV,
|
||||||
|
},
|
||||||
|
else => return RuntimeError.InvalidValueType,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
fn readSInt(value: *const Value) RuntimeError!i64 {
|
||||||
|
return switch (value.*) {
|
||||||
|
.Int => |i| switch (i.bit_count) {
|
||||||
|
8 => i.value.sint8,
|
||||||
|
16 => i.value.sint16,
|
||||||
|
32 => i.value.sint32,
|
||||||
|
64 => i.value.sint64,
|
||||||
|
else => return RuntimeError.InvalidSpirV,
|
||||||
|
},
|
||||||
|
else => return RuntimeError.InvalidValueType,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
fn readBool(value: *const Value) RuntimeError!bool {
|
||||||
|
return switch (value.*) {
|
||||||
|
.Bool => |b| b,
|
||||||
|
else => return RuntimeError.InvalidValueType,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
fn writeUInt(dst: *Value, raw: u64) RuntimeError!void {
|
||||||
|
switch (dst.*) {
|
||||||
|
.Int => |*i| switch (i.bit_count) {
|
||||||
|
8 => i.value.uint8 = @truncate(raw),
|
||||||
|
16 => i.value.uint16 = @truncate(raw),
|
||||||
|
32 => i.value.uint32 = @truncate(raw),
|
||||||
|
64 => i.value.uint64 = raw,
|
||||||
|
else => return RuntimeError.InvalidSpirV,
|
||||||
|
},
|
||||||
|
else => return RuntimeError.InvalidValueType,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn shiftLeftLogical(value: u64, amount: u64, bit_count: usize) RuntimeError!u64 {
|
||||||
|
return switch (bit_count) {
|
||||||
|
inline 8, 16, 32, 64 => |bits| blk: {
|
||||||
|
if (amount >= bits) break :blk 0;
|
||||||
|
|
||||||
|
const UInt = std.meta.Int(.unsigned, bits);
|
||||||
|
const shift: std.math.Log2Int(UInt) = @intCast(amount);
|
||||||
|
const result = @as(UInt, @truncate(value)) << shift;
|
||||||
|
break :blk @as(u64, result);
|
||||||
|
},
|
||||||
|
else => return RuntimeError.InvalidSpirV,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
fn shiftRightLogical(value: u64, amount: u64, bit_count: usize) RuntimeError!u64 {
|
||||||
|
return switch (bit_count) {
|
||||||
|
inline 8, 16, 32, 64 => |bits| blk: {
|
||||||
|
if (amount >= bits) break :blk 0;
|
||||||
|
|
||||||
|
const UInt = std.meta.Int(.unsigned, bits);
|
||||||
|
const shift: std.math.Log2Int(UInt) = @intCast(amount);
|
||||||
|
const result = @as(UInt, @truncate(value)) >> shift;
|
||||||
|
break :blk @as(u64, result);
|
||||||
|
},
|
||||||
|
else => return RuntimeError.InvalidSpirV,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
fn shiftRightArithmetic(value: *const Value, amount: u64, bit_count: usize) RuntimeError!u64 {
|
||||||
|
return switch (bit_count) {
|
||||||
|
inline 8, 16, 32, 64 => |bits| blk: {
|
||||||
|
const SInt = std.meta.Int(.signed, bits);
|
||||||
|
const UInt = std.meta.Int(.unsigned, bits);
|
||||||
|
const lhs: SInt = @bitCast(@as(UInt, @truncate(try readUInt(value))));
|
||||||
|
if (amount >= bits) {
|
||||||
|
break :blk @as(u64, @as(UInt, @bitCast(if (lhs < 0) @as(SInt, -1) else @as(SInt, 0))));
|
||||||
|
}
|
||||||
|
|
||||||
|
const shift: std.math.Log2Int(SInt) = @intCast(amount);
|
||||||
|
break :blk @as(u64, @as(UInt, @bitCast(lhs >> shift)));
|
||||||
|
},
|
||||||
|
else => return RuntimeError.InvalidSpirV,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
fn bitNot(value: u64, bit_count: usize) RuntimeError!u64 {
|
||||||
|
return switch (bit_count) {
|
||||||
|
inline 8, 16, 32, 64 => |bits| blk: {
|
||||||
|
const UInt = std.meta.Int(.unsigned, bits);
|
||||||
|
break :blk @as(u64, ~@as(UInt, @truncate(value)));
|
||||||
|
},
|
||||||
|
else => return RuntimeError.InvalidSpirV,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const target = try setupConstant(allocator, rt);
|
const target = try setupConstant(allocator, rt);
|
||||||
const inner_op = try rt.it.nextAs(spv.SpvOp);
|
const inner_op = try rt.it.nextAs(spv.SpvOp);
|
||||||
|
|
||||||
const target_value = try target.getValue();
|
const target_value = try target.getValue();
|
||||||
|
|
||||||
switch (target_value.*) {
|
switch (target_value.*) {
|
||||||
.Int => |*dst| {
|
.Int => |dst| {
|
||||||
if (word_count != 5)
|
const bit_count = dst.bit_count;
|
||||||
return RuntimeError.UnsupportedSpirV;
|
|
||||||
|
|
||||||
const lhs = (try rt.results[try rt.it.next()].getValue()).Int;
|
const result = switch (inner_op) {
|
||||||
const rhs = (try rt.results[try rt.it.next()].getValue()).Int;
|
.Not => blk: {
|
||||||
const lhs_u = lhs.value.uint64;
|
if (word_count != 4)
|
||||||
const rhs_u = rhs.value.uint64;
|
return RuntimeError.InvalidSpirV;
|
||||||
|
|
||||||
dst.value.uint64 = switch (inner_op) {
|
const operand = try rt.results[try rt.it.next()].getValue();
|
||||||
.IAdd => @addWithOverflow(lhs_u, rhs_u)[0],
|
break :blk try helpers.bitNot(try helpers.readUInt(operand), bit_count);
|
||||||
.ISub => @subWithOverflow(lhs_u, rhs_u)[0],
|
|
||||||
.IMul => @mulWithOverflow(lhs_u, rhs_u)[0],
|
|
||||||
.UDiv => if (rhs_u != 0) @divTrunc(lhs_u, rhs_u) else return RuntimeError.DivisionByZero,
|
|
||||||
.UMod => if (rhs_u != 0) @mod(lhs_u, rhs_u) else return RuntimeError.DivisionByZero,
|
|
||||||
.SDiv => switch (dst.bit_count) {
|
|
||||||
32 => @as(u32, @bitCast(@divTrunc(lhs.value.sint32, rhs.value.sint32))),
|
|
||||||
64 => @bitCast(@divTrunc(lhs.value.sint64, rhs.value.sint64)),
|
|
||||||
else => return RuntimeError.UnsupportedSpirV,
|
|
||||||
},
|
},
|
||||||
.SMod => switch (dst.bit_count) {
|
else => blk: {
|
||||||
32 => @as(u32, @bitCast(@mod(lhs.value.sint32, rhs.value.sint32))),
|
if (word_count != 5)
|
||||||
64 => @bitCast(@mod(lhs.value.sint64, rhs.value.sint64)),
|
return RuntimeError.InvalidSpirV;
|
||||||
else => return RuntimeError.UnsupportedSpirV,
|
|
||||||
|
const lhs_value = try rt.results[try rt.it.next()].getValue();
|
||||||
|
const rhs_value = try rt.results[try rt.it.next()].getValue();
|
||||||
|
const lhs_u = try helpers.readUInt(lhs_value);
|
||||||
|
const rhs_u = try helpers.readUInt(rhs_value);
|
||||||
|
|
||||||
|
break :blk switch (inner_op) {
|
||||||
|
.IAdd => @addWithOverflow(lhs_u, rhs_u)[0],
|
||||||
|
.ISub => @subWithOverflow(lhs_u, rhs_u)[0],
|
||||||
|
.IMul => @mulWithOverflow(lhs_u, rhs_u)[0],
|
||||||
|
|
||||||
|
.UDiv => if (rhs_u != 0) @divTrunc(lhs_u, rhs_u) else return RuntimeError.DivisionByZero,
|
||||||
|
.UMod => if (rhs_u != 0) @mod(lhs_u, rhs_u) else return RuntimeError.DivisionByZero,
|
||||||
|
.SDiv => blk_signed: {
|
||||||
|
if (rhs_u == 0) return RuntimeError.DivisionByZero;
|
||||||
|
break :blk_signed switch (bit_count) {
|
||||||
|
8 => @as(u8, @bitCast(@divTrunc(@as(i8, @bitCast(@as(u8, @truncate(lhs_u)))), @as(i8, @bitCast(@as(u8, @truncate(rhs_u))))))),
|
||||||
|
16 => @as(u16, @bitCast(@divTrunc(@as(i16, @bitCast(@as(u16, @truncate(lhs_u)))), @as(i16, @bitCast(@as(u16, @truncate(rhs_u))))))),
|
||||||
|
32 => @as(u32, @bitCast(@divTrunc(@as(i32, @bitCast(@as(u32, @truncate(lhs_u)))), @as(i32, @bitCast(@as(u32, @truncate(rhs_u))))))),
|
||||||
|
64 => @as(u64, @bitCast(@divTrunc(@as(i64, @bitCast(lhs_u)), @as(i64, @bitCast(rhs_u))))),
|
||||||
|
else => return RuntimeError.InvalidSpirV,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
.SMod => blk_signed: {
|
||||||
|
if (rhs_u == 0) return RuntimeError.DivisionByZero;
|
||||||
|
break :blk_signed switch (bit_count) {
|
||||||
|
8 => @as(u8, @bitCast(@mod(@as(i8, @bitCast(@as(u8, @truncate(lhs_u)))), @as(i8, @bitCast(@as(u8, @truncate(rhs_u))))))),
|
||||||
|
16 => @as(u16, @bitCast(@mod(@as(i16, @bitCast(@as(u16, @truncate(lhs_u)))), @as(i16, @bitCast(@as(u16, @truncate(rhs_u))))))),
|
||||||
|
32 => @as(u32, @bitCast(@mod(@as(i32, @bitCast(@as(u32, @truncate(lhs_u)))), @as(i32, @bitCast(@as(u32, @truncate(rhs_u))))))),
|
||||||
|
64 => @as(u64, @bitCast(@mod(@as(i64, @bitCast(lhs_u)), @as(i64, @bitCast(rhs_u))))),
|
||||||
|
else => return RuntimeError.InvalidSpirV,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
|
||||||
|
.BitwiseAnd => lhs_u & rhs_u,
|
||||||
|
.BitwiseOr => lhs_u | rhs_u,
|
||||||
|
.BitwiseXor => lhs_u ^ rhs_u,
|
||||||
|
.ShiftLeftLogical => try helpers.shiftLeftLogical(lhs_u, rhs_u, bit_count),
|
||||||
|
.ShiftRightLogical => try helpers.shiftRightLogical(lhs_u, rhs_u, bit_count),
|
||||||
|
.ShiftRightArithmetic => try helpers.shiftRightArithmetic(lhs_value, rhs_u, bit_count),
|
||||||
|
|
||||||
|
else => return RuntimeError.UnsupportedSpirV,
|
||||||
|
};
|
||||||
},
|
},
|
||||||
else => return RuntimeError.UnsupportedSpirV,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
try helpers.writeUInt(target_value, result);
|
||||||
|
},
|
||||||
|
.Bool => |*dst| {
|
||||||
|
const result = switch (inner_op) {
|
||||||
|
.LogicalNot => blk: {
|
||||||
|
if (word_count != 4)
|
||||||
|
return RuntimeError.InvalidSpirV;
|
||||||
|
|
||||||
|
const operand = try rt.results[try rt.it.next()].getValue();
|
||||||
|
break :blk !(try helpers.readBool(operand));
|
||||||
|
},
|
||||||
|
else => blk: {
|
||||||
|
if (word_count != 5)
|
||||||
|
return RuntimeError.InvalidSpirV;
|
||||||
|
|
||||||
|
const lhs_value = try rt.results[try rt.it.next()].getValue();
|
||||||
|
const rhs_value = try rt.results[try rt.it.next()].getValue();
|
||||||
|
|
||||||
|
break :blk switch (inner_op) {
|
||||||
|
.IEqual => (try helpers.readUInt(lhs_value)) == (try helpers.readUInt(rhs_value)),
|
||||||
|
.INotEqual => (try helpers.readUInt(lhs_value)) != (try helpers.readUInt(rhs_value)),
|
||||||
|
.UGreaterThan => (try helpers.readUInt(lhs_value)) > (try helpers.readUInt(rhs_value)),
|
||||||
|
.UGreaterThanEqual => (try helpers.readUInt(lhs_value)) >= (try helpers.readUInt(rhs_value)),
|
||||||
|
.ULessThan => (try helpers.readUInt(lhs_value)) < (try helpers.readUInt(rhs_value)),
|
||||||
|
.ULessThanEqual => (try helpers.readUInt(lhs_value)) <= (try helpers.readUInt(rhs_value)),
|
||||||
|
.SGreaterThan => (try helpers.readSInt(lhs_value)) > (try helpers.readSInt(rhs_value)),
|
||||||
|
.SGreaterThanEqual => (try helpers.readSInt(lhs_value)) >= (try helpers.readSInt(rhs_value)),
|
||||||
|
.SLessThan => (try helpers.readSInt(lhs_value)) < (try helpers.readSInt(rhs_value)),
|
||||||
|
.SLessThanEqual => (try helpers.readSInt(lhs_value)) <= (try helpers.readSInt(rhs_value)),
|
||||||
|
.LogicalAnd => (try helpers.readBool(lhs_value)) and (try helpers.readBool(rhs_value)),
|
||||||
|
.LogicalOr => (try helpers.readBool(lhs_value)) or (try helpers.readBool(rhs_value)),
|
||||||
|
.LogicalEqual => (try helpers.readBool(lhs_value)) == (try helpers.readBool(rhs_value)),
|
||||||
|
.LogicalNotEqual => (try helpers.readBool(lhs_value)) != (try helpers.readBool(rhs_value)),
|
||||||
|
else => return RuntimeError.UnsupportedSpirV,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
dst.* = result;
|
||||||
},
|
},
|
||||||
else => return RuntimeError.UnsupportedSpirV,
|
else => return RuntimeError.UnsupportedSpirV,
|
||||||
}
|
}
|
||||||
@@ -3450,6 +3664,31 @@ fn opDot(_: std.mem.Allocator, _: SpvWord, rt: *Runtime) RuntimeError!void {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn opFwidth(allocator: std.mem.Allocator, _: SpvWord, rt: *Runtime) RuntimeError!void {
|
||||||
|
const target_type = (try rt.results[try rt.it.next()].getVariant()).Type;
|
||||||
|
const id = try rt.it.next();
|
||||||
|
const operand = try rt.it.next();
|
||||||
|
|
||||||
|
const derivative = rt.derivatives.get(operand) orelse return RuntimeError.UnsupportedSpirV;
|
||||||
|
const dst = try rt.results[id].getValue();
|
||||||
|
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);
|
||||||
|
for (0..lane_count) |lane_index| {
|
||||||
|
const dx = try Value.readLane(.Float, bits, &derivative.dx, lane_index);
|
||||||
|
const dy = try Value.readLane(.Float, bits, &derivative.dy, lane_index);
|
||||||
|
try Value.writeLane(.Float, bits, dst, lane_index, @as(FloatT, @abs(dx) + @abs(dy)));
|
||||||
|
}
|
||||||
|
},
|
||||||
|
else => return RuntimeError.InvalidSpirV,
|
||||||
|
}
|
||||||
|
|
||||||
|
rt.clearDerivative(allocator, id);
|
||||||
|
}
|
||||||
|
|
||||||
fn DerivativeEngine(comptime axis: enum { x, y }) type {
|
fn DerivativeEngine(comptime axis: enum { x, y }) type {
|
||||||
return struct {
|
return struct {
|
||||||
fn op(allocator: std.mem.Allocator, _: SpvWord, rt: *Runtime) RuntimeError!void {
|
fn op(allocator: std.mem.Allocator, _: SpvWord, rt: *Runtime) RuntimeError!void {
|
||||||
@@ -3519,7 +3758,9 @@ fn opExtInst(allocator: std.mem.Allocator, word_count: SpvWord, rt: *Runtime) Ru
|
|||||||
const inst = try rt.it.next();
|
const inst = try rt.it.next();
|
||||||
|
|
||||||
switch ((try rt.results[set].getVariant()).*) {
|
switch ((try rt.results[set].getVariant()).*) {
|
||||||
.Extension => |ext| if (ext.dispatcher[inst]) |pfn| {
|
.Extension => |ext| {
|
||||||
|
if (inst >= ext.dispatcher.len) return RuntimeError.UnsupportedSpirV;
|
||||||
|
const pfn = ext.dispatcher[inst] orelse return RuntimeError.UnsupportedSpirV;
|
||||||
try pfn(allocator, target_type, id, word_count, rt);
|
try pfn(allocator, target_type, id, word_count, rt);
|
||||||
},
|
},
|
||||||
else => return RuntimeError.InvalidSpirV,
|
else => return RuntimeError.InvalidSpirV,
|
||||||
@@ -3603,10 +3844,6 @@ fn opFunctionParameter(_: std.mem.Allocator, _: SpvWord, rt: *Runtime) RuntimeEr
|
|||||||
const target = &rt.results[id];
|
const target = &rt.results[id];
|
||||||
|
|
||||||
const resolved = rt.results[var_type].resolveType(rt.results);
|
const resolved = rt.results[var_type].resolveType(rt.results);
|
||||||
const member_count = resolved.getMemberCounts();
|
|
||||||
if (member_count == 0) {
|
|
||||||
return RuntimeError.InvalidSpirV;
|
|
||||||
}
|
|
||||||
target.variant = .{
|
target.variant = .{
|
||||||
.FunctionParameter = .{
|
.FunctionParameter = .{
|
||||||
.type_word = var_type,
|
.type_word = var_type,
|
||||||
@@ -4190,6 +4427,88 @@ fn opVariable(allocator: std.mem.Allocator, word_count: SpvWord, rt: *Runtime) R
|
|||||||
_ = initializer;
|
_ = initializer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn readDynamicVectorIndex(index_value: *const Value) RuntimeError!usize {
|
||||||
|
return switch (index_value.*) {
|
||||||
|
.Int => |i| switch (i.bit_count) {
|
||||||
|
8 => if (i.is_signed) std.math.cast(usize, i.value.sint8) orelse RuntimeError.OutOfBounds else @as(usize, i.value.uint8),
|
||||||
|
16 => if (i.is_signed) std.math.cast(usize, i.value.sint16) orelse RuntimeError.OutOfBounds else @as(usize, i.value.uint16),
|
||||||
|
32 => if (i.is_signed) std.math.cast(usize, i.value.sint32) orelse RuntimeError.OutOfBounds else @as(usize, i.value.uint32),
|
||||||
|
64 => if (i.is_signed) std.math.cast(usize, i.value.sint64) orelse RuntimeError.OutOfBounds else std.math.cast(usize, i.value.uint64) orelse RuntimeError.OutOfBounds,
|
||||||
|
else => return RuntimeError.InvalidSpirV,
|
||||||
|
},
|
||||||
|
else => return RuntimeError.InvalidSpirV,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
fn readVectorLaneAsValue(src: *const Value, lane_index: usize) RuntimeError!Value {
|
||||||
|
return switch (src.*) {
|
||||||
|
.Vector => |lanes| blk: {
|
||||||
|
if (lane_index >= lanes.len) return RuntimeError.OutOfBounds;
|
||||||
|
break :blk lanes[lane_index];
|
||||||
|
},
|
||||||
|
|
||||||
|
.Vector2f32 => |lanes| .{ .Float = .{ .bit_count = 32, .value = .{ .float32 = switch (lane_index) {
|
||||||
|
inline 0...1 => |idx| lanes[idx],
|
||||||
|
else => return RuntimeError.OutOfBounds,
|
||||||
|
} } } },
|
||||||
|
.Vector3f32 => |lanes| .{ .Float = .{ .bit_count = 32, .value = .{ .float32 = switch (lane_index) {
|
||||||
|
inline 0...2 => |idx| lanes[idx],
|
||||||
|
else => return RuntimeError.OutOfBounds,
|
||||||
|
} } } },
|
||||||
|
.Vector4f32 => |lanes| .{ .Float = .{ .bit_count = 32, .value = .{ .float32 = switch (lane_index) {
|
||||||
|
inline 0...3 => |idx| lanes[idx],
|
||||||
|
else => return RuntimeError.OutOfBounds,
|
||||||
|
} } } },
|
||||||
|
|
||||||
|
.Vector2i32 => |lanes| .{ .Int = .{ .bit_count = 32, .is_signed = true, .value = .{ .sint32 = switch (lane_index) {
|
||||||
|
inline 0...1 => |idx| lanes[idx],
|
||||||
|
else => return RuntimeError.OutOfBounds,
|
||||||
|
} } } },
|
||||||
|
.Vector3i32 => |lanes| .{ .Int = .{ .bit_count = 32, .is_signed = true, .value = .{ .sint32 = switch (lane_index) {
|
||||||
|
inline 0...2 => |idx| lanes[idx],
|
||||||
|
else => return RuntimeError.OutOfBounds,
|
||||||
|
} } } },
|
||||||
|
.Vector4i32 => |lanes| .{ .Int = .{ .bit_count = 32, .is_signed = true, .value = .{ .sint32 = switch (lane_index) {
|
||||||
|
inline 0...3 => |idx| lanes[idx],
|
||||||
|
else => return RuntimeError.OutOfBounds,
|
||||||
|
} } } },
|
||||||
|
|
||||||
|
.Vector2u32 => |lanes| .{ .Int = .{ .bit_count = 32, .is_signed = false, .value = .{ .uint32 = switch (lane_index) {
|
||||||
|
inline 0...1 => |idx| lanes[idx],
|
||||||
|
else => return RuntimeError.OutOfBounds,
|
||||||
|
} } } },
|
||||||
|
.Vector3u32 => |lanes| .{ .Int = .{ .bit_count = 32, .is_signed = false, .value = .{ .uint32 = switch (lane_index) {
|
||||||
|
inline 0...2 => |idx| lanes[idx],
|
||||||
|
else => return RuntimeError.OutOfBounds,
|
||||||
|
} } } },
|
||||||
|
.Vector4u32 => |lanes| .{ .Int = .{ .bit_count = 32, .is_signed = false, .value = .{ .uint32 = switch (lane_index) {
|
||||||
|
inline 0...3 => |idx| lanes[idx],
|
||||||
|
else => return RuntimeError.OutOfBounds,
|
||||||
|
} } } },
|
||||||
|
|
||||||
|
else => return RuntimeError.InvalidSpirV,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
fn opVectorExtractDynamic(allocator: std.mem.Allocator, _: SpvWord, rt: *Runtime) RuntimeError!void {
|
||||||
|
_ = try rt.it.next(); // result type
|
||||||
|
const result_id = try rt.it.next();
|
||||||
|
const vector_id = try rt.it.next();
|
||||||
|
const vector = try rt.results[vector_id].getValue();
|
||||||
|
const index = try readDynamicVectorIndex(try rt.results[try rt.it.next()].getValue());
|
||||||
|
|
||||||
|
const lane_value = try readVectorLaneAsValue(vector, index);
|
||||||
|
try copyValue(try rt.results[result_id].getValue(), &lane_value);
|
||||||
|
|
||||||
|
if (rt.derivatives.get(vector_id)) |derivative| {
|
||||||
|
const dx_lane = try readVectorLaneAsValue(&derivative.dx, index);
|
||||||
|
const dy_lane = try readVectorLaneAsValue(&derivative.dy, index);
|
||||||
|
try rt.setDerivative(allocator, result_id, &dx_lane, &dy_lane);
|
||||||
|
} else {
|
||||||
|
rt.clearDerivative(allocator, result_id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn opVectorShuffle(_: std.mem.Allocator, _: SpvWord, rt: *Runtime) RuntimeError!void {
|
fn opVectorShuffle(_: std.mem.Allocator, _: SpvWord, rt: *Runtime) RuntimeError!void {
|
||||||
_ = try rt.it.next();
|
_ = try rt.it.next();
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user