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