Skip to content

Commit

Permalink
- avoid creating a new render pass if a pipeline bind will suffice
Browse files Browse the repository at this point in the history
  • Loading branch information
dpjudas committed May 18, 2019
1 parent 9ab19d0 commit 7e37d64
Show file tree
Hide file tree
Showing 4 changed files with 99 additions and 50 deletions.
16 changes: 12 additions & 4 deletions src/rendering/vulkan/renderer/vk_renderpass.cpp
Expand Up @@ -203,7 +203,6 @@ std::unique_ptr<VulkanDescriptorSet> VkRenderPassManager::AllocateTextureDescrip
VkRenderPassSetup::VkRenderPassSetup(const VkRenderPassKey &key)
{
CreateRenderPass(key);
CreatePipeline(key);
}

void VkRenderPassSetup::CreateRenderPass(const VkRenderPassKey &key)
Expand Down Expand Up @@ -258,7 +257,15 @@ void VkRenderPassSetup::CreateRenderPass(const VkRenderPassKey &key)
RenderPass->SetDebugName("VkRenderPassSetup.RenderPass");
}

void VkRenderPassSetup::CreatePipeline(const VkRenderPassKey &key)
VulkanPipeline *VkRenderPassSetup::GetPipeline(const VkPipelineKey &key)
{
auto &item = Pipelines[key];
if (!item)
item = CreatePipeline(key);
return item.get();
}

std::unique_ptr<VulkanPipeline> VkRenderPassSetup::CreatePipeline(const VkPipelineKey &key)
{
auto fb = GetVulkanFrameBuffer();
GraphicsPipelineBuilder builder;
Expand Down Expand Up @@ -348,6 +355,7 @@ void VkRenderPassSetup::CreatePipeline(const VkRenderPassKey &key)

builder.setLayout(fb->GetRenderPassManager()->GetPipelineLayout(key.NumTextureLayers));
builder.setRenderPass(RenderPass.get());
Pipeline = builder.create(fb->device);
Pipeline->SetDebugName("VkRenderPassSetup.Pipeline");
auto pipeline = builder.create(fb->device);
pipeline->SetDebugName("VkRenderPassSetup.Pipeline");
return pipeline;
}
38 changes: 35 additions & 3 deletions src/rendering/vulkan/renderer/vk_renderpass.h
Expand Up @@ -10,7 +10,7 @@

class VKDataBuffer;

class VkRenderPassKey
class VkPipelineKey
{
public:
FRenderStyle RenderStyle;
Expand All @@ -36,6 +36,36 @@ class VkRenderPassKey

bool UsesDepthStencil() const { return DepthTest || DepthWrite || StencilTest || (ClearTargets & (CT_Depth | CT_Stencil)); }

bool operator<(const VkPipelineKey &other) const { return memcmp(this, &other, sizeof(VkPipelineKey)) < 0; }
bool operator==(const VkPipelineKey &other) const { return memcmp(this, &other, sizeof(VkPipelineKey)) == 0; }
bool operator!=(const VkPipelineKey &other) const { return memcmp(this, &other, sizeof(VkPipelineKey)) != 0; }
};

class VkRenderPassKey
{
public:
VkRenderPassKey() = default;
VkRenderPassKey(const VkPipelineKey &key)
{
DepthWrite = key.DepthWrite;
DepthTest = key.DepthTest;
StencilTest = key.StencilTest;
Samples = key.Samples;
ClearTargets = key.ClearTargets;
DrawBuffers = key.DrawBuffers;
DrawBufferFormat = key.DrawBufferFormat;
}

int DepthWrite;
int DepthTest;
int StencilTest;
int Samples;
int ClearTargets;
int DrawBuffers;
VkFormat DrawBufferFormat;

bool UsesDepthStencil() const { return DepthTest || DepthWrite || StencilTest || (ClearTargets & (CT_Depth | CT_Stencil)); }

bool operator<(const VkRenderPassKey &other) const { return memcmp(this, &other, sizeof(VkRenderPassKey)) < 0; }
bool operator==(const VkRenderPassKey &other) const { return memcmp(this, &other, sizeof(VkRenderPassKey)) == 0; }
bool operator!=(const VkRenderPassKey &other) const { return memcmp(this, &other, sizeof(VkRenderPassKey)) != 0; }
Expand All @@ -46,13 +76,15 @@ class VkRenderPassSetup
public:
VkRenderPassSetup(const VkRenderPassKey &key);

VulkanPipeline *GetPipeline(const VkPipelineKey &key);

std::unique_ptr<VulkanRenderPass> RenderPass;
std::unique_ptr<VulkanPipeline> Pipeline;
std::map<VkPipelineKey, std::unique_ptr<VulkanPipeline>> Pipelines;
std::map<VkImageView, std::unique_ptr<VulkanFramebuffer>> Framebuffer;

private:
void CreatePipeline(const VkRenderPassKey &key);
void CreateRenderPass(const VkRenderPassKey &key);
std::unique_ptr<VulkanPipeline> CreatePipeline(const VkPipelineKey &key);
};

