Skip to content

Commit

Permalink
- use one render pass for the entire scene or until postprocess or co…
Browse files Browse the repository at this point in the history
…mmand buffer flushing forces it to end
  • Loading branch information
dpjudas committed May 18, 2019
1 parent 7e37d64 commit 680a6f3
Show file tree
Hide file tree
Showing 4 changed files with 59 additions and 84 deletions.
51 changes: 29 additions & 22 deletions src/rendering/vulkan/renderer/vk_renderpass.cpp
Expand Up @@ -200,12 +200,11 @@ std::unique_ptr<VulkanDescriptorSet> VkRenderPassManager::AllocateTextureDescrip

/////////////////////////////////////////////////////////////////////////////

VkRenderPassSetup::VkRenderPassSetup(const VkRenderPassKey &key)
VkRenderPassSetup::VkRenderPassSetup(const VkRenderPassKey &key) : PassKey(key)
{
CreateRenderPass(key);
}

void VkRenderPassSetup::CreateRenderPass(const VkRenderPassKey &key)
std::unique_ptr<VulkanRenderPass> VkRenderPassSetup::CreateRenderPass(int clearTargets)
{
auto buffers = GetVulkanFrameBuffer()->GetBuffers();

Expand All @@ -214,31 +213,31 @@ void VkRenderPassSetup::CreateRenderPass(const VkRenderPassKey &key)
RenderPassBuilder builder;

builder.addAttachment(
key.DrawBufferFormat, (VkSampleCountFlagBits)key.Samples,
(key.ClearTargets & CT_Color) ? VK_ATTACHMENT_LOAD_OP_CLEAR : VK_ATTACHMENT_LOAD_OP_LOAD, VK_ATTACHMENT_STORE_OP_STORE,
PassKey.DrawBufferFormat, (VkSampleCountFlagBits)PassKey.Samples,
(clearTargets & CT_Color) ? VK_ATTACHMENT_LOAD_OP_CLEAR : VK_ATTACHMENT_LOAD_OP_LOAD, VK_ATTACHMENT_STORE_OP_STORE,
VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);

for (int i = 1; i < key.DrawBuffers; i++)
for (int i = 1; i < PassKey.DrawBuffers; i++)
{
builder.addAttachment(
drawBufferFormats[i], buffers->GetSceneSamples(),
(key.ClearTargets & CT_Color) ? VK_ATTACHMENT_LOAD_OP_CLEAR : VK_ATTACHMENT_LOAD_OP_LOAD, VK_ATTACHMENT_STORE_OP_STORE,
(clearTargets & CT_Color) ? VK_ATTACHMENT_LOAD_OP_CLEAR : VK_ATTACHMENT_LOAD_OP_LOAD, VK_ATTACHMENT_STORE_OP_STORE,
VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
}
if (key.UsesDepthStencil())
if (PassKey.DepthStencil)
{
builder.addDepthStencilAttachment(
buffers->SceneDepthStencilFormat, key.DrawBufferFormat == VK_FORMAT_R8G8B8A8_UNORM ? VK_SAMPLE_COUNT_1_BIT : buffers->GetSceneSamples(),
(key.ClearTargets & CT_Depth) ? VK_ATTACHMENT_LOAD_OP_CLEAR : VK_ATTACHMENT_LOAD_OP_LOAD, VK_ATTACHMENT_STORE_OP_STORE,
(key.ClearTargets & CT_Stencil) ? VK_ATTACHMENT_LOAD_OP_CLEAR : VK_ATTACHMENT_LOAD_OP_LOAD, VK_ATTACHMENT_STORE_OP_STORE,
buffers->SceneDepthStencilFormat, PassKey.DrawBufferFormat == VK_FORMAT_R8G8B8A8_UNORM ? VK_SAMPLE_COUNT_1_BIT : buffers->GetSceneSamples(),
(clearTargets & CT_Depth) ? VK_ATTACHMENT_LOAD_OP_CLEAR : VK_ATTACHMENT_LOAD_OP_LOAD, VK_ATTACHMENT_STORE_OP_STORE,
(clearTargets & CT_Stencil) ? VK_ATTACHMENT_LOAD_OP_CLEAR : VK_ATTACHMENT_LOAD_OP_LOAD, VK_ATTACHMENT_STORE_OP_STORE,
VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL);
}
builder.addSubpass();
for (int i = 0; i < key.DrawBuffers; i++)
for (int i = 0; i < PassKey.DrawBuffers; i++)
builder.addSubpassColorAttachmentRef(i, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
if (key.UsesDepthStencil())
if (PassKey.DepthStencil)
{
builder.addSubpassDepthStencilAttachmentRef(key.DrawBuffers, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL);
builder.addSubpassDepthStencilAttachmentRef(PassKey.DrawBuffers, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL);
builder.addExternalSubpassDependency(
VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
Expand All @@ -253,8 +252,16 @@ void VkRenderPassSetup::CreateRenderPass(const VkRenderPassKey &key)
VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
VK_ACCESS_COLOR_ATTACHMENT_READ_BIT);
}
RenderPass = builder.create(GetVulkanFrameBuffer()->device);
RenderPass->SetDebugName("VkRenderPassSetup.RenderPass");
auto renderpass = builder.create(GetVulkanFrameBuffer()->device);
renderpass->SetDebugName("VkRenderPassSetup.RenderPass");
return renderpass;
}

VulkanRenderPass *VkRenderPassSetup::GetRenderPass(int clearTargets)
{
if (!RenderPasses[clearTargets])
RenderPasses[clearTargets] = CreateRenderPass(clearTargets);
return RenderPasses[clearTargets].get();
}

VulkanPipeline *VkRenderPassSetup::GetPipeline(const VkPipelineKey &key)
Expand All @@ -273,11 +280,11 @@ std::unique_ptr<VulkanPipeline> VkRenderPassSetup::CreatePipeline(const VkPipeli
VkShaderProgram *program;
if (key.SpecialEffect != EFF_NONE)
{
program = fb->GetShaderManager()->GetEffect(key.SpecialEffect, key.DrawBuffers > 1 ? GBUFFER_PASS : NORMAL_PASS);
program = fb->GetShaderManager()->GetEffect(key.SpecialEffect, PassKey.DrawBuffers > 1 ? GBUFFER_PASS : NORMAL_PASS);
}
else
{
program = fb->GetShaderManager()->Get(key.EffectState, key.AlphaTest, key.DrawBuffers > 1 ? GBUFFER_PASS : NORMAL_PASS);
program = fb->GetShaderManager()->Get(key.EffectState, key.AlphaTest, PassKey.DrawBuffers > 1 ? GBUFFER_PASS : NORMAL_PASS);
}
builder.addVertexShader(program->vert.get());
builder.addFragmentShader(program->frag.get());
Expand Down Expand Up @@ -305,7 +312,7 @@ std::unique_ptr<VulkanPipeline> VkRenderPassSetup::CreatePipeline(const VkPipeli
inputLocations[attr.location] = true;
}

// To do: does vulkan absolutely needs a binding for each location or not? What happens if it isn't specified? Better be safe than sorry..
// Vulkan requires an attribute binding for each location specified in the shader
for (int i = 0; i < 6; i++)
{
if (!inputLocations[i])
Expand Down Expand Up @@ -350,11 +357,11 @@ std::unique_ptr<VulkanPipeline> VkRenderPassSetup::CreatePipeline(const VkPipeli
builder.setColorWriteMask((VkColorComponentFlags)key.ColorMask);
builder.setStencil(VK_STENCIL_OP_KEEP, op2vk[key.StencilPassOp], VK_STENCIL_OP_KEEP, VK_COMPARE_OP_EQUAL, 0xffffffff, 0xffffffff, 0);
builder.setBlendMode(key.RenderStyle);
builder.setSubpassColorAttachmentCount(key.DrawBuffers);
builder.setRasterizationSamples((VkSampleCountFlagBits)key.Samples);
builder.setSubpassColorAttachmentCount(PassKey.DrawBuffers);
builder.setRasterizationSamples((VkSampleCountFlagBits)PassKey.Samples);

builder.setLayout(fb->GetRenderPassManager()->GetPipelineLayout(key.NumTextureLayers));
builder.setRenderPass(RenderPass.get());
builder.setRenderPass(GetRenderPass(0));
auto pipeline = builder.create(fb->device);
pipeline->SetDebugName("VkRenderPassSetup.Pipeline");
return pipeline;
Expand Down
31 changes: 5 additions & 26 deletions src/rendering/vulkan/renderer/vk_renderpass.h
Expand Up @@ -28,13 +28,7 @@ class VkPipelineKey
int CullMode;
int VertexFormat;
int DrawType;
int Samples;
int ClearTargets;
int DrawBuffers;
int NumTextureLayers;
VkFormat DrawBufferFormat;

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; }
Expand All @@ -44,28 +38,11 @@ class VkPipelineKey
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 DepthStencil;
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 @@ -76,14 +53,16 @@ class VkRenderPassSetup
public:
VkRenderPassSetup(const VkRenderPassKey &key);

VulkanRenderPass *GetRenderPass(int clearTargets);
VulkanPipeline *GetPipeline(const VkPipelineKey &key);

std::unique_ptr<VulkanRenderPass> RenderPass;
VkRenderPassKey PassKey;
std::unique_ptr<VulkanRenderPass> RenderPasses[8];
std::map<VkPipelineKey, std::unique_ptr<VulkanPipeline>> Pipelines;
std::map<VkImageView, std::unique_ptr<VulkanFramebuffer>> Framebuffer;

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

Expand Down
58 changes: 23 additions & 35 deletions src/rendering/vulkan/renderer/vk_renderstate.cpp
Expand Up @@ -195,9 +195,8 @@ void VkRenderState::ApplyDepthBias()

void VkRenderState::ApplyRenderPass(int dt)
{
// Find a render pass that matches our state
// Find a pipeline that matches our state
VkPipelineKey pipelineKey;
pipelineKey.ClearTargets = mPipelineKey.ClearTargets | mClearTargets;
pipelineKey.DrawType = dt;
pipelineKey.VertexFormat = static_cast<VKVertexBuffer*>(mVertexBuffer)->VertexFormat;
pipelineKey.RenderStyle = mRenderStyle;
Expand All @@ -210,9 +209,6 @@ void VkRenderState::ApplyRenderPass(int dt)
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)
{
Expand All @@ -228,44 +224,25 @@ void VkRenderState::ApplyRenderPass(int dt)
pipelineKey.AlphaTest = mAlphaThreshold >= 0.f;
}

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

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

BeginRenderPass(mCommandBuffer);
}

if (changingPipeline)
{
pipelineKey.ClearTargets = mClearTargets;

// Only clear depth+stencil if the render target actually has that
if (!mRenderTarget.DepthStencil)
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));

mCommandBuffer->bindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS, mPassSetup->GetPipeline(pipelineKey));
mPipelineKey = pipelineKey;
mClearTargets = 0;
}
}

