| Lloyd Pique | 32cbe28 | 2018-10-19 13:09:22 -0700 | [diff] [blame] | 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 |  | 
| Lloyd Pique | f8cf14d | 2019-02-28 16:03:12 -0800 | [diff] [blame] | 17 | #include <thread> | 
 | 18 |  | 
| Lloyd Pique | 32cbe28 | 2018-10-19 13:09:22 -0700 | [diff] [blame] | 19 | #include <android-base/stringprintf.h> | 
 | 20 | #include <compositionengine/CompositionEngine.h> | 
| Lloyd Pique | f8cf14d | 2019-02-28 16:03:12 -0800 | [diff] [blame] | 21 | #include <compositionengine/CompositionRefreshArgs.h> | 
| Lloyd Pique | 3d0c02e | 2018-10-19 18:38:12 -0700 | [diff] [blame] | 22 | #include <compositionengine/DisplayColorProfile.h> | 
| Lloyd Pique | cc01a45 | 2018-12-04 17:24:00 -0800 | [diff] [blame] | 23 | #include <compositionengine/LayerFE.h> | 
| Lloyd Pique | 9755fb7 | 2019-03-26 14:44:40 -0700 | [diff] [blame] | 24 | #include <compositionengine/LayerFECompositionState.h> | 
| Lloyd Pique | 31cb294 | 2018-10-19 17:23:03 -0700 | [diff] [blame] | 25 | #include <compositionengine/RenderSurface.h> | 
| Lloyd Pique | 32cbe28 | 2018-10-19 13:09:22 -0700 | [diff] [blame] | 26 | #include <compositionengine/impl/Output.h> | 
| Lloyd Pique | a38ea7e | 2019-04-16 18:10:26 -0700 | [diff] [blame] | 27 | #include <compositionengine/impl/OutputCompositionState.h> | 
| Lloyd Pique | cc01a45 | 2018-12-04 17:24:00 -0800 | [diff] [blame] | 28 | #include <compositionengine/impl/OutputLayer.h> | 
| Lloyd Pique | a38ea7e | 2019-04-16 18:10:26 -0700 | [diff] [blame] | 29 | #include <compositionengine/impl/OutputLayerCompositionState.h> | 
| Lloyd Pique | 3b5a69e | 2020-01-16 17:51:01 -0800 | [diff] [blame] | 30 |  | 
 | 31 | // TODO(b/129481165): remove the #pragma below and fix conversion issues | 
 | 32 | #pragma clang diagnostic push | 
 | 33 | #pragma clang diagnostic ignored "-Wconversion" | 
 | 34 |  | 
| Lloyd Pique | 688abd4 | 2019-02-15 15:42:24 -0800 | [diff] [blame] | 35 | #include <renderengine/DisplaySettings.h> | 
 | 36 | #include <renderengine/RenderEngine.h> | 
| Lloyd Pique | 3b5a69e | 2020-01-16 17:51:01 -0800 | [diff] [blame] | 37 |  | 
 | 38 | // TODO(b/129481165): remove the #pragma below and fix conversion issues | 
 | 39 | #pragma clang diagnostic pop // ignored "-Wconversion" | 
 | 40 |  | 
