diff --git a/assets/cubyz/shaders/animation_pre_processing.glsl b/assets/cubyz/shaders/animation_pre_processing.glsl new file mode 100644 index 00000000..8cc9654d --- /dev/null +++ b/assets/cubyz/shaders/animation_pre_processing.glsl @@ -0,0 +1,42 @@ +#version 430 + +layout (local_size_x = 64, local_size_y = 1, local_size_z = 1) in; + +struct AnimationData { + int frames; + int time; +}; + +struct TextureData { + int textureIndices[6]; + uint absorption; + float reflectivity; + float fogDensity; + uint fogColor; +}; + +layout(std430, binding = 0) buffer _animation +{ + AnimationData animation[]; +}; +layout(std430, binding = 6) buffer _textureDataIn +{ + TextureData textureDataIn[]; +}; +layout(std430, binding = 1) buffer _textureDataOut +{ + TextureData textureDataOut[]; +}; + +uniform int time; +uniform int size; + +void main() { + uint index = gl_GlobalInvocationID.x; + if(index >= size) return; + for(int i = 0; i < 6; i++) { + int textureIndex = textureDataIn[index].textureIndices[i]; + textureIndex = textureIndex + time / animation[textureIndex].time % animation[textureIndex].frames; + textureDataOut[index].textureIndices[i] = textureIndex; + } +} \ No newline at end of file diff --git a/assets/cubyz/shaders/chunks/chunk_fragment.fs b/assets/cubyz/shaders/chunks/chunk_fragment.fs index edf4484a..c1bef69b 100644 --- a/assets/cubyz/shaders/chunks/chunk_fragment.fs +++ b/assets/cubyz/shaders/chunks/chunk_fragment.fs @@ -10,18 +10,12 @@ flat in int ditherSeed; in vec3 startPosition; in vec3 direction; -uniform int time; uniform vec3 ambientLight; uniform sampler2DArray texture_sampler; uniform sampler2DArray emissionSampler; layout(location = 0) out vec4 fragColor; -struct AnimationData { - int frames; - int time; -}; - #define modelSize 16 struct VoxelModel { ivec4 minimum; @@ -37,10 +31,6 @@ struct TextureData { uint fogColor; }; -layout(std430, binding = 0) buffer _animation -{ - AnimationData animation[]; -}; layout(std430, binding = 1) buffer _textureData { TextureData textureData[]; @@ -237,7 +227,6 @@ void main() { } if(!result.hitAThing) discard; int textureIndex = textureData[blockType].textureIndices[result.textureDir]; - textureIndex = textureIndex + time / animation[textureIndex].time % animation[textureIndex].frames; float normalVariation = normalVariations[result.normal]; float lod = getLod(result.voxelPosition, result.normal, direction, variance); ivec2 textureCoords = getTextureCoords(result.voxelPosition, result.textureDir); diff --git a/assets/cubyz/shaders/chunks/transparent_fragment.fs b/assets/cubyz/shaders/chunks/transparent_fragment.fs index b6318c86..2bc2e944 100644 --- a/assets/cubyz/shaders/chunks/transparent_fragment.fs +++ b/assets/cubyz/shaders/chunks/transparent_fragment.fs @@ -9,7 +9,6 @@ flat in int ditherSeed; in vec3 startPosition; in vec3 direction; -uniform int time; uniform vec3 ambientLight; uniform sampler2DArray texture_sampler; uniform sampler2DArray emissionSampler; @@ -26,11 +25,6 @@ struct Fog { float density; }; -struct AnimationData { - int frames; - int time; -}; - struct TextureData { int textureIndices[6]; uint absorption; @@ -39,10 +33,6 @@ struct TextureData { uint fogColor; }; -layout(std430, binding = 0) buffer _animation -{ - AnimationData animation[]; -}; layout(std430, binding = 1) buffer _textureData { TextureData textureData[]; @@ -143,7 +133,6 @@ vec4 fixedCubeMapLookup(vec3 v) { // Taken from http://the-witness.net/news/2012 void main() { int textureIndex = textureData[blockType].textureIndices[faceNormal]; - textureIndex = textureIndex + time / animation[textureIndex].time % animation[textureIndex].frames; vec3 textureCoords = vec3(getTextureCoordsNormal(startPosition/16, faceNormal), textureIndex); float normalVariation = normalVariations[faceNormal]; float densityAdjustment = sqrt(dot(mvVertexPos, mvVertexPos))/abs(mvVertexPos.z); diff --git a/src/blocks.zig b/src/blocks.zig index 188f732e..172eb65f 100644 --- a/src/blocks.zig +++ b/src/blocks.zig @@ -3,10 +3,12 @@ const std = @import("std"); const main = @import("root"); const JsonElement = @import("json.zig").JsonElement; const Neighbors = @import("chunk.zig").Neighbors; -const SSBO = @import("graphics.zig").SSBO; -const Image = @import("graphics.zig").Image; -const Color = @import("graphics.zig").Color; -const TextureArray = @import("graphics.zig").TextureArray; +const graphics = @import("graphics.zig"); +const Shader = graphics.Shader; +const SSBO = graphics.SSBO; +const Image = graphics.Image; +const Color = graphics.Color; +const TextureArray = graphics.TextureArray; const items = @import("items.zig"); const models = @import("models.zig"); const rotation = @import("rotation.zig"); @@ -344,7 +346,14 @@ pub const meshes = struct { }; var animationSSBO: SSBO = undefined; - var textureIndexSSBO: SSBO = undefined; + var textureDataSSBO: SSBO = undefined; + var animatedTextureDataSSBO: SSBO = undefined; + + var animationShader: Shader = undefined; + var animationUniforms: struct { + time: c_int, + size: c_int, + } = undefined; pub var blockTextureArray: TextureArray = undefined; pub var emissionTextureArray: TextureArray = undefined; @@ -356,11 +365,14 @@ pub const meshes = struct { var emptyTexture = [_]Color {black}; const emptyImage = Image{.width = 1, .height = 1, .imageData = emptyTexture[0..]}; - pub fn init() void { + pub fn init() !void { animationSSBO = SSBO.init(); animationSSBO.bind(0); - textureIndexSSBO = SSBO.init(); - textureIndexSSBO.bind(1); + textureDataSSBO = SSBO.init(); + textureDataSSBO.bind(6); + animatedTextureDataSSBO = SSBO.init(); + animatedTextureDataSSBO.bind(1); + animationShader = try Shader.initComputeAndGetUniforms("assets/cubyz/shaders/animation_pre_processing.glsl", &animationUniforms); blockTextureArray = TextureArray.init(); emissionTextureArray = TextureArray.init(); arenaForArrayLists = std.heap.ArenaAllocator.init(main.globalAllocator); @@ -373,7 +385,9 @@ pub const meshes = struct { pub fn deinit() void { animationSSBO.deinit(); - textureIndexSSBO.deinit(); + textureDataSSBO.deinit(); + animatedTextureDataSSBO.deinit(); + animationShader.deinit(); blockTextureArray.deinit(); emissionTextureArray.deinit(); arenaForArrayLists.deinit(); @@ -549,12 +563,21 @@ pub const meshes = struct { // } // } + pub fn preProcessAnimationData(time: u32) void { + animationShader.bind(); + graphics.c.glUniform1i(animationUniforms.time, @bitCast(time)); + graphics.c.glUniform1i(animationUniforms.size, @intCast(meshes.size)); + graphics.c.glDispatchCompute(@divFloor(meshes.size + 63, 64), 1, 1); // TODO: Replace with @divCeil once available + graphics.c.glMemoryBarrier(graphics.c.GL_SHADER_STORAGE_BARRIER_BIT); + } + pub fn generateTextureArray() !void { try blockTextureArray.generate(blockTextures.items, true); try emissionTextureArray.generate(emissionTextures.items, true); // Also generate additional buffers: animationSSBO.bufferData(AnimationData, animation.items); - textureIndexSSBO.bufferData(TextureData, textureData[0..meshes.size]); + textureDataSSBO.bufferData(TextureData, textureData[0..meshes.size]); + animatedTextureDataSSBO.bufferData(TextureData, textureData[0..meshes.size]); } }; diff --git a/src/chunk.zig b/src/chunk.zig index 2537123a..ba680e86 100644 --- a/src/chunk.zig +++ b/src/chunk.zig @@ -399,7 +399,6 @@ pub const meshing = struct { emissionSampler: c_int, reflectionMap: c_int, reflectionMapSize: c_int, - time: c_int, visibilityMask: c_int, voxelSize: c_int, zNear: c_int, @@ -444,7 +443,7 @@ pub const meshing = struct { faceBuffer.deinit(); } - pub fn bindShaderAndUniforms(projMatrix: Mat4f, ambient: Vec3f, time: u32) void { + pub fn bindShaderAndUniforms(projMatrix: Mat4f, ambient: Vec3f) void { shader.bind(); c.glUniformMatrix4fv(uniforms.projectionMatrix, 1, c.GL_FALSE, @ptrCast(&projMatrix)); @@ -458,15 +457,13 @@ pub const meshing = struct { c.glUniform3f(uniforms.ambientLight, ambient[0], ambient[1], ambient[2]); - c.glUniform1i(uniforms.time, @as(u31, @truncate(time))); - c.glUniform1f(uniforms.zNear, renderer.zNear); c.glUniform1f(uniforms.zFar, renderer.zFar); c.glBindVertexArray(vao); } - pub fn bindTransparentShaderAndUniforms(projMatrix: Mat4f, ambient: Vec3f, time: u32) void { + pub fn bindTransparentShaderAndUniforms(projMatrix: Mat4f, ambient: Vec3f) void { transparentShader.bind(); c.glUniform3fv(transparentUniforms.@"fog.color", 1, @ptrCast(&game.fog.color)); @@ -483,8 +480,6 @@ pub const meshing = struct { c.glUniform3f(transparentUniforms.ambientLight, ambient[0], ambient[1], ambient[2]); - c.glUniform1i(transparentUniforms.time, @as(u31, @truncate(time))); - c.glUniform1f(transparentUniforms.zNear, renderer.zNear); c.glUniform1f(transparentUniforms.zFar, renderer.zFar); diff --git a/src/graphics.zig b/src/graphics.zig index a57bb01e..c9f36e13 100644 --- a/src/graphics.zig +++ b/src/graphics.zig @@ -1110,6 +1110,23 @@ pub const Shader = struct { return self; } + pub fn initCompute(compute: []const u8) !Shader { + var shader = Shader{.id = c.glCreateProgram()}; + try shader.addShader(compute, c.GL_COMPUTE_SHADER); + try shader.link(); + return shader; + } + + pub fn initComputeAndGetUniforms(compute: []const u8, ptrToUniformStruct: anytype) !Shader { + const self = try Shader.initCompute(compute); + inline for(@typeInfo(@TypeOf(ptrToUniformStruct.*)).Struct.fields) |field| { + if(field.type == c_int) { + @field(ptrToUniformStruct, field.name) = c.glGetUniformLocation(self.id, field.name[0..] ++ "\x00"); // TODO: #16072 + } + } + return self; + } + pub fn bind(self: *const Shader) void { c.glUseProgram(self.id); } @@ -1753,9 +1770,9 @@ pub fn generateBlockTexture(blockType: u16) !Texture { if(block.transparent()) { c.glBlendEquation(c.GL_FUNC_ADD); c.glBlendFunc(c.GL_ONE, c.GL_SRC1_COLOR); - main.chunk.meshing.bindTransparentShaderAndUniforms(projMatrix, .{1, 1, 1}, 0); + main.chunk.meshing.bindTransparentShaderAndUniforms(projMatrix, .{1, 1, 1}); } else { - main.chunk.meshing.bindShaderAndUniforms(projMatrix, .{1, 1, 1}, 0); + main.chunk.meshing.bindShaderAndUniforms(projMatrix, .{1, 1, 1}); } const uniforms = if(block.transparent()) &main.chunk.meshing.transparentUniforms else &main.chunk.meshing.uniforms; diff --git a/src/gui/windows/gpu_performance_measuring.zig b/src/gui/windows/gpu_performance_measuring.zig index 707faec6..effbd9d0 100644 --- a/src/gui/windows/gpu_performance_measuring.zig +++ b/src/gui/windows/gpu_performance_measuring.zig @@ -15,6 +15,7 @@ const GuiComponent = gui.GuiComponent; pub const Samples = enum(u8) { screenbuffer_clear, clear, + animation, chunk_rendering, entity_rendering, transparent_rendering, @@ -29,6 +30,7 @@ pub const Samples = enum(u8) { const names = [_][]const u8 { "Screenbuffer clear", "Clear", + "Pre-processing Block Animations", "Chunk Rendering", "Entity Rendering", "Transparent Rendering", diff --git a/src/main.zig b/src/main.zig index 4366426d..dc71ea3f 100644 --- a/src/main.zig +++ b/src/main.zig @@ -686,7 +686,7 @@ pub fn main() !void { try assets.init(); defer assets.deinit(); - blocks.meshes.init(); + try blocks.meshes.init(); defer blocks.meshes.deinit(); try chunk.meshing.init(); diff --git a/src/renderer.zig b/src/renderer.zig index 2b42fb5b..affef396 100644 --- a/src/renderer.zig +++ b/src/renderer.zig @@ -173,8 +173,13 @@ pub fn renderWorld(world: *World, ambientLight: Vec3f, skyColor: Vec3f, playerPo const time: u32 = @intCast(std.time.milliTimestamp() & std.math.maxInt(u32)); + gpu_performance_measuring.startQuery(.animation); + blocks.meshes.preProcessAnimationData(time); + gpu_performance_measuring.stopQuery(); + + // Update the uniforms. The uniforms are needed to render the replacement meshes. - chunk.meshing.bindShaderAndUniforms(game.projectionMatrix, ambientLight, time); + chunk.meshing.bindShaderAndUniforms(game.projectionMatrix, ambientLight); reflectionCubeMap.bindTo(2); c.glActiveTexture(c.GL_TEXTURE0); @@ -202,7 +207,7 @@ pub fn renderWorld(world: *World, ambientLight: Vec3f, skyColor: Vec3f, playerPo MeshSelection.select(playerPos, game.camera.direction); MeshSelection.render(game.projectionMatrix, game.camera.viewMatrix, playerPos); - chunk.meshing.bindShaderAndUniforms(game.projectionMatrix, ambientLight, time); + chunk.meshing.bindShaderAndUniforms(game.projectionMatrix, ambientLight); for(meshes) |mesh| { mesh.render(playerPos); @@ -225,7 +230,7 @@ pub fn renderWorld(world: *World, ambientLight: Vec3f, skyColor: Vec3f, playerPo gpu_performance_measuring.startQuery(.transparent_rendering); c.glTextureBarrier(); - chunk.meshing.bindTransparentShaderAndUniforms(game.projectionMatrix, ambientLight, time); + chunk.meshing.bindTransparentShaderAndUniforms(game.projectionMatrix, ambientLight); c.glBlendEquation(c.GL_FUNC_ADD); c.glBlendFunc(c.GL_ONE, c.GL_SRC1_COLOR);