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

[dxvk] Reimplemented clearRenderTarget

Closer to the D3D11 API. We cannot use the normal clearColorImage and
clearDepthStencilImage methods in case the game uses a 2D array view
for a 3D image. Fixes some validation issues in Hellblade.
This commit is contained in:
Philip Rebohle 2018-03-17 17:59:43 +01:00
parent 1af52abb67
commit 52a9a4f406
No known key found for this signature in database
GPG Key ID: C8CC613427A31C99
6 changed files with 169 additions and 139 deletions

View File

@ -473,62 +473,35 @@ namespace dxvk {
if (rtv == nullptr) if (rtv == nullptr)
return; return;
// Find out whether the given attachment is currently bound
// or not, and if it is, which attachment index it has.
int32_t attachmentIndex = -1;
for (uint32_t i = 0; i < m_state.om.renderTargetViews.size(); i++) {
if (m_state.om.renderTargetViews.at(i) == rtv)
attachmentIndex = i;
}
// Copy the clear color into a clear value structure.
// This should also work for images that don nott have
// a floating point format.
const Rc<DxvkImageView> view = rtv->GetImageView(); const Rc<DxvkImageView> view = rtv->GetImageView();
VkClearColorValue clearValue; VkClearValue clearValue;
std::memcpy(clearValue.float32, ColorRGBA, clearValue.color.float32[0] = ColorRGBA[0];
sizeof(clearValue.float32)); clearValue.color.float32[1] = ColorRGBA[1];
clearValue.color.float32[2] = ColorRGBA[2];
clearValue.color.float32[3] = ColorRGBA[3];
if (attachmentIndex >= 0) { VkClearRect clearRect;
// Image is bound to the pipeline for rendering. We can clearRect.rect.offset.x = 0;
// use the clear function that operates on attachments. clearRect.rect.offset.y = 0;
VkClearAttachment clearInfo; clearRect.rect.extent.width = view->mipLevelExtent(0).width;
clearInfo.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; clearRect.rect.extent.height = view->mipLevelExtent(0).height;
clearInfo.colorAttachment = static_cast<uint32_t>(attachmentIndex); clearRect.baseArrayLayer = 0;
clearInfo.clearValue.color = clearValue; clearRect.layerCount = view->info().numLayers;
// Clear the full area. On FL 9.x, only the first array if (m_parent->GetFeatureLevel() < D3D_FEATURE_LEVEL_10_0)
// layer will be cleared, rather than all array layers. clearRect.layerCount = 1;
VkClearRect clearRect;
clearRect.rect.offset.x = 0; EmitCs([
clearRect.rect.offset.y = 0; cClearValue = clearValue,
clearRect.rect.extent.width = view->mipLevelExtent(0).width; cClearRect = clearRect,
clearRect.rect.extent.height = view->mipLevelExtent(0).height; cImageView = view
clearRect.baseArrayLayer = 0; ] (DxvkContext* ctx) {
clearRect.layerCount = view->info().numLayers; ctx->clearRenderTarget(
cImageView, cClearRect,
if (m_parent->GetFeatureLevel() < D3D_FEATURE_LEVEL_10_0) VK_IMAGE_ASPECT_COLOR_BIT,
clearRect.layerCount = 1; cClearValue);
});
EmitCs([
cClearInfo = clearInfo,
cClearRect = clearRect
] (DxvkContext* ctx) {
ctx->clearRenderTarget(cClearInfo, cClearRect);
});
} else {
// Image is not bound to the pipeline. We can still clear
// it, but we'll have to use a generic clear function.
EmitCs([
cClearValue = clearValue,
cDstView = view
] (DxvkContext* ctx) {
ctx->clearColorImage(cDstView->image(),
cClearValue, cDstView->subresources());
});
}
} }
@ -606,53 +579,33 @@ namespace dxvk {
if (ClearFlags & D3D11_CLEAR_STENCIL) if (ClearFlags & D3D11_CLEAR_STENCIL)
aspectMask |= VK_IMAGE_ASPECT_STENCIL_BIT; aspectMask |= VK_IMAGE_ASPECT_STENCIL_BIT;
const DxvkFormatInfo* formatInfo = aspectMask &= imageFormatInfo(view->info().format)->aspectMask;
imageFormatInfo(view->info().format);
aspectMask &= formatInfo->aspectMask;
VkClearDepthStencilValue clearValue; VkClearValue clearValue;
clearValue.depth = Depth; clearValue.depthStencil.depth = Depth;
clearValue.stencil = Stencil; clearValue.depthStencil.stencil = Stencil;
if (m_state.om.depthStencilView == dsv) { VkClearRect clearRect;
// Image is bound to the pipeline for rendering. We can clearRect.rect.offset.x = 0;
// use the clear function that operates on attachments. clearRect.rect.offset.y = 0;
VkClearAttachment clearInfo; clearRect.rect.extent.width = view->mipLevelExtent(0).width;
clearInfo.aspectMask = aspectMask; clearRect.rect.extent.height = view->mipLevelExtent(0).height;
clearInfo.colorAttachment = 0; clearRect.baseArrayLayer = 0;
clearInfo.clearValue.depthStencil = clearValue; clearRect.layerCount = view->info().numLayers;
// Clear the full area if (m_parent->GetFeatureLevel() < D3D_FEATURE_LEVEL_10_0)
VkClearRect clearRect; clearRect.layerCount = 1;
clearRect.rect.offset.x = 0;
clearRect.rect.offset.y = 0; EmitCs([
clearRect.rect.extent.width = view->mipLevelExtent(0).width; cClearValue = clearValue,
clearRect.rect.extent.height = view->mipLevelExtent(0).height; cClearRect = clearRect,
clearRect.baseArrayLayer = 0; cAspectMask = aspectMask,
clearRect.layerCount = view->info().numLayers; cImageView = view
] (DxvkContext* ctx) {
if (m_parent->GetFeatureLevel() < D3D_FEATURE_LEVEL_10_0) ctx->clearRenderTarget(
clearRect.layerCount = 1; cImageView, cClearRect,
cAspectMask, cClearValue);
EmitCs([ });
cClearInfo = clearInfo,
cClearRect = clearRect
] (DxvkContext* ctx) {
ctx->clearRenderTarget(cClearInfo, cClearRect);
});
} else {
EmitCs([
cClearValue = clearValue,
cDstView = view,
cAspectMask = aspectMask
] (DxvkContext* ctx) {
VkImageSubresourceRange subresources = cDstView->subresources();
subresources.aspectMask = cAspectMask;
ctx->clearDepthStencilImage(cDstView->image(),
cClearValue, subresources);
});
}
} }

