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

[dxvk] Track current render target image layouts

This can be used to optimize away some barriers and layout transitions.
This commit is contained in:
Philip Rebohle 2021-02-09 17:53:25 +01:00
parent 2787ba8450
commit 29afaea338
No known key found for this signature in database
GPG Key ID: C8CC613427A31C99
3 changed files with 158 additions and 23 deletions

View File

@ -1720,8 +1720,9 @@ namespace dxvk {
if (clearAspects & VK_IMAGE_ASPECT_STENCIL_BIT) if (clearAspects & VK_IMAGE_ASPECT_STENCIL_BIT)
depthOp.loadOpS = VK_ATTACHMENT_LOAD_OP_CLEAR; depthOp.loadOpS = VK_ATTACHMENT_LOAD_OP_CLEAR;
if (clearAspects == imageView->info().aspect bool is3D = imageView->imageInfo().type != VK_IMAGE_TYPE_3D;
&& imageView->imageInfo().type != VK_IMAGE_TYPE_3D) {
if (clearAspects == imageView->info().aspect && !is3D) {
colorOp.loadLayout = VK_IMAGE_LAYOUT_UNDEFINED; colorOp.loadLayout = VK_IMAGE_LAYOUT_UNDEFINED;
depthOp.loadLayout = VK_IMAGE_LAYOUT_UNDEFINED; depthOp.loadLayout = VK_IMAGE_LAYOUT_UNDEFINED;
} }
@ -1789,7 +1790,9 @@ namespace dxvk {
} else { } else {
// Perform the clear when starting the render pass // Perform the clear when starting the render pass
if (clearAspects & VK_IMAGE_ASPECT_COLOR_BIT) { if (clearAspects & VK_IMAGE_ASPECT_COLOR_BIT) {
m_state.om.renderPassOps.colorOps[attachmentIndex] = colorOp; m_state.om.renderPassOps.colorOps[attachmentIndex].loadOp = colorOp.loadOp;
if (m_state.om.renderPassOps.colorOps[attachmentIndex].loadOp == VK_ATTACHMENT_LOAD_OP_CLEAR && !is3D)
m_state.om.renderPassOps.colorOps[attachmentIndex].loadLayout = VK_IMAGE_LAYOUT_UNDEFINED;
m_state.om.clearValues[attachmentIndex].color = clearValue.color; m_state.om.clearValues[attachmentIndex].color = clearValue.color;
} }
@ -1804,9 +1807,6 @@ namespace dxvk {
} }
if (clearAspects & (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT)) { if (clearAspects & (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT)) {
m_state.om.renderPassOps.depthOps.loadLayout = depthOp.loadLayout;
m_state.om.renderPassOps.depthOps.storeLayout = depthOp.storeLayout;
if (m_state.om.renderPassOps.depthOps.loadOpD == VK_ATTACHMENT_LOAD_OP_CLEAR if (m_state.om.renderPassOps.depthOps.loadOpD == VK_ATTACHMENT_LOAD_OP_CLEAR
&& 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;
@ -3384,6 +3384,7 @@ namespace dxvk {
void DxvkContext::startRenderPass() { void DxvkContext::startRenderPass() {
if (!m_flags.test(DxvkContextFlag::GpRenderPassBound)) { if (!m_flags.test(DxvkContextFlag::GpRenderPassBound)) {
this->applyRenderTargetLoadLayouts();
this->flushClears(true); this->flushClears(true);
m_flags.set(DxvkContextFlag::GpRenderPassBound); m_flags.set(DxvkContextFlag::GpRenderPassBound);
@ -3396,6 +3397,9 @@ namespace dxvk {
m_state.om.clearValues.size(), m_state.om.clearValues.size(),
m_state.om.clearValues.data()); m_state.om.clearValues.data());
// Track the final layout of each render target
this->applyRenderTargetStoreLayouts();
// Don't discard image contents if we have // Don't discard image contents if we have
// to spill the current render pass // to spill the current render pass
this->resetRenderPassOps( this->resetRenderPassOps(
@ -3419,16 +3423,15 @@ namespace dxvk {
m_queryManager.endQueries(m_cmd, VK_QUERY_TYPE_PIPELINE_STATISTICS); m_queryManager.endQueries(m_cmd, VK_QUERY_TYPE_PIPELINE_STATISTICS);
this->renderPassUnbindFramebuffer(); this->renderPassUnbindFramebuffer();
this->transitionRenderTargetLayouts(m_gfxBarriers);
m_gfxBarriers.recordCommands(m_cmd); m_gfxBarriers.recordCommands(m_cmd);
m_gfxBarriers.reset();
this->unbindGraphicsPipeline(); this->unbindGraphicsPipeline();
m_flags.clr(DxvkContextFlag::GpDirtyXfbCounters); m_flags.clr(DxvkContextFlag::GpDirtyXfbCounters);
} else if (flushClears) { } else if (flushClears) {
// We defer clears with a render pass bound, // Execute deferred clears if necessary
// no need to call this for the common path.
this->flushClears(false); this->flushClears(false);
} }
} }
@ -3496,10 +3499,8 @@ namespace dxvk {
if (renderTargets.depth.view != nullptr) { if (renderTargets.depth.view != nullptr) {
renderPassOps.depthOps = DxvkDepthAttachmentOps { renderPassOps.depthOps = DxvkDepthAttachmentOps {
VK_ATTACHMENT_LOAD_OP_LOAD, VK_ATTACHMENT_LOAD_OP_LOAD, VK_ATTACHMENT_LOAD_OP_LOAD,
VK_ATTACHMENT_LOAD_OP_LOAD, renderTargets.depth.layout, renderTargets.depth.layout };
renderTargets.depth.view->imageInfo().layout,
renderTargets.depth.view->imageInfo().layout };
renderPassOps.barrier.srcStages |= VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT renderPassOps.barrier.srcStages |= VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT
| VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT; | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT;
@ -3516,8 +3517,8 @@ namespace dxvk {
if (renderTargets.color[i].view != nullptr) { if (renderTargets.color[i].view != nullptr) {
renderPassOps.colorOps[i] = DxvkColorAttachmentOps { renderPassOps.colorOps[i] = DxvkColorAttachmentOps {
VK_ATTACHMENT_LOAD_OP_LOAD, VK_ATTACHMENT_LOAD_OP_LOAD,
renderTargets.color[i].view->imageInfo().layout, renderTargets.color[i].layout,
renderTargets.color[i].view->imageInfo().layout }; renderTargets.color[i].layout };
renderPassOps.barrier.srcStages |= VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; renderPassOps.barrier.srcStages |= VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
renderPassOps.barrier.srcAccess |= VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; renderPassOps.barrier.srcAccess |= VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
@ -3526,11 +3527,6 @@ namespace dxvk {
renderPassOps.colorOps[i] = DxvkColorAttachmentOps { }; renderPassOps.colorOps[i] = DxvkColorAttachmentOps { };
} }
} }
if (renderPassOps.colorOps[0].loadLayout == VK_IMAGE_LAYOUT_PRESENT_SRC_KHR) {
renderPassOps.colorOps[0].loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
renderPassOps.colorOps[0].loadLayout = VK_IMAGE_LAYOUT_UNDEFINED;
}
} }
@ -3980,6 +3976,7 @@ namespace dxvk {
this->spillRenderPass(false); this->spillRenderPass(false);
auto fb = m_device->createFramebuffer(m_state.om.renderTargets); auto fb = m_device->createFramebuffer(m_state.om.renderTargets);
this->updateRenderTargetLayouts(fb, m_state.om.framebuffer);
m_state.gp.state.ms.setSampleCount(fb->getSampleCount()); m_state.gp.state.ms.setSampleCount(fb->getSampleCount());
m_state.om.framebuffer = fb; m_state.om.framebuffer = fb;
@ -3999,6 +3996,122 @@ namespace dxvk {
} }
void DxvkContext::applyRenderTargetLoadLayouts() {
for (uint32_t i = 0; i < MaxNumRenderTargets; i++)
m_state.om.renderPassOps.colorOps[i].loadLayout = m_rtLayouts.color[i];
m_state.om.renderPassOps.depthOps.loadLayout = m_rtLayouts.depth;
// Always discard swap chain images since we currently don't have a better solution for this.
if (m_state.om.renderPassOps.colorOps[0].loadLayout == VK_IMAGE_LAYOUT_PRESENT_SRC_KHR) {
m_state.om.renderPassOps.colorOps[0].loadLayout = VK_IMAGE_LAYOUT_UNDEFINED;
m_state.om.renderPassOps.colorOps[0].loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
}
}
void DxvkContext::applyRenderTargetStoreLayouts() {
for (uint32_t i = 0; i < MaxNumRenderTargets; i++)
m_rtLayouts.color[i] = m_state.om.renderPassOps.colorOps[i].storeLayout;
m_rtLayouts.depth = m_state.om.renderPassOps.depthOps.storeLayout;
}
void DxvkContext::transitionRenderTargetLayouts(
DxvkBarrierSet& barriers) {
for (uint32_t i = 0; i < MaxNumRenderTargets; i++) {
const DxvkAttachment& color = m_state.om.framebuffer->getColorTarget(i);
if (color.view != nullptr) {
barriers.accessImage(
color.view->image(),
color.view->subresources(),
m_rtLayouts.color[i],
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
color.view->imageInfo().layout,
color.view->imageInfo().stages,
color.view->imageInfo().access);
m_rtLayouts.color[i] = color.view->imageInfo().layout;
}
}
const DxvkAttachment& depth = m_state.om.framebuffer->getDepthTarget();
if (depth.view != nullptr) {
barriers.accessImage(
depth.view->image(),
depth.view->subresources(),
m_rtLayouts.depth,
VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT |
VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT,
m_rtLayouts.depth != VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL
? VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT : 0,
depth.view->imageInfo().layout,
depth.view->imageInfo().stages,
depth.view->imageInfo().access);
m_rtLayouts.depth = depth.view->imageInfo().layout;
}
}
void DxvkContext::updateRenderTargetLayouts(
const Rc<DxvkFramebuffer>& newFb,
const Rc<DxvkFramebuffer>& oldFb) {
DxvkRenderTargetLayouts layouts = { };
for (uint32_t i = 0; i < MaxNumRenderTargets; i++) {
if (newFb->getColorTarget(i).view != nullptr)
layouts.color[i] = newFb->getColorTarget(i).view->imageInfo().layout;
}
if (newFb->getDepthTarget().view != nullptr)
layouts.depth = newFb->getDepthTarget().view->imageInfo().layout;
if (oldFb != nullptr) {
// Check whether any of the previous attachments have been moved
// around or been rebound with a different view. This may help
// reduce the number of image layout transitions between passes.
for (uint32_t i = 0; i < MaxNumRenderTargets; i++) {
const DxvkAttachment& oldAttachment = oldFb->getColorTarget(i);
if (oldAttachment.view != nullptr) {
bool found = false;
for (uint32_t j = 0; j < MaxNumRenderTargets && !found; j++) {
const DxvkAttachment& newAttachment = newFb->getColorTarget(j);
found = newAttachment.view == oldAttachment.view || (newAttachment.view != nullptr
&& newAttachment.view->image() == oldAttachment.view->image()
&& newAttachment.view->subresources() == oldAttachment.view->subresources());
if (found)
layouts.color[j] = m_rtLayouts.color[i];
}
}
}
const DxvkAttachment& oldAttachment = oldFb->getDepthTarget();
if (oldAttachment.view != nullptr) {
const DxvkAttachment& newAttachment = newFb->getDepthTarget();
bool found = newAttachment.view == oldAttachment.view || (newAttachment.view != nullptr
&& newAttachment.view->image() == oldAttachment.view->image()
&& newAttachment.view->subresources() == oldAttachment.view->subresources());
if (found)
layouts.depth = m_rtLayouts.depth;
}
}
m_rtLayouts = layouts;
}
bool DxvkContext::updateIndexBufferBinding() { bool DxvkContext::updateIndexBufferBinding() {
if (unlikely(!m_state.vi.indexBuffer.defined())) if (unlikely(!m_state.vi.indexBuffer.defined()))
return false; return false;

View File

@ -1006,6 +1006,8 @@ namespace dxvk {
DxvkGpuQueryManager m_queryManager; DxvkGpuQueryManager m_queryManager;
DxvkStagingDataAlloc m_staging; DxvkStagingDataAlloc m_staging;
DxvkRenderTargetLayouts m_rtLayouts = { };
VkPipeline m_gpActivePipeline = VK_NULL_HANDLE; VkPipeline m_gpActivePipeline = VK_NULL_HANDLE;
VkPipeline m_cpActivePipeline = VK_NULL_HANDLE; VkPipeline m_cpActivePipeline = VK_NULL_HANDLE;
@ -1139,6 +1141,17 @@ namespace dxvk {
void updateFramebuffer(); void updateFramebuffer();
void applyRenderTargetLoadLayouts();
void applyRenderTargetStoreLayouts();
void transitionRenderTargetLayouts(
DxvkBarrierSet& barriers);
void updateRenderTargetLayouts(
const Rc<DxvkFramebuffer>& newFb,
const Rc<DxvkFramebuffer>& oldFb);
bool updateIndexBufferBinding(); bool updateIndexBufferBinding();
void updateVertexBufferBindings(); void updateVertexBufferBindings();

View File

@ -43,6 +43,15 @@ namespace dxvk {
}; };
/**
* \brief Render target layouts
*/
struct DxvkRenderTargetLayouts {
VkImageLayout color[MaxNumRenderTargets];
VkImageLayout depth;
};
/** /**
* \brief Framebuffer * \brief Framebuffer
* *