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