mirror of
https://github.com/PixelGuys/Cubyz.git
synced 2025-08-03 19:28:49 -04:00
Move all chunk data into single SSBO.
Right now this doesn't change much, but in the future this will be helpful when(if?) I get started with multidraw and putting stuff like frustum culling onto the gpu.
This commit is contained in:
parent
a777449a7c
commit
0d6303f7de
@ -28,7 +28,6 @@ struct FaceData {
|
||||
};
|
||||
layout(std430, binding = 3) buffer _faceData
|
||||
{
|
||||
int voxelSize;
|
||||
FaceData faceData[];
|
||||
};
|
||||
|
||||
@ -46,6 +45,7 @@ layout(std430, binding = 4) buffer _voxelModels
|
||||
};
|
||||
|
||||
uniform int time;
|
||||
uniform int voxelSize;
|
||||
|
||||
const vec3[6] normals = vec3[6](
|
||||
vec3(0, 1, 0),
|
||||
|
@ -393,10 +393,12 @@ pub const meshing = struct {
|
||||
@"waterFog.density": c_int,
|
||||
time: c_int,
|
||||
visibilityMask: c_int,
|
||||
voxelSize: c_int,
|
||||
} = undefined;
|
||||
var vao: c_uint = undefined;
|
||||
var vbo: c_uint = undefined;
|
||||
var faces: std.ArrayList(u32) = undefined;
|
||||
var faceData: graphics.LargeBuffer = undefined;
|
||||
|
||||
pub fn init() !void {
|
||||
shader = try Shader.create("assets/cubyz/shaders/chunks/chunk_vertex.vs", "assets/cubyz/shaders/chunks/chunk_fragment.fs");
|
||||
@ -417,6 +419,7 @@ pub const meshing = struct {
|
||||
c.glBindVertexArray(0);
|
||||
|
||||
faces = try std.ArrayList(u32).initCapacity(std.heap.page_allocator, 65536);
|
||||
try faceData.init(main.globalAllocator, 64 << 20, 3);
|
||||
}
|
||||
|
||||
pub fn deinit() void {
|
||||
@ -424,6 +427,7 @@ pub const meshing = struct {
|
||||
c.glDeleteVertexArrays(1, &vao);
|
||||
c.glDeleteBuffers(1, &vbo);
|
||||
faces.deinit();
|
||||
faceData.deinit();
|
||||
}
|
||||
|
||||
pub fn bindShaderAndUniforms(projMatrix: Mat4f, ambient: Vec3f, time: u32) void {
|
||||
@ -452,7 +456,7 @@ pub const meshing = struct {
|
||||
size: ChunkCoordinate,
|
||||
chunk: std.atomic.Atomic(?*Chunk),
|
||||
faces: std.ArrayList(u32),
|
||||
faceData: SSBO,
|
||||
bufferAllocation: graphics.LargeBuffer.Allocation = .{.start = 0, .len = 0},
|
||||
coreCount: u31 = 0,
|
||||
neighborStart: [7]u31 = [_]u31{0} ** 7,
|
||||
vertexCount: u31 = 0,
|
||||
@ -466,12 +470,11 @@ pub const meshing = struct {
|
||||
.size = chunkSize*pos.voxelSize,
|
||||
.faces = std.ArrayList(u32).init(allocator),
|
||||
.chunk = std.atomic.Atomic(?*Chunk).init(null),
|
||||
.faceData = SSBO.init(),
|
||||
};
|
||||
}
|
||||
|
||||
pub fn deinit(self: *ChunkMesh) void {
|
||||
self.faceData.deinit();
|
||||
faceData.free(self.bufferAllocation) catch unreachable;
|
||||
self.faces.deinit();
|
||||
if(self.chunk.load(.Monotonic)) |ch| {
|
||||
renderer.RenderStructure.allocator.destroy(ch);
|
||||
@ -508,13 +511,13 @@ pub const meshing = struct {
|
||||
or other.typ == 0
|
||||
or false // TODO: Blocks.mode(other).checkTransparency(other, neighbor) // TODO: make blocks.meshes.modelIndices(other) != 0 more strict to avoid overdraw.
|
||||
or (!std.meta.eql(block, other) and other.viewThrough())
|
||||
or blocks.meshes.modelIndices(other) != 0);
|
||||
or blocks.meshes.modelIndices(other) != 0
|
||||
);
|
||||
}
|
||||
|
||||
pub fn regenerateMainMesh(self: *ChunkMesh, chunk: *Chunk) !void {
|
||||
std.debug.assert(!self.mutex.tryLock()); // The mutex should be locked when calling this function.
|
||||
self.faces.clearRetainingCapacity();
|
||||
try self.faces.append(chunk.pos.voxelSize);
|
||||
var n: u32 = 0;
|
||||
var x: u8 = 0;
|
||||
while(x < chunkSize): (x += 1) {
|
||||
@ -582,7 +585,7 @@ pub const meshing = struct {
|
||||
start.* -= 2;
|
||||
}
|
||||
} else {
|
||||
searchStart = 1;
|
||||
searchStart = 0;
|
||||
searchEnd = self.coreCount;
|
||||
self.coreCount -= 2;
|
||||
for(self.neighborStart) |*start| {
|
||||
@ -606,7 +609,7 @@ pub const meshing = struct {
|
||||
if(fromNeighborChunk) |neighbor| {
|
||||
searchRange = self.faces.items[self.neighborStart[neighbor]..self.neighborStart[neighbor+1]];
|
||||
} else {
|
||||
searchRange = self.faces.items[1..self.coreCount];
|
||||
searchRange = self.faces.items[0..self.coreCount];
|
||||
}
|
||||
var i: u32 = 0;
|
||||
while(i < searchRange.len): (i += 2) {
|
||||
@ -699,15 +702,16 @@ pub const meshing = struct {
|
||||
}
|
||||
}
|
||||
}
|
||||
if(neighborMesh != self) neighborMesh.uploadData();
|
||||
if(neighborMesh != self) try neighborMesh.uploadData();
|
||||
}
|
||||
self.chunk.load(.Monotonic).?.blocks[getIndex(x, y, z)] = newBlock;
|
||||
self.uploadData();
|
||||
try self.uploadData();
|
||||
}
|
||||
|
||||
fn uploadData(self: *ChunkMesh) void {
|
||||
self.vertexCount = @intCast(u31, 6*(self.faces.items.len-1)/2);
|
||||
self.faceData.bufferData(u32, self.faces.items);
|
||||
fn uploadData(self: *ChunkMesh) !void {
|
||||
self.vertexCount = @intCast(u31, 6*self.faces.items.len/2);
|
||||
try faceData.realloc(&self.bufferAllocation, @intCast(u31, 4*self.faces.items.len));
|
||||
faceData.bufferSubData(self.bufferAllocation.start, u32, self.faces.items);
|
||||
}
|
||||
|
||||
pub fn uploadDataAndFinishNeighbors(self: *ChunkMesh) !void {
|
||||
@ -772,8 +776,7 @@ pub const meshing = struct {
|
||||
for(neighborMesh.neighborStart[1+(neighbor ^ 1)..]) |*neighborStart| {
|
||||
neighborStart.* = neighborStart.* - (rangeEnd - rangeStart) + @intCast(u31, additionalNeighborFaces.items.len);
|
||||
}
|
||||
neighborMesh.vertexCount = @intCast(u31, 6*(neighborMesh.faces.items.len-1)/2);
|
||||
neighborMesh.faceData.bufferData(u32, neighborMesh.faces.items);
|
||||
try neighborMesh.uploadData();
|
||||
continue;
|
||||
}
|
||||
}
|
||||
@ -826,7 +829,7 @@ pub const meshing = struct {
|
||||
}
|
||||
}
|
||||
self.neighborStart[6] = @intCast(u31, self.faces.items.len);
|
||||
self.uploadData();
|
||||
try self.uploadData();
|
||||
self.generated = true;
|
||||
}
|
||||
|
||||
@ -842,8 +845,8 @@ pub const meshing = struct {
|
||||
@floatCast(f32, @intToFloat(f64, self.pos.wz) - playerPosition[2])
|
||||
);
|
||||
c.glUniform1i(uniforms.visibilityMask, self.visibilityMask);
|
||||
self.faceData.bind(3);
|
||||
c.glDrawElements(c.GL_TRIANGLES, self.vertexCount, c.GL_UNSIGNED_INT, null);
|
||||
c.glUniform1i(uniforms.voxelSize, self.pos.voxelSize);
|
||||
c.glDrawElementsBaseVertex(c.GL_TRIANGLES, self.vertexCount, c.GL_UNSIGNED_INT, null, self.bufferAllocation.start/8*4);
|
||||
}
|
||||
};
|
||||
};
|
116
src/graphics.zig
116
src/graphics.zig
@ -423,6 +423,122 @@ pub const SSBO = struct {
|
||||
c.glBufferData(c.GL_SHADER_STORAGE_BUFFER, @intCast(c_long, data.len*@sizeOf(T)), data.ptr, c.GL_STATIC_DRAW);
|
||||
c.glBindBuffer(c.GL_SHADER_STORAGE_BUFFER, 0);
|
||||
}
|
||||
|
||||
pub fn createDynamicBuffer(self: SSBO, size: usize) void {
|
||||
c.glBindBuffer(c.GL_SHADER_STORAGE_BUFFER, self.bufferID);
|
||||
c.glBufferData(c.GL_SHADER_STORAGE_BUFFER, @intCast(c_long, size), null, c.GL_DYNAMIC_DRAW);
|
||||
c.glBindBuffer(c.GL_SHADER_STORAGE_BUFFER, 0);
|
||||
}
|
||||
};
|
||||
|
||||
/// A big SSBO that is able to allocate/free smaller regions.
|
||||
pub const LargeBuffer = struct {
|
||||
pub const Allocation = struct {
|
||||
start: u31,
|
||||
len: u31,
|
||||
};
|
||||
ssbo: SSBO,
|
||||
freeBlocks: std.ArrayList(Allocation),
|
||||
|
||||
pub fn init(self: *LargeBuffer, allocator: Allocator, size: u31, binding: c_uint) !void {
|
||||
self.ssbo = SSBO.init();
|
||||
self.ssbo.createDynamicBuffer(size);
|
||||
self.ssbo.bind(binding);
|
||||
|
||||
self.freeBlocks = std.ArrayList(Allocation).init(allocator);
|
||||
try self.freeBlocks.append(.{.start = 0, .len = size});
|
||||
}
|
||||
|
||||
pub fn deinit(self: *LargeBuffer) void {
|
||||
self.ssbo.deinit();
|
||||
self.freeBlocks.deinit();
|
||||
}
|
||||
|
||||
fn alloc(self: *LargeBuffer, size: u31) !Allocation {
|
||||
var smallestBlock: ?*Allocation = null;
|
||||
for(self.freeBlocks.items) |*block, i| {
|
||||
if(size == block.len) {
|
||||
return self.freeBlocks.swapRemove(i);
|
||||
}
|
||||
if(size < block.len and if(smallestBlock) |_smallestBlock| block.len > _smallestBlock.len else true) {
|
||||
smallestBlock = block;
|
||||
}
|
||||
}
|
||||
if(smallestBlock) |block| {
|
||||
const result = Allocation {.start = block.start, .len = size};
|
||||
block.start += size;
|
||||
block.len -= size;
|
||||
return result;
|
||||
} else return error.OutOfMemory; // TODO: Increase the buffer size.
|
||||
}
|
||||
|
||||
pub fn free(self: *LargeBuffer, _allocation: Allocation) !void {
|
||||
var allocation = _allocation;
|
||||
if(allocation.len == 0) return;
|
||||
for(self.freeBlocks.items) |*block, i| {
|
||||
if(allocation.start + allocation.len == block.start) {
|
||||
allocation.len += block.len;
|
||||
_ = self.freeBlocks.swapRemove(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
for(self.freeBlocks.items) |*block| {
|
||||
if(allocation.start == block.start + block.len) {
|
||||
block.len += allocation.len;
|
||||
return;
|
||||
}
|
||||
}
|
||||
try self.freeBlocks.append(allocation);
|
||||
}
|
||||
|
||||
pub fn realloc(self: *LargeBuffer, allocation: *Allocation, newSize: u31) !void {
|
||||
if(allocation.len == 0) allocation.* = try self.alloc(newSize);
|
||||
if(newSize == allocation.len) return;
|
||||
if(newSize < allocation.len) {
|
||||
const diff = allocation.len - newSize;
|
||||
// Check if there is a free block directly after:
|
||||
for(self.freeBlocks.items) |*block| {
|
||||
if(allocation.start + allocation.len == block.start and block.len + allocation.len >= newSize) {
|
||||
block.start -= diff;
|
||||
block.len += diff;
|
||||
allocation.len -= diff;
|
||||
return;
|
||||
}
|
||||
}
|
||||
// Create a new free block:
|
||||
allocation.len -= diff;
|
||||
try self.freeBlocks.append(.{.start = allocation.start + allocation.len, .len = diff});
|
||||
} else {
|
||||
// Check if the buffer can be extended without a problem:
|
||||
for(self.freeBlocks.items) |*block, i| {
|
||||
if(allocation.start + allocation.len == block.start and block.len + allocation.len >= newSize) {
|
||||
const diff = newSize - allocation.len;
|
||||
allocation.len += diff;
|
||||
if(block.len != diff) {
|
||||
block.start += diff;
|
||||
block.len -= diff;
|
||||
} else {
|
||||
_ = self.freeBlocks.swapRemove(i);
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
const oldAllocation = allocation.*;
|
||||
allocation.* = try self.alloc(newSize);
|
||||
|
||||
c.glBindBuffer(c.GL_SHADER_STORAGE_BUFFER, self.ssbo.bufferID);
|
||||
c.glCopyBufferSubData(c.GL_SHADER_STORAGE_BUFFER, c.GL_SHADER_STORAGE_BUFFER, oldAllocation.start, allocation.start, oldAllocation.len);
|
||||
c.glBindBuffer(c.GL_SHADER_STORAGE_BUFFER, 0);
|
||||
|
||||
try self.free(oldAllocation);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn bufferSubData(self: *LargeBuffer, offset: u31, comptime T: type, data: []T) void {
|
||||
c.glBindBuffer(c.GL_SHADER_STORAGE_BUFFER, self.ssbo.bufferID);
|
||||
c.glBufferSubData(c.GL_SHADER_STORAGE_BUFFER, offset, @sizeOf(T)*@intCast(c_long, data.len), data.ptr);
|
||||
c.glBindBuffer(c.GL_SHADER_STORAGE_BUFFER, 0);
|
||||
}
|
||||
};
|
||||
|
||||
pub const FrameBuffer = struct {
|
||||
|
Loading…
x
Reference in New Issue
Block a user