diff options
| author | 2020-09-22 11:41:01 +0000 | |
|---|---|---|
| committer | 2020-09-22 11:41:01 +0000 | |
| commit | b2d6a712e8fbe7cc81696ed38809689727d30ec6 (patch) | |
| tree | eccce6563cecda2042a2e7a7ada5ff96677864f9 | |
| parent | 95055aa8966c3bd5e3f06ad9fef9cd12bf2f5347 (diff) | |
| parent | 68933fb83aeffbbc0cb2d0a082feed26cb2e57a4 (diff) | |
Merge "[CE] Extract transform computation logic to ProjectionSpace"
14 files changed, 290 insertions, 104 deletions
diff --git a/libs/ui/include/ui/Transform.h b/libs/ui/include/ui/Transform.h index 9a434e541b..a197b3b20e 100644 --- a/libs/ui/include/ui/Transform.h +++ b/libs/ui/include/ui/Transform.h @@ -111,7 +111,7 @@ public: void dump(std::string& result, const char* name, const char* prefix = "") const; void dump(const char* name, const char* prefix = "") const; - static RotationFlags toRotationFlags(Rotation); + static constexpr RotationFlags toRotationFlags(Rotation); private: struct mat33 { @@ -136,7 +136,7 @@ inline void PrintTo(const Transform& t, ::std::ostream* os) { *os << out; } -inline Transform::RotationFlags Transform::toRotationFlags(Rotation rotation) { +inline constexpr Transform::RotationFlags Transform::toRotationFlags(Rotation rotation) { switch (rotation) { case ROTATION_0: return ROT_0; diff --git a/services/surfaceflinger/CompositionEngine/Android.bp b/services/surfaceflinger/CompositionEngine/Android.bp index 4863297d82..57dc60bbac 100644 --- a/services/surfaceflinger/CompositionEngine/Android.bp +++ b/services/surfaceflinger/CompositionEngine/Android.bp @@ -95,8 +95,9 @@ cc_test { "tests/MockHWC2.cpp", "tests/MockHWComposer.cpp", "tests/MockPowerAdvisor.cpp", - "tests/OutputTest.cpp", "tests/OutputLayerTest.cpp", + "tests/OutputTest.cpp", + "tests/ProjectionSpaceTest.cpp", "tests/RenderSurfaceTest.cpp", ], static_libs: [ diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h index 6552c5460a..fc1adccfb7 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h @@ -163,9 +163,8 @@ public: virtual void setCompositionEnabled(bool) = 0; // Sets the projection state to use - virtual void setProjection(const ui::Transform&, uint32_t orientation, - const Rect& orientedDisplaySpaceRect, - const Rect& layerStackSpaceRect, const Rect& displaySpaceRect) = 0; + virtual void setProjection(ui::Rotation orientation, const Rect& layerStackSpaceRect, + const Rect& orientedDisplaySpaceRect) = 0; // Sets the bounds to use virtual void setDisplaySpaceSize(const ui::Size&) = 0; diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/ProjectionSpace.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/ProjectionSpace.h index 9d15665af1..7ca91d86eb 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/ProjectionSpace.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/ProjectionSpace.h @@ -38,14 +38,73 @@ struct ProjectionSpace { // Rect onto which content is projected. Rect content; + + // The orientation of this space. This value is meaningful only in relation to the rotation + // of another projection space and it's used to determine the rotating transformation when + // mapping between the two. + // As a convention when using this struct orientation = 0 for the "oriented*" projection + // spaces. For example when the display is rotated 90 degress counterclockwise, the orientation + // of the display space will become 90, while the orientation of the layer stack space will + // remain the same. + ui::Rotation orientation = ui::ROTATION_0; + + // Returns a transform which maps this.content into destination.content + // and also rotates according to this.orientation and destination.orientation + ui::Transform getTransform(const ProjectionSpace& destination) const { + ui::Rotation rotation = destination.orientation - orientation; + + // Compute a transformation which rotates the destination in a way it has the same + // orientation as us. + const uint32_t inverseRotationFlags = ui::Transform::toRotationFlags(-rotation); + ui::Transform inverseRotatingTransform; + inverseRotatingTransform.set(inverseRotationFlags, destination.bounds.width(), + destination.bounds.height()); + // The destination content rotated so it has the same orientation as us. + Rect orientedDestContent = inverseRotatingTransform.transform(destination.content); + + // Compute translation from the source content to (0, 0). + const float sourceX = content.left; + const float sourceY = content.top; + ui::Transform sourceTranslation; + sourceTranslation.set(-sourceX, -sourceY); + + // Compute scaling transform which maps source content to destination content, assuming + // they are both at (0, 0). + ui::Transform scale; + const float scaleX = static_cast<float>(orientedDestContent.width()) / content.width(); + const float scaleY = static_cast<float>(orientedDestContent.height()) / content.height(); + scale.set(scaleX, 0, 0, scaleY); + + // Compute translation from (0, 0) to the orientated destination content. + const float destX = orientedDestContent.left; + const float destY = orientedDestContent.top; + ui::Transform destTranslation; + destTranslation.set(destX, destY); + + // Compute rotation transform. + const uint32_t orientationFlags = ui::Transform::toRotationFlags(rotation); + auto orientedDestWidth = destination.bounds.width(); + auto orientedDestHeight = destination.bounds.height(); + if (rotation == ui::ROTATION_90 || rotation == ui::ROTATION_270) { + std::swap(orientedDestWidth, orientedDestHeight); + } + ui::Transform rotationTransform; + rotationTransform.set(orientationFlags, orientedDestWidth, orientedDestHeight); + + // The layerStackSpaceRect and orientedDisplaySpaceRect are both in the logical orientation. + // Apply the logical translation, scale to physical size, apply the + // physical translation and finally rotate to the physical orientation. + return rotationTransform * destTranslation * scale * sourceTranslation; + } }; } // namespace compositionengine inline std::string to_string(const android::compositionengine::ProjectionSpace& space) { - return android::base::StringPrintf("ProjectionSpace(bounds = %s, content = %s)", - to_string(space.bounds).c_str(), - to_string(space.content).c_str()); + return android::base:: + StringPrintf("ProjectionSpace(bounds = %s, content = %s, orientation = %s)", + to_string(space.bounds).c_str(), to_string(space.content).c_str(), + toCString(space.orientation)); } // Defining PrintTo helps with Google Tests. diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h index e009894964..6fe93bfc20 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h @@ -38,9 +38,8 @@ public: bool isValid() const override; std::optional<DisplayId> getDisplayId() const override; void setCompositionEnabled(bool) override; - void setProjection(const ui::Transform&, uint32_t orientation, - const Rect& orientedDisplaySpaceRect, const Rect& layerStackSpaceRect, - const Rect& displaySpaceRect) override; + void setProjection(ui::Rotation orientation, const Rect& layerStackSpaceRect, + const Rect& orientedDisplaySpaceRect) override; void setDisplaySpaceSize(const ui::Size&) override; void setLayerStackFilter(uint32_t layerStackId, bool isInternal) override; diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputCompositionState.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputCompositionState.h index 462d9525cc..f4d2b56d3a 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputCompositionState.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputCompositionState.h @@ -64,13 +64,11 @@ struct OutputCompositionState { uint32_t layerStackId{~0u}; // The common space for all layers in the layer stack. layerStackSpace.content is the Rect - // which gets projected on the display. The content in this space is always in a single - // orientation. + // which gets projected on the display. The orientation of this space is always ROTATION_0. ProjectionSpace layerStackSpace; // Oriented physical display space. It will have the same size as displaySpace oriented to - // match the orientation of layerStackSpace. The content in this space is always in a single - // orientation. + // match the orientation of layerStackSpace. The orientation of this space is always ROTATION_0. ProjectionSpace orientedDisplaySpace; // The space of the physical display. It is as big as the currently active display mode. The @@ -80,9 +78,6 @@ struct OutputCompositionState { // Transformation from layerStackSpace to displaySpace ui::Transform transform; - // The physical orientation of the display, expressed as ui::Transform orientation flags. - uint32_t orientation{0}; - // If true, RenderEngine filtering should be enabled bool needsFiltering{false}; diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h index 5350611ae4..19025c1edc 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h @@ -36,8 +36,7 @@ public: MOCK_CONST_METHOD0(getDisplayId, std::optional<DisplayId>()); MOCK_METHOD1(setCompositionEnabled, void(bool)); - MOCK_METHOD5(setProjection, - void(const ui::Transform&, uint32_t, const Rect&, const Rect&, const Rect&)); + MOCK_METHOD3(setProjection, void(ui::Rotation, const Rect&, const Rect&)); MOCK_METHOD1(setDisplaySpaceSize, void(const ui::Size&)); MOCK_METHOD2(setLayerStackFilter, void(uint32_t, bool)); diff --git a/services/surfaceflinger/CompositionEngine/src/Output.cpp b/services/surfaceflinger/CompositionEngine/src/Output.cpp index 816a09b05c..abb8769563 100644 --- a/services/surfaceflinger/CompositionEngine/src/Output.cpp +++ b/services/surfaceflinger/CompositionEngine/src/Output.cpp @@ -105,25 +105,34 @@ void Output::setCompositionEnabled(bool enabled) { dirtyEntireOutput(); } -void Output::setProjection(const ui::Transform& transform, uint32_t orientation, - const Rect& orientedDisplaySpaceRect, const Rect& layerStackSpaceRect, - const Rect& displaySpaceRect) { +void Output::setProjection(ui::Rotation orientation, const Rect& layerStackSpaceRect, + const Rect& orientedDisplaySpaceRect) { auto& outputState = editState(); - outputState.transform = transform; - outputState.orientation = orientation; - outputState.displaySpace.content = displaySpaceRect; + + outputState.displaySpace.orientation = orientation; // outputState.displaySpace.bounds should be already set from setDisplaySpaceSize(). - outputState.orientedDisplaySpace.content = orientedDisplaySpaceRect; + // Compute the orientedDisplaySpace bounds ui::Size orientedSize = outputState.displaySpace.bounds.getSize(); - if (orientation == ui::Transform::ROT_90 || orientation == ui::Transform::ROT_270) { + if (orientation == ui::ROTATION_90 || orientation == ui::ROTATION_270) { std::swap(orientedSize.width, orientedSize.height); } outputState.orientedDisplaySpace.bounds = Rect(orientedSize); + outputState.orientedDisplaySpace.content = orientedDisplaySpaceRect; + + // Compute displaySpace.content + const uint32_t transformOrientationFlags = ui::Transform::toRotationFlags(orientation); + ui::Transform rotation; + if (transformOrientationFlags != ui::Transform::ROT_INVALID) { + const auto displaySize = outputState.displaySpace.bounds; + rotation.set(transformOrientationFlags, displaySize.width(), displaySize.height()); + } + outputState.displaySpace.content = rotation.transform(orientedDisplaySpaceRect); outputState.layerStackSpace.content = layerStackSpaceRect; outputState.layerStackSpace.bounds = layerStackSpaceRect; - outputState.needsFiltering = transform.needsBilinearFiltering(); + outputState.transform = outputState.layerStackSpace.getTransform(outputState.displaySpace); + outputState.needsFiltering = outputState.transform.needsBilinearFiltering(); dirtyEntireOutput(); } @@ -870,7 +879,8 @@ std::optional<base::unique_fd> Output::composeSurfaces( renderengine::DisplaySettings clientCompositionDisplay; clientCompositionDisplay.physicalDisplay = outputState.displaySpace.content; clientCompositionDisplay.clip = outputState.layerStackSpace.content; - clientCompositionDisplay.orientation = outputState.orientation; + clientCompositionDisplay.orientation = + ui::Transform::toRotationFlags(outputState.displaySpace.orientation); clientCompositionDisplay.outputDataspace = mDisplayColorProfile->hasWideColorGamut() ? outputState.dataspace : ui::Dataspace::UNKNOWN; diff --git a/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp b/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp index 0f536411a9..0faab6fbf4 100644 --- a/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp +++ b/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp @@ -133,7 +133,8 @@ FloatRect OutputLayer::calculateOutputSourceCrop() const { * the code below applies the primary display's inverse transform to the * buffer */ - uint32_t invTransformOrient = outputState.orientation; + uint32_t invTransformOrient = + ui::Transform::toRotationFlags(outputState.displaySpace.orientation); // calculate the inverse transform if (invTransformOrient & HAL_TRANSFORM_ROT_90) { invTransformOrient ^= HAL_TRANSFORM_FLIP_V | HAL_TRANSFORM_FLIP_H; diff --git a/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp b/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp index d9fb0982f2..dcfc162922 100644 --- a/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp +++ b/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp @@ -21,6 +21,7 @@ #include <compositionengine/mock/LayerFE.h> #include <compositionengine/mock/Output.h> #include <gtest/gtest.h> +#include <log/log.h> #include "MockHWC2.h" #include "MockHWComposer.h" @@ -55,6 +56,22 @@ MATCHER_P(ColorEq, expected, "") { return expected.r == arg.r && expected.g == arg.g && expected.b == arg.b && expected.a == arg.a; } +ui::Rotation toRotation(uint32_t rotationFlag) { + switch (rotationFlag) { + case ui::Transform::RotationFlags::ROT_0: + return ui::ROTATION_0; + case ui::Transform::RotationFlags::ROT_90: + return ui::ROTATION_90; + case ui::Transform::RotationFlags::ROT_180: + return ui::ROTATION_180; + case ui::Transform::RotationFlags::ROT_270: + return ui::ROTATION_270; + default: + LOG_FATAL("Unexpected rotation flag %d", rotationFlag); + return ui::Rotation(-1); + } +} + struct OutputLayerTest : public testing::Test { struct OutputLayer final : public impl::OutputLayer { OutputLayer(const compositionengine::Output& output, sp<compositionengine::LayerFE> layerFE) @@ -209,7 +226,7 @@ TEST_F(OutputLayerSourceCropTest, calculateOutputSourceCropWorksWithATransformed mLayerFEState.geomBufferUsesDisplayInverseTransform = entry.bufferInvDisplay; mLayerFEState.geomBufferTransform = entry.buffer; - mOutputState.orientation = entry.display; + mOutputState.displaySpace.orientation = toRotation(entry.display); EXPECT_THAT(calculateOutputSourceCrop(), entry.expected) << "entry " << i; } @@ -358,7 +375,7 @@ TEST_F(OutputLayerTest, calculateOutputRelativeBufferTransformTestsNeeded) { mLayerFEState.geomLayerTransform.set(entry.layer, 1920, 1080); mLayerFEState.geomBufferTransform = entry.buffer; - mOutputState.orientation = entry.display; + mOutputState.displaySpace.orientation = toRotation(entry.display); mOutputState.transform = ui::Transform{entry.display}; const auto actual = mOutputLayer.calculateOutputRelativeBufferTransform(entry.display); @@ -470,7 +487,7 @@ TEST_F(OutputLayerTest, mLayerFEState.geomLayerTransform.set(entry.layer, 1920, 1080); mLayerFEState.geomBufferTransform = entry.buffer; - mOutputState.orientation = entry.display; + mOutputState.displaySpace.orientation = toRotation(entry.display); mOutputState.transform = ui::Transform{entry.display}; const auto actual = mOutputLayer.calculateOutputRelativeBufferTransform(entry.internal); @@ -853,7 +870,7 @@ TEST_F(OutputLayerTest, displayInstallOrientationBufferTransformSetTo90) { // This test simulates a scenario where displayInstallOrientation is set to // ROT_90. This only has an effect on the transform; orientation stays 0 (see // DisplayDevice::setProjection). - mOutputState.orientation = TR_IDENT; + mOutputState.displaySpace.orientation = ui::ROTATION_0; mOutputState.transform = ui::Transform{TR_ROT_90}; // Buffers are pre-rotated based on the transform hint (ROT_90); their // geomBufferTransform is set to the inverse transform. diff --git a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp index 23efd2dc18..c01f3e00a2 100644 --- a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp +++ b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp @@ -236,19 +236,15 @@ TEST_F(OutputTest, setCompositionEnabledSetsDisabledAndDirtiesEntireOutput) { */ TEST_F(OutputTest, setProjectionTriviallyWorks) { - const ui::Transform transform{ui::Transform::ROT_180}; - const int32_t orientation = 123; + const ui::Rotation orientation = ui::ROTATION_90; const Rect frame{1, 2, 3, 4}; const Rect viewport{5, 6, 7, 8}; - const Rect destinationClip{13, 14, 15, 16}; - mOutput->setProjection(transform, orientation, frame, viewport, destinationClip); + mOutput->setProjection(orientation, viewport, frame); - EXPECT_THAT(mOutput->getState().transform, transform); - EXPECT_EQ(orientation, mOutput->getState().orientation); + EXPECT_EQ(orientation, mOutput->getState().displaySpace.orientation); EXPECT_EQ(frame, mOutput->getState().orientedDisplaySpace.content); EXPECT_EQ(viewport, mOutput->getState().layerStackSpace.content); - EXPECT_EQ(destinationClip, mOutput->getState().displaySpace.content); } /* @@ -2783,8 +2779,8 @@ struct OutputComposeSurfacesTest : public testing::Test { mOutput.mState.orientedDisplaySpace.content = kDefaultOutputFrame; mOutput.mState.layerStackSpace.content = kDefaultOutputViewport; mOutput.mState.displaySpace.content = kDefaultOutputDestinationClip; - mOutput.mState.transform = ui::Transform{kDefaultOutputOrientation}; - mOutput.mState.orientation = kDefaultOutputOrientation; + mOutput.mState.transform = ui::Transform{kDefaultOutputOrientationFlags}; + mOutput.mState.displaySpace.orientation = kDefaultOutputOrientation; mOutput.mState.dataspace = kDefaultOutputDataspace; mOutput.mState.colorTransformMatrix = kDefaultColorTransformMat; mOutput.mState.isSecure = false; @@ -2819,7 +2815,9 @@ struct OutputComposeSurfacesTest : public testing::Test { // Call this member function to start using the mini-DSL defined above. [[nodiscard]] auto verify() { return ExecuteState::make(this); } - static constexpr uint32_t kDefaultOutputOrientation = TR_IDENT; + static constexpr ui::Rotation kDefaultOutputOrientation = ui::ROTATION_0; + static constexpr uint32_t kDefaultOutputOrientationFlags = + ui::Transform::toRotationFlags(kDefaultOutputOrientation); static constexpr ui::Dataspace kDefaultOutputDataspace = ui::Dataspace::UNKNOWN; static constexpr ui::Dataspace kExpensiveOutputDataspace = ui::Dataspace::DISPLAY_P3; static constexpr float kDefaultMaxLuminance = 0.9f; @@ -3116,7 +3114,7 @@ TEST_F(OutputComposeSurfacesTest_UsesExpectedDisplaySettings, forHdrMixedComposi .andIfSkipColorTransform(false) .thenExpectDisplaySettingsUsed({kDefaultOutputDestinationClip, kDefaultOutputViewport, kDefaultMaxLuminance, kDefaultOutputDataspace, mat4(), - Region::INVALID_REGION, kDefaultOutputOrientation}) + Region::INVALID_REGION, kDefaultOutputOrientationFlags}) .execute() .expectAFenceWasReturned(); } @@ -3127,7 +3125,7 @@ TEST_F(OutputComposeSurfacesTest_UsesExpectedDisplaySettings, forNonHdrMixedComp .andIfSkipColorTransform(false) .thenExpectDisplaySettingsUsed({kDefaultOutputDestinationClip, kDefaultOutputViewport, kDefaultMaxLuminance, kDefaultOutputDataspace, mat4(), - Region::INVALID_REGION, kDefaultOutputOrientation}) + Region::INVALID_REGION, kDefaultOutputOrientationFlags}) .execute() .expectAFenceWasReturned(); } @@ -3139,7 +3137,7 @@ TEST_F(OutputComposeSurfacesTest_UsesExpectedDisplaySettings, forHdrOnlyClientCo .thenExpectDisplaySettingsUsed({kDefaultOutputDestinationClip, kDefaultOutputViewport, kDefaultMaxLuminance, kDefaultOutputDataspace, kDefaultColorTransformMat, Region::INVALID_REGION, - kDefaultOutputOrientation}) + kDefaultOutputOrientationFlags}) .execute() .expectAFenceWasReturned(); } @@ -3151,7 +3149,7 @@ TEST_F(OutputComposeSurfacesTest_UsesExpectedDisplaySettings, forNonHdrOnlyClien .thenExpectDisplaySettingsUsed({kDefaultOutputDestinationClip, kDefaultOutputViewport, kDefaultMaxLuminance, kDefaultOutputDataspace, kDefaultColorTransformMat, Region::INVALID_REGION, - kDefaultOutputOrientation}) + kDefaultOutputOrientationFlags}) .execute() .expectAFenceWasReturned(); } @@ -3163,7 +3161,7 @@ TEST_F(OutputComposeSurfacesTest_UsesExpectedDisplaySettings, .andIfSkipColorTransform(true) .thenExpectDisplaySettingsUsed({kDefaultOutputDestinationClip, kDefaultOutputViewport, kDefaultMaxLuminance, kDefaultOutputDataspace, mat4(), - Region::INVALID_REGION, kDefaultOutputOrientation}) + Region::INVALID_REGION, kDefaultOutputOrientationFlags}) .execute() .expectAFenceWasReturned(); } @@ -3409,8 +3407,9 @@ struct GenerateClientCompositionRequestsTest_ThreeLayers mOutput.mState.orientedDisplaySpace.content = kDisplayFrame; mOutput.mState.layerStackSpace.content = kDisplayViewport; mOutput.mState.displaySpace.content = kDisplayDestinationClip; - mOutput.mState.transform = ui::Transform{kDisplayOrientation}; - mOutput.mState.orientation = kDisplayOrientation; + mOutput.mState.transform = + ui::Transform{ui::Transform::toRotationFlags(kDisplayOrientation)}; + mOutput.mState.displaySpace.orientation = kDisplayOrientation; mOutput.mState.needsFiltering = false; mOutput.mState.isSecure = false; @@ -3434,7 +3433,7 @@ struct GenerateClientCompositionRequestsTest_ThreeLayers EXPECT_CALL(mOutput, getOutputLayerCount()).WillRepeatedly(Return(mLayers.size())); } - static constexpr uint32_t kDisplayOrientation = TR_IDENT; + static constexpr ui::Rotation kDisplayOrientation = ui::ROTATION_0; static constexpr ui::Dataspace kDisplayDataspace = ui::Dataspace::UNKNOWN; static const Rect kDisplayFrame; @@ -3918,14 +3917,14 @@ TEST_F(GenerateClientCompositionRequestsTest, handlesLandscapeModeSplitScreenReq const Rect kPortraitFrame(0, 0, 1000, 2000); const Rect kPortraitViewport(0, 0, 2000, 1000); const Rect kPortraitDestinationClip(0, 0, 1000, 2000); - const uint32_t kPortraitOrientation = TR_ROT_90; + const ui::Rotation kPortraitOrientation = ui::ROTATION_90; constexpr ui::Dataspace kOutputDataspace = ui::Dataspace::DISPLAY_P3; mOutput.mState.orientedDisplaySpace.content = kPortraitFrame; mOutput.mState.layerStackSpace.content = kPortraitViewport; mOutput.mState.displaySpace.content = kPortraitDestinationClip; - mOutput.mState.transform = ui::Transform{kPortraitOrientation}; - mOutput.mState.orientation = kPortraitOrientation; + mOutput.mState.transform = ui::Transform{ui::Transform::toRotationFlags(kPortraitOrientation)}; + mOutput.mState.displaySpace.orientation = kPortraitOrientation; mOutput.mState.needsFiltering = false; mOutput.mState.isSecure = true; diff --git a/services/surfaceflinger/CompositionEngine/tests/ProjectionSpaceTest.cpp b/services/surfaceflinger/CompositionEngine/tests/ProjectionSpaceTest.cpp new file mode 100644 index 0000000000..704f5a8c07 --- /dev/null +++ b/services/surfaceflinger/CompositionEngine/tests/ProjectionSpaceTest.cpp @@ -0,0 +1,144 @@ +/* + * Copyright 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include <compositionengine/ProjectionSpace.h> +#include <gtest/gtest.h> + +namespace android::compositionengine { +namespace { + +// Returns a rectangular strip along the side of the given rect pointed by +// rotation. E.g. if rotation is ROTATION_0, the srip will be along the top +// side, if it is ROTATION_90 the stip will be along the right wall. +// One of the dimensions of the strip will be 0 and the other one will match +// the length of the corresponding side. +// The strip will be contained inside the given rect. +Rect getSideStrip(const Rect& rect, ui::Rotation rotation) { + int width, height; + if (rotation == ui::ROTATION_90 || rotation == ui::ROTATION_270) { + width = 0; + height = rect.height(); + } else { + width = rect.width(); + height = 0; + } + + if (rotation == ui::ROTATION_0 || rotation == ui::ROTATION_270) { + return Rect(rect.left, rect.top, rect.left + width, rect.top + height); + } + + if (rotation == ui::ROTATION_90) { + return Rect(rect.right, rect.top, rect.right + width, rect.top + height); + } + + if (rotation == ui::ROTATION_180) { + return Rect(rect.left, rect.bottom, rect.left + width, rect.bottom + height); + } + + return Rect::INVALID_RECT; +} +} // namespace + +TEST(ProjectionSpaceTest, getTransformToSelfIsIdentity) { + ProjectionSpace space; + space.content = Rect(100, 200); + space.bounds = Rect(100, 200); + + const ui::Transform identity; + for (int rotation = 0; rotation <= 3; rotation++) { + space.orientation = ui::Rotation(rotation); + EXPECT_EQ(space.getTransform(space), identity); + } +} + +TEST(ProjectionSpaceTest, getTransformWhenTranslationIsNeeded) { + ProjectionSpace source; + source.content = Rect(10, 10, 20, 20); + source.bounds = Rect(100, 200); + + ProjectionSpace dest; + dest.content = Rect(10, 20, 30, 20); + dest.bounds = source.bounds; + + const auto transform = source.getTransform(dest); + EXPECT_EQ(transform.transform(source.content), dest.content); +} + +TEST(ProjectionSpaceTest, getTransformWhenScaleIsNeeded) { + ProjectionSpace source; + source.content = Rect(0, 0, 20, 20); + source.bounds = Rect(100, 200); + + ProjectionSpace dest; + dest.content = Rect(0, 0, 40, 30); + dest.bounds = source.bounds; + + const auto transform = source.getTransform(dest); + EXPECT_EQ(transform.transform(source.content), dest.content); +} + +TEST(ProjectionSpaceTest, getSideStripTest) { + const Rect rect(10, 20, 40, 100); + EXPECT_EQ(getSideStrip(rect, ui::ROTATION_0), Rect(10, 20, 40, 20)); + EXPECT_EQ(getSideStrip(rect, ui::ROTATION_90), Rect(40, 20, 40, 100)); + EXPECT_EQ(getSideStrip(rect, ui::ROTATION_180), Rect(10, 100, 40, 100)); + EXPECT_EQ(getSideStrip(rect, ui::ROTATION_270), Rect(10, 20, 10, 100)); +} + +void testTransform(const ProjectionSpace& source, const ProjectionSpace& dest) { + const auto transform = source.getTransform(dest); + EXPECT_EQ(transform.transform(source.content), dest.content) + << "Source content doesn't map to dest content when projecting " << to_string(source) + << " onto " << to_string(dest); + + // We take a strip at the top (according to the orientation) of each + // content rect and verify that transform maps between them. This way we + // verify that the transform is rotating properly. + // In the following example the strip is marked with asterisks: + // + // ******* +-------* + // | | | * + // | | | * + // +-----+ +-------* + // source(ROTATION_0) dest (ROTATION_90) + const auto sourceStrip = getSideStrip(source.content, source.orientation); + const auto destStrip = getSideStrip(dest.content, dest.orientation); + ASSERT_NE(sourceStrip, Rect::INVALID_RECT); + ASSERT_NE(destStrip, Rect::INVALID_RECT); + const auto mappedStrip = transform.transform(sourceStrip); + EXPECT_EQ(mappedStrip, destStrip) + << to_string(sourceStrip) << " maps to " << to_string(mappedStrip) << " instead of " + << to_string(destStrip) << " when projecting " << to_string(source) << " onto " + << to_string(dest); +} + +TEST(ProjectionSpaceTest, getTransformWithOrienations) { + ProjectionSpace source; + source.bounds = Rect(12, 13, 678, 789); + source.content = Rect(40, 50, 234, 343); + ProjectionSpace dest; + dest.bounds = Rect(17, 18, 879, 564); + dest.content = Rect(43, 52, 432, 213); + + for (int sourceRot = 0; sourceRot <= 3; sourceRot++) { + source.orientation = ui::Rotation(sourceRot); + for (int destRot = 0; destRot <= 3; destRot++) { + dest.orientation = ui::Rotation(destRot); + testTransform(source, dest); + } + } +} + +} // namespace android::compositionengine diff --git a/services/surfaceflinger/DisplayDevice.cpp b/services/surfaceflinger/DisplayDevice.cpp index b53f88de58..7df9b766bd 100644 --- a/services/surfaceflinger/DisplayDevice.cpp +++ b/services/surfaceflinger/DisplayDevice.cpp @@ -163,6 +163,10 @@ void DisplayDevice::setProjection(ui::Rotation orientation, Rect layerStackSpace Rect orientedDisplaySpaceRect) { mOrientation = orientation; + if (isPrimary()) { + sPrimaryDisplayRotationFlags = ui::Transform::toRotationFlags(orientation); + } + const Rect& displayBounds = getCompositionDisplay()->getState().displaySpace.bounds; const int displayWidth = displayBounds.width(); const int displayHeight = displayBounds.height(); @@ -184,52 +188,11 @@ void DisplayDevice::setProjection(ui::Rotation orientation, Rect layerStackSpace } } - ui::Transform logicalTranslation, physicalTranslation, scale; - const float sourceWidth = layerStackSpaceRect.width(); - const float sourceHeight = layerStackSpaceRect.height(); - const float destWidth = orientedDisplaySpaceRect.width(); - const float destHeight = orientedDisplaySpaceRect.height(); - if (sourceWidth != destWidth || sourceHeight != destHeight) { - const float scaleX = destWidth / sourceWidth; - const float scaleY = destHeight / sourceHeight; - scale.set(scaleX, 0, 0, scaleY); - } - - const float sourceX = layerStackSpaceRect.left; - const float sourceY = layerStackSpaceRect.top; - const float destX = orientedDisplaySpaceRect.left; - const float destY = orientedDisplaySpaceRect.top; - logicalTranslation.set(-sourceX, -sourceY); - physicalTranslation.set(destX, destY); - // We need to take care of display rotation for globalTransform for case if the panel is not // installed aligned with device orientation. const auto transformOrientation = orientation + mPhysicalOrientation; - const uint32_t transformOrientationFlags = ui::Transform::toRotationFlags(transformOrientation); - ui::Transform rotation; - if (transformOrientationFlags != ui::Transform::ROT_INVALID) { - rotation.set(transformOrientationFlags, displayWidth, displayHeight); - } - - // The layerStackSpaceRect and orientedDisplaySpaceRect are both in the logical orientation. - // Apply the logical translation, scale to physical size, apply the - // physical translation and finally rotate to the physical orientation. - ui::Transform globalTransform = rotation * physicalTranslation * scale * logicalTranslation; - - Rect displaySpaceRect = globalTransform.transform(layerStackSpaceRect); - if (displaySpaceRect.isEmpty()) { - displaySpaceRect = displayBounds; - } - // Make sure the displaySpaceRect is contained in the display bounds - displaySpaceRect.intersect(displayBounds, &displaySpaceRect); - - if (isPrimary()) { - sPrimaryDisplayRotationFlags = ui::Transform::toRotationFlags(orientation); - } - - getCompositionDisplay()->setProjection(globalTransform, transformOrientationFlags, - orientedDisplaySpaceRect, layerStackSpaceRect, - displaySpaceRect); + getCompositionDisplay()->setProjection(transformOrientation, layerStackSpaceRect, + orientedDisplaySpaceRect); } ui::Transform::RotationFlags DisplayDevice::getPrimaryDisplayRotationFlags() { diff --git a/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp b/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp index b42d9de9b7..b750d6b39b 100644 --- a/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp +++ b/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp @@ -1481,7 +1481,7 @@ public: EXPECT_EQ(ui::Transform(TRANSFORM_FLAGS_ROT_0, mHardwareDisplaySize.width, mHardwareDisplaySize.height), compositionState.transform); - EXPECT_EQ(TRANSFORM_FLAGS_ROT_0, compositionState.orientation); + EXPECT_EQ(ui::ROTATION_0, compositionState.displaySpace.orientation); EXPECT_EQ(Rect(mHardwareDisplaySize), compositionState.displaySpace.content); EXPECT_EQ(Rect(mHardwareDisplaySize), compositionState.orientedDisplaySpace.content); EXPECT_EQ(Rect(mHardwareDisplaySize), compositionState.layerStackSpace.content); @@ -1493,7 +1493,7 @@ public: EXPECT_EQ(ui::Transform(TRANSFORM_FLAGS_ROT_90, mHardwareDisplaySize.width, mHardwareDisplaySize.height), compositionState.transform); - EXPECT_EQ(TRANSFORM_FLAGS_ROT_90, compositionState.orientation); + EXPECT_EQ(ui::ROTATION_90, compositionState.displaySpace.orientation); EXPECT_EQ(Rect(mHardwareDisplaySize), compositionState.displaySpace.content); // For 90, the orientedDisplaySpaceRect and layerStackSpaceRect have the hardware display // size width and height swapped @@ -1508,7 +1508,7 @@ public: EXPECT_EQ(ui::Transform(TRANSFORM_FLAGS_ROT_180, mHardwareDisplaySize.width, mHardwareDisplaySize.height), compositionState.transform); - EXPECT_EQ(TRANSFORM_FLAGS_ROT_180, compositionState.orientation); + EXPECT_EQ(ui::ROTATION_180, compositionState.displaySpace.orientation); EXPECT_EQ(Rect(mHardwareDisplaySize), compositionState.orientedDisplaySpace.content); EXPECT_EQ(Rect(mHardwareDisplaySize), compositionState.layerStackSpace.content); EXPECT_EQ(false, compositionState.needsFiltering); @@ -1519,7 +1519,7 @@ public: EXPECT_EQ(ui::Transform(TRANSFORM_FLAGS_ROT_270, mHardwareDisplaySize.width, mHardwareDisplaySize.height), compositionState.transform); - EXPECT_EQ(TRANSFORM_FLAGS_ROT_270, compositionState.orientation); + EXPECT_EQ(ui::ROTATION_270, compositionState.displaySpace.orientation); EXPECT_EQ(Rect(mHardwareDisplaySize), compositionState.displaySpace.content); // For 270, the orientedDisplaySpaceRect and layerStackSpaceRect have the hardware display // size width and height swapped |