mirror of
https://github.com/electron/electron.git
synced 2026-04-10 03:01:51 -04:00
135 lines
6.1 KiB
Diff
135 lines
6.1 KiB
Diff
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
|
From: Shahbaz Youssefi <syoussefi@chromium.org>
|
|
Date: Thu, 16 Feb 2023 23:16:46 -0500
|
|
Subject: M110: Vulkan: Don't close render pass if rebind to same fbo
|
|
|
|
In the Vulkan backend, the render pass can occasionally (and
|
|
transiently) be in a state of "open but inactive". This is when the
|
|
render pass is closed, but has the potential for future modifications
|
|
(for example to add a resolve attachment). Under many circumstances, it
|
|
is expected that an open render pass cannot be in such a state.
|
|
|
|
This assumption can be broken in this scenario:
|
|
|
|
- Open render pass, draw, etc
|
|
- Change framebuffer binding
|
|
- Change framebuffer binding back to original
|
|
- Masked Clear
|
|
|
|
When ContextVk is synced before clear, it sees that the framebuffer
|
|
binding is changed (though it hasn't really), and it closes the render
|
|
passes and sets the render pass dirty bit. If a draw were to follow, a
|
|
new render pass would have started (unnecessarily). However, in the
|
|
case of a masked clear, UtilsVk notices that the render pass is started,
|
|
assumes it must be active, and continues recording to it. While the
|
|
operation itself succeeds, the assumption that the render pass is active
|
|
is false (and fails assertion).
|
|
|
|
This change makes sure that framebuffer binding change is no-oped if the
|
|
framebuffer is the same one that has opened the current render pass. If
|
|
any application does unnecessary binding changes and back, it will be
|
|
optimized by this change as well.
|
|
|
|
Bug: chromium:1411210
|
|
Change-Id: I37a3a9f2eaa1a81a1b3393840b9458ec71a87377
|
|
Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/4261215
|
|
Reviewed-by: Charlie Lao <cclao@google.com>
|
|
Commit-Queue: Shahbaz Youssefi <syoussefi@chromium.org>
|
|
(cherry picked from commit 05e62f39412e8c6bfc98582f5e7a49041991c97b)
|
|
Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/4296296
|
|
Commit-Queue: Geoff Lang <geofflang@chromium.org>
|
|
Reviewed-by: Prudhvikumar Bommana <pbommana@google.com>
|
|
Commit-Queue: Prudhvikumar Bommana <pbommana@google.com>
|
|
|
|
diff --git a/src/libANGLE/renderer/vulkan/ContextVk.cpp b/src/libANGLE/renderer/vulkan/ContextVk.cpp
|
|
index ad5f83854f29c7245553fe3e98b7f6545d7ea91c..9f05c2a32ae2e0f6a4b1466d9f4423b3022b4975 100644
|
|
--- a/src/libANGLE/renderer/vulkan/ContextVk.cpp
|
|
+++ b/src/libANGLE/renderer/vulkan/ContextVk.cpp
|
|
@@ -5224,6 +5224,15 @@ angle::Result ContextVk::syncState(const gl::Context *context,
|
|
// as some optimizations in non-draw commands require the render pass to remain
|
|
// open, such as invalidate or blit. Note that we always start a new command buffer
|
|
// because we currently can only support one open RenderPass at a time.
|
|
+ //
|
|
+ // The render pass is not closed if binding is changed to the same framebuffer as
|
|
+ // before.
|
|
+ if (hasStartedRenderPass() && hasStartedRenderPassWithQueueSerial(
|
|
+ drawFramebufferVk->getLastRenderPassQueueSerial()))
|
|
+ {
|
|
+ break;
|
|
+ }
|
|
+
|
|
onRenderPassFinished(RenderPassClosureReason::FramebufferBindingChange);
|
|
if (getFeatures().preferSubmitAtFBOBoundary.enabled &&
|
|
mRenderPassCommands->started())
|
|
diff --git a/src/tests/gl_tests/ClearTest.cpp b/src/tests/gl_tests/ClearTest.cpp
|
|
index bbe243281fce2b7503767b2553d2900b598b7e81..51a953019c53e8ed1f09184965164002f4cc4c79 100644
|
|
--- a/src/tests/gl_tests/ClearTest.cpp
|
|
+++ b/src/tests/gl_tests/ClearTest.cpp
|
|
@@ -2863,6 +2863,26 @@ TEST_P(ClearTest, DISABLED_ClearReachesWindow)
|
|
angle::Sleep(2000);
|
|
}
|
|
|
|
+// Tests that masked clear after a no-op framebuffer binding change with an open render pass works.
|
|
+TEST_P(ClearTest, DrawThenChangeFBOBindingAndBackThenMaskedClear)
|
|
+{
|
|
+ ANGLE_GL_PROGRAM(blueProgram, essl1_shaders::vs::Simple(), essl1_shaders::fs::Blue());
|
|
+
|
|
+ // Draw blue.
|
|
+ drawQuad(blueProgram, essl1_shaders::PositionAttrib(), 0.5f);
|
|
+
|
|
+ // Change framebuffer and back
|
|
+ glBindFramebuffer(GL_FRAMEBUFFER, mFBOs[0]);
|
|
+ glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
|
+
|
|
+ // Masked clear
|
|
+ glColorMask(1, 0, 0, 1);
|
|
+ glClearColor(1.0f, 0.5f, 0.5f, 1.0f);
|
|
+ glClear(GL_COLOR_BUFFER_BIT);
|
|
+
|
|
+ EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::magenta);
|
|
+}
|
|
+
|
|
// Test that clearing slices of a 3D texture and reading them back works.
|
|
TEST_P(ClearTestES3, ClearAndReadPixels3DTexture)
|
|
{
|
|
diff --git a/src/tests/gl_tests/VulkanPerformanceCounterTest.cpp b/src/tests/gl_tests/VulkanPerformanceCounterTest.cpp
|
|
index b62f434d5db1eac4bf5039db49d50ffd092b3621..bacac33673b9d2c2b8d62b9ff12a61773273eff1 100644
|
|
--- a/src/tests/gl_tests/VulkanPerformanceCounterTest.cpp
|
|
+++ b/src/tests/gl_tests/VulkanPerformanceCounterTest.cpp
|
|
@@ -5,7 +5,7 @@
|
|
//
|
|
// VulkanPerformanceCounterTest:
|
|
// Validates specific GL call patterns with ANGLE performance counters.
|
|
-// For example we can verify a certain call set doesn't break the RenderPass.
|
|
+// For example we can verify a certain call set doesn't break the render pass.
|
|
|
|
#include "test_utils/ANGLETest.h"
|
|
#include "test_utils/angle_test_instantiate.h"
|
|
@@ -7090,6 +7090,26 @@ TEST_P(VulkanPerformanceCounterTest, AsyncMonolithicPipelineCreation)
|
|
EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red);
|
|
}
|
|
|
|
+// Verify that changing framebuffer and back doesn't break the render pass.
|
|
+TEST_P(VulkanPerformanceCounterTest, FBOChangeAndBackDoesNotBreakRenderPass)
|
|
+{
|
|
+ uint64_t expectedRenderPassCount = getPerfCounters().renderPasses + 1;
|
|
+
|
|
+ ANGLE_GL_PROGRAM(drawRed, essl3_shaders::vs::Simple(), essl3_shaders::fs::Red());
|
|
+ drawQuad(drawRed, essl1_shaders::PositionAttrib(), 0);
|
|
+
|
|
+ GLFramebuffer fbo;
|
|
+ glBindFramebuffer(GL_FRAMEBUFFER, fbo);
|
|
+ glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
|
+
|
|
+ drawQuad(drawRed, essl1_shaders::PositionAttrib(), 0);
|
|
+
|
|
+ // Verify render pass count.
|
|
+ EXPECT_EQ(getPerfCounters().renderPasses, expectedRenderPassCount);
|
|
+
|
|
+ EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red);
|
|
+}
|
|
+
|
|
GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(VulkanPerformanceCounterTest);
|
|
ANGLE_INSTANTIATE_TEST(
|
|
VulkanPerformanceCounterTest,
|