simple triangle example working with new sdl api

This commit is contained in:
Peter Li 2025-04-14 17:59:00 -07:00
parent 86d56cf5e6
commit 373eb9600c
9 changed files with 250 additions and 9 deletions

View File

@ -169,6 +169,11 @@ pub fn createObject(comptime T: type, params: engine.NeonObjectParams) !*T {
return gEngine.createObject(T, params);
}
pub fn registerRendererSetup(ctx: *anyopaque, setup: engine.SetupFuncFn) void {
gEngine.rendererCtx = ctx;
gEngine.rendererSetupFunc = setup;
}
pub fn setupEnginePlatform(ctx: *anyopaque, setup: engine.SetupFuncFn, poll: engine.PollFuncFn, proc: engine.ProcEventsFn) void {
gEngine.platformCtx = ctx;

View File

@ -70,6 +70,9 @@ pub const Engine = struct {
platformSetupFunc: ?PollFuncFn = null,
platformProcEventsFunc: ?ProcEventsFn = null,
rendererCtx: *anyopaque = undefined,
rendererSetupFunc: ?PollFuncFn = null,
engineStartTime: f64 = 0,
nfdRuntime: *nfd.NFDRuntime,
@ -280,6 +283,10 @@ pub const Engine = struct {
setupFunc(ctx.engine.platformCtx) catch unreachable;
}
if (ctx.engine.rendererSetupFunc) |setupFunc| {
setupFunc(ctx.engine.rendererCtx) catch unreachable;
}
while (true) {
ctx.engine.tick() catch unreachable;

View File

@ -8,7 +8,7 @@ const realMain = @import("main");
pub const options = @import("BacklogOptions");
pub const std_options = std.Options{
.enable_segfault_handler = false,
// .enable_segfault_handler = false,
};
//pub const build_options = @import("build_options");
@ -21,6 +21,6 @@ pub const std_options = std.Options{
// }
pub fn main() !void {
panickers.attachSegfaultHandler();
// panickers.attachSegfaultHandler();
try realMain.main();
}

View File

@ -43,6 +43,5 @@ pub fn shutdown_module(allocator: std.mem.Allocator) void {
gPlatformInstance.deinit();
// I have a bug somewhere. need to find out where it is
allocator.destroy(gPlatformInstance);
}

View File

@ -112,7 +112,7 @@ pub const PlatformInstance = struct {
.video = true,
.gamepad = true,
}) catch return error.BadInit;
self.window = sdl3.c.SDL_CreateWindow(self.windowName, self.windowExtent.x, self.windowExtent.y, 0x20).?; // resizeable
self.window = sdl3.c.SDL_CreateWindow(self.windowName, self.windowExtent.x, self.windowExtent.y, 0).?; // resizeable
}
pub fn registerSetupFuncs(self: *@This()) !void {

View File

@ -1,6 +1,6 @@
const std = @import("std");
const core = @import("core");
const sample_vert = @import("sample.vert");
const sgpu_renderer = @import("sgpu/renderer.zig");
// controls glfw and general windowing
// graphics depends on this one
@ -14,11 +14,10 @@ pub fn start_module(comptime programSpec: anytype, args: anytype, allocator: std
_ = args;
_ = programSpec;
_ = allocator;
core.engine_log("starting up [REND] module...", .{});
core.engine_log("sample_vert.Scene size = {d}", .{@sizeOf(sample_vert.Scene)});
try sgpu_renderer.start();
}
pub fn shutdown_module(allocator: std.mem.Allocator) void {
_ = allocator;
core.engine_log("shutting down [REND] module...", .{});
sgpu_renderer.shutdown();
}

View File

@ -0,0 +1,221 @@
// sdl3_gpu is like 8 characterso
// so instead of refering to it by it's full name every time
//
// we will just call it sgpu.
pub const Renderer = struct {
allocator: std.mem.Allocator,
totalTime: f64 = 0,
device: *gpu.GPUDevice = undefined,
shaderType: []const u8 = undefined,
shaderSuffix: []const u8 = undefined,
shaderformat: gpu.GPUShaderFormat = undefined,
entrypoint: []const u8 = "main",
pipeline: *gpu.GPUGraphicsPipeline = undefined,
scissor: gpu.Rect = .{ .x = 0, .y = 0, .w = 1600, .h = 900 },
colorBuffer: *gpu.GPUBuffer = undefined,
colorBufferTransfer: *gpu.GPUTransferBuffer = undefined,
window: *sdl3.Window = undefined,
pub var NeonObjectTable: core.EngineObjectVTable = core.EngineObjectVTable.from(@This());
pub fn init(allocator: std.mem.Allocator) !*@This() {
const self = try allocator.create(@This());
self.* = .{
.allocator = allocator,
};
core.registerRendererSetup(self, engineSetup);
return self;
}
pub fn engineSetup(p: *anyopaque) core.EngineDataEventError!void {
@as(*@This(), @ptrCast(@alignCast(p))).startRenderer() catch return error.BadInit;
}
pub fn startRenderer(self: *@This()) !void {
self.device = gpu.createGPUDevice(.{
.shaderformatSpirv = true,
.shaderformatDxil = true,
.shaderformatMsl = true,
}, false, null);
self.window = platform.getInstance().window;
if (!self.device.claimWindowForGPUDevice(self.window))
return error.UnableToClaimGpu;
try self.discoverFormats();
core.engine_log("sgpu device created, using shader format: {s}", .{self.shaderSuffix});
try self.createPipeline();
}
pub fn discoverFormats(self: *@This()) !void {
const formats = self.device.getGPUShaderFormats();
if (formats.shaderformatSpirv) {
self.shaderType = "spv"; // shaderformatSpirv
self.shaderSuffix = ".spv";
self.shaderformat = .{ .shaderformatSpirv = true };
} else if (formats.shaderformatMsl) {
self.shaderType = "msl"; // shaderformatSpirv
self.shaderSuffix = ".msl";
self.entrypoint = "main0";
self.shaderformat = .{ .shaderformatMsl = true };
} else if (formats.shaderformatDxil) {
self.shaderType = "dxil"; // shaderformatSpirv
self.shaderSuffix = ".dxil";
self.shaderformat = .{ .shaderformatDxil = true };
}
}
pub fn createPipeline(self: *@This()) !void {
const vertex = try self.loadShader("sample.vert", 0, 0, 1, 0);
const fragment = try self.loadShader("sample.frag", 0, 0, 0, 0);
var pci = std.mem.zeroes(gpu.GPUGraphicsPipelineCreateInfo);
pci.fragment_shader = fragment;
pci.vertex_shader = vertex;
pci.target_info.num_color_targets = 1;
pci.target_info.color_target_descriptions = &[_]gpu.GPUColorTargetDescription{
.{
.format = self.device.getGPUSwapchainTextureFormat(self.window),
.blend_state = std.mem.zeroes(gpu.GPUColorTargetBlendState),
},
};
pci.rasterizer_state.fill_mode = .fillmodeFill;
self.pipeline = self.device.createGPUGraphicsPipeline(&pci);
self.colorBuffer = self.device.createGPUBuffer(&.{
.usage = .{ .bufferusageVertex = true },
.size = 8192 * 2,
.props = 0,
});
self.colorBufferTransfer = self.device.createGPUTransferBuffer(&.{
.usage = .transferbufferusageUpload,
.size = 8192 * 2,
.props = 0,
});
}
pub fn loadShader(
self: *@This(),
shaderName: []const u8,
num_samplers: u32, // The number of samplers defined in the shader.
num_storage_textures: u32, // The number of storage textures defined in the shader.
num_storage_buffers: u32, // The number of storage buffers defined in the shader.
num_uniform_buffers: u32, // The number of uniform buffers defined in the shader.
) !*gpu.GPUShader {
const contentPath = try std.fmt.allocPrint(self.allocator, "_shaders/{s}/{s}{s}", .{ self.shaderType, shaderName, self.shaderSuffix });
defer self.allocator.free(contentPath);
const mapping = try core.fs().loadFile(contentPath);
defer core.fs().unmap(mapping);
var stage: gpu.GPUShaderStage = undefined;
if (std.mem.endsWith(u8, shaderName, ".vert")) {
stage = .shaderstageVertex;
} else if (std.mem.endsWith(u8, shaderName, ".frag")) {
stage = .shaderstageFragment;
} else {
return error.NotImplemented;
}
const sci = gpu.GPUShaderCreateInfo{
.code = @ptrCast(mapping.bytes.ptr),
.entrypoint = @ptrCast(self.entrypoint.ptr),
.format = self.shaderformat,
.code_size = mapping.bytes.len - 1,
.stage = stage,
.num_samplers = num_samplers,
.num_storage_textures = num_storage_textures, // The number of storage textures defined in the shader.
.num_storage_buffers = num_storage_buffers, // The number of storage buffers defined in the shader.
.num_uniform_buffers = num_uniform_buffers, // The number of uniform buffers defined in the shader.
.props = 0,
};
const rv = self.device.createGPUShader(&sci);
core.engine_log("creating shader {s} => {s} {any}", .{ shaderName, contentPath, stage });
return rv;
}
pub fn tick(self: *@This(), dt: f64) void {
self.totalTime += dt;
const cmd = self.device.acquireGPUCommandBuffer();
var swapchain_texture: *gpu.GPUTexture = undefined;
{
const buffer = self.device.mapGPUTransferBuffer(self.colorBufferTransfer, true);
var b: [*][4]f32 = @ptrCast(@alignCast(buffer));
b[0] = .{ @floatCast(std.math.sin(self.totalTime * 3 * 2 + 0.8) * 0.2 + 0.8), 0.4, 0.4, 1.0 };
b[1] = .{ 0.4, @floatCast(std.math.sin(self.totalTime * 2 * 2 + 0.3) * 0.2 + 0.8), 0.4, 1.0 };
b[2] = .{ 0.4, 0.4, @floatCast(std.math.sin(self.totalTime * 4 * 2) * 0.2 + 0.8), 1.0 };
self.device.unmapGPUTransferBuffer(self.colorBufferTransfer);
}
{
const copyPass = cmd.beginGPUCopyPass();
defer copyPass.endGPUCopyPass();
copyPass.uploadToGPUBuffer(&.{ .transfer_buffer = self.colorBufferTransfer, .offset = 0 }, &.{
.buffer = self.colorBuffer,
.offset = 0,
.size = 4 * 12,
}, true);
}
if (cmd.waitAndAcquireGPUSwapchainTexture(self.window, &swapchain_texture, null, null)) {
var targetInfo: gpu.GPUColorTargetInfo = std.mem.zeroes(gpu.GPUColorTargetInfo);
targetInfo.texture = swapchain_texture;
targetInfo.clear_color = .{ .r = 0.1, .g = 0.1, .b = 0.1, .a = 1.0 };
targetInfo.load_op = .loadopClear;
targetInfo.store_op = .storeopStore;
const renderpass = cmd.beginGPURenderPass(&targetInfo, 1, null);
renderpass.bindGPUGraphicsPipeline(self.pipeline);
renderpass.bindGPUVertexStorageBuffers(0, &self.colorBuffer, 1);
renderpass.setGPUScissor(&self.scissor);
renderpass.drawGPUPrimitives(3, 1, 0, 0);
renderpass.endGPURenderPass();
}
_ = cmd.submitGPUCommandBuffer();
}
pub fn deinit(self: *@This()) void {
self.allocator.destroy(self);
}
};
pub var gRenderer: *Renderer = undefined;
pub var gAllocator: std.mem.Allocator = undefined;
pub fn start() !void {
gRenderer = try core.createObject(Renderer, .{ .can_tick = true, .isCore = true });
gAllocator = gRenderer.allocator;
}
pub fn shutdown() void {}
const rend = @import("../rend.zig");
const std = @import("std");
const core = @import("core");
const platform = @import("platform");
const sdl3 = @import("sdl3");
const gpu = sdl3.gpu;
const SSBO_Scene = @import("sample.vert").Scene;

View File

@ -0,0 +1,10 @@
// renderer agnostic shader management
pub const loadShader = renderer.loadShader;
const renderer = @import("gpu/renderer");
const std = @import("std");
const core = @import("core");
const rend = @import("rend.zig");

View File

@ -46,7 +46,7 @@ pub fn startContext(self: *@This()) !void {
.shaderformatSpirv = true,
.shaderformatDxil = true,
.shaderformatMsl = true,
}, false, null);
}, true, null);
if (!self.device.claimWindowForGPUDevice(self.window))
return error.UnableToClaimGpu;