Vulkan basic buffer allocator
This commit is contained in:
parent
41eb636826
commit
c00f3f64a6
|
@ -19,9 +19,10 @@
|
|||
namespace tracy
|
||||
{
|
||||
class VkCtxScope {};
|
||||
class VkCtx;
|
||||
}
|
||||
|
||||
using TracyVkCtx = void*;
|
||||
using TracyVkCtx = tracy::VkCtx*;
|
||||
|
||||
#else
|
||||
|
||||
|
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
resource/content/shaders/Tris.vs.spv (Stored with Git LFS)
BIN
resource/content/shaders/Tris.vs.spv (Stored with Git LFS)
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -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);
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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];
|
||||
}
|
|
@ -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) {
|
|
@ -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;
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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
|
||||
$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
|
|
@ -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();
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -49,8 +49,8 @@ namespace contouring {
|
|||
|
||||
void enqueue(const area_<chunk_pos> &, 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;
|
||||
|
|
|
@ -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)) {
|
||||
|
|
|
@ -0,0 +1,282 @@
|
|||
#include "Allocator.hpp"
|
||||
|
||||
#include "PhysicalDeviceInfo.hpp"
|
||||
#include <TracyVulkan.hpp>
|
||||
#include "buffer/VertexData.hpp"
|
||||
#include <memory.h>
|
||||
|
||||
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<buffer_requirement> 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<buffer_info> 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<buffer_requirement>& requirements, VkMemoryPropertyFlags properties, std::vector<buffer_info>& out) {
|
||||
assert(!requirements.empty());
|
||||
out.resize(requirements.size());
|
||||
|
||||
// Create buffers
|
||||
VkMemoryRequirements memRequirements = {0, 0, UINT32_MAX};
|
||||
std::vector<std::pair<VkDeviceSize, VkDeviceSize>> 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<uint32_t> 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);
|
||||
}
|
|
@ -0,0 +1,92 @@
|
|||
#pragma once
|
||||
|
||||
#include "forward.hpp"
|
||||
#include <vector>
|
||||
#include <optional>
|
||||
#include <memory>
|
||||
|
||||
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_area, MemoryDeleter>;
|
||||
|
||||
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<buffer_requirement> &, VkMemoryPropertyFlags, std::vector<buffer_info> &);
|
||||
//TODO: create Buffer{MemoryArea + VkBuffer}
|
||||
//TODO: create readonly buffer with data
|
||||
|
||||
void copyBuffer(buffer_info srcBuffer, buffer_info dstBuffer, VkDeviceSize size);
|
||||
|
||||
std::pair<VkBuffer, VkBuffer> getBuffer() { return {vertexBuffer.buffer, indexBuffer.buffer}; }
|
||||
void setTracyZone(const char* name);
|
||||
|
||||
private:
|
||||
std::optional<uint32_t> 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<area> 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<std::unique_ptr<Allocation>> allocations;
|
||||
};
|
||||
}
|
|
@ -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<VkImageView>& views, PipelineRef pipe, const PhysicalDeviceInfo& info, const renderOptions& opt):
|
||||
device(device) {
|
||||
CommandCenter::CommandCenter(VkDevice device, const std::vector<VkImageView> &views, PipelineRef pipe,
|
||||
std::pair<VkBuffer, VkBuffer> 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<VkImageView>& views, PipelineRef pipe, VkExtent2D extent, const renderOptions& opt) {
|
||||
void CommandCenter::allocate(const std::vector<VkImageView>& views, PipelineRef pipe, std::pair<VkBuffer, VkBuffer> buffer, VkExtent2D extent,
|
||||
const renderOptions& opt)
|
||||
{
|
||||
assert(freed);
|
||||
|
||||
framebuffers.resize(views.size());
|
||||
|
@ -47,16 +52,17 @@ void CommandPool::allocate(const std::vector<VkImageView>& 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<VkImageView>& 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<uint32_t>(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{};
|
|
@ -0,0 +1,31 @@
|
|||
#pragma once
|
||||
|
||||
#include "forward.hpp"
|
||||
#include <vector>
|
||||
|
||||
namespace render::vk {
|
||||
class SwapChain;
|
||||
class Pipeline;
|
||||
|
||||
class CommandCenter {
|
||||
public:
|
||||
CommandCenter(VkDevice, const std::vector<VkImageView>&, PipelineRef, std::pair<VkBuffer, VkBuffer>, const PhysicalDeviceInfo&, const renderOptions&);
|
||||
~CommandCenter();
|
||||
|
||||
void submitGraphics(uint32_t, VkSemaphore, VkSemaphore, VkFence);
|
||||
|
||||
void allocate(const std::vector<VkImageView> &, PipelineRef, std::pair<VkBuffer, VkBuffer>, VkExtent2D, const renderOptions&);
|
||||
void free();
|
||||
|
||||
private:
|
||||
VkDevice device;
|
||||
|
||||
std::vector<VkFramebuffer> framebuffers;
|
||||
|
||||
VkQueue graphicsQueue;
|
||||
VkCommandPool graphicsPool;
|
||||
std::vector<VkCommandBuffer> graphicsBuffers;
|
||||
|
||||
bool freed = true;
|
||||
};
|
||||
}
|
|
@ -1,29 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include "forward.hpp"
|
||||
#include <vector>
|
||||
|
||||
namespace render::vk {
|
||||
class SwapChain;
|
||||
class Pipeline;
|
||||
|
||||
class CommandPool {
|
||||
public:
|
||||
CommandPool(VkDevice, const std::vector<VkImageView>&, PipelineRef, const PhysicalDeviceInfo&, const renderOptions&);
|
||||
~CommandPool();
|
||||
|
||||
void submitGraphics(uint32_t, VkQueue, VkSemaphore, VkSemaphore, VkFence);
|
||||
|
||||
void allocate(const std::vector<VkImageView>&, PipelineRef, VkExtent2D, const renderOptions&);
|
||||
void free();
|
||||
|
||||
private:
|
||||
VkDevice device;
|
||||
|
||||
std::vector<VkFramebuffer> framebuffers;
|
||||
|
||||
VkCommandPool graphicsPool;
|
||||
std::vector<VkCommandBuffer> graphicsBuffers;
|
||||
bool freed = true;
|
||||
};
|
||||
}
|
|
@ -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<VkQueueFamilyProperties> 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];
|
||||
}
|
|
@ -17,15 +17,23 @@ struct SwapChainSupportDetails {
|
|||
struct QueueFamilyIndices {
|
||||
std::optional<uint32_t> graphicsFamily;
|
||||
std::optional<uint32_t> presentFamily;
|
||||
std::optional<uint32_t> 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;
|
||||
};
|
||||
}
|
|
@ -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;
|
||||
|
|
|
@ -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 <GLFW/glfw3.h>
|
||||
#include <string.h>
|
||||
#include <algorithm>
|
||||
|
@ -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<PhysicalDeviceInfo>(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<Allocator>(device, *physicalInfo.get());
|
||||
swapChain = std::make_unique<SwapChain>(device, *physicalInfo.get());
|
||||
pipeline = std::make_unique<Pipeline>(device, *physicalInfo.get(), options);
|
||||
commandPool = std::make_unique<CommandPool>(device, swapChain->getImageViews(), pipeline->getRef(), *physicalInfo.get(), options);
|
||||
commandCenter = std::make_unique<CommandCenter>(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<SwapChain>(device, *physicalInfo.get());
|
||||
pipeline = std::make_unique<Pipeline>(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<VkQueueFamilyProperties> 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<buffer::params(glm::mat4)> 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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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<PhysicalDeviceInfo> physicalInfo;
|
||||
std::unique_ptr<Allocator> allocator;
|
||||
std::unique_ptr<SwapChain> swapChain;
|
||||
std::unique_ptr<Pipeline> pipeline;
|
||||
std::unique_ptr<CommandPool> commandPool;
|
||||
std::unique_ptr<CommandCenter> commandCenter;
|
||||
|
||||
size_t currentFrame = 0;
|
||||
uint32_t currentImage = UINT32_MAX;
|
||||
|
|
|
@ -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<uint32_t> 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;
|
||||
|
|
|
@ -14,12 +14,13 @@ public:
|
|||
const std::vector<VkImageView> &getImageViews() { return imageViews; }
|
||||
|
||||
std::optional<uint32_t> 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<VkImage> images;
|
||||
std::vector<VkImageView> imageViews;
|
||||
std::vector<VkFence> imagesInFlight;
|
||||
|
|
|
@ -0,0 +1,27 @@
|
|||
#pragma once
|
||||
|
||||
#include <volk.h>
|
||||
|
||||
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;
|
||||
};
|
||||
|
||||
}
|
|
@ -0,0 +1,45 @@
|
|||
#pragma once
|
||||
|
||||
#include <glm/glm.hpp>
|
||||
#include <vector>
|
||||
#include <array>
|
||||
#include <volk.h>
|
||||
|
||||
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<VkVertexInputAttributeDescription, 2> getAttributeDescriptions() {
|
||||
std::array<VkVertexInputAttributeDescription, 2> 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<VertexData> 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<uint16_t> indices = {
|
||||
0, 1, 2, 2, 3, 0
|
||||
};
|
||||
|
||||
}
|
|
@ -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<chunk_pos> 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<server_packet_type>(*packet->data);
|
||||
switch (type) {
|
||||
case server_packet_type::CAPABILITIES: {
|
||||
PacketReader(packet).read(serverDistance);
|
||||
break;
|
||||
}
|
||||
|
||||
case server_packet_type::COMPRESSION: {
|
||||
if(dict.has_value())
|
||||
break;
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
}
|
|
@ -44,9 +44,9 @@ public:
|
|||
}
|
||||
|
||||
template<typename D, typename R>
|
||||
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<typename D>
|
||||
bool send(client_packet_type type, const D& data, channel_type channel, std::optional<enet_uint32> flags = {}) {
|
||||
static_assert(!std::is_pointer<D>::value);
|
||||
return send(type, &data, sizeof(data), channel, flags);
|
||||
}
|
||||
|
||||
|
|
|
@ -27,9 +27,9 @@ public:
|
|||
}
|
||||
|
||||
template<typename C, typename D, typename R>
|
||||
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<typename D>
|
||||
bool sendTo(peer_t* peer, server_packet_type type, const D& data, channel_type channel, std::optional<enet_uint32> flags = {}) {
|
||||
static_assert(!std::is_pointer<D>::value);
|
||||
return sendTo(peer, type, &data, sizeof(data), channel, flags);
|
||||
}
|
||||
|
||||
|
@ -84,6 +85,7 @@ public:
|
|||
}
|
||||
template<typename D>
|
||||
bool send(peer_t* peer, server_packet_type type, const D& data, channel_type channel, std::optional<enet_uint32> flags = {}) {
|
||||
static_assert(!std::is_pointer<D>::value);
|
||||
return send(peer, type, &data, sizeof(data), channel, flags);
|
||||
}
|
||||
|
||||
|
@ -96,6 +98,7 @@ public:
|
|||
}
|
||||
template<typename D>
|
||||
void broadcast(server_packet_type type, const D& data, channel_type channel, std::optional<enet_uint32> flags = {}) {
|
||||
static_assert(!std::is_pointer<D>::value);
|
||||
broadcast(type, &data, sizeof(data), channel, flags);
|
||||
}
|
||||
|
||||
|
|
|
@ -37,13 +37,16 @@ enum class server_packet_type: enet_uint8 {
|
|||
/// {area_<chunk_pos>, zstd<chunk rle>} 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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -4,11 +4,9 @@
|
|||
#include "world/SharedUniverse.hpp"
|
||||
#endif
|
||||
#include <signal.h>
|
||||
#include <chrono>
|
||||
|
||||
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<float, std::ratio<1>> 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;
|
||||
}
|
||||
}
|
|
@ -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<salt_t>(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<net_client>(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<world::Item> Universe::set(const area_<voxel_pos>& pos, const Voxe
|
|||
return {};
|
||||
}
|
||||
world::ItemList Universe::setCube(const area_<voxel_pos>& 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<chunk_pos, std::vector<Chunk::Edit>> edits;
|
||||
|
@ -476,6 +482,7 @@ world::ItemList Universe::setCube(const area_<voxel_pos>& pos, const Voxel& val,
|
|||
}
|
||||
}
|
||||
}}}
|
||||
ZoneScopedN("Packet");
|
||||
size_t size = sizeof(area_id);
|
||||
for(const auto& part: edits) {
|
||||
size += sizeof(chunk_pos);
|
||||
|
|
|
@ -98,8 +98,8 @@ namespace world::server {
|
|||
using save_task_t = std::pair<area_it_t, robin_hood::pair<chunk_pos, std::shared_ptr<world::server::Chunk>>>;
|
||||
data::safe_queue<save_task_t> saveQueue; //NOTE: consider Area and Chunk const
|
||||
|
||||
int loadDistance;
|
||||
int keepDistance;
|
||||
ushort loadDistance;
|
||||
ushort keepDistance;
|
||||
std::string folderPath;
|
||||
|
||||
net::Server host;
|
||||
|
|
Loading…
Reference in New Issue