- move streaming uniform buffers out of VkRenderState

This commit is contained in:
Magnus Norddahl 2019-07-28 16:28:43 +02:00
parent 05cae50612
commit 4adac3fe59
8 changed files with 227 additions and 88 deletions

View file

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

View file

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

View file

@ -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();
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<typename T>
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 (mMatricesOffset + (fb->UniformBufferAlignedSize<MatricesUBO>() << 1) >= fb->MatricesUBO->Size())
if (!fb->MatrixBuffer->Write(mModelMatrix, mModelMatrixEnabled, mTextureMatrix, mTextureMatrixEnabled))
{
WaitForStreamBuffers();
mMatricesOffset += fb->UniformBufferAlignedSize<MatricesUBO>();
memcpy(static_cast<uint8_t*>(fb->MatricesUBO->Memory()) + mMatricesOffset, &mMatrices, sizeof(MatricesUBO));
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 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)

View file

@ -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 @@ protected:
void ApplyVertexBuffers();
void ApplyMaterial();
void WaitForStreamBuffers();
void BeginRenderPass(VulkanCommandBuffer *cmdbuffer);
void WaitForStreamBuffers();
bool mDepthClamp = true;
VulkanCommandBuffer *mCommandBuffer = nullptr;
@ -90,18 +91,14 @@ protected:
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;

View file

@ -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<typename T>
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<StreamUBO>(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<MatricesUBO>(50000), nullptr, false);
}
VkMatrixBuffer::~VkMatrixBuffer()
{
delete UniformBuffer;
}
template<typename T>
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<MatricesUBO>(2) >= UniformBuffer->Size())
return false;
mOffset += UniformBufferAlignedSize<MatricesUBO>(1);
memcpy(static_cast<uint8_t*>(UniformBuffer->Memory()) + mOffset, &mMatrices, sizeof(MatricesUBO));
}
return true;
}
void VkMatrixBuffer::Reset()
{
mOffset = 0;
}

View file

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

View file

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

View file

@ -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 @@ public:
unsigned int GetLightBufferBlockSize() const;
template<typename T>
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;