adding storage image read and writes
Build / build (push) Successful in 1m42s
Test / build (push) Successful in 8m27s

This commit is contained in:
2026-04-29 01:19:48 +02:00
parent cc041c9677
commit 046b1c8f9e
10 changed files with 473 additions and 62 deletions
+30 -1
View File
@@ -85,13 +85,42 @@ typedef enum
SPV_LOCATION_OUTPUT = 1,
} 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* SpvRuntime;
SPV_API SpvResult SpvInitModule(SpvModule* module, const SpvWord* source, SpvSize source_len, SpvModuleOptions options);
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 SpvResult SpvFlushDescriptorSets(SpvRuntime runtime);
+151 -29
View File
@@ -13,6 +13,32 @@ const LocationType = enum(c_int) {
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 {
return switch (err) {
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;
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.*);
return toCResult(err);
};
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;
rt.deinit(allocator);
rt.rt.deinit(allocator);
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;
rt.addSpecializationInfo(
rt.rt.addSpecializationInfo(
allocator,
.{
.id = entry.id,
@@ -63,60 +179,66 @@ export fn SpvAddSpecializationInfo(rt: *spv.Runtime, entry: CSpecializationEntry
return .Success;
}
export fn SpvGetEntryPointByName(rt: *spv.Runtime, name: [*:0]const u8, result: *spv.SpvWord) callconv(.c) ffi.Result {
result.* = rt.getEntryPointByName(std.mem.span(name)) catch |err| return toCResult(err);
export fn SpvGetEntryPointByName(rt: *RuntimeWrapper, name: [*:0]const u8, result: *spv.SpvWord) callconv(.c) ffi.Result {
result.* = rt.rt.getEntryPointByName(std.mem.span(name)) catch |err| return toCResult(err);
return .Success;
}
export fn SpvGetResultByLocation(rt: *spv.Runtime, location: spv.SpvWord, kind: LocationType, result: *spv.SpvWord) callconv(.c) ffi.Result {
result.* = rt.getResultByLocation(location, switch (kind) {
export fn SpvGetResultByLocation(rt: *RuntimeWrapper, location: spv.SpvWord, kind: LocationType, result: *spv.SpvWord) callconv(.c) ffi.Result {
result.* = rt.rt.getResultByLocation(location, switch (kind) {
.input => .input,
.output => .output,
}) catch |err| return toCResult(err);
return .Success;
}
export fn SpvGetResultByName(rt: *spv.Runtime, name: [*:0]const u8, result: *spv.SpvWord) callconv(.c) ffi.Result {
result.* = rt.getResultByName(std.mem.span(name)) catch |err| return toCResult(err);
export fn SpvGetResultByName(rt: *RuntimeWrapper, name: [*:0]const u8, result: *spv.SpvWord) callconv(.c) ffi.Result {
result.* = rt.rt.getResultByName(std.mem.span(name)) catch |err| return toCResult(err);
return .Success;
}
export fn SpvGetResultMemorySize(rt: *spv.Runtime, result: spv.SpvWord, size: *c_ulong) callconv(.c) ffi.Result {
size.* = rt.getResultMemorySize(result) catch |err| return toCResult(err);
export fn SpvGetResultMemorySize(rt: *RuntimeWrapper, result: spv.SpvWord, size: *c_ulong) callconv(.c) ffi.Result {
size.* = rt.rt.getResultMemorySize(result) catch |err| return toCResult(err);
return .Success;
}
export fn SpvHasResultDecoration(rt: *spv.Runtime, result: spv.SpvWord, decoration: spv.spv.SpvDecoration) callconv(.c) c_int {
return if (rt.hasResultDecoration(result, decoration)) 1 else 0;
export fn SpvHasResultDecoration(rt: *RuntimeWrapper, result: spv.SpvWord, decoration: spv.spv.SpvDecoration) callconv(.c) c_int {
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;
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;
}
export fn SpvReadOutput(rt: *spv.Runtime, 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);
export fn SpvReadOutput(rt: *RuntimeWrapper, output: [*]u8, output_size: c_ulong, result: spv.SpvWord) callconv(.c) ffi.Result {
rt.rt.readOutput(output[0..output_size], result) catch |err| return toCResult(err);
return .Success;
}
export fn SpvReadBuiltIn(rt: *spv.Runtime, 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);
export fn SpvReadBuiltIn(rt: *RuntimeWrapper, output: [*]u8, output_size: c_ulong, builtin: spv.spv.SpvBuiltIn) callconv(.c) ffi.Result {
rt.rt.readBuiltIn(output[0..output_size], builtin) catch |err| return toCResult(err);
return .Success;
}
export fn SpvWriteInput(rt: *spv.Runtime, 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);
export fn SpvWriteInput(rt: *RuntimeWrapper, input: [*]const u8, input_size: c_ulong, result: spv.SpvWord) callconv(.c) ffi.Result {
rt.rt.writeInput(input[0..input_size], result) catch |err| return toCResult(err);
return .Success;
}
export fn SpvWriteBuiltIn(rt: *spv.Runtime, 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);
export fn SpvWriteBuiltIn(rt: *RuntimeWrapper, input: [*]const u8, input_size: c_ulong, builtin: spv.spv.SpvBuiltIn) callconv(.c) ffi.Result {
rt.rt.writeBuiltIn(input[0..input_size], builtin) catch |err| return toCResult(err);
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 {
rt.writeDescriptorSet(input[0..input_size], set, binding, descriptor_index) catch |err| return toCResult(err);
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.rt.writeDescriptorSet(input[0..input_size], set, binding, descriptor_index) catch |err| return toCResult(err);
return .Success;
}