From 4adac3fe59fac974c6cadd8d81865e87c0078ef6 Mon Sep 17 00:00:00 2001 From: Magnus Norddahl Date: Sun, 28 Jul 2019 16:28:43 +0200 Subject: [PATCH] - move streaming uniform buffers out of VkRenderState --- src/CMakeLists.txt | 1 + .../vulkan/renderer/vk_renderpass.cpp | 4 +- .../vulkan/renderer/vk_renderstate.cpp | 88 +++--------- .../vulkan/renderer/vk_renderstate.h | 9 +- .../vulkan/renderer/vk_streambuffer.cpp | 135 ++++++++++++++++++ .../vulkan/renderer/vk_streambuffer.h | 58 ++++++++ .../vulkan/system/vk_framebuffer.cpp | 11 +- src/rendering/vulkan/system/vk_framebuffer.h | 9 +- 8 files changed, 227 insertions(+), 88 deletions(-) create mode 100644 src/rendering/vulkan/renderer/vk_streambuffer.cpp create mode 100644 src/rendering/vulkan/renderer/vk_streambuffer.h diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 997c7958dfe..3b49c584820 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -920,6 +920,7 @@ set (VULKAN_SOURCES rendering/vulkan/system/vk_buffers.cpp rendering/vulkan/renderer/vk_renderstate.cpp rendering/vulkan/renderer/vk_renderpass.cpp + rendering/vulkan/renderer/vk_streambuffer.cpp rendering/vulkan/renderer/vk_postprocess.cpp rendering/vulkan/renderer/vk_renderbuffers.cpp rendering/vulkan/shaders/vk_shader.cpp diff --git a/src/rendering/vulkan/renderer/vk_renderpass.cpp b/src/rendering/vulkan/renderer/vk_renderpass.cpp index e76b00711af..f773f8527e5 100644 --- a/src/rendering/vulkan/renderer/vk_renderpass.cpp +++ b/src/rendering/vulkan/renderer/vk_renderpass.cpp @@ -173,8 +173,8 @@ void VkRenderPassManager::UpdateDynamicSet() WriteDescriptors update; update.addBuffer(DynamicSet.get(), 0, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, fb->ViewpointUBO->mBuffer.get(), 0, sizeof(HWViewpointUniforms)); update.addBuffer(DynamicSet.get(), 1, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, fb->LightBufferSSO->mBuffer.get()); - update.addBuffer(DynamicSet.get(), 2, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, fb->MatricesUBO->mBuffer.get(), 0, sizeof(MatricesUBO)); - update.addBuffer(DynamicSet.get(), 3, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, fb->StreamUBO->mBuffer.get(), 0, sizeof(StreamUBO)); + update.addBuffer(DynamicSet.get(), 2, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, fb->MatrixBuffer->UniformBuffer->mBuffer.get(), 0, sizeof(MatricesUBO)); + update.addBuffer(DynamicSet.get(), 3, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, fb->StreamBuffer->UniformBuffer->mBuffer.get(), 0, sizeof(StreamUBO)); update.addCombinedImageSampler(DynamicSet.get(), 4, fb->GetBuffers()->Shadowmap.View.get(), fb->GetBuffers()->ShadowmapSampler.get(), VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); update.updateSets(fb->device); } diff --git a/src/rendering/vulkan/renderer/vk_renderstate.cpp b/src/rendering/vulkan/renderer/vk_renderstate.cpp index 07425ad08df..2f55fee24ab 100644 --- a/src/rendering/vulkan/renderer/vk_renderstate.cpp +++ b/src/rendering/vulkan/renderer/vk_renderstate.cpp @@ -21,7 +21,6 @@ CVAR(Int, vk_submit_size, 1000, 0); VkRenderState::VkRenderState() { - mIdentityMatrix.loadIdentity(); Reset(); } @@ -322,17 +321,11 @@ void VkRenderState::ApplyStreamData() else mStreamData.timer = 0.0f; - mDataIndex++; - if (mDataIndex == MAX_STREAM_DATA) + if (!mStreamBufferWriter.Write(mStreamData)) { - mDataIndex = 0; - mStreamDataOffset += sizeof(StreamUBO); - - if (mStreamDataOffset + sizeof(StreamUBO) >= fb->StreamUBO->Size()) - WaitForStreamBuffers(); + WaitForStreamBuffers(); + mStreamBufferWriter.Write(mStreamData); } - uint8_t *ptr = (uint8_t*)fb->StreamUBO->Memory(); - memcpy(ptr + mStreamDataOffset + sizeof(StreamData) * mDataIndex, &mStreamData, sizeof(StreamData)); } void VkRenderState::ApplyPushConstants() @@ -371,63 +364,20 @@ void VkRenderState::ApplyPushConstants() mPushConstants.uSpecularMaterial = { mMaterial.mMaterial->tex->Glossiness, mMaterial.mMaterial->tex->SpecularLevel }; mPushConstants.uLightIndex = mLightIndex; - mPushConstants.uDataIndex = mDataIndex; + mPushConstants.uDataIndex = mStreamBufferWriter.DataIndex(); auto fb = GetVulkanFrameBuffer(); auto passManager = fb->GetRenderPassManager(); mCommandBuffer->pushConstants(passManager->GetPipelineLayout(mPipelineKey.NumTextureLayers), VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, 0, (uint32_t)sizeof(PushConstants), &mPushConstants); } -template -static void BufferedSet(bool &modified, T &dst, const T &src) -{ - if (dst == src) - return; - dst = src; - modified = true; -} - -static void BufferedSet(bool &modified, VSMatrix &dst, const VSMatrix &src) -{ - if (memcmp(dst.get(), src.get(), sizeof(FLOATTYPE) * 16) == 0) - return; - dst = src; - modified = true; -} - void VkRenderState::ApplyMatrices() { - bool modified = (mMatricesOffset == 0); // always modified first call - if (mTextureMatrixEnabled) - { - BufferedSet(modified, mMatrices.TextureMatrix, mTextureMatrix); - } - else - { - BufferedSet(modified, mMatrices.TextureMatrix, mIdentityMatrix); - } - - if (mModelMatrixEnabled) - { - BufferedSet(modified, mMatrices.ModelMatrix, mModelMatrix); - if (modified) - mMatrices.NormalModelMatrix.computeNormalMatrix(mModelMatrix); - } - else - { - BufferedSet(modified, mMatrices.ModelMatrix, mIdentityMatrix); - BufferedSet(modified, mMatrices.NormalModelMatrix, mIdentityMatrix); - } - - if (modified) + auto fb = GetVulkanFrameBuffer(); + if (!fb->MatrixBuffer->Write(mModelMatrix, mModelMatrixEnabled, mTextureMatrix, mTextureMatrixEnabled)) { - auto fb = GetVulkanFrameBuffer(); - - if (mMatricesOffset + (fb->UniformBufferAlignedSize() << 1) >= fb->MatricesUBO->Size()) - WaitForStreamBuffers(); - - mMatricesOffset += fb->UniformBufferAlignedSize(); - memcpy(static_cast(fb->MatricesUBO->Memory()) + mMatricesOffset, &mMatrices, sizeof(MatricesUBO)); + WaitForStreamBuffers(); + fb->MatrixBuffer->Write(mModelMatrix, mModelMatrixEnabled, mTextureMatrix, mTextureMatrixEnabled); } } @@ -470,17 +420,19 @@ void VkRenderState::ApplyMaterial() void VkRenderState::ApplyDynamicSet() { - if (mViewpointOffset != mLastViewpointOffset || mMatricesOffset != mLastMatricesOffset || mStreamDataOffset != mLastStreamDataOffset) + auto fb = GetVulkanFrameBuffer(); + uint32_t matrixOffset = fb->MatrixBuffer->Offset(); + uint32_t streamDataOffset = mStreamBufferWriter.StreamDataOffset(); + if (mViewpointOffset != mLastViewpointOffset || matrixOffset != mLastMatricesOffset || streamDataOffset != mLastStreamDataOffset) { - auto fb = GetVulkanFrameBuffer(); auto passManager = fb->GetRenderPassManager(); - uint32_t offsets[3] = { mViewpointOffset, mMatricesOffset, mStreamDataOffset }; + uint32_t offsets[3] = { mViewpointOffset, matrixOffset, streamDataOffset }; mCommandBuffer->bindDescriptorSet(VK_PIPELINE_BIND_POINT_GRAPHICS, passManager->GetPipelineLayout(mPipelineKey.NumTextureLayers), 0, passManager->DynamicSet.get(), 3, offsets); mLastViewpointOffset = mViewpointOffset; - mLastMatricesOffset = mMatricesOffset; - mLastStreamDataOffset = mStreamDataOffset; + mLastMatricesOffset = matrixOffset; + mLastStreamDataOffset = streamDataOffset; } } @@ -489,9 +441,8 @@ void VkRenderState::WaitForStreamBuffers() EndRenderPass(); GetVulkanFrameBuffer()->WaitForCommands(false); mApplyCount = 0; - mStreamDataOffset = 0; - mDataIndex = 0; - mMatricesOffset = 0; + mStreamBufferWriter.Reset(); + GetVulkanFrameBuffer()->MatrixBuffer->Reset(); } void VkRenderState::Bind(int bindingpoint, uint32_t offset) @@ -527,9 +478,8 @@ void VkRenderState::EndRenderPass() void VkRenderState::EndFrame() { - mMatricesOffset = 0; - mStreamDataOffset = 0; - mDataIndex = -1; + GetVulkanFrameBuffer()->MatrixBuffer->Reset(); + mStreamBufferWriter.Reset(); } void VkRenderState::EnableDrawBuffers(int count) diff --git a/src/rendering/vulkan/renderer/vk_renderstate.h b/src/rendering/vulkan/renderer/vk_renderstate.h index 6848d15a57b..58582e0b05d 100644 --- a/src/rendering/vulkan/renderer/vk_renderstate.h +++ b/src/rendering/vulkan/renderer/vk_renderstate.h @@ -4,6 +4,7 @@ #include "vulkan/system/vk_buffers.h" #include "vulkan/shaders/vk_shader.h" #include "vulkan/renderer/vk_renderpass.h" +#include "vulkan/renderer/vk_streambuffer.h" #include "name.h" @@ -63,8 +64,8 @@ class VkRenderState : public FRenderState void ApplyVertexBuffers(); void ApplyMaterial(); - void WaitForStreamBuffers(); void BeginRenderPass(VulkanCommandBuffer *cmdbuffer); + void WaitForStreamBuffers(); bool mDepthClamp = true; VulkanCommandBuffer *mCommandBuffer = nullptr; @@ -90,18 +91,14 @@ class VkRenderState : public FRenderState int mColorMask = 15; int mCullMode = 0; - MatricesUBO mMatrices = {}; PushConstants mPushConstants = {}; uint32_t mLastViewpointOffset = 0xffffffff; uint32_t mLastMatricesOffset = 0xffffffff; uint32_t mLastStreamDataOffset = 0xffffffff; uint32_t mViewpointOffset = 0; - uint32_t mMatricesOffset = 0; - uint32_t mDataIndex = -1; - uint32_t mStreamDataOffset = 0; - VSMatrix mIdentityMatrix; + VkStreamBufferWriter mStreamBufferWriter; int mLastVertexOffsets[2] = { 0, 0 }; IVertexBuffer *mLastVertexBuffer = nullptr; diff --git a/src/rendering/vulkan/renderer/vk_streambuffer.cpp b/src/rendering/vulkan/renderer/vk_streambuffer.cpp new file mode 100644 index 00000000000..b8377ba403f --- /dev/null +++ b/src/rendering/vulkan/renderer/vk_streambuffer.cpp @@ -0,0 +1,135 @@ + +#include "vk_renderstate.h" +#include "vulkan/system/vk_framebuffer.h" +#include "vulkan/system/vk_builders.h" +#include "vulkan/renderer/vk_streambuffer.h" + +template +int UniformBufferAlignedSize(int count) { return ((sizeof(T) + screen->uniformblockalignment - 1) / screen->uniformblockalignment * screen->uniformblockalignment) * count; } + +VkStreamBuffer::VkStreamBuffer() +{ + auto fb = GetVulkanFrameBuffer(); + UniformBuffer = (VKDataBuffer*)fb->CreateDataBuffer(-1, false, false); + UniformBuffer->SetData(UniformBufferAlignedSize(200), nullptr, false); +} + +VkStreamBuffer::~VkStreamBuffer() +{ + delete UniformBuffer; +} + +uint32_t VkStreamBuffer::NextStreamDataBlock() +{ + mStreamDataOffset += sizeof(StreamUBO); + if (mStreamDataOffset + sizeof(StreamUBO) >= UniformBuffer->Size()) + { + mStreamDataOffset = 0; + return 0xffffffff; + } + return mStreamDataOffset; +} + +///////////////////////////////////////////////////////////////////////////// + +VkStreamBufferWriter::VkStreamBufferWriter() +{ + mBuffer = GetVulkanFrameBuffer()->StreamBuffer; +} + +bool VkStreamBufferWriter::Write(const StreamData& data) +{ + mDataIndex++; + if (mDataIndex == MAX_STREAM_DATA) + { + mDataIndex = 0; + mStreamDataOffset = mBuffer->NextStreamDataBlock(); + if (mStreamDataOffset == 0xffffffff) + return false; + } + uint8_t* ptr = (uint8_t*)mBuffer->UniformBuffer->Memory(); + memcpy(ptr + mStreamDataOffset + sizeof(StreamData) * mDataIndex, &data, sizeof(StreamData)); + return true; +} + +void VkStreamBufferWriter::Reset() +{ + mDataIndex = MAX_STREAM_DATA - 1; + mStreamDataOffset = 0; + mBuffer->Reset(); +} + +///////////////////////////////////////////////////////////////////////////// + +VkMatrixBuffer::VkMatrixBuffer() +{ + mIdentityMatrix.loadIdentity(); + + auto fb = GetVulkanFrameBuffer(); + UniformBuffer = (VKDataBuffer*)fb->CreateDataBuffer(-1, false, false); + UniformBuffer->SetData(UniformBufferAlignedSize(50000), nullptr, false); +} + +VkMatrixBuffer::~VkMatrixBuffer() +{ + delete UniformBuffer; +} + +template +static void BufferedSet(bool& modified, T& dst, const T& src) +{ + if (dst == src) + return; + dst = src; + modified = true; +} + +static void BufferedSet(bool& modified, VSMatrix& dst, const VSMatrix& src) +{ + if (memcmp(dst.get(), src.get(), sizeof(FLOATTYPE) * 16) == 0) + return; + dst = src; + modified = true; +} + +bool VkMatrixBuffer::Write(const VSMatrix& modelMatrix, bool modelMatrixEnabled, const VSMatrix& textureMatrix, bool textureMatrixEnabled) +{ + bool modified = (mOffset == 0); // always modified first call + + if (modelMatrixEnabled) + { + BufferedSet(modified, mMatrices.ModelMatrix, modelMatrix); + if (modified) + mMatrices.NormalModelMatrix.computeNormalMatrix(modelMatrix); + } + else + { + BufferedSet(modified, mMatrices.ModelMatrix, mIdentityMatrix); + BufferedSet(modified, mMatrices.NormalModelMatrix, mIdentityMatrix); + } + + if (textureMatrixEnabled) + { + BufferedSet(modified, mMatrices.TextureMatrix, textureMatrixEnabled); + } + else + { + BufferedSet(modified, mMatrices.TextureMatrix, mIdentityMatrix); + } + + if (modified) + { + if (mOffset + (size_t)UniformBufferAlignedSize(2) >= UniformBuffer->Size()) + return false; + + mOffset += UniformBufferAlignedSize(1); + memcpy(static_cast(UniformBuffer->Memory()) + mOffset, &mMatrices, sizeof(MatricesUBO)); + } + + return true; +} + +void VkMatrixBuffer::Reset() +{ + mOffset = 0; +} diff --git a/src/rendering/vulkan/renderer/vk_streambuffer.h b/src/rendering/vulkan/renderer/vk_streambuffer.h new file mode 100644 index 00000000000..da1a5bf836a --- /dev/null +++ b/src/rendering/vulkan/renderer/vk_streambuffer.h @@ -0,0 +1,58 @@ + +#pragma once + +#include "vulkan/system/vk_buffers.h" +#include "vulkan/shaders/vk_shader.h" + +class VkStreamBuffer; + +class VkStreamBufferWriter +{ +public: + VkStreamBufferWriter(); + + bool Write(const StreamData& data); + void Reset(); + + uint32_t DataIndex() const { return mDataIndex; } + uint32_t StreamDataOffset() const { return mStreamDataOffset; } + +private: + VkStreamBuffer* mBuffer; + uint32_t mDataIndex = MAX_STREAM_DATA - 1; + uint32_t mStreamDataOffset = 0; +}; + +class VkStreamBuffer +{ +public: + VkStreamBuffer(); + ~VkStreamBuffer(); + + uint32_t NextStreamDataBlock(); + void Reset() { mStreamDataOffset = 0; } + + VKDataBuffer* UniformBuffer = nullptr; + +private: + uint32_t mStreamDataOffset = 0; +}; + +class VkMatrixBuffer +{ +public: + VkMatrixBuffer(); + ~VkMatrixBuffer(); + + bool Write(const VSMatrix &modelMatrix, bool modelMatrixEnabled, const VSMatrix& textureMatrix, bool textureMatrixEnabled); + void Reset(); + + uint32_t Offset() const { return mOffset; } + + VKDataBuffer* UniformBuffer = nullptr; + +private: + MatricesUBO mMatrices = {}; + VSMatrix mIdentityMatrix; + uint32_t mOffset = 0; +}; diff --git a/src/rendering/vulkan/system/vk_framebuffer.cpp b/src/rendering/vulkan/system/vk_framebuffer.cpp index 17610145c1e..5b36207e161 100644 --- a/src/rendering/vulkan/system/vk_framebuffer.cpp +++ b/src/rendering/vulkan/system/vk_framebuffer.cpp @@ -50,6 +50,7 @@ #include "vk_buffers.h" #include "vulkan/renderer/vk_renderstate.h" #include "vulkan/renderer/vk_renderpass.h" +#include "vulkan/renderer/vk_streambuffer.h" #include "vulkan/renderer/vk_postprocess.h" #include "vulkan/renderer/vk_renderbuffers.h" #include "vulkan/shaders/vk_shader.h" @@ -106,8 +107,8 @@ VulkanFrameBuffer::~VulkanFrameBuffer() VKBuffer::ResetAll(); PPResource::ResetAll(); - delete MatricesUBO; - delete StreamUBO; + delete MatrixBuffer; + delete StreamBuffer; delete mVertexData; delete mSkyData; delete mViewpoints; @@ -158,10 +159,8 @@ void VulkanFrameBuffer::InitializeState() CreateFanToTrisIndexBuffer(); // To do: move this to HW renderer interface maybe? - MatricesUBO = (VKDataBuffer*)CreateDataBuffer(-1, false, false); - StreamUBO = (VKDataBuffer*)CreateDataBuffer(-1, false, false); - MatricesUBO->SetData(UniformBufferAlignedSize<::MatricesUBO>() * 50000, nullptr, false); - StreamUBO->SetData(UniformBufferAlignedSize<::StreamUBO>() * 200, nullptr, false); + MatrixBuffer = new VkMatrixBuffer(); + StreamBuffer = new VkStreamBuffer(); mShaderManager.reset(new VkShaderManager(device)); mSamplerManager.reset(new VkSamplerManager(device)); diff --git a/src/rendering/vulkan/system/vk_framebuffer.h b/src/rendering/vulkan/system/vk_framebuffer.h index 9010b8d6b9b..b157bd1008a 100644 --- a/src/rendering/vulkan/system/vk_framebuffer.h +++ b/src/rendering/vulkan/system/vk_framebuffer.h @@ -9,6 +9,8 @@ class VkSamplerManager; class VkShaderManager; class VkRenderPassManager; class VkRenderState; +class VkStreamBuffer; +class VkMatrixBuffer; class VKDataBuffer; class VkHardwareTexture; class VkRenderBuffers; @@ -38,13 +40,10 @@ class VulkanFrameBuffer : public SystemBaseFrameBuffer unsigned int GetLightBufferBlockSize() const; - template - int UniformBufferAlignedSize() const { return (sizeof(T) + uniformblockalignment - 1) / uniformblockalignment * uniformblockalignment; } - VKDataBuffer *ViewpointUBO = nullptr; VKDataBuffer *LightBufferSSO = nullptr; - VKDataBuffer *MatricesUBO = nullptr; - VKDataBuffer *StreamUBO = nullptr; + VkMatrixBuffer *MatrixBuffer = nullptr; + VkStreamBuffer *StreamBuffer = nullptr; VKDataBuffer *LightNodes = nullptr; VKDataBuffer *LightLines = nullptr;