diff --git a/resource/content/shaders/Sky.vs.spv b/resource/content/shaders/Sky.vs.spv index 3230de5..9245725 100644 --- a/resource/content/shaders/Sky.vs.spv +++ b/resource/content/shaders/Sky.vs.spv @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:c144bd2cfa1f0a64beb88bdbaa804009cf538454df27a64e3afb4a0bc95db0c6 -size 1452 +oid sha256:828ef16d9df0c78afdff93f7c0873e50fe162d236caed3ca1a4606f047704df3 +size 1664 diff --git a/resource/content/shaders/Tris.vs.spv b/resource/content/shaders/Tris.vs.spv index c49d17f..1185d02 100644 --- a/resource/content/shaders/Tris.vs.spv +++ b/resource/content/shaders/Tris.vs.spv @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:e3ebf7b30e7fcda926bddd63a4f3e3c7d78b8b2945b8d75f77621a8c58ed84d0 -size 1876 +oid sha256:4690f6b8744b857929110d5057255ce2fe1266275f1b0fdb581bf0beff4e08a3 +size 1964 diff --git a/resource/content/shaders/Voxel.fs.geo.ins.spv b/resource/content/shaders/Voxel.fs.geo.ins.spv index ae73ac2..762ebb0 100644 --- a/resource/content/shaders/Voxel.fs.geo.ins.spv +++ b/resource/content/shaders/Voxel.fs.geo.ins.spv @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:ae0afc141f00d35ba125fe9b3b8c3a485b95d40c7bf86cdcad5c5e5347b9061e -size 20828 +oid sha256:7bd1d2f677b8714ab6c4a7d6921b60c1b047403b59a1982b5292f70a532fee2d +size 20640 diff --git a/resource/content/shaders/Voxel.fs.geo.spv b/resource/content/shaders/Voxel.fs.geo.spv index 47084c6..762ebb0 100644 --- a/resource/content/shaders/Voxel.fs.geo.spv +++ b/resource/content/shaders/Voxel.fs.geo.spv @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:6a10d61fe025d3d53f5e4cc22e90ec69ec3b64838f268928ca2675d3c0d26297 -size 20908 +oid sha256:7bd1d2f677b8714ab6c4a7d6921b60c1b047403b59a1982b5292f70a532fee2d +size 20640 diff --git a/resource/content/shaders/Voxel.fs.ins.spv b/resource/content/shaders/Voxel.fs.ins.spv index 9ac2d8c..e0992ae 100644 --- a/resource/content/shaders/Voxel.fs.ins.spv +++ b/resource/content/shaders/Voxel.fs.ins.spv @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:25f64f888a26bae6db16da3e75630e29c07ec221a2fc664b3a9383d57092ee1c -size 17716 +oid sha256:2f50de047dcdd53f99c20a86db1c2945c71455112e5e47d9a07aad36f803d31e +size 17528 diff --git a/resource/content/shaders/Voxel.fs.spv b/resource/content/shaders/Voxel.fs.spv index d460d0f..e0992ae 100644 --- a/resource/content/shaders/Voxel.fs.spv +++ b/resource/content/shaders/Voxel.fs.spv @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:1ec14629c4675c4d78187733cfe04dff41706f92a45e27d1373cd0d2f9ee179a -size 17796 +oid sha256:2f50de047dcdd53f99c20a86db1c2945c71455112e5e47d9a07aad36f803d31e +size 17528 diff --git a/resource/content/shaders/Voxel.vs.geo.ins.spv b/resource/content/shaders/Voxel.vs.geo.ins.spv index 4da465b..bb74c08 100644 --- a/resource/content/shaders/Voxel.vs.geo.ins.spv +++ b/resource/content/shaders/Voxel.vs.geo.ins.spv @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:36b8484857b9123797ef404267cf1da90bf8ce8b6a8e3bbae30db2f385f268e7 +oid sha256:3cba8a7d42afcb5d943ccb89b57e5cb25876fc30e5ad879e25f91e391e8990bb size 5716 diff --git a/resource/content/shaders/Voxel.vs.geo.spv b/resource/content/shaders/Voxel.vs.geo.spv index da385fd..33a7bd3 100644 --- a/resource/content/shaders/Voxel.vs.geo.spv +++ b/resource/content/shaders/Voxel.vs.geo.spv @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:430d5380075d8ab8dd3cb78bbc74794b35b6f179c82ab286e63e5f792dac4f4d -size 5824 +oid sha256:3401b8a047bdff2ba0a2a697bf621d7c44b5ca64977a01009e8064603983c21f +size 5840 diff --git a/resource/content/shaders/Voxel.vs.ins.spv b/resource/content/shaders/Voxel.vs.ins.spv index 4da465b..bb74c08 100644 --- a/resource/content/shaders/Voxel.vs.ins.spv +++ b/resource/content/shaders/Voxel.vs.ins.spv @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:36b8484857b9123797ef404267cf1da90bf8ce8b6a8e3bbae30db2f385f268e7 +oid sha256:3cba8a7d42afcb5d943ccb89b57e5cb25876fc30e5ad879e25f91e391e8990bb size 5716 diff --git a/resource/content/shaders/Voxel.vs.spv b/resource/content/shaders/Voxel.vs.spv index da385fd..33a7bd3 100644 --- a/resource/content/shaders/Voxel.vs.spv +++ b/resource/content/shaders/Voxel.vs.spv @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:430d5380075d8ab8dd3cb78bbc74794b35b6f179c82ab286e63e5f792dac4f4d -size 5824 +oid sha256:3401b8a047bdff2ba0a2a697bf621d7c44b5ca64977a01009e8064603983c21f +size 5840 diff --git a/resource/shaders-src/Sky.vert b/resource/shaders-src/Sky.vert index 9b05b98..6b99e2a 100644 --- a/resource/shaders-src/Sky.vert +++ b/resource/shaders-src/Sky.vert @@ -1,9 +1,9 @@ #version 450 core -layout(push_constant) uniform PushConstants { - mat4 View; - mat4 Projection; -} Push; +layout(binding = 0) uniform UniformBufferObject { + mat4 view; + mat4 proj; +} ubo; layout (location = 0) in vec3 Position_modelspace; @@ -11,5 +11,7 @@ layout (location = 0) out vec3 UV; void main(){ UV = Position_modelspace; - gl_Position = (Push.Projection * Push.View * vec4(Position_modelspace, 1.0)).xyww; + mat4 view = ubo.view; + view[3] = vec4(0.0f, 0.0f, 0.0f, 1.0f); + gl_Position = (ubo.proj * view * vec4(Position_modelspace, 1.0)).xyww; } \ No newline at end of file diff --git a/resource/shaders-src/Tris.vert b/resource/shaders-src/Tris.vert index ff0f539..9e36d40 100644 --- a/resource/shaders-src/Tris.vert +++ b/resource/shaders-src/Tris.vert @@ -2,10 +2,12 @@ #extension GL_ARB_separate_shader_objects : enable layout(binding = 0) uniform UniformBufferObject { - mat4 model; mat4 view; mat4 proj; } ubo; +layout(push_constant) uniform PushConst { + mat4 model; +} Push; layout(location = 0) in vec3 inPosition; layout(location = 1) in vec3 inColor; @@ -15,7 +17,7 @@ layout(location = 0) out vec3 fragColor; layout(location = 1) out vec2 fragTexCoord; void main() { - gl_Position = ubo.proj * ubo.view * ubo.model * vec4(inPosition, 1.0); + gl_Position = ubo.proj * ubo.view * Push.model * vec4(inPosition, 1.0); fragColor = inColor; fragTexCoord = inTexCoord; } \ No newline at end of file diff --git a/resource/shaders-src/Voxel.frag b/resource/shaders-src/Voxel.frag index 33c8ef9..de62715 100644 --- a/resource/shaders-src/Voxel.frag +++ b/resource/shaders-src/Voxel.frag @@ -10,26 +10,18 @@ layout (constant_id = 4) const bool BLEND = true; layout (constant_id = 16) const int UNIT_SIZE = 8; layout (binding = 0) uniform UniformBufferObject { - vec3 FogColor; - float FogDepth; + mat4 Proj; + mat4 View; vec3 LightInvDirection_worldspace; + + vec3 FogColor; + float FogDepth; } UBO; layout (binding = 1) uniform sampler2DArray TextureAtlas; layout (binding = 2) uniform sampler2DArray NormalAtlas; layout (binding = 3) uniform sampler2DArray HOSAtlas; -layout(push_constant) uniform PushConstants { - mat4 Proj; - mat4 View; -#ifndef INSTANCED - mat4 Model; -#endif - - vec4 SphereProj; - float Curvature; -} Push; - #ifdef GEOMETRY layout (location = 0) in GeometryData #else @@ -189,7 +181,7 @@ if(PBR) { vec3 TextureAmbientColor = vec3(.1) * TextureDiffuseColor * texHOS.y; vec3 TextureSpecularColor = vec3(.8) * texHOS.z; - vec3 Normal_cameraspace = normalize((Push.View * vec4(worldNormal,0)).xyz); + vec3 Normal_cameraspace = normalize((UBO.View * vec4(worldNormal,0)).xyz); // Light emission properties // You probably want to put them as uniforms diff --git a/resource/shaders-src/Voxel.vert b/resource/shaders-src/Voxel.vert index 2a6fadb..9e9cbb0 100644 --- a/resource/shaders-src/Voxel.vert +++ b/resource/shaders-src/Voxel.vert @@ -8,15 +8,16 @@ layout (constant_id = 5) const bool DO_CURVATURE = false; layout (constant_id = 6) const bool CURV_DEPTH = true; layout (binding = 0) uniform UniformBufferObject { - vec3 FogColor; - float FogDepth; + mat4 Proj; + mat4 View; vec3 LightInvDirection_worldspace; + + vec3 FogColor; + float FogDepth; } UBO; layout(push_constant) uniform PushConstants { - mat4 Proj; //MAYBE: move Proj View to UBO - mat4 View; #ifndef INSTANCED mat4 Model; #endif @@ -63,8 +64,8 @@ if(DO_CURVATURE) { } } - vec4 Position_cameraspace = Push.View * Model * vec4(vs.Position_modelspace, 1); - gl_Position = Push.Proj * Position_cameraspace; + vec4 Position_cameraspace = UBO.View * Model * vec4(vs.Position_modelspace, 1); + gl_Position = UBO.Proj * Position_cameraspace; if(FOG) { vs.Depth = length(Position_cameraspace.xyz) / UBO.FogDepth; @@ -82,6 +83,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 = (Push.View * vec4(UBO.LightInvDirection_worldspace,0)).xyz; + vs.LightDirection_cameraspace = (UBO.View * vec4(UBO.LightInvDirection_worldspace,0)).xyz; } } diff --git a/src/client/Client.cpp b/src/client/Client.cpp index bf41153..6f52055 100644 --- a/src/client/Client.cpp +++ b/src/client/Client.cpp @@ -30,7 +30,6 @@ void Client::run(server_handle* const localHandle) { auto world = world::client::Load(options.connection, localHandle, options.world, options.contouring); state.contouring = world->getContouring(); - //TODO: loop do { window.startFrame(); FrameMark; @@ -131,9 +130,8 @@ void Client::run(server_handle* const localHandle) { { // Chunks const auto pass = pipeline->beginWorldPass(); const auto draw = [&](glm::mat4 model, render::LodModel *const buffer, const contouring::Abstract::area_info &area, const voxel_pos &pos) { - pipeline->setCurvature(glm::vec4(pos, std::get<1>(area)), std::get<2>(area)); reports.models_count++; - reports.tris_count += pass(buffer, model); + reports.tris_count += pass(buffer, model, glm::vec4(pos, std::get<1>(area)), std::get<2>(area)); }; if (options.culling > 0) { std::vector occlusion; @@ -166,9 +164,9 @@ void Client::run(server_handle* const localHandle) { reports.models_count++; reports.tris_count += pipeline->drawIndicatorCube(model); } - pipeline->endPass(); - + pipeline->postProcess(); render::UI::Get()->render(); + pipeline->endFrame(); } { // Swap buffers diff --git a/src/client/control/Camera.cpp b/src/client/control/Camera.cpp index 05239c6..8fdb98b 100644 --- a/src/client/control/Camera.cpp +++ b/src/client/control/Camera.cpp @@ -14,6 +14,7 @@ void Camera::updateProjection() { void Camera::update() { const auto &offset = origin->position.offset; + // FIXME: up inverted after backflip const auto axis = origin->getAxis(); // Camera matrix ViewMatrix = glm::lookAt( diff --git a/src/client/render/Renderer.hpp b/src/client/render/Renderer.hpp index a6c994a..7c3827a 100644 --- a/src/client/render/Renderer.hpp +++ b/src/client/render/Renderer.hpp @@ -64,13 +64,16 @@ public: /// Start new frame and setup virtual void beginFrame() = 0; /// Get started world program - virtual std::function beginWorldPass() = 0; + /// (vertex buffer, model matrix, sphereProj, curvature) + virtual std::function beginWorldPass() = 0; /// Get started entity program virtual std::function &)> beginEntityPass() = 0; /// Draw cube indicator virtual size_t drawIndicatorCube(glm::mat4 model) = 0; /// Apply postprocessing - virtual void endPass() = 0; + virtual void postProcess() = 0; + /// Finalise frame + virtual void endFrame() = 0; /// Swap displayed image virtual void swapBuffer(Window &) = 0; @@ -78,7 +81,6 @@ public: virtual void lookFrom(const Camera &) = 0; virtual void setClearColor(glm::vec4) = 0; - virtual void setCurvature(glm::vec4, float) = 0; virtual void reloadShaders(const passOptions &) = 0; virtual void reloadTextures(const std::string &, float mipMapLOD, float anisotropy) = 0; diff --git a/src/client/render/api/Images.cpp b/src/client/render/api/Images.cpp index 0f34fd1..751ea90 100644 --- a/src/client/render/api/Images.cpp +++ b/src/client/render/api/Images.cpp @@ -3,6 +3,8 @@ using namespace render; std::unique_ptr (*Texture::loadFunc)(const std::string&, const sampling&) = nullptr; +std::unique_ptr (*TextureCube::loadFunc)(const std::array&, const Texture::sampling &) = nullptr; +std::unique_ptr (*TextureArray::loadFunc)(const std::vector&, const Texture::sampling &) = nullptr; #include #include diff --git a/src/client/render/api/Images.hpp b/src/client/render/api/Images.hpp index f0d9557..b72c969 100644 --- a/src/client/render/api/Images.hpp +++ b/src/client/render/api/Images.hpp @@ -73,20 +73,24 @@ public: }; struct requirement: properties { requirement(const properties& props, Layout layout, Usage usage, Aspect aspect, - int samples = 1, bool optimal = true): properties(props), layout(layout), - usage(usage), aspect(aspect), samples(samples), optimal(optimal) + int samples = 1, uint32_t layers = 1, bool cube = false, bool optimal = true): + properties(props), layout(layout), usage(usage), aspect(aspect), samples(samples), + layers(layers), cube(cube), optimal(optimal) { assert(samples > 0 && (std::ceil(std::log2(samples)) == std::floor(std::log2(samples))) && "Samples must be pow2"); + assert(!cube || layers == 6); } Layout layout; Usage usage; Aspect aspect; //NOTE: matches VkSampleCountFlagBits int samples; + uint32_t layers; + bool cube; bool optimal; - static requirement Texture(const properties &props) { - return requirement(props, Layout::SHADER_READ_ONLY, Usage::SAMPLED, Aspect::COLOR); } + static requirement Texture(const properties &props, uint32_t arraySize = 1, bool cube = false) { + return requirement(props, Layout::SHADER_READ_ONLY, Usage::SAMPLED, Aspect::COLOR, 1, arraySize, cube); } }; static std::optional Read(const std::string&, std::vector& data); @@ -120,4 +124,36 @@ public: protected: static std::unique_ptr (*loadFunc)(const std::string&, const sampling&); }; + +/// Const 6 dept image (single textureCube) with sampler +class TextureCube: public Image { +public: + /// Only supports dds files + /// DXT3(BC2) DXT5(BC3) + static _FORCE_INLINE_ std::unique_ptr LoadFromFiles(const std::array &paths, const Texture::sampling &props) { + assert(loadFunc != nullptr && "Uninitialized renderer"); + return loadFunc(paths, props); + } + +protected: + static std::unique_ptr (*loadFunc)(const std::array&, const Texture::sampling&); +}; + +/// Const image array (textureArray) with sampler +class TextureArray: public Image { +public: + /// Only supports dds files + /// DXT3(BC2) DXT5(BC3) + static _FORCE_INLINE_ std::unique_ptr LoadFromFiles(const std::vector &paths, const Texture::sampling &props) { + assert(loadFunc != nullptr && "Uninitialized renderer"); + return loadFunc(paths, props); + } + + constexpr uint32_t getSize() const { return size; } + +protected: + TextureArray(uint32_t size): size(size) { } + uint32_t size; + static std::unique_ptr (*loadFunc)(const std::vector&, const Texture::sampling&); +}; } \ No newline at end of file diff --git a/src/client/render/gl/Renderer.cpp b/src/client/render/gl/Renderer.cpp index 0432d33..c4df42f 100644 --- a/src/client/render/gl/Renderer.cpp +++ b/src/client/render/gl/Renderer.cpp @@ -115,11 +115,11 @@ void Renderer::beginFrame() { glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); } -std::function Renderer::beginWorldPass() { +std::function Renderer::beginWorldPass() { WorldPass->useIt(); WorldPass->start(this); - return [&](render::LodModel *const buf, glm::mat4 model) { - WorldPass->setup(this, model); + return [&](render::LodModel *const buf, glm::mat4 model, glm::vec4 sph, float curv) { + WorldPass->setup(model, sph, curv); return dynamic_cast(buf)->draw(); }; } @@ -128,7 +128,7 @@ std::function &)> Rend EntityPass->useIt(); EntityPass->start(this); return [&](render::Model *const buf, const std::vector &models) { - EntityPass->setup(this, models); + EntityPass->setup(models); return dynamic_cast(buf)->drawInstanced(models.size()); }; } @@ -139,11 +139,12 @@ size_t Renderer::drawIndicatorCube(glm::mat4 model) { return IndicatorCubeBuffer.draw(); } -void Renderer::endPass() { +void Renderer::postProcess() { if(SkyEnable) { SkyPass->draw(this); } } +void Renderer::endFrame() { } void Renderer::swapBuffer(Window& w) { TracyGpuZone("Swap"); @@ -188,7 +189,3 @@ void Renderer::setClearColor(glm::vec4 c) { FogColor = c; glClearColor(c.r, c.g, c.b, c.a); } -void Renderer::setCurvature(glm::vec4 sp, float c) { - SphereProj = sp; - Curvature = c; -} \ No newline at end of file diff --git a/src/client/render/gl/Renderer.hpp b/src/client/render/gl/Renderer.hpp index 607487c..5047ade 100644 --- a/src/client/render/gl/Renderer.hpp +++ b/src/client/render/gl/Renderer.hpp @@ -41,20 +41,14 @@ public: } void beginFrame() override; - std::function beginWorldPass() override; + std::function beginWorldPass() override; std::function&)> beginEntityPass() override; size_t drawIndicatorCube(glm::mat4 model) override; - void endPass() override; + void postProcess() override; + void endFrame() override; void swapBuffer(Window&) override; void setClearColor(glm::vec4) override; - void setCurvature(glm::vec4, float) override; - glm::vec4 getSphereProj() const { - return SphereProj; - } - float getCurvature() const { - return Curvature; - } /// Apply camera matrices void lookFrom(const Camera&) override; @@ -84,12 +78,6 @@ private: GLuint HOSAtlas; GLuint Skybox; - /// Sphere bending - /// offset.xyz radius.w - glm::vec4 SphereProj; - /// Ratio between spherical and cartesian - float Curvature; - /// Draw skybox bool SkyEnable; diff --git a/src/client/render/gl/pass/EntityProgram.cpp b/src/client/render/gl/pass/EntityProgram.cpp index d5fe6d6..e0d5aad 100644 --- a/src/client/render/gl/pass/EntityProgram.cpp +++ b/src/client/render/gl/pass/EntityProgram.cpp @@ -17,9 +17,9 @@ EntityProgram::EntityProgram(const EntityProgram::options &opts) : VoxelProgram( } EntityProgram::~EntityProgram() { } -void EntityProgram::setup(render::gl::Renderer *renderer, const std::vector& modelsMatrices) { +void EntityProgram::setup(const std::vector& modelsMatrices) { setModels(&modelsMatrices[0][0][0], modelsMatrices.size()); - VoxelProgram::setup(renderer); + VoxelProgram::setup(glm::vec4(0), 0); } void EntityProgram::setModels(const GLfloat *matrices, size_t count) { diff --git a/src/client/render/gl/pass/EntityProgram.hpp b/src/client/render/gl/pass/EntityProgram.hpp index f72fd82..64d4c72 100644 --- a/src/client/render/gl/pass/EntityProgram.hpp +++ b/src/client/render/gl/pass/EntityProgram.hpp @@ -11,7 +11,7 @@ namespace pass { static constexpr auto LOCATION = 6; - void setup(render::gl::Renderer *, const std::vector &modelsMatrices); + void setup(const std::vector &modelsMatrices); void disable(); protected: diff --git a/src/client/render/gl/pass/VoxelProgram.cpp b/src/client/render/gl/pass/VoxelProgram.cpp index 894fa17..08400bb 100644 --- a/src/client/render/gl/pass/VoxelProgram.cpp +++ b/src/client/render/gl/pass/VoxelProgram.cpp @@ -62,9 +62,9 @@ void VoxelProgram::start(render::gl::Renderer *renderer) { setView(&renderer->getViewMatrix()[0][0]); setProj(&renderer->getProjectionMatrix()[0][0]); } -void VoxelProgram::setup(render::gl::Renderer *renderer) { - setSphereProj(&renderer->getSphereProj()[0]); - setCurvature(renderer->getCurvature()); +void VoxelProgram::setup(glm::vec4 sphereProj, float curvature) { + setSphereProj(&sphereProj[0]); + setCurvature(curvature); } void VoxelProgram::setProj(const GLfloat *matrix) { diff --git a/src/client/render/gl/pass/VoxelProgram.hpp b/src/client/render/gl/pass/VoxelProgram.hpp index 9d611e3..3061c17 100644 --- a/src/client/render/gl/pass/VoxelProgram.hpp +++ b/src/client/render/gl/pass/VoxelProgram.hpp @@ -14,7 +14,7 @@ namespace pass { void start(render::gl::Renderer *); protected: - void setup(render::gl::Renderer *); + void setup(glm::vec4 sphereProj, float curvature); std::string getName() const override; void setView(const GLfloat *matrix); diff --git a/src/client/render/gl/pass/WorldProgram.cpp b/src/client/render/gl/pass/WorldProgram.cpp index f933ad9..26fbddb 100644 --- a/src/client/render/gl/pass/WorldProgram.cpp +++ b/src/client/render/gl/pass/WorldProgram.cpp @@ -11,9 +11,9 @@ WorldProgram::WorldProgram(const WorldProgram::options& opts): VoxelProgram(opts WorldProgram::~WorldProgram() { } -void WorldProgram::setup(render::gl::Renderer *renderer, glm::mat4 modelMatrix) { +void WorldProgram::setup(glm::mat4 modelMatrix, glm::vec4 sphereProj, float curvature) { setModel(&modelMatrix[0][0]); - VoxelProgram::setup(renderer); + VoxelProgram::setup(sphereProj, curvature); } void WorldProgram::setModel(const GLfloat *matrix) { diff --git a/src/client/render/gl/pass/WorldProgram.hpp b/src/client/render/gl/pass/WorldProgram.hpp index a3e0189..a7c4ec4 100644 --- a/src/client/render/gl/pass/WorldProgram.hpp +++ b/src/client/render/gl/pass/WorldProgram.hpp @@ -9,7 +9,7 @@ namespace pass { WorldProgram(const options &opts); ~WorldProgram(); - void setup(render::gl::Renderer *, glm::mat4 modelMatrix); + void setup(glm::mat4 modelMatrix, glm::vec4 sphereProj, float curvature); protected: void setModel(const GLfloat *matrix); diff --git a/src/client/render/vk/Allocator.cpp b/src/client/render/vk/Allocator.cpp index ab8cfb0..31627a6 100644 --- a/src/client/render/vk/Allocator.cpp +++ b/src/client/render/vk/Allocator.cpp @@ -195,7 +195,7 @@ void Allocator::copyBuffer(VkBuffer src, VkBuffer dst, VkDeviceSize size) { submitCmd(transferBuffer, transferQueue); } -void Allocator::transitionImageLayout(VkImage image, VkFormat format, VkImageLayout oldLayout, VkImageLayout newLayout, uint32_t mipLevels) { +void Allocator::transitionImageLayout(VkImage image, VkFormat format, VkImageLayout oldLayout, VkImageLayout newLayout, uint32_t mipLevels, uint32_t arrayLayers) { beginCmd(graphicsBuffer); VkImageMemoryBarrier barrier{}; @@ -210,7 +210,7 @@ void Allocator::transitionImageLayout(VkImage image, VkFormat format, VkImageLay barrier.subresourceRange.baseMipLevel = 0; barrier.subresourceRange.levelCount = mipLevels; barrier.subresourceRange.baseArrayLayer = 0; - barrier.subresourceRange.layerCount = 1; + barrier.subresourceRange.layerCount = arrayLayers; if (newLayout == VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL) { barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT; @@ -257,7 +257,7 @@ void Allocator::transitionImageLayout(VkImage image, VkFormat format, VkImageLay submitCmd(graphicsBuffer, graphicsQueue); } -void Allocator::copyBufferToImage(VkBuffer src, VkImage dest, uint32_t width, uint32_t height, uint32_t mipLevels) { +void Allocator::copyBufferToImage(VkBuffer src, VkImage dest, uint32_t width, uint32_t height, uint32_t mipLevels, uint32_t arrayLayer) { beginCmd(transferBuffer); @@ -266,7 +266,7 @@ void Allocator::copyBufferToImage(VkBuffer src, VkImage dest, uint32_t width, ui for (size_t i = 0; i < mipLevels; i++) { regions[i].imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; regions[i].imageSubresource.mipLevel = i; - regions[i].imageSubresource.baseArrayLayer = 0; + regions[i].imageSubresource.baseArrayLayer = arrayLayer; regions[i].imageSubresource.layerCount = 1; regions[i].imageOffset = {0, 0, 0}; diff --git a/src/client/render/vk/Allocator.hpp b/src/client/render/vk/Allocator.hpp index daeaac3..03d7ffb 100644 --- a/src/client/render/vk/Allocator.hpp +++ b/src/client/render/vk/Allocator.hpp @@ -37,8 +37,8 @@ public: bool deallocate(const memory::area&); void copyBuffer(VkBuffer src, VkBuffer dst, VkDeviceSize size); - void transitionImageLayout(VkImage image, VkFormat format, VkImageLayout oldLayout, VkImageLayout newLayout, uint32_t mipLevels); - void copyBufferToImage(VkBuffer src, VkImage dst, uint32_t width, uint32_t height, uint32_t mipLevels = 1); + void transitionImageLayout(VkImage image, VkFormat format, VkImageLayout oldLayout, VkImageLayout newLayout, uint32_t mipLevels, uint32_t arrayLayers); + void copyBufferToImage(VkBuffer src, VkImage dst, uint32_t width, uint32_t height, uint32_t mipLevels = 1, uint32_t arrayLayer = 0); void setTracyZone(const char* name); diff --git a/src/client/render/vk/CommandCenter.cpp b/src/client/render/vk/CommandCenter.cpp index e9e98d1..21b0beb 100644 --- a/src/client/render/vk/CommandCenter.cpp +++ b/src/client/render/vk/CommandCenter.cpp @@ -16,24 +16,38 @@ CommandCenter::CommandCenter(VkDevice device, const PhysicalDeviceInfo &info, co VkCommandPoolCreateInfo poolInfo{}; poolInfo.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO; poolInfo.queueFamilyIndex = info.queueIndices.graphicsFamily.value(); - poolInfo.flags = 0; + poolInfo.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT; if (vkCreateCommandPool(device, &poolInfo, ALLOC, &graphicsPool) != VK_SUCCESS) { FATAL("Failed to create graphics pool!"); } } - { // Vertex buffers (const) - modelBuffer = ShortIndexedVertexBuffer::Create(buffer::vk::vertices, buffer::vk::indices); - if (!modelBuffer) { - FATAL("Cannot create vertex buffer"); - } + + modelBuffer = ShortIndexedVertexBuffer::Create(buffer::vk::vertices, buffer::vk::indices); + if (!modelBuffer) { + FATAL("Cannot create vertex buffer"); } - { // Texture sampler (const) - sampleTexture = Texture::LoadFromFile(TEXTURES_DIR "1024-realistic/terrain/Mapl.dds", {true, true, Texture::Wrap::MIRRORED_REPEAT, opt.anisotropy}); - if (!sampleTexture) { - FATAL("Failed to create texture sampler!"); - } + sampleTexture = Texture::LoadFromFile(TEXTURES_DIR + opt.textures + "/terrain/Mapl.dds", {true, true, Texture::Wrap::MIRRORED_REPEAT, opt.anisotropy}); + if (!sampleTexture) { + FATAL("Failed to create texture sampler!"); } + + skyCubeBuffer = Shape::Create({ + {-1.0f, 1.0f, -1.0f}, {-1.0f, -1.0f, -1.0f}, { 1.0f, -1.0f, -1.0f}, { 1.0f, -1.0f, -1.0f}, { 1.0f, 1.0f, -1.0f}, {-1.0f, 1.0f, -1.0f}, + {-1.0f, -1.0f, 1.0f}, {-1.0f, -1.0f, -1.0f}, {-1.0f, 1.0f, -1.0f}, {-1.0f, 1.0f, -1.0f}, {-1.0f, 1.0f, 1.0f}, {-1.0f, -1.0f, 1.0f}, + { 1.0f, -1.0f, -1.0f}, { 1.0f, -1.0f, 1.0f}, { 1.0f, 1.0f, 1.0f}, { 1.0f, 1.0f, 1.0f}, { 1.0f, 1.0f, -1.0f}, { 1.0f, -1.0f, -1.0f}, + {-1.0f, -1.0f, 1.0f}, {-1.0f, 1.0f, 1.0f}, { 1.0f, 1.0f, 1.0f}, { 1.0f, 1.0f, 1.0f}, { 1.0f, -1.0f, 1.0f}, {-1.0f, -1.0f, 1.0f}, + {-1.0f, 1.0f, -1.0f}, { 1.0f, 1.0f, -1.0f}, { 1.0f, 1.0f, 1.0f}, { 1.0f, 1.0f, 1.0f}, {-1.0f, 1.0f, 1.0f}, {-1.0f, 1.0f, -1.0f}, + {-1.0f, -1.0f, -1.0f}, {-1.0f, -1.0f, 1.0f}, { 1.0f, -1.0f, -1.0f}, { 1.0f, -1.0f, -1.0f}, {-1.0f, -1.0f, 1.0f}, { 1.0f, -1.0f, 1.0f} + }); + if (!skyCubeBuffer) { + FATAL("Failed to create vertex buffer!"); + } + skyboxTexture = TextureCube::LoadFromFiles(TEXTURES_DIR + opt.textures + "/sky/Space_tray.cube", {}); + if (!skyboxTexture) { + FATAL("Failed to create texture sampler!"); + } + colorFormat = info.getSurfaceFormat().format; colorSamples = info.samples; LOG_D("Samples: " << colorSamples); @@ -46,12 +60,12 @@ CommandCenter::~CommandCenter() { vkDestroyCommandPool(device, graphicsPool, ALLOC); } #include -void CommandCenter::allocate(const std::vector& views, const Pipeline& pipe, VkExtent2D extent, const renderOptions& opt) { +void CommandCenter::allocate(const std::vector& views, const Pipeline& pipe, VkExtent2D extent) { assert(freed); if (colorSamples > 1) { colorbuffer = Image::Create(Image::requirement({{extent.height, extent.width}, 1, (Image::Format)colorFormat}, - Image::Layout::COLOR_ATTACHMENT, Image::Usage::COLOR_ATTACHMENT | Image::Usage::TRANSIENT_ATTACHMENT, + Image::Layout::COLOR_ATTACHMENT, Image::Usage::COLOR_ATTACHMENT | Image::Usage::TRANSIENT_ATTACHMENT, // NOTE: VulkanTutorial#118 Image::Aspect::COLOR, colorSamples)); } @@ -84,16 +98,14 @@ void CommandCenter::allocate(const std::vector& views, const Pipeli } { // Uniform buffers - VkDeviceSize bufferSize = sizeof(buffer::vk::UniformBufferObject); - std::vector requirements; - requirements.resize(framebuffers.size(), Buffer::requirement(bufferSize, Buffer::Usage::UNIFORM)); + requirements.resize(framebuffers.size(), Buffer::requirement(sizeof(buffer::vk::UniformBufferObject), Buffer::Usage::UNIFORM)); uniformBuffers.allocate(requirements, true); if (!uniformBuffers) { FATAL("Failed to allocate UBO"); } } - { // Descriptor pool + { // Voxel Descriptor pool std::array poolSizes{}; poolSizes[0].type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; poolSizes[0].descriptorCount = framebuffers.size(); @@ -107,24 +119,37 @@ void CommandCenter::allocate(const std::vector& views, const Pipeli poolInfo.maxSets = framebuffers.size(); poolInfo.flags = 0; //VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT - if (vkCreateDescriptorPool(device, &poolInfo, nullptr, &descriptorPool) != VK_SUCCESS) { + if (vkCreateDescriptorPool(device, &poolInfo, nullptr, &voxelDescriptorPool) != VK_SUCCESS) { + FATAL("Failed to create descriptor pool!"); + } + + if (vkCreateDescriptorPool(device, &poolInfo, nullptr, &skyDescriptorPool) != VK_SUCCESS) { FATAL("Failed to create descriptor pool!"); } } { // Descriptor sets - std::vector layouts(framebuffers.size(), pipe.getDescriptorSet()); + std::vector voxLayouts(framebuffers.size(), pipe.getVoxelDescriptorSet()); VkDescriptorSetAllocateInfo allocInfo{}; allocInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO; - allocInfo.descriptorPool = descriptorPool; + allocInfo.descriptorPool = voxelDescriptorPool; allocInfo.descriptorSetCount = framebuffers.size(); - allocInfo.pSetLayouts = layouts.data(); + allocInfo.pSetLayouts = voxLayouts.data(); - descriptorSets.resize(framebuffers.size()); - if (vkAllocateDescriptorSets(device, &allocInfo, descriptorSets.data()) != VK_SUCCESS) { + voxelDescriptorSets.resize(framebuffers.size()); + if (vkAllocateDescriptorSets(device, &allocInfo, voxelDescriptorSets.data()) != VK_SUCCESS) { FATAL("Failed to allocate descriptor sets!"); } - for (size_t i = 0; i < descriptorSets.size(); i++) { + std::vector skyLayouts(framebuffers.size(), pipe.getSkyDescriptorSet()); + allocInfo.descriptorPool = skyDescriptorPool; + allocInfo.pSetLayouts = skyLayouts.data(); + + skyDescriptorSets.resize(framebuffers.size()); + if (vkAllocateDescriptorSets(device, &allocInfo, skyDescriptorSets.data()) != VK_SUCCESS) { + FATAL("Failed to allocate descriptor sets!"); + } + + for (size_t i = 0; i < voxelDescriptorSets.size(); i++) { VkDescriptorBufferInfo bufferInfo{}; bufferInfo.buffer = uniformBuffers.at(i); bufferInfo.offset = 0; @@ -132,7 +157,7 @@ void CommandCenter::allocate(const std::vector& views, const Pipeli std::array descriptorWrites{}; descriptorWrites[0].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; - descriptorWrites[0].dstSet = descriptorSets[i]; + descriptorWrites[0].dstSet = voxelDescriptorSets[i]; descriptorWrites[0].dstBinding = 0; descriptorWrites[0].dstArrayElement = 0; descriptorWrites[0].descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; @@ -140,7 +165,7 @@ void CommandCenter::allocate(const std::vector& views, const Pipeli descriptorWrites[0].pBufferInfo = &bufferInfo; descriptorWrites[1].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; - descriptorWrites[1].dstSet = descriptorSets[i]; + descriptorWrites[1].dstSet = voxelDescriptorSets[i]; descriptorWrites[1].dstBinding = 1; descriptorWrites[1].dstArrayElement = 0; descriptorWrites[1].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; @@ -148,9 +173,13 @@ void CommandCenter::allocate(const std::vector& views, const Pipeli descriptorWrites[1].pImageInfo = &sampleTexture->getDescriptor(); vkUpdateDescriptorSets(device, descriptorWrites.size(), descriptorWrites.data(), 0, nullptr); + + descriptorWrites[0].dstSet = skyDescriptorSets[i]; + descriptorWrites[1].dstSet = skyDescriptorSets[i]; + descriptorWrites[1].pImageInfo = &skyboxTexture->getDescriptor(); + vkUpdateDescriptorSets(device, descriptorWrites.size(), descriptorWrites.data(), 0, nullptr); } } - { graphicsBuffers.resize(framebuffers.size()); VkCommandBufferAllocateInfo allocInfo{}; @@ -164,44 +193,6 @@ void CommandCenter::allocate(const std::vector& views, const Pipeli } } - for (size_t i = 0; i < graphicsBuffers.size(); i++) { - VkCommandBufferBeginInfo beginInfo{}; - beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; - beginInfo.flags = 0; - beginInfo.pInheritanceInfo = nullptr; - - if (vkBeginCommandBuffer(graphicsBuffers[i], &beginInfo) != VK_SUCCESS) { - FATAL("Failed to begin recording command buffer!"); - } - - VkRenderPassBeginInfo renderPassInfo{}; - renderPassInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO; - renderPassInfo.renderPass = pipe.getRenderPass(); - renderPassInfo.framebuffer = framebuffers[i]; - renderPassInfo.renderArea.offset = {0, 0}; - renderPassInfo.renderArea.extent = extent; - - std::array clearValues{}; - clearValues[0].color = {opt.clear_color.x, opt.clear_color.y, opt.clear_color.z, opt.clear_color.a}; - clearValues[1].depthStencil = {1.0f, 0}; - renderPassInfo.clearValueCount = clearValues.size(); - renderPassInfo.pClearValues = clearValues.data(); - - vkCmdBeginRenderPass(graphicsBuffers[i], &renderPassInfo, VK_SUBPASS_CONTENTS_INLINE); - vkCmdBindPipeline(graphicsBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, pipe.getPipeline()); - VkBuffer vertexBuffers[] = {modelBuffer->getVertex()}; - VkDeviceSize offsets[] = {0}; - vkCmdBindVertexBuffers(graphicsBuffers[i], 0, 1, vertexBuffers, offsets); - vkCmdBindIndexBuffer(graphicsBuffers[i], modelBuffer->getIndex(), 0, VK_INDEX_TYPE_UINT16); - vkCmdBindDescriptorSets(graphicsBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, pipe.getLayout(), 0, 1, &descriptorSets[i], 0, nullptr); - vkCmdDrawIndexed(graphicsBuffers[i], static_cast(buffer::vk::indices.size()), 1, 0, 0, 0); - vkCmdEndRenderPass(graphicsBuffers[i]); - - if (vkEndCommandBuffer(graphicsBuffers[i]) != VK_SUCCESS) { - FATAL("Failed to record graphics buffer!"); - } - } - proj = glm::perspectiveZO(glm::radians(45.0f), extent.width / (float) extent.height, 0.1f, 10.0f); proj[1][1] *= -1; @@ -211,13 +202,14 @@ void CommandCenter::free() { assert(!freed); vkFreeCommandBuffers(device, graphicsPool, static_cast(graphicsBuffers.size()), graphicsBuffers.data()); - vkDestroyDescriptorPool(device, descriptorPool, nullptr); + vkDestroyDescriptorPool(device, voxelDescriptorPool, ALLOC); + vkDestroyDescriptorPool(device, skyDescriptorPool, ALLOC); colorbuffer.reset(); depthbuffer.reset(); for (size_t i = 0; i < framebuffers.size(); i++) { - vkDestroyFramebuffer(device, framebuffers[i], nullptr); + vkDestroyFramebuffer(device, framebuffers[i], ALLOC); } freed = true; @@ -226,22 +218,79 @@ void CommandCenter::free() { #include #include -void CommandCenter::updateUBO(uint32_t idx) { +void CommandCenter::startRecording(uint32_t idx, VkRenderPass renderPass, VkExtent2D extent, const glm::vec4& clear_color, glm::mat4 view, glm::mat4 proj) { + buffer::vk::UniformBufferObject ubo{}; + ubo.view = view; + ubo.proj = proj; + uniformBuffers.write(idx, data_view(&ubo, sizeof(ubo))); + + VkCommandBufferBeginInfo beginInfo{}; + beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; + beginInfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT; + //TODO: reuse + beginInfo.pInheritanceInfo = nullptr; + + if (vkBeginCommandBuffer(graphicsBuffers[idx], &beginInfo) != VK_SUCCESS) { + FATAL("Failed to begin recording command buffer!"); + } + + VkRenderPassBeginInfo renderPassInfo{}; + renderPassInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO; + renderPassInfo.renderPass = renderPass; + renderPassInfo.framebuffer = framebuffers[idx]; + renderPassInfo.renderArea.offset = {0, 0}; + renderPassInfo.renderArea.extent = extent; + + std::array clearValues{}; + clearValues[0].color = {clear_color.x, clear_color.y, clear_color.z, clear_color.a}; + clearValues[1].depthStencil = {1.0f, 0}; + renderPassInfo.clearValueCount = clearValues.size(); + renderPassInfo.pClearValues = clearValues.data(); + + vkCmdBeginRenderPass(graphicsBuffers[idx], &renderPassInfo, VK_SUBPASS_CONTENTS_INLINE); +} + +void CommandCenter::startWorldPass(uint32_t idx, const Subpass &worldPass) { + vkCmdBindPipeline(graphicsBuffers[idx], VK_PIPELINE_BIND_POINT_GRAPHICS, worldPass.pipeline); + vkCmdBindDescriptorSets(graphicsBuffers[idx], VK_PIPELINE_BIND_POINT_GRAPHICS, worldPass.layout, 0, 1, &voxelDescriptorSets[idx], 0, nullptr); + static auto startTime = std::chrono::high_resolution_clock::now(); auto currentTime = std::chrono::high_resolution_clock::now(); float time = std::chrono::duration(currentTime - startTime).count(); - buffer::vk::UniformBufferObject ubo{}; - time = 0.1; - ubo.model = glm::rotate(glm::mat4(1.0f), time * glm::radians(90.0f), glm::vec3(0.0f, 0.0f, 1.0f)); - ubo.view = glm::lookAt(glm::vec3(2.0f, 2.0f, 2.0f), glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3(0.0f, 0.0f, 1.0f)); - ubo.proj = proj; - uniformBuffers.write(idx, data_view(&ubo, sizeof(ubo))); + buffer::vk::ModelPush push{}; + push.model = glm::translate(glm::mat4(1.0f), glm::vec3(98.0f, -2.f, -2.f)); + push.model = glm::rotate(push.model, time * glm::radians(90.0f), glm::vec3(0.0f, 0.0f, 1.0f)); + vkCmdPushConstants(graphicsBuffers[idx], worldPass.layout, VK_SHADER_STAGE_VERTEX_BIT, 0, sizeof(push), &push); +} +void CommandCenter::recordModel(uint32_t i) { + VkBuffer vertexBuffers[] = {modelBuffer->getVertex()}; + VkDeviceSize offsets[] = {0}; + vkCmdBindVertexBuffers(graphicsBuffers[i], 0, 1, vertexBuffers, offsets); + vkCmdBindIndexBuffer(graphicsBuffers[i], modelBuffer->getIndex(), 0, VK_INDEX_TYPE_UINT16); + vkCmdDrawIndexed(graphicsBuffers[i], static_cast(buffer::vk::indices.size()), 1, 0, 0, 0); +} +void CommandCenter::startEntityPass(uint32_t) { } +void CommandCenter::recordPostprocess(uint32_t idx, const Subpass& skyPass, bool skybox, glm::mat4, glm::mat4) { + vkCmdNextSubpass(graphicsBuffers[idx], VK_SUBPASS_CONTENTS_INLINE); + if (skybox) { + vkCmdBindPipeline(graphicsBuffers[idx], VK_PIPELINE_BIND_POINT_GRAPHICS, skyPass.pipeline); + vkCmdBindDescriptorSets(graphicsBuffers[idx], VK_PIPELINE_BIND_POINT_GRAPHICS, skyPass.layout, 0, 1, &skyDescriptorSets[idx], 0, nullptr); + VkBuffer vertexBuffers[] = {skyCubeBuffer->getRef()}; + VkDeviceSize offsets[] = {0}; + vkCmdBindVertexBuffers(graphicsBuffers[idx], 0, 1, vertexBuffers, offsets); + vkCmdDraw(graphicsBuffers[idx], skyCubeBuffer->size, 1, 0, 0); + } + vkCmdEndRenderPass(graphicsBuffers[idx]); } void CommandCenter::submitGraphics(uint32_t idx, VkSemaphore waitSemaphore, VkSemaphore signalSemaphore, VkFence submittedFence) { assert(!freed); + if (vkEndCommandBuffer(graphicsBuffers[idx]) != VK_SUCCESS) { + FATAL("Failed to record graphics buffer!"); + } + VkSubmitInfo submitInfo{}; submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; diff --git a/src/client/render/vk/CommandCenter.hpp b/src/client/render/vk/CommandCenter.hpp index a4d7288..73889c5 100644 --- a/src/client/render/vk/CommandCenter.hpp +++ b/src/client/render/vk/CommandCenter.hpp @@ -5,20 +5,27 @@ #include #include "api/Buffers.hpp" #include "api/Images.hpp" +#include "api/Models.hpp" namespace render::vk { class SwapChain; class Pipeline; +struct Subpass; class CommandCenter final { public: CommandCenter(VkDevice, const PhysicalDeviceInfo&, const renderOptions&); ~CommandCenter(); - void updateUBO(uint32_t idx); + void startRecording(uint32_t idx, VkRenderPass, VkExtent2D, const glm::vec4& clear, glm::mat4 view, glm::mat4 proj); + void startWorldPass(uint32_t idx, const Subpass&); + void recordModel(uint32_t idx); + void startEntityPass(uint32_t idx); + //void recordModel(uint32_t idx); + void recordPostprocess(uint32_t idx, const Subpass&, bool skybox, glm::mat4 view, glm::mat4 proj); void submitGraphics(uint32_t, VkSemaphore, VkSemaphore, VkFence); - void allocate(const std::vector&, const Pipeline&, VkExtent2D, const renderOptions&); + void allocate(const std::vector&, const Pipeline&, VkExtent2D); void free(); private: @@ -36,15 +43,19 @@ private: VkCommandPool graphicsPool; std::vector graphicsBuffers; - VkDescriptorPool descriptorPool; - std::vector descriptorSets; + BufferGroup uniformBuffers; + VkDescriptorPool voxelDescriptorPool; + std::vector voxelDescriptorSets; + std::unique_ptr sampleTexture; std::unique_ptr modelBuffer; - std::unique_ptr sampleTexture; + VkDescriptorPool skyDescriptorPool; + std::vector skyDescriptorSets; + std::unique_ptr skyboxTexture; + std::unique_ptr skyCubeBuffer; glm::mat4 proj; - BufferGroup uniformBuffers; bool freed = true; }; diff --git a/src/client/render/vk/Pipeline.cpp b/src/client/render/vk/Pipeline.cpp index 74c9395..1642b26 100644 --- a/src/client/render/vk/Pipeline.cpp +++ b/src/client/render/vk/Pipeline.cpp @@ -4,6 +4,7 @@ #include "../../../core/data/file.hpp" #include "../Renderer.hpp" #include "buffer/VertexData.hpp" +#include "api/Models.hpp" #define CONTENT_DIR "content/" #define SHADER_DIR CONTENT_DIR "shaders/" @@ -58,24 +59,41 @@ Pipeline::Pipeline(VkDevice device, const PhysicalDeviceInfo &info, const render colorAttachmentResolveRef.attachment = 2; colorAttachmentResolveRef.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; - //TODO: subpasses (world, entities, colors, sky, ui) - - VkSubpassDescription subpass{}; - subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS; - subpass.colorAttachmentCount = 1; - subpass.pColorAttachments = &colorAttachmentRef; - subpass.pDepthStencilAttachment = &depthAttachmentRef; + VkSubpassDescription colorDepthSubpass{}; + colorDepthSubpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS; + colorDepthSubpass.colorAttachmentCount = 1; + colorDepthSubpass.pColorAttachments = &colorAttachmentRef; + colorDepthSubpass.pDepthStencilAttachment = &depthAttachmentRef; if (hasSamples) { - subpass.pResolveAttachments = &colorAttachmentResolveRef; + colorDepthSubpass.pResolveAttachments = &colorAttachmentResolveRef; } + std::array subpasses = {colorDepthSubpass, colorDepthSubpass}; - VkSubpassDependency dependency{}; - dependency.srcSubpass = VK_SUBPASS_EXTERNAL; - dependency.dstSubpass = 0; - dependency.srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; - dependency.srcAccessMask = 0; - dependency.dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; - dependency.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; + std::array dependencies{}; + dependencies[0].srcSubpass = VK_SUBPASS_EXTERNAL; + dependencies[0].dstSubpass = 0; + dependencies[0].srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; + dependencies[0].srcAccessMask = 0; + dependencies[0].dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; + dependencies[0].dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; + dependencies[0].dependencyFlags = 0; + + dependencies[1].srcSubpass = 0; + dependencies[1].dstSubpass = 1; + dependencies[1].srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; + dependencies[1].srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; + dependencies[1].dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; + dependencies[1].dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; + dependencies[1].dependencyFlags = VK_DEPENDENCY_BY_REGION_BIT; + + dependencies[2].srcSubpass = 0; + dependencies[2].dstSubpass = 1; + dependencies[2].srcStageMask = VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT; + dependencies[2].srcAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT; + dependencies[2].dstStageMask = VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT; + dependencies[2].dstAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT; + dependencies[2].dependencyFlags = VK_DEPENDENCY_BY_REGION_BIT; + //FIXME: probably needs depth dependency and/or 1->external VkRenderPassCreateInfo renderPassInfo{}; renderPassInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO; @@ -85,16 +103,16 @@ Pipeline::Pipeline(VkDevice device, const PhysicalDeviceInfo &info, const render } renderPassInfo.attachmentCount = attachments.size(); renderPassInfo.pAttachments = attachments.data(); - renderPassInfo.subpassCount = 1; - renderPassInfo.pSubpasses = &subpass; - renderPassInfo.dependencyCount = 1; - renderPassInfo.pDependencies = &dependency; + renderPassInfo.subpassCount = subpasses.size(); + renderPassInfo.pSubpasses = subpasses.data(); + renderPassInfo.dependencyCount = dependencies.size(); + renderPassInfo.pDependencies = dependencies.data(); if (vkCreateRenderPass(device, &renderPassInfo, ALLOC, &renderPass) != VK_SUCCESS) { FATAL("Failed to create render pass!"); } } - { + { // Voxel descriptor VkDescriptorSetLayoutBinding samplerLayoutBinding{}; samplerLayoutBinding.binding = 1; samplerLayoutBinding.descriptorCount = 1; @@ -108,61 +126,172 @@ Pipeline::Pipeline(VkDevice device, const PhysicalDeviceInfo &info, const render layoutInfo.bindingCount = bindings.size(); layoutInfo.pBindings = bindings.data(); - if (vkCreateDescriptorSetLayout(device, &layoutInfo, ALLOC, &descriptorSetLayout) != VK_SUCCESS) { + if (vkCreateDescriptorSetLayout(device, &layoutInfo, ALLOC, &voxelDescriptorSet) != VK_SUCCESS) { FATAL("Failed to create descriptor set layout!"); } } - { - VkPipelineLayoutCreateInfo pipelineLayoutInfo{}; - pipelineLayoutInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO; - pipelineLayoutInfo.setLayoutCount = 1; - pipelineLayoutInfo.pSetLayouts = &descriptorSetLayout; - pipelineLayoutInfo.pushConstantRangeCount = 0; - pipelineLayoutInfo.pPushConstantRanges = nullptr; + { // Sky descriptor + VkDescriptorSetLayoutBinding samplerLayoutBinding{}; + samplerLayoutBinding.binding = 1; + samplerLayoutBinding.descriptorCount = 1; + samplerLayoutBinding.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; + samplerLayoutBinding.pImmutableSamplers = nullptr; + samplerLayoutBinding.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT; - if (vkCreatePipelineLayout(device, &pipelineLayoutInfo, ALLOC, &pipelineLayout) != VK_SUCCESS) { - FATAL("Failed to create pipeline layout!"); + std::vector bindings = {buffer::vk::UniformBufferObject::getLayoutBinding(), samplerLayoutBinding}; + VkDescriptorSetLayoutCreateInfo layoutInfo{}; + layoutInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO; + layoutInfo.bindingCount = bindings.size(); + layoutInfo.pBindings = bindings.data(); + + if (vkCreateDescriptorSetLayout(device, &layoutInfo, ALLOC, &skyDescriptorSet) != VK_SUCCESS) { + FATAL("Failed to create descriptor set layout!"); } } - { // Pipeline - { // Modules - data::file_content vsFile({SHADER_DIR "Tris.vs.spv"}); - data::file_content fsFile({SHADER_DIR "Tris.fs.spv"}); - - auto createShaderModule = [&](const data::file_content &code) { - VkShaderModuleCreateInfo createInfo{}; - createInfo.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO; - createInfo.codeSize = code.size(); - createInfo.pCode = reinterpret_cast(code.data()); - - VkShaderModule shaderModule; - if (vkCreateShaderModule(device, &createInfo, ALLOC, &shaderModule) != VK_SUCCESS) { - FATAL("Failed to create shader module!"); - } - return shaderModule; - }; - - vsShader = createShaderModule(vsFile); - fsShader = createShaderModule(fsFile); - } + // Common pipeline settings + auto setShaders = [&](Subpass &pass, const std::string &shaderName) -> std::vector { + auto createShaderModule = [&](const data::file_content &code) { + VkShaderModuleCreateInfo createInfo{}; + createInfo.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO; + createInfo.codeSize = code.size(); + createInfo.pCode = reinterpret_cast(code.data()); + VkShaderModule shaderModule; + if (vkCreateShaderModule(device, &createInfo, ALLOC, &shaderModule) != VK_SUCCESS) { + FATAL("Failed to create shader module!"); + } + return shaderModule; + }; VkPipelineShaderStageCreateInfo vertShaderStageInfo{}; vertShaderStageInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; vertShaderStageInfo.stage = VK_SHADER_STAGE_VERTEX_BIT; - vertShaderStageInfo.module = vsShader; + data::file_content vsFile({SHADER_DIR + shaderName + ".vs.spv"}); + vertShaderStageInfo.module = pass.vsShader = createShaderModule(vsFile); vertShaderStageInfo.pName = "main"; vertShaderStageInfo.pSpecializationInfo = nullptr; //TODO: pass constants VkPipelineShaderStageCreateInfo fragShaderStageInfo{}; fragShaderStageInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; fragShaderStageInfo.stage = VK_SHADER_STAGE_FRAGMENT_BIT; - fragShaderStageInfo.module = fsShader; + data::file_content fsFile({SHADER_DIR + shaderName + ".fs.spv"}); + fragShaderStageInfo.module = pass.fsShader = createShaderModule(fsFile); fragShaderStageInfo.pName = "main"; fragShaderStageInfo.pSpecializationInfo = nullptr; //TODO: pass constants //TODO: geometry - VkPipelineShaderStageCreateInfo shaderStages[] = {vertShaderStageInfo, fragShaderStageInfo}; + return {vertShaderStageInfo, fragShaderStageInfo}; + }; + auto setLayout = [&](Subpass& pass, const std::vector& layout, const std::vector& push = {}) { + VkPipelineLayoutCreateInfo pipelineLayoutInfo{}; + pipelineLayoutInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO; + pipelineLayoutInfo.setLayoutCount = layout.size(); + pipelineLayoutInfo.pSetLayouts = layout.data(); + pipelineLayoutInfo.pushConstantRangeCount = push.size(); + pipelineLayoutInfo.pPushConstantRanges = push.data(); + + if (vkCreatePipelineLayout(device, &pipelineLayoutInfo, ALLOC, &pass.layout) != VK_SUCCESS) { + FATAL("Failed to create pipeline layout!"); + } + }; + + VkPipelineDepthStencilStateCreateInfo depthStencil{}; + depthStencil.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO; + depthStencil.depthTestEnable = VK_TRUE; + depthStencil.depthWriteEnable = VK_TRUE; + depthStencil.depthCompareOp = VK_COMPARE_OP_LESS; + depthStencil.depthBoundsTestEnable = VK_FALSE; // Restrict sub depth area + depthStencil.minDepthBounds = 0.0f; + depthStencil.maxDepthBounds = 1.0f; + + depthStencil.stencilTestEnable = VK_FALSE; + // Stencil options front/back + + VkPipelineColorBlendAttachmentState colorBlendAttachment{}; + colorBlendAttachment.colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT; + if constexpr (BLENDING) { + colorBlendAttachment.blendEnable = VK_TRUE; + colorBlendAttachment.srcColorBlendFactor = VK_BLEND_FACTOR_SRC_ALPHA; + colorBlendAttachment.dstColorBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA; + colorBlendAttachment.colorBlendOp = VK_BLEND_OP_ADD; + colorBlendAttachment.srcAlphaBlendFactor = VK_BLEND_FACTOR_ONE; + colorBlendAttachment.dstAlphaBlendFactor = VK_BLEND_FACTOR_ZERO; + colorBlendAttachment.alphaBlendOp = VK_BLEND_OP_ADD; + } else { + colorBlendAttachment.blendEnable = VK_FALSE; + } + + VkPipelineColorBlendStateCreateInfo colorBlending{}; + colorBlending.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO; + colorBlending.attachmentCount = 1; //NOTE: For multitarget + colorBlending.pAttachments = &colorBlendAttachment; + colorBlending.logicOpEnable = VK_FALSE; + colorBlending.logicOp = VK_LOGIC_OP_COPY; + colorBlending.blendConstants[0] = 0.0f; + colorBlending.blendConstants[1] = 0.0f; + colorBlending.blendConstants[2] = 0.0f; + colorBlending.blendConstants[3] = 0.0f; + + VkPipelineInputAssemblyStateCreateInfo trisInputAssembly{}; + trisInputAssembly.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO; + trisInputAssembly.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST; + trisInputAssembly.primitiveRestartEnable = VK_FALSE; + + // Viewport + VkViewport viewport{}; + viewport.x = 0.0f; + viewport.y = 0.0f; + viewport.width = (float)info.swapDetails.capabilities.currentExtent.width; + viewport.height = (float)info.swapDetails.capabilities.currentExtent.height; + viewport.minDepth = 0.0f; + viewport.maxDepth = 1.0f; + + VkRect2D scissor{}; + scissor.offset = {0, 0}; + scissor.extent = info.swapDetails.capabilities.currentExtent; + + VkPipelineViewportStateCreateInfo viewportState{}; + viewportState.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO; + viewportState.viewportCount = 1; + viewportState.pViewports = &viewport; + viewportState.scissorCount = 1; + viewportState.pScissors = &scissor; + + VkPipelineRasterizationStateCreateInfo rasterizer{}; + rasterizer.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO; + rasterizer.depthClampEnable = VK_FALSE; + rasterizer.rasterizerDiscardEnable = VK_FALSE; + rasterizer.polygonMode = options.wireframe ? VK_POLYGON_MODE_LINE : VK_POLYGON_MODE_FILL; + rasterizer.lineWidth = 1.0f; + rasterizer.cullMode = VK_CULL_MODE_BACK_BIT; + rasterizer.frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE; + rasterizer.depthBiasEnable = VK_FALSE; + rasterizer.depthBiasConstantFactor = 0.0f; + rasterizer.depthBiasClamp = 0.0f; + rasterizer.depthBiasSlopeFactor = 0.0f; + + VkPipelineMultisampleStateCreateInfo multisampling{}; + multisampling.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO; + multisampling.rasterizationSamples = info.samples; + //MAYBE: add option + multisampling.sampleShadingEnable = info.features.sampleRateShading && hasSamples; + multisampling.minSampleShading = .2f; + multisampling.pSampleMask = nullptr; + multisampling.alphaToCoverageEnable = VK_FALSE; + multisampling.alphaToOneEnable = VK_FALSE; + + { // World pipeline + /*struct Push { + alignas(16) glm::mat4 Model; + alignas(16) glm::vec4 SphereProj; + alignas(4) float Curvature; + };*/ + VkPushConstantRange pushRange{}; + pushRange.offset = 0; + pushRange.size = sizeof(buffer::vk::ModelPush); + pushRange.stageFlags = VK_SHADER_STAGE_VERTEX_BIT; + setLayout(worldPass, {voxelDescriptorSet}, {pushRange}); + auto shaderStages = setShaders(worldPass, "Tris"); VkPipelineVertexInputStateCreateInfo vertexInputInfo{}; vertexInputInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO; @@ -174,108 +303,12 @@ Pipeline::Pipeline(VkDevice device, const PhysicalDeviceInfo &info, const render vertexInputInfo.vertexAttributeDescriptionCount = attributeDescriptions.size(); vertexInputInfo.pVertexAttributeDescriptions = attributeDescriptions.data(); - VkPipelineInputAssemblyStateCreateInfo inputAssembly{}; - inputAssembly.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO; - inputAssembly.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST; - inputAssembly.primitiveRestartEnable = VK_FALSE; - - // Viewport - VkViewport viewport{}; - viewport.x = 0.0f; - viewport.y = 0.0f; - viewport.width = (float)info.swapDetails.capabilities.currentExtent.width; - viewport.height = (float)info.swapDetails.capabilities.currentExtent.height; - viewport.minDepth = 0.0f; - viewport.maxDepth = 1.0f; - - VkRect2D scissor{}; - scissor.offset = {0, 0}; - scissor.extent = info.swapDetails.capabilities.currentExtent; - - VkPipelineViewportStateCreateInfo viewportState{}; - viewportState.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO; - viewportState.viewportCount = 1; - viewportState.pViewports = &viewport; - viewportState.scissorCount = 1; - viewportState.pScissors = &scissor; - - VkPipelineRasterizationStateCreateInfo rasterizer{}; - rasterizer.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO; - rasterizer.depthClampEnable = VK_FALSE; - rasterizer.rasterizerDiscardEnable = VK_FALSE; - rasterizer.polygonMode = options.wireframe ? VK_POLYGON_MODE_LINE : VK_POLYGON_MODE_FILL; - rasterizer.lineWidth = 1.0f; - rasterizer.cullMode = VK_CULL_MODE_BACK_BIT; - rasterizer.frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE; - rasterizer.depthBiasEnable = VK_FALSE; - rasterizer.depthBiasConstantFactor = 0.0f; - rasterizer.depthBiasClamp = 0.0f; - rasterizer.depthBiasSlopeFactor = 0.0f; - - VkPipelineMultisampleStateCreateInfo multisampling{}; - multisampling.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO; - multisampling.rasterizationSamples = info.samples; - //MAYBE: add option - multisampling.sampleShadingEnable = info.features.sampleRateShading && hasSamples; - multisampling.minSampleShading = .2f; - multisampling.pSampleMask = nullptr; - multisampling.alphaToCoverageEnable = VK_FALSE; - multisampling.alphaToOneEnable = VK_FALSE; - - VkPipelineDepthStencilStateCreateInfo depthStencil{}; - depthStencil.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO; - depthStencil.depthTestEnable = VK_TRUE; - depthStencil.depthWriteEnable = VK_TRUE; - depthStencil.depthCompareOp = VK_COMPARE_OP_LESS; //FIXME: LEQUAL for skybox - depthStencil.depthBoundsTestEnable = VK_FALSE; // Restrict sub depth area - depthStencil.minDepthBounds = 0.0f; - depthStencil.maxDepthBounds = 1.0f; - - depthStencil.stencilTestEnable = VK_FALSE; - // Stencil options front/back - - VkPipelineColorBlendAttachmentState colorBlendAttachment{}; - colorBlendAttachment.colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT; - if constexpr (BLENDING) { - colorBlendAttachment.blendEnable = VK_TRUE; - colorBlendAttachment.srcColorBlendFactor = VK_BLEND_FACTOR_SRC_ALPHA; - colorBlendAttachment.dstColorBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA; - colorBlendAttachment.colorBlendOp = VK_BLEND_OP_ADD; - colorBlendAttachment.srcAlphaBlendFactor = VK_BLEND_FACTOR_ONE; - colorBlendAttachment.dstAlphaBlendFactor = VK_BLEND_FACTOR_ZERO; - colorBlendAttachment.alphaBlendOp = VK_BLEND_OP_ADD; - } else { - colorBlendAttachment.blendEnable = VK_FALSE; - } - - VkPipelineColorBlendStateCreateInfo colorBlending{}; - colorBlending.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO; - colorBlending.attachmentCount = 1; //MAYBE: deferred multitarget - colorBlending.pAttachments = &colorBlendAttachment; - colorBlending.logicOpEnable = VK_FALSE; - colorBlending.logicOp = VK_LOGIC_OP_COPY; - colorBlending.blendConstants[0] = 0.0f; - colorBlending.blendConstants[1] = 0.0f; - colorBlending.blendConstants[2] = 0.0f; - colorBlending.blendConstants[3] = 0.0f; - - /* MAYBE: dynamic state - VkDynamicState dynamicStates[] = { - VK_DYNAMIC_STATE_VIEWPORT, - VK_DYNAMIC_STATE_LINE_WIDTH}; - - VkPipelineDynamicStateCreateInfo dynamicState{}; - dynamicState.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO; - dynamicState.dynamicStateCount = 2; - dynamicState.pDynamicStates = dynamicStates; - */ - VkGraphicsPipelineCreateInfo pipelineInfo{}; pipelineInfo.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO; - pipelineInfo.stageCount = 2; - pipelineInfo.pStages = shaderStages; + pipelineInfo.stageCount = shaderStages.size(); + pipelineInfo.pStages = shaderStages.data(); pipelineInfo.pVertexInputState = &vertexInputInfo; - pipelineInfo.pInputAssemblyState = &inputAssembly; + pipelineInfo.pInputAssemblyState = &trisInputAssembly; pipelineInfo.pViewportState = &viewportState; pipelineInfo.pRasterizationState = &rasterizer; pipelineInfo.pMultisampleState = &multisampling; @@ -283,24 +316,73 @@ Pipeline::Pipeline(VkDevice device, const PhysicalDeviceInfo &info, const render pipelineInfo.pColorBlendState = &colorBlending; pipelineInfo.pDynamicState = nullptr; - pipelineInfo.layout = pipelineLayout; + pipelineInfo.layout = worldPass.layout; pipelineInfo.renderPass = renderPass; pipelineInfo.subpass = 0; pipelineInfo.basePipelineHandle = VK_NULL_HANDLE; pipelineInfo.basePipelineIndex = -1; - if (vkCreateGraphicsPipelines(device, VK_NULL_HANDLE, 1, &pipelineInfo, ALLOC, &graphicsPipeline) != VK_SUCCESS) { + if (vkCreateGraphicsPipelines(device, VK_NULL_HANDLE, 1, &pipelineInfo, ALLOC, &worldPass.pipeline) != VK_SUCCESS) { + FATAL("Failed to create graphics pipeline!"); + } + } + { // Sky pipeline + VkPushConstantRange pushRange{}; + pushRange.offset = 0; + pushRange.size = sizeof(buffer::vk::SkyPush); + pushRange.stageFlags = VK_SHADER_STAGE_VERTEX_BIT; + setLayout(skyPass, {skyDescriptorSet}, {pushRange}); + auto shaderStages = setShaders(skyPass, "Sky"); + + depthStencil.depthCompareOp = VK_COMPARE_OP_LESS_OR_EQUAL; + + VkPipelineVertexInputStateCreateInfo vertexInputInfo{}; + vertexInputInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO; + auto bindingDescription = Shape::getBindingDescription(); + vertexInputInfo.vertexBindingDescriptionCount = 1; + vertexInputInfo.pVertexBindingDescriptions = &bindingDescription; + auto attributeDescription = Shape::getAttributeDescription(); + vertexInputInfo.vertexAttributeDescriptionCount = 1; + vertexInputInfo.pVertexAttributeDescriptions = &attributeDescription; + + VkGraphicsPipelineCreateInfo pipelineInfo{}; + pipelineInfo.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO; + pipelineInfo.stageCount = shaderStages.size(); + pipelineInfo.pStages = shaderStages.data(); + pipelineInfo.pVertexInputState = &vertexInputInfo; + pipelineInfo.pInputAssemblyState = &trisInputAssembly; + pipelineInfo.pViewportState = &viewportState; + pipelineInfo.pRasterizationState = &rasterizer; + pipelineInfo.pMultisampleState = &multisampling; + pipelineInfo.pDepthStencilState = &depthStencil; + pipelineInfo.pColorBlendState = &colorBlending; + pipelineInfo.pDynamicState = nullptr; + + pipelineInfo.layout = skyPass.layout; + pipelineInfo.renderPass = renderPass; + pipelineInfo.subpass = 1; + + pipelineInfo.basePipelineHandle = VK_NULL_HANDLE; + pipelineInfo.basePipelineIndex = -1; + + if (vkCreateGraphicsPipelines(device, VK_NULL_HANDLE, 1, &pipelineInfo, ALLOC, &skyPass.pipeline) != VK_SUCCESS) { FATAL("Failed to create graphics pipeline!"); } } } Pipeline::~Pipeline() { - vkDestroyPipeline(device, graphicsPipeline, ALLOC); - vkDestroyPipelineLayout(device, pipelineLayout, ALLOC); - vkDestroyDescriptorSetLayout(device, descriptorSetLayout, ALLOC); - vkDestroyRenderPass(device, renderPass, ALLOC); + auto destroy = [&](Subpass &pass) { + vkDestroyShaderModule(device, pass.fsShader, ALLOC); + vkDestroyShaderModule(device, pass.vsShader, ALLOC); + vkDestroyPipeline(device, pass.pipeline, ALLOC); + vkDestroyPipelineLayout(device, pass.layout, ALLOC); + }; - vkDestroyShaderModule(device, fsShader, ALLOC); - vkDestroyShaderModule(device, vsShader, ALLOC); + destroy(worldPass); + destroy(skyPass); + + vkDestroyDescriptorSetLayout(device, voxelDescriptorSet, ALLOC); + vkDestroyDescriptorSetLayout(device, skyDescriptorSet, ALLOC); + vkDestroyRenderPass(device, renderPass, ALLOC); } \ No newline at end of file diff --git a/src/client/render/vk/Pipeline.hpp b/src/client/render/vk/Pipeline.hpp index 88e8dbd..2a81941 100644 --- a/src/client/render/vk/Pipeline.hpp +++ b/src/client/render/vk/Pipeline.hpp @@ -4,26 +4,36 @@ namespace render::vk { +struct Subpass { + VkShaderModule vsShader; + VkShaderModule fsShader; + VkPipelineLayout layout; + VkPipeline pipeline; +}; + class Pipeline final { public: Pipeline(VkDevice, const PhysicalDeviceInfo&, const renderOptions&); ~Pipeline(); + + // Universe renderpass constexpr VkRenderPass getRenderPass() const { return renderPass; } - constexpr VkPipeline getPipeline() const { return graphicsPipeline; } - constexpr VkPipelineLayout getLayout() const { return pipelineLayout; } - constexpr VkDescriptorSetLayout getDescriptorSet() const { return descriptorSetLayout; } + // Voxels (world & entity) passes descriptor set + constexpr VkDescriptorSetLayout getVoxelDescriptorSet() const { return voxelDescriptorSet; } + constexpr const Subpass& getWorldPass() const { return worldPass; } + constexpr VkDescriptorSetLayout getSkyDescriptorSet() const { return skyDescriptorSet; } + constexpr const Subpass& getSkyPass() const { return skyPass; } private: VkDevice device; - VkShaderModule vsShader; - VkShaderModule fsShader; - VkRenderPass renderPass; - VkDescriptorSetLayout descriptorSetLayout; - VkPipelineLayout pipelineLayout; - VkPipeline graphicsPipeline; -}; + VkDescriptorSetLayout voxelDescriptorSet; + VkDescriptorSetLayout skyDescriptorSet; + + Subpass worldPass; + Subpass skyPass; +}; } \ No newline at end of file diff --git a/src/client/render/vk/Renderer.cpp b/src/client/render/vk/Renderer.cpp index bfaa714..0bd5826 100644 --- a/src/client/render/vk/Renderer.cpp +++ b/src/client/render/vk/Renderer.cpp @@ -2,6 +2,7 @@ #include "UI.hpp" #include "../../Window.hpp" +#include "../../control/Camera.hpp" #include "PhysicalDeviceInfo.hpp" #include "Allocator.hpp" #include "SwapChain.hpp" @@ -34,7 +35,7 @@ Renderer::Renderer(VkInstance instance, VkDevice device, const PhysicalDeviceInf if constexpr(VALIDATION_LAYER) { VkDebugUtilsMessengerCreateInfoEXT createInfo{}; createInfo.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT; - createInfo.messageSeverity = VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT; + createInfo.messageSeverity = VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT; createInfo.messageType = VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT; createInfo.pfnUserCallback = debugValidationCallback; createInfo.pUserData = nullptr; @@ -51,7 +52,7 @@ Renderer::Renderer(VkInstance instance, VkDevice device, const PhysicalDeviceInf swapChain = std::make_unique(device, getInfos()); pipeline = std::make_unique(device, getInfos(), options); commandCenter = std::make_unique(device, getInfos(), options); - commandCenter->allocate(swapChain->getImageViews(), *pipeline.get(), getInfos().swapDetails.capabilities.currentExtent, options); + commandCenter->allocate(swapChain->getImageViews(), *pipeline.get(), getInfos().swapDetails.capabilities.currentExtent); { imageAvailableSemaphores.resize(opt.inFlightFrames); @@ -105,7 +106,7 @@ void Renderer::recreateSwapChain() { set_current_extent(physicalInfo->swapDetails.capabilities, physicalInfo->window); swapChain = std::make_unique(device, getInfos()); pipeline = std::make_unique(device, getInfos(), options); - commandCenter->allocate(swapChain->getImageViews(), *pipeline.get(), getInfos().swapDetails.capabilities.currentExtent, options); + commandCenter->allocate(swapChain->getImageViews(), *pipeline.get(), getInfos().swapDetails.capabilities.currentExtent); } void Renderer::destroySwapChain() { commandCenter->free(); @@ -409,6 +410,8 @@ void Renderer::beginFrame() { if (auto newImage = swapChain->acquireNextImage(imageAvailableSemaphores[currentFrame], inFlightFences[currentFrame])) { currentImage = newImage.value(); + commandCenter->startRecording(currentImage, pipeline->getRenderPass(), + getInfos().swapDetails.capabilities.currentExtent, options.clear_color, ViewMatrix, ProjectionMatrix); allocator->setTracyZone("Submit"); } else { recreateSwapChain(); @@ -416,37 +419,39 @@ void Renderer::beginFrame() { } } -std::function Renderer::beginWorldPass() { +std::function Renderer::beginWorldPass() { assert(currentImage < swapChain->getImageViews().size()); - commandCenter->updateUBO(currentImage); - commandCenter->submitGraphics(currentImage, imageAvailableSemaphores[currentFrame], - renderFinishedSemaphores[currentFrame], inFlightFences[currentFrame]); - /*WorldPass->useIt(); - WorldPass->start(this);*/ - return [&](render::LodModel *const, glm::mat4) { + commandCenter->startWorldPass(currentImage, pipeline->getWorldPass()); + commandCenter->recordModel(currentImage); + return [&](render::LodModel *const, glm::mat4, glm::vec4, float) { return 0; //WorldPass->setup(this, model); }; } std::function &)> Renderer::beginEntityPass() { - /*EntityPass->useIt(); - EntityPass->start(this);*/ + assert(currentImage < swapChain->getImageViews().size()); + + commandCenter->startEntityPass(currentImage); return [&](render::Model *const, const std::vector&) { return 0; //EntityPass->setup(this, models); }; } size_t Renderer::drawIndicatorCube(glm::mat4) { - /*IndicatorPass->useIt(); - return IndicatorCubeBuffer.draw(IndicatorPass->setup(this, model));*/ + assert(currentImage < swapChain->getImageViews().size()); + + //commandCenter->drawIndicator(model); return 0; } -void Renderer::endPass() { - /*if(SkyEnable) { - SkyPass->draw(this); - }*/ +void Renderer::postProcess() { + commandCenter->recordPostprocess(currentImage, pipeline->getSkyPass(), options.skybox, ViewMatrix, ProjectionMatrix); +} + +void Renderer::endFrame() { + commandCenter->submitGraphics(currentImage, imageAvailableSemaphores[currentFrame], + renderFinishedSemaphores[currentFrame], inFlightFences[currentFrame]); } void Renderer::swapBuffer(Window&) { @@ -471,17 +476,13 @@ void Renderer::reloadTextures(const std::string&, float, float) { loadTextures(texturePath, mipMapLOD, anisotropy);*/ } -void Renderer::lookFrom(const Camera&) { - /*ProjectionMatrix = camera.getProjectionMatrix(); +void Renderer::lookFrom(const Camera& camera) { + ProjectionMatrix = camera.getProjectionMatrix(); + ProjectionMatrix[1][1] *= -1; ViewMatrix = camera.getViewMatrix(); - FogDepth = camera.getDepth();*/ + FogDepth = camera.getDepth(); } -void Renderer::setClearColor(glm::vec4) { - /*FogColor = c; - glClearColor(c.r, c.g, c.b, c.a);*/ -} -void Renderer::setCurvature(glm::vec4, float) { - /*SphereProj = sp; - Curvature = c;*/ +void Renderer::setClearColor(glm::vec4 c) { + options.clear_color = c; } \ No newline at end of file diff --git a/src/client/render/vk/Renderer.hpp b/src/client/render/vk/Renderer.hpp index e858592..c851515 100644 --- a/src/client/render/vk/Renderer.hpp +++ b/src/client/render/vk/Renderer.hpp @@ -20,14 +20,14 @@ public: static _FORCE_INLINE_ Renderer *Get() { return static_cast(render::Renderer::Get()); } void beginFrame() override; - std::function beginWorldPass() override; + std::function beginWorldPass() override; std::function &)> beginEntityPass() override; size_t drawIndicatorCube(glm::mat4 model) override; - void endPass() override; - void swapBuffer(Window&) override; + void postProcess() override; + void endFrame() override; + void swapBuffer(Window &) override; void setClearColor(glm::vec4) override; - void setCurvature(glm::vec4, float) override; /// Apply camera matrices void lookFrom(const Camera &) override; @@ -65,5 +65,9 @@ private: bool framebufferResized = false; void recreateSwapChain(); void destroySwapChain(); + + glm::mat4 ProjectionMatrix; + glm::mat4 ViewMatrix; + float FogDepth; }; } \ No newline at end of file diff --git a/src/client/render/vk/api/Buffers.cpp b/src/client/render/vk/api/Buffers.cpp index 6dcdd7e..dc46277 100644 --- a/src/client/render/vk/api/Buffers.cpp +++ b/src/client/render/vk/api/Buffers.cpp @@ -9,7 +9,7 @@ Buffer::~Buffer() { //NOTE: memory_ptr self destroy } -memory::ptr createBuffer(VkDeviceSize size, VkBufferUsageFlags usage, VkMemoryPropertyFlags properties, const render::data_view view, Buffer::info &out) { +memory::ptr render::vk::createBuffer(VkDeviceSize size, VkBufferUsageFlags usage, VkMemoryPropertyFlags properties, const render::data_view view, Buffer::info &out) { auto alloc = Allocator::GetDefault(); auto device = alloc->getDevice(); diff --git a/src/client/render/vk/api/Buffers.hpp b/src/client/render/vk/api/Buffers.hpp index 5e28488..1dfb513 100644 --- a/src/client/render/vk/api/Buffers.hpp +++ b/src/client/render/vk/api/Buffers.hpp @@ -88,4 +88,5 @@ private: memory::ptr memory; }; +memory::ptr createBuffer(VkDeviceSize size, VkBufferUsageFlags usage, VkMemoryPropertyFlags properties, const render::data_view view, Buffer::info &out); } \ No newline at end of file diff --git a/src/client/render/vk/api/Images.cpp b/src/client/render/vk/api/Images.cpp index 49ff48b..f611c05 100644 --- a/src/client/render/vk/api/Images.cpp +++ b/src/client/render/vk/api/Images.cpp @@ -2,6 +2,7 @@ #include "Buffers.hpp" #include "../Allocator.hpp" #include "../../../../core/utils/logger.hpp" +#include using namespace render::vk; @@ -13,7 +14,7 @@ Texture::~Texture() { vkDestroySampler(Allocator::GetDefault()->getDevice(), sampler, ALLOC); } -memory::ptr createImage(const Image::requirement& req, VkMemoryPropertyFlags properties, const render::data_view data, Image::info& out) { +memory::ptr createImage(const Image::requirement& req, VkMemoryPropertyFlags properties, const std::vector& datas, Image::info& out) { auto alloc = Allocator::GetDefault(); auto device = alloc->getDevice(); @@ -24,7 +25,7 @@ memory::ptr createImage(const Image::requirement& req, VkMemoryPropertyFlags pro info.extent.height = req.size.height; info.extent.depth = 1; info.mipLevels = req.mipmapLevels; - info.arrayLayers = 1; + info.arrayLayers = req.layers; info.format = static_cast(req.format); info.tiling = req.optimal ? VK_IMAGE_TILING_OPTIMAL : VK_IMAGE_TILING_LINEAR; info.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; @@ -32,7 +33,13 @@ memory::ptr createImage(const Image::requirement& req, VkMemoryPropertyFlags pro info.sharingMode = VK_SHARING_MODE_EXCLUSIVE; info.samples = static_cast(req.samples); info.flags = 0; - if (data) { + if (req.cube) { + info.flags |= VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT; + } else if (req.layers > 1) { + info.flags |= VK_IMAGE_CREATE_2D_ARRAY_COMPATIBLE_BIT; + } + + if (!datas.empty()) { info.usage |= VK_IMAGE_USAGE_TRANSFER_DST_BIT; } @@ -51,29 +58,46 @@ memory::ptr createImage(const Image::requirement& req, VkMemoryPropertyFlags pro return memory::GetNull(); } - if (data) { - if(auto staging = WritableBuffer::Create(data.size)) { - staging->write(data, 0); - alloc->transitionImageLayout(out.ref, info.format, info.initialLayout, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, req.mipmapLevels); + if (!datas.empty()) { + assert(datas.size() <= req.layers); + const auto maxSize = [&] { + size_t max = 0; + for (auto& data: datas) + max = std::max(max, data.size); + return max; + }(); + if(auto staging = WritableBuffer::Create(maxSize)) { + alloc->transitionImageLayout(out.ref, info.format, info.initialLayout, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, req.mipmapLevels, req.layers); info.initialLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; - alloc->copyBufferToImage(staging->getRef(), out.ref, info.extent.width, info.extent.height, req.mipmapLevels); + for (size_t layer = 0; layer < req.layers && layer < datas.size(); layer++) { + if(datas[layer].isUsable()) { + staging->write(datas[layer], 0); + alloc->copyBufferToImage(staging->getRef(), out.ref, info.extent.width, info.extent.height, req.mipmapLevels, layer); + } + } } else { LOG_E("Cannot allocate staging memory"); return memory::GetNull(); } } - alloc->transitionImageLayout(out.ref, info.format, info.initialLayout, static_cast(req.layout), req.mipmapLevels); + alloc->transitionImageLayout(out.ref, info.format, info.initialLayout, static_cast(req.layout), req.mipmapLevels, req.layers); VkImageViewCreateInfo viewInfo{}; viewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; viewInfo.image = out.ref; - viewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D; + if (req.cube) { + viewInfo.viewType = VK_IMAGE_VIEW_TYPE_CUBE; + } else if (req.layers > 1) { + viewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D_ARRAY; + } else { + viewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D; + } viewInfo.format = static_cast(req.format); viewInfo.subresourceRange.aspectMask = static_cast(req.aspect); viewInfo.subresourceRange.baseMipLevel = 0; viewInfo.subresourceRange.levelCount = req.mipmapLevels; viewInfo.subresourceRange.baseArrayLayer = 0; - viewInfo.subresourceRange.layerCount = 1; + viewInfo.subresourceRange.layerCount = req.layers; if (vkCreateImageView(device, &viewInfo, ALLOC, &out.view) != VK_SUCCESS) { LOG_E("Failed to create texture image view!"); @@ -81,35 +105,17 @@ memory::ptr createImage(const Image::requirement& req, VkMemoryPropertyFlags pro } return memory; } -//TODO: createImages std::unique_ptr Image::Create(const requirement & req) { vk::Image::info img; - auto mem = createImage(req, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, data_view(), img); + auto mem = createImage(req, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, {}, img); if(!mem) { FATAL("Cannot create texture image"); } return std::unique_ptr(new Image(img.ref, img.view, std::move(mem))); } -std::unique_ptr Texture::LoadFromFile(const std::string& path, const sampling& props) { - auto device = Allocator::GetDefault()->getDevice(); - - std::vector data; - auto header = [&] { - if (auto header = render::Image::Read(path, data)) { - return header.value(); - } - FATAL("Cannot read texture"); - }(); - - vk::Image::info img; - auto mem = createImage(requirement::Texture(header), - VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, data, img); - if(!mem) { - FATAL("Cannot create texture image"); - } - +VkSampler createSampler(const Texture::sampling& props, uint32_t mipmapLevels) { VkSamplerCreateInfo samplerInfo{}; samplerInfo.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO; samplerInfo.magFilter = props.magLinear ? VK_FILTER_LINEAR : VK_FILTER_NEAREST; @@ -138,16 +144,108 @@ std::unique_ptr Texture::LoadFromFile(const std::string& path, const sa samplerInfo.mipmapMode = props.minLinear ? VK_SAMPLER_MIPMAP_MODE_LINEAR : VK_SAMPLER_MIPMAP_MODE_NEAREST; samplerInfo.mipLodBias = 0.0f; //TODO: samplerInfo.minLod = 0.0f; - samplerInfo.maxLod = props.mipmap ? header.mipmapLevels : 0.0f; + samplerInfo.maxLod = props.mipmap ? mipmapLevels : 0.0f; - if (props.mipmap && header.mipmapLevels <= 1) { + if (props.mipmap && mipmapLevels <= 1) { LOG_D("Sampler requires mipmap but image does not"); } VkSampler sampler; - if (vkCreateSampler(device, &samplerInfo, ALLOC, &sampler) != VK_SUCCESS) { + if (vkCreateSampler(Allocator::GetDefault()->getDevice(), &samplerInfo, ALLOC, &sampler) != VK_SUCCESS) { FATAL("Failed to create texture sampler!"); } + return sampler; +} - return std::unique_ptr(new Texture(sampler, img.view, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, img.ref, std::move(mem))); +std::unique_ptr Texture::LoadFromFile(const std::string& path, const sampling& props) { + std::vector data; + auto header = [&] { + if (auto header = render::Image::Read(path, data)) { + return header.value(); + } + FATAL("Cannot read texture"); + }(); + + vk::Image::info img; + auto mem = createImage(requirement::Texture(header), + VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, {data}, img); + if(!mem) { + FATAL("Cannot create texture image"); + } + + return std::unique_ptr(new Texture(createSampler(props, header.mipmapLevels), img.view, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, img.ref, std::move(mem))); +} + +std::unique_ptr TextureCube::LoadFromFiles(const std::array& paths, const sampling& props) { + std::vector> datas; + std::vector views; + views.reserve(6); + datas.resize(1); + auto header = [&] { + if (auto header = render::Image::Read(paths.at(0), datas.at(0))) { + views.push_back(datas.at(0)); + return header.value(); + } + FATAL("Cannot read first texture"); + }(); + datas.resize(paths.size()); + for (size_t i = 1; i < paths.size(); i++) { + if(!render::Image::Read(paths.at(i), datas.at(i)).has_value()) { + FATAL("Cannot read depth texture"); + } + views.push_back(datas.at(i)); + } + + vk::Image::info img; + auto mem = createImage(requirement::Texture(header, paths.size(), true), + VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, views, img); + if(!mem) { + FATAL("Cannot create texture cube image"); + } + + return std::unique_ptr(new TextureCube(createSampler(props, header.mipmapLevels), img.view, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, img.ref, std::move(mem))); +} +std::unique_ptr TextureCube::LoadFromFiles(const std::string& prefix, const sampling& props) { + const std::array faces { + "right", + "left", + "top", + "bottom", + "front", + "back" + }; + std::array paths; + std::transform(faces.begin(), faces.end(), paths.begin(), + [prefix](const std::string &face) -> std::string { return prefix + "." + face + ".dds"; }); + return LoadFromFiles(paths, props); +} + +std::unique_ptr TextureArray::LoadFromFiles(const std::vector& paths, const sampling& props) { + std::vector> datas; + std::vector views; + datas.resize(1); + views.reserve(6); + auto header = [&] { + if (auto header = render::Image::Read(paths.at(0), datas.at(0))) { + views.push_back(datas.at(0)); + return header.value(); + } + FATAL("Cannot read first texture"); + }(); + datas.reserve(paths.size()); + for (size_t i = 1; i < paths.size(); i++) { + if(!render::Image::Read(paths.at(i), datas.at(i)).has_value()) { + FATAL("Cannot read depth texture"); + } + views.push_back(datas.at(i)); + } + + vk::Image::info img; + auto mem = createImage(requirement::Texture(header, paths.size()), + VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, views, img); + if(!mem) { + FATAL("Cannot create texture cube image"); + } + + return std::unique_ptr(new TextureArray(paths.size(), createSampler(props, header.mipmapLevels), img.view, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, img.ref, std::move(mem))); } \ No newline at end of file diff --git a/src/client/render/vk/api/Images.hpp b/src/client/render/vk/api/Images.hpp index 13a1990..10f3edf 100644 --- a/src/client/render/vk/api/Images.hpp +++ b/src/client/render/vk/api/Images.hpp @@ -44,4 +44,24 @@ protected: const VkDescriptorImageInfo descriptor; }; +class TextureCube: public render::TextureCube, public Texture { +public: + /// Looks for .right.dds, .left.dds, .top.dds, .bottom.dds, .front.dds, .back.dds + static std::unique_ptr LoadFromFiles(const std::string& prefix, const sampling&); + static std::unique_ptr LoadFromFiles(const std::array& paths, const sampling&); + +protected: + TextureCube(VkSampler sampler, VkImageView view, VkImageLayout layout, VkImage ref, memory::ptr memory): + Texture(sampler, view, layout, ref, std::move(memory)) { } +}; + +class TextureArray: public render::TextureArray, public Texture { +public: + static std::unique_ptr LoadFromFiles(const std::vector&, const sampling&); + +protected: + TextureArray(uint32_t size, VkSampler sampler, VkImageView view, VkImageLayout layout, VkImage ref, memory::ptr memory): + render::TextureArray(size), Texture(sampler, view, layout, ref, std::move(memory)) { } +}; + } \ No newline at end of file diff --git a/src/client/render/vk/api/Models.cpp b/src/client/render/vk/api/Models.cpp new file mode 100644 index 0000000..b33b2a0 --- /dev/null +++ b/src/client/render/vk/api/Models.cpp @@ -0,0 +1,10 @@ +#include "Models.hpp" + +using namespace render::vk; + +std::unique_ptr Shape::Create(const std::vector& vertices) { + vk::Buffer::info tmp; + data_view view(vertices); + auto mem = createBuffer(view.size, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, view, tmp); + return std::unique_ptr(new Shape(tmp.ref, std::move(mem), vertices.size())); +} \ No newline at end of file diff --git a/src/client/render/vk/api/Models.hpp b/src/client/render/vk/api/Models.hpp new file mode 100644 index 0000000..e792802 --- /dev/null +++ b/src/client/render/vk/api/Models.hpp @@ -0,0 +1,81 @@ +#pragma once + +#include "../../api/Models.hpp" +#include "Buffers.hpp" + +namespace render::vk { + +/// Positions only buffer +class Shape final: public Buffer { +public: + const size_t size; + + static std::unique_ptr Create(const std::vector&); + + static VkVertexInputBindingDescription getBindingDescription() { + VkVertexInputBindingDescription description{}; + description.binding = 0; + description.stride = sizeof(glm::vec3); + description.inputRate = VK_VERTEX_INPUT_RATE_VERTEX; + return description; + } + static VkVertexInputAttributeDescription getAttributeDescription() { + VkVertexInputAttributeDescription attributeDescription{}; + attributeDescription.binding = 0; + attributeDescription.location = 0; + attributeDescription.format = VK_FORMAT_R32G32B32_SFLOAT; + attributeDescription.offset = 0; + return attributeDescription; + } + +protected: + Shape(VkBuffer ref, memory::ptr mem, size_t size): + Buffer(ref, std::move(mem)), size(size) { } +}; + +/*class Indicator final: public render::Indicator { +public: + Indicator(const std::vector&, const std::vector&); + ~Indicator(); + + size_t draw(); + size_t drawInstanced(size_t count); + +private: + size_t size; + GLuint vertexBufferId; + GLuint colorBufferId; + + void enableAttribs(); + void disableAttribs(); +}; + +class Model final: public render::Model { +public: + Model(const Data&); + ~Model(); + + size_t draw(); + size_t drawInstanced(size_t count); + +private: + size_t indexSize; + GLuint vertexBufferId; + GLuint indexBufferId; +}; +class LodModel final: public render::LodModel { +public: + LodModel(const LodData&); + ~LodModel(); + + static void MakeDefault(); + + size_t draw(); + size_t drawInstanced(size_t count); + +private: + GLuint vertexBufferId; + GLuint indexBufferId; +};*/ + +} \ No newline at end of file diff --git a/src/client/render/vk/buffer/VertexData.hpp b/src/client/render/vk/buffer/VertexData.hpp index 19b9353..022b218 100644 --- a/src/client/render/vk/buffer/VertexData.hpp +++ b/src/client/render/vk/buffer/VertexData.hpp @@ -54,7 +54,6 @@ const std::vector indices = { }; struct UniformBufferObject { - alignas(16) glm::mat4 model; alignas(16) glm::mat4 view; alignas(16) glm::mat4 proj; @@ -69,4 +68,13 @@ struct UniformBufferObject { } }; +struct ModelPush { + alignas(16) glm::mat4 model; +}; + +struct SkyPush { + alignas(16) glm::mat4 view; + alignas(16) glm::mat4 proj; +}; + } \ No newline at end of file