Wire ssbo rendering into sandbox
This commit is contained in:
parent
63d72dd94f
commit
3549f2de9c
3 changed files with 60 additions and 3 deletions
|
|
@ -8,6 +8,7 @@ pub fn build(b: *std.Build) void {
|
||||||
.target = target,
|
.target = target,
|
||||||
.optimize = optimize,
|
.optimize = optimize,
|
||||||
.linux_display_backend = .X11,
|
.linux_display_backend = .X11,
|
||||||
|
.opengl_version = .gl_4_3,
|
||||||
});
|
});
|
||||||
|
|
||||||
// sandbox executable
|
// sandbox executable
|
||||||
|
|
|
||||||
|
|
@ -286,3 +286,35 @@ test "update respawns entity at edge when reaching center" {
|
||||||
|
|
||||||
try std.testing.expect(on_left or on_right or on_top or on_bottom);
|
try std.testing.expect(on_left or on_right or on_top or on_bottom);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GPU entity for SSBO rendering (position + color only, no velocity)
|
||||||
|
pub const GpuEntity = extern struct {
|
||||||
|
x: f32,
|
||||||
|
y: f32,
|
||||||
|
color: u32,
|
||||||
|
};
|
||||||
|
|
||||||
|
test "GpuEntity struct has correct size for SSBO" {
|
||||||
|
// SSBO layout: x(4) + y(4) + color(4) = 12 bytes
|
||||||
|
try std.testing.expectEqual(@as(usize, 12), @sizeOf(GpuEntity));
|
||||||
|
}
|
||||||
|
|
||||||
|
test "GpuEntity can be created from Entity" {
|
||||||
|
const entity = Entity{
|
||||||
|
.x = 100.0,
|
||||||
|
.y = 200.0,
|
||||||
|
.vx = 1.5, // ignored for GPU
|
||||||
|
.vy = -0.5, // ignored for GPU
|
||||||
|
.color = 0x00FFFF,
|
||||||
|
};
|
||||||
|
|
||||||
|
const gpu_entity = GpuEntity{
|
||||||
|
.x = entity.x,
|
||||||
|
.y = entity.y,
|
||||||
|
.color = entity.color,
|
||||||
|
};
|
||||||
|
|
||||||
|
try std.testing.expectEqual(@as(f32, 100.0), gpu_entity.x);
|
||||||
|
try std.testing.expectEqual(@as(f32, 200.0), gpu_entity.y);
|
||||||
|
try std.testing.expectEqual(@as(u32, 0x00FFFF), gpu_entity.color);
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@ const std = @import("std");
|
||||||
const rl = @import("raylib");
|
const rl = @import("raylib");
|
||||||
const sandbox = @import("sandbox.zig");
|
const sandbox = @import("sandbox.zig");
|
||||||
const ui = @import("ui.zig");
|
const ui = @import("ui.zig");
|
||||||
|
const SsboRenderer = @import("ssbo_renderer.zig").SsboRenderer;
|
||||||
|
|
||||||
const SCREEN_WIDTH = sandbox.SCREEN_WIDTH;
|
const SCREEN_WIDTH = sandbox.SCREEN_WIDTH;
|
||||||
const SCREEN_HEIGHT = sandbox.SCREEN_HEIGHT;
|
const SCREEN_HEIGHT = sandbox.SCREEN_HEIGHT;
|
||||||
|
|
@ -26,7 +27,7 @@ const HEARTBEAT_INTERVAL: f32 = 10.0; // seconds between periodic logs
|
||||||
|
|
||||||
// auto-benchmark settings
|
// auto-benchmark settings
|
||||||
const BENCH_RAMP_INTERVAL: f32 = 2.0; // seconds between entity ramps
|
const BENCH_RAMP_INTERVAL: f32 = 2.0; // seconds between entity ramps
|
||||||
const BENCH_RAMP_AMOUNT: usize = 10_000; // entities added per ramp
|
const BENCH_RAMP_AMOUNT: usize = 50_000; // entities added per ramp
|
||||||
const BENCH_EXIT_THRESHOLD_MS: f32 = 25.0; // exit when frame time exceeds this
|
const BENCH_EXIT_THRESHOLD_MS: f32 = 25.0; // exit when frame time exceeds this
|
||||||
const BENCH_EXIT_SUSTAIN: f32 = 1.0; // must stay above threshold for this long
|
const BENCH_EXIT_SUSTAIN: f32 = 1.0; // must stay above threshold for this long
|
||||||
|
|
||||||
|
|
@ -154,14 +155,19 @@ pub fn main() !void {
|
||||||
// parse args
|
// parse args
|
||||||
var bench_mode = false;
|
var bench_mode = false;
|
||||||
var use_instancing = false;
|
var use_instancing = false;
|
||||||
|
var use_ssbo = false;
|
||||||
var args = try std.process.argsWithAllocator(std.heap.page_allocator);
|
var args = try std.process.argsWithAllocator(std.heap.page_allocator);
|
||||||
defer args.deinit();
|
defer args.deinit();
|
||||||
_ = args.skip(); // skip program name
|
_ = args.skip(); // skip program name
|
||||||
while (args.next()) |arg| {
|
while (args.next()) |arg| {
|
||||||
if (std.mem.eql(u8, arg, "--bench")) {
|
if (std.mem.eql(u8, arg, "--bench")) {
|
||||||
bench_mode = true;
|
bench_mode = true;
|
||||||
|
use_ssbo = true; // bench mode uses SSBO by default
|
||||||
} else if (std.mem.eql(u8, arg, "--gpu")) {
|
} else if (std.mem.eql(u8, arg, "--gpu")) {
|
||||||
use_instancing = true;
|
use_instancing = true;
|
||||||
|
use_ssbo = false; // explicit --gpu overrides SSBO
|
||||||
|
} else if (std.mem.eql(u8, arg, "--ssbo")) {
|
||||||
|
use_ssbo = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -221,6 +227,21 @@ pub fn main() !void {
|
||||||
if (transforms) |t| std.heap.page_allocator.free(t);
|
if (transforms) |t| std.heap.page_allocator.free(t);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SSBO rendering setup (only if --ssbo flag)
|
||||||
|
var ssbo_renderer: ?SsboRenderer = null;
|
||||||
|
|
||||||
|
if (use_ssbo) {
|
||||||
|
ssbo_renderer = SsboRenderer.init(circle_texture) orelse {
|
||||||
|
std.debug.print("failed to initialize SSBO renderer\n", .{});
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
std.debug.print("SSBO instancing mode enabled\n", .{});
|
||||||
|
}
|
||||||
|
|
||||||
|
defer {
|
||||||
|
if (ssbo_renderer) |*r| r.deinit();
|
||||||
|
}
|
||||||
|
|
||||||
// load UI font (embedded)
|
// load UI font (embedded)
|
||||||
const font_data = @embedFile("verdanab.ttf");
|
const font_data = @embedFile("verdanab.ttf");
|
||||||
const ui_font = rl.loadFontFromMemory(".ttf", font_data, 32, null) catch {
|
const ui_font = rl.loadFontFromMemory(".ttf", font_data, 32, null) catch {
|
||||||
|
|
@ -301,8 +322,11 @@ pub fn main() !void {
|
||||||
rl.beginDrawing();
|
rl.beginDrawing();
|
||||||
rl.clearBackground(BG_COLOR);
|
rl.clearBackground(BG_COLOR);
|
||||||
|
|
||||||
if (use_instancing) {
|
if (use_ssbo) {
|
||||||
// GPU instancing path
|
// SSBO instanced rendering path (12 bytes per entity)
|
||||||
|
ssbo_renderer.?.render(&entities);
|
||||||
|
} else if (use_instancing) {
|
||||||
|
// GPU instancing path (64 bytes per entity)
|
||||||
const xforms = transforms.?;
|
const xforms = transforms.?;
|
||||||
// fill transforms array with entity positions
|
// fill transforms array with entity positions
|
||||||
for (entities.items[0..entities.count], 0..) |entity, i| {
|
for (entities.items[0..entities.count], 0..) |entity, i| {
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue