Refactor frame state to allow access to the destroy queue from asset manager
This commit is contained in:
parent
05f2deb5df
commit
afa00106e4
@ -30,6 +30,9 @@ const tracy = @import("tracy");
|
|||||||
const vk = @import("vk");
|
const vk = @import("vk");
|
||||||
const GraphicsContext = @import("GraphicsContext.zig");
|
const GraphicsContext = @import("GraphicsContext.zig");
|
||||||
const DescriptorManager = @import("DescriptorManager.zig");
|
const DescriptorManager = @import("DescriptorManager.zig");
|
||||||
|
const render_common = @import("render_common.zig");
|
||||||
|
const DeferredDestroyQueue = render_common.DeferredDestroyQueue;
|
||||||
|
const RenderFrameState = render_common.RenderFrameState;
|
||||||
|
|
||||||
pub const AssetId = assets.AssetId;
|
pub const AssetId = assets.AssetId;
|
||||||
pub const Handle = assets.Handle;
|
pub const Handle = assets.Handle;
|
||||||
@ -64,6 +67,8 @@ texture_heap_memory: vk.DeviceMemory = .null_handle,
|
|||||||
vertex_heap: VertexBufferHeap,
|
vertex_heap: VertexBufferHeap,
|
||||||
gc: *GraphicsContext,
|
gc: *GraphicsContext,
|
||||||
descriptorman: *DescriptorManager,
|
descriptorman: *DescriptorManager,
|
||||||
|
// A way to access destroy queue
|
||||||
|
frame_state: *RenderFrameState,
|
||||||
|
|
||||||
// For uploads
|
// For uploads
|
||||||
queue: *GraphicsContext.QueueInstance,
|
queue: *GraphicsContext.QueueInstance,
|
||||||
@ -157,7 +162,7 @@ const AssetWatcher = struct {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
pub fn init(allocator: std.mem.Allocator, frame_arena: std.mem.Allocator, gc: *GraphicsContext, descriptorman: *DescriptorManager) !AssetManager {
|
pub fn init(allocator: std.mem.Allocator, frame_arena: std.mem.Allocator, gc: *GraphicsContext, descriptorman: *DescriptorManager, frame_state: *RenderFrameState) !AssetManager {
|
||||||
var buf: [std.fs.MAX_PATH_BYTES]u8 = undefined;
|
var buf: [std.fs.MAX_PATH_BYTES]u8 = undefined;
|
||||||
const exe_dir_path = std.fs.selfExeDirPath(&buf) catch @panic("can't find self exe dir path");
|
const exe_dir_path = std.fs.selfExeDirPath(&buf) catch @panic("can't find self exe dir path");
|
||||||
const exe_dir = std.fs.openDirAbsolute(exe_dir_path, .{}) catch @panic("can't open self exe dir path");
|
const exe_dir = std.fs.openDirAbsolute(exe_dir_path, .{}) catch @panic("can't open self exe dir path");
|
||||||
@ -180,6 +185,7 @@ pub fn init(allocator: std.mem.Allocator, frame_arena: std.mem.Allocator, gc: *G
|
|||||||
.vertex_heap = VertexBufferHeap.init(allocator) catch @panic("OOM"),
|
.vertex_heap = VertexBufferHeap.init(allocator) catch @panic("OOM"),
|
||||||
.gc = gc,
|
.gc = gc,
|
||||||
.descriptorman = descriptorman,
|
.descriptorman = descriptorman,
|
||||||
|
.frame_state = frame_state,
|
||||||
.queue = queue,
|
.queue = queue,
|
||||||
.command_pool = try queue.createCommandPool(.{ .transient_bit = true }),
|
.command_pool = try queue.createCommandPool(.{ .transient_bit = true }),
|
||||||
};
|
};
|
||||||
@ -1873,6 +1879,7 @@ fn deleteDependees(self: *AssetManager, id: AssetId) void {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn freeAsset(self: *AssetManager, asset: *LoadedAsset) void {
|
fn freeAsset(self: *AssetManager, asset: *LoadedAsset) void {
|
||||||
|
const destroy_queue = &self.frame_state.frame_data[self.frame_state.frame].destroy_queue;
|
||||||
switch (asset.*) {
|
switch (asset.*) {
|
||||||
.mesh => |*mesh| {
|
.mesh => |*mesh| {
|
||||||
self.vertex_heap.free(mesh.heap_handle);
|
self.vertex_heap.free(mesh.heap_handle);
|
||||||
@ -1881,18 +1888,12 @@ fn freeAsset(self: *AssetManager, asset: *LoadedAsset) void {
|
|||||||
self.allocator.free(shader.source);
|
self.allocator.free(shader.source);
|
||||||
},
|
},
|
||||||
.shaderProgram => |*program| {
|
.shaderProgram => |*program| {
|
||||||
self.gc.queues.graphics.mu.lock();
|
destroy_queue.queueDestroyPipeline(program.pipeline);
|
||||||
defer self.gc.queues.graphics.mu.unlock();
|
|
||||||
// TODO: wait for async compute idle to
|
|
||||||
|
|
||||||
self.gc.device.queueWaitIdle(self.gc.queues.graphics.handle) catch @panic("Wait Idle failed");
|
|
||||||
|
|
||||||
self.gc.device.destroyPipeline(program.pipeline, null);
|
|
||||||
},
|
},
|
||||||
.texture => |*texture| {
|
.texture => |*texture| {
|
||||||
_ = texture; // autofix
|
destroy_queue.queueDestroyImageDescriptor(texture.descriptor_handle);
|
||||||
// gl.GL_ARB_bindless_texture.makeTextureHandleNonResidentARB(texture.handle);
|
destroy_queue.queueDestroyImageView(texture.view);
|
||||||
// gl.deleteTextures(1, &texture.name);
|
destroy_queue.queueDestroyImage(texture.image);
|
||||||
},
|
},
|
||||||
.scene => |*scene| {
|
.scene => |*scene| {
|
||||||
self.allocator.free(scene.buf);
|
self.allocator.free(scene.buf);
|
||||||
@ -1950,9 +1951,6 @@ const VertexBufferHeap = struct {
|
|||||||
indices: Buffer,
|
indices: Buffer,
|
||||||
|
|
||||||
pub fn init(allocator: std.mem.Allocator) !Self {
|
pub fn init(allocator: std.mem.Allocator) !Self {
|
||||||
// 256 mega vertices :)
|
|
||||||
// memory usage for vertices (- indices) = n * 11 * 4
|
|
||||||
// 4096, 12 will take 704 mb for vertices
|
|
||||||
var vertex_buddy = try BuddyAllocator.init(allocator, 4096, 13);
|
var vertex_buddy = try BuddyAllocator.init(allocator, 4096, 13);
|
||||||
errdefer vertex_buddy.deinit();
|
errdefer vertex_buddy.deinit();
|
||||||
|
|
||||||
|
134
src/Render2.zig
134
src/Render2.zig
@ -8,6 +8,11 @@ const za = @import("zalgebra");
|
|||||||
const Vec3 = za.Vec3;
|
const Vec3 = za.Vec3;
|
||||||
const Mat4 = za.Mat4;
|
const Mat4 = za.Mat4;
|
||||||
const common = @import("common.zig");
|
const common = @import("common.zig");
|
||||||
|
const render_common = @import("render_common.zig");
|
||||||
|
const MAX_FRAME_LAG = render_common.MAX_FRAME_LAG;
|
||||||
|
const DeferredDestroyQueue = render_common.DeferredDestroyQueue;
|
||||||
|
const FrameData = render_common.FrameData;
|
||||||
|
const RenderFrameState = render_common.RenderFrameState;
|
||||||
|
|
||||||
const Render2 = @This();
|
const Render2 = @This();
|
||||||
|
|
||||||
@ -29,7 +34,6 @@ pub const Camera = struct {
|
|||||||
|
|
||||||
var default_camera: Camera = .{};
|
var default_camera: Camera = .{};
|
||||||
|
|
||||||
const MAX_FRAME_LAG = 3;
|
|
||||||
const PER_FRAME_ARENA_SIZE = 256 * common.MB;
|
const PER_FRAME_ARENA_SIZE = 256 * common.MB;
|
||||||
|
|
||||||
frame_allocator: std.mem.Allocator,
|
frame_allocator: std.mem.Allocator,
|
||||||
@ -40,13 +44,12 @@ command_pool: GraphicsContext.CommandPool,
|
|||||||
vulkan_frame_arena: VulkanPerFrameArena,
|
vulkan_frame_arena: VulkanPerFrameArena,
|
||||||
camera: *Camera = &default_camera,
|
camera: *Camera = &default_camera,
|
||||||
|
|
||||||
frame: u32 = 0,
|
|
||||||
frame_data: [MAX_FRAME_LAG]FrameData = undefined,
|
|
||||||
|
|
||||||
// Global sampler to use for reading screen color in post processing
|
// Global sampler to use for reading screen color in post processing
|
||||||
screen_color_sampler: vk.Sampler = .null_handle,
|
screen_color_sampler: vk.Sampler = .null_handle,
|
||||||
screen_color_sampler_descriptor_handle: DescriptorManager.DescriptorHandle = .{},
|
screen_color_sampler_descriptor_handle: DescriptorManager.DescriptorHandle = .{},
|
||||||
|
|
||||||
|
frame_state: *RenderFrameState,
|
||||||
|
|
||||||
// Ring buffer/arena for per frame data
|
// Ring buffer/arena for per frame data
|
||||||
pub const VulkanPerFrameArena = struct {
|
pub const VulkanPerFrameArena = struct {
|
||||||
const Self = @This();
|
const Self = @This();
|
||||||
@ -204,7 +207,7 @@ pub const VulkanPerFrameArena = struct {
|
|||||||
|
|
||||||
try device.bindBufferMemory(buffer, self.memory, out_addr.*);
|
try device.bindBufferMemory(buffer, self.memory, out_addr.*);
|
||||||
|
|
||||||
frame.queueDestroyBuffer(buffer);
|
frame.destroy_queue.queueDestroyBuffer(buffer);
|
||||||
|
|
||||||
return buffer;
|
return buffer;
|
||||||
}
|
}
|
||||||
@ -222,7 +225,7 @@ pub const VulkanPerFrameArena = struct {
|
|||||||
|
|
||||||
try gc.device.bindImageMemory(image, self.memory, out_addr.*);
|
try gc.device.bindImageMemory(image, self.memory, out_addr.*);
|
||||||
|
|
||||||
frame.queueDestroyImage(image);
|
frame.destroy_queue.queueDestroyImage(image);
|
||||||
|
|
||||||
return image;
|
return image;
|
||||||
}
|
}
|
||||||
@ -232,7 +235,7 @@ pub const VulkanPerFrameArena = struct {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
pub fn init(self: *Render2, frame_allocator: std.mem.Allocator, gc: *GraphicsContext, descriptorman: *DescriptorManager, assetman: *AssetManager) !void {
|
pub fn init(self: *Render2, frame_allocator: std.mem.Allocator, gc: *GraphicsContext, frame_state: *RenderFrameState, descriptorman: *DescriptorManager, assetman: *AssetManager) !void {
|
||||||
// Allocated in device local mem
|
// Allocated in device local mem
|
||||||
const per_frame_upload_memory = try gc.device.allocateMemory(&.{
|
const per_frame_upload_memory = try gc.device.allocateMemory(&.{
|
||||||
.memory_type_index = gc.memory_config.gpu.type_index,
|
.memory_type_index = gc.memory_config.gpu.type_index,
|
||||||
@ -245,6 +248,7 @@ pub fn init(self: *Render2, frame_allocator: std.mem.Allocator, gc: *GraphicsCon
|
|||||||
.descriptorman = descriptorman,
|
.descriptorman = descriptorman,
|
||||||
.assetman = assetman,
|
.assetman = assetman,
|
||||||
.command_pool = try gc.queues.graphics.createCommandPool(.{ .reset_command_buffer_bit = true }),
|
.command_pool = try gc.queues.graphics.createCommandPool(.{ .reset_command_buffer_bit = true }),
|
||||||
|
.frame_state = frame_state,
|
||||||
.vulkan_frame_arena = VulkanPerFrameArena{
|
.vulkan_frame_arena = VulkanPerFrameArena{
|
||||||
.memory_type_index = gc.memory_config.gpu.type_index,
|
.memory_type_index = gc.memory_config.gpu.type_index,
|
||||||
.memory = per_frame_upload_memory,
|
.memory = per_frame_upload_memory,
|
||||||
@ -273,9 +277,8 @@ pub fn init(self: *Render2, frame_allocator: std.mem.Allocator, gc: *GraphicsCon
|
|||||||
}, null);
|
}, null);
|
||||||
self.screen_color_sampler_descriptor_handle = self.descriptorman.sampler_descriptor_array.alloc(self.screen_color_sampler).handle;
|
self.screen_color_sampler_descriptor_handle = self.descriptorman.sampler_descriptor_array.alloc(self.screen_color_sampler).handle;
|
||||||
|
|
||||||
for (0..MAX_FRAME_LAG) |i| {
|
// TODO: Kinda strange to initialize here
|
||||||
self.frame_data[i] = try FrameData.init(gc, self.command_pool);
|
try self.frame_state.init(gc, self.command_pool);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub const MainRenderTarget = struct {
|
pub const MainRenderTarget = struct {
|
||||||
@ -370,15 +373,15 @@ fn allocateRenderTarget(self: *Render2) !MainRenderTarget {
|
|||||||
|
|
||||||
fn createPerFrameBuffer(self: *Render2, usage: vk.BufferUsageFlags, size: u64, out_addr: *u64) !vk.Buffer {
|
fn createPerFrameBuffer(self: *Render2, usage: vk.BufferUsageFlags, size: u64, out_addr: *u64) !vk.Buffer {
|
||||||
while (true) {
|
while (true) {
|
||||||
if (self.vulkan_frame_arena.createBufferRaw(&self.frame_data[self.frame], self.gc.device, usage, size, out_addr)) |buffer| {
|
if (self.vulkan_frame_arena.createBufferRaw(&self.frame_state.frame_data[self.frame_state.frame], self.gc.device, usage, size, out_addr)) |buffer| {
|
||||||
return buffer;
|
return buffer;
|
||||||
} else |err| switch (err) {
|
} else |err| switch (err) {
|
||||||
error.OverlapsPreviousFrame => {
|
error.OverlapsPreviousFrame => {
|
||||||
const overlapped_frame = (self.frame + 1) % MAX_FRAME_LAG;
|
const overlapped_frame = (self.frame_state.frame + 1) % MAX_FRAME_LAG;
|
||||||
|
|
||||||
std.debug.print("Vulkan Frame Allocator Overlapped frame {}, waiting for it to finish...\n", .{overlapped_frame});
|
std.debug.print("Vulkan Frame Allocator Overlapped frame {}, waiting for it to finish...\n", .{overlapped_frame});
|
||||||
|
|
||||||
try self.frame_data[overlapped_frame].waitForDrawAndReset(self);
|
try self.frame_state.frame_data[overlapped_frame].waitForDrawAndReset(self.gc.device, self.descriptorman);
|
||||||
self.vulkan_frame_arena.frame_regions[overlapped_frame] = null;
|
self.vulkan_frame_arena.frame_regions[overlapped_frame] = null;
|
||||||
},
|
},
|
||||||
else => return err,
|
else => return err,
|
||||||
@ -388,15 +391,15 @@ fn createPerFrameBuffer(self: *Render2, usage: vk.BufferUsageFlags, size: u64, o
|
|||||||
|
|
||||||
fn createPerFrameImage(self: *Render2, create_info: *const vk.ImageCreateInfo, out_addr: *u64) !vk.Image {
|
fn createPerFrameImage(self: *Render2, create_info: *const vk.ImageCreateInfo, out_addr: *u64) !vk.Image {
|
||||||
while (true) {
|
while (true) {
|
||||||
if (self.vulkan_frame_arena.createImageRaw(&self.frame_data[self.frame], self.gc, create_info, out_addr)) |image| {
|
if (self.vulkan_frame_arena.createImageRaw(&self.frame_state.frame_data[self.frame_state.frame], self.gc, create_info, out_addr)) |image| {
|
||||||
return image;
|
return image;
|
||||||
} else |err| switch (err) {
|
} else |err| switch (err) {
|
||||||
error.OverlapsPreviousFrame => {
|
error.OverlapsPreviousFrame => {
|
||||||
const overlapped_frame = (self.frame + 1) % MAX_FRAME_LAG;
|
const overlapped_frame = (self.frame_state.frame + 1) % MAX_FRAME_LAG;
|
||||||
|
|
||||||
std.debug.print("Vulkan Frame Allocator Overlapped frame {}, waiting for it to finish...\n", .{overlapped_frame});
|
std.debug.print("Vulkan Frame Allocator Overlapped frame {}, waiting for it to finish...\n", .{overlapped_frame});
|
||||||
|
|
||||||
try self.frame_data[overlapped_frame].waitForDrawAndReset(self);
|
try self.frame_state.frame_data[overlapped_frame].waitForDrawAndReset(self.gc.device, self.descriptorman);
|
||||||
self.vulkan_frame_arena.frame_regions[overlapped_frame] = null;
|
self.vulkan_frame_arena.frame_regions[overlapped_frame] = null;
|
||||||
},
|
},
|
||||||
else => return err,
|
else => return err,
|
||||||
@ -406,14 +409,14 @@ fn createPerFrameImage(self: *Render2, create_info: *const vk.ImageCreateInfo, o
|
|||||||
|
|
||||||
fn createPerFrameImageView(self: *Render2, create_info: *const vk.ImageViewCreateInfo) !vk.ImageView {
|
fn createPerFrameImageView(self: *Render2, create_info: *const vk.ImageViewCreateInfo) !vk.ImageView {
|
||||||
const view = try self.gc.device.createImageView(create_info, null);
|
const view = try self.gc.device.createImageView(create_info, null);
|
||||||
self.frame_data[self.frame].queueDestroyImageView(view);
|
self.frame_state.frame_data[self.frame_state.frame].destroy_queue.queueDestroyImageView(view);
|
||||||
|
|
||||||
return view;
|
return view;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn createPerFrameImageDescriptor(self: *Render2, view: vk.ImageView, layout: vk.ImageLayout) *DescriptorManager.DescriptorT(DescriptorManager.SampledImageDescriptorData) {
|
fn createPerFrameImageDescriptor(self: *Render2, view: vk.ImageView, layout: vk.ImageLayout) *DescriptorManager.DescriptorT(DescriptorManager.SampledImageDescriptorData) {
|
||||||
const result = self.descriptorman.image_descriptor_array_2d.alloc(.{ .view = view, .layout = layout });
|
const result = self.descriptorman.image_descriptor_array_2d.alloc(.{ .view = view, .layout = layout });
|
||||||
self.frame_data[self.frame].queueDestroyImageDescriptor(result.handle);
|
self.frame_state.frame_data[self.frame_state.frame].destroy_queue.queueDestroyImageDescriptor(result.handle);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -424,13 +427,13 @@ fn pushConstants(self: *Render2, cmds: GraphicsContext.CommandBuffer, stage_flag
|
|||||||
pub fn draw(self: *Render2) !void {
|
pub fn draw(self: *Render2) !void {
|
||||||
const gc = self.gc;
|
const gc = self.gc;
|
||||||
const device = gc.device;
|
const device = gc.device;
|
||||||
const frame = &self.frame_data[self.frame];
|
const frame = &self.frame_state.frame_data[self.frame_state.frame];
|
||||||
|
|
||||||
try frame.waitForDrawAndReset(self);
|
try frame.waitForDrawAndReset(self.gc.device, self.descriptorman);
|
||||||
|
|
||||||
const swapchain_image_index: u32 = try gc.acquireSwapchainImage(frame.acquire_swapchain_image);
|
const swapchain_image_index: u32 = try gc.acquireSwapchainImage(frame.acquire_swapchain_image);
|
||||||
|
|
||||||
self.vulkan_frame_arena.startFrame(self.frame);
|
self.vulkan_frame_arena.startFrame(self.frame_state.frame);
|
||||||
|
|
||||||
var global_buffer_addr: u64 = 0;
|
var global_buffer_addr: u64 = 0;
|
||||||
const global_uniform_buffer_handle = try self.createPerFrameBuffer(.{ .uniform_buffer_bit = true, .transfer_dst_bit = true }, @sizeOf(GlobalUniform), &global_buffer_addr);
|
const global_uniform_buffer_handle = try self.createPerFrameBuffer(.{ .uniform_buffer_bit = true, .transfer_dst_bit = true }, @sizeOf(GlobalUniform), &global_buffer_addr);
|
||||||
@ -684,7 +687,7 @@ pub fn draw(self: *Render2) !void {
|
|||||||
.p_image_indices = &.{swapchain_image_index},
|
.p_image_indices = &.{swapchain_image_index},
|
||||||
});
|
});
|
||||||
|
|
||||||
self.frame = (self.frame + 1) % MAX_FRAME_LAG;
|
self.frame_state.frame = (self.frame_state.frame + 1) % MAX_FRAME_LAG;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn uploadData(self: *Render2, cmds: GraphicsContext.CommandBuffer, dst: GraphicsContext.Buffer, dst_offset: usize, len: usize) !void {
|
fn uploadData(self: *Render2, cmds: GraphicsContext.CommandBuffer, dst: GraphicsContext.Buffer, dst_offset: usize, len: usize) !void {
|
||||||
@ -702,93 +705,6 @@ fn uploadData(self: *Render2, cmds: GraphicsContext.CommandBuffer, dst: Graphics
|
|||||||
self.upload_buffer_cursor += len;
|
self.upload_buffer_cursor += len;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Per frame stuff
|
|
||||||
pub const FrameData = struct {
|
|
||||||
// Sync
|
|
||||||
acquire_swapchain_image: vk.Semaphore,
|
|
||||||
draw_sema: vk.Semaphore,
|
|
||||||
draw_fence: vk.Fence,
|
|
||||||
draw_submitted: bool = true,
|
|
||||||
|
|
||||||
command_buffer: GraphicsContext.CommandBuffer,
|
|
||||||
|
|
||||||
// Store references to per frame allocated objects here, they will be cleaned up after frame finished rendering
|
|
||||||
buffers: [1024]vk.Buffer = undefined,
|
|
||||||
buffer_count: u32 = 0,
|
|
||||||
|
|
||||||
images: [1024]vk.Image = undefined,
|
|
||||||
image_count: u32 = 0,
|
|
||||||
|
|
||||||
image_views: [1024]vk.ImageView = undefined,
|
|
||||||
image_view_count: u32 = 0,
|
|
||||||
|
|
||||||
image_descriptors: [1024]DescriptorManager.DescriptorHandle = undefined,
|
|
||||||
image_descriptor_count: u32 = 0,
|
|
||||||
|
|
||||||
pub fn init(gc: *GraphicsContext, command_pool: GraphicsContext.CommandPool) !FrameData {
|
|
||||||
return FrameData{
|
|
||||||
.acquire_swapchain_image = try gc.device.createSemaphore(&.{}, null),
|
|
||||||
.draw_sema = try gc.device.createSemaphore(&.{}, null),
|
|
||||||
.draw_fence = try gc.device.createFence(&.{ .flags = .{ .signaled_bit = true } }, null),
|
|
||||||
|
|
||||||
.command_buffer = try command_pool.allocateCommandBuffer(),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn queueDestroyBuffer(self: *FrameData, buffer: vk.Buffer) void {
|
|
||||||
self.buffers[self.buffer_count] = buffer;
|
|
||||||
self.buffer_count += 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn queueDestroyImage(self: *FrameData, image: vk.Image) void {
|
|
||||||
self.images[self.image_count] = image;
|
|
||||||
self.image_count += 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn queueDestroyImageView(self: *FrameData, view: vk.ImageView) void {
|
|
||||||
self.image_views[self.image_view_count] = view;
|
|
||||||
self.image_view_count += 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn queueDestroyImageDescriptor(self: *FrameData, descriptor: DescriptorManager.DescriptorHandle) void {
|
|
||||||
self.image_descriptors[self.image_descriptor_count] = descriptor;
|
|
||||||
self.image_descriptor_count += 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn waitForDrawAndReset(self: *FrameData, render: *Render2) !void {
|
|
||||||
if (!self.draw_submitted) return;
|
|
||||||
|
|
||||||
self.draw_submitted = false;
|
|
||||||
const device = render.gc.device;
|
|
||||||
_ = try device.waitForFences(1, &.{self.draw_fence}, vk.TRUE, std.math.maxInt(u64));
|
|
||||||
try device.resetFences(1, &.{self.draw_fence});
|
|
||||||
|
|
||||||
try self.command_buffer.resetCommandBuffer(.{ .release_resources_bit = true });
|
|
||||||
|
|
||||||
for (self.image_descriptors[0..self.image_descriptor_count]) |desc| {
|
|
||||||
render.descriptorman.image_descriptor_array_2d.free(desc);
|
|
||||||
}
|
|
||||||
self.image_descriptor_count = 0;
|
|
||||||
|
|
||||||
try render.descriptorman.commitDescriptorArrayUpdates();
|
|
||||||
|
|
||||||
for (self.buffers[0..self.buffer_count]) |buf| {
|
|
||||||
device.destroyBuffer(buf, null);
|
|
||||||
}
|
|
||||||
self.buffer_count = 0;
|
|
||||||
|
|
||||||
for (self.image_views[0..self.image_view_count]) |view| {
|
|
||||||
device.destroyImageView(view, null);
|
|
||||||
}
|
|
||||||
self.image_view_count = 0;
|
|
||||||
|
|
||||||
for (self.images[0..self.image_count]) |img| {
|
|
||||||
device.destroyImage(img, null);
|
|
||||||
}
|
|
||||||
self.image_count = 0;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const GlobalUniform = extern struct {
|
const GlobalUniform = extern struct {
|
||||||
pub const View = extern struct {
|
pub const View = extern struct {
|
||||||
world_to_clip: Mat4,
|
world_to_clip: Mat4,
|
||||||
|
@ -176,11 +176,11 @@ export fn game_init(global_allocator: *std.mem.Allocator) void {
|
|||||||
.global_allocator = global_allocator.*,
|
.global_allocator = global_allocator.*,
|
||||||
.frame_fba = std.heap.FixedBufferAllocator.init(frame_arena_buffer),
|
.frame_fba = std.heap.FixedBufferAllocator.init(frame_arena_buffer),
|
||||||
.descriptorman = DescriptorManager.init(&globals.g_init.gc, globals.g_mem.frame_fba.allocator()) catch @panic("DescriptorManager.init"),
|
.descriptorman = DescriptorManager.init(&globals.g_init.gc, globals.g_mem.frame_fba.allocator()) catch @panic("DescriptorManager.init"),
|
||||||
.assetman = AssetManager.init(global_allocator.*, globals.g_mem.frame_fba.allocator(), &globals.g_init.gc, &globals.g_mem.descriptorman) catch @panic("AssetManager.init"),
|
.assetman = AssetManager.init(global_allocator.*, globals.g_mem.frame_fba.allocator(), &globals.g_init.gc, &globals.g_mem.descriptorman, &globals.g_mem.frame_state) catch @panic("AssetManager.init"),
|
||||||
// .render = Render.init(global_allocator.*, globals.g_mem.frame_fba.allocator(), &globals.g_mem.assetman),
|
// .render = Render.init(global_allocator.*, globals.g_mem.frame_fba.allocator(), &globals.g_mem.assetman),
|
||||||
.world = .{ .frame_arena = globals.g_mem.frame_fba.allocator() },
|
.world = .{ .frame_arena = globals.g_mem.frame_fba.allocator() },
|
||||||
};
|
};
|
||||||
globals.g_mem.render2.init(globals.g_mem.frame_fba.allocator(), &globals.g_init.gc, &globals.g_mem.descriptorman, &globals.g_mem.assetman) catch @panic("OOM");
|
globals.g_mem.render2.init(globals.g_mem.frame_fba.allocator(), &globals.g_init.gc, &globals.g_mem.frame_state, &globals.g_mem.descriptorman, &globals.g_mem.assetman) catch @panic("OOM");
|
||||||
globals.g_mem.render2.camera = &globals.g_mem.free_cam.camera;
|
globals.g_mem.render2.camera = &globals.g_mem.free_cam.camera;
|
||||||
std.log.debug("actual ptr: {}, correct ptr {}", .{ globals.g_mem.assetman.frame_arena.ptr, globals.g_mem.frame_fba.allocator().ptr });
|
std.log.debug("actual ptr: {}, correct ptr {}", .{ globals.g_mem.assetman.frame_arena.ptr, globals.g_mem.frame_fba.allocator().ptr });
|
||||||
globals.g_assetman = &globals.g_mem.assetman;
|
globals.g_assetman = &globals.g_mem.assetman;
|
||||||
|
@ -4,6 +4,7 @@ const Render = @import("Render.zig");
|
|||||||
const Render2 = @import("Render2.zig");
|
const Render2 = @import("Render2.zig");
|
||||||
const AssetManager = @import("AssetManager.zig");
|
const AssetManager = @import("AssetManager.zig");
|
||||||
const DescriptorManager = @import("DescriptorManager.zig");
|
const DescriptorManager = @import("DescriptorManager.zig");
|
||||||
|
const RenderFrameState = @import("render_common.zig").RenderFrameState;
|
||||||
const World = @import("entity.zig").World;
|
const World = @import("entity.zig").World;
|
||||||
const GraphicsContext = @import("GraphicsContext.zig");
|
const GraphicsContext = @import("GraphicsContext.zig");
|
||||||
|
|
||||||
@ -37,6 +38,7 @@ pub const GameMemory = struct {
|
|||||||
global_allocator: std.mem.Allocator,
|
global_allocator: std.mem.Allocator,
|
||||||
frame_fba: std.heap.FixedBufferAllocator,
|
frame_fba: std.heap.FixedBufferAllocator,
|
||||||
descriptorman: DescriptorManager,
|
descriptorman: DescriptorManager,
|
||||||
|
frame_state: RenderFrameState = .{},
|
||||||
assetman: AssetManager,
|
assetman: AssetManager,
|
||||||
render: Render = undefined,
|
render: Render = undefined,
|
||||||
render2: Render2 = undefined,
|
render2: Render2 = undefined,
|
||||||
|
149
src/render_common.zig
Normal file
149
src/render_common.zig
Normal file
@ -0,0 +1,149 @@
|
|||||||
|
const std = @import("std");
|
||||||
|
const vk = @import("vk");
|
||||||
|
const GraphicsContext = @import("GraphicsContext.zig");
|
||||||
|
const DescriptorManager = @import("DescriptorManager.zig");
|
||||||
|
|
||||||
|
pub const MAX_FRAME_LAG = 3;
|
||||||
|
|
||||||
|
/// Destroy queue attached to a fence. Useful for freeing buffers and stuff after render has finished for example.
|
||||||
|
/// Call destroy only when fence is signaled
|
||||||
|
pub const DeferredDestroyQueue = struct {
|
||||||
|
const Self = @This();
|
||||||
|
|
||||||
|
fence: vk.Fence,
|
||||||
|
|
||||||
|
// TODO: replace with dynamic arrays?
|
||||||
|
buffers: [1024]vk.Buffer = undefined,
|
||||||
|
buffer_count: u32 = 0,
|
||||||
|
|
||||||
|
images: [1024]vk.Image = undefined,
|
||||||
|
image_count: u32 = 0,
|
||||||
|
|
||||||
|
image_views: [1024]vk.ImageView = undefined,
|
||||||
|
image_view_count: u32 = 0,
|
||||||
|
|
||||||
|
image_descriptors: [1024]DescriptorManager.DescriptorHandle = undefined,
|
||||||
|
image_descriptor_count: u32 = 0,
|
||||||
|
|
||||||
|
pipelines: [1024]vk.Pipeline = undefined,
|
||||||
|
pipeline_count: u32 = 0,
|
||||||
|
|
||||||
|
pub fn init(fence: vk.Fence) Self {
|
||||||
|
return Self{
|
||||||
|
.fence = fence,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn queueDestroyBuffer(self: *Self, buffer: vk.Buffer) void {
|
||||||
|
self.buffers[self.buffer_count] = buffer;
|
||||||
|
self.buffer_count += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn queueDestroyImage(self: *Self, image: vk.Image) void {
|
||||||
|
self.images[self.image_count] = image;
|
||||||
|
self.image_count += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn queueDestroyImageView(self: *Self, view: vk.ImageView) void {
|
||||||
|
self.image_views[self.image_view_count] = view;
|
||||||
|
self.image_view_count += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn queueDestroyImageDescriptor(self: *Self, descriptor: DescriptorManager.DescriptorHandle) void {
|
||||||
|
self.image_descriptors[self.image_descriptor_count] = descriptor;
|
||||||
|
self.image_descriptor_count += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn queueDestroyPipeline(self: *Self, pipeline: vk.Pipeline) void {
|
||||||
|
self.pipelines[self.image_descriptor_count] = pipeline;
|
||||||
|
self.pipeline_count += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn isSignaled(self: *const Self, device: GraphicsContext.Device) !bool {
|
||||||
|
return (try device.getFenceStatus(self.fence)) == .success;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn wait(self: *const Self, device: GraphicsContext.Device, timeout: u64) void {
|
||||||
|
_ = try device.waitForFences(1, &.{self.fence}, vk.TRUE, timeout);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn destroy(self: *Self, device: GraphicsContext.Device, descriptorman: *DescriptorManager) !void {
|
||||||
|
std.debug.assert(try self.isSignaled(device)); // fence is not signaled yet, not safe to destroy
|
||||||
|
|
||||||
|
for (self.image_descriptors[0..self.image_descriptor_count]) |desc| {
|
||||||
|
descriptorman.image_descriptor_array_2d.free(desc);
|
||||||
|
}
|
||||||
|
self.image_descriptor_count = 0;
|
||||||
|
|
||||||
|
try descriptorman.commitDescriptorArrayUpdates();
|
||||||
|
|
||||||
|
for (self.buffers[0..self.buffer_count]) |buf| {
|
||||||
|
device.destroyBuffer(buf, null);
|
||||||
|
}
|
||||||
|
self.buffer_count = 0;
|
||||||
|
|
||||||
|
for (self.image_views[0..self.image_view_count]) |view| {
|
||||||
|
device.destroyImageView(view, null);
|
||||||
|
}
|
||||||
|
self.image_view_count = 0;
|
||||||
|
|
||||||
|
for (self.images[0..self.image_count]) |img| {
|
||||||
|
device.destroyImage(img, null);
|
||||||
|
}
|
||||||
|
self.image_count = 0;
|
||||||
|
|
||||||
|
for (self.pipelines[0..self.pipeline_count]) |pipeline| {
|
||||||
|
device.destroyPipeline(pipeline, null);
|
||||||
|
}
|
||||||
|
self.pipeline_count = 0;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Per frame stuff
|
||||||
|
pub const FrameData = struct {
|
||||||
|
// Sync
|
||||||
|
acquire_swapchain_image: vk.Semaphore,
|
||||||
|
draw_sema: vk.Semaphore,
|
||||||
|
draw_fence: vk.Fence,
|
||||||
|
draw_submitted: bool = true,
|
||||||
|
destroy_queue: DeferredDestroyQueue,
|
||||||
|
|
||||||
|
command_buffer: GraphicsContext.CommandBuffer,
|
||||||
|
|
||||||
|
pub fn init(gc: *GraphicsContext, command_pool: GraphicsContext.CommandPool) !FrameData {
|
||||||
|
const fence = try gc.device.createFence(&.{ .flags = .{ .signaled_bit = true } }, null);
|
||||||
|
|
||||||
|
return FrameData{
|
||||||
|
.acquire_swapchain_image = try gc.device.createSemaphore(&.{}, null),
|
||||||
|
.draw_sema = try gc.device.createSemaphore(&.{}, null),
|
||||||
|
.draw_fence = fence,
|
||||||
|
|
||||||
|
.command_buffer = try command_pool.allocateCommandBuffer(),
|
||||||
|
.destroy_queue = DeferredDestroyQueue.init(fence),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn waitForDrawAndReset(self: *FrameData, device: GraphicsContext.Device, descriptorman: *DescriptorManager) !void {
|
||||||
|
if (!self.draw_submitted) return;
|
||||||
|
|
||||||
|
self.draw_submitted = false;
|
||||||
|
_ = try device.waitForFences(1, &.{self.draw_fence}, vk.TRUE, std.math.maxInt(u64));
|
||||||
|
|
||||||
|
try self.destroy_queue.destroy(device, descriptorman);
|
||||||
|
|
||||||
|
try device.resetFences(1, &.{self.draw_fence});
|
||||||
|
|
||||||
|
try self.command_buffer.resetCommandBuffer(.{ .release_resources_bit = true });
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const RenderFrameState = struct {
|
||||||
|
frame: u32 = 0,
|
||||||
|
frame_data: [MAX_FRAME_LAG]FrameData = undefined,
|
||||||
|
|
||||||
|
pub fn init(self: *RenderFrameState, gc: *GraphicsContext, command_pool: GraphicsContext.CommandPool) !void {
|
||||||
|
for (0..MAX_FRAME_LAG) |i| {
|
||||||
|
self.frame_data[i] = try FrameData.init(gc, command_pool);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
Loading…
x
Reference in New Issue
Block a user