1
0
mirror of https://github.com/doitsujin/dxvk.git synced 2025-04-01 09:25:24 +02:00

[dxvk] Add helper functions to do handle deferred clears while rendering

This commit is contained in:
Philip Rebohle 2025-03-21 02:57:07 +01:00
parent 9cac7b0447
commit 3417c559c8
2 changed files with 103 additions and 16 deletions

View File

@ -2332,6 +2332,44 @@ namespace dxvk {
} }
void DxvkContext::preparePostRenderPassClears() {
for (const auto& clear : m_deferredClears)
prepareImage(clear.imageView->image(), clear.imageView->imageSubresources(), false);
}
void DxvkContext::flushClearsInline() {
small_vector<VkClearAttachment, MaxNumRenderTargets + 1u> attachments;
for (const auto& clear : m_deferredClears) {
// Ignore pure discards, we can't do anything useful with
// those without interrupting the render pass again.
if (!clear.clearAspects)
continue;
// If we end up here, the image is guaranteed to be bound.
int32_t attachmentIndex = m_state.om.framebufferInfo.findAttachment(clear.imageView);
auto& entry = attachments.emplace_back();
entry.aspectMask = clear.clearAspects;
entry.clearValue = clear.clearValue;
if (clear.clearAspects & VK_IMAGE_ASPECT_COLOR_BIT)
entry.colorAttachment = m_state.om.framebufferInfo.getColorAttachmentIndex(attachmentIndex);
}
if (!attachments.empty()) {
VkClearRect clearRect = { };
clearRect.rect = m_state.om.renderingInfo.rendering.renderArea;
clearRect.layerCount = m_state.om.renderingInfo.rendering.layerCount;
m_cmd->cmdClearAttachments(attachments.size(), attachments.data(), 1u, &clearRect);
}
m_deferredClears.clear();
}
void DxvkContext::flushClears( void DxvkContext::flushClears(
bool useRenderPass) { bool useRenderPass) {
for (const auto& clear : m_deferredClears) { for (const auto& clear : m_deferredClears) {
@ -2362,6 +2400,45 @@ namespace dxvk {
} }
void DxvkContext::flushRenderPassDiscards() {
if (!m_deferredClears.empty()) {
for (size_t i = 0; i < m_state.om.framebufferInfo.numAttachments(); i++) {
auto view = m_state.om.framebufferInfo.getAttachment(i).view;
if (m_deferredResolves.at(i).imageView)
continue;
for (const auto& clear : m_deferredClears) {
if (clear.imageView->image() != view->image())
continue;
// Make sure that the cleared and discarded subresources are a superset
// of the subresources currently active in the render pass
auto clearSubresource = clear.imageView->subresources();
auto renderSubresource = view->subresources();
if (clearSubresource.aspectMask != renderSubresource.aspectMask
|| !vk::checkSubresourceRangeSuperset(clearSubresource, renderSubresource))
continue;
VkImageAspectFlags aspects = clear.clearAspects | clear.discardAspects;
int32_t colorIndex = m_state.om.framebufferInfo.getColorAttachmentIndex(i);
if (colorIndex < 0) {
if ((aspects & VK_IMAGE_ASPECT_DEPTH_BIT) && m_state.om.renderingInfo.rendering.pDepthAttachment)
m_state.om.renderingInfo.depth.storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
if ((aspects & VK_IMAGE_ASPECT_STENCIL_BIT) && m_state.om.renderingInfo.rendering.pStencilAttachment)
m_state.om.renderingInfo.stencil.storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
} else if (aspects & VK_IMAGE_ASPECT_COLOR_BIT) {
if (uint32_t(colorIndex) < m_state.om.renderingInfo.rendering.colorAttachmentCount)
m_state.om.renderingInfo.color[colorIndex].storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
}
}
}
}
}
void DxvkContext::flushRenderPassResolves() { void DxvkContext::flushRenderPassResolves() {
for (size_t i = 0; i < m_state.om.framebufferInfo.numAttachments(); i++) { for (size_t i = 0; i < m_state.om.framebufferInfo.numAttachments(); i++) {
auto& resolve = m_deferredResolves.at(i); auto& resolve = m_deferredResolves.at(i);
@ -5172,6 +5249,11 @@ namespace dxvk {
if (!m_flags.test(DxvkContextFlag::GpRenderPassSecondaryCmd)) if (!m_flags.test(DxvkContextFlag::GpRenderPassSecondaryCmd))
return false; return false;
// Otherwise, if any clears are queued up for the source image,
// that clear operation needs to be performed first.
if (findOverlappingDeferredClear(srcImage, vk::makeSubresourceRange(region.srcSubresource)))
flushClearsInline();
// Check whether we're dealing with a color or depth attachment, one // Check whether we're dealing with a color or depth attachment, one
// of those flags needs to be set for resolve to even make sense // of those flags needs to be set for resolve to even make sense
VkImageUsageFlags usage = srcImage->info().usage & (VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT); VkImageUsageFlags usage = srcImage->info().usage & (VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT);
@ -5438,6 +5520,12 @@ namespace dxvk {
flushBarriers(); flushBarriers();
flushResolves(); flushResolves();
// Need to process pending clears after resolves
preparePostRenderPassClears();
if (!suspend)
flushClears(false);
if (unlikely(m_features.test(DxvkContextFeature::DebugUtils))) if (unlikely(m_features.test(DxvkContextFeature::DebugUtils)))
popDebugRegion(util::DxvkDebugLabelType::InternalRenderPass); popDebugRegion(util::DxvkDebugLabelType::InternalRenderPass);
} else if (!suspend) { } else if (!suspend) {
@ -5753,6 +5841,7 @@ namespace dxvk {
// Record scoped rendering commands with potentially // Record scoped rendering commands with potentially
// modified store or resolve ops here // modified store or resolve ops here
flushRenderPassResolves(); flushRenderPassResolves();
flushRenderPassDiscards();
auto& renderingInfo = m_state.om.renderingInfo.rendering; auto& renderingInfo = m_state.om.renderingInfo.rendering;
m_cmd->cmdBeginRendering(&renderingInfo); m_cmd->cmdBeginRendering(&renderingInfo);
@ -7032,6 +7121,10 @@ namespace dxvk {
if (!m_flags.test(DxvkContextFlag::GpRenderPassBound)) if (!m_flags.test(DxvkContextFlag::GpRenderPassBound))
this->startRenderPass(); this->startRenderPass();
// If there are any pending clears, record them now
if (unlikely(!m_deferredClears.empty()))
flushClearsInline();
if (m_flags.test(DxvkContextFlag::GpRenderPassSideEffects)) { if (m_flags.test(DxvkContextFlag::GpRenderPassSideEffects)) {
// Make sure that the debug label for barrier control // Make sure that the debug label for barrier control
// always starts within an active render pass // always starts within an active render pass
@ -7908,6 +8001,8 @@ namespace dxvk {
void DxvkContext::discardRenderTarget( void DxvkContext::discardRenderTarget(
const DxvkImage& image, const DxvkImage& image,
const VkImageSubresourceRange& subresources) { const VkImageSubresourceRange& subresources) {
// We can only retroactively change store ops if we are currently
// inside a render pass that uses secondary command buffers.
if (!m_flags.test(DxvkContextFlag::GpRenderPassSecondaryCmd)) if (!m_flags.test(DxvkContextFlag::GpRenderPassSecondaryCmd))
return; return;
@ -7925,22 +8020,8 @@ namespace dxvk {
// retroactively change the corresponding store op to DONT_CARE. // retroactively change the corresponding store op to DONT_CARE.
auto viewSubresources = view->imageSubresources(); auto viewSubresources = view->imageSubresources();
if (vk::checkSubresourceRangeSuperset(subresources, viewSubresources)) { if (vk::checkSubresourceRangeSuperset(subresources, viewSubresources))
if (subresources.aspectMask & (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT)) { deferDiscard(view, subresources.aspectMask);
if ((subresources.aspectMask & VK_IMAGE_ASPECT_DEPTH_BIT) && m_state.om.renderingInfo.depth.imageView)
m_state.om.renderingInfo.depth.storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
if ((subresources.aspectMask & VK_IMAGE_ASPECT_STENCIL_BIT) && m_state.om.renderingInfo.stencil.imageView)
m_state.om.renderingInfo.stencil.storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
} else {
uint32_t index = m_state.om.framebufferInfo.getColorAttachmentIndex(i);
if (index < m_state.om.renderingInfo.rendering.colorAttachmentCount)
m_state.om.renderingInfo.color[i].storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
}
m_flags.set(DxvkContextFlag::GpRenderPassNeedsFlush);
}
} }
} }

View File

@ -1662,11 +1662,17 @@ namespace dxvk {
const Rc<DxvkImageView>& imageView, const Rc<DxvkImageView>& imageView,
VkImageAspectFlags discardAspects); VkImageAspectFlags discardAspects);
void preparePostRenderPassClears();
void flushClearsInline();
void flushClears( void flushClears(
bool useRenderPass); bool useRenderPass);
void flushSharedImages(); void flushSharedImages();
void flushRenderPassDiscards();
void flushRenderPassResolves(); void flushRenderPassResolves();
void flushResolves(); void flushResolves();