|
@@ -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;
|