Skip to content

Commit e874721

Browse files
DeviceContextVk: clear attachments through LOAD_OP_CLEAR when using dynamic rendering
1 parent e101e29 commit e874721

File tree

4 files changed

+149
-65
lines changed

4 files changed

+149
-65
lines changed

Graphics/GraphicsEngineVulkan/include/DeviceContextVkImpl.hpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -410,6 +410,7 @@ class DeviceContextVkImpl final : public DeviceContextNextGenBase<EngineVkImplTr
410410
private:
411411
void TransitionRenderTargets(RESOURCE_STATE_TRANSITION_MODE StateTransitionMode);
412412
__forceinline void CommitRenderPassAndFramebuffer(bool VerifyStates);
413+
__forceinline void EndRenderScope();
413414
void CommitVkVertexBuffers();
414415
void CommitViewports();
415416
void CommitScissorRects();

Graphics/GraphicsEngineVulkan/include/VulkanUtilities/RenderingInfoWrapper.hpp

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,8 @@ class RenderingInfoWrapper
5151

5252
operator const VkRenderingInfoKHR&() const { return m_RI; }
5353

54+
const VkRenderingInfoKHR& Get() const { return m_RI; }
55+
5456
size_t GetHash() const { return m_Hash; }
5557

5658
RenderingInfoWrapper& SetFlags(VkRenderingFlagsKHR flags)
@@ -97,6 +99,34 @@ class RenderingInfoWrapper
9799

98100
VkRenderingFragmentShadingRateAttachmentInfoKHR& GetShadingRateAttachment();
99101

102+
103+
void SetColorAttachmentClearValue(uint32_t Index, const VkClearColorValue& ClearValue)
104+
{
105+
VERIFY_EXPR(Index < m_RI.colorAttachmentCount);
106+
m_Attachments[Index].clearValue.color = ClearValue;
107+
m_Attachments[Index].loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
108+
m_AttachmentClearMask |= 1u << Index;
109+
}
110+
111+
void SetDepthAttachmentClearValue(float Depth)
112+
{
113+
VERIFY_EXPR(m_RI.pDepthAttachment != nullptr && m_DepthAttachmentIndex != ~0u);
114+
m_Attachments[m_DepthAttachmentIndex].clearValue.depthStencil.depth = Depth;
115+
m_Attachments[m_DepthAttachmentIndex].loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
116+
m_AttachmentClearMask |= 1u << m_DepthAttachmentIndex;
117+
}
118+
119+
void SetStencilAttachmentClearValue(uint32_t Stencil)
120+
{
121+
VERIFY_EXPR(m_RI.pStencilAttachment != nullptr && m_StencilAttachmentIndex != ~0u);
122+
m_Attachments[m_StencilAttachmentIndex].clearValue.depthStencil.stencil = Stencil;
123+
m_Attachments[m_StencilAttachmentIndex].loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
124+
m_AttachmentClearMask |= 1u << m_StencilAttachmentIndex;
125+
}
126+
127+
void ResetClears();
128+
bool HasClears() const { return m_AttachmentClearMask != 0; }
129+
100130
private:
101131
VkRenderingInfoKHR m_RI;
102132

@@ -107,6 +137,7 @@ class RenderingInfoWrapper
107137

108138
uint32_t m_DepthAttachmentIndex = ~0u;
109139
uint32_t m_StencilAttachmentIndex = ~0u;
140+
uint32_t m_AttachmentClearMask = 0;
110141
};
111142

112143
} // namespace VulkanUtilities

Graphics/GraphicsEngineVulkan/src/DeviceContextVkImpl.cpp

Lines changed: 102 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -1056,7 +1056,7 @@ void DeviceContextVkImpl::PrepareForDispatchCompute()
10561056
EnsureVkCmdBuffer();
10571057

10581058
// Dispatch commands must be executed outside of render pass
1059-
m_CommandBuffer.EndRenderScope();
1059+
EndRenderScope();
10601060

