Loading services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp +2 −1 Original line number Original line Diff line number Diff line Loading @@ -282,7 +282,8 @@ uint32_t OutputLayer::calculateOutputRelativeBufferTransform() const { * computation so it's enough to just omit it in the composition. * computation so it's enough to just omit it in the composition. * See comment in BufferLayer::prepareClientLayer with ref to b/36727915 for why. * See comment in BufferLayer::prepareClientLayer with ref to b/36727915 for why. */ */ transform = ui::Transform(invTransform) * displayTransform * bufferTransform; transform = ui::Transform(invTransform) * displayTransform * layerTransform * bufferTransform; } } // this gives us only the "orientation" component of the transform // this gives us only the "orientation" component of the transform Loading services/surfaceflinger/CompositionEngine/tests/FloatRectMatcher.h 0 → 100644 +48 −0 Original line number Original line Diff line number Diff line /* * Copyright 2019 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. */ #pragma once #include <string> #include <android-base/stringprintf.h> #include <gmock/gmock.h> namespace { using android::base::StringAppendF; using FloatRect = android::FloatRect; void dumpFloatRect(const FloatRect& rect, std::string& result, const char* name) { StringAppendF(&result, "%s (%f %f %f %f) ", name, rect.left, rect.top, rect.right, rect.bottom); } // Checks for a region match MATCHER_P(FloatRectEq, expected, "") { std::string buf; buf.append("FloatRects are not equal\n"); dumpFloatRect(expected, buf, "expected rect"); dumpFloatRect(arg, buf, "actual rect"); *result_listener << buf; const float TOLERANCE = 1e-3f; return (std::fabs(expected.left - arg.left) < TOLERANCE) && (std::fabs(expected.top - arg.top) < TOLERANCE) && (std::fabs(expected.right - arg.right) < TOLERANCE) && (std::fabs(expected.bottom - arg.bottom) < TOLERANCE); } } // namespace services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp +263 −1 Original line number Original line Diff line number Diff line Loading @@ -21,6 +21,7 @@ #include <compositionengine/mock/Output.h> #include <compositionengine/mock/Output.h> #include <gtest/gtest.h> #include <gtest/gtest.h> #include "FloatRectMatcher.h" #include "MockHWC2.h" #include "MockHWC2.h" #include "MockHWComposer.h" #include "MockHWComposer.h" #include "RectMatcher.h" #include "RectMatcher.h" Loading Loading @@ -105,6 +106,114 @@ TEST_F(OutputLayerTest, initializingOutputLayerWithHwcDisplayCreatesHwcLayer) { mOutputLayer.editState().hwc.reset(); mOutputLayer.editState().hwc.reset(); } } /* * OutputLayer::calculateOutputSourceCrop() */ struct OutputLayerSourceCropTest : public OutputLayerTest { OutputLayerSourceCropTest() { // Set reasonable default values for a simple case. Each test will // set one specific value to something different. mLayerState.frontEnd.geomUsesSourceCrop = true; mLayerState.frontEnd.geomContentCrop = Rect{0, 0, 1920, 1080}; mLayerState.frontEnd.geomActiveTransparentRegion = Region{}; mLayerState.frontEnd.geomLayerBounds = FloatRect{0.f, 0.f, 1920.f, 1080.f}; mLayerState.frontEnd.geomLayerTransform = ui::Transform{TR_IDENT}; mLayerState.frontEnd.geomBufferSize = Rect{0, 0, 1920, 1080}; mLayerState.frontEnd.geomBufferTransform = TR_IDENT; mOutputState.viewport = Rect{0, 0, 1920, 1080}; } FloatRect calculateOutputSourceCrop() { mLayerState.frontEnd.geomInverseLayerTransform = mLayerState.frontEnd.geomLayerTransform.inverse(); return mOutputLayer.calculateOutputSourceCrop(); } }; TEST_F(OutputLayerSourceCropTest, computesEmptyIfSourceCropNotUsed) { mLayerState.frontEnd.geomUsesSourceCrop = false; const FloatRect expected{}; EXPECT_THAT(calculateOutputSourceCrop(), FloatRectEq(expected)); } TEST_F(OutputLayerSourceCropTest, correctForSimpleDefaultCase) { const FloatRect expected{0.f, 0.f, 1920.f, 1080.f}; EXPECT_THAT(calculateOutputSourceCrop(), FloatRectEq(expected)); } TEST_F(OutputLayerSourceCropTest, handlesBoundsOutsideViewport) { mLayerState.frontEnd.geomLayerBounds = FloatRect{-2000.f, -2000.f, 2000.f, 2000.f}; const FloatRect expected{0.f, 0.f, 1920.f, 1080.f}; EXPECT_THAT(calculateOutputSourceCrop(), FloatRectEq(expected)); } TEST_F(OutputLayerSourceCropTest, handlesBoundsOutsideViewportRotated) { mLayerState.frontEnd.geomLayerBounds = FloatRect{-2000.f, -2000.f, 2000.f, 2000.f}; mLayerState.frontEnd.geomLayerTransform.set(HAL_TRANSFORM_ROT_90, 1920, 1080); const FloatRect expected{0.f, 0.f, 1080.f, 1080.f}; EXPECT_THAT(calculateOutputSourceCrop(), FloatRectEq(expected)); } TEST_F(OutputLayerSourceCropTest, calculateOutputSourceCropWorksWithATransformedBuffer) { struct Entry { uint32_t bufferInvDisplay; uint32_t buffer; uint32_t display; FloatRect expected; }; // Not an exhaustive list of cases, but hopefully enough. const std::array<Entry, 12> testData = { // clang-format off // inv buffer display expected /* 0 */ Entry{false, TR_IDENT, TR_IDENT, FloatRect{0.f, 0.f, 1920.f, 1080.f}}, /* 1 */ Entry{false, TR_IDENT, TR_ROT_90, FloatRect{0.f, 0.f, 1920.f, 1080.f}}, /* 2 */ Entry{false, TR_IDENT, TR_ROT_180, FloatRect{0.f, 0.f, 1920.f, 1080.f}}, /* 3 */ Entry{false, TR_IDENT, TR_ROT_270, FloatRect{0.f, 0.f, 1920.f, 1080.f}}, /* 4 */ Entry{true, TR_IDENT, TR_IDENT, FloatRect{0.f, 0.f, 1920.f, 1080.f}}, /* 5 */ Entry{true, TR_IDENT, TR_ROT_90, FloatRect{0.f, 0.f, 1920.f, 1080.f}}, /* 6 */ Entry{true, TR_IDENT, TR_ROT_180, FloatRect{0.f, 0.f, 1920.f, 1080.f}}, /* 7 */ Entry{true, TR_IDENT, TR_ROT_270, FloatRect{0.f, 0.f, 1920.f, 1080.f}}, /* 8 */ Entry{false, TR_IDENT, TR_IDENT, FloatRect{0.f, 0.f, 1920.f, 1080.f}}, /* 9 */ Entry{false, TR_ROT_90, TR_ROT_90, FloatRect{0.f, 0.f, 1920.f, 1080.f}}, /* 10 */ Entry{false, TR_ROT_180, TR_ROT_180, FloatRect{0.f, 0.f, 1920.f, 1080.f}}, /* 11 */ Entry{false, TR_ROT_270, TR_ROT_270, FloatRect{0.f, 0.f, 1920.f, 1080.f}}, // clang-format on }; for (size_t i = 0; i < testData.size(); i++) { const auto& entry = testData[i]; mLayerState.frontEnd.geomBufferUsesDisplayInverseTransform = entry.bufferInvDisplay; mLayerState.frontEnd.geomBufferTransform = entry.buffer; mOutputState.orientation = entry.display; EXPECT_THAT(calculateOutputSourceCrop(), FloatRectEq(entry.expected)) << "entry " << i; } } TEST_F(OutputLayerSourceCropTest, geomContentCropAffectsCrop) { mLayerState.frontEnd.geomContentCrop = Rect{0, 0, 960, 540}; const FloatRect expected{0.f, 0.f, 960.f, 540.f}; EXPECT_THAT(calculateOutputSourceCrop(), FloatRectEq(expected)); } TEST_F(OutputLayerSourceCropTest, viewportAffectsCrop) { mOutputState.viewport = Rect{0, 0, 960, 540}; const FloatRect expected{0.f, 0.f, 960.f, 540.f}; EXPECT_THAT(calculateOutputSourceCrop(), FloatRectEq(expected)); } /* /* * OutputLayer::calculateOutputDisplayFrame() * OutputLayer::calculateOutputDisplayFrame() */ */ Loading Loading @@ -163,7 +272,7 @@ TEST_F(OutputLayerDisplayFrameTest, emptyGeomCropIsNotUsedToComputeFrame) { EXPECT_THAT(calculateOutputDisplayFrame(), RectEq(expected)); EXPECT_THAT(calculateOutputDisplayFrame(), RectEq(expected)); } } TEST_F(OutputLayerDisplayFrameTest, geomLayerSnapToBoundsAffectsFrame) { TEST_F(OutputLayerDisplayFrameTest, geomLayerBoundsAffectsFrame) { mLayerState.frontEnd.geomLayerBounds = FloatRect{0.f, 0.f, 960.f, 540.f}; mLayerState.frontEnd.geomLayerBounds = FloatRect{0.f, 0.f, 960.f, 540.f}; const Rect expected{0, 0, 960, 540}; const Rect expected{0, 0, 960, 540}; EXPECT_THAT(calculateOutputDisplayFrame(), RectEq(expected)); EXPECT_THAT(calculateOutputDisplayFrame(), RectEq(expected)); Loading Loading @@ -242,6 +351,159 @@ TEST_F(OutputLayerTest, calculateOutputRelativeBufferTransformTestsNeeded) { } } } } TEST_F(OutputLayerTest, calculateOutputRelativeBufferTransformTestWithOfBufferUsesDisplayInverseTransform) { mLayerState.frontEnd.geomBufferUsesDisplayInverseTransform = true; struct Entry { uint32_t layer; uint32_t buffer; uint32_t display; uint32_t expected; }; // Not an exhaustive list of cases, but hopefully enough. const std::array<Entry, 24> testData = { // clang-format off // layer buffer display expected /* 0 */ Entry{TR_IDENT, TR_IDENT, TR_IDENT, TR_IDENT}, /* 1 */ Entry{TR_IDENT, TR_IDENT, TR_ROT_90, TR_IDENT}, /* 2 */ Entry{TR_IDENT, TR_IDENT, TR_ROT_180, TR_IDENT}, /* 3 */ Entry{TR_IDENT, TR_IDENT, TR_ROT_270, TR_IDENT}, /* 4 */ Entry{TR_IDENT, TR_FLP_H, TR_IDENT, TR_FLP_H}, /* 5 */ Entry{TR_IDENT, TR_FLP_H, TR_ROT_90, TR_FLP_H}, /* 6 */ Entry{TR_IDENT, TR_FLP_H, TR_ROT_180, TR_FLP_H}, /* 7 */ Entry{TR_IDENT, TR_FLP_H, TR_ROT_270, TR_FLP_H}, /* 8 */ Entry{TR_IDENT, TR_FLP_V, TR_IDENT, TR_FLP_V}, /* 9 */ Entry{TR_IDENT, TR_ROT_90, TR_ROT_90, TR_ROT_90}, /* 10 */ Entry{TR_IDENT, TR_ROT_180, TR_ROT_180, TR_ROT_180}, /* 11 */ Entry{TR_IDENT, TR_ROT_270, TR_ROT_270, TR_ROT_270}, /* 12 */ Entry{TR_ROT_90, TR_IDENT, TR_IDENT, TR_IDENT ^ TR_ROT_90}, /* 13 */ Entry{TR_ROT_90, TR_FLP_H, TR_ROT_90, TR_FLP_H ^ TR_ROT_90}, /* 14 */ Entry{TR_ROT_90, TR_IDENT, TR_ROT_180, TR_IDENT ^ TR_ROT_90}, /* 15 */ Entry{TR_ROT_90, TR_FLP_H, TR_ROT_270, TR_FLP_H ^ TR_ROT_90}, /* 16 */ Entry{TR_ROT_180, TR_FLP_H, TR_IDENT, TR_FLP_H ^ TR_ROT_180}, /* 17 */ Entry{TR_ROT_180, TR_IDENT, TR_ROT_90, TR_IDENT ^ TR_ROT_180}, /* 18 */ Entry{TR_ROT_180, TR_FLP_H, TR_ROT_180, TR_FLP_H ^ TR_ROT_180}, /* 19 */ Entry{TR_ROT_180, TR_IDENT, TR_ROT_270, TR_IDENT ^ TR_ROT_180}, /* 20 */ Entry{TR_ROT_270, TR_IDENT, TR_IDENT, TR_IDENT ^ TR_ROT_270}, /* 21 */ Entry{TR_ROT_270, TR_FLP_H, TR_ROT_90, TR_FLP_H ^ TR_ROT_270}, /* 22 */ Entry{TR_ROT_270, TR_FLP_H, TR_ROT_180, TR_FLP_H ^ TR_ROT_270}, /* 23 */ Entry{TR_ROT_270, TR_IDENT, TR_ROT_270, TR_IDENT ^ TR_ROT_270}, // clang-format on }; for (size_t i = 0; i < testData.size(); i++) { const auto& entry = testData[i]; mLayerState.frontEnd.geomLayerTransform = ui::Transform{entry.layer}; mLayerState.frontEnd.geomBufferTransform = entry.buffer; mOutputState.orientation = entry.display; auto actual = mOutputLayer.calculateOutputRelativeBufferTransform(); EXPECT_EQ(entry.expected, actual) << "entry " << i; } } /* * OutputLayer::updateCompositionState() */ struct OutputLayerPartialMockForUpdateCompositionState : public impl::OutputLayer { OutputLayerPartialMockForUpdateCompositionState(const compositionengine::Output& output, std::shared_ptr<compositionengine::Layer> layer, sp<compositionengine::LayerFE> layerFE) : impl::OutputLayer(output, layer, layerFE) {} // Mock everything called by updateCompositionState to simplify testing it. MOCK_CONST_METHOD0(calculateOutputSourceCrop, FloatRect()); MOCK_CONST_METHOD0(calculateOutputDisplayFrame, Rect()); MOCK_CONST_METHOD0(calculateOutputRelativeBufferTransform, uint32_t()); }; struct OutputLayerUpdateCompositionStateTest : public OutputLayerTest { public: OutputLayerUpdateCompositionStateTest() { EXPECT_CALL(*mLayer, getState()).WillRepeatedly(ReturnRef(mLayerState)); EXPECT_CALL(mOutput, getState()).WillRepeatedly(ReturnRef(mOutputState)); } ~OutputLayerUpdateCompositionStateTest() = default; void setupGeometryChildCallValues() { EXPECT_CALL(mOutputLayer, calculateOutputSourceCrop()).WillOnce(Return(kSourceCrop)); EXPECT_CALL(mOutputLayer, calculateOutputDisplayFrame()).WillOnce(Return(kDisplayFrame)); EXPECT_CALL(mOutputLayer, calculateOutputRelativeBufferTransform()) .WillOnce(Return(mBufferTransform)); } void validateComputedGeometryState() { const auto& state = mOutputLayer.getState(); EXPECT_EQ(kSourceCrop, state.sourceCrop); EXPECT_EQ(kDisplayFrame, state.displayFrame); EXPECT_EQ(static_cast<Hwc2::Transform>(mBufferTransform), state.bufferTransform); } const FloatRect kSourceCrop{1.f, 2.f, 3.f, 4.f}; const Rect kDisplayFrame{11, 12, 13, 14}; uint32_t mBufferTransform{21}; using OutputLayer = OutputLayerPartialMockForUpdateCompositionState; StrictMock<OutputLayer> mOutputLayer{mOutput, mLayer, mLayerFE}; }; TEST_F(OutputLayerUpdateCompositionStateTest, setsStateNormally) { mLayerState.frontEnd.isSecure = true; mOutputState.isSecure = true; setupGeometryChildCallValues(); mOutputLayer.updateCompositionState(true); validateComputedGeometryState(); EXPECT_EQ(false, mOutputLayer.getState().forceClientComposition); } TEST_F(OutputLayerUpdateCompositionStateTest, alsoSetsForceCompositionIfSecureLayerOnNonsecureOutput) { mLayerState.frontEnd.isSecure = true; mOutputState.isSecure = false; setupGeometryChildCallValues(); mOutputLayer.updateCompositionState(true); validateComputedGeometryState(); EXPECT_EQ(true, mOutputLayer.getState().forceClientComposition); } TEST_F(OutputLayerUpdateCompositionStateTest, alsoSetsForceCompositionIfUnsupportedBufferTransform) { mLayerState.frontEnd.isSecure = true; mOutputState.isSecure = true; mBufferTransform = ui::Transform::ROT_INVALID; setupGeometryChildCallValues(); mOutputLayer.updateCompositionState(true); validateComputedGeometryState(); EXPECT_EQ(true, mOutputLayer.getState().forceClientComposition); } TEST_F(OutputLayerUpdateCompositionStateTest, doesNotRecomputeGeometryIfNotRequested) { mOutputLayer.updateCompositionState(false); EXPECT_EQ(false, mOutputLayer.getState().forceClientComposition); } /* /* * OutputLayer::writeStateToHWC() * OutputLayer::writeStateToHWC() */ */ Loading Loading
services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp +2 −1 Original line number Original line Diff line number Diff line Loading @@ -282,7 +282,8 @@ uint32_t OutputLayer::calculateOutputRelativeBufferTransform() const { * computation so it's enough to just omit it in the composition. * computation so it's enough to just omit it in the composition. * See comment in BufferLayer::prepareClientLayer with ref to b/36727915 for why. * See comment in BufferLayer::prepareClientLayer with ref to b/36727915 for why. */ */ transform = ui::Transform(invTransform) * displayTransform * bufferTransform; transform = ui::Transform(invTransform) * displayTransform * layerTransform * bufferTransform; } } // this gives us only the "orientation" component of the transform // this gives us only the "orientation" component of the transform Loading
services/surfaceflinger/CompositionEngine/tests/FloatRectMatcher.h 0 → 100644 +48 −0 Original line number Original line Diff line number Diff line /* * Copyright 2019 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. */ #pragma once #include <string> #include <android-base/stringprintf.h> #include <gmock/gmock.h> namespace { using android::base::StringAppendF; using FloatRect = android::FloatRect; void dumpFloatRect(const FloatRect& rect, std::string& result, const char* name) { StringAppendF(&result, "%s (%f %f %f %f) ", name, rect.left, rect.top, rect.right, rect.bottom); } // Checks for a region match MATCHER_P(FloatRectEq, expected, "") { std::string buf; buf.append("FloatRects are not equal\n"); dumpFloatRect(expected, buf, "expected rect"); dumpFloatRect(arg, buf, "actual rect"); *result_listener << buf; const float TOLERANCE = 1e-3f; return (std::fabs(expected.left - arg.left) < TOLERANCE) && (std::fabs(expected.top - arg.top) < TOLERANCE) && (std::fabs(expected.right - arg.right) < TOLERANCE) && (std::fabs(expected.bottom - arg.bottom) < TOLERANCE); } } // namespace
services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp +263 −1 Original line number Original line Diff line number Diff line Loading @@ -21,6 +21,7 @@ #include <compositionengine/mock/Output.h> #include <compositionengine/mock/Output.h> #include <gtest/gtest.h> #include <gtest/gtest.h> #include "FloatRectMatcher.h" #include "MockHWC2.h" #include "MockHWC2.h" #include "MockHWComposer.h" #include "MockHWComposer.h" #include "RectMatcher.h" #include "RectMatcher.h" Loading Loading @@ -105,6 +106,114 @@ TEST_F(OutputLayerTest, initializingOutputLayerWithHwcDisplayCreatesHwcLayer) { mOutputLayer.editState().hwc.reset(); mOutputLayer.editState().hwc.reset(); } } /* * OutputLayer::calculateOutputSourceCrop() */ struct OutputLayerSourceCropTest : public OutputLayerTest { OutputLayerSourceCropTest() { // Set reasonable default values for a simple case. Each test will // set one specific value to something different. mLayerState.frontEnd.geomUsesSourceCrop = true; mLayerState.frontEnd.geomContentCrop = Rect{0, 0, 1920, 1080}; mLayerState.frontEnd.geomActiveTransparentRegion = Region{}; mLayerState.frontEnd.geomLayerBounds = FloatRect{0.f, 0.f, 1920.f, 1080.f}; mLayerState.frontEnd.geomLayerTransform = ui::Transform{TR_IDENT}; mLayerState.frontEnd.geomBufferSize = Rect{0, 0, 1920, 1080}; mLayerState.frontEnd.geomBufferTransform = TR_IDENT; mOutputState.viewport = Rect{0, 0, 1920, 1080}; } FloatRect calculateOutputSourceCrop() { mLayerState.frontEnd.geomInverseLayerTransform = mLayerState.frontEnd.geomLayerTransform.inverse(); return mOutputLayer.calculateOutputSourceCrop(); } }; TEST_F(OutputLayerSourceCropTest, computesEmptyIfSourceCropNotUsed) { mLayerState.frontEnd.geomUsesSourceCrop = false; const FloatRect expected{}; EXPECT_THAT(calculateOutputSourceCrop(), FloatRectEq(expected)); } TEST_F(OutputLayerSourceCropTest, correctForSimpleDefaultCase) { const FloatRect expected{0.f, 0.f, 1920.f, 1080.f}; EXPECT_THAT(calculateOutputSourceCrop(), FloatRectEq(expected)); } TEST_F(OutputLayerSourceCropTest, handlesBoundsOutsideViewport) { mLayerState.frontEnd.geomLayerBounds = FloatRect{-2000.f, -2000.f, 2000.f, 2000.f}; const FloatRect expected{0.f, 0.f, 1920.f, 1080.f}; EXPECT_THAT(calculateOutputSourceCrop(), FloatRectEq(expected)); } TEST_F(OutputLayerSourceCropTest, handlesBoundsOutsideViewportRotated) { mLayerState.frontEnd.geomLayerBounds = FloatRect{-2000.f, -2000.f, 2000.f, 2000.f}; mLayerState.frontEnd.geomLayerTransform.set(HAL_TRANSFORM_ROT_90, 1920, 1080); const FloatRect expected{0.f, 0.f, 1080.f, 1080.f}; EXPECT_THAT(calculateOutputSourceCrop(), FloatRectEq(expected)); } TEST_F(OutputLayerSourceCropTest, calculateOutputSourceCropWorksWithATransformedBuffer) { struct Entry { uint32_t bufferInvDisplay; uint32_t buffer; uint32_t display; FloatRect expected; }; // Not an exhaustive list of cases, but hopefully enough. const std::array<Entry, 12> testData = { // clang-format off // inv buffer display expected /* 0 */ Entry{false, TR_IDENT, TR_IDENT, FloatRect{0.f, 0.f, 1920.f, 1080.f}}, /* 1 */ Entry{false, TR_IDENT, TR_ROT_90, FloatRect{0.f, 0.f, 1920.f, 1080.f}}, /* 2 */ Entry{false, TR_IDENT, TR_ROT_180, FloatRect{0.f, 0.f, 1920.f, 1080.f}}, /* 3 */ Entry{false, TR_IDENT, TR_ROT_270, FloatRect{0.f, 0.f, 1920.f, 1080.f}}, /* 4 */ Entry{true, TR_IDENT, TR_IDENT, FloatRect{0.f, 0.f, 1920.f, 1080.f}}, /* 5 */ Entry{true, TR_IDENT, TR_ROT_90, FloatRect{0.f, 0.f, 1920.f, 1080.f}}, /* 6 */ Entry{true, TR_IDENT, TR_ROT_180, FloatRect{0.f, 0.f, 1920.f, 1080.f}}, /* 7 */ Entry{true, TR_IDENT, TR_ROT_270, FloatRect{0.f, 0.f, 1920.f, 1080.f}}, /* 8 */ Entry{false, TR_IDENT, TR_IDENT, FloatRect{0.f, 0.f, 1920.f, 1080.f}}, /* 9 */ Entry{false, TR_ROT_90, TR_ROT_90, FloatRect{0.f, 0.f, 1920.f, 1080.f}}, /* 10 */ Entry{false, TR_ROT_180, TR_ROT_180, FloatRect{0.f, 0.f, 1920.f, 1080.f}}, /* 11 */ Entry{false, TR_ROT_270, TR_ROT_270, FloatRect{0.f, 0.f, 1920.f, 1080.f}}, // clang-format on }; for (size_t i = 0; i < testData.size(); i++) { const auto& entry = testData[i]; mLayerState.frontEnd.geomBufferUsesDisplayInverseTransform = entry.bufferInvDisplay; mLayerState.frontEnd.geomBufferTransform = entry.buffer; mOutputState.orientation = entry.display; EXPECT_THAT(calculateOutputSourceCrop(), FloatRectEq(entry.expected)) << "entry " << i; } } TEST_F(OutputLayerSourceCropTest, geomContentCropAffectsCrop) { mLayerState.frontEnd.geomContentCrop = Rect{0, 0, 960, 540}; const FloatRect expected{0.f, 0.f, 960.f, 540.f}; EXPECT_THAT(calculateOutputSourceCrop(), FloatRectEq(expected)); } TEST_F(OutputLayerSourceCropTest, viewportAffectsCrop) { mOutputState.viewport = Rect{0, 0, 960, 540}; const FloatRect expected{0.f, 0.f, 960.f, 540.f}; EXPECT_THAT(calculateOutputSourceCrop(), FloatRectEq(expected)); } /* /* * OutputLayer::calculateOutputDisplayFrame() * OutputLayer::calculateOutputDisplayFrame() */ */ Loading Loading @@ -163,7 +272,7 @@ TEST_F(OutputLayerDisplayFrameTest, emptyGeomCropIsNotUsedToComputeFrame) { EXPECT_THAT(calculateOutputDisplayFrame(), RectEq(expected)); EXPECT_THAT(calculateOutputDisplayFrame(), RectEq(expected)); } } TEST_F(OutputLayerDisplayFrameTest, geomLayerSnapToBoundsAffectsFrame) { TEST_F(OutputLayerDisplayFrameTest, geomLayerBoundsAffectsFrame) { mLayerState.frontEnd.geomLayerBounds = FloatRect{0.f, 0.f, 960.f, 540.f}; mLayerState.frontEnd.geomLayerBounds = FloatRect{0.f, 0.f, 960.f, 540.f}; const Rect expected{0, 0, 960, 540}; const Rect expected{0, 0, 960, 540}; EXPECT_THAT(calculateOutputDisplayFrame(), RectEq(expected)); EXPECT_THAT(calculateOutputDisplayFrame(), RectEq(expected)); Loading Loading @@ -242,6 +351,159 @@ TEST_F(OutputLayerTest, calculateOutputRelativeBufferTransformTestsNeeded) { } } } } TEST_F(OutputLayerTest, calculateOutputRelativeBufferTransformTestWithOfBufferUsesDisplayInverseTransform) { mLayerState.frontEnd.geomBufferUsesDisplayInverseTransform = true; struct Entry { uint32_t layer; uint32_t buffer; uint32_t display; uint32_t expected; }; // Not an exhaustive list of cases, but hopefully enough. const std::array<Entry, 24> testData = { // clang-format off // layer buffer display expected /* 0 */ Entry{TR_IDENT, TR_IDENT, TR_IDENT, TR_IDENT}, /* 1 */ Entry{TR_IDENT, TR_IDENT, TR_ROT_90, TR_IDENT}, /* 2 */ Entry{TR_IDENT, TR_IDENT, TR_ROT_180, TR_IDENT}, /* 3 */ Entry{TR_IDENT, TR_IDENT, TR_ROT_270, TR_IDENT}, /* 4 */ Entry{TR_IDENT, TR_FLP_H, TR_IDENT, TR_FLP_H}, /* 5 */ Entry{TR_IDENT, TR_FLP_H, TR_ROT_90, TR_FLP_H}, /* 6 */ Entry{TR_IDENT, TR_FLP_H, TR_ROT_180, TR_FLP_H}, /* 7 */ Entry{TR_IDENT, TR_FLP_H, TR_ROT_270, TR_FLP_H}, /* 8 */ Entry{TR_IDENT, TR_FLP_V, TR_IDENT, TR_FLP_V}, /* 9 */ Entry{TR_IDENT, TR_ROT_90, TR_ROT_90, TR_ROT_90}, /* 10 */ Entry{TR_IDENT, TR_ROT_180, TR_ROT_180, TR_ROT_180}, /* 11 */ Entry{TR_IDENT, TR_ROT_270, TR_ROT_270, TR_ROT_270}, /* 12 */ Entry{TR_ROT_90, TR_IDENT, TR_IDENT, TR_IDENT ^ TR_ROT_90}, /* 13 */ Entry{TR_ROT_90, TR_FLP_H, TR_ROT_90, TR_FLP_H ^ TR_ROT_90}, /* 14 */ Entry{TR_ROT_90, TR_IDENT, TR_ROT_180, TR_IDENT ^ TR_ROT_90}, /* 15 */ Entry{TR_ROT_90, TR_FLP_H, TR_ROT_270, TR_FLP_H ^ TR_ROT_90}, /* 16 */ Entry{TR_ROT_180, TR_FLP_H, TR_IDENT, TR_FLP_H ^ TR_ROT_180}, /* 17 */ Entry{TR_ROT_180, TR_IDENT, TR_ROT_90, TR_IDENT ^ TR_ROT_180}, /* 18 */ Entry{TR_ROT_180, TR_FLP_H, TR_ROT_180, TR_FLP_H ^ TR_ROT_180}, /* 19 */ Entry{TR_ROT_180, TR_IDENT, TR_ROT_270, TR_IDENT ^ TR_ROT_180}, /* 20 */ Entry{TR_ROT_270, TR_IDENT, TR_IDENT, TR_IDENT ^ TR_ROT_270}, /* 21 */ Entry{TR_ROT_270, TR_FLP_H, TR_ROT_90, TR_FLP_H ^ TR_ROT_270}, /* 22 */ Entry{TR_ROT_270, TR_FLP_H, TR_ROT_180, TR_FLP_H ^ TR_ROT_270}, /* 23 */ Entry{TR_ROT_270, TR_IDENT, TR_ROT_270, TR_IDENT ^ TR_ROT_270}, // clang-format on }; for (size_t i = 0; i < testData.size(); i++) { const auto& entry = testData[i]; mLayerState.frontEnd.geomLayerTransform = ui::Transform{entry.layer}; mLayerState.frontEnd.geomBufferTransform = entry.buffer; mOutputState.orientation = entry.display; auto actual = mOutputLayer.calculateOutputRelativeBufferTransform(); EXPECT_EQ(entry.expected, actual) << "entry " << i; } } /* * OutputLayer::updateCompositionState() */ struct OutputLayerPartialMockForUpdateCompositionState : public impl::OutputLayer { OutputLayerPartialMockForUpdateCompositionState(const compositionengine::Output& output, std::shared_ptr<compositionengine::Layer> layer, sp<compositionengine::LayerFE> layerFE) : impl::OutputLayer(output, layer, layerFE) {} // Mock everything called by updateCompositionState to simplify testing it. MOCK_CONST_METHOD0(calculateOutputSourceCrop, FloatRect()); MOCK_CONST_METHOD0(calculateOutputDisplayFrame, Rect()); MOCK_CONST_METHOD0(calculateOutputRelativeBufferTransform, uint32_t()); }; struct OutputLayerUpdateCompositionStateTest : public OutputLayerTest { public: OutputLayerUpdateCompositionStateTest() { EXPECT_CALL(*mLayer, getState()).WillRepeatedly(ReturnRef(mLayerState)); EXPECT_CALL(mOutput, getState()).WillRepeatedly(ReturnRef(mOutputState)); } ~OutputLayerUpdateCompositionStateTest() = default; void setupGeometryChildCallValues() { EXPECT_CALL(mOutputLayer, calculateOutputSourceCrop()).WillOnce(Return(kSourceCrop)); EXPECT_CALL(mOutputLayer, calculateOutputDisplayFrame()).WillOnce(Return(kDisplayFrame)); EXPECT_CALL(mOutputLayer, calculateOutputRelativeBufferTransform()) .WillOnce(Return(mBufferTransform)); } void validateComputedGeometryState() { const auto& state = mOutputLayer.getState(); EXPECT_EQ(kSourceCrop, state.sourceCrop); EXPECT_EQ(kDisplayFrame, state.displayFrame); EXPECT_EQ(static_cast<Hwc2::Transform>(mBufferTransform), state.bufferTransform); } const FloatRect kSourceCrop{1.f, 2.f, 3.f, 4.f}; const Rect kDisplayFrame{11, 12, 13, 14}; uint32_t mBufferTransform{21}; using OutputLayer = OutputLayerPartialMockForUpdateCompositionState; StrictMock<OutputLayer> mOutputLayer{mOutput, mLayer, mLayerFE}; }; TEST_F(OutputLayerUpdateCompositionStateTest, setsStateNormally) { mLayerState.frontEnd.isSecure = true; mOutputState.isSecure = true; setupGeometryChildCallValues(); mOutputLayer.updateCompositionState(true); validateComputedGeometryState(); EXPECT_EQ(false, mOutputLayer.getState().forceClientComposition); } TEST_F(OutputLayerUpdateCompositionStateTest, alsoSetsForceCompositionIfSecureLayerOnNonsecureOutput) { mLayerState.frontEnd.isSecure = true; mOutputState.isSecure = false; setupGeometryChildCallValues(); mOutputLayer.updateCompositionState(true); validateComputedGeometryState(); EXPECT_EQ(true, mOutputLayer.getState().forceClientComposition); } TEST_F(OutputLayerUpdateCompositionStateTest, alsoSetsForceCompositionIfUnsupportedBufferTransform) { mLayerState.frontEnd.isSecure = true; mOutputState.isSecure = true; mBufferTransform = ui::Transform::ROT_INVALID; setupGeometryChildCallValues(); mOutputLayer.updateCompositionState(true); validateComputedGeometryState(); EXPECT_EQ(true, mOutputLayer.getState().forceClientComposition); } TEST_F(OutputLayerUpdateCompositionStateTest, doesNotRecomputeGeometryIfNotRequested) { mOutputLayer.updateCompositionState(false); EXPECT_EQ(false, mOutputLayer.getState().forceClientComposition); } /* /* * OutputLayer::writeStateToHWC() * OutputLayer::writeStateToHWC() */ */ Loading