renderer_vulkan: Handle depth-stencil copies through depth render overrides. (#2134)

This commit is contained in:
squidbus 2025-01-14 21:48:40 -08:00 committed by GitHub
parent d94abffd9a
commit 5040be1640
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
8 changed files with 146 additions and 13 deletions

View file

@ -70,6 +70,26 @@ bool Rasterizer::FilterDraw() {
return false;
}
const bool cb_disabled =
regs.color_control.mode == AmdGpu::Liverpool::ColorControl::OperationMode::Disable;
const auto depth_copy =
regs.depth_render_override.force_z_dirty && regs.depth_render_override.force_z_valid &&
regs.depth_buffer.DepthValid() && regs.depth_buffer.DepthWriteValid() &&
regs.depth_buffer.DepthAddress() != regs.depth_buffer.DepthWriteAddress();
const auto stencil_copy =
regs.depth_render_override.force_stencil_dirty &&
regs.depth_render_override.force_stencil_valid && regs.depth_buffer.StencilValid() &&
regs.depth_buffer.StencilWriteValid() &&
regs.depth_buffer.StencilAddress() != regs.depth_buffer.StencilWriteAddress();
if (cb_disabled && (depth_copy || stencil_copy)) {
// Games may disable color buffer and enable force depth/stencil dirty and valid to
// do a copy from one depth-stencil surface to another, without a pixel shader.
// We need to detect this case and perform the copy, otherwise it will have no effect.
LOG_TRACE(Render_Vulkan, "Performing depth-stencil override copy");
DepthStencilCopy(depth_copy, stencil_copy);
return false;
}
return true;
}
@ -899,6 +919,59 @@ void Rasterizer::Resolve() {
}
}
void Rasterizer::DepthStencilCopy(bool is_depth, bool is_stencil) {
auto& regs = liverpool->regs;
auto read_desc = VideoCore::TextureCache::DepthTargetDesc(
regs.depth_buffer, regs.depth_view, regs.depth_control,
regs.depth_htile_data_base.GetAddress(), liverpool->last_db_extent, false);
auto write_desc = VideoCore::TextureCache::DepthTargetDesc(
regs.depth_buffer, regs.depth_view, regs.depth_control,
regs.depth_htile_data_base.GetAddress(), liverpool->last_db_extent, true);
auto& read_image = texture_cache.GetImage(texture_cache.FindImage(read_desc));
auto& write_image = texture_cache.GetImage(texture_cache.FindImage(write_desc));
VideoCore::SubresourceRange sub_range;
sub_range.base.layer = liverpool->regs.depth_view.slice_start;
sub_range.extent.layers = liverpool->regs.depth_view.NumSlices() - sub_range.base.layer;
read_image.Transit(vk::ImageLayout::eTransferSrcOptimal, vk::AccessFlagBits2::eTransferRead,
sub_range);
write_image.Transit(vk::ImageLayout::eTransferDstOptimal, vk::AccessFlagBits2::eTransferWrite,
sub_range);
auto aspect_mask = vk::ImageAspectFlags(0);
if (is_depth) {
aspect_mask |= vk::ImageAspectFlagBits::eDepth;
}
if (is_stencil) {
aspect_mask |= vk::ImageAspectFlagBits::eStencil;
}
vk::ImageCopy region = {
.srcSubresource =
{
.aspectMask = aspect_mask,
.mipLevel = 0,
.baseArrayLayer = sub_range.base.layer,
.layerCount = sub_range.extent.layers,
},
.srcOffset = {0, 0, 0},
.dstSubresource =
{
.aspectMask = aspect_mask,
.mipLevel = 0,
.baseArrayLayer = sub_range.base.layer,
.layerCount = sub_range.extent.layers,
},
.dstOffset = {0, 0, 0},
.extent = {write_image.info.size.width, write_image.info.size.height, 1},
};
const auto cmdbuf = scheduler.CommandBuffer();
cmdbuf.copyImage(read_image.image, vk::ImageLayout::eTransferSrcOptimal, write_image.image,
vk::ImageLayout::eTransferDstOptimal, region);
}
void Rasterizer::InlineData(VAddr address, const void* value, u32 num_bytes, bool is_gds) {
buffer_cache.InlineData(address, value, num_bytes, is_gds);
}

View file

@ -71,6 +71,7 @@ private:
RenderState PrepareRenderState(u32 mrt_mask);
void BeginRendering(const GraphicsPipeline& pipeline, RenderState& state);
void Resolve();
void DepthStencilCopy(bool is_depth, bool is_stencil);
void EliminateFastClear();
void UpdateDynamicState(const GraphicsPipeline& pipeline);