Major update | Cleaned up some stuff | Added makeInstance etc for allowing users to pick what type of vk API version and features they want | still f ton stuff to do

This commit is contained in:
abux 2026-08-18 14:57:55 +01:00
parent 9cec2d7810
commit 814abc328d
30 changed files with 819 additions and 458 deletions

1
.gitignore vendored
View file

@ -1,3 +1,2 @@
.zig-cache/ .zig-cache/
zig-pkg/ zig-pkg/
zig-out/

View file

@ -44,5 +44,5 @@ src/rhi/vulkan/resource.zig
## Examples ## Examples
- ```zig build run-simple``` - ```zig build run-simple```
- ```zig build run-3D```
- ```zig build run-imgui``` - ```zig build run-imgui```
- ```zig build run-3D```

View file

@ -73,6 +73,8 @@ pub fn build(b: *std.Build) !void {
mod.addImport("fast_obj", fast_obj.createModule()); mod.addImport("fast_obj", fast_obj.createModule());
mod.addCSourceFiles(.{ .files = &.{"src/vendor/fast_obj/fast_obj.c"} }); mod.addCSourceFiles(.{ .files = &.{"src/vendor/fast_obj/fast_obj.c"} });
const check_step = b.step("check", "Check if compiles");
// //
// EXAMPLES // EXAMPLES
// //
@ -125,6 +127,11 @@ pub fn build(b: *std.Build) !void {
example.root_module.addImport("gfx", mod); 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(.{ const sdl = b.addTranslateC(.{
.target = target, .target = target,
.optimize = optimize, .optimize = optimize,
@ -187,7 +194,6 @@ pub fn build(b: *std.Build) !void {
const example_build_step = b.addInstallArtifact(example, .{}); const example_build_step = b.addInstallArtifact(example, .{});
example_step.dependOn(&example_build_step.step); 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);
} }
} }

View file

@ -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

View file

@ -4,8 +4,8 @@
// IO // IO
// //
layout(location = 0) in vec2 in_position; layout(location = 0) in vec3 in_position;
layout(location = 1) in vec2 in_normal; layout(location = 1) in vec3 in_normal;
layout(location = 2) in vec2 in_UV; layout(location = 2) in vec2 in_UV;
layout(location = 0) out vec2 out_UV; layout(location = 0) out vec2 out_UV;
@ -13,6 +13,6 @@ layout(location = 0) out vec2 out_UV;
/// ---------------------------------------------------- /// ----------------------------------------------------
/// ---------------------------------------------------- /// ----------------------------------------------------
void main() { void main() {
gl_Position = vec4(in_position, 0.0, 1.0); gl_Position = vec4(in_position, 1.0);
out_UV = in_UV; out_UV = in_UV;
} }

View file

@ -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,
};
};

View file