class VkVertexFormat
Expand Down
93 changes: 51 additions & 42 deletions src/rendering/vulkan/renderer/vk_renderstate.cpp
Expand Up @@ -196,65 +196,75 @@ void VkRenderState::ApplyDepthBias()
void VkRenderState::ApplyRenderPass(int dt)
{
// Find a render pass that matches our state
VkRenderPassKey passKey;
passKey.ClearTargets = mRenderPassKey.ClearTargets | mClearTargets;
passKey.DrawType = dt;
passKey.VertexFormat = static_cast<VKVertexBuffer*>(mVertexBuffer)->VertexFormat;
passKey.RenderStyle = mRenderStyle;
passKey.DepthTest = mDepthTest;
passKey.DepthWrite = mDepthTest && mDepthWrite;
passKey.DepthFunc = mDepthFunc;
passKey.DepthClamp = mDepthClamp;
passKey.DepthBias = !(mBias.mFactor == 0 && mBias.mUnits == 0);
passKey.StencilTest = mStencilTest;
passKey.StencilPassOp = mStencilOp;
passKey.ColorMask = mColorMask;
passKey.CullMode = mCullMode;
passKey.DrawBufferFormat = mRenderTarget.Format;
passKey.Samples = mRenderTarget.Samples;
passKey.DrawBuffers = mRenderTarget.DrawBuffers;
passKey.NumTextureLayers = mMaterial.mMaterial ? mMaterial.mMaterial->GetLayers() : 0;
VkPipelineKey pipelineKey;
pipelineKey.ClearTargets = mPipelineKey.ClearTargets | mClearTargets;
pipelineKey.DrawType = dt;
pipelineKey.VertexFormat = static_cast<VKVertexBuffer*>(mVertexBuffer)->VertexFormat;
pipelineKey.RenderStyle = mRenderStyle;
pipelineKey.DepthTest = mDepthTest;
pipelineKey.DepthWrite = mDepthTest && mDepthWrite;
pipelineKey.DepthFunc = mDepthFunc;
pipelineKey.DepthClamp = mDepthClamp;
pipelineKey.DepthBias = !(mBias.mFactor == 0 && mBias.mUnits == 0);
pipelineKey.StencilTest = mStencilTest;
pipelineKey.StencilPassOp = mStencilOp;
pipelineKey.ColorMask = mColorMask;
pipelineKey.CullMode = mCullMode;
pipelineKey.DrawBufferFormat = mRenderTarget.Format;
pipelineKey.Samples = mRenderTarget.Samples;
pipelineKey.DrawBuffers = mRenderTarget.DrawBuffers;
pipelineKey.NumTextureLayers = mMaterial.mMaterial ? mMaterial.mMaterial->GetLayers() : 0;
if (mSpecialEffect > EFF_NONE)
{
passKey.SpecialEffect = mSpecialEffect;
passKey.EffectState = 0;
passKey.AlphaTest = false;
pipelineKey.SpecialEffect = mSpecialEffect;
pipelineKey.EffectState = 0;
pipelineKey.AlphaTest = false;
}
else
{
int effectState = mMaterial.mOverrideShader >= 0 ? mMaterial.mOverrideShader : (mMaterial.mMaterial ? mMaterial.mMaterial->GetShaderIndex() : 0);
passKey.SpecialEffect = EFF_NONE;
passKey.EffectState = mTextureEnabled ? effectState : SHADER_NoTexture;
passKey.AlphaTest = mAlphaThreshold >= 0.f;
pipelineKey.SpecialEffect = EFF_NONE;
pipelineKey.EffectState = mTextureEnabled ? effectState : SHADER_NoTexture;
pipelineKey.AlphaTest = mAlphaThreshold >= 0.f;
}

// Is this the one we already have or do we need to change render pass?
bool changingRenderPass = (passKey != mRenderPassKey);
// Is this the one we already have or do we need to change pipeline?
bool changingPipeline = (pipelineKey != mPipelineKey);
bool inRenderPass = mCommandBuffer;

if (!mCommandBuffer)
if (!inRenderPass)
{
mCommandBuffer = GetVulkanFrameBuffer()->GetDrawCommands();
changingRenderPass = true;
changingPipeline = true;
mScissorChanged = true;
mViewportChanged = true;
mStencilRefChanged = true;
mBias.mChanged = true;
}
else if (changingRenderPass)
{
mCommandBuffer->endRenderPass();
}

if (changingRenderPass)
if (changingPipeline)
{
passKey.ClearTargets = mClearTargets;
pipelineKey.ClearTargets = mClearTargets;

// Only clear depth+stencil if the render target actually has that
if (!mRenderTarget.DepthStencil)
passKey.ClearTargets &= ~(CT_Depth | CT_Stencil);
pipelineKey.ClearTargets &= ~(CT_Depth | CT_Stencil);

// Begin new render pass if needed
VkRenderPassKey passKey = pipelineKey;
if (!inRenderPass || passKey != VkRenderPassKey(mPipelineKey))
{
if (inRenderPass)
mCommandBuffer->endRenderPass();

BeginRenderPass(passKey, mCommandBuffer);
}

// Bind the pipeline
VkRenderPassSetup *passSetup = GetVulkanFrameBuffer()->GetRenderPassManager()->GetRenderPass(passKey);
mCommandBuffer->bindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS, passSetup->GetPipeline(pipelineKey));

BeginRenderPass(passKey, mCommandBuffer);
mRenderPassKey = passKey;
mPipelineKey = pipelineKey;
mClearTargets = 0;
}
}
Expand Down Expand Up @@ -385,7 +395,7 @@ void VkRenderState::ApplyPushConstants()

