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:
OutputTest()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 
TEST_F(OutputTest,canInstantiateOutput)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 
TEST_F(OutputTest,setCompositionEnabledDoesNothingIfAlreadyEnabled)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 
TEST_F(OutputTest,setCompositionEnabledSetsEnabledAndDirtiesEntireOutput)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 
TEST_F(OutputTest,setCompositionEnabledSetsDisabledAndDirtiesEntireOutput)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 
TEST_F(OutputTest,setProjectionTriviallyWorks)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 
TEST_F(OutputTest,setBoundsSetsSizeAndDirtiesEntireOutput)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 
TEST_F(OutputTest,setLayerStackFilterSetsFilterAndDirtiesEntireOutput)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 
TEST_F(OutputTest,setColorTransformSetsTransform)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 
TEST_F(OutputTest,setColorModeSetsStateAndDirtiesOutputIfChanged)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 
TEST_F(OutputTest,setColorModeDoesNothingIfNoChange)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 
TEST_F(OutputTest,setRenderSurfaceResetsBounds)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 
TEST_F(OutputTest,getDirtyRegionWithRepaintEverythingTrue)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 
TEST_F(OutputTest,getDirtyRegionWithRepaintEverythingFalse)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 
TEST_F(OutputTest,belongsInOutputFiltersAsExpected)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 
TEST_F(OutputTest,getOutputLayerForLayerWorks)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 
TEST_F(OutputTest,getOrCreateOutputLayerWorks)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