mirror of
https://github.com/PixelGuys/Cubyz.git
synced 2025-08-04 03:37:59 -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
|
layout(std430, binding = 3) buffer _faceData
|
||||||
{
|
{
|
||||||
int voxelSize;
|
|
||||||
FaceData faceData[];
|
FaceData faceData[];
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -46,6 +45,7 @@ layout(std430, binding = 4) buffer _voxelModels
|
|||||||
};
|
};
|
||||||
|
|
||||||
uniform int time;
|
uniform int time;
|
||||||
|
uniform int voxelSize;
|
||||||
|
|
||||||
const vec3[6] normals = vec3[6](
|
const vec3[6] normals = vec3[6](
|
||||||
vec3(0, 1, 0),
|
vec3(0, 1, 0),
|
||||||
|
@ -393,10 +393,12 @@ pub const meshing = struct {
|
|||||||
@"waterFog.density": c_int,
|
@"waterFog.density": c_int,
|
||||||
time: c_int,
|
time: c_int,
|
||||||
visibilityMask: c_int,
|
visibilityMask: c_int,
|
||||||
|
voxelSize: c_int,
|
||||||
} = undefined;
|
} = undefined;
|
||||||
var vao: c_uint = undefined;
|
var vao: c_uint = undefined;
|
||||||
var vbo: c_uint = undefined;
|
var vbo: c_uint = undefined;
|
||||||
var faces: std.ArrayList(u32) = undefined;
|
var faces: std.ArrayList(u32) = undefined;
|
||||||
|
var faceData: graphics.LargeBuffer = undefined;
|
||||||
|
|
||||||
pub fn init() !void {
|
pub fn init() !void {
|
||||||
shader = try Shader.create("assets/cubyz/shaders/chunks/chunk_vertex.vs", "assets/cubyz/shaders/chunks/chunk_fragment.fs");
|
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);
|
c.glBindVertexArray(0);
|
||||||
|
|
||||||
faces = try std.ArrayList(u32).initCapacity(std.heap.page_allocator, 65536);
|
faces = try std.ArrayList(u32).initCapacity(std.heap.page_allocator, 65536);
|
||||||
|
try faceData.init(main.globalAllocator, 64 << 20, 3);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn deinit() void {
|
pub fn deinit() void {
|
||||||
@ -424,6 +427,7 @@ pub const meshing = struct {
|
|||||||
c.glDeleteVertexArrays(1, &vao);
|
c.glDeleteVertexArrays(1, &vao);
|
||||||
c.glDeleteBuffers(1, &vbo);
|
c.glDeleteBuffers(1, &vbo);
|
||||||
faces.deinit();
|
faces.deinit();
|
||||||
|
faceData.deinit();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn bindShaderAndUniforms(projMatrix: Mat4f, ambient: Vec3f, time: u32) void {
|
pub fn bindShaderAndUniforms(projMatrix: Mat4f, ambient: Vec3f, time: u32) void {
|
||||||
@ -452,7 +456,7 @@ pub const meshing = struct {
|
|||||||
size: ChunkCoordinate,
|
size: ChunkCoordinate,
|
||||||
chunk: std.atomic.Atomic(?*Chunk),
|
chunk: std.atomic.Atomic(?*Chunk),
|
||||||
faces: std.ArrayList(u32),
|
faces: std.ArrayList(u32),
|
||||||
faceData: SSBO,
|
bufferAllocation: graphics.LargeBuffer.Allocation = .{.start = 0, .len = 0},
|
||||||
coreCount: u31 = 0,
|
coreCount: u31 = 0,
|
||||||
neighborStart: [7]u31 = [_]u31{0} ** 7,
|
neighborStart: [7]u31 = [_]u31{0} ** 7,
|
||||||
vertexCount: u31 = 0,
|
vertexCount: u31 = 0,
|
||||||
@ -466,12 +470,11 @@ pub const meshing = struct {
|
|||||||
.size = chunkSize*pos.voxelSize,
|
.size = chunkSize*pos.voxelSize,
|
||||||
.faces = std.ArrayList(u32).init(allocator),
|
.faces = std.ArrayList(u32).init(allocator),
|
||||||
.chunk = std.atomic.Atomic(?*Chunk).init(null),
|
.chunk = std.atomic.Atomic(?*Chunk).init(null),
|
||||||
.faceData = SSBO.init(),
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn deinit(self: *ChunkMesh) void {
|
pub fn deinit(self: *ChunkMesh) void {
|
||||||
self.faceData.deinit();
|
faceData.free(self.bufferAllocation) catch unreachable;
|
||||||
self.faces.deinit();
|
self.faces.deinit();
|
||||||
if(self.chunk.load(.Monotonic)) |ch| {
|
if(self.chunk.load(.Monotonic)) |ch| {
|
||||||
renderer.RenderStructure.allocator.destroy(ch);
|
renderer.RenderStructure.allocator.destroy(ch);
|
||||||
@ -508,13 +511,13 @@ pub const meshing = struct {
|
|||||||
or other.typ == 0
|
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 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 (!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 {
|
pub fn regenerateMainMesh(self: *ChunkMesh, chunk: *Chunk) !void {
|
||||||
std.debug.assert(!self.mutex.tryLock()); // The mutex should be locked when calling this function.
|
std.debug.assert(!self.mutex.tryLock()); // The mutex should be locked when calling this function.
|
||||||
self.faces.clearRetainingCapacity();
|
self.faces.clearRetainingCapacity();
|
||||||
try self.faces.append(chunk.pos.voxelSize);
|
|
||||||
var n: u32 = 0;
|
var n: u32 = 0;
|
||||||
var x: u8 = 0;
|
var x: u8 = 0;
|
||||||
while(x < chunkSize): (x += 1) {
|
while(x < chunkSize): (x += 1) {
|
||||||
@ -582,7 +585,7 @@ pub const meshing = struct {
|
|||||||
start.* -= 2;
|
start.* -= 2;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
searchStart = 1;
|
searchStart = 0;
|
||||||
searchEnd = self.coreCount;
|
searchEnd = self.coreCount;
|
||||||
self.coreCount -= 2;
|
self.coreCount -= 2;
|
||||||
for(self.neighborStart) |*start| {
|
for(self.neighborStart) |*start| {
|
||||||
@ -606,7 +609,7 @@ pub const meshing = struct {
|
|||||||
if(fromNeighborChunk) |neighbor| {
|
if(fromNeighborChunk) |neighbor| {
|
||||||
searchRange = self.faces.items[self.neighborStart[neighbor]..self.neighborStart[neighbor+1]];
|
searchRange = self.faces.items[self.neighborStart[neighbor]..self.neighborStart[neighbor+1]];
|
||||||
} else {
|
} else {
|
||||||
searchRange = self.faces.items[1..self.coreCount];
|
searchRange = self.faces.items[0..self.coreCount];
|
||||||
}
|
}
|
||||||
var i: u32 = 0;
|
var i: u32 = 0;
|
||||||
while(i < searchRange.len): (i += 2) {
|
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.chunk.load(.Monotonic).?.blocks[getIndex(x, y, z)] = newBlock;
|
||||||
self.uploadData();
|
try self.uploadData();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn uploadData(self: *ChunkMesh) void {
|
fn uploadData(self: *ChunkMesh) !void {
|
||||||
self.vertexCount = @intCast(u31, 6*(self.faces.items.len-1)/2);
|
self.vertexCount = @intCast(u31, 6*self.faces.items.len/2);
|
||||||
self.faceData.bufferData(u32, self.faces.items);
|
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 {
|
pub fn uploadDataAndFinishNeighbors(self: *ChunkMesh) !void {
|
||||||
@ -772,8 +776,7 @@ pub const meshing = struct {
|
|||||||
for(neighborMesh.neighborStart[1+(neighbor ^ 1)..]) |*neighborStart| {
|
for(neighborMesh.neighborStart[1+(neighbor ^ 1)..]) |*neighborStart| {
|
||||||
neighborStart.* = neighborStart.* - (rangeEnd - rangeStart) + @intCast(u31, additionalNeighborFaces.items.len);
|
neighborStart.* = neighborStart.* - (rangeEnd - rangeStart) + @intCast(u31, additionalNeighborFaces.items.len);
|
||||||
}
|
}
|
||||||
neighborMesh.vertexCount = @intCast(u31, 6*(neighborMesh.faces.items.len-1)/2);
|
try neighborMesh.uploadData();
|
||||||
neighborMesh.faceData.bufferData(u32, neighborMesh.faces.items);
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -826,7 +829,7 @@ pub const meshing = struct {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
self.neighborStart[6] = @intCast(u31, self.faces.items.len);
|
self.neighborStart[6] = @intCast(u31, self.faces.items.len);
|
||||||
self.uploadData();
|
try self.uploadData();
|
||||||
self.generated = true;
|
self.generated = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -842,8 +845,8 @@ pub const meshing = struct {
|
|||||||
@floatCast(f32, @intToFloat(f64, self.pos.wz) - playerPosition[2])
|
@floatCast(f32, @intToFloat(f64, self.pos.wz) - playerPosition[2])
|
||||||
);
|
);
|
||||||
c.glUniform1i(uniforms.visibilityMask, self.visibilityMask);
|
c.glUniform1i(uniforms.visibilityMask, self.visibilityMask);
|
||||||
self.faceData.bind(3);
|
c.glUniform1i(uniforms.voxelSize, self.pos.voxelSize);
|
||||||
c.glDrawElements(c.GL_TRIANGLES, self.vertexCount, c.GL_UNSIGNED_INT, null);
|
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.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);
|
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 {
|
pub const FrameBuffer = struct {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user