| /* | 
 |  * Copyright (C) 2010 The Android Open Source Project | 
 |  * | 
 |  * Licensed under the Apache License, Version 2.0 (the "License"); | 
 |  * you may not use this file except in compliance with the License. | 
 |  * You may obtain a copy of the License at | 
 |  * | 
 |  *      http://www.apache.org/licenses/LICENSE-2.0 | 
 |  * | 
 |  * Unless required by applicable law or agreed to in writing, software | 
 |  * distributed under the License is distributed on an "AS IS" BASIS, | 
 |  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 
 |  * See the License for the specific language governing permissions and | 
 |  * limitations under the License. | 
 |  */ | 
 |  | 
 | // #define LOG_NDEBUG 0 | 
 |  | 
 | #undef LOG_TAG | 
 | #define LOG_TAG "HWComposer" | 
 | #define ATRACE_TAG ATRACE_TAG_GRAPHICS | 
 |  | 
 | #include <inttypes.h> | 
 | #include <math.h> | 
 | #include <stdint.h> | 
 | #include <stdio.h> | 
 | #include <stdlib.h> | 
 | #include <string.h> | 
 | #include <sys/types.h> | 
 |  | 
 | #include <utils/Errors.h> | 
 | #include <utils/misc.h> | 
 | #include <utils/NativeHandle.h> | 
 | #include <utils/String8.h> | 
 | #include <utils/Thread.h> | 
 | #include <utils/Trace.h> | 
 | #include <utils/Vector.h> | 
 |  | 
 | #include <ui/GraphicBuffer.h> | 
 |  | 
 | #include <hardware/hardware.h> | 
 | #include <hardware/hwcomposer.h> | 
 |  | 
 | #include <android/configuration.h> | 
 |  | 
 | #include <cutils/properties.h> | 
 | #include <log/log.h> | 
 |  | 
 | #include "HWComposer.h" | 
 | #include "HWC2.h" | 
 | #include "ComposerHal.h" | 
 |  | 
 | #include "../Layer.h"           // needed only for debugging | 
 | #include "../SurfaceFlinger.h" | 
 |  | 
 | namespace android { | 
 |  | 
 | #define MIN_HWC_HEADER_VERSION HWC_HEADER_VERSION | 
 |  | 
 | // --------------------------------------------------------------------------- | 
 |  | 
 | HWComposer::HWComposer(std::unique_ptr<android::Hwc2::Composer> composer) | 
 |       : mHwcDevice(std::make_unique<HWC2::Device>(std::move(composer))) {} | 
 |  | 
 | HWComposer::~HWComposer() = default; | 
 |  | 
 | void HWComposer::registerCallback(HWC2::ComposerCallback* callback, | 
 |                                   int32_t sequenceId) { | 
 |     mHwcDevice->registerCallback(callback, sequenceId); | 
 | } | 
 |  | 
 | bool HWComposer::hasCapability(HWC2::Capability capability) const | 
 | { | 
 |     return mHwcDevice->getCapabilities().count(capability) > 0; | 
 | } | 
 |  | 
 | bool HWComposer::isValidDisplay(int32_t displayId) const { | 
 |     return static_cast<size_t>(displayId) < mDisplayData.size() && | 
 |             mDisplayData[displayId].hwcDisplay; | 
 | } | 
 |  | 
 | void HWComposer::validateChange(HWC2::Composition from, HWC2::Composition to) { | 
 |     bool valid = true; | 
 |     switch (from) { | 
 |         case HWC2::Composition::Client: | 
 |             valid = false; | 
 |             break; | 
 |         case HWC2::Composition::Device: | 
 |         case HWC2::Composition::SolidColor: | 
 |             valid = (to == HWC2::Composition::Client); | 
 |             break; | 
 |         case HWC2::Composition::Cursor: | 
 |         case HWC2::Composition::Sideband: | 
 |             valid = (to == HWC2::Composition::Client || | 
 |                     to == HWC2::Composition::Device); | 
 |             break; | 
 |         default: | 
 |             break; | 
 |     } | 
 |  | 
 |     if (!valid) { | 
 |         ALOGE("Invalid layer type change: %s --> %s", to_string(from).c_str(), | 
 |                 to_string(to).c_str()); | 
 |     } | 
 | } | 
 |  | 
 | void HWComposer::onHotplug(hwc2_display_t displayId, int32_t displayType, | 
 |                            HWC2::Connection connection) { | 
 |     if (displayType >= HWC_NUM_PHYSICAL_DISPLAY_TYPES) { | 
 |         ALOGE("Invalid display type of %d", displayType); | 
 |         return; | 
 |     } | 
 |  | 
 |     ALOGV("hotplug: %" PRIu64 ", %s %s", displayId, | 
 |             displayType == DisplayDevice::DISPLAY_PRIMARY ? "primary" : "external", | 
 |             to_string(connection).c_str()); | 
 |     mHwcDevice->onHotplug(displayId, connection); | 
 |     // Disconnect is handled through HWComposer::disconnectDisplay via | 
 |     // SurfaceFlinger's onHotplugReceived callback handling | 
 |     if (connection == HWC2::Connection::Connected) { | 
 |         mDisplayData[displayType].hwcDisplay = mHwcDevice->getDisplayById(displayId); | 
 |         mHwcDisplaySlots[displayId] = displayType; | 
 |     } | 
 | } | 
 |  | 
 | bool HWComposer::onVsync(hwc2_display_t displayId, int64_t timestamp, | 
 |                          int32_t* outDisplay) { | 
 |     auto display = mHwcDevice->getDisplayById(displayId); | 
 |     if (!display) { | 
 |         ALOGE("onVsync Failed to find display %" PRIu64, displayId); | 
 |         return false; | 
 |     } | 
 |     auto displayType = HWC2::DisplayType::Invalid; | 
 |     auto error = display->getType(&displayType); | 
 |     if (error != HWC2::Error::None) { | 
 |         ALOGE("onVsync: Failed to determine type of display %" PRIu64, | 
 |                 display->getId()); | 
 |         return false; | 
 |     } | 
 |  | 
 |     if (displayType == HWC2::DisplayType::Virtual) { | 
 |         ALOGE("Virtual display %" PRIu64 " passed to vsync callback", | 
 |                 display->getId()); | 
 |         return false; | 
 |     } | 
 |  | 
 |     if (mHwcDisplaySlots.count(display->getId()) == 0) { | 
 |         ALOGE("Unknown physical display %" PRIu64 " passed to vsync callback", | 
 |                 display->getId()); | 
 |         return false; | 
 |     } | 
 |  | 
 |     int32_t disp = mHwcDisplaySlots[display->getId()]; | 
 |     { | 
 |         Mutex::Autolock _l(mLock); | 
 |  | 
 |         // There have been reports of HWCs that signal several vsync events | 
 |         // with the same timestamp when turning the display off and on. This | 
 |         // is a bug in the HWC implementation, but filter the extra events | 
 |         // out here so they don't cause havoc downstream. | 
 |         if (timestamp == mLastHwVSync[disp]) { | 
 |             ALOGW("Ignoring duplicate VSYNC event from HWC (t=%" PRId64 ")", | 
 |                     timestamp); | 
 |             return false; | 
 |         } | 
 |  | 
 |         mLastHwVSync[disp] = timestamp; | 
 |     } | 
 |  | 
 |     if (outDisplay) { | 
 |         *outDisplay = disp; | 
 |     } | 
 |  | 
 |     char tag[16]; | 
 |     snprintf(tag, sizeof(tag), "HW_VSYNC_%1u", disp); | 
 |     ATRACE_INT(tag, ++mVSyncCounts[disp] & 1); | 
 |  | 
 |     return true; | 
 | } | 
 |  | 
 | status_t HWComposer::allocateVirtualDisplay(uint32_t width, uint32_t height, | 
 |         ui::PixelFormat* format, int32_t *outId) { | 
 |     if (mRemainingHwcVirtualDisplays == 0) { | 
 |         ALOGE("allocateVirtualDisplay: No remaining virtual displays"); | 
 |         return NO_MEMORY; | 
 |     } | 
 |  | 
 |     if (SurfaceFlinger::maxVirtualDisplaySize != 0 && | 
 |         (width > SurfaceFlinger::maxVirtualDisplaySize || | 
 |          height > SurfaceFlinger::maxVirtualDisplaySize)) { | 
 |         ALOGE("createVirtualDisplay: Can't create a virtual display with" | 
 |                       " a dimension > %" PRIu64 " (tried %u x %u)", | 
 |               SurfaceFlinger::maxVirtualDisplaySize, width, height); | 
 |         return INVALID_OPERATION; | 
 |     } | 
 |  | 
 |     HWC2::Display* display; | 
 |     auto error = mHwcDevice->createVirtualDisplay(width, height, format, | 
 |             &display); | 
 |     if (error != HWC2::Error::None) { | 
 |         ALOGE("allocateVirtualDisplay: Failed to create HWC virtual display"); | 
 |         return NO_MEMORY; | 
 |     } | 
 |  | 
 |     size_t displaySlot = 0; | 
 |     if (!mFreeDisplaySlots.empty()) { | 
 |         displaySlot = *mFreeDisplaySlots.begin(); | 
 |         mFreeDisplaySlots.erase(displaySlot); | 
 |     } else if (mDisplayData.size() < INT32_MAX) { | 
 |         // Don't bother allocating a slot larger than we can return | 
 |         displaySlot = mDisplayData.size(); | 
 |         mDisplayData.resize(displaySlot + 1); | 
 |     } else { | 
 |         ALOGE("allocateVirtualDisplay: Unable to allocate a display slot"); | 
 |         return NO_MEMORY; | 
 |     } | 
 |  | 
 |     mDisplayData[displaySlot].hwcDisplay = display; | 
 |  | 
 |     --mRemainingHwcVirtualDisplays; | 
 |     *outId = static_cast<int32_t>(displaySlot); | 
 |  | 
 |     return NO_ERROR; | 
 | } | 
 |  | 
 | HWC2::Layer* HWComposer::createLayer(int32_t displayId) { | 
 |     if (!isValidDisplay(displayId)) { | 
 |         ALOGE("Failed to create layer on invalid display %d", displayId); | 
 |         return nullptr; | 
 |     } | 
 |     auto display = mDisplayData[displayId].hwcDisplay; | 
 |     HWC2::Layer* layer; | 
 |     auto error = display->createLayer(&layer); | 
 |     if (error != HWC2::Error::None) { | 
 |         ALOGE("Failed to create layer on display %d: %s (%d)", displayId, | 
 |                 to_string(error).c_str(), static_cast<int32_t>(error)); | 
 |         return nullptr; | 
 |     } | 
 |     return layer; | 
 | } | 
 |  | 
 | void HWComposer::destroyLayer(int32_t displayId, HWC2::Layer* layer) { | 
 |     if (!isValidDisplay(displayId)) { | 
 |         ALOGE("Failed to destroy layer on invalid display %d", displayId); | 
 |         return; | 
 |     } | 
 |     auto display = mDisplayData[displayId].hwcDisplay; | 
 |     auto error = display->destroyLayer(layer); | 
 |     if (error != HWC2::Error::None) { | 
 |         ALOGE("Failed to destroy layer on display %d: %s (%d)", displayId, | 
 |                 to_string(error).c_str(), static_cast<int32_t>(error)); | 
 |     } | 
 | } | 
 |  | 
 | nsecs_t HWComposer::getRefreshTimestamp(int32_t displayId) const { | 
 |     // this returns the last refresh timestamp. | 
 |     // if the last one is not available, we estimate it based on | 
 |     // the refresh period and whatever closest timestamp we have. | 
 |     Mutex::Autolock _l(mLock); | 
 |     nsecs_t now = systemTime(CLOCK_MONOTONIC); | 
 |     auto vsyncPeriod = getActiveConfig(displayId)->getVsyncPeriod(); | 
 |     return now - ((now - mLastHwVSync[displayId]) % vsyncPeriod); | 
 | } | 
 |  | 
 | bool HWComposer::isConnected(int32_t displayId) const { | 
 |     if (!isValidDisplay(displayId)) { | 
 |         ALOGE("isConnected: Attempted to access invalid display %d", displayId); | 
 |         return false; | 
 |     } | 
 |     return mDisplayData[displayId].hwcDisplay->isConnected(); | 
 | } | 
 |  | 
 | std::vector<std::shared_ptr<const HWC2::Display::Config>> | 
 |         HWComposer::getConfigs(int32_t displayId) const { | 
 |     if (!isValidDisplay(displayId)) { | 
 |         ALOGE("getConfigs: Attempted to access invalid display %d", displayId); | 
 |         return {}; | 
 |     } | 
 |     auto& displayData = mDisplayData[displayId]; | 
 |     auto configs = mDisplayData[displayId].hwcDisplay->getConfigs(); | 
 |     if (displayData.configMap.empty()) { | 
 |         for (size_t i = 0; i < configs.size(); ++i) { | 
 |             displayData.configMap[i] = configs[i]; | 
 |         } | 
 |     } | 
 |     return configs; | 
 | } | 
 |  | 
 | std::shared_ptr<const HWC2::Display::Config> | 
 |         HWComposer::getActiveConfig(int32_t displayId) const { | 
 |     if (!isValidDisplay(displayId)) { | 
 |         ALOGV("getActiveConfigs: Attempted to access invalid display %d", | 
 |                 displayId); | 
 |         return nullptr; | 
 |     } | 
 |     std::shared_ptr<const HWC2::Display::Config> config; | 
 |     auto error = mDisplayData[displayId].hwcDisplay->getActiveConfig(&config); | 
 |     if (error == HWC2::Error::BadConfig) { | 
 |         ALOGE("getActiveConfig: No config active, returning null"); | 
 |         return nullptr; | 
 |     } else if (error != HWC2::Error::None) { | 
 |         ALOGE("getActiveConfig failed for display %d: %s (%d)", displayId, | 
 |                 to_string(error).c_str(), static_cast<int32_t>(error)); | 
 |         return nullptr; | 
 |     } else if (!config) { | 
 |         ALOGE("getActiveConfig returned an unknown config for display %d", | 
 |                 displayId); | 
 |         return nullptr; | 
 |     } | 
 |  | 
 |     return config; | 
 | } | 
 |  | 
 | std::vector<ui::ColorMode> HWComposer::getColorModes(int32_t displayId) const { | 
 |     std::vector<ui::ColorMode> modes; | 
 |  | 
 |     if (!isValidDisplay(displayId)) { | 
 |         ALOGE("getColorModes: Attempted to access invalid display %d", | 
 |                 displayId); | 
 |         return modes; | 
 |     } | 
 |  | 
 |     auto error = mDisplayData[displayId].hwcDisplay->getColorModes(&modes); | 
 |     if (error != HWC2::Error::None) { | 
 |         ALOGE("getColorModes failed for display %d: %s (%d)", displayId, | 
 |                 to_string(error).c_str(), static_cast<int32_t>(error)); | 
 |         return std::vector<ui::ColorMode>(); | 
 |     } | 
 |  | 
 |     return modes; | 
 | } | 
 |  | 
 | status_t HWComposer::setActiveColorMode(int32_t displayId, ui::ColorMode mode, | 
 |         ui::RenderIntent renderIntent) { | 
 |     if (!isValidDisplay(displayId)) { | 
 |         ALOGE("setActiveColorMode: Display %d is not valid", displayId); | 
 |         return BAD_INDEX; | 
 |     } | 
 |  | 
 |     auto& displayData = mDisplayData[displayId]; | 
 |     auto error = displayData.hwcDisplay->setColorMode(mode, renderIntent); | 
 |     if (error != HWC2::Error::None) { | 
 |         ALOGE("setActiveConfig: Failed to set color mode %d" | 
 |                 "with render intent %d on display %d: " | 
 |                 "%s (%d)", mode, renderIntent, displayId, | 
 |                 to_string(error).c_str(), | 
 |                 static_cast<int32_t>(error)); | 
 |         return UNKNOWN_ERROR; | 
 |     } | 
 |  | 
 |     return NO_ERROR; | 
 | } | 
 |  | 
 |  | 
 | void HWComposer::setVsyncEnabled(int32_t displayId, HWC2::Vsync enabled) { | 
 |     if (displayId < 0 || displayId >= HWC_DISPLAY_VIRTUAL) { | 
 |         ALOGD("setVsyncEnabled: Ignoring for virtual display %d", displayId); | 
 |         return; | 
 |     } | 
 |  | 
 |     if (!isValidDisplay(displayId)) { | 
 |         ALOGE("setVsyncEnabled: Attempted to access invalid display %d", | 
 |                displayId); | 
 |         return; | 
 |     } | 
 |  | 
 |     // NOTE: we use our own internal lock here because we have to call | 
 |     // into the HWC with the lock held, and we want to make sure | 
 |     // that even if HWC blocks (which it shouldn't), it won't | 
 |     // affect other threads. | 
 |     Mutex::Autolock _l(mVsyncLock); | 
 |     auto& displayData = mDisplayData[displayId]; | 
 |     if (enabled != displayData.vsyncEnabled) { | 
 |         ATRACE_CALL(); | 
 |         auto error = displayData.hwcDisplay->setVsyncEnabled(enabled); | 
 |         if (error == HWC2::Error::None) { | 
 |             displayData.vsyncEnabled = enabled; | 
 |  | 
 |             char tag[16]; | 
 |             snprintf(tag, sizeof(tag), "HW_VSYNC_ON_%1u", displayId); | 
 |             ATRACE_INT(tag, enabled == HWC2::Vsync::Enable ? 1 : 0); | 
 |         } else { | 
 |             ALOGE("setVsyncEnabled: Failed to set vsync to %s on %d/%" PRIu64 | 
 |                     ": %s (%d)", to_string(enabled).c_str(), displayId, | 
 |                     mDisplayData[displayId].hwcDisplay->getId(), | 
 |                     to_string(error).c_str(), static_cast<int32_t>(error)); | 
 |         } | 
 |     } | 
 | } | 
 |  | 
 | status_t HWComposer::setClientTarget(int32_t displayId, uint32_t slot, | 
 |         const sp<Fence>& acquireFence, const sp<GraphicBuffer>& target, | 
 |         ui::Dataspace dataspace) { | 
 |     if (!isValidDisplay(displayId)) { | 
 |         return BAD_INDEX; | 
 |     } | 
 |  | 
 |     ALOGV("setClientTarget for display %d", displayId); | 
 |     auto& hwcDisplay = mDisplayData[displayId].hwcDisplay; | 
 |     auto error = hwcDisplay->setClientTarget(slot, target, acquireFence, dataspace); | 
 |     if (error != HWC2::Error::None) { | 
 |         ALOGE("Failed to set client target for display %d: %s (%d)", displayId, | 
 |                 to_string(error).c_str(), static_cast<int32_t>(error)); | 
 |         return BAD_VALUE; | 
 |     } | 
 |  | 
 |     return NO_ERROR; | 
 | } | 
 |  | 
 | status_t HWComposer::prepare(DisplayDevice& displayDevice) { | 
 |     ATRACE_CALL(); | 
 |  | 
 |     Mutex::Autolock _l(mDisplayLock); | 
 |     auto displayId = displayDevice.getHwcDisplayId(); | 
 |     if (displayId == DisplayDevice::DISPLAY_ID_INVALID) { | 
 |         ALOGV("Skipping HWComposer prepare for non-HWC display"); | 
 |         return NO_ERROR; | 
 |     } | 
 |     if (!isValidDisplay(displayId)) { | 
 |         return BAD_INDEX; | 
 |     } | 
 |  | 
 |     auto& displayData = mDisplayData[displayId]; | 
 |     auto& hwcDisplay = displayData.hwcDisplay; | 
 |     if (!hwcDisplay->isConnected()) { | 
 |         return NO_ERROR; | 
 |     } | 
 |  | 
 |     uint32_t numTypes = 0; | 
 |     uint32_t numRequests = 0; | 
 |  | 
 |     HWC2::Error error = HWC2::Error::None; | 
 |  | 
 |     // First try to skip validate altogether when there is no client | 
 |     // composition.  When there is client composition, since we haven't | 
 |     // rendered to the client target yet, we should not attempt to skip | 
 |     // validate. | 
 |     // | 
 |     // displayData.hasClientComposition hasn't been updated for this frame. | 
 |     // The check below is incorrect.  We actually rely on HWC here to fall | 
 |     // back to validate when there is any client layer. | 
 |     displayData.validateWasSkipped = false; | 
 |     if (!displayData.hasClientComposition) { | 
 |         sp<android::Fence> outPresentFence; | 
 |         uint32_t state = UINT32_MAX; | 
 |         error = hwcDisplay->presentOrValidate(&numTypes, &numRequests, &outPresentFence , &state); | 
 |         if (error != HWC2::Error::None && error != HWC2::Error::HasChanges) { | 
 |             ALOGV("skipValidate: Failed to Present or Validate"); | 
 |             return UNKNOWN_ERROR; | 
 |         } | 
 |         if (state == 1) { //Present Succeeded. | 
 |             std::unordered_map<HWC2::Layer*, sp<Fence>> releaseFences; | 
 |             error = hwcDisplay->getReleaseFences(&releaseFences); | 
 |             displayData.releaseFences = std::move(releaseFences); | 
 |             displayData.lastPresentFence = outPresentFence; | 
 |             displayData.validateWasSkipped = true; | 
 |             displayData.presentError = error; | 
 |             return NO_ERROR; | 
 |         } | 
 |         // Present failed but Validate ran. | 
 |     } else { | 
 |         error = hwcDisplay->validate(&numTypes, &numRequests); | 
 |     } | 
 |     ALOGV("SkipValidate failed, Falling back to SLOW validate/present"); | 
 |     if (error != HWC2::Error::None && error != HWC2::Error::HasChanges) { | 
 |         ALOGE("prepare: validate failed for display %d: %s (%d)", displayId, | 
 |                 to_string(error).c_str(), static_cast<int32_t>(error)); | 
 |         return BAD_INDEX; | 
 |     } | 
 |  | 
 |     std::unordered_map<HWC2::Layer*, HWC2::Composition> changedTypes; | 
 |     changedTypes.reserve(numTypes); | 
 |     error = hwcDisplay->getChangedCompositionTypes(&changedTypes); | 
 |     if (error != HWC2::Error::None) { | 
 |         ALOGE("prepare: getChangedCompositionTypes failed on display %d: " | 
 |                 "%s (%d)", displayId, to_string(error).c_str(), | 
 |                 static_cast<int32_t>(error)); | 
 |         return BAD_INDEX; | 
 |     } | 
 |  | 
 |  | 
 |     displayData.displayRequests = static_cast<HWC2::DisplayRequest>(0); | 
 |     std::unordered_map<HWC2::Layer*, HWC2::LayerRequest> layerRequests; | 
 |     layerRequests.reserve(numRequests); | 
 |     error = hwcDisplay->getRequests(&displayData.displayRequests, | 
 |             &layerRequests); | 
 |     if (error != HWC2::Error::None) { | 
 |         ALOGE("prepare: getRequests failed on display %d: %s (%d)", displayId, | 
 |                 to_string(error).c_str(), static_cast<int32_t>(error)); | 
 |         return BAD_INDEX; | 
 |     } | 
 |  | 
 |     displayData.hasClientComposition = false; | 
 |     displayData.hasDeviceComposition = false; | 
 |     for (auto& layer : displayDevice.getVisibleLayersSortedByZ()) { | 
 |         auto hwcLayer = layer->getHwcLayer(displayId); | 
 |  | 
 |         if (changedTypes.count(hwcLayer) != 0) { | 
 |             // We pass false so we only update our state and don't call back | 
 |             // into the HWC device | 
 |             validateChange(layer->getCompositionType(displayId), | 
 |                     changedTypes[hwcLayer]); | 
 |             layer->setCompositionType(displayId, changedTypes[hwcLayer], false); | 
 |         } | 
 |  | 
 |         switch (layer->getCompositionType(displayId)) { | 
 |             case HWC2::Composition::Client: | 
 |                 displayData.hasClientComposition = true; | 
 |                 break; | 
 |             case HWC2::Composition::Device: | 
 |             case HWC2::Composition::SolidColor: | 
 |             case HWC2::Composition::Cursor: | 
 |             case HWC2::Composition::Sideband: | 
 |                 displayData.hasDeviceComposition = true; | 
 |                 break; | 
 |             default: | 
 |                 break; | 
 |         } | 
 |  | 
 |         if (layerRequests.count(hwcLayer) != 0 && | 
 |                 layerRequests[hwcLayer] == | 
 |                         HWC2::LayerRequest::ClearClientTarget) { | 
 |             layer->setClearClientTarget(displayId, true); | 
 |         } else { | 
 |             if (layerRequests.count(hwcLayer) != 0) { | 
 |                 ALOGE("prepare: Unknown layer request: %s", | 
 |                         to_string(layerRequests[hwcLayer]).c_str()); | 
 |             } | 
 |             layer->setClearClientTarget(displayId, false); | 
 |         } | 
 |     } | 
 |  | 
 |     error = hwcDisplay->acceptChanges(); | 
 |     if (error != HWC2::Error::None) { | 
 |         ALOGE("prepare: acceptChanges failed: %s", to_string(error).c_str()); | 
 |         return BAD_INDEX; | 
 |     } | 
 |  | 
 |     return NO_ERROR; | 
 | } | 
 |  | 
 | bool HWComposer::hasDeviceComposition(int32_t displayId) const { | 
 |     if (displayId == DisplayDevice::DISPLAY_ID_INVALID) { | 
 |         // Displays without a corresponding HWC display are never composed by | 
 |         // the device | 
 |         return false; | 
 |     } | 
 |     if (!isValidDisplay(displayId)) { | 
 |         ALOGE("hasDeviceComposition: Invalid display %d", displayId); | 
 |         return false; | 
 |     } | 
 |     return mDisplayData[displayId].hasDeviceComposition; | 
 | } | 
 |  | 
 | bool HWComposer::hasFlipClientTargetRequest(int32_t displayId) const { | 
 |     if (displayId == DisplayDevice::DISPLAY_ID_INVALID) { | 
 |         // Displays without a corresponding HWC display are never composed by | 
 |         // the device | 
 |         return false; | 
 |     } | 
 |     if (!isValidDisplay(displayId)) { | 
 |         ALOGE("hasFlipClientTargetRequest: Invalid display %d", displayId); | 
 |         return false; | 
 |     } | 
 |     return ((static_cast<uint32_t>(mDisplayData[displayId].displayRequests) & | 
 |              static_cast<uint32_t>(HWC2::DisplayRequest::FlipClientTarget)) != 0); | 
 | } | 
 |  | 
 | bool HWComposer::hasClientComposition(int32_t displayId) const { | 
 |     if (displayId == DisplayDevice::DISPLAY_ID_INVALID) { | 
 |         // Displays without a corresponding HWC display are always composed by | 
 |         // the client | 
 |         return true; | 
 |     } | 
 |     if (!isValidDisplay(displayId)) { | 
 |         ALOGE("hasClientComposition: Invalid display %d", displayId); | 
 |         return true; | 
 |     } | 
 |     return mDisplayData[displayId].hasClientComposition; | 
 | } | 
 |  | 
 | sp<Fence> HWComposer::getPresentFence(int32_t displayId) const { | 
 |     if (!isValidDisplay(displayId)) { | 
 |         ALOGE("getPresentFence failed for invalid display %d", displayId); | 
 |         return Fence::NO_FENCE; | 
 |     } | 
 |     return mDisplayData[displayId].lastPresentFence; | 
 | } | 
 |  | 
 | sp<Fence> HWComposer::getLayerReleaseFence(int32_t displayId, | 
 |         HWC2::Layer* layer) const { | 
 |     if (!isValidDisplay(displayId)) { | 
 |         ALOGE("getLayerReleaseFence: Invalid display"); | 
 |         return Fence::NO_FENCE; | 
 |     } | 
 |     auto displayFences = mDisplayData[displayId].releaseFences; | 
 |     if (displayFences.count(layer) == 0) { | 
 |         ALOGV("getLayerReleaseFence: Release fence not found"); | 
 |         return Fence::NO_FENCE; | 
 |     } | 
 |     return displayFences[layer]; | 
 | } | 
 |  | 
 | status_t HWComposer::presentAndGetReleaseFences(int32_t displayId) { | 
 |     ATRACE_CALL(); | 
 |  | 
 |     if (!isValidDisplay(displayId)) { | 
 |         return BAD_INDEX; | 
 |     } | 
 |  | 
 |     auto& displayData = mDisplayData[displayId]; | 
 |     auto& hwcDisplay = displayData.hwcDisplay; | 
 |  | 
 |     if (displayData.validateWasSkipped) { | 
 |         // explicitly flush all pending commands | 
 |         auto error = mHwcDevice->flushCommands(); | 
 |         if (displayData.presentError != HWC2::Error::None) { | 
 |             error = displayData.presentError; | 
 |         } | 
 |         if (error != HWC2::Error::None) { | 
 |             ALOGE("skipValidate: failed for display %d: %s (%d)", | 
 |                   displayId, to_string(error).c_str(), static_cast<int32_t>(error)); | 
 |             return UNKNOWN_ERROR; | 
 |         } | 
 |         return NO_ERROR; | 
 |     } | 
 |  | 
 |     auto error = hwcDisplay->present(&displayData.lastPresentFence); | 
 |     if (error != HWC2::Error::None) { | 
 |         ALOGE("presentAndGetReleaseFences: failed for display %d: %s (%d)", | 
 |               displayId, to_string(error).c_str(), static_cast<int32_t>(error)); | 
 |         return UNKNOWN_ERROR; | 
 |     } | 
 |  | 
 |     std::unordered_map<HWC2::Layer*, sp<Fence>> releaseFences; | 
 |     error = hwcDisplay->getReleaseFences(&releaseFences); | 
 |     if (error != HWC2::Error::None) { | 
 |         ALOGE("presentAndGetReleaseFences: Failed to get release fences " | 
 |               "for display %d: %s (%d)", | 
 |                 displayId, to_string(error).c_str(), | 
 |                 static_cast<int32_t>(error)); | 
 |         return UNKNOWN_ERROR; | 
 |     } | 
 |  | 
 |     displayData.releaseFences = std::move(releaseFences); | 
 |  | 
 |     return NO_ERROR; | 
 | } | 
 |  | 
 | status_t HWComposer::setPowerMode(int32_t displayId, int32_t intMode) { | 
 |     ALOGV("setPowerMode(%d, %d)", displayId, intMode); | 
 |     if (!isValidDisplay(displayId)) { | 
 |         ALOGE("setPowerMode: Bad display"); | 
 |         return BAD_INDEX; | 
 |     } | 
 |     if (displayId >= VIRTUAL_DISPLAY_ID_BASE) { | 
 |         ALOGE("setPowerMode: Virtual display %d passed in, returning", | 
 |                 displayId); | 
 |         return BAD_INDEX; | 
 |     } | 
 |  | 
 |     auto mode = static_cast<HWC2::PowerMode>(intMode); | 
 |     if (mode == HWC2::PowerMode::Off) { | 
 |         setVsyncEnabled(displayId, HWC2::Vsync::Disable); | 
 |     } | 
 |  | 
 |     auto& hwcDisplay = mDisplayData[displayId].hwcDisplay; | 
 |     switch (mode) { | 
 |         case HWC2::PowerMode::Off: | 
 |         case HWC2::PowerMode::On: | 
 |             ALOGV("setPowerMode: Calling HWC %s", to_string(mode).c_str()); | 
 |             { | 
 |                 auto error = hwcDisplay->setPowerMode(mode); | 
 |                 if (error != HWC2::Error::None) { | 
 |                     ALOGE("setPowerMode: Unable to set power mode %s for " | 
 |                             "display %d: %s (%d)", to_string(mode).c_str(), | 
 |                             displayId, to_string(error).c_str(), | 
 |                             static_cast<int32_t>(error)); | 
 |                 } | 
 |             } | 
 |             break; | 
 |         case HWC2::PowerMode::Doze: | 
 |         case HWC2::PowerMode::DozeSuspend: | 
 |             ALOGV("setPowerMode: Calling HWC %s", to_string(mode).c_str()); | 
 |             { | 
 |                 bool supportsDoze = false; | 
 |                 auto error = hwcDisplay->supportsDoze(&supportsDoze); | 
 |                 if (error != HWC2::Error::None) { | 
 |                     ALOGE("setPowerMode: Unable to query doze support for " | 
 |                             "display %d: %s (%d)", displayId, | 
 |                             to_string(error).c_str(), | 
 |                             static_cast<int32_t>(error)); | 
 |                 } | 
 |                 if (!supportsDoze) { | 
 |                     mode = HWC2::PowerMode::On; | 
 |                 } | 
 |  | 
 |                 error = hwcDisplay->setPowerMode(mode); | 
 |                 if (error != HWC2::Error::None) { | 
 |                     ALOGE("setPowerMode: Unable to set power mode %s for " | 
 |                             "display %d: %s (%d)", to_string(mode).c_str(), | 
 |                             displayId, to_string(error).c_str(), | 
 |                             static_cast<int32_t>(error)); | 
 |                 } | 
 |             } | 
 |             break; | 
 |         default: | 
 |             ALOGV("setPowerMode: Not calling HWC"); | 
 |             break; | 
 |     } | 
 |  | 
 |     return NO_ERROR; | 
 | } | 
 |  | 
 | status_t HWComposer::setActiveConfig(int32_t displayId, size_t configId) { | 
 |     if (!isValidDisplay(displayId)) { | 
 |         ALOGE("setActiveConfig: Display %d is not valid", displayId); | 
 |         return BAD_INDEX; | 
 |     } | 
 |  | 
 |     auto& displayData = mDisplayData[displayId]; | 
 |     if (displayData.configMap.count(configId) == 0) { | 
 |         ALOGE("setActiveConfig: Invalid config %zd", configId); | 
 |         return BAD_INDEX; | 
 |     } | 
 |  | 
 |     auto error = displayData.hwcDisplay->setActiveConfig( | 
 |             displayData.configMap[configId]); | 
 |     if (error != HWC2::Error::None) { | 
 |         ALOGE("setActiveConfig: Failed to set config %zu on display %d: " | 
 |                 "%s (%d)", configId, displayId, to_string(error).c_str(), | 
 |                 static_cast<int32_t>(error)); | 
 |         return UNKNOWN_ERROR; | 
 |     } | 
 |  | 
 |     return NO_ERROR; | 
 | } | 
 |  | 
 | status_t HWComposer::setColorTransform(int32_t displayId, | 
 |         const mat4& transform) { | 
 |     if (!isValidDisplay(displayId)) { | 
 |         ALOGE("setColorTransform: Display %d is not valid", displayId); | 
 |         return BAD_INDEX; | 
 |     } | 
 |  | 
 |     auto& displayData = mDisplayData[displayId]; | 
 |     bool isIdentity = transform == mat4(); | 
 |     auto error = displayData.hwcDisplay->setColorTransform(transform, | 
 |             isIdentity ? HAL_COLOR_TRANSFORM_IDENTITY : | 
 |             HAL_COLOR_TRANSFORM_ARBITRARY_MATRIX); | 
 |     if (error != HWC2::Error::None) { | 
 |         ALOGE("setColorTransform: Failed to set transform on display %d: " | 
 |                 "%s (%d)", displayId, to_string(error).c_str(), | 
 |                 static_cast<int32_t>(error)); | 
 |         return UNKNOWN_ERROR; | 
 |     } | 
 |  | 
 |     return NO_ERROR; | 
 | } | 
 |  | 
 | void HWComposer::disconnectDisplay(int displayId) { | 
 |     LOG_ALWAYS_FATAL_IF(displayId < 0); | 
 |     auto& displayData = mDisplayData[displayId]; | 
 |  | 
 |     auto displayType = HWC2::DisplayType::Invalid; | 
 |     auto error = displayData.hwcDisplay->getType(&displayType); | 
 |     if (error != HWC2::Error::None) { | 
 |         ALOGE("disconnectDisplay: Failed to determine type of display %d", | 
 |                 displayId); | 
 |         return; | 
 |     } | 
 |  | 
 |     // If this was a virtual display, add its slot back for reuse by future | 
 |     // virtual displays | 
 |     if (displayType == HWC2::DisplayType::Virtual) { | 
 |         mFreeDisplaySlots.insert(displayId); | 
 |         ++mRemainingHwcVirtualDisplays; | 
 |     } | 
 |  | 
 |     auto hwcId = displayData.hwcDisplay->getId(); | 
 |     mHwcDisplaySlots.erase(hwcId); | 
 |     displayData.reset(); | 
 |  | 
 |     mHwcDevice->destroyDisplay(hwcId); | 
 | } | 
 |  | 
 | status_t HWComposer::setOutputBuffer(int32_t displayId, | 
 |         const sp<Fence>& acquireFence, const sp<GraphicBuffer>& buffer) { | 
 |     if (!isValidDisplay(displayId)) { | 
 |         ALOGE("setOutputBuffer: Display %d is not valid", displayId); | 
 |         return BAD_INDEX; | 
 |     } | 
 |  | 
 |     auto& hwcDisplay = mDisplayData[displayId].hwcDisplay; | 
 |     auto displayType = HWC2::DisplayType::Invalid; | 
 |     auto error = hwcDisplay->getType(&displayType); | 
 |     if (error != HWC2::Error::None) { | 
 |         ALOGE("setOutputBuffer: Failed to determine type of display %d", | 
 |                 displayId); | 
 |         return NAME_NOT_FOUND; | 
 |     } | 
 |  | 
 |     if (displayType != HWC2::DisplayType::Virtual) { | 
 |         ALOGE("setOutputBuffer: Display %d is not virtual", displayId); | 
 |         return INVALID_OPERATION; | 
 |     } | 
 |  | 
 |     error = hwcDisplay->setOutputBuffer(buffer, acquireFence); | 
 |     if (error != HWC2::Error::None) { | 
 |         ALOGE("setOutputBuffer: Failed to set buffer on display %d: %s (%d)", | 
 |                 displayId, to_string(error).c_str(), | 
 |                 static_cast<int32_t>(error)); | 
 |         return UNKNOWN_ERROR; | 
 |     } | 
 |  | 
 |     return NO_ERROR; | 
 | } | 
 |  | 
 | void HWComposer::clearReleaseFences(int32_t displayId) { | 
 |     if (!isValidDisplay(displayId)) { | 
 |         ALOGE("clearReleaseFences: Display %d is not valid", displayId); | 
 |         return; | 
 |     } | 
 |     mDisplayData[displayId].releaseFences.clear(); | 
 | } | 
 |  | 
 | std::unique_ptr<HdrCapabilities> HWComposer::getHdrCapabilities( | 
 |         int32_t displayId) { | 
 |     if (!isValidDisplay(displayId)) { | 
 |         ALOGE("getHdrCapabilities: Display %d is not valid", displayId); | 
 |         return nullptr; | 
 |     } | 
 |  | 
 |     auto& hwcDisplay = mDisplayData[displayId].hwcDisplay; | 
 |     std::unique_ptr<HdrCapabilities> capabilities; | 
 |     auto error = hwcDisplay->getHdrCapabilities(&capabilities); | 
 |     if (error != HWC2::Error::None) { | 
 |         ALOGE("getOutputCapabilities: Failed to get capabilities on display %d:" | 
 |                 " %s (%d)", displayId, to_string(error).c_str(), | 
 |                 static_cast<int32_t>(error)); | 
 |         return nullptr; | 
 |     } | 
 |  | 
 |     return capabilities; | 
 | } | 
 |  | 
 | std::vector<ui::RenderIntent> HWComposer::getRenderIntents(int32_t displayId, | 
 |         ui::ColorMode colorMode) const { | 
 |     if (!isValidDisplay(displayId)) { | 
 |         ALOGE("getRenderIntents: Attempted to access invalid display %d", | 
 |                 displayId); | 
 |         return {}; | 
 |     } | 
 |  | 
 |     std::vector<ui::RenderIntent> renderIntents; | 
 |     auto error = mDisplayData[displayId].hwcDisplay->getRenderIntents(colorMode, &renderIntents); | 
 |     if (error != HWC2::Error::None) { | 
 |         ALOGE("getColorModes failed for display %d: %s (%d)", displayId, | 
 |                 to_string(error).c_str(), static_cast<int32_t>(error)); | 
 |         return std::vector<ui::RenderIntent>(); | 
 |     } | 
 |  | 
 |     return renderIntents; | 
 | } | 
 |  | 
 | mat4 HWComposer::getDataspaceSaturationMatrix(int32_t displayId, ui::Dataspace dataspace) { | 
 |     if (!isValidDisplay(displayId)) { | 
 |         ALOGE("getDataSpaceSaturationMatrix: Attempted to access invalid display %d", | 
 |                 displayId); | 
 |         return {}; | 
 |     } | 
 |  | 
 |     mat4 matrix; | 
 |     auto error = mDisplayData[displayId].hwcDisplay->getDataspaceSaturationMatrix(dataspace, | 
 |             &matrix); | 
 |     if (error != HWC2::Error::None) { | 
 |         ALOGE("getDataSpaceSaturationMatrix failed for display %d: %s (%d)", displayId, | 
 |                 to_string(error).c_str(), static_cast<int32_t>(error)); | 
 |         return mat4(); | 
 |     } | 
 |  | 
 |     return matrix; | 
 | } | 
 |  | 
 | // Converts a PixelFormat to a human-readable string.  Max 11 chars. | 
 | // (Could use a table of prefab String8 objects.) | 
 | /* | 
 | static String8 getFormatStr(PixelFormat format) { | 
 |     switch (format) { | 
 |     case PIXEL_FORMAT_RGBA_8888:    return String8("RGBA_8888"); | 
 |     case PIXEL_FORMAT_RGBX_8888:    return String8("RGBx_8888"); | 
 |     case PIXEL_FORMAT_RGB_888:      return String8("RGB_888"); | 
 |     case PIXEL_FORMAT_RGB_565:      return String8("RGB_565"); | 
 |     case PIXEL_FORMAT_BGRA_8888:    return String8("BGRA_8888"); | 
 |     case HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED: | 
 |                                     return String8("ImplDef"); | 
 |     default: | 
 |         String8 result; | 
 |         result.appendFormat("? %08x", format); | 
 |         return result; | 
 |     } | 
 | } | 
 | */ | 
 |  | 
 | bool HWComposer::isUsingVrComposer() const { | 
 |     return getComposer()->isUsingVrComposer(); | 
 | } | 
 |  | 
 | void HWComposer::dump(String8& result) const { | 
 |     // TODO: In order to provide a dump equivalent to HWC1, we need to shadow | 
 |     // all the state going into the layers. This is probably better done in | 
 |     // Layer itself, but it's going to take a bit of work to get there. | 
 |     result.append(mHwcDevice->dump().c_str()); | 
 | } | 
 |  | 
 | std::optional<hwc2_display_t> | 
 | HWComposer::getHwcDisplayId(int32_t displayId) const { | 
 |     if (!isValidDisplay(displayId)) { | 
 |         return {}; | 
 |     } | 
 |     return mDisplayData[displayId].hwcDisplay->getId(); | 
 | } | 
 |  | 
 | // --------------------------------------------------------------------------- | 
 |  | 
 | HWComposer::DisplayData::DisplayData() | 
 |   : hasClientComposition(false), | 
 |     hasDeviceComposition(false), | 
 |     hwcDisplay(nullptr), | 
 |     lastPresentFence(Fence::NO_FENCE), | 
 |     outbufHandle(nullptr), | 
 |     outbufAcquireFence(Fence::NO_FENCE), | 
 |     vsyncEnabled(HWC2::Vsync::Disable) { | 
 |     ALOGV("Created new DisplayData"); | 
 | } | 
 |  | 
 | HWComposer::DisplayData::~DisplayData() { | 
 | } | 
 |  | 
 | void HWComposer::DisplayData::reset() { | 
 |     ALOGV("DisplayData reset"); | 
 |     *this = DisplayData(); | 
 | } | 
 |  | 
 | // --------------------------------------------------------------------------- | 
 | }; // namespace android |