working on example and adding opcodes
All checks were successful
Build / build (push) Successful in 2m6s
Test / build (push) Successful in 6m5s

This commit is contained in:
2026-01-23 02:09:30 +01:00
parent bb866f1312
commit 27172539e5
13 changed files with 736 additions and 266 deletions

View File

@@ -4,91 +4,120 @@ const spv = @import("spv");
const shader_source = @embedFile("shader.spv");
const screen_width = 640;
const screen_height = 480;
const screen_width = 1250;
const screen_height = 720;
pub fn main() !void {
{
//var gpa: std.heap.DebugAllocator(.{}) = .init;
//defer _ = gpa.deinit();
var gpa = std.heap.ArenaAllocator.init(std.heap.page_allocator);
defer gpa.deinit();
defer sdl3.shutdown();
const init_flags = sdl3.InitFlags{ .video = true };
const init_flags = sdl3.InitFlags{ .video = true, .events = true };
try sdl3.init(init_flags);
defer sdl3.quit(init_flags);
const window = try sdl3.video.Window.init("Hello triangle", screen_width, screen_height, .{});
defer window.deinit();
const allocator = gpa.allocator();
const surface = try window.getSurface();
const allocator = std.heap.smp_allocator;
var module = try spv.Module.init(allocator, @ptrCast(@alignCast(shader_source)), .{});
defer module.deinit(allocator);
const surface = try window.getSurface();
try surface.clear(.{ .r = 0.0, .g = 0.0, .b = 0.0, .a = 0.0 });
{
try surface.lock();
defer surface.unlock();
var pixel_map: [*]u32 = @as([*]u32, @ptrCast(@alignCast((surface.getPixels() orelse return).ptr)));
const margin_x = @divTrunc(screen_width, 3);
const margin_y = @divTrunc(screen_height, 3);
const top_y = margin_y;
const bottom_y = (screen_height - 1) - margin_y;
const center_x = @divTrunc(screen_width, 2);
const tri_h = bottom_y - top_y;
const max_half_w = @divTrunc(screen_width, 2) - margin_x;
var timer = try std.time.Timer.start();
defer {
const ns = timer.lap();
std.log.info("Took {d:.3}s to render", .{@as(f32, @floatFromInt(ns)) / std.time.ns_per_s});
}
for (top_y..bottom_y) |y| {
const t: f32 = @as(f32, @floatFromInt(y - top_y)) / @as(f32, @floatFromInt(tri_h));
const half_w: usize = @intFromFloat((t * @as(f32, @floatFromInt(max_half_w))) + 0.5);
const x0 = std.math.clamp(center_x - half_w, 0, screen_width - 1);
const x1 = std.math.clamp(center_x + half_w, 0, screen_width - 1);
for (x0..x1) |x| {
var rt = try spv.Runtime.init(allocator, &module);
defer rt.deinit(allocator);
var output: [4]f32 = undefined;
const entry = try rt.getEntryPointByName("main");
const color = try rt.getResultByName("color");
const dim = try rt.getResultByName("dim");
const pos = try rt.getResultByName("pos");
try rt.writeInput(f32, &.{ @floatFromInt(x1 - x0), @floatFromInt(bottom_y - top_y) }, dim);
try rt.writeInput(f32, &.{ @floatFromInt(x), @floatFromInt(y) }, pos);
try rt.callEntryPoint(allocator, entry);
try rt.readOutput(f32, output[0..], color);
const rgba = surface.mapRgba(
@truncate(@as(u32, @intFromFloat(output[0] * 255.0))),
@truncate(@as(u32, @intFromFloat(output[1] * 255.0))),
@truncate(@as(u32, @intFromFloat(output[2] * 255.0))),
@truncate(@as(u32, @intFromFloat(output[3] * 255.0))),
);
pixel_map[(y * surface.getWidth()) + x] = rgba.value;
}
var runner_cache: std.ArrayList(Runner) = try .initCapacity(allocator, screen_height);
defer {
for (runner_cache.items) |*runner| {
runner.rt.deinit(allocator);
}
runner_cache.deinit(allocator);
}
try window.updateSurface();
for (0..screen_height) |_| {
(try runner_cache.addOne(allocator)).* = .{
.allocator = allocator,
.surface = surface,
.rt = try spv.Runtime.init(allocator, &module),
};
}
std.Thread.sleep(2_000_000_000);
var thread_pool: std.Thread.Pool = undefined;
try thread_pool.init(.{
.allocator = allocator,
});
var quit = false;
while (!quit) {
try surface.clear(.{ .r = 0.0, .g = 0.0, .b = 0.0, .a = 0.0 });
while (sdl3.events.poll()) |event|
switch (event) {
.quit => quit = true,
.terminating => quit = true,
else => {},
};
{
try surface.lock();
defer surface.unlock();
const pixel_map: [*]u32 = @as([*]u32, @ptrCast(@alignCast((surface.getPixels() orelse return).ptr)));
var timer = try std.time.Timer.start();
defer {
const ns = timer.lap();
const ms = @as(f32, @floatFromInt(ns)) / std.time.ns_per_s;
std.log.info("Took {d:.3}s - {d:.3}fps to render", .{ ms, 1.0 / ms });
}
var wait_group: std.Thread.WaitGroup = .{};
for (0..screen_height) |y| {
const runner = &runner_cache.items[y];
thread_pool.spawnWg(&wait_group, Runner.run, .{ runner, y, pixel_map });
}
thread_pool.waitAndWork(&wait_group);
}
try window.updateSurface();
}
}
std.log.info("Successfully executed", .{});
}
const Runner = struct {
const Self = @This();
allocator: std.mem.Allocator,
surface: sdl3.surface.Surface,
rt: spv.Runtime,
fn run(self: *Self, y: usize, pixel_map: [*]u32) void {
const entry = self.rt.getEntryPointByName("main") catch |err| std.debug.panic("Catch error {s}", .{@errorName(err)});
const color = self.rt.getResultByName("color") catch |err| std.debug.panic("Catch error {s}", .{@errorName(err)});
const time = self.rt.getResultByName("time") catch |err| std.debug.panic("Catch error {s}", .{@errorName(err)});
const pos = self.rt.getResultByName("pos") catch |err| std.debug.panic("Catch error {s}", .{@errorName(err)});
const res = self.rt.getResultByName("res") catch |err| std.debug.panic("Catch error {s}", .{@errorName(err)});
var output: [4]f32 = undefined;
var rt = self.rt; // Copy to avoid pointer access of `self` at runtime. Okay as Runtime contains only pointers and trivially copyable fields
for (0..screen_width) |x| {
rt.writeInput(f32, &.{@as(f32, @floatFromInt(std.time.milliTimestamp()))}, time) catch |err| std.debug.panic("Catch error {s}", .{@errorName(err)});
rt.writeInput(f32, &.{ @floatFromInt(screen_width), @floatFromInt(screen_height) }, res) catch |err| std.debug.panic("Catch error {s}", .{@errorName(err)});
rt.writeInput(f32, &.{ @floatFromInt(x), @floatFromInt(y) }, pos) catch |err| std.debug.panic("Catch error {s}", .{@errorName(err)});
rt.callEntryPoint(self.allocator, entry) catch |err| std.debug.panic("Catch error {s}", .{@errorName(err)});
rt.readOutput(f32, output[0..], color) catch |err| std.debug.panic("Catch error {s}", .{@errorName(err)});
const rgba = self.surface.mapRgba(
@truncate(@as(u32, @intFromFloat(output[0] * 255.0))),
@truncate(@as(u32, @intFromFloat(output[1] * 255.0))),
@truncate(@as(u32, @intFromFloat(output[2] * 255.0))),
@truncate(@as(u32, @intFromFloat(output[3] * 255.0))),
);
pixel_map[(y * self.surface.getWidth()) + x] = rgba.value;
}
}
};

View File

@@ -3,8 +3,9 @@ module;
struct FragIn
{
[location(0)] dim: vec2[f32],
[location(1)] pos: vec2[f32],
[location(0)] time: u32,
[location(1)] dim: vec2[f32],
[location(2)] pos: vec2[f32],
}
struct FragOut

Binary file not shown.

View File

@@ -1,75 +1,86 @@
Version 1.0
Generator: 2560130
Bound: 45
Bound: 51
Schema: 0
OpCapability Capability(Shader)
OpMemoryModel AddressingModel(Logical) MemoryModel(GLSL450)
OpEntryPoint ExecutionModel(Fragment) %20 "main" %6 %10 %16
OpExecutionMode %20 ExecutionMode(OriginUpperLeft)
OpEntryPoint ExecutionModel(Fragment) %25 "main" %5 %12 %15 %21
OpExecutionMode %25 ExecutionMode(OriginUpperLeft)
OpSource SourceLanguage(NZSL) 4198400
OpSourceExtension "Version: 1.1"
OpName %12 "FragIn"
OpMemberName %12 0 "dim"
OpMemberName %12 1 "pos"
OpName %17 "FragOut"
OpMemberName %17 0 "color"
OpName %6 "dim"
OpName %10 "pos"
OpName %16 "color"
OpName %20 "main"
OpDecorate %6 Decoration(Location) 0
OpDecorate %10 Decoration(Location) 1
OpDecorate %16 Decoration(Location) 0
OpMemberDecorate %12 0 Decoration(Offset) 0
OpMemberDecorate %12 1 Decoration(Offset) 8
OpName %17 "FragIn"
OpMemberName %17 0 "time"
OpMemberName %17 1 "dim"
OpMemberName %17 2 "pos"
OpName %22 "FragOut"
OpMemberName %22 0 "color"
OpName %5 "time"
OpName %12 "dim"
OpName %15 "pos"
OpName %21 "color"
OpName %25 "main"
OpDecorate %5 Decoration(Location) 0
OpDecorate %12 Decoration(Location) 1
OpDecorate %15 Decoration(Location) 2
OpDecorate %21 Decoration(Location) 0
OpMemberDecorate %17 0 Decoration(Offset) 0
OpMemberDecorate %17 1 Decoration(Offset) 8
OpMemberDecorate %17 2 Decoration(Offset) 16
OpMemberDecorate %22 0 Decoration(Offset) 0
%1 = OpTypeVoid
%2 = OpTypeFunction %1
%3 = OpTypeFloat 32
%4 = OpTypeVector %3 2
%5 = OpTypePointer StorageClass(Input) %4
%7 = OpTypeInt 32 1
%8 = OpConstant %7 i32(0)
%9 = OpTypePointer StorageClass(Function) %4
%11 = OpConstant %7 i32(1)
%12 = OpTypeStruct %4 %4
%13 = OpTypePointer StorageClass(Function) %12
%14 = OpTypeVector %3 4
%15 = OpTypePointer StorageClass(Output) %14
%17 = OpTypeStruct %14
%3 = OpTypeInt 32 0
%4 = OpTypePointer StorageClass(Input) %3
%6 = OpTypeInt 32 1
%7 = OpConstant %6 i32(0)
%8 = OpTypePointer StorageClass(Function) %3
%9 = OpTypeFloat 32
%10 = OpTypeVector %9 2
%11 = OpTypePointer StorageClass(Input) %10
%13 = OpConstant %6 i32(1)
%14 = OpTypePointer StorageClass(Function) %10
%16 = OpConstant %6 i32(2)
%17 = OpTypeStruct %3 %10 %10
%18 = OpTypePointer StorageClass(Function) %17
%19 = OpConstant %3 f32(1)
%42 = OpTypePointer StorageClass(Function) %14
%6 = OpVariable %5 StorageClass(Input)
%10 = OpVariable %5 StorageClass(Input)
%16 = OpVariable %15 StorageClass(Output)
%20 = OpFunction %1 FunctionControl(0) %2
%21 = OpLabel
%22 = OpVariable %18 StorageClass(Function)
%23 = OpVariable %13 StorageClass(Function)
%24 = OpAccessChain %9 %23 %8
OpCopyMemory %24 %6
%25 = OpAccessChain %9 %23 %11
OpCopyMemory %25 %10
%26 = OpAccessChain %9 %23 %11
%27 = OpLoad %4 %26
%28 = OpCompositeExtract %3 %27 0
%29 = OpAccessChain %9 %23 %8
%30 = OpLoad %4 %29
%31 = OpCompositeExtract %3 %30 0
%32 = OpFDiv %3 %28 %31
%33 = OpAccessChain %9 %23 %11
%34 = OpLoad %4 %33
%35 = OpCompositeExtract %3 %34 1
%36 = OpAccessChain %9 %23 %8
%37 = OpLoad %4 %36
%38 = OpCompositeExtract %3 %37 1
%39 = OpFDiv %3 %35 %38
%40 = OpCompositeConstruct %14 %32 %39 %19 %19
%41 = OpAccessChain %42 %22 %8
OpStore %41 %40
%43 = OpLoad %17 %22
%44 = OpCompositeExtract %14 %43 0
OpStore %16 %44
%19 = OpTypeVector %9 4
%20 = OpTypePointer StorageClass(Output) %19
%22 = OpTypeStruct %19
%23 = OpTypePointer StorageClass(Function) %22
%24 = OpConstant %9 f32(1)
%48 = OpTypePointer StorageClass(Function) %19
%5 = OpVariable %4 StorageClass(Input)
%12 = OpVariable %11 StorageClass(Input)
%15 = OpVariable %11 StorageClass(Input)
%21 = OpVariable %20 StorageClass(Output)
%25 = OpFunction %1 FunctionControl(0) %2
%26 = OpLabel
%27 = OpVariable %23 StorageClass(Function)
%28 = OpVariable %18 StorageClass(Function)
%29 = OpAccessChain %8 %28 %7
OpCopyMemory %29 %5
%30 = OpAccessChain %14 %28 %13
OpCopyMemory %30 %12
%31 = OpAccessChain %14 %28 %16
OpCopyMemory %31 %15
%32 = OpAccessChain %14 %28 %16
%33 = OpLoad %10 %32
%34 = OpCompositeExtract %9 %33 0
%35 = OpAccessChain %14 %28 %13
%36 = OpLoad %10 %35
%37 = OpCompositeExtract %9 %36 0
%38 = OpFDiv %9 %34 %37
%39 = OpAccessChain %14 %28 %16
%40 = OpLoad %10 %39
%41 = OpCompositeExtract %9 %40 1
%42 = OpAccessChain %14 %28 %13
%43 = OpLoad %10 %42
%44 = OpCompositeExtract %9 %43 1
%45 = OpFDiv %9 %41 %44
%46 = OpCompositeConstruct %19 %38 %45 %24 %24
%47 = OpAccessChain %48 %27 %7
OpStore %47 %46
%49 = OpLoad %22 %27
%50 = OpCompositeExtract %19 %49 0
OpStore %21 %50
OpReturn
OpFunctionEnd