1
0
mirror of https://github.com/doitsujin/dxvk.git synced 2024-12-02 01:24:11 +01:00

[dxvk] Improve deferred clear logic

Ignores currently bound render targets until we actually begin a
render pass. This allows us to use LOAD_OP_CLEAR in more situations,
including when games clear their RTs before binding them.
This commit is contained in:
Philip Rebohle 2020-05-01 17:27:25 +02:00
parent 3cbd109020
commit b9c56e3e97
No known key found for this signature in database
GPG Key ID: C8CC613427A31C99
3 changed files with 61 additions and 79 deletions

View File

@ -40,8 +40,7 @@ namespace dxvk {
// before any draw or dispatch command is recorded.
m_flags.clr(
DxvkContextFlag::GpRenderPassBound,
DxvkContextFlag::GpXfbActive,
DxvkContextFlag::GpClearRenderTargets);
DxvkContextFlag::GpXfbActive);
m_flags.set(
DxvkContextFlag::GpDirtyFramebuffer,
@ -98,10 +97,6 @@ namespace dxvk {
void DxvkContext::bindRenderTargets(
const DxvkRenderTargets& targets) {
// If necessary, perform clears on the active render targets
if (m_flags.test(DxvkContextFlag::GpClearRenderTargets))
this->clearRenderPass();
// Set up default render pass ops
m_state.om.renderTargets = targets;
@ -569,8 +564,6 @@ namespace dxvk {
const Rc<DxvkImageView>& imageView,
VkImageAspectFlags clearAspects,
VkClearValue clearValue) {
this->updateFramebuffer();
// Make sure the color components are ordered correctly
if (clearAspects & VK_IMAGE_ASPECT_COLOR_BIT) {
clearValue.color = util::swizzleClearColor(clearValue.color,
@ -582,13 +575,18 @@ namespace dxvk {
// If not, we need to create a temporary framebuffer.
int32_t attachmentIndex = -1;
if (m_state.om.framebuffer->isFullSize(imageView) && this->checkFramebufferBarrier().isClear())
attachmentIndex = m_state.om.framebuffer->findAttachment(imageView);
if (m_flags.test(DxvkContextFlag::GpRenderPassBound)) {
if (m_state.om.framebuffer->isFullSize(imageView) && this->checkFramebufferBarrier().isClear())
attachmentIndex = m_state.om.framebuffer->findAttachment(imageView);
if (attachmentIndex < 0)
this->spillRenderPass();
if (attachmentIndex < 1)
this->spillRenderPass();
}
this->performClear(imageView, attachmentIndex, clearAspects, clearValue);
if (m_flags.test(DxvkContextFlag::GpRenderPassBound))
this->performClear(imageView, attachmentIndex, clearAspects, clearValue);
else
this->deferClear(imageView, clearAspects, clearValue);
}
@ -1826,12 +1824,33 @@ namespace dxvk {
&& m_state.om.renderPassOps.depthOps.loadOpS == VK_ATTACHMENT_LOAD_OP_CLEAR)
m_state.om.renderPassOps.depthOps.loadLayout = VK_IMAGE_LAYOUT_UNDEFINED;
}
m_flags.set(DxvkContextFlag::GpClearRenderTargets);
}
}
void DxvkContext::deferClear(
const Rc<DxvkImageView>& imageView,
VkImageAspectFlags clearAspects,
VkClearValue clearValue) {
m_deferredClears.push_back({ imageView, clearAspects, clearValue });
}
void DxvkContext::flushClears(
bool useRenderPass) {
for (const auto& clear : m_deferredClears) {
int32_t attachmentIndex = -1;
if (useRenderPass && m_state.om.framebuffer->isFullSize(clear.imageView))
attachmentIndex = m_state.om.framebuffer->findAttachment(clear.imageView);
this->performClear(clear.imageView, attachmentIndex, clear.clearAspects, clear.clearValue);
}
m_deferredClears.clear();
}
void DxvkContext::updateBuffer(
const Rc<DxvkBuffer>& buffer,
VkDeviceSize offset,
@ -3432,8 +3451,9 @@ namespace dxvk {
void DxvkContext::startRenderPass() {
if (!m_flags.test(DxvkContextFlag::GpRenderPassBound)) {
this->flushClears(true);
m_flags.set(DxvkContextFlag::GpRenderPassBound);
m_flags.clr(DxvkContextFlag::GpClearRenderTargets);
m_execBarriers.recordCommands(m_cmd);
@ -3456,10 +3476,7 @@ namespace dxvk {
}
void DxvkContext::spillRenderPass() {
if (m_flags.test(DxvkContextFlag::GpClearRenderTargets))
this->clearRenderPass();
void DxvkContext::spillRenderPass(bool flushClears) {
if (m_flags.test(DxvkContextFlag::GpRenderPassBound)) {
m_flags.clr(DxvkContextFlag::GpRenderPassBound);
@ -3475,60 +3492,14 @@ namespace dxvk {
this->commitPredicateUpdates();
m_flags.clr(DxvkContextFlag::GpDirtyXfbCounters);
} else if (flushClears) {
// We defer clears with a render pass bound,
// no need to call this for the common path.
this->flushClears(false);
}
}
void DxvkContext::clearRenderPass() {
if (m_flags.test(DxvkContextFlag::GpClearRenderTargets)) {
m_flags.clr(DxvkContextFlag::GpClearRenderTargets);
bool flushBarriers = false;
for (uint32_t i = 0; i < m_state.om.framebuffer->numAttachments(); i++) {
const DxvkAttachment& attachment = m_state.om.framebuffer->getAttachment(i);
flushBarriers |= m_execBarriers.isImageDirty(
attachment.view->image(),
attachment.view->imageSubresources(),
DxvkAccess::Write);
}
if (flushBarriers)
m_execBarriers.recordCommands(m_cmd);
this->renderPassBindFramebuffer(
m_state.om.framebuffer,
m_state.om.renderPassOps,
m_state.om.clearValues.size(),
m_state.om.clearValues.data());
this->resetRenderPassOps(
m_state.om.renderTargets,
m_state.om.renderPassOps);
this->renderPassUnbindFramebuffer();
for (uint32_t i = 0; i < m_state.om.framebuffer->numAttachments(); i++) {
const DxvkAttachment& attachment = m_state.om.framebuffer->getAttachment(i);
m_execBarriers.accessImage(
attachment.view->image(),
attachment.view->imageSubresources(),
attachment.view->imageInfo().layout,
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT |
VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT |
VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT,
VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT |
VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT,
attachment.view->imageInfo().layout,
attachment.view->imageInfo().stages,
attachment.view->imageInfo().access);
}
}
}
void DxvkContext::renderPassBindFramebuffer(
const Rc<DxvkFramebuffer>& framebuffer,
const DxvkRenderPassOps& ops,
@ -4129,7 +4100,7 @@ namespace dxvk {
if (m_flags.test(DxvkContextFlag::GpDirtyFramebuffer)) {
m_flags.clr(DxvkContextFlag::GpDirtyFramebuffer);
this->spillRenderPass();
this->spillRenderPass(false);
auto fb = m_device->createFramebuffer(m_state.om.renderTargets);
@ -4334,12 +4305,8 @@ namespace dxvk {
bool DxvkContext::commitComputeState() {
if (m_flags.test(DxvkContextFlag::GpRenderPassBound))
this->spillRenderPass();
this->spillRenderPass();
if (m_flags.test(DxvkContextFlag::GpClearRenderTargets))
this->clearRenderPass();
if (m_flags.test(DxvkContextFlag::CpDirtyPipeline)) {
if (unlikely(!this->updateComputePipeline()))
return false;

View File

@ -1040,6 +1040,8 @@ namespace dxvk {
DxvkBindingSet<MaxNumVertexBindings + 1> m_vbTracked;
DxvkBindingSet<MaxNumResourceSlots> m_rcTracked;
std::vector<DxvkDeferredClear> m_deferredClears;
std::array<DxvkShaderResourceSlot, MaxNumResourceSlots> m_rc;
std::array<DxvkGraphicsPipeline*, 4096> m_gpLookupCache = { };
std::array<DxvkComputePipeline*, 256> m_cpLookupCache = { };
@ -1119,6 +1121,14 @@ namespace dxvk {
VkImageAspectFlags clearAspects,
VkClearValue clearValue);
void deferClear(
const Rc<DxvkImageView>& imageView,
VkImageAspectFlags clearAspects,
VkClearValue clearValue);
void flushClears(
bool useRenderPass);
void updatePredicate(
const DxvkBufferSliceHandle& predicate,
const DxvkGpuQueryHandle& query);
@ -1126,8 +1136,7 @@ namespace dxvk {
void commitPredicateUpdates();
void startRenderPass();
void spillRenderPass();
void clearRenderPass();
void spillRenderPass(bool flushClears = true);
void renderPassBindFramebuffer(
const Rc<DxvkFramebuffer>& framebuffer,

View File

@ -24,7 +24,6 @@ namespace dxvk {
GpRenderPassBound, ///< Render pass is currently bound
GpCondActive, ///< Conditional rendering is enabled
GpXfbActive, ///< Transform feedback is enabled
GpClearRenderTargets, ///< Render targets need to be cleared
GpDirtyFramebuffer, ///< Framebuffer binding is out of date
GpDirtyPipeline, ///< Graphics pipeline binding is out of date
GpDirtyPipelineState, ///< Graphics pipeline needs to be recompiled
@ -148,6 +147,13 @@ namespace dxvk {
DxvkBufferSlice predicate;
VkConditionalRenderingFlagsEXT flags;
};
struct DxvkDeferredClear {
Rc<DxvkImageView> imageView;
VkImageAspectFlags clearAspects;
VkClearValue clearValue;
};
/**