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,34 +473,14 @@ 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) {
// Image is bound to the pipeline for rendering. We can
// use the clear function that operates on attachments.
VkClearAttachment clearInfo;
clearInfo.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
clearInfo.colorAttachment = static_cast<uint32_t>(attachmentIndex);
clearInfo.clearValue.color = clearValue;
// Clear the full area. On FL 9.x, only the first array
// layer will be cleared, rather than all array layers.
VkClearRect clearRect; VkClearRect clearRect;
clearRect.rect.offset.x = 0; clearRect.rect.offset.x = 0;
clearRect.rect.offset.y = 0; clearRect.rect.offset.y = 0;
@ -512,24 +492,17 @@ namespace dxvk {
if (m_parent->GetFeatureLevel() < D3D_FEATURE_LEVEL_10_0) if (m_parent->GetFeatureLevel() < D3D_FEATURE_LEVEL_10_0)
clearRect.layerCount = 1; clearRect.layerCount = 1;
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([ EmitCs([
cClearValue = clearValue, cClearValue = clearValue,
cDstView = view cClearRect = clearRect,
cImageView = view
] (DxvkContext* ctx) { ] (DxvkContext* ctx) {
ctx->clearColorImage(cDstView->image(), ctx->clearRenderTarget(
cClearValue, cDstView->subresources()); cImageView, cClearRect,
VK_IMAGE_ASPECT_COLOR_BIT,
cClearValue);
}); });
} }
}
void STDMETHODCALLTYPE D3D11DeviceContext::ClearUnorderedAccessViewUint( void STDMETHODCALLTYPE D3D11DeviceContext::ClearUnorderedAccessViewUint(
@ -606,23 +579,12 @@ 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) {
// Image is bound to the pipeline for rendering. We can
// use the clear function that operates on attachments.
VkClearAttachment clearInfo;
clearInfo.aspectMask = aspectMask;
clearInfo.colorAttachment = 0;
clearInfo.clearValue.depthStencil = clearValue;
// Clear the full area
VkClearRect clearRect; VkClearRect clearRect;
clearRect.rect.offset.x = 0; clearRect.rect.offset.x = 0;
clearRect.rect.offset.y = 0; clearRect.rect.offset.y = 0;
@ -634,26 +596,17 @@ namespace dxvk {
if (m_parent->GetFeatureLevel() < D3D_FEATURE_LEVEL_10_0) if (m_parent->GetFeatureLevel() < D3D_FEATURE_LEVEL_10_0)
clearRect.layerCount = 1; clearRect.layerCount = 1;
EmitCs([
cClearInfo = clearInfo,
cClearRect = clearRect
] (DxvkContext* ctx) {
ctx->clearRenderTarget(cClearInfo, cClearRect);
});
} else {
EmitCs([ EmitCs([
cClearValue = clearValue, cClearValue = clearValue,
cDstView = view, cClearRect = clearRect,
cAspectMask = aspectMask cAspectMask = aspectMask,
cImageView = view
] (DxvkContext* ctx) { ] (DxvkContext* ctx) {
VkImageSubresourceRange subresources = cDstView->subresources(); ctx->clearRenderTarget(
subresources.aspectMask = cAspectMask; cImageView, cClearRect,
cAspectMask, cClearValue);
ctx->clearDepthStencilImage(cDstView->image(),
cClearValue, subresources);
}); });
} }
}
void STDMETHODCALLTYPE D3D11DeviceContext::GenerateMips(ID3D11ShaderResourceView* pShaderResourceView) { void STDMETHODCALLTYPE D3D11DeviceContext::GenerateMips(ID3D11ShaderResourceView* pShaderResourceView) {

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
// 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(); 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,9 +1339,21 @@ 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(); void DxvkContext::renderPassEnd() {
if (m_flags.test(DxvkContextFlag::GpRenderPassBound)) {
m_flags.clr(DxvkContextFlag::GpRenderPassBound);
this->renderPassUnbindFramebuffer();
}
}
void DxvkContext::renderPassBindFramebuffer(const Rc<DxvkFramebuffer>& framebuffer) {
const DxvkFramebufferSize fbSize = framebuffer->size();
VkRect2D renderArea; VkRect2D renderArea;
renderArea.offset = VkOffset2D { 0, 0 }; renderArea.offset = VkOffset2D { 0, 0 };
@ -1309,26 +1362,21 @@ namespace dxvk {
VkRenderPassBeginInfo info; VkRenderPassBeginInfo info;
info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO; info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
info.pNext = nullptr; info.pNext = nullptr;
info.renderPass = m_state.om.framebuffer->renderPass(); info.renderPass = framebuffer->renderPass();
info.framebuffer = m_state.om.framebuffer->handle(); info.framebuffer = framebuffer->handle();
info.renderArea = renderArea; info.renderArea = renderArea;
info.clearValueCount = 0; info.clearValueCount = 0;
info.pClearValues = nullptr; info.pClearValues = nullptr;
m_cmd->cmdBeginRenderPass(&info, m_cmd->cmdBeginRenderPass(&info,
VK_SUBPASS_CONTENTS_INLINE); VK_SUBPASS_CONTENTS_INLINE);
m_cmd->trackResource( m_cmd->trackResource(framebuffer);
m_state.om.framebuffer);
}
} }
void DxvkContext::renderPassEnd() { void DxvkContext::renderPassUnbindFramebuffer() {
if (m_flags.test(DxvkContextFlag::GpRenderPassBound)) {
m_flags.clr(DxvkContextFlag::GpRenderPassBound);
m_cmd->cmdEndRenderPass(); m_cmd->cmdEndRenderPass();
} }
}
void DxvkContext::updateComputePipeline() { void DxvkContext::updateComputePipeline() {

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;