Start using SSBOs for lights

This commit is contained in:
sergeypdev 2024-03-15 18:35:09 +04:00
parent a41e4b64d3
commit f92283d152
2 changed files with 67 additions and 27 deletions

View File

@ -27,9 +27,9 @@ layout(std140, binding = 0) uniform Matrices {
mat4 view; mat4 view;
}; };
layout(std140, binding = 1) uniform Lights { layout(std430, binding = 1) readonly buffer Lights {
Light lights[MAX_POINT_LIGHTS];
uint lights_count; uint lights_count;
Light lights[];
}; };
int getShadowMapIndex(int lightIdx) { int getShadowMapIndex(int lightIdx) {

View File

@ -40,13 +40,14 @@ tripple_buffer_index: usize = MAX_FRAMES_QUEUED - 1,
gl_fences: [MAX_FRAMES_QUEUED]?gl.GLsync = [_]?gl.GLsync{null} ** MAX_FRAMES_QUEUED, gl_fences: [MAX_FRAMES_QUEUED]?gl.GLsync = [_]?gl.GLsync{null} ** MAX_FRAMES_QUEUED,
camera_ubo: gl.GLuint = 0, camera_ubo: gl.GLuint = 0,
camera_matrices: []u8 = &.{}, camera_matrices: []u8 = &.{},
point_lights_ubo: gl.GLuint = 0, point_lights_ssbo: gl.GLuint = 0,
point_lights: []u8 = &.{}, // TODO: remove point_lights: []u8 = &.{}, // TODO: remove
lights: [MAX_LIGHT_COMMANDS]LightCommand = undefined, lights: [MAX_LIGHT_COMMANDS]LightCommand = undefined,
light_count: usize = 0, light_count: usize = 0,
command_buffer: [MAX_DRAW_COMMANDS]DrawCommand = undefined, command_buffer: [MAX_DRAW_COMMANDS]DrawCommand = undefined,
command_count: usize = 0, command_count: usize = 0,
ubo_align: usize = 0, ubo_align: usize = 0,
ssbo_align: usize = 0,
shadow_vao: gl.GLuint = 0, shadow_vao: gl.GLuint = 0,
shadow_texture_array: gl.GLuint = 0, shadow_texture_array: gl.GLuint = 0,
shadow_texture_handle: gl.GLuint64 = 0, shadow_texture_handle: gl.GLuint64 = 0,
@ -84,12 +85,19 @@ pub fn init(allocator: std.mem.Allocator, frame_arena: std.mem.Allocator, assetm
gl.clipControl(gl.LOWER_LEFT, gl.ZERO_TO_ONE); // use [0, 1] depth in NDC gl.clipControl(gl.LOWER_LEFT, gl.ZERO_TO_ONE); // use [0, 1] depth in NDC
var buffer_align_int: gl.GLint = 0; {
gl.getIntegerv(gl.UNIFORM_BUFFER_OFFSET_ALIGNMENT, &buffer_align_int); var buffer_align_int: gl.GLint = 0;
gl.getIntegerv(gl.UNIFORM_BUFFER_OFFSET_ALIGNMENT, &buffer_align_int);
if (buffer_align_int == 0) @panic("Failed to query GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT");
render.ubo_align = @intCast(buffer_align_int);
}
if (buffer_align_int == 0) @panic("Failed to query GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT"); {
var buffer_align_int: gl.GLint = 0;
render.ubo_align = @intCast(buffer_align_int); gl.getIntegerv(gl.SHADER_STORAGE_BUFFER_OFFSET_ALIGNMENT, &buffer_align_int);
if (buffer_align_int == 0) @panic("Failed to query GL_SHADER_STORAGE_BUFFER_OFFSET_ALIGNMENT");
render.ssbo_align = @intCast(buffer_align_int);
}
{ {
// MESH VAO // MESH VAO
@ -148,24 +156,24 @@ pub fn init(allocator: std.mem.Allocator, frame_arena: std.mem.Allocator, assetm
// Point lights ubo // Point lights ubo
{ {
gl.createBuffers(1, &render.point_lights_ubo); gl.createBuffers(1, &render.point_lights_ssbo);
std.debug.assert(render.camera_ubo != 0); std.debug.assert(render.camera_ubo != 0);
const buf_size = render.uboAlignedSizeOf(LightArray) * MAX_FRAMES_QUEUED; const buf_size = render.ssboAlign(@sizeOf(LightArraySSBO) + Light.sizeOfStd430() * MAX_LIGHTS) * MAX_FRAMES_QUEUED;
gl.namedBufferStorage( gl.namedBufferStorage(
render.point_lights_ubo, render.point_lights_ssbo,
@intCast(buf_size), @intCast(buf_size),
null, null,
PERSISTENT_BUFFER_FLAGS, PERSISTENT_BUFFER_FLAGS,
); );
const point_lights_c: [*]u8 = @ptrCast(gl.mapNamedBufferRange( const point_lights_c: [*]u8 = @ptrCast(gl.mapNamedBufferRange(
render.point_lights_ubo, render.point_lights_ssbo,
0, 0,
@intCast(buf_size), @intCast(buf_size),
PERSISTENT_BUFFER_FLAGS, PERSISTENT_BUFFER_FLAGS,
) orelse { ) orelse {
checkGLError(); checkGLError();
@panic("bind point_lights_ubo"); @panic("bind point_lights_ssbo");
}); });
render.point_lights = point_lights_c[0..buf_size]; render.point_lights = point_lights_c[0..buf_size];
} }
@ -391,21 +399,22 @@ pub fn begin(self: *Render) void {
} }
} }
fn getLightBuffer(self: *Render) *LightArray { fn getLightBuffer(self: *Render) *LightArraySSBO {
return @alignCast(@ptrCast(self.point_lights[self.tripple_buffer_index * self.uboAlignedSizeOf(LightArray) ..].ptr)); return @alignCast(@ptrCast(self.point_lights[self.tripple_buffer_index * self.ssboAlign(@sizeOf(LightArraySSBO) + Light.sizeOfStd430() * MAX_LIGHTS) ..].ptr));
} }
// TODO: get rid of this // TODO: get rid of this
pub fn flushUBOs(self: *Render) void { pub fn flushUBOs(self: *Render) void {
const idx = self.tripple_buffer_index; const idx = self.tripple_buffer_index;
// gl.flushMappedNamedBufferRange(self.point_lights_ubo, idx * @sizeOf(PointLightArray), @sizeOf(PointLightArray)); const light_array_size = self.ssboAlign(@sizeOf(LightArraySSBO) + Light.sizeOfStd430() * MAX_LIGHTS);
// gl.flushMappedNamedBufferRange(self.point_lights_ssbo, idx * @sizeOf(PointLightArray), @sizeOf(PointLightArray));
gl.bindBufferRange( gl.bindBufferRange(
gl.UNIFORM_BUFFER, gl.SHADER_STORAGE_BUFFER,
UBO.PointLights.value(), SSBO.PointLights.value(),
self.point_lights_ubo, self.point_lights_ssbo,
idx * self.uboAlignedSizeOf(LightArray), idx * light_array_size,
@intCast(self.uboAlignedSizeOf(LightArray)), @intCast(light_array_size),
); );
checkGLError(); checkGLError();
} }
@ -497,6 +506,7 @@ pub fn finish(self: *Render) void {
const lights_buf = self.getLightBuffer(); const lights_buf = self.getLightBuffer();
lights_buf.count = 0; lights_buf.count = 0;
const lights_buf_lights = lights_buf.getLights();
var dir_view_proj_mat: [CSM_SPLITS]Mat4 = undefined; var dir_view_proj_mat: [CSM_SPLITS]Mat4 = undefined;
@ -513,9 +523,9 @@ pub fn finish(self: *Render) void {
for (lights) |light_cmd| { for (lights) |light_cmd| {
const i = lights_buf.count; const i = lights_buf.count;
if (i == lights_buf.lights.len) break; if (i == lights_buf_lights.len) break;
const light = &lights_buf.lights[i]; const light = &lights_buf_lights[i];
lights_buf.count += 1; lights_buf.count += 1;
switch (light_cmd) { switch (light_cmd) {
@ -697,7 +707,7 @@ pub fn finish(self: *Render) void {
} }
// Light world space to view space // Light world space to view space
for (lights_buf.lights[0..lights_buf.count]) |*light| { for (lights_buf_lights[0..lights_buf.count]) |*light| {
light.pos = self.camera.view_mat.mulByVec4(light.pos); light.pos = self.camera.view_mat.mulByVec4(light.pos);
} }
@ -1093,12 +1103,18 @@ pub const Attrib = enum(gl.GLuint) {
}; };
pub const UBO = enum(gl.GLuint) { pub const UBO = enum(gl.GLuint) {
CameraMatrices = 0, CameraMatrices = 0,
PointLights = 1,
pub inline fn value(self: UBO) gl.GLuint { pub inline fn value(self: UBO) gl.GLuint {
return @intFromEnum(self); return @intFromEnum(self);
} }
}; };
pub const SSBO = enum(gl.GLuint) {
PointLights = 1,
pub inline fn value(self: SSBO) gl.GLuint {
return @intFromEnum(self);
}
};
pub const Uniform = enum(gl.GLint) { pub const Uniform = enum(gl.GLint) {
ModelMatrix = 1, ModelMatrix = 1,
@ -1169,14 +1185,38 @@ pub const Light = extern struct {
csm_split_count: f32, csm_split_count: f32,
}, },
csm_split_points: [4]f32 = undefined, csm_split_points: [4]f32 = undefined,
/// Alignment of this struct if it was in a std430 array
pub fn alignStd430() usize {
return 16;
}
/// Aligned size of this struct if it was in a std430 array
pub fn sizeOfStd430() usize {
return std.mem.alignForward(usize, @sizeOf(Light), Light.alignStd430());
}
}; };
// TODO: rename // TODO: rename
pub const LightArray = extern struct { pub const LightArraySSBO = extern struct {
lights: [MAX_LIGHTS]Light align(16),
count: c_uint, count: c_uint,
// Zero sized field that just has the right alignment
_lights_start: [0]Light align(Light.alignStd430()),
pub fn getLights(self: *LightArraySSBO) []align(Light.alignStd430()) Light {
var lights_c: [*]align(Light.alignStd430()) Light = @ptrFromInt(@intFromPtr(self) + @offsetOf(LightArraySSBO, "_lights_start"));
return lights_c[0..MAX_LIGHTS];
}
}; };
fn uboAlignedSizeOf(self: *const Render, comptime T: type) usize { fn uboAlignedSizeOf(self: *const Render, comptime T: type) usize {
return std.mem.alignForward(usize, @sizeOf(T), self.ubo_align); return std.mem.alignForward(usize, @sizeOf(T), self.ubo_align);
} }
fn ssboAlign(self: *const Render, size: usize) usize {
return std.mem.alignForward(usize, size, self.ssbo_align);
}
fn ssboAlignedSizeOf(self: *const Render, comptime T: type) usize {
return self.ssboAlign(@sizeOf(T));
}