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 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 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 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 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 75 const compositionengine::Output& OutputLayer::getOutput() const { 76 return mOutput; 77 } 78 79 compositionengine::Layer& OutputLayer::getLayer() const { 80 return *mLayer; 81 } 82 83 compositionengine::LayerFE& OutputLayer::getLayerFE() const { 84 return *mLayerFE; 85 } 86 87 const OutputLayerCompositionState& OutputLayer::getState() const { 88 return mState; 89 } 90 91 OutputLayerCompositionState& OutputLayer::editState() { 92 return mState; 93 } 94 95 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 128 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 205 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 252 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.orientation}; 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 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 306 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 379 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