yuzu-emu
/
yuzu
Archived
1
0
Fork 0

vk_rasterizer: Don't preserve contents on full screen clears

There's no need to load contents from the CPU when a clear resets all
the contents of the underlying memory. This is already implemented on
OpenGL and the texture cache.
This commit is contained in:
ReinUsesLisp 2020-06-18 18:16:21 -03:00
parent de644d506f
commit cf137ea40b
2 changed files with 58 additions and 7 deletions

View File

@ -143,6 +143,49 @@ Tegra::Texture::FullTextureInfo GetTextureInfo(const Engine& engine, const Entry
} }
} }
/// @brief Determine if an attachment to be updated has to preserve contents
/// @param is_clear True when a clear is being executed
/// @param regs 3D registers
/// @return True when the contents have to be preserved
bool HasToPreserveColorContents(bool is_clear, const Maxwell& regs) {
if (!is_clear) {
return true;
}
// First we have to make sure all clear masks are enabled.
if (!regs.clear_buffers.R || !regs.clear_buffers.G || !regs.clear_buffers.B ||
!regs.clear_buffers.A) {
return true;
}
// If scissors are disabled, the whole screen is cleared
if (!regs.clear_flags.scissor) {
return false;
}
// Then we have to confirm scissor testing clears the whole image
const std::size_t index = regs.clear_buffers.RT;
const auto& scissor = regs.scissor_test[0];
return scissor.min_x > 0 || scissor.min_y > 0 || scissor.max_x < regs.rt[index].width ||
scissor.max_y < regs.rt[index].height;
}
/// @brief Determine if an attachment to be updated has to preserve contents
/// @param is_clear True when a clear is being executed
/// @param regs 3D registers
/// @return True when the contents have to be preserved
bool HasToPreserveDepthContents(bool is_clear, const Maxwell& regs) {
// If we are not clearing, the contents have to be preserved
if (!is_clear) {
return true;
}
// For depth stencil clears we only have to confirm scissor test covers the whole image
if (!regs.clear_flags.scissor) {
return false;
}
// Make sure the clear cover the whole image
const auto& scissor = regs.scissor_test[0];
return scissor.min_x > 0 || scissor.min_y > 0 || scissor.max_x < regs.zeta_width ||
scissor.max_y < regs.zeta_height;
}
} // Anonymous namespace } // Anonymous namespace
class BufferBindings final { class BufferBindings final {
@ -344,7 +387,7 @@ void RasterizerVulkan::Draw(bool is_indexed, bool is_instanced) {
buffer_cache.Unmap(); buffer_cache.Unmap();
const Texceptions texceptions = UpdateAttachments(); const Texceptions texceptions = UpdateAttachments(false);
SetupImageTransitions(texceptions, color_attachments, zeta_attachment); SetupImageTransitions(texceptions, color_attachments, zeta_attachment);
key.renderpass_params = GetRenderPassParams(texceptions); key.renderpass_params = GetRenderPassParams(texceptions);
@ -400,7 +443,7 @@ void RasterizerVulkan::Clear() {
return; return;
} }
[[maybe_unused]] const auto texceptions = UpdateAttachments(); [[maybe_unused]] const auto texceptions = UpdateAttachments(true);
DEBUG_ASSERT(texceptions.none()); DEBUG_ASSERT(texceptions.none());
SetupImageTransitions(0, color_attachments, zeta_attachment); SetupImageTransitions(0, color_attachments, zeta_attachment);
@ -677,9 +720,12 @@ void RasterizerVulkan::FlushWork() {
draw_counter = 0; draw_counter = 0;
} }
RasterizerVulkan::Texceptions RasterizerVulkan::UpdateAttachments() { RasterizerVulkan::Texceptions RasterizerVulkan::UpdateAttachments(bool is_clear) {
MICROPROFILE_SCOPE(Vulkan_RenderTargets); MICROPROFILE_SCOPE(Vulkan_RenderTargets);
auto& dirty = system.GPU().Maxwell3D().dirty.flags; auto& maxwell3d = system.GPU().Maxwell3D();
auto& dirty = maxwell3d.dirty.flags;
auto& regs = maxwell3d.regs;
const bool update_rendertargets = dirty[VideoCommon::Dirty::RenderTargets]; const bool update_rendertargets = dirty[VideoCommon::Dirty::RenderTargets];
dirty[VideoCommon::Dirty::RenderTargets] = false; dirty[VideoCommon::Dirty::RenderTargets] = false;
@ -688,7 +734,8 @@ RasterizerVulkan::Texceptions RasterizerVulkan::UpdateAttachments() {
Texceptions texceptions; Texceptions texceptions;
for (std::size_t rt = 0; rt < Maxwell::NumRenderTargets; ++rt) { for (std::size_t rt = 0; rt < Maxwell::NumRenderTargets; ++rt) {
if (update_rendertargets) { if (update_rendertargets) {
color_attachments[rt] = texture_cache.GetColorBufferSurface(rt, true); const bool preserve_contents = HasToPreserveColorContents(is_clear, regs);
color_attachments[rt] = texture_cache.GetColorBufferSurface(rt, preserve_contents);
} }
if (color_attachments[rt] && WalkAttachmentOverlaps(*color_attachments[rt])) { if (color_attachments[rt] && WalkAttachmentOverlaps(*color_attachments[rt])) {
texceptions[rt] = true; texceptions[rt] = true;
@ -696,7 +743,8 @@ RasterizerVulkan::Texceptions RasterizerVulkan::UpdateAttachments() {
} }
if (update_rendertargets) { if (update_rendertargets) {
zeta_attachment = texture_cache.GetDepthBufferSurface(true); const bool preserve_contents = HasToPreserveDepthContents(is_clear, regs);
zeta_attachment = texture_cache.GetDepthBufferSurface(preserve_contents);
} }
if (zeta_attachment && WalkAttachmentOverlaps(*zeta_attachment)) { if (zeta_attachment && WalkAttachmentOverlaps(*zeta_attachment)) {
texceptions[ZETA_TEXCEPTION_INDEX] = true; texceptions[ZETA_TEXCEPTION_INDEX] = true;

View File

@ -159,7 +159,10 @@ private:
void FlushWork(); void FlushWork();
Texceptions UpdateAttachments(); /// @brief Updates the currently bound attachments
/// @param is_clear True when the framebuffer is updated as a clear
/// @return Bitfield of attachments being used as sampled textures
Texceptions UpdateAttachments(bool is_clear);
std::tuple<VkFramebuffer, VkExtent2D> ConfigureFramebuffers(VkRenderPass renderpass); std::tuple<VkFramebuffer, VkExtent2D> ConfigureFramebuffers(VkRenderPass renderpass);