adding opcodes, reworking atomic engine
This commit is contained in:
@@ -471,6 +471,8 @@ typedef SpvResult (*SpvReadImageFloat4_PFN)(void* driver_image, SpvDim dim, int
|
|||||||
typedef SpvResult (*SpvReadImageInt4_PFN)(void* driver_image, SpvDim dim, int x, int y, int z, SpvVec4u* dst);
|
typedef SpvResult (*SpvReadImageInt4_PFN)(void* driver_image, SpvDim dim, int x, int y, int z, SpvVec4u* dst);
|
||||||
typedef SpvResult (*SpvWriteImageFloat4_PFN)(void* driver_image, SpvDim dim, int x, int y, int z, SpvVec4f src);
|
typedef SpvResult (*SpvWriteImageFloat4_PFN)(void* driver_image, SpvDim dim, int x, int y, int z, SpvVec4f src);
|
||||||
typedef SpvResult (*SpvWriteImageInt4_PFN)(void* driver_image, SpvDim dim, int x, int y, int z, SpvVec4u src);
|
typedef SpvResult (*SpvWriteImageInt4_PFN)(void* driver_image, SpvDim dim, int x, int y, int z, SpvVec4u src);
|
||||||
|
typedef SpvResult (*SpvSampleImageFloat4_PFN)(void* driver_image, void* driver_sampler, SpvDim dim, float x, float y, float z, SpvVec4f* dst);
|
||||||
|
typedef SpvResult (*SpvQueryImageSize_PFN)(void* driver_image, SpvDim dim, SpvBool arrayed, SpvVec4u* dst);
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
@@ -478,6 +480,8 @@ typedef struct
|
|||||||
SpvReadImageInt4_PFN SpvReadImageInt4;
|
SpvReadImageInt4_PFN SpvReadImageInt4;
|
||||||
SpvWriteImageFloat4_PFN SpvWriteImageFloat4;
|
SpvWriteImageFloat4_PFN SpvWriteImageFloat4;
|
||||||
SpvWriteImageInt4_PFN SpvWriteImageInt4;
|
SpvWriteImageInt4_PFN SpvWriteImageInt4;
|
||||||
|
SpvSampleImageFloat4_PFN SpvSampleImageFloat4;
|
||||||
|
SpvQueryImageSize_PFN SpvQueryImageSize;
|
||||||
} SpvImageAPI;
|
} SpvImageAPI;
|
||||||
|
|
||||||
typedef void* SpvModule;
|
typedef void* SpvModule;
|
||||||
|
|||||||
@@ -31,12 +31,16 @@ const readImageFloat4_PFN = *const fn (driver_image: ?*anyopaque, dim: spv.spv.S
|
|||||||
const readImageInt4_PFN = *const fn (driver_image: ?*anyopaque, dim: spv.spv.SpvDim, x: c_int, y: c_int, z: c_int, dst: *Vec4u) callconv(.c) ffi.Result;
|
const readImageInt4_PFN = *const fn (driver_image: ?*anyopaque, dim: spv.spv.SpvDim, x: c_int, y: c_int, z: c_int, dst: *Vec4u) callconv(.c) ffi.Result;
|
||||||
const writeImageFloat4_PFN = *const fn (driver_image: ?*anyopaque, dim: spv.spv.SpvDim, x: c_int, y: c_int, z: c_int, src: Vec4f) callconv(.c) ffi.Result;
|
const writeImageFloat4_PFN = *const fn (driver_image: ?*anyopaque, dim: spv.spv.SpvDim, x: c_int, y: c_int, z: c_int, src: Vec4f) callconv(.c) ffi.Result;
|
||||||
const writeImageInt4_PFN = *const fn (driver_image: ?*anyopaque, dim: spv.spv.SpvDim, x: c_int, y: c_int, z: c_int, src: Vec4u) callconv(.c) ffi.Result;
|
const writeImageInt4_PFN = *const fn (driver_image: ?*anyopaque, dim: spv.spv.SpvDim, x: c_int, y: c_int, z: c_int, src: Vec4u) callconv(.c) ffi.Result;
|
||||||
|
const sampleImageFloat4_PFN = *const fn (driver_image: ?*anyopaque, driver_sampler: ?*anyopaque, dim: spv.spv.SpvDim, x: f32, y: f32, z: f32, dst: *Vec4f) callconv(.c) ffi.Result;
|
||||||
|
const queryImageSize_PFN = *const fn (driver_image: ?*anyopaque, dim: spv.spv.SpvDim, arrayed: ffi.SpvCBool, dst: *Vec4u) callconv(.c) ffi.Result;
|
||||||
|
|
||||||
const ImageAPI = extern struct {
|
const ImageAPI = extern struct {
|
||||||
readImageFloat4: readImageFloat4_PFN,
|
readImageFloat4: readImageFloat4_PFN,
|
||||||
readImageInt4: readImageInt4_PFN,
|
readImageInt4: readImageInt4_PFN,
|
||||||
writeImageFloat4: writeImageFloat4_PFN,
|
writeImageFloat4: writeImageFloat4_PFN,
|
||||||
writeImageInt4: writeImageInt4_PFN,
|
writeImageInt4: writeImageInt4_PFN,
|
||||||
|
sampleImageFloat4: sampleImageFloat4_PFN,
|
||||||
|
queryImageSize: queryImageSize_PFN,
|
||||||
};
|
};
|
||||||
|
|
||||||
fn toCResult(err: spv.Runtime.RuntimeError) ffi.Result {
|
fn toCResult(err: spv.Runtime.RuntimeError) ffi.Result {
|
||||||
@@ -131,6 +135,38 @@ const ImageAPIBridge = struct {
|
|||||||
|
|
||||||
try fromCResult(result);
|
try fromCResult(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn sampleImageFloat4(driver_image: *anyopaque, driver_sampler: *anyopaque, dim: spv.spv.SpvDim, x: f32, y: f32, z: f32) spv.Runtime.RuntimeError!spv.Runtime.Vec4(f32) {
|
||||||
|
const image_api = try getImageAPI();
|
||||||
|
|
||||||
|
var dst: Vec4f = undefined;
|
||||||
|
const result = image_api.sampleImageFloat4(driver_image, driver_sampler, dim, x, y, z, &dst);
|
||||||
|
|
||||||
|
try fromCResult(result);
|
||||||
|
|
||||||
|
return .{
|
||||||
|
.x = dst.x,
|
||||||
|
.y = dst.y,
|
||||||
|
.z = dst.z,
|
||||||
|
.w = dst.w,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
fn queryImageSize(driver_image: *anyopaque, dim: spv.spv.SpvDim, arrayed: bool) spv.Runtime.RuntimeError!spv.Runtime.Vec4(u32) {
|
||||||
|
const image_api = try getImageAPI();
|
||||||
|
|
||||||
|
var dst: Vec4u = undefined;
|
||||||
|
const result = image_api.queryImageSize(driver_image, dim, if (arrayed) 1 else 0, &dst);
|
||||||
|
|
||||||
|
try fromCResult(result);
|
||||||
|
|
||||||
|
return .{
|
||||||
|
.x = dst.x,
|
||||||
|
.y = dst.y,
|
||||||
|
.z = dst.z,
|
||||||
|
.w = dst.w,
|
||||||
|
};
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const RuntimeWrapper = struct {
|
const RuntimeWrapper = struct {
|
||||||
@@ -152,6 +188,8 @@ export fn SpvInitRuntime(rt: **RuntimeWrapper, module: *spv.Module, image_api: I
|
|||||||
.readImageInt4 = ImageAPIBridge.readImageInt4,
|
.readImageInt4 = ImageAPIBridge.readImageInt4,
|
||||||
.writeImageFloat4 = ImageAPIBridge.writeImageFloat4,
|
.writeImageFloat4 = ImageAPIBridge.writeImageFloat4,
|
||||||
.writeImageInt4 = ImageAPIBridge.writeImageInt4,
|
.writeImageInt4 = ImageAPIBridge.writeImageInt4,
|
||||||
|
.sampleImageFloat4 = ImageAPIBridge.sampleImageFloat4,
|
||||||
|
.queryImageSize = ImageAPIBridge.queryImageSize,
|
||||||
},
|
},
|
||||||
) catch |err| {
|
) catch |err| {
|
||||||
allocator.destroy(rt.*);
|
allocator.destroy(rt.*);
|
||||||
|
|||||||
@@ -60,6 +60,7 @@ pub const ImageAPI = struct {
|
|||||||
writeImageFloat4: *const fn (driver_image: *anyopaque, dim: spv.SpvDim, x: i32, y: i32, z: i32, pixel: Vec4(f32)) RuntimeError!void,
|
writeImageFloat4: *const fn (driver_image: *anyopaque, dim: spv.SpvDim, x: i32, y: i32, z: i32, pixel: Vec4(f32)) RuntimeError!void,
|
||||||
writeImageInt4: *const fn (driver_image: *anyopaque, dim: spv.SpvDim, x: i32, y: i32, z: i32, pixel: Vec4(u32)) RuntimeError!void,
|
writeImageInt4: *const fn (driver_image: *anyopaque, dim: spv.SpvDim, x: i32, y: i32, z: i32, pixel: Vec4(u32)) RuntimeError!void,
|
||||||
sampleImageFloat4: *const fn (driver_image: *anyopaque, driver_sampler: *anyopaque, dim: spv.SpvDim, x: f32, y: f32, z: f32) RuntimeError!Vec4(f32),
|
sampleImageFloat4: *const fn (driver_image: *anyopaque, driver_sampler: *anyopaque, dim: spv.SpvDim, x: f32, y: f32, z: f32) RuntimeError!Vec4(f32),
|
||||||
|
queryImageSize: *const fn (driver_image: *anyopaque, dim: spv.SpvDim, arrayed: bool) RuntimeError!Vec4(u32),
|
||||||
};
|
};
|
||||||
|
|
||||||
mod: *Module,
|
mod: *Module,
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
const lib = @import("lib.zig");
|
const lib = @import("lib.zig");
|
||||||
|
const spv = @import("spv.zig");
|
||||||
|
|
||||||
const Result = @import("Result.zig");
|
const Result = @import("Result.zig");
|
||||||
const Runtime = @import("Runtime.zig");
|
const Runtime = @import("Runtime.zig");
|
||||||
@@ -125,6 +126,13 @@ pub const Value = union(Type) {
|
|||||||
i32_ptr: *i32, //< For vector specializations
|
i32_ptr: *i32, //< For vector specializations
|
||||||
u32_ptr: *u32,
|
u32_ptr: *u32,
|
||||||
},
|
},
|
||||||
|
image_texel: ?struct {
|
||||||
|
driver_image: *anyopaque,
|
||||||
|
dim: spv.SpvDim,
|
||||||
|
x: i32,
|
||||||
|
y: i32,
|
||||||
|
z: i32,
|
||||||
|
} = null,
|
||||||
|
|
||||||
/// Exact byte window in externally visible descriptor storage that
|
/// Exact byte window in externally visible descriptor storage that
|
||||||
/// corresponds to this pointer. For a pointer to struct member N this
|
/// corresponds to this pointer. For a pointer to struct member N this
|
||||||
@@ -582,6 +590,12 @@ pub const Value = union(Type) {
|
|||||||
|
|
||||||
p.uniform_slice_window = null;
|
p.uniform_slice_window = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (p.uniform_backing_value) |backing| {
|
||||||
|
backing.deinit(allocator);
|
||||||
|
allocator.destroy(backing);
|
||||||
|
p.uniform_backing_value = null;
|
||||||
|
}
|
||||||
},
|
},
|
||||||
else => {},
|
else => {},
|
||||||
}
|
}
|
||||||
|
|||||||
+337
-7
@@ -70,6 +70,7 @@ const BitOp = enum {
|
|||||||
|
|
||||||
const ImageOp = enum {
|
const ImageOp = enum {
|
||||||
Fetch,
|
Fetch,
|
||||||
|
QuerySize,
|
||||||
Read,
|
Read,
|
||||||
Resolve,
|
Resolve,
|
||||||
SampleExplicitLod,
|
SampleExplicitLod,
|
||||||
@@ -77,6 +78,22 @@ const ImageOp = enum {
|
|||||||
Write,
|
Write,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const AtomicOp = enum {
|
||||||
|
Add,
|
||||||
|
And,
|
||||||
|
CompareExchange,
|
||||||
|
Decrement,
|
||||||
|
Exchange,
|
||||||
|
Increment,
|
||||||
|
MaxSigned,
|
||||||
|
MaxUnsigned,
|
||||||
|
MinSigned,
|
||||||
|
MinUnsigned,
|
||||||
|
Or,
|
||||||
|
Sub,
|
||||||
|
Xor,
|
||||||
|
};
|
||||||
|
|
||||||
pub const OpCodeFunc = *const fn (std.mem.Allocator, SpvWord, *Runtime) RuntimeError!void;
|
pub const OpCodeFunc = *const fn (std.mem.Allocator, SpvWord, *Runtime) RuntimeError!void;
|
||||||
pub const OpCodeExtFunc = *const fn (std.mem.Allocator, SpvWord, SpvWord, SpvWord, *Runtime) RuntimeError!void;
|
pub const OpCodeExtFunc = *const fn (std.mem.Allocator, SpvWord, SpvWord, SpvWord, *Runtime) RuntimeError!void;
|
||||||
|
|
||||||
@@ -92,6 +109,7 @@ 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,
|
||||||
@@ -162,9 +180,11 @@ pub const SetupDispatcher = block: {
|
|||||||
.ISubBorrow = autoSetupConstant,
|
.ISubBorrow = autoSetupConstant,
|
||||||
.Image = autoSetupConstant,
|
.Image = autoSetupConstant,
|
||||||
.ImageFetch = autoSetupConstant,
|
.ImageFetch = autoSetupConstant,
|
||||||
|
.ImageQuerySize = autoSetupConstant,
|
||||||
.ImageRead = autoSetupConstant,
|
.ImageRead = autoSetupConstant,
|
||||||
.ImageSampleExplicitLod = autoSetupConstant,
|
.ImageSampleExplicitLod = autoSetupConstant,
|
||||||
.ImageSampleImplicitLod = autoSetupConstant,
|
.ImageSampleImplicitLod = autoSetupConstant,
|
||||||
|
.ImageTexelPointer = autoSetupConstant,
|
||||||
.InBoundsAccessChain = setupAccessChain,
|
.InBoundsAccessChain = setupAccessChain,
|
||||||
.IsFinite = autoSetupConstant,
|
.IsFinite = autoSetupConstant,
|
||||||
.IsInf = autoSetupConstant,
|
.IsInf = autoSetupConstant,
|
||||||
@@ -241,10 +261,21 @@ pub fn initRuntimeDispatcher() void {
|
|||||||
runtime_dispatcher[@intFromEnum(spv.SpvOp.AccessChain)] = opAccessChain;
|
runtime_dispatcher[@intFromEnum(spv.SpvOp.AccessChain)] = opAccessChain;
|
||||||
runtime_dispatcher[@intFromEnum(spv.SpvOp.All)] = opAll;
|
runtime_dispatcher[@intFromEnum(spv.SpvOp.All)] = opAll;
|
||||||
runtime_dispatcher[@intFromEnum(spv.SpvOp.Any)] = opAny;
|
runtime_dispatcher[@intFromEnum(spv.SpvOp.Any)] = opAny;
|
||||||
runtime_dispatcher[@intFromEnum(spv.SpvOp.AtomicIAdd)] = MathEngine(.SInt, .Add, true).op;
|
runtime_dispatcher[@intFromEnum(spv.SpvOp.AtomicAnd)] = AtomicEngine(.And).op;
|
||||||
runtime_dispatcher[@intFromEnum(spv.SpvOp.AtomicISub)] = MathEngine(.SInt, .Sub, true).op;
|
runtime_dispatcher[@intFromEnum(spv.SpvOp.AtomicCompareExchange)] = AtomicEngine(.CompareExchange).op;
|
||||||
|
runtime_dispatcher[@intFromEnum(spv.SpvOp.AtomicExchange)] = AtomicEngine(.Exchange).op;
|
||||||
|
runtime_dispatcher[@intFromEnum(spv.SpvOp.AtomicIAdd)] = AtomicEngine(.Add).op;
|
||||||
|
runtime_dispatcher[@intFromEnum(spv.SpvOp.AtomicIDecrement)] = AtomicEngine(.Decrement).op;
|
||||||
|
runtime_dispatcher[@intFromEnum(spv.SpvOp.AtomicIIncrement)] = AtomicEngine(.Increment).op;
|
||||||
|
runtime_dispatcher[@intFromEnum(spv.SpvOp.AtomicISub)] = AtomicEngine(.Sub).op;
|
||||||
runtime_dispatcher[@intFromEnum(spv.SpvOp.AtomicLoad)] = opLoad;
|
runtime_dispatcher[@intFromEnum(spv.SpvOp.AtomicLoad)] = opLoad;
|
||||||
|
runtime_dispatcher[@intFromEnum(spv.SpvOp.AtomicOr)] = AtomicEngine(.Or).op;
|
||||||
|
runtime_dispatcher[@intFromEnum(spv.SpvOp.AtomicSMax)] = AtomicEngine(.MaxSigned).op;
|
||||||
|
runtime_dispatcher[@intFromEnum(spv.SpvOp.AtomicSMin)] = AtomicEngine(.MinSigned).op;
|
||||||
runtime_dispatcher[@intFromEnum(spv.SpvOp.AtomicStore)] = opAtomicStore;
|
runtime_dispatcher[@intFromEnum(spv.SpvOp.AtomicStore)] = opAtomicStore;
|
||||||
|
runtime_dispatcher[@intFromEnum(spv.SpvOp.AtomicUMax)] = AtomicEngine(.MaxUnsigned).op;
|
||||||
|
runtime_dispatcher[@intFromEnum(spv.SpvOp.AtomicUMin)] = AtomicEngine(.MinUnsigned).op;
|
||||||
|
runtime_dispatcher[@intFromEnum(spv.SpvOp.AtomicXor)] = AtomicEngine(.Xor).op;
|
||||||
runtime_dispatcher[@intFromEnum(spv.SpvOp.BitCount)] = BitEngine(.UInt, .BitCount).op;
|
runtime_dispatcher[@intFromEnum(spv.SpvOp.BitCount)] = BitEngine(.UInt, .BitCount).op;
|
||||||
runtime_dispatcher[@intFromEnum(spv.SpvOp.BitFieldInsert)] = BitEngine(.UInt, .BitFieldInsert).op;
|
runtime_dispatcher[@intFromEnum(spv.SpvOp.BitFieldInsert)] = BitEngine(.UInt, .BitFieldInsert).op;
|
||||||
runtime_dispatcher[@intFromEnum(spv.SpvOp.BitFieldSExtract)] = BitEngine(.SInt, .BitFieldSExtract).op;
|
runtime_dispatcher[@intFromEnum(spv.SpvOp.BitFieldSExtract)] = BitEngine(.SInt, .BitFieldSExtract).op;
|
||||||
@@ -296,9 +327,11 @@ pub fn initRuntimeDispatcher() void {
|
|||||||
runtime_dispatcher[@intFromEnum(spv.SpvOp.ISubBorrow)] = opISubBorrow;
|
runtime_dispatcher[@intFromEnum(spv.SpvOp.ISubBorrow)] = opISubBorrow;
|
||||||
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.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;
|
||||||
|
runtime_dispatcher[@intFromEnum(spv.SpvOp.ImageTexelPointer)] = opImageTexelPointer;
|
||||||
runtime_dispatcher[@intFromEnum(spv.SpvOp.ImageWrite)] = ImageEngine(.Write).op;
|
runtime_dispatcher[@intFromEnum(spv.SpvOp.ImageWrite)] = ImageEngine(.Write).op;
|
||||||
runtime_dispatcher[@intFromEnum(spv.SpvOp.InBoundsAccessChain)] = opAccessChain;
|
runtime_dispatcher[@intFromEnum(spv.SpvOp.InBoundsAccessChain)] = opAccessChain;
|
||||||
runtime_dispatcher[@intFromEnum(spv.SpvOp.IsFinite)] = CondEngine(.Float, .IsNan).op;
|
runtime_dispatcher[@intFromEnum(spv.SpvOp.IsFinite)] = CondEngine(.Float, .IsNan).op;
|
||||||
@@ -993,6 +1026,7 @@ fn ImageEngine(comptime Op: ImageOp) type {
|
|||||||
type_word: SpvWord,
|
type_word: SpvWord,
|
||||||
driver_image: *anyopaque,
|
driver_image: *anyopaque,
|
||||||
dim: spv.SpvDim,
|
dim: spv.SpvDim,
|
||||||
|
arrayed: bool,
|
||||||
};
|
};
|
||||||
|
|
||||||
const SampledImageOperand = struct {
|
const SampledImageOperand = struct {
|
||||||
@@ -1013,12 +1047,24 @@ fn ImageEngine(comptime Op: ImageOp) type {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn resolveImageArrayed(rt: *Runtime, type_word: SpvWord) RuntimeError!bool {
|
||||||
|
return switch ((try rt.results[type_word].getConstVariant()).*) {
|
||||||
|
.Type => |t| switch (t) {
|
||||||
|
.Image => |i| i.arrayed != 0,
|
||||||
|
.SampledImage => |i| return resolveImageArrayed(rt, i.image_type),
|
||||||
|
else => return RuntimeError.InvalidSpirV,
|
||||||
|
},
|
||||||
|
else => return RuntimeError.InvalidSpirV,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
fn resolveImage(image: *Result, rt: *Runtime) RuntimeError!ImageOperand {
|
fn resolveImage(image: *Result, rt: *Runtime) RuntimeError!ImageOperand {
|
||||||
return switch ((try image.getValue()).*) {
|
return switch ((try image.getValue()).*) {
|
||||||
.Image => |img| .{
|
.Image => |img| .{
|
||||||
.type_word = img.type_word,
|
.type_word = img.type_word,
|
||||||
.driver_image = img.driver_image,
|
.driver_image = img.driver_image,
|
||||||
.dim = try resolveImageDim(rt, img.type_word),
|
.dim = try resolveImageDim(rt, img.type_word),
|
||||||
|
.arrayed = try resolveImageArrayed(rt, img.type_word),
|
||||||
},
|
},
|
||||||
else => return RuntimeError.InvalidSpirV,
|
else => return RuntimeError.InvalidSpirV,
|
||||||
};
|
};
|
||||||
@@ -1353,6 +1399,30 @@ fn ImageEngine(comptime Op: ImageOp) type {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn queryImageSize(rt: *Runtime, dst: *Value, image_operand: ImageOperand) RuntimeError!void {
|
||||||
|
const size = try rt.image_api.queryImageSize(image_operand.driver_image, image_operand.dim, image_operand.arrayed);
|
||||||
|
switch (dst.*) {
|
||||||
|
.Int => |*v| v.value.uint32 = size.x,
|
||||||
|
.Vector2i32 => |*v| v.* = .{ @bitCast(size.x), @bitCast(size.y) },
|
||||||
|
.Vector3i32 => |*v| v.* = .{ @bitCast(size.x), @bitCast(size.y), @bitCast(size.z) },
|
||||||
|
.Vector4i32 => |*v| v.* = .{ @bitCast(size.x), @bitCast(size.y), @bitCast(size.z), @bitCast(size.w) },
|
||||||
|
.Vector2u32 => |*v| v.* = .{ size.x, size.y },
|
||||||
|
.Vector3u32 => |*v| v.* = .{ size.x, size.y, size.z },
|
||||||
|
.Vector4u32 => |*v| v.* = .{ size.x, size.y, size.z, size.w },
|
||||||
|
.Vector => |lanes| {
|
||||||
|
const values = [_]u32{ size.x, size.y, size.z, size.w };
|
||||||
|
for (lanes, 0..) |*lane, i| {
|
||||||
|
if (i >= values.len) return RuntimeError.InvalidSpirV;
|
||||||
|
switch (lane.*) {
|
||||||
|
.Int => |*int| int.value.uint32 = values[i],
|
||||||
|
else => return RuntimeError.InvalidValueType,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
else => return RuntimeError.InvalidValueType,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn op(_: std.mem.Allocator, _: SpvWord, rt: *Runtime) RuntimeError!void {
|
fn op(_: std.mem.Allocator, _: SpvWord, rt: *Runtime) RuntimeError!void {
|
||||||
if (comptime Op == .Resolve) {
|
if (comptime Op == .Resolve) {
|
||||||
_ = try rt.it.next(); // result type
|
_ = try rt.it.next(); // result type
|
||||||
@@ -1385,6 +1455,12 @@ 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) {
|
||||||
|
const image_operand = try resolveImage(image, rt);
|
||||||
|
const dst = try rt.results[result_id].getValue();
|
||||||
|
return try queryImageSize(rt, dst, image_operand);
|
||||||
|
}
|
||||||
|
|
||||||
const coordinate = try rt.results[try rt.it.next()].getValue();
|
const coordinate = try rt.results[try rt.it.next()].getValue();
|
||||||
const dst = try rt.results[result_id].getValue();
|
const dst = try rt.results[result_id].getValue();
|
||||||
|
|
||||||
@@ -1442,6 +1518,232 @@ fn ImageEngine(comptime Op: ImageOp) type {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn resolveImageDimForTexelPointer(rt: *Runtime, type_word: SpvWord) RuntimeError!spv.SpvDim {
|
||||||
|
return switch ((try rt.results[type_word].getConstVariant()).*) {
|
||||||
|
.Type => |t| switch (t) {
|
||||||
|
.Image => |i| i.dim,
|
||||||
|
.SampledImage => |i| return resolveImageDimForTexelPointer(rt, i.image_type),
|
||||||
|
else => return RuntimeError.InvalidSpirV,
|
||||||
|
},
|
||||||
|
else => return RuntimeError.InvalidSpirV,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
fn readStorageCoordLaneForTexelPointer(coord: *const Value, lane_index: usize) RuntimeError!i32 {
|
||||||
|
return switch (coord.*) {
|
||||||
|
.Int => |i| {
|
||||||
|
if (lane_index != 0) return RuntimeError.OutOfBounds;
|
||||||
|
return if (i.is_signed) i.value.sint32 else @intCast(i.value.uint32);
|
||||||
|
},
|
||||||
|
.Vector => |lanes| {
|
||||||
|
if (lane_index >= lanes.len) return RuntimeError.OutOfBounds;
|
||||||
|
return readStorageCoordLaneForTexelPointer(&lanes[lane_index], 0);
|
||||||
|
},
|
||||||
|
.Vector4i32 => |v| switch (lane_index) {
|
||||||
|
inline 0...3 => |idx| v[idx],
|
||||||
|
else => return RuntimeError.OutOfBounds,
|
||||||
|
},
|
||||||
|
.Vector3i32 => |v| switch (lane_index) {
|
||||||
|
inline 0...2 => |idx| v[idx],
|
||||||
|
else => return RuntimeError.OutOfBounds,
|
||||||
|
},
|
||||||
|
.Vector2i32 => |v| switch (lane_index) {
|
||||||
|
inline 0...1 => |idx| v[idx],
|
||||||
|
else => return RuntimeError.OutOfBounds,
|
||||||
|
},
|
||||||
|
.Vector4u32 => |v| switch (lane_index) {
|
||||||
|
inline 0...3 => |idx| @intCast(v[idx]),
|
||||||
|
else => return RuntimeError.OutOfBounds,
|
||||||
|
},
|
||||||
|
.Vector3u32 => |v| switch (lane_index) {
|
||||||
|
inline 0...2 => |idx| @intCast(v[idx]),
|
||||||
|
else => return RuntimeError.OutOfBounds,
|
||||||
|
},
|
||||||
|
.Vector2u32 => |v| switch (lane_index) {
|
||||||
|
inline 0...1 => |idx| @intCast(v[idx]),
|
||||||
|
else => return RuntimeError.OutOfBounds,
|
||||||
|
},
|
||||||
|
else => return RuntimeError.InvalidValueType,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
fn opImageTexelPointer(allocator: std.mem.Allocator, word_count: SpvWord, rt: *Runtime) RuntimeError!void {
|
||||||
|
_ = word_count;
|
||||||
|
const result_type = try rt.it.next();
|
||||||
|
const result_id = try rt.it.next();
|
||||||
|
const image_id = try rt.it.next();
|
||||||
|
const coord = try rt.results[try rt.it.next()].getValue();
|
||||||
|
_ = try rt.it.next(); // sample
|
||||||
|
|
||||||
|
const image = switch ((try rt.results[image_id].getValue()).*) {
|
||||||
|
.Image => |img| img,
|
||||||
|
else => return RuntimeError.InvalidSpirV,
|
||||||
|
};
|
||||||
|
const dim = try resolveImageDimForTexelPointer(rt, image.type_word);
|
||||||
|
const x = try readStorageCoordLaneForTexelPointer(coord, 0);
|
||||||
|
const y = readStorageCoordLaneForTexelPointer(coord, 1) catch 0;
|
||||||
|
const z = readStorageCoordLaneForTexelPointer(coord, 2) catch 0;
|
||||||
|
const texel = try rt.image_api.readImageInt4(image.driver_image, dim, x, y, z);
|
||||||
|
|
||||||
|
const pointer_type = switch ((try rt.results[result_type].getConstVariant()).*) {
|
||||||
|
.Type => |t| switch (t) {
|
||||||
|
.Pointer => |ptr| ptr,
|
||||||
|
else => return RuntimeError.InvalidSpirV,
|
||||||
|
},
|
||||||
|
else => return RuntimeError.InvalidSpirV,
|
||||||
|
};
|
||||||
|
const target_type = switch ((try rt.results[pointer_type.target].getConstVariant()).*) {
|
||||||
|
.Type => |t| t,
|
||||||
|
else => return RuntimeError.InvalidSpirV,
|
||||||
|
};
|
||||||
|
|
||||||
|
const backing = allocator.create(Value) catch return RuntimeError.OutOfMemory;
|
||||||
|
errdefer allocator.destroy(backing);
|
||||||
|
backing.* = switch (target_type) {
|
||||||
|
.Int => |i| .{ .Int = .{
|
||||||
|
.bit_count = i.bit_length,
|
||||||
|
.is_signed = i.is_signed,
|
||||||
|
.value = if (i.is_signed) .{ .sint32 = @bitCast(texel.x) } else .{ .uint32 = texel.x },
|
||||||
|
} },
|
||||||
|
else => return RuntimeError.InvalidSpirV,
|
||||||
|
};
|
||||||
|
errdefer backing.deinit(allocator);
|
||||||
|
|
||||||
|
if (rt.results[result_id].variant) |*variant| {
|
||||||
|
switch (variant.*) {
|
||||||
|
.AccessChain => |*a| {
|
||||||
|
allocator.free(a.indexes);
|
||||||
|
a.value.deinit(allocator);
|
||||||
|
},
|
||||||
|
else => {},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const indexes = allocator.alloc(SpvWord, 0) catch return RuntimeError.OutOfMemory;
|
||||||
|
rt.results[result_id].variant = .{
|
||||||
|
.AccessChain = .{
|
||||||
|
.target = result_type,
|
||||||
|
.base = image_id,
|
||||||
|
.indexes = indexes,
|
||||||
|
.value = .{ .Pointer = .{
|
||||||
|
.ptr = .{ .common = backing },
|
||||||
|
.image_texel = .{
|
||||||
|
.driver_image = image.driver_image,
|
||||||
|
.dim = dim,
|
||||||
|
.x = x,
|
||||||
|
.y = y,
|
||||||
|
.z = z,
|
||||||
|
},
|
||||||
|
.uniform_backing_value = backing,
|
||||||
|
} },
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
fn writeImageTexelPointer(rt: *Runtime, ptr: *Value) RuntimeError!void {
|
||||||
|
if (std.meta.activeTag(ptr.*) != .Pointer)
|
||||||
|
return;
|
||||||
|
const image_texel = ptr.Pointer.image_texel orelse return;
|
||||||
|
const value = switch (ptr.Pointer.ptr) {
|
||||||
|
.common => |v| v,
|
||||||
|
else => return RuntimeError.InvalidSpirV,
|
||||||
|
};
|
||||||
|
const component = switch (value.*) {
|
||||||
|
.Int => |i| if (i.is_signed) @as(u32, @bitCast(i.value.sint32)) else i.value.uint32,
|
||||||
|
else => return RuntimeError.InvalidValueType,
|
||||||
|
};
|
||||||
|
try rt.image_api.writeImageInt4(
|
||||||
|
image_texel.driver_image,
|
||||||
|
image_texel.dim,
|
||||||
|
image_texel.x,
|
||||||
|
image_texel.y,
|
||||||
|
image_texel.z,
|
||||||
|
.{ .x = component, .y = 0, .z = 0, .w = 0 },
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn AtomicEngine(comptime Op: AtomicOp) type {
|
||||||
|
return struct {
|
||||||
|
fn apply(old: u32, value: u32, comparator: u32) u32 {
|
||||||
|
return switch (Op) {
|
||||||
|
.Add => old +% value,
|
||||||
|
.And => old & value,
|
||||||
|
.CompareExchange => if (old == comparator) value else old,
|
||||||
|
.Decrement => old -% 1,
|
||||||
|
.Exchange => value,
|
||||||
|
.Increment => old +% 1,
|
||||||
|
.MaxSigned => @bitCast(@max(@as(i32, @bitCast(old)), @as(i32, @bitCast(value)))),
|
||||||
|
.MaxUnsigned => @max(old, value),
|
||||||
|
.MinSigned => @bitCast(@min(@as(i32, @bitCast(old)), @as(i32, @bitCast(value)))),
|
||||||
|
.MinUnsigned => @min(old, value),
|
||||||
|
.Or => old | value,
|
||||||
|
.Sub => old -% value,
|
||||||
|
.Xor => old ^ value,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
fn readU32(value: *const Value) RuntimeError!u32 {
|
||||||
|
return switch (value.*) {
|
||||||
|
.Int => |i| if (i.is_signed) @bitCast(i.value.sint32) else i.value.uint32,
|
||||||
|
.Pointer => |p| switch (p.ptr) {
|
||||||
|
.common => |v| readU32(v),
|
||||||
|
.u32_ptr => |ptr| ptr.*,
|
||||||
|
.i32_ptr => |ptr| @bitCast(ptr.*),
|
||||||
|
else => return RuntimeError.InvalidValueType,
|
||||||
|
},
|
||||||
|
else => return RuntimeError.InvalidValueType,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
fn writeU32(value: *Value, bits: u32) RuntimeError!void {
|
||||||
|
switch (value.*) {
|
||||||
|
.Int => |*i| {
|
||||||
|
if (i.is_signed) {
|
||||||
|
i.value.sint32 = @bitCast(bits);
|
||||||
|
} else {
|
||||||
|
i.value.uint32 = bits;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
.Pointer => |p| switch (p.ptr) {
|
||||||
|
.common => |v| try writeU32(v, bits),
|
||||||
|
.u32_ptr => |ptr| ptr.* = bits,
|
||||||
|
.i32_ptr => |ptr| ptr.* = @bitCast(bits),
|
||||||
|
else => return RuntimeError.InvalidValueType,
|
||||||
|
},
|
||||||
|
else => return RuntimeError.InvalidValueType,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn op(allocator: std.mem.Allocator, _: SpvWord, rt: *Runtime) RuntimeError!void {
|
||||||
|
_ = try rt.it.next(); // result type
|
||||||
|
const dst = try rt.results[try rt.it.next()].getValue();
|
||||||
|
const ptr = try rt.results[try rt.it.next()].getValue();
|
||||||
|
_ = try rt.it.next(); // scope
|
||||||
|
_ = try rt.it.next(); // semantics
|
||||||
|
|
||||||
|
if (comptime Op == .CompareExchange) {
|
||||||
|
_ = try rt.it.next(); // unequal semantics
|
||||||
|
}
|
||||||
|
|
||||||
|
const value: u32 = switch (Op) {
|
||||||
|
.Decrement, .Increment => 0,
|
||||||
|
else => try readU32(try rt.results[try rt.it.next()].getValue()),
|
||||||
|
};
|
||||||
|
const comparator: u32 = if (comptime Op == .CompareExchange)
|
||||||
|
try readU32(try rt.results[try rt.it.next()].getValue())
|
||||||
|
else
|
||||||
|
0;
|
||||||
|
|
||||||
|
const old = try readU32(ptr);
|
||||||
|
const new = apply(old, value, comparator);
|
||||||
|
try writeU32(ptr, new);
|
||||||
|
try writeU32(dst, old);
|
||||||
|
try writeImageTexelPointer(rt, ptr);
|
||||||
|
try ptr.flushPtr(allocator);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
fn MathEngine(comptime T: PrimitiveType, comptime Op: MathOp, comptime IsAtomic: bool) type {
|
fn MathEngine(comptime T: PrimitiveType, comptime Op: MathOp, comptime IsAtomic: bool) type {
|
||||||
return struct {
|
return struct {
|
||||||
fn operation(comptime TT: type, op1: TT, op2: TT) RuntimeError!TT {
|
fn operation(comptime TT: type, op1: TT, op2: TT) RuntimeError!TT {
|
||||||
@@ -1839,17 +2141,45 @@ fn copyValue(dst: *Value, src: *const Value) RuntimeError!void {
|
|||||||
};
|
};
|
||||||
|
|
||||||
if (std.meta.activeTag(dst.*) == .Pointer) {
|
if (std.meta.activeTag(dst.*) == .Pointer) {
|
||||||
switch (dst.Pointer.ptr) {
|
const dst_ptr = dst.Pointer;
|
||||||
.common => |dst_val_ptr| return switch (src.*) {
|
switch (dst_ptr.ptr) {
|
||||||
|
.common => |dst_val_ptr| {
|
||||||
|
switch (src.*) {
|
||||||
.Pointer => |src_ptr| switch (src_ptr.ptr) {
|
.Pointer => |src_ptr| switch (src_ptr.ptr) {
|
||||||
.common => |src_val_ptr| try copyValue(dst_val_ptr, src_val_ptr),
|
.common => |src_val_ptr| try copyValue(dst_val_ptr, src_val_ptr),
|
||||||
else => dst_val_ptr.* = src.*,
|
else => dst_val_ptr.* = src.*,
|
||||||
},
|
},
|
||||||
else => try copyValue(dst_val_ptr, src),
|
else => try copyValue(dst_val_ptr, src),
|
||||||
|
}
|
||||||
|
if (dst_ptr.uniform_slice_window) |window| {
|
||||||
|
_ = try dst_val_ptr.read(window);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
},
|
||||||
|
.f32_ptr => |dst_f32_ptr| {
|
||||||
|
try helpers.writeF32(dst_f32_ptr, src);
|
||||||
|
if (dst_ptr.uniform_slice_window) |window| {
|
||||||
|
if (window.len < @sizeOf(f32)) return RuntimeError.OutOfBounds;
|
||||||
|
@memcpy(window[0..@sizeOf(f32)], std.mem.asBytes(dst_f32_ptr));
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
},
|
||||||
|
.i32_ptr => |dst_i32_ptr| {
|
||||||
|
try helpers.writeI32(dst_i32_ptr, src);
|
||||||
|
if (dst_ptr.uniform_slice_window) |window| {
|
||||||
|
if (window.len < @sizeOf(i32)) return RuntimeError.OutOfBounds;
|
||||||
|
@memcpy(window[0..@sizeOf(i32)], std.mem.asBytes(dst_i32_ptr));
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
},
|
||||||
|
.u32_ptr => |dst_u32_ptr| {
|
||||||
|
try helpers.writeU32(dst_u32_ptr, src);
|
||||||
|
if (dst_ptr.uniform_slice_window) |window| {
|
||||||
|
if (window.len < @sizeOf(u32)) return RuntimeError.OutOfBounds;
|
||||||
|
@memcpy(window[0..@sizeOf(u32)], std.mem.asBytes(dst_u32_ptr));
|
||||||
|
}
|
||||||
|
return;
|
||||||
},
|
},
|
||||||
.f32_ptr => |dst_f32_ptr| try helpers.writeF32(dst_f32_ptr, src),
|
|
||||||
.i32_ptr => |dst_i32_ptr| try helpers.writeI32(dst_i32_ptr, src),
|
|
||||||
.u32_ptr => |dst_u32_ptr| try helpers.writeU32(dst_u32_ptr, src),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user