diff --git a/include/platform/FeaturesVk.h b/include/platform/FeaturesVk.h index 6e44f8748..b6b93ca37 100644 --- a/include/platform/FeaturesVk.h +++ b/include/platform/FeaturesVk.h @@ -456,6 +456,21 @@ struct FeaturesVk : FeatureSetBase "On some hardware, clear using a draw call instead of vkCmdClearAttachments in the middle " "of render pass due to bugs", &members, "https://issuetracker.google.com/166809097"}; + + // Whether prerotation is being emulated for testing. 90 degree rotation. + Feature emulatedPrerotation90 = {"emulated_prerotation_90", FeatureCategory::VulkanFeatures, + "Emulate 90-degree prerotation.", &members, + "http://anglebug.com/4901"}; + + // Whether prerotation is being emulated for testing. 180 degree rotation. + Feature emulatedPrerotation180 = {"emulated_prerotation_180", FeatureCategory::VulkanFeatures, + "Emulate 180-degree prerotation.", &members, + "http://anglebug.com/4901"}; + + // Whether prerotation is being emulated for testing. 270 degree rotation. + Feature emulatedPrerotation270 = {"emulated_prerotation_270", FeatureCategory::VulkanFeatures, + "Emulate 270-degree prerotation.", &members, + "http://anglebug.com/4901"}; }; inline FeaturesVk::FeaturesVk() = default; diff --git a/src/libANGLE/renderer/vulkan/ShaderVk.cpp b/src/libANGLE/renderer/vulkan/ShaderVk.cpp index 14ee3a51a..16c7e022b 100644 --- a/src/libANGLE/renderer/vulkan/ShaderVk.cpp +++ b/src/libANGLE/renderer/vulkan/ShaderVk.cpp @@ -72,9 +72,12 @@ std::shared_ptr ShaderVk::compile(const gl::Context *conte // context state does not allow it compileOptions |= SH_EARLY_FRAGMENT_TESTS_OPTIMIZATION; - if (contextVk->getFeatures().enablePreRotateSurfaces.enabled) + if (contextVk->getFeatures().enablePreRotateSurfaces.enabled || + contextVk->getFeatures().emulatedPrerotation90.enabled || + contextVk->getFeatures().emulatedPrerotation180.enabled || + contextVk->getFeatures().emulatedPrerotation270.enabled) { - // Let compiler inserts pre-rotation code. + // Let compiler insert pre-rotation code. compileOptions |= SH_ADD_PRE_ROTATION; } diff --git a/src/libANGLE/renderer/vulkan/SurfaceVk.cpp b/src/libANGLE/renderer/vulkan/SurfaceVk.cpp index c3b7ea8ad..a3546654a 100644 --- a/src/libANGLE/renderer/vulkan/SurfaceVk.cpp +++ b/src/libANGLE/renderer/vulkan/SurfaceVk.cpp @@ -475,6 +475,7 @@ WindowSurfaceVk::WindowSurfaceVk(const egl::SurfaceState &surfaceState, EGLNativ mDesiredSwapchainPresentMode(VK_PRESENT_MODE_FIFO_KHR), mMinImageCount(0), mPreTransform(VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR), + mEmulatedPreTransform(VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR), mCompositeAlpha(VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR), mCurrentSwapHistoryIndex(0), mCurrentSwapchainImageIndex(0), @@ -610,12 +611,37 @@ angle::Result WindowSurfaceVk::initializeImpl(DisplayVk *displayVk) { // Default to identity transform. mPreTransform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR; + if ((mSurfaceCaps.supportedTransforms & mPreTransform) == 0) { mPreTransform = mSurfaceCaps.currentTransform; } } + // Set emulated pre-transform if any emulated prerotation features are set. + if (renderer->getFeatures().emulatedPrerotation90.enabled) + { + mEmulatedPreTransform = VK_SURFACE_TRANSFORM_ROTATE_90_BIT_KHR; + } + else if (renderer->getFeatures().emulatedPrerotation180.enabled) + { + mEmulatedPreTransform = VK_SURFACE_TRANSFORM_ROTATE_180_BIT_KHR; + } + else if (renderer->getFeatures().emulatedPrerotation270.enabled) + { + mEmulatedPreTransform = VK_SURFACE_TRANSFORM_ROTATE_270_BIT_KHR; + } + + // If prerotation is emulated, the window is physically rotated. With real prerotation, the + // surface reports the rotated sizes. With emulated prerotation however, the surface reports + // the actual window sizes. Adjust the window extents to match what real prerotation would have + // reported. + if (Is90DegreeRotation(mEmulatedPreTransform)) + { + ASSERT(mPreTransform == VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR); + std::swap(extents.width, extents.height); + } + uint32_t presentModeCount = 0; ANGLE_VK_TRY(displayVk, vkGetPhysicalDeviceSurfacePresentModesKHR(physicalDevice, mSurface, &presentModeCount, nullptr)); @@ -779,7 +805,16 @@ angle::Result WindowSurfaceVk::recreateSwapchain(ContextVk *contextVk, const gl: releaseSwapchainImages(contextVk); - angle::Result result = createSwapChain(contextVk, extents, lastSwapchain); + // If prerotation is emulated, adjust the window extents to match what real prerotation would + // have reported. + gl::Extents swapchainExtents = extents; + if (Is90DegreeRotation(mEmulatedPreTransform)) + { + ASSERT(mPreTransform == VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR); + std::swap(swapchainExtents.width, swapchainExtents.height); + } + + angle::Result result = createSwapChain(contextVk, swapchainExtents, lastSwapchain); // Notify the parent classes of the surface's new state. onStateChange(angle::SubjectMessage::SurfaceChanged); @@ -882,7 +917,7 @@ angle::Result WindowSurfaceVk::createSwapChain(vk::Context *context, VkFormat nativeFormat = format.vkImageFormat; gl::Extents rotatedExtents = extents; - if (Is90DegreeRotation(mPreTransform)) + if (Is90DegreeRotation(getPreTransform())) { // The Surface is oriented such that its aspect ratio no longer matches that of the // device. In this case, the width and height of the swapchain images must be swapped to @@ -1300,7 +1335,7 @@ angle::Result WindowSurfaceVk::present(ContextVk *contextVk, 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(mPreTransform)) + if (Is90DegreeRotation(getPreTransform())) { std::swap(rect.offset.x, rect.offset.y); std::swap(rect.extent.width, rect.extent.height); @@ -1702,7 +1737,7 @@ angle::Result WindowSurfaceVk::getCurrentFramebuffer(ContextVk *contextVk, framebufferInfo.pAttachments = imageViews.data(); framebufferInfo.width = static_cast(extents.width); framebufferInfo.height = static_cast(extents.height); - if (Is90DegreeRotation(mPreTransform)) + if (Is90DegreeRotation(getPreTransform())) { std::swap(framebufferInfo.width, framebufferInfo.height); } diff --git a/src/libANGLE/renderer/vulkan/SurfaceVk.h b/src/libANGLE/renderer/vulkan/SurfaceVk.h index 8d23775bb..16b2b3dbd 100644 --- a/src/libANGLE/renderer/vulkan/SurfaceVk.h +++ b/src/libANGLE/renderer/vulkan/SurfaceVk.h @@ -243,7 +243,14 @@ class WindowSurfaceVk : public SurfaceVk vk::Semaphore getAcquireImageSemaphore(); - VkSurfaceTransformFlagBitsKHR getPreTransform() { return mPreTransform; } + VkSurfaceTransformFlagBitsKHR getPreTransform() + { + if (mEmulatedPreTransform != VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR) + { + return mEmulatedPreTransform; + } + return mPreTransform; + } protected: angle::Result swapImpl(const gl::Context *context, @@ -302,6 +309,7 @@ class WindowSurfaceVk : public SurfaceVk VkPresentModeKHR mDesiredSwapchainPresentMode; // Desired mode set through setSwapInterval() uint32_t mMinImageCount; VkSurfaceTransformFlagBitsKHR mPreTransform; + VkSurfaceTransformFlagBitsKHR mEmulatedPreTransform; VkCompositeAlphaFlagBitsKHR mCompositeAlpha; // A circular buffer that stores the submission fence of the context on every swap. The CPU is diff --git a/src/tests/gl_tests/BlitFramebufferANGLETest.cpp b/src/tests/gl_tests/BlitFramebufferANGLETest.cpp index 9998dbacc..c699709df 100644 --- a/src/tests/gl_tests/BlitFramebufferANGLETest.cpp +++ b/src/tests/gl_tests/BlitFramebufferANGLETest.cpp @@ -14,7 +14,7 @@ class BlitFramebufferANGLETest : public ANGLETest protected: BlitFramebufferANGLETest() { - setWindowWidth(32); + setWindowWidth(64); setWindowHeight(32); setConfigRedBits(8); setConfigGreenBits(8); @@ -2447,6 +2447,9 @@ ANGLE_INSTANTIATE_TEST(BlitFramebufferANGLETest, ES3_OPENGL(), ES2_VULKAN(), ES3_VULKAN(), + WithEmulatedPrerotation(ES3_VULKAN(), 90), + WithEmulatedPrerotation(ES3_VULKAN(), 180), + WithEmulatedPrerotation(ES3_VULKAN(), 270), ES2_METAL(), WithNoShaderStencilOutput(ES2_METAL())); diff --git a/src/tests/test_utils/ANGLETest.cpp b/src/tests/test_utils/ANGLETest.cpp index e668a957d..f9a047a57 100644 --- a/src/tests/test_utils/ANGLETest.cpp +++ b/src/tests/test_utils/ANGLETest.cpp @@ -538,9 +538,27 @@ void ANGLETestBase::ANGLETestSetUp() // Resize the window before creating the context so that the first make current // sets the viewport and scissor box to the right size. bool needSwap = false; - if (mFixture->osWindow->getWidth() != mWidth || mFixture->osWindow->getHeight() != mHeight) + + int osWindowWidth = mFixture->osWindow->getWidth(); + int osWindowHeight = mFixture->osWindow->getHeight(); + + const bool isRotated = mCurrentParams->eglParameters.emulatedPrerotation == 90 || + mCurrentParams->eglParameters.emulatedPrerotation == 270; + if (isRotated) { - if (!mFixture->osWindow->resize(mWidth, mHeight)) + std::swap(osWindowWidth, osWindowHeight); + } + + if (osWindowWidth != mWidth || osWindowHeight != mHeight) + { + int newWindowWidth = mWidth; + int newWindowHeight = mHeight; + if (isRotated) + { + std::swap(newWindowWidth, newWindowHeight); + } + + if (!mFixture->osWindow->resize(newWindowWidth, newWindowHeight)) { FAIL() << "Failed to resize ANGLE test window."; } @@ -1229,9 +1247,9 @@ int ANGLETestBase::getWindowHeight() const return mHeight; } -bool ANGLETestBase::isMultisampleEnabled() const +bool ANGLETestBase::isEmulatedPrerotation() const { - return mFixture->eglWindow->isMultisample(); + return mCurrentParams->eglParameters.emulatedPrerotation != 0; } void ANGLETestBase::setWindowVisible(OSWindow *osWindow, bool isVisible) diff --git a/src/tests/test_utils/ANGLETest.h b/src/tests/test_utils/ANGLETest.h index 63affc3ab..9fa1434f7 100644 --- a/src/tests/test_utils/ANGLETest.h +++ b/src/tests/test_utils/ANGLETest.h @@ -462,7 +462,7 @@ class ANGLETestBase EGLWindow *getEGLWindow() const; int getWindowWidth() const; int getWindowHeight() const; - bool isMultisampleEnabled() const; + bool isEmulatedPrerotation() const; EGLint getPlatformRenderer() const; diff --git a/src/tests/test_utils/angle_test_configs.cpp b/src/tests/test_utils/angle_test_configs.cpp index eaca913c3..e710a2afc 100644 --- a/src/tests/test_utils/angle_test_configs.cpp +++ b/src/tests/test_utils/angle_test_configs.cpp @@ -219,6 +219,19 @@ std::ostream &operator<<(std::ostream &stream, const PlatformParameters &pp) stream << "_NoGenMultipleMipsPerPass"; } + if (pp.eglParameters.emulatedPrerotation == 90) + { + stream << "_PreRotation90"; + } + else if (pp.eglParameters.emulatedPrerotation == 180) + { + stream << "_PreRotation180"; + } + else if (pp.eglParameters.emulatedPrerotation == 270) + { + stream << "_PreRotation270"; + } + return stream; } diff --git a/src/tests/test_utils/angle_test_configs.h b/src/tests/test_utils/angle_test_configs.h index 8404ad04f..64d29fa35 100644 --- a/src/tests/test_utils/angle_test_configs.h +++ b/src/tests/test_utils/angle_test_configs.h @@ -247,6 +247,13 @@ inline PlatformParameters WithRobustness(const PlatformParameters ¶ms) withRobustness.eglParameters.robustness = EGL_TRUE; return withRobustness; } + +inline PlatformParameters WithEmulatedPrerotation(const PlatformParameters ¶ms, EGLint rotation) +{ + PlatformParameters prerotation = params; + prerotation.eglParameters.emulatedPrerotation = rotation; + return prerotation; +} } // namespace angle #endif // ANGLE_TEST_CONFIGS_H_ diff --git a/util/EGLPlatformParameters.h b/util/EGLPlatformParameters.h index 1ce4af961..fb951fcc6 100644 --- a/util/EGLPlatformParameters.h +++ b/util/EGLPlatformParameters.h @@ -62,7 +62,7 @@ struct EGLPlatformParameters debugLayersEnabled, contextVirtualization, transformFeedbackFeature, allocateNonZeroMemoryFeature, emulateCopyTexImage2DFromRenderbuffers, shaderStencilOutputFeature, genMultipleMipsPerPassFeature, platformMethods, - robustness); + robustness, emulatedPrerotation); } EGLint renderer = EGL_PLATFORM_ANGLE_TYPE_DEFAULT_ANGLE; @@ -78,6 +78,7 @@ struct EGLPlatformParameters EGLint emulateCopyTexImage2DFromRenderbuffers = EGL_DONT_CARE; EGLint shaderStencilOutputFeature = EGL_DONT_CARE; EGLint genMultipleMipsPerPassFeature = EGL_DONT_CARE; + uint32_t emulatedPrerotation = 0; // Can be 0, 90, 180 or 270 angle::PlatformMethods *platformMethods = nullptr; }; diff --git a/util/EGLWindow.cpp b/util/EGLWindow.cpp index ea57375de..9c683707d 100644 --- a/util/EGLWindow.cpp +++ b/util/EGLWindow.cpp @@ -206,6 +206,19 @@ bool EGLWindow::initializeDisplay(OSWindow *osWindow, disabledFeatureOverrides.push_back("gen_multiple_mips_per_pass"); } + if (params.emulatedPrerotation == 90) + { + enabledFeatureOverrides.push_back("emulated_prerotation_90"); + } + else if (params.emulatedPrerotation == 180) + { + enabledFeatureOverrides.push_back("emulated_prerotation_180"); + } + else if (params.emulatedPrerotation == 270) + { + enabledFeatureOverrides.push_back("emulated_prerotation_270"); + } + if (!disabledFeatureOverrides.empty()) { if (strstr(extensionString, "EGL_ANGLE_feature_control") == nullptr) diff --git a/util/x11/X11Window.cpp b/util/x11/X11Window.cpp index ea985ea85..6f8a78075 100644 --- a/util/x11/X11Window.cpp +++ b/util/x11/X11Window.cpp @@ -438,7 +438,7 @@ bool X11Window::resize(int width, int height) Timer timer; timer.start(); - // Wait until the window as actually been resized so that the code calling resize + // Wait until the window has actually been resized so that the code calling resize // can assume the window has been resized. const double kResizeWaitDelay = 0.2; while ((mHeight != height || mWidth != width) && timer.getElapsedTime() < kResizeWaitDelay)