Add GPU instance setup

This commit is contained in:
Jared Miller 2025-12-15 21:59:48 -05:00
parent faeb366bfb
commit 3a54b0dde3

View file

@ -16,6 +16,7 @@ const CYAN = rl.Color{ .r = 0, .g = 255, .b = 255, .a = 255 };
// entity rendering // entity rendering
const ENTITY_RADIUS: f32 = 4.0; const ENTITY_RADIUS: f32 = 4.0;
const TEXTURE_SIZE: i32 = 16; // must be >= 2 * radius const TEXTURE_SIZE: i32 = 16; // must be >= 2 * radius
const MESH_SIZE: f32 = @floatFromInt(TEXTURE_SIZE); // match texture size
// logging thresholds // logging thresholds
const TARGET_FRAME_MS: f32 = 16.7; // 60fps const TARGET_FRAME_MS: f32 = 16.7; // 60fps
@ -129,15 +130,38 @@ fn createCircleTexture() ?rl.Texture2D {
return target.texture; return target.texture;
} }
fn createOrthoCamera() rl.Camera3D {
// orthographic camera looking down -Y axis at XZ plane
// positioned to match 2D screen coordinates
const hw = @as(f32, @floatFromInt(SCREEN_WIDTH)) / 2.0;
const hh = @as(f32, @floatFromInt(SCREEN_HEIGHT)) / 2.0;
return .{
.position = .{ .x = hw, .y = 1000, .z = hh },
.target = .{ .x = hw, .y = 0, .z = hh },
.up = .{ .x = 0, .y = 0, .z = -1 }, // -Z is up to match screen Y
.fovy = @floatFromInt(SCREEN_HEIGHT), // ortho uses fovy as height
.projection = .orthographic,
};
}
fn createInstanceMaterial(texture: rl.Texture2D) ?rl.Material {
var material = rl.loadMaterialDefault() catch return null;
rl.setMaterialTexture(&material, rl.MATERIAL_MAP_DIFFUSE, texture);
return material;
}
pub fn main() !void { pub fn main() !void {
// parse args // parse args
var bench_mode = false; var bench_mode = false;
var use_instancing = 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;
} else if (std.mem.eql(u8, arg, "--gpu")) {
use_instancing = true;
} }
} }
@ -162,6 +186,36 @@ pub fn main() !void {
}; };
defer rl.unloadTexture(circle_texture); defer rl.unloadTexture(circle_texture);
// GPU instancing setup (only if --gpu flag)
var quad_mesh: ?rl.Mesh = null;
var instance_material: ?rl.Material = null;
var ortho_camera: rl.Camera3D = undefined;
// static buffer for transforms - allocated once, reused each frame
var transforms: [sandbox.MAX_ENTITIES]rl.Matrix = undefined;
if (use_instancing) {
// create quad mesh (XZ plane, will view from above)
quad_mesh = rl.genMeshPlane(MESH_SIZE, MESH_SIZE, 1, 1);
rl.uploadMesh(&quad_mesh.?, false); // upload to GPU
// material with circle texture
instance_material = createInstanceMaterial(circle_texture) orelse {
std.debug.print("failed to create instance material\n", .{});
return;
};
// orthographic camera for 2D-like rendering
ortho_camera = createOrthoCamera();
std.debug.print("GPU instancing mode enabled\n", .{});
}
defer {
if (quad_mesh) |*m| rl.unloadMesh(m.*);
if (instance_material) |mat| mat.unload();
}
// 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 {
@ -242,7 +296,20 @@ pub fn main() !void {
rl.beginDrawing(); rl.beginDrawing();
rl.clearBackground(BG_COLOR); rl.clearBackground(BG_COLOR);
// draw entities using rlgl quad batching if (use_instancing) {
// GPU instancing path
// fill transforms array with entity positions
for (entities.items[0..entities.count], 0..) |entity, i| {
// entity (x, y) maps to 3D (x, 0, y) on XZ plane
transforms[i] = rl.Matrix.translate(entity.x, 0, entity.y);
}
// draw all entities with single instanced call
ortho_camera.begin();
rl.drawMeshInstanced(quad_mesh.?, instance_material.?, transforms[0..entities.count]);
ortho_camera.end();
} else {
// rlgl quad batching path (original)
const size = @as(f32, @floatFromInt(TEXTURE_SIZE)); const size = @as(f32, @floatFromInt(TEXTURE_SIZE));
const half = size / 2.0; const half = size / 2.0;
@ -274,6 +341,7 @@ pub fn main() !void {
rl.gl.rlEnd(); rl.gl.rlEnd();
rl.gl.rlSetTexture(0); rl.gl.rlSetTexture(0);
}
// metrics overlay (skip in bench mode for cleaner headless run) // metrics overlay (skip in bench mode for cleaner headless run)
if (!bench_mode) { if (!bench_mode) {