Expand Down Expand Up @@ -563,32 +540,42 @@ void VkRenderState::SetRenderTarget(VulkanImageView *view, VulkanImageView *dept
mRenderTarget.Samples = samples;
}

void VkRenderState::BeginRenderPass(const VkRenderPassKey &key, VulkanCommandBuffer *cmdbuffer)
void VkRenderState::BeginRenderPass(VulkanCommandBuffer *cmdbuffer)
{
auto fb = GetVulkanFrameBuffer();

VkRenderPassSetup *passSetup = fb->GetRenderPassManager()->GetRenderPass(key);
VkRenderPassKey key = {};
key.DrawBufferFormat = mRenderTarget.Format;
key.Samples = mRenderTarget.Samples;
key.DrawBuffers = mRenderTarget.DrawBuffers;
key.DepthStencil = !!mRenderTarget.DepthStencil;

auto &framebuffer = passSetup->Framebuffer[mRenderTarget.View->view];
mPassSetup = fb->GetRenderPassManager()->GetRenderPass(key);

auto &framebuffer = mPassSetup->Framebuffer[mRenderTarget.View->view];
if (!framebuffer)
{
auto buffers = fb->GetBuffers();
FramebufferBuilder builder;
builder.setRenderPass(passSetup->RenderPass.get());
builder.setRenderPass(mPassSetup->GetRenderPass(0));
builder.setSize(mRenderTarget.Width, mRenderTarget.Height);
builder.addAttachment(mRenderTarget.View);
if (key.DrawBuffers > 1)
builder.addAttachment(buffers->SceneFog.View.get());
if (key.DrawBuffers > 2)
builder.addAttachment(buffers->SceneNormal.View.get());
if (key.UsesDepthStencil())
if (key.DepthStencil)
builder.addAttachment(mRenderTarget.DepthStencil);
framebuffer = builder.create(GetVulkanFrameBuffer()->device);
framebuffer->SetDebugName("VkRenderPassSetup.Framebuffer");
}

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

RenderPassBegin beginInfo;
beginInfo.setRenderPass(passSetup->RenderPass.get());
beginInfo.setRenderPass(mPassSetup->GetRenderPass(mClearTargets));
beginInfo.setRenderArea(0, 0, mRenderTarget.Width, mRenderTarget.Height);
beginInfo.setFramebuffer(framebuffer.get());
beginInfo.addClearColor(screen->mSceneClearColor[0], screen->mSceneClearColor[1], screen->mSceneClearColor[2], screen->mSceneClearColor[3]);
Expand All @@ -600,6 +587,7 @@ void VkRenderState::BeginRenderPass(const VkRenderPassKey &key, VulkanCommandBuf
cmdbuffer->beginRenderPass(beginInfo);

mMaterial.mChanged = true;
mClearTargets = 0;
}

/////////////////////////////////////////////////////////////////////////////
Expand Down
3 changes: 2 additions & 1 deletion src/rendering/vulkan/renderer/vk_renderstate.h
Expand Up @@ -62,11 +62,12 @@ class VkRenderState : public FRenderState
void ApplyVertexBuffers();
void ApplyMaterial();

void BeginRenderPass(const VkRenderPassKey &key, VulkanCommandBuffer *cmdbuffer);
void BeginRenderPass(VulkanCommandBuffer *cmdbuffer);

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

Expand Down

0 comments on commit 680a6f3

Please sign in to comment.