From c00f3f64a66d0e3e3f7f1dd0a8e9a34a8d18ae2c Mon Sep 17 00:00:00 2001 From: Shu Date: Sun, 27 Sep 2020 22:25:35 +0200 Subject: [PATCH] Vulkan basic buffer allocator --- include/tracy/TracyVulkan.hpp | 3 +- resource/content/shaders/Color.fs.spv | 3 + resource/content/shaders/Color.vs.spv | 3 + resource/content/shaders/Sky.fs.spv | 3 + resource/content/shaders/Sky.vs.spv | 3 + resource/content/shaders/Tris.vs.spv | 4 +- resource/content/shaders/Voxel.fs.geo.ins.spv | 3 + resource/content/shaders/Voxel.fs.geo.spv | 3 + resource/content/shaders/Voxel.fs.ins.spv | 3 + resource/content/shaders/Voxel.fs.spv | 3 + resource/content/shaders/Voxel.gs.geo.ins.spv | 3 + resource/content/shaders/Voxel.gs.geo.spv | 3 + resource/content/shaders/Voxel.vs.geo.ins.spv | 3 + resource/content/shaders/Voxel.vs.geo.spv | 3 + resource/content/shaders/Voxel.vs.ins.spv | 3 + resource/content/shaders/Voxel.vs.spv | 3 + resource/shaders-src/Color.frag | 10 + resource/shaders-src/Color.vert | 16 + resource/shaders-src/Sky.frag | 12 + resource/shaders-src/Sky.vert | 15 + resource/shaders-src/{Tris.fs => Tris.frag} | 0 resource/shaders-src/Tris.vert | 12 + resource/shaders-src/Tris.vs | 21 -- resource/shaders-src/{Voxel.fs => Voxel.frag} | 72 +++-- resource/shaders-src/{Voxel.gs => Voxel.geom} | 5 +- resource/shaders-src/{Voxel.vs => Voxel.vert} | 72 +++-- resource/shaders-src/compile.sh | 36 ++- src/client/Client.cpp | 2 +- src/client/contouring/FlatDualMC.cpp | 12 +- src/client/contouring/FlatDualMC.hpp | 4 +- src/client/render/UI.cpp | 8 +- src/client/render/vk/Allocator.cpp | 282 ++++++++++++++++++ src/client/render/vk/Allocator.hpp | 92 ++++++ .../vk/{CommandPool.cpp => CommandCenter.cpp} | 66 ++-- src/client/render/vk/CommandCenter.hpp | 31 ++ src/client/render/vk/CommandPool.hpp | 29 -- src/client/render/vk/PhysicalDeviceInfo.cpp | 68 +++++ .../vk/{shared.hpp => PhysicalDeviceInfo.hpp} | 14 +- src/client/render/vk/Pipeline.cpp | 16 +- src/client/render/vk/Renderer.cpp | 100 ++----- src/client/render/vk/Renderer.hpp | 8 +- src/client/render/vk/SwapChain.cpp | 15 +- src/client/render/vk/SwapChain.hpp | 5 +- src/client/render/vk/buffer/Buffer.hpp | 27 ++ src/client/render/vk/buffer/VertexData.hpp | 45 +++ src/client/world/DistantUniverse.cpp | 19 +- src/client/world/DistantUniverse.hpp | 5 +- src/core/net/Client.hpp | 5 +- src/core/net/Server.hpp | 7 +- src/core/net/data.hpp | 5 +- src/core/world/Universe.hpp | 4 +- src/server/Server.cpp | 19 +- src/server/world/Universe.cpp | 9 +- src/server/world/Universe.hpp | 4 +- 54 files changed, 926 insertions(+), 295 deletions(-) create mode 100644 resource/content/shaders/Color.fs.spv create mode 100644 resource/content/shaders/Color.vs.spv create mode 100644 resource/content/shaders/Sky.fs.spv create mode 100644 resource/content/shaders/Sky.vs.spv create mode 100644 resource/content/shaders/Voxel.fs.geo.ins.spv create mode 100644 resource/content/shaders/Voxel.fs.geo.spv create mode 100644 resource/content/shaders/Voxel.fs.ins.spv create mode 100644 resource/content/shaders/Voxel.fs.spv create mode 100644 resource/content/shaders/Voxel.gs.geo.ins.spv create mode 100644 resource/content/shaders/Voxel.gs.geo.spv create mode 100644 resource/content/shaders/Voxel.vs.geo.ins.spv create mode 100644 resource/content/shaders/Voxel.vs.geo.spv create mode 100644 resource/content/shaders/Voxel.vs.ins.spv create mode 100644 resource/content/shaders/Voxel.vs.spv create mode 100644 resource/shaders-src/Color.frag create mode 100644 resource/shaders-src/Color.vert create mode 100644 resource/shaders-src/Sky.frag create mode 100644 resource/shaders-src/Sky.vert rename resource/shaders-src/{Tris.fs => Tris.frag} (100%) create mode 100644 resource/shaders-src/Tris.vert delete mode 100644 resource/shaders-src/Tris.vs rename resource/shaders-src/{Voxel.fs => Voxel.frag} (75%) rename resource/shaders-src/{Voxel.gs => Voxel.geom} (89%) rename resource/shaders-src/{Voxel.vs => Voxel.vert} (50%) create mode 100644 src/client/render/vk/Allocator.cpp create mode 100644 src/client/render/vk/Allocator.hpp rename src/client/render/vk/{CommandPool.cpp => CommandCenter.cpp} (60%) create mode 100644 src/client/render/vk/CommandCenter.hpp delete mode 100644 src/client/render/vk/CommandPool.hpp create mode 100644 src/client/render/vk/PhysicalDeviceInfo.cpp rename src/client/render/vk/{shared.hpp => PhysicalDeviceInfo.hpp} (67%) create mode 100644 src/client/render/vk/buffer/Buffer.hpp create mode 100644 src/client/render/vk/buffer/VertexData.hpp diff --git a/include/tracy/TracyVulkan.hpp b/include/tracy/TracyVulkan.hpp index 7f6b918..0cf9d63 100644 --- a/include/tracy/TracyVulkan.hpp +++ b/include/tracy/TracyVulkan.hpp @@ -19,9 +19,10 @@ namespace tracy { class VkCtxScope {}; +class VkCtx; } -using TracyVkCtx = void*; +using TracyVkCtx = tracy::VkCtx*; #else diff --git a/resource/content/shaders/Color.fs.spv b/resource/content/shaders/Color.fs.spv new file mode 100644 index 0000000..b148912 --- /dev/null +++ b/resource/content/shaders/Color.fs.spv @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:5311d6e728a8130264f2142f937cc4f893757bc5820bc3258c7b17b0b79f2e2f +size 632 diff --git a/resource/content/shaders/Color.vs.spv b/resource/content/shaders/Color.vs.spv new file mode 100644 index 0000000..1bcadce --- /dev/null +++ b/resource/content/shaders/Color.vs.spv @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:de2683c8c34c4c6d1f340ae75cf561e0b36b8c87b66c08374df336d35d1ced76 +size 1316 diff --git a/resource/content/shaders/Sky.fs.spv b/resource/content/shaders/Sky.fs.spv new file mode 100644 index 0000000..72d7b55 --- /dev/null +++ b/resource/content/shaders/Sky.fs.spv @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:fd7c280636d4b76039fa80bcb2a5dc96a50b0f5281bb52a8d4b4e501fb6f2eb6 +size 656 diff --git a/resource/content/shaders/Sky.vs.spv b/resource/content/shaders/Sky.vs.spv new file mode 100644 index 0000000..3230de5 --- /dev/null +++ b/resource/content/shaders/Sky.vs.spv @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:c144bd2cfa1f0a64beb88bdbaa804009cf538454df27a64e3afb4a0bc95db0c6 +size 1452 diff --git a/resource/content/shaders/Tris.vs.spv b/resource/content/shaders/Tris.vs.spv index 2e150a5..7581a72 100644 --- a/resource/content/shaders/Tris.vs.spv +++ b/resource/content/shaders/Tris.vs.spv @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:d2d81db6472dd4bb993a716c95c2e9714453ff67f2c3d2deab74f80b73285713 -size 1540 +oid sha256:b55f16f755a1ea2809ba5d3cb5401c07a2680cde6f412709a85f63e4b063c955 +size 1116 diff --git a/resource/content/shaders/Voxel.fs.geo.ins.spv b/resource/content/shaders/Voxel.fs.geo.ins.spv new file mode 100644 index 0000000..66e4764 --- /dev/null +++ b/resource/content/shaders/Voxel.fs.geo.ins.spv @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:790843dd8159e2f3fbf32c19ed467b8f9c73daa087ba2544509e570a51775129 +size 20704 diff --git a/resource/content/shaders/Voxel.fs.geo.spv b/resource/content/shaders/Voxel.fs.geo.spv new file mode 100644 index 0000000..d697bad --- /dev/null +++ b/resource/content/shaders/Voxel.fs.geo.spv @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:7a778d3b8d14791bfe7a5afe587894012c8079298402ae107f2fd45e157260ea +size 20784 diff --git a/resource/content/shaders/Voxel.fs.ins.spv b/resource/content/shaders/Voxel.fs.ins.spv new file mode 100644 index 0000000..a7895a0 --- /dev/null +++ b/resource/content/shaders/Voxel.fs.ins.spv @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:d81ea2408908d3e86a5642b1deb24ed2aad26e8d04beac54d0a027fe20a71daa +size 17592 diff --git a/resource/content/shaders/Voxel.fs.spv b/resource/content/shaders/Voxel.fs.spv new file mode 100644 index 0000000..1725abe --- /dev/null +++ b/resource/content/shaders/Voxel.fs.spv @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:2ec30779731aa36d3583d05d4eaa543b98a4c63d1cf07a58b7e121cf3d3675fc +size 17672 diff --git a/resource/content/shaders/Voxel.gs.geo.ins.spv b/resource/content/shaders/Voxel.gs.geo.ins.spv new file mode 100644 index 0000000..b177fcb --- /dev/null +++ b/resource/content/shaders/Voxel.gs.geo.ins.spv @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:ff0fe922ae4878d89d51e9356617691561d3820a0c678530945add2da6c3d473 +size 3772 diff --git a/resource/content/shaders/Voxel.gs.geo.spv b/resource/content/shaders/Voxel.gs.geo.spv new file mode 100644 index 0000000..b177fcb --- /dev/null +++ b/resource/content/shaders/Voxel.gs.geo.spv @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:ff0fe922ae4878d89d51e9356617691561d3820a0c678530945add2da6c3d473 +size 3772 diff --git a/resource/content/shaders/Voxel.vs.geo.ins.spv b/resource/content/shaders/Voxel.vs.geo.ins.spv new file mode 100644 index 0000000..750637d --- /dev/null +++ b/resource/content/shaders/Voxel.vs.geo.ins.spv @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:c84dbcc50fcfb569e6c5f5cef508b350e0e64bacd1e6076c15a4e8635cfe6a5a +size 5576 diff --git a/resource/content/shaders/Voxel.vs.geo.spv b/resource/content/shaders/Voxel.vs.geo.spv new file mode 100644 index 0000000..f8cb822 --- /dev/null +++ b/resource/content/shaders/Voxel.vs.geo.spv @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:78cd40dc708c52bfa43f216b21f7e7fddcfe174c3403ca123a1af0cdad058d21 +size 5700 diff --git a/resource/content/shaders/Voxel.vs.ins.spv b/resource/content/shaders/Voxel.vs.ins.spv new file mode 100644 index 0000000..750637d --- /dev/null +++ b/resource/content/shaders/Voxel.vs.ins.spv @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:c84dbcc50fcfb569e6c5f5cef508b350e0e64bacd1e6076c15a4e8635cfe6a5a +size 5576 diff --git a/resource/content/shaders/Voxel.vs.spv b/resource/content/shaders/Voxel.vs.spv new file mode 100644 index 0000000..f8cb822 --- /dev/null +++ b/resource/content/shaders/Voxel.vs.spv @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:78cd40dc708c52bfa43f216b21f7e7fddcfe174c3403ca123a1af0cdad058d21 +size 5700 diff --git a/resource/shaders-src/Color.frag b/resource/shaders-src/Color.frag new file mode 100644 index 0000000..d53aeda --- /dev/null +++ b/resource/shaders-src/Color.frag @@ -0,0 +1,10 @@ +#version 450 core +#extension GL_ARB_separate_shader_objects : enable + +layout(location = 0) in vec4 Color; + +layout(location = 0) out vec4 color; + +void main(){ + color = vec4(Color.xyz, .5); +} \ No newline at end of file diff --git a/resource/shaders-src/Color.vert b/resource/shaders-src/Color.vert new file mode 100644 index 0000000..4f17928 --- /dev/null +++ b/resource/shaders-src/Color.vert @@ -0,0 +1,16 @@ +#version 450 core + +layout(push_constant) uniform PushConstants { + mat4 MVP; +} Push; + +layout(location = 0) in vec3 Position_modelspace; +layout(location = 1) in vec4 Color_model; + +layout(location = 0) out vec4 Color; + +void main(){ + gl_Position = Push.MVP * vec4(Position_modelspace, 1); + Color = Color_model; +} + diff --git a/resource/shaders-src/Sky.frag b/resource/shaders-src/Sky.frag new file mode 100644 index 0000000..9356144 --- /dev/null +++ b/resource/shaders-src/Sky.frag @@ -0,0 +1,12 @@ +#version 450 core +#extension GL_ARB_separate_shader_objects : enable + +layout(binding = 1) uniform samplerCube Texture; + +layout(location = 0) in vec3 UV; + +layout(location = 0) out vec4 color; + +void main(){ + color = texture(Texture, UV); +} \ No newline at end of file diff --git a/resource/shaders-src/Sky.vert b/resource/shaders-src/Sky.vert new file mode 100644 index 0000000..9b05b98 --- /dev/null +++ b/resource/shaders-src/Sky.vert @@ -0,0 +1,15 @@ +#version 450 core + +layout(push_constant) uniform PushConstants { + mat4 View; + mat4 Projection; +} Push; + +layout (location = 0) in vec3 Position_modelspace; + +layout (location = 0) out vec3 UV; + +void main(){ + UV = Position_modelspace; + gl_Position = (Push.Projection * Push.View * vec4(Position_modelspace, 1.0)).xyww; +} \ No newline at end of file diff --git a/resource/shaders-src/Tris.fs b/resource/shaders-src/Tris.frag similarity index 100% rename from resource/shaders-src/Tris.fs rename to resource/shaders-src/Tris.frag diff --git a/resource/shaders-src/Tris.vert b/resource/shaders-src/Tris.vert new file mode 100644 index 0000000..92a086e --- /dev/null +++ b/resource/shaders-src/Tris.vert @@ -0,0 +1,12 @@ +#version 450 +#extension GL_ARB_separate_shader_objects : enable + +layout(location = 0) in vec2 inPosition; +layout(location = 1) in vec3 inColor; + +layout(location = 0) out vec3 fragColor; + +void main() { + gl_Position = vec4(inPosition, 0.0, 1.0); + fragColor = inColor; +} \ No newline at end of file diff --git a/resource/shaders-src/Tris.vs b/resource/shaders-src/Tris.vs deleted file mode 100644 index 0439d32..0000000 --- a/resource/shaders-src/Tris.vs +++ /dev/null @@ -1,21 +0,0 @@ -#version 450 -#extension GL_ARB_separate_shader_objects : enable - -layout(location = 0) out vec3 fragColor; - -vec2 positions[3] = vec2[]( - vec2(0.0, -0.5), - vec2(0.5, 0.5), - vec2(-0.5, 0.5) -); - -vec3 colors[3] = vec3[]( - vec3(1.0, 0.0, 0.0), - vec3(0.0, 1.0, 0.0), - vec3(0.0, 0.0, 1.0) -); - -void main() { - gl_Position = vec4(positions[gl_VertexIndex], 0.0, 1.0); - fragColor = colors[gl_VertexIndex]; -} \ No newline at end of file diff --git a/resource/shaders-src/Voxel.fs b/resource/shaders-src/Voxel.frag similarity index 75% rename from resource/shaders-src/Voxel.fs rename to resource/shaders-src/Voxel.frag index 34a2581..7d97fb7 100644 --- a/resource/shaders-src/Voxel.fs +++ b/resource/shaders-src/Voxel.frag @@ -1,27 +1,39 @@ #version 450 core +#extension GL_ARB_separate_shader_objects : enable layout (constant_id = 0) const bool FOG = true; layout (constant_id = 1) const bool PBR = true; layout (constant_id = 2) const bool TRIPLANAR = false; layout (constant_id = 3) const bool STOCHASTIC = false; layout (constant_id = 4) const bool BLEND = true; +// ... +layout (constant_id = 16) const int UNIT_SIZE = 8; -layout (constant_id = 16) UNIT_SIZE = 8; +layout (binding = 1) uniform sampler2DArray TextureAtlas; +layout (binding = 2) uniform sampler2DArray NormalAtlas; +layout (binding = 3) uniform sampler2DArray HOSAtlas; -// Ouput data -layout(location = 0) out vec3 color; +layout(push_constant) uniform PushConstants { + mat4 Proj; + mat4 View; +#ifndef INSTANCED + mat4 Model; +#endif -uniform sampler2DArray TextureAtlas; -uniform sampler2DArray NormalAtlas; -uniform sampler2DArray HOSAtlas; + vec4 SphereProj; + float Curvature; -uniform mat4 View; -uniform vec3 FogColor; + //MAYBE: extract + vec3 FogColor; + float FogDepth; + + vec3 LightInvDirection_worldspace; +} Push; #ifdef GEOMETRY -in GeometryData +layout (location = 0) in GeometryData #else -in VertexData +layout (location = 0) in VertexData #endif { vec3 Position_modelspace; @@ -40,6 +52,8 @@ in VertexData float Depth; } vs; +layout(location = 0) out vec3 color; + vec3 expand(vec3 v) { return (v - 0.5) * 2; } @@ -49,7 +63,7 @@ vec2 hash2D(vec2 s) { return fract(sin(mod(vec2(dot(s, vec2(127.1, 311.7)), dot(s, vec2(269.5, 183.3))), 3.14159)) * 43758.5453); } -vec4 textureStochastic(sampler2DArray sample, vec3 UV) { +vec4 textureStochastic(sampler2DArray smpl, vec3 UV) { if(STOCHASTIC) { // triangular by approx 2*sqrt(3) vec2 skewUV = mat2(1.0, 0.0, -0.57735027, 1.15470054) * (UV.xy * 3.46400); @@ -79,46 +93,48 @@ if(STOCHASTIC) { vec2 dx = dFdx(UV.xy); vec2 dy = dFdy(UV.xy); - return textureGrad(sample, vec3(UV.xy + hash2D(BW_vx0.xy), UV.z), dx, dy) * BW_vx3.x + - textureGrad(sample, vec3(UV.xy + hash2D(BW_vx1.xy), UV.z), dx, dy) * BW_vx3.y + - textureGrad(sample, vec3(UV.xy + hash2D(BW_vx2.xy), UV.z), dx, dy) * BW_vx3.z; + return textureGrad(smpl, vec3(UV.xy + hash2D(BW_vx0.xy), UV.z), dx, dy) * BW_vx3.x + + textureGrad(smpl, vec3(UV.xy + hash2D(BW_vx1.xy), UV.z), dx, dy) * BW_vx3.y + + textureGrad(smpl, vec3(UV.xy + hash2D(BW_vx2.xy), UV.z), dx, dy) * BW_vx3.z; } else { - return texture(sample, UV); + return texture(smpl, UV); } } -vec4 getTexture(sampler2DArray sample, vec2 UV) { +vec4 getTexture(sampler2DArray smpl, vec2 UV) { #ifdef GEOMETRY if(BLEND) { - vec4 colx = textureStochastic(sample, vec3(UV, vs.Textures[0])); + vec4 colx = textureStochastic(smpl, vec3(UV, vs.Textures[0])); if(vs.Textures[1] == vs.Textures[0]) { return vs.Textures[2] == vs.Textures[0] ? colx : - mix(colx, textureStochastic(sample, vec3(UV, vs.Textures[2])), vs.TextureRatio.z); + mix(colx, textureStochastic(smpl, vec3(UV, vs.Textures[2])), vs.TextureRatio.z); } else { - vec4 coly = textureStochastic(sample, vec3(UV, vs.Textures[1])); + vec4 coly = textureStochastic(smpl, vec3(UV, vs.Textures[1])); return vs.Textures[2] == vs.Textures[0] ? mix(colx, coly, vs.TextureRatio.y) : ( vs.Textures[2] == vs.Textures[1] ? mix(coly, colx, vs.TextureRatio.x) : - colx * vs.TextureRatio.x + coly * vs.TextureRatio.y + textureStochastic(sample, vec3(UV, vs.Textures[2])) * vs.TextureRatio.z); + colx * vs.TextureRatio.x + coly * vs.TextureRatio.y + textureStochastic(smpl, vec3(UV, vs.Textures[2])) * vs.TextureRatio.z); } } else { int mainTexture = vs.TextureRatio.x >= vs.TextureRatio.y ? (vs.TextureRatio.x >= vs.TextureRatio.z ? 0 : 2) : (vs.TextureRatio.y >= vs.TextureRatio.z ? 1 : 2); - return textureStochastic(sample, vec3(UV, vs.Textures[mainTexture])); + return textureStochastic(smpl, vec3(UV, vs.Textures[mainTexture])); } #else - return textureStochastic(sample, vec3(UV, vs.Texture)); + return textureStochastic(smpl, vec3(UV, vs.Texture)); #endif } -vec3 getTriTexture(sampler2DArray sample, vec2 crdx, vec2 crdy, vec2 crdz, vec3 weights) { - return getTexture(sample, crdx).rgb * weights.x + - getTexture(sample, crdy).rgb * weights.y + - getTexture(sample, crdz).rgb * weights.z; +vec3 getTriTexture(sampler2DArray smpl, vec2 crdx, vec2 crdy, vec2 crdz, vec3 weights) { + return getTexture(smpl, crdx).rgb * weights.x + + getTexture(smpl, crdy).rgb * weights.y + + getTexture(smpl, crdz).rgb * weights.z; } void main() { float texScale = 1. / UNIT_SIZE; + vec3 tex, texN, worldNormal, texHOS; + if(TRIPLANAR) { // Triplanar float plateauSize = 0.001; @@ -173,7 +189,7 @@ if(PBR) { vec3 TextureAmbientColor = vec3(.1) * TextureDiffuseColor * texHOS.y; vec3 TextureSpecularColor = vec3(.8) * texHOS.z; - vec3 Normal_cameraspace = normalize((View * vec4(worldNormal,0)).xyz); + vec3 Normal_cameraspace = normalize((Push.View * vec4(worldNormal,0)).xyz); // Light emission properties // You probably want to put them as uniforms @@ -218,7 +234,7 @@ if(PBR) { } if(FOG) { float ratio = exp(vs.Depth * 0.69)-1; - color = mix(color, pow(FogColor, vec3(2.2)), clamp(ratio, 0, 1)); + color = mix(color, pow(Push.FogColor, vec3(2.2)), clamp(ratio, 0, 1)); } color = pow(color, vec3(1.0 / 2.2)); if(color.r > 1 || color.g > 1 || color.b > 1) { diff --git a/resource/shaders-src/Voxel.gs b/resource/shaders-src/Voxel.geom similarity index 89% rename from resource/shaders-src/Voxel.gs rename to resource/shaders-src/Voxel.geom index de33fc0..7d7369a 100644 --- a/resource/shaders-src/Voxel.gs +++ b/resource/shaders-src/Voxel.geom @@ -1,4 +1,5 @@ #version 450 core +#extension GL_ARB_separate_shader_objects : enable layout (constant_id = 0) const bool FOG = true; layout (constant_id = 1) const bool PBR = true; @@ -6,7 +7,7 @@ layout (constant_id = 1) const bool PBR = true; layout (triangles) in; layout (triangle_strip, max_vertices = 3) out; -in VertexData { +layout (location = 0) in VertexData { vec3 Position_modelspace; flat uint Texture; vec3 FaceNormal_modelspace; @@ -18,7 +19,7 @@ in VertexData { float Depth; } vs_in[]; -out GeometryData { +layout (location = 0) out GeometryData { vec3 Position_modelspace; flat uint Textures[3]; vec3 TextureRatio; diff --git a/resource/shaders-src/Voxel.vs b/resource/shaders-src/Voxel.vert similarity index 50% rename from resource/shaders-src/Voxel.vs rename to resource/shaders-src/Voxel.vert index 2d4294d..dd4627c 100644 --- a/resource/shaders-src/Voxel.vs +++ b/resource/shaders-src/Voxel.vert @@ -1,4 +1,5 @@ #version 450 core +#extension GL_ARB_separate_shader_objects : enable layout (constant_id = 0) const bool FOG = true; layout (constant_id = 1) const bool PBR = true; @@ -6,11 +7,32 @@ layout (constant_id = 1) const bool PBR = true; layout (constant_id = 5) const bool DO_CURVATURE = false; layout (constant_id = 6) const bool CURV_DEPTH = true; -layout(location = 0) in vec3 Position_modelspace; -layout(location = 1) in uint Texture_model; -layout(location = 2) in vec3 Normal_modelspace; +layout(push_constant) uniform PushConstants { + mat4 Proj; + mat4 View; +#ifndef INSTANCED + mat4 Model; +#endif -out VertexData { + vec4 SphereProj; + float Curvature; + + //MAYBE: extract + vec3 FogColor; + float FogDepth; + + vec3 LightInvDirection_worldspace; +} Push; + +layout (location = 0) in vec3 Position_modelspace; +layout (location = 1) in uint Texture_model; +layout (location = 2) in vec3 Normal_modelspace; + +#ifdef INSTANCED +layout (location = 6) in mat4 Model; +#endif + +layout (location = 0) out VertexData { vec3 Position_modelspace; flat uint Texture; vec3 FaceNormal_modelspace; @@ -22,47 +44,35 @@ out VertexData { float Depth; } vs; -#ifdef INSTANCED -layout(location = 6) in mat4 Model; -#else -uniform mat4 Model; -#endif -uniform mat4 View; -uniform mat4 Proj; - -uniform vec4 SphereProj; -uniform float Curvature; - -uniform vec3 LightInvDirection_worldspace; -uniform float FogDepth; - void main(){ +#ifndef INSTANCED + mat4 Model = Push.Model; +#endif + vs.Position_modelspace = Position_modelspace; if(DO_CURVATURE) { - if(Curvature > 0) { - vec3 Position_areaspace = Position_modelspace + SphereProj.xyz; + if(Push.Curvature > 0) { + vec3 Position_areaspace = Position_modelspace + Push.SphereProj.xyz; vec2 sph = vec2(acos(Position_areaspace.z / length(Position_areaspace.xyz)), atan(Position_areaspace.y, Position_areaspace.x)); -if(CURV_DEPTH) { - float radius = max(max(abs(Position_areaspace.x), abs(Position_areaspace.y)), abs(Position_areaspace.z)); -} else { - float radius = SphereProj.w; -} - vs.Position_modelspace = mix(vs.Position_modelspace, vec3(sin(sph.x)*cos(sph.y), sin(sph.x)*sin(sph.y), cos(sph.x)) * radius - SphereProj.xyz, Curvature); + float radius = CURV_DEPTH ? + max(max(abs(Position_areaspace.x), abs(Position_areaspace.y)), abs(Position_areaspace.z)) : + Push.SphereProj.w; + vs.Position_modelspace = mix(vs.Position_modelspace, vec3(sin(sph.x)*cos(sph.y), sin(sph.x)*sin(sph.y), cos(sph.x)) * radius - Push.SphereProj.xyz, Push.Curvature); } } - vec4 Position_cameraspace = View * Model * vec4(vs.Position_modelspace, 1); - gl_Position = Proj * Position_cameraspace; + vec4 Position_cameraspace = Push.View * Model * vec4(vs.Position_modelspace, 1); + gl_Position = Push.Proj * Position_cameraspace; if(FOG) { - vs.Depth = length(Position_cameraspace.xyz) / FogDepth; + vs.Depth = length(Position_cameraspace.xyz) / Push.FogDepth; } vs.Texture = Texture_model; vs.FaceNormal_modelspace = normalize(Normal_modelspace); -if(PBR) +if(PBR) { // TODO: correct normal curvature vs.FaceNormal_worldspace = normalize((Model * vec4(vs.FaceNormal_modelspace, 0)).xyz); @@ -71,6 +81,6 @@ if(PBR) vs.EyeDirection_cameraspace = vec3(0,0,0) - Position_cameraspace.xyz; // Vector that goes from the vertex to the light, in camera space - vs.LightDirection_cameraspace = (View * vec4(LightInvDirection_worldspace,0)).xyz; + vs.LightDirection_cameraspace = (Push.View * vec4(Push.LightInvDirection_worldspace,0)).xyz; } } diff --git a/resource/shaders-src/compile.sh b/resource/shaders-src/compile.sh index 1f3618c..8310056 100755 --- a/resource/shaders-src/compile.sh +++ b/resource/shaders-src/compile.sh @@ -2,28 +2,32 @@ BASEDIR=$(dirname "$0") TARGETDIR="$BASEDIR/../content/shaders" +GLSL="glslc" + +rm $TARGETDIR/*.spv # Tris -glslc -fshader-stage=vertex $BASEDIR/Tris.vs -o $TARGETDIR/Tris.vs.spv -glslc -fshader-stage=fragment $BASEDIR/Tris.fs -o $TARGETDIR/Tris.fs.spv +$GLSL $BASEDIR/Tris.vert -o $TARGETDIR/Tris.vs.spv +$GLSL $BASEDIR/Tris.frag -o $TARGETDIR/Tris.fs.spv +$GLSL $BASEDIR/Tris.vert $BASEDIR/Tris.frag -o $TARGETDIR/Tris.spv # Color -glslc -fshader-stage=vertex $TARGETDIR/Color.vs -o $TARGETDIR/Color.vs.spv -glslc -fshader-stage=fragment $TARGETDIR/Color.fs -o $TARGETDIR/Color.fs.spv +$GLSL $BASEDIR/Color.vert -o $TARGETDIR/Color.vs.spv +$GLSL $BASEDIR/Color.frag -o $TARGETDIR/Color.fs.spv # Sky -glslc -fshader-stage=vertex $TARGETDIR/Sky.vs -o $TARGETDIR/Sky.vs.spv -glslc -fshader-stage=fragment $TARGETDIR/Sky.fs -o $TARGETDIR/Sky.fs.spv +$GLSL $BASEDIR/Sky.vert -o $TARGETDIR/Sky.vs.spv +$GLSL $BASEDIR/Sky.frag -o $TARGETDIR/Sky.fs.spv # Voxel -glslc -fshader-stage=vertex $BASEDIR/Voxel.vs -o $TARGETDIR/Voxel.vs.spv -glslc -fshader-stage=fragment $BASEDIR/Voxel.fs -o $TARGETDIR/Voxel.fs.spv -glslc -fshader-stage=vertex $BASEDIR/Voxel.vs -DINSTANCED -o $TARGETDIR/Voxel.vs.ins.spv -glslc -fshader-stage=fragment $BASEDIR/Voxel.fs -DINSTANCED -o $TARGETDIR/Voxel.fs.ins.spv +$GLSL $BASEDIR/Voxel.vert -o $TARGETDIR/Voxel.vs.spv +$GLSL $BASEDIR/Voxel.frag -o $TARGETDIR/Voxel.fs.spv +$GLSL $BASEDIR/Voxel.vert -DINSTANCED -o $TARGETDIR/Voxel.vs.ins.spv +$GLSL $BASEDIR/Voxel.frag -DINSTANCED -o $TARGETDIR/Voxel.fs.ins.spv -glslc -fshader-stage=vertex $BASEDIR/Voxel.vs -DGEOMETRY -o $TARGETDIR/Voxel.vs.geo.spv -glslc -fshader-stage=geometry $BASEDIR/Voxel.gs -DGEOMETRY -o $TARGETDIR/Voxel.gs.geo.spv -glslc -fshader-stage=fragment $BASEDIR/Voxel.fs -DGEOMETRY -o $TARGETDIR/Voxel.fs.geo.spv -glslc -fshader-stage=vertex $BASEDIR/Voxel.vs -DGEOMETRY -DINSTANCED -o $TARGETDIR/Voxel.vs.geo.ins.spv -glslc -fshader-stage=geometry $BASEDIR/Voxel.gs -DGEOMETRY -DINSTANCED -o $TARGETDIR/Voxel.gs.geo.ins.spv -glslc -fshader-stage=fragment $BASEDIR/Voxel.fs -DGEOMETRY -DINSTANCED -o $TARGETDIR/Voxel.fs.geo.ins.spv \ No newline at end of file +$GLSL $BASEDIR/Voxel.vert -DGEOMETRY -o $TARGETDIR/Voxel.vs.geo.spv +$GLSL $BASEDIR/Voxel.geom -DGEOMETRY -o $TARGETDIR/Voxel.gs.geo.spv +$GLSL $BASEDIR/Voxel.frag -DGEOMETRY -o $TARGETDIR/Voxel.fs.geo.spv +$GLSL $BASEDIR/Voxel.vert -DGEOMETRY -DINSTANCED -o $TARGETDIR/Voxel.vs.geo.ins.spv +$GLSL $BASEDIR/Voxel.geom -DGEOMETRY -DINSTANCED -o $TARGETDIR/Voxel.gs.geo.ins.spv +$GLSL $BASEDIR/Voxel.frag -DGEOMETRY -DINSTANCED -o $TARGETDIR/Voxel.fs.geo.ins.spv \ No newline at end of file diff --git a/src/client/Client.cpp b/src/client/Client.cpp index ff5f653..7b20a31 100644 --- a/src/client/Client.cpp +++ b/src/client/Client.cpp @@ -35,6 +35,7 @@ void Client::run(server_handle* const localHandle) { //TODO: loop do { window.startFrame(); + FrameMark; { // Update ZoneScopedN("Update"); static double lastTime = window.getTime(); @@ -178,7 +179,6 @@ void Client::run(server_handle* const localHandle) { ZoneScopedN("Swap"); pipeline->swapBuffer(window); inputs.poll(); - FrameMarkNamed("Client"); } window.waitTargetFPS(); diff --git a/src/client/contouring/FlatDualMC.cpp b/src/client/contouring/FlatDualMC.cpp index d2af0d6..77e32ee 100644 --- a/src/client/contouring/FlatDualMC.cpp +++ b/src/client/contouring/FlatDualMC.cpp @@ -183,8 +183,16 @@ namespace contouring { } void FlatDualMC::onGui() { - ImGui::SliderInt("Load Distance", &loadDistance, 1, keepDistance); - ImGui::SliderInt("Keep Distance", &keepDistance, loadDistance + 1, 21); + { + int load = loadDistance; + ImGui::SliderInt("Load Distance", &load, 1, keepDistance); + loadDistance = load; + } + { + int keep = keepDistance; + ImGui::SliderInt("Keep Distance", &keep, loadDistance + 1, 21); + keepDistance = keep; + } ImGui::Checkbox("Transparency", &transparency); ImGui::SliderFloat("Iso", &iso, 0, 1); ImGui::Checkbox("Manifold", &manifold); diff --git a/src/client/contouring/FlatDualMC.hpp b/src/client/contouring/FlatDualMC.hpp index af4277a..b65433e 100644 --- a/src/client/contouring/FlatDualMC.hpp +++ b/src/client/contouring/FlatDualMC.hpp @@ -49,8 +49,8 @@ namespace contouring { void enqueue(const area_ &, const chunk_pos &offset, const world::ChunkContainer &); - int loadDistance = 3; - int keepDistance = 4; + ushort loadDistance = 3; + ushort keepDistance = 4; bool transparency = false; float iso = .1f; bool manifold = true; diff --git a/src/client/render/UI.cpp b/src/client/render/UI.cpp index 2bc0638..1d27322 100644 --- a/src/client/render/UI.cpp +++ b/src/client/render/UI.cpp @@ -114,8 +114,12 @@ UI::Actions UI::draw(config::client::options &options, state::state &state, cons if (options.debugMenu.world) { ImGui::Begin("Debug: World", &options.debugMenu.world, ImGuiWindowFlags_AlwaysAutoResize); - if (ImGui::SliderInt("Load distance", &options.world.loadDistance, 1, options.world.keepDistance) | - ImGui::SliderInt("Keep distance", &options.world.keepDistance, options.world.loadDistance + 1, 21)) { + int load = options.world.loadDistance; + int keep = options.world.keepDistance; + if (ImGui::SliderInt("Load distance", &load, 1, options.world.keepDistance) | + ImGui::SliderInt("Keep distance", &keep, options.world.loadDistance + 1, 21)) { + options.world.loadDistance = load; + options.world.keepDistance = keep; actions |= Actions::World; } if(ImGui::SliderInt("Voxel density", &options.voxel_density, 1, CHUNK_LENGTH * REGION_LENGTH)) { diff --git a/src/client/render/vk/Allocator.cpp b/src/client/render/vk/Allocator.cpp new file mode 100644 index 0000000..c95c981 --- /dev/null +++ b/src/client/render/vk/Allocator.cpp @@ -0,0 +1,282 @@ +#include "Allocator.hpp" + +#include "PhysicalDeviceInfo.hpp" +#include +#include "buffer/VertexData.hpp" +#include + +using namespace render::vk; + +const auto NO_DELETER = Allocator::MemoryDeleter(nullptr); +Allocator::memory_ptr get_null_ptr() { return Allocator::memory_ptr(nullptr, NO_DELETER); } + +Allocator::Allocator(VkDevice device, const PhysicalDeviceInfo &info) : device(device), indexedBufferMemory(get_null_ptr()) { + vkGetPhysicalDeviceMemoryProperties(info.device, &properties); + + { + if (!info.queueIndices.transferFamily.has_value()) { + LOG_W("No transfer queue family. Using graphics one"); + } + const auto family = info.queueIndices.transferFamily.value_or(info.queueIndices.graphicsFamily.value()); + + vkGetDeviceQueue(device, family, 0, &transferQueue); + VkCommandPoolCreateInfo poolInfo{}; + poolInfo.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO; + poolInfo.queueFamilyIndex = family; + poolInfo.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT; + + if (vkCreateCommandPool(device, &poolInfo, ALLOC, &transferPool) != VK_SUCCESS) { + FATAL("Failed to create transfer pool!"); + } + } + { + VkCommandBufferAllocateInfo allocInfo{}; + allocInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; + allocInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY; + allocInfo.commandPool = transferPool; + allocInfo.commandBufferCount = 1; + + vkAllocateCommandBuffers(device, &allocInfo, &transferBuffer); + tracyCtx = TracyVkContext(info.device, device, transferQueue, transferBuffer); + } + { + size_t vertexSize = sizeof(buffer::vk::vertices[0]) * buffer::vk::vertices.size(); + size_t indexSize = sizeof(buffer::vk::indices[0]) * buffer::vk::indices.size(); + size_t stagingSize = std::max(vertexSize, indexSize); + buffer_info stagingBuffer; + if(auto stagingMemory = createBuffer(stagingSize, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, stagingBuffer)) { + std::vector requirements = { + {indexSize, VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_INDEX_BUFFER_BIT}, + {vertexSize, VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT} + }; + if(std::vector out; indexedBufferMemory = createBuffers(requirements, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, out)) { + indexBuffer = out[0]; + vertexBuffer = out[1]; + } else { + FATAL("Cannot allocate buffer memory"); + } + + stagingMemory->write(buffer::vk::vertices.data(), vertexSize); + copyBuffer(stagingBuffer, vertexBuffer, vertexSize); + stagingMemory->write(buffer::vk::indices.data(), indexSize); + copyBuffer(stagingBuffer, indexBuffer, indexSize); + + vkDestroyBuffer(device, stagingBuffer.buffer, ALLOC); //TODO: move to buffer + } else { + FATAL("Cannot allocate staging memory"); + } + } +} +Allocator::~Allocator() { + vkDestroyBuffer(device, indexBuffer.buffer, ALLOC); + vkDestroyBuffer(device, vertexBuffer.buffer, ALLOC); + indexedBufferMemory.reset(); + + TracyVkDestroy(tracyCtx); + vkFreeCommandBuffers(device, transferPool, 1, &transferBuffer); + + vkDestroyCommandPool(device, transferPool, ALLOC); + //NOTE: all allocations are delete by ~vector +} + +void Allocator::setTracyZone(const char* name) { + TracyVkCollect(tracyCtx, transferBuffer); + TracyVkZone(tracyCtx, transferBuffer, name); + (void)name; +} + +Allocator::memory_ptr Allocator::createBuffer(VkDeviceSize size, VkMemoryPropertyFlags properties, VkBufferUsageFlags usage, buffer_info& out) { + VkBufferCreateInfo bufferInfo{}; + bufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; + bufferInfo.size = size; + bufferInfo.usage = usage; + bufferInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; + + if (vkCreateBuffer(device, &bufferInfo, ALLOC, &out.buffer) != VK_SUCCESS) { + LOG_E("Failed to create buffer"); + return get_null_ptr(); + } + + VkMemoryRequirements memRequirements; + vkGetBufferMemoryRequirements(device, out.buffer, &memRequirements); + + if (auto memory = allocate(memRequirements, properties)) { + if(vkBindBufferMemory(device, out.buffer, memory->ref, memory->offset) == VK_SUCCESS) + return memory; + } + LOG_E("Failed to allocate buffer memory"); + return get_null_ptr(); +} +Allocator::memory_ptr Allocator::createBuffers(const std::vector& requirements, VkMemoryPropertyFlags properties, std::vector& out) { + assert(!requirements.empty()); + out.resize(requirements.size()); + + // Create buffers + VkMemoryRequirements memRequirements = {0, 0, UINT32_MAX}; + std::vector> ranges; + ranges.resize(requirements.size()); + for (size_t i = 0; i < requirements.size(); i++) { + VkBufferCreateInfo bufferInfo{}; + bufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; + bufferInfo.size = requirements[i].size; + bufferInfo.usage = requirements[i].usage; + bufferInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; + + if (vkCreateBuffer(device, &bufferInfo, ALLOC, &out[i].buffer) != VK_SUCCESS) { + LOG_E("Failed to create buffer"); + return get_null_ptr(); + } + + VkMemoryRequirements individualMemRequirements; + vkGetBufferMemoryRequirements(device, out[i].buffer, &individualMemRequirements); + memRequirements.alignment = std::max(memRequirements.alignment, individualMemRequirements.alignment); + memRequirements.memoryTypeBits &= individualMemRequirements.memoryTypeBits; + ranges[i].first = individualMemRequirements.size; + } + + // Align blocks + auto aligned = [&](VkDeviceSize offset) { + if (offset % memRequirements.alignment == 0) + return offset; + return offset + memRequirements.alignment - (offset % memRequirements.alignment); + }; + ranges[0].second = 0; + for (size_t i = 1; i < requirements.size(); i++) { + ranges[i].second = aligned(ranges[i-1].second + ranges[i-1].first); + } + memRequirements.size = aligned(ranges.back().second + ranges.back().first); + + // Bind memory + if (auto memory = allocate(memRequirements, properties)) { + for (size_t i = 0; i < requirements.size(); i++) { + if (vkBindBufferMemory(device, out[i].buffer, memory->ref, memory->offset + ranges[i].second) != VK_SUCCESS) { + LOG_E("Failed to bind buffer"); + return get_null_ptr(); + } + } + return memory; + } + LOG_E("Failed to allocate buffers"); + return get_null_ptr(); +} + +Allocator::memory_ptr Allocator::allocate(VkMemoryRequirements requirements, VkMemoryPropertyFlags properties) { + //TODO: search for existing allocation + //TODO: allocate more ??? + + VkMemoryAllocateInfo allocInfo{}; + allocInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; + allocInfo.allocationSize = requirements.size; + if (const auto memIdx = findMemory(requirements.memoryTypeBits, properties, requirements.size)) { + //TODO: check budget + allocInfo.memoryTypeIndex = memIdx.value(); + } else { + LOG_E("No suitable memory heap"); + return get_null_ptr(); + } + + VkDeviceMemory memory; + if (vkAllocateMemory(device, &allocInfo, ALLOC, &memory) != VK_SUCCESS) { + LOG_E("Failed to allocate memory!"); + return get_null_ptr(); + } + + void *ptr = nullptr; + if (properties & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) { + vkMapMemory(device, memory, 0, VK_WHOLE_SIZE, 0, &ptr); + } + + auto allocation = allocations.emplace_back(new Allocation(device, memory, allocInfo.allocationSize, allocInfo.memoryTypeIndex, ptr)).get(); + allocation->areas.push_back({allocInfo.allocationSize, 0}); + + return memory_ptr(new memory_area{memory, requirements.size, 0, ptr}, allocation->deleter); +} + +void Allocator::copyBuffer(buffer_info src, buffer_info dst, VkDeviceSize size) { + //FIXME: assert no out of range + + VkCommandBufferBeginInfo beginInfo{}; + beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; + beginInfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT; + + vkBeginCommandBuffer(transferBuffer, &beginInfo); + + VkBufferCopy copyRegion{}; + copyRegion.srcOffset = 0; + copyRegion.dstOffset = 0; + copyRegion.size = size; + vkCmdCopyBuffer(transferBuffer, src.buffer, dst.buffer, 1, ©Region); + + vkEndCommandBuffer(transferBuffer); + + VkSubmitInfo submitInfo{}; + submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; + submitInfo.commandBufferCount = 1; + submitInfo.pCommandBuffers = &transferBuffer; + + vkQueueSubmit(transferQueue, 1, &submitInfo, VK_NULL_HANDLE); + vkQueueWaitIdle(transferQueue); //MAYBE: use fences + vkResetCommandBuffer(transferBuffer, 0); +} + +std::optional Allocator::findMemory(uint32_t typeFilter, VkMemoryPropertyFlags requirement, VkDeviceSize size) const { +#if DEBUG + LOG_D("available memory:"); + for (uint32_t i = 0; i < properties.memoryTypeCount; i++) { + LOG_D('\t' << i << ": " << ((properties.memoryTypes[i].propertyFlags & VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT) ? "local " : "") + << ((properties.memoryTypes[i].propertyFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) ? "visible " : "") + << ((properties.memoryTypes[i].propertyFlags & VK_MEMORY_PROPERTY_HOST_COHERENT_BIT) ? "coherent " : "") + << ((properties.memoryTypes[i].propertyFlags & VK_MEMORY_PROPERTY_HOST_CACHED_BIT) ? "cached " : "") + << ((properties.memoryTypes[i].propertyFlags & VK_MEMORY_PROPERTY_LAZILY_ALLOCATED_BIT) ? "lazy " : "") + << ((properties.memoryTypes[i].propertyFlags & VK_MEMORY_PROPERTY_PROTECTED_BIT) ? "protected " : "") + << properties.memoryHeaps[properties.memoryTypes[i].heapIndex].size); + } +#endif + for (uint32_t i = 0; i < properties.memoryTypeCount; i++) { + if ((typeFilter & (1 << i)) && (properties.memoryTypes[i].propertyFlags & requirement) == requirement) { + VkDeviceSize usage = size; + for(const auto& alloc: allocations) { + if(alloc->memoryType == i) + usage += alloc->size; + } + VkDeviceSize budget = properties.memoryHeaps[properties.memoryTypes[i].heapIndex].size; + //TODO: use memory budjet extension + if(budget >= usage) { + return i; + } + } + } + return {}; +} + +void Allocator::memory_area::write(const void* data, size_t data_size, size_t write_offset) { + assert(ptr != nullptr && size >= write_offset + data_size); + memcpy(ptr + write_offset, data, data_size); +} + +void Allocator::MemoryDeleter::operator()(memory_area* area) { + assert(area != nullptr && "Deleting null area"); + if(owner != nullptr) { + for (auto it = owner->areas.begin(); it != owner->areas.end(); ++it) { + if(it->offset == area->offset) { + assert(it->size == area->size); + owner->areas.erase(it); + delete area; + return; + } + } + } + LOG_E("Allocation area not found"); + delete area; +} +Allocator::Allocation::Allocation(VkDevice device, VkDeviceMemory memory, VkDeviceSize size, uint32_t memoryType, void *ptr): + device(device), memory(memory), size(size), memoryType(memoryType), ptr(ptr), deleter(this) { } +Allocator::Allocation::~Allocation() { + if(!areas.empty()) + LOG_E("Freeing " << areas.size() << " floating buffers"); + + if(ptr != nullptr) + vkUnmapMemory(device, memory); + + vkFreeMemory(device, memory, ALLOC); +} \ No newline at end of file diff --git a/src/client/render/vk/Allocator.hpp b/src/client/render/vk/Allocator.hpp new file mode 100644 index 0000000..2c746a4 --- /dev/null +++ b/src/client/render/vk/Allocator.hpp @@ -0,0 +1,92 @@ +#pragma once + +#include "forward.hpp" +#include +#include +#include + +namespace tracy { + class VkCtx; +} +typedef tracy::VkCtx* TracyVkCtx; +namespace render::vk { + +class Allocator { +private: + struct Allocation; +public: + Allocator(VkDevice, const PhysicalDeviceInfo&); + ~Allocator(); + + struct memory_area { + VkDeviceMemory ref; + VkDeviceSize size; + VkDeviceSize offset; + void *ptr = nullptr; + + void write(const void*, VkDeviceSize size, VkDeviceSize offset = 0); + void read(void*, VkDeviceSize size, VkDeviceSize offset = 0); + }; + + class MemoryDeleter { + public: + MemoryDeleter(Allocation *owner): owner(owner) { } + void operator()(memory_area *); + private: + Allocation *owner; + }; + + using memory_ptr = std::unique_ptr; + + memory_ptr allocate(VkMemoryRequirements, VkMemoryPropertyFlags); + bool deallocate(const memory_area&); + + struct buffer_info { + VkBuffer buffer = nullptr; + }; + memory_ptr createBuffer(VkDeviceSize, VkMemoryPropertyFlags, VkBufferUsageFlags, buffer_info&); + struct buffer_requirement { + VkDeviceSize size; + VkBufferUsageFlags usage; + }; + memory_ptr createBuffers(const std::vector &, VkMemoryPropertyFlags, std::vector &); + //TODO: create Buffer{MemoryArea + VkBuffer} + //TODO: create readonly buffer with data + + void copyBuffer(buffer_info srcBuffer, buffer_info dstBuffer, VkDeviceSize size); + + std::pair getBuffer() { return {vertexBuffer.buffer, indexBuffer.buffer}; } + void setTracyZone(const char* name); + +private: + std::optional findMemory(uint32_t, VkMemoryPropertyFlags, VkDeviceSize size = 0) const; + + struct Allocation { + Allocation(VkDevice, VkDeviceMemory, VkDeviceSize, uint32_t, void *ptr); + ~Allocation(); + + const VkDevice device; + const VkDeviceMemory memory; + const VkDeviceSize size; + const uint32_t memoryType; + const void *ptr = nullptr; + const MemoryDeleter deleter; + + struct area { VkDeviceSize size; VkDeviceSize offset; }; + std::vector areas; + }; + + VkDevice device; + VkPhysicalDeviceMemoryProperties properties; + + VkQueue transferQueue; + VkCommandPool transferPool; + VkCommandBuffer transferBuffer; // MAYBE: parallel upload + TracyVkCtx tracyCtx; + + buffer_info vertexBuffer; + buffer_info indexBuffer; + memory_ptr indexedBufferMemory; + std::vector> allocations; +}; +} \ No newline at end of file diff --git a/src/client/render/vk/CommandPool.cpp b/src/client/render/vk/CommandCenter.cpp similarity index 60% rename from src/client/render/vk/CommandPool.cpp rename to src/client/render/vk/CommandCenter.cpp index 3218b3f..974e44b 100644 --- a/src/client/render/vk/CommandPool.cpp +++ b/src/client/render/vk/CommandCenter.cpp @@ -1,31 +1,36 @@ -#include "CommandPool.hpp" +#include "CommandCenter.hpp" -#include "shared.hpp" +#include "PhysicalDeviceInfo.hpp" #include "../Renderer.hpp" +#include "buffer/VertexData.hpp" using namespace render::vk; -CommandPool::CommandPool(VkDevice device, const std::vector& views, PipelineRef pipe, const PhysicalDeviceInfo& info, const renderOptions& opt): - device(device) { +CommandCenter::CommandCenter(VkDevice device, const std::vector &views, PipelineRef pipe, + std::pair buffer, const PhysicalDeviceInfo &info, const renderOptions &opt) : device(device) { + { + vkGetDeviceQueue(device, info.queueIndices.graphicsFamily.value(), 0, &graphicsQueue); + VkCommandPoolCreateInfo poolInfo{}; + poolInfo.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO; + poolInfo.queueFamilyIndex = info.queueIndices.graphicsFamily.value(); + poolInfo.flags = 0; - VkCommandPoolCreateInfo poolInfo{}; - poolInfo.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO; - poolInfo.queueFamilyIndex = info.queueIndices.graphicsFamily.value(); - poolInfo.flags = 0; // Optional - - if (vkCreateCommandPool(device, &poolInfo, ALLOC, &graphicsPool) != VK_SUCCESS) { - FATAL("Failed to create command pool!"); + if (vkCreateCommandPool(device, &poolInfo, ALLOC, &graphicsPool) != VK_SUCCESS) { + FATAL("Failed to create graphics pool!"); + } } - allocate(views, pipe, info.swapDetails.capabilities.currentExtent, opt); + allocate(views, pipe, buffer, info.swapDetails.capabilities.currentExtent, opt); } -CommandPool::~CommandPool() { +CommandCenter::~CommandCenter() { if(!freed) free(); vkDestroyCommandPool(device, graphicsPool, ALLOC); } -void CommandPool::allocate(const std::vector& views, PipelineRef pipe, VkExtent2D extent, const renderOptions& opt) { +void CommandCenter::allocate(const std::vector& views, PipelineRef pipe, std::pair buffer, VkExtent2D extent, + const renderOptions& opt) +{ assert(freed); framebuffers.resize(views.size()); @@ -47,16 +52,17 @@ void CommandPool::allocate(const std::vector& views, PipelineRef pi } } - graphicsBuffers.resize(framebuffers.size()); + { + graphicsBuffers.resize(framebuffers.size()); + VkCommandBufferAllocateInfo allocInfo{}; + allocInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; + allocInfo.commandPool = graphicsPool; + allocInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY; + allocInfo.commandBufferCount = (uint32_t) graphicsBuffers.size(); - VkCommandBufferAllocateInfo allocInfo{}; - allocInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; - allocInfo.commandPool = graphicsPool; - allocInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY; - allocInfo.commandBufferCount = (uint32_t) graphicsBuffers.size(); - - if (vkAllocateCommandBuffers(device, &allocInfo, graphicsBuffers.data()) != VK_SUCCESS) { - FATAL("Failed to allocate command buffers!"); + if (vkAllocateCommandBuffers(device, &allocInfo, graphicsBuffers.data()) != VK_SUCCESS) { + FATAL("Failed to allocate graphics buffers!"); + } } for (size_t i = 0; i < graphicsBuffers.size(); i++) { @@ -82,17 +88,21 @@ void CommandPool::allocate(const std::vector& views, PipelineRef pi vkCmdBeginRenderPass(graphicsBuffers[i], &renderPassInfo, VK_SUBPASS_CONTENTS_INLINE); vkCmdBindPipeline(graphicsBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, pipe.second); - vkCmdDraw(graphicsBuffers[i], 3, 1, 0, 0); + VkBuffer vertexBuffers[] = {buffer.first}; + VkDeviceSize offsets[] = {0}; + vkCmdBindVertexBuffers(graphicsBuffers[i], 0, 1, vertexBuffers, offsets); + vkCmdBindIndexBuffer(graphicsBuffers[i], buffer.second, 0, VK_INDEX_TYPE_UINT16); + vkCmdDrawIndexed(graphicsBuffers[i], static_cast(buffer::vk::indices.size()), 1, 0, 0, 0); vkCmdEndRenderPass(graphicsBuffers[i]); if (vkEndCommandBuffer(graphicsBuffers[i]) != VK_SUCCESS) { - FATAL("Failed to record command buffer!"); + FATAL("Failed to record graphics buffer!"); } } freed = false; } -void CommandPool::free() { +void CommandCenter::free() { assert(!freed); for (size_t i = 0; i < framebuffers.size(); i++) { vkDestroyFramebuffer(device, framebuffers[i], nullptr); @@ -103,7 +113,7 @@ void CommandPool::free() { freed = true; } -void CommandPool::submitGraphics(uint32_t idx, VkQueue graphicsQueue, VkSemaphore waitSemaphore, VkSemaphore signalSemaphore, VkFence submittedFence) { +void CommandCenter::submitGraphics(uint32_t idx, VkSemaphore waitSemaphore, VkSemaphore signalSemaphore, VkFence submittedFence) { assert(!freed); VkSubmitInfo submitInfo{}; @@ -126,4 +136,4 @@ void CommandPool::submitGraphics(uint32_t idx, VkQueue graphicsQueue, VkSemaphor if (vkQueueSubmit(graphicsQueue, 1, &submitInfo, submittedFence) != VK_SUCCESS) { FATAL("Failed to submit draw command buffer!"); } -} \ No newline at end of file +} diff --git a/src/client/render/vk/CommandCenter.hpp b/src/client/render/vk/CommandCenter.hpp new file mode 100644 index 0000000..63975b0 --- /dev/null +++ b/src/client/render/vk/CommandCenter.hpp @@ -0,0 +1,31 @@ +#pragma once + +#include "forward.hpp" +#include + +namespace render::vk { +class SwapChain; +class Pipeline; + +class CommandCenter { +public: + CommandCenter(VkDevice, const std::vector&, PipelineRef, std::pair, const PhysicalDeviceInfo&, const renderOptions&); + ~CommandCenter(); + + void submitGraphics(uint32_t, VkSemaphore, VkSemaphore, VkFence); + + void allocate(const std::vector &, PipelineRef, std::pair, VkExtent2D, const renderOptions&); + void free(); + +private: + VkDevice device; + + std::vector framebuffers; + + VkQueue graphicsQueue; + VkCommandPool graphicsPool; + std::vector graphicsBuffers; + + bool freed = true; +}; +} \ No newline at end of file diff --git a/src/client/render/vk/CommandPool.hpp b/src/client/render/vk/CommandPool.hpp deleted file mode 100644 index 34a9d4c..0000000 --- a/src/client/render/vk/CommandPool.hpp +++ /dev/null @@ -1,29 +0,0 @@ -#pragma once - -#include "forward.hpp" -#include - -namespace render::vk { -class SwapChain; -class Pipeline; - -class CommandPool { -public: - CommandPool(VkDevice, const std::vector&, PipelineRef, const PhysicalDeviceInfo&, const renderOptions&); - ~CommandPool(); - - void submitGraphics(uint32_t, VkQueue, VkSemaphore, VkSemaphore, VkFence); - - void allocate(const std::vector&, PipelineRef, VkExtent2D, const renderOptions&); - void free(); - -private: - VkDevice device; - - std::vector framebuffers; - - VkCommandPool graphicsPool; - std::vector graphicsBuffers; - bool freed = true; -}; -} \ No newline at end of file diff --git a/src/client/render/vk/PhysicalDeviceInfo.cpp b/src/client/render/vk/PhysicalDeviceInfo.cpp new file mode 100644 index 0000000..d9676b5 --- /dev/null +++ b/src/client/render/vk/PhysicalDeviceInfo.cpp @@ -0,0 +1,68 @@ +#include "PhysicalDeviceInfo.hpp" + +using namespace render::vk; + +SwapChainSupportDetails SwapChainSupportDetails::Query(VkPhysicalDevice device, VkSurfaceKHR surface) { + SwapChainSupportDetails swapDetails; + vkGetPhysicalDeviceSurfaceCapabilitiesKHR(device, surface, &swapDetails.capabilities); + + uint32_t formatCount; + vkGetPhysicalDeviceSurfaceFormatsKHR(device, surface, &formatCount, nullptr); + if (formatCount != 0) { + swapDetails.formats.resize(formatCount); + vkGetPhysicalDeviceSurfaceFormatsKHR(device, surface, &formatCount, swapDetails.formats.data()); + } + + uint32_t presentModeCount; + vkGetPhysicalDeviceSurfacePresentModesKHR(device, surface, &presentModeCount, nullptr); + if (presentModeCount != 0) { + swapDetails.presentModes.resize(presentModeCount); + vkGetPhysicalDeviceSurfacePresentModesKHR(device, surface, &presentModeCount, swapDetails.presentModes.data()); + } + return swapDetails; +} + +QueueFamilyIndices QueueFamilyIndices::Query(VkPhysicalDevice device, VkSurfaceKHR surface) { + QueueFamilyIndices queueIndices; + uint32_t queueFamilyCount = 0; + vkGetPhysicalDeviceQueueFamilyProperties(device, &queueFamilyCount, nullptr); + std::vector queueFamilies(queueFamilyCount); + vkGetPhysicalDeviceQueueFamilyProperties(device, &queueFamilyCount, queueFamilies.data()); + + uint32_t i = 0; + for(const auto& queueFamily: queueFamilies) { + if (queueFamily.queueFlags & VK_QUEUE_GRAPHICS_BIT) { + queueIndices.graphicsFamily = i; + } else if (queueFamily.queueFlags & VK_QUEUE_TRANSFER_BIT) { + queueIndices.transferFamily = i; + } + VkBool32 presentSupport = false; + vkGetPhysicalDeviceSurfaceSupportKHR(device, i, surface, &presentSupport); + if (presentSupport) { + queueIndices.presentFamily = i; + } + +#if DEBUG + LOG_D("Queue " << i << ' ' << (queueFamily.queueFlags & VK_QUEUE_GRAPHICS_BIT ? "graphics " : "") + << (queueFamily.queueFlags & VK_QUEUE_COMPUTE_BIT ? "compute " : "") + << (presentSupport ? "present " : "") + << (queueFamily.queueFlags & VK_QUEUE_TRANSFER_BIT ? "transfer " : "") + << (queueFamily.queueFlags & VK_QUEUE_PROTECTED_BIT ? "protected " : "") + << 'x' << queueFamily.queueCount); +#endif + i++; + } + + return queueIndices; +} + +VkSurfaceFormatKHR PhysicalDeviceInfo::getFormat() const { + for(const auto& format: swapDetails.formats) { + if (format.format == VK_FORMAT_B8G8R8A8_SRGB && format.colorSpace == VK_COLOR_SPACE_SRGB_NONLINEAR_KHR) { + return format; + } + } + + LOG_W("Using suboptimal surface format"); + return swapDetails.formats[0]; +} \ No newline at end of file diff --git a/src/client/render/vk/shared.hpp b/src/client/render/vk/PhysicalDeviceInfo.hpp similarity index 67% rename from src/client/render/vk/shared.hpp rename to src/client/render/vk/PhysicalDeviceInfo.hpp index a546981..f144eb9 100644 --- a/src/client/render/vk/shared.hpp +++ b/src/client/render/vk/PhysicalDeviceInfo.hpp @@ -17,15 +17,23 @@ struct SwapChainSupportDetails { struct QueueFamilyIndices { std::optional graphicsFamily; std::optional presentFamily; + std::optional transferFamily; static QueueFamilyIndices Query(VkPhysicalDevice, VkSurfaceKHR); bool isComplete() const { return graphicsFamily.has_value() && presentFamily.has_value(); } + bool isOptimal() const { return isComplete() && transferFamily.has_value(); } }; struct PhysicalDeviceInfo { - VkPhysicalDevice device = VK_NULL_HANDLE; + PhysicalDeviceInfo() {} + PhysicalDeviceInfo(GLFWwindow *window, VkPhysicalDevice device, VkSurfaceKHR surface): + window(window), device(device), surface(surface), + swapDetails(SwapChainSupportDetails::Query(device, surface)), queueIndices(QueueFamilyIndices::Query(device, surface)) { } + + VkSurfaceFormatKHR getFormat() const; + GLFWwindow *window; + VkPhysicalDevice device = VK_NULL_HANDLE; + VkSurfaceKHR surface; SwapChainSupportDetails swapDetails; QueueFamilyIndices queueIndices; - VkSurfaceFormatKHR surfaceFormat; - VkSurfaceKHR surface; }; } \ No newline at end of file diff --git a/src/client/render/vk/Pipeline.cpp b/src/client/render/vk/Pipeline.cpp index 9b3ac41..12fb450 100644 --- a/src/client/render/vk/Pipeline.cpp +++ b/src/client/render/vk/Pipeline.cpp @@ -1,8 +1,9 @@ #include "Pipeline.hpp" -#include "shared.hpp" +#include "PhysicalDeviceInfo.hpp" #include "../../../core/data/file.hpp" #include "../Renderer.hpp" +#include "buffer/VertexData.hpp" #define CONTENT_DIR "content/" #define SHADER_DIR CONTENT_DIR "shaders/" @@ -15,7 +16,7 @@ using namespace render::vk; Pipeline::Pipeline(VkDevice device, const PhysicalDeviceInfo &info, const renderOptions &options): device(device) { { // Render pass VkAttachmentDescription colorAttachment{}; - colorAttachment.format = info.surfaceFormat.format; + colorAttachment.format = info.getFormat().format; colorAttachment.samples = VK_SAMPLE_COUNT_1_BIT; colorAttachment.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; colorAttachment.storeOp = VK_ATTACHMENT_STORE_OP_STORE; @@ -110,10 +111,13 @@ Pipeline::Pipeline(VkDevice device, const PhysicalDeviceInfo &info, const render VkPipelineVertexInputStateCreateInfo vertexInputInfo{}; vertexInputInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO; - vertexInputInfo.vertexBindingDescriptionCount = 0; - vertexInputInfo.pVertexBindingDescriptions = nullptr; // TODO: uniforms, and buffers - vertexInputInfo.vertexAttributeDescriptionCount = 0; - vertexInputInfo.pVertexAttributeDescriptions = nullptr; // TODO: uniforms, and buffers + + auto bindingDescription = buffer::vk::VertexData::getBindingDescription(); + vertexInputInfo.vertexBindingDescriptionCount = 1; + vertexInputInfo.pVertexBindingDescriptions = &bindingDescription; + auto attributeDescriptions = buffer::vk::VertexData::getAttributeDescriptions(); + vertexInputInfo.vertexAttributeDescriptionCount = attributeDescriptions.size(); + vertexInputInfo.pVertexAttributeDescriptions = attributeDescriptions.data(); VkPipelineInputAssemblyStateCreateInfo inputAssembly{}; inputAssembly.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO; diff --git a/src/client/render/vk/Renderer.cpp b/src/client/render/vk/Renderer.cpp index 7bd2350..03d33d4 100644 --- a/src/client/render/vk/Renderer.cpp +++ b/src/client/render/vk/Renderer.cpp @@ -2,10 +2,11 @@ #include "UI.hpp" #include "../../Window.hpp" -#include "shared.hpp" +#include "PhysicalDeviceInfo.hpp" +#include "Allocator.hpp" #include "SwapChain.hpp" #include "Pipeline.hpp" -#include "CommandPool.hpp" +#include "CommandCenter.hpp" #include #include #include @@ -21,24 +22,12 @@ void set_current_extent(VkSurfaceCapabilitiesKHR &capabilities, GLFWwindow *ptr) Renderer::Renderer(VkInstance instance, VkDevice device, const PhysicalDeviceInfo& info, const renderOptions& opt): options(opt), instance(instance), surface(info.surface), device(device), physicalInfo(std::make_unique(info)) { - vkGetDeviceQueue(device, info.queueIndices.graphicsFamily.value(), 0, &graphicsQueue); - vkGetDeviceQueue(device, info.queueIndices.presentFamily.value(), 0, &presentQueue); - set_current_extent(physicalInfo->swapDetails.capabilities, physicalInfo->window); - physicalInfo->surfaceFormat = [&]() { - for(const auto& format: info.swapDetails.formats) { - if (format.format == VK_FORMAT_B8G8R8A8_SRGB && format.colorSpace == VK_COLOR_SPACE_SRGB_NONLINEAR_KHR) { - return format; - } - } - - LOG_W("Using suboptimal surface format"); - return info.swapDetails.formats[0]; - }(); + allocator = std::make_unique(device, *physicalInfo.get()); swapChain = std::make_unique(device, *physicalInfo.get()); pipeline = std::make_unique(device, *physicalInfo.get(), options); - commandPool = std::make_unique(device, swapChain->getImageViews(), pipeline->getRef(), *physicalInfo.get(), options); + commandCenter = std::make_unique(device, swapChain->getImageViews(), pipeline->getRef(), allocator->getBuffer(), *physicalInfo.get(), options); { imageAvailableSemaphores.resize(opt.inFlightFrames); @@ -73,7 +62,8 @@ Renderer::~Renderer() { vkDestroySemaphore(device, imageAvailableSemaphores[i], ALLOC); } - commandPool.reset(); + commandCenter.reset(); + allocator.reset(); vkDestroyDevice(device, ALLOC); vkDestroySurfaceKHR(instance, surface, ALLOC); @@ -81,7 +71,6 @@ Renderer::~Renderer() { } void Renderer::recreateSwapChain() { - LOG_D("Recreating swapchain"); vkDeviceWaitIdle(device); destroySwapChain(); @@ -89,10 +78,10 @@ void Renderer::recreateSwapChain() { set_current_extent(physicalInfo->swapDetails.capabilities, physicalInfo->window); swapChain = std::make_unique(device, *physicalInfo.get()); pipeline = std::make_unique(device, *physicalInfo.get(), options); - commandPool->allocate(swapChain->getImageViews(), pipeline->getRef(), physicalInfo->swapDetails.capabilities.currentExtent, options); + commandCenter->allocate(swapChain->getImageViews(), pipeline->getRef(), allocator->getBuffer(), physicalInfo->swapDetails.capabilities.currentExtent, options); } void Renderer::destroySwapChain() { - commandPool->free(); + commandCenter->free(); pipeline.reset(); swapChain.reset(); } @@ -215,7 +204,7 @@ bool Renderer::Load(Window& window, const renderOptions& opt) { } const auto version = volkGetInstanceVersion(); - LOG_D("Vulkan " << VK_VERSION_MAJOR(version) << '.' << VK_VERSION_MINOR(version) << '.' << VK_VERSION_PATCH(version) << ", GLSL TODO:"); + LOG_D("Vulkan " << VK_VERSION_MAJOR(version) << '.' << VK_VERSION_MINOR(version) << '.' << VK_VERSION_PATCH(version) << ", GLSL precompiled"); VkSurfaceKHR surface; if (glfwCreateWindowSurface(instance, window.getPtr(), ALLOC, &surface) != VK_SUCCESS) { @@ -266,12 +255,11 @@ bool Renderer::Load(Window& window, const renderOptions& opt) { score += deviceProperties.limits.maxImageDimension2D; //TODO: check others limits - auto infos = PhysicalDeviceInfo{device, window.getPtr(), - SwapChainSupportDetails::Query(device, surface), QueueFamilyIndices::Query(device, surface), - VkSurfaceFormatKHR(), surface}; - + auto infos = PhysicalDeviceInfo(window.getPtr(), device, surface); if (!infos.queueIndices.isComplete()) continue; + if (infos.queueIndices.isOptimal()) + score += 5000; if (!infos.swapDetails.isValid()) continue; @@ -339,63 +327,12 @@ void Renderer::loadUI(Window& w) { UI::Load(w); } -SwapChainSupportDetails SwapChainSupportDetails::Query(VkPhysicalDevice device, VkSurfaceKHR surface) { - SwapChainSupportDetails swapDetails; - vkGetPhysicalDeviceSurfaceCapabilitiesKHR(device, surface, &swapDetails.capabilities); - - uint32_t formatCount; - vkGetPhysicalDeviceSurfaceFormatsKHR(device, surface, &formatCount, nullptr); - if (formatCount != 0) { - swapDetails.formats.resize(formatCount); - vkGetPhysicalDeviceSurfaceFormatsKHR(device, surface, &formatCount, swapDetails.formats.data()); - } - - uint32_t presentModeCount; - vkGetPhysicalDeviceSurfacePresentModesKHR(device, surface, &presentModeCount, nullptr); - if (presentModeCount != 0) { - swapDetails.presentModes.resize(presentModeCount); - vkGetPhysicalDeviceSurfacePresentModesKHR(device, surface, &presentModeCount, swapDetails.presentModes.data()); - } - return swapDetails; -} - -QueueFamilyIndices QueueFamilyIndices::Query(VkPhysicalDevice device, VkSurfaceKHR surface) { - QueueFamilyIndices queueIndices; - uint32_t queueFamilyCount = 0; - vkGetPhysicalDeviceQueueFamilyProperties(device, &queueFamilyCount, nullptr); - std::vector queueFamilies(queueFamilyCount); - vkGetPhysicalDeviceQueueFamilyProperties(device, &queueFamilyCount, queueFamilies.data()); - - int i = 0; - for(const auto& queueFamily: queueFamilies) { - if (queueFamily.queueFlags & VK_QUEUE_GRAPHICS_BIT) { - queueIndices.graphicsFamily = i; - } - VkBool32 presentSupport = false; - vkGetPhysicalDeviceSurfaceSupportKHR(device, i, surface, &presentSupport); - if (presentSupport) { - queueIndices.presentFamily = i; - } - -#if DEBUG - LOG_D("Queue " << i << ' ' << (queueFamily.queueFlags & VK_QUEUE_GRAPHICS_BIT ? "graphics " : "") - << (queueFamily.queueFlags & VK_QUEUE_COMPUTE_BIT ? "compute " : "") - << (queueFamily.queueFlags & VK_QUEUE_TRANSFER_BIT ? "transfer " : "") - << (queueFamily.queueFlags & VK_QUEUE_PROTECTED_BIT ? "protected " : "") - << 'x' << queueFamily.queueCount); -#endif - i++; - } - - return queueIndices; -} - void Renderer::beginFrame() { assert(currentImage == UINT32_MAX); - //FIXME: TracyGpuZone("Render"); if (auto newImage = swapChain->acquireNextImage(imageAvailableSemaphores[currentFrame], inFlightFences[currentFrame])) { currentImage = newImage.value(); + allocator->setTracyZone("Submit"); } else { recreateSwapChain(); beginFrame(); @@ -405,7 +342,7 @@ void Renderer::beginFrame() { std::function Renderer::beginWorldPass() { assert(currentImage < swapChain->getImageViews().size()); - commandPool->submitGraphics(currentImage, graphicsQueue, imageAvailableSemaphores[currentFrame], + commandCenter->submitGraphics(currentImage, imageAvailableSemaphores[currentFrame], renderFinishedSemaphores[currentFrame], inFlightFences[currentFrame]); /*WorldPass->useIt(); @@ -436,11 +373,7 @@ void Renderer::endPass() { } void Renderer::swapBuffer(Window&) { - /*TracyGpuZone("Swap"); - glfwSwapBuffers(ptr); - TracyGpuCollect;*/ - - if(!swapChain->presentImage(currentImage, presentQueue, renderFinishedSemaphores[currentFrame]) || framebufferResized) { + if(!swapChain->presentImage(currentImage, renderFinishedSemaphores[currentFrame]) || framebufferResized) { framebufferResized = false; recreateSwapChain(); } @@ -448,6 +381,7 @@ void Renderer::swapBuffer(Window&) { currentFrame = (currentFrame + 1) % renderFinishedSemaphores.size(); currentImage = UINT32_MAX; + allocator->setTracyZone("Swap"); vkWaitForFences(device, 1, &inFlightFences[currentFrame], VK_TRUE, UINT64_MAX); } diff --git a/src/client/render/vk/Renderer.hpp b/src/client/render/vk/Renderer.hpp index 8f517e5..18eded7 100644 --- a/src/client/render/vk/Renderer.hpp +++ b/src/client/render/vk/Renderer.hpp @@ -3,9 +3,10 @@ #include "forward.hpp" namespace render::vk { +class Allocator; class SwapChain; class Pipeline; -class CommandPool; +class CommandCenter; /// Vulkan rendering class Renderer final: public render::Renderer { @@ -43,13 +44,12 @@ private: VkInstance instance; VkSurfaceKHR surface; VkDevice device; - VkQueue graphicsQueue; - VkQueue presentQueue; std::unique_ptr physicalInfo; + std::unique_ptr allocator; std::unique_ptr swapChain; std::unique_ptr pipeline; - std::unique_ptr commandPool; + std::unique_ptr commandCenter; size_t currentFrame = 0; uint32_t currentImage = UINT32_MAX; diff --git a/src/client/render/vk/SwapChain.cpp b/src/client/render/vk/SwapChain.cpp index 0feb3a5..47a37c3 100644 --- a/src/client/render/vk/SwapChain.cpp +++ b/src/client/render/vk/SwapChain.cpp @@ -1,10 +1,11 @@ #include "SwapChain.hpp" -#include "shared.hpp" +#include "PhysicalDeviceInfo.hpp" using namespace render::vk; SwapChain::SwapChain(VkDevice device, const PhysicalDeviceInfo& info): device(device) { + vkGetDeviceQueue(device, info.queueIndices.presentFamily.value(), 0, &presentQueue); { // Swapchain VkPresentModeKHR presentMode = [&]() { // MAYBE: add prefer no triple buffering options @@ -26,14 +27,14 @@ SwapChain::SwapChain(VkDevice device, const PhysicalDeviceInfo& info): device(de createInfo.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR; createInfo.surface = info.surface; createInfo.minImageCount = imageCount; - createInfo.imageFormat = info.surfaceFormat.format; - createInfo.imageColorSpace = info.surfaceFormat.colorSpace; + createInfo.imageFormat = info.getFormat().format; + createInfo.imageColorSpace = info.getFormat().colorSpace; createInfo.imageExtent = info.swapDetails.capabilities.currentExtent; createInfo.imageArrayLayers = 1; createInfo.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; //VK_IMAGE_USAGE_TRANSFER_DST_BIT + uint32_t queueFamilyIndices[] = {info.queueIndices.graphicsFamily.value(), info.queueIndices.presentFamily.value()}; if (info.queueIndices.graphicsFamily != info.queueIndices.presentFamily) { - uint32_t queueFamilyIndices[] = {info.queueIndices.graphicsFamily.value(), info.queueIndices.presentFamily.value()}; createInfo.imageSharingMode = VK_SHARING_MODE_CONCURRENT; createInfo.queueFamilyIndexCount = 2; createInfo.pQueueFamilyIndices = queueFamilyIndices; @@ -66,7 +67,7 @@ SwapChain::SwapChain(VkDevice device, const PhysicalDeviceInfo& info): device(de createInfo.image = images[i]; createInfo.viewType = VK_IMAGE_VIEW_TYPE_2D; - createInfo.format = info.surfaceFormat.format; + createInfo.format = info.getFormat().format; createInfo.components.r = VK_COMPONENT_SWIZZLE_IDENTITY; createInfo.components.g = VK_COMPONENT_SWIZZLE_IDENTITY; createInfo.components.b = VK_COMPONENT_SWIZZLE_IDENTITY; @@ -111,7 +112,7 @@ std::optional SwapChain::acquireNextImage(VkSemaphore semaphore, VkFen imagesInFlight[imageIndex] = fence; return imageIndex; } -bool SwapChain::presentImage(uint32_t idx, VkQueue queue, VkSemaphore signalSemaphore) { +bool SwapChain::presentImage(uint32_t idx, VkSemaphore signalSemaphore) { VkSemaphore signalSemaphores[] = {signalSemaphore}; VkPresentInfoKHR presentInfo{}; @@ -125,7 +126,7 @@ bool SwapChain::presentImage(uint32_t idx, VkQueue queue, VkSemaphore signalSema presentInfo.pImageIndices = &idx; presentInfo.pResults = nullptr; - auto result = vkQueuePresentKHR(queue, &presentInfo); + auto result = vkQueuePresentKHR(presentQueue, &presentInfo); if (result == VK_ERROR_OUT_OF_DATE_KHR || result == VK_SUBOPTIMAL_KHR) { return false; diff --git a/src/client/render/vk/SwapChain.hpp b/src/client/render/vk/SwapChain.hpp index c740c1f..5a4d03a 100644 --- a/src/client/render/vk/SwapChain.hpp +++ b/src/client/render/vk/SwapChain.hpp @@ -14,12 +14,13 @@ public: const std::vector &getImageViews() { return imageViews; } std::optional acquireNextImage(VkSemaphore, VkFence); - bool presentImage(uint32_t, VkQueue, VkSemaphore); + bool presentImage(uint32_t, VkSemaphore); private: VkDevice device; - VkSwapchainKHR chain; + VkQueue presentQueue; + VkSwapchainKHR chain = VK_NULL_HANDLE; std::vector images; std::vector imageViews; std::vector imagesInFlight; diff --git a/src/client/render/vk/buffer/Buffer.hpp b/src/client/render/vk/buffer/Buffer.hpp new file mode 100644 index 0000000..0c55b95 --- /dev/null +++ b/src/client/render/vk/buffer/Buffer.hpp @@ -0,0 +1,27 @@ +#pragma once + +#include + +namespace buffer::vk { + +class MemoryArea { + +private: + VkDeviceMemory ref; + size_t size; + std::vector<> +}; +class Buffer { + +private: + std::weak_ptr<> + VkBuffer ref; + + size_t offset; + size_t size; + + // Only is mappable + void* data = nullptr; +}; + +} \ No newline at end of file diff --git a/src/client/render/vk/buffer/VertexData.hpp b/src/client/render/vk/buffer/VertexData.hpp new file mode 100644 index 0000000..fcabea6 --- /dev/null +++ b/src/client/render/vk/buffer/VertexData.hpp @@ -0,0 +1,45 @@ +#pragma once + +#include +#include +#include +#include + +namespace buffer::vk { + +struct VertexData { + glm::vec2 pos; + glm::vec3 color; + + static VkVertexInputBindingDescription getBindingDescription() { + VkVertexInputBindingDescription description{}; + description.binding = 0; + description.stride = sizeof(VertexData); + description.inputRate = VK_VERTEX_INPUT_RATE_VERTEX; + return description; + } + static std::array getAttributeDescriptions() { + std::array attributeDescriptions{}; + attributeDescriptions[0].binding = 0; + attributeDescriptions[0].location = 0; + attributeDescriptions[0].format = VK_FORMAT_R32G32_SFLOAT; + attributeDescriptions[0].offset = offsetof(VertexData, pos); + attributeDescriptions[1].binding = 0; + attributeDescriptions[1].location = 1; + attributeDescriptions[1].format = VK_FORMAT_R32G32B32_SFLOAT; + attributeDescriptions[1].offset = offsetof(VertexData, color); + return attributeDescriptions; + } +}; + +const std::vector vertices = { + {{-0.5f, -0.5f}, {1.0f, 0.0f, 0.0f}}, + {{0.5f, -0.5f}, {0.0f, 1.0f, 0.0f}}, + {{0.5f, 0.5f}, {0.0f, 0.0f, 1.0f}}, + {{-0.5f, 0.5f}, {1.0f, 1.0f, 1.0f}} +}; +const std::vector indices = { + 0, 1, 2, 2, 3, 0 +}; + +} \ No newline at end of file diff --git a/src/client/world/DistantUniverse.cpp b/src/client/world/DistantUniverse.cpp index 6dc0675..53cb24a 100644 --- a/src/client/world/DistantUniverse.cpp +++ b/src/client/world/DistantUniverse.cpp @@ -12,7 +12,7 @@ using namespace world::client; DistantUniverse::DistantUniverse(const connection& ct, const options& opt): Universe(), peer(ct), - loadDistance(opt.loadDistance), keepDistance(opt.keepDistance) { } + loadDistance(opt.loadDistance), keepDistance(opt.keepDistance), serverDistance(0) { } DistantUniverse::~DistantUniverse() { } void DistantUniverse::update(voxel_pos pos, float deltaTime) { @@ -46,11 +46,12 @@ void DistantUniverse::update(voxel_pos pos, float deltaTime) { ZoneScopedN("Missing"); std::vector missing; //TODO: use easy sphere fill - for (int x = -loadDistance; x <= loadDistance; x++) { - for (int y = -loadDistance; y <= loadDistance; y++) { - for (int z = -loadDistance; z <= loadDistance; z++) { + const int queryDistance = std::min(loadDistance, serverDistance); + for (int x = -queryDistance; x <= queryDistance; x++) { + for (int y = -queryDistance; y <= queryDistance; y++) { + for (int z = -queryDistance; z <= queryDistance; z++) { const auto dist2 = x * x + y * y + z * z; - if (dist2 <= loadDistance * loadDistance) { + if (dist2 <= queryDistance * queryDistance) { const auto p = diff + chunk_pos(x, y, z); if (chunks.inRange(p) && chunks.find(p) == chunks.end()) { missing.push_back(p); @@ -58,7 +59,8 @@ void DistantUniverse::update(voxel_pos pos, float deltaTime) { } }}} if(!missing.empty()) { - auto packet = net::Client::makePacket(net::client_packet_type::MISSING_CHUNKS, NULL, sizeof(area_id) + missing.size() * sizeof(chunk_pos), ENET_PACKET_FLAG_RELIABLE, peer.getSalt()); + auto packet = net::Client::makePacket(net::client_packet_type::MISSING_CHUNKS, NULL, + sizeof(area_id) + missing.size() * sizeof(chunk_pos), ENET_PACKET_FLAG_RELIABLE, peer.getSalt()); packet.write(area.first); packet.write(missing.data(), missing.size() * sizeof(chunk_pos)); peer.send(packet.get(), net::channel_type::RELIABLE); @@ -78,6 +80,11 @@ void DistantUniverse::pullNetwork(voxel_pos pos) { [&](packet_t* packet, channel_type){ const server_packet_type type = static_cast(*packet->data); switch (type) { + case server_packet_type::CAPABILITIES: { + PacketReader(packet).read(serverDistance); + break; + } + case server_packet_type::COMPRESSION: { if(dict.has_value()) break; diff --git a/src/client/world/DistantUniverse.hpp b/src/client/world/DistantUniverse.hpp index 761a518..e44096c 100644 --- a/src/client/world/DistantUniverse.hpp +++ b/src/client/world/DistantUniverse.hpp @@ -29,7 +29,8 @@ namespace world::client { chunk_pos last_chunk = chunk_pos(INT_MAX); - int loadDistance; - int keepDistance; + ushort loadDistance; + ushort keepDistance; + ushort serverDistance; }; } \ No newline at end of file diff --git a/src/core/net/Client.hpp b/src/core/net/Client.hpp index 08126a6..e5f9bea 100644 --- a/src/core/net/Client.hpp +++ b/src/core/net/Client.hpp @@ -44,9 +44,9 @@ public: } template - void pull(R onData, D onDisconnect, int delay = 0) { + void pull(R onData, D onDisconnect, int delay = 0, int count = 10) { ENetEvent event; - while(enet_host_service(host, &event, delay) > 0) { + for(int i = 0; i < count && enet_host_service(host, &event, delay) > 0; i++) { switch(event.type) { case ENET_EVENT_TYPE_CONNECT: LOG_D("Client reconnected"); @@ -110,6 +110,7 @@ public: } template bool send(client_packet_type type, const D& data, channel_type channel, std::optional flags = {}) { + static_assert(!std::is_pointer::value); return send(type, &data, sizeof(data), channel, flags); } diff --git a/src/core/net/Server.hpp b/src/core/net/Server.hpp index e1e7b71..0930421 100644 --- a/src/core/net/Server.hpp +++ b/src/core/net/Server.hpp @@ -27,9 +27,9 @@ public: } template - void pull(C onConnect, D onDisconnect, R onData, int delay = 0) { + void pull(C onConnect, D onDisconnect, R onData, int delay = 10, int count = 10) { ENetEvent event; - while(enet_host_service(host, &event, delay) > 0) { + for(int i = 0; i < count && enet_host_service(host, &event, delay) > 0; i++) { switch(event.type) { case ENET_EVENT_TYPE_CONNECT: onConnect(event.peer, event.data); @@ -72,6 +72,7 @@ public: } template bool sendTo(peer_t* peer, server_packet_type type, const D& data, channel_type channel, std::optional flags = {}) { + static_assert(!std::is_pointer::value); return sendTo(peer, type, &data, sizeof(data), channel, flags); } @@ -84,6 +85,7 @@ public: } template bool send(peer_t* peer, server_packet_type type, const D& data, channel_type channel, std::optional flags = {}) { + static_assert(!std::is_pointer::value); return send(peer, type, &data, sizeof(data), channel, flags); } @@ -96,6 +98,7 @@ public: } template void broadcast(server_packet_type type, const D& data, channel_type channel, std::optional flags = {}) { + static_assert(!std::is_pointer::value); broadcast(type, &data, sizeof(data), channel, flags); } diff --git a/src/core/net/data.hpp b/src/core/net/data.hpp index e6aa352..a9a874f 100644 --- a/src/core/net/data.hpp +++ b/src/core/net/data.hpp @@ -37,13 +37,16 @@ enum class server_packet_type: enet_uint8 { /// {area_, zstd} realable CHUNK = 17, /// Chunk changes - /// {area_id, {chunk_pos, short(count), Chunk::Edit[]}[]} notify + /// {area_id, {chunk_pos, ushort(count), Chunk::Edit[]}[]} notify /// FIXME: to big !!! MAYBE: compress EDITS = 18, /// World compression dictionary /// zstd dict realable COMPRESSION = 24, + /// Server capabilities + /// ushort(loadDistance), MAYBE: more realable + CAPABILITIES = 25, }; enum class client_packet_type: enet_uint8 { /// Interact with voxels diff --git a/src/core/world/Universe.hpp b/src/core/world/Universe.hpp index a57e096..be5fb09 100644 --- a/src/core/world/Universe.hpp +++ b/src/core/world/Universe.hpp @@ -15,9 +15,9 @@ namespace world { /// Distance management struct options { /// Radius in chunks to load if missing - int loadDistance = 5; + ushort loadDistance = 5; /// Radius in chunks to keep in memory - int keepDistance = 6; + ushort keepDistance = 6; }; /// Universe voxel ray intersection diff --git a/src/server/Server.cpp b/src/server/Server.cpp index fba5016..7526335 100644 --- a/src/server/Server.cpp +++ b/src/server/Server.cpp @@ -4,11 +4,9 @@ #include "world/SharedUniverse.hpp" #endif #include +#include -Server::Server(config::server::options& options): options(options) { - //MAYBE: if allow local - localHandle = options.allowLocal ? new server_handle() : nullptr; -} +Server::Server(config::server::options& options): options(options), localHandle(options.allowLocal ? new server_handle() : nullptr) { } Server::~Server() { } const auto TPS = 10; @@ -29,9 +27,16 @@ void Server::run() { signal(SIGINT, handle_signal); signal(SIGTERM, handle_signal); + auto lastTick = std::chrono::steady_clock::now(); while(running && (localHandle == nullptr || localHandle->running)) { - universe->update(1. / TPS); //FIXME: use chrono - FrameMarkNamed("Server"); - std::this_thread::sleep_for(std::chrono::milliseconds(1000 / TPS)); + FrameMarkStart("Server"); + auto startTick = std::chrono::steady_clock::now(); + const std::chrono::duration> deltaTime = startTick - lastTick; + universe->update(deltaTime.count()); + FrameMarkEnd("Server"); + while (std::chrono::steady_clock::now() < startTick + std::chrono::milliseconds(1000 / TPS)) { + std::this_thread::sleep_for(std::chrono::milliseconds(1)); + } + lastTick = startTick; } } \ No newline at end of file diff --git a/src/server/world/Universe.cpp b/src/server/world/Universe.cpp index 9a86583..ce0d219 100644 --- a/src/server/world/Universe.cpp +++ b/src/server/world/Universe.cpp @@ -328,9 +328,11 @@ struct net_client { }; void Universe::pullNetwork() { + ZoneScopedN("Network"); using namespace net; host.pull( [&](peer_t *peer, salt_t salt) { + ZoneScopedN("Connect"); LOG_D("Client connect from " << peer->address); net_client* client = new net_client(salt, entities.at(PLAYER_ENTITY_ID).instances.emplace(Entity::Instance{ })); peer->data = client; @@ -339,15 +341,18 @@ void Universe::pullNetwork() { host.sendTo(peer, server_packet_type::CHALLENGE, rnd, channel_type::RELIABLE); client->salt = salt ^ rnd; + host.send(peer, server_packet_type::CAPABILITIES, loadDistance, channel_type::RELIABLE); host.send(peer, server_packet_type::COMPRESSION, dict_content.data(), dict_content.size(), channel_type::RELIABLE); broadcastAreas(); }, [](peer_t *peer, disconnect_reason reason) { + ZoneScopedN("Disconnect"); LOG_D("Client disconnect from " << peer->address << " with " << (enet_uint32)reason); if (const auto data = Server::GetPeerData(peer); data != nullptr) delete data; }, [&](peer_t *peer, packet_t* packet, channel_type) { + ZoneScopedN("Data"); if(packet->dataLength < sizeof(client_packet_type) + sizeof(salt_t)) { LOG_D("Empty packet from " << peer->address); return; @@ -403,7 +408,7 @@ void Universe::pullNetwork() { LOG_D("Bad packet from " << peer->address); break; } - }, 100); + }); } void Universe::broadcastAreas() { constexpr size_t ITEM_SIZE = sizeof(area_id) + sizeof(world::Area::params); @@ -453,6 +458,7 @@ std::optional Universe::set(const area_& pos, const Voxe return {}; } world::ItemList Universe::setCube(const area_& pos, const Voxel& val, int radius) { + ZoneScopedN("Fill"); ItemList list; if(const auto it = areas.find(pos.first); it != areas.end()) { robin_hood::unordered_map> edits; @@ -476,6 +482,7 @@ world::ItemList Universe::setCube(const area_& pos, const Voxel& val, } } }}} + ZoneScopedN("Packet"); size_t size = sizeof(area_id); for(const auto& part: edits) { size += sizeof(chunk_pos); diff --git a/src/server/world/Universe.hpp b/src/server/world/Universe.hpp index cc7966f..151e3b3 100644 --- a/src/server/world/Universe.hpp +++ b/src/server/world/Universe.hpp @@ -98,8 +98,8 @@ namespace world::server { using save_task_t = std::pair>>; data::safe_queue saveQueue; //NOTE: consider Area and Chunk const - int loadDistance; - int keepDistance; + ushort loadDistance; + ushort keepDistance; std::string folderPath; net::Server host;