blob: 4dfdebae02904875ef7a7db9a4d2d5c70b8372a9 [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
Lloyd Pique3eb1b212019-03-07 21:15:40 -0800102void Output::setColorTransform(const compositionengine::CompositionRefreshArgs& args) {
103 if (!args.colorTransformMatrix || mState.colorTransformMatrix == *args.colorTransformMatrix) {
Lloyd Pique77f79a22019-04-29 15:55:40 -0700104 return;
105 }
106
Lloyd Pique3eb1b212019-03-07 21:15:40 -0800107 mState.colorTransformMatrix = *args.colorTransformMatrix;
Lloyd Piqueef958122019-02-05 18:00:12 -0800108
109 dirtyEntireOutput();
Lloyd Pique32cbe282018-10-19 13:09:22 -0700110}
111
Lloyd Pique6a3b4462019-03-07 20:58:12 -0800112void Output::setColorProfile(const ColorProfile& colorProfile) {
113 const ui::Dataspace targetDataspace =
114 getDisplayColorProfile()->getTargetDataspace(colorProfile.mode, colorProfile.dataspace,
115 colorProfile.colorSpaceAgnosticDataspace);
Lloyd Piquef5275482019-01-29 18:42:42 -0800116
Lloyd Pique6a3b4462019-03-07 20:58:12 -0800117 if (mState.colorMode == colorProfile.mode && mState.dataspace == colorProfile.dataspace &&
118 mState.renderIntent == colorProfile.renderIntent &&
119 mState.targetDataspace == targetDataspace) {
Lloyd Piqueef958122019-02-05 18:00:12 -0800120 return;
121 }
122
Lloyd Pique6a3b4462019-03-07 20:58:12 -0800123 mState.colorMode = colorProfile.mode;
124 mState.dataspace = colorProfile.dataspace;
125 mState.renderIntent = colorProfile.renderIntent;
Lloyd Piquef5275482019-01-29 18:42:42 -0800126 mState.targetDataspace = targetDataspace;
Lloyd Pique32cbe282018-10-19 13:09:22 -0700127
Lloyd Pique6a3b4462019-03-07 20:58:12 -0800128 mRenderSurface->setBufferDataspace(colorProfile.dataspace);
Lloyd Pique31cb2942018-10-19 17:23:03 -0700129
Lloyd Pique32cbe282018-10-19 13:09:22 -0700130 ALOGV("Set active color mode: %s (%d), active render intent: %s (%d)",
Lloyd Pique6a3b4462019-03-07 20:58:12 -0800131 decodeColorMode(colorProfile.mode).c_str(), colorProfile.mode,
132 decodeRenderIntent(colorProfile.renderIntent).c_str(), colorProfile.renderIntent);
Lloyd Piqueef958122019-02-05 18:00:12 -0800133
134 dirtyEntireOutput();
Lloyd Pique32cbe282018-10-19 13:09:22 -0700135}
136
137void Output::dump(std::string& out) const {
138 using android::base::StringAppendF;
139
140 StringAppendF(&out, " Composition Output State: [\"%s\"]", mName.c_str());
141
142 out.append("\n ");
143
144 dumpBase(out);
145}
146
147void Output::dumpBase(std::string& out) const {
148 mState.dump(out);
Lloyd Pique31cb2942018-10-19 17:23:03 -0700149
Lloyd Pique3d0c02e2018-10-19 18:38:12 -0700150 if (mDisplayColorProfile) {
151 mDisplayColorProfile->dump(out);
152 } else {
153 out.append(" No display color profile!\n");
154 }
155
Lloyd Pique31cb2942018-10-19 17:23:03 -0700156 if (mRenderSurface) {
157 mRenderSurface->dump(out);
158 } else {
159 out.append(" No render surface!\n");
160 }
Lloyd Pique37c2c9b2018-12-04 17:25:10 -0800161
Lloyd Pique207def92019-02-28 16:09:52 -0800162 android::base::StringAppendF(&out, "\n %zu Layers\b", mOutputLayersOrderedByZ.size());
Lloyd Pique37c2c9b2018-12-04 17:25:10 -0800163 for (const auto& outputLayer : mOutputLayersOrderedByZ) {
164 if (!outputLayer) {
165 continue;
166 }
167 outputLayer->dump(out);
168 }
Lloyd Pique31cb2942018-10-19 17:23:03 -0700169}
170
Lloyd Pique3d0c02e2018-10-19 18:38:12 -0700171compositionengine::DisplayColorProfile* Output::getDisplayColorProfile() const {
172 return mDisplayColorProfile.get();
173}
174
175void Output::setDisplayColorProfile(std::unique_ptr<compositionengine::DisplayColorProfile> mode) {
176 mDisplayColorProfile = std::move(mode);
177}
178
179void Output::setDisplayColorProfileForTest(
180 std::unique_ptr<compositionengine::DisplayColorProfile> mode) {
181 mDisplayColorProfile = std::move(mode);
182}
183
Lloyd Pique31cb2942018-10-19 17:23:03 -0700184compositionengine::RenderSurface* Output::getRenderSurface() const {
185 return mRenderSurface.get();
186}
187
188void Output::setRenderSurface(std::unique_ptr<compositionengine::RenderSurface> surface) {
189 mRenderSurface = std::move(surface);
190 mState.bounds = Rect(mRenderSurface->getSize());
191
192 dirtyEntireOutput();
193}
194
195void Output::setRenderSurfaceForTest(std::unique_ptr<compositionengine::RenderSurface> surface) {
196 mRenderSurface = std::move(surface);
Lloyd Pique32cbe282018-10-19 13:09:22 -0700197}
198
199const OutputCompositionState& Output::getState() const {
200 return mState;
201}
202
203OutputCompositionState& Output::editState() {
204 return mState;
205}
206
Alec Mourie7d1d4a2019-02-05 01:13:46 +0000207Region Output::getDirtyRegion(bool repaintEverything) const {
208 Region dirty(mState.viewport);
209 if (!repaintEverything) {
210 dirty.andSelf(mState.dirtyRegion);
Lloyd Pique32cbe282018-10-19 13:09:22 -0700211 }
212 return dirty;
213}
214
Lloyd Piquec6687342019-03-07 21:34:57 -0800215bool Output::belongsInOutput(std::optional<uint32_t> layerStackId, bool internalOnly) const {
Lloyd Piqueef36b002019-01-23 17:52:04 -0800216 // The layerStackId's must match, and also the layer must not be internal
217 // only when not on an internal output.
Lloyd Piquec6687342019-03-07 21:34:57 -0800218 return layerStackId && (*layerStackId == mState.layerStackId) &&
219 (!internalOnly || mState.layerStackInternal);
Lloyd Pique32cbe282018-10-19 13:09:22 -0700220}
221
Lloyd Piquecc01a452018-12-04 17:24:00 -0800222compositionengine::OutputLayer* Output::getOutputLayerForLayer(
223 compositionengine::Layer* layer) const {
224 for (const auto& outputLayer : mOutputLayersOrderedByZ) {
225 if (outputLayer && &outputLayer->getLayer() == layer) {
226 return outputLayer.get();
227 }
228 }
229 return nullptr;
230}
231
232std::unique_ptr<compositionengine::OutputLayer> Output::getOrCreateOutputLayer(
Lloyd Pique07e33212018-12-18 16:33:37 -0800233 std::optional<DisplayId> displayId, std::shared_ptr<compositionengine::Layer> layer,
234 sp<compositionengine::LayerFE> layerFE) {
Lloyd Piquecc01a452018-12-04 17:24:00 -0800235 for (auto& outputLayer : mOutputLayersOrderedByZ) {
236 if (outputLayer && &outputLayer->getLayer() == layer.get()) {
237 return std::move(outputLayer);
238 }
239 }
Lloyd Pique07e33212018-12-18 16:33:37 -0800240 return createOutputLayer(mCompositionEngine, displayId, *this, layer, layerFE);
Lloyd Piquecc01a452018-12-04 17:24:00 -0800241}
242
243void Output::setOutputLayersOrderedByZ(OutputLayers&& layers) {
244 mOutputLayersOrderedByZ = std::move(layers);
245}
246
247const Output::OutputLayers& Output::getOutputLayersOrderedByZ() const {
248 return mOutputLayersOrderedByZ;
249}
250
Lloyd Piquec7ef21b2019-01-29 18:43:00 -0800251void Output::setReleasedLayers(Output::ReleasedLayers&& layers) {
252 mReleasedLayers = std::move(layers);
253}
254
255Output::ReleasedLayers Output::takeReleasedLayers() {
256 return std::move(mReleasedLayers);
257}
258
Lloyd Pique3eb1b212019-03-07 21:15:40 -0800259void Output::prepare(compositionengine::CompositionRefreshArgs& refreshArgs) {
260 if (CC_LIKELY(!refreshArgs.updatingGeometryThisFrame)) {
261 return;
262 }
263
264 uint32_t zOrder = 0;
265 for (auto& layer : mOutputLayersOrderedByZ) {
266 // Assign a simple Z order sequence to each visible layer.
267 layer->editState().z = zOrder++;
268 }
269}
270
Lloyd Piqued7b429f2019-03-07 21:11:02 -0800271void Output::present(const compositionengine::CompositionRefreshArgs& refreshArgs) {
Lloyd Pique3eb1b212019-03-07 21:15:40 -0800272 updateColorProfile(refreshArgs);
273 updateAndWriteCompositionState(refreshArgs);
274 setColorTransform(refreshArgs);
Lloyd Piqued7b429f2019-03-07 21:11:02 -0800275 beginFrame();
276 prepareFrame();
277 devOptRepaintFlash(refreshArgs);
278 finishFrame(refreshArgs);
279 postFramebuffer();
280}
281
Lloyd Pique3eb1b212019-03-07 21:15:40 -0800282void Output::updateLayerStateFromFE(const CompositionRefreshArgs& args) const {
283 for (auto& layer : mOutputLayersOrderedByZ) {
284 layer->getLayerFE().latchCompositionState(layer->getLayer().editState().frontEnd,
Lloyd Piquec6687342019-03-07 21:34:57 -0800285 args.updatingGeometryThisFrame
286 ? LayerFE::StateSubset::GeometryAndContent
287 : LayerFE::StateSubset::Content);
Lloyd Pique3eb1b212019-03-07 21:15:40 -0800288 }
289}
290
291void Output::updateAndWriteCompositionState(
292 const compositionengine::CompositionRefreshArgs& refreshArgs) {
293 ATRACE_CALL();
294 ALOGV(__FUNCTION__);
295
296 for (auto& layer : mOutputLayersOrderedByZ) {
297 if (refreshArgs.devOptForceClientComposition) {
298 layer->editState().forceClientComposition = true;
299 }
300
301 layer->updateCompositionState(refreshArgs.updatingGeometryThisFrame);
302
303 // Send the updated state to the HWC, if appropriate.
304 layer->writeStateToHWC(refreshArgs.updatingGeometryThisFrame);
305 }
306}
307
Lloyd Pique6a3b4462019-03-07 20:58:12 -0800308void Output::updateColorProfile(const compositionengine::CompositionRefreshArgs& refreshArgs) {
309 setColorProfile(pickColorProfile(refreshArgs));
310}
311
312// Returns a data space that fits all visible layers. The returned data space
313// can only be one of
314// - Dataspace::SRGB (use legacy dataspace and let HWC saturate when colors are enhanced)
315// - Dataspace::DISPLAY_P3
316// - Dataspace::DISPLAY_BT2020
317// The returned HDR data space is one of
318// - Dataspace::UNKNOWN
319// - Dataspace::BT2020_HLG
320// - Dataspace::BT2020_PQ
321ui::Dataspace Output::getBestDataspace(ui::Dataspace* outHdrDataSpace,
322 bool* outIsHdrClientComposition) const {
323 ui::Dataspace bestDataSpace = ui::Dataspace::V0_SRGB;
324 *outHdrDataSpace = ui::Dataspace::UNKNOWN;
325
326 for (const auto& layer : mOutputLayersOrderedByZ) {
327 switch (layer->getLayer().getState().frontEnd.dataspace) {
328 case ui::Dataspace::V0_SCRGB:
329 case ui::Dataspace::V0_SCRGB_LINEAR:
330 case ui::Dataspace::BT2020:
331 case ui::Dataspace::BT2020_ITU:
332 case ui::Dataspace::BT2020_LINEAR:
333 case ui::Dataspace::DISPLAY_BT2020:
334 bestDataSpace = ui::Dataspace::DISPLAY_BT2020;
335 break;
336 case ui::Dataspace::DISPLAY_P3:
337 bestDataSpace = ui::Dataspace::DISPLAY_P3;
338 break;
339 case ui::Dataspace::BT2020_PQ:
340 case ui::Dataspace::BT2020_ITU_PQ:
341 bestDataSpace = ui::Dataspace::DISPLAY_P3;
342 *outHdrDataSpace = ui::Dataspace::BT2020_PQ;
343 *outIsHdrClientComposition =
344 layer->getLayer().getState().frontEnd.forceClientComposition;
345 break;
346 case ui::Dataspace::BT2020_HLG:
347 case ui::Dataspace::BT2020_ITU_HLG:
348 bestDataSpace = ui::Dataspace::DISPLAY_P3;
349 // When there's mixed PQ content and HLG content, we set the HDR
350 // data space to be BT2020_PQ and convert HLG to PQ.
351 if (*outHdrDataSpace == ui::Dataspace::UNKNOWN) {
352 *outHdrDataSpace = ui::Dataspace::BT2020_HLG;
353 }
354 break;
355 default:
356 break;
357 }
358 }
359
360 return bestDataSpace;
361}
362
363compositionengine::Output::ColorProfile Output::pickColorProfile(
364 const compositionengine::CompositionRefreshArgs& refreshArgs) const {
365 if (refreshArgs.outputColorSetting == OutputColorSetting::kUnmanaged) {
366 return ColorProfile{ui::ColorMode::NATIVE, ui::Dataspace::UNKNOWN,
367 ui::RenderIntent::COLORIMETRIC,
368 refreshArgs.colorSpaceAgnosticDataspace};
369 }
370
371 ui::Dataspace hdrDataSpace;
372 bool isHdrClientComposition = false;
373 ui::Dataspace bestDataSpace = getBestDataspace(&hdrDataSpace, &isHdrClientComposition);
374
375 switch (refreshArgs.forceOutputColorMode) {
376 case ui::ColorMode::SRGB:
377 bestDataSpace = ui::Dataspace::V0_SRGB;
378 break;
379 case ui::ColorMode::DISPLAY_P3:
380 bestDataSpace = ui::Dataspace::DISPLAY_P3;
381 break;
382 default:
383 break;
384 }
385
386 // respect hdrDataSpace only when there is no legacy HDR support
387 const bool isHdr = hdrDataSpace != ui::Dataspace::UNKNOWN &&
388 !mDisplayColorProfile->hasLegacyHdrSupport(hdrDataSpace) && !isHdrClientComposition;
389 if (isHdr) {
390 bestDataSpace = hdrDataSpace;
391 }
392
393 ui::RenderIntent intent;
394 switch (refreshArgs.outputColorSetting) {
395 case OutputColorSetting::kManaged:
396 case OutputColorSetting::kUnmanaged:
397 intent = isHdr ? ui::RenderIntent::TONE_MAP_COLORIMETRIC
398 : ui::RenderIntent::COLORIMETRIC;
399 break;
400 case OutputColorSetting::kEnhanced:
401 intent = isHdr ? ui::RenderIntent::TONE_MAP_ENHANCE : ui::RenderIntent::ENHANCE;
402 break;
403 default: // vendor display color setting
404 intent = static_cast<ui::RenderIntent>(refreshArgs.outputColorSetting);
405 break;
406 }
407
408 ui::ColorMode outMode;
409 ui::Dataspace outDataSpace;
410 ui::RenderIntent outRenderIntent;
411 mDisplayColorProfile->getBestColorMode(bestDataSpace, intent, &outDataSpace, &outMode,
412 &outRenderIntent);
413
414 return ColorProfile{outMode, outDataSpace, outRenderIntent,
415 refreshArgs.colorSpaceAgnosticDataspace};
416}
417
Lloyd Piqued0a92a02019-02-19 17:47:26 -0800418void Output::beginFrame() {
419 const bool dirty = !getDirtyRegion(false).isEmpty();
420 const bool empty = mOutputLayersOrderedByZ.empty();
421 const bool wasEmpty = !mState.lastCompositionHadVisibleLayers;
422
423 // If nothing has changed (!dirty), don't recompose.
424 // If something changed, but we don't currently have any visible layers,
425 // and didn't when we last did a composition, then skip it this time.
426 // The second rule does two things:
427 // - When all layers are removed from a display, we'll emit one black
428 // frame, then nothing more until we get new layers.
429 // - When a display is created with a private layer stack, we won't
430 // emit any black frames until a layer is added to the layer stack.
431 const bool mustRecompose = dirty && !(empty && wasEmpty);
432
433 const char flagPrefix[] = {'-', '+'};
434 static_cast<void>(flagPrefix);
435 ALOGV_IF("%s: %s composition for %s (%cdirty %cempty %cwasEmpty)", __FUNCTION__,
436 mustRecompose ? "doing" : "skipping", getName().c_str(), flagPrefix[dirty],
437 flagPrefix[empty], flagPrefix[wasEmpty]);
438
439 mRenderSurface->beginFrame(mustRecompose);
440
441 if (mustRecompose) {
442 mState.lastCompositionHadVisibleLayers = !empty;
443 }
444}
445
Lloyd Pique66d68602019-02-13 14:23:31 -0800446void Output::prepareFrame() {
447 ATRACE_CALL();
448 ALOGV(__FUNCTION__);
449
450 if (!mState.isEnabled) {
451 return;
452 }
453
454 chooseCompositionStrategy();
455
456 mRenderSurface->prepareFrame(mState.usesClientComposition, mState.usesDeviceComposition);
457}
458
Lloyd Piquef8cf14d2019-02-28 16:03:12 -0800459void Output::devOptRepaintFlash(const compositionengine::CompositionRefreshArgs& refreshArgs) {
460 if (CC_LIKELY(!refreshArgs.devOptFlashDirtyRegionsDelay)) {
461 return;
462 }
463
464 if (mState.isEnabled) {
465 // transform the dirty region into this screen's coordinate space
466 const Region dirtyRegion = getDirtyRegion(refreshArgs.repaintEverything);
467 if (!dirtyRegion.isEmpty()) {
468 base::unique_fd readyFence;
469 // redraw the whole screen
Lloyd Piqued3d69882019-02-28 16:03:46 -0800470 static_cast<void>(composeSurfaces(dirtyRegion));
Lloyd Piquef8cf14d2019-02-28 16:03:12 -0800471
472 mRenderSurface->queueBuffer(std::move(readyFence));
473 }
474 }
475
476 postFramebuffer();
477
478 std::this_thread::sleep_for(*refreshArgs.devOptFlashDirtyRegionsDelay);
479
480 prepareFrame();
481}
482
Lloyd Piqued3d69882019-02-28 16:03:46 -0800483void Output::finishFrame(const compositionengine::CompositionRefreshArgs&) {
484 ATRACE_CALL();
485 ALOGV(__FUNCTION__);
486
487 if (!mState.isEnabled) {
488 return;
489 }
490
491 // Repaint the framebuffer (if needed), getting the optional fence for when
492 // the composition completes.
493 auto optReadyFence = composeSurfaces(Region::INVALID_REGION);
494 if (!optReadyFence) {
495 return;
496 }
497
498 // swap buffers (presentation)
499 mRenderSurface->queueBuffer(std::move(*optReadyFence));
500}
501
502std::optional<base::unique_fd> Output::composeSurfaces(const Region& debugRegion) {
Lloyd Pique688abd42019-02-15 15:42:24 -0800503 ATRACE_CALL();
504 ALOGV(__FUNCTION__);
505
506 const TracedOrdinal<bool> hasClientComposition = {"hasClientComposition",
507 mState.usesClientComposition};
Lloyd Piqued3d69882019-02-28 16:03:46 -0800508 base::unique_fd readyFence;
509
Lloyd Pique688abd42019-02-15 15:42:24 -0800510 if (!hasClientComposition) {
Lloyd Piqued3d69882019-02-28 16:03:46 -0800511 return readyFence;
Lloyd Pique688abd42019-02-15 15:42:24 -0800512 }
513
514 ALOGV("hasClientComposition");
515
516 auto& renderEngine = mCompositionEngine.getRenderEngine();
517 const bool supportsProtectedContent = renderEngine.supportsProtectedContent();
518
519 renderengine::DisplaySettings clientCompositionDisplay;
Lloyd Pique810b0302019-08-14 16:09:32 -0700520 clientCompositionDisplay.physicalDisplay = mState.scissor;
Lloyd Pique688abd42019-02-15 15:42:24 -0800521 clientCompositionDisplay.clip = mState.scissor;
522 clientCompositionDisplay.globalTransform = mState.transform.asMatrix4();
523 clientCompositionDisplay.orientation = mState.orientation;
524 clientCompositionDisplay.outputDataspace =
525 mDisplayColorProfile->hasWideColorGamut() ? mState.dataspace : ui::Dataspace::UNKNOWN;
526 clientCompositionDisplay.maxLuminance =
527 mDisplayColorProfile->getHdrCapabilities().getDesiredMaxLuminance();
528
529 // Compute the global color transform matrix.
530 if (!mState.usesDeviceComposition && !getSkipColorTransform()) {
Lloyd Pique3eb1b212019-03-07 21:15:40 -0800531 clientCompositionDisplay.colorTransform = mState.colorTransformMatrix;
Lloyd Pique688abd42019-02-15 15:42:24 -0800532 }
533
534 // Note: Updated by generateClientCompositionRequests
535 clientCompositionDisplay.clearRegion = Region::INVALID_REGION;
536
537 // Generate the client composition requests for the layers on this output.
538 std::vector<renderengine::LayerSettings> clientCompositionLayers =
539 generateClientCompositionRequests(supportsProtectedContent,
540 clientCompositionDisplay.clearRegion);
541 appendRegionFlashRequests(debugRegion, clientCompositionLayers);
542
543 // If we the display is secure, protected content support is enabled, and at
544 // least one layer has protected content, we need to use a secure back
545 // buffer.
546 if (mState.isSecure && supportsProtectedContent) {
547 bool needsProtected =
548 std::any_of(mOutputLayersOrderedByZ.begin(), mOutputLayersOrderedByZ.end(),
549 [](auto& layer) {
550 return layer->getLayer().getState().frontEnd.hasProtectedContent;
551 });
552 if (needsProtected != renderEngine.isProtected()) {
553 renderEngine.useProtectedContext(needsProtected);
554 }
555 if (needsProtected != mRenderSurface->isProtected() &&
556 needsProtected == renderEngine.isProtected()) {
557 mRenderSurface->setProtected(needsProtected);
558 }
559 }
560
561 base::unique_fd fd;
562 sp<GraphicBuffer> buf = mRenderSurface->dequeueBuffer(&fd);
563 if (buf == nullptr) {
564 ALOGW("Dequeuing buffer for display [%s] failed, bailing out of "
565 "client composition for this frame",
566 mName.c_str());
Lloyd Piqued3d69882019-02-28 16:03:46 -0800567 return std::nullopt;
Lloyd Pique688abd42019-02-15 15:42:24 -0800568 }
569
570 // We boost GPU frequency here because there will be color spaces conversion
571 // and it's expensive. We boost the GPU frequency so that GPU composition can
572 // finish in time. We must reset GPU frequency afterwards, because high frequency
573 // consumes extra battery.
574 const bool expensiveRenderingExpected =
575 clientCompositionDisplay.outputDataspace == ui::Dataspace::DISPLAY_P3;
576 if (expensiveRenderingExpected) {
577 setExpensiveRenderingExpected(true);
578 }
579
580 renderEngine.drawLayers(clientCompositionDisplay, clientCompositionLayers,
581 buf->getNativeBuffer(), /*useFramebufferCache=*/true, std::move(fd),
Lloyd Piqued3d69882019-02-28 16:03:46 -0800582 &readyFence);
Lloyd Pique688abd42019-02-15 15:42:24 -0800583
584 if (expensiveRenderingExpected) {
585 setExpensiveRenderingExpected(false);
586 }
587
Lloyd Piqued3d69882019-02-28 16:03:46 -0800588 return readyFence;
Lloyd Pique688abd42019-02-15 15:42:24 -0800589}
590
591std::vector<renderengine::LayerSettings> Output::generateClientCompositionRequests(
592 bool supportsProtectedContent, Region& clearRegion) {
593 std::vector<renderengine::LayerSettings> clientCompositionLayers;
594 ALOGV("Rendering client layers");
595
596 const Region viewportRegion(mState.viewport);
597 const bool useIdentityTransform = false;
598 bool firstLayer = true;
599 // Used when a layer clears part of the buffer.
600 Region dummyRegion;
601
602 for (auto& layer : mOutputLayersOrderedByZ) {
603 const auto& layerState = layer->getState();
604 const auto& layerFEState = layer->getLayer().getState().frontEnd;
605 auto& layerFE = layer->getLayerFE();
606
Lloyd Piquea2468662019-03-07 21:31:06 -0800607 const Region clip(viewportRegion.intersect(layerState.visibleRegion));
Lloyd Pique688abd42019-02-15 15:42:24 -0800608 ALOGV("Layer: %s", layerFE.getDebugName());
609 if (clip.isEmpty()) {
610 ALOGV(" Skipping for empty clip");
611 firstLayer = false;
612 continue;
613 }
614
615 bool clientComposition = layer->requiresClientComposition();
616
617 // We clear the client target for non-client composed layers if
618 // requested by the HWC. We skip this if the layer is not an opaque
619 // rectangle, as by definition the layer must blend with whatever is
620 // underneath. We also skip the first layer as the buffer target is
621 // guaranteed to start out cleared.
622 bool clearClientComposition =
623 layerState.clearClientTarget && layerFEState.isOpaque && !firstLayer;
624
625 ALOGV(" Composition type: client %d clear %d", clientComposition, clearClientComposition);
626
627 if (clientComposition || clearClientComposition) {
628 compositionengine::LayerFE::ClientCompositionTargetSettings targetSettings{
629 clip,
630 useIdentityTransform,
631 layer->needsFiltering() || mState.needsFiltering,
632 mState.isSecure,
633 supportsProtectedContent,
634 clientComposition ? clearRegion : dummyRegion,
635 };
636 if (auto result = layerFE.prepareClientComposition(targetSettings)) {
Lloyd Piquec2d54d42019-08-28 18:04:21 -0700637 if (!clientComposition) {
Lloyd Pique688abd42019-02-15 15:42:24 -0800638 auto& layerSettings = *result;
639 layerSettings.source.buffer.buffer = nullptr;
640 layerSettings.source.solidColor = half3(0.0, 0.0, 0.0);
641 layerSettings.alpha = half(0.0);
642 layerSettings.disableBlending = true;
643 }
644
645 clientCompositionLayers.push_back(*result);
646 }
647 }
648
649 firstLayer = false;
650 }
651
652 return clientCompositionLayers;
653}
654
655void Output::appendRegionFlashRequests(
656 const Region& flashRegion,
657 std::vector<renderengine::LayerSettings>& clientCompositionLayers) {
658 if (flashRegion.isEmpty()) {
659 return;
660 }
661
662 renderengine::LayerSettings layerSettings;
663 layerSettings.source.buffer.buffer = nullptr;
664 layerSettings.source.solidColor = half3(1.0, 0.0, 1.0);
665 layerSettings.alpha = half(1.0);
666
667 for (const auto& rect : flashRegion) {
668 layerSettings.geometry.boundaries = rect.toFloatRect();
669 clientCompositionLayers.push_back(layerSettings);
670 }
671}
672
673void Output::setExpensiveRenderingExpected(bool) {
674 // The base class does nothing with this call.
675}
676
Lloyd Pique35fca9d2019-02-13 14:24:11 -0800677void Output::postFramebuffer() {
678 ATRACE_CALL();
679 ALOGV(__FUNCTION__);
680
681 if (!getState().isEnabled) {
682 return;
683 }
684
Lloyd Piqued3d69882019-02-28 16:03:46 -0800685 mState.dirtyRegion.clear();
686 mRenderSurface->flip();
687
Lloyd Pique35fca9d2019-02-13 14:24:11 -0800688 auto frame = presentAndGetFrameFences();
689
Lloyd Pique7d90ba52019-08-08 11:57:53 -0700690 mRenderSurface->onPresentDisplayCompleted();
691
Lloyd Pique35fca9d2019-02-13 14:24:11 -0800692 for (auto& layer : getOutputLayersOrderedByZ()) {
693 // The layer buffer from the previous frame (if any) is released
694 // by HWC only when the release fence from this frame (if any) is
695 // signaled. Always get the release fence from HWC first.
696 sp<Fence> releaseFence = Fence::NO_FENCE;
697
698 if (auto hwcLayer = layer->getHwcLayer()) {
699 if (auto f = frame.layerFences.find(hwcLayer); f != frame.layerFences.end()) {
700 releaseFence = f->second;
701 }
702 }
703
704 // If the layer was client composited in the previous frame, we
705 // need to merge with the previous client target acquire fence.
706 // Since we do not track that, always merge with the current
707 // client target acquire fence when it is available, even though
708 // this is suboptimal.
709 // TODO(b/121291683): Track previous frame client target acquire fence.
710 if (mState.usesClientComposition) {
711 releaseFence =
712 Fence::merge("LayerRelease", releaseFence, frame.clientTargetAcquireFence);
713 }
714
715 layer->getLayerFE().onLayerDisplayed(releaseFence);
716 }
717
718 // We've got a list of layers needing fences, that are disjoint with
719 // getOutputLayersOrderedByZ. The best we can do is to
720 // supply them with the present fence.
721 for (auto& weakLayer : mReleasedLayers) {
722 if (auto layer = weakLayer.promote(); layer != nullptr) {
723 layer->onLayerDisplayed(frame.presentFence);
724 }
725 }
726
727 // Clear out the released layers now that we're done with them.
728 mReleasedLayers.clear();
729}
730
Lloyd Pique32cbe282018-10-19 13:09:22 -0700731void Output::dirtyEntireOutput() {
732 mState.dirtyRegion.set(mState.bounds);
733}
734
Lloyd Pique66d68602019-02-13 14:23:31 -0800735void Output::chooseCompositionStrategy() {
736 // The base output implementation can only do client composition
737 mState.usesClientComposition = true;
738 mState.usesDeviceComposition = false;
739}
740
Lloyd Pique688abd42019-02-15 15:42:24 -0800741bool Output::getSkipColorTransform() const {
742 return true;
743}
744
Lloyd Pique35fca9d2019-02-13 14:24:11 -0800745compositionengine::Output::FrameFences Output::presentAndGetFrameFences() {
746 compositionengine::Output::FrameFences result;
747 if (mState.usesClientComposition) {
748 result.clientTargetAcquireFence = mRenderSurface->getClientTargetAcquireFence();
749 }
750 return result;
751}
752
Lloyd Piquefeb73d72018-12-04 17:23:44 -0800753} // namespace impl
754} // namespace android::compositionengine