auto fb = GetVulkanFrameBuffer();
auto passManager = fb->GetRenderPassManager();
mCommandBuffer->pushConstants(passManager->GetPipelineLayout(mRenderPassKey.NumTextureLayers), VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, 0, (uint32_t)sizeof(PushConstants), &mPushConstants);
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>
Expand Down Expand Up @@ -471,7 +481,7 @@ void VkRenderState::ApplyMaterial()
{
auto fb = GetVulkanFrameBuffer();
auto passManager = fb->GetRenderPassManager();
mCommandBuffer->bindDescriptorSet(VK_PIPELINE_BIND_POINT_GRAPHICS, passManager->GetPipelineLayout(mRenderPassKey.NumTextureLayers), 1, base->GetDescriptorSet(mMaterial));
mCommandBuffer->bindDescriptorSet(VK_PIPELINE_BIND_POINT_GRAPHICS, passManager->GetPipelineLayout(mPipelineKey.NumTextureLayers), 1, base->GetDescriptorSet(mMaterial));
}

mMaterial.mChanged = false;
Expand All @@ -486,7 +496,7 @@ void VkRenderState::ApplyDynamicSet()
auto passManager = fb->GetRenderPassManager();

uint32_t offsets[3] = { mViewpointOffset, mMatricesOffset, mStreamDataOffset };
mCommandBuffer->bindDescriptorSet(VK_PIPELINE_BIND_POINT_GRAPHICS, passManager->GetPipelineLayout(mRenderPassKey.NumTextureLayers), 0, passManager->DynamicSet.get(), 3, offsets);
mCommandBuffer->bindDescriptorSet(VK_PIPELINE_BIND_POINT_GRAPHICS, passManager->GetPipelineLayout(mPipelineKey.NumTextureLayers), 0, passManager->DynamicSet.get(), 3, offsets);

mLastViewpointOffset = mViewpointOffset;
mLastMatricesOffset = mMatricesOffset;
Expand Down Expand Up @@ -515,7 +525,7 @@ void VkRenderState::EndRenderPass()
{
mCommandBuffer->endRenderPass();
mCommandBuffer = nullptr;
mRenderPassKey = {};
mPipelineKey = {};

mLastViewpointOffset = 0xffffffff;
mLastVertexBuffer = nullptr;
Expand Down Expand Up @@ -588,7 +598,6 @@ void VkRenderState::BeginRenderPass(const VkRenderPassKey &key, VulkanCommandBuf
beginInfo.addClearColor(0.0f, 0.0f, 0.0f, 0.0f);
beginInfo.addClearDepthStencil(1.0f, 0);
cmdbuffer->beginRenderPass(beginInfo);
cmdbuffer->bindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS, passSetup->Pipeline.get());

mMaterial.mChanged = true;
}
Expand Down
2 changes: 1 addition & 1 deletion src/rendering/vulkan/renderer/vk_renderstate.h
Expand Up @@ -66,7 +66,7 @@ class VkRenderState : public FRenderState

bool mDepthClamp = true;
VulkanCommandBuffer *mCommandBuffer = nullptr;
VkRenderPassKey mRenderPassKey = {};
VkPipelineKey mPipelineKey = {};
int mClearTargets = 0;
bool mNeedApply = true;

Expand Down

0 comments on commit 7e37d64

Please sign in to comment.