Home | History | Annotate | Download | only in tests
      1 /*
      2  * Copyright 2019 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 #include <cmath>
     18 
     19 #include <compositionengine/impl/Output.h>
     20 #include <compositionengine/mock/CompositionEngine.h>
     21 #include <compositionengine/mock/DisplayColorProfile.h>
     22 #include <compositionengine/mock/Layer.h>
     23 #include <compositionengine/mock/LayerFE.h>
     24 #include <compositionengine/mock/OutputLayer.h>
     25 #include <compositionengine/mock/RenderSurface.h>
     26 #include <gtest/gtest.h>
     27 #include <ui/Rect.h>
     28 #include <ui/Region.h>
     29 
     30 #include "RegionMatcher.h"
     31 #include "TransformMatcher.h"
     32 
     33 namespace android::compositionengine {
     34 namespace {
     35 
     36 using testing::Return;
     37 using testing::ReturnRef;
     38 using testing::StrictMock;
     39 
     40 class OutputTest : public testing::Test {
     41 public:
     42     OutputTest() {
     43         mOutput.setDisplayColorProfileForTest(
     44                 std::unique_ptr<DisplayColorProfile>(mDisplayColorProfile));
     45         mOutput.setRenderSurfaceForTest(std::unique_ptr<RenderSurface>(mRenderSurface));
     46 
     47         mOutput.editState().bounds = kDefaultDisplaySize;
     48     }
     49     ~OutputTest() override = default;
     50 
     51     static const Rect kDefaultDisplaySize;
     52 
     53     StrictMock<mock::CompositionEngine> mCompositionEngine;
     54     mock::DisplayColorProfile* mDisplayColorProfile = new StrictMock<mock::DisplayColorProfile>();
     55     mock::RenderSurface* mRenderSurface = new StrictMock<mock::RenderSurface>();
     56     impl::Output mOutput{mCompositionEngine};
     57 };
     58 
     59 const Rect OutputTest::kDefaultDisplaySize{100, 200};
     60 
     61 /* ------------------------------------------------------------------------
     62  * Basic construction
     63  */
     64 
     65 TEST_F(OutputTest, canInstantiateOutput) {
     66     // The validation check checks each required component.
     67     EXPECT_CALL(*mDisplayColorProfile, isValid()).WillOnce(Return(true));
     68     EXPECT_CALL(*mRenderSurface, isValid()).WillOnce(Return(true));
     69 
     70     EXPECT_TRUE(mOutput.isValid());
     71 
     72     // If we take away the required components, it is no longer valid.
     73     mOutput.setRenderSurfaceForTest(std::unique_ptr<RenderSurface>());
     74 
     75     EXPECT_CALL(*mDisplayColorProfile, isValid()).WillOnce(Return(true));
     76 
     77     EXPECT_FALSE(mOutput.isValid());
     78 }
     79 
     80 /* ------------------------------------------------------------------------
     81  * Output::setCompositionEnabled()
     82  */
     83 
     84 TEST_F(OutputTest, setCompositionEnabledDoesNothingIfAlreadyEnabled) {
     85     mOutput.editState().isEnabled = true;
     86 
     87     mOutput.setCompositionEnabled(true);
     88 
     89     EXPECT_TRUE(mOutput.getState().isEnabled);
     90     EXPECT_THAT(mOutput.getState().dirtyRegion, RegionEq(Region()));
     91 }
     92 
     93 TEST_F(OutputTest, setCompositionEnabledSetsEnabledAndDirtiesEntireOutput) {
     94     mOutput.editState().isEnabled = false;
     95 
     96     mOutput.setCompositionEnabled(true);
     97 
     98     EXPECT_TRUE(mOutput.getState().isEnabled);
     99     EXPECT_THAT(mOutput.getState().dirtyRegion, RegionEq(Region(kDefaultDisplaySize)));
    100 }
    101 
    102 TEST_F(OutputTest, setCompositionEnabledSetsDisabledAndDirtiesEntireOutput) {
    103     mOutput.editState().isEnabled = true;
    104 
    105     mOutput.setCompositionEnabled(false);
    106 
    107     EXPECT_FALSE(mOutput.getState().isEnabled);
    108     EXPECT_THAT(mOutput.getState().dirtyRegion, RegionEq(Region(kDefaultDisplaySize)));
    109 }
    110 
    111 /* ------------------------------------------------------------------------
    112  * Output::setProjection()
    113  */
    114 
    115 TEST_F(OutputTest, setProjectionTriviallyWorks) {
    116     const ui::Transform transform{ui::Transform::ROT_180};
    117     const int32_t orientation = 123;
    118     const Rect frame{1, 2, 3, 4};
    119     const Rect viewport{5, 6, 7, 8};
    120     const Rect scissor{9, 10, 11, 12};
    121     const bool needsFiltering = true;
    122 
    123     mOutput.setProjection(transform, orientation, frame, viewport, scissor, needsFiltering);
    124 
    125     EXPECT_THAT(mOutput.getState().transform, TransformEq(transform));
    126     EXPECT_EQ(orientation, mOutput.getState().orientation);
    127     EXPECT_EQ(frame, mOutput.getState().frame);
    128     EXPECT_EQ(viewport, mOutput.getState().viewport);
    129     EXPECT_EQ(scissor, mOutput.getState().scissor);
    130     EXPECT_EQ(needsFiltering, mOutput.getState().needsFiltering);
    131 }
    132 
    133 /* ------------------------------------------------------------------------
    134  * Output::setBounds()
    135  */
    136 
    137 TEST_F(OutputTest, setBoundsSetsSizeAndDirtiesEntireOutput) {
    138     const ui::Size displaySize{200, 400};
    139 
    140     EXPECT_CALL(*mRenderSurface, setDisplaySize(displaySize)).Times(1);
    141     EXPECT_CALL(*mRenderSurface, getSize()).WillOnce(ReturnRef(displaySize));
    142 
    143     mOutput.setBounds(displaySize);
    144 
    145     EXPECT_EQ(Rect(displaySize), mOutput.getState().bounds);
    146 
    147     EXPECT_THAT(mOutput.getState().dirtyRegion, RegionEq(Region(Rect(displaySize))));
    148 }
    149 
    150 /* ------------------------------------------------------------------------
    151  * Output::setLayerStackFilter()
    152  */
    153 
    154 TEST_F(OutputTest, setLayerStackFilterSetsFilterAndDirtiesEntireOutput) {
    155     const uint32_t layerStack = 123u;
    156     mOutput.setLayerStackFilter(layerStack, true);
    157 
    158     EXPECT_TRUE(mOutput.getState().layerStackInternal);
    159     EXPECT_EQ(layerStack, mOutput.getState().layerStackId);
    160 
    161     EXPECT_THAT(mOutput.getState().dirtyRegion, RegionEq(Region(kDefaultDisplaySize)));
    162 }
    163 
    164 /* ------------------------------------------------------------------------
    165  * Output::setColorTransform
    166  */
    167 
    168 TEST_F(OutputTest, setColorTransformSetsTransform) {
    169     // Identity matrix sets an identity state value
    170     const mat4 identity;
    171 
    172     mOutput.setColorTransform(identity);
    173 
    174     EXPECT_EQ(HAL_COLOR_TRANSFORM_IDENTITY, mOutput.getState().colorTransform);
    175     EXPECT_EQ(identity, mOutput.getState().colorTransformMat);
    176 
    177     // Since identity is the default, the dirty region should be unchanged (empty)
    178     EXPECT_THAT(mOutput.getState().dirtyRegion, RegionEq(Region()));
    179 
    180     // Non-identity matrix sets a non-identity state value
    181     const mat4 nonIdentityHalf = mat4() * 0.5;
    182 
    183     mOutput.setColorTransform(nonIdentityHalf);
    184 
    185     EXPECT_EQ(HAL_COLOR_TRANSFORM_ARBITRARY_MATRIX, mOutput.getState().colorTransform);
    186     EXPECT_EQ(nonIdentityHalf, mOutput.getState().colorTransformMat);
    187 
    188     // Since this is a state change, the entire output should now be dirty.
    189     EXPECT_THAT(mOutput.getState().dirtyRegion, RegionEq(Region(kDefaultDisplaySize)));
    190 
    191     // Non-identity matrix sets a non-identity state value
    192     const mat4 nonIdentityQuarter = mat4() * 0.25;
    193 
    194     mOutput.setColorTransform(nonIdentityQuarter);
    195 
    196     EXPECT_EQ(HAL_COLOR_TRANSFORM_ARBITRARY_MATRIX, mOutput.getState().colorTransform);
    197     EXPECT_EQ(nonIdentityQuarter, mOutput.getState().colorTransformMat);
    198 
    199     // Since this is a state change, the entire output should now be dirty.
    200     EXPECT_THAT(mOutput.getState().dirtyRegion, RegionEq(Region(kDefaultDisplaySize)));
    201 }
    202 
    203 /* ------------------------------------------------------------------------
    204  * Output::setColorMode
    205  */
    206 
    207 TEST_F(OutputTest, setColorModeSetsStateAndDirtiesOutputIfChanged) {
    208     EXPECT_CALL(*mRenderSurface, setBufferDataspace(ui::Dataspace::DISPLAY_P3)).Times(1);
    209 
    210     mOutput.setColorMode(ui::ColorMode::DISPLAY_P3, ui::Dataspace::DISPLAY_P3,
    211                          ui::RenderIntent::TONE_MAP_COLORIMETRIC);
    212 
    213     EXPECT_EQ(ui::ColorMode::DISPLAY_P3, mOutput.getState().colorMode);
    214     EXPECT_EQ(ui::Dataspace::DISPLAY_P3, mOutput.getState().dataspace);
    215     EXPECT_EQ(ui::RenderIntent::TONE_MAP_COLORIMETRIC, mOutput.getState().renderIntent);
    216     EXPECT_THAT(mOutput.getState().dirtyRegion, RegionEq(Region(kDefaultDisplaySize)));
    217 }
    218 
    219 TEST_F(OutputTest, setColorModeDoesNothingIfNoChange) {
    220     mOutput.editState().colorMode = ui::ColorMode::DISPLAY_P3;
    221     mOutput.editState().dataspace = ui::Dataspace::DISPLAY_P3;
    222     mOutput.editState().renderIntent = ui::RenderIntent::TONE_MAP_COLORIMETRIC;
    223 
    224     mOutput.setColorMode(ui::ColorMode::DISPLAY_P3, ui::Dataspace::DISPLAY_P3,
    225                          ui::RenderIntent::TONE_MAP_COLORIMETRIC);
    226 
    227     EXPECT_THAT(mOutput.getState().dirtyRegion, RegionEq(Region()));
    228 }
    229 
    230 /* ------------------------------------------------------------------------
    231  * Output::setRenderSurface()
    232  */
    233 
    234 TEST_F(OutputTest, setRenderSurfaceResetsBounds) {
    235     const ui::Size newDisplaySize{640, 480};
    236 
    237     mock::RenderSurface* renderSurface = new StrictMock<mock::RenderSurface>();
    238     EXPECT_CALL(*renderSurface, getSize()).WillOnce(ReturnRef(newDisplaySize));
    239 
    240     mOutput.setRenderSurface(std::unique_ptr<RenderSurface>(renderSurface));
    241 
    242     EXPECT_EQ(Rect(newDisplaySize), mOutput.getState().bounds);
    243 }
    244 
    245 /* ------------------------------------------------------------------------
    246  * Output::getDirtyRegion()
    247  */
    248 
    249 TEST_F(OutputTest, getDirtyRegionWithRepaintEverythingTrue) {
    250     const Rect viewport{100, 200};
    251     mOutput.editState().viewport = viewport;
    252     mOutput.editState().dirtyRegion.set(50, 300);
    253 
    254     {
    255         Region result = mOutput.getDirtyRegion(true);
    256 
    257         EXPECT_THAT(result, RegionEq(Region(viewport)));
    258     }
    259 }
    260 
    261 TEST_F(OutputTest, getDirtyRegionWithRepaintEverythingFalse) {
    262     const Rect viewport{100, 200};
    263     mOutput.editState().viewport = viewport;
    264     mOutput.editState().dirtyRegion.set(50, 300);
    265 
    266     {
    267         Region result = mOutput.getDirtyRegion(false);
    268 
    269         // The dirtyRegion should be clipped to the display bounds.
    270         EXPECT_THAT(result, RegionEq(Region(Rect(50, 200))));
    271     }
    272 }
    273 
    274 /* ------------------------------------------------------------------------
    275  * Output::belongsInOutput()
    276  */
    277 
    278 TEST_F(OutputTest, belongsInOutputFiltersAsExpected) {
    279     const uint32_t layerStack1 = 123u;
    280     const uint32_t layerStack2 = 456u;
    281 
    282     // If the output accepts layerStack1 and internal-only layers....
    283     mOutput.setLayerStackFilter(layerStack1, true);
    284 
    285     // Any layer with layerStack1 belongs to it, internal-only or not.
    286     EXPECT_TRUE(mOutput.belongsInOutput(layerStack1, false));
    287     EXPECT_TRUE(mOutput.belongsInOutput(layerStack1, true));
    288     EXPECT_FALSE(mOutput.belongsInOutput(layerStack2, true));
    289     EXPECT_FALSE(mOutput.belongsInOutput(layerStack2, false));
    290 
    291     // If the output accepts layerStack21 but not internal-only layers...
    292     mOutput.setLayerStackFilter(layerStack1, false);
    293 
    294     // Only non-internal layers with layerStack1 belong to it.
    295     EXPECT_TRUE(mOutput.belongsInOutput(layerStack1, false));
    296     EXPECT_FALSE(mOutput.belongsInOutput(layerStack1, true));
    297     EXPECT_FALSE(mOutput.belongsInOutput(layerStack2, true));
    298     EXPECT_FALSE(mOutput.belongsInOutput(layerStack2, false));
    299 }
    300 
    301 /* ------------------------------------------------------------------------
    302  * Output::getOutputLayerForLayer()
    303  */
    304 
    305 TEST_F(OutputTest, getOutputLayerForLayerWorks) {
    306     mock::OutputLayer* outputLayer1 = new StrictMock<mock::OutputLayer>();
    307     mock::OutputLayer* outputLayer2 = new StrictMock<mock::OutputLayer>();
    308 
    309     Output::OutputLayers outputLayers;
    310     outputLayers.emplace_back(std::unique_ptr<OutputLayer>(outputLayer1));
    311     outputLayers.emplace_back(nullptr);
    312     outputLayers.emplace_back(std::unique_ptr<OutputLayer>(outputLayer2));
    313     mOutput.setOutputLayersOrderedByZ(std::move(outputLayers));
    314 
    315     StrictMock<mock::Layer> layer;
    316     StrictMock<mock::Layer> otherLayer;
    317 
    318     // If the input layer matches the first OutputLayer, it will be returned.
    319     EXPECT_CALL(*outputLayer1, getLayer()).WillOnce(ReturnRef(layer));
    320     EXPECT_EQ(outputLayer1, mOutput.getOutputLayerForLayer(&layer));
    321 
    322     // If the input layer matches the second OutputLayer, it will be returned.
    323     EXPECT_CALL(*outputLayer1, getLayer()).WillOnce(ReturnRef(otherLayer));
    324     EXPECT_CALL(*outputLayer2, getLayer()).WillOnce(ReturnRef(layer));
    325     EXPECT_EQ(outputLayer2, mOutput.getOutputLayerForLayer(&layer));
    326 
    327     // If the input layer does not match an output layer, null will be returned.
    328     EXPECT_CALL(*outputLayer1, getLayer()).WillOnce(ReturnRef(otherLayer));
    329     EXPECT_CALL(*outputLayer2, getLayer()).WillOnce(ReturnRef(otherLayer));
    330     EXPECT_EQ(nullptr, mOutput.getOutputLayerForLayer(&layer));
    331 }
    332 
    333 /* ------------------------------------------------------------------------
    334  * Output::getOrCreateOutputLayer()
    335  */
    336 
    337 TEST_F(OutputTest, getOrCreateOutputLayerWorks) {
    338     mock::OutputLayer* existingOutputLayer = new StrictMock<mock::OutputLayer>();
    339 
    340     Output::OutputLayers outputLayers;
    341     outputLayers.emplace_back(nullptr);
    342     outputLayers.emplace_back(std::unique_ptr<OutputLayer>(existingOutputLayer));
    343     mOutput.setOutputLayersOrderedByZ(std::move(outputLayers));
    344 
    345     std::shared_ptr<mock::Layer> layer{new StrictMock<mock::Layer>()};
    346     sp<LayerFE> layerFE{new StrictMock<mock::LayerFE>()};
    347 
    348     StrictMock<mock::Layer> otherLayer;
    349 
    350     {
    351         // If there is no OutputLayer corresponding to the input layer, a
    352         // new OutputLayer is constructed and returned.
    353         EXPECT_CALL(*existingOutputLayer, getLayer()).WillOnce(ReturnRef(otherLayer));
    354         auto result = mOutput.getOrCreateOutputLayer(std::nullopt, layer, layerFE);
    355         EXPECT_NE(existingOutputLayer, result.get());
    356         EXPECT_TRUE(result.get() != nullptr);
    357         EXPECT_EQ(layer.get(), &result->getLayer());
    358         EXPECT_EQ(layerFE.get(), &result->getLayerFE());
    359 
    360         // The entries in the ordered array should be unchanged.
    361         auto& outputLayers = mOutput.getOutputLayersOrderedByZ();
    362         EXPECT_EQ(nullptr, outputLayers[0].get());
    363         EXPECT_EQ(existingOutputLayer, outputLayers[1].get());
    364     }
    365 
    366     {
    367         // If there is an existing OutputLayer for the requested layer, an owned
    368         // pointer is returned
    369         EXPECT_CALL(*existingOutputLayer, getLayer()).WillOnce(ReturnRef(*layer));
    370         auto result = mOutput.getOrCreateOutputLayer(std::nullopt, layer, layerFE);
    371         EXPECT_EQ(existingOutputLayer, result.get());
    372 
    373         // The corresponding entry in the ordered array should be cleared.
    374         auto& outputLayers = mOutput.getOutputLayersOrderedByZ();
    375         EXPECT_EQ(nullptr, outputLayers[0].get());
    376         EXPECT_EQ(nullptr, outputLayers[1].get());
    377     }
    378 }
    379 
    380 } // namespace
    381 } // namespace android::compositionengine
    382