blob: 635e4502c367322086887a424e127a324a147ed1 [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
Lloyd Piquef8cf14d2019-02-28 16:03:12 -080017#include <thread>
18
Lloyd Pique32cbe282018-10-19 13:09:22 -070019#include <android-base/stringprintf.h>
20#include <compositionengine/CompositionEngine.h>
Lloyd Piquef8cf14d2019-02-28 16:03:12 -080021#include <compositionengine/CompositionRefreshArgs.h>
Lloyd Pique3d0c02e2018-10-19 18:38:12 -070022#include <compositionengine/DisplayColorProfile.h>
Lloyd Pique688abd42019-02-15 15:42:24 -080023#include <compositionengine/Layer.h>
Lloyd Piquecc01a452018-12-04 17:24:00 -080024#include <compositionengine/LayerFE.h>
Lloyd Pique31cb2942018-10-19 17:23:03 -070025#include <compositionengine/RenderSurface.h>
Lloyd Pique688abd42019-02-15 15:42:24 -080026#include <compositionengine/impl/LayerCompositionState.h>
Lloyd Pique32cbe282018-10-19 13:09:22 -070027#include <compositionengine/impl/Output.h>
Lloyd Piquecc01a452018-12-04 17:24:00 -080028#include <compositionengine/impl/OutputLayer.h>
Lloyd Pique688abd42019-02-15 15:42:24 -080029#include <renderengine/DisplaySettings.h>
30#include <renderengine/RenderEngine.h>
Lloyd Pique32cbe282018-10-19 13:09:22 -070031#include <ui/DebugUtils.h>
Lloyd Pique688abd42019-02-15 15:42:24 -080032#include <ui/HdrCapabilities.h>
Lloyd Pique66d68602019-02-13 14:23:31 -080033#include <utils/Trace.h>
Lloyd Pique32cbe282018-10-19 13:09:22 -070034
Lloyd Pique688abd42019-02-15 15:42:24 -080035#include "TracedOrdinal.h"
36
Lloyd Piquefeb73d72018-12-04 17:23:44 -080037namespace android::compositionengine {
38
39Output::~Output() = default;
40
41namespace impl {
Lloyd Pique32cbe282018-10-19 13:09:22 -070042
43Output::Output(const CompositionEngine& compositionEngine)
44 : mCompositionEngine(compositionEngine) {}
45
46Output::~Output() = default;
47
48const CompositionEngine& Output::getCompositionEngine() const {
49 return mCompositionEngine;
50}
51
52bool Output::isValid() const {
Lloyd Pique3d0c02e2018-10-19 18:38:12 -070053 return mDisplayColorProfile && mDisplayColorProfile->isValid() && mRenderSurface &&
54 mRenderSurface->isValid();
Lloyd Pique32cbe282018-10-19 13:09:22 -070055}
56
57const std::string& Output::getName() const {
58 return mName;
59}
60
61void Output::setName(const std::string& name) {
62 mName = name;
63}
64
65void Output::setCompositionEnabled(bool enabled) {
66 if (mState.isEnabled == enabled) {
67 return;
68 }
69
70 mState.isEnabled = enabled;
71 dirtyEntireOutput();
72}
73
74void Output::setProjection(const ui::Transform& transform, int32_t orientation, const Rect& frame,
75 const Rect& viewport, const Rect& scissor, bool needsFiltering) {
76 mState.transform = transform;
77 mState.orientation = orientation;
78 mState.scissor = scissor;
79 mState.frame = frame;
80 mState.viewport = viewport;
81 mState.needsFiltering = needsFiltering;
82
83 dirtyEntireOutput();
84}
85
Lloyd Pique688abd42019-02-15 15:42:24 -080086// TODO(b/121291683): Rename setSize() once more is moved.
Lloyd Pique31cb2942018-10-19 17:23:03 -070087void Output::setBounds(const ui::Size& size) {
88 mRenderSurface->setDisplaySize(size);
Lloyd Pique688abd42019-02-15 15:42:24 -080089 // TODO(b/121291683): Rename mState.size once more is moved.
Lloyd Pique31cb2942018-10-19 17:23:03 -070090 mState.bounds = Rect(mRenderSurface->getSize());
Lloyd Pique32cbe282018-10-19 13:09:22 -070091
92 dirtyEntireOutput();
93}
94
Lloyd Piqueef36b002019-01-23 17:52:04 -080095void Output::setLayerStackFilter(uint32_t layerStackId, bool isInternal) {
96 mState.layerStackId = layerStackId;
97 mState.layerStackInternal = isInternal;
Lloyd Pique32cbe282018-10-19 13:09:22 -070098
99 dirtyEntireOutput();
100}
101
102void Output::setColorTransform(const mat4& transform) {
Lloyd Pique77f79a22019-04-29 15:55:40 -0700103 if (mState.colorTransformMat == transform) {
104 return;
105 }
106
Lloyd Pique32cbe282018-10-19 13:09:22 -0700107 const bool isIdentity = (transform == mat4());
Lloyd Piqueef958122019-02-05 18:00:12 -0800108 const auto newColorTransform =
Lloyd Pique32cbe282018-10-19 13:09:22 -0700109 isIdentity ? HAL_COLOR_TRANSFORM_IDENTITY : HAL_COLOR_TRANSFORM_ARBITRARY_MATRIX;
Lloyd Piqueef958122019-02-05 18:00:12 -0800110
Lloyd Piqueef958122019-02-05 18:00:12 -0800111 mState.colorTransform = newColorTransform;
Alec Mouric7e8ce82019-04-02 12:28:05 -0700112 mState.colorTransformMat = transform;
Lloyd Piqueef958122019-02-05 18:00:12 -0800113
114 dirtyEntireOutput();
Lloyd Pique32cbe282018-10-19 13:09:22 -0700115}
116
Lloyd Pique6a3b4462019-03-07 20:58:12 -0800117void Output::setColorProfile(const ColorProfile& colorProfile) {
118 const ui::Dataspace targetDataspace =
119 getDisplayColorProfile()->getTargetDataspace(colorProfile.mode, colorProfile.dataspace,
120 colorProfile.colorSpaceAgnosticDataspace);
Lloyd Piquef5275482019-01-29 18:42:42 -0800121
Lloyd Pique6a3b4462019-03-07 20:58:12 -0800122 if (mState.colorMode == colorProfile.mode && mState.dataspace == colorProfile.dataspace &&
123 mState.renderIntent == colorProfile.renderIntent &&
124 mState.targetDataspace == targetDataspace) {
Lloyd Piqueef958122019-02-05 18:00:12 -0800125 return;
126 }
127
Lloyd Pique6a3b4462019-03-07 20:58:12 -0800128 mState.colorMode = colorProfile.mode;
129 mState.dataspace = colorProfile.dataspace;
130 mState.renderIntent = colorProfile.renderIntent;
Lloyd Piquef5275482019-01-29 18:42:42 -0800131 mState.targetDataspace = targetDataspace;
Lloyd Pique32cbe282018-10-19 13:09:22 -0700132
Lloyd Pique6a3b4462019-03-07 20:58:12 -0800133 mRenderSurface->setBufferDataspace(colorProfile.dataspace);
Lloyd Pique31cb2942018-10-19 17:23:03 -0700134
Lloyd Pique32cbe282018-10-19 13:09:22 -0700135 ALOGV("Set active color mode: %s (%d), active render intent: %s (%d)",
Lloyd Pique6a3b4462019-03-07 20:58:12 -0800136 decodeColorMode(colorProfile.mode).c_str(), colorProfile.mode,
137 decodeRenderIntent(colorProfile.renderIntent).c_str(), colorProfile.renderIntent);
Lloyd Piqueef958122019-02-05 18:00:12 -0800138
139 dirtyEntireOutput();
Lloyd Pique32cbe282018-10-19 13:09:22 -0700140}
141
142void Output::dump(std::string& out) const {
143 using android::base::StringAppendF;
144
145 StringAppendF(&out, " Composition Output State: [\"%s\"]", mName.c_str());
146
147 out.append("\n ");
148
149 dumpBase(out);
150}
151
152void Output::dumpBase(std::string& out) const {
153 mState.dump(out);
Lloyd Pique31cb2942018-10-19 17:23:03 -0700154
Lloyd Pique3d0c02e2018-10-19 18:38:12 -0700155 if (mDisplayColorProfile) {
156 mDisplayColorProfile->dump(out);
157 } else {
158 out.append(" No display color profile!\n");
159 }
160
Lloyd Pique31cb2942018-10-19 17:23:03 -0700161 if (mRenderSurface) {
162 mRenderSurface->dump(out);
163 } else {
164 out.append(" No render surface!\n");
165 }
Lloyd Pique37c2c9b2018-12-04 17:25:10 -0800166
Lloyd Pique207def92019-02-28 16:09:52 -0800167 android::base::StringAppendF(&out, "\n %zu Layers\b", mOutputLayersOrderedByZ.size());
Lloyd Pique37c2c9b2018-12-04 17:25:10 -0800168 for (const auto& outputLayer : mOutputLayersOrderedByZ) {
169 if (!outputLayer) {
170 continue;
171 }
172 outputLayer->dump(out);
173 }
Lloyd Pique31cb2942018-10-19 17:23:03 -0700174}
175
Lloyd Pique3d0c02e2018-10-19 18:38:12 -0700176compositionengine::DisplayColorProfile* Output::getDisplayColorProfile() const {
177 return mDisplayColorProfile.get();
178}
179
180void Output::setDisplayColorProfile(std::unique_ptr<compositionengine::DisplayColorProfile> mode) {
181 mDisplayColorProfile = std::move(mode);
182}
183
184void Output::setDisplayColorProfileForTest(
185 std::unique_ptr<compositionengine::DisplayColorProfile> mode) {
186 mDisplayColorProfile = std::move(mode);
187}
188
Lloyd Pique31cb2942018-10-19 17:23:03 -0700189compositionengine::RenderSurface* Output::getRenderSurface() const {
190 return mRenderSurface.get();
191}
192
193void Output::setRenderSurface(std::unique_ptr<compositionengine::RenderSurface> surface) {
194 mRenderSurface = std::move(surface);
195 mState.bounds = Rect(mRenderSurface->getSize());
196
197 dirtyEntireOutput();
198}
199
200void Output::setRenderSurfaceForTest(std::unique_ptr<compositionengine::RenderSurface> surface) {
201 mRenderSurface = std::move(surface);
Lloyd Pique32cbe282018-10-19 13:09:22 -0700202}
203
204const OutputCompositionState& Output::getState() const {
205 return mState;
206}
207
208OutputCompositionState& Output::editState() {
209 return mState;
210}
211
Alec Mourie7d1d4a2019-02-05 01:13:46 +0000212Region Output::getDirtyRegion(bool repaintEverything) const {
213 Region dirty(mState.viewport);
214 if (!repaintEverything) {
215 dirty.andSelf(mState.dirtyRegion);
Lloyd Pique32cbe282018-10-19 13:09:22 -0700216 }
217 return dirty;
218}
219
Lloyd Piqueef36b002019-01-23 17:52:04 -0800220bool Output::belongsInOutput(uint32_t layerStackId, bool internalOnly) const {
221 // The layerStackId's must match, and also the layer must not be internal
222 // only when not on an internal output.
223 return (layerStackId == mState.layerStackId) && (!internalOnly || mState.layerStackInternal);
Lloyd Pique32cbe282018-10-19 13:09:22 -0700224}
225
Lloyd Piquecc01a452018-12-04 17:24:00 -0800226compositionengine::OutputLayer* Output::getOutputLayerForLayer(
227 compositionengine::Layer* layer) const {
228 for (const auto& outputLayer : mOutputLayersOrderedByZ) {
229 if (outputLayer && &outputLayer->getLayer() == layer) {
230 return outputLayer.get();
231 }
232 }
233 return nullptr;
234}
235
236std::unique_ptr<compositionengine::OutputLayer> Output::getOrCreateOutputLayer(
Lloyd Pique07e33212018-12-18 16:33:37 -0800237 std::optional<DisplayId> displayId, std::shared_ptr<compositionengine::Layer> layer,
238 sp<compositionengine::LayerFE> layerFE) {
Lloyd Piquecc01a452018-12-04 17:24:00 -0800239 for (auto& outputLayer : mOutputLayersOrderedByZ) {
240 if (outputLayer && &outputLayer->getLayer() == layer.get()) {
241 return std::move(outputLayer);
242 }
243 }
Lloyd Pique07e33212018-12-18 16:33:37 -0800244 return createOutputLayer(mCompositionEngine, displayId, *this, layer, layerFE);
Lloyd Piquecc01a452018-12-04 17:24:00 -0800245}
246
247void Output::setOutputLayersOrderedByZ(OutputLayers&& layers) {
248 mOutputLayersOrderedByZ = std::move(layers);
249}
250
251const Output::OutputLayers& Output::getOutputLayersOrderedByZ() const {
252 return mOutputLayersOrderedByZ;
253}
254
Lloyd Piquec7ef21b2019-01-29 18:43:00 -0800255void Output::setReleasedLayers(Output::ReleasedLayers&& layers) {
256 mReleasedLayers = std::move(layers);
257}
258
259Output::ReleasedLayers Output::takeReleasedLayers() {
260 return std::move(mReleasedLayers);
261}
262
Lloyd Piqued7b429f2019-03-07 21:11:02 -0800263void Output::present(const compositionengine::CompositionRefreshArgs& refreshArgs) {
264 beginFrame();
265 prepareFrame();
266 devOptRepaintFlash(refreshArgs);
267 finishFrame(refreshArgs);
268 postFramebuffer();
269}
270
Lloyd Pique6a3b4462019-03-07 20:58:12 -0800271void Output::updateColorProfile(const compositionengine::CompositionRefreshArgs& refreshArgs) {
272 setColorProfile(pickColorProfile(refreshArgs));
273}
274
275// Returns a data space that fits all visible layers. The returned data space
276// can only be one of
277// - Dataspace::SRGB (use legacy dataspace and let HWC saturate when colors are enhanced)
278// - Dataspace::DISPLAY_P3
279// - Dataspace::DISPLAY_BT2020
280// The returned HDR data space is one of
281// - Dataspace::UNKNOWN
282// - Dataspace::BT2020_HLG
283// - Dataspace::BT2020_PQ
284ui::Dataspace Output::getBestDataspace(ui::Dataspace* outHdrDataSpace,
285 bool* outIsHdrClientComposition) const {
286 ui::Dataspace bestDataSpace = ui::Dataspace::V0_SRGB;
287 *outHdrDataSpace = ui::Dataspace::UNKNOWN;
288
289 for (const auto& layer : mOutputLayersOrderedByZ) {
290 switch (layer->getLayer().getState().frontEnd.dataspace) {
291 case ui::Dataspace::V0_SCRGB:
292 case ui::Dataspace::V0_SCRGB_LINEAR:
293 case ui::Dataspace::BT2020:
294 case ui::Dataspace::BT2020_ITU:
295 case ui::Dataspace::BT2020_LINEAR:
296 case ui::Dataspace::DISPLAY_BT2020:
297 bestDataSpace = ui::Dataspace::DISPLAY_BT2020;
298 break;
299 case ui::Dataspace::DISPLAY_P3:
300 bestDataSpace = ui::Dataspace::DISPLAY_P3;
301 break;
302 case ui::Dataspace::BT2020_PQ:
303 case ui::Dataspace::BT2020_ITU_PQ:
304 bestDataSpace = ui::Dataspace::DISPLAY_P3;
305 *outHdrDataSpace = ui::Dataspace::BT2020_PQ;
306 *outIsHdrClientComposition =
307 layer->getLayer().getState().frontEnd.forceClientComposition;
308 break;
309 case ui::Dataspace::BT2020_HLG:
310 case ui::Dataspace::BT2020_ITU_HLG:
311 bestDataSpace = ui::Dataspace::DISPLAY_P3;
312 // When there's mixed PQ content and HLG content, we set the HDR
313 // data space to be BT2020_PQ and convert HLG to PQ.
314 if (*outHdrDataSpace == ui::Dataspace::UNKNOWN) {
315 *outHdrDataSpace = ui::Dataspace::BT2020_HLG;
316 }
317 break;
318 default:
319 break;
320 }
321 }
322
323 return bestDataSpace;
324}
325
326compositionengine::Output::ColorProfile Output::pickColorProfile(
327 const compositionengine::CompositionRefreshArgs& refreshArgs) const {
328 if (refreshArgs.outputColorSetting == OutputColorSetting::kUnmanaged) {
329 return ColorProfile{ui::ColorMode::NATIVE, ui::Dataspace::UNKNOWN,
330 ui::RenderIntent::COLORIMETRIC,
331 refreshArgs.colorSpaceAgnosticDataspace};
332 }
333
334 ui::Dataspace hdrDataSpace;
335 bool isHdrClientComposition = false;
336 ui::Dataspace bestDataSpace = getBestDataspace(&hdrDataSpace, &isHdrClientComposition);
337
338 switch (refreshArgs.forceOutputColorMode) {
339 case ui::ColorMode::SRGB:
340 bestDataSpace = ui::Dataspace::V0_SRGB;
341 break;
342 case ui::ColorMode::DISPLAY_P3:
343 bestDataSpace = ui::Dataspace::DISPLAY_P3;
344 break;
345 default:
346 break;
347 }
348
349 // respect hdrDataSpace only when there is no legacy HDR support
350 const bool isHdr = hdrDataSpace != ui::Dataspace::UNKNOWN &&
351 !mDisplayColorProfile->hasLegacyHdrSupport(hdrDataSpace) && !isHdrClientComposition;
352 if (isHdr) {
353 bestDataSpace = hdrDataSpace;
354 }
355
356 ui::RenderIntent intent;
357 switch (refreshArgs.outputColorSetting) {
358 case OutputColorSetting::kManaged:
359 case OutputColorSetting::kUnmanaged:
360 intent = isHdr ? ui::RenderIntent::TONE_MAP_COLORIMETRIC
361 : ui::RenderIntent::COLORIMETRIC;
362 break;
363 case OutputColorSetting::kEnhanced:
364 intent = isHdr ? ui::RenderIntent::TONE_MAP_ENHANCE : ui::RenderIntent::ENHANCE;
365 break;
366 default: // vendor display color setting
367 intent = static_cast<ui::RenderIntent>(refreshArgs.outputColorSetting);
368 break;
369 }
370
371 ui::ColorMode outMode;
372 ui::Dataspace outDataSpace;
373 ui::RenderIntent outRenderIntent;
374 mDisplayColorProfile->getBestColorMode(bestDataSpace, intent, &outDataSpace, &outMode,
375 &outRenderIntent);
376
377 return ColorProfile{outMode, outDataSpace, outRenderIntent,
378 refreshArgs.colorSpaceAgnosticDataspace};
379}
380
Lloyd Piqued0a92a02019-02-19 17:47:26 -0800381void Output::beginFrame() {
382 const bool dirty = !getDirtyRegion(false).isEmpty();
383 const bool empty = mOutputLayersOrderedByZ.empty();
384 const bool wasEmpty = !mState.lastCompositionHadVisibleLayers;
385
386 // If nothing has changed (!dirty), don't recompose.
387 // If something changed, but we don't currently have any visible layers,
388 // and didn't when we last did a composition, then skip it this time.
389 // The second rule does two things:
390 // - When all layers are removed from a display, we'll emit one black
391 // frame, then nothing more until we get new layers.
392 // - When a display is created with a private layer stack, we won't
393 // emit any black frames until a layer is added to the layer stack.
394 const bool mustRecompose = dirty && !(empty && wasEmpty);
395
396 const char flagPrefix[] = {'-', '+'};
397 static_cast<void>(flagPrefix);
398 ALOGV_IF("%s: %s composition for %s (%cdirty %cempty %cwasEmpty)", __FUNCTION__,
399 mustRecompose ? "doing" : "skipping", getName().c_str(), flagPrefix[dirty],
400 flagPrefix[empty], flagPrefix[wasEmpty]);
401
402 mRenderSurface->beginFrame(mustRecompose);
403
404 if (mustRecompose) {
405 mState.lastCompositionHadVisibleLayers = !empty;
406 }
407}
408
Lloyd Pique66d68602019-02-13 14:23:31 -0800409void Output::prepareFrame() {
410 ATRACE_CALL();
411 ALOGV(__FUNCTION__);
412
413 if (!mState.isEnabled) {
414 return;
415 }
416
417 chooseCompositionStrategy();
418
419 mRenderSurface->prepareFrame(mState.usesClientComposition, mState.usesDeviceComposition);
420}
421
Lloyd Piquef8cf14d2019-02-28 16:03:12 -0800422void Output::devOptRepaintFlash(const compositionengine::CompositionRefreshArgs& refreshArgs) {
423 if (CC_LIKELY(!refreshArgs.devOptFlashDirtyRegionsDelay)) {
424 return;
425 }
426
427 if (mState.isEnabled) {
428 // transform the dirty region into this screen's coordinate space
429 const Region dirtyRegion = getDirtyRegion(refreshArgs.repaintEverything);
430 if (!dirtyRegion.isEmpty()) {
431 base::unique_fd readyFence;
432 // redraw the whole screen
Lloyd Piqued3d69882019-02-28 16:03:46 -0800433 static_cast<void>(composeSurfaces(dirtyRegion));
Lloyd Piquef8cf14d2019-02-28 16:03:12 -0800434
435 mRenderSurface->queueBuffer(std::move(readyFence));
436 }
437 }
438
439 postFramebuffer();
440
441 std::this_thread::sleep_for(*refreshArgs.devOptFlashDirtyRegionsDelay);
442
443 prepareFrame();
444}
445
Lloyd Piqued3d69882019-02-28 16:03:46 -0800446void Output::finishFrame(const compositionengine::CompositionRefreshArgs&) {
447 ATRACE_CALL();
448 ALOGV(__FUNCTION__);
449
450 if (!mState.isEnabled) {
451 return;
452 }
453
454 // Repaint the framebuffer (if needed), getting the optional fence for when
455 // the composition completes.
456 auto optReadyFence = composeSurfaces(Region::INVALID_REGION);
457 if (!optReadyFence) {
458 return;
459 }
460
461 // swap buffers (presentation)
462 mRenderSurface->queueBuffer(std::move(*optReadyFence));
463}
464
465std::optional<base::unique_fd> Output::composeSurfaces(const Region& debugRegion) {
Lloyd Pique688abd42019-02-15 15:42:24 -0800466 ATRACE_CALL();
467 ALOGV(__FUNCTION__);
468
469 const TracedOrdinal<bool> hasClientComposition = {"hasClientComposition",
470 mState.usesClientComposition};
Lloyd Piqued3d69882019-02-28 16:03:46 -0800471 base::unique_fd readyFence;
472
Lloyd Pique688abd42019-02-15 15:42:24 -0800473 if (!hasClientComposition) {
Lloyd Piqued3d69882019-02-28 16:03:46 -0800474 return readyFence;
Lloyd Pique688abd42019-02-15 15:42:24 -0800475 }
476
477 ALOGV("hasClientComposition");
478
479 auto& renderEngine = mCompositionEngine.getRenderEngine();
480 const bool supportsProtectedContent = renderEngine.supportsProtectedContent();
481
482 renderengine::DisplaySettings clientCompositionDisplay;
Lloyd Pique810b0302019-08-14 16:09:32 -0700483 clientCompositionDisplay.physicalDisplay = mState.scissor;
Lloyd Pique688abd42019-02-15 15:42:24 -0800484 clientCompositionDisplay.clip = mState.scissor;
485 clientCompositionDisplay.globalTransform = mState.transform.asMatrix4();
486 clientCompositionDisplay.orientation = mState.orientation;
487 clientCompositionDisplay.outputDataspace =
488 mDisplayColorProfile->hasWideColorGamut() ? mState.dataspace : ui::Dataspace::UNKNOWN;
489 clientCompositionDisplay.maxLuminance =
490 mDisplayColorProfile->getHdrCapabilities().getDesiredMaxLuminance();
491
492 // Compute the global color transform matrix.
493 if (!mState.usesDeviceComposition && !getSkipColorTransform()) {
494 clientCompositionDisplay.colorTransform = mState.colorTransformMat;
495 }
496
497 // Note: Updated by generateClientCompositionRequests
498 clientCompositionDisplay.clearRegion = Region::INVALID_REGION;
499
500 // Generate the client composition requests for the layers on this output.
501 std::vector<renderengine::LayerSettings> clientCompositionLayers =
502 generateClientCompositionRequests(supportsProtectedContent,
503 clientCompositionDisplay.clearRegion);
504 appendRegionFlashRequests(debugRegion, clientCompositionLayers);
505
506 // If we the display is secure, protected content support is enabled, and at
507 // least one layer has protected content, we need to use a secure back
508 // buffer.
509 if (mState.isSecure && supportsProtectedContent) {
510 bool needsProtected =
511 std::any_of(mOutputLayersOrderedByZ.begin(), mOutputLayersOrderedByZ.end(),
512 [](auto& layer) {
513 return layer->getLayer().getState().frontEnd.hasProtectedContent;
514 });
515 if (needsProtected != renderEngine.isProtected()) {
516 renderEngine.useProtectedContext(needsProtected);
517 }
518 if (needsProtected != mRenderSurface->isProtected() &&
519 needsProtected == renderEngine.isProtected()) {
520 mRenderSurface->setProtected(needsProtected);
521 }
522 }
523
524 base::unique_fd fd;
525 sp<GraphicBuffer> buf = mRenderSurface->dequeueBuffer(&fd);
526 if (buf == nullptr) {
527 ALOGW("Dequeuing buffer for display [%s] failed, bailing out of "
528 "client composition for this frame",
529 mName.c_str());
Lloyd Piqued3d69882019-02-28 16:03:46 -0800530 return std::nullopt;
Lloyd Pique688abd42019-02-15 15:42:24 -0800531 }
532
533 // We boost GPU frequency here because there will be color spaces conversion
534 // and it's expensive. We boost the GPU frequency so that GPU composition can
535 // finish in time. We must reset GPU frequency afterwards, because high frequency
536 // consumes extra battery.
537 const bool expensiveRenderingExpected =
538 clientCompositionDisplay.outputDataspace == ui::Dataspace::DISPLAY_P3;
539 if (expensiveRenderingExpected) {
540 setExpensiveRenderingExpected(true);
541 }
542
543 renderEngine.drawLayers(clientCompositionDisplay, clientCompositionLayers,
544 buf->getNativeBuffer(), /*useFramebufferCache=*/true, std::move(fd),
Lloyd Piqued3d69882019-02-28 16:03:46 -0800545 &readyFence);
Lloyd Pique688abd42019-02-15 15:42:24 -0800546
547 if (expensiveRenderingExpected) {
548 setExpensiveRenderingExpected(false);
549 }
550
Lloyd Piqued3d69882019-02-28 16:03:46 -0800551 return readyFence;
Lloyd Pique688abd42019-02-15 15:42:24 -0800552}
553
554std::vector<renderengine::LayerSettings> Output::generateClientCompositionRequests(
555 bool supportsProtectedContent, Region& clearRegion) {
556 std::vector<renderengine::LayerSettings> clientCompositionLayers;
557 ALOGV("Rendering client layers");
558
559 const Region viewportRegion(mState.viewport);
560 const bool useIdentityTransform = false;
561 bool firstLayer = true;
562 // Used when a layer clears part of the buffer.
563 Region dummyRegion;
564
565 for (auto& layer : mOutputLayersOrderedByZ) {
566 const auto& layerState = layer->getState();
567 const auto& layerFEState = layer->getLayer().getState().frontEnd;
568 auto& layerFE = layer->getLayerFE();
569
Lloyd Pique56eba802019-08-28 15:45:25 -0700570 const Region clip(viewportRegion.intersect(layerFEState.geomVisibleRegion));
Lloyd Pique688abd42019-02-15 15:42:24 -0800571 ALOGV("Layer: %s", layerFE.getDebugName());
572 if (clip.isEmpty()) {
573 ALOGV(" Skipping for empty clip");
574 firstLayer = false;
575 continue;
576 }
577
578 bool clientComposition = layer->requiresClientComposition();
579
580 // We clear the client target for non-client composed layers if
581 // requested by the HWC. We skip this if the layer is not an opaque
582 // rectangle, as by definition the layer must blend with whatever is
583 // underneath. We also skip the first layer as the buffer target is
584 // guaranteed to start out cleared.
585 bool clearClientComposition =
586 layerState.clearClientTarget && layerFEState.isOpaque && !firstLayer;
587
588 ALOGV(" Composition type: client %d clear %d", clientComposition, clearClientComposition);
589
590 if (clientComposition || clearClientComposition) {
591 compositionengine::LayerFE::ClientCompositionTargetSettings targetSettings{
592 clip,
593 useIdentityTransform,
594 layer->needsFiltering() || mState.needsFiltering,
595 mState.isSecure,
596 supportsProtectedContent,
597 clientComposition ? clearRegion : dummyRegion,
598 };
599 if (auto result = layerFE.prepareClientComposition(targetSettings)) {
Lloyd Piquec2d54d42019-08-28 18:04:21 -0700600 if (!clientComposition) {
Lloyd Pique688abd42019-02-15 15:42:24 -0800601 auto& layerSettings = *result;
602 layerSettings.source.buffer.buffer = nullptr;
603 layerSettings.source.solidColor = half3(0.0, 0.0, 0.0);
604 layerSettings.alpha = half(0.0);
605 layerSettings.disableBlending = true;
606 }
607
608 clientCompositionLayers.push_back(*result);
609 }
610 }
611
612 firstLayer = false;
613 }
614
615 return clientCompositionLayers;
616}
617
618void Output::appendRegionFlashRequests(
619 const Region& flashRegion,
620 std::vector<renderengine::LayerSettings>& clientCompositionLayers) {
621 if (flashRegion.isEmpty()) {
622 return;
623 }
624
625 renderengine::LayerSettings layerSettings;
626 layerSettings.source.buffer.buffer = nullptr;
627 layerSettings.source.solidColor = half3(1.0, 0.0, 1.0);
628 layerSettings.alpha = half(1.0);
629
630 for (const auto& rect : flashRegion) {
631 layerSettings.geometry.boundaries = rect.toFloatRect();
632 clientCompositionLayers.push_back(layerSettings);
633 }
634}
635
636void Output::setExpensiveRenderingExpected(bool) {
637 // The base class does nothing with this call.
638}
639
Lloyd Pique35fca9d2019-02-13 14:24:11 -0800640void Output::postFramebuffer() {
641 ATRACE_CALL();
642 ALOGV(__FUNCTION__);
643
644 if (!getState().isEnabled) {
645 return;
646 }
647
Lloyd Piqued3d69882019-02-28 16:03:46 -0800648 mState.dirtyRegion.clear();
649 mRenderSurface->flip();
650
Lloyd Pique35fca9d2019-02-13 14:24:11 -0800651 auto frame = presentAndGetFrameFences();
652
Lloyd Pique7d90ba52019-08-08 11:57:53 -0700653 mRenderSurface->onPresentDisplayCompleted();
654
Lloyd Pique35fca9d2019-02-13 14:24:11 -0800655 for (auto& layer : getOutputLayersOrderedByZ()) {
656 // The layer buffer from the previous frame (if any) is released
657 // by HWC only when the release fence from this frame (if any) is
658 // signaled. Always get the release fence from HWC first.
659 sp<Fence> releaseFence = Fence::NO_FENCE;
660
661 if (auto hwcLayer = layer->getHwcLayer()) {
662 if (auto f = frame.layerFences.find(hwcLayer); f != frame.layerFences.end()) {
663 releaseFence = f->second;
664 }
665 }
666
667 // If the layer was client composited in the previous frame, we
668 // need to merge with the previous client target acquire fence.
669 // Since we do not track that, always merge with the current
670 // client target acquire fence when it is available, even though
671 // this is suboptimal.
672 // TODO(b/121291683): Track previous frame client target acquire fence.
673 if (mState.usesClientComposition) {
674 releaseFence =
675 Fence::merge("LayerRelease", releaseFence, frame.clientTargetAcquireFence);
676 }
677
678 layer->getLayerFE().onLayerDisplayed(releaseFence);
679 }
680
681 // We've got a list of layers needing fences, that are disjoint with
682 // getOutputLayersOrderedByZ. The best we can do is to
683 // supply them with the present fence.
684 for (auto& weakLayer : mReleasedLayers) {
685 if (auto layer = weakLayer.promote(); layer != nullptr) {
686 layer->onLayerDisplayed(frame.presentFence);
687 }
688 }
689
690 // Clear out the released layers now that we're done with them.
691 mReleasedLayers.clear();
692}
693
Lloyd Pique32cbe282018-10-19 13:09:22 -0700694void Output::dirtyEntireOutput() {
695 mState.dirtyRegion.set(mState.bounds);
696}
697
Lloyd Pique66d68602019-02-13 14:23:31 -0800698void Output::chooseCompositionStrategy() {
699 // The base output implementation can only do client composition
700 mState.usesClientComposition = true;
701 mState.usesDeviceComposition = false;
702}
703
Lloyd Pique688abd42019-02-15 15:42:24 -0800704bool Output::getSkipColorTransform() const {
705 return true;
706}
707
Lloyd Pique35fca9d2019-02-13 14:24:11 -0800708compositionengine::Output::FrameFences Output::presentAndGetFrameFences() {
709 compositionengine::Output::FrameFences result;
710 if (mState.usesClientComposition) {
711 result.clientTargetAcquireFence = mRenderSurface->getClientTargetAcquireFence();
712 }
713 return result;
714}
715
Lloyd Piquefeb73d72018-12-04 17:23:44 -0800716} // namespace impl
717} // namespace android::compositionengine