mirror of
https://github.com/EduApps-CDG/OpenDX
synced 2024-12-30 09:45:37 +01:00
[dxvk] Oprimize render target clear operations
We can save one image layout transition when clearing a render target by delaying clears until vkCmdBeginRenderPass is called.
This commit is contained in:
parent
16a25db846
commit
5d5be87402
@ -29,7 +29,8 @@ namespace dxvk {
|
|||||||
// undefined, so we have to bind and set up everything
|
// undefined, so we have to bind and set up everything
|
||||||
// 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::GpClearRenderTargets);
|
||||||
|
|
||||||
m_flags.set(
|
m_flags.set(
|
||||||
DxvkContextFlag::GpDirtyPipeline,
|
DxvkContextFlag::GpDirtyPipeline,
|
||||||
@ -88,7 +89,9 @@ namespace dxvk {
|
|||||||
void DxvkContext::bindRenderTargets(const DxvkRenderTargets& targets) {
|
void DxvkContext::bindRenderTargets(const DxvkRenderTargets& targets) {
|
||||||
m_state.om.renderTargets = targets;
|
m_state.om.renderTargets = targets;
|
||||||
|
|
||||||
// TODO execute pending clears
|
// If necessary, perform clears on the active render targets
|
||||||
|
if (m_flags.test(DxvkContextFlag::GpClearRenderTargets))
|
||||||
|
this->startRenderPass();
|
||||||
|
|
||||||
// Set up default render pass ops
|
// Set up default render pass ops
|
||||||
this->resetRenderPassOps(
|
this->resetRenderPassOps(
|
||||||
@ -398,8 +401,8 @@ namespace dxvk {
|
|||||||
this->spillRenderPass();
|
this->spillRenderPass();
|
||||||
|
|
||||||
DxvkAttachmentOps op;
|
DxvkAttachmentOps op;
|
||||||
op.loadOp = VK_ATTACHMENT_LOAD_OP_LOAD;
|
op.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
|
||||||
op.loadLayout = imageView->imageInfo().layout;
|
op.loadLayout = VK_IMAGE_LAYOUT_UNDEFINED;
|
||||||
op.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
|
op.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
|
||||||
op.storeLayout = imageView->imageInfo().layout;
|
op.storeLayout = imageView->imageInfo().layout;
|
||||||
|
|
||||||
@ -418,29 +421,33 @@ namespace dxvk {
|
|||||||
}
|
}
|
||||||
|
|
||||||
this->renderPassBindFramebuffer(
|
this->renderPassBindFramebuffer(
|
||||||
m_device->createFramebuffer(attachments), ops);
|
m_device->createFramebuffer(attachments),
|
||||||
} else {
|
ops, 1, &clearValue);
|
||||||
// Make sure that the currently bound
|
|
||||||
// framebuffer can be rendered to
|
|
||||||
this->startRenderPass();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Clear the attachment in quesion
|
|
||||||
VkClearAttachment clearInfo;
|
|
||||||
clearInfo.aspectMask = clearAspects;
|
|
||||||
clearInfo.colorAttachment = attachmentIndex;
|
|
||||||
clearInfo.clearValue = clearValue;
|
|
||||||
|
|
||||||
if (attachmentIndex < 0)
|
|
||||||
clearInfo.colorAttachment = 0;
|
|
||||||
|
|
||||||
m_cmd->cmdClearAttachments(
|
|
||||||
1, &clearInfo, 1, &clearRect);
|
|
||||||
|
|
||||||
// If we used a temporary framebuffer, we'll have to unbind it
|
|
||||||
// again in order to not disturb subsequent rendering commands.
|
|
||||||
if (attachmentIndex < 0)
|
|
||||||
this->renderPassUnbindFramebuffer();
|
this->renderPassUnbindFramebuffer();
|
||||||
|
} else if (m_flags.test(DxvkContextFlag::GpRenderPassBound)) {
|
||||||
|
// Clear the attachment in quesion. For color images,
|
||||||
|
// the attachment index for the current subpass is
|
||||||
|
// equal to the render pass attachment index.
|
||||||
|
VkClearAttachment clearInfo;
|
||||||
|
clearInfo.aspectMask = clearAspects;
|
||||||
|
clearInfo.colorAttachment = attachmentIndex;
|
||||||
|
clearInfo.clearValue = clearValue;
|
||||||
|
|
||||||
|
m_cmd->cmdClearAttachments(
|
||||||
|
1, &clearInfo, 1, &clearRect);
|
||||||
|
} else {
|
||||||
|
// Perform the clear when starting the render pass
|
||||||
|
if (clearAspects & VK_IMAGE_ASPECT_COLOR_BIT) {
|
||||||
|
m_state.om.renderPassOps.colorOps[attachmentIndex].loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
|
||||||
|
m_state.om.renderPassOps.colorOps[attachmentIndex].loadLayout = VK_IMAGE_LAYOUT_UNDEFINED;
|
||||||
|
} else {
|
||||||
|
m_state.om.renderPassOps.depthOps.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
|
||||||
|
m_state.om.renderPassOps.depthOps.loadLayout = VK_IMAGE_LAYOUT_UNDEFINED;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_state.om.clearValues[attachmentIndex] = clearValue;
|
||||||
|
m_flags.set(DxvkContextFlag::GpClearRenderTargets);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -1515,10 +1522,13 @@ namespace dxvk {
|
|||||||
if (!m_flags.test(DxvkContextFlag::GpRenderPassBound)
|
if (!m_flags.test(DxvkContextFlag::GpRenderPassBound)
|
||||||
&& (m_state.om.framebuffer != nullptr)) {
|
&& (m_state.om.framebuffer != nullptr)) {
|
||||||
m_flags.set(DxvkContextFlag::GpRenderPassBound);
|
m_flags.set(DxvkContextFlag::GpRenderPassBound);
|
||||||
|
m_flags.clr(DxvkContextFlag::GpClearRenderTargets);
|
||||||
|
|
||||||
this->renderPassBindFramebuffer(
|
this->renderPassBindFramebuffer(
|
||||||
m_state.om.framebuffer,
|
m_state.om.framebuffer,
|
||||||
m_state.om.renderPassOps);
|
m_state.om.renderPassOps,
|
||||||
|
m_state.om.clearValues.size(),
|
||||||
|
m_state.om.clearValues.data());
|
||||||
|
|
||||||
// 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
|
||||||
@ -1530,7 +1540,8 @@ namespace dxvk {
|
|||||||
|
|
||||||
|
|
||||||
void DxvkContext::spillRenderPass() {
|
void DxvkContext::spillRenderPass() {
|
||||||
// TODO execute pending clears
|
if (m_flags.test(DxvkContextFlag::GpClearRenderTargets))
|
||||||
|
this->startRenderPass();
|
||||||
|
|
||||||
if (m_flags.test(DxvkContextFlag::GpRenderPassBound)) {
|
if (m_flags.test(DxvkContextFlag::GpRenderPassBound)) {
|
||||||
m_flags.clr(DxvkContextFlag::GpRenderPassBound);
|
m_flags.clr(DxvkContextFlag::GpRenderPassBound);
|
||||||
@ -1541,7 +1552,9 @@ namespace dxvk {
|
|||||||
|
|
||||||
void DxvkContext::renderPassBindFramebuffer(
|
void DxvkContext::renderPassBindFramebuffer(
|
||||||
const Rc<DxvkFramebuffer>& framebuffer,
|
const Rc<DxvkFramebuffer>& framebuffer,
|
||||||
const DxvkRenderPassOps& ops) {
|
const DxvkRenderPassOps& ops,
|
||||||
|
uint32_t clearValueCount,
|
||||||
|
const VkClearValue* clearValues) {
|
||||||
const DxvkFramebufferSize fbSize = framebuffer->size();
|
const DxvkFramebufferSize fbSize = framebuffer->size();
|
||||||
|
|
||||||
VkRect2D renderArea;
|
VkRect2D renderArea;
|
||||||
@ -1554,8 +1567,8 @@ namespace dxvk {
|
|||||||
info.renderPass = framebuffer->getRenderPassHandle(ops);
|
info.renderPass = framebuffer->getRenderPassHandle(ops);
|
||||||
info.framebuffer = framebuffer->handle();
|
info.framebuffer = framebuffer->handle();
|
||||||
info.renderArea = renderArea;
|
info.renderArea = renderArea;
|
||||||
info.clearValueCount = 0;
|
info.clearValueCount = clearValueCount;
|
||||||
info.pClearValues = nullptr;
|
info.pClearValues = clearValues;
|
||||||
|
|
||||||
m_cmd->cmdBeginRenderPass(&info,
|
m_cmd->cmdBeginRenderPass(&info,
|
||||||
VK_SUBPASS_CONTENTS_INLINE);
|
VK_SUBPASS_CONTENTS_INLINE);
|
||||||
|
@ -644,7 +644,9 @@ namespace dxvk {
|
|||||||
|
|
||||||
void renderPassBindFramebuffer(
|
void renderPassBindFramebuffer(
|
||||||
const Rc<DxvkFramebuffer>& framebuffer,
|
const Rc<DxvkFramebuffer>& framebuffer,
|
||||||
const DxvkRenderPassOps& ops);
|
const DxvkRenderPassOps& ops,
|
||||||
|
uint32_t clearValueCount,
|
||||||
|
const VkClearValue* clearValues);
|
||||||
|
|
||||||
void renderPassUnbindFramebuffer();
|
void renderPassUnbindFramebuffer();
|
||||||
|
|
||||||
|
@ -16,12 +16,13 @@ namespace dxvk {
|
|||||||
/**
|
/**
|
||||||
* \brief Graphics pipeline state flags
|
* \brief Graphics pipeline state flags
|
||||||
*
|
*
|
||||||
* Stores some information on which state of the
|
* Stores some information on which state
|
||||||
* graphics pipeline has changed and/or needs to
|
* of the graphics and compute pipelines
|
||||||
* be updated.
|
* has changed and/or needs to be updated.
|
||||||
*/
|
*/
|
||||||
enum class DxvkContextFlag : uint64_t {
|
enum class DxvkContextFlag : uint64_t {
|
||||||
GpRenderPassBound, ///< Render pass is currently bound
|
GpRenderPassBound, ///< Render pass is currently bound
|
||||||
|
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
|
||||||
@ -54,7 +55,7 @@ namespace dxvk {
|
|||||||
|
|
||||||
|
|
||||||
struct DxvkOutputMergerState {
|
struct DxvkOutputMergerState {
|
||||||
std::array<VkClearValue, MaxNumRenderTargets + 1> clearValue;
|
std::array<VkClearValue, MaxNumRenderTargets + 1> clearValues = { };
|
||||||
|
|
||||||
DxvkRenderTargets renderTargets;
|
DxvkRenderTargets renderTargets;
|
||||||
DxvkRenderPassOps renderPassOps;
|
DxvkRenderPassOps renderPassOps;
|
||||||
|
@ -13,20 +13,18 @@ namespace dxvk {
|
|||||||
m_renderSize (computeRenderSize(defaultSize)) {
|
m_renderSize (computeRenderSize(defaultSize)) {
|
||||||
std::array<VkImageView, MaxNumRenderTargets + 1> views;
|
std::array<VkImageView, MaxNumRenderTargets + 1> views;
|
||||||
|
|
||||||
uint32_t viewId = 0;
|
|
||||||
|
|
||||||
for (uint32_t i = 0; i < MaxNumRenderTargets; i++) {
|
for (uint32_t i = 0; i < MaxNumRenderTargets; i++) {
|
||||||
if (m_renderTargets.color[i].view != nullptr) {
|
if (m_renderTargets.color[i].view != nullptr) {
|
||||||
views[viewId] = m_renderTargets.color[i].view->handle();
|
views[m_attachmentCount] = m_renderTargets.color[i].view->handle();
|
||||||
m_attachments[viewId] = &m_renderTargets.color[i];
|
m_attachments[m_attachmentCount] = &m_renderTargets.color[i];
|
||||||
viewId += 1;
|
m_attachmentCount += 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_renderTargets.depth.view != nullptr) {
|
if (m_renderTargets.depth.view != nullptr) {
|
||||||
views[viewId] = m_renderTargets.depth.view->handle();
|
views[m_attachmentCount] = m_renderTargets.depth.view->handle();
|
||||||
m_attachments[viewId] = &m_renderTargets.depth;
|
m_attachments[m_attachmentCount] = &m_renderTargets.depth;
|
||||||
viewId += 1;
|
m_attachmentCount += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
VkFramebufferCreateInfo info;
|
VkFramebufferCreateInfo info;
|
||||||
@ -34,7 +32,7 @@ namespace dxvk {
|
|||||||
info.pNext = nullptr;
|
info.pNext = nullptr;
|
||||||
info.flags = 0;
|
info.flags = 0;
|
||||||
info.renderPass = m_renderPass->getDefaultHandle();
|
info.renderPass = m_renderPass->getDefaultHandle();
|
||||||
info.attachmentCount = viewId;
|
info.attachmentCount = m_attachmentCount;
|
||||||
info.pAttachments = views.data();
|
info.pAttachments = views.data();
|
||||||
info.width = m_renderSize.width;
|
info.width = m_renderSize.width;
|
||||||
info.height = m_renderSize.height;
|
info.height = m_renderSize.height;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user