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