1
0
Fork 0

Vulkan basic buffer allocator

tmp
May B. 2020-09-27 22:25:35 +02:00
parent 41eb636826
commit c00f3f64a6
54 changed files with 926 additions and 295 deletions

View File

@ -19,9 +19,10 @@
namespace tracy
{
class VkCtxScope {};
class VkCtx;
}
using TracyVkCtx = void*;
using TracyVkCtx = tracy::VkCtx*;
#else

BIN
resource/content/shaders/Color.fs.spv (Stored with Git LFS) Normal file

Binary file not shown.

BIN
resource/content/shaders/Color.vs.spv (Stored with Git LFS) Normal file

Binary file not shown.

BIN
resource/content/shaders/Sky.fs.spv (Stored with Git LFS) Normal file

Binary file not shown.

BIN
resource/content/shaders/Sky.vs.spv (Stored with Git LFS) Normal file

Binary file not shown.

BIN
resource/content/shaders/Tris.vs.spv (Stored with Git LFS)

Binary file not shown.

BIN
resource/content/shaders/Voxel.fs.geo.ins.spv (Stored with Git LFS) Normal file

Binary file not shown.

BIN
resource/content/shaders/Voxel.fs.geo.spv (Stored with Git LFS) Normal file

Binary file not shown.

BIN
resource/content/shaders/Voxel.fs.ins.spv (Stored with Git LFS) Normal file

Binary file not shown.

BIN
resource/content/shaders/Voxel.fs.spv (Stored with Git LFS) Normal file

Binary file not shown.

BIN
resource/content/shaders/Voxel.gs.geo.ins.spv (Stored with Git LFS) Normal file

Binary file not shown.

BIN
resource/content/shaders/Voxel.gs.geo.spv (Stored with Git LFS) Normal file

Binary file not shown.

BIN
resource/content/shaders/Voxel.vs.geo.ins.spv (Stored with Git LFS) Normal file

Binary file not shown.

BIN
resource/content/shaders/Voxel.vs.geo.spv (Stored with Git LFS) Normal file

Binary file not shown.

BIN
resource/content/shaders/Voxel.vs.ins.spv (Stored with Git LFS) Normal file

Binary file not shown.

BIN
resource/content/shaders/Voxel.vs.spv (Stored with Git LFS) Normal file

Binary file not shown.

View File

@ -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);
}

View File

@ -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;
}

View File

@ -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);
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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];
}

View File

@ -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) {

View File

@ -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;

View File

@ -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;
}
}

View File

@ -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

View File

@ -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();

View File

@ -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);

View File

@ -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;

View File

@ -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)) {

View File

@ -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, &copyRegion);
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);
}

View File

@ -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;
};
}

View File

@ -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{};
@ -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!");
}
}
}

View File

@ -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;
};
}

View File

@ -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;
};
}

View File

@ -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];
}

View File

@ -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;
};
}

View File

@ -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;

View File

@ -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);
}

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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;
};
}

View File

@ -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
};
}

View File

@ -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;

View File

@ -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;
};
}

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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

View File

@ -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

View File

@ -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;
}
}

View File

@ -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);

View File

@ -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;