Vulkan: Disable rotating damage rectangles on Android This fixes visual problems with Android games that use eglSwapBuffersWithDamageKHR(). In 90/270-degree cases, the damage rectangles are being double-rotated, leaving them 90-degrees out of alignment with the window. On Android, VK_KHR_incremental_present is built on top of the same platform code as eglSwapBuffersWithDamageKHR(). The platform code rotates all damage rectangles (assuming they are application-provided). Therefore, ANGLE should not also pre-rotate damage rectangles. Test: Black Desert Mobile Test: Grand Theft Auto: San Andreas Test: Extreme Car Driving Simulator Bug: b/181796746 Change-Id: I6510e7540bb00afc75863e8ae8a9ea3841d1641d Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/2744984 Reviewed-by: Shahbaz Youssefi <syoussefi@chromium.org> Reviewed-by: Cody Northrop <cnorthrop@google.com> Commit-Queue: Ian Elliott <ianelliott@google.com>
diff --git a/include/platform/FeaturesVk.h b/include/platform/FeaturesVk.h index e58a24f..35ab1a2 100644 --- a/include/platform/FeaturesVk.h +++ b/include/platform/FeaturesVk.h
@@ -90,6 +90,16 @@ "supportsIncrementalPresent", FeatureCategory::VulkanFeatures, "VkDevice supports the VK_KHR_incremental_present extension", &members}; + // Whether the Vulkan presentation engine rotates the present region rectangles of the + // VK_KHR_incremental_present extension in pre-rotation situations. The Android presentation + // engine assumes that these rectangles need to be rotated, and thus ANGLE should not also + // pre-rotate them. + Feature disablePreRotateIncrementalPresentRectangles = { + "disablePreRotateIncrementalPresentRectangles", FeatureCategory::VulkanFeatures, + "Presentation engine performs necessary rotation for present region rectangles of the " + "VK_KHR_incremental_present extension", + &members}; + // Whether texture copies on cube map targets should be done on GPU. This is a workaround for // Intel drivers on windows that have an issue with creating single-layer views on cube map // textures.
diff --git a/src/libANGLE/renderer/vulkan/RendererVk.cpp b/src/libANGLE/renderer/vulkan/RendererVk.cpp index d14fa70..9069e82 100644 --- a/src/libANGLE/renderer/vulkan/RendererVk.cpp +++ b/src/libANGLE/renderer/vulkan/RendererVk.cpp
@@ -1935,6 +1935,13 @@ &mFeatures, supportsIncrementalPresent, ExtensionFound(VK_KHR_INCREMENTAL_PRESENT_EXTENSION_NAME, deviceExtensionNames)); + // The Vulkan specification for the VK_KHR_incremental_present extension does not address + // rotation. In Android, this extension is implemented on top of the same platform code as + // eglSwapBuffersWithDamageKHR(), which code assumes that it should rotate each rectangle. To + // avoid double-rotating damage rectangles on Android, we must avoid pre-rotating + // application-provided rectangles. See: https://issuetracker.google.com/issues/181796746 + ANGLE_FEATURE_CONDITION(&mFeatures, disablePreRotateIncrementalPresentRectangles, IsAndroid()); + #if defined(ANGLE_PLATFORM_ANDROID) ANGLE_FEATURE_CONDITION( &mFeatures, supportsAndroidHardwareBuffer,
diff --git a/src/libANGLE/renderer/vulkan/SurfaceVk.cpp b/src/libANGLE/renderer/vulkan/SurfaceVk.cpp index c989902..a986499 100644 --- a/src/libANGLE/renderer/vulkan/SurfaceVk.cpp +++ b/src/libANGLE/renderer/vulkan/SurfaceVk.cpp
@@ -1253,29 +1253,7 @@ { DisplayVk *displayVk = vk::GetImpl(context->getDisplay()); angle::Result result; - if (n_rects == 1 && rects[0] == 0 && rects[1] == 0 && rects[2] == getWidth() && - rects[3] == getHeight()) - { - // Work-around a defect on at least the Pixel 4 family, likely in the hardware composer - // (HWC) driver that SurfaceFlinger (SF) uses to composite results to the display. When - // some games switch FROM one EGLSurface and using eglSwapBuffers() TO a new EGLSurface and - // using eglSwapBuffersWithDamageKHR(), the user will frequently see the right half of the - // window stick with previous contents. Causing SF to composite the window differently - // (e.g. swiping to show the nagivation buttons or to show the list of apps) immediately - // stops the problem, further pointing to a HWC bug. - // - // In this case, the "damage area" is the entire window, which means that a normal - // eglSwapBuffers() should be functionally identical (except for whatever SW/HWC will do - // differently for compositing). - // - // TODO: Remove this work-around when we no longer support affected devices (at least Pixel - // 4 XL, but not Arm-GPU devices). https://issuetracker.google.com/issues/182213414 - result = swapImpl(context, nullptr, 0, nullptr); - } - else - { - result = swapImpl(context, rects, n_rects, nullptr); - } + result = swapImpl(context, rects, n_rects, nullptr); return angle::ToEGL(result, displayVk, EGL_BAD_SURFACE); } @@ -1439,7 +1417,8 @@ rect.extent.width = gl::clamp(*eglRects++, 0, width - rect.offset.x); rect.extent.height = gl::clamp(*eglRects++, 0, height - rect.offset.y); rect.layer = 0; - if (Is90DegreeRotation(getPreTransform())) + if (Is90DegreeRotation(getPreTransform()) && + !contextVk->getFeatures().disablePreRotateIncrementalPresentRectangles.enabled) { std::swap(rect.offset.x, rect.offset.y); std::swap(rect.extent.width, rect.extent.height);