blob: cc1211bf1afc87f8ba96fe7afeb94d1b8d6b36ed [file] [log] [blame]
Lloyd Pique32cbe282018-10-19 13:09:22 -07001/*
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>
Lloyd Pique3d0c02e2018-10-19 18:38:12 -070021#include <compositionengine/mock/DisplayColorProfile.h>
Lloyd Piquecc01a452018-12-04 17:24:00 -080022#include <compositionengine/mock/Layer.h>
23#include <compositionengine/mock/LayerFE.h>
24#include <compositionengine/mock/OutputLayer.h>
Lloyd Pique31cb2942018-10-19 17:23:03 -070025#include <compositionengine/mock/RenderSurface.h>
Lloyd Pique32cbe282018-10-19 13:09:22 -070026#include <gtest/gtest.h>
27#include <ui/Rect.h>
28#include <ui/Region.h>
29
30#include "RegionMatcher.h"
31#include "TransformMatcher.h"
32
33namespace android::compositionengine {
34namespace {
35
Lloyd Pique31cb2942018-10-19 17:23:03 -070036using testing::Return;
Lloyd Pique32cbe282018-10-19 13:09:22 -070037using testing::ReturnRef;
38using testing::StrictMock;
39
40class OutputTest : public testing::Test {
41public:
Lloyd Pique31cb2942018-10-19 17:23:03 -070042 OutputTest() {
Lloyd Pique3d0c02e2018-10-19 18:38:12 -070043 mOutput.setDisplayColorProfileForTest(
44 std::unique_ptr<DisplayColorProfile>(mDisplayColorProfile));
Lloyd Pique31cb2942018-10-19 17:23:03 -070045 mOutput.setRenderSurfaceForTest(std::unique_ptr<RenderSurface>(mRenderSurface));
46 }
Lloyd Pique32cbe282018-10-19 13:09:22 -070047 ~OutputTest() override = default;
48
49 StrictMock<mock::CompositionEngine> mCompositionEngine;
Lloyd Pique3d0c02e2018-10-19 18:38:12 -070050 mock::DisplayColorProfile* mDisplayColorProfile = new StrictMock<mock::DisplayColorProfile>();
Lloyd Pique31cb2942018-10-19 17:23:03 -070051 mock::RenderSurface* mRenderSurface = new StrictMock<mock::RenderSurface>();
Lloyd Pique32cbe282018-10-19 13:09:22 -070052 impl::Output mOutput{mCompositionEngine};
53};
54
55/* ------------------------------------------------------------------------
56 * Basic construction
57 */
58
Lloyd Pique31cb2942018-10-19 17:23:03 -070059TEST_F(OutputTest, canInstantiateOutput) {
60 // The validation check checks each required component.
Lloyd Pique3d0c02e2018-10-19 18:38:12 -070061 EXPECT_CALL(*mDisplayColorProfile, isValid()).WillOnce(Return(true));
Lloyd Pique31cb2942018-10-19 17:23:03 -070062 EXPECT_CALL(*mRenderSurface, isValid()).WillOnce(Return(true));
63
64 EXPECT_TRUE(mOutput.isValid());
65
66 // If we take away the required components, it is no longer valid.
67 mOutput.setRenderSurfaceForTest(std::unique_ptr<RenderSurface>());
68
Lloyd Pique3d0c02e2018-10-19 18:38:12 -070069 EXPECT_CALL(*mDisplayColorProfile, isValid()).WillOnce(Return(true));
70
Lloyd Pique31cb2942018-10-19 17:23:03 -070071 EXPECT_FALSE(mOutput.isValid());
72}
Lloyd Pique32cbe282018-10-19 13:09:22 -070073
74/* ------------------------------------------------------------------------
75 * Output::setCompositionEnabled()
76 */
77
78TEST_F(OutputTest, setCompositionEnabledDoesNothingIfAlreadyEnabled) {
79 const Rect displaySize{100, 200};
80 mOutput.editState().bounds = displaySize;
81 mOutput.editState().isEnabled = true;
82
83 mOutput.setCompositionEnabled(true);
84
85 EXPECT_TRUE(mOutput.getState().isEnabled);
86 EXPECT_THAT(mOutput.getState().dirtyRegion, RegionEq(Region()));
87}
88
89TEST_F(OutputTest, setCompositionEnabledSetsEnabledAndDirtiesEntireOutput) {
90 const Rect displaySize{100, 200};
91 mOutput.editState().bounds = displaySize;
92 mOutput.editState().isEnabled = false;
93
94 mOutput.setCompositionEnabled(true);
95
96 EXPECT_TRUE(mOutput.getState().isEnabled);
97 EXPECT_THAT(mOutput.getState().dirtyRegion, RegionEq(Region(displaySize)));
98}
99
100TEST_F(OutputTest, setCompositionEnabledSetsDisabledAndDirtiesEntireOutput) {
101 const Rect displaySize{100, 200};
102 mOutput.editState().bounds = displaySize;
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(displaySize)));
109}
110
111/* ------------------------------------------------------------------------
112 * Output::setProjection()
113 */
114
115TEST_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
137TEST_F(OutputTest, setBoundsSetsSizeAndDirtiesEntireOutput) {
Lloyd Pique31cb2942018-10-19 17:23:03 -0700138 const ui::Size displaySize{100, 200};
139
140 EXPECT_CALL(*mRenderSurface, setDisplaySize(displaySize)).Times(1);
141 EXPECT_CALL(*mRenderSurface, getSize()).WillOnce(ReturnRef(displaySize));
142
Lloyd Pique32cbe282018-10-19 13:09:22 -0700143 mOutput.setBounds(displaySize);
144
Lloyd Pique31cb2942018-10-19 17:23:03 -0700145 EXPECT_EQ(Rect(displaySize), mOutput.getState().bounds);
Lloyd Pique32cbe282018-10-19 13:09:22 -0700146
Lloyd Pique31cb2942018-10-19 17:23:03 -0700147 EXPECT_THAT(mOutput.getState().dirtyRegion, RegionEq(Region(Rect(displaySize))));
Lloyd Pique32cbe282018-10-19 13:09:22 -0700148}
149
150/* ------------------------------------------------------------------------
151 * Output::setLayerStackFilter()
152 */
153
154TEST_F(OutputTest, setLayerStackFilterSetsFilterAndDirtiesEntireOutput) {
155 const Rect displaySize{100, 200};
156 mOutput.editState().bounds = displaySize;
157
158 const uint32_t layerStack = 123u;
Lloyd Piqueef36b002019-01-23 17:52:04 -0800159 mOutput.setLayerStackFilter(layerStack, true);
Lloyd Pique32cbe282018-10-19 13:09:22 -0700160
Lloyd Piqueef36b002019-01-23 17:52:04 -0800161 EXPECT_TRUE(mOutput.getState().layerStackInternal);
162 EXPECT_EQ(layerStack, mOutput.getState().layerStackId);
Lloyd Pique32cbe282018-10-19 13:09:22 -0700163
164 EXPECT_THAT(mOutput.getState().dirtyRegion, RegionEq(Region(displaySize)));
165}
166
167/* ------------------------------------------------------------------------
168 * Output::setColorTransform
169 */
170
171TEST_F(OutputTest, setColorTransformSetsTransform) {
172 // Identity matrix sets an identity state value
173 const mat4 identity;
174
175 mOutput.setColorTransform(identity);
176
177 EXPECT_EQ(HAL_COLOR_TRANSFORM_IDENTITY, mOutput.getState().colorTransform);
178
179 // Non-identity matrix sets a non-identity state value
180 const mat4 nonIdentity = mat4() * 2;
181
182 mOutput.setColorTransform(nonIdentity);
183
184 EXPECT_EQ(HAL_COLOR_TRANSFORM_ARBITRARY_MATRIX, mOutput.getState().colorTransform);
185}
186
187/* ------------------------------------------------------------------------
188 * Output::setColorMode
189 */
190
191TEST_F(OutputTest, setColorModeSetsModeUnlessNoChange) {
Lloyd Pique31cb2942018-10-19 17:23:03 -0700192 EXPECT_CALL(*mRenderSurface, setBufferDataspace(ui::Dataspace::SRGB)).Times(1);
193
Lloyd Pique32cbe282018-10-19 13:09:22 -0700194 mOutput.setColorMode(ui::ColorMode::BT2100_PQ, ui::Dataspace::SRGB,
195 ui::RenderIntent::TONE_MAP_COLORIMETRIC);
196
197 EXPECT_EQ(ui::ColorMode::BT2100_PQ, mOutput.getState().colorMode);
198 EXPECT_EQ(ui::Dataspace::SRGB, mOutput.getState().dataspace);
199 EXPECT_EQ(ui::RenderIntent::TONE_MAP_COLORIMETRIC, mOutput.getState().renderIntent);
200}
201
202/* ------------------------------------------------------------------------
Lloyd Pique31cb2942018-10-19 17:23:03 -0700203 * Output::setRenderSurface()
204 */
205
206TEST_F(OutputTest, setRenderSurfaceResetsBounds) {
207 const ui::Size newDisplaySize{640, 480};
208
209 mock::RenderSurface* renderSurface = new StrictMock<mock::RenderSurface>();
210 EXPECT_CALL(*renderSurface, getSize()).WillOnce(ReturnRef(newDisplaySize));
211
212 mOutput.setRenderSurface(std::unique_ptr<RenderSurface>(renderSurface));
213
214 EXPECT_EQ(Rect(newDisplaySize), mOutput.getState().bounds);
215}
216
217/* ------------------------------------------------------------------------
Alec Mouri79108df2019-02-04 19:33:44 +0000218 * Output::getPhysicalSpaceDirtyRegion()
Lloyd Pique32cbe282018-10-19 13:09:22 -0700219 */
220
Alec Mouri79108df2019-02-04 19:33:44 +0000221TEST_F(OutputTest, getPhysicalSpaceDirtyRegionWithRepaintEverythingTrue) {
222 const Rect displaySize{100, 200};
223 mOutput.editState().bounds = displaySize;
Lloyd Pique32cbe282018-10-19 13:09:22 -0700224 mOutput.editState().dirtyRegion.set(50, 300);
225
226 {
Alec Mouri79108df2019-02-04 19:33:44 +0000227 Region result = mOutput.getPhysicalSpaceDirtyRegion(true);
Lloyd Pique32cbe282018-10-19 13:09:22 -0700228
Alec Mouri79108df2019-02-04 19:33:44 +0000229 EXPECT_THAT(result, RegionEq(Region(displaySize)));
230 }
231
232 // For repaint everything == true, the returned value does not depend on the display
233 // rotation.
234 mOutput.editState().transform.set(ui::Transform::ROT_90, 0, 0);
235
236 {
237 Region result = mOutput.getPhysicalSpaceDirtyRegion(true);
238
239 EXPECT_THAT(result, RegionEq(Region(displaySize)));
Lloyd Pique32cbe282018-10-19 13:09:22 -0700240 }
241}
242
Alec Mouri79108df2019-02-04 19:33:44 +0000243TEST_F(OutputTest, getPhysicalSpaceDirtyRegionWithRepaintEverythingFalse) {
244 const Rect displaySize{100, 200};
245 mOutput.editState().bounds = displaySize;
Lloyd Pique32cbe282018-10-19 13:09:22 -0700246 mOutput.editState().dirtyRegion.set(50, 300);
247
248 {
Alec Mouri79108df2019-02-04 19:33:44 +0000249 Region result = mOutput.getPhysicalSpaceDirtyRegion(false);
Lloyd Pique32cbe282018-10-19 13:09:22 -0700250
251 // The dirtyRegion should be clipped to the display bounds.
252 EXPECT_THAT(result, RegionEq(Region(Rect(50, 200))));
253 }
Alec Mouri79108df2019-02-04 19:33:44 +0000254
255 mOutput.editState().transform.set(ui::Transform::ROT_90, displaySize.getWidth(),
256 displaySize.getHeight());
257
258 {
259 Region result = mOutput.getPhysicalSpaceDirtyRegion(false);
260
261 // The dirtyRegion should be rotated and clipped to the display bounds.
262 EXPECT_THAT(result, RegionEq(Region(Rect(100, 50))));
263 }
Lloyd Pique32cbe282018-10-19 13:09:22 -0700264}
265
Lloyd Piqueef36b002019-01-23 17:52:04 -0800266/* ------------------------------------------------------------------------
267 * Output::belongsInOutput()
268 */
269
270TEST_F(OutputTest, belongsInOutputFiltersAsExpected) {
271 const uint32_t layerStack1 = 123u;
272 const uint32_t layerStack2 = 456u;
273
274 // If the output accepts layerStack1 and internal-only layers....
275 mOutput.setLayerStackFilter(layerStack1, true);
276
277 // Any layer with layerStack1 belongs to it, internal-only or not.
278 EXPECT_TRUE(mOutput.belongsInOutput(layerStack1, false));
279 EXPECT_TRUE(mOutput.belongsInOutput(layerStack1, true));
280 EXPECT_FALSE(mOutput.belongsInOutput(layerStack2, true));
281 EXPECT_FALSE(mOutput.belongsInOutput(layerStack2, false));
282
283 // If the output accepts layerStack21 but not internal-only layers...
284 mOutput.setLayerStackFilter(layerStack1, false);
285
286 // Only non-internal layers with layerStack1 belong to it.
287 EXPECT_TRUE(mOutput.belongsInOutput(layerStack1, false));
288 EXPECT_FALSE(mOutput.belongsInOutput(layerStack1, true));
289 EXPECT_FALSE(mOutput.belongsInOutput(layerStack2, true));
290 EXPECT_FALSE(mOutput.belongsInOutput(layerStack2, false));
291}
292
Lloyd Piquecc01a452018-12-04 17:24:00 -0800293/* ------------------------------------------------------------------------
294 * Output::getOutputLayerForLayer()
295 */
296
297TEST_F(OutputTest, getOutputLayerForLayerWorks) {
298 mock::OutputLayer* outputLayer1 = new StrictMock<mock::OutputLayer>();
299 mock::OutputLayer* outputLayer2 = new StrictMock<mock::OutputLayer>();
300
301 Output::OutputLayers outputLayers;
302 outputLayers.emplace_back(std::unique_ptr<OutputLayer>(outputLayer1));
303 outputLayers.emplace_back(nullptr);
304 outputLayers.emplace_back(std::unique_ptr<OutputLayer>(outputLayer2));
305 mOutput.setOutputLayersOrderedByZ(std::move(outputLayers));
306
307 StrictMock<mock::Layer> layer;
308 StrictMock<mock::Layer> otherLayer;
309
310 // If the input layer matches the first OutputLayer, it will be returned.
311 EXPECT_CALL(*outputLayer1, getLayer()).WillOnce(ReturnRef(layer));
312 EXPECT_EQ(outputLayer1, mOutput.getOutputLayerForLayer(&layer));
313
314 // If the input layer matches the second OutputLayer, it will be returned.
315 EXPECT_CALL(*outputLayer1, getLayer()).WillOnce(ReturnRef(otherLayer));
316 EXPECT_CALL(*outputLayer2, getLayer()).WillOnce(ReturnRef(layer));
317 EXPECT_EQ(outputLayer2, mOutput.getOutputLayerForLayer(&layer));
318
319 // If the input layer does not match an output layer, null will be returned.
320 EXPECT_CALL(*outputLayer1, getLayer()).WillOnce(ReturnRef(otherLayer));
321 EXPECT_CALL(*outputLayer2, getLayer()).WillOnce(ReturnRef(otherLayer));
322 EXPECT_EQ(nullptr, mOutput.getOutputLayerForLayer(&layer));
323}
324
325/* ------------------------------------------------------------------------
326 * Output::getOrCreateOutputLayer()
327 */
328
329TEST_F(OutputTest, getOrCreateOutputLayerWorks) {
330 mock::OutputLayer* existingOutputLayer = new StrictMock<mock::OutputLayer>();
331
332 Output::OutputLayers outputLayers;
333 outputLayers.emplace_back(nullptr);
334 outputLayers.emplace_back(std::unique_ptr<OutputLayer>(existingOutputLayer));
335 mOutput.setOutputLayersOrderedByZ(std::move(outputLayers));
336
337 std::shared_ptr<mock::Layer> layer{new StrictMock<mock::Layer>()};
338 sp<LayerFE> layerFE{new StrictMock<mock::LayerFE>()};
339
340 StrictMock<mock::Layer> otherLayer;
341
342 {
343 // If there is no OutputLayer corresponding to the input layer, a
344 // new OutputLayer is constructed and returned.
345 EXPECT_CALL(*existingOutputLayer, getLayer()).WillOnce(ReturnRef(otherLayer));
346 auto result = mOutput.getOrCreateOutputLayer(layer, layerFE);
347 EXPECT_NE(existingOutputLayer, result.get());
348 EXPECT_TRUE(result.get() != nullptr);
349 EXPECT_EQ(layer.get(), &result->getLayer());
350 EXPECT_EQ(layerFE.get(), &result->getLayerFE());
351
352 // The entries in the ordered array should be unchanged.
353 auto& outputLayers = mOutput.getOutputLayersOrderedByZ();
354 EXPECT_EQ(nullptr, outputLayers[0].get());
355 EXPECT_EQ(existingOutputLayer, outputLayers[1].get());
356 }
357
358 {
359 // If there is an existing OutputLayer for the requested layer, an owned
360 // pointer is returned
361 EXPECT_CALL(*existingOutputLayer, getLayer()).WillOnce(ReturnRef(*layer));
362 auto result = mOutput.getOrCreateOutputLayer(layer, layerFE);
363 EXPECT_EQ(existingOutputLayer, result.get());
364
365 // The corresponding entry in the ordered array should be cleared.
366 auto& outputLayers = mOutput.getOutputLayersOrderedByZ();
367 EXPECT_EQ(nullptr, outputLayers[0].get());
368 EXPECT_EQ(nullptr, outputLayers[1].get());
369 }
370}
371
Lloyd Pique32cbe282018-10-19 13:09:22 -0700372} // namespace
373} // namespace android::compositionengine