10611061
ResourceBindInfo& BindInfo = GetBindInfo(PIPELINE_TYPE_COMPUTE);
10621062
if (Uint32 CommitMask = BindInfo.GetCommitMask())
@@ -1158,44 +1158,60 @@ void DeviceContextVkImpl::ClearDepthStencil(ITextureView* pView
11581158
"checks if the DSV is bound as a framebuffer attachment and triggers an assert otherwise (in development mode).");
11591159
if (ClearAsAttachment)
11601160
{
1161-
VERIFY_EXPR((m_vkRenderPass != VK_NULL_HANDLE && m_vkFramebuffer != VK_NULL_HANDLE) || m_DynamicRenderingInfo);
1162-
if (m_pActiveRenderPass == nullptr)
1161+
if (m_DynamicRenderingInfo && m_CommandBuffer.GetState().DynamicRenderingHash == 0)
11631162
{
1164-
// Render pass may not be currently committed
1163+
// Dynamic render pass has not been started yet
1164+
if ((ClearFlags & CLEAR_DEPTH_FLAG) != 0 && m_DynamicRenderingInfo->Get().pDepthAttachment != nullptr)
1165+
{
1166+
m_DynamicRenderingInfo->SetDepthAttachmentClearValue(fDepth);
1167+
}
11651168

1166-
TransitionRenderTargets(StateTransitionMode);
1167-
// No need to verify states again
1168-
CommitRenderPassAndFramebuffer(false);
1169+
if ((ClearFlags & CLEAR_STENCIL_FLAG) != 0 && m_DynamicRenderingInfo->Get().pStencilAttachment != nullptr)
1170+
{
1171+
m_DynamicRenderingInfo->SetStencilAttachmentClearValue(Stencil);
1172+
}
11691173
}
1174+
else
1175+
{
1176+
VERIFY_EXPR((m_vkRenderPass != VK_NULL_HANDLE && m_vkFramebuffer != VK_NULL_HANDLE) || m_DynamicRenderingInfo);
1177+
if (m_pActiveRenderPass == nullptr)
1178+
{
1179+
// Render pass may not be currently committed
11701180

1171-
VkClearAttachment ClearAttachment = {};
1172-
ClearAttachment.aspectMask = 0;
1173-
if (ClearFlags & CLEAR_DEPTH_FLAG) ClearAttachment.aspectMask |= VK_IMAGE_ASPECT_DEPTH_BIT;
1174-
if (ClearFlags & CLEAR_STENCIL_FLAG) ClearAttachment.aspectMask |= VK_IMAGE_ASPECT_STENCIL_BIT;
1175-
// colorAttachment is only meaningful if VK_IMAGE_ASPECT_COLOR_BIT is set in aspectMask
1176-
ClearAttachment.colorAttachment = VK_ATTACHMENT_UNUSED;
1177-
ClearAttachment.clearValue.depthStencil.depth = fDepth;
1178-
ClearAttachment.clearValue.depthStencil.stencil = Stencil;
1179-
VkClearRect ClearRect;
1180-
// m_FramebufferWidth, m_FramebufferHeight are scaled to the proper mip level
1181-
ClearRect.rect = {{0, 0}, {m_FramebufferWidth, m_FramebufferHeight}};
1182-
// The layers [baseArrayLayer, baseArrayLayer + layerCount) count from the base layer of
1183-
// the attachment image view (17.2), so baseArrayLayer is 0, not ViewDesc.FirstArraySlice
1184-
ClearRect.baseArrayLayer = 0;
1185-
ClearRect.layerCount = ViewDesc.NumArraySlices;
1186-
// No memory barriers are needed between vkCmdClearAttachments and preceding or
1187-
// subsequent draw or attachment clear commands in the same subpass (17.2)
1188-
m_CommandBuffer.ClearAttachment(ClearAttachment, ClearRect);
1181+
TransitionRenderTargets(StateTransitionMode);
1182+
// No need to verify states again
1183+
CommitRenderPassAndFramebuffer(false);
1184+
}
1185+
1186+
VkClearAttachment ClearAttachment = {};
1187+
ClearAttachment.aspectMask = 0;
1188+
if (ClearFlags & CLEAR_DEPTH_FLAG) ClearAttachment.aspectMask |= VK_IMAGE_ASPECT_DEPTH_BIT;
1189+
if (ClearFlags & CLEAR_STENCIL_FLAG) ClearAttachment.aspectMask |= VK_IMAGE_ASPECT_STENCIL_BIT;
1190+
// colorAttachment is only meaningful if VK_IMAGE_ASPECT_COLOR_BIT is set in aspectMask
1191+
ClearAttachment.colorAttachment = VK_ATTACHMENT_UNUSED;
1192+
ClearAttachment.clearValue.depthStencil.depth = fDepth;
1193+
ClearAttachment.clearValue.depthStencil.stencil = Stencil;
1194+
VkClearRect ClearRect;
1195+
// m_FramebufferWidth, m_FramebufferHeight are scaled to the proper mip level
1196+
ClearRect.rect = {{0, 0}, {m_FramebufferWidth, m_FramebufferHeight}};
1197+
// The layers [baseArrayLayer, baseArrayLayer + layerCount) count from the base layer of
1198+
// the attachment image view, so baseArrayLayer is 0, not ViewDesc.FirstArraySlice
1199+
ClearRect.baseArrayLayer = 0;
1200+
ClearRect.layerCount = ViewDesc.NumArraySlices;
1201+
// No memory barriers are needed between vkCmdClearAttachments and preceding or
1202+
// subsequent draw or attachment clear commands in the same subpass
1203+
m_CommandBuffer.ClearAttachment(ClearAttachment, ClearRect);
1204+
}
11891205
}
11901206
else
11911207
{
11921208
// End render pass to clear the buffer with vkCmdClearDepthStencilImage
1193-
m_CommandBuffer.EndRenderScope();
1209+
EndRenderScope();
11941210

11951211
ITexture* pTexture = pVkDSV->GetTexture();
11961212
TextureVkImpl* pTextureVk = ClassPtrCast<TextureVkImpl>(pTexture);
11971213

1198-
// Image layout must be VK_IMAGE_LAYOUT_GENERAL or VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL (17.1)
1214+
// Image layout must be VK_IMAGE_LAYOUT_GENERAL or VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL
11991215
TransitionOrVerifyTextureState(*pTextureVk, StateTransitionMode, RESOURCE_STATE_COPY_DEST, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
12001216
"Clearing depth-stencil buffer outside of render pass (DeviceContextVkImpl::ClearDepthStencil)");
12011217

@@ -1218,7 +1234,7 @@ void DeviceContextVkImpl::ClearDepthStencil(ITextureView* pView
12181234
++m_State.NumCommands;
12191235
}
12201236

1221-
VkClearColorValue ClearValueToVkClearValue(const void* RGBA, TEXTURE_FORMAT TexFmt)
1237+
static VkClearColorValue ClearValueToVkClearValue(const void* RGBA, TEXTURE_FORMAT TexFmt)
12221238
{
12231239
VkClearColorValue ClearValue;
12241240
const TextureFormatAttribs& FmtAttribs = GetTextureFormatAttribs(TexFmt);
@@ -1273,43 +1289,52 @@ void DeviceContextVkImpl::ClearRenderTarget(ITextureView* pView, const void* RGB
12731289
"Render target was not found in the framebuffer. This is unexpected because TDeviceContextBase::ClearRenderTarget "
12741290
"checks if the RTV is bound as a framebuffer attachment and triggers an assert otherwise (in development mode).");
12751291

1292+
const VkClearColorValue vkClearValue = ClearValueToVkClearValue(RGBA, ViewDesc.Format);
12761293
if (attachmentIndex != InvalidAttachmentIndex)
12771294
{
12781295
VERIFY_EXPR((m_vkRenderPass != VK_NULL_HANDLE && m_vkFramebuffer != VK_NULL_HANDLE) || m_DynamicRenderingInfo);
1279-
if (m_pActiveRenderPass == nullptr)
1296+
if (m_DynamicRenderingInfo && m_CommandBuffer.GetState().DynamicRenderingHash == 0)
12801297
{
1281-
// Render pass may not be currently committed
1282-
1283-
TransitionRenderTargets(StateTransitionMode);
1284-
// No need to verify states again
1285-
CommitRenderPassAndFramebuffer(false);
1298+
// Dynamic render pass has not been started yet
1299+
m_DynamicRenderingInfo->SetColorAttachmentClearValue(attachmentIndex, vkClearValue);
12861300
}
1301+
else
1302+
{
1303+
if (m_pActiveRenderPass == nullptr)
1304+
{
1305+
// Render pass may not be currently committed
12871306

1288-
VkClearAttachment ClearAttachment = {};
1289-
ClearAttachment.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
1290-
// colorAttachment is only meaningful if VK_IMAGE_ASPECT_COLOR_BIT is set in aspectMask,
1291-
// in which case it is an index to the pColorAttachments array in the VkSubpassDescription
1292-
// structure of the current subpass which selects the color attachment to clear (17.2)
1293-
// It is NOT the render pass attachment index
1294-
ClearAttachment.colorAttachment = attachmentIndex;
1295-
ClearAttachment.clearValue.color = ClearValueToVkClearValue(RGBA, ViewDesc.Format);
1296-
VkClearRect ClearRect;
1297-
// m_FramebufferWidth, m_FramebufferHeight are scaled to the proper mip level
1298-
ClearRect.rect = {{0, 0}, {m_FramebufferWidth, m_FramebufferHeight}};
1299-
// The layers [baseArrayLayer, baseArrayLayer + layerCount) count from the base layer of
1300-
// the attachment image view (17.2), so baseArrayLayer is 0, not ViewDesc.FirstArraySlice
1301-
ClearRect.baseArrayLayer = 0;
1302-
ClearRect.layerCount = ViewDesc.NumArraySlices;
1303-
// No memory barriers are needed between vkCmdClearAttachments and preceding or
1304-
// subsequent draw or attachment clear commands in the same subpass (17.2)
1305-
m_CommandBuffer.ClearAttachment(ClearAttachment, ClearRect);
1307+
TransitionRenderTargets(StateTransitionMode);
1308+
// No need to verify states again
1309+
CommitRenderPassAndFramebuffer(false);
1310+
}
1311+
1312+
VkClearAttachment ClearAttachment = {};
1313+
ClearAttachment.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
1314+
// colorAttachment is only meaningful if VK_IMAGE_ASPECT_COLOR_BIT is set in aspectMask,
1315+
// in which case it is an index to the pColorAttachments array in the VkSubpassDescription
1316+
// structure of the current subpass which selects the color attachment to clear.
1317+
// It is NOT the render pass attachment index
1318+
ClearAttachment.colorAttachment = attachmentIndex;
1319+
ClearAttachment.clearValue.color = vkClearValue;
1320+
VkClearRect ClearRect;
1321+
// m_FramebufferWidth, m_FramebufferHeight are scaled to the proper mip level
1322+
ClearRect.rect = {{0, 0}, {m_FramebufferWidth, m_FramebufferHeight}};
1323+
// The layers [baseArrayLayer, baseArrayLayer + layerCount) count from the base layer of
1324+
// the attachment image view , so baseArrayLayer is 0, not ViewDesc.FirstArraySlice
1325+
ClearRect.baseArrayLayer = 0;
1326+
ClearRect.layerCount = ViewDesc.NumArraySlices;
1327+
// No memory barriers are needed between vkCmdClearAttachments and preceding or
1328+
// subsequent draw or attachment clear commands in the same subpass (17.2)
1329+
m_CommandBuffer.ClearAttachment(ClearAttachment, ClearRect);
1330+
}
13061331
}
13071332
else
13081333
{
13091334
VERIFY(m_pActiveRenderPass == nullptr, "This branch should never execute inside a render pass.");
13101335

13111336
// End current render pass and clear the image with vkCmdClearColorImage
1312-
m_CommandBuffer.EndRenderScope();
1337+
EndRenderScope();
13131338

13141339
ITexture* pTexture = pVkRTV->GetTexture();
13151340
TextureVkImpl* pTextureVk = ClassPtrCast<TextureVkImpl>(pTexture);
@@ -1318,8 +1343,6 @@ void DeviceContextVkImpl::ClearRenderTarget(ITextureView* pView, const void* RGB
13181343
TransitionOrVerifyTextureState(*pTextureVk, StateTransitionMode, RESOURCE_STATE_COPY_DEST, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
13191344
"Clearing render target outside of render pass (DeviceContextVkImpl::ClearRenderTarget)");
13201345

1321-
VkClearColorValue ClearValue = ClearValueToVkClearValue(RGBA, ViewDesc.Format);
1322-
13231346
VkImageSubresourceRange Subresource;
13241347
Subresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
13251348
// We are clearing the image, not image view with vkCmdClearColorImage
@@ -1329,7 +1352,7 @@ void DeviceContextVkImpl::ClearRenderTarget(ITextureView* pView, const void* RGB
13291352
Subresource.levelCount = ViewDesc.NumMipLevels;
13301353
VERIFY(ViewDesc.NumMipLevels, "RTV must contain single mip level");
13311354

1332-
m_CommandBuffer.ClearColorImage(pTextureVk->GetVkImage(), ClearValue, Subresource);
1355+
m_CommandBuffer.ClearColorImage(pTextureVk->GetVkImage(), vkClearValue, Subresource);
13331356
}
13341357

13351358
++m_State.NumCommands;
@@ -1438,7 +1461,7 @@ void DeviceContextVkImpl::Flush(Uint32 NumCommandLists,
14381461

14391462
if (m_State.NumCommands != 0)
14401463
{
1441-
m_CommandBuffer.EndRenderScope();
1464+
EndRenderScope();
14421465

14431466
#ifdef DILIGENT_DEVELOPMENT
14441467
DEV_CHECK_ERR(m_DvpDebugGroupCount == 0, "Not all debug groups have been ended");
@@ -1831,6 +1854,7 @@ void DeviceContextVkImpl::CommitRenderPassAndFramebuffer(bool VerifyStates)
18311854
else if (DynamicRenderingHash != 0)
18321855
{
18331856
m_CommandBuffer.BeginRendering(*m_DynamicRenderingInfo, DynamicRenderingHash);
1857+
m_DynamicRenderingInfo->ResetClears();
18341858
}
18351859
}
18361860
}
@@ -1937,6 +1961,19 @@ void DeviceContextVkImpl::ChooseRenderPassAndFramebuffer()
19371961
}
19381962
}
19391963

1964+
void DeviceContextVkImpl::EndRenderScope()
1965+
{
1966+
if (m_DynamicRenderingInfo && m_DynamicRenderingInfo->HasClears())
1967+
{
1968+
VERIFY(m_CommandBuffer.GetState().DynamicRenderingHash == 0, "Command buffer must not be in a dynamic render scope when there are pending clears");
1969+
EnsureVkCmdBuffer();
1970+
// Apply clears
1971+
CommitRenderPassAndFramebuffer(/*VerifyStates = */ false);
1972+
}
1973+
1974+
m_CommandBuffer.EndRenderScope();
1975+
}
1976+
19401977
void DeviceContextVkImpl::SetRenderTargetsExt(const SetRenderTargetsAttribs& Attribs)
19411978
{
19421979
DEV_CHECK_ERR(m_pActiveRenderPass == nullptr, "Calling SetRenderTargets inside active render pass is invalid. End the render pass first");
@@ -1959,11 +1996,11 @@ void DeviceContextVkImpl::SetRenderTargetsExt(const SetRenderTargetsAttribs& Att
19591996
void DeviceContextVkImpl::ResetRenderTargets()
19601997
{
19611998
TDeviceContextBase::ResetRenderTargets();
1999+
if (m_CommandBuffer.GetVkCmdBuffer() != VK_NULL_HANDLE)
2000+
EndRenderScope();
19622001
m_vkRenderPass = VK_NULL_HANDLE;
19632002
m_vkFramebuffer = VK_NULL_HANDLE;
19642003
m_DynamicRenderingInfo.reset();
1965-
if (m_CommandBuffer.GetVkCmdBuffer() != VK_NULL_HANDLE)
1966-
m_CommandBuffer.EndRenderScope();
19672004
m_State.ShadingRateIsSet = false;
19682005
}
19692006

@@ -2738,7 +2775,7 @@ void DeviceContextVkImpl::FinishCommandList(ICommandList** ppCommandList)
27382775
DEV_CHECK_ERR(IsDeferred(), "Only deferred context can record command list");
27392776
DEV_CHECK_ERR(m_pActiveRenderPass == nullptr, "Finishing command list inside an active render pass.");
27402777

2741-
m_CommandBuffer.EndRenderScope();
2778+
EndRenderScope();
27422779

27432780
VkCommandBuffer vkCmdBuff = m_CommandBuffer.GetVkCmdBuffer();
27442781
VkResult err = vkEndCommandBuffer(vkCmdBuff);
@@ -2826,14 +2863,14 @@ void DeviceContextVkImpl::BeginQuery(IQuery* pQuery)
28262863
}
28272864

28282865
// A query must either begin and end inside the same subpass of a render pass instance, or must
2829-
// both begin and end outside of a render pass instance (i.e. contain entire render pass instances). (17.2)
2866+
// both begin and end outside of a render pass instance (i.e. contain entire render pass instances).
28302867

28312868
++m_ActiveQueriesCounter;
28322869
m_CommandBuffer.BeginQuery(vkQueryPool,
28332870
Idx,
28342871
// If flags does not contain VK_QUERY_CONTROL_PRECISE_BIT an implementation
28352872
// may generate any non-zero result value for the query if the count of
2836-
// passing samples is non-zero (17.3).
2873+
// passing samples is non-zero.
28372874
QueryType == QUERY_TYPE_OCCLUSION ? VK_QUERY_CONTROL_PRECISE_BIT : 0,
28382875
1u << QueryType);
28392876
}
@@ -2863,21 +2900,21 @@ void DeviceContextVkImpl::EndQuery(IQuery* pQuery)
28632900
VERIFY(m_ActiveQueriesCounter > 0, "Active query counter is 0 which means there was a mismatch between BeginQuery() / EndQuery() calls");
28642901

28652902
// A query must either begin and end inside the same subpass of a render pass instance, or must
2866-
// both begin and end outside of a render pass instance (i.e. contain entire render pass instances). (17.2)
2903+
// both begin and end outside of a render pass instance (i.e. contain entire render pass instances).
28672904
const VulkanUtilities::VulkanCommandBuffer::StateCache& CmdBuffState = m_CommandBuffer.GetState();
28682905
VERIFY((CmdBuffState.InsidePassQueries | CmdBuffState.OutsidePassQueries) & (1u << QueryType),
28692906
"No query flag is set which indicates there was no matching BeginQuery call or there was an error while beginning the query.");
28702907
if (CmdBuffState.OutsidePassQueries & (1 << QueryType))
28712908
{
2872-
m_CommandBuffer.EndRenderScope();
2909+
EndRenderScope();
28732910
}
28742911
else
28752912
{
28762913
if (!m_CommandBuffer.GetState().RenderPass)
28772914
LOG_ERROR_MESSAGE("The query was started inside render pass, but is being ended outside of render pass. "
28782915
"Vulkan requires that a query must either begin and end inside the same "
28792916
"subpass of a render pass instance, or must both begin and end outside of a render pass "
2880-
"instance (i.e. contain entire render pass instances). (17.2)");
2917+
"instance (i.e. contain entire render pass instances).");
28812918
}
28822919

28832920
--m_ActiveQueriesCounter;

0 commit comments

Comments
 (0)