Refactored source code structure.
This commit is contained in:
parent
5bab2c4bcf
commit
1d64275dee
9 changed files with 114 additions and 6 deletions
119
src/rendering/mesh.zig
Normal file
119
src/rendering/mesh.zig
Normal file
|
|
@ -0,0 +1,119 @@
|
|||
const c = @import("../c.zig");
|
||||
const std = @import("std");
|
||||
const vk = @import("vulkan.zig");
|
||||
const Allocator = std.mem.Allocator;
|
||||
|
||||
pub const Vertex = struct {
|
||||
position: [3]f32,
|
||||
|
||||
pub fn create(x: f32, y: f32, z: f32) Vertex {
|
||||
return Vertex{
|
||||
.position = .{ x, y, z },
|
||||
};
|
||||
}
|
||||
|
||||
pub fn bindingDescription() c.VkVertexInputBindingDescription {
|
||||
const binding_description: c.VkVertexInputBindingDescription = .{
|
||||
.binding = 0,
|
||||
.stride = @sizeOf(Vertex),
|
||||
.inputRate = c.VK_VERTEX_INPUT_RATE_VERTEX,
|
||||
};
|
||||
|
||||
return binding_description;
|
||||
}
|
||||
|
||||
pub fn attributeDescription() c.VkVertexInputAttributeDescription {
|
||||
const attribute_description: c.VkVertexInputAttributeDescription = .{
|
||||
.location = 0,
|
||||
.binding = 0,
|
||||
.format = c.VK_FORMAT_R32G32B32_SFLOAT,
|
||||
.offset = 0,
|
||||
};
|
||||
|
||||
return attribute_description;
|
||||
}
|
||||
};
|
||||
|
||||
pub const Mesh = struct {
|
||||
vertex_buffer: vk.Buffer,
|
||||
index_buffer: vk.Buffer,
|
||||
|
||||
pub fn createVertexBuffer(device: anytype) !vk.Buffer {
|
||||
const vertices = [_]Vertex{
|
||||
Vertex.create(0.5, -0.5, 0.0),
|
||||
Vertex.create(0.5, 0.5, 0.0),
|
||||
Vertex.create(-0.5, 0.5, 0.0),
|
||||
Vertex.create(-0.5, -0.5, 0.0),
|
||||
};
|
||||
|
||||
var data: [*c]?*anyopaque = null;
|
||||
|
||||
const buffer = try device.createBuffer(vk.BufferUsage{ .transfer_src = true }, vk.BufferFlags{ .host_visible = true, .host_coherent = true }, @sizeOf(Vertex) * vertices.len);
|
||||
|
||||
try vk.mapError(c.vkMapMemory(
|
||||
device.handle,
|
||||
buffer.memory,
|
||||
0,
|
||||
buffer.size,
|
||||
0,
|
||||
@ptrCast(&data),
|
||||
));
|
||||
|
||||
if (data) |ptr| {
|
||||
const gpu_vertices: [*]Vertex = @ptrCast(@alignCast(ptr));
|
||||
|
||||
@memcpy(gpu_vertices, vertices[0..]);
|
||||
}
|
||||
|
||||
c.vkUnmapMemory(device.handle, buffer.memory);
|
||||
|
||||
const vertex_buffer = try device.createBuffer(vk.BufferUsage{ .vertex_buffer = true, .transfer_dst = true }, vk.BufferFlags{ .device_local = true }, @sizeOf(Vertex) * vertices.len);
|
||||
|
||||
try buffer.copyTo(device, vertex_buffer);
|
||||
buffer.destroy(device.handle);
|
||||
|
||||
return vertex_buffer;
|
||||
}
|
||||
|
||||
pub fn createIndexBuffer(device: anytype) !vk.Buffer {
|
||||
const indices = [_]u16{ 0, 1, 2, 3, 0, 2 };
|
||||
|
||||
var data: [*c]?*anyopaque = null;
|
||||
|
||||
const buffer = try device.createBuffer(vk.BufferUsage{ .transfer_src = true }, vk.BufferFlags{ .host_visible = true, .host_coherent = true }, @sizeOf(u16) * indices.len);
|
||||
|
||||
try vk.mapError(c.vkMapMemory(
|
||||
device.handle,
|
||||
buffer.memory,
|
||||
0,
|
||||
buffer.size,
|
||||
0,
|
||||
@ptrCast(&data),
|
||||
));
|
||||
|
||||
if (data) |ptr| {
|
||||
const gpu_indices: [*]u16 = @ptrCast(@alignCast(ptr));
|
||||
|
||||
@memcpy(gpu_indices, indices[0..]);
|
||||
}
|
||||
|
||||
c.vkUnmapMemory(device.handle, buffer.memory);
|
||||
|
||||
const index_buffer = try device.createBuffer(vk.BufferUsage{ .index_buffer = true, .transfer_dst = true }, vk.BufferFlags{ .device_local = true }, @sizeOf(u16) * indices.len);
|
||||
|
||||
try buffer.copyTo(device, index_buffer);
|
||||
buffer.destroy(device.handle);
|
||||
|
||||
return index_buffer;
|
||||
}
|
||||
|
||||
pub fn create(device: anytype) !Mesh {
|
||||
const vertex_buffer = try Mesh.createVertexBuffer(device);
|
||||
const index_buffer = try Mesh.createIndexBuffer(device);
|
||||
|
||||
return Mesh{
|
||||
.vertex_buffer = vertex_buffer,
|
||||
.index_buffer = index_buffer,
|
||||
};
|
||||
}
|
||||
};
|
||||
94
src/rendering/renderer_vulkan.zig
Normal file
94
src/rendering/renderer_vulkan.zig
Normal file
|
|
@ -0,0 +1,94 @@
|
|||
const c = @import("../c.zig");
|
||||
const std = @import("std");
|
||||
const vk = @import("vulkan.zig");
|
||||
const window = @import("window.zig");
|
||||
const mesh = @import("mesh.zig");
|
||||
const Allocator = std.mem.Allocator;
|
||||
|
||||
const Renderer = @This();
|
||||
|
||||
instance: vk.Instance,
|
||||
surface: vk.Surface,
|
||||
physical_device: vk.PhysicalDevice,
|
||||
device: vk.Device(2),
|
||||
render_pass: vk.RenderPass(2),
|
||||
swapchain: vk.Swapchain(2),
|
||||
graphics_pipeline: vk.GraphicsPipeline(2),
|
||||
current_frame: u32,
|
||||
vertex_buffer: vk.Buffer,
|
||||
index_buffer: vk.Buffer,
|
||||
|
||||
pub fn create(allocator: Allocator, w: window.Window) !Renderer {
|
||||
const instance = try vk.Instance.create(allocator);
|
||||
|
||||
const surface = try vk.Surface.create(instance, w);
|
||||
|
||||
var physical_device = try vk.PhysicalDevice.pick(allocator, instance);
|
||||
const device = try physical_device.create_device(surface, allocator, 2);
|
||||
|
||||
const vertex_shader = try device.createShader("shader_vert");
|
||||
defer device.destroyShader(vertex_shader);
|
||||
const fragment_shader = try device.createShader("shader_frag");
|
||||
defer device.destroyShader(fragment_shader);
|
||||
|
||||
const render_pass = try vk.RenderPass(2).create(allocator, device, surface, physical_device);
|
||||
|
||||
const swapchain = try vk.Swapchain(2).create(allocator, surface, device, physical_device, w, render_pass);
|
||||
|
||||
const graphics_pipeline = try vk.GraphicsPipeline(2).create(device, swapchain, render_pass, vertex_shader, fragment_shader);
|
||||
|
||||
// TODO: I think the renderer shouldn't have to interact with buffers. I think the API should change to
|
||||
// something along the lines of
|
||||
// renderer.begin()
|
||||
// renderer.render(triangle);
|
||||
// renderer.render(some_other_thing);
|
||||
// ...
|
||||
// renderer.submit()
|
||||
const triangle = try mesh.Mesh.create(device);
|
||||
|
||||
return Renderer{
|
||||
.instance = instance,
|
||||
.surface = surface,
|
||||
.physical_device = physical_device,
|
||||
.device = device,
|
||||
.render_pass = render_pass,
|
||||
.swapchain = swapchain,
|
||||
.graphics_pipeline = graphics_pipeline,
|
||||
.current_frame = 0,
|
||||
// TODO: Why are we storing the buffer and not the Mesh?
|
||||
.vertex_buffer = triangle.vertex_buffer,
|
||||
.index_buffer = triangle.index_buffer,
|
||||
};
|
||||
}
|
||||
|
||||
pub fn destroy(self: Renderer) void {
|
||||
self.device.waitIdle();
|
||||
self.index_buffer.destroy(self.device.handle);
|
||||
self.vertex_buffer.destroy(self.device.handle);
|
||||
self.graphics_pipeline.destroy(self.device);
|
||||
self.swapchain.destroy(self.device);
|
||||
self.render_pass.destroy(self.device);
|
||||
self.device.destroy();
|
||||
self.surface.destroy(self.instance);
|
||||
self.instance.destroy();
|
||||
}
|
||||
|
||||
// TODO: tick is maybe a bad name? something like present() or submit() is better?
|
||||
pub fn tick(self: *Renderer) !void {
|
||||
try self.device.waitFence(self.current_frame);
|
||||
const image = try self.swapchain.nextImage(self.device, self.current_frame);
|
||||
try self.device.resetCommand(self.current_frame);
|
||||
try self.device.beginCommand(self.current_frame);
|
||||
self.render_pass.begin(self.swapchain, self.device, image, self.current_frame);
|
||||
self.graphics_pipeline.bind(self.device, self.current_frame);
|
||||
self.device.bindVertexBuffer(self.vertex_buffer, self.current_frame);
|
||||
self.device.bindIndexBuffer(self.index_buffer, self.current_frame);
|
||||
self.device.bindDescriptorSets(self.graphics_pipeline, self.current_frame);
|
||||
self.device.draw(@intCast(self.index_buffer.size / @sizeOf(u16)), self.current_frame);
|
||||
self.render_pass.end(self.device, self.current_frame);
|
||||
try self.device.endCommand(self.current_frame);
|
||||
|
||||
try self.device.submit(self.swapchain, image, self.current_frame);
|
||||
|
||||
self.current_frame = (self.current_frame + 1) % 2;
|
||||
}
|
||||
1151
src/rendering/vulkan.zig
Normal file
1151
src/rendering/vulkan.zig
Normal file
File diff suppressed because it is too large
Load diff
64
src/rendering/window.zig
Normal file
64
src/rendering/window.zig
Normal file
|
|
@ -0,0 +1,64 @@
|
|||
const c = @import("../c.zig");
|
||||
const std = @import("std");
|
||||
|
||||
pub const Error = error{
|
||||
platform_unavailable,
|
||||
platform_error,
|
||||
};
|
||||
|
||||
pub fn getExtensions() [][*c]const u8 {
|
||||
var extension_count: u32 = undefined;
|
||||
const raw: [*c][*c]const u8 = c.glfwGetRequiredInstanceExtensions(&extension_count);
|
||||
const extensions = raw[0..extension_count];
|
||||
|
||||
return extensions;
|
||||
}
|
||||
|
||||
pub const Window = struct {
|
||||
title: []const u8,
|
||||
width: usize,
|
||||
height: usize,
|
||||
raw: *c.GLFWwindow,
|
||||
|
||||
pub fn create(width: usize, height: usize, title: []const u8) !Window {
|
||||
if (c.glfwInit() != c.GLFW_TRUE) {
|
||||
const status = c.glfwGetError(null);
|
||||
|
||||
return switch (status) {
|
||||
c.GLFW_PLATFORM_UNAVAILABLE => Error.platform_unavailable,
|
||||
c.GLFW_PLATFORM_ERROR => Error.platform_error,
|
||||
else => unreachable,
|
||||
};
|
||||
}
|
||||
|
||||
c.glfwWindowHint(c.GLFW_RESIZABLE, c.GLFW_FALSE);
|
||||
c.glfwWindowHint(c.GLFW_CLIENT_API, c.GLFW_NO_API);
|
||||
const raw = c.glfwCreateWindow(@intCast(width), @intCast(height), title.ptr, null, null);
|
||||
c.glfwShowWindow(raw);
|
||||
|
||||
return Window{
|
||||
.title = title,
|
||||
.width = width,
|
||||
.height = height,
|
||||
.raw = raw.?,
|
||||
};
|
||||
}
|
||||
|
||||
pub fn shouldClose(self: Window) bool {
|
||||
return c.glfwWindowShouldClose(self.raw) == c.GLFW_TRUE;
|
||||
}
|
||||
|
||||
pub fn size(self: Window) struct { usize, usize } {
|
||||
var width: u32 = undefined;
|
||||
var height: u32 = undefined;
|
||||
|
||||
c.glfwGetFramebufferSize(self.raw, @ptrCast(&width), @ptrCast(&height));
|
||||
|
||||
return .{ @intCast(width), @intCast(height) };
|
||||
}
|
||||
|
||||
pub fn destroy(self: Window) void {
|
||||
c.glfwDestroyWindow(self.raw);
|
||||
c.glfwTerminate();
|
||||
}
|
||||
};
|
||||
Loading…
Add table
Add a link
Reference in a new issue