diff --git a/.gitignore b/.gitignore index 47e7af4..5858b8d 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,2 @@ .zig-cache/ zig-pkg/ -zig-out/ diff --git a/README.md b/README.md index fdca7bb..09c336e 100644 --- a/README.md +++ b/README.md @@ -44,5 +44,5 @@ src/rhi/vulkan/resource.zig ## Examples - ```zig build run-simple``` -- ```zig build run-3D``` - ```zig build run-imgui``` +- ```zig build run-3D``` diff --git a/build.zig b/build.zig index 5ec2c24..56cd08c 100644 --- a/build.zig +++ b/build.zig @@ -73,6 +73,8 @@ pub fn build(b: *std.Build) !void { mod.addImport("fast_obj", fast_obj.createModule()); mod.addCSourceFiles(.{ .files = &.{"src/vendor/fast_obj/fast_obj.c"} }); + const check_step = b.step("check", "Check if compiles"); + // // EXAMPLES // @@ -125,6 +127,11 @@ pub fn build(b: *std.Build) !void { example.root_module.addImport("gfx", mod); + const common = b.addModule("common", .{ + .root_source_file = b.path("examples/common.zig"), + }); + example.root_module.addImport("common", common); + const sdl = b.addTranslateC(.{ .target = target, .optimize = optimize, @@ -187,7 +194,6 @@ pub fn build(b: *std.Build) !void { const example_build_step = b.addInstallArtifact(example, .{}); example_step.dependOn(&example_build_step.step); - // const check_step = b.step("check", "Check if compiles"); - // check_step.dependOn(&example.step); + check_step.dependOn(&example.step); } } diff --git a/compile.sh b/compile.sh deleted file mode 100755 index 90ca2a6..0000000 --- a/compile.sh +++ /dev/null @@ -1,10 +0,0 @@ -clear - -glslc examples/assets/shaders/simple.vert -o examples/assets/shaders/compiled/simple.vert.spv -glslc examples/assets/shaders/simple.frag -o examples/assets/shaders/compiled/simple.frag.spv - -glslc examples/assets/shaders/3D.vert -o examples/assets/shaders/compiled/3D.vert.spv -glslc examples/assets/shaders/3D.frag -o examples/assets/shaders/compiled/3D.frag.spv - -glslc examples/assets/shaders/imgui.vert -o examples/assets/shaders/compiled/imgui.vert.spv -glslc examples/assets/shaders/imgui.frag -o examples/assets/shaders/compiled/imgui.frag.spv diff --git a/examples/assets/shaders/compiled/simple.vert.spv b/examples/assets/shaders/compiled/simple.vert.spv index 52c6643..4988259 100644 Binary files a/examples/assets/shaders/compiled/simple.vert.spv and b/examples/assets/shaders/compiled/simple.vert.spv differ diff --git a/examples/assets/shaders/simple.vert b/examples/assets/shaders/simple.vert index 6737479..54638dc 100644 --- a/examples/assets/shaders/simple.vert +++ b/examples/assets/shaders/simple.vert @@ -4,8 +4,8 @@ // IO // -layout(location = 0) in vec2 in_position; -layout(location = 1) in vec2 in_normal; +layout(location = 0) in vec3 in_position; +layout(location = 1) in vec3 in_normal; layout(location = 2) in vec2 in_UV; layout(location = 0) out vec2 out_UV; @@ -13,6 +13,6 @@ layout(location = 0) out vec2 out_UV; /// ---------------------------------------------------- /// ---------------------------------------------------- void main() { - gl_Position = vec4(in_position, 0.0, 1.0); + gl_Position = vec4(in_position, 1.0); out_UV = in_UV; } diff --git a/examples/common.zig b/examples/common.zig index e69de29..549a1d8 100644 --- a/examples/common.zig +++ b/examples/common.zig @@ -0,0 +1,85 @@ +/// ---------------------------------------------------- +/// ---------------------------------------------------- +pub const UnlitMaterial = struct { + albedo: [4]f32 = .{ 1, 1, 1, 1 }, +}; + +/// ---------------------------------------------------- +/// ---------------------------------------------------- +pub const Vertex = struct { + pos: [3]f32, + normal: [3]f32, + uv: [2]f32, +}; + +/// ---------------------------------------------------- +/// ---------------------------------------------------- +pub const Square = struct { + pub const vertices = [_]Vertex{ + .{ .pos = .{ -0.5, -0.5, 0 }, .normal = .{ 0, 0, 0 }, .uv = .{ 0, 0 } }, + .{ .pos = .{ 0.5, -0.5, 0 }, .normal = .{ 0, 0, 0 }, .uv = .{ 1, 0 } }, + .{ .pos = .{ 0.5, 0.5, 0 }, .normal = .{ 0, 0, 0 }, .uv = .{ 1, 1 } }, + .{ .pos = .{ -0.5, 0.5, 0 }, .normal = .{ 0, 0, 0 }, .uv = .{ 0, 1 } }, + }; + + pub const indices = [_]u32{ + 0, 1, 2, + 0, 2, 3, + }; +}; + +/// ---------------------------------------------------- +/// ---------------------------------------------------- +pub const Cube = struct { + pub const vertices = [_]Vertex{ + .{ .pos = .{ -0.5, -0.5, 0.5 }, .normal = .{ 0, 0, 1 }, .uv = .{ 0, 0 } }, + .{ .pos = .{ 0.5, -0.5, 0.5 }, .normal = .{ 0, 0, 1 }, .uv = .{ 1, 0 } }, + .{ .pos = .{ 0.5, 0.5, 0.5 }, .normal = .{ 0, 0, 1 }, .uv = .{ 1, 1 } }, + .{ .pos = .{ -0.5, 0.5, 0.5 }, .normal = .{ 0, 0, 1 }, .uv = .{ 0, 1 } }, + + .{ .pos = .{ 0.5, -0.5, -0.5 }, .normal = .{ 0, 0, -1 }, .uv = .{ 0, 0 } }, + .{ .pos = .{ -0.5, -0.5, -0.5 }, .normal = .{ 0, 0, -1 }, .uv = .{ 1, 0 } }, + .{ .pos = .{ -0.5, 0.5, -0.5 }, .normal = .{ 0, 0, -1 }, .uv = .{ 1, 1 } }, + .{ .pos = .{ 0.5, 0.5, -0.5 }, .normal = .{ 0, 0, -1 }, .uv = .{ 0, 1 } }, + + .{ .pos = .{ -0.5, -0.5, -0.5 }, .normal = .{ -1, 0, 0 }, .uv = .{ 0, 0 } }, + .{ .pos = .{ -0.5, -0.5, 0.5 }, .normal = .{ -1, 0, 0 }, .uv = .{ 1, 0 } }, + .{ .pos = .{ -0.5, 0.5, 0.5 }, .normal = .{ -1, 0, 0 }, .uv = .{ 1, 1 } }, + .{ .pos = .{ -0.5, 0.5, -0.5 }, .normal = .{ -1, 0, 0 }, .uv = .{ 0, 1 } }, + + .{ .pos = .{ 0.5, -0.5, 0.5 }, .normal = .{ 1, 0, 0 }, .uv = .{ 0, 0 } }, + .{ .pos = .{ 0.5, -0.5, -0.5 }, .normal = .{ 1, 0, 0 }, .uv = .{ 1, 0 } }, + .{ .pos = .{ 0.5, 0.5, -0.5 }, .normal = .{ 1, 0, 0 }, .uv = .{ 1, 1 } }, + .{ .pos = .{ 0.5, 0.5, 0.5 }, .normal = .{ 1, 0, 0 }, .uv = .{ 0, 1 } }, + + .{ .pos = .{ -0.5, 0.5, 0.5 }, .normal = .{ 0, 1, 0 }, .uv = .{ 0, 0 } }, + .{ .pos = .{ 0.5, 0.5, 0.5 }, .normal = .{ 0, 1, 0 }, .uv = .{ 1, 0 } }, + .{ .pos = .{ 0.5, 0.5, -0.5 }, .normal = .{ 0, 1, 0 }, .uv = .{ 1, 1 } }, + .{ .pos = .{ -0.5, 0.5, -0.5 }, .normal = .{ 0, 1, 0 }, .uv = .{ 0, 1 } }, + + .{ .pos = .{ -0.5, -0.5, -0.5 }, .normal = .{ 0, -1, 0 }, .uv = .{ 0, 0 } }, + .{ .pos = .{ 0.5, -0.5, -0.5 }, .normal = .{ 0, -1, 0 }, .uv = .{ 1, 0 } }, + .{ .pos = .{ 0.5, -0.5, 0.5 }, .normal = .{ 0, -1, 0 }, .uv = .{ 1, 1 } }, + .{ .pos = .{ -0.5, -0.5, 0.5 }, .normal = .{ 0, -1, 0 }, .uv = .{ 0, 1 } }, + }; + + pub const indices = [_]u32{ + 0, 1, 2, + 0, 2, 3, + + 4, 5, 6, + 4, 6, 7, + + 8, 9, 10, + 8, 10, 11, + + 12, 13, 14, + 12, 14, 15, + + 16, 17, 18, + 16, 18, 19, + + 20, 21, 22, + 20, 22, 23, + }; +}; diff --git a/examples/imgui/imgui.zig b/examples/imgui/imgui.zig index 621efca..6fde90d 100644 --- a/examples/imgui/imgui.zig +++ b/examples/imgui/imgui.zig @@ -37,19 +37,27 @@ pub fn main(init: std.process.Init) !void { // // --- # --- - var gfx: Gfx = try .init(.{ - .window = .{ - .xlib = .{ - .window = @intCast(xwindow), - .display = display.?, - }, - }, - }, init.gpa, init.io); + var gfx: Gfx = try .init( + init.gpa, + init.io, + ); defer gfx.deinit(); // --- # --- - const adapter = try gfx.makeAdapter(.{ .gpu_type = .any }); - const surface = try gfx.makeSurface(); + const instance = try gfx.makeInstance(.{ + .vulkan = .{ + .api_version = .v1_3, + }, + }); + + const surface = try gfx.makeSurface(.{ + .xlib = .{ + .window = @intCast(xwindow), + .display = display.?, + }, + }, instance); + + const adapter = try gfx.makeAdapter(.{}, instance); const device = try gfx.makeDevice(adapter, surface); const swapchain = try gfx.makeSwapchain(adapter, device, surface); @@ -65,6 +73,11 @@ pub fn main(init: std.process.Init) !void { if (!im_sdl.cImGui_ImplSDL3_InitForVulkan(@ptrCast(window))) return error.FailedToImplImGuiForSDL; defer im_sdl.cImGui_ImplSDL3_Shutdown(); + // --- SET IO --- + const io = im.ImGui_GetIO() orelse return error.FailedToGetImGuiIO; + io.*.ConfigFlags |= im.ImGuiConfigFlags_NavEnableKeyboard; + io.*.ConfigFlags |= im.ImGuiConfigFlags_DockingEnable; + // --- GET VK RAW DEVICE --- const raw_device = switch (try gfx.getRawDevice(device)) { .vulkan => |v| v, @@ -76,7 +89,7 @@ pub fn main(init: std.process.Init) !void { // --- INIT IMGUI FOR VK --- var color_format: im_vk.VkFormat = raw_swapchain.format; var im_info: im_vk.ImGui_ImplVulkan_InitInfo = .{ - .Instance = @ptrCast(gfx.getRawInstance().vulkan), + .Instance = @ptrCast((try gfx.getRawInstance(instance)).vulkan), .PhysicalDevice = blk: { switch (try gfx.getRawAdapter(adapter)) { .vulkan => |v| break :blk @ptrCast(v), diff --git a/examples/simple/README.md b/examples/simple/README.md new file mode 100644 index 0000000..d133520 --- /dev/null +++ b/examples/simple/README.md @@ -0,0 +1,3 @@ +# Simple Example + +![simple](image.png) diff --git a/examples/simple/image b/examples/simple/image new file mode 100644 index 0000000..3cdbcb8 Binary files /dev/null and b/examples/simple/image differ diff --git a/examples/simple/simple.zig b/examples/simple/simple.zig index 90bb019..7241d68 100644 --- a/examples/simple/simple.zig +++ b/examples/simple/simple.zig @@ -3,38 +3,9 @@ const std = @import("std"); const sdl = @import("sdl"); +const cmn = @import("common"); const Gfx = @import("gfx"); -/// ---------------------------------------------------- -/// ---------------------------------------------------- -const UnlitMaterial = struct { - albedo: [4]f32 = .{ 1, 1, 1, 1 }, -}; - -/// ---------------------------------------------------- -/// ---------------------------------------------------- -const Vertex = struct { - pos: [2]f32, - normal: [2]f32, - uv: [2]f32, -}; - -/// ---------------------------------------------------- -/// ---------------------------------------------------- -const vertices = [_]Vertex{ - .{ .pos = .{ -0.5, -0.5 }, .normal = .{ 0, 0 }, .uv = .{ 0, 0 } }, - .{ .pos = .{ 0.5, -0.5 }, .normal = .{ 0, 0 }, .uv = .{ 1, 0 } }, - .{ .pos = .{ 0.5, 0.5 }, .normal = .{ 0, 0 }, .uv = .{ 1, 1 } }, - .{ .pos = .{ -0.5, 0.5 }, .normal = .{ 0, 0 }, .uv = .{ 0, 1 } }, -}; - -/// ---------------------------------------------------- -/// ---------------------------------------------------- -const indices = [_]u32{ - 0, 1, 2, - 0, 2, 3, -}; - /// ---------------------------------------------------- /// ---------------------------------------------------- pub fn main(init: std.process.Init) !void { @@ -43,7 +14,7 @@ pub fn main(init: std.process.Init) !void { // DATA // - var material: UnlitMaterial = .{ .albedo = .{ 1.0, 0.2, 0.2, 1.0 } }; + var material: cmn.UnlitMaterial = .{ .albedo = .{ 1.0, 0.2, 0.2, 1.0 } }; // // SDL @@ -67,21 +38,27 @@ pub fn main(init: std.process.Init) !void { // // --- # --- - var gfx: Gfx = try .init(.{ - .window = .{ - .xlib = .{ - .window = @intCast(xwindow), - .display = display.?, - }, - }, - }, init.gpa, init.io); + var gfx: Gfx = try .init( + init.gpa, + init.io, + ); defer gfx.deinit(); - errdefer gfx.deinit(); - // --- # --- - const adapter = try gfx.makeAdapter(.{ .gpu_type = .any }); - const surface = try gfx.makeSurface(); + const instance = try gfx.makeInstance(.{ + .vulkan = .{ + .api_version = .v1_3, + }, + }); + + const surface = try gfx.makeSurface(.{ + .xlib = .{ + .window = @intCast(xwindow), + .display = display.?, + }, + }, instance); + + const adapter = try gfx.makeAdapter(.{}, instance); const device = try gfx.makeDevice(adapter, surface); const swapchain = try gfx.makeSwapchain(adapter, device, surface); @@ -92,8 +69,8 @@ pub fn main(init: std.process.Init) !void { }, adapter, device); // --- BUFFERS --- - const vbuf = try gfx.makeBuffer(vertices, .vertex, adapter, device); - const ibuf = try gfx.makeBuffer(indices, .index, adapter, device); + const vbuf = try gfx.makeBuffer(cmn.Square.vertices, .vertex, adapter, device); + const ibuf = try gfx.makeBuffer(cmn.Square.indices, .index, adapter, device); // --- SHADERS --- const simple_vert = try gfx.makeShader("examples/assets/shaders/compiled/simple.vert.spv", device); @@ -102,14 +79,14 @@ pub fn main(init: std.process.Init) !void { // --- PIPELINE --- const pipeline = try gfx.makePipeline(.{ .vertex_attributes = &.{ - .{ .location = 0, .format = .vec2, .offset = @offsetOf(Vertex, "pos") }, - .{ .location = 1, .format = .vec2, .offset = @offsetOf(Vertex, "normal") }, - .{ .location = 2, .format = .vec2, .offset = @offsetOf(Vertex, "uv") }, + .{ .location = 0, .format = .vec3, .offset = @offsetOf(cmn.Vertex, "pos") }, + .{ .location = 1, .format = .vec3, .offset = @offsetOf(cmn.Vertex, "normal") }, + .{ .location = 2, .format = .vec2, .offset = @offsetOf(cmn.Vertex, "uv") }, }, - .vertex_binding = .{ .stride = @sizeOf(Vertex) }, + .vertex_binding = .{ .stride = @sizeOf(cmn.Vertex) }, .uniforms = &.{ - .{ .name = "material", .size = @sizeOf(UnlitMaterial) }, + .{ .name = "material", .size = @sizeOf(cmn.UnlitMaterial) }, }, .textures = &.{ @@ -160,7 +137,7 @@ pub fn main(init: std.process.Init) !void { try ibuf.bind(); try pipeline.bind(); - pass.drawIndexed(indices.len, 1, 0, 0, 0); + pass.drawIndexed(cmn.Square.indices.len, 1, 0, 0, 0); } // --- NEW PASS --- diff --git a/examples/simple_3D/simple_3D.zig b/examples/simple_3D/simple_3D.zig index 14a898c..a0ff307 100644 --- a/examples/simple_3D/simple_3D.zig +++ b/examples/simple_3D/simple_3D.zig @@ -5,78 +5,9 @@ const vk = @import("vulkan"); const std = @import("std"); const sdl = @import("sdl"); const math = @import("math"); +const cmn = @import("common"); const Gfx = @import("gfx"); -/// ---------------------------------------------------- -/// ---------------------------------------------------- -const UnlitMaterial = struct { - albedo: [4]f32 = .{ 1, 1, 1, 1 }, -}; - -/// ---------------------------------------------------- -/// ---------------------------------------------------- -const Vertex = struct { - pos: [3]f32, - normal: [3]f32, - uv: [2]f32, -}; - -/// ---------------------------------------------------- -/// ---------------------------------------------------- -const vertices = [_]Vertex{ - .{ .pos = .{ -0.5, -0.5, 0.5 }, .normal = .{ 0, 0, 1 }, .uv = .{ 0, 0 } }, - .{ .pos = .{ 0.5, -0.5, 0.5 }, .normal = .{ 0, 0, 1 }, .uv = .{ 1, 0 } }, - .{ .pos = .{ 0.5, 0.5, 0.5 }, .normal = .{ 0, 0, 1 }, .uv = .{ 1, 1 } }, - .{ .pos = .{ -0.5, 0.5, 0.5 }, .normal = .{ 0, 0, 1 }, .uv = .{ 0, 1 } }, - - .{ .pos = .{ 0.5, -0.5, -0.5 }, .normal = .{ 0, 0, -1 }, .uv = .{ 0, 0 } }, - .{ .pos = .{ -0.5, -0.5, -0.5 }, .normal = .{ 0, 0, -1 }, .uv = .{ 1, 0 } }, - .{ .pos = .{ -0.5, 0.5, -0.5 }, .normal = .{ 0, 0, -1 }, .uv = .{ 1, 1 } }, - .{ .pos = .{ 0.5, 0.5, -0.5 }, .normal = .{ 0, 0, -1 }, .uv = .{ 0, 1 } }, - - .{ .pos = .{ -0.5, -0.5, -0.5 }, .normal = .{ -1, 0, 0 }, .uv = .{ 0, 0 } }, - .{ .pos = .{ -0.5, -0.5, 0.5 }, .normal = .{ -1, 0, 0 }, .uv = .{ 1, 0 } }, - .{ .pos = .{ -0.5, 0.5, 0.5 }, .normal = .{ -1, 0, 0 }, .uv = .{ 1, 1 } }, - .{ .pos = .{ -0.5, 0.5, -0.5 }, .normal = .{ -1, 0, 0 }, .uv = .{ 0, 1 } }, - - .{ .pos = .{ 0.5, -0.5, 0.5 }, .normal = .{ 1, 0, 0 }, .uv = .{ 0, 0 } }, - .{ .pos = .{ 0.5, -0.5, -0.5 }, .normal = .{ 1, 0, 0 }, .uv = .{ 1, 0 } }, - .{ .pos = .{ 0.5, 0.5, -0.5 }, .normal = .{ 1, 0, 0 }, .uv = .{ 1, 1 } }, - .{ .pos = .{ 0.5, 0.5, 0.5 }, .normal = .{ 1, 0, 0 }, .uv = .{ 0, 1 } }, - - .{ .pos = .{ -0.5, 0.5, 0.5 }, .normal = .{ 0, 1, 0 }, .uv = .{ 0, 0 } }, - .{ .pos = .{ 0.5, 0.5, 0.5 }, .normal = .{ 0, 1, 0 }, .uv = .{ 1, 0 } }, - .{ .pos = .{ 0.5, 0.5, -0.5 }, .normal = .{ 0, 1, 0 }, .uv = .{ 1, 1 } }, - .{ .pos = .{ -0.5, 0.5, -0.5 }, .normal = .{ 0, 1, 0 }, .uv = .{ 0, 1 } }, - - .{ .pos = .{ -0.5, -0.5, -0.5 }, .normal = .{ 0, -1, 0 }, .uv = .{ 0, 0 } }, - .{ .pos = .{ 0.5, -0.5, -0.5 }, .normal = .{ 0, -1, 0 }, .uv = .{ 1, 0 } }, - .{ .pos = .{ 0.5, -0.5, 0.5 }, .normal = .{ 0, -1, 0 }, .uv = .{ 1, 1 } }, - .{ .pos = .{ -0.5, -0.5, 0.5 }, .normal = .{ 0, -1, 0 }, .uv = .{ 0, 1 } }, -}; - -/// ---------------------------------------------------- -/// ---------------------------------------------------- -const indices = [_]u32{ - 0, 1, 2, - 0, 2, 3, - - 4, 5, 6, - 4, 6, 7, - - 8, 9, 10, - 8, 10, 11, - - 12, 13, 14, - 12, 14, 15, - - 16, 17, 18, - 16, 18, 19, - - 20, 21, 22, - 20, 22, 23, -}; - /// ---------------------------------------------------- /// ---------------------------------------------------- const Camera = struct { @@ -98,7 +29,7 @@ pub fn main(init: std.process.Init) !void { // DATA // - var material: UnlitMaterial = .{ .albedo = .{ 1.0, 0.2, 0.2, 1.0 } }; + var material: cmn.UnlitMaterial = .{ .albedo = .{ 1.0, 0.2, 0.2, 1.0 } }; const camera: Camera = .{ .projection = .perspective(std.math.degreesToRadians(90), 800.0 / 600.0, 0.01, 1000), .view = .lookAt(.new(.{ 1, 1, -2 }), .new(.{ 0, 0, 1 }), .new(.{ 0, 1, 0 })), @@ -138,23 +69,26 @@ pub fn main(init: std.process.Init) !void { // GFX // - // --- # --- - var gfx: Gfx = try .init(.{ - .window = .{ - .xlib = .{ - .window = @intCast(xwindow), - .display = display.?, - }, - }, - .backend = .vulkan, - }, init.gpa, init.io); + var gfx: Gfx = try .init( + init.gpa, + init.io, + ); defer gfx.deinit(); - errdefer gfx.deinit(); + const instance = try gfx.makeInstance(.{ + .vulkan = .{ + .api_version = .v1_3, + }, + }); - // --- # --- - const adapter = try gfx.makeAdapter(.{ .gpu_type = .any }); - const surface = try gfx.makeSurface(); + const surface = try gfx.makeSurface(.{ + .xlib = .{ + .window = @intCast(xwindow), + .display = display.?, + }, + }, instance); + + const adapter = try gfx.makeAdapter(.{}, instance); const device = try gfx.makeDevice(adapter, surface); const swapchain = try gfx.makeSwapchain(adapter, device, surface); @@ -169,8 +103,8 @@ pub fn main(init: std.process.Init) !void { }, adapter, device); // --- BUFFERS --- - const vbuf = try gfx.makeBuffer(vertices, .vertex, adapter, device); - const ibuf = try gfx.makeBuffer(indices, .index, adapter, device); + const vbuf = try gfx.makeBuffer(cmn.Cube.vertices, .vertex, adapter, device); + const ibuf = try gfx.makeBuffer(cmn.Cube.indices, .index, adapter, device); // --- SHADERS --- const simple_vert = try gfx.makeShader("examples/assets/shaders/compiled/3D.vert.spv", device); @@ -179,11 +113,11 @@ pub fn main(init: std.process.Init) !void { // --- PIPELINE --- const pipeline = try gfx.makePipeline(.{ .vertex_attributes = &.{ - .{ .location = 0, .format = .vec3, .offset = @offsetOf(Vertex, "pos") }, - .{ .location = 1, .format = .vec3, .offset = @offsetOf(Vertex, "normal") }, - .{ .location = 2, .format = .vec2, .offset = @offsetOf(Vertex, "uv") }, + .{ .location = 0, .format = .vec3, .offset = @offsetOf(cmn.Vertex, "pos") }, + .{ .location = 1, .format = .vec3, .offset = @offsetOf(cmn.Vertex, "normal") }, + .{ .location = 2, .format = .vec2, .offset = @offsetOf(cmn.Vertex, "uv") }, }, - .vertex_binding = .{ .stride = @sizeOf(Vertex) }, + .vertex_binding = .{ .stride = @sizeOf(cmn.Vertex) }, .uniforms = &.{ .{ .name = "camera", .size = @sizeOf(Camera) }, @@ -245,7 +179,7 @@ pub fn main(init: std.process.Init) !void { try ibuf.bind(); try pipeline.bind(); - pass.drawIndexed(indices.len, 1, 0, 0, 0); + pass.drawIndexed(cmn.Cube.indices.len, 1, 0, 0, 0); } // --- NEW PASS --- diff --git a/imgui.ini b/imgui.ini index b979702..fb2edcd 100644 --- a/imgui.ini +++ b/imgui.ini @@ -2,17 +2,37 @@ Pos=60,60 Size=400,400 Collapsed=0 -LastUsed=20260814 +LastUsed=20260818 [Window][Inspector] -Pos=25,55 -Size=341,210 +Pos=87,36 +Size=622,253 Collapsed=0 -LastUsed=20260814 +DockId=0x00000002,0 +LastUsed=20260818 [Window][Dear ImGui Demo] -Pos=416,63 -Size=305,363 +Pos=87,291 +Size=622,257 Collapsed=0 +DockId=0x00000003,0 +LastUsed=20260818 + +[Table][0x51D6F5EA,3] +Column 0 Weight=1.0000 +Column 1 Weight=1.0000 +Column 2 Weight=1.0000 LastUsed=20260814 +[Table][0xE102187A,3] +RefScale=13 +Column 0 Width=63 +Column 1 Width=63 +Column 2 Width=63 +LastUsed=20260814 + +[Docking][Data] +DockNode ID=0x00000001 Pos=87,36 Size=622,512 Split=Y + DockNode ID=0x00000002 Parent=0x00000001 SizeRef=361,237 Selected=0x36DC96AB + DockNode ID=0x00000003 Parent=0x00000001 SizeRef=361,241 Selected=0x5E5F7166 + diff --git a/src/gfx.zig b/src/gfx.zig index 073c3f6..d70cfa6 100644 --- a/src/gfx.zig +++ b/src/gfx.zig @@ -13,6 +13,7 @@ const Self = @This(); pub const Handle = gtl.Handle; // --- CONFIGS --- +pub const InstanceConfig = common.InstanceConfig; pub const AdapterConfig = common.AdapterConfig; pub const RenderPassConfig = common.RenderPassConfig; pub const PipelineConfig = common.PipelineConfig; @@ -23,6 +24,7 @@ pub const SamplerConfig = common.SamplerConfig; pub const TextureConfig = common.TextureConfig; // --- HANDLES --- +pub const Instance = common.Instance; pub const Window = common.Window; pub const Adapter = common.Adapter; pub const Device = common.Device; @@ -59,23 +61,11 @@ const BackendCTX = union(Backend) { vulkan: VulkanRHI, }; -/// ---------------------------------------------------- -/// ---------------------------------------------------- -pub const Config = struct { - app_name: []const u8 = "NYXGFX", - engine_name: []const u8 = "NYX", - enable_validation: bool = true, - - window: Window, - backend: Backend = .vulkan, -}; - // // FIELDS // -ctx: BackendCTX, -config: Config, +ctx: ?BackendCTX, alloc: std.mem.Allocator, io: std.Io, @@ -87,17 +77,11 @@ io: std.Io, /// ---------------------------------------------------- /// ---------------------------------------------------- pub fn init( - config: Config, alloc: std.mem.Allocator, io: std.Io, ) !Self { - const backend_ctx: BackendCTX = switch (config.backend) { - .vulkan => .{ .vulkan = try .init(config, alloc, io) }, - }; - return .{ - .config = config, - .ctx = backend_ctx, + .ctx = null, .alloc = alloc, .io = io, }; @@ -106,7 +90,7 @@ pub fn init( /// ---------------------------------------------------- /// ---------------------------------------------------- pub fn deinit(self: *Self) void { - switch (self.ctx) { + switch ((self.getBackend() catch return).*) { .vulkan => |*v| v.deinit(), } } @@ -117,16 +101,47 @@ pub fn deinit(self: *Self) void { /// ---------------------------------------------------- /// ---------------------------------------------------- -pub fn getRawInstance(self: *Self) RawInstance { - return switch (self.ctx) { - .vulkan => |*v| .{ .vulkan = v.instance.raw }, +pub fn makeInstance(self: *Self, config: InstanceConfig) !Handle(Instance) { + switch (config) { + .vulkan => |v| { + self.ctx = .{ + .vulkan = .init(self.alloc, self.io), + }; + return try self.ctx.?.vulkan.makeInstance(v); + }, + } +} + +/// ---------------------------------------------------- +/// ---------------------------------------------------- +pub fn deleteInstance(self: *Self, instance: Handle(Instance)) void { + switch ((self.getBackend() catch return).*) { + .vulkan => |*v| v.deleteInstance(instance), + } +} + +/// ---------------------------------------------------- +/// ---------------------------------------------------- +pub fn releaseInstance(self: *Self, instance: Handle(Instance)) void { + switch ((self.getBackend() catch return).*) { + .vulkan => |*v| v.releaseInstance(instance), + } +} + +/// ---------------------------------------------------- +/// ---------------------------------------------------- +pub fn getRawInstance(self: *Self, instance: Handle(Instance)) !RawInstance { + return switch ((try self.getBackend()).*) { + .vulkan => |*v| .{ + .vulkan = (v.resource.instances.get(instance) orelse return error.InstanceNotFound).raw, + }, }; } /// ---------------------------------------------------- /// ---------------------------------------------------- pub fn getRawFrame(self: *Self) !RawFrame { - switch (self.ctx) { + switch ((try self.getBackend()).*) { .vulkan => |*v| { const raw_frame = v.currentFrame(); return .{ @@ -147,16 +162,16 @@ pub fn getRawFrame(self: *Self) !RawFrame { /// ---------------------------------------------------- /// ---------------------------------------------------- -pub fn makeAdapter(self: *Self, config: AdapterConfig) !Handle(Adapter) { - return try switch (self.ctx) { - .vulkan => |*v| v.makeAdapter(config), +pub fn makeAdapter(self: *Self, config: AdapterConfig, instance: Handle(Instance)) !Handle(Adapter) { + return try switch ((try self.getBackend()).*) { + .vulkan => |*v| v.makeAdapter(config, instance), }; } /// ---------------------------------------------------- /// ---------------------------------------------------- pub fn deleteAdapter(self: *Self, adapter: Handle(Adapter)) void { - switch (self.ctx) { + switch ((try self.getBackend()).*) { .vulkan => |*v| v.deleteAdapter(adapter), } } @@ -164,7 +179,7 @@ pub fn deleteAdapter(self: *Self, adapter: Handle(Adapter)) void { /// ---------------------------------------------------- /// ---------------------------------------------------- pub fn releaseAdapter(self: *Self, adapter: Handle(Adapter)) void { - switch (self.ctx) { + switch ((try self.getBackend()).*) { .vulkan => |*v| v.releaseAdapter(adapter), } } @@ -172,7 +187,7 @@ pub fn releaseAdapter(self: *Self, adapter: Handle(Adapter)) void { /// ---------------------------------------------------- /// ---------------------------------------------------- pub fn getAdapterInfo(self: *Self, adapter: Handle(Adapter)) ?AdapterInfo { - return switch (self.ctx) { + return switch ((self.getBackend() catch return null).*) { .vulkan => |*v| v.getAdapterInfo(adapter), }; } @@ -180,7 +195,7 @@ pub fn getAdapterInfo(self: *Self, adapter: Handle(Adapter)) ?AdapterInfo { /// ---------------------------------------------------- /// ---------------------------------------------------- pub fn getRawAdapter(self: *Self, adapter: Handle(Adapter)) !RawAdapter { - return switch (self.ctx) { + return switch ((try self.getBackend()).*) { .vulkan => |*v| .{ .vulkan = try v.getRawAdapter(adapter) }, }; } @@ -196,7 +211,7 @@ pub fn makeDevice( adapter: Handle(Adapter), surface: Handle(Surface), ) !Handle(Device) { - return try switch (self.ctx) { + return try switch ((try self.getBackend()).*) { .vulkan => |*v| v.makeDevice(adapter, surface), }; } @@ -204,7 +219,7 @@ pub fn makeDevice( /// ---------------------------------------------------- /// ---------------------------------------------------- pub fn deleteDevice(self: *Self, device: Handle(Device)) void { - switch (self.ctx) { + switch ((try self.getBackend()).*) { .vulkan => |*v| v.deleteDevice(device), } } @@ -212,7 +227,7 @@ pub fn deleteDevice(self: *Self, device: Handle(Device)) void { /// ---------------------------------------------------- /// ---------------------------------------------------- pub fn releaseDevice(self: *Self, device: Handle(Device)) void { - switch (self.ctx) { + switch ((try self.getBackend()).*) { .vulkan => |*v| v.releaseDevice(device), } } @@ -220,12 +235,12 @@ pub fn releaseDevice(self: *Self, device: Handle(Device)) void { /// ---------------------------------------------------- /// ---------------------------------------------------- pub fn getRawDevice(self: *Self, device: Handle(Device)) !RawDevice { - switch (self.ctx) { + switch ((try self.getBackend()).*) { .vulkan => |*v| { const raw_device = v.resource.devices.get(device) orelse return error.DeviceNotFound; return .{ .vulkan = .{ - .device = raw_device.raw orelse return error.NullDevice, + .device = raw_device.raw, .graphics_queue = raw_device.graphics_queue, .present_queue = raw_device.present_queue, }, @@ -237,7 +252,7 @@ pub fn getRawDevice(self: *Self, device: Handle(Device)) !RawDevice { // /// ---------------------------------------------------- // /// ---------------------------------------------------- // pub fn getRawDevice(self: *Self, device: Handle(Device)) !RawDevice { -// return switch (self.ctx) { +// return switch ((try self.getBackend()).*) { // .vulkan => |*v| .{ .vulkan = try v.getRawDevice(device) }, // }; // } @@ -257,7 +272,7 @@ pub fn makeBuffer( ) !Buffer { const size = @sizeOf(@TypeOf(value)); - const handle = try switch (self.ctx) { + const handle = try switch ((try self.getBackend()).*) { .vulkan => |*v| v.makeBuffer(size, usage, .exclusive, adapter, device), }; @@ -274,7 +289,7 @@ pub fn makeBuffer( /// ---------------------------------------------------- /// ---------------------------------------------------- pub fn deleteBuffer(self: *Self, buffer: Handle(Buffer)) void { - switch (self.ctx) { + switch ((try self.getBackend()).*) { .vulkan => |*v| v.deleteBuffer(buffer), } } @@ -282,7 +297,7 @@ pub fn deleteBuffer(self: *Self, buffer: Handle(Buffer)) void { /// ---------------------------------------------------- /// ---------------------------------------------------- pub fn releaseBuffer(self: *Self, buffer: Handle(Buffer)) void { - switch (self.ctx) { + switch ((try self.getBackend()).*) { .vulkan => |*v| v.releaseBuffer(buffer), } } @@ -290,7 +305,7 @@ pub fn releaseBuffer(self: *Self, buffer: Handle(Buffer)) void { /// ---------------------------------------------------- /// ---------------------------------------------------- pub fn getRawBuffer(self: *Self, buffer: Handle(Buffer)) !RawBuffer { - return switch (self.ctx) { + return switch ((try self.getBackend()).*) { .vulkan => |*v| .{ .vulkan = try v.getRawBuffer(buffer) }, }; } @@ -301,9 +316,13 @@ pub fn getRawBuffer(self: *Self, buffer: Handle(Buffer)) !RawBuffer { /// ---------------------------------------------------- /// ---------------------------------------------------- -pub fn makeSurface(self: *Self) !Handle(Surface) { - return try switch (self.ctx) { - .vulkan => |*v| v.makeSurface(), +pub fn makeSurface( + self: *Self, + window: Window, + instance: Handle(Instance), +) !Handle(Surface) { + return try switch ((try self.getBackend()).*) { + .vulkan => |*v| v.makeSurface(instance, window), }; } @@ -319,7 +338,7 @@ pub fn makeSwapchain( device: Handle(Device), surface: Handle(Surface), ) !Handle(Swapchain) { - return try switch (self.ctx) { + return try switch ((try self.getBackend()).*) { .vulkan => |*v| v.makeSwapchain(adapter, device, surface), }; } @@ -327,7 +346,7 @@ pub fn makeSwapchain( /// ---------------------------------------------------- /// ---------------------------------------------------- pub fn getRawSwapchain(self: *Self, swapchain: Handle(Swapchain)) !*VKSwapchain { - return switch (self.ctx) { + return switch ((try self.getBackend()).*) { .vulkan => |*v| v.getRawSwapchain(swapchain), }; } @@ -343,7 +362,7 @@ pub fn makeShader( spv_path: []const u8, device: Handle(Device), ) !Handle(Shader) { - return try switch (self.ctx) { + return try switch ((try self.getBackend()).*) { .vulkan => |*v| v.makeShader(spv_path, device), }; } @@ -351,7 +370,7 @@ pub fn makeShader( /// ---------------------------------------------------- /// ---------------------------------------------------- pub fn deleteShader(self: *Self, shader: Handle(Shader)) void { - switch (self.ctx) { + switch ((try self.getBackend()).*) { .vulkan => |*v| v.deleteShader(shader), } } @@ -359,7 +378,7 @@ pub fn deleteShader(self: *Self, shader: Handle(Shader)) void { /// ---------------------------------------------------- /// ---------------------------------------------------- pub fn releaseShader(self: *Self, shader: Handle(Shader)) void { - switch (self.ctx) { + switch ((try self.getBackend()).*) { .vulkan => |*v| v.releaseShader(shader), } } @@ -367,7 +386,7 @@ pub fn releaseShader(self: *Self, shader: Handle(Shader)) void { /// ---------------------------------------------------- /// ---------------------------------------------------- pub fn getRawShader(self: *Self, shader: Handle(Shader)) !RawShader { - return switch (self.ctx) { + return switch ((try self.getBackend()).*) { .vulkan => |*v| .{ .vulkan = try v.getRawShader(shader) }, }; } @@ -379,7 +398,7 @@ pub fn getRawShader(self: *Self, shader: Handle(Shader)) !RawShader { /// ---------------------------------------------------- pub fn makePipeline(self: *Self, config: PipelineConfig) !Pipeline { return .{ - .handle = try switch (self.ctx) { + .handle = try switch ((try self.getBackend()).*) { .vulkan => |*v| v.makePipeline(config), }, .device = config.device, @@ -390,7 +409,7 @@ pub fn makePipeline(self: *Self, config: PipelineConfig) !Pipeline { /// ---------------------------------------------------- /// ---------------------------------------------------- pub fn deletePipeline(self: *Self, pipeline: Handle(Pipeline)) void { - switch (self.ctx) { + switch ((try self.getBackend()).*) { .vulkan => |*v| v.deletePipeline(pipeline), } } @@ -398,7 +417,7 @@ pub fn deletePipeline(self: *Self, pipeline: Handle(Pipeline)) void { /// ---------------------------------------------------- /// ---------------------------------------------------- pub fn releasePipeline(self: *Self, pipeline: Handle(Pipeline)) void { - switch (self.ctx) { + switch ((try self.getBackend()).*) { .vulkan => |*v| v.releasePipeline(pipeline), } } @@ -406,18 +425,18 @@ pub fn releasePipeline(self: *Self, pipeline: Handle(Pipeline)) void { /// ---------------------------------------------------- /// ---------------------------------------------------- pub fn getRawPipeline(self: *Self, pipeline: Handle(Pipeline)) !RawPipeline { - switch (self.ctx) { + switch ((try self.getBackend()).*) { .vulkan => |*v| { const raw_pipe = v.resource.pipelines.get(pipeline) orelse return error.PipelineNotFound; return .{ .vulkan = .{ - .pipeline = raw_pipe.raw orelse return error.NullPipeline, - .descriptor_pool = raw_pipe.descriptor_pool orelse return error.NullDescriptorPool, + .pipeline = raw_pipe.raw, + .descriptor_pool = raw_pipe.descriptor_pool, }, }; }, } - // return switch (self.ctx) { + // return switch ((try self.getBackend()).*) { // .vulkan => |*v| .{ .vulkan = try v.getRawPipeline(pipeline) }, // }; } @@ -434,7 +453,7 @@ pub fn makeImage( adapter: Handle(Adapter), device: Handle(Device), ) !Handle(Image) { - return try switch (self.ctx) { + return try switch ((try self.getBackend()).*) { .vulkan => |*v| v.makeImage(config, adapter, device), }; } @@ -446,7 +465,7 @@ pub fn makeSampler( config: SamplerConfig, device: Handle(Device), ) !Handle(Sampler) { - return try switch (self.ctx) { + return try switch ((try self.getBackend()).*) { .vulkan => |*v| v.makeSampler(config, device), }; } @@ -459,7 +478,7 @@ pub fn makeTexture( adapter: Handle(Adapter), device: Handle(Device), ) !Handle(Texture) { - return try switch (self.ctx) { + return try switch ((try self.getBackend()).*) { .vulkan => |*v| v.makeTexture(config, adapter, device), }; } @@ -475,7 +494,7 @@ pub fn beginFrame( swapchain: Handle(Swapchain), device: Handle(Device), ) !void { - try switch (self.ctx) { + try switch ((try self.getBackend()).*) { .vulkan => |*v| v.beginFrame(swapchain, device), }; } @@ -487,7 +506,7 @@ pub fn endFrame( swapchain: Handle(Swapchain), device: Handle(Device), ) !void { - try switch (self.ctx) { + try switch ((try self.getBackend()).*) { .vulkan => |*v| v.endFrame(swapchain, device), }; } @@ -499,7 +518,7 @@ pub fn beginPass( swapchain: Handle(Swapchain), config: RenderPassConfig, ) ?Pass { - switch (self.ctx) { + switch ((self.getBackend() catch return null).*) { .vulkan => |*v| v.beginPass(swapchain, config) catch return null, } @@ -508,3 +527,10 @@ pub fn beginPass( .gfx = self, }; } + +/// ---------------------------------------------------- +/// ---------------------------------------------------- +pub fn getBackend(self: *Self) !*BackendCTX { + if (self.ctx) |*ctx| return ctx; + return error.BackendNotInitialized; +} diff --git a/src/rhi/common.zig b/src/rhi/common.zig index 365bd99..b0b2129 100644 --- a/src/rhi/common.zig +++ b/src/rhi/common.zig @@ -7,12 +7,47 @@ const gtl = @import("gtl"); const Gfx = @import("../gfx.zig"); const Handle = gtl.Handle; -// TODO: Organize these into categories... someday - -/// ---------------------------------------------------- -/// ---------------------------------------------------- pub const Backend = enum { vulkan }; +pub const VKAPIVersion = enum { + v1_0, + v1_1, + v1_2, + v1_3, + v1_4, +}; + +pub const VK11Features = struct { + shader_draw_parameters: bool = true, +}; + +pub const VK13Features = struct { + dynamic_rendering: bool = true, + synchronization2: bool = true, +}; + +pub const VK14Features = struct { + dynamic_rendering_local_read: bool = true, +}; + +pub const DeviceType = enum { + discrete, + integrated, + software, +}; + +pub const VKInstanceConfig = struct { + api_version: VKAPIVersion = .v1_3, + + vk_11_features: VK11Features = .{}, + vk_13_features: VK13Features = .{}, + vk_14_features: VK14Features = .{}, +}; + +pub const InstanceConfig = union(Backend) { + vulkan: VKInstanceConfig, +}; + // // RAW // @@ -67,7 +102,7 @@ pub const RawPipeline = union(Backend) { /// ---------------------------------------------------- pub const AdapterInfo = struct { name: [256]u8, - gpu_type: GPUType, + gpu_type: DeviceType, device_id: u32, vendor_id: u32, @@ -97,24 +132,10 @@ pub const Window = union(enum) { }, }; -/// ---------------------------------------------------- -/// ---------------------------------------------------- -pub const GPUType = enum { - any, - discrete, - integrated, - software, -}; - /// ---------------------------------------------------- /// ---------------------------------------------------- pub const AdapterConfig = struct { - /// Preferred class of GPU - /// `.any` disables filtering by class - gpu_type: GPUType = .discrete, - - /// Select the adapter at a specific enumeration index - /// `null` picks the first suitable one + device_type: DeviceType = .discrete, index: ?u32 = null, }; @@ -184,12 +205,25 @@ pub const DepthFormat = enum { d32_sfloat, }; +/// ---------------------------------------------------- +/// TODO: Mabe mabe use this for slang shader +/// ---------------------------------------------------- +pub const ShaderDescriptor = struct { + shaders: []const Handle(Shader), + + vert_entry_point_name: ?[]const u8 = null, + frag_entry_point_name: ?[]const u8 = null, +}; + /// ---------------------------------------------------- /// ---------------------------------------------------- pub const PipelineConfig = struct { vert_shader: Handle(Shader), frag_shader: Handle(Shader), + vert_entry_point_name: ?[]const u8 = null, + frag_entry_point_name: ?[]const u8 = null, + swapchain: Handle(Swapchain), device: Handle(Device), @@ -236,7 +270,7 @@ pub const Pass = struct { /// ---------------------------------------------------- /// ---------------------------------------------------- pub fn end(self: *const Pass) void { - switch (self.gfx.ctx) { + switch ((self.gfx.getBackend() catch return).*) { .vulkan => |*v| v.endPass(self.swapchain), } } @@ -244,7 +278,7 @@ pub const Pass = struct { /// ---------------------------------------------------- /// ---------------------------------------------------- pub fn draw(self: *const Pass, vertex_count: u32, instance_count: u32, first_vertex: u32, first_instance: u32) void { - switch (self.gfx.ctx) { + switch ((self.gfx.getBackend() catch return).*) { .vulkan => |*v| v.draw(vertex_count, instance_count, first_vertex, first_instance), } } @@ -252,7 +286,7 @@ pub const Pass = struct { /// ---------------------------------------------------- /// ---------------------------------------------------- pub fn drawIndexed(self: *const Pass, index_count: u32, instance_count: u32, first_index: u32, vertex_offset: i32, first_instance: u32) void { - switch (self.gfx.ctx) { + switch ((self.gfx.getBackend() catch return).*) { .vulkan => |*v| v.drawIndexed(index_count, instance_count, first_index, vertex_offset, first_instance), } } @@ -278,6 +312,9 @@ pub const StoreOp = enum { pub const RenderPassConfig = struct { clear_color: [4]f32 = .{ 0.0, 0.0, 0.0, 1.0 }, + /// Optional texture to render into instead of the swapchain image + render_target: ?Handle(Texture) = null, + depth_enabled: bool = false, depth_format: DepthFormat = .d32_sfloat, depth_load_op: LoadOp = .clear, @@ -390,6 +427,7 @@ pub const TextureConfig = struct { // HANDLE TYPES // +pub const Instance = struct {}; pub const Adapter = struct {}; pub const Device = struct {}; @@ -402,7 +440,7 @@ pub const Buffer = struct { gfx: *Gfx, pub fn set(self: *const Buffer, value: anytype) !void { - switch (self.gfx.ctx) { + switch ((try self.gfx.getBackend()).*) { .vulkan => |*v| { const raw = v.resource.buffers.get(self.handle) orelse return error.BufferNotFound; try raw.set(value, @sizeOf(@TypeOf(value))); @@ -411,7 +449,7 @@ pub const Buffer = struct { } pub fn bind(self: *const Buffer) !void { - switch (self.gfx.ctx) { + switch ((try self.gfx.getBackend()).*) { .vulkan => |*v| try v.bindBuffer(self.handle), } } @@ -431,13 +469,13 @@ pub const Pipeline = struct { gfx: *Gfx, pub fn bind(self: *const Pipeline) !void { - try switch (self.gfx.ctx) { + try switch ((try self.gfx.getBackend()).*) { .vulkan => |*v| v.bindPipeline(self.handle), }; } pub fn setUniform(self: *const Pipeline, name: []const u8, value: anytype) !void { - try switch (self.gfx.ctx) { + try switch ((try self.gfx.getBackend()).*) { .vulkan => |*v| v.setUniform(self.handle, name, value), }; } diff --git a/src/rhi/vulkan/resource.zig b/src/rhi/vulkan/resource.zig index 57c047a..82fea19 100644 --- a/src/rhi/vulkan/resource.zig +++ b/src/rhi/vulkan/resource.zig @@ -5,9 +5,12 @@ const vk = @import("vulkan"); const std = @import("std"); const gtl = @import("gtl"); const common = @import("../common.zig"); -const Instance = @import("instance.zig"); +const Handle = gtl.Handle; const Self = @This(); +const Instance = common.Instance; +const VKInstance = @import("resource/instance.zig"); + const Adapter = common.Adapter; const VKAdapter = @import("resource/adapter.zig"); @@ -43,6 +46,8 @@ const VKTexture = @import("resource/texture.zig"); // FIELDS // +instances: gtl.ResourceMap(Instance, VKInstance), + adapters: gtl.ResourceMap(Adapter, VKAdapter), devices: gtl.ResourceMap(Device, VKDevice), @@ -58,10 +63,14 @@ textures: gtl.ResourceMap(Texture, VKTexture), shaders: gtl.ResourceMap(Shader, VKShader), pipelines: gtl.ResourceMap(Pipeline, VKPipeline), +current_instance: ?Handle(Instance) = null, + /// ---------------------------------------------------- /// ---------------------------------------------------- pub fn init(alloc: std.mem.Allocator) Self { return .{ + .instances = .init(alloc), + .adapters = .init(alloc), .devices = .init(alloc), @@ -81,10 +90,7 @@ pub fn init(alloc: std.mem.Allocator) Self { /// ---------------------------------------------------- /// ---------------------------------------------------- -pub fn deinit( - self: *Self, - instance: *Instance, -) void { +pub fn deinit(self: *Self) void { { // FREE SWAPCHAINS var it = self.swapchains.valueIterator(); while (it.next()) |v| { @@ -96,6 +102,7 @@ pub fn deinit( { // FREE SURFACES var it = self.surfaces.valueIterator(); while (it.next()) |v| { + const instance = if (self.current_instance) |h| self.instances.get(h) orelse break else break; v.deinit(instance); } self.surfaces.deinit(); @@ -160,4 +167,12 @@ pub fn deinit( } self.devices.deinit(); } + + { // FREE INSTANCES + var it = self.instances.valueIterator(); + while (it.next()) |v| { + v.deinit(); + } + self.instances.deinit(); + } } diff --git a/src/rhi/vulkan/resource/adapter.zig b/src/rhi/vulkan/resource/adapter.zig index fbf8930..71fe08a 100644 --- a/src/rhi/vulkan/resource/adapter.zig +++ b/src/rhi/vulkan/resource/adapter.zig @@ -8,9 +8,11 @@ const vk = @import("vulkan"); const common = @import("../../common.zig"); const VKBackend = @import("../vulkan.zig"); const AdapterConfig = common.AdapterConfig; -const GPUType = common.GPUType; +const DeviceType = common.DeviceType; const Self = @This(); +const Instance = @import("instance.zig"); + // // FIELDS // @@ -19,49 +21,124 @@ raw: *vk.VkPhysicalDevice_T, /// ---------------------------------------------------- /// ---------------------------------------------------- -pub fn init(backend: *const VKBackend, config: AdapterConfig) !Self { - var physical: vk.VkPhysicalDevice = null; +pub fn init( + config: AdapterConfig, + instance: *const Instance, + alloc: std.mem.Allocator, +) !Self { + // --- GET ADAPTER COUNT --- var count: u32 = 0; + if (vk.vkEnumeratePhysicalDevices(instance.raw, &count, null) != vk.VK_SUCCESS) {} - // --- GET PHYSICAL DEVICES COUNT --- - if (vk.vkEnumeratePhysicalDevices(backend.instance.raw, &count, null) != vk.VK_SUCCESS) { - return error.FailedToEnumeratePhysicalDevices; - } - if (count == 0) { - return error.FailedToFindGPUWithVKSupport; - } + // --- CREATE LIST OF ADAPTERS --- + const items = try alloc.alloc(vk.VkPhysicalDevice, count); + defer alloc.free(items); - // --- # --- - const devices = try backend.alloc.alloc(vk.VkPhysicalDevice, count); - defer backend.alloc.free(devices); + // --- POPULATE ADAPTERS LIST --- + if (vk.vkEnumeratePhysicalDevices(instance.raw, &count, items.ptr) != vk.VK_SUCCESS) {} - // --- GET PHYSICAL DEVICES --- - if (vk.vkEnumeratePhysicalDevices(backend.instance.raw, &count, devices.ptr) != vk.VK_SUCCESS) { - return error.FailedToEnumeratePhysicalDevices; - } + // --- CHECK ADAPTER --- + var raw: vk.VkPhysicalDevice = null; + for (items) |adapter| { + var props: vk.VkPhysicalDeviceProperties2 = .{ + .sType = vk.VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2, + }; - // --- CHECK WHICH DEVICE IS SUITABLE --- - for (devices, 0..) |device, i| { - if (config.index) |index| { - if (index != i) continue; + var features14: vk.VkPhysicalDeviceVulkan14Features = .{ + .sType = vk.VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_4_FEATURES, + }; + + var features13: vk.VkPhysicalDeviceVulkan13Features = .{ + .sType = vk.VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_3_FEATURES, + .pNext = &features14, + }; + + var features12: vk.VkPhysicalDeviceVulkan12Features = .{ + .sType = vk.VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_2_FEATURES, + .pNext = &features13, + }; + + var features11: vk.VkPhysicalDeviceVulkan11Features = .{ + .sType = vk.VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_1_FEATURES, + .pNext = &features12, + }; + + var features: vk.VkPhysicalDeviceFeatures2 = .{ + .sType = vk.VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2, + .pNext = &features11, + }; + + vk.vkGetPhysicalDeviceProperties2(adapter, &props); + vk.vkGetPhysicalDeviceFeatures2(adapter, &features); + + const api_version: u32 = switch (instance.api_version) { + .v1_0 => vk.VK_API_VERSION_1_0, + .v1_1 => vk.VK_API_VERSION_1_1, + .v1_2 => vk.VK_API_VERSION_1_2, + .v1_3 => vk.VK_API_VERSION_1_3, + .v1_4 => vk.VK_API_VERSION_1_4, + }; + + const adapter_type: DeviceType = switch (props.properties.deviceType) { + vk.VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU => .discrete, + vk.VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU => .integrated, + vk.VK_PHYSICAL_DEVICE_TYPE_CPU => .software, + else => return error.UnknownDeviceType, + }; + + if (props.properties.apiVersion <= api_version) { + gtl.log.warn("{s} does not support {s} Vulkan API!\n", .{ + props.properties.deviceName, + @tagName(instance.api_version), + }, null); + continue; } - if (try isDeviceSuitable(device, config.gpu_type)) { - physical = device; - break; + + if (config.device_type != adapter_type) continue; + + if (instance.vk_11_features.shader_draw_parameters and features11.shaderDrawParameters != vk.VK_TRUE) { + gtl.log.warn("{s} does not support {s} feature!\n", .{ + props.properties.deviceName, + "shader_draw_parameters", + }, null); + continue; } - } - if (physical == null) { - return error.FailedToFindSuitableDevice; + + if (instance.vk_13_features.dynamic_rendering and features13.dynamicRendering != vk.VK_TRUE) { + gtl.log.warn("{s} does not support {s} feature!\n", .{ + props.properties.deviceName, + "dynamic_rendering", + }, null); + continue; + } + + if (instance.vk_13_features.synchronization2 and features13.synchronization2 != vk.VK_TRUE) { + gtl.log.warn("{s} does not support {s} feature!\n", .{ + props.properties.deviceName, + "synchronization2", + }, null); + continue; + } + + if (instance.vk_14_features.dynamic_rendering_local_read and features14.dynamicRenderingLocalRead != vk.VK_TRUE) { + gtl.log.warn("{s} does not support {s} feature!\n", .{ + props.properties.deviceName, + "dynamic_rendering_local_read", + }, null); + continue; + } + + raw = adapter; } // --- FIND GFX QUEUE FAMILY --- var queue_family_index: u32 = 0; - if (!try findGraphicsQueueFamily(physical, backend.alloc, &queue_family_index)) { + if (!try findGraphicsQueueFamily(raw, alloc, &queue_family_index)) { return error.FailedToFindGraphicsQueueFamily; } return .{ - .raw = physical.?, + .raw = raw orelse return error.FailedToFindProperAdapter, }; } @@ -89,22 +166,3 @@ fn findGraphicsQueueFamily( return false; } - -/// ---------------------------------------------------- -/// ---------------------------------------------------- -fn isDeviceSuitable(device: vk.VkPhysicalDevice, gpu_type: GPUType) !bool { - var properties: vk.VkPhysicalDeviceProperties = .{}; - vk.vkGetPhysicalDeviceProperties(device, &properties); - - var features: vk.VkPhysicalDeviceFeatures = .{}; - vk.vkGetPhysicalDeviceFeatures(device, &features); - - const matches_class = switch (gpu_type) { - .any => true, - .discrete => properties.deviceType == vk.VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU, - .integrated => properties.deviceType == vk.VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU, - .software => properties.deviceType == vk.VK_PHYSICAL_DEVICE_TYPE_CPU, - }; - - return matches_class and features.geometryShader == 1; -} diff --git a/src/rhi/vulkan/resource/device.zig b/src/rhi/vulkan/resource/device.zig index d6a0901..6f0b866 100644 --- a/src/rhi/vulkan/resource/device.zig +++ b/src/rhi/vulkan/resource/device.zig @@ -19,11 +19,11 @@ pub const QueueFamilies = struct { // FIELDS // -raw: vk.VkDevice, -physical_device: vk.VkPhysicalDevice, +raw: *vk.VkDevice_T, +physical_device: *vk.VkPhysicalDevice_T, graphics_queue: *vk.VkQueue_T, present_queue: *vk.VkQueue_T, -graphics_command_pool: vk.VkCommandPool, +graphics_command_pool: *vk.VkCommandPool_T, /// ---------------------------------------------------- /// ---------------------------------------------------- @@ -109,26 +109,19 @@ pub fn init( vk.vkGetDeviceQueue(device, queue_families.present.?, 0, &present_queue); return .{ - .raw = device, + .raw = device.?, .physical_device = adapter.raw, .graphics_queue = graphics_queue.?, .present_queue = present_queue.?, - .graphics_command_pool = graphics_command_pool, + .graphics_command_pool = graphics_command_pool.?, }; } /// ---------------------------------------------------- /// ---------------------------------------------------- pub fn deinit(self: *Self) void { - if (self.graphics_command_pool) |raw| { - vk.vkDestroyCommandPool(self.raw, raw, null); - self.graphics_command_pool = null; - } - - if (self.raw) |raw| { - vk.vkDestroyDevice(raw, null); - self.raw = null; - } + vk.vkDestroyCommandPool(self.raw, self.graphics_command_pool, null); + vk.vkDestroyDevice(self.raw, null); } /// ---------------------------------------------------- diff --git a/src/rhi/vulkan/resource/image.zig b/src/rhi/vulkan/resource/image.zig index f31c59e..3d86641 100644 --- a/src/rhi/vulkan/resource/image.zig +++ b/src/rhi/vulkan/resource/image.zig @@ -44,28 +44,36 @@ pub fn init( errdefer self.deinit(); // --- DECODE PIXELS --- + var pixels: ?[]const u8 = null; var loaded: ?[*]u8 = null; - var pixels: []const u8 = undefined; var tex_size: [2]i32 = .{ 0, 0 }; - if (config.path) |path| { - var tex_channel: i32 = 0; - stb.stbi_set_flip_vertically_on_load(@intFromBool(config.vertical_flip)); - const data = stb.stbi_load(path.ptr, &tex_size[0], &tex_size[1], &tex_channel, stb.STBI_rgb_alpha) orelse { - return error.FileNotFound; - }; - loaded = data; - pixels = data[0..@as(usize, @intCast(tex_size[0] * tex_size[1] * 4))]; - } else if (config.data) |data| { - pixels = data; - } else { - return error.MissingImageSource; + const needs_pixels = config.usage == .texture; + + if (needs_pixels) { + if (config.path) |path| { + var tex_channel: i32 = 0; + stb.stbi_set_flip_vertically_on_load(@intFromBool(config.vertical_flip)); + const data = stb.stbi_load(path.ptr, &tex_size[0], &tex_size[1], &tex_channel, stb.STBI_rgb_alpha) orelse { + return error.FileNotFound; + }; + loaded = data; + pixels = data[0..@as(usize, @intCast(tex_size[0] * tex_size[1] * 4))]; + } else if (config.data) |data| { + pixels = data; + } else { + return error.MissingImageSource; + } } defer if (loaded) |data| stb.stbi_image_free(data); // --- SIZE --- const size: [2]u32 = blk: { - if (config.path) |_| break :blk .{ @intCast(tex_size[0]), @intCast(tex_size[1]) }; + if (needs_pixels) { + if (config.path) |_| break :blk .{ @intCast(tex_size[0]), @intCast(tex_size[1]) }; + if (config.size) |size| break :blk size; + return error.SizeRequired; + } if (config.size) |size| break :blk size; return error.SizeRequired; }; @@ -132,7 +140,9 @@ pub fn init( _ = vk.vkBindImageMemory(device.raw, self.raw, self.memory, 0); // --- UPLOAD --- - try uploadPixels(&self, pixels); + if (needs_pixels) { + try uploadPixels(&self, pixels.?); + } // --- DEFAULT IMAGE VIEW --- var view_create_info: vk.VkImageViewCreateInfo = .{ diff --git a/src/rhi/vulkan/instance.zig b/src/rhi/vulkan/resource/instance.zig similarity index 76% rename from src/rhi/vulkan/instance.zig rename to src/rhi/vulkan/resource/instance.zig index 5d32825..e932a4a 100644 --- a/src/rhi/vulkan/instance.zig +++ b/src/rhi/vulkan/resource/instance.zig @@ -2,14 +2,14 @@ //! `🗲` Vulkan Instance `🗲` //! ---------------------------------------------------- -const std = @import("std"); -const gtl = @import("gtl"); const vk = @import("vulkan"); -const Resource = @import("resource.zig"); -const Window = @import("../common.zig").Window; -const MainConfig = @import("../../gfx.zig").Config; +const std = @import("std"); +const cmn = @import("../../common.zig"); +const gtl = @import("gtl"); const Self = @This(); +const Window = cmn.Window; + // // FIELDS // @@ -18,26 +18,39 @@ raw: *vk.VkInstance_T, messenger: ?vk.VkDebugUtilsMessengerEXT = null, pfn_destroy_debug_utils_messenger: vk.PFN_vkDestroyDebugUtilsMessengerEXT = null, +api_version: cmn.VKAPIVersion, +vk_11_features: cmn.VK11Features, +vk_13_features: cmn.VK13Features, +vk_14_features: cmn.VK14Features, + /// ---------------------------------------------------- /// ---------------------------------------------------- -pub fn init( - config: MainConfig, - alloc: std.mem.Allocator, -) !Self { +pub fn init(config: cmn.VKInstanceConfig, alloc: std.mem.Allocator) !Self { const validation_layers: []const [*:0]const u8 = &.{ "VK_LAYER_KHRONOS_validation", }; - const extensions = getWindowExtensions( - config.window, - config.enable_validation, - ); + const extensions: []const [*:0]const u8 = &.{ + "VK_KHR_surface", "VK_KHR_xlib_surface", "VK_EXT_debug_utils", + }; + + // const extensions = getWindowExtensions( + // config.window, + // config.enable_validation, + // ); var app_info: vk.VkApplicationInfo = .{ .sType = vk.VK_STRUCTURE_TYPE_APPLICATION_INFO, - .pApplicationName = config.app_name.ptr, - .pEngineName = config.engine_name.ptr, - .apiVersion = vk.VK_API_VERSION_1_3, + // TODO: + // .pApplicationName = config.app_name.ptr, + // .pEngineName = config.engine_name.ptr, + .apiVersion = switch (config.api_version) { + .v1_0 => vk.VK_API_VERSION_1_0, + .v1_1 => vk.VK_API_VERSION_1_1, + .v1_2 => vk.VK_API_VERSION_1_2, + .v1_3 => vk.VK_API_VERSION_1_3, + .v1_4 => vk.VK_API_VERSION_1_4, + }, }; var messenger_info: vk.VkDebugUtilsMessengerCreateInfoEXT = undefined; @@ -49,18 +62,18 @@ pub fn init( .ppEnabledExtensionNames = extensions.ptr, }; - if (config.enable_validation) { - if (!try checkValidationLayerSupport(validation_layers, alloc)) { - return error.ValidationLayerNotAvailable; - } - - create_info.enabledLayerCount = @intCast(validation_layers.len); - create_info.ppEnabledLayerNames = validation_layers.ptr; - - messenger_info = makeMessengerInfo(); - create_info.pNext = &messenger_info; + // if (config.enable_validation) { + if (!try checkValidationLayerSupport(validation_layers, alloc)) { + return error.ValidationLayerNotAvailable; } + create_info.enabledLayerCount = @intCast(validation_layers.len); + create_info.ppEnabledLayerNames = validation_layers.ptr; + + messenger_info = makeMessengerInfo(); + create_info.pNext = &messenger_info; + // } + var instance: vk.VkInstance = null; if (vk.vkCreateInstance(&create_info, null, &instance) != vk.VK_SUCCESS) { return error.FailedToCreateVulkanInstance; @@ -69,23 +82,28 @@ pub fn init( var messenger: vk.VkDebugUtilsMessengerEXT = null; var pfn_destroy: vk.PFN_vkDestroyDebugUtilsMessengerEXT = null; - if (config.enable_validation) { - const pfn_create: vk.PFN_vkCreateDebugUtilsMessengerEXT = @ptrCast( - vk.vkGetInstanceProcAddr(instance.?, "vkCreateDebugUtilsMessengerEXT"), - ); - pfn_destroy = @ptrCast( - vk.vkGetInstanceProcAddr(instance.?, "vkDestroyDebugUtilsMessengerEXT"), - ); + // if (config.enable_validation) { + const pfn_create: vk.PFN_vkCreateDebugUtilsMessengerEXT = @ptrCast( + vk.vkGetInstanceProcAddr(instance.?, "vkCreateDebugUtilsMessengerEXT"), + ); + pfn_destroy = @ptrCast( + vk.vkGetInstanceProcAddr(instance.?, "vkDestroyDebugUtilsMessengerEXT"), + ); - if (pfn_create.?(instance.?, &messenger_info, null, &messenger) != vk.VK_SUCCESS) { - return error.FailedToCreateDebugUtilsMessenger; - } + if (pfn_create.?(instance.?, &messenger_info, null, &messenger) != vk.VK_SUCCESS) { + return error.FailedToCreateDebugUtilsMessenger; } + // } return .{ .raw = instance.?, .messenger = messenger, .pfn_destroy_debug_utils_messenger = pfn_destroy, + + .api_version = config.api_version, + .vk_11_features = config.vk_11_features, + .vk_13_features = config.vk_13_features, + .vk_14_features = config.vk_14_features, }; } diff --git a/src/rhi/vulkan/resource/pipeline.zig b/src/rhi/vulkan/resource/pipeline.zig index dedf6d6..00b710c 100644 --- a/src/rhi/vulkan/resource/pipeline.zig +++ b/src/rhi/vulkan/resource/pipeline.zig @@ -23,8 +23,8 @@ const MAX_WRITES = MAX_BINDINGS; // FIELDS // -raw: vk.VkPipeline = null, -layout: vk.VkPipelineLayout = null, +raw: *vk.VkPipeline_T, +layout: *vk.VkPipelineLayout_T, device: *const Device, descriptor_set_layout: vk.VkDescriptorSetLayout = null, @@ -50,6 +50,9 @@ pub fn init( alloc: std.mem.Allocator, ) !Self { var self: Self = .{ + .raw = undefined, + .layout = undefined, + .device = device, .uniforms = &.{}, .uniform_offsets = &.{}, @@ -59,10 +62,6 @@ pub fn init( errdefer self.deinit(); // --- COMPUTE UNIFORM LAYOUT --- - // Each uniform block gets its own descriptor binding. Blocks are packed - // into a single per-frame buffer, each at a `minUniformBufferOffsetAlignment` - // aligned offset so the same layout maps to `glBindBufferRange` (GL) and - // CBV offsets (D3D12) unchanged. var uniform_size: u32 = 0; if (config.uniforms.len > 0) { var props: vk.VkPhysicalDeviceProperties = .{}; @@ -158,7 +157,7 @@ pub fn init( .sType = vk.VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, .stage = vk.VK_SHADER_STAGE_VERTEX_BIT, - .pName = "main", + .pName = if (config.vert_entry_point_name) |v| v.ptr else "main", .module = raw_vert_shader.raw, }; @@ -166,7 +165,7 @@ pub fn init( .sType = vk.VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, .stage = vk.VK_SHADER_STAGE_FRAGMENT_BIT, - .pName = "main", + .pName = if (config.frag_entry_point_name) |v| v.ptr else "main", .module = raw_frag_shader.raw, }; @@ -545,12 +544,10 @@ pub fn deinit(self: *Self) void { vk.vkDestroyBuffer(self.device.raw, b, null); } } - if (self.layout) |layout| { - vk.vkDestroyPipelineLayout(self.device.raw, layout, null); - } - if (self.raw) |raw| { - vk.vkDestroyPipeline(self.device.raw, raw, null); - } + + vk.vkDestroyPipelineLayout(self.device.raw, self.layout, null); + vk.vkDestroyPipeline(self.device.raw, self.raw, null); + self.alloc.free(self.uniforms); self.alloc.free(self.uniform_offsets); } diff --git a/src/rhi/vulkan/resource/shader.zig b/src/rhi/vulkan/resource/shader.zig index 8ac88bd..1a5a354 100644 --- a/src/rhi/vulkan/resource/shader.zig +++ b/src/rhi/vulkan/resource/shader.zig @@ -12,7 +12,7 @@ const Self = @This(); // FIELDS // -raw: vk.VkShaderModule, +raw: *vk.VkShaderModule_T, device: *const Device, /// ---------------------------------------------------- @@ -40,10 +40,7 @@ pub fn init( /// ---------------------------------------------------- /// ---------------------------------------------------- pub fn deinit(self: *Self) void { - if (self.raw) |raw| { - vk.vkDestroyShaderModule(self.device.raw, raw, null); - self.raw = null; - } + vk.vkDestroyShaderModule(self.device.raw, self.raw, null); } /// ---------------------------------------------------- diff --git a/src/rhi/vulkan/resource/surface.zig b/src/rhi/vulkan/resource/surface.zig index e8a4fdb..37c1ffc 100644 --- a/src/rhi/vulkan/resource/surface.zig +++ b/src/rhi/vulkan/resource/surface.zig @@ -4,10 +4,11 @@ const std = @import("std"); const vk = @import("vulkan"); -const Instance = @import("../instance.zig"); const Window = @import("../../common.zig").Window; const Self = @This(); +const Instance = @import("instance.zig"); + // // FIELDS // @@ -17,7 +18,7 @@ raw: *vk.VkSurfaceKHR_T, /// ---------------------------------------------------- /// ---------------------------------------------------- pub fn init( - instance: *Instance, + instance: *const Instance, window: Window, ) !Self { const surface: *vk.VkSurfaceKHR_T = blk: { @@ -48,6 +49,6 @@ pub fn init( /// ---------------------------------------------------- /// ---------------------------------------------------- -pub fn deinit(self: *Self, instance: *Instance) void { +pub fn deinit(self: *Self, instance: *const Instance) void { vk.vkDestroySurfaceKHR(instance.raw, self.raw, null); } diff --git a/src/rhi/vulkan/resource/texture.zig b/src/rhi/vulkan/resource/texture.zig index 9b54d64..be8f178 100644 --- a/src/rhi/vulkan/resource/texture.zig +++ b/src/rhi/vulkan/resource/texture.zig @@ -27,12 +27,15 @@ pub fn init( adapter: *const Adapter, device: *const Device, ) !Self { - var image = try VKImage.init(config.image, adapter, device); + var image: VKImage = try .init(config.image, adapter, device); errdefer image.deinit(); + var sampler: VKSampler = try .init(config.sampler, device); + errdefer sampler.deinit(); + return .{ .image = image, - .sampler = try VKSampler.init(config.sampler, device), + .sampler = sampler, }; } diff --git a/src/rhi/vulkan/vulkan.zig b/src/rhi/vulkan/vulkan.zig index b46058d..d315309 100644 --- a/src/rhi/vulkan/vulkan.zig +++ b/src/rhi/vulkan/vulkan.zig @@ -1,5 +1,5 @@ //! ---------------------------------------------------- -//! `🗲` Vulkan RHI `🗲` +//! `🗲` Vulkan RHI 1.4 `🗲` //! 😭 Send Help 😭 //! ---------------------------------------------------- @@ -8,9 +8,9 @@ const vk = @import("vulkan"); const gtl = @import("gtl"); const common = @import("../common.zig"); -const Instance = @import("instance.zig"); const Resource = @import("resource.zig"); const SwapchainResource = @import("resource/swapchain.zig"); +const VKImage = @import("resource/image.zig"); const MainConfig = @import("../../gfx.zig").Config; const Handle = gtl.Handle; @@ -49,16 +49,6 @@ const AdapterInfo = common.AdapterInfo; // --- # --- pub const MAX_FRAMES_IN_FLIGHT: usize = 3; -/// ---------------------------------------------------- -/// ---------------------------------------------------- -pub fn depthFormatToVk(format: common.DepthFormat) vk.VkFormat { - return switch (format) { - .d16_unorm => vk.VK_FORMAT_D16_UNORM, - .d24_unorm_s8 => vk.VK_FORMAT_D24_UNORM_S8_UINT, - .d32_sfloat => vk.VK_FORMAT_D32_SFLOAT, - }; -} - /// ---------------------------------------------------- /// ---------------------------------------------------- const Frame = struct { @@ -74,13 +64,13 @@ const Frame = struct { // FIELDS // -instance: Instance, resource: Resource, -config: MainConfig, frames: [MAX_FRAMES_IN_FLIGHT]Frame = .{ .{}, .{}, .{} }, current_frame: usize = 0, +active_pass_target: ?Handle(Texture) = null, + render_finished: []vk.VkSemaphore = &.{}, sync_device: ?*vk.VkDevice_T = null, @@ -94,19 +84,9 @@ io: std.Io, /// ---------------------------------------------------- /// ---------------------------------------------------- -pub fn init( - config: MainConfig, - alloc: std.mem.Allocator, - io: std.Io, -) !Self { - // --- INSTANCE --- - var instance: Instance = try .init(config, alloc); - errdefer instance.deinit(); - +pub fn init(alloc: std.mem.Allocator, io: std.Io) Self { return .{ - .instance = instance, .resource = .init(alloc), - .config = config, .alloc = alloc, .io = io, }; @@ -133,8 +113,36 @@ pub fn deinit(self: *Self) void { } } - self.resource.deinit(&self.instance); - self.instance.deinit(); + self.resource.deinit(); +} + +// +// INSTANCE +// + +/// ---------------------------------------------------- +/// ---------------------------------------------------- +pub fn makeInstance(self: *Self, config: common.VKInstanceConfig) !Handle(common.Instance) { + const h = try self.resource.instances.put(try .init(config, self.alloc)); + self.resource.current_instance = h; + return h; +} + +/// ---------------------------------------------------- +/// ---------------------------------------------------- +pub fn deleteInstance(self: *Self, instance: Handle(common.Instance)) void { + if (self.resource.instances.get(instance)) |_| { + self.resource.instances.remove(instance) catch unreachable; + self.resource.current_instance = null; + } +} + +/// ---------------------------------------------------- +/// ---------------------------------------------------- +pub fn releaseInstance(self: *Self, instance: Handle(common.Instance)) void { + if (self.resource.instances.get(instance)) |v| { + v.deinit(); + } } // @@ -143,8 +151,9 @@ pub fn deinit(self: *Self) void { /// ---------------------------------------------------- /// ---------------------------------------------------- -pub fn makeAdapter(self: *Self, config: AdapterConfig) !Handle(Adapter) { - return try self.resource.adapters.put(try .init(self, config)); +pub fn makeAdapter(self: *Self, config: AdapterConfig, instance: Handle(common.Instance)) !Handle(Adapter) { + const raw_instance = self.resource.instances.get(instance) orelse return error.InstanceNotFound; + return try self.resource.adapters.put(try .init(config, raw_instance, self.alloc)); } /// ---------------------------------------------------- @@ -175,7 +184,7 @@ pub fn getAdapterInfo(self: *Self, adapter: Handle(Adapter)) ?AdapterInfo { vk.VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU => .discrete, vk.VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU => .integrated, vk.VK_PHYSICAL_DEVICE_TYPE_CPU => .software, - else => .any, + else => .discrete, }, .device_id = props.deviceID, .vendor_id = props.vendorID, @@ -225,7 +234,7 @@ pub fn releaseDevice(self: *Self, device: Handle(Device)) void { /// ---------------------------------------------------- /// ---------------------------------------------------- pub fn getRawDevice(self: *Self, device: Handle(Device)) !*vk.VkDevice_T { - if (self.resource.devices.get(device)) |raw| return raw.raw orelse return error.NullDevice; + if (self.resource.devices.get(device)) |raw| return raw.raw; return error.DeviceNotFound; } @@ -235,8 +244,13 @@ pub fn getRawDevice(self: *Self, device: Handle(Device)) !*vk.VkDevice_T { /// ---------------------------------------------------- /// ---------------------------------------------------- -pub fn makeSurface(self: *Self) !Handle(Surface) { - return try self.resource.surfaces.put(try .init(&self.instance, self.config.window)); +pub fn makeSurface( + self: *Self, + instance: Handle(common.Instance), + window: Window, +) !Handle(Surface) { + const raw_instance = self.resource.instances.get(instance) orelse return error.InstanceNotFound; + return try self.resource.surfaces.put(try .init(raw_instance, window)); } // @@ -305,7 +319,7 @@ pub fn releaseShader(self: *Self, shader: Handle(Shader)) void { /// ---------------------------------------------------- /// ---------------------------------------------------- pub fn getRawShader(self: *Self, shader: Handle(Shader)) !*vk.VkShaderModule_T { - if (self.resource.shaders.get(shader)) |raw| return raw.raw orelse return error.NullShader; + if (self.resource.shaders.get(shader)) |raw| return raw.raw; return error.ShaderNotFound; } @@ -341,7 +355,7 @@ pub fn releasePipeline(self: *Self, pipeline: Handle(Pipeline)) void { /// ---------------------------------------------------- /// ---------------------------------------------------- pub fn getRawPipeline(self: *Self, pipeline: Handle(Pipeline)) !*vk.VkPipeline_T { - if (self.resource.pipelines.get(pipeline)) |raw| return raw.raw orelse return error.NullPipeline; + if (self.resource.pipelines.get(pipeline)) |raw| return raw.raw; return error.PipelineNotFound; } @@ -438,7 +452,7 @@ pub fn bindBuffer(self: *Self, buffer: Handle(Buffer)) !void { switch (raw.usage) { .vertex => vk.vkCmdBindVertexBuffers(cmd, 0, 1, &buffers, &offsets), .index => vk.vkCmdBindIndexBuffer(cmd, raw.raw, 0, vk.VK_INDEX_TYPE_UINT32), - .image => {}, // TODO: + .image => {}, } } } @@ -457,7 +471,10 @@ pub fn beginFrame( const raw_device = self.resource.devices.get(device) orelse return error.DeviceNotFound; const raw_swapchain = self.resource.swapchains.get(swapchain) orelse return error.SwapchainNotFound; - try self.ensureFrameSync(raw_device.raw.?, raw_swapchain.raw); + try self.ensureFrameSync( + raw_device.raw, + raw_swapchain.raw, + ); const frame = self.currentFrame(); @@ -583,9 +600,17 @@ pub fn beginPass( const frame = self.currentFrame(); + // --- RENDER TO OFFSCREEN TARGET INSTEAD OF THE SWAPCHAIN --- + const target_image: ?*VKImage = if (config.render_target) |target| blk: { + const raw_texture = self.resource.textures.get(target) orelse return error.TextureNotFound; + break :blk &raw_texture.image; + } else null; + + self.active_pass_target = config.render_target; + const extent: vk.VkExtent2D = .{ - .width = config.width orelse raw_swapchain.extent.width, - .height = config.height orelse raw_swapchain.extent.height, + .width = config.width orelse if (target_image) |img| img.width else raw_swapchain.extent.width, + .height = config.height orelse if (target_image) |img| img.height else raw_swapchain.extent.height, }; const barrier: vk.VkImageMemoryBarrier = .{ @@ -600,7 +625,7 @@ pub fn beginPass( .srcQueueFamilyIndex = vk.VK_QUEUE_FAMILY_IGNORED, .dstQueueFamilyIndex = vk.VK_QUEUE_FAMILY_IGNORED, - .image = raw_swapchain.images[frame.image_index], + .image = if (target_image) |img| img.raw else raw_swapchain.images[frame.image_index], .subresourceRange = .{ .aspectMask = vk.VK_IMAGE_ASPECT_COLOR_BIT, @@ -704,7 +729,7 @@ pub fn beginPass( const color_attachment: vk.VkRenderingAttachmentInfo = .{ .sType = vk.VK_STRUCTURE_TYPE_RENDERING_ATTACHMENT_INFO, - .imageView = raw_swapchain.image_views[frame.image_index], + .imageView = if (target_image) |img| img.raw_view else raw_swapchain.image_views[frame.image_index], .imageLayout = vk.VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, .loadOp = switch (config.load_op) { .clear => vk.VK_ATTACHMENT_LOAD_OP_CLEAR, @@ -777,6 +802,100 @@ pub fn endPass( vk.vkCmdEndRendering(frame.cmd_buf); + const target = self.active_pass_target; + self.active_pass_target = null; + + if (target) |t| { + // --- TARGET --- + const raw_texture = self.resource.textures.get(t) orelse return; + + const target_barrier: vk.VkImageMemoryBarrier = .{ + .sType = vk.VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, + + .srcAccessMask = vk.VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, + .dstAccessMask = vk.VK_ACCESS_SHADER_READ_BIT, + + .oldLayout = vk.VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, + .newLayout = vk.VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, + + .srcQueueFamilyIndex = vk.VK_QUEUE_FAMILY_IGNORED, + .dstQueueFamilyIndex = vk.VK_QUEUE_FAMILY_IGNORED, + + .image = raw_texture.image.raw, + + .subresourceRange = .{ + .aspectMask = vk.VK_IMAGE_ASPECT_COLOR_BIT, + .baseMipLevel = 0, + .levelCount = 1, + .baseArrayLayer = 0, + .layerCount = 1, + }, + }; + + vk.vkCmdPipelineBarrier( + frame.cmd_buf, + + vk.VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, + vk.VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, + + 0, + + 0, + null, + + 0, + null, + + 1, + &target_barrier, + ); + + // --- SWAPCHAIN --- + const swapchain_barrier: vk.VkImageMemoryBarrier = .{ + .sType = vk.VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, + + .srcAccessMask = 0, + .dstAccessMask = 0, + + .oldLayout = vk.VK_IMAGE_LAYOUT_UNDEFINED, + .newLayout = vk.VK_IMAGE_LAYOUT_PRESENT_SRC_KHR, + + .srcQueueFamilyIndex = vk.VK_QUEUE_FAMILY_IGNORED, + .dstQueueFamilyIndex = vk.VK_QUEUE_FAMILY_IGNORED, + + .image = raw_swapchain.images[frame.image_index], + + .subresourceRange = .{ + .aspectMask = vk.VK_IMAGE_ASPECT_COLOR_BIT, + .baseMipLevel = 0, + .levelCount = 1, + .baseArrayLayer = 0, + .layerCount = 1, + }, + }; + + vk.vkCmdPipelineBarrier( + frame.cmd_buf, + + vk.VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, + vk.VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, + + 0, + + 0, + null, + + 0, + null, + + 1, + &swapchain_barrier, + ); + + return; + } + + // --- SWAPCHAIN ONLY --- const barrier: vk.VkImageMemoryBarrier = .{ .sType = vk.VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, @@ -824,12 +943,12 @@ pub fn endPass( pub fn bindPipeline(self: *Self, pipeline: Handle(Pipeline)) !void { const raw_pipeline = self.resource.pipelines.get(pipeline) orelse return error.PipelineNotFound; const frame = self.currentFrame(); - vk.vkCmdBindPipeline(frame.cmd_buf, vk.VK_PIPELINE_BIND_POINT_GRAPHICS, raw_pipeline.raw.?); + vk.vkCmdBindPipeline(frame.cmd_buf, vk.VK_PIPELINE_BIND_POINT_GRAPHICS, raw_pipeline.raw); if (raw_pipeline.descriptor_sets[self.current_frame]) |set| { vk.vkCmdBindDescriptorSets( frame.cmd_buf, vk.VK_PIPELINE_BIND_POINT_GRAPHICS, - raw_pipeline.layout.?, + raw_pipeline.layout, 0, 1, &set, @@ -921,3 +1040,14 @@ fn ensureFrameSync( frame.fence = fence.?; } } + +/// ---------------------------------------------------- +/// TODO: Create vk helper +/// ---------------------------------------------------- +pub fn depthFormatToVk(format: common.DepthFormat) vk.VkFormat { + return switch (format) { + .d16_unorm => vk.VK_FORMAT_D16_UNORM, + .d24_unorm_s8 => vk.VK_FORMAT_D24_UNORM_S8_UINT, + .d32_sfloat => vk.VK_FORMAT_D32_SFLOAT, + }; +} diff --git a/tools/shaders.bash b/tools/shaders.bash new file mode 100755 index 0000000..d46f918 --- /dev/null +++ b/tools/shaders.bash @@ -0,0 +1,53 @@ +#!/bin/bash + +clear + +# --- GET ARGS --- +while getopts "i:o:" opt; do + case $opt in + i) + input="$OPTARG" + ;; + o) + output="$OPTARG" + ;; + *) + echo "[USAGE] $0 -i -o " + exit 1 + ;; + esac +done + +# --- CHECK INPUT --- +if [[ -z "$input" ]]; then + echo -e "\x1b[31m[ERROR]\x1b[0m input path is required." + echo -e "\x1b[33m[USAGE]\x1b[0m $0 -i -o " + exit 1 +fi + +# --- CHECK OUTPUT --- +if [[ -z "$output" ]]; then + echo -e "\x1b[31m[ERROR]\x1b[0m output path is required." + echo -e "\x1b[33m[USAGE]\x1b[0m $0 -i -o " + exit 1 +fi + +# --- ENSURE OUTPUT PATH --- +mkdir -p "$output" + +# --- COMPILE EACH FILE IN INPUT --- +for file in "$input"/*; do + if [[ ! -f "$file" ]]; then + continue + fi + + filename=$(basename "$file") + output_file="$output/$filename.spv" + + if [[ ! -f "$output_file" || "$file" -nt "$output_file" ]]; then + echo -e "\x1b[32m[COMPILING]\x1b[0m $filename" + glslc "$file" -o "$output_file" + else + echo -e "\x1b[90m[SKIPPING]\x1b[0m $filename" + fi +done diff --git a/tools/shaders.zig b/tools/shaders.zig deleted file mode 100644 index 8db7e3f..0000000 --- a/tools/shaders.zig +++ /dev/null @@ -1,5 +0,0 @@ -const std = @import("std"); - -pub fn main(init: std.process.Init) !void { - _ = init; -} diff --git a/zig-out/bin/3D b/zig-out/bin/3D new file mode 100755 index 0000000..96c5039 Binary files /dev/null and b/zig-out/bin/3D differ diff --git a/zig-out/bin/imgui b/zig-out/bin/imgui new file mode 100755 index 0000000..a855209 Binary files /dev/null and b/zig-out/bin/imgui differ diff --git a/zig-out/bin/simple b/zig-out/bin/simple index c60c1b8..7a58711 100755 Binary files a/zig-out/bin/simple and b/zig-out/bin/simple differ