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:
parent
3cbd109020
commit
b9c56e3e97
@ -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,56 +3492,10 @@ namespace dxvk {
|
||||
this->commitPredicateUpdates();
|
||||
|
||||
m_flags.clr(DxvkContextFlag::GpDirtyXfbCounters);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
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);
|
||||
}
|
||||
} else if (flushClears) {
|
||||
// We defer clears with a render pass bound,
|
||||
// no need to call this for the common path.
|
||||
this->flushClears(false);
|
||||
}
|
||||
}
|
||||
|
||||
@ -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,11 +4305,7 @@ namespace dxvk {
|
||||
|
||||
|
||||
bool DxvkContext::commitComputeState() {
|
||||
if (m_flags.test(DxvkContextFlag::GpRenderPassBound))
|
||||
this->spillRenderPass();
|
||||
|
||||
if (m_flags.test(DxvkContextFlag::GpClearRenderTargets))
|
||||
this->clearRenderPass();
|
||||
this->spillRenderPass();
|
||||
|
||||
if (m_flags.test(DxvkContextFlag::CpDirtyPipeline)) {
|
||||
if (unlikely(!this->updateComputePipeline()))
|
||||
|
@ -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,
|
||||
|
@ -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
|
||||
@ -150,6 +149,13 @@ namespace dxvk {
|
||||
};
|
||||
|
||||
|
||||
struct DxvkDeferredClear {
|
||||
Rc<DxvkImageView> imageView;
|
||||
VkImageAspectFlags clearAspects;
|
||||
VkClearValue clearValue;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* \brief Pipeline state
|
||||
*
|
||||
|
Loading…
Reference in New Issue
Block a user