adding storage image read and writes
This commit is contained in:
+30
-1
@@ -85,13 +85,42 @@ typedef enum
|
|||||||
SPV_LOCATION_OUTPUT = 1,
|
SPV_LOCATION_OUTPUT = 1,
|
||||||
} SpvLocationType;
|
} SpvLocationType;
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
float x;
|
||||||
|
float y;
|
||||||
|
float z;
|
||||||
|
float w;
|
||||||
|
} SpvVec4f;
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
unsigned int x;
|
||||||
|
unsigned int y;
|
||||||
|
unsigned int z;
|
||||||
|
unsigned int w;
|
||||||
|
} SpvVec4u;
|
||||||
|
|
||||||
|
typedef SpvResult (*SpvReadImageFloat4_PFN)(void* driver_image, int x, int y, int z, SpvVec4f* dst);
|
||||||
|
typedef SpvResult (*SpvReadImageInt4_PFN)(void* driver_image, int x, int y, int z, SpvVec4u* dst);
|
||||||
|
typedef SpvResult (*SpvWriteImageFloat4_PFN)(void* driver_image, int x, int y, int z, SpvVec4f src);
|
||||||
|
typedef SpvResult (*SpvWriteImageInt4_PFN)(void* driver_image, int x, int y, int z, SpvVec4u src);
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
SpvReadImageFloat4_PFN SpvReadImageFloat4;
|
||||||
|
SpvReadImageInt4_PFN SpvReadImageInt4;
|
||||||
|
SpvWriteImageFloat4_PFN SpvWriteImageFloat4;
|
||||||
|
SpvWriteImageInt4_PFN SpvWriteImageInt4;
|
||||||
|
} SpvImageAPI;
|
||||||
|
|
||||||
typedef void* SpvModule;
|
typedef void* SpvModule;
|
||||||
typedef void* SpvRuntime;
|
typedef void* SpvRuntime;
|
||||||
|
|
||||||
SPV_API SpvResult SpvInitModule(SpvModule* module, const SpvWord* source, SpvSize source_len, SpvModuleOptions options);
|
SPV_API SpvResult SpvInitModule(SpvModule* module, const SpvWord* source, SpvSize source_len, SpvModuleOptions options);
|
||||||
SPV_API void SpvDeinitModule(SpvModule module);
|
SPV_API void SpvDeinitModule(SpvModule module);
|
||||||
|
|
||||||
SPV_API SpvResult SpvInitRuntime(SpvRuntime* runtime, SpvModule module);
|
SPV_API SpvResult SpvInitRuntime(SpvRuntime* runtime, SpvModule module, SpvImageAPI image_api);
|
||||||
SPV_API void SpvDeinitRuntime(SpvRuntime runtime);
|
SPV_API void SpvDeinitRuntime(SpvRuntime runtime);
|
||||||
|
|
||||||
SPV_API SpvResult SpvFlushDescriptorSets(SpvRuntime runtime);
|
SPV_API SpvResult SpvFlushDescriptorSets(SpvRuntime runtime);
|
||||||
|
|||||||
+151
-29
@@ -13,6 +13,32 @@ const LocationType = enum(c_int) {
|
|||||||
output = 1,
|
output = 1,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const Vec4f = extern struct {
|
||||||
|
x: f32,
|
||||||
|
y: f32,
|
||||||
|
z: f32,
|
||||||
|
w: f32,
|
||||||
|
};
|
||||||
|
|
||||||
|
const Vec4u = extern struct {
|
||||||
|
x: c_uint,
|
||||||
|
y: c_uint,
|
||||||
|
z: c_uint,
|
||||||
|
w: c_uint,
|
||||||
|
};
|
||||||
|
|
||||||
|
const readImageFloat4_PFN = *const fn (driver_image: ?*anyopaque, x: c_int, y: c_int, z: c_int, dst: *Vec4f) callconv(.c) ffi.Result;
|
||||||
|
const readImageInt4_PFN = *const fn (driver_image: ?*anyopaque, x: c_int, y: c_int, z: c_int, dst: *Vec4u) callconv(.c) ffi.Result;
|
||||||
|
const writeImageFloat4_PFN = *const fn (driver_image: ?*anyopaque, x: c_int, y: c_int, z: c_int, src: Vec4f) callconv(.c) ffi.Result;
|
||||||
|
const writeImageInt4_PFN = *const fn (driver_image: ?*anyopaque, x: c_int, y: c_int, z: c_int, src: Vec4u) callconv(.c) ffi.Result;
|
||||||
|
|
||||||
|
const ImageAPI = extern struct {
|
||||||
|
readImageFloat4: readImageFloat4_PFN,
|
||||||
|
readImageInt4: readImageInt4_PFN,
|
||||||
|
writeImageFloat4: writeImageFloat4_PFN,
|
||||||
|
writeImageInt4: writeImageInt4_PFN,
|
||||||
|
};
|
||||||
|
|
||||||
fn toCResult(err: spv.Runtime.RuntimeError) ffi.Result {
|
fn toCResult(err: spv.Runtime.RuntimeError) ffi.Result {
|
||||||
return switch (err) {
|
return switch (err) {
|
||||||
spv.Runtime.RuntimeError.DivisionByZero => ffi.Result.DivisionByZero,
|
spv.Runtime.RuntimeError.DivisionByZero => ffi.Result.DivisionByZero,
|
||||||
@@ -31,27 +57,117 @@ fn toCResult(err: spv.Runtime.RuntimeError) ffi.Result {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export fn SpvInitRuntime(rt: **spv.Runtime, module: *spv.Module) callconv(.c) ffi.Result {
|
fn fromCResult(res: ffi.Result) spv.Runtime.RuntimeError!void {
|
||||||
|
return switch (res) {
|
||||||
|
ffi.Result.DivisionByZero => spv.Runtime.RuntimeError.DivisionByZero,
|
||||||
|
ffi.Result.InvalidEntryPoint => spv.Runtime.RuntimeError.InvalidEntryPoint,
|
||||||
|
ffi.Result.InvalidSpirV => spv.Runtime.RuntimeError.InvalidSpirV,
|
||||||
|
ffi.Result.InvalidValueType => spv.Runtime.RuntimeError.InvalidValueType,
|
||||||
|
ffi.Result.Killed => spv.Runtime.RuntimeError.Killed,
|
||||||
|
ffi.Result.NotFound => spv.Runtime.RuntimeError.NotFound,
|
||||||
|
ffi.Result.OutOfMemory => spv.Runtime.RuntimeError.OutOfMemory,
|
||||||
|
ffi.Result.OutOfBounds => spv.Runtime.RuntimeError.OutOfBounds,
|
||||||
|
ffi.Result.ToDo => spv.Runtime.RuntimeError.ToDo,
|
||||||
|
ffi.Result.Unreachable => spv.Runtime.RuntimeError.Unreachable,
|
||||||
|
ffi.Result.UnsupportedSpirV => spv.Runtime.RuntimeError.UnsupportedSpirV,
|
||||||
|
ffi.Result.UnsupportedExtension => spv.Runtime.RuntimeError.UnsupportedExtension,
|
||||||
|
ffi.Result.Unknown => spv.Runtime.RuntimeError.Unknown,
|
||||||
|
else => {},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const ImageAPIBridge = struct {
|
||||||
|
threadlocal var current_image_api: ?*const ImageAPI = null; // Hacky
|
||||||
|
|
||||||
|
fn getImageAPI() spv.Runtime.RuntimeError!*const ImageAPI {
|
||||||
|
return current_image_api orelse spv.Runtime.RuntimeError.Unknown;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn readImageFloat4(driver_image: *anyopaque, x: i32, y: i32, z: i32) spv.Runtime.RuntimeError!spv.Runtime.Vec4(f32) {
|
||||||
|
const image_api = try getImageAPI();
|
||||||
|
|
||||||
|
var dst: Vec4f = undefined;
|
||||||
|
const result = image_api.readImageFloat4(driver_image, @intCast(x), @intCast(y), @intCast(z), &dst);
|
||||||
|
|
||||||
|
try fromCResult(result);
|
||||||
|
|
||||||
|
return .{
|
||||||
|
.x = dst.x,
|
||||||
|
.y = dst.y,
|
||||||
|
.z = dst.z,
|
||||||
|
.w = dst.w,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
fn readImageInt4(driver_image: *anyopaque, x: i32, y: i32, z: i32) spv.Runtime.RuntimeError!spv.Runtime.Vec4(u32) {
|
||||||
|
const image_api = try getImageAPI();
|
||||||
|
|
||||||
|
var dst: Vec4u = undefined;
|
||||||
|
const result = image_api.readImageInt4(driver_image, @intCast(x), @intCast(y), @intCast(z), &dst);
|
||||||
|
|
||||||
|
try fromCResult(result);
|
||||||
|
|
||||||
|
return .{
|
||||||
|
.x = dst.x,
|
||||||
|
.y = dst.y,
|
||||||
|
.z = dst.z,
|
||||||
|
.w = dst.w,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
fn writeImageFloat4(driver_image: *anyopaque, x: i32, y: i32, z: i32, pixel: spv.Runtime.Vec4(f32)) spv.Runtime.RuntimeError!void {
|
||||||
|
const image_api = try getImageAPI();
|
||||||
|
|
||||||
|
const result = image_api.writeImageFloat4(driver_image, @intCast(x), @intCast(y), @intCast(z), .{ .x = pixel.x, .y = pixel.y, .z = pixel.z, .w = pixel.w });
|
||||||
|
|
||||||
|
try fromCResult(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn writeImageInt4(driver_image: *anyopaque, x: i32, y: i32, z: i32, pixel: spv.Runtime.Vec4(u32)) spv.Runtime.RuntimeError!void {
|
||||||
|
const image_api = try getImageAPI();
|
||||||
|
|
||||||
|
const result = image_api.writeImageInt4(driver_image, @intCast(x), @intCast(y), @intCast(z), .{ .x = pixel.x, .y = pixel.y, .z = pixel.z, .w = pixel.w });
|
||||||
|
|
||||||
|
try fromCResult(result);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const RuntimeWrapper = struct {
|
||||||
|
rt: spv.Runtime,
|
||||||
|
image_api: ImageAPI,
|
||||||
|
};
|
||||||
|
|
||||||
|
export fn SpvInitRuntime(rt: **RuntimeWrapper, module: *spv.Module, image_api: ImageAPI) callconv(.c) ffi.Result {
|
||||||
const allocator = std.heap.c_allocator;
|
const allocator = std.heap.c_allocator;
|
||||||
|
|
||||||
rt.* = allocator.create(spv.Runtime) catch return .OutOfMemory;
|
rt.* = allocator.create(RuntimeWrapper) catch return .OutOfMemory;
|
||||||
|
rt.*.image_api = image_api;
|
||||||
|
|
||||||
rt.*.* = spv.Runtime.init(allocator, module) catch |err| {
|
rt.*.rt = spv.Runtime.init(
|
||||||
|
allocator,
|
||||||
|
module,
|
||||||
|
.{
|
||||||
|
.readImageFloat4 = ImageAPIBridge.readImageFloat4,
|
||||||
|
.readImageInt4 = ImageAPIBridge.readImageInt4,
|
||||||
|
.writeImageFloat4 = ImageAPIBridge.writeImageFloat4,
|
||||||
|
.writeImageInt4 = ImageAPIBridge.writeImageInt4,
|
||||||
|
},
|
||||||
|
) catch |err| {
|
||||||
allocator.destroy(rt.*);
|
allocator.destroy(rt.*);
|
||||||
return toCResult(err);
|
return toCResult(err);
|
||||||
};
|
};
|
||||||
return .Success;
|
return .Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
export fn SpvDeinitRuntime(rt: *spv.Runtime) callconv(.c) void {
|
export fn SpvDeinitRuntime(rt: *RuntimeWrapper) callconv(.c) void {
|
||||||
const allocator = std.heap.c_allocator;
|
const allocator = std.heap.c_allocator;
|
||||||
rt.deinit(allocator);
|
rt.rt.deinit(allocator);
|
||||||
allocator.destroy(rt);
|
allocator.destroy(rt);
|
||||||
}
|
}
|
||||||
|
|
||||||
export fn SpvAddSpecializationInfo(rt: *spv.Runtime, entry: CSpecializationEntry, data: [*]const u8, data_size: c_ulong) callconv(.c) ffi.Result {
|
export fn SpvAddSpecializationInfo(rt: *RuntimeWrapper, entry: CSpecializationEntry, data: [*]const u8, data_size: c_ulong) callconv(.c) ffi.Result {
|
||||||
const allocator = std.heap.c_allocator;
|
const allocator = std.heap.c_allocator;
|
||||||
rt.addSpecializationInfo(
|
rt.rt.addSpecializationInfo(
|
||||||
allocator,
|
allocator,
|
||||||
.{
|
.{
|
||||||
.id = entry.id,
|
.id = entry.id,
|
||||||
@@ -63,60 +179,66 @@ export fn SpvAddSpecializationInfo(rt: *spv.Runtime, entry: CSpecializationEntry
|
|||||||
return .Success;
|
return .Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
export fn SpvGetEntryPointByName(rt: *spv.Runtime, name: [*:0]const u8, result: *spv.SpvWord) callconv(.c) ffi.Result {
|
export fn SpvGetEntryPointByName(rt: *RuntimeWrapper, name: [*:0]const u8, result: *spv.SpvWord) callconv(.c) ffi.Result {
|
||||||
result.* = rt.getEntryPointByName(std.mem.span(name)) catch |err| return toCResult(err);
|
result.* = rt.rt.getEntryPointByName(std.mem.span(name)) catch |err| return toCResult(err);
|
||||||
return .Success;
|
return .Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
export fn SpvGetResultByLocation(rt: *spv.Runtime, location: spv.SpvWord, kind: LocationType, result: *spv.SpvWord) callconv(.c) ffi.Result {
|
export fn SpvGetResultByLocation(rt: *RuntimeWrapper, location: spv.SpvWord, kind: LocationType, result: *spv.SpvWord) callconv(.c) ffi.Result {
|
||||||
result.* = rt.getResultByLocation(location, switch (kind) {
|
result.* = rt.rt.getResultByLocation(location, switch (kind) {
|
||||||
.input => .input,
|
.input => .input,
|
||||||
.output => .output,
|
.output => .output,
|
||||||
}) catch |err| return toCResult(err);
|
}) catch |err| return toCResult(err);
|
||||||
return .Success;
|
return .Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
export fn SpvGetResultByName(rt: *spv.Runtime, name: [*:0]const u8, result: *spv.SpvWord) callconv(.c) ffi.Result {
|
export fn SpvGetResultByName(rt: *RuntimeWrapper, name: [*:0]const u8, result: *spv.SpvWord) callconv(.c) ffi.Result {
|
||||||
result.* = rt.getResultByName(std.mem.span(name)) catch |err| return toCResult(err);
|
result.* = rt.rt.getResultByName(std.mem.span(name)) catch |err| return toCResult(err);
|
||||||
return .Success;
|
return .Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
export fn SpvGetResultMemorySize(rt: *spv.Runtime, result: spv.SpvWord, size: *c_ulong) callconv(.c) ffi.Result {
|
export fn SpvGetResultMemorySize(rt: *RuntimeWrapper, result: spv.SpvWord, size: *c_ulong) callconv(.c) ffi.Result {
|
||||||
size.* = rt.getResultMemorySize(result) catch |err| return toCResult(err);
|
size.* = rt.rt.getResultMemorySize(result) catch |err| return toCResult(err);
|
||||||
return .Success;
|
return .Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
export fn SpvHasResultDecoration(rt: *spv.Runtime, result: spv.SpvWord, decoration: spv.spv.SpvDecoration) callconv(.c) c_int {
|
export fn SpvHasResultDecoration(rt: *RuntimeWrapper, result: spv.SpvWord, decoration: spv.spv.SpvDecoration) callconv(.c) c_int {
|
||||||
return if (rt.hasResultDecoration(result, decoration)) 1 else 0;
|
return if (rt.rt.hasResultDecoration(result, decoration)) 1 else 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
export fn SpvCallEntryPoint(rt: *spv.Runtime, entry_point: spv.SpvWord) callconv(.c) ffi.Result {
|
export fn SpvCallEntryPoint(rt: *RuntimeWrapper, entry_point: spv.SpvWord) callconv(.c) ffi.Result {
|
||||||
const allocator = std.heap.c_allocator;
|
const allocator = std.heap.c_allocator;
|
||||||
rt.callEntryPoint(allocator, entry_point) catch |err| return toCResult(err);
|
|
||||||
|
// Ultra hacky
|
||||||
|
const previous_image_api = ImageAPIBridge.current_image_api;
|
||||||
|
ImageAPIBridge.current_image_api = &rt.image_api;
|
||||||
|
defer ImageAPIBridge.current_image_api = previous_image_api;
|
||||||
|
|
||||||
|
rt.rt.callEntryPoint(allocator, entry_point) catch |err| return toCResult(err);
|
||||||
return .Success;
|
return .Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
export fn SpvReadOutput(rt: *spv.Runtime, output: [*]u8, output_size: c_ulong, result: spv.SpvWord) callconv(.c) ffi.Result {
|
export fn SpvReadOutput(rt: *RuntimeWrapper, output: [*]u8, output_size: c_ulong, result: spv.SpvWord) callconv(.c) ffi.Result {
|
||||||
rt.readOutput(output[0..output_size], result) catch |err| return toCResult(err);
|
rt.rt.readOutput(output[0..output_size], result) catch |err| return toCResult(err);
|
||||||
return .Success;
|
return .Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
export fn SpvReadBuiltIn(rt: *spv.Runtime, output: [*]u8, output_size: c_ulong, builtin: spv.spv.SpvBuiltIn) callconv(.c) ffi.Result {
|
export fn SpvReadBuiltIn(rt: *RuntimeWrapper, output: [*]u8, output_size: c_ulong, builtin: spv.spv.SpvBuiltIn) callconv(.c) ffi.Result {
|
||||||
rt.readBuiltIn(output[0..output_size], builtin) catch |err| return toCResult(err);
|
rt.rt.readBuiltIn(output[0..output_size], builtin) catch |err| return toCResult(err);
|
||||||
return .Success;
|
return .Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
export fn SpvWriteInput(rt: *spv.Runtime, input: [*]const u8, input_size: c_ulong, result: spv.SpvWord) callconv(.c) ffi.Result {
|
export fn SpvWriteInput(rt: *RuntimeWrapper, input: [*]const u8, input_size: c_ulong, result: spv.SpvWord) callconv(.c) ffi.Result {
|
||||||
rt.writeInput(input[0..input_size], result) catch |err| return toCResult(err);
|
rt.rt.writeInput(input[0..input_size], result) catch |err| return toCResult(err);
|
||||||
return .Success;
|
return .Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
export fn SpvWriteBuiltIn(rt: *spv.Runtime, input: [*]const u8, input_size: c_ulong, builtin: spv.spv.SpvBuiltIn) callconv(.c) ffi.Result {
|
export fn SpvWriteBuiltIn(rt: *RuntimeWrapper, input: [*]const u8, input_size: c_ulong, builtin: spv.spv.SpvBuiltIn) callconv(.c) ffi.Result {
|
||||||
rt.writeBuiltIn(input[0..input_size], builtin) catch |err| return toCResult(err);
|
rt.rt.writeBuiltIn(input[0..input_size], builtin) catch |err| return toCResult(err);
|
||||||
return .Success;
|
return .Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
export fn SpvWriteDescriptorSet(rt: *spv.Runtime, input: [*]const u8, input_size: c_ulong, set: spv.SpvWord, binding: spv.SpvWord, descriptor_index: spv.SpvWord) callconv(.c) ffi.Result {
|
export fn SpvWriteDescriptorSet(rt: *RuntimeWrapper, input: [*]const u8, input_size: c_ulong, set: spv.SpvWord, binding: spv.SpvWord, descriptor_index: spv.SpvWord) callconv(.c) ffi.Result {
|
||||||
rt.writeDescriptorSet(input[0..input_size], set, binding, descriptor_index) catch |err| return toCResult(err);
|
rt.rt.writeDescriptorSet(input[0..input_size], set, binding, descriptor_index) catch |err| return toCResult(err);
|
||||||
return .Success;
|
return .Success;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,13 +0,0 @@
|
|||||||
const std = @import("std");
|
|
||||||
const spv = @import("spv.zig");
|
|
||||||
|
|
||||||
const SpvVoid = spv.SpvVoid;
|
|
||||||
const SpvByte = spv.SpvByte;
|
|
||||||
const SpvWord = spv.SpvWord;
|
|
||||||
const SpvBool = spv.SpvBool;
|
|
||||||
|
|
||||||
width: u32,
|
|
||||||
height: u32,
|
|
||||||
depth: u32,
|
|
||||||
layers: u32,
|
|
||||||
levels: u32,
|
|
||||||
+1
-1
@@ -142,7 +142,7 @@ 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) catch return ModuleError.OutOfMemory;
|
var rt = Runtime.init(allocator, self, undefined) catch return ModuleError.OutOfMemory;
|
||||||
defer {
|
defer {
|
||||||
for (self.results, rt.results) |*result, new_result| {
|
for (self.results, rt.results) |*result, new_result| {
|
||||||
result.deinit(allocator);
|
result.deinit(allocator);
|
||||||
|
|||||||
+20
-2
@@ -11,7 +11,6 @@ const SpvByte = spv.SpvByte;
|
|||||||
const SpvWord = spv.SpvWord;
|
const SpvWord = spv.SpvWord;
|
||||||
const SpvBool = spv.SpvBool;
|
const SpvBool = spv.SpvBool;
|
||||||
|
|
||||||
const Image = @import("Image.zig");
|
|
||||||
const Module = @import("Module.zig");
|
const Module = @import("Module.zig");
|
||||||
const Result = @import("Result.zig");
|
const Result = @import("Result.zig");
|
||||||
const WordIterator = @import("WordIterator.zig");
|
const WordIterator = @import("WordIterator.zig");
|
||||||
@@ -46,6 +45,22 @@ pub const Function = struct {
|
|||||||
ret: *Result,
|
ret: *Result,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
pub fn Vec4(comptime T: type) type {
|
||||||
|
return struct {
|
||||||
|
x: T,
|
||||||
|
y: T,
|
||||||
|
z: T,
|
||||||
|
w: T,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub const ImageAPI = struct {
|
||||||
|
readImageFloat4: *const fn (driver_image: *anyopaque, x: i32, y: i32, z: i32) RuntimeError!Vec4(f32),
|
||||||
|
readImageInt4: *const fn (driver_image: *anyopaque, x: i32, y: i32, z: i32) RuntimeError!Vec4(u32),
|
||||||
|
writeImageFloat4: *const fn (driver_image: *anyopaque, x: i32, y: i32, z: i32, pixel: Vec4(f32)) RuntimeError!void,
|
||||||
|
writeImageInt4: *const fn (driver_image: *anyopaque, x: i32, y: i32, z: i32, pixel: Vec4(u32)) RuntimeError!void,
|
||||||
|
};
|
||||||
|
|
||||||
mod: *Module,
|
mod: *Module,
|
||||||
it: WordIterator,
|
it: WordIterator,
|
||||||
|
|
||||||
@@ -61,7 +76,9 @@ previous_label: ?SpvWord,
|
|||||||
|
|
||||||
specialization_constants: std.AutoHashMapUnmanaged(u32, []const u8),
|
specialization_constants: std.AutoHashMapUnmanaged(u32, []const u8),
|
||||||
|
|
||||||
pub fn init(allocator: std.mem.Allocator, module: *Module) RuntimeError!Self {
|
image_api: ImageAPI,
|
||||||
|
|
||||||
|
pub fn init(allocator: std.mem.Allocator, module: *Module, image_api: ImageAPI) RuntimeError!Self {
|
||||||
return .{
|
return .{
|
||||||
.mod = module,
|
.mod = module,
|
||||||
.it = module.it,
|
.it = module.it,
|
||||||
@@ -78,6 +95,7 @@ pub fn init(allocator: std.mem.Allocator, module: *Module) RuntimeError!Self {
|
|||||||
.current_label = null,
|
.current_label = null,
|
||||||
.previous_label = null,
|
.previous_label = null,
|
||||||
.specialization_constants = .empty,
|
.specialization_constants = .empty,
|
||||||
|
.image_api = image_api,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+3
-13
@@ -109,17 +109,7 @@ pub const Value = union(Type) {
|
|||||||
Function: noreturn,
|
Function: noreturn,
|
||||||
Image: struct {
|
Image: struct {
|
||||||
type_word: SpvWord,
|
type_word: SpvWord,
|
||||||
data: []u8,
|
driver_image: *anyopaque,
|
||||||
|
|
||||||
pub inline fn getInfos(self: *const @This(), results: []const Result) RuntimeError!@FieldType(Result.TypeData, "Image") {
|
|
||||||
return switch (try results[self.type_word].getConstVariant()) {
|
|
||||||
.Type => |t| switch (t) {
|
|
||||||
.Image => |i| i,
|
|
||||||
else => RuntimeError.InvalidSpirV,
|
|
||||||
},
|
|
||||||
else => RuntimeError.InvalidSpirV,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
Sampler: struct {},
|
Sampler: struct {},
|
||||||
SampledImage: struct {},
|
SampledImage: struct {},
|
||||||
@@ -236,7 +226,7 @@ pub const Value = union(Type) {
|
|||||||
.Image => .{
|
.Image => .{
|
||||||
.Image = .{
|
.Image = .{
|
||||||
.type_word = resolved,
|
.type_word = resolved,
|
||||||
.data = &.{},
|
.driver_image = undefined,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
.Sampler => RuntimeError.ToDo,
|
.Sampler => RuntimeError.ToDo,
|
||||||
@@ -545,7 +535,7 @@ pub const Value = union(Type) {
|
|||||||
return offset;
|
return offset;
|
||||||
},
|
},
|
||||||
.RuntimeArray => |*arr| arr.data = input[0..],
|
.RuntimeArray => |*arr| arr.data = input[0..],
|
||||||
.Image => |*img| img.data = input[0..],
|
.Image => |*img| img.driver_image = @ptrFromInt(std.mem.bytesToValue(usize, input[0..])),
|
||||||
else => return RuntimeError.InvalidValueType,
|
else => return RuntimeError.InvalidValueType,
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
|
|||||||
@@ -30,7 +30,6 @@
|
|||||||
|
|
||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
|
|
||||||
pub const Image = @import("Image.zig");
|
|
||||||
pub const Module = @import("Module.zig");
|
pub const Module = @import("Module.zig");
|
||||||
pub const Runtime = @import("Runtime.zig");
|
pub const Runtime = @import("Runtime.zig");
|
||||||
|
|
||||||
|
|||||||
+266
@@ -324,6 +324,8 @@ pub fn initRuntimeDispatcher() void {
|
|||||||
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;
|
||||||
runtime_dispatcher[@intFromEnum(spv.SpvOp.SMulExtended)] = opSMulExtended;
|
runtime_dispatcher[@intFromEnum(spv.SpvOp.SMulExtended)] = opSMulExtended;
|
||||||
|
runtime_dispatcher[@intFromEnum(spv.SpvOp.ImageRead)] = opImageRead;
|
||||||
|
runtime_dispatcher[@intFromEnum(spv.SpvOp.ImageWrite)] = opImageWrite;
|
||||||
// zig fmt: on
|
// zig fmt: on
|
||||||
|
|
||||||
// Extensions init
|
// Extensions init
|
||||||
@@ -2144,6 +2146,270 @@ fn opFunctionParameter(_: std.mem.Allocator, _: SpvWord, rt: *Runtime) RuntimeEr
|
|||||||
rt.current_parameter_index += 1;
|
rt.current_parameter_index += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn opImageRead(_: std.mem.Allocator, _: SpvWord, rt: *Runtime) RuntimeError!void {
|
||||||
|
_ = try rt.it.next(); // result Type
|
||||||
|
const result_id = try rt.it.next();
|
||||||
|
const image = &rt.results[try rt.it.next()];
|
||||||
|
const coordinate = try rt.results[try rt.it.next()].getValue();
|
||||||
|
const dst = try rt.results[result_id].getValue();
|
||||||
|
|
||||||
|
const driver_image = switch ((try image.getValue()).*) {
|
||||||
|
.Image => |img| img.driver_image,
|
||||||
|
else => return RuntimeError.InvalidSpirV,
|
||||||
|
};
|
||||||
|
|
||||||
|
const helpers = struct {
|
||||||
|
fn readCoordLane(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 readCoordLane(&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 writeFloatTexel(dst_value: *Value, texel: Runtime.Vec4(f32)) RuntimeError!void {
|
||||||
|
switch (dst_value.*) {
|
||||||
|
.Vector4f32 => |*v| v.* = .{ texel.x, texel.y, texel.z, texel.w },
|
||||||
|
.Vector3f32 => |*v| v.* = .{ texel.x, texel.y, texel.z },
|
||||||
|
.Vector2f32 => |*v| v.* = .{ texel.x, texel.y },
|
||||||
|
.Vector => |lanes| {
|
||||||
|
if (lanes.len > 4) return RuntimeError.InvalidSpirV;
|
||||||
|
const values = [_]f32{ texel.x, texel.y, texel.z, texel.w };
|
||||||
|
for (lanes, 0..) |*lane, i| {
|
||||||
|
switch (lane.*) {
|
||||||
|
.Float => |*f| f.value.float32 = values[i],
|
||||||
|
else => return RuntimeError.InvalidValueType,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
else => return RuntimeError.InvalidValueType,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn writeIntTexel(dst_value: *Value, texel: Runtime.Vec4(u32)) RuntimeError!void {
|
||||||
|
switch (dst_value.*) {
|
||||||
|
.Vector4i32 => |*v| v.* = .{ @bitCast(texel.x), @bitCast(texel.y), @bitCast(texel.z), @bitCast(texel.w) },
|
||||||
|
.Vector3i32 => |*v| v.* = .{ @bitCast(texel.x), @bitCast(texel.y), @bitCast(texel.z) },
|
||||||
|
.Vector2i32 => |*v| v.* = .{ @bitCast(texel.x), @bitCast(texel.y) },
|
||||||
|
.Vector4u32 => |*v| v.* = .{ texel.x, texel.y, texel.z, texel.w },
|
||||||
|
.Vector3u32 => |*v| v.* = .{ texel.x, texel.y, texel.z },
|
||||||
|
.Vector2u32 => |*v| v.* = .{ texel.x, texel.y },
|
||||||
|
.Vector => |lanes| {
|
||||||
|
if (lanes.len > 4) return RuntimeError.InvalidSpirV;
|
||||||
|
const values = [_]u32{ texel.x, texel.y, texel.z, texel.w };
|
||||||
|
for (lanes, 0..) |*lane, i| {
|
||||||
|
switch (lane.*) {
|
||||||
|
.Int => |*int| int.value.uint32 = values[i],
|
||||||
|
else => return RuntimeError.InvalidValueType,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
else => return RuntimeError.InvalidValueType,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const x = try helpers.readCoordLane(coordinate, 0);
|
||||||
|
const y = helpers.readCoordLane(coordinate, 1) catch 0;
|
||||||
|
const z = helpers.readCoordLane(coordinate, 2) catch 0;
|
||||||
|
|
||||||
|
switch (dst.*) {
|
||||||
|
.Vector4f32, .Vector3f32, .Vector2f32 => try helpers.writeFloatTexel(dst, try rt.image_api.readImageFloat4(driver_image, x, y, z)),
|
||||||
|
.Vector4i32, .Vector3i32, .Vector2i32, .Vector4u32, .Vector3u32, .Vector2u32 => try helpers.writeIntTexel(dst, try rt.image_api.readImageInt4(driver_image, x, y, z)),
|
||||||
|
.Vector => |lanes| {
|
||||||
|
if (lanes.len == 0) return RuntimeError.InvalidSpirV;
|
||||||
|
switch (lanes[0]) {
|
||||||
|
.Float => try helpers.writeFloatTexel(dst, try rt.image_api.readImageFloat4(driver_image, x, y, z)),
|
||||||
|
.Int => try helpers.writeIntTexel(dst, try rt.image_api.readImageInt4(driver_image, x, y, z)),
|
||||||
|
else => return RuntimeError.InvalidValueType,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
else => return RuntimeError.InvalidValueType,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
fn opImageWrite(_: std.mem.Allocator, _: SpvWord, rt: *Runtime) RuntimeError!void {
|
||||||
|
const image = &rt.results[try rt.it.next()];
|
||||||
|
const coordinate = try rt.results[try rt.it.next()].getValue();
|
||||||
|
const texel = try rt.results[try rt.it.next()].getValue();
|
||||||
|
|
||||||
|
const driver_image = switch ((try image.getValue()).*) {
|
||||||
|
.Image => |img| img.driver_image,
|
||||||
|
else => return RuntimeError.InvalidSpirV,
|
||||||
|
};
|
||||||
|
|
||||||
|
const helpers = struct {
|
||||||
|
fn readCoordLane(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 readCoordLane(&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 readFloatLane(texel_value: *const Value, lane_index: usize) RuntimeError!f32 {
|
||||||
|
return switch (texel_value.*) {
|
||||||
|
.Float => |f| {
|
||||||
|
if (lane_index != 0) return RuntimeError.OutOfBounds;
|
||||||
|
return f.value.float32;
|
||||||
|
},
|
||||||
|
.Vector => |lanes| {
|
||||||
|
if (lane_index >= lanes.len) return RuntimeError.OutOfBounds;
|
||||||
|
return readFloatLane(&lanes[lane_index], 0);
|
||||||
|
},
|
||||||
|
.Vector4f32 => |v| switch (lane_index) {
|
||||||
|
inline 0...3 => |idx| v[idx],
|
||||||
|
else => return RuntimeError.OutOfBounds,
|
||||||
|
},
|
||||||
|
.Vector3f32 => |v| switch (lane_index) {
|
||||||
|
inline 0...2 => |idx| v[idx],
|
||||||
|
else => return RuntimeError.OutOfBounds,
|
||||||
|
},
|
||||||
|
.Vector2f32 => |v| switch (lane_index) {
|
||||||
|
inline 0...1 => |idx| v[idx],
|
||||||
|
else => return RuntimeError.OutOfBounds,
|
||||||
|
},
|
||||||
|
else => return RuntimeError.InvalidValueType,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
fn readIntLane(texel_value: *const Value, lane_index: usize) RuntimeError!u32 {
|
||||||
|
return switch (texel_value.*) {
|
||||||
|
.Int => |i| {
|
||||||
|
if (lane_index != 0) return RuntimeError.OutOfBounds;
|
||||||
|
return if (i.is_signed) @bitCast(i.value.sint32) else i.value.uint32;
|
||||||
|
},
|
||||||
|
.Vector => |lanes| {
|
||||||
|
if (lane_index >= lanes.len) return RuntimeError.OutOfBounds;
|
||||||
|
return readIntLane(&lanes[lane_index], 0);
|
||||||
|
},
|
||||||
|
.Vector4i32 => |v| switch (lane_index) {
|
||||||
|
inline 0...3 => |idx| @bitCast(v[idx]),
|
||||||
|
else => return RuntimeError.OutOfBounds,
|
||||||
|
},
|
||||||
|
.Vector3i32 => |v| switch (lane_index) {
|
||||||
|
inline 0...2 => |idx| @bitCast(v[idx]),
|
||||||
|
else => return RuntimeError.OutOfBounds,
|
||||||
|
},
|
||||||
|
.Vector2i32 => |v| switch (lane_index) {
|
||||||
|
inline 0...1 => |idx| @bitCast(v[idx]),
|
||||||
|
else => return RuntimeError.OutOfBounds,
|
||||||
|
},
|
||||||
|
.Vector4u32 => |v| switch (lane_index) {
|
||||||
|
inline 0...3 => |idx| v[idx],
|
||||||
|
else => return RuntimeError.OutOfBounds,
|
||||||
|
},
|
||||||
|
.Vector3u32 => |v| switch (lane_index) {
|
||||||
|
inline 0...2 => |idx| v[idx],
|
||||||
|
else => return RuntimeError.OutOfBounds,
|
||||||
|
},
|
||||||
|
.Vector2u32 => |v| switch (lane_index) {
|
||||||
|
inline 0...1 => |idx| v[idx],
|
||||||
|
else => return RuntimeError.OutOfBounds,
|
||||||
|
},
|
||||||
|
else => return RuntimeError.InvalidValueType,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
fn readFloatTexel(texel_value: *const Value) RuntimeError!Runtime.Vec4(f32) {
|
||||||
|
return .{
|
||||||
|
.x = try readFloatLane(texel_value, 0),
|
||||||
|
.y = readFloatLane(texel_value, 1) catch 0.0,
|
||||||
|
.z = readFloatLane(texel_value, 2) catch 0.0,
|
||||||
|
.w = readFloatLane(texel_value, 3) catch 0.0,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
fn readIntTexel(texel_value: *const Value) RuntimeError!Runtime.Vec4(u32) {
|
||||||
|
return .{
|
||||||
|
.x = try readIntLane(texel_value, 0),
|
||||||
|
.y = readIntLane(texel_value, 1) catch 0,
|
||||||
|
.z = readIntLane(texel_value, 2) catch 0,
|
||||||
|
.w = readIntLane(texel_value, 3) catch 0,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const x = try helpers.readCoordLane(coordinate, 0);
|
||||||
|
const y = helpers.readCoordLane(coordinate, 1) catch 0;
|
||||||
|
const z = helpers.readCoordLane(coordinate, 2) catch 0;
|
||||||
|
|
||||||
|
switch (texel.*) {
|
||||||
|
.Float, .Vector4f32, .Vector3f32, .Vector2f32 => try rt.image_api.writeImageFloat4(driver_image, x, y, z, try helpers.readFloatTexel(texel)),
|
||||||
|
.Int, .Vector4i32, .Vector3i32, .Vector2i32, .Vector4u32, .Vector3u32, .Vector2u32 => try rt.image_api.writeImageInt4(driver_image, x, y, z, try helpers.readIntTexel(texel)),
|
||||||
|
.Vector => |lanes| {
|
||||||
|
if (lanes.len == 0) return RuntimeError.InvalidSpirV;
|
||||||
|
switch (lanes[0]) {
|
||||||
|
.Float => try rt.image_api.writeImageFloat4(driver_image, x, y, z, try helpers.readFloatTexel(texel)),
|
||||||
|
.Int => try rt.image_api.writeImageInt4(driver_image, x, y, z, try helpers.readIntTexel(texel)),
|
||||||
|
else => return RuntimeError.InvalidValueType,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
else => return RuntimeError.InvalidValueType,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn opLabel(_: std.mem.Allocator, _: SpvWord, rt: *Runtime) RuntimeError!void {
|
fn opLabel(_: std.mem.Allocator, _: SpvWord, rt: *Runtime) RuntimeError!void {
|
||||||
const id = try rt.it.next();
|
const id = try rt.it.next();
|
||||||
rt.current_label = id;
|
rt.current_label = id;
|
||||||
|
|||||||
+1
-1
@@ -45,7 +45,7 @@ pub const case = struct {
|
|||||||
var module = try spv.Module.init(allocator, config.source, opt);
|
var module = try spv.Module.init(allocator, config.source, opt);
|
||||||
defer module.deinit(allocator);
|
defer module.deinit(allocator);
|
||||||
|
|
||||||
var rt = try spv.Runtime.init(allocator, &module);
|
var rt = try spv.Runtime.init(allocator, &module, undefined);
|
||||||
defer rt.deinit(allocator);
|
defer rt.deinit(allocator);
|
||||||
|
|
||||||
for (config.inputs, 0..) |input, n| {
|
for (config.inputs, 0..) |input, n| {
|
||||||
|
|||||||
+1
-1
@@ -54,7 +54,7 @@ int main(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
SpvRuntime runtime;
|
SpvRuntime runtime;
|
||||||
if(SpvInitRuntime(&runtime, module) != SPV_RESULT_SUCCESS)
|
if(SpvInitRuntime(&runtime, module, (SpvImageAPI){0}) != SPV_RESULT_SUCCESS)
|
||||||
{
|
{
|
||||||
fprintf(stderr, "Runtime init failed\n");
|
fprintf(stderr, "Runtime init failed\n");
|
||||||
return -1;
|
return -1;
|
||||||
|
|||||||
Reference in New Issue
Block a user