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:
parent
1af52abb67
commit
52a9a4f406
@ -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);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -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);
|
||||||
|
@ -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();
|
||||||
|
|
||||||
|
@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
@ -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;
|
||||||
|
@ -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;
|
||||||
|
Loading…
Reference in New Issue
Block a user