Uniforms
This commit is contained in:
parent
3f8b5617e0
commit
ce1b032361
17 changed files with 538 additions and 176 deletions
19
README.md
19
README.md
|
|
@ -11,5 +11,22 @@ Low cortisol crossplatform RHI (Rendering Hardware Interface)
|
||||||
- Dead simple + Performance + Flexible
|
- Dead simple + Performance + Flexible
|
||||||
- Handles
|
- Handles
|
||||||
|
|
||||||
# Examples
|
## Architecture
|
||||||
|
```text
|
||||||
|
examples/simple/simple.zig
|
||||||
|
|
||||||
|
src/gfx.zig
|
||||||
|
└─ Selected Backend
|
||||||
|
|
||||||
|
src/rhi/root.zig
|
||||||
|
└─ Common / Handles / Configs
|
||||||
|
|
||||||
|
src/rhi/vulkan/vulkan.zig
|
||||||
|
└─ Vulkan Backend / RHI
|
||||||
|
|
||||||
|
src/rhi/vulkan/resource.zig
|
||||||
|
└─ Adapter / Device / Shader
|
||||||
|
```
|
||||||
|
|
||||||
|
## Examples
|
||||||
- ```zig build run-simple```
|
- ```zig build run-simple```
|
||||||
|
|
|
||||||
Binary file not shown.
Binary file not shown.
|
|
@ -1,7 +0,0 @@
|
||||||
#version 450
|
|
||||||
|
|
||||||
layout(location = 0) out vec4 outColor;
|
|
||||||
|
|
||||||
void main() {
|
|
||||||
outColor = vec4(0.2, 0.2, 0.8, 1.0);
|
|
||||||
}
|
|
||||||
BIN
examples/assets/shaders/compiled/simple.frag.spv
Normal file
BIN
examples/assets/shaders/compiled/simple.frag.spv
Normal file
Binary file not shown.
BIN
examples/assets/shaders/compiled/simple.vert.spv
Normal file
BIN
examples/assets/shaders/compiled/simple.vert.spv
Normal file
Binary file not shown.
11
examples/assets/shaders/simple.frag
Normal file
11
examples/assets/shaders/simple.frag
Normal file
|
|
@ -0,0 +1,11 @@
|
||||||
|
#version 450
|
||||||
|
|
||||||
|
layout(binding = 0) uniform UnlitMaterial {
|
||||||
|
vec4 albedo;
|
||||||
|
} material;
|
||||||
|
|
||||||
|
layout(location = 0) out vec4 outColor;
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
outColor = material.albedo;
|
||||||
|
}
|
||||||
|
|
@ -1,5 +1,9 @@
|
||||||
#version 450
|
#version 450
|
||||||
|
|
||||||
|
layout(binding = 0) uniform UnlitMaterial {
|
||||||
|
vec4 albedo;
|
||||||
|
} material;
|
||||||
|
|
||||||
layout(location = 0) in vec2 inPosition;
|
layout(location = 0) in vec2 inPosition;
|
||||||
layout(location = 1) in vec2 inNormal;
|
layout(location = 1) in vec2 inNormal;
|
||||||
layout(location = 2) in vec2 inUV;
|
layout(location = 2) in vec2 inUV;
|
||||||
|
|
@ -5,6 +5,12 @@ const std = @import("std");
|
||||||
const sdl = @import("sdl");
|
const sdl = @import("sdl");
|
||||||
const Gfx = @import("gfx");
|
const Gfx = @import("gfx");
|
||||||
|
|
||||||
|
/// ----------------------------------------------------
|
||||||
|
/// ----------------------------------------------------
|
||||||
|
const UnlitMaterial = struct {
|
||||||
|
albedo: [4]f32 = .{ 1, 1, 1, 1 },
|
||||||
|
};
|
||||||
|
|
||||||
/// ----------------------------------------------------
|
/// ----------------------------------------------------
|
||||||
/// ----------------------------------------------------
|
/// ----------------------------------------------------
|
||||||
const Vertex = struct {
|
const Vertex = struct {
|
||||||
|
|
@ -33,6 +39,12 @@ const indices = [_]u32{
|
||||||
/// ----------------------------------------------------
|
/// ----------------------------------------------------
|
||||||
pub fn main(init: std.process.Init) !void {
|
pub fn main(init: std.process.Init) !void {
|
||||||
|
|
||||||
|
//
|
||||||
|
// DATA
|
||||||
|
//
|
||||||
|
|
||||||
|
var material: UnlitMaterial = .{ .albedo = .{ 1.0, 0.2, 0.2, 1.0 } };
|
||||||
|
|
||||||
//
|
//
|
||||||
// SDL
|
// SDL
|
||||||
//
|
//
|
||||||
|
|
@ -42,7 +54,7 @@ pub fn main(init: std.process.Init) !void {
|
||||||
defer sdl.SDL_Quit();
|
defer sdl.SDL_Quit();
|
||||||
|
|
||||||
// --- # ---
|
// --- # ---
|
||||||
const window = sdl.SDL_CreateWindow("NYXGFX", 800, 600, 0) orelse return error.FailedToCreateWindow;
|
const window = sdl.SDL_CreateWindow("NYXGFX", 800, 600, 0) orelse return error.FailedTomakeWindow;
|
||||||
defer sdl.SDL_DestroyWindow(window);
|
defer sdl.SDL_DestroyWindow(window);
|
||||||
|
|
||||||
// --- # ---
|
// --- # ---
|
||||||
|
|
@ -66,23 +78,21 @@ pub fn main(init: std.process.Init) !void {
|
||||||
defer gfx.deinit();
|
defer gfx.deinit();
|
||||||
|
|
||||||
// --- # ---
|
// --- # ---
|
||||||
const adapter = try gfx.createAdapter();
|
const adapter = try gfx.makeAdapter(.{});
|
||||||
const surface = try gfx.createSurface();
|
const surface = try gfx.makeSurface();
|
||||||
const device = try gfx.createDevice(adapter, surface);
|
const device = try gfx.makeDevice(adapter, surface);
|
||||||
const swapchain = try gfx.createSwapchain(adapter, device, surface);
|
const swapchain = try gfx.makeSwapchain(adapter, device, surface);
|
||||||
|
|
||||||
// --- BUFFERS ---
|
// --- BUFFERS ---
|
||||||
const vbuf = try gfx.createBuffer(vertices, .vertex, adapter, device);
|
const vbuf = try gfx.makeBuffer(vertices, .vertex, adapter, device);
|
||||||
const ibuf = try gfx.createBuffer(indices, .index, adapter, device);
|
const ibuf = try gfx.makeBuffer(indices, .index, adapter, device);
|
||||||
|
|
||||||
// --- SHADERS ---
|
// --- SHADERS ---
|
||||||
const simple_shader = try gfx.createShader(
|
const simple_vert = try gfx.makeShader("examples/assets/shaders/compiled/simple.vert.spv", device);
|
||||||
"assets/shaders/compiled/simple.vert.spv",
|
const simple_frag = try gfx.makeShader("examples/assets/shaders/compiled/simple.frag.spv", device);
|
||||||
"assets/shaders/compiled/simple.frag.spv",
|
|
||||||
device,
|
|
||||||
);
|
|
||||||
|
|
||||||
const pipeline = try gfx.createPipeline(.{
|
// --- PIPELINE ---
|
||||||
|
const pipeline = try gfx.makePipeline(.{
|
||||||
.vertex_attributes = &.{
|
.vertex_attributes = &.{
|
||||||
.{ .location = 0, .format = .vec2, .offset = @offsetOf(Vertex, "pos") },
|
.{ .location = 0, .format = .vec2, .offset = @offsetOf(Vertex, "pos") },
|
||||||
.{ .location = 1, .format = .vec2, .offset = @offsetOf(Vertex, "normal") },
|
.{ .location = 1, .format = .vec2, .offset = @offsetOf(Vertex, "normal") },
|
||||||
|
|
@ -90,18 +100,24 @@ pub fn main(init: std.process.Init) !void {
|
||||||
},
|
},
|
||||||
.vertex_binding = .{ .stride = @sizeOf(Vertex) },
|
.vertex_binding = .{ .stride = @sizeOf(Vertex) },
|
||||||
|
|
||||||
.shader = simple_shader,
|
.uniforms = &.{
|
||||||
|
.{ .name = "material", .offset = 0, .size = @sizeOf(UnlitMaterial) },
|
||||||
|
},
|
||||||
|
|
||||||
|
.vert_shader = simple_vert,
|
||||||
|
.frag_shader = simple_frag,
|
||||||
|
|
||||||
.device = device,
|
.device = device,
|
||||||
.swapchain = swapchain,
|
.swapchain = swapchain,
|
||||||
});
|
});
|
||||||
|
|
||||||
try pipeline.setUniform("uTime", 0.1);
|
// --- MISC ---
|
||||||
try pipeline.setUniform("uTime", 0.1);
|
|
||||||
|
|
||||||
var event: sdl.SDL_Event = undefined;
|
var event: sdl.SDL_Event = undefined;
|
||||||
var running: bool = true;
|
var running: bool = true;
|
||||||
|
var i: f32 = 0;
|
||||||
|
|
||||||
while (running) {
|
while (running) {
|
||||||
|
// --- INPUTS ---
|
||||||
while (sdl.SDL_PollEvent(&event)) {
|
while (sdl.SDL_PollEvent(&event)) {
|
||||||
switch (event.type) {
|
switch (event.type) {
|
||||||
sdl.SDL_EVENT_QUIT => running = false,
|
sdl.SDL_EVENT_QUIT => running = false,
|
||||||
|
|
@ -109,24 +125,34 @@ pub fn main(init: std.process.Init) !void {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// --- ANIMATION ---
|
||||||
|
i += 0.001;
|
||||||
|
i = @mod(i, 1);
|
||||||
|
material.albedo[1] = i;
|
||||||
|
try pipeline.setUniform("material", material);
|
||||||
|
|
||||||
|
// --- FRAME ---
|
||||||
try gfx.beginFrame(swapchain, device);
|
try gfx.beginFrame(swapchain, device);
|
||||||
defer gfx.endFrame(swapchain, device) catch unreachable;
|
defer gfx.endFrame(swapchain, device) catch unreachable;
|
||||||
|
|
||||||
{
|
// --- NEW PASS ---
|
||||||
try gfx.beginRendering(swapchain);
|
if (gfx.beginPass(swapchain, .{
|
||||||
defer gfx.endRendering(swapchain) catch unreachable;
|
.clear_color = .{ 0.01, 0.01, 0.01, 1.0 },
|
||||||
|
})) |pass| {
|
||||||
|
defer pass.end();
|
||||||
|
|
||||||
try pipeline.bind();
|
|
||||||
try vbuf.bind();
|
try vbuf.bind();
|
||||||
try ibuf.bind();
|
try ibuf.bind();
|
||||||
try gfx.drawIndexed(indices.len, 1, 0, 0, 0);
|
|
||||||
|
try pipeline.bind();
|
||||||
|
pass.drawIndexed(indices.len, 1, 0, 0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
// if (gfx.beginRendering(...)) |pass| {
|
// --- NEW PASS ---
|
||||||
// defer pass.end();
|
if (gfx.beginPass(swapchain, .{
|
||||||
//
|
.load_op = .load,
|
||||||
// try pass.bindPipeline(...);
|
})) |pass| {
|
||||||
// try pass.draw(...);
|
defer pass.end();
|
||||||
// }
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
86
src/gfx.zig
86
src/gfx.zig
|
|
@ -11,8 +11,11 @@ const Handle = gtl.Handle;
|
||||||
const Self = @This();
|
const Self = @This();
|
||||||
|
|
||||||
// --- CONFIGS ---
|
// --- CONFIGS ---
|
||||||
|
const AdapterConfig = common.AdapterConfig;
|
||||||
|
const RenderPassConfig = common.RenderPassConfig;
|
||||||
const PipelineConfig = common.PipelineConfig;
|
const PipelineConfig = common.PipelineConfig;
|
||||||
const BufferUsage = common.BufferUsage;
|
const BufferUsage = common.BufferUsage;
|
||||||
|
const Pass = common.Pass;
|
||||||
|
|
||||||
// --- HANDLES ---
|
// --- HANDLES ---
|
||||||
const Window = @import("rhi/root.zig").Window;
|
const Window = @import("rhi/root.zig").Window;
|
||||||
|
|
@ -88,21 +91,21 @@ pub fn deinit(self: *Self) void {
|
||||||
|
|
||||||
/// ----------------------------------------------------
|
/// ----------------------------------------------------
|
||||||
/// ----------------------------------------------------
|
/// ----------------------------------------------------
|
||||||
pub fn createAdapter(self: *Self) !Handle(Adapter) {
|
pub fn makeAdapter(self: *Self, config: AdapterConfig) !Handle(Adapter) {
|
||||||
return try switch (self.ctx) {
|
return try switch (self.ctx) {
|
||||||
.vulkan => |*v| v.createAdapter(),
|
.vulkan => |*v| v.makeAdapter(config),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
/// ----------------------------------------------------
|
/// ----------------------------------------------------
|
||||||
/// ----------------------------------------------------
|
/// ----------------------------------------------------
|
||||||
pub fn createDevice(
|
pub fn makeDevice(
|
||||||
self: *Self,
|
self: *Self,
|
||||||
adapter: Handle(Adapter),
|
adapter: Handle(Adapter),
|
||||||
surface: Handle(Surface),
|
surface: Handle(Surface),
|
||||||
) !Handle(Device) {
|
) !Handle(Device) {
|
||||||
return try switch (self.ctx) {
|
return try switch (self.ctx) {
|
||||||
.vulkan => |*v| v.createDevice(adapter, surface),
|
.vulkan => |*v| v.makeDevice(adapter, surface),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -116,7 +119,7 @@ pub fn destroyDevice(self: *Self, device: Handle(Device)) !void {
|
||||||
|
|
||||||
/// ----------------------------------------------------
|
/// ----------------------------------------------------
|
||||||
/// ----------------------------------------------------
|
/// ----------------------------------------------------
|
||||||
pub fn createBuffer(
|
pub fn makeBuffer(
|
||||||
self: *Self,
|
self: *Self,
|
||||||
value: anytype,
|
value: anytype,
|
||||||
usage: BufferUsage,
|
usage: BufferUsage,
|
||||||
|
|
@ -126,7 +129,7 @@ pub fn createBuffer(
|
||||||
const size = @sizeOf(@TypeOf(value));
|
const size = @sizeOf(@TypeOf(value));
|
||||||
|
|
||||||
const handle = try switch (self.ctx) {
|
const handle = try switch (self.ctx) {
|
||||||
.vulkan => |*v| v.createBuffer(size, usage, .exclusive, adapter, device),
|
.vulkan => |*v| v.makeBuffer(size, usage, .exclusive, adapter, device),
|
||||||
};
|
};
|
||||||
|
|
||||||
var buffer: Buffer = .{
|
var buffer: Buffer = .{
|
||||||
|
|
@ -140,45 +143,52 @@ pub fn createBuffer(
|
||||||
}
|
}
|
||||||
|
|
||||||
/// ----------------------------------------------------
|
/// ----------------------------------------------------
|
||||||
|
/// TODO:
|
||||||
/// ----------------------------------------------------
|
/// ----------------------------------------------------
|
||||||
pub fn createSurface(self: *Self) !Handle(Surface) {
|
pub fn getRawVKBuffer(self: *Self, buffer: Handle(Buffer)) !void {
|
||||||
|
_ = self;
|
||||||
|
_ = buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// ----------------------------------------------------
|
||||||
|
/// ----------------------------------------------------
|
||||||
|
pub fn makeSurface(self: *Self) !Handle(Surface) {
|
||||||
return try switch (self.ctx) {
|
return try switch (self.ctx) {
|
||||||
.vulkan => |*v| v.createSurface(),
|
.vulkan => |*v| v.makeSurface(),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
/// ----------------------------------------------------
|
/// ----------------------------------------------------
|
||||||
/// ----------------------------------------------------
|
/// ----------------------------------------------------
|
||||||
pub fn createSwapchain(
|
pub fn makeSwapchain(
|
||||||
self: *Self,
|
self: *Self,
|
||||||
adapter: Handle(Adapter),
|
adapter: Handle(Adapter),
|
||||||
device: Handle(Device),
|
device: Handle(Device),
|
||||||
surface: Handle(Surface),
|
surface: Handle(Surface),
|
||||||
) !Handle(Swapchain) {
|
) !Handle(Swapchain) {
|
||||||
return try switch (self.ctx) {
|
return try switch (self.ctx) {
|
||||||
.vulkan => |*v| v.createSwapchain(adapter, device, surface),
|
.vulkan => |*v| v.makeSwapchain(adapter, device, surface),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
/// ----------------------------------------------------
|
/// ----------------------------------------------------
|
||||||
/// ----------------------------------------------------
|
/// ----------------------------------------------------
|
||||||
pub fn createShader(
|
pub fn makeShader(
|
||||||
self: *Self,
|
self: *Self,
|
||||||
vert_spv_path: []const u8,
|
spv_path: []const u8,
|
||||||
frag_spv_path: []const u8,
|
|
||||||
device: Handle(Device),
|
device: Handle(Device),
|
||||||
) !Handle(Shader) {
|
) !Handle(Shader) {
|
||||||
return try switch (self.ctx) {
|
return try switch (self.ctx) {
|
||||||
.vulkan => |*v| v.createShader(vert_spv_path, frag_spv_path, device),
|
.vulkan => |*v| v.makeShader(spv_path, device),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
/// ----------------------------------------------------
|
/// ----------------------------------------------------
|
||||||
/// ----------------------------------------------------
|
/// ----------------------------------------------------
|
||||||
pub fn createPipeline(self: *Self, config: PipelineConfig) !Pipeline {
|
pub fn makePipeline(self: *Self, config: PipelineConfig) !Pipeline {
|
||||||
return .{
|
return .{
|
||||||
.handle = try switch (self.ctx) {
|
.handle = try switch (self.ctx) {
|
||||||
.vulkan => |*v| v.createPipeline(config),
|
.vulkan => |*v| v.makePipeline(config),
|
||||||
},
|
},
|
||||||
.device = config.device,
|
.device = config.device,
|
||||||
.gfx = self,
|
.gfx = self,
|
||||||
|
|
@ -211,43 +221,17 @@ pub fn endFrame(
|
||||||
|
|
||||||
/// ----------------------------------------------------
|
/// ----------------------------------------------------
|
||||||
/// ----------------------------------------------------
|
/// ----------------------------------------------------
|
||||||
pub fn beginRendering(
|
pub fn beginPass(
|
||||||
self: *Self,
|
self: *Self,
|
||||||
swapchain: Handle(Swapchain),
|
swapchain: Handle(Swapchain),
|
||||||
) !void {
|
config: RenderPassConfig,
|
||||||
try switch (self.ctx) {
|
) ?Pass {
|
||||||
.vulkan => |*v| v.beginRendering(swapchain),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
/// ----------------------------------------------------
|
|
||||||
/// ----------------------------------------------------
|
|
||||||
pub fn endRendering(
|
|
||||||
self: *Self,
|
|
||||||
swapchain: Handle(Swapchain),
|
|
||||||
) !void {
|
|
||||||
try switch (self.ctx) {
|
|
||||||
.vulkan => |*v| v.endRendering(swapchain),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
/// ----------------------------------------------------
|
|
||||||
/// ----------------------------------------------------
|
|
||||||
pub fn draw(self: *Self, vertex_count: u32, instance_count: u32, first_vertex: u32, first_instance: u32) !void {
|
|
||||||
try switch (self.ctx) {
|
|
||||||
.vulkan => |*v| v.draw(vertex_count, instance_count, first_vertex, first_instance),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
/// ----------------------------------------------------
|
|
||||||
/// ----------------------------------------------------
|
|
||||||
pub fn drawIndexed(self: *Self, index_count: u32, instance_count: u32, first_index: u32, vertex_offset: i32, first_instance: u32) !void {
|
|
||||||
switch (self.ctx) {
|
switch (self.ctx) {
|
||||||
.vulkan => |*v| {
|
.vulkan => |*v| v.beginRendering(swapchain, config) catch return null,
|
||||||
const frame = v.currentFrame();
|
|
||||||
if (frame.cmd_buf) |cmd| {
|
|
||||||
vk.vkCmdDrawIndexed(cmd, index_count, instance_count, first_index, vertex_offset, first_instance);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return .{
|
||||||
|
.swapchain = swapchain,
|
||||||
|
.gfx = self,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -32,7 +32,24 @@ pub const Window = union(enum) {
|
||||||
|
|
||||||
/// ----------------------------------------------------
|
/// ----------------------------------------------------
|
||||||
/// ----------------------------------------------------
|
/// ----------------------------------------------------
|
||||||
pub const AdapterConfig = struct {};
|
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
|
||||||
|
index: ?u32 = null,
|
||||||
|
};
|
||||||
|
|
||||||
/// ----------------------------------------------------
|
/// ----------------------------------------------------
|
||||||
/// ----------------------------------------------------
|
/// ----------------------------------------------------
|
||||||
|
|
@ -72,16 +89,28 @@ pub const VertexAttribute = struct {
|
||||||
format: Format,
|
format: Format,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// ----------------------------------------------------
|
||||||
|
/// ----------------------------------------------------
|
||||||
|
pub const UniformDesc = struct {
|
||||||
|
name: []const u8,
|
||||||
|
offset: u32,
|
||||||
|
size: u32,
|
||||||
|
};
|
||||||
|
|
||||||
/// ----------------------------------------------------
|
/// ----------------------------------------------------
|
||||||
/// ----------------------------------------------------
|
/// ----------------------------------------------------
|
||||||
pub const PipelineConfig = struct {
|
pub const PipelineConfig = struct {
|
||||||
shader: Handle(Shader),
|
vert_shader: Handle(Shader),
|
||||||
|
frag_shader: Handle(Shader),
|
||||||
|
|
||||||
swapchain: Handle(Swapchain),
|
swapchain: Handle(Swapchain),
|
||||||
device: Handle(Device),
|
device: Handle(Device),
|
||||||
|
|
||||||
vertex_binding: ?VertexBinding = null,
|
vertex_binding: ?VertexBinding = null,
|
||||||
vertex_attributes: []const VertexAttribute = &.{},
|
vertex_attributes: []const VertexAttribute = &.{},
|
||||||
|
|
||||||
|
uniforms: []const UniformDesc = &.{},
|
||||||
|
|
||||||
topology: enum {
|
topology: enum {
|
||||||
triangle_list,
|
triangle_list,
|
||||||
line_list,
|
line_list,
|
||||||
|
|
@ -100,6 +129,65 @@ pub const PipelineConfig = struct {
|
||||||
} = .cw,
|
} = .cw,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// ----------------------------------------------------
|
||||||
|
/// ----------------------------------------------------
|
||||||
|
pub const Pass = struct {
|
||||||
|
swapchain: Handle(Swapchain),
|
||||||
|
gfx: *Gfx,
|
||||||
|
|
||||||
|
pub fn end(self: *const Pass) void {
|
||||||
|
switch (self.gfx.ctx) {
|
||||||
|
.vulkan => |*v| v.endRendering(self.swapchain),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// ----------------------------------------------------
|
||||||
|
/// ----------------------------------------------------
|
||||||
|
pub fn draw(self: *const Pass, vertex_count: u32, instance_count: u32, first_vertex: u32, first_instance: u32) void {
|
||||||
|
switch (self.gfx.ctx) {
|
||||||
|
.vulkan => |*v| v.draw(vertex_count, instance_count, first_vertex, first_instance) catch {},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// ----------------------------------------------------
|
||||||
|
/// ----------------------------------------------------
|
||||||
|
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) {
|
||||||
|
.vulkan => |*v| {
|
||||||
|
const frame = v.currentFrame();
|
||||||
|
if (frame.cmd_buf) |cmd| {
|
||||||
|
vk.vkCmdDrawIndexed(cmd, index_count, instance_count, first_index, vertex_offset, first_instance);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/// ----------------------------------------------------
|
||||||
|
/// ----------------------------------------------------
|
||||||
|
pub const LoadOp = enum {
|
||||||
|
clear,
|
||||||
|
load,
|
||||||
|
dont_care,
|
||||||
|
};
|
||||||
|
|
||||||
|
/// ----------------------------------------------------
|
||||||
|
/// ----------------------------------------------------
|
||||||
|
pub const StoreOp = enum {
|
||||||
|
store,
|
||||||
|
dont_care,
|
||||||
|
};
|
||||||
|
|
||||||
|
/// ----------------------------------------------------
|
||||||
|
/// ----------------------------------------------------
|
||||||
|
pub const RenderPassConfig = struct {
|
||||||
|
clear_color: [4]f32 = .{ 0.0, 0.0, 0.0, 1.0 },
|
||||||
|
load_op: LoadOp = .clear,
|
||||||
|
store_op: StoreOp = .store,
|
||||||
|
width: ?u32 = null,
|
||||||
|
height: ?u32 = null,
|
||||||
|
};
|
||||||
|
|
||||||
/// ----------------------------------------------------
|
/// ----------------------------------------------------
|
||||||
/// ----------------------------------------------------
|
/// ----------------------------------------------------
|
||||||
pub const BufferUsage = enum {
|
pub const BufferUsage = enum {
|
||||||
|
|
@ -175,8 +263,8 @@ pub const Pipeline = struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn setUniform(self: *const Pipeline, name: []const u8, value: anytype) !void {
|
pub fn setUniform(self: *const Pipeline, name: []const u8, value: anytype) !void {
|
||||||
_ = self;
|
try switch (self.gfx.ctx) {
|
||||||
_ = name;
|
.vulkan => |*v| v.setUniform(self.handle, name, value),
|
||||||
_ = value;
|
};
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,8 @@ const std = @import("std");
|
||||||
const gtl = @import("gtl");
|
const gtl = @import("gtl");
|
||||||
const vk = @import("vulkan");
|
const vk = @import("vulkan");
|
||||||
const VKBackend = @import("../vulkan.zig");
|
const VKBackend = @import("../vulkan.zig");
|
||||||
|
const AdapterConfig = @import("../../root.zig").AdapterConfig;
|
||||||
|
const GpuType = @import("../../root.zig").GpuType;
|
||||||
const Self = @This();
|
const Self = @This();
|
||||||
|
|
||||||
//
|
//
|
||||||
|
|
@ -16,7 +18,7 @@ raw: *vk.VkPhysicalDevice_T,
|
||||||
|
|
||||||
/// ----------------------------------------------------
|
/// ----------------------------------------------------
|
||||||
/// ----------------------------------------------------
|
/// ----------------------------------------------------
|
||||||
pub fn init(backend: *const VKBackend) !Self {
|
pub fn init(backend: *const VKBackend, config: AdapterConfig) !Self {
|
||||||
var physical: vk.VkPhysicalDevice = null;
|
var physical: vk.VkPhysicalDevice = null;
|
||||||
var count: u32 = 0;
|
var count: u32 = 0;
|
||||||
|
|
||||||
|
|
@ -38,12 +40,18 @@ pub fn init(backend: *const VKBackend) !Self {
|
||||||
}
|
}
|
||||||
|
|
||||||
// --- CHECK WHICH DEVICE IS SUITABLE ---
|
// --- CHECK WHICH DEVICE IS SUITABLE ---
|
||||||
for (devices) |device| {
|
for (devices, 0..) |device, i| {
|
||||||
if (try isDeviceSuitable(device)) {
|
if (config.index) |index| {
|
||||||
|
if (index != i) continue;
|
||||||
|
}
|
||||||
|
if (try isDeviceSuitable(device, config.gpu_type)) {
|
||||||
physical = device;
|
physical = device;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (physical == null) {
|
||||||
|
return error.FailedToFindSuitableDevice;
|
||||||
|
}
|
||||||
|
|
||||||
// --- FIND GFX QUEUE FAMILY ---
|
// --- FIND GFX QUEUE FAMILY ---
|
||||||
var queue_family_index: u32 = 0;
|
var queue_family_index: u32 = 0;
|
||||||
|
|
@ -83,7 +91,7 @@ fn findGraphicsQueueFamily(
|
||||||
|
|
||||||
/// ----------------------------------------------------
|
/// ----------------------------------------------------
|
||||||
/// ----------------------------------------------------
|
/// ----------------------------------------------------
|
||||||
fn isDeviceSuitable(device: vk.VkPhysicalDevice) !bool {
|
fn isDeviceSuitable(device: vk.VkPhysicalDevice, gpu_type: GpuType) !bool {
|
||||||
var properties: vk.VkPhysicalDeviceProperties = .{};
|
var properties: vk.VkPhysicalDeviceProperties = .{};
|
||||||
vk.vkGetPhysicalDeviceProperties(device, &properties);
|
vk.vkGetPhysicalDeviceProperties(device, &properties);
|
||||||
|
|
||||||
|
|
@ -102,5 +110,12 @@ fn isDeviceSuitable(device: vk.VkPhysicalDevice) !bool {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
return properties.deviceType == vk.VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU and features.geometryShader == 1;
|
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;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -20,6 +20,7 @@ pub const QueueFamilies = struct {
|
||||||
//
|
//
|
||||||
|
|
||||||
raw: *vk.VkDevice_T,
|
raw: *vk.VkDevice_T,
|
||||||
|
physical_device: vk.VkPhysicalDevice,
|
||||||
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_T,
|
graphics_command_pool: *vk.VkCommandPool_T,
|
||||||
|
|
@ -109,6 +110,7 @@ pub fn init(
|
||||||
|
|
||||||
return .{
|
return .{
|
||||||
.raw = device.?,
|
.raw = device.?,
|
||||||
|
.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.?,
|
||||||
|
|
|
||||||
|
|
@ -5,55 +5,116 @@
|
||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
const vk = @import("vulkan");
|
const vk = @import("vulkan");
|
||||||
const gtl = @import("gtl");
|
const gtl = @import("gtl");
|
||||||
|
const VulkanRHI = @import("../vulkan.zig");
|
||||||
const Self = @This();
|
const Self = @This();
|
||||||
|
|
||||||
const Device = @import("device.zig");
|
const Device = @import("device.zig");
|
||||||
const Shader = @import("shader.zig");
|
|
||||||
const Swapchain = @import("swapchain.zig");
|
const Swapchain = @import("swapchain.zig");
|
||||||
const Config = @import("../../root.zig").PipelineConfig;
|
const Config = @import("../../root.zig").PipelineConfig;
|
||||||
|
const UniformDesc = @import("../../root.zig").UniformDesc;
|
||||||
|
|
||||||
//
|
//
|
||||||
// FIELDS
|
// FIELDS
|
||||||
//
|
//
|
||||||
|
|
||||||
raw: *vk.VkPipeline_T,
|
raw: vk.VkPipeline = null,
|
||||||
layout: *vk.VkPipelineLayout_T,
|
layout: vk.VkPipelineLayout = null,
|
||||||
device: *const Device,
|
device: *const Device,
|
||||||
|
|
||||||
|
descriptor_set_layout: vk.VkDescriptorSetLayout = null,
|
||||||
|
descriptor_pool: vk.VkDescriptorPool = null,
|
||||||
|
descriptor_set: vk.VkDescriptorSet = null,
|
||||||
|
|
||||||
|
uniform_buffer: vk.VkBuffer = null,
|
||||||
|
uniform_memory: vk.VkDeviceMemory = null,
|
||||||
|
uniforms: []UniformDesc,
|
||||||
|
|
||||||
|
alloc: std.mem.Allocator,
|
||||||
|
|
||||||
/// ----------------------------------------------------
|
/// ----------------------------------------------------
|
||||||
/// ----------------------------------------------------
|
/// ----------------------------------------------------
|
||||||
pub fn init(
|
pub fn init(
|
||||||
shader: *const Shader,
|
|
||||||
swapchain: *const Swapchain,
|
swapchain: *const Swapchain,
|
||||||
device: *const Device,
|
device: *const Device,
|
||||||
config: Config,
|
config: Config,
|
||||||
|
vulkan: *VulkanRHI,
|
||||||
alloc: std.mem.Allocator,
|
alloc: std.mem.Allocator,
|
||||||
) !Self {
|
) !Self {
|
||||||
|
var self: Self = .{
|
||||||
|
.device = device,
|
||||||
|
.uniforms = &.{},
|
||||||
|
.alloc = alloc,
|
||||||
|
};
|
||||||
|
errdefer self.deinit();
|
||||||
|
|
||||||
|
// --- COMPUTE UNIFORM LAYOUT ---
|
||||||
|
var uniform_size: u32 = 0;
|
||||||
|
for (config.uniforms) |u| {
|
||||||
|
uniform_size = @max(uniform_size, u.offset + u.size);
|
||||||
|
}
|
||||||
|
uniform_size = std.mem.alignForward(u32, uniform_size, 16);
|
||||||
|
|
||||||
|
// --- COPY UNIFORMS ---
|
||||||
|
if (config.uniforms.len > 0) {
|
||||||
|
const uniforms = try alloc.alloc(UniformDesc, config.uniforms.len);
|
||||||
|
@memcpy(uniforms, config.uniforms);
|
||||||
|
self.uniforms = uniforms;
|
||||||
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
// LAYOUT
|
// LAYOUT
|
||||||
//
|
//
|
||||||
|
|
||||||
|
var set_layout: vk.VkDescriptorSetLayout = null;
|
||||||
|
|
||||||
|
if (uniform_size > 0) {
|
||||||
|
const bindings = [_]vk.VkDescriptorSetLayoutBinding{
|
||||||
|
.{
|
||||||
|
.binding = 0,
|
||||||
|
.descriptorType = vk.VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
|
||||||
|
.descriptorCount = 1,
|
||||||
|
.stageFlags = vk.VK_SHADER_STAGE_VERTEX_BIT | vk.VK_SHADER_STAGE_FRAGMENT_BIT,
|
||||||
|
.pImmutableSamplers = null,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
var set_layout_info: vk.VkDescriptorSetLayoutCreateInfo = .{
|
||||||
|
.sType = vk.VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO,
|
||||||
|
.bindingCount = bindings.len,
|
||||||
|
.pBindings = &bindings,
|
||||||
|
};
|
||||||
|
|
||||||
|
if (vk.vkCreateDescriptorSetLayout(device.raw, &set_layout_info, null, &set_layout) != vk.VK_SUCCESS) {
|
||||||
|
return error.FailedToCreateDescriptorSetLayout;
|
||||||
|
}
|
||||||
|
self.descriptor_set_layout = set_layout.?;
|
||||||
|
}
|
||||||
|
|
||||||
var pipeline_layout_info: vk.VkPipelineLayoutCreateInfo = .{
|
var pipeline_layout_info: vk.VkPipelineLayoutCreateInfo = .{
|
||||||
.sType = vk.VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,
|
.sType = vk.VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,
|
||||||
|
.setLayoutCount = if (set_layout != null) 1 else 0,
|
||||||
|
.pSetLayouts = if (set_layout != null) @ptrCast(&set_layout) else null,
|
||||||
};
|
};
|
||||||
|
|
||||||
var pipeline_layout: vk.VkPipelineLayout = null;
|
var pipeline_layout: vk.VkPipelineLayout = null;
|
||||||
if (vk.vkCreatePipelineLayout(device.raw, &pipeline_layout_info, null, &pipeline_layout) != vk.VK_SUCCESS) {
|
if (vk.vkCreatePipelineLayout(device.raw, &pipeline_layout_info, null, &pipeline_layout) != vk.VK_SUCCESS) {
|
||||||
return error.FailedToCreatePipelineLayout;
|
return error.FailedToCreatePipelineLayout;
|
||||||
}
|
}
|
||||||
errdefer vk.vkDestroyPipelineLayout(device.raw, pipeline_layout, null);
|
self.layout = pipeline_layout.?;
|
||||||
|
|
||||||
//
|
//
|
||||||
// PIPELINE
|
// PIPELINE
|
||||||
//
|
//
|
||||||
|
|
||||||
|
const raw_vert_shader = vulkan.resource.shaders.get(config.vert_shader) orelse return error.VertexShaderNotFound;
|
||||||
|
const raw_frag_shader = vulkan.resource.shaders.get(config.frag_shader) orelse return error.FragmentShaderNotFound;
|
||||||
|
|
||||||
const vert_shader_stage_info: vk.VkPipelineShaderStageCreateInfo = .{
|
const vert_shader_stage_info: vk.VkPipelineShaderStageCreateInfo = .{
|
||||||
.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 = "main",
|
||||||
.module = shader.vert,
|
.module = raw_vert_shader.raw,
|
||||||
};
|
};
|
||||||
|
|
||||||
const frag_shader_stage_info: vk.VkPipelineShaderStageCreateInfo = .{
|
const frag_shader_stage_info: vk.VkPipelineShaderStageCreateInfo = .{
|
||||||
|
|
@ -61,7 +122,7 @@ pub fn init(
|
||||||
.stage = vk.VK_SHADER_STAGE_FRAGMENT_BIT,
|
.stage = vk.VK_SHADER_STAGE_FRAGMENT_BIT,
|
||||||
|
|
||||||
.pName = "main",
|
.pName = "main",
|
||||||
.module = shader.frag,
|
.module = raw_frag_shader.raw,
|
||||||
};
|
};
|
||||||
|
|
||||||
var shader_stages = [_]vk.VkPipelineShaderStageCreateInfo{
|
var shader_stages = [_]vk.VkPipelineShaderStageCreateInfo{
|
||||||
|
|
@ -231,17 +292,167 @@ pub fn init(
|
||||||
if (vk.vkCreateGraphicsPipelines(device.raw, null, 1, &pipeline_info, null, &pipeline) != vk.VK_SUCCESS) {
|
if (vk.vkCreateGraphicsPipelines(device.raw, null, 1, &pipeline_info, null, &pipeline) != vk.VK_SUCCESS) {
|
||||||
return error.FailedToCreateGraphicsPipelines;
|
return error.FailedToCreateGraphicsPipelines;
|
||||||
}
|
}
|
||||||
|
self.raw = pipeline.?;
|
||||||
|
|
||||||
return .{
|
//
|
||||||
.raw = pipeline.?,
|
// UNIFORM BUFFER + DESCRIPTORS
|
||||||
.layout = pipeline_layout.?,
|
//
|
||||||
.device = device,
|
|
||||||
};
|
if (uniform_size > 0) {
|
||||||
|
var buffer_info: vk.VkBufferCreateInfo = .{
|
||||||
|
.sType = vk.VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
|
||||||
|
.size = uniform_size,
|
||||||
|
.usage = vk.VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT,
|
||||||
|
.sharingMode = vk.VK_SHARING_MODE_EXCLUSIVE,
|
||||||
|
};
|
||||||
|
|
||||||
|
var uniform_buffer: vk.VkBuffer = null;
|
||||||
|
if (vk.vkCreateBuffer(device.raw, &buffer_info, null, &uniform_buffer) != vk.VK_SUCCESS) {
|
||||||
|
return error.FailedToCreateUniformBuffer;
|
||||||
|
}
|
||||||
|
self.uniform_buffer = uniform_buffer.?;
|
||||||
|
|
||||||
|
var mem_req: vk.VkMemoryRequirements = .{};
|
||||||
|
var mem_props: vk.VkPhysicalDeviceMemoryProperties = .{};
|
||||||
|
|
||||||
|
vk.vkGetBufferMemoryRequirements(device.raw, uniform_buffer, &mem_req);
|
||||||
|
vk.vkGetPhysicalDeviceMemoryProperties(device.physical_device, &mem_props);
|
||||||
|
|
||||||
|
var mem_type: u32 = 0;
|
||||||
|
for (0..mem_props.memoryTypeCount) |i| {
|
||||||
|
if ((mem_req.memoryTypeBits & (@as(u32, 1) << @intCast(i))) != 0 and
|
||||||
|
(mem_props.memoryTypes[i].propertyFlags &
|
||||||
|
(vk.VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT |
|
||||||
|
vk.VK_MEMORY_PROPERTY_HOST_COHERENT_BIT)) != 0)
|
||||||
|
{
|
||||||
|
mem_type = @intCast(i);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var alloc_info: vk.VkMemoryAllocateInfo = .{
|
||||||
|
.sType = vk.VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,
|
||||||
|
.allocationSize = mem_req.size,
|
||||||
|
.memoryTypeIndex = mem_type,
|
||||||
|
};
|
||||||
|
|
||||||
|
var uniform_memory: vk.VkDeviceMemory = null;
|
||||||
|
if (vk.vkAllocateMemory(device.raw, &alloc_info, null, &uniform_memory) != vk.VK_SUCCESS) {
|
||||||
|
return error.FailedToAllocateUniformMemory;
|
||||||
|
}
|
||||||
|
self.uniform_memory = uniform_memory;
|
||||||
|
|
||||||
|
_ = vk.vkBindBufferMemory(device.raw, uniform_buffer, uniform_memory, 0);
|
||||||
|
|
||||||
|
// --- DESCRIPTOR POOL ---
|
||||||
|
const pool_sizes = [_]vk.VkDescriptorPoolSize{
|
||||||
|
.{
|
||||||
|
.type = vk.VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
|
||||||
|
.descriptorCount = 1,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
var pool_info: vk.VkDescriptorPoolCreateInfo = .{
|
||||||
|
.sType = vk.VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO,
|
||||||
|
.poolSizeCount = pool_sizes.len,
|
||||||
|
.pPoolSizes = &pool_sizes,
|
||||||
|
.maxSets = 1,
|
||||||
|
};
|
||||||
|
|
||||||
|
var descriptor_pool: vk.VkDescriptorPool = null;
|
||||||
|
if (vk.vkCreateDescriptorPool(device.raw, &pool_info, null, &descriptor_pool) != vk.VK_SUCCESS) {
|
||||||
|
return error.FailedToCreateDescriptorPool;
|
||||||
|
}
|
||||||
|
self.descriptor_pool = descriptor_pool.?;
|
||||||
|
|
||||||
|
// --- DESCRIPTOR SET ---
|
||||||
|
var set_alloc_info: vk.VkDescriptorSetAllocateInfo = .{
|
||||||
|
.sType = vk.VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO,
|
||||||
|
.descriptorPool = descriptor_pool,
|
||||||
|
.descriptorSetCount = 1,
|
||||||
|
.pSetLayouts = @ptrCast(&self.descriptor_set_layout),
|
||||||
|
};
|
||||||
|
|
||||||
|
if (vk.vkAllocateDescriptorSets(device.raw, &set_alloc_info, &self.descriptor_set) != vk.VK_SUCCESS) {
|
||||||
|
return error.FailedToAllocateDescriptorSets;
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- WRITE DESCRIPTOR SET ---
|
||||||
|
const buffer_descriptor: vk.VkDescriptorBufferInfo = .{
|
||||||
|
.buffer = uniform_buffer,
|
||||||
|
.offset = 0,
|
||||||
|
.range = uniform_size,
|
||||||
|
};
|
||||||
|
|
||||||
|
const write_descriptor: vk.VkWriteDescriptorSet = .{
|
||||||
|
.sType = vk.VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
|
||||||
|
.dstSet = self.descriptor_set,
|
||||||
|
.dstBinding = 0,
|
||||||
|
.dstArrayElement = 0,
|
||||||
|
.descriptorCount = 1,
|
||||||
|
.descriptorType = vk.VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
|
||||||
|
.pBufferInfo = &buffer_descriptor,
|
||||||
|
};
|
||||||
|
|
||||||
|
vk.vkUpdateDescriptorSets(device.raw, 1, &write_descriptor, 0, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
return self;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// ----------------------------------------------------
|
/// ----------------------------------------------------
|
||||||
/// ----------------------------------------------------
|
/// ----------------------------------------------------
|
||||||
pub fn deinit(self: *Self) void {
|
pub fn deinit(self: *Self) void {
|
||||||
vk.vkDestroyPipelineLayout(self.device.raw, self.layout, null);
|
if (self.descriptor_set_layout) |set_layout| {
|
||||||
vk.vkDestroyPipeline(self.device.raw, self.raw, null);
|
vk.vkDestroyDescriptorSetLayout(self.device.raw, set_layout, null);
|
||||||
|
}
|
||||||
|
if (self.descriptor_pool) |pool| {
|
||||||
|
vk.vkDestroyDescriptorPool(self.device.raw, pool, null);
|
||||||
|
}
|
||||||
|
if (self.uniform_memory) |memory| {
|
||||||
|
vk.vkFreeMemory(self.device.raw, memory, null);
|
||||||
|
}
|
||||||
|
if (self.uniform_buffer) |buffer| {
|
||||||
|
vk.vkDestroyBuffer(self.device.raw, buffer, null);
|
||||||
|
}
|
||||||
|
if (self.layout) |layout| {
|
||||||
|
vk.vkDestroyPipelineLayout(self.device.raw, layout, null);
|
||||||
|
}
|
||||||
|
if (self.raw) |raw| {
|
||||||
|
vk.vkDestroyPipeline(self.device.raw, raw, null);
|
||||||
|
}
|
||||||
|
self.alloc.free(self.uniforms);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// ----------------------------------------------------
|
||||||
|
/// Set a uniform value by name
|
||||||
|
/// ----------------------------------------------------
|
||||||
|
pub fn setUniform(self: *Self, name: []const u8, value: anytype) !void {
|
||||||
|
for (self.uniforms) |uniform| {
|
||||||
|
if (std.mem.eql(u8, uniform.name, name)) {
|
||||||
|
if (@sizeOf(@TypeOf(value)) > uniform.size) {
|
||||||
|
return error.UniformSizeMismatch;
|
||||||
|
}
|
||||||
|
|
||||||
|
var mapped: ?*anyopaque = null;
|
||||||
|
if (vk.vkMapMemory(
|
||||||
|
self.device.raw,
|
||||||
|
self.uniform_memory,
|
||||||
|
uniform.offset,
|
||||||
|
uniform.size,
|
||||||
|
0,
|
||||||
|
&mapped,
|
||||||
|
) != vk.VK_SUCCESS) {
|
||||||
|
return error.FailedToMapMemory;
|
||||||
|
}
|
||||||
|
|
||||||
|
const dst: [*]u8 = @ptrCast(mapped.?);
|
||||||
|
const src: [*]const u8 = @ptrCast(&value);
|
||||||
|
@memcpy(dst[0..@sizeOf(@TypeOf(value))], src[0..@sizeOf(@TypeOf(value))]);
|
||||||
|
|
||||||
|
vk.vkUnmapMemory(self.device.raw, self.uniform_memory);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return error.UniformNotFound;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -12,31 +12,27 @@ const Self = @This();
|
||||||
// FIELDS
|
// FIELDS
|
||||||
//
|
//
|
||||||
|
|
||||||
vert: *vk.VkShaderModule_T,
|
raw: *vk.VkShaderModule_T,
|
||||||
frag: *vk.VkShaderModule_T,
|
|
||||||
device: *const Device,
|
device: *const Device,
|
||||||
|
|
||||||
/// ----------------------------------------------------
|
/// ----------------------------------------------------
|
||||||
/// ----------------------------------------------------
|
/// ----------------------------------------------------
|
||||||
pub fn init(
|
pub fn init(
|
||||||
vert_spv_path: []const u8,
|
spv_path: []const u8,
|
||||||
frag_spv_path: []const u8,
|
|
||||||
device: *const Device,
|
device: *const Device,
|
||||||
alloc: std.mem.Allocator,
|
alloc: std.mem.Allocator,
|
||||||
io: std.Io,
|
io: std.Io,
|
||||||
) !Self {
|
) !Self {
|
||||||
const vert_code = try readFile(vert_spv_path, alloc, io);
|
const code = try readFile(spv_path, alloc, io);
|
||||||
defer alloc.free(vert_code);
|
defer alloc.free(code);
|
||||||
|
|
||||||
const frag_code = try readFile(frag_spv_path, alloc, io);
|
const module = try createModule(
|
||||||
defer alloc.free(frag_code);
|
code,
|
||||||
|
device,
|
||||||
const vert_module = try createModule(vert_code, device);
|
);
|
||||||
const frag_module = try createModule(frag_code, device);
|
|
||||||
|
|
||||||
return .{
|
return .{
|
||||||
.vert = vert_module,
|
.raw = module,
|
||||||
.frag = frag_module,
|
|
||||||
.device = device,
|
.device = device,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
@ -44,8 +40,7 @@ pub fn init(
|
||||||
/// ----------------------------------------------------
|
/// ----------------------------------------------------
|
||||||
/// ----------------------------------------------------
|
/// ----------------------------------------------------
|
||||||
pub fn deinit(self: *Self) void {
|
pub fn deinit(self: *Self) void {
|
||||||
vk.vkDestroyShaderModule(self.device.raw, self.vert, null);
|
vk.vkDestroyShaderModule(self.device.raw, self.raw, null);
|
||||||
vk.vkDestroyShaderModule(self.device.raw, self.frag, null);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// ----------------------------------------------------
|
/// ----------------------------------------------------
|
||||||
|
|
|
||||||
|
|
@ -19,6 +19,8 @@ const BufferUsage = common.BufferUsage;
|
||||||
const BufferSharingMode = common.BufferSharingMode;
|
const BufferSharingMode = common.BufferSharingMode;
|
||||||
|
|
||||||
// --- CONFIGS ---
|
// --- CONFIGS ---
|
||||||
|
const AdapterConfig = common.AdapterConfig;
|
||||||
|
const RenderPassConfig = common.RenderPassConfig;
|
||||||
const PipelineConfig = common.PipelineConfig;
|
const PipelineConfig = common.PipelineConfig;
|
||||||
|
|
||||||
// --- HANDLES ---
|
// --- HANDLES ---
|
||||||
|
|
@ -63,10 +65,6 @@ sync_device: ?*vk.VkDevice_T = null,
|
||||||
alloc: std.mem.Allocator,
|
alloc: std.mem.Allocator,
|
||||||
io: std.Io,
|
io: std.Io,
|
||||||
|
|
||||||
pub fn currentFrame(self: *Self) *Frame {
|
|
||||||
return &self.frames[self.current_frame];
|
|
||||||
}
|
|
||||||
|
|
||||||
/// ----------------------------------------------------
|
/// ----------------------------------------------------
|
||||||
/// ----------------------------------------------------
|
/// ----------------------------------------------------
|
||||||
pub fn init(
|
pub fn init(
|
||||||
|
|
@ -114,13 +112,13 @@ pub fn deinit(self: *Self) void {
|
||||||
|
|
||||||
/// ----------------------------------------------------
|
/// ----------------------------------------------------
|
||||||
/// ----------------------------------------------------
|
/// ----------------------------------------------------
|
||||||
pub fn createAdapter(self: *Self) !Handle(Adapter) {
|
pub fn makeAdapter(self: *Self, config: AdapterConfig) !Handle(Adapter) {
|
||||||
return try self.resource.adapters.put(try .init(self));
|
return try self.resource.adapters.put(try .init(self, config));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// ----------------------------------------------------
|
/// ----------------------------------------------------
|
||||||
/// ----------------------------------------------------
|
/// ----------------------------------------------------
|
||||||
pub fn createDevice(
|
pub fn makeDevice(
|
||||||
self: *Self,
|
self: *Self,
|
||||||
adapter: Handle(Adapter),
|
adapter: Handle(Adapter),
|
||||||
surface: Handle(Surface),
|
surface: Handle(Surface),
|
||||||
|
|
@ -141,13 +139,13 @@ pub fn destroyDevice(self: *Self, device: Handle(Device)) !void {
|
||||||
|
|
||||||
/// ----------------------------------------------------
|
/// ----------------------------------------------------
|
||||||
/// ----------------------------------------------------
|
/// ----------------------------------------------------
|
||||||
pub fn createSurface(self: *Self) !Handle(Surface) {
|
pub fn makeSurface(self: *Self) !Handle(Surface) {
|
||||||
return try self.resource.surfaces.put(try .init(&self.instance, self.config.window));
|
return try self.resource.surfaces.put(try .init(&self.instance, self.config.window));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// ----------------------------------------------------
|
/// ----------------------------------------------------
|
||||||
/// ----------------------------------------------------
|
/// ----------------------------------------------------
|
||||||
pub fn createSwapchain(
|
pub fn makeSwapchain(
|
||||||
self: *Self,
|
self: *Self,
|
||||||
adapter: Handle(Adapter),
|
adapter: Handle(Adapter),
|
||||||
device: Handle(Device),
|
device: Handle(Device),
|
||||||
|
|
@ -168,28 +166,26 @@ pub fn createSwapchain(
|
||||||
|
|
||||||
/// ----------------------------------------------------
|
/// ----------------------------------------------------
|
||||||
/// ----------------------------------------------------
|
/// ----------------------------------------------------
|
||||||
pub fn createShader(
|
pub fn makeShader(
|
||||||
self: *Self,
|
self: *Self,
|
||||||
vert_spv_path: []const u8,
|
spv_path: []const u8,
|
||||||
frag_spv_path: []const u8,
|
|
||||||
device: Handle(Device),
|
device: Handle(Device),
|
||||||
) !Handle(Shader) {
|
) !Handle(Shader) {
|
||||||
const raw_device = self.resource.devices.get(device) orelse return error.DeviceNotFound;
|
const raw_device = self.resource.devices.get(device) orelse return error.DeviceNotFound;
|
||||||
return try self.resource.shaders.put(try .init(vert_spv_path, frag_spv_path, raw_device, self.alloc, self.io));
|
return try self.resource.shaders.put(try .init(spv_path, raw_device, self.alloc, self.io));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// ----------------------------------------------------
|
/// ----------------------------------------------------
|
||||||
/// ----------------------------------------------------
|
/// ----------------------------------------------------
|
||||||
pub fn createPipeline(self: *Self, config: PipelineConfig) !Handle(Pipeline) {
|
pub fn makePipeline(self: *Self, config: PipelineConfig) !Handle(Pipeline) {
|
||||||
const raw_device = self.resource.devices.get(config.device) orelse return error.DeviceNotFound;
|
const raw_device = self.resource.devices.get(config.device) orelse return error.DeviceNotFound;
|
||||||
const raw_swapchain = self.resource.swapchains.get(config.swapchain) orelse return error.SwapchainNotFound;
|
const raw_swapchain = self.resource.swapchains.get(config.swapchain) orelse return error.SwapchainNotFound;
|
||||||
const raw_shader = self.resource.shaders.get(config.shader) orelse return error.ShaderNotFound;
|
return try self.resource.pipelines.put(try .init(raw_swapchain, raw_device, config, self, self.alloc));
|
||||||
return try self.resource.pipelines.put(try .init(raw_shader, raw_swapchain, raw_device, config, self.alloc));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// ----------------------------------------------------
|
/// ----------------------------------------------------
|
||||||
/// ----------------------------------------------------
|
/// ----------------------------------------------------
|
||||||
pub fn createBuffer(
|
pub fn makeBuffer(
|
||||||
self: *Self,
|
self: *Self,
|
||||||
size: u32,
|
size: u32,
|
||||||
usage: BufferUsage,
|
usage: BufferUsage,
|
||||||
|
|
@ -202,25 +198,6 @@ pub fn createBuffer(
|
||||||
return try self.resource.buffers.put(try .init(size, usage, sharing, raw_adapter, raw_device));
|
return try self.resource.buffers.put(try .init(size, usage, sharing, raw_adapter, raw_device));
|
||||||
}
|
}
|
||||||
|
|
||||||
// /// ----------------------------------------------------
|
|
||||||
// /// ----------------------------------------------------
|
|
||||||
// pub const AttributeDesc = struct {
|
|
||||||
// binding: u32,
|
|
||||||
// location: u32,
|
|
||||||
// uniform_type: UniformType,
|
|
||||||
// offset: u32,
|
|
||||||
// };
|
|
||||||
|
|
||||||
// /// ----------------------------------------------------
|
|
||||||
// /// ----------------------------------------------------
|
|
||||||
// pub fn createUniform(
|
|
||||||
// self: *Self,
|
|
||||||
// attributes: []const AttributeDesc,
|
|
||||||
// ) !void {
|
|
||||||
// _ = self;
|
|
||||||
// _ = attributes;
|
|
||||||
// }
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// FRAME + RENDERING
|
// FRAME + RENDERING
|
||||||
//
|
//
|
||||||
|
|
@ -355,11 +332,17 @@ pub fn endFrame(
|
||||||
pub fn beginRendering(
|
pub fn beginRendering(
|
||||||
self: *Self,
|
self: *Self,
|
||||||
swapchain: Handle(Swapchain),
|
swapchain: Handle(Swapchain),
|
||||||
|
config: RenderPassConfig,
|
||||||
) !void {
|
) !void {
|
||||||
const raw_swapchain = self.resource.swapchains.get(swapchain) orelse return error.SwapchainNotFound;
|
const raw_swapchain = self.resource.swapchains.get(swapchain) orelse return error.SwapchainNotFound;
|
||||||
|
|
||||||
const frame = self.currentFrame();
|
const frame = self.currentFrame();
|
||||||
|
|
||||||
|
const extent: vk.VkExtent2D = .{
|
||||||
|
.width = config.width orelse raw_swapchain.extent.width,
|
||||||
|
.height = config.height orelse raw_swapchain.extent.height,
|
||||||
|
};
|
||||||
|
|
||||||
const barrier: vk.VkImageMemoryBarrier = .{
|
const barrier: vk.VkImageMemoryBarrier = .{
|
||||||
.sType = vk.VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
|
.sType = vk.VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
|
||||||
|
|
||||||
|
|
@ -405,11 +388,18 @@ pub fn beginRendering(
|
||||||
.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 = raw_swapchain.image_views[frame.image_index],
|
||||||
.imageLayout = vk.VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
|
.imageLayout = vk.VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
|
||||||
.loadOp = vk.VK_ATTACHMENT_LOAD_OP_CLEAR,
|
.loadOp = switch (config.load_op) {
|
||||||
.storeOp = vk.VK_ATTACHMENT_STORE_OP_STORE,
|
.clear => vk.VK_ATTACHMENT_LOAD_OP_CLEAR,
|
||||||
|
.load => vk.VK_ATTACHMENT_LOAD_OP_LOAD,
|
||||||
|
.dont_care => vk.VK_ATTACHMENT_LOAD_OP_DONT_CARE,
|
||||||
|
},
|
||||||
|
.storeOp = switch (config.store_op) {
|
||||||
|
.store => vk.VK_ATTACHMENT_STORE_OP_STORE,
|
||||||
|
.dont_care => vk.VK_ATTACHMENT_STORE_OP_DONT_CARE,
|
||||||
|
},
|
||||||
.clearValue = .{
|
.clearValue = .{
|
||||||
.color = .{
|
.color = .{
|
||||||
.float32 = .{ 0.01, 0.01, 0.01, 1.0 },
|
.float32 = config.clear_color,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
@ -421,7 +411,7 @@ pub fn beginRendering(
|
||||||
.x = 0,
|
.x = 0,
|
||||||
.y = 0,
|
.y = 0,
|
||||||
},
|
},
|
||||||
.extent = raw_swapchain.extent,
|
.extent = extent,
|
||||||
},
|
},
|
||||||
.layerCount = 1,
|
.layerCount = 1,
|
||||||
.colorAttachmentCount = 1,
|
.colorAttachmentCount = 1,
|
||||||
|
|
@ -436,8 +426,8 @@ pub fn beginRendering(
|
||||||
const viewport: vk.VkViewport = .{
|
const viewport: vk.VkViewport = .{
|
||||||
.x = 0,
|
.x = 0,
|
||||||
.y = 0,
|
.y = 0,
|
||||||
.width = @floatFromInt(raw_swapchain.extent.width),
|
.width = @floatFromInt(extent.width),
|
||||||
.height = @floatFromInt(raw_swapchain.extent.height),
|
.height = @floatFromInt(extent.height),
|
||||||
.minDepth = 0.0,
|
.minDepth = 0.0,
|
||||||
.maxDepth = 1.0,
|
.maxDepth = 1.0,
|
||||||
};
|
};
|
||||||
|
|
@ -447,7 +437,7 @@ pub fn beginRendering(
|
||||||
.x = 0,
|
.x = 0,
|
||||||
.y = 0,
|
.y = 0,
|
||||||
},
|
},
|
||||||
.extent = raw_swapchain.extent,
|
.extent = extent,
|
||||||
};
|
};
|
||||||
|
|
||||||
vk.vkCmdSetViewport(frame.cmd_buf, 0, 1, &viewport);
|
vk.vkCmdSetViewport(frame.cmd_buf, 0, 1, &viewport);
|
||||||
|
|
@ -459,8 +449,8 @@ pub fn beginRendering(
|
||||||
pub fn endRendering(
|
pub fn endRendering(
|
||||||
self: *Self,
|
self: *Self,
|
||||||
swapchain: Handle(Swapchain),
|
swapchain: Handle(Swapchain),
|
||||||
) !void {
|
) void {
|
||||||
const raw_swapchain = self.resource.swapchains.get(swapchain) orelse return error.SwapchainNotFound;
|
const raw_swapchain = self.resource.swapchains.get(swapchain) orelse return;
|
||||||
|
|
||||||
const frame = self.currentFrame();
|
const frame = self.currentFrame();
|
||||||
|
|
||||||
|
|
@ -512,7 +502,27 @@ pub fn endRendering(
|
||||||
/// ----------------------------------------------------
|
/// ----------------------------------------------------
|
||||||
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;
|
||||||
vk.vkCmdBindPipeline(self.currentFrame().cmd_buf, vk.VK_PIPELINE_BIND_POINT_GRAPHICS, raw_pipeline.raw);
|
const frame = self.currentFrame();
|
||||||
|
vk.vkCmdBindPipeline(frame.cmd_buf, vk.VK_PIPELINE_BIND_POINT_GRAPHICS, raw_pipeline.raw.?);
|
||||||
|
if (raw_pipeline.descriptor_set) |set| {
|
||||||
|
vk.vkCmdBindDescriptorSets(
|
||||||
|
frame.cmd_buf,
|
||||||
|
vk.VK_PIPELINE_BIND_POINT_GRAPHICS,
|
||||||
|
raw_pipeline.layout.?,
|
||||||
|
0,
|
||||||
|
1,
|
||||||
|
&set,
|
||||||
|
0,
|
||||||
|
null,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// ----------------------------------------------------
|
||||||
|
/// ----------------------------------------------------
|
||||||
|
pub fn setUniform(self: *Self, pipeline: Handle(Pipeline), name: []const u8, value: anytype) !void {
|
||||||
|
const raw_pipeline = self.resource.pipelines.get(pipeline) orelse return error.PipelineNotFound;
|
||||||
|
try raw_pipeline.setUniform(name, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// ----------------------------------------------------
|
/// ----------------------------------------------------
|
||||||
|
|
@ -522,7 +532,13 @@ pub fn draw(self: *Self, vertex_count: u32, instance_count: u32, first_vertex: u
|
||||||
}
|
}
|
||||||
|
|
||||||
/// ----------------------------------------------------
|
/// ----------------------------------------------------
|
||||||
/// Lazily create the frame sync objects (semaphores + fence)
|
/// ----------------------------------------------------
|
||||||
|
pub fn currentFrame(self: *Self) *Frame {
|
||||||
|
return &self.frames[self.current_frame];
|
||||||
|
}
|
||||||
|
|
||||||
|
/// ----------------------------------------------------
|
||||||
|
/// Lazily make the frame sync objects (semaphores + fence)
|
||||||
/// ----------------------------------------------------
|
/// ----------------------------------------------------
|
||||||
fn ensureFrameSync(
|
fn ensureFrameSync(
|
||||||
self: *Self,
|
self: *Self,
|
||||||
|
|
@ -550,7 +566,7 @@ fn ensureFrameSync(
|
||||||
for (render_finished, 0..) |*semaphore, i| {
|
for (render_finished, 0..) |*semaphore, i| {
|
||||||
_ = i;
|
_ = i;
|
||||||
if (vk.vkCreateSemaphore(device, &semaphore_info, null, semaphore) != vk.VK_SUCCESS) {
|
if (vk.vkCreateSemaphore(device, &semaphore_info, null, semaphore) != vk.VK_SUCCESS) {
|
||||||
return error.FailedToCreateSemaphore;
|
return error.FailedTomakeSemaphore;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
self.render_finished = render_finished;
|
self.render_finished = render_finished;
|
||||||
|
|
@ -558,13 +574,13 @@ fn ensureFrameSync(
|
||||||
for (&self.frames) |*frame| {
|
for (&self.frames) |*frame| {
|
||||||
var image_available: vk.VkSemaphore = null;
|
var image_available: vk.VkSemaphore = null;
|
||||||
if (vk.vkCreateSemaphore(device, &semaphore_info, null, &image_available) != vk.VK_SUCCESS) {
|
if (vk.vkCreateSemaphore(device, &semaphore_info, null, &image_available) != vk.VK_SUCCESS) {
|
||||||
return error.FailedToCreateSemaphore;
|
return error.FailedTomakeSemaphore;
|
||||||
}
|
}
|
||||||
|
|
||||||
var fence: vk.VkFence = null;
|
var fence: vk.VkFence = null;
|
||||||
if (vk.vkCreateFence(device, &fence_info, null, &fence) != vk.VK_SUCCESS) {
|
if (vk.vkCreateFence(device, &fence_info, null, &fence) != vk.VK_SUCCESS) {
|
||||||
vk.vkDestroySemaphore(device, image_available, null);
|
vk.vkDestroySemaphore(device, image_available, null);
|
||||||
return error.FailedToCreateFence;
|
return error.FailedTomakeFence;
|
||||||
}
|
}
|
||||||
|
|
||||||
frame.image_available = image_available.?;
|
frame.image_available = image_available.?;
|
||||||
|
|
|
||||||
BIN
zig-out/bin/simple
Executable file
BIN
zig-out/bin/simple
Executable file
Binary file not shown.
Loading…
Add table
Reference in a new issue