| Lloyd Pique | 32cbe28 | 2018-10-19 13:09:22 -0700 | [diff] [blame] | 41 | #include <ui/DebugUtils.h> | 
| Lloyd Pique | 688abd4 | 2019-02-15 15:42:24 -0800 | [diff] [blame] | 42 | #include <ui/HdrCapabilities.h> | 
| Lloyd Pique | 66d6860 | 2019-02-13 14:23:31 -0800 | [diff] [blame] | 43 | #include <utils/Trace.h> | 
| Lloyd Pique | 32cbe28 | 2018-10-19 13:09:22 -0700 | [diff] [blame] | 44 |  | 
| Lloyd Pique | 688abd4 | 2019-02-15 15:42:24 -0800 | [diff] [blame] | 45 | #include "TracedOrdinal.h" | 
| Lloyd Pique | 32cbe28 | 2018-10-19 13:09:22 -0700 | [diff] [blame] | 46 |  | 
| Lloyd Pique | feb73d7 | 2018-12-04 17:23:44 -0800 | [diff] [blame] | 47 | namespace android::compositionengine { | 
 | 48 |  | 
 | 49 | Output::~Output() = default; | 
 | 50 |  | 
 | 51 | namespace impl { | 
| Lloyd Pique | 32cbe28 | 2018-10-19 13:09:22 -0700 | [diff] [blame] | 52 |  | 
| Lloyd Pique | c29e4c6 | 2019-03-07 21:48:19 -0800 | [diff] [blame] | 53 | namespace { | 
 | 54 |  | 
 | 55 | template <typename T> | 
 | 56 | class Reversed { | 
 | 57 | public: | 
 | 58 |     explicit Reversed(const T& container) : mContainer(container) {} | 
 | 59 |     auto begin() { return mContainer.rbegin(); } | 
 | 60 |     auto end() { return mContainer.rend(); } | 
 | 61 |  | 
 | 62 | private: | 
 | 63 |     const T& mContainer; | 
 | 64 | }; | 
 | 65 |  | 
 | 66 | // Helper for enumerating over a container in reverse order | 
 | 67 | template <typename T> | 
 | 68 | Reversed<T> reversed(const T& c) { | 
 | 69 |     return Reversed<T>(c); | 
 | 70 | } | 
 | 71 |  | 
 | 72 | } // namespace | 
 | 73 |  | 
| Lloyd Pique | a38ea7e | 2019-04-16 18:10:26 -0700 | [diff] [blame] | 74 | std::shared_ptr<Output> createOutput( | 
 | 75 |         const compositionengine::CompositionEngine& compositionEngine) { | 
 | 76 |     return createOutputTemplated<Output>(compositionEngine); | 
 | 77 | } | 
| Lloyd Pique | 32cbe28 | 2018-10-19 13:09:22 -0700 | [diff] [blame] | 78 |  | 
 | 79 | Output::~Output() = default; | 
 | 80 |  | 
| Lloyd Pique | 32cbe28 | 2018-10-19 13:09:22 -0700 | [diff] [blame] | 81 | bool Output::isValid() const { | 
| Lloyd Pique | 3d0c02e | 2018-10-19 18:38:12 -0700 | [diff] [blame] | 82 |     return mDisplayColorProfile && mDisplayColorProfile->isValid() && mRenderSurface && | 
 | 83 |             mRenderSurface->isValid(); | 
| Lloyd Pique | 32cbe28 | 2018-10-19 13:09:22 -0700 | [diff] [blame] | 84 | } | 
 | 85 |  | 
| Lloyd Pique | 6c564cf | 2019-05-17 17:31:36 -0700 | [diff] [blame] | 86 | std::optional<DisplayId> Output::getDisplayId() const { | 
 | 87 |     return {}; | 
 | 88 | } | 
 | 89 |  | 
| Lloyd Pique | 32cbe28 | 2018-10-19 13:09:22 -0700 | [diff] [blame] | 90 | const std::string& Output::getName() const { | 
 | 91 |     return mName; | 
 | 92 | } | 
 | 93 |  | 
 | 94 | void Output::setName(const std::string& name) { | 
 | 95 |     mName = name; | 
 | 96 | } | 
 | 97 |  | 
 | 98 | void Output::setCompositionEnabled(bool enabled) { | 
| Lloyd Pique | a38ea7e | 2019-04-16 18:10:26 -0700 | [diff] [blame] | 99 |     auto& outputState = editState(); | 
 | 100 |     if (outputState.isEnabled == enabled) { | 
| Lloyd Pique | 32cbe28 | 2018-10-19 13:09:22 -0700 | [diff] [blame] | 101 |         return; | 
 | 102 |     } | 
 | 103 |  | 
| Lloyd Pique | a38ea7e | 2019-04-16 18:10:26 -0700 | [diff] [blame] | 104 |     outputState.isEnabled = enabled; | 
| Lloyd Pique | 32cbe28 | 2018-10-19 13:09:22 -0700 | [diff] [blame] | 105 |     dirtyEntireOutput(); | 
 | 106 | } | 
 | 107 |  | 
| Lloyd Pique | 0a45623 | 2020-01-16 17:51:13 -0800 | [diff] [blame] | 108 | void Output::setProjection(const ui::Transform& transform, uint32_t orientation, const Rect& frame, | 
| Lloyd Pique | e8fe474 | 2020-01-21 15:26:18 -0800 | [diff] [blame] | 109 |                            const Rect& viewport, const Rect& sourceClip, | 
 | 110 |                            const Rect& destinationClip, bool needsFiltering) { | 
| Lloyd Pique | a38ea7e | 2019-04-16 18:10:26 -0700 | [diff] [blame] | 111 |     auto& outputState = editState(); | 
 | 112 |     outputState.transform = transform; | 
 | 113 |     outputState.orientation = orientation; | 
| Lloyd Pique | e8fe474 | 2020-01-21 15:26:18 -0800 | [diff] [blame] | 114 |     outputState.sourceClip = sourceClip; | 
 | 115 |     outputState.destinationClip = destinationClip; | 
| Lloyd Pique | a38ea7e | 2019-04-16 18:10:26 -0700 | [diff] [blame] | 116 |     outputState.frame = frame; | 
 | 117 |     outputState.viewport = viewport; | 
 | 118 |     outputState.needsFiltering = needsFiltering; | 
| Lloyd Pique | 32cbe28 | 2018-10-19 13:09:22 -0700 | [diff] [blame] | 119 |  | 
 | 120 |     dirtyEntireOutput(); | 
 | 121 | } | 
 | 122 |  | 
| Lloyd Pique | 688abd4 | 2019-02-15 15:42:24 -0800 | [diff] [blame] | 123 | // TODO(b/121291683): Rename setSize() once more is moved. | 
| Lloyd Pique | 31cb294 | 2018-10-19 17:23:03 -0700 | [diff] [blame] | 124 | void Output::setBounds(const ui::Size& size) { | 
 | 125 |     mRenderSurface->setDisplaySize(size); | 
| Lloyd Pique | a38ea7e | 2019-04-16 18:10:26 -0700 | [diff] [blame] | 126 |     // TODO(b/121291683): Rename outputState.size once more is moved. | 
 | 127 |     editState().bounds = Rect(mRenderSurface->getSize()); | 
| Lloyd Pique | 32cbe28 | 2018-10-19 13:09:22 -0700 | [diff] [blame] | 128 |  | 
 | 129 |     dirtyEntireOutput(); | 
 | 130 | } | 
 | 131 |  | 
| Lloyd Pique | ef36b00 | 2019-01-23 17:52:04 -0800 | [diff] [blame] | 132 | void Output::setLayerStackFilter(uint32_t layerStackId, bool isInternal) { | 
| Lloyd Pique | a38ea7e | 2019-04-16 18:10:26 -0700 | [diff] [blame] | 133 |     auto& outputState = editState(); | 
 | 134 |     outputState.layerStackId = layerStackId; | 
 | 135 |     outputState.layerStackInternal = isInternal; | 
| Lloyd Pique | 32cbe28 | 2018-10-19 13:09:22 -0700 | [diff] [blame] | 136 |  | 
 | 137 |     dirtyEntireOutput(); | 
 | 138 | } | 
 | 139 |  | 
| Lloyd Pique | 3eb1b21 | 2019-03-07 21:15:40 -0800 | [diff] [blame] | 140 | void Output::setColorTransform(const compositionengine::CompositionRefreshArgs& args) { | 
| Lloyd Pique | a38ea7e | 2019-04-16 18:10:26 -0700 | [diff] [blame] | 141 |     auto& colorTransformMatrix = editState().colorTransformMatrix; | 
 | 142 |     if (!args.colorTransformMatrix || colorTransformMatrix == args.colorTransformMatrix) { | 
| Lloyd Pique | 77f79a2 | 2019-04-29 15:55:40 -0700 | [diff] [blame] | 143 |         return; | 
 | 144 |     } | 
 | 145 |  | 
| Lloyd Pique | a38ea7e | 2019-04-16 18:10:26 -0700 | [diff] [blame] | 146 |     colorTransformMatrix = *args.colorTransformMatrix; | 
| Lloyd Pique | ef95812 | 2019-02-05 18:00:12 -0800 | [diff] [blame] | 147 |  | 
 | 148 |     dirtyEntireOutput(); | 
| Lloyd Pique | 32cbe28 | 2018-10-19 13:09:22 -0700 | [diff] [blame] | 149 | } | 
 | 150 |  | 
| Lloyd Pique | 6a3b446 | 2019-03-07 20:58:12 -0800 | [diff] [blame] | 151 | void Output::setColorProfile(const ColorProfile& colorProfile) { | 
| Lloyd Pique | a38ea7e | 2019-04-16 18:10:26 -0700 | [diff] [blame] | 152 |     ui::Dataspace targetDataspace = | 
| Lloyd Pique | 6a3b446 | 2019-03-07 20:58:12 -0800 | [diff] [blame] | 153 |             getDisplayColorProfile()->getTargetDataspace(colorProfile.mode, colorProfile.dataspace, | 
 | 154 |                                                          colorProfile.colorSpaceAgnosticDataspace); | 
| Lloyd Pique | f527548 | 2019-01-29 18:42:42 -0800 | [diff] [blame] | 155 |  | 
| Lloyd Pique | a38ea7e | 2019-04-16 18:10:26 -0700 | [diff] [blame] | 156 |     auto& outputState = editState(); | 
 | 157 |     if (outputState.colorMode == colorProfile.mode && | 
 | 158 |         outputState.dataspace == colorProfile.dataspace && | 
 | 159 |         outputState.renderIntent == colorProfile.renderIntent && | 
 | 160 |         outputState.targetDataspace == targetDataspace) { | 
| Lloyd Pique | ef95812 | 2019-02-05 18:00:12 -0800 | [diff] [blame] | 161 |         return; | 
 | 162 |     } | 
 | 163 |  | 
| Lloyd Pique | a38ea7e | 2019-04-16 18:10:26 -0700 | [diff] [blame] | 164 |     outputState.colorMode = colorProfile.mode; | 
 | 165 |     outputState.dataspace = colorProfile.dataspace; | 
 | 166 |     outputState.renderIntent = colorProfile.renderIntent; | 
 | 167 |     outputState.targetDataspace = targetDataspace; | 
| Lloyd Pique | 32cbe28 | 2018-10-19 13:09:22 -0700 | [diff] [blame] | 168 |  | 
| Lloyd Pique | 6a3b446 | 2019-03-07 20:58:12 -0800 | [diff] [blame] | 169 |     mRenderSurface->setBufferDataspace(colorProfile.dataspace); | 
| Lloyd Pique | 31cb294 | 2018-10-19 17:23:03 -0700 | [diff] [blame] | 170 |  | 
| Lloyd Pique | 32cbe28 | 2018-10-19 13:09:22 -0700 | [diff] [blame] | 171 |     ALOGV("Set active color mode: %s (%d), active render intent: %s (%d)", | 
| Lloyd Pique | 6a3b446 | 2019-03-07 20:58:12 -0800 | [diff] [blame] | 172 |           decodeColorMode(colorProfile.mode).c_str(), colorProfile.mode, | 
 | 173 |           decodeRenderIntent(colorProfile.renderIntent).c_str(), colorProfile.renderIntent); | 
| Lloyd Pique | ef95812 | 2019-02-05 18:00:12 -0800 | [diff] [blame] | 174 |  | 
 | 175 |     dirtyEntireOutput(); | 
| Lloyd Pique | 32cbe28 | 2018-10-19 13:09:22 -0700 | [diff] [blame] | 176 | } | 
 | 177 |  | 
 | 178 | void Output::dump(std::string& out) const { | 
 | 179 |     using android::base::StringAppendF; | 
 | 180 |  | 
 | 181 |     StringAppendF(&out, "   Composition Output State: [\"%s\"]", mName.c_str()); | 
 | 182 |  | 
 | 183 |     out.append("\n   "); | 
 | 184 |  | 
 | 185 |     dumpBase(out); | 
 | 186 | } | 
 | 187 |  | 
 | 188 | void Output::dumpBase(std::string& out) const { | 
| Lloyd Pique | a38ea7e | 2019-04-16 18:10:26 -0700 | [diff] [blame] | 189 |     dumpState(out); | 
| Lloyd Pique | 31cb294 | 2018-10-19 17:23:03 -0700 | [diff] [blame] | 190 |  | 
| Lloyd Pique | 3d0c02e | 2018-10-19 18:38:12 -0700 | [diff] [blame] | 191 |     if (mDisplayColorProfile) { | 
 | 192 |         mDisplayColorProfile->dump(out); | 
 | 193 |     } else { | 
 | 194 |         out.append("    No display color profile!\n"); | 
 | 195 |     } | 
 | 196 |  | 
| Lloyd Pique | 31cb294 | 2018-10-19 17:23:03 -0700 | [diff] [blame] | 197 |     if (mRenderSurface) { | 
 | 198 |         mRenderSurface->dump(out); | 
 | 199 |     } else { | 
 | 200 |         out.append("    No render surface!\n"); | 
 | 201 |     } | 
| Lloyd Pique | 37c2c9b | 2018-12-04 17:25:10 -0800 | [diff] [blame] | 202 |  | 
| Lloyd Pique | 01c77c1 | 2019-04-17 12:48:32 -0700 | [diff] [blame] | 203 |     android::base::StringAppendF(&out, "\n   %zu Layers\n", getOutputLayerCount()); | 
 | 204 |     for (const auto* outputLayer : getOutputLayersOrderedByZ()) { | 
| Lloyd Pique | 37c2c9b | 2018-12-04 17:25:10 -0800 | [diff] [blame] | 205 |         if (!outputLayer) { | 
 | 206 |             continue; | 
 | 207 |         } | 
 | 208 |         outputLayer->dump(out); | 
 | 209 |     } | 
| Lloyd Pique | 31cb294 | 2018-10-19 17:23:03 -0700 | [diff] [blame] | 210 | } | 
 | 211 |  | 
| Lloyd Pique | 3d0c02e | 2018-10-19 18:38:12 -0700 | [diff] [blame] | 212 | compositionengine::DisplayColorProfile* Output::getDisplayColorProfile() const { | 
 | 213 |     return mDisplayColorProfile.get(); | 
 | 214 | } | 
 | 215 |  | 
 | 216 | void Output::setDisplayColorProfile(std::unique_ptr<compositionengine::DisplayColorProfile> mode) { | 
 | 217 |     mDisplayColorProfile = std::move(mode); | 
 | 218 | } | 
 | 219 |  | 
| Lloyd Pique | c29e4c6 | 2019-03-07 21:48:19 -0800 | [diff] [blame] | 220 | const Output::ReleasedLayers& Output::getReleasedLayersForTest() const { | 
 | 221 |     return mReleasedLayers; | 
 | 222 | } | 
 | 223 |  | 
| Lloyd Pique | 3d0c02e | 2018-10-19 18:38:12 -0700 | [diff] [blame] | 224 | void Output::setDisplayColorProfileForTest( | 
 | 225 |         std::unique_ptr<compositionengine::DisplayColorProfile> mode) { | 
 | 226 |     mDisplayColorProfile = std::move(mode); | 
 | 227 | } | 
 | 228 |  | 
| Lloyd Pique | 31cb294 | 2018-10-19 17:23:03 -0700 | [diff] [blame] | 229 | compositionengine::RenderSurface* Output::getRenderSurface() const { | 
 | 230 |     return mRenderSurface.get(); | 
 | 231 | } | 
 | 232 |  | 
 | 233 | void Output::setRenderSurface(std::unique_ptr<compositionengine::RenderSurface> surface) { | 
 | 234 |     mRenderSurface = std::move(surface); | 
| Lloyd Pique | a38ea7e | 2019-04-16 18:10:26 -0700 | [diff] [blame] | 235 |     editState().bounds = Rect(mRenderSurface->getSize()); | 
| Lloyd Pique | 31cb294 | 2018-10-19 17:23:03 -0700 | [diff] [blame] | 236 |  | 
 | 237 |     dirtyEntireOutput(); | 
 | 238 | } | 
 | 239 |  | 
| Vishnu Nair | 9b079a2 | 2020-01-21 14:36:08 -0800 | [diff] [blame] | 240 | void Output::cacheClientCompositionRequests(uint32_t cacheSize) { | 
 | 241 |     if (cacheSize == 0) { | 
 | 242 |         mClientCompositionRequestCache.reset(); | 
 | 243 |     } else { | 
 | 244 |         mClientCompositionRequestCache = std::make_unique<ClientCompositionRequestCache>(cacheSize); | 
 | 245 |     } | 
 | 246 | }; | 
 | 247 |  | 
| Lloyd Pique | 31cb294 | 2018-10-19 17:23:03 -0700 | [diff] [blame] | 248 | void Output::setRenderSurfaceForTest(std::unique_ptr<compositionengine::RenderSurface> surface) { | 
 | 249 |     mRenderSurface = std::move(surface); | 
| Lloyd Pique | 32cbe28 | 2018-10-19 13:09:22 -0700 | [diff] [blame] | 250 | } | 
 | 251 |  | 
| Alec Mouri | e7d1d4a | 2019-02-05 01:13:46 +0000 | [diff] [blame] | 252 | Region Output::getDirtyRegion(bool repaintEverything) const { | 
| Lloyd Pique | a38ea7e | 2019-04-16 18:10:26 -0700 | [diff] [blame] | 253 |     const auto& outputState = getState(); | 
 | 254 |     Region dirty(outputState.viewport); | 
| Alec Mouri | e7d1d4a | 2019-02-05 01:13:46 +0000 | [diff] [blame] | 255 |     if (!repaintEverything) { | 
| Lloyd Pique | a38ea7e | 2019-04-16 18:10:26 -0700 | [diff] [blame] | 256 |         dirty.andSelf(outputState.dirtyRegion); | 
| Lloyd Pique | 32cbe28 | 2018-10-19 13:09:22 -0700 | [diff] [blame] | 257 |     } | 
 | 258 |     return dirty; | 
 | 259 | } | 
 | 260 |  | 
| Lloyd Pique | c668734 | 2019-03-07 21:34:57 -0800 | [diff] [blame] | 261 | bool Output::belongsInOutput(std::optional<uint32_t> layerStackId, bool internalOnly) const { | 
| Lloyd Pique | ef36b00 | 2019-01-23 17:52:04 -0800 | [diff] [blame] | 262 |     // The layerStackId's must match, and also the layer must not be internal | 
 | 263 |     // only when not on an internal output. | 
| Lloyd Pique | a38ea7e | 2019-04-16 18:10:26 -0700 | [diff] [blame] | 264 |     const auto& outputState = getState(); | 
 | 265 |     return layerStackId && (*layerStackId == outputState.layerStackId) && | 
 | 266 |             (!internalOnly || outputState.layerStackInternal); | 
| Lloyd Pique | 32cbe28 | 2018-10-19 13:09:22 -0700 | [diff] [blame] | 267 | } | 
 | 268 |  | 
| Lloyd Pique | de19665 | 2020-01-22 17:29:58 -0800 | [diff] [blame] | 269 | bool Output::belongsInOutput(const sp<compositionengine::LayerFE>& layerFE) const { | 
 | 270 |     const auto* layerFEState = layerFE->getCompositionState(); | 
 | 271 |     return layerFEState && belongsInOutput(layerFEState->layerStackId, layerFEState->internalOnly); | 
| Lloyd Pique | 66c20c4 | 2019-03-07 21:44:02 -0800 | [diff] [blame] | 272 | } | 
 | 273 |  | 
| Lloyd Pique | df336d9 | 2019-03-07 21:38:42 -0800 | [diff] [blame] | 274 | std::unique_ptr<compositionengine::OutputLayer> Output::createOutputLayer( | 
| Lloyd Pique | de19665 | 2020-01-22 17:29:58 -0800 | [diff] [blame] | 275 |         const sp<LayerFE>& layerFE) const { | 
 | 276 |     return impl::createOutputLayer(*this, layerFE); | 
| Lloyd Pique | cc01a45 | 2018-12-04 17:24:00 -0800 | [diff] [blame] | 277 | } | 
 | 278 |  | 
| Lloyd Pique | de19665 | 2020-01-22 17:29:58 -0800 | [diff] [blame] | 279 | compositionengine::OutputLayer* Output::getOutputLayerForLayer(const sp<LayerFE>& layerFE) const { | 
 | 280 |     auto index = findCurrentOutputLayerForLayer(layerFE); | 
| Lloyd Pique | 01c77c1 | 2019-04-17 12:48:32 -0700 | [diff] [blame] | 281 |     return index ? getOutputLayerOrderedByZByIndex(*index) : nullptr; | 
| Lloyd Pique | cc01a45 | 2018-12-04 17:24:00 -0800 | [diff] [blame] | 282 | } | 
 | 283 |  | 
| Lloyd Pique | 01c77c1 | 2019-04-17 12:48:32 -0700 | [diff] [blame] | 284 | std::optional<size_t> Output::findCurrentOutputLayerForLayer( | 
| Lloyd Pique | de19665 | 2020-01-22 17:29:58 -0800 | [diff] [blame] | 285 |         const sp<compositionengine::LayerFE>& layer) const { | 
| Lloyd Pique | 01c77c1 | 2019-04-17 12:48:32 -0700 | [diff] [blame] | 286 |     for (size_t i = 0; i < getOutputLayerCount(); i++) { | 
 | 287 |         auto outputLayer = getOutputLayerOrderedByZByIndex(i); | 
| Lloyd Pique | de19665 | 2020-01-22 17:29:58 -0800 | [diff] [blame] | 288 |         if (outputLayer && &outputLayer->getLayerFE() == layer.get()) { | 
| Lloyd Pique | 01c77c1 | 2019-04-17 12:48:32 -0700 | [diff] [blame] | 289 |             return i; | 
| Lloyd Pique | cc01a45 | 2018-12-04 17:24:00 -0800 | [diff] [blame] | 290 |         } | 
 | 291 |     } | 
| Lloyd Pique | 01c77c1 | 2019-04-17 12:48:32 -0700 | [diff] [blame] | 292 |     return std::nullopt; | 
| Lloyd Pique | cc01a45 | 2018-12-04 17:24:00 -0800 | [diff] [blame] | 293 | } | 
 | 294 |  | 
| Lloyd Pique | c7ef21b | 2019-01-29 18:43:00 -0800 | [diff] [blame] | 295 | void Output::setReleasedLayers(Output::ReleasedLayers&& layers) { | 
 | 296 |     mReleasedLayers = std::move(layers); | 
 | 297 | } | 
 | 298 |  | 
| Lloyd Pique | c29e4c6 | 2019-03-07 21:48:19 -0800 | [diff] [blame] | 299 | void Output::prepare(const compositionengine::CompositionRefreshArgs& refreshArgs, | 
 | 300 |                      LayerFESet& geomSnapshots) { | 
 | 301 |     ATRACE_CALL(); | 
 | 302 |     ALOGV(__FUNCTION__); | 
| Lloyd Pique | 3eb1b21 | 2019-03-07 21:15:40 -0800 | [diff] [blame] | 303 |  | 
| Lloyd Pique | c29e4c6 | 2019-03-07 21:48:19 -0800 | [diff] [blame] | 304 |     rebuildLayerStacks(refreshArgs, geomSnapshots); | 
| Lloyd Pique | 3eb1b21 | 2019-03-07 21:15:40 -0800 | [diff] [blame] | 305 | } | 
 | 306 |  | 
| Lloyd Pique | d7b429f | 2019-03-07 21:11:02 -0800 | [diff] [blame] | 307 | void Output::present(const compositionengine::CompositionRefreshArgs& refreshArgs) { | 
| Lloyd Pique | c29e4c6 | 2019-03-07 21:48:19 -0800 | [diff] [blame] | 308 |     ATRACE_CALL(); | 
 | 309 |     ALOGV(__FUNCTION__); | 
 | 310 |  | 
| Lloyd Pique | 3eb1b21 | 2019-03-07 21:15:40 -0800 | [diff] [blame] | 311 |     updateColorProfile(refreshArgs); | 
 | 312 |     updateAndWriteCompositionState(refreshArgs); | 
 | 313 |     setColorTransform(refreshArgs); | 
| Lloyd Pique | d7b429f | 2019-03-07 21:11:02 -0800 | [diff] [blame] | 314 |     beginFrame(); | 
 | 315 |     prepareFrame(); | 
 | 316 |     devOptRepaintFlash(refreshArgs); | 
 | 317 |     finishFrame(refreshArgs); | 
 | 318 |     postFramebuffer(); | 
 | 319 | } | 
 | 320 |  | 
| Lloyd Pique | c29e4c6 | 2019-03-07 21:48:19 -0800 | [diff] [blame] | 321 | void Output::rebuildLayerStacks(const compositionengine::CompositionRefreshArgs& refreshArgs, | 
 | 322 |                                 LayerFESet& layerFESet) { | 
 | 323 |     ATRACE_CALL(); | 
 | 324 |     ALOGV(__FUNCTION__); | 
 | 325 |  | 
| Lloyd Pique | a38ea7e | 2019-04-16 18:10:26 -0700 | [diff] [blame] | 326 |     auto& outputState = editState(); | 
 | 327 |  | 
| Lloyd Pique | c29e4c6 | 2019-03-07 21:48:19 -0800 | [diff] [blame] | 328 |     // Do nothing if this output is not enabled or there is no need to perform this update | 
| Lloyd Pique | a38ea7e | 2019-04-16 18:10:26 -0700 | [diff] [blame] | 329 |     if (!outputState.isEnabled || CC_LIKELY(!refreshArgs.updatingOutputGeometryThisFrame)) { | 
| Lloyd Pique | c29e4c6 | 2019-03-07 21:48:19 -0800 | [diff] [blame] | 330 |         return; | 
 | 331 |     } | 
 | 332 |  | 
 | 333 |     // Process the layers to determine visibility and coverage | 
 | 334 |     compositionengine::Output::CoverageState coverage{layerFESet}; | 
 | 335 |     collectVisibleLayers(refreshArgs, coverage); | 
 | 336 |  | 
 | 337 |     // Compute the resulting coverage for this output, and store it for later | 
| Lloyd Pique | a38ea7e | 2019-04-16 18:10:26 -0700 | [diff] [blame] | 338 |     const ui::Transform& tr = outputState.transform; | 
 | 339 |     Region undefinedRegion{outputState.bounds}; | 
| Lloyd Pique | c29e4c6 | 2019-03-07 21:48:19 -0800 | [diff] [blame] | 340 |     undefinedRegion.subtractSelf(tr.transform(coverage.aboveOpaqueLayers)); | 
 | 341 |  | 
| Lloyd Pique | a38ea7e | 2019-04-16 18:10:26 -0700 | [diff] [blame] | 342 |     outputState.undefinedRegion = undefinedRegion; | 
 | 343 |     outputState.dirtyRegion.orSelf(coverage.dirtyRegion); | 
| Lloyd Pique | c29e4c6 | 2019-03-07 21:48:19 -0800 | [diff] [blame] | 344 | } | 
 | 345 |  | 
 | 346 | void Output::collectVisibleLayers(const compositionengine::CompositionRefreshArgs& refreshArgs, | 
 | 347 |                                   compositionengine::Output::CoverageState& coverage) { | 
| Lloyd Pique | c29e4c6 | 2019-03-07 21:48:19 -0800 | [diff] [blame] | 348 |     // Evaluate the layers from front to back to determine what is visible. This | 
 | 349 |     // also incrementally calculates the coverage information for each layer as | 
 | 350 |     // well as the entire output. | 
| Lloyd Pique | de19665 | 2020-01-22 17:29:58 -0800 | [diff] [blame] | 351 |     for (auto layer : reversed(refreshArgs.layers)) { | 
| Lloyd Pique | 01c77c1 | 2019-04-17 12:48:32 -0700 | [diff] [blame] | 352 |         // Incrementally process the coverage for each layer | 
 | 353 |         ensureOutputLayerIfVisible(layer, coverage); | 
| Lloyd Pique | c29e4c6 | 2019-03-07 21:48:19 -0800 | [diff] [blame] | 354 |  | 
 | 355 |         // TODO(b/121291683): Stop early if the output is completely covered and | 
 | 356 |         // no more layers could even be visible underneath the ones on top. | 
 | 357 |     } | 
 | 358 |  | 
| Lloyd Pique | 01c77c1 | 2019-04-17 12:48:32 -0700 | [diff] [blame] | 359 |     setReleasedLayers(refreshArgs); | 
 | 360 |  | 
 | 361 |     finalizePendingOutputLayers(); | 
| Lloyd Pique | c29e4c6 | 2019-03-07 21:48:19 -0800 | [diff] [blame] | 362 |  | 
 | 363 |     // Generate a simple Z-order values to each visible output layer | 
 | 364 |     uint32_t zOrder = 0; | 
| Lloyd Pique | 01c77c1 | 2019-04-17 12:48:32 -0700 | [diff] [blame] | 365 |     for (auto* outputLayer : getOutputLayersOrderedByZ()) { | 
| Lloyd Pique | c29e4c6 | 2019-03-07 21:48:19 -0800 | [diff] [blame] | 366 |         outputLayer->editState().z = zOrder++; | 
 | 367 |     } | 
| Lloyd Pique | c29e4c6 | 2019-03-07 21:48:19 -0800 | [diff] [blame] | 368 | } | 
 | 369 |  | 
| Lloyd Pique | de19665 | 2020-01-22 17:29:58 -0800 | [diff] [blame] | 370 | void Output::ensureOutputLayerIfVisible(sp<compositionengine::LayerFE>& layerFE, | 
| Lloyd Pique | 01c77c1 | 2019-04-17 12:48:32 -0700 | [diff] [blame] | 371 |                                         compositionengine::Output::CoverageState& coverage) { | 
| Lloyd Pique | c29e4c6 | 2019-03-07 21:48:19 -0800 | [diff] [blame] | 372 |     // Ensure we have a snapshot of the basic geometry layer state. Limit the | 
 | 373 |     // snapshots to once per frame for each candidate layer, as layers may | 
 | 374 |     // appear on multiple outputs. | 
 | 375 |     if (!coverage.latchedLayers.count(layerFE)) { | 
 | 376 |         coverage.latchedLayers.insert(layerFE); | 
| Lloyd Pique | de19665 | 2020-01-22 17:29:58 -0800 | [diff] [blame] | 377 |         layerFE->prepareCompositionState(compositionengine::LayerFE::StateSubset::BasicGeometry); | 
| Lloyd Pique | c29e4c6 | 2019-03-07 21:48:19 -0800 | [diff] [blame] | 378 |     } | 
 | 379 |  | 
| Lloyd Pique | c29e4c6 | 2019-03-07 21:48:19 -0800 | [diff] [blame] | 380 |     // Only consider the layers on the given layer stack | 
| Lloyd Pique | de19665 | 2020-01-22 17:29:58 -0800 | [diff] [blame] | 381 |     if (!belongsInOutput(layerFE)) { | 
 | 382 |         return; | 
 | 383 |     } | 
 | 384 |  | 
 | 385 |     // Obtain a read-only pointer to the front-end layer state | 
 | 386 |     const auto* layerFEState = layerFE->getCompositionState(); | 
 | 387 |     if (CC_UNLIKELY(!layerFEState)) { | 
 | 388 |         return; | 
 | 389 |     } | 
 | 390 |  | 
 | 391 |     // handle hidden surfaces by setting the visible region to empty | 
 | 392 |     if (CC_UNLIKELY(!layerFEState->isVisible)) { | 
| Lloyd Pique | 01c77c1 | 2019-04-17 12:48:32 -0700 | [diff] [blame] | 393 |         return; | 
| Lloyd Pique | c29e4c6 | 2019-03-07 21:48:19 -0800 | [diff] [blame] | 394 |     } | 
 | 395 |  | 
 | 396 |     /* | 
 | 397 |      * opaqueRegion: area of a surface that is fully opaque. | 
 | 398 |      */ | 
 | 399 |     Region opaqueRegion; | 
 | 400 |  | 
 | 401 |     /* | 
 | 402 |      * visibleRegion: area of a surface that is visible on screen and not fully | 
 | 403 |      * transparent. This is essentially the layer's footprint minus the opaque | 
 | 404 |      * regions above it. Areas covered by a translucent surface are considered | 
 | 405 |      * visible. | 
 | 406 |      */ | 
 | 407 |     Region visibleRegion; | 
 | 408 |  | 
 | 409 |     /* | 
 | 410 |      * coveredRegion: area of a surface that is covered by all visible regions | 
 | 411 |      * above it (which includes the translucent areas). | 
 | 412 |      */ | 
 | 413 |     Region coveredRegion; | 
 | 414 |  | 
 | 415 |     /* | 
 | 416 |      * transparentRegion: area of a surface that is hinted to be completely | 
 | 417 |      * transparent. This is only used to tell when the layer has no visible non- | 
 | 418 |      * transparent regions and can be removed from the layer list. It does not | 
 | 419 |      * affect the visibleRegion of this layer or any layers beneath it. The hint | 
 | 420 |      * may not be correct if apps don't respect the SurfaceView restrictions | 
 | 421 |      * (which, sadly, some don't). | 
 | 422 |      */ | 
 | 423 |     Region transparentRegion; | 
 | 424 |  | 
| Vishnu Nair | a483b4a | 2019-12-12 15:07:52 -0800 | [diff] [blame] | 425 |     /* | 
 | 426 |      * shadowRegion: Region cast by the layer's shadow. | 
 | 427 |      */ | 
 | 428 |     Region shadowRegion; | 
 | 429 |  | 
| Lloyd Pique | de19665 | 2020-01-22 17:29:58 -0800 | [diff] [blame] | 430 |     const ui::Transform& tr = layerFEState->geomLayerTransform; | 
| Lloyd Pique | c29e4c6 | 2019-03-07 21:48:19 -0800 | [diff] [blame] | 431 |  | 
 | 432 |     // Get the visible region | 
 | 433 |     // TODO(b/121291683): Is it worth creating helper methods on LayerFEState | 
 | 434 |     // for computations like this? | 
| Lloyd Pique | de19665 | 2020-01-22 17:29:58 -0800 | [diff] [blame] | 435 |     const Rect visibleRect(tr.transform(layerFEState->geomLayerBounds)); | 
| Vishnu Nair | a483b4a | 2019-12-12 15:07:52 -0800 | [diff] [blame] | 436 |     visibleRegion.set(visibleRect); | 
 | 437 |  | 
| Lloyd Pique | de19665 | 2020-01-22 17:29:58 -0800 | [diff] [blame] | 438 |     if (layerFEState->shadowRadius > 0.0f) { | 
| Vishnu Nair | a483b4a | 2019-12-12 15:07:52 -0800 | [diff] [blame] | 439 |         // if the layer casts a shadow, offset the layers visible region and | 
 | 440 |         // calculate the shadow region. | 
| Lloyd Pique | de19665 | 2020-01-22 17:29:58 -0800 | [diff] [blame] | 441 |         const auto inset = static_cast<int32_t>(ceilf(layerFEState->shadowRadius) * -1.0f); | 
| Vishnu Nair | a483b4a | 2019-12-12 15:07:52 -0800 | [diff] [blame] | 442 |         Rect visibleRectWithShadows(visibleRect); | 
 | 443 |         visibleRectWithShadows.inset(inset, inset, inset, inset); | 
 | 444 |         visibleRegion.set(visibleRectWithShadows); | 
 | 445 |         shadowRegion = visibleRegion.subtract(visibleRect); | 
 | 446 |     } | 
| Lloyd Pique | c29e4c6 | 2019-03-07 21:48:19 -0800 | [diff] [blame] | 447 |  | 
 | 448 |     if (visibleRegion.isEmpty()) { | 
| Lloyd Pique | 01c77c1 | 2019-04-17 12:48:32 -0700 | [diff] [blame] | 449 |         return; | 
| Lloyd Pique | c29e4c6 | 2019-03-07 21:48:19 -0800 | [diff] [blame] | 450 |     } | 
 | 451 |  | 
 | 452 |     // Remove the transparent area from the visible region | 
| Lloyd Pique | de19665 | 2020-01-22 17:29:58 -0800 | [diff] [blame] | 453 |     if (!layerFEState->isOpaque) { | 
| Lloyd Pique | c29e4c6 | 2019-03-07 21:48:19 -0800 | [diff] [blame] | 454 |         if (tr.preserveRects()) { | 
 | 455 |             // transform the transparent region | 
| Lloyd Pique | de19665 | 2020-01-22 17:29:58 -0800 | [diff] [blame] | 456 |             transparentRegion = tr.transform(layerFEState->transparentRegionHint); | 
| Lloyd Pique | c29e4c6 | 2019-03-07 21:48:19 -0800 | [diff] [blame] | 457 |         } else { | 
 | 458 |             // transformation too complex, can't do the | 
 | 459 |             // transparent region optimization. | 
 | 460 |             transparentRegion.clear(); | 
| Lloyd Pique | cc01a45 | 2018-12-04 17:24:00 -0800 | [diff] [blame] | 461 |         } | 
 | 462 |     } | 
| Lloyd Pique | c29e4c6 | 2019-03-07 21:48:19 -0800 | [diff] [blame] | 463 |  | 
 | 464 |     // compute the opaque region | 
| Lloyd Pique | 0a45623 | 2020-01-16 17:51:13 -0800 | [diff] [blame] | 465 |     const auto layerOrientation = tr.getOrientation(); | 
| Lloyd Pique | de19665 | 2020-01-22 17:29:58 -0800 | [diff] [blame] | 466 |     if (layerFEState->isOpaque && ((layerOrientation & ui::Transform::ROT_INVALID) == 0)) { | 
| Lloyd Pique | c29e4c6 | 2019-03-07 21:48:19 -0800 | [diff] [blame] | 467 |         // If we one of the simple category of transforms (0/90/180/270 rotation | 
 | 468 |         // + any flip), then the opaque region is the layer's footprint. | 
 | 469 |         // Otherwise we don't try and compute the opaque region since there may | 
 | 470 |         // be errors at the edges, and we treat the entire layer as | 
 | 471 |         // translucent. | 
| Vishnu Nair | a483b4a | 2019-12-12 15:07:52 -0800 | [diff] [blame] | 472 |         opaqueRegion.set(visibleRect); | 
| Lloyd Pique | c29e4c6 | 2019-03-07 21:48:19 -0800 | [diff] [blame] | 473 |     } | 
 | 474 |  | 
 | 475 |     // Clip the covered region to the visible region | 
 | 476 |     coveredRegion = coverage.aboveCoveredLayers.intersect(visibleRegion); | 
 | 477 |  | 
 | 478 |     // Update accumAboveCoveredLayers for next (lower) layer | 
 | 479 |     coverage.aboveCoveredLayers.orSelf(visibleRegion); | 
 | 480 |  | 
 | 481 |     // subtract the opaque region covered by the layers above us | 
 | 482 |     visibleRegion.subtractSelf(coverage.aboveOpaqueLayers); | 
 | 483 |  | 
 | 484 |     if (visibleRegion.isEmpty()) { | 
| Lloyd Pique | 01c77c1 | 2019-04-17 12:48:32 -0700 | [diff] [blame] | 485 |         return; | 
| Lloyd Pique | c29e4c6 | 2019-03-07 21:48:19 -0800 | [diff] [blame] | 486 |     } | 
 | 487 |  | 
 | 488 |     // Get coverage information for the layer as previously displayed, | 
 | 489 |     // also taking over ownership from mOutputLayersorderedByZ. | 
| Lloyd Pique | de19665 | 2020-01-22 17:29:58 -0800 | [diff] [blame] | 490 |     auto prevOutputLayerIndex = findCurrentOutputLayerForLayer(layerFE); | 
| Lloyd Pique | 01c77c1 | 2019-04-17 12:48:32 -0700 | [diff] [blame] | 491 |     auto prevOutputLayer = | 
 | 492 |             prevOutputLayerIndex ? getOutputLayerOrderedByZByIndex(*prevOutputLayerIndex) : nullptr; | 
| Lloyd Pique | c29e4c6 | 2019-03-07 21:48:19 -0800 | [diff] [blame] | 493 |  | 
 | 494 |     //  Get coverage information for the layer as previously displayed | 
 | 495 |     // TODO(b/121291683): Define kEmptyRegion as a constant in Region.h | 
 | 496 |     const Region kEmptyRegion; | 
 | 497 |     const Region& oldVisibleRegion = | 
 | 498 |             prevOutputLayer ? prevOutputLayer->getState().visibleRegion : kEmptyRegion; | 
 | 499 |     const Region& oldCoveredRegion = | 
 | 500 |             prevOutputLayer ? prevOutputLayer->getState().coveredRegion : kEmptyRegion; | 
 | 501 |  | 
 | 502 |     // compute this layer's dirty region | 
 | 503 |     Region dirty; | 
| Lloyd Pique | de19665 | 2020-01-22 17:29:58 -0800 | [diff] [blame] | 504 |     if (layerFEState->contentDirty) { | 
| Lloyd Pique | c29e4c6 | 2019-03-07 21:48:19 -0800 | [diff] [blame] | 505 |         // we need to invalidate the whole region | 
 | 506 |         dirty = visibleRegion; | 
 | 507 |         // as well, as the old visible region | 
 | 508 |         dirty.orSelf(oldVisibleRegion); | 
 | 509 |     } else { | 
 | 510 |         /* compute the exposed region: | 
 | 511 |          *   the exposed region consists of two components: | 
 | 512 |          *   1) what's VISIBLE now and was COVERED before | 
 | 513 |          *   2) what's EXPOSED now less what was EXPOSED before | 
 | 514 |          * | 
 | 515 |          * note that (1) is conservative, we start with the whole visible region | 
 | 516 |          * but only keep what used to be covered by something -- which mean it | 
 | 517 |          * may have been exposed. | 
 | 518 |          * | 
 | 519 |          * (2) handles areas that were not covered by anything but got exposed | 
 | 520 |          * because of a resize. | 
 | 521 |          * | 
 | 522 |          */ | 
 | 523 |         const Region newExposed = visibleRegion - coveredRegion; | 
 | 524 |         const Region oldExposed = oldVisibleRegion - oldCoveredRegion; | 
 | 525 |         dirty = (visibleRegion & oldCoveredRegion) | (newExposed - oldExposed); | 
 | 526 |     } | 
 | 527 |     dirty.subtractSelf(coverage.aboveOpaqueLayers); | 
 | 528 |  | 
 | 529 |     // accumulate to the screen dirty region | 
 | 530 |     coverage.dirtyRegion.orSelf(dirty); | 
 | 531 |  | 
 | 532 |     // Update accumAboveOpaqueLayers for next (lower) layer | 
 | 533 |     coverage.aboveOpaqueLayers.orSelf(opaqueRegion); | 
 | 534 |  | 
 | 535 |     // Compute the visible non-transparent region | 
 | 536 |     Region visibleNonTransparentRegion = visibleRegion.subtract(transparentRegion); | 
 | 537 |  | 
| Vishnu Nair | a483b4a | 2019-12-12 15:07:52 -0800 | [diff] [blame] | 538 |     // Perform the final check to see if this layer is visible on this output | 
| Lloyd Pique | c29e4c6 | 2019-03-07 21:48:19 -0800 | [diff] [blame] | 539 |     // TODO(b/121291683): Why does this not use visibleRegion? (see outputSpaceVisibleRegion below) | 
| Lloyd Pique | a38ea7e | 2019-04-16 18:10:26 -0700 | [diff] [blame] | 540 |     const auto& outputState = getState(); | 
 | 541 |     Region drawRegion(outputState.transform.transform(visibleNonTransparentRegion)); | 
 | 542 |     drawRegion.andSelf(outputState.bounds); | 
| Lloyd Pique | c29e4c6 | 2019-03-07 21:48:19 -0800 | [diff] [blame] | 543 |     if (drawRegion.isEmpty()) { | 
| Lloyd Pique | 01c77c1 | 2019-04-17 12:48:32 -0700 | [diff] [blame] | 544 |         return; | 
| Lloyd Pique | c29e4c6 | 2019-03-07 21:48:19 -0800 | [diff] [blame] | 545 |     } | 
 | 546 |  | 
| Vishnu Nair | a483b4a | 2019-12-12 15:07:52 -0800 | [diff] [blame] | 547 |     Region visibleNonShadowRegion = visibleRegion.subtract(shadowRegion); | 
 | 548 |  | 
| Lloyd Pique | c29e4c6 | 2019-03-07 21:48:19 -0800 | [diff] [blame] | 549 |     // The layer is visible. Either reuse the existing outputLayer if we have | 
 | 550 |     // one, or create a new one if we do not. | 
| Lloyd Pique | de19665 | 2020-01-22 17:29:58 -0800 | [diff] [blame] | 551 |     auto result = ensureOutputLayer(prevOutputLayerIndex, layerFE); | 
| Lloyd Pique | c29e4c6 | 2019-03-07 21:48:19 -0800 | [diff] [blame] | 552 |  | 
 | 553 |     // Store the layer coverage information into the layer state as some of it | 
 | 554 |     // is useful later. | 
 | 555 |     auto& outputLayerState = result->editState(); | 
 | 556 |     outputLayerState.visibleRegion = visibleRegion; | 
 | 557 |     outputLayerState.visibleNonTransparentRegion = visibleNonTransparentRegion; | 
 | 558 |     outputLayerState.coveredRegion = coveredRegion; | 
| Vishnu Nair | a483b4a | 2019-12-12 15:07:52 -0800 | [diff] [blame] | 559 |     outputLayerState.outputSpaceVisibleRegion = | 
 | 560 |             outputState.transform.transform(visibleNonShadowRegion.intersect(outputState.viewport)); | 
 | 561 |     outputLayerState.shadowRegion = shadowRegion; | 
| Lloyd Pique | cc01a45 | 2018-12-04 17:24:00 -0800 | [diff] [blame] | 562 | } | 
 | 563 |  | 
| Lloyd Pique | c29e4c6 | 2019-03-07 21:48:19 -0800 | [diff] [blame] | 564 | void Output::setReleasedLayers(const compositionengine::CompositionRefreshArgs&) { | 
 | 565 |     // The base class does nothing with this call. | 
| Lloyd Pique | cc01a45 | 2018-12-04 17:24:00 -0800 | [diff] [blame] | 566 | } | 
 | 567 |  | 
| Lloyd Pique | 3eb1b21 | 2019-03-07 21:15:40 -0800 | [diff] [blame] | 568 | void Output::updateLayerStateFromFE(const CompositionRefreshArgs& args) const { | 
| Lloyd Pique | 01c77c1 | 2019-04-17 12:48:32 -0700 | [diff] [blame] | 569 |     for (auto* layer : getOutputLayersOrderedByZ()) { | 
| Lloyd Pique | de19665 | 2020-01-22 17:29:58 -0800 | [diff] [blame] | 570 |         layer->getLayerFE().prepareCompositionState( | 
 | 571 |                 args.updatingGeometryThisFrame ? LayerFE::StateSubset::GeometryAndContent | 
 | 572 |                                                : LayerFE::StateSubset::Content); | 
| Lloyd Pique | 3eb1b21 | 2019-03-07 21:15:40 -0800 | [diff] [blame] | 573 |     } | 
 | 574 | } | 
 | 575 |  | 
 | 576 | void Output::updateAndWriteCompositionState( | 
 | 577 |         const compositionengine::CompositionRefreshArgs& refreshArgs) { | 
 | 578 |     ATRACE_CALL(); | 
 | 579 |     ALOGV(__FUNCTION__); | 
 | 580 |  | 
| Alec Mouri | f9a2a2c | 2019-11-12 12:46:02 -0800 | [diff] [blame] | 581 |     if (!getState().isEnabled) { | 
 | 582 |         return; | 
 | 583 |     } | 
 | 584 |  | 
| Lucas Dupin | 19c8f0e | 2019-11-25 17:55:44 -0800 | [diff] [blame] | 585 |     mLayerRequestingBackgroundBlur = findLayerRequestingBackgroundComposition(); | 
 | 586 |     bool forceClientComposition = mLayerRequestingBackgroundBlur != nullptr; | 
 | 587 |  | 
| Lloyd Pique | 01c77c1 | 2019-04-17 12:48:32 -0700 | [diff] [blame] | 588 |     for (auto* layer : getOutputLayersOrderedByZ()) { | 
| Lloyd Pique | 7a23491 | 2019-10-03 11:54:27 -0700 | [diff] [blame] | 589 |         layer->updateCompositionState(refreshArgs.updatingGeometryThisFrame, | 
| Lucas Dupin | 19c8f0e | 2019-11-25 17:55:44 -0800 | [diff] [blame] | 590 |                                       refreshArgs.devOptForceClientComposition || | 
| Snild Dolkow | 9e217d6 | 2020-04-22 15:53:42 +0200 | [diff] [blame] | 591 |                                               forceClientComposition, | 
 | 592 |                                       refreshArgs.internalDisplayRotationFlags); | 
| Lucas Dupin | 19c8f0e | 2019-11-25 17:55:44 -0800 | [diff] [blame] | 593 |  | 
 | 594 |         if (mLayerRequestingBackgroundBlur == layer) { | 
 | 595 |             forceClientComposition = false; | 
 | 596 |         } | 
| Lloyd Pique | 3eb1b21 | 2019-03-07 21:15:40 -0800 | [diff] [blame] | 597 |  | 
 | 598 |         // Send the updated state to the HWC, if appropriate. | 
 | 599 |         layer->writeStateToHWC(refreshArgs.updatingGeometryThisFrame); | 
 | 600 |     } | 
 | 601 | } | 
 | 602 |  | 
| Lucas Dupin | 19c8f0e | 2019-11-25 17:55:44 -0800 | [diff] [blame] | 603 | compositionengine::OutputLayer* Output::findLayerRequestingBackgroundComposition() const { | 
 | 604 |     compositionengine::OutputLayer* layerRequestingBgComposition = nullptr; | 
 | 605 |     for (auto* layer : getOutputLayersOrderedByZ()) { | 
| Lloyd Pique | de19665 | 2020-01-22 17:29:58 -0800 | [diff] [blame] | 606 |         if (layer->getLayerFE().getCompositionState()->backgroundBlurRadius > 0) { | 
| Lucas Dupin | 19c8f0e | 2019-11-25 17:55:44 -0800 | [diff] [blame] | 607 |             layerRequestingBgComposition = layer; | 
 | 608 |         } | 
 | 609 |     } | 
 | 610 |     return layerRequestingBgComposition; | 
 | 611 | } | 
 | 612 |  | 
| Lloyd Pique | 6a3b446 | 2019-03-07 20:58:12 -0800 | [diff] [blame] | 613 | void Output::updateColorProfile(const compositionengine::CompositionRefreshArgs& refreshArgs) { | 
 | 614 |     setColorProfile(pickColorProfile(refreshArgs)); | 
 | 615 | } | 
 | 616 |  | 
 | 617 | // Returns a data space that fits all visible layers.  The returned data space | 
 | 618 | // can only be one of | 
 | 619 | //  - Dataspace::SRGB (use legacy dataspace and let HWC saturate when colors are enhanced) | 
 | 620 | //  - Dataspace::DISPLAY_P3 | 
 | 621 | //  - Dataspace::DISPLAY_BT2020 | 
 | 622 | // The returned HDR data space is one of | 
 | 623 | //  - Dataspace::UNKNOWN | 
 | 624 | //  - Dataspace::BT2020_HLG | 
 | 625 | //  - Dataspace::BT2020_PQ | 
 | 626 | ui::Dataspace Output::getBestDataspace(ui::Dataspace* outHdrDataSpace, | 
 | 627 |                                        bool* outIsHdrClientComposition) const { | 
 | 628 |     ui::Dataspace bestDataSpace = ui::Dataspace::V0_SRGB; | 
 | 629 |     *outHdrDataSpace = ui::Dataspace::UNKNOWN; | 
 | 630 |  | 
| Lloyd Pique | 01c77c1 | 2019-04-17 12:48:32 -0700 | [diff] [blame] | 631 |     for (const auto* layer : getOutputLayersOrderedByZ()) { | 
| Lloyd Pique | de19665 | 2020-01-22 17:29:58 -0800 | [diff] [blame] | 632 |         switch (layer->getLayerFE().getCompositionState()->dataspace) { | 
| Lloyd Pique | 6a3b446 | 2019-03-07 20:58:12 -0800 | [diff] [blame] | 633 |             case ui::Dataspace::V0_SCRGB: | 
 | 634 |             case ui::Dataspace::V0_SCRGB_LINEAR: | 
 | 635 |             case ui::Dataspace::BT2020: | 
 | 636 |             case ui::Dataspace::BT2020_ITU: | 
 | 637 |             case ui::Dataspace::BT2020_LINEAR: | 
 | 638 |             case ui::Dataspace::DISPLAY_BT2020: | 
 | 639 |                 bestDataSpace = ui::Dataspace::DISPLAY_BT2020; | 
 | 640 |                 break; | 
 | 641 |             case ui::Dataspace::DISPLAY_P3: | 
 | 642 |                 bestDataSpace = ui::Dataspace::DISPLAY_P3; | 
 | 643 |                 break; | 
 | 644 |             case ui::Dataspace::BT2020_PQ: | 
 | 645 |             case ui::Dataspace::BT2020_ITU_PQ: | 
 | 646 |                 bestDataSpace = ui::Dataspace::DISPLAY_P3; | 
 | 647 |                 *outHdrDataSpace = ui::Dataspace::BT2020_PQ; | 
| Lloyd Pique | de19665 | 2020-01-22 17:29:58 -0800 | [diff] [blame] | 648 |                 *outIsHdrClientComposition = | 
 | 649 |                         layer->getLayerFE().getCompositionState()->forceClientComposition; | 
| Lloyd Pique | 6a3b446 | 2019-03-07 20:58:12 -0800 | [diff] [blame] | 650 |                 break; | 
 | 651 |             case ui::Dataspace::BT2020_HLG: | 
 | 652 |             case ui::Dataspace::BT2020_ITU_HLG: | 
 | 653 |                 bestDataSpace = ui::Dataspace::DISPLAY_P3; | 
 | 654 |                 // When there's mixed PQ content and HLG content, we set the HDR | 
 | 655 |                 // data space to be BT2020_PQ and convert HLG to PQ. | 
 | 656 |                 if (*outHdrDataSpace == ui::Dataspace::UNKNOWN) { | 
 | 657 |                     *outHdrDataSpace = ui::Dataspace::BT2020_HLG; | 
 | 658 |                 } | 
 | 659 |                 break; | 
 | 660 |             default: | 
 | 661 |                 break; | 
 | 662 |         } | 
 | 663 |     } | 
 | 664 |  | 
 | 665 |     return bestDataSpace; | 
 | 666 | } | 
 | 667 |  | 
 | 668 | compositionengine::Output::ColorProfile Output::pickColorProfile( | 
 | 669 |         const compositionengine::CompositionRefreshArgs& refreshArgs) const { | 
 | 670 |     if (refreshArgs.outputColorSetting == OutputColorSetting::kUnmanaged) { | 
 | 671 |         return ColorProfile{ui::ColorMode::NATIVE, ui::Dataspace::UNKNOWN, | 
 | 672 |                             ui::RenderIntent::COLORIMETRIC, | 
 | 673 |                             refreshArgs.colorSpaceAgnosticDataspace}; | 
 | 674 |     } | 
 | 675 |  | 
 | 676 |     ui::Dataspace hdrDataSpace; | 
 | 677 |     bool isHdrClientComposition = false; | 
 | 678 |     ui::Dataspace bestDataSpace = getBestDataspace(&hdrDataSpace, &isHdrClientComposition); | 
 | 679 |  | 
 | 680 |     switch (refreshArgs.forceOutputColorMode) { | 
 | 681 |         case ui::ColorMode::SRGB: | 
 | 682 |             bestDataSpace = ui::Dataspace::V0_SRGB; | 
 | 683 |             break; | 
 | 684 |         case ui::ColorMode::DISPLAY_P3: | 
 | 685 |             bestDataSpace = ui::Dataspace::DISPLAY_P3; | 
 | 686 |             break; | 
 | 687 |         default: | 
 | 688 |             break; | 
 | 689 |     } | 
 | 690 |  | 
 | 691 |     // respect hdrDataSpace only when there is no legacy HDR support | 
 | 692 |     const bool isHdr = hdrDataSpace != ui::Dataspace::UNKNOWN && | 
 | 693 |             !mDisplayColorProfile->hasLegacyHdrSupport(hdrDataSpace) && !isHdrClientComposition; | 
 | 694 |     if (isHdr) { | 
 | 695 |         bestDataSpace = hdrDataSpace; | 
 | 696 |     } | 
 | 697 |  | 
 | 698 |     ui::RenderIntent intent; | 
 | 699 |     switch (refreshArgs.outputColorSetting) { | 
 | 700 |         case OutputColorSetting::kManaged: | 
 | 701 |         case OutputColorSetting::kUnmanaged: | 
 | 702 |             intent = isHdr ? ui::RenderIntent::TONE_MAP_COLORIMETRIC | 
 | 703 |                            : ui::RenderIntent::COLORIMETRIC; | 
 | 704 |             break; | 
 | 705 |         case OutputColorSetting::kEnhanced: | 
 | 706 |             intent = isHdr ? ui::RenderIntent::TONE_MAP_ENHANCE : ui::RenderIntent::ENHANCE; | 
 | 707 |             break; | 
 | 708 |         default: // vendor display color setting | 
 | 709 |             intent = static_cast<ui::RenderIntent>(refreshArgs.outputColorSetting); | 
 | 710 |             break; | 
 | 711 |     } | 
 | 712 |  | 
 | 713 |     ui::ColorMode outMode; | 
 | 714 |     ui::Dataspace outDataSpace; | 
 | 715 |     ui::RenderIntent outRenderIntent; | 
 | 716 |     mDisplayColorProfile->getBestColorMode(bestDataSpace, intent, &outDataSpace, &outMode, | 
 | 717 |                                            &outRenderIntent); | 
 | 718 |  | 
 | 719 |     return ColorProfile{outMode, outDataSpace, outRenderIntent, | 
 | 720 |                         refreshArgs.colorSpaceAgnosticDataspace}; | 
 | 721 | } | 
 | 722 |  | 
| Lloyd Pique | d0a92a0 | 2019-02-19 17:47:26 -0800 | [diff] [blame] | 723 | void Output::beginFrame() { | 
| Lloyd Pique | a38ea7e | 2019-04-16 18:10:26 -0700 | [diff] [blame] | 724 |     auto& outputState = editState(); | 
| Lloyd Pique | d0a92a0 | 2019-02-19 17:47:26 -0800 | [diff] [blame] | 725 |     const bool dirty = !getDirtyRegion(false).isEmpty(); | 
| Lloyd Pique | 01c77c1 | 2019-04-17 12:48:32 -0700 | [diff] [blame] | 726 |     const bool empty = getOutputLayerCount() == 0; | 
| Lloyd Pique | a38ea7e | 2019-04-16 18:10:26 -0700 | [diff] [blame] | 727 |     const bool wasEmpty = !outputState.lastCompositionHadVisibleLayers; | 
| Lloyd Pique | d0a92a0 | 2019-02-19 17:47:26 -0800 | [diff] [blame] | 728 |  | 
 | 729 |     // If nothing has changed (!dirty), don't recompose. | 
 | 730 |     // If something changed, but we don't currently have any visible layers, | 
 | 731 |     //   and didn't when we last did a composition, then skip it this time. | 
 | 732 |     // The second rule does two things: | 
 | 733 |     // - When all layers are removed from a display, we'll emit one black | 
 | 734 |     //   frame, then nothing more until we get new layers. | 
 | 735 |     // - When a display is created with a private layer stack, we won't | 
 | 736 |     //   emit any black frames until a layer is added to the layer stack. | 
 | 737 |     const bool mustRecompose = dirty && !(empty && wasEmpty); | 
 | 738 |  | 
 | 739 |     const char flagPrefix[] = {'-', '+'}; | 
 | 740 |     static_cast<void>(flagPrefix); | 
 | 741 |     ALOGV_IF("%s: %s composition for %s (%cdirty %cempty %cwasEmpty)", __FUNCTION__, | 
 | 742 |              mustRecompose ? "doing" : "skipping", getName().c_str(), flagPrefix[dirty], | 
 | 743 |              flagPrefix[empty], flagPrefix[wasEmpty]); | 
 | 744 |  | 
 | 745 |     mRenderSurface->beginFrame(mustRecompose); | 
 | 746 |  | 
 | 747 |     if (mustRecompose) { | 
| Lloyd Pique | a38ea7e | 2019-04-16 18:10:26 -0700 | [diff] [blame] | 748 |         outputState.lastCompositionHadVisibleLayers = !empty; | 
| Lloyd Pique | d0a92a0 | 2019-02-19 17:47:26 -0800 | [diff] [blame] | 749 |     } | 
 | 750 | } | 
 | 751 |  | 
| Lloyd Pique | 66d6860 | 2019-02-13 14:23:31 -0800 | [diff] [blame] | 752 | void Output::prepareFrame() { | 
 | 753 |     ATRACE_CALL(); | 
 | 754 |     ALOGV(__FUNCTION__); | 
 | 755 |  | 
| Lloyd Pique | a38ea7e | 2019-04-16 18:10:26 -0700 | [diff] [blame] | 756 |     const auto& outputState = getState(); | 
 | 757 |     if (!outputState.isEnabled) { | 
| Lloyd Pique | 66d6860 | 2019-02-13 14:23:31 -0800 | [diff] [blame] | 758 |         return; | 
 | 759 |     } | 
 | 760 |  | 
 | 761 |     chooseCompositionStrategy(); | 
 | 762 |  | 
| Lloyd Pique | a38ea7e | 2019-04-16 18:10:26 -0700 | [diff] [blame] | 763 |     mRenderSurface->prepareFrame(outputState.usesClientComposition, | 
 | 764 |                                  outputState.usesDeviceComposition); | 
| Lloyd Pique | 66d6860 | 2019-02-13 14:23:31 -0800 | [diff] [blame] | 765 | } | 
 | 766 |  | 
| Lloyd Pique | f8cf14d | 2019-02-28 16:03:12 -0800 | [diff] [blame] | 767 | void Output::devOptRepaintFlash(const compositionengine::CompositionRefreshArgs& refreshArgs) { | 
 | 768 |     if (CC_LIKELY(!refreshArgs.devOptFlashDirtyRegionsDelay)) { | 
 | 769 |         return; | 
 | 770 |     } | 
 | 771 |  | 
| Lloyd Pique | a38ea7e | 2019-04-16 18:10:26 -0700 | [diff] [blame] | 772 |     if (getState().isEnabled) { | 
| Lloyd Pique | f8cf14d | 2019-02-28 16:03:12 -0800 | [diff] [blame] | 773 |         // transform the dirty region into this screen's coordinate space | 
 | 774 |         const Region dirtyRegion = getDirtyRegion(refreshArgs.repaintEverything); | 
 | 775 |         if (!dirtyRegion.isEmpty()) { | 
 | 776 |             base::unique_fd readyFence; | 
 | 777 |             // redraw the whole screen | 
| Lucas Dupin | 2dd6f39 | 2020-02-18 17:43:36 -0800 | [diff] [blame] | 778 |             static_cast<void>(composeSurfaces(dirtyRegion, refreshArgs)); | 
| Lloyd Pique | f8cf14d | 2019-02-28 16:03:12 -0800 | [diff] [blame] | 779 |  | 
 | 780 |             mRenderSurface->queueBuffer(std::move(readyFence)); | 
 | 781 |         } | 
 | 782 |     } | 
 | 783 |  | 
 | 784 |     postFramebuffer(); | 
 | 785 |  | 
 | 786 |     std::this_thread::sleep_for(*refreshArgs.devOptFlashDirtyRegionsDelay); | 
 | 787 |  | 
 | 788 |     prepareFrame(); | 
 | 789 | } | 
 | 790 |  | 
| Lucas Dupin | 2dd6f39 | 2020-02-18 17:43:36 -0800 | [diff] [blame] | 791 | void Output::finishFrame(const compositionengine::CompositionRefreshArgs& refreshArgs) { | 
| Lloyd Pique | d3d6988 | 2019-02-28 16:03:46 -0800 | [diff] [blame] | 792 |     ATRACE_CALL(); | 
 | 793 |     ALOGV(__FUNCTION__); | 
 | 794 |  | 
| Lloyd Pique | a38ea7e | 2019-04-16 18:10:26 -0700 | [diff] [blame] | 795 |     if (!getState().isEnabled) { | 
| Lloyd Pique | d3d6988 | 2019-02-28 16:03:46 -0800 | [diff] [blame] | 796 |         return; | 
 | 797 |     } | 
 | 798 |  | 
 | 799 |     // Repaint the framebuffer (if needed), getting the optional fence for when | 
 | 800 |     // the composition completes. | 
| Lucas Dupin | 2dd6f39 | 2020-02-18 17:43:36 -0800 | [diff] [blame] | 801 |     auto optReadyFence = composeSurfaces(Region::INVALID_REGION, refreshArgs); | 
| Lloyd Pique | d3d6988 | 2019-02-28 16:03:46 -0800 | [diff] [blame] | 802 |     if (!optReadyFence) { | 
 | 803 |         return; | 
 | 804 |     } | 
 | 805 |  | 
 | 806 |     // swap buffers (presentation) | 
 | 807 |     mRenderSurface->queueBuffer(std::move(*optReadyFence)); | 
 | 808 | } | 
 | 809 |  | 
| Lucas Dupin | 2dd6f39 | 2020-02-18 17:43:36 -0800 | [diff] [blame] | 810 | std::optional<base::unique_fd> Output::composeSurfaces( | 
 | 811 |         const Region& debugRegion, const compositionengine::CompositionRefreshArgs& refreshArgs) { | 
| Lloyd Pique | 688abd4 | 2019-02-15 15:42:24 -0800 | [diff] [blame] | 812 |     ATRACE_CALL(); | 
 | 813 |     ALOGV(__FUNCTION__); | 
 | 814 |  | 
| Lloyd Pique | a38ea7e | 2019-04-16 18:10:26 -0700 | [diff] [blame] | 815 |     const auto& outputState = getState(); | 
| Vishnu Nair | 9b079a2 | 2020-01-21 14:36:08 -0800 | [diff] [blame] | 816 |     OutputCompositionState& outputCompositionState = editState(); | 
| Lloyd Pique | 688abd4 | 2019-02-15 15:42:24 -0800 | [diff] [blame] | 817 |     const TracedOrdinal<bool> hasClientComposition = {"hasClientComposition", | 
| Lloyd Pique | a38ea7e | 2019-04-16 18:10:26 -0700 | [diff] [blame] | 818 |                                                       outputState.usesClientComposition}; | 
| Lloyd Pique | e9eff97 | 2020-05-05 12:36:44 -0700 | [diff] [blame] | 819 |  | 
 | 820 |     auto& renderEngine = getCompositionEngine().getRenderEngine(); | 
 | 821 |     const bool supportsProtectedContent = renderEngine.supportsProtectedContent(); | 
 | 822 |  | 
 | 823 |     // If we the display is secure, protected content support is enabled, and at | 
 | 824 |     // least one layer has protected content, we need to use a secure back | 
 | 825 |     // buffer. | 
 | 826 |     if (outputState.isSecure && supportsProtectedContent) { | 
 | 827 |         auto layers = getOutputLayersOrderedByZ(); | 
 | 828 |         bool needsProtected = std::any_of(layers.begin(), layers.end(), [](auto* layer) { | 
 | 829 |             return layer->getLayerFE().getCompositionState()->hasProtectedContent; | 
 | 830 |         }); | 
 | 831 |         if (needsProtected != renderEngine.isProtected()) { | 
 | 832 |             renderEngine.useProtectedContext(needsProtected); | 
 | 833 |         } | 
 | 834 |         if (needsProtected != mRenderSurface->isProtected() && | 
 | 835 |             needsProtected == renderEngine.isProtected()) { | 
 | 836 |             mRenderSurface->setProtected(needsProtected); | 
 | 837 |         } | 
| Peiyong Lin | b494757 | 2020-09-25 10:54:13 -0700 | [diff] [blame] | 838 |     } else if (!outputState.isSecure && renderEngine.isProtected()) { | 
 | 839 |         renderEngine.useProtectedContext(false); | 
| Lloyd Pique | e9eff97 | 2020-05-05 12:36:44 -0700 | [diff] [blame] | 840 |     } | 
 | 841 |  | 
 | 842 |     base::unique_fd fd; | 
 | 843 |     sp<GraphicBuffer> buf; | 
 | 844 |  | 
 | 845 |     // If we aren't doing client composition on this output, but do have a | 
 | 846 |     // flipClientTarget request for this frame on this output, we still need to | 
 | 847 |     // dequeue a buffer. | 
 | 848 |     if (hasClientComposition || outputState.flipClientTarget) { | 
 | 849 |         buf = mRenderSurface->dequeueBuffer(&fd); | 
 | 850 |         if (buf == nullptr) { | 
 | 851 |             ALOGW("Dequeuing buffer for display [%s] failed, bailing out of " | 
 | 852 |                   "client composition for this frame", | 
 | 853 |                   mName.c_str()); | 
 | 854 |             return {}; | 
 | 855 |         } | 
 | 856 |     } | 
 | 857 |  | 
| Lloyd Pique | d3d6988 | 2019-02-28 16:03:46 -0800 | [diff] [blame] | 858 |     base::unique_fd readyFence; | 
| Lloyd Pique | 688abd4 | 2019-02-15 15:42:24 -0800 | [diff] [blame] | 859 |     if (!hasClientComposition) { | 
| Lloyd Pique | a76ce46 | 2020-01-14 13:06:37 -0800 | [diff] [blame] | 860 |         setExpensiveRenderingExpected(false); | 
| Lloyd Pique | d3d6988 | 2019-02-28 16:03:46 -0800 | [diff] [blame] | 861 |         return readyFence; | 
| Lloyd Pique | 688abd4 | 2019-02-15 15:42:24 -0800 | [diff] [blame] | 862 |     } | 
 | 863 |  | 
 | 864 |     ALOGV("hasClientComposition"); | 
 | 865 |  | 
| Lloyd Pique | 688abd4 | 2019-02-15 15:42:24 -0800 | [diff] [blame] | 866 |     renderengine::DisplaySettings clientCompositionDisplay; | 
| Lloyd Pique | e8fe474 | 2020-01-21 15:26:18 -0800 | [diff] [blame] | 867 |     clientCompositionDisplay.physicalDisplay = outputState.destinationClip; | 
 | 868 |     clientCompositionDisplay.clip = outputState.sourceClip; | 
| Lloyd Pique | a38ea7e | 2019-04-16 18:10:26 -0700 | [diff] [blame] | 869 |     clientCompositionDisplay.orientation = outputState.orientation; | 
 | 870 |     clientCompositionDisplay.outputDataspace = mDisplayColorProfile->hasWideColorGamut() | 
 | 871 |             ? outputState.dataspace | 
 | 872 |             : ui::Dataspace::UNKNOWN; | 
| Lloyd Pique | 688abd4 | 2019-02-15 15:42:24 -0800 | [diff] [blame] | 873 |     clientCompositionDisplay.maxLuminance = | 
 | 874 |             mDisplayColorProfile->getHdrCapabilities().getDesiredMaxLuminance(); | 
 | 875 |  | 
 | 876 |     // Compute the global color transform matrix. | 
| Lloyd Pique | a38ea7e | 2019-04-16 18:10:26 -0700 | [diff] [blame] | 877 |     if (!outputState.usesDeviceComposition && !getSkipColorTransform()) { | 
 | 878 |         clientCompositionDisplay.colorTransform = outputState.colorTransformMatrix; | 
| Lloyd Pique | 688abd4 | 2019-02-15 15:42:24 -0800 | [diff] [blame] | 879 |     } | 
 | 880 |  | 
 | 881 |     // Note: Updated by generateClientCompositionRequests | 
 | 882 |     clientCompositionDisplay.clearRegion = Region::INVALID_REGION; | 
 | 883 |  | 
 | 884 |     // Generate the client composition requests for the layers on this output. | 
| Vishnu Nair | 9b079a2 | 2020-01-21 14:36:08 -0800 | [diff] [blame] | 885 |     std::vector<LayerFE::LayerSettings> clientCompositionLayers = | 
| Lloyd Pique | 688abd4 | 2019-02-15 15:42:24 -0800 | [diff] [blame] | 886 |             generateClientCompositionRequests(supportsProtectedContent, | 
| Vishnu Nair | 3a7346c | 2019-12-04 08:09:09 -0800 | [diff] [blame] | 887 |                                               clientCompositionDisplay.clearRegion, | 
 | 888 |                                               clientCompositionDisplay.outputDataspace); | 
| Lloyd Pique | 688abd4 | 2019-02-15 15:42:24 -0800 | [diff] [blame] | 889 |     appendRegionFlashRequests(debugRegion, clientCompositionLayers); | 
 | 890 |  | 
| Vishnu Nair | 9b079a2 | 2020-01-21 14:36:08 -0800 | [diff] [blame] | 891 |     // Check if the client composition requests were rendered into the provided graphic buffer. If | 
 | 892 |     // so, we can reuse the buffer and avoid client composition. | 
 | 893 |     if (mClientCompositionRequestCache) { | 
 | 894 |         if (mClientCompositionRequestCache->exists(buf->getId(), clientCompositionDisplay, | 
 | 895 |                                                    clientCompositionLayers)) { | 
 | 896 |             outputCompositionState.reusedClientComposition = true; | 
 | 897 |             setExpensiveRenderingExpected(false); | 
 | 898 |             return readyFence; | 
 | 899 |         } | 
 | 900 |         mClientCompositionRequestCache->add(buf->getId(), clientCompositionDisplay, | 
 | 901 |                                             clientCompositionLayers); | 
 | 902 |     } | 
 | 903 |  | 
| Lloyd Pique | 688abd4 | 2019-02-15 15:42:24 -0800 | [diff] [blame] | 904 |     // We boost GPU frequency here because there will be color spaces conversion | 
| Lucas Dupin | 19c8f0e | 2019-11-25 17:55:44 -0800 | [diff] [blame] | 905 |     // or complex GPU shaders and it's expensive. We boost the GPU frequency so that | 
 | 906 |     // GPU composition can finish in time. We must reset GPU frequency afterwards, | 
 | 907 |     // because high frequency consumes extra battery. | 
| Lucas Dupin | 2dd6f39 | 2020-02-18 17:43:36 -0800 | [diff] [blame] | 908 |     const bool expensiveBlurs = | 
 | 909 |             refreshArgs.blursAreExpensive && mLayerRequestingBackgroundBlur != nullptr; | 
| Lloyd Pique | 688abd4 | 2019-02-15 15:42:24 -0800 | [diff] [blame] | 910 |     const bool expensiveRenderingExpected = | 
| Lucas Dupin | 2dd6f39 | 2020-02-18 17:43:36 -0800 | [diff] [blame] | 911 |             clientCompositionDisplay.outputDataspace == ui::Dataspace::DISPLAY_P3 || expensiveBlurs; | 
| Lloyd Pique | 688abd4 | 2019-02-15 15:42:24 -0800 | [diff] [blame] | 912 |     if (expensiveRenderingExpected) { | 
 | 913 |         setExpensiveRenderingExpected(true); | 
 | 914 |     } | 
 | 915 |  | 
| Vishnu Nair | 9b079a2 | 2020-01-21 14:36:08 -0800 | [diff] [blame] | 916 |     std::vector<const renderengine::LayerSettings*> clientCompositionLayerPointers; | 
 | 917 |     clientCompositionLayerPointers.reserve(clientCompositionLayers.size()); | 
 | 918 |     std::transform(clientCompositionLayers.begin(), clientCompositionLayers.end(), | 
 | 919 |                    std::back_inserter(clientCompositionLayerPointers), | 
 | 920 |                    [](LayerFE::LayerSettings& settings) -> renderengine::LayerSettings* { | 
 | 921 |                        return &settings; | 
 | 922 |                    }); | 
 | 923 |  | 
| Alec Mouri | e4034bb | 2019-11-19 12:45:54 -0800 | [diff] [blame] | 924 |     const nsecs_t renderEngineStart = systemTime(); | 
| Vishnu Nair | 9b079a2 | 2020-01-21 14:36:08 -0800 | [diff] [blame] | 925 |     status_t status = | 
 | 926 |             renderEngine.drawLayers(clientCompositionDisplay, clientCompositionLayerPointers, | 
 | 927 |                                     buf->getNativeBuffer(), /*useFramebufferCache=*/true, | 
 | 928 |                                     std::move(fd), &readyFence); | 
 | 929 |  | 
 | 930 |     if (status != NO_ERROR && mClientCompositionRequestCache) { | 
 | 931 |         // If rendering was not successful, remove the request from the cache. | 
 | 932 |         mClientCompositionRequestCache->remove(buf->getId()); | 
 | 933 |     } | 
 | 934 |  | 
| Alec Mouri | e4034bb | 2019-11-19 12:45:54 -0800 | [diff] [blame] | 935 |     auto& timeStats = getCompositionEngine().getTimeStats(); | 
 | 936 |     if (readyFence.get() < 0) { | 
 | 937 |         timeStats.recordRenderEngineDuration(renderEngineStart, systemTime()); | 
 | 938 |     } else { | 
 | 939 |         timeStats.recordRenderEngineDuration(renderEngineStart, | 
 | 940 |                                              std::make_shared<FenceTime>( | 
 | 941 |                                                      new Fence(dup(readyFence.get())))); | 
 | 942 |     } | 
| Lloyd Pique | 688abd4 | 2019-02-15 15:42:24 -0800 | [diff] [blame] | 943 |  | 
| Lloyd Pique | d3d6988 | 2019-02-28 16:03:46 -0800 | [diff] [blame] | 944 |     return readyFence; | 
| Lloyd Pique | 688abd4 | 2019-02-15 15:42:24 -0800 | [diff] [blame] | 945 | } | 
 | 946 |  | 
| Vishnu Nair | 9b079a2 | 2020-01-21 14:36:08 -0800 | [diff] [blame] | 947 | std::vector<LayerFE::LayerSettings> Output::generateClientCompositionRequests( | 
| Vishnu Nair | 3a7346c | 2019-12-04 08:09:09 -0800 | [diff] [blame] | 948 |         bool supportsProtectedContent, Region& clearRegion, ui::Dataspace outputDataspace) { | 
| Vishnu Nair | 9b079a2 | 2020-01-21 14:36:08 -0800 | [diff] [blame] | 949 |     std::vector<LayerFE::LayerSettings> clientCompositionLayers; | 
| Lloyd Pique | 688abd4 | 2019-02-15 15:42:24 -0800 | [diff] [blame] | 950 |     ALOGV("Rendering client layers"); | 
 | 951 |  | 
| Lloyd Pique | a38ea7e | 2019-04-16 18:10:26 -0700 | [diff] [blame] | 952 |     const auto& outputState = getState(); | 
 | 953 |     const Region viewportRegion(outputState.viewport); | 
| Lloyd Pique | 688abd4 | 2019-02-15 15:42:24 -0800 | [diff] [blame] | 954 |     const bool useIdentityTransform = false; | 
 | 955 |     bool firstLayer = true; | 
 | 956 |     // Used when a layer clears part of the buffer. | 
| Xin Li | e8b4e70 | 2020-08-29 01:34:09 -0700 | [diff] [blame] | 957 |     Region stubRegion; | 
| Lloyd Pique | 688abd4 | 2019-02-15 15:42:24 -0800 | [diff] [blame] | 958 |  | 
| Lloyd Pique | 01c77c1 | 2019-04-17 12:48:32 -0700 | [diff] [blame] | 959 |     for (auto* layer : getOutputLayersOrderedByZ()) { | 
| Lloyd Pique | 688abd4 | 2019-02-15 15:42:24 -0800 | [diff] [blame] | 960 |         const auto& layerState = layer->getState(); | 
| Lloyd Pique | de19665 | 2020-01-22 17:29:58 -0800 | [diff] [blame] | 961 |         const auto* layerFEState = layer->getLayerFE().getCompositionState(); | 
| Lloyd Pique | 688abd4 | 2019-02-15 15:42:24 -0800 | [diff] [blame] | 962 |         auto& layerFE = layer->getLayerFE(); | 
 | 963 |  | 
| Lloyd Pique | a246866 | 2019-03-07 21:31:06 -0800 | [diff] [blame] | 964 |         const Region clip(viewportRegion.intersect(layerState.visibleRegion)); | 
| Lloyd Pique | 688abd4 | 2019-02-15 15:42:24 -0800 | [diff] [blame] | 965 |         ALOGV("Layer: %s", layerFE.getDebugName()); | 
 | 966 |         if (clip.isEmpty()) { | 
 | 967 |             ALOGV("  Skipping for empty clip"); | 
 | 968 |             firstLayer = false; | 
 | 969 |             continue; | 
 | 970 |         } | 
 | 971 |  | 
| Vishnu Nair | a483b4a | 2019-12-12 15:07:52 -0800 | [diff] [blame] | 972 |         const bool clientComposition = layer->requiresClientComposition(); | 
| Lloyd Pique | 688abd4 | 2019-02-15 15:42:24 -0800 | [diff] [blame] | 973 |  | 
 | 974 |         // We clear the client target for non-client composed layers if | 
 | 975 |         // requested by the HWC. We skip this if the layer is not an opaque | 
 | 976 |         // rectangle, as by definition the layer must blend with whatever is | 
 | 977 |         // underneath. We also skip the first layer as the buffer target is | 
 | 978 |         // guaranteed to start out cleared. | 
| Vishnu Nair | b87d94f | 2020-02-13 09:17:36 -0800 | [diff] [blame] | 979 |         const bool clearClientComposition = | 
| Lloyd Pique | de19665 | 2020-01-22 17:29:58 -0800 | [diff] [blame] | 980 |                 layerState.clearClientTarget && layerFEState->isOpaque && !firstLayer; | 
| Lloyd Pique | 688abd4 | 2019-02-15 15:42:24 -0800 | [diff] [blame] | 981 |  | 
 | 982 |         ALOGV("  Composition type: client %d clear %d", clientComposition, clearClientComposition); | 
 | 983 |  | 
| Vishnu Nair | b87d94f | 2020-02-13 09:17:36 -0800 | [diff] [blame] | 984 |         // If the layer casts a shadow but the content casting the shadow is occluded, skip | 
 | 985 |         // composing the non-shadow content and only draw the shadows. | 
 | 986 |         const bool realContentIsVisible = clientComposition && | 
 | 987 |                 !layerState.visibleRegion.subtract(layerState.shadowRegion).isEmpty(); | 
 | 988 |  | 
| Lloyd Pique | 688abd4 | 2019-02-15 15:42:24 -0800 | [diff] [blame] | 989 |         if (clientComposition || clearClientComposition) { | 
 | 990 |             compositionengine::LayerFE::ClientCompositionTargetSettings targetSettings{ | 
 | 991 |                     clip, | 
 | 992 |                     useIdentityTransform, | 
| Lloyd Pique | a38ea7e | 2019-04-16 18:10:26 -0700 | [diff] [blame] | 993 |                     layer->needsFiltering() || outputState.needsFiltering, | 
 | 994 |                     outputState.isSecure, | 
| Lloyd Pique | 688abd4 | 2019-02-15 15:42:24 -0800 | [diff] [blame] | 995 |                     supportsProtectedContent, | 
| Xin Li | e8b4e70 | 2020-08-29 01:34:09 -0700 | [diff] [blame] | 996 |                     clientComposition ? clearRegion : stubRegion, | 
| Vishnu Nair | b87d94f | 2020-02-13 09:17:36 -0800 | [diff] [blame] | 997 |                     outputState.viewport, | 
 | 998 |                     outputDataspace, | 
 | 999 |                     realContentIsVisible, | 
 | 1000 |                     !clientComposition, /* clearContent  */ | 
| Lloyd Pique | 688abd4 | 2019-02-15 15:42:24 -0800 | [diff] [blame] | 1001 |             }; | 
| Vishnu Nair | b87d94f | 2020-02-13 09:17:36 -0800 | [diff] [blame] | 1002 |             std::vector<LayerFE::LayerSettings> results = | 
 | 1003 |                     layerFE.prepareClientCompositionList(targetSettings); | 
 | 1004 |             if (realContentIsVisible && !results.empty()) { | 
 | 1005 |                 layer->editState().clientCompositionTimestamp = systemTime(); | 
| Lloyd Pique | 688abd4 | 2019-02-15 15:42:24 -0800 | [diff] [blame] | 1006 |             } | 
| Vishnu Nair | b87d94f | 2020-02-13 09:17:36 -0800 | [diff] [blame] | 1007 |  | 
 | 1008 |             clientCompositionLayers.insert(clientCompositionLayers.end(), | 
 | 1009 |                                            std::make_move_iterator(results.begin()), | 
 | 1010 |                                            std::make_move_iterator(results.end())); | 
 | 1011 |             results.clear(); | 
| Lloyd Pique | 688abd4 | 2019-02-15 15:42:24 -0800 | [diff] [blame] | 1012 |         } | 
 | 1013 |  | 
 | 1014 |         firstLayer = false; | 
 | 1015 |     } | 
 | 1016 |  | 
 | 1017 |     return clientCompositionLayers; | 
 | 1018 | } | 
 | 1019 |  | 
 | 1020 | void Output::appendRegionFlashRequests( | 
| Vishnu Nair | 9b079a2 | 2020-01-21 14:36:08 -0800 | [diff] [blame] | 1021 |         const Region& flashRegion, std::vector<LayerFE::LayerSettings>& clientCompositionLayers) { | 
| Lloyd Pique | 688abd4 | 2019-02-15 15:42:24 -0800 | [diff] [blame] | 1022 |     if (flashRegion.isEmpty()) { | 
 | 1023 |         return; | 
 | 1024 |     } | 
 | 1025 |  | 
| Vishnu Nair | 9b079a2 | 2020-01-21 14:36:08 -0800 | [diff] [blame] | 1026 |     LayerFE::LayerSettings layerSettings; | 
| Lloyd Pique | 688abd4 | 2019-02-15 15:42:24 -0800 | [diff] [blame] | 1027 |     layerSettings.source.buffer.buffer = nullptr; | 
 | 1028 |     layerSettings.source.solidColor = half3(1.0, 0.0, 1.0); | 
 | 1029 |     layerSettings.alpha = half(1.0); | 
 | 1030 |  | 
 | 1031 |     for (const auto& rect : flashRegion) { | 
 | 1032 |         layerSettings.geometry.boundaries = rect.toFloatRect(); | 
 | 1033 |         clientCompositionLayers.push_back(layerSettings); | 
 | 1034 |     } | 
 | 1035 | } | 
 | 1036 |  | 
 | 1037 | void Output::setExpensiveRenderingExpected(bool) { | 
 | 1038 |     // The base class does nothing with this call. | 
 | 1039 | } | 
 | 1040 |  | 
| Lloyd Pique | 35fca9d | 2019-02-13 14:24:11 -0800 | [diff] [blame] | 1041 | void Output::postFramebuffer() { | 
 | 1042 |     ATRACE_CALL(); | 
 | 1043 |     ALOGV(__FUNCTION__); | 
 | 1044 |  | 
 | 1045 |     if (!getState().isEnabled) { | 
 | 1046 |         return; | 
 | 1047 |     } | 
 | 1048 |  | 
| Lloyd Pique | a38ea7e | 2019-04-16 18:10:26 -0700 | [diff] [blame] | 1049 |     auto& outputState = editState(); | 
 | 1050 |     outputState.dirtyRegion.clear(); | 
| Lloyd Pique | d3d6988 | 2019-02-28 16:03:46 -0800 | [diff] [blame] | 1051 |     mRenderSurface->flip(); | 
 | 1052 |  | 
| Lloyd Pique | 35fca9d | 2019-02-13 14:24:11 -0800 | [diff] [blame] | 1053 |     auto frame = presentAndGetFrameFences(); | 
 | 1054 |  | 
| Lloyd Pique | 7d90ba5 | 2019-08-08 11:57:53 -0700 | [diff] [blame] | 1055 |     mRenderSurface->onPresentDisplayCompleted(); | 
 | 1056 |  | 
| Lloyd Pique | 01c77c1 | 2019-04-17 12:48:32 -0700 | [diff] [blame] | 1057 |     for (auto* layer : getOutputLayersOrderedByZ()) { | 
| Lloyd Pique | 35fca9d | 2019-02-13 14:24:11 -0800 | [diff] [blame] | 1058 |         // The layer buffer from the previous frame (if any) is released | 
 | 1059 |         // by HWC only when the release fence from this frame (if any) is | 
 | 1060 |         // signaled.  Always get the release fence from HWC first. | 
 | 1061 |         sp<Fence> releaseFence = Fence::NO_FENCE; | 
 | 1062 |  | 
 | 1063 |         if (auto hwcLayer = layer->getHwcLayer()) { | 
 | 1064 |             if (auto f = frame.layerFences.find(hwcLayer); f != frame.layerFences.end()) { | 
 | 1065 |                 releaseFence = f->second; | 
 | 1066 |             } | 
 | 1067 |         } | 
 | 1068 |  | 
 | 1069 |         // If the layer was client composited in the previous frame, we | 
 | 1070 |         // need to merge with the previous client target acquire fence. | 
 | 1071 |         // Since we do not track that, always merge with the current | 
 | 1072 |         // client target acquire fence when it is available, even though | 
 | 1073 |         // this is suboptimal. | 
 | 1074 |         // TODO(b/121291683): Track previous frame client target acquire fence. | 
| Lloyd Pique | a38ea7e | 2019-04-16 18:10:26 -0700 | [diff] [blame] | 1075 |         if (outputState.usesClientComposition) { | 
| Lloyd Pique | 35fca9d | 2019-02-13 14:24:11 -0800 | [diff] [blame] | 1076 |             releaseFence = | 
 | 1077 |                     Fence::merge("LayerRelease", releaseFence, frame.clientTargetAcquireFence); | 
 | 1078 |         } | 
 | 1079 |  | 
 | 1080 |         layer->getLayerFE().onLayerDisplayed(releaseFence); | 
 | 1081 |     } | 
 | 1082 |  | 
 | 1083 |     // We've got a list of layers needing fences, that are disjoint with | 
| Lloyd Pique | 01c77c1 | 2019-04-17 12:48:32 -0700 | [diff] [blame] | 1084 |     // OutputLayersOrderedByZ.  The best we can do is to | 
| Lloyd Pique | 35fca9d | 2019-02-13 14:24:11 -0800 | [diff] [blame] | 1085 |     // supply them with the present fence. | 
 | 1086 |     for (auto& weakLayer : mReleasedLayers) { | 
 | 1087 |         if (auto layer = weakLayer.promote(); layer != nullptr) { | 
 | 1088 |             layer->onLayerDisplayed(frame.presentFence); | 
 | 1089 |         } | 
 | 1090 |     } | 
 | 1091 |  | 
 | 1092 |     // Clear out the released layers now that we're done with them. | 
 | 1093 |     mReleasedLayers.clear(); | 
| Lloyd Pique | cc01a45 | 2018-12-04 17:24:00 -0800 | [diff] [blame] | 1094 | } | 
 | 1095 |  | 
| Lloyd Pique | 32cbe28 | 2018-10-19 13:09:22 -0700 | [diff] [blame] | 1096 | void Output::dirtyEntireOutput() { | 
| Lloyd Pique | a38ea7e | 2019-04-16 18:10:26 -0700 | [diff] [blame] | 1097 |     auto& outputState = editState(); | 
 | 1098 |     outputState.dirtyRegion.set(outputState.bounds); | 
| Lloyd Pique | 32cbe28 | 2018-10-19 13:09:22 -0700 | [diff] [blame] | 1099 | } | 
 | 1100 |  | 
| Lloyd Pique | 66d6860 | 2019-02-13 14:23:31 -0800 | [diff] [blame] | 1101 | void Output::chooseCompositionStrategy() { | 
 | 1102 |     // The base output implementation can only do client composition | 
| Lloyd Pique | a38ea7e | 2019-04-16 18:10:26 -0700 | [diff] [blame] | 1103 |     auto& outputState = editState(); | 
 | 1104 |     outputState.usesClientComposition = true; | 
 | 1105 |     outputState.usesDeviceComposition = false; | 
| Vishnu Nair | 9b079a2 | 2020-01-21 14:36:08 -0800 | [diff] [blame] | 1106 |     outputState.reusedClientComposition = false; | 
| Lloyd Pique | 66d6860 | 2019-02-13 14:23:31 -0800 | [diff] [blame] | 1107 | } | 
 | 1108 |  | 
| Lloyd Pique | 688abd4 | 2019-02-15 15:42:24 -0800 | [diff] [blame] | 1109 | bool Output::getSkipColorTransform() const { | 
 | 1110 |     return true; | 
 | 1111 | } | 
 | 1112 |  | 
| Lloyd Pique | 35fca9d | 2019-02-13 14:24:11 -0800 | [diff] [blame] | 1113 | compositionengine::Output::FrameFences Output::presentAndGetFrameFences() { | 
 | 1114 |     compositionengine::Output::FrameFences result; | 
| Lloyd Pique | a38ea7e | 2019-04-16 18:10:26 -0700 | [diff] [blame] | 1115 |     if (getState().usesClientComposition) { | 
| Lloyd Pique | 35fca9d | 2019-02-13 14:24:11 -0800 | [diff] [blame] | 1116 |         result.clientTargetAcquireFence = mRenderSurface->getClientTargetAcquireFence(); | 
 | 1117 |     } | 
 | 1118 |     return result; | 
| Lloyd Pique | 32cbe28 | 2018-10-19 13:09:22 -0700 | [diff] [blame] | 1119 | } | 
 | 1120 |  | 
| Lloyd Pique | feb73d7 | 2018-12-04 17:23:44 -0800 | [diff] [blame] | 1121 | } // namespace impl | 
 | 1122 | } // namespace android::compositionengine |