@ -37,19 +37,27 @@ pub fn main(init: std.process.Init) !void {
// //
// --- # --- // --- # ---
var gfx: Gfx = try .init(.{ var gfx: Gfx = try .init(
.window = .{ init.gpa,
.xlib = .{ init.io,
.window = @intCast(xwindow), );
.display = display.?,
},
},
}, init.gpa, init.io);
defer gfx.deinit(); defer gfx.deinit();
// --- # --- // --- # ---
const adapter = try gfx.makeAdapter(.{ .gpu_type = .any }); const instance = try gfx.makeInstance(.{
const surface = try gfx.makeSurface(); .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 device = try gfx.makeDevice(adapter, surface);
const swapchain = try gfx.makeSwapchain(adapter, device, 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; if (!im_sdl.cImGui_ImplSDL3_InitForVulkan(@ptrCast(window))) return error.FailedToImplImGuiForSDL;
defer im_sdl.cImGui_ImplSDL3_Shutdown(); 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 --- // --- GET VK RAW DEVICE ---
const raw_device = switch (try gfx.getRawDevice(device)) { const raw_device = switch (try gfx.getRawDevice(device)) {
.vulkan => |v| v, .vulkan => |v| v,
@ -76,7 +89,7 @@ pub fn main(init: std.process.Init) !void {
// --- INIT IMGUI FOR VK --- // --- INIT IMGUI FOR VK ---
var color_format: im_vk.VkFormat = raw_swapchain.format; var color_format: im_vk.VkFormat = raw_swapchain.format;
var im_info: im_vk.ImGui_ImplVulkan_InitInfo = .{ var im_info: im_vk.ImGui_ImplVulkan_InitInfo = .{
.Instance = @ptrCast(gfx.getRawInstance().vulkan), .Instance = @ptrCast((try gfx.getRawInstance(instance)).vulkan),
.PhysicalDevice = blk: { .PhysicalDevice = blk: {
switch (try gfx.getRawAdapter(adapter)) { switch (try gfx.getRawAdapter(adapter)) {
.vulkan => |v| break :blk @ptrCast(v), .vulkan => |v| break :blk @ptrCast(v),

View file

@ -0,0 +1,3 @@
# Simple Example
![simple](image.png)

BIN
examples/simple/image Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 281 KiB

View file

@ -3,38 +3,9 @@
const std = @import("std"); const std = @import("std");
const sdl = @import("sdl"); const sdl = @import("sdl");
const cmn = @import("common");
const Gfx = @import("gfx"); 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 { pub fn main(init: std.process.Init) !void {
@ -43,7 +14,7 @@ pub fn main(init: std.process.Init) !void {
// DATA // 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 // SDL
@ -67,21 +38,27 @@ pub fn main(init: std.process.Init) !void {
// //
// --- # --- // --- # ---
var gfx: Gfx = try .init(.{ var gfx: Gfx = try .init(
.window = .{ init.gpa,
.xlib = .{ init.io,
.window = @intCast(xwindow), );
.display = display.?,
},
},
}, init.gpa, init.io);
defer gfx.deinit(); defer gfx.deinit();
errdefer gfx.deinit();
// --- # --- // --- # ---
const adapter = try gfx.makeAdapter(.{ .gpu_type = .any }); const instance = try gfx.makeInstance(.{
const surface = try gfx.makeSurface(); .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 device = try gfx.makeDevice(adapter, surface);
const swapchain = try gfx.makeSwapchain(adapter, device, surface); const swapchain = try gfx.makeSwapchain(adapter, device, surface);
@ -92,8 +69,8 @@ pub fn main(init: std.process.Init) !void {
}, adapter, device); }, adapter, device);
// --- BUFFERS --- // --- BUFFERS ---
const vbuf = try gfx.makeBuffer(vertices, .vertex, adapter, device); const vbuf = try gfx.makeBuffer(cmn.Square.vertices, .vertex, adapter, device);
const ibuf = try gfx.makeBuffer(indices, .index, adapter, device); const ibuf = try gfx.makeBuffer(cmn.Square.indices, .index, adapter, device);
// --- SHADERS --- // --- SHADERS ---
const simple_vert = try gfx.makeShader("examples/assets/shaders/compiled/simple.vert.spv", device); 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 --- // --- PIPELINE ---
const pipeline = try gfx.makePipeline(.{ const pipeline = try gfx.makePipeline(.{
.vertex_attributes = &.{ .vertex_attributes = &.{
.{ .location = 0, .format = .vec2, .offset = @offsetOf(Vertex, "pos") }, .{ .location = 0, .format = .vec3, .offset = @offsetOf(cmn.Vertex, "pos") },
.{ .location = 1, .format = .vec2, .offset = @offsetOf(Vertex, "normal") }, .{ .location = 1, .format = .vec3, .offset = @offsetOf(cmn.Vertex, "normal") },
.{ .location = 2, .format = .vec2, .offset = @offsetOf(Vertex, "uv") }, .{ .location = 2, .format = .vec2, .offset = @offsetOf(cmn.Vertex, "uv") },
}, },
.vertex_binding = .{ .stride = @sizeOf(Vertex) }, .vertex_binding = .{ .stride = @sizeOf(cmn.Vertex) },
.uniforms = &.{ .uniforms = &.{
.{ .name = "material", .size = @sizeOf(UnlitMaterial) }, .{ .name = "material", .size = @sizeOf(cmn.UnlitMaterial) },
}, },
.textures = &.{ .textures = &.{
@ -160,7 +137,7 @@ pub fn main(init: std.process.Init) !void {
try ibuf.bind(); try ibuf.bind();
try pipeline.bind(); try pipeline.bind();
pass.drawIndexed(indices.len, 1, 0, 0, 0); pass.drawIndexed(cmn.Square.indices.len, 1, 0, 0, 0);
} }
// --- NEW PASS --- // --- NEW PASS ---

View file

@ -5,78 +5,9 @@ const vk = @import("vulkan");
const std = @import("std"); const std = @import("std");
const sdl = @import("sdl"); const sdl = @import("sdl");
const math = @import("math"); const math = @import("math");
const cmn = @import("common");
const Gfx = @import("gfx"); 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 { const Camera = struct {
@ -98,7 +29,7 @@ pub fn main(init: std.process.Init) !void {
// DATA // 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 = .{ const camera: Camera = .{
.projection = .perspective(std.math.degreesToRadians(90), 800.0 / 600.0, 0.01, 1000), .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 })), .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 // GFX
// //
// --- # --- var gfx: Gfx = try .init(
var gfx: Gfx = try .init(.{ init.gpa,
.window = .{ init.io,
.xlib = .{ );
.window = @intCast(xwindow),
.display = display.?,
},
},
.backend = .vulkan,
}, init.gpa, init.io);
defer gfx.deinit(); defer gfx.deinit();
errdefer gfx.deinit(); const instance = try gfx.makeInstance(.{
.vulkan = .{
.api_version = .v1_3,
},
});
// --- # --- const surface = try gfx.makeSurface(.{
const adapter = try gfx.makeAdapter(.{ .gpu_type = .any }); .xlib = .{
const surface = try gfx.makeSurface(); .window = @intCast(xwindow),
.display = display.?,
},
}, instance);
const adapter = try gfx.makeAdapter(.{}, instance);
const device = try gfx.makeDevice(adapter, surface); const device = try gfx.makeDevice(adapter, surface);
const swapchain = try gfx.makeSwapchain(adapter, device, surface); const swapchain = try gfx.makeSwapchain(adapter, device, surface);
@ -169,8 +103,8 @@ pub fn main(init: std.process.Init) !void {
}, adapter, device); }, adapter, device);
// --- BUFFERS --- // --- BUFFERS ---
const vbuf = try gfx.makeBuffer(vertices, .vertex, adapter, device); const vbuf = try gfx.makeBuffer(cmn.Cube.vertices, .vertex, adapter, device);
const ibuf = try gfx.makeBuffer(indices, .index, adapter, device); const ibuf = try gfx.makeBuffer(cmn.Cube.indices, .index, adapter, device);
// --- SHADERS --- // --- SHADERS ---
const simple_vert = try gfx.makeShader("examples/assets/shaders/compiled/3D.vert.spv", device); 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 --- // --- PIPELINE ---
const pipeline = try gfx.makePipeline(.{ const pipeline = try gfx.makePipeline(.{
.vertex_attributes = &.{ .vertex_attributes = &.{
.{ .location = 0, .format = .vec3, .offset = @offsetOf(Vertex, "pos") }, .{ .location = 0, .format = .vec3, .offset = @offsetOf(cmn.Vertex, "pos") },
.{ .location = 1, .format = .vec3, .offset = @offsetOf(Vertex, "normal") }, .{ .location = 1, .format = .vec3, .offset = @offsetOf(cmn.Vertex, "normal") },
.{ .location = 2, .format = .vec2, .offset = @offsetOf(Vertex, "uv") }, .{ .location = 2, .format = .vec2, .offset = @offsetOf(cmn.Vertex, "uv") },
}, },
.vertex_binding = .{ .stride = @sizeOf(Vertex) }, .vertex_binding = .{ .stride = @sizeOf(cmn.Vertex) },
.uniforms = &.{ .uniforms = &.{
.{ .name = "camera", .size = @sizeOf(Camera) }, .{ .name = "camera", .size = @sizeOf(Camera) },
@ -245,7 +179,7 @@ pub fn main(init: std.process.Init) !void {
try ibuf.bind(); try ibuf.bind();
try pipeline.bind(); try pipeline.bind();
pass.drawIndexed(indices.len, 1, 0, 0, 0); pass.drawIndexed(cmn.Cube.indices.len, 1, 0, 0, 0);
} }
// --- NEW PASS --- // --- NEW PASS ---

View file

@ -2,17 +2,37 @@
Pos=60,60 Pos=60,60
Size=400,400 Size=400,400
Collapsed=0 Collapsed=0
LastUsed=20260814 LastUsed=20260818
[Window][Inspector] [Window][Inspector]
Pos=25,55 Pos=87,36
Size=341,210 Size=622,253
Collapsed=0 Collapsed=0
LastUsed=20260814 DockId=0x00000002,0
LastUsed=20260818
[Window][Dear ImGui Demo] [Window][Dear ImGui Demo]
Pos=416,63 Pos=87,291
Size=305,363 Size=622,257
Collapsed=0 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 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

View file

@ -13,6 +13,7 @@ const Self = @This();
pub const Handle = gtl.Handle; pub const Handle = gtl.Handle;
// --- CONFIGS --- // --- CONFIGS ---
pub const InstanceConfig = common.InstanceConfig;
pub const AdapterConfig = common.AdapterConfig; pub const AdapterConfig = common.AdapterConfig;
pub const RenderPassConfig = common.RenderPassConfig; pub const RenderPassConfig = common.RenderPassConfig;
pub const PipelineConfig = common.PipelineConfig; pub const PipelineConfig = common.PipelineConfig;
@ -23,6 +24,7 @@ pub const SamplerConfig = common.SamplerConfig;
pub const TextureConfig = common.TextureConfig; pub const TextureConfig = common.TextureConfig;
// --- HANDLES --- // --- HANDLES ---
pub const Instance = common.Instance;
pub const Window = common.Window; pub const Window = common.Window;
pub const Adapter = common.Adapter; pub const Adapter = common.Adapter;
pub const Device = common.Device; pub const Device = common.Device;
@ -59,23 +61,11 @@ const BackendCTX = union(Backend) {
vulkan: VulkanRHI, 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 // FIELDS
// //
ctx: BackendCTX, ctx: ?BackendCTX,
config: Config,
alloc: std.mem.Allocator, alloc: std.mem.Allocator,
io: std.Io, io: std.Io,
@ -87,17 +77,11 @@ io: std.Io,
/// ---------------------------------------------------- /// ----------------------------------------------------
/// ---------------------------------------------------- /// ----------------------------------------------------
pub fn init( pub fn init(
config: Config,
alloc: std.mem.Allocator, alloc: std.mem.Allocator,
io: std.Io, io: std.Io,
) !Self { ) !Self {
const backend_ctx: BackendCTX = switch (config.backend) {
.vulkan => .{ .vulkan = try .init(config, alloc, io) },
};
return .{ return .{
.config = config, .ctx = null,
.ctx = backend_ctx,
.alloc = alloc, .alloc = alloc,
.io = io, .io = io,
}; };
@ -106,7 +90,7 @@ pub fn init(
/// ---------------------------------------------------- /// ----------------------------------------------------
/// ---------------------------------------------------- /// ----------------------------------------------------
pub fn deinit(self: *Self) void { pub fn deinit(self: *Self) void {
switch (self.ctx) { switch ((self.getBackend() catch return).*) {
.vulkan => |*v| v.deinit(), .vulkan => |*v| v.deinit(),
} }
} }
@ -117,16 +101,47 @@ pub fn deinit(self: *Self) void {
/// ---------------------------------------------------- /// ----------------------------------------------------
/// ---------------------------------------------------- /// ----------------------------------------------------
pub fn getRawInstance(self: *Self) RawInstance { pub fn makeInstance(self: *Self, config: InstanceConfig) !Handle(Instance) {
return switch (self.ctx) { switch (config) {
.vulkan => |*v| .{ .vulkan = v.instance.raw }, .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 { pub fn getRawFrame(self: *Self) !RawFrame {
switch (self.ctx) { switch ((try self.getBackend()).*) {
.vulkan => |*v| { .vulkan => |*v| {
const raw_frame = v.currentFrame(); const raw_frame = v.currentFrame();
return .{ return .{
@ -147,16 +162,16 @@ pub fn getRawFrame(self: *Self) !RawFrame {
/// ---------------------------------------------------- /// ----------------------------------------------------
/// ---------------------------------------------------- /// ----------------------------------------------------
pub fn makeAdapter(self: *Self, config: AdapterConfig) !Handle(Adapter) { pub fn makeAdapter(self: *Self, config: AdapterConfig, instance: Handle(Instance)) !Handle(Adapter) {
return try switch (self.ctx) { return try switch ((try self.getBackend()).*) {
.vulkan => |*v| v.makeAdapter(config), .vulkan => |*v| v.makeAdapter(config, instance),
}; };
} }
/// ---------------------------------------------------- /// ----------------------------------------------------
/// ---------------------------------------------------- /// ----------------------------------------------------
pub fn deleteAdapter(self: *Self, adapter: Handle(Adapter)) void { pub fn deleteAdapter(self: *Self, adapter: Handle(Adapter)) void {
switch (self.ctx) { switch ((try self.getBackend()).*) {
.vulkan => |*v| v.deleteAdapter(adapter), .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 { pub fn releaseAdapter(self: *Self, adapter: Handle(Adapter)) void {
switch (self.ctx) { switch ((try self.getBackend()).*) {
.vulkan => |*v| v.releaseAdapter(adapter), .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 { 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), .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 { 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) }, .vulkan => |*v| .{ .vulkan = try v.getRawAdapter(adapter) },
}; };
} }
@ -196,7 +211,7 @@ pub fn makeDevice(
adapter: Handle(Adapter), adapter: Handle(Adapter),
surface: Handle(Surface), surface: Handle(Surface),
) !Handle(Device) { ) !Handle(Device) {
return try switch (self.ctx) { return try switch ((try self.getBackend()).*) {
.vulkan => |*v| v.makeDevice(adapter, surface), .vulkan => |*v| v.makeDevice(adapter, surface),
}; };
} }
@ -204,7 +219,7 @@ pub fn makeDevice(
/// ---------------------------------------------------- /// ----------------------------------------------------
/// ---------------------------------------------------- /// ----------------------------------------------------
pub fn deleteDevice(self: *Self, device: Handle(Device)) void { pub fn deleteDevice(self: *Self, device: Handle(Device)) void {
switch (self.ctx) { switch ((try self.getBackend()).*) {
.vulkan => |*v| v.deleteDevice(device), .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 { pub fn releaseDevice(self: *Self, device: Handle(Device)) void {
switch (self.ctx) { switch ((try self.getBackend()).*) {
.vulkan => |*v| v.releaseDevice(device), .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 { pub fn getRawDevice(self: *Self, device: Handle(Device)) !RawDevice {
switch (self.ctx) { switch ((try self.getBackend()).*) {
.vulkan => |*v| { .vulkan => |*v| {
const raw_device = v.resource.devices.get(device) orelse return error.DeviceNotFound; const raw_device = v.resource.devices.get(device) orelse return error.DeviceNotFound;
return .{ return .{
.vulkan = .{ .vulkan = .{
.device = raw_device.raw orelse return error.NullDevice, .device = raw_device.raw,
.graphics_queue = raw_device.graphics_queue, .graphics_queue = raw_device.graphics_queue,
.present_queue = raw_device.present_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 { // 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) }, // .vulkan => |*v| .{ .vulkan = try v.getRawDevice(device) },
// }; // };
// } // }
@ -257,7 +272,7 @@ pub fn makeBuffer(
) !Buffer { ) !Buffer {
const size = @sizeOf(@TypeOf(value)); 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), .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 { pub fn deleteBuffer(self: *Self, buffer: Handle(Buffer)) void {
switch (self.ctx) { switch ((try self.getBackend()).*) {
.vulkan => |*v| v.deleteBuffer(buffer), .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 { pub fn releaseBuffer(self: *Self, buffer: Handle(Buffer)) void {
switch (self.ctx) { switch ((try self.getBackend()).*) {
.vulkan => |*v| v.releaseBuffer(buffer), .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 { 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) }, .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) { pub fn makeSurface(
return try switch (self.ctx) { self: *Self,
.vulkan => |*v| v.makeSurface(), 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), device: Handle(Device),
surface: Handle(Surface), surface: Handle(Surface),
) !Handle(Swapchain) { ) !Handle(Swapchain) {
return try switch (self.ctx) { return try switch ((try self.getBackend()).*) {
.vulkan => |*v| v.makeSwapchain(adapter, device, surface), .vulkan => |*v| v.makeSwapchain(adapter, device, surface),
}; };
} }
@ -327,7 +346,7 @@ pub fn makeSwapchain(
/// ---------------------------------------------------- /// ----------------------------------------------------
/// ---------------------------------------------------- /// ----------------------------------------------------
pub fn getRawSwapchain(self: *Self, swapchain: Handle(Swapchain)) !*VKSwapchain { pub fn getRawSwapchain(self: *Self, swapchain: Handle(Swapchain)) !*VKSwapchain {
return switch (self.ctx) { return switch ((try self.getBackend()).*) {
.vulkan => |*v| v.getRawSwapchain(swapchain), .vulkan => |*v| v.getRawSwapchain(swapchain),
}; };
} }
@ -343,7 +362,7 @@ pub fn makeShader(
spv_path: []const u8, spv_path: []const u8,
device: Handle(Device), device: Handle(Device),
) !Handle(Shader) { ) !Handle(Shader) {
return try switch (self.ctx) { return try switch ((try self.getBackend()).*) {
.vulkan => |*v| v.makeShader(spv_path, device), .vulkan => |*v| v.makeShader(spv_path, device),
}; };
} }
@ -351,7 +370,7 @@ pub fn makeShader(
/// ---------------------------------------------------- /// ----------------------------------------------------
/// ---------------------------------------------------- /// ----------------------------------------------------
pub fn deleteShader(self: *Self, shader: Handle(Shader)) void { pub fn deleteShader(self: *Self, shader: Handle(Shader)) void {
switch (self.ctx) { switch ((try self.getBackend()).*) {
.vulkan => |*v| v.deleteShader(shader), .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 { pub fn releaseShader(self: *Self, shader: Handle(Shader)) void {
switch (self.ctx) { switch ((try self.getBackend()).*) {
.vulkan => |*v| v.releaseShader(shader), .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 { 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) }, .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 { pub fn makePipeline(self: *Self, config: PipelineConfig) !Pipeline {
return .{ return .{
.handle = try switch (self.ctx) { .handle = try switch ((try self.getBackend()).*) {
.vulkan => |*v| v.makePipeline(config), .vulkan => |*v| v.makePipeline(config),
}, },
.device = config.device, .device = config.device,
@ -390,7 +409,7 @@ pub fn makePipeline(self: *Self, config: PipelineConfig) !Pipeline {
/// ---------------------------------------------------- /// ----------------------------------------------------
/// ---------------------------------------------------- /// ----------------------------------------------------
pub fn deletePipeline(self: *Self, pipeline: Handle(Pipeline)) void { pub fn deletePipeline(self: *Self, pipeline: Handle(Pipeline)) void {
switch (self.ctx) { switch ((try self.getBackend()).*) {
.vulkan => |*v| v.deletePipeline(pipeline), .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 { pub fn releasePipeline(self: *Self, pipeline: Handle(Pipeline)) void {
switch (self.ctx) { switch ((try self.getBackend()).*) {
.vulkan => |*v| v.releasePipeline(pipeline), .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 { pub fn getRawPipeline(self: *Self, pipeline: Handle(Pipeline)) !RawPipeline {
switch (self.ctx) { switch ((try self.getBackend()).*) {
.vulkan => |*v| { .vulkan => |*v| {
const raw_pipe = v.resource.pipelines.get(pipeline) orelse return error.PipelineNotFound; const raw_pipe = v.resource.pipelines.get(pipeline) orelse return error.PipelineNotFound;
return .{ return .{
.vulkan = .{ .vulkan = .{
.pipeline = raw_pipe.raw orelse return error.NullPipeline, .pipeline = raw_pipe.raw,
.descriptor_pool = raw_pipe.descriptor_pool orelse return error.NullDescriptorPool, .descriptor_pool = raw_pipe.descriptor_pool,
}, },
}; };
}, },
} }
// return switch (self.ctx) { // return switch ((try self.getBackend()).*) {
// .vulkan => |*v| .{ .vulkan = try v.getRawPipeline(pipeline) }, // .vulkan => |*v| .{ .vulkan = try v.getRawPipeline(pipeline) },
// }; // };
} }
@ -434,7 +453,7 @@ pub fn makeImage(
adapter: Handle(Adapter), adapter: Handle(Adapter),
device: Handle(Device), device: Handle(Device),
) !Handle(Image) { ) !Handle(Image) {
return try switch (self.ctx) { return try switch ((try self.getBackend()).*) {
.vulkan => |*v| v.makeImage(config, adapter, device), .vulkan => |*v| v.makeImage(config, adapter, device),
}; };
} }
@ -446,7 +465,7 @@ pub fn makeSampler(
config: SamplerConfig, config: SamplerConfig,
device: Handle(Device), device: Handle(Device),
) !Handle(Sampler) { ) !Handle(Sampler) {
return try switch (self.ctx) { return try switch ((try self.getBackend()).*) {
.vulkan => |*v| v.makeSampler(config, device), .vulkan => |*v| v.makeSampler(config, device),
}; };
} }
@ -459,7 +478,7 @@ pub fn makeTexture(
adapter: Handle(Adapter), adapter: Handle(Adapter),
device: Handle(Device), device: Handle(Device),
) !Handle(Texture) { ) !Handle(Texture) {
return try switch (self.ctx) { return try switch ((try self.getBackend()).*) {
.vulkan => |*v| v.makeTexture(config, adapter, device), .vulkan => |*v| v.makeTexture(config, adapter, device),
}; };
} }
@ -475,7 +494,7 @@ pub fn beginFrame(
swapchain: Handle(Swapchain), swapchain: Handle(Swapchain),
device: Handle(Device), device: Handle(Device),
) !void { ) !void {
try switch (self.ctx) { try switch ((try self.getBackend()).*) {
.vulkan => |*v| v.beginFrame(swapchain, device), .vulkan => |*v| v.beginFrame(swapchain, device),
}; };
} }
@ -487,7 +506,7 @@ pub fn endFrame(
swapchain: Handle(Swapchain), swapchain: Handle(Swapchain),
device: Handle(Device), device: Handle(Device),
) !void { ) !void {
try switch (self.ctx) { try switch ((try self.getBackend()).*) {
.vulkan => |*v| v.endFrame(swapchain, device), .vulkan => |*v| v.endFrame(swapchain, device),
}; };
} }
@ -499,7 +518,7 @@ pub fn beginPass(
swapchain: Handle(Swapchain), swapchain: Handle(Swapchain),
config: RenderPassConfig, config: RenderPassConfig,
) ?Pass { ) ?Pass {
switch (self.ctx) { switch ((self.getBackend() catch return null).*) {
.vulkan => |*v| v.beginPass(swapchain, config) catch return null, .vulkan => |*v| v.beginPass(swapchain, config) catch return null,
} }
@ -508,3 +527,10 @@ pub fn beginPass(
.gfx = self, .gfx = self,
}; };
} }
/// ----------------------------------------------------
/// ----------------------------------------------------
pub fn getBackend(self: *Self) !*BackendCTX {
if (self.ctx) |*ctx| return ctx;
return error.BackendNotInitialized;
}

View file

@ -7,12 +7,47 @@ const gtl = @import("gtl");
const Gfx = @import("../gfx.zig"); const Gfx = @import("../gfx.zig");
const Handle = gtl.Handle; const Handle = gtl.Handle;
// TODO: Organize these into categories... someday
/// ----------------------------------------------------
/// ----------------------------------------------------
pub const Backend = enum { vulkan }; 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 // RAW
// //
@ -67,7 +102,7 @@ pub const RawPipeline = union(Backend) {
/// ---------------------------------------------------- /// ----------------------------------------------------
pub const AdapterInfo = struct { pub const AdapterInfo = struct {
name: [256]u8, name: [256]u8,
gpu_type: GPUType, gpu_type: DeviceType,
device_id: u32, device_id: u32,
vendor_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 { pub const AdapterConfig = struct {
/// Preferred class of GPU device_type: DeviceType = .discrete,
/// `.any` disables filtering by class
gpu_type: GPUType = .discrete,
/// Select the adapter at a specific enumeration index
/// `null` picks the first suitable one
index: ?u32 = null, index: ?u32 = null,
}; };
@ -184,12 +205,25 @@ pub const DepthFormat = enum {
d32_sfloat, 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 { pub const PipelineConfig = struct {
vert_shader: Handle(Shader), vert_shader: Handle(Shader),
frag_shader: Handle(Shader), frag_shader: Handle(Shader),
vert_entry_point_name: ?[]const u8 = null,
frag_entry_point_name: ?[]const u8 = null,
swapchain: Handle(Swapchain), swapchain: Handle(Swapchain),
device: Handle(Device), device: Handle(Device),
@ -236,7 +270,7 @@ pub const Pass = struct {
/// ---------------------------------------------------- /// ----------------------------------------------------
/// ---------------------------------------------------- /// ----------------------------------------------------
pub fn end(self: *const Pass) void { pub fn end(self: *const Pass) void {
switch (self.gfx.ctx) { switch ((self.gfx.getBackend() catch return).*) {
.vulkan => |*v| v.endPass(self.swapchain), .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 { 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), .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 { 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), .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 { pub const RenderPassConfig = struct {
clear_color: [4]f32 = .{ 0.0, 0.0, 0.0, 1.0 }, 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_enabled: bool = false,
depth_format: DepthFormat = .d32_sfloat, depth_format: DepthFormat = .d32_sfloat,
depth_load_op: LoadOp = .clear, depth_load_op: LoadOp = .clear,
@ -390,6 +427,7 @@ pub const TextureConfig = struct {
// HANDLE TYPES // HANDLE TYPES
// //
pub const Instance = struct {};
pub const Adapter = struct {}; pub const Adapter = struct {};
pub const Device = struct {}; pub const Device = struct {};
@ -402,7 +440,7 @@ pub const Buffer = struct {
gfx: *Gfx, gfx: *Gfx,
pub fn set(self: *const Buffer, value: anytype) !void { pub fn set(self: *const Buffer, value: anytype) !void {
switch (self.gfx.ctx) { switch ((try self.gfx.getBackend()).*) {
.vulkan => |*v| { .vulkan => |*v| {
const raw = v.resource.buffers.get(self.handle) orelse return error.BufferNotFound; const raw = v.resource.buffers.get(self.handle) orelse return error.BufferNotFound;
try raw.set(value, @sizeOf(@TypeOf(value))); try raw.set(value, @sizeOf(@TypeOf(value)));
@ -411,7 +449,7 @@ pub const Buffer = struct {
} }
pub fn bind(self: *const Buffer) !void { pub fn bind(self: *const Buffer) !void {
switch (self.gfx.ctx) { switch ((try self.gfx.getBackend()).*) {
.vulkan => |*v| try v.bindBuffer(self.handle), .vulkan => |*v| try v.bindBuffer(self.handle),
} }
} }
@ -431,13 +469,13 @@ pub const Pipeline = struct {
gfx: *Gfx, gfx: *Gfx,
pub fn bind(self: *const Pipeline) !void { pub fn bind(self: *const Pipeline) !void {
try switch (self.gfx.ctx) { try switch ((try self.gfx.getBackend()).*) {
.vulkan => |*v| v.bindPipeline(self.handle), .vulkan => |*v| v.bindPipeline(self.handle),
}; };
} }
pub fn setUniform(self: *const Pipeline, name: []const u8, value: anytype) !void { 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), .vulkan => |*v| v.setUniform(self.handle, name, value),
}; };
} }

View file

@ -5,9 +5,12 @@ const vk = @import("vulkan");
const std = @import("std"); const std = @import("std");
const gtl = @import("gtl"); const gtl = @import("gtl");
const common = @import("../common.zig"); const common = @import("../common.zig");
const Instance = @import("instance.zig"); const Handle = gtl.Handle;
const Self = @This(); const Self = @This();
const Instance = common.Instance;
const VKInstance = @import("resource/instance.zig");
const Adapter = common.Adapter; const Adapter = common.Adapter;
const VKAdapter = @import("resource/adapter.zig"); const VKAdapter = @import("resource/adapter.zig");
@ -43,6 +46,8 @@ const VKTexture = @import("resource/texture.zig");
// FIELDS // FIELDS
// //
instances: gtl.ResourceMap(Instance, VKInstance),
adapters: gtl.ResourceMap(Adapter, VKAdapter), adapters: gtl.ResourceMap(Adapter, VKAdapter),
devices: gtl.ResourceMap(Device, VKDevice), devices: gtl.ResourceMap(Device, VKDevice),
@ -58,10 +63,14 @@ textures: gtl.ResourceMap(Texture, VKTexture),
shaders: gtl.ResourceMap(Shader, VKShader), shaders: gtl.ResourceMap(Shader, VKShader),
pipelines: gtl.ResourceMap(Pipeline, VKPipeline), pipelines: gtl.ResourceMap(Pipeline, VKPipeline),
current_instance: ?Handle(Instance) = null,
/// ---------------------------------------------------- /// ----------------------------------------------------
/// ---------------------------------------------------- /// ----------------------------------------------------
pub fn init(alloc: std.mem.Allocator) Self { pub fn init(alloc: std.mem.Allocator) Self {
return .{ return .{
.instances = .init(alloc),
.adapters = .init(alloc), .adapters = .init(alloc),
.devices = .init(alloc), .devices = .init(alloc),
@ -81,10 +90,7 @@ pub fn init(alloc: std.mem.Allocator) Self {
/// ---------------------------------------------------- /// ----------------------------------------------------
/// ---------------------------------------------------- /// ----------------------------------------------------
pub fn deinit( pub fn deinit(self: *Self) void {
self: *Self,
instance: *Instance,
) void {
{ // FREE SWAPCHAINS { // FREE SWAPCHAINS
var it = self.swapchains.valueIterator(); var it = self.swapchains.valueIterator();
while (it.next()) |v| { while (it.next()) |v| {
@ -96,6 +102,7 @@ pub fn deinit(
{ // FREE SURFACES { // FREE SURFACES
var it = self.surfaces.valueIterator(); var it = self.surfaces.valueIterator();
while (it.next()) |v| { while (it.next()) |v| {
const instance = if (self.current_instance) |h| self.instances.get(h) orelse break else break;
v.deinit(instance); v.deinit(instance);
} }
self.surfaces.deinit(); self.surfaces.deinit();
@ -160,4 +167,12 @@ pub fn deinit(
} }
self.devices.deinit(); self.devices.deinit();
} }
{ // FREE INSTANCES
var it = self.instances.valueIterator();
while (it.next()) |v| {
v.deinit();
}
self.instances.deinit();
}
} }

View file

@ -8,9 +8,11 @@ const vk = @import("vulkan");
const common = @import("../../common.zig"); const common = @import("../../common.zig");
const VKBackend = @import("../vulkan.zig"); const VKBackend = @import("../vulkan.zig");
const AdapterConfig = common.AdapterConfig; const AdapterConfig = common.AdapterConfig;
const GPUType = common.GPUType; const DeviceType = common.DeviceType;
const Self = @This(); const Self = @This();
const Instance = @import("instance.zig");
// //
// FIELDS // FIELDS
// //
@ -19,49 +21,124 @@ raw: *vk.VkPhysicalDevice_T,
/// ---------------------------------------------------- /// ----------------------------------------------------
/// ---------------------------------------------------- /// ----------------------------------------------------
pub fn init(backend: *const VKBackend, config: AdapterConfig) !Self { pub fn init(
var physical: vk.VkPhysicalDevice = null; config: AdapterConfig,
instance: *const Instance,
alloc: std.mem.Allocator,
) !Self {
// --- GET ADAPTER COUNT ---
var count: u32 = 0; var count: u32 = 0;
if (vk.vkEnumeratePhysicalDevices(instance.raw, &count, null) != vk.VK_SUCCESS) {}
// --- GET PHYSICAL DEVICES COUNT --- // --- CREATE LIST OF ADAPTERS ---
if (vk.vkEnumeratePhysicalDevices(backend.instance.raw, &count, null) != vk.VK_SUCCESS) { const items = try alloc.alloc(vk.VkPhysicalDevice, count);
return error.FailedToEnumeratePhysicalDevices; defer alloc.free(items);
}
if (count == 0) {
return error.FailedToFindGPUWithVKSupport;
}
// --- # --- // --- POPULATE ADAPTERS LIST ---
const devices = try backend.alloc.alloc(vk.VkPhysicalDevice, count); if (vk.vkEnumeratePhysicalDevices(instance.raw, &count, items.ptr) != vk.VK_SUCCESS) {}
defer backend.alloc.free(devices);
// --- GET PHYSICAL DEVICES --- // --- CHECK ADAPTER ---
if (vk.vkEnumeratePhysicalDevices(backend.instance.raw, &count, devices.ptr) != vk.VK_SUCCESS) { var raw: vk.VkPhysicalDevice = null;
return error.FailedToEnumeratePhysicalDevices; for (items) |adapter| {
} var props: vk.VkPhysicalDeviceProperties2 = .{
.sType = vk.VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2,
};
// --- CHECK WHICH DEVICE IS SUITABLE --- var features14: vk.VkPhysicalDeviceVulkan14Features = .{
for (devices, 0..) |device, i| { .sType = vk.VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_4_FEATURES,
if (config.index) |index| { };
if (index != i) continue;
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; if (config.device_type != adapter_type) continue;
break;
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) { if (instance.vk_13_features.dynamic_rendering and features13.dynamicRendering != vk.VK_TRUE) {
return error.FailedToFindSuitableDevice; 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 --- // --- FIND GFX QUEUE FAMILY ---
var queue_family_index: u32 = 0; 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 error.FailedToFindGraphicsQueueFamily;
} }
return .{ return .{
.raw = physical.?, .raw = raw orelse return error.FailedToFindProperAdapter,
}; };
} }
@ -89,22 +166,3 @@ fn findGraphicsQueueFamily(
return false; 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;
}

View file

@ -19,11 +19,11 @@ pub const QueueFamilies = struct {
// FIELDS // FIELDS
// //
raw: vk.VkDevice, raw: *vk.VkDevice_T,
physical_device: vk.VkPhysicalDevice, physical_device: *vk.VkPhysicalDevice_T,
graphics_queue: *vk.VkQueue_T, graphics_queue: *vk.VkQueue_T,
present_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); vk.vkGetDeviceQueue(device, queue_families.present.?, 0, &present_queue);
return .{ return .{
.raw = device, .raw = device.?,
.physical_device = adapter.raw, .physical_device = adapter.raw,
.graphics_queue = graphics_queue.?, .graphics_queue = graphics_queue.?,
.present_queue = present_queue.?, .present_queue = present_queue.?,
.graphics_command_pool = graphics_command_pool, .graphics_command_pool = graphics_command_pool.?,
}; };
} }
/// ---------------------------------------------------- /// ----------------------------------------------------
/// ---------------------------------------------------- /// ----------------------------------------------------
pub fn deinit(self: *Self) void { pub fn deinit(self: *Self) void {
if (self.graphics_command_pool) |raw| { vk.vkDestroyCommandPool(self.raw, self.graphics_command_pool, null);
vk.vkDestroyCommandPool(self.raw, raw, null); vk.vkDestroyDevice(self.raw, null);
self.graphics_command_pool = null;
}
if (self.raw) |raw| {
vk.vkDestroyDevice(raw, null);
self.raw = null;
}
} }
/// ---------------------------------------------------- /// ----------------------------------------------------

View file

@ -44,28 +44,36 @@ pub fn init(
errdefer self.deinit(); errdefer self.deinit();
// --- DECODE PIXELS --- // --- DECODE PIXELS ---
var pixels: ?[]const u8 = null;
var loaded: ?[*]u8 = null; var loaded: ?[*]u8 = null;
var pixels: []const u8 = undefined;
var tex_size: [2]i32 = .{ 0, 0 }; var tex_size: [2]i32 = .{ 0, 0 };
if (config.path) |path| { const needs_pixels = config.usage == .texture;
var tex_channel: i32 = 0;
stb.stbi_set_flip_vertically_on_load(@intFromBool(config.vertical_flip)); if (needs_pixels) {
const data = stb.stbi_load(path.ptr, &tex_size[0], &tex_size[1], &tex_channel, stb.STBI_rgb_alpha) orelse { if (config.path) |path| {
return error.FileNotFound; var tex_channel: i32 = 0;
}; stb.stbi_set_flip_vertically_on_load(@intFromBool(config.vertical_flip));
loaded = data; const data = stb.stbi_load(path.ptr, &tex_size[0], &tex_size[1], &tex_channel, stb.STBI_rgb_alpha) orelse {
pixels = data[0..@as(usize, @intCast(tex_size[0] * tex_size[1] * 4))]; return error.FileNotFound;
} else if (config.data) |data| { };
pixels = data; loaded = data;
} else { pixels = data[0..@as(usize, @intCast(tex_size[0] * tex_size[1] * 4))];
return error.MissingImageSource; } else if (config.data) |data| {
pixels = data;
} else {
return error.MissingImageSource;
}
} }
defer if (loaded) |data| stb.stbi_image_free(data); defer if (loaded) |data| stb.stbi_image_free(data);
// --- SIZE --- // --- SIZE ---
const size: [2]u32 = blk: { 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; if (config.size) |size| break :blk size;
return error.SizeRequired; return error.SizeRequired;
}; };
@ -132,7 +140,9 @@ pub fn init(
_ = vk.vkBindImageMemory(device.raw, self.raw, self.memory, 0); _ = vk.vkBindImageMemory(device.raw, self.raw, self.memory, 0);
// --- UPLOAD --- // --- UPLOAD ---
try uploadPixels(&self, pixels); if (needs_pixels) {
try uploadPixels(&self, pixels.?);
}
// --- DEFAULT IMAGE VIEW --- // --- DEFAULT IMAGE VIEW ---
var view_create_info: vk.VkImageViewCreateInfo = .{ var view_create_info: vk.VkImageViewCreateInfo = .{

View file

@ -2,14 +2,14 @@
//! `🗲` Vulkan Instance `🗲` //! `🗲` Vulkan Instance `🗲`
//! ---------------------------------------------------- //! ----------------------------------------------------
const std = @import("std");
const gtl = @import("gtl");
const vk = @import("vulkan"); const vk = @import("vulkan");
const Resource = @import("resource.zig"); const std = @import("std");
const Window = @import("../common.zig").Window; const cmn = @import("../../common.zig");
const MainConfig = @import("../../gfx.zig").Config; const gtl = @import("gtl");
const Self = @This(); const Self = @This();
const Window = cmn.Window;
// //
// FIELDS // FIELDS
// //
@ -18,26 +18,39 @@ raw: *vk.VkInstance_T,
messenger: ?vk.VkDebugUtilsMessengerEXT = null, messenger: ?vk.VkDebugUtilsMessengerEXT = null,
pfn_destroy_debug_utils_messenger: vk.PFN_vkDestroyDebugUtilsMessengerEXT = 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( pub fn init(config: cmn.VKInstanceConfig, alloc: std.mem.Allocator) !Self {
config: MainConfig,
alloc: std.mem.Allocator,
) !Self {
const validation_layers: []const [*:0]const u8 = &.{ const validation_layers: []const [*:0]const u8 = &.{
"VK_LAYER_KHRONOS_validation", "VK_LAYER_KHRONOS_validation",
}; };
const extensions = getWindowExtensions( const extensions: []const [*:0]const u8 = &.{
config.window, "VK_KHR_surface", "VK_KHR_xlib_surface", "VK_EXT_debug_utils",
config.enable_validation, };
);
// const extensions = getWindowExtensions(
// config.window,
// config.enable_validation,
// );
var app_info: vk.VkApplicationInfo = .{ var app_info: vk.VkApplicationInfo = .{
.sType = vk.VK_STRUCTURE_TYPE_APPLICATION_INFO, .sType = vk.VK_STRUCTURE_TYPE_APPLICATION_INFO,
.pApplicationName = config.app_name.ptr, // TODO:
.pEngineName = config.engine_name.ptr, // .pApplicationName = config.app_name.ptr,
.apiVersion = vk.VK_API_VERSION_1_3, // .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; var messenger_info: vk.VkDebugUtilsMessengerCreateInfoEXT = undefined;
@ -49,18 +62,18 @@ pub fn init(
.ppEnabledExtensionNames = extensions.ptr, .ppEnabledExtensionNames = extensions.ptr,
}; };
if (config.enable_validation) { // if (config.enable_validation) {
if (!try checkValidationLayerSupport(validation_layers, alloc)) { if (!try checkValidationLayerSupport(validation_layers, alloc)) {
return error.ValidationLayerNotAvailable; return error.ValidationLayerNotAvailable;
}
create_info.enabledLayerCount = @intCast(validation_layers.len);
create_info.ppEnabledLayerNames = validation_layers.ptr;
messenger_info = makeMessengerInfo();
create_info.pNext = &messenger_info;
} }
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; var instance: vk.VkInstance = null;
if (vk.vkCreateInstance(&create_info, null, &instance) != vk.VK_SUCCESS) { if (vk.vkCreateInstance(&create_info, null, &instance) != vk.VK_SUCCESS) {
return error.FailedToCreateVulkanInstance; return error.FailedToCreateVulkanInstance;
@ -69,23 +82,28 @@ pub fn init(
var messenger: vk.VkDebugUtilsMessengerEXT = null; var messenger: vk.VkDebugUtilsMessengerEXT = null;
var pfn_destroy: vk.PFN_vkDestroyDebugUtilsMessengerEXT = null; var pfn_destroy: vk.PFN_vkDestroyDebugUtilsMessengerEXT = null;
if (config.enable_validation) { // if (config.enable_validation) {
const pfn_create: vk.PFN_vkCreateDebugUtilsMessengerEXT = @ptrCast( const pfn_create: vk.PFN_vkCreateDebugUtilsMessengerEXT = @ptrCast(
vk.vkGetInstanceProcAddr(instance.?, "vkCreateDebugUtilsMessengerEXT"), vk.vkGetInstanceProcAddr(instance.?, "vkCreateDebugUtilsMessengerEXT"),
); );
pfn_destroy = @ptrCast( pfn_destroy = @ptrCast(
vk.vkGetInstanceProcAddr(instance.?, "vkDestroyDebugUtilsMessengerEXT"), vk.vkGetInstanceProcAddr(instance.?, "vkDestroyDebugUtilsMessengerEXT"),
); );
if (pfn_create.?(instance.?, &messenger_info, null, &messenger) != vk.VK_SUCCESS) { if (pfn_create.?(instance.?, &messenger_info, null, &messenger) != vk.VK_SUCCESS) {
return error.FailedToCreateDebugUtilsMessenger; return error.FailedToCreateDebugUtilsMessenger;
}
} }
// }
return .{ return .{
.raw = instance.?, .raw = instance.?,
.messenger = messenger, .messenger = messenger,
.pfn_destroy_debug_utils_messenger = pfn_destroy, .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,
}; };
} }

View file

@ -23,8 +23,8 @@ const MAX_WRITES = MAX_BINDINGS;
// FIELDS // FIELDS
// //
raw: vk.VkPipeline = null, raw: *vk.VkPipeline_T,
layout: vk.VkPipelineLayout = null, layout: *vk.VkPipelineLayout_T,
device: *const Device, device: *const Device,
descriptor_set_layout: vk.VkDescriptorSetLayout = null, descriptor_set_layout: vk.VkDescriptorSetLayout = null,
@ -50,6 +50,9 @@ pub fn init(
alloc: std.mem.Allocator, alloc: std.mem.Allocator,
) !Self { ) !Self {
var self: Self = .{ var self: Self = .{
.raw = undefined,
.layout = undefined,
.device = device, .device = device,
.uniforms = &.{}, .uniforms = &.{},
.uniform_offsets = &.{}, .uniform_offsets = &.{},
@ -59,10 +62,6 @@ pub fn init(
errdefer self.deinit(); errdefer self.deinit();
// --- COMPUTE UNIFORM LAYOUT --- // --- 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; var uniform_size: u32 = 0;
if (config.uniforms.len > 0) { if (config.uniforms.len > 0) {
var props: vk.VkPhysicalDeviceProperties = .{}; var props: vk.VkPhysicalDeviceProperties = .{};
@ -158,7 +157,7 @@ pub fn init(
.sType = vk.VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, .sType = vk.VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
.stage = vk.VK_SHADER_STAGE_VERTEX_BIT, .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, .module = raw_vert_shader.raw,
}; };
@ -166,7 +165,7 @@ pub fn init(
.sType = vk.VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, .sType = vk.VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
.stage = vk.VK_SHADER_STAGE_FRAGMENT_BIT, .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, .module = raw_frag_shader.raw,
}; };
@ -545,12 +544,10 @@ pub fn deinit(self: *Self) void {
vk.vkDestroyBuffer(self.device.raw, b, null); vk.vkDestroyBuffer(self.device.raw, b, null);
} }
} }
if (self.layout) |layout| {
vk.vkDestroyPipelineLayout(self.device.raw, layout, null); vk.vkDestroyPipelineLayout(self.device.raw, self.layout, null);
} vk.vkDestroyPipeline(self.device.raw, self.raw, null);
if (self.raw) |raw| {
vk.vkDestroyPipeline(self.device.raw, raw, null);
}
self.alloc.free(self.uniforms); self.alloc.free(self.uniforms);
self.alloc.free(self.uniform_offsets); self.alloc.free(self.uniform_offsets);
} }

View file

@ -12,7 +12,7 @@ const Self = @This();
// FIELDS // FIELDS
// //
raw: vk.VkShaderModule, raw: *vk.VkShaderModule_T,
device: *const Device, device: *const Device,
/// ---------------------------------------------------- /// ----------------------------------------------------
@ -40,10 +40,7 @@ pub fn init(
/// ---------------------------------------------------- /// ----------------------------------------------------
/// ---------------------------------------------------- /// ----------------------------------------------------
pub fn deinit(self: *Self) void { pub fn deinit(self: *Self) void {
if (self.raw) |raw| { vk.vkDestroyShaderModule(self.device.raw, self.raw, null);
vk.vkDestroyShaderModule(self.device.raw, raw, null);
self.raw = null;
}
} }
/// ---------------------------------------------------- /// ----------------------------------------------------

View file

@ -4,10 +4,11 @@
const std = @import("std"); const std = @import("std");
const vk = @import("vulkan"); const vk = @import("vulkan");
const Instance = @import("../instance.zig");
const Window = @import("../../common.zig").Window; const Window = @import("../../common.zig").Window;
const Self = @This(); const Self = @This();
const Instance = @import("instance.zig");
// //
// FIELDS // FIELDS
// //
@ -17,7 +18,7 @@ raw: *vk.VkSurfaceKHR_T,
/// ---------------------------------------------------- /// ----------------------------------------------------
/// ---------------------------------------------------- /// ----------------------------------------------------
pub fn init( pub fn init(
instance: *Instance, instance: *const Instance,
window: Window, window: Window,
) !Self { ) !Self {
const surface: *vk.VkSurfaceKHR_T = blk: { 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); vk.vkDestroySurfaceKHR(instance.raw, self.raw, null);
} }

View file

@ -27,12 +27,15 @@ pub fn init(
adapter: *const Adapter, adapter: *const Adapter,
device: *const Device, device: *const Device,
) !Self { ) !Self {
var image = try VKImage.init(config.image, adapter, device); var image: VKImage = try .init(config.image, adapter, device);
errdefer image.deinit(); errdefer image.deinit();
var sampler: VKSampler = try .init(config.sampler, device);
errdefer sampler.deinit();
return .{ return .{
.image = image, .image = image,
.sampler = try VKSampler.init(config.sampler, device), .sampler = sampler,
}; };
} }

View file

@ -1,5 +1,5 @@
//! ---------------------------------------------------- //! ----------------------------------------------------
//! `🗲` Vulkan RHI `🗲` //! `🗲` Vulkan RHI 1.4 `🗲`
//! 😭 Send Help 😭 //! 😭 Send Help 😭
//! ---------------------------------------------------- //! ----------------------------------------------------
@ -8,9 +8,9 @@ const vk = @import("vulkan");
const gtl = @import("gtl"); const gtl = @import("gtl");
const common = @import("../common.zig"); const common = @import("../common.zig");
const Instance = @import("instance.zig");
const Resource = @import("resource.zig"); const Resource = @import("resource.zig");
const SwapchainResource = @import("resource/swapchain.zig"); const SwapchainResource = @import("resource/swapchain.zig");
const VKImage = @import("resource/image.zig");
const MainConfig = @import("../../gfx.zig").Config; const MainConfig = @import("../../gfx.zig").Config;
const Handle = gtl.Handle; const Handle = gtl.Handle;
@ -49,16 +49,6 @@ const AdapterInfo = common.AdapterInfo;
// --- # --- // --- # ---
pub const MAX_FRAMES_IN_FLIGHT: usize = 3; 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 { const Frame = struct {
@ -74,13 +64,13 @@ const Frame = struct {
// FIELDS // FIELDS
// //
instance: Instance,
resource: Resource, resource: Resource,
config: MainConfig,
frames: [MAX_FRAMES_IN_FLIGHT]Frame = .{ .{}, .{}, .{} }, frames: [MAX_FRAMES_IN_FLIGHT]Frame = .{ .{}, .{}, .{} },
current_frame: usize = 0, current_frame: usize = 0,
active_pass_target: ?Handle(Texture) = null,
render_finished: []vk.VkSemaphore = &.{}, render_finished: []vk.VkSemaphore = &.{},
sync_device: ?*vk.VkDevice_T = null, sync_device: ?*vk.VkDevice_T = null,
@ -94,19 +84,9 @@ io: std.Io,
/// ---------------------------------------------------- /// ----------------------------------------------------
/// ---------------------------------------------------- /// ----------------------------------------------------
pub fn init( pub fn init(alloc: std.mem.Allocator, io: std.Io) Self {
config: MainConfig,
alloc: std.mem.Allocator,
io: std.Io,
) !Self {
// --- INSTANCE ---
var instance: Instance = try .init(config, alloc);
errdefer instance.deinit();
return .{ return .{
.instance = instance,
.resource = .init(alloc), .resource = .init(alloc),
.config = config,
.alloc = alloc, .alloc = alloc,
.io = io, .io = io,
}; };
@ -133,8 +113,36 @@ pub fn deinit(self: *Self) void {
} }
} }
self.resource.deinit(&self.instance); self.resource.deinit();
self.instance.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) { pub fn makeAdapter(self: *Self, config: AdapterConfig, instance: Handle(common.Instance)) !Handle(Adapter) {
return try self.resource.adapters.put(try .init(self, config)); 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_DISCRETE_GPU => .discrete,
vk.VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU => .integrated, vk.VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU => .integrated,
vk.VK_PHYSICAL_DEVICE_TYPE_CPU => .software, vk.VK_PHYSICAL_DEVICE_TYPE_CPU => .software,
else => .any, else => .discrete,
}, },
.device_id = props.deviceID, .device_id = props.deviceID,
.vendor_id = props.vendorID, .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 { 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; 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) { pub fn makeSurface(
return try self.resource.surfaces.put(try .init(&self.instance, self.config.window)); 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 { 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; 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 { 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; return error.PipelineNotFound;
} }
@ -438,7 +452,7 @@ pub fn bindBuffer(self: *Self, buffer: Handle(Buffer)) !void {
switch (raw.usage) { switch (raw.usage) {
.vertex => vk.vkCmdBindVertexBuffers(cmd, 0, 1, &buffers, &offsets), .vertex => vk.vkCmdBindVertexBuffers(cmd, 0, 1, &buffers, &offsets),
.index => vk.vkCmdBindIndexBuffer(cmd, raw.raw, 0, vk.VK_INDEX_TYPE_UINT32), .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_device = self.resource.devices.get(device) orelse return error.DeviceNotFound;
const raw_swapchain = self.resource.swapchains.get(swapchain) orelse return error.SwapchainNotFound; 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(); const frame = self.currentFrame();
@ -583,9 +600,17 @@ pub fn beginPass(
const frame = self.currentFrame(); 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 = .{ const extent: vk.VkExtent2D = .{
.width = config.width orelse raw_swapchain.extent.width, .width = config.width orelse if (target_image) |img| img.width else raw_swapchain.extent.width,
.height = config.height orelse raw_swapchain.extent.height, .height = config.height orelse if (target_image) |img| img.height else raw_swapchain.extent.height,
}; };
const barrier: vk.VkImageMemoryBarrier = .{ const barrier: vk.VkImageMemoryBarrier = .{
@ -600,7 +625,7 @@ pub fn beginPass(
.srcQueueFamilyIndex = vk.VK_QUEUE_FAMILY_IGNORED, .srcQueueFamilyIndex = vk.VK_QUEUE_FAMILY_IGNORED,
.dstQueueFamilyIndex = 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 = .{ .subresourceRange = .{
.aspectMask = vk.VK_IMAGE_ASPECT_COLOR_BIT, .aspectMask = vk.VK_IMAGE_ASPECT_COLOR_BIT,
@ -704,7 +729,7 @@ pub fn beginPass(
const color_attachment: vk.VkRenderingAttachmentInfo = .{ const color_attachment: vk.VkRenderingAttachmentInfo = .{
.sType = vk.VK_STRUCTURE_TYPE_RENDERING_ATTACHMENT_INFO, .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, .imageLayout = vk.VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
.loadOp = switch (config.load_op) { .loadOp = switch (config.load_op) {
.clear => vk.VK_ATTACHMENT_LOAD_OP_CLEAR, .clear => vk.VK_ATTACHMENT_LOAD_OP_CLEAR,
@ -777,6 +802,100 @@ pub fn endPass(
vk.vkCmdEndRendering(frame.cmd_buf); 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 = .{ const barrier: vk.VkImageMemoryBarrier = .{
.sType = vk.VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, .sType = vk.VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
@ -824,12 +943,12 @@ pub fn endPass(
pub fn bindPipeline(self: *Self, pipeline: Handle(Pipeline)) !void { pub fn bindPipeline(self: *Self, pipeline: Handle(Pipeline)) !void {
const raw_pipeline = self.resource.pipelines.get(pipeline) orelse return error.PipelineNotFound; const raw_pipeline = self.resource.pipelines.get(pipeline) orelse return error.PipelineNotFound;
const frame = self.currentFrame(); 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| { if (raw_pipeline.descriptor_sets[self.current_frame]) |set| {
vk.vkCmdBindDescriptorSets( vk.vkCmdBindDescriptorSets(
frame.cmd_buf, frame.cmd_buf,
vk.VK_PIPELINE_BIND_POINT_GRAPHICS, vk.VK_PIPELINE_BIND_POINT_GRAPHICS,
raw_pipeline.layout.?, raw_pipeline.layout,
0, 0,
1, 1,
&set, &set,
@ -921,3 +1040,14 @@ fn ensureFrameSync(
frame.fence = fence.?; 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,
};
}

53
tools/shaders.bash Executable file
View file

@ -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 <input_path> -o <output_path>"
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 <input_path> -o <output_path>"
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 <input_path> -o <output_path>"
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

View file

@ -1,5 +0,0 @@
const std = @import("std");
pub fn main(init: std.process.Init) !void {
_ = init;
}

BIN
zig-out/bin/3D Executable file

Binary file not shown.

BIN
zig-out/bin/imgui Executable file

Binary file not shown.

Binary file not shown.