From 2b33e97dfd764a036862efe3867fd9441c706077 Mon Sep 17 00:00:00 2001 From: Shu Date: Fri, 9 Oct 2020 16:41:24 +0200 Subject: [PATCH] WIP --- src/client/Client.cpp | 8 +- src/client/render/Renderer.hpp | 8 +- src/client/render/api/Images.cpp | 2 + src/client/render/api/Images.hpp | 43 +++++- src/client/render/gl/Renderer.cpp | 15 +- src/client/render/gl/Renderer.hpp | 18 +-- src/client/render/gl/pass/EntityProgram.cpp | 4 +- src/client/render/gl/pass/EntityProgram.hpp | 2 +- src/client/render/gl/pass/VoxelProgram.cpp | 6 +- src/client/render/gl/pass/VoxelProgram.hpp | 2 +- src/client/render/gl/pass/WorldProgram.cpp | 4 +- src/client/render/gl/pass/WorldProgram.hpp | 2 +- src/client/render/vk/Allocator.cpp | 12 +- src/client/render/vk/Allocator.hpp | 4 +- src/client/render/vk/CommandCenter.cpp | 87 ++++++------ src/client/render/vk/CommandCenter.hpp | 13 +- src/client/render/vk/Renderer.cpp | 47 +++---- src/client/render/vk/Renderer.hpp | 8 +- src/client/render/vk/api/Buffers.cpp | 2 +- src/client/render/vk/api/Buffers.hpp | 1 + src/client/render/vk/api/Images.cpp | 148 +++++++++++++++----- src/client/render/vk/api/Images.hpp | 18 +++ src/client/render/vk/api/Models.cpp | 10 ++ src/client/render/vk/api/Models.hpp | 65 +++++++++ 24 files changed, 366 insertions(+), 163 deletions(-) create mode 100644 src/client/render/vk/api/Models.cpp create mode 100644 src/client/render/vk/api/Models.hpp 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/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..281c242 100644 --- a/src/client/render/api/Images.hpp +++ b/src/client/render/api/Images.hpp @@ -73,8 +73,9 @@ 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 depth = 1, uint32_t layers = 1, bool optimal = true): + properties(props), layout(layout), usage(usage), aspect(aspect), samples(samples), + depth(depth), layers(layers), optimal(optimal) { assert(samples > 0 && (std::ceil(std::log2(samples)) == std::floor(std::log2(samples))) && "Samples must be pow2"); } @@ -83,10 +84,12 @@ public: Aspect aspect; //NOTE: matches VkSampleCountFlagBits int samples; + uint32_t depth; + uint32_t layers; 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, bool cube = false, uint32_t arraySize = 1) { + return requirement(props, Layout::SHADER_READ_ONLY, Usage::SAMPLED, Aspect::COLOR, 1, cube ? 6 : 1, arraySize); } }; static std::optional Read(const std::string&, std::vector& data); @@ -120,4 +123,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..386e917 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 depth, uint32_t arrayLayer) { beginCmd(transferBuffer); @@ -266,11 +266,11 @@ 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}; - regions[i].imageExtent = {width >> i, height >> i, 1}; + regions[i].imageOffset = {0, 0, depth+0}; + regions[i].imageExtent = {width >> i, height >> i, depth+1}; regions[i].bufferOffset = offset; regions[i].bufferRowLength = std::max(4, regions[i].imageExtent.width); diff --git a/src/client/render/vk/Allocator.hpp b/src/client/render/vk/Allocator.hpp index daeaac3..5799c5f 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 depth = 0, 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..280e944 100644 --- a/src/client/render/vk/CommandCenter.cpp +++ b/src/client/render/vk/CommandCenter.cpp @@ -46,7 +46,7 @@ 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) { @@ -164,44 +164,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; @@ -226,22 +188,65 @@ void CommandCenter::free() { #include #include -void CommandCenter::updateUBO(uint32_t idx) { +void CommandCenter::startRecording(uint32_t idx) { 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))); + + 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!"); + } +} + +void CommandCenter::startWorldPass(uint32_t idx, const Pipeline &pipe, VkExtent2D extent, const glm::vec4& clear_color) { + VkRenderPassBeginInfo renderPassInfo{}; + renderPassInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO; + renderPassInfo.renderPass = pipe.getRenderPass(); + 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); + vkCmdBindPipeline(graphicsBuffers[idx], VK_PIPELINE_BIND_POINT_GRAPHICS, pipe.getPipeline()); + vkCmdBindDescriptorSets(graphicsBuffers[idx], VK_PIPELINE_BIND_POINT_GRAPHICS, pipe.getLayout(), 0, 1, &descriptorSets[idx], 0, nullptr); +} +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) { + 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..d01b983 100644 --- a/src/client/render/vk/CommandCenter.hpp +++ b/src/client/render/vk/CommandCenter.hpp @@ -5,6 +5,7 @@ #include #include "api/Buffers.hpp" #include "api/Images.hpp" +#include "api/Models.hpp" namespace render::vk { class SwapChain; @@ -15,10 +16,15 @@ public: CommandCenter(VkDevice, const PhysicalDeviceInfo&, const renderOptions&); ~CommandCenter(); - void updateUBO(uint32_t idx); + void startRecording(uint32_t idx); + void startWorldPass(uint32_t idx, const Pipeline &, VkExtent2D, const glm::vec4 &clear); + void recordModel(uint32_t idx); + void startEntityPass(uint32_t idx); + //void recordModel(uint32_t idx); + void recordPostprocess(uint32_t idx); 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: @@ -43,6 +49,9 @@ private: std::unique_ptr sampleTexture; + std::unique_ptr skyboxTexture; + std::unique_ptr skyCubeBuffer; + glm::mat4 proj; BufferGroup uniformBuffers; diff --git a/src/client/render/vk/Renderer.cpp b/src/client/render/vk/Renderer.cpp index bfaa714..f741a69 100644 --- a/src/client/render/vk/Renderer.cpp +++ b/src/client/render/vk/Renderer.cpp @@ -51,7 +51,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 +105,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 +409,7 @@ void Renderer::beginFrame() { if (auto newImage = swapChain->acquireNextImage(imageAvailableSemaphores[currentFrame], inFlightFences[currentFrame])) { currentImage = newImage.value(); + commandCenter->startRecording(currentImage); allocator->setTracyZone("Submit"); } else { recreateSwapChain(); @@ -416,37 +417,40 @@ 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.get(), + getInfos().swapDetails.capabilities.currentExtent, options.clear_color); + 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/*, options.skybox*/); +} + +void Renderer::endFrame() { + commandCenter->submitGraphics(currentImage, imageAvailableSemaphores[currentFrame], + renderFinishedSemaphores[currentFrame], inFlightFences[currentFrame]); } void Renderer::swapBuffer(Window&) { @@ -477,11 +481,6 @@ void Renderer::lookFrom(const Camera&) { 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..a21b39f 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; 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..fb5a8d7 100644 --- a/src/client/render/vk/api/Images.cpp +++ b/src/client/render/vk/api/Images.cpp @@ -13,18 +13,18 @@ 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(); VkImageCreateInfo info{}; info.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO; - info.imageType = VK_IMAGE_TYPE_2D; + info.imageType = req.depth > 1 ? VK_IMAGE_TYPE_3D : VK_IMAGE_TYPE_2D; info.extent.width = req.size.width; info.extent.height = req.size.height; - info.extent.depth = 1; + info.extent.depth = req.depth; 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 +32,7 @@ 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 (!datas.empty()) { info.usage |= VK_IMAGE_USAGE_TRANSFER_DST_BIT; } @@ -51,29 +51,43 @@ 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()) { + 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); + size_t i = 0; + for (size_t layer = 0; layer < req.layers && i < datas.size(); layer++) { + for (size_t depth = 0; depth < req.depth && i < datas.size(); depth++) { + if(datas[i].isUsable()) { + staging->write(datas[i], 0); + alloc->copyBufferToImage(staging->getRef(), out.ref, info.extent.width, info.extent.height, req.mipmapLevels, depth, layer); + } + i++; + }} } 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; + viewInfo.viewType = req.layers > 1 ? VK_IMAGE_VIEW_TYPE_2D_ARRAY : + (req.depth == 6 ? VK_IMAGE_VIEW_TYPE_CUBE : 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 +95,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 +134,94 @@ 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, 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 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, false, 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..5222e5e 100644 --- a/src/client/render/vk/api/Images.hpp +++ b/src/client/render/vk/api/Images.hpp @@ -44,4 +44,22 @@ protected: const VkDescriptorImageInfo descriptor; }; +class TextureCube: public render::TextureCube, Texture { +public: + static std::unique_ptr LoadFromFiles(const std::array&, 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, 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..b250c2a --- /dev/null +++ b/src/client/render/vk/api/Models.hpp @@ -0,0 +1,65 @@ +#pragma once + +#include "../../api/Models.hpp" +#include "Buffers.hpp" + +namespace render::vk { + +/// Positions only buffer +class Shape final: Buffer { +public: + const size_t size; + + static std::unique_ptr Create(const std::vector&); + +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