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:
parent
de644d506f
commit
cf137ea40b
|
@ -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
|
||||
|
||||
class BufferBindings final {
|
||||
|
@ -344,7 +387,7 @@ void RasterizerVulkan::Draw(bool is_indexed, bool is_instanced) {
|
|||
|
||||
buffer_cache.Unmap();
|
||||
|
||||
const Texceptions texceptions = UpdateAttachments();
|
||||
const Texceptions texceptions = UpdateAttachments(false);
|
||||
SetupImageTransitions(texceptions, color_attachments, zeta_attachment);
|
||||
|
||||
key.renderpass_params = GetRenderPassParams(texceptions);
|
||||
|
@ -400,7 +443,7 @@ void RasterizerVulkan::Clear() {
|
|||
return;
|
||||
}
|
||||
|
||||
[[maybe_unused]] const auto texceptions = UpdateAttachments();
|
||||
[[maybe_unused]] const auto texceptions = UpdateAttachments(true);
|
||||
DEBUG_ASSERT(texceptions.none());
|
||||
SetupImageTransitions(0, color_attachments, zeta_attachment);
|
||||
|
||||
|
@ -677,9 +720,12 @@ void RasterizerVulkan::FlushWork() {
|
|||
draw_counter = 0;
|
||||
}
|
||||
|
||||
RasterizerVulkan::Texceptions RasterizerVulkan::UpdateAttachments() {
|
||||
RasterizerVulkan::Texceptions RasterizerVulkan::UpdateAttachments(bool is_clear) {
|
||||
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];
|
||||
dirty[VideoCommon::Dirty::RenderTargets] = false;
|
||||
|
||||
|
@ -688,7 +734,8 @@ RasterizerVulkan::Texceptions RasterizerVulkan::UpdateAttachments() {
|
|||
Texceptions texceptions;
|
||||
for (std::size_t rt = 0; rt < Maxwell::NumRenderTargets; ++rt) {
|
||||
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])) {
|
||||
texceptions[rt] = true;
|
||||
|
@ -696,7 +743,8 @@ RasterizerVulkan::Texceptions RasterizerVulkan::UpdateAttachments() {
|
|||
}
|
||||
|
||||
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)) {
|
||||
texceptions[ZETA_TEXCEPTION_INDEX] = true;
|
||||
|
|
|
@ -159,7 +159,10 @@ private:
|
|||
|
||||
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);
|
||||
|
||||
|
|
Reference in New Issue