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 <android-base/stringprintf.h>
18 #include <compositionengine/CompositionEngine.h>
19 #include <compositionengine/Layer.h>
20 #include <compositionengine/LayerFE.h>
21 #include <compositionengine/Output.h>
22 #include <compositionengine/impl/LayerCompositionState.h>
23 #include <compositionengine/impl/OutputCompositionState.h>
24 #include <compositionengine/impl/OutputLayer.h>
25 #include <compositionengine/impl/OutputLayerCompositionState.h>
26
27 #include "DisplayHardware/HWComposer.h"
28
29 namespace android::compositionengine {
30
31 OutputLayer::~OutputLayer() = default;
32
33 namespace impl {
34
35 namespace {
36
reduce(const FloatRect & win,const Region & exclude)37 FloatRect reduce(const FloatRect& win, const Region& exclude) {
38 if (CC_LIKELY(exclude.isEmpty())) {
39 return win;
40 }
41 // Convert through Rect (by rounding) for lack of FloatRegion
42 return Region(Rect{win}).subtract(exclude).getBounds().toFloatRect();
43 }
44
45 } // namespace
46
createOutputLayer(const CompositionEngine & compositionEngine,std::optional<DisplayId> displayId,const compositionengine::Output & output,std::shared_ptr<compositionengine::Layer> layer,sp<compositionengine::LayerFE> layerFE)47 std::unique_ptr<compositionengine::OutputLayer> createOutputLayer(
48 const CompositionEngine& compositionEngine, std::optional<DisplayId> displayId,
49 const compositionengine::Output& output, std::shared_ptr<compositionengine::Layer> layer,
50 sp<compositionengine::LayerFE> layerFE) {
51 auto result = std::make_unique<OutputLayer>(output, layer, layerFE);
52 result->initialize(compositionEngine, displayId);
53 return result;
54 }
55
OutputLayer(const Output & output,std::shared_ptr<Layer> layer,sp<LayerFE> layerFE)56 OutputLayer::OutputLayer(const Output& output, std::shared_ptr<Layer> layer, sp<LayerFE> layerFE)
57 : mOutput(output), mLayer(layer), mLayerFE(layerFE) {}
58
59 OutputLayer::~OutputLayer() = default;
60
initialize(const CompositionEngine & compositionEngine,std::optional<DisplayId> displayId)61 void OutputLayer::initialize(const CompositionEngine& compositionEngine,
62 std::optional<DisplayId> displayId) {
63 if (!displayId) {
64 return;
65 }
66
67 auto& hwc = compositionEngine.getHwComposer();
68
69 mState.hwc.emplace(std::shared_ptr<HWC2::Layer>(hwc.createLayer(*displayId),
70 [&hwc, displayId](HWC2::Layer* layer) {
71 hwc.destroyLayer(*displayId, layer);
72 }));
73 }
74
getOutput() const75 const compositionengine::Output& OutputLayer::getOutput() const {
76 return mOutput;
77 }
78
getLayer() const79 compositionengine::Layer& OutputLayer::getLayer() const {
80 return *mLayer;
81 }
82
getLayerFE() const83 compositionengine::LayerFE& OutputLayer::getLayerFE() const {
84 return *mLayerFE;
85 }
86
getState() const87 const OutputLayerCompositionState& OutputLayer::getState() const {
88 return mState;
89 }
90
editState()91 OutputLayerCompositionState& OutputLayer::editState() {
92 return mState;
93 }
94
calculateInitialCrop() const95 Rect OutputLayer::calculateInitialCrop() const {
96 const auto& layerState = mLayer->getState().frontEnd;
97
98 // apply the projection's clipping to the window crop in
99 // layerstack space, and convert-back to layer space.
100 // if there are no window scaling involved, this operation will map to full
101 // pixels in the buffer.
102
103 FloatRect activeCropFloat =
104 reduce(layerState.geomLayerBounds, layerState.geomActiveTransparentRegion);
105
106 const Rect& viewport = mOutput.getState().viewport;
107 const ui::Transform& layerTransform = layerState.geomLayerTransform;
108 const ui::Transform& inverseLayerTransform = layerState.geomInverseLayerTransform;
109 // Transform to screen space.
110 activeCropFloat = layerTransform.transform(activeCropFloat);
111 activeCropFloat = activeCropFloat.intersect(viewport.toFloatRect());
112 // Back to layer space to work with the content crop.
113 activeCropFloat = inverseLayerTransform.transform(activeCropFloat);
114
115 // This needs to be here as transform.transform(Rect) computes the
116 // transformed rect and then takes the bounding box of the result before
117 // returning. This means
118 // transform.inverse().transform(transform.transform(Rect)) != Rect
119 // in which case we need to make sure the final rect is clipped to the
120 // display bounds.
121 Rect activeCrop{activeCropFloat};
122 if (!activeCrop.intersect(layerState.geomBufferSize, &activeCrop)) {
123 activeCrop.clear();
124 }
125 return activeCrop;
126 }
127
calculateOutputSourceCrop() const128 FloatRect OutputLayer::calculateOutputSourceCrop() const {
129 const auto& layerState = mLayer->getState().frontEnd;
130 const auto& outputState = mOutput.getState();
131
132 if (!layerState.geomUsesSourceCrop) {
133 return {};
134 }
135
136 // the content crop is the area of the content that gets scaled to the
137 // layer's size. This is in buffer space.
138 FloatRect crop = layerState.geomContentCrop.toFloatRect();
139
140 // In addition there is a WM-specified crop we pull from our drawing state.
141 Rect activeCrop = calculateInitialCrop();
142 const Rect& bufferSize = layerState.geomBufferSize;
143
144 int winWidth = bufferSize.getWidth();
145 int winHeight = bufferSize.getHeight();
146
147 // The bufferSize for buffer state layers can be unbounded ([0, 0, -1, -1])
148 // if display frame hasn't been set and the parent is an unbounded layer.
149 if (winWidth < 0 && winHeight < 0) {
150 return crop;
151 }
152
153 // Transform the window crop to match the buffer coordinate system,
154 // which means using the inverse of the current transform set on the
155 // SurfaceFlingerConsumer.
156 uint32_t invTransform = layerState.geomBufferTransform;
157 if (layerState.geomBufferUsesDisplayInverseTransform) {
158 /*
159 * the code below applies the primary display's inverse transform to the
160 * buffer
161 */
162 uint32_t invTransformOrient = outputState.orientation;
163 // calculate the inverse transform
164 if (invTransformOrient & HAL_TRANSFORM_ROT_90) {
165 invTransformOrient ^= HAL_TRANSFORM_FLIP_V | HAL_TRANSFORM_FLIP_H;
166 }
167 // and apply to the current transform
168 invTransform =
169 (ui::Transform(invTransformOrient) * ui::Transform(invTransform)).getOrientation();
170 }
171
172 if (invTransform & HAL_TRANSFORM_ROT_90) {
173 // If the activeCrop has been rotate the ends are rotated but not
174 // the space itself so when transforming ends back we can't rely on
175 // a modification of the axes of rotation. To account for this we
176 // need to reorient the inverse rotation in terms of the current
177 // axes of rotation.
178 bool is_h_flipped = (invTransform & HAL_TRANSFORM_FLIP_H) != 0;
179 bool is_v_flipped = (invTransform & HAL_TRANSFORM_FLIP_V) != 0;
180 if (is_h_flipped == is_v_flipped) {
181 invTransform ^= HAL_TRANSFORM_FLIP_V | HAL_TRANSFORM_FLIP_H;
182 }
183 std::swap(winWidth, winHeight);
184 }
185 const Rect winCrop =
186 activeCrop.transform(invTransform, bufferSize.getWidth(), bufferSize.getHeight());
187
188 // below, crop is intersected with winCrop expressed in crop's coordinate space
189 float xScale = crop.getWidth() / float(winWidth);
190 float yScale = crop.getHeight() / float(winHeight);
191
192 float insetL = winCrop.left * xScale;
193 float insetT = winCrop.top * yScale;
194 float insetR = (winWidth - winCrop.right) * xScale;
195 float insetB = (winHeight - winCrop.bottom) * yScale;
196
197 crop.left += insetL;
198 crop.top += insetT;
199 crop.right -= insetR;
200 crop.bottom -= insetB;
201
202 return crop;
203 }
204
calculateOutputDisplayFrame() const205 Rect OutputLayer::calculateOutputDisplayFrame() const {
206 const auto& layerState = mLayer->getState().frontEnd;
207 const auto& outputState = mOutput.getState();
208
209 // apply the layer's transform, followed by the display's global transform
210 // here we're guaranteed that the layer's transform preserves rects
211 Region activeTransparentRegion = layerState.geomActiveTransparentRegion;
212 const ui::Transform& layerTransform = layerState.geomLayerTransform;
213 const ui::Transform& inverseLayerTransform = layerState.geomInverseLayerTransform;
214 const Rect& bufferSize = layerState.geomBufferSize;
215 Rect activeCrop = layerState.geomCrop;
216 if (!activeCrop.isEmpty() && bufferSize.isValid()) {
217 activeCrop = layerTransform.transform(activeCrop);
218 if (!activeCrop.intersect(outputState.viewport, &activeCrop)) {
219 activeCrop.clear();
220 }
221 activeCrop = inverseLayerTransform.transform(activeCrop, true);
222 // This needs to be here as transform.transform(Rect) computes the
223 // transformed rect and then takes the bounding box of the result before
224 // returning. This means
225 // transform.inverse().transform(transform.transform(Rect)) != Rect
226 // in which case we need to make sure the final rect is clipped to the
227 // display bounds.
228 if (!activeCrop.intersect(bufferSize, &activeCrop)) {
229 activeCrop.clear();
230 }
231 // mark regions outside the crop as transparent
232 activeTransparentRegion.orSelf(Rect(0, 0, bufferSize.getWidth(), activeCrop.top));
233 activeTransparentRegion.orSelf(
234 Rect(0, activeCrop.bottom, bufferSize.getWidth(), bufferSize.getHeight()));
235 activeTransparentRegion.orSelf(Rect(0, activeCrop.top, activeCrop.left, activeCrop.bottom));
236 activeTransparentRegion.orSelf(
237 Rect(activeCrop.right, activeCrop.top, bufferSize.getWidth(), activeCrop.bottom));
238 }
239
240 // reduce uses a FloatRect to provide more accuracy during the
241 // transformation. We then round upon constructing 'frame'.
242 Rect frame{
243 layerTransform.transform(reduce(layerState.geomLayerBounds, activeTransparentRegion))};
244 if (!frame.intersect(outputState.viewport, &frame)) {
245 frame.clear();
246 }
247 const ui::Transform displayTransform{outputState.transform};
248
249 return displayTransform.transform(frame);
250 }
251
calculateOutputRelativeBufferTransform() const252 uint32_t OutputLayer::calculateOutputRelativeBufferTransform() const {
253 const auto& layerState = mLayer->getState().frontEnd;
254 const auto& outputState = mOutput.getState();
255
256 /*
257 * Transformations are applied in this order:
258 * 1) buffer orientation/flip/mirror
259 * 2) state transformation (window manager)
260 * 3) layer orientation (screen orientation)
261 * (NOTE: the matrices are multiplied in reverse order)
262 */
263 const ui::Transform& layerTransform = layerState.geomLayerTransform;
264 const ui::Transform displayTransform{outputState.transform};
265 const ui::Transform bufferTransform{layerState.geomBufferTransform};
266 ui::Transform transform(displayTransform * layerTransform * bufferTransform);
267
268 if (layerState.geomBufferUsesDisplayInverseTransform) {
269 /*
270 * the code below applies the primary display's inverse transform to the
271 * buffer
272 */
273 uint32_t invTransform = outputState.orientation;
274 // calculate the inverse transform
275 if (invTransform & HAL_TRANSFORM_ROT_90) {
276 invTransform ^= HAL_TRANSFORM_FLIP_V | HAL_TRANSFORM_FLIP_H;
277 }
278
279 /*
280 * Here we cancel out the orientation component of the WM transform.
281 * The scaling and translate components are already included in our bounds
282 * computation so it's enough to just omit it in the composition.
283 * See comment in BufferLayer::prepareClientLayer with ref to b/36727915 for why.
284 */
285 transform = ui::Transform(invTransform) * displayTransform * bufferTransform;
286 }
287
288 // this gives us only the "orientation" component of the transform
289 return transform.getOrientation();
290 } // namespace impl
291
updateCompositionState(bool includeGeometry)292 void OutputLayer::updateCompositionState(bool includeGeometry) {
293 if (includeGeometry) {
294 mState.displayFrame = calculateOutputDisplayFrame();
295 mState.sourceCrop = calculateOutputSourceCrop();
296 mState.bufferTransform =
297 static_cast<Hwc2::Transform>(calculateOutputRelativeBufferTransform());
298
299 if ((mLayer->getState().frontEnd.isSecure && !mOutput.getState().isSecure) ||
300 (mState.bufferTransform & ui::Transform::ROT_INVALID)) {
301 mState.forceClientComposition = true;
302 }
303 }
304 }
305
writeStateToHWC(bool includeGeometry) const306 void OutputLayer::writeStateToHWC(bool includeGeometry) const {
307 // Skip doing this if there is no HWC interface
308 if (!mState.hwc) {
309 return;
310 }
311
312 auto& hwcLayer = (*mState.hwc).hwcLayer;
313 if (!hwcLayer) {
314 ALOGE("[%s] failed to write composition state to HWC -- no hwcLayer for output %s",
315 mLayerFE->getDebugName(), mOutput.getName().c_str());
316 return;
317 }
318
319 if (includeGeometry) {
320 // Output dependent state
321
322 if (auto error = hwcLayer->setDisplayFrame(mState.displayFrame);
323 error != HWC2::Error::None) {
324 ALOGE("[%s] Failed to set display frame [%d, %d, %d, %d]: %s (%d)",
325 mLayerFE->getDebugName(), mState.displayFrame.left, mState.displayFrame.top,
326 mState.displayFrame.right, mState.displayFrame.bottom, to_string(error).c_str(),
327 static_cast<int32_t>(error));
328 }
329
330 if (auto error = hwcLayer->setSourceCrop(mState.sourceCrop); error != HWC2::Error::None) {
331 ALOGE("[%s] Failed to set source crop [%.3f, %.3f, %.3f, %.3f]: "
332 "%s (%d)",
333 mLayerFE->getDebugName(), mState.sourceCrop.left, mState.sourceCrop.top,
334 mState.sourceCrop.right, mState.sourceCrop.bottom, to_string(error).c_str(),
335 static_cast<int32_t>(error));
336 }
337
338 if (auto error = hwcLayer->setZOrder(mState.z); error != HWC2::Error::None) {
339 ALOGE("[%s] Failed to set Z %u: %s (%d)", mLayerFE->getDebugName(), mState.z,
340 to_string(error).c_str(), static_cast<int32_t>(error));
341 }
342
343 if (auto error =
344 hwcLayer->setTransform(static_cast<HWC2::Transform>(mState.bufferTransform));
345 error != HWC2::Error::None) {
346 ALOGE("[%s] Failed to set transform %s: %s (%d)", mLayerFE->getDebugName(),
347 toString(mState.bufferTransform).c_str(), to_string(error).c_str(),
348 static_cast<int32_t>(error));
349 }
350
351 // Output independent state
352
353 const auto& outputIndependentState = mLayer->getState().frontEnd;
354
355 if (auto error = hwcLayer->setBlendMode(
356 static_cast<HWC2::BlendMode>(outputIndependentState.blendMode));
357 error != HWC2::Error::None) {
358 ALOGE("[%s] Failed to set blend mode %s: %s (%d)", mLayerFE->getDebugName(),
359 toString(outputIndependentState.blendMode).c_str(), to_string(error).c_str(),
360 static_cast<int32_t>(error));
361 }
362
363 if (auto error = hwcLayer->setPlaneAlpha(outputIndependentState.alpha);
364 error != HWC2::Error::None) {
365 ALOGE("[%s] Failed to set plane alpha %.3f: %s (%d)", mLayerFE->getDebugName(),
366 outputIndependentState.alpha, to_string(error).c_str(),
367 static_cast<int32_t>(error));
368 }
369
370 if (auto error =
371 hwcLayer->setInfo(outputIndependentState.type, outputIndependentState.appId);
372 error != HWC2::Error::None) {
373 ALOGE("[%s] Failed to set info %s (%d)", mLayerFE->getDebugName(),
374 to_string(error).c_str(), static_cast<int32_t>(error));
375 }
376 }
377 }
378
dump(std::string & out) const379 void OutputLayer::dump(std::string& out) const {
380 using android::base::StringAppendF;
381
382 StringAppendF(&out, " - Output Layer %p (Composition layer %p) (%s)\n", this, mLayer.get(),
383 mLayerFE->getDebugName());
384 mState.dump(out);
385 }
386
387 } // namespace impl
388 } // namespace android::compositionengine
389