View File

@ -311,15 +311,56 @@ namespace dxvk {
void DxvkContext::clearRenderTarget( void DxvkContext::clearRenderTarget(
const VkClearAttachment& attachment, const Rc<DxvkImageView>& imageView,
const VkClearRect& clearArea) { const VkClearRect& clearRect,
// We only need the framebuffer to be bound. Flushing the VkImageAspectFlags clearAspects,
// entire pipeline state is not required and might actually const VkClearValue& clearValue) {
// cause problems if the current pipeline state is invalid. // Check whether the render target view is an attachment
this->renderPassBegin(); // of the current framebuffer. If not, we need to create
// a temporary framebuffer.
uint32_t attachmentIndex = MaxNumRenderTargets;
if (m_state.om.framebuffer != nullptr)
attachmentIndex = m_state.om.framebuffer->findAttachment(imageView);
if (attachmentIndex == MaxNumRenderTargets) {
this->renderPassEnd();
// Set up and bind a temporary framebuffer
DxvkRenderTargets attachments;
if (clearAspects & VK_IMAGE_ASPECT_COLOR_BIT) {
attachments.setColorTarget(0, imageView,
VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
} else {
attachments.setDepthTarget(imageView,
VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL);
}
this->renderPassBindFramebuffer(
m_device->createFramebuffer(attachments));
} else {
// Make sure that the currently bound
// framebuffer can be rendered to
this->renderPassBegin();
}
// Clear the attachment in quesion
VkClearAttachment clearInfo;
clearInfo.aspectMask = clearAspects;
clearInfo.colorAttachment = attachmentIndex;
clearInfo.clearValue = clearValue;
if (attachmentIndex == MaxNumRenderTargets)
clearInfo.colorAttachment = 0;
m_cmd->cmdClearAttachments( m_cmd->cmdClearAttachments(
1, &attachment, 1, &clearArea); 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 == MaxNumRenderTargets)
this->renderPassUnbindFramebuffer();
} }
@ -1298,27 +1339,7 @@ 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);
this->renderPassBindFramebuffer(m_state.om.framebuffer);
const DxvkFramebufferSize fbSize
= m_state.om.framebuffer->size();
VkRect2D renderArea;
renderArea.offset = VkOffset2D { 0, 0 };
renderArea.extent = VkExtent2D { fbSize.width, fbSize.height };
VkRenderPassBeginInfo info;
info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
info.pNext = nullptr;
info.renderPass = m_state.om.framebuffer->renderPass();
info.framebuffer = m_state.om.framebuffer->handle();
info.renderArea = renderArea;
info.clearValueCount = 0;
info.pClearValues = nullptr;
m_cmd->cmdBeginRenderPass(&info,
VK_SUBPASS_CONTENTS_INLINE);
m_cmd->trackResource(
m_state.om.framebuffer);
} }
} }
@ -1326,11 +1347,38 @@ namespace dxvk {
void DxvkContext::renderPassEnd() { void DxvkContext::renderPassEnd() {
if (m_flags.test(DxvkContextFlag::GpRenderPassBound)) { if (m_flags.test(DxvkContextFlag::GpRenderPassBound)) {
m_flags.clr(DxvkContextFlag::GpRenderPassBound); m_flags.clr(DxvkContextFlag::GpRenderPassBound);
m_cmd->cmdEndRenderPass(); this->renderPassUnbindFramebuffer();
} }
} }
void DxvkContext::renderPassBindFramebuffer(const Rc<DxvkFramebuffer>& framebuffer) {
const DxvkFramebufferSize fbSize = framebuffer->size();
VkRect2D renderArea;
renderArea.offset = VkOffset2D { 0, 0 };
renderArea.extent = VkExtent2D { fbSize.width, fbSize.height };
VkRenderPassBeginInfo info;
info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
info.pNext = nullptr;
info.renderPass = framebuffer->renderPass();
info.framebuffer = framebuffer->handle();
info.renderArea = renderArea;
info.clearValueCount = 0;
info.pClearValues = nullptr;
m_cmd->cmdBeginRenderPass(&info,
VK_SUBPASS_CONTENTS_INLINE);
m_cmd->trackResource(framebuffer);
}
void DxvkContext::renderPassUnbindFramebuffer() {
m_cmd->cmdEndRenderPass();
}
void DxvkContext::updateComputePipeline() { void DxvkContext::updateComputePipeline() {
if (m_flags.test(DxvkContextFlag::CpDirtyPipeline)) { if (m_flags.test(DxvkContextFlag::CpDirtyPipeline)) {
m_flags.clr(DxvkContextFlag::CpDirtyPipeline); m_flags.clr(DxvkContextFlag::CpDirtyPipeline);

View File

@ -188,12 +188,16 @@ namespace dxvk {
/** /**
* \brief Clears an active render target * \brief Clears an active render target
* *
* \param [in] attachment Attachment to clear * \param [in] imageView Render target view to clear
* \param [in] clearArea Rectangular area to clear * \param [in] clearArea Image area to clear
* \param [in] clearAspects Image aspects to clear
* \param [in] clearValue The clear value
*/ */
void clearRenderTarget( void clearRenderTarget(
const VkClearAttachment& attachment, const Rc<DxvkImageView>& imageView,
const VkClearRect& clearArea); const VkClearRect& clearRect,
VkImageAspectFlags clearAspects,
const VkClearValue& clearValue);
/** /**
* \brief Copies data from one buffer to another * \brief Copies data from one buffer to another
@ -579,6 +583,10 @@ namespace dxvk {
void renderPassBegin(); void renderPassBegin();
void renderPassEnd(); void renderPassEnd();
void renderPassBindFramebuffer(
const Rc<DxvkFramebuffer>& framebuffer);
void renderPassUnbindFramebuffer();
void updateComputePipeline(); void updateComputePipeline();
void updateComputePipelineState(); void updateComputePipelineState();

View File

@ -111,4 +111,18 @@ namespace dxvk {
m_vkd->device(), m_framebuffer, nullptr); m_vkd->device(), m_framebuffer, nullptr);
} }
uint32_t DxvkFramebuffer::findAttachment(
const Rc<DxvkImageView>& view) const {
if (m_renderTargets.getDepthTarget().view == view)
return 0;
for (uint32_t i = 0; i < MaxNumRenderTargets; i++) {
if (m_renderTargets.getColorTarget(i).view == view)
return i;
}
return MaxNumRenderTargets;
}
} }

View File

@ -185,6 +185,17 @@ namespace dxvk {
return m_renderPass->sampleCount(); return m_renderPass->sampleCount();
} }
/**
* \brief Retrieves index of a given attachment
*
* \param [in] view The image view to look up
* \returns The attachment index, or \c 0 for a depth-stencil
* attachment, or \c MaxNumRenderTargets if the given
* view is not a framebuffer attachment.
*/
uint32_t findAttachment(
const Rc<DxvkImageView>& view) const;
private: private:
Rc<vk::DeviceFn> m_vkd; Rc<vk::DeviceFn> m_vkd;

View File

@ -93,13 +93,6 @@ namespace dxvk::hud {
0, 1, 0, 1 }); 0, 1, 0, 1 });
} }
VkClearAttachment clearInfo;
clearInfo.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
clearInfo.colorAttachment = 0;
for (uint32_t i = 0; i < 4; i++)
clearInfo.clearValue.color.float32[i] = 0.0f;
VkClearRect clearRect; VkClearRect clearRect;
clearRect.rect.offset = { 0, 0 }; clearRect.rect.offset = { 0, 0 };
clearRect.rect.extent = m_surfaceSize; clearRect.rect.extent = m_surfaceSize;
@ -107,7 +100,10 @@ namespace dxvk::hud {
clearRect.layerCount = 1; clearRect.layerCount = 1;
m_context->bindFramebuffer(m_renderTargetFbo); m_context->bindFramebuffer(m_renderTargetFbo);
m_context->clearRenderTarget(clearInfo, clearRect); m_context->clearRenderTarget(
m_renderTargetView, clearRect,
VK_IMAGE_ASPECT_COLOR_BIT,
VkClearValue { });
VkViewport viewport; VkViewport viewport;
viewport.x = 0.0f; viewport.x = 0.0f;