mirror of
https://github.com/doitsujin/dxvk.git
synced 2024-12-03 04: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.
|
// before any draw or dispatch command is recorded.
|
||||||
m_flags.clr(
|
m_flags.clr(
|
||||||
DxvkContextFlag::GpRenderPassBound,
|
DxvkContextFlag::GpRenderPassBound,
|
||||||
DxvkContextFlag::GpXfbActive,
|
DxvkContextFlag::GpXfbActive);
|
||||||
DxvkContextFlag::GpClearRenderTargets);
|
|
||||||
|
|
||||||
m_flags.set(
|
m_flags.set(
|
||||||
DxvkContextFlag::GpDirtyFramebuffer,
|
DxvkContextFlag::GpDirtyFramebuffer,
|
||||||
@ -98,10 +97,6 @@ namespace dxvk {
|
|||||||
|
|
||||||
void DxvkContext::bindRenderTargets(
|
void DxvkContext::bindRenderTargets(
|
||||||
const DxvkRenderTargets& targets) {
|
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
|
// Set up default render pass ops
|
||||||
m_state.om.renderTargets = targets;
|
m_state.om.renderTargets = targets;
|
||||||
|
|
||||||
@ -569,8 +564,6 @@ namespace dxvk {
|
|||||||
const Rc<DxvkImageView>& imageView,
|
const Rc<DxvkImageView>& imageView,
|
||||||
VkImageAspectFlags clearAspects,
|
VkImageAspectFlags clearAspects,
|
||||||
VkClearValue clearValue) {
|
VkClearValue clearValue) {
|
||||||
this->updateFramebuffer();
|
|
||||||
|
|
||||||
// Make sure the color components are ordered correctly
|
// Make sure the color components are ordered correctly
|
||||||
if (clearAspects & VK_IMAGE_ASPECT_COLOR_BIT) {
|
if (clearAspects & VK_IMAGE_ASPECT_COLOR_BIT) {
|
||||||
clearValue.color = util::swizzleClearColor(clearValue.color,
|
clearValue.color = util::swizzleClearColor(clearValue.color,
|
||||||
@ -582,13 +575,18 @@ namespace dxvk {
|
|||||||
// If not, we need to create a temporary framebuffer.
|
// If not, we need to create a temporary framebuffer.
|
||||||
int32_t attachmentIndex = -1;
|
int32_t attachmentIndex = -1;
|
||||||
|
|
||||||
if (m_state.om.framebuffer->isFullSize(imageView) && this->checkFramebufferBarrier().isClear())
|
if (m_flags.test(DxvkContextFlag::GpRenderPassBound)) {
|
||||||
attachmentIndex = m_state.om.framebuffer->findAttachment(imageView);
|
if (m_state.om.framebuffer->isFullSize(imageView) && this->checkFramebufferBarrier().isClear())
|
||||||
|
attachmentIndex = m_state.om.framebuffer->findAttachment(imageView);
|
||||||
|
|
||||||
if (attachmentIndex < 0)
|
if (attachmentIndex < 1)
|
||||||
this->spillRenderPass();
|
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.loadOpS == VK_ATTACHMENT_LOAD_OP_CLEAR)
|
||||||
m_state.om.renderPassOps.depthOps.loadLayout = VK_IMAGE_LAYOUT_UNDEFINED;
|
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(
|
void DxvkContext::updateBuffer(
|
||||||
const Rc<DxvkBuffer>& buffer,
|
const Rc<DxvkBuffer>& buffer,
|
||||||
VkDeviceSize offset,
|
VkDeviceSize offset,
|
||||||
@ -3432,8 +3451,9 @@ namespace dxvk {
|
|||||||
|
|
||||||
void DxvkContext::startRenderPass() {
|
void DxvkContext::startRenderPass() {
|
||||||
if (!m_flags.test(DxvkContextFlag::GpRenderPassBound)) {
|
if (!m_flags.test(DxvkContextFlag::GpRenderPassBound)) {
|
||||||
|
this->flushClears(true);
|
||||||
|
|
||||||
m_flags.set(DxvkContextFlag::GpRenderPassBound);
|
m_flags.set(DxvkContextFlag::GpRenderPassBound);
|
||||||
m_flags.clr(DxvkContextFlag::GpClearRenderTargets);
|
|
||||||
|
|
||||||
m_execBarriers.recordCommands(m_cmd);
|
m_execBarriers.recordCommands(m_cmd);
|
||||||
|
|
||||||
@ -3456,10 +3476,7 @@ namespace dxvk {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void DxvkContext::spillRenderPass() {
|
void DxvkContext::spillRenderPass(bool flushClears) {
|
||||||
if (m_flags.test(DxvkContextFlag::GpClearRenderTargets))
|
|
||||||
this->clearRenderPass();
|
|
||||||
|
|
||||||
if (m_flags.test(DxvkContextFlag::GpRenderPassBound)) {
|
if (m_flags.test(DxvkContextFlag::GpRenderPassBound)) {
|
||||||
m_flags.clr(DxvkContextFlag::GpRenderPassBound);
|
m_flags.clr(DxvkContextFlag::GpRenderPassBound);
|
||||||
|
|
||||||
@ -3475,56 +3492,10 @@ namespace dxvk {
|
|||||||
this->commitPredicateUpdates();
|
this->commitPredicateUpdates();
|
||||||
|
|
||||||
m_flags.clr(DxvkContextFlag::GpDirtyXfbCounters);
|
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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -4129,7 +4100,7 @@ namespace dxvk {
|
|||||||
if (m_flags.test(DxvkContextFlag::GpDirtyFramebuffer)) {
|
if (m_flags.test(DxvkContextFlag::GpDirtyFramebuffer)) {
|
||||||
m_flags.clr(DxvkContextFlag::GpDirtyFramebuffer);
|
m_flags.clr(DxvkContextFlag::GpDirtyFramebuffer);
|
||||||
|
|
||||||
this->spillRenderPass();
|
this->spillRenderPass(false);
|
||||||
|
|
||||||
auto fb = m_device->createFramebuffer(m_state.om.renderTargets);
|
auto fb = m_device->createFramebuffer(m_state.om.renderTargets);
|
||||||
|
|
||||||
@ -4334,11 +4305,7 @@ namespace dxvk {
|
|||||||
|
|
||||||
|
|
||||||
bool DxvkContext::commitComputeState() {
|
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 (m_flags.test(DxvkContextFlag::CpDirtyPipeline)) {
|
||||||
if (unlikely(!this->updateComputePipeline()))
|
if (unlikely(!this->updateComputePipeline()))
|
||||||
|
@ -1040,6 +1040,8 @@ namespace dxvk {
|
|||||||
DxvkBindingSet<MaxNumVertexBindings + 1> m_vbTracked;
|
DxvkBindingSet<MaxNumVertexBindings + 1> m_vbTracked;
|
||||||
DxvkBindingSet<MaxNumResourceSlots> m_rcTracked;
|
DxvkBindingSet<MaxNumResourceSlots> m_rcTracked;
|
||||||
|
|
||||||
|
std::vector<DxvkDeferredClear> m_deferredClears;
|
||||||
|
|
||||||
std::array<DxvkShaderResourceSlot, MaxNumResourceSlots> m_rc;
|
std::array<DxvkShaderResourceSlot, MaxNumResourceSlots> m_rc;
|
||||||
std::array<DxvkGraphicsPipeline*, 4096> m_gpLookupCache = { };
|
std::array<DxvkGraphicsPipeline*, 4096> m_gpLookupCache = { };
|
||||||
std::array<DxvkComputePipeline*, 256> m_cpLookupCache = { };
|
std::array<DxvkComputePipeline*, 256> m_cpLookupCache = { };
|
||||||
@ -1119,6 +1121,14 @@ namespace dxvk {
|
|||||||
VkImageAspectFlags clearAspects,
|
VkImageAspectFlags clearAspects,
|
||||||
VkClearValue clearValue);
|
VkClearValue clearValue);
|
||||||
|
|
||||||
|
void deferClear(
|
||||||
|
const Rc<DxvkImageView>& imageView,
|
||||||
|
VkImageAspectFlags clearAspects,
|
||||||
|
VkClearValue clearValue);
|
||||||
|
|
||||||
|
void flushClears(
|
||||||
|
bool useRenderPass);
|
||||||
|
|
||||||
void updatePredicate(
|
void updatePredicate(
|
||||||
const DxvkBufferSliceHandle& predicate,
|
const DxvkBufferSliceHandle& predicate,
|
||||||
const DxvkGpuQueryHandle& query);
|
const DxvkGpuQueryHandle& query);
|
||||||
@ -1126,8 +1136,7 @@ namespace dxvk {
|
|||||||
void commitPredicateUpdates();
|
void commitPredicateUpdates();
|
||||||
|
|
||||||
void startRenderPass();
|
void startRenderPass();
|
||||||
void spillRenderPass();
|
void spillRenderPass(bool flushClears = true);
|
||||||
void clearRenderPass();
|
|
||||||
|
|
||||||
void renderPassBindFramebuffer(
|
void renderPassBindFramebuffer(
|
||||||
const Rc<DxvkFramebuffer>& framebuffer,
|
const Rc<DxvkFramebuffer>& framebuffer,
|
||||||
|
@ -24,7 +24,6 @@ namespace dxvk {
|
|||||||
GpRenderPassBound, ///< Render pass is currently bound
|
GpRenderPassBound, ///< Render pass is currently bound
|
||||||
GpCondActive, ///< Conditional rendering is enabled
|
GpCondActive, ///< Conditional rendering is enabled
|
||||||
GpXfbActive, ///< Transform feedback is enabled
|
GpXfbActive, ///< Transform feedback is enabled
|
||||||
GpClearRenderTargets, ///< Render targets need to be cleared
|
|
||||||
GpDirtyFramebuffer, ///< Framebuffer binding is out of date
|
GpDirtyFramebuffer, ///< Framebuffer binding is out of date
|
||||||
GpDirtyPipeline, ///< Graphics pipeline binding is out of date
|
GpDirtyPipeline, ///< Graphics pipeline binding is out of date
|
||||||
GpDirtyPipelineState, ///< Graphics pipeline needs to be recompiled
|
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
|
* \brief Pipeline state
|
||||||
*
|
*
|
||||||
|
Loading…
Reference in New Issue
Block a user