From 919d7d5a9d3efdff1a81a847128b9bb73510e66b Mon Sep 17 00:00:00 2001 From: IntegratedQuantum Date: Thu, 16 Nov 2023 17:49:45 +0100 Subject: [PATCH] Dynamically resize the GPU buffer if needed. It does create some lag, but that should only happen once. Maybe in the future I should investigate some alternatives to the copying. --- src/chunk.zig | 2 +- src/graphics.zig | 33 ++++++++++++++++++++++++++++----- 2 files changed, 29 insertions(+), 6 deletions(-) diff --git a/src/chunk.zig b/src/chunk.zig index 87c9ff2c..42492914 100644 --- a/src/chunk.zig +++ b/src/chunk.zig @@ -441,7 +441,7 @@ pub const meshing = struct { c.glBindVertexArray(0); faces = try std.ArrayList(u32).initCapacity(main.globalAllocator, 65536); - try faceBuffer.init(main.globalAllocator, 1 << 30, 3); + try faceBuffer.init(main.globalAllocator, 1 << 20, 3); } pub fn deinit() void { diff --git a/src/graphics.zig b/src/graphics.zig index 2e6fd412..346c97e4 100644 --- a/src/graphics.zig +++ b/src/graphics.zig @@ -1211,17 +1211,23 @@ pub const LargeBuffer = struct { fences: [3]c.GLsync, fencedFreeLists: [3]std.ArrayList(Allocation), activeFence: u8, - capacity: u32, + capacity: u31, used: u32, + binding: c_uint, - pub fn init(self: *LargeBuffer, allocator: Allocator, size: u31, binding: c_uint) !void { + fn createBuffer(self: *LargeBuffer, size: u31) void { self.ssbo = SSBO.init(); c.glBindBuffer(c.GL_SHADER_STORAGE_BUFFER, self.ssbo.bufferID); const flags = c.GL_MAP_WRITE_BIT | c.GL_MAP_PERSISTENT_BIT | c.GL_MAP_COHERENT_BIT; c.glBufferStorage(c.GL_SHADER_STORAGE_BUFFER, size, null, flags); self.persistentBuffer = @ptrCast(c.glMapBufferRange(c.GL_SHADER_STORAGE_BUFFER, 0, size, flags | c.GL_MAP_INVALIDATE_BUFFER_BIT).?); - self.ssbo.bind(binding); + self.ssbo.bind(self.binding); self.capacity = size; + } + + pub fn init(self: *LargeBuffer, allocator: Allocator, size: u31, binding: c_uint) !void { + self.binding = binding; + self.createBuffer(size); self.activeFence = 0; for(&self.fences) |*fence| { fence.* = c.glFenceSync(c.GL_SYNC_GPU_COMMANDS_COMPLETE, 0); @@ -1241,6 +1247,8 @@ pub const LargeBuffer = struct { for(self.fencedFreeLists) |list| { list.deinit(); } + c.glBindBuffer(c.GL_SHADER_STORAGE_BUFFER, self.ssbo.bufferID); + _ = c.glUnmapBuffer(c.GL_SHADER_STORAGE_BUFFER); self.ssbo.deinit(); self.freeBlocks.deinit(); } @@ -1276,7 +1284,22 @@ pub const LargeBuffer = struct { block.start += size; block.len -= size; return result; - } else return error.OutOfMemory; // TODO: Increase the buffer size. + } else { + std.log.info("Resizing internal mesh buffer from {} MiB to {} MiB", .{self.capacity >> 20, (self.capacity >> 20)*2}); + const oldBuffer = self.ssbo; + defer oldBuffer.deinit(); + c.glBindBuffer(c.GL_SHADER_STORAGE_BUFFER, oldBuffer.bufferID); + _ = c.glUnmapBuffer(c.GL_SHADER_STORAGE_BUFFER); + const oldCapacity = self.capacity; + self.createBuffer(self.capacity*2); // TODO: Is there a way to free the old buffer before creating the new one? + self.used += self.capacity - oldCapacity; + try self.finalFree(.{.start = oldCapacity, .len = self.capacity - oldCapacity}); + + c.glBindBuffer(c.GL_COPY_READ_BUFFER, oldBuffer.bufferID); + c.glBindBuffer(c.GL_COPY_WRITE_BUFFER, self.ssbo.bufferID); + c.glCopyBufferSubData(c.GL_COPY_READ_BUFFER, c.GL_COPY_WRITE_BUFFER, 0, 0, oldCapacity); + return alloc(self, size); + } } fn finalFree(self: *LargeBuffer, _allocation: Allocation) !void { @@ -1838,7 +1861,7 @@ pub fn generateBlockTexture(blockType: u16) !Texture { c.glActiveTexture(c.GL_TEXTURE1); main.blocks.meshes.emissionTextureArray.bind(); block_texture.depthTexture.bindTo(3); - c.glDrawElementsBaseVertex(c.GL_TRIANGLES, 6*faces, c.GL_UNSIGNED_INT, null, allocation.start/8*4); + c.glDrawElementsBaseVertex(c.GL_TRIANGLES, 6*faces, c.GL_UNSIGNED_INT, null, allocation.start/@sizeOf(main.chunk.meshing.FaceData)*4); var finalFrameBuffer: FrameBuffer = undefined; finalFrameBuffer.init(false, c.GL_NEAREST, c.GL_REPEAT);