summaryrefslogtreecommitdiffstats
path: root/Graphics/GraphicsEngine
diff options
context:
space:
mode:
authorassiduous <assiduous@diligentgraphics.com>2020-08-07 03:41:08 +0000
committerassiduous <assiduous@diligentgraphics.com>2020-08-07 03:41:08 +0000
commita72d485f4b157d5c8fb488bc2afb3b9278e465b7 (patch)
treec542c04aee507fe12757f7d76dcf4f30df4513bf /Graphics/GraphicsEngine
parentAdded few debug checks (diff)
downloadDiligentCore-a72d485f4b157d5c8fb488bc2afb3b9278e465b7.tar.gz
DiligentCore-a72d485f4b157d5c8fb488bc2afb3b9278e465b7.zip
Treating subpass render target and depth stencil attachments as current RT and DS buffers
Diffstat (limited to 'Graphics/GraphicsEngine')
-rw-r--r--Graphics/GraphicsEngine/include/DeviceContextBase.hpp176
-rw-r--r--Graphics/GraphicsEngine/include/PipelineStateBase.hpp30
2 files changed, 125 insertions, 81 deletions
diff --git a/Graphics/GraphicsEngine/include/DeviceContextBase.hpp b/Graphics/GraphicsEngine/include/DeviceContextBase.hpp
index 4df47bfc..3e1a5779 100644
--- a/Graphics/GraphicsEngine/include/DeviceContextBase.hpp
+++ b/Graphics/GraphicsEngine/include/DeviceContextBase.hpp
@@ -122,10 +122,6 @@ public:
/// Caches the scissor rects
inline void SetScissorRects(Uint32 NumRects, const Rect* pRects, Uint32& RTWidth, Uint32& RTHeight);
- /// Caches the render target and depth stencil views. Returns true if any view is different
- /// from the cached value and false otherwise.
- inline bool SetRenderTargets(Uint32 NumRenderTargets, ITextureView* ppRenderTargets[], ITextureView* pDepthStencil);
-
virtual void DILIGENT_CALL_TYPE BeginRenderPass(const BeginRenderPassAttribs& Attribs) override = 0;
virtual void DILIGENT_CALL_TYPE NextSubpass() override = 0;
@@ -210,6 +206,13 @@ public:
bool UnbindTextureFromFramebuffer(TextureImplType* pTexture, bool bShowMessage);
protected:
+ /// Caches the render target and depth stencil views. Returns true if any view is different
+ /// from the cached value and false otherwise.
+ inline bool SetRenderTargets(Uint32 NumRenderTargets, ITextureView* ppRenderTargets[], ITextureView* pDepthStencil);
+
+ /// Initializes render targets for the current subpass
+ inline bool SetSubpassRenderTargets();
+
inline bool SetBlendFactors(const float* BlendFactors, int Dummy);
inline bool SetStencilRef(Uint32 StencilRef, int Dummy);
@@ -581,8 +584,6 @@ inline bool DeviceContextBase<BaseInterface, ImplementationTraits>::
return false;
}
- VERIFY(m_pActiveRenderPass == nullptr, "Setting render targets inside the render pass is not allowed. The render pass must be ended first.");
-
bool bBindRenderTargets = false;
m_FramebufferWidth = 0;
m_FramebufferHeight = 0;
@@ -684,6 +685,49 @@ inline bool DeviceContextBase<BaseInterface, ImplementationTraits>::
}
template <typename BaseInterface, typename ImplementationTraits>
+inline bool DeviceContextBase<BaseInterface, ImplementationTraits>::SetSubpassRenderTargets()
+{
+ VERIFY_EXPR(m_pBoundFramebuffer);
+ VERIFY_EXPR(m_pActiveRenderPass);
+
+ const auto& RPDesc = m_pActiveRenderPass->GetDesc();
+ const auto& FBDesc = m_pBoundFramebuffer->GetDesc();
+ VERIFY_EXPR(m_SubpassIndex < RPDesc.SubpassCount);
+ const auto& Subpass = RPDesc.pSubpasses[m_SubpassIndex];
+
+ ITextureView* ppRTVs[MAX_RENDER_TARGETS] = {};
+ ITextureView* pDSV = nullptr;
+ for (Uint32 rt = 0; rt < Subpass.RenderTargetAttachmentCount; ++rt)
+ {
+ const auto& RTAttachmentRef = Subpass.pRenderTargetAttachments[rt];
+ if (RTAttachmentRef.AttachmentIndex != ATTACHMENT_UNUSED)
+ {
+ VERIFY_EXPR(RTAttachmentRef.AttachmentIndex < RPDesc.AttachmentCount);
+ ppRTVs[rt] = FBDesc.ppAttachments[RTAttachmentRef.AttachmentIndex];
+ }
+ }
+
+ if (Subpass.pDepthStencilAttachment != nullptr)
+ {
+ const auto& DSAttachmentRef = *Subpass.pDepthStencilAttachment;
+ if (DSAttachmentRef.AttachmentIndex != ATTACHMENT_UNUSED)
+ {
+ VERIFY_EXPR(DSAttachmentRef.AttachmentIndex < RPDesc.AttachmentCount);
+ pDSV = FBDesc.ppAttachments[DSAttachmentRef.AttachmentIndex];
+ }
+ }
+ bool BindRenderTargets = SetRenderTargets(Subpass.RenderTargetAttachmentCount, ppRTVs, pDSV);
+
+ // Use framebuffer dimensions (override what was set by SetRenderTargets)
+ m_FramebufferWidth = FBDesc.Width;
+ m_FramebufferHeight = FBDesc.Height;
+ m_FramebufferSlices = FBDesc.NumArraySlices;
+
+ return BindRenderTargets;
+}
+
+
+template <typename BaseInterface, typename ImplementationTraits>
inline void DeviceContextBase<BaseInterface, ImplementationTraits>::
GetRenderTargets(Uint32& NumRenderTargets, ITextureView** ppRTVs, ITextureView** ppDSV)
{
@@ -751,6 +795,7 @@ inline void DeviceContextBase<BaseInterface, ImplementationTraits>::ClearStateCa
ResetRenderTargets();
+ VERIFY(!m_pActiveRenderPass, "Clearing state cache inside an active render pass");
m_pActiveRenderPass = nullptr;
m_pBoundFramebuffer = nullptr;
}
@@ -838,8 +883,6 @@ bool DeviceContextBase<BaseInterface, ImplementationTraits>::UnbindTextureFromFr
template <typename BaseInterface, typename ImplementationTraits>
void DeviceContextBase<BaseInterface, ImplementationTraits>::ResetRenderTargets()
{
- VERIFY(m_pActiveRenderPass == nullptr, "Resetting render targets inside the render pass may result in undefined behavior.");
-
for (Uint32 rt = 0; rt < m_NumBoundRenderTargets; ++rt)
m_pBoundRenderTargets[rt].Release();
#ifdef DILIGENT_DEBUG
@@ -854,12 +897,16 @@ void DeviceContextBase<BaseInterface, ImplementationTraits>::ResetRenderTargets(
m_FramebufferSlices = 0;
m_pBoundDepthStencil.Release();
+
+ // Do not reset framebuffer here as there may potentially
+ // be a subpass without any render target attachments.
}
template <typename BaseInterface, typename ImplementationTraits>
inline void DeviceContextBase<BaseInterface, ImplementationTraits>::BeginRenderPass(const BeginRenderPassAttribs& Attribs)
{
VERIFY(m_pActiveRenderPass == nullptr, "Attempting to begin render pass while another render pass ('", m_pActiveRenderPass->GetDesc().Name, "') is active.");
+ VERIFY(m_pBoundFramebuffer == nullptr, "Attempting to begin render pass while another framebuffer ('", m_pBoundFramebuffer->GetDesc().Name, "') is bound.");
VERIFY(Attribs.pRenderPass != nullptr, "Render pass must not be null");
VERIFY(Attribs.pFramebuffer != nullptr, "Framebuffer must not be null");
#ifdef DILIGENT_DEBUG
@@ -892,16 +939,10 @@ inline void DeviceContextBase<BaseInterface, ImplementationTraits>::BeginRenderP
auto* pNewRenderPass = ValidatedCast<RenderPassImplType>(Attribs.pRenderPass);
auto* pNewFramebuffer = ValidatedCast<FramebufferImplType>(Attribs.pFramebuffer);
- m_SubpassIndex = 0;
-
- const auto& FBDesc = pNewFramebuffer->GetDesc();
- m_FramebufferWidth = FBDesc.Width;
- m_FramebufferHeight = FBDesc.Height;
- m_FramebufferSlices = FBDesc.NumArraySlices;
-
if (Attribs.StateTransitionMode != RESOURCE_STATE_TRANSITION_MODE_NONE)
{
const auto& RPDesc = pNewRenderPass->GetDesc();
+ const auto& FBDesc = pNewFramebuffer->GetDesc();
VERIFY(RPDesc.AttachmentCount <= FBDesc.AttachmentCount,
"The number of attachments (", FBDesc.AttachmentCount,
") in currently bound framebuffer is smaller than the number of attachments in the render pass (", RPDesc.AttachmentCount, ")");
@@ -915,8 +956,11 @@ inline void DeviceContextBase<BaseInterface, ImplementationTraits>::BeginRenderP
auto RequiredState = RPDesc.pAttachments[i].InitialState;
if (Attribs.StateTransitionMode == RESOURCE_STATE_TRANSITION_MODE_TRANSITION)
{
- StateTransitionDesc Barrier{pTex, RESOURCE_STATE_UNKNOWN, RequiredState, true};
- this->TransitionResourceStates(1, &Barrier);
+ if (pTex->IsInKnownState() && !pTex->CheckState(RequiredState))
+ {
+ StateTransitionDesc Barrier{pTex, RESOURCE_STATE_UNKNOWN, RequiredState, true};
+ this->TransitionResourceStates(1, &Barrier);
+ }
}
else if (Attribs.StateTransitionMode == RESOURCE_STATE_TRANSITION_MODE_VERIFY)
{
@@ -928,6 +972,7 @@ inline void DeviceContextBase<BaseInterface, ImplementationTraits>::BeginRenderP
m_pActiveRenderPass = pNewRenderPass;
m_pBoundFramebuffer = pNewFramebuffer;
m_SubpassIndex = 0;
+ SetSubpassRenderTargets();
}
template <typename BaseInterface, typename ImplementationTraits>
@@ -936,6 +981,7 @@ inline void DeviceContextBase<BaseInterface, ImplementationTraits>::NextSubpass(
VERIFY(m_pActiveRenderPass != nullptr, "There is no active render pass");
VERIFY(m_SubpassIndex + 1 < m_pActiveRenderPass->GetDesc().SubpassCount, "The render pass has reached the final subpass already");
++m_SubpassIndex;
+ SetSubpassRenderTargets();
}
template <typename BaseInterface, typename ImplementationTraits>
@@ -964,6 +1010,7 @@ inline void DeviceContextBase<BaseInterface, ImplementationTraits>::EndRenderPas
m_pActiveRenderPass.Release();
m_pBoundFramebuffer.Release();
m_SubpassIndex = 0;
+ ResetRenderTargets();
}
@@ -986,44 +1033,28 @@ inline bool DeviceContextBase<BaseInterface, ImplementationTraits>::ClearDepthSt
return false;
}
- if (m_pActiveRenderPass != nullptr)
+ if (pView != m_pBoundDepthStencil)
{
- bool AttachmentFound = false;
- if (m_pBoundFramebuffer != nullptr)
+ if (m_pActiveRenderPass != nullptr)
{
- const auto& FBDesc = m_pBoundFramebuffer->GetDesc();
- for (Uint32 i = 0; i < FBDesc.AttachmentCount && !AttachmentFound; ++i)
- {
- AttachmentFound = FBDesc.ppAttachments[i] == pView;
- }
+ LOG_ERROR_MESSAGE("Depth-stencil view '", ViewDesc.Name,
+ "' is not bound as framebuffer attachment. ClearDepthStencil command inside a render pass "
+ "requires depth-stencil view to be bound as a framebuffer attachment.");
+ return false;
}
-
- if (!AttachmentFound)
+ else if (m_pDevice->GetDeviceCaps().IsGLDevice())
{
LOG_ERROR_MESSAGE("Depth-stencil view '", ViewDesc.Name,
- "' is not bound as framebuffer attachment. ClearDepthStencil command inside a render pass "
- "requires depth-stencil view be bound as framebuffer attachment.");
+ "' is not bound to the device context. ClearDepthStencil command requires "
+ "depth-stencil view be bound to the device contex in OpenGL backend");
return false;
}
- }
- else
- {
- if (pView != m_pBoundDepthStencil)
+ else
{
- if (m_pDevice->GetDeviceCaps().IsGLDevice())
- {
- LOG_ERROR_MESSAGE("Depth-stencil view '", ViewDesc.Name,
- "' is not bound to the device context. ClearDepthStencil command requires "
- "depth-stencil view be bound to the device contex in OpenGL backend");
- return false;
- }
- else
- {
- LOG_WARNING_MESSAGE("Depth-stencil view '", ViewDesc.Name,
- "' is not bound to the device context. "
- "ClearDepthStencil command is more efficient when depth-stencil "
- "view is bound to the context. In OpenGL backend this is a requirement.");
- }
+ LOG_WARNING_MESSAGE("Depth-stencil view '", ViewDesc.Name,
+ "' is not bound to the device context. "
+ "ClearDepthStencil command is more efficient when depth-stencil "
+ "view is bound to the context. In OpenGL backend this is a requirement.");
}
}
}
@@ -1051,48 +1082,33 @@ inline bool DeviceContextBase<BaseInterface, ImplementationTraits>::ClearRenderT
return false;
}
- if (m_pActiveRenderPass != nullptr)
+ bool RTFound = false;
+ for (Uint32 i = 0; i < m_NumBoundRenderTargets && !RTFound; ++i)
{
- bool AttachmentFound = false;
- if (m_pBoundFramebuffer != nullptr)
- {
- const auto& FBDesc = m_pBoundFramebuffer->GetDesc();
- for (Uint32 i = 0; i < FBDesc.AttachmentCount && !AttachmentFound; ++i)
- {
- AttachmentFound = FBDesc.ppAttachments[i] == pView;
- }
- }
+ RTFound = m_pBoundRenderTargets[i] == pView;
+ }
- if (!AttachmentFound)
+ if (!RTFound)
+ {
+ if (m_pActiveRenderPass != nullptr)
{
LOG_ERROR_MESSAGE("Render target view '", ViewDesc.Name,
"' is not bound as framebuffer attachment. ClearRenderTarget command inside a render pass "
- "requires render target view be bound as framebuffer attachment.");
+ "requires render target view to be bound as a framebuffer attachment.");
return false;
}
- }
- else
- {
- bool RTFound = false;
- for (Uint32 i = 0; i < m_NumBoundRenderTargets && !RTFound; ++i)
+ else if (m_pDevice->GetDeviceCaps().IsGLDevice())
{
- RTFound = m_pBoundRenderTargets[i] == pView;
+ LOG_ERROR_MESSAGE("Render target view '", ViewDesc.Name,
+ "' is not bound to the device context. ClearRenderTarget command "
+ "requires render target view to be bound to the device contex in OpenGL backend");
+ return false;
}
- if (!RTFound)
+ else
{
- if (m_pDevice->GetDeviceCaps().IsGLDevice())
- {
- LOG_ERROR_MESSAGE("Render target view '", ViewDesc.Name,
- "' is not bound to the device context. ClearRenderTarget command "
- "requires render target view be bound to the device contex in OpenGL backend");
- return false;
- }
- else
- {
- LOG_WARNING_MESSAGE("Render target view '", ViewDesc.Name,
- "' is not bound to the device context. ClearRenderTarget command is more efficient "
- "if render target view is bound to the device context. In OpenGL backend this is a requirement.");
- }
+ LOG_WARNING_MESSAGE("Render target view '", ViewDesc.Name,
+ "' is not bound to the device context. ClearRenderTarget command is more efficient "
+ "if render target view is bound to the device context. In OpenGL backend this is a requirement.");
}
}
}
@@ -1564,7 +1580,7 @@ inline void DeviceContextBase<BaseInterface, ImplementationTraits>::
const auto& GraphicsPipeline = PSODesc.GraphicsPipeline;
if (GraphicsPipeline.NumRenderTargets != m_NumBoundRenderTargets)
{
- LOG_WARNING_MESSAGE("Number of currently bound render targets (", m_NumBoundRenderTargets,
+ LOG_WARNING_MESSAGE("The number of currently bound render targets (", m_NumBoundRenderTargets,
") does not match the number of outputs specified by the PSO '", PSODesc.Name,
"' (", Uint32{GraphicsPipeline.NumRenderTargets}, ").");
}
diff --git a/Graphics/GraphicsEngine/include/PipelineStateBase.hpp b/Graphics/GraphicsEngine/include/PipelineStateBase.hpp
index 109b6ce4..fbfbb100 100644
--- a/Graphics/GraphicsEngine/include/PipelineStateBase.hpp
+++ b/Graphics/GraphicsEngine/include/PipelineStateBase.hpp
@@ -201,6 +201,34 @@ public:
}
}
+ if (m_pRenderPass)
+ {
+ const auto& RPDesc = m_pRenderPass->GetDesc();
+ VERIFY_EXPR(GraphicsPipeline.SubpassIndex < RPDesc.SubpassCount);
+ const auto& Subpass = RPDesc.pSubpasses[GraphicsPipeline.SubpassIndex];
+
+ this->m_Desc.GraphicsPipeline.NumRenderTargets = static_cast<Uint8>(Subpass.RenderTargetAttachmentCount);
+ for (Uint32 rt = 0; rt < Subpass.RenderTargetAttachmentCount; ++rt)
+ {
+ const auto& RTAttachmentRef = Subpass.pRenderTargetAttachments[rt];
+ if (RTAttachmentRef.AttachmentIndex != ATTACHMENT_UNUSED)
+ {
+ VERIFY_EXPR(RTAttachmentRef.AttachmentIndex < RPDesc.AttachmentCount);
+ this->m_Desc.GraphicsPipeline.RTVFormats[rt] = RPDesc.pAttachments[RTAttachmentRef.AttachmentIndex].Format;
+ }
+ }
+
+ if (Subpass.pDepthStencilAttachment != nullptr)
+ {
+ const auto& DSAttachmentRef = *Subpass.pDepthStencilAttachment;
+ if (DSAttachmentRef.AttachmentIndex != ATTACHMENT_UNUSED)
+ {
+ VERIFY_EXPR(DSAttachmentRef.AttachmentIndex < RPDesc.AttachmentCount);
+ this->m_Desc.GraphicsPipeline.DSVFormat = RPDesc.pAttachments[DSAttachmentRef.AttachmentIndex].Format;
+ }
+ }
+ }
+
const auto& InputLayout = PSODesc.GraphicsPipeline.InputLayout;
LayoutElement* pLayoutElements = nullptr;
if (InputLayout.NumElements > 0)
@@ -407,7 +435,7 @@ private:
{
if (this->m_Desc.GraphicsPipeline.pRenderPass != nullptr)
{
- LOG_PSO_ERROR_AND_THROW("GraphicsPipeline.pRenderPass must be null");
+ LOG_PSO_ERROR_AND_THROW("GraphicsPipeline.pRenderPass must be null for compute pipelines");
}
}
else