| /* |
| * Copyright (C) 2022 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. |
| */ |
| |
| #include "ComposerClient.h" |
| |
| #include <aidlcommonsupport/NativeHandle.h> |
| #include <android/binder_ibinder_platform.h> |
| |
| #include "Common.h" |
| #include "Device.h" |
| #include "GuestFrameComposer.h" |
| #include "HostFrameComposer.h" |
| |
| namespace aidl::android::hardware::graphics::composer3::impl { |
| namespace { |
| |
| #define GET_DISPLAY_OR_RETURN_ERROR() \ |
| Display* display = getDisplay(displayId); \ |
| if (display == nullptr) { \ |
| ALOGE("%s failed to get display:%" PRIu64, __FUNCTION__, displayId); \ |
| return ToBinderStatus(HWC3::Error::BadDisplay); \ |
| } |
| |
| } // namespace |
| |
| using ::aidl::android::hardware::graphics::common::PixelFormat; |
| |
| class ComposerClient::CommandResultWriter { |
| public: |
| CommandResultWriter(std::vector<CommandResultPayload>* results) |
| : mIndex(0), mResults(results) {} |
| |
| void nextCommand() { ++mIndex; } |
| |
| void addError(HWC3::Error error) { |
| CommandError commandErrorResult; |
| commandErrorResult.commandIndex = mIndex; |
| commandErrorResult.errorCode = static_cast<int32_t>(error); |
| mResults->emplace_back(std::move(commandErrorResult)); |
| } |
| |
| void addPresentFence(int64_t displayId, ::android::base::unique_fd fence) { |
| if (fence >= 0) { |
| PresentFence presentFenceResult; |
| presentFenceResult.display = displayId; |
| presentFenceResult.fence = ndk::ScopedFileDescriptor(fence.release()); |
| mResults->emplace_back(std::move(presentFenceResult)); |
| } |
| } |
| |
| void addReleaseFences(int64_t displayId, |
| std::unordered_map<int64_t, ::android::base::unique_fd> layerFences) { |
| ReleaseFences releaseFencesResult; |
| releaseFencesResult.display = displayId; |
| for (auto& [layer, layerFence] : layerFences) { |
| if (layerFence >= 0) { |
| ReleaseFences::Layer releaseFencesLayerResult; |
| releaseFencesLayerResult.layer = layer; |
| releaseFencesLayerResult.fence = ndk::ScopedFileDescriptor(layerFence.release()); |
| releaseFencesResult.layers.emplace_back(std::move(releaseFencesLayerResult)); |
| } |
| } |
| mResults->emplace_back(std::move(releaseFencesResult)); |
| } |
| |
| void addChanges(const DisplayChanges& changes) { |
| if (changes.compositionChanges) { |
| mResults->emplace_back(*changes.compositionChanges); |
| } |
| if (changes.displayRequestChanges) { |
| mResults->emplace_back(*changes.displayRequestChanges); |
| } |
| } |
| |
| void addPresentOrValidateResult(int64_t displayId, PresentOrValidate::Result pov) { |
| PresentOrValidate result; |
| result.display = displayId; |
| result.result = pov; |
| mResults->emplace_back(std::move(result)); |
| } |
| |
| private: |
| int32_t mIndex = 0; |
| std::vector<CommandResultPayload>* mResults = nullptr; |
| }; |
| |
| ComposerClient::ComposerClient() { DEBUG_LOG("%s", __FUNCTION__); } |
| |
| ComposerClient::~ComposerClient() { |
| DEBUG_LOG("%s", __FUNCTION__); |
| |
| std::unique_lock<std::mutex> lock(mStateMutex); |
| |
| destroyDisplaysLocked(); |
| |
| if (mOnClientDestroyed) { |
| mOnClientDestroyed(); |
| } |
| } |
| |
| HWC3::Error ComposerClient::init() { |
| DEBUG_LOG("%s", __FUNCTION__); |
| |
| HWC3::Error error = HWC3::Error::None; |
| |
| std::unique_lock<std::mutex> lock(mStateMutex); |
| |
| mResources = std::make_unique<ComposerResources>(); |
| if (!mResources) { |
| ALOGE("%s failed to allocate ComposerResources", __FUNCTION__); |
| return HWC3::Error::NoResources; |
| } |
| |
| error = mResources->init(); |
| if (error != HWC3::Error::None) { |
| ALOGE("%s failed to initialize ComposerResources", __FUNCTION__); |
| return error; |
| } |
| |
| error = Device::getInstance().getComposer(&mComposer); |
| if (error != HWC3::Error::None) { |
| ALOGE("%s failed to get FrameComposer", __FUNCTION__); |
| return error; |
| } |
| |
| const auto HotplugCallback = [this](bool connected, // |
| uint32_t id, // |
| uint32_t width, // |
| uint32_t height, // |
| uint32_t dpiX, // |
| uint32_t dpiY, // |
| uint32_t refreshRate) { |
| handleHotplug(connected, id, width, height, dpiX, dpiY, refreshRate); |
| }; |
| error = mComposer->registerOnHotplugCallback(HotplugCallback); |
| if (error != HWC3::Error::None) { |
| ALOGE("%s failed to register hotplug callback", __FUNCTION__); |
| return error; |
| } |
| |
| error = createDisplaysLocked(); |
| if (error != HWC3::Error::None) { |
| ALOGE("%s failed to create displays.", __FUNCTION__); |
| return error; |
| } |
| |
| DEBUG_LOG("%s initialized!", __FUNCTION__); |
| return HWC3::Error::None; |
| } |
| |
| ndk::ScopedAStatus ComposerClient::createLayer(int64_t displayId, int32_t bufferSlotCount, |
| int64_t* layerId) { |
| DEBUG_LOG("%s display:%" PRIu64, __FUNCTION__, displayId); |
| |
| std::unique_lock<std::mutex> lock(mStateMutex); |
| |
| GET_DISPLAY_OR_RETURN_ERROR(); |
| |
| HWC3::Error error = display->createLayer(layerId); |
| if (error != HWC3::Error::None) { |
| ALOGE("%s: display:%" PRIu64 " failed to create layer", __FUNCTION__, displayId); |
| return ToBinderStatus(error); |
| } |
| |
| error = mResources->addLayer(displayId, *layerId, static_cast<uint32_t>(bufferSlotCount)); |
| if (error != HWC3::Error::None) { |
| ALOGE("%s: display:%" PRIu64 " resources failed to create layer", __FUNCTION__, displayId); |
| return ToBinderStatus(error); |
| } |
| |
| return ToBinderStatus(HWC3::Error::None); |
| } |
| |
| ndk::ScopedAStatus ComposerClient::createVirtualDisplay(int32_t /*width*/, int32_t /*height*/, |
| PixelFormat /*formatHint*/, |
| int32_t /*outputBufferSlotCount*/, |
| VirtualDisplay* /*display*/) { |
| DEBUG_LOG("%s", __FUNCTION__); |
| |
| return ToBinderStatus(HWC3::Error::Unsupported); |
| } |
| |
| ndk::ScopedAStatus ComposerClient::destroyLayer(int64_t displayId, int64_t layerId) { |
| DEBUG_LOG("%s display:%" PRIu64, __FUNCTION__, displayId); |
| |
| std::unique_lock<std::mutex> lock(mStateMutex); |
| |
| GET_DISPLAY_OR_RETURN_ERROR(); |
| |
| HWC3::Error error = display->destroyLayer(layerId); |
| if (error != HWC3::Error::None) { |
| ALOGE("%s: display:%" PRIu64 " failed to destroy layer:%" PRIu64, __FUNCTION__, displayId, |
| layerId); |
| return ToBinderStatus(error); |
| } |
| |
| error = mResources->removeLayer(displayId, layerId); |
| if (error != HWC3::Error::None) { |
| ALOGE("%s: display:%" PRIu64 " resources failed to destroy layer:%" PRIu64, __FUNCTION__, |
| displayId, layerId); |
| return ToBinderStatus(error); |
| } |
| |
| return ToBinderStatus(HWC3::Error::None); |
| } |
| |
| ndk::ScopedAStatus ComposerClient::destroyVirtualDisplay(int64_t /*displayId*/) { |
| DEBUG_LOG("%s", __FUNCTION__); |
| |
| return ToBinderStatus(HWC3::Error::Unsupported); |
| } |
| |
| ndk::ScopedAStatus ComposerClient::executeCommands( |
| const std::vector<DisplayCommand>& commands, |
| std::vector<CommandResultPayload>* commandResultPayloads) { |
| DEBUG_LOG("%s", __FUNCTION__); |
| |
| std::unique_lock<std::mutex> lock(mStateMutex); |
| |
| mCommandResults = std::make_unique<CommandResultWriter>(commandResultPayloads); |
| |
| for (const DisplayCommand& command : commands) { |
| executeDisplayCommand(command); |
| mCommandResults->nextCommand(); |
| } |
| |
| mCommandResults.reset(); |
| |
| return ToBinderStatus(HWC3::Error::None); |
| } |
| |
| ndk::ScopedAStatus ComposerClient::getActiveConfig(int64_t displayId, int32_t* config) { |
| DEBUG_LOG("%s", __FUNCTION__); |
| |
| std::unique_lock<std::mutex> lock(mStateMutex); |
| |
| GET_DISPLAY_OR_RETURN_ERROR(); |
| |
| return ToBinderStatus(display->getActiveConfig(config)); |
| } |
| |
| ndk::ScopedAStatus ComposerClient::getColorModes(int64_t displayId, |
| std::vector<ColorMode>* colorModes) { |
| DEBUG_LOG("%s", __FUNCTION__); |
| |
| std::unique_lock<std::mutex> lock(mStateMutex); |
| |
| GET_DISPLAY_OR_RETURN_ERROR(); |
| |
| return ToBinderStatus(display->getColorModes(colorModes)); |
| } |
| |
| ndk::ScopedAStatus ComposerClient::getDataspaceSaturationMatrix(common::Dataspace dataspace, |
| std::vector<float>* matrix) { |
| DEBUG_LOG("%s", __FUNCTION__); |
| |
| if (dataspace != common::Dataspace::SRGB_LINEAR) { |
| return ToBinderStatus(HWC3::Error::BadParameter); |
| } |
| |
| // clang-format off |
| constexpr std::array<float, 16> kUnit { |
| 1.0f, 0.0f, 0.0f, 0.0f, |
| 0.0f, 1.0f, 0.0f, 0.0f, |
| 0.0f, 0.0f, 1.0f, 0.0f, |
| 0.0f, 0.0f, 0.0f, 1.0f, |
| }; |
| // clang-format on |
| matrix->clear(); |
| matrix->insert(matrix->begin(), kUnit.begin(), kUnit.end()); |
| |
| return ToBinderStatus(HWC3::Error::None); |
| } |
| |
| ndk::ScopedAStatus ComposerClient::getDisplayAttribute(int64_t displayId, int32_t config, |
| DisplayAttribute attribute, int32_t* value) { |
| DEBUG_LOG("%s", __FUNCTION__); |
| |
| std::unique_lock<std::mutex> lock(mStateMutex); |
| |
| GET_DISPLAY_OR_RETURN_ERROR(); |
| |
| return ToBinderStatus(display->getDisplayAttribute(config, attribute, value)); |
| } |
| |
| ndk::ScopedAStatus ComposerClient::getDisplayCapabilities(int64_t displayId, |
| std::vector<DisplayCapability>* outCaps) { |
| DEBUG_LOG("%s", __FUNCTION__); |
| |
| std::unique_lock<std::mutex> lock(mStateMutex); |
| |
| GET_DISPLAY_OR_RETURN_ERROR(); |
| |
| return ToBinderStatus(display->getDisplayCapabilities(outCaps)); |
| } |
| |
| ndk::ScopedAStatus ComposerClient::getDisplayConfigs(int64_t displayId, |
| std::vector<int32_t>* outConfigs) { |
| DEBUG_LOG("%s", __FUNCTION__); |
| |
| std::unique_lock<std::mutex> lock(mStateMutex); |
| |
| GET_DISPLAY_OR_RETURN_ERROR(); |
| |
| return ToBinderStatus(display->getDisplayConfigs(outConfigs)); |
| } |
| |
| ndk::ScopedAStatus ComposerClient::getDisplayConnectionType(int64_t displayId, |
| DisplayConnectionType* outType) { |
| DEBUG_LOG("%s", __FUNCTION__); |
| |
| std::unique_lock<std::mutex> lock(mStateMutex); |
| |
| GET_DISPLAY_OR_RETURN_ERROR(); |
| |
| return ToBinderStatus(display->getDisplayConnectionType(outType)); |
| } |
| |
| ndk::ScopedAStatus ComposerClient::getDisplayIdentificationData( |
| int64_t displayId, DisplayIdentification* outIdentification) { |
| DEBUG_LOG("%s", __FUNCTION__); |
| |
| std::unique_lock<std::mutex> lock(mStateMutex); |
| |
| GET_DISPLAY_OR_RETURN_ERROR(); |
| |
| return ToBinderStatus(display->getDisplayIdentificationData(outIdentification)); |
| } |
| |
| ndk::ScopedAStatus ComposerClient::getDisplayName(int64_t displayId, std::string* outName) { |
| DEBUG_LOG("%s", __FUNCTION__); |
| |
| std::unique_lock<std::mutex> lock(mStateMutex); |
| |
| GET_DISPLAY_OR_RETURN_ERROR(); |
| |
| return ToBinderStatus(display->getDisplayName(outName)); |
| } |
| |
| ndk::ScopedAStatus ComposerClient::getDisplayVsyncPeriod(int64_t displayId, |
| int32_t* outVsyncPeriod) { |
| DEBUG_LOG("%s", __FUNCTION__); |
| |
| std::unique_lock<std::mutex> lock(mStateMutex); |
| |
| GET_DISPLAY_OR_RETURN_ERROR(); |
| |
| return ToBinderStatus(display->getDisplayVsyncPeriod(outVsyncPeriod)); |
| } |
| |
| ndk::ScopedAStatus ComposerClient::getDisplayedContentSample(int64_t displayId, int64_t maxFrames, |
| int64_t timestamp, |
| DisplayContentSample* outSamples) { |
| DEBUG_LOG("%s", __FUNCTION__); |
| |
| std::unique_lock<std::mutex> lock(mStateMutex); |
| |
| GET_DISPLAY_OR_RETURN_ERROR(); |
| |
| return ToBinderStatus(display->getDisplayedContentSample(maxFrames, timestamp, outSamples)); |
| } |
| |
| ndk::ScopedAStatus ComposerClient::getDisplayedContentSamplingAttributes( |
| int64_t displayId, DisplayContentSamplingAttributes* outAttributes) { |
| DEBUG_LOG("%s", __FUNCTION__); |
| |
| std::unique_lock<std::mutex> lock(mStateMutex); |
| |
| GET_DISPLAY_OR_RETURN_ERROR(); |
| |
| return ToBinderStatus(display->getDisplayedContentSamplingAttributes(outAttributes)); |
| } |
| |
| ndk::ScopedAStatus ComposerClient::getDisplayPhysicalOrientation( |
| int64_t displayId, common::Transform* outOrientation) { |
| DEBUG_LOG("%s", __FUNCTION__); |
| |
| std::unique_lock<std::mutex> lock(mStateMutex); |
| |
| GET_DISPLAY_OR_RETURN_ERROR(); |
| |
| return ToBinderStatus(display->getDisplayPhysicalOrientation(outOrientation)); |
| } |
| |
| ndk::ScopedAStatus ComposerClient::getHdrCapabilities(int64_t displayId, |
| HdrCapabilities* outCapabilities) { |
| DEBUG_LOG("%s", __FUNCTION__); |
| |
| std::unique_lock<std::mutex> lock(mStateMutex); |
| |
| GET_DISPLAY_OR_RETURN_ERROR(); |
| |
| return ToBinderStatus(display->getHdrCapabilities(outCapabilities)); |
| } |
| |
| ndk::ScopedAStatus ComposerClient::getOverlaySupport(OverlayProperties* properties) { |
| DEBUG_LOG("%s", __FUNCTION__); |
| |
| // no supported combinations |
| properties->combinations.clear(); |
| |
| return ToBinderStatus(HWC3::Error::None); |
| } |
| |
| ndk::ScopedAStatus ComposerClient::getMaxVirtualDisplayCount(int32_t* outCount) { |
| DEBUG_LOG("%s", __FUNCTION__); |
| |
| // Not supported. |
| *outCount = 0; |
| |
| return ToBinderStatus(HWC3::Error::None); |
| } |
| |
| ndk::ScopedAStatus ComposerClient::getPerFrameMetadataKeys( |
| int64_t displayId, std::vector<PerFrameMetadataKey>* outKeys) { |
| DEBUG_LOG("%s", __FUNCTION__); |
| |
| std::unique_lock<std::mutex> lock(mStateMutex); |
| |
| GET_DISPLAY_OR_RETURN_ERROR(); |
| |
| return ToBinderStatus(display->getPerFrameMetadataKeys(outKeys)); |
| } |
| |
| ndk::ScopedAStatus ComposerClient::getReadbackBufferAttributes( |
| int64_t displayId, ReadbackBufferAttributes* outAttributes) { |
| DEBUG_LOG("%s", __FUNCTION__); |
| |
| std::unique_lock<std::mutex> lock(mStateMutex); |
| |
| GET_DISPLAY_OR_RETURN_ERROR(); |
| |
| return ToBinderStatus(display->getReadbackBufferAttributes(outAttributes)); |
| } |
| |
| ndk::ScopedAStatus ComposerClient::getReadbackBufferFence( |
| int64_t displayId, ndk::ScopedFileDescriptor* outAcquireFence) { |
| DEBUG_LOG("%s", __FUNCTION__); |
| |
| std::unique_lock<std::mutex> lock(mStateMutex); |
| |
| GET_DISPLAY_OR_RETURN_ERROR(); |
| |
| return ToBinderStatus(display->getReadbackBufferFence(outAcquireFence)); |
| } |
| |
| ndk::ScopedAStatus ComposerClient::getRenderIntents(int64_t displayId, ColorMode mode, |
| std::vector<RenderIntent>* outIntents) { |
| DEBUG_LOG("%s", __FUNCTION__); |
| |
| std::unique_lock<std::mutex> lock(mStateMutex); |
| |
| GET_DISPLAY_OR_RETURN_ERROR(); |
| |
| return ToBinderStatus(display->getRenderIntents(mode, outIntents)); |
| } |
| |
| ndk::ScopedAStatus ComposerClient::getSupportedContentTypes(int64_t displayId, |
| std::vector<ContentType>* outTypes) { |
| DEBUG_LOG("%s", __FUNCTION__); |
| |
| std::unique_lock<std::mutex> lock(mStateMutex); |
| |
| GET_DISPLAY_OR_RETURN_ERROR(); |
| |
| return ToBinderStatus(display->getSupportedContentTypes(outTypes)); |
| } |
| |
| ndk::ScopedAStatus ComposerClient::getDisplayDecorationSupport( |
| int64_t displayId, std::optional<common::DisplayDecorationSupport>* outSupport) { |
| DEBUG_LOG("%s", __FUNCTION__); |
| |
| std::unique_lock<std::mutex> lock(mStateMutex); |
| |
| GET_DISPLAY_OR_RETURN_ERROR(); |
| |
| return ToBinderStatus(display->getDecorationSupport(outSupport)); |
| } |
| |
| ndk::ScopedAStatus ComposerClient::registerCallback( |
| const std::shared_ptr<IComposerCallback>& callback) { |
| DEBUG_LOG("%s", __FUNCTION__); |
| |
| std::unique_lock<std::mutex> lock(mStateMutex); |
| |
| const bool isFirstRegisterCallback = mCallbacks == nullptr; |
| |
| mCallbacks = callback; |
| |
| for (auto& [_, display] : mDisplays) { |
| display->registerCallback(callback); |
| } |
| |
| if (isFirstRegisterCallback) { |
| lock.unlock(); |
| for (auto& [displayId, _] : mDisplays) { |
| mCallbacks->onHotplug(displayId, /*connected=*/true); |
| } |
| } |
| |
| return ndk::ScopedAStatus::ok(); |
| } |
| |
| ndk::ScopedAStatus ComposerClient::setActiveConfig(int64_t displayId, int32_t configId) { |
| DEBUG_LOG("%s display:%" PRIu64 " config:%" PRIu32, __FUNCTION__, displayId, configId); |
| |
| std::unique_lock<std::mutex> lock(mStateMutex); |
| |
| GET_DISPLAY_OR_RETURN_ERROR(); |
| |
| return ToBinderStatus(display->setActiveConfig(configId)); |
| } |
| |
| ndk::ScopedAStatus ComposerClient::setActiveConfigWithConstraints( |
| int64_t displayId, int32_t configId, const VsyncPeriodChangeConstraints& constraints, |
| VsyncPeriodChangeTimeline* outTimeline) { |
| DEBUG_LOG("%s display:%" PRIu64 " config:%" PRIu32, __FUNCTION__, displayId, configId); |
| |
| std::unique_lock<std::mutex> lock(mStateMutex); |
| |
| GET_DISPLAY_OR_RETURN_ERROR(); |
| |
| return ToBinderStatus( |
| display->setActiveConfigWithConstraints(configId, constraints, outTimeline)); |
| } |
| |
| ndk::ScopedAStatus ComposerClient::setBootDisplayConfig(int64_t displayId, int32_t configId) { |
| DEBUG_LOG("%s display:%" PRIu64 " config:%" PRIu32, __FUNCTION__, displayId, configId); |
| |
| std::unique_lock<std::mutex> lock(mStateMutex); |
| |
| GET_DISPLAY_OR_RETURN_ERROR(); |
| |
| return ToBinderStatus(display->setBootConfig(configId)); |
| } |
| |
| ndk::ScopedAStatus ComposerClient::clearBootDisplayConfig(int64_t displayId) { |
| DEBUG_LOG("%s display:%" PRIu64, __FUNCTION__, displayId); |
| |
| std::unique_lock<std::mutex> lock(mStateMutex); |
| |
| GET_DISPLAY_OR_RETURN_ERROR(); |
| |
| return ToBinderStatus(display->clearBootConfig()); |
| } |
| |
| ndk::ScopedAStatus ComposerClient::getPreferredBootDisplayConfig(int64_t displayId, |
| int32_t* outConfigId) { |
| DEBUG_LOG("%s display:%" PRIu64, __FUNCTION__, displayId); |
| |
| std::unique_lock<std::mutex> lock(mStateMutex); |
| |
| GET_DISPLAY_OR_RETURN_ERROR(); |
| |
| return ToBinderStatus(display->getPreferredBootConfig(outConfigId)); |
| } |
| |
| ndk::ScopedAStatus ComposerClient::getHdrConversionCapabilities( |
| std::vector<aidl::android::hardware::graphics::common::HdrConversionCapability>* capabilities) { |
| DEBUG_LOG("%s", __FUNCTION__); |
| capabilities->clear(); |
| return ToBinderStatus(HWC3::Error::None); |
| } |
| |
| ndk::ScopedAStatus ComposerClient::setHdrConversionStrategy( |
| const aidl::android::hardware::graphics::common::HdrConversionStrategy& conversionStrategy, |
| aidl::android::hardware::graphics::common::Hdr* preferredHdrOutputType) { |
| DEBUG_LOG("%s", __FUNCTION__); |
| using HdrConversionStrategyTag = |
| aidl::android::hardware::graphics::common::HdrConversionStrategy::Tag; |
| switch (conversionStrategy.getTag()) { |
| case HdrConversionStrategyTag::autoAllowedHdrTypes: { |
| auto autoHdrTypes = |
| conversionStrategy.get<HdrConversionStrategyTag::autoAllowedHdrTypes>(); |
| if (autoHdrTypes.size() != 0) { |
| return ToBinderStatus(HWC3::Error::Unsupported); |
| } |
| break; |
| } |
| case HdrConversionStrategyTag::passthrough: |
| case HdrConversionStrategyTag::forceHdrConversion: { |
| break; |
| } |
| } |
| *preferredHdrOutputType = aidl::android::hardware::graphics::common::Hdr::INVALID; |
| return ToBinderStatus(HWC3::Error::None); |
| } |
| |
| ndk::ScopedAStatus ComposerClient::setAutoLowLatencyMode(int64_t displayId, bool on) { |
| DEBUG_LOG("%s", __FUNCTION__); |
| |
| std::unique_lock<std::mutex> lock(mStateMutex); |
| |
| GET_DISPLAY_OR_RETURN_ERROR(); |
| |
| return ToBinderStatus(display->setAutoLowLatencyMode(on)); |
| } |
| |
| ndk::ScopedAStatus ComposerClient::setClientTargetSlotCount(int64_t displayId, int32_t count) { |
| DEBUG_LOG("%s", __FUNCTION__); |
| |
| std::unique_lock<std::mutex> lock(mStateMutex); |
| |
| GET_DISPLAY_OR_RETURN_ERROR(); |
| |
| return ToBinderStatus( |
| mResources->setDisplayClientTargetCacheSize(displayId, static_cast<uint32_t>(count))); |
| } |
| |
| ndk::ScopedAStatus ComposerClient::setColorMode(int64_t displayId, ColorMode mode, |
| RenderIntent intent) { |
| DEBUG_LOG("%s", __FUNCTION__); |
| |
| std::unique_lock<std::mutex> lock(mStateMutex); |
| |
| GET_DISPLAY_OR_RETURN_ERROR(); |
| |
| return ToBinderStatus(display->setColorMode(mode, intent)); |
| } |
| |
| ndk::ScopedAStatus ComposerClient::setContentType(int64_t displayId, ContentType type) { |
| DEBUG_LOG("%s", __FUNCTION__); |
| |
| std::unique_lock<std::mutex> lock(mStateMutex); |
| |
| GET_DISPLAY_OR_RETURN_ERROR(); |
| |
| return ToBinderStatus(display->setContentType(type)); |
| } |
| |
| ndk::ScopedAStatus ComposerClient::setDisplayedContentSamplingEnabled( |
| int64_t displayId, bool enable, FormatColorComponent componentMask, int64_t maxFrames) { |
| DEBUG_LOG("%s", __FUNCTION__); |
| |
| std::unique_lock<std::mutex> lock(mStateMutex); |
| |
| GET_DISPLAY_OR_RETURN_ERROR(); |
| |
| return ToBinderStatus( |
| display->setDisplayedContentSamplingEnabled(enable, componentMask, maxFrames)); |
| } |
| |
| ndk::ScopedAStatus ComposerClient::setPowerMode(int64_t displayId, PowerMode mode) { |
| DEBUG_LOG("%s", __FUNCTION__); |
| |
| std::unique_lock<std::mutex> lock(mStateMutex); |
| |
| GET_DISPLAY_OR_RETURN_ERROR(); |
| |
| return ToBinderStatus(display->setPowerMode(mode)); |
| } |
| |
| ndk::ScopedAStatus ComposerClient::setReadbackBuffer( |
| int64_t displayId, const aidl::android::hardware::common::NativeHandle& buffer, |
| const ndk::ScopedFileDescriptor& releaseFence) { |
| DEBUG_LOG("%s", __FUNCTION__); |
| |
| std::unique_lock<std::mutex> lock(mStateMutex); |
| |
| GET_DISPLAY_OR_RETURN_ERROR(); |
| |
| // Owned by mResources. |
| buffer_handle_t importedBuffer = nullptr; |
| |
| auto releaser = mResources->createReleaser(true /* isBuffer */); |
| auto error = |
| mResources->getDisplayReadbackBuffer(displayId, buffer, &importedBuffer, releaser.get()); |
| if (error != HWC3::Error::None) { |
| ALOGE("%s: failed to get readback buffer from resources.", __FUNCTION__); |
| return ToBinderStatus(error); |
| } |
| |
| error = display->setReadbackBuffer(importedBuffer, releaseFence); |
| if (error != HWC3::Error::None) { |
| ALOGE("%s: failed to set readback buffer to display.", __FUNCTION__); |
| return ToBinderStatus(error); |
| } |
| |
| return ToBinderStatus(HWC3::Error::None); |
| } |
| |
| ndk::ScopedAStatus ComposerClient::setVsyncEnabled(int64_t displayId, bool enabled) { |
| DEBUG_LOG("%s", __FUNCTION__); |
| |
| std::unique_lock<std::mutex> lock(mStateMutex); |
| |
| GET_DISPLAY_OR_RETURN_ERROR(); |
| |
| return ToBinderStatus(display->setVsyncEnabled(enabled)); |
| } |
| |
| ndk::ScopedAStatus ComposerClient::setIdleTimerEnabled(int64_t displayId, int32_t timeoutMs) { |
| DEBUG_LOG("%s", __FUNCTION__); |
| |
| std::unique_lock<std::mutex> lock(mStateMutex); |
| |
| GET_DISPLAY_OR_RETURN_ERROR(); |
| |
| return ToBinderStatus(display->setIdleTimerEnabled(timeoutMs)); |
| } |
| |
| ndk::ScopedAStatus ComposerClient::setRefreshRateChangedCallbackDebugEnabled(int64_t displayId, |
| bool) { |
| DEBUG_LOG("%s", __FUNCTION__); |
| |
| GET_DISPLAY_OR_RETURN_ERROR(); |
| |
| return ToBinderStatus(HWC3::Error::Unsupported); |
| } |
| |
| ndk::SpAIBinder ComposerClient::createBinder() { |
| auto binder = BnComposerClient::createBinder(); |
| AIBinder_setInheritRt(binder.get(), true); |
| return binder; |
| } |
| |
| namespace { |
| |
| #define DISPATCH_LAYER_COMMAND(layerCmd, display, layer, field, funcName) \ |
| do { \ |
| if (layerCmd.field) { \ |
| ComposerClient::executeLayerCommandSetLayer##funcName(display, layer, \ |
| *layerCmd.field); \ |
| } \ |
| } while (0) |
| |
| #define DISPATCH_DISPLAY_COMMAND(displayCmd, display, field, funcName) \ |
| do { \ |
| if (displayCmd.field) { \ |
| executeDisplayCommand##funcName(display, *displayCmd.field); \ |
| } \ |
| } while (0) |
| |
| #define DISPATCH_DISPLAY_BOOL_COMMAND(displayCmd, display, field, funcName) \ |
| do { \ |
| if (displayCmd.field) { \ |
| executeDisplayCommand##funcName(display); \ |
| } \ |
| } while (0) |
| |
| #define DISPATCH_DISPLAY_BOOL_COMMAND_AND_DATA(displayCmd, display, field, data, funcName) \ |
| do { \ |
| if (displayCmd.field) { \ |
| executeDisplayCommand##funcName(display, displayCmd.data); \ |
| } \ |
| } while (0) |
| |
| #define LOG_DISPLAY_COMMAND_ERROR(display, error) \ |
| do { \ |
| const std::string errorString = toString(error); \ |
| ALOGE("%s: display:%" PRId64 " failed with:%s", __FUNCTION__, display->getId(), \ |
| errorString.c_str()); \ |
| } while (0) |
| |
| #define LOG_LAYER_COMMAND_ERROR(display, layer, error) \ |
| do { \ |
| const std::string errorString = toString(error); \ |
| ALOGE("%s: display:%" PRId64 " layer:%" PRId64 " failed with:%s", __FUNCTION__, \ |
| display->getId(), layer->getId(), errorString.c_str()); \ |
| } while (0) |
| |
| } // namespace |
| |
| void ComposerClient::executeDisplayCommand(const DisplayCommand& displayCommand) { |
| Display* display = getDisplay(displayCommand.display); |
| if (display == nullptr) { |
| mCommandResults->addError(HWC3::Error::BadDisplay); |
| return; |
| } |
| |
| for (const LayerCommand& layerCmd : displayCommand.layers) { |
| executeLayerCommand(display, layerCmd); |
| } |
| |
| DISPATCH_DISPLAY_COMMAND(displayCommand, display, colorTransformMatrix, SetColorTransform); |
| DISPATCH_DISPLAY_COMMAND(displayCommand, display, brightness, SetBrightness); |
| DISPATCH_DISPLAY_COMMAND(displayCommand, display, clientTarget, SetClientTarget); |
| DISPATCH_DISPLAY_COMMAND(displayCommand, display, virtualDisplayOutputBuffer, SetOutputBuffer); |
| DISPATCH_DISPLAY_BOOL_COMMAND_AND_DATA(displayCommand, display, validateDisplay, |
| expectedPresentTime, ValidateDisplay); |
| DISPATCH_DISPLAY_BOOL_COMMAND(displayCommand, display, acceptDisplayChanges, |
| AcceptDisplayChanges); |
| DISPATCH_DISPLAY_BOOL_COMMAND(displayCommand, display, presentDisplay, PresentDisplay); |
| DISPATCH_DISPLAY_BOOL_COMMAND_AND_DATA(displayCommand, display, presentOrValidateDisplay, |
| expectedPresentTime, PresentOrValidateDisplay); |
| } |
| |
| void ComposerClient::executeLayerCommand(Display* display, const LayerCommand& layerCommand) { |
| Layer* layer = display->getLayer(layerCommand.layer); |
| if (layer == nullptr) { |
| mCommandResults->addError(HWC3::Error::BadLayer); |
| return; |
| } |
| |
| DISPATCH_LAYER_COMMAND(layerCommand, display, layer, cursorPosition, CursorPosition); |
| DISPATCH_LAYER_COMMAND(layerCommand, display, layer, buffer, Buffer); |
| DISPATCH_LAYER_COMMAND(layerCommand, display, layer, damage, SurfaceDamage); |
| DISPATCH_LAYER_COMMAND(layerCommand, display, layer, blendMode, BlendMode); |
| DISPATCH_LAYER_COMMAND(layerCommand, display, layer, color, Color); |
| DISPATCH_LAYER_COMMAND(layerCommand, display, layer, composition, Composition); |
| DISPATCH_LAYER_COMMAND(layerCommand, display, layer, dataspace, Dataspace); |
| DISPATCH_LAYER_COMMAND(layerCommand, display, layer, displayFrame, DisplayFrame); |
| DISPATCH_LAYER_COMMAND(layerCommand, display, layer, planeAlpha, PlaneAlpha); |
| DISPATCH_LAYER_COMMAND(layerCommand, display, layer, sidebandStream, SidebandStream); |
| DISPATCH_LAYER_COMMAND(layerCommand, display, layer, sourceCrop, SourceCrop); |
| DISPATCH_LAYER_COMMAND(layerCommand, display, layer, transform, Transform); |
| DISPATCH_LAYER_COMMAND(layerCommand, display, layer, visibleRegion, VisibleRegion); |
| DISPATCH_LAYER_COMMAND(layerCommand, display, layer, z, ZOrder); |
| DISPATCH_LAYER_COMMAND(layerCommand, display, layer, colorTransform, ColorTransform); |
| DISPATCH_LAYER_COMMAND(layerCommand, display, layer, brightness, Brightness); |
| DISPATCH_LAYER_COMMAND(layerCommand, display, layer, perFrameMetadata, PerFrameMetadata); |
| DISPATCH_LAYER_COMMAND(layerCommand, display, layer, perFrameMetadataBlob, |
| PerFrameMetadataBlobs); |
| } |
| |
| void ComposerClient::executeDisplayCommandSetColorTransform(Display* display, |
| const std::vector<float>& matrix) { |
| DEBUG_LOG("%s", __FUNCTION__); |
| |
| auto error = display->setColorTransform(matrix); |
| if (error != HWC3::Error::None) { |
| LOG_DISPLAY_COMMAND_ERROR(display, error); |
| mCommandResults->addError(error); |
| } |
| } |
| |
| void ComposerClient::executeDisplayCommandSetBrightness(Display* display, |
| const DisplayBrightness& brightness) { |
| DEBUG_LOG("%s", __FUNCTION__); |
| |
| auto error = display->setBrightness(brightness.brightness); |
| if (error != HWC3::Error::None) { |
| LOG_DISPLAY_COMMAND_ERROR(display, error); |
| mCommandResults->addError(error); |
| } |
| } |
| |
| void ComposerClient::executeDisplayCommandSetClientTarget(Display* display, |
| const ClientTarget& clientTarget) { |
| DEBUG_LOG("%s", __FUNCTION__); |
| |
| // Owned by mResources. |
| buffer_handle_t importedBuffer = nullptr; |
| |
| auto releaser = mResources->createReleaser(/*isBuffer=*/true); |
| auto error = mResources->getDisplayClientTarget(display->getId(), clientTarget.buffer, |
| &importedBuffer, releaser.get()); |
| if (error != HWC3::Error::None) { |
| LOG_DISPLAY_COMMAND_ERROR(display, error); |
| mCommandResults->addError(error); |
| return; |
| } |
| |
| error = display->setClientTarget(importedBuffer, clientTarget.buffer.fence, |
| clientTarget.dataspace, clientTarget.damage); |
| if (error != HWC3::Error::None) { |
| LOG_DISPLAY_COMMAND_ERROR(display, error); |
| mCommandResults->addError(error); |
| return; |
| } |
| } |
| |
| void ComposerClient::executeDisplayCommandSetOutputBuffer(Display* display, const Buffer& buffer) { |
| DEBUG_LOG("%s", __FUNCTION__); |
| |
| // Owned by mResources. |
| buffer_handle_t importedBuffer = nullptr; |
| |
| auto releaser = mResources->createReleaser(/*isBuffer=*/true); |
| auto error = mResources->getDisplayOutputBuffer(display->getId(), buffer, &importedBuffer, |
| releaser.get()); |
| if (error != HWC3::Error::None) { |
| LOG_DISPLAY_COMMAND_ERROR(display, error); |
| mCommandResults->addError(error); |
| return; |
| } |
| |
| error = display->setOutputBuffer(importedBuffer, buffer.fence); |
| if (error != HWC3::Error::None) { |
| LOG_DISPLAY_COMMAND_ERROR(display, error); |
| mCommandResults->addError(error); |
| return; |
| } |
| } |
| |
| void ComposerClient::executeDisplayCommandValidateDisplay( |
| Display* display, const std::optional<ClockMonotonicTimestamp> expectedPresentTime) { |
| DEBUG_LOG("%s", __FUNCTION__); |
| |
| auto error = display->setExpectedPresentTime(expectedPresentTime); |
| if (error != HWC3::Error::None) { |
| LOG_DISPLAY_COMMAND_ERROR(display, error); |
| mCommandResults->addError(error); |
| } |
| |
| DisplayChanges changes; |
| |
| error = display->validate(&changes); |
| if (error != HWC3::Error::None) { |
| LOG_DISPLAY_COMMAND_ERROR(display, error); |
| mCommandResults->addError(error); |
| } else { |
| mCommandResults->addChanges(changes); |
| } |
| |
| mResources->setDisplayMustValidateState(display->getId(), false); |
| } |
| |
| void ComposerClient::executeDisplayCommandAcceptDisplayChanges(Display* display) { |
| DEBUG_LOG("%s", __FUNCTION__); |
| |
| auto error = display->acceptChanges(); |
| if (error != HWC3::Error::None) { |
| LOG_DISPLAY_COMMAND_ERROR(display, error); |
| mCommandResults->addError(error); |
| } |
| } |
| |
| void ComposerClient::executeDisplayCommandPresentOrValidateDisplay( |
| Display* display, const std::optional<ClockMonotonicTimestamp> expectedPresentTime) { |
| DEBUG_LOG("%s", __FUNCTION__); |
| |
| // TODO: Support SKIP_VALIDATE. |
| |
| auto error = display->setExpectedPresentTime(expectedPresentTime); |
| if (error != HWC3::Error::None) { |
| LOG_DISPLAY_COMMAND_ERROR(display, error); |
| mCommandResults->addError(error); |
| } |
| |
| DisplayChanges changes; |
| |
| error = display->validate(&changes); |
| if (error != HWC3::Error::None) { |
| LOG_DISPLAY_COMMAND_ERROR(display, error); |
| mCommandResults->addError(error); |
| } else { |
| const int64_t displayId = display->getId(); |
| mCommandResults->addChanges(changes); |
| mCommandResults->addPresentOrValidateResult(displayId, |
| PresentOrValidate::Result::Validated); |
| } |
| |
| mResources->setDisplayMustValidateState(display->getId(), false); |
| } |
| |
| void ComposerClient::executeDisplayCommandPresentDisplay(Display* display) { |
| DEBUG_LOG("%s", __FUNCTION__); |
| |
| if (mResources->mustValidateDisplay(display->getId())) { |
| ALOGE("%s: display:%" PRIu64 " not validated", __FUNCTION__, display->getId()); |
| mCommandResults->addError(HWC3::Error::NotValidated); |
| return; |
| } |
| |
| ::android::base::unique_fd displayFence; |
| std::unordered_map<int64_t, ::android::base::unique_fd> layerFences; |
| |
| auto error = display->present(&displayFence, &layerFences); |
| if (error != HWC3::Error::None) { |
| LOG_DISPLAY_COMMAND_ERROR(display, error); |
| mCommandResults->addError(error); |
| } else { |
| const int64_t displayId = display->getId(); |
| mCommandResults->addPresentFence(displayId, std::move(displayFence)); |
| mCommandResults->addReleaseFences(displayId, std::move(layerFences)); |
| } |
| } |
| |
| void ComposerClient::executeLayerCommandSetLayerCursorPosition( |
| Display* display, Layer* layer, const common::Point& cursorPosition) { |
| DEBUG_LOG("%s", __FUNCTION__); |
| |
| auto error = layer->setCursorPosition(cursorPosition); |
| if (error != HWC3::Error::None) { |
| LOG_LAYER_COMMAND_ERROR(display, layer, error); |
| mCommandResults->addError(error); |
| } |
| } |
| |
| void ComposerClient::executeLayerCommandSetLayerBuffer(Display* display, Layer* layer, |
| const Buffer& buffer) { |
| DEBUG_LOG("%s", __FUNCTION__); |
| |
| // Owned by mResources. |
| buffer_handle_t importedBuffer = nullptr; |
| |
| auto releaser = mResources->createReleaser(/*isBuffer=*/true); |
| auto error = mResources->getLayerBuffer(display->getId(), layer->getId(), buffer, |
| &importedBuffer, releaser.get()); |
| if (error != HWC3::Error::None) { |
| LOG_LAYER_COMMAND_ERROR(display, layer, error); |
| mCommandResults->addError(error); |
| return; |
| } |
| |
| error = layer->setBuffer(importedBuffer, buffer.fence); |
| if (error != HWC3::Error::None) { |
| LOG_LAYER_COMMAND_ERROR(display, layer, error); |
| mCommandResults->addError(error); |
| } |
| } |
| |
| void ComposerClient::executeLayerCommandSetLayerSurfaceDamage( |
| Display* display, Layer* layer, const std::vector<std::optional<common::Rect>>& damage) { |
| DEBUG_LOG("%s", __FUNCTION__); |
| |
| auto error = layer->setSurfaceDamage(damage); |
| if (error != HWC3::Error::None) { |
| LOG_LAYER_COMMAND_ERROR(display, layer, error); |
| mCommandResults->addError(error); |
| } |
| } |
| |
| void ComposerClient::executeLayerCommandSetLayerBlendMode(Display* display, Layer* layer, |
| const ParcelableBlendMode& blendMode) { |
| DEBUG_LOG("%s", __FUNCTION__); |
| |
| auto error = layer->setBlendMode(blendMode.blendMode); |
| if (error != HWC3::Error::None) { |
| LOG_LAYER_COMMAND_ERROR(display, layer, error); |
| mCommandResults->addError(error); |
| } |
| } |
| |
| void ComposerClient::executeLayerCommandSetLayerColor(Display* display, Layer* layer, |
| const Color& color) { |
| DEBUG_LOG("%s", __FUNCTION__); |
| |
| auto error = layer->setColor(color); |
| if (error != HWC3::Error::None) { |
| LOG_LAYER_COMMAND_ERROR(display, layer, error); |
| mCommandResults->addError(error); |
| } |
| } |
| |
| void ComposerClient::executeLayerCommandSetLayerComposition( |
| Display* display, Layer* layer, const ParcelableComposition& composition) { |
| DEBUG_LOG("%s", __FUNCTION__); |
| |
| auto error = layer->setCompositionType(composition.composition); |
| if (error != HWC3::Error::None) { |
| LOG_LAYER_COMMAND_ERROR(display, layer, error); |
| mCommandResults->addError(error); |
| } |
| } |
| |
| void ComposerClient::executeLayerCommandSetLayerDataspace(Display* display, Layer* layer, |
| const ParcelableDataspace& dataspace) { |
| DEBUG_LOG("%s", __FUNCTION__); |
| |
| auto error = layer->setDataspace(dataspace.dataspace); |
| if (error != HWC3::Error::None) { |
| LOG_LAYER_COMMAND_ERROR(display, layer, error); |
| mCommandResults->addError(error); |
| } |
| } |
| |
| void ComposerClient::executeLayerCommandSetLayerDisplayFrame(Display* display, Layer* layer, |
| const common::Rect& rect) { |
| DEBUG_LOG("%s", __FUNCTION__); |
| |
| auto error = layer->setDisplayFrame(rect); |
| if (error != HWC3::Error::None) { |
| LOG_LAYER_COMMAND_ERROR(display, layer, error); |
| mCommandResults->addError(error); |
| } |
| } |
| |
| void ComposerClient::executeLayerCommandSetLayerPlaneAlpha(Display* display, Layer* layer, |
| const PlaneAlpha& planeAlpha) { |
| DEBUG_LOG("%s", __FUNCTION__); |
| |
| auto error = layer->setPlaneAlpha(planeAlpha.alpha); |
| if (error != HWC3::Error::None) { |
| LOG_LAYER_COMMAND_ERROR(display, layer, error); |
| mCommandResults->addError(error); |
| } |
| } |
| |
| void ComposerClient::executeLayerCommandSetLayerSidebandStream( |
| Display* display, Layer* layer, const aidl::android::hardware::common::NativeHandle& handle) { |
| DEBUG_LOG("%s", __FUNCTION__); |
| |
| // Owned by mResources. |
| buffer_handle_t importedStream = nullptr; |
| |
| auto releaser = mResources->createReleaser(/*isBuffer=*/false); |
| auto error = mResources->getLayerSidebandStream(display->getId(), layer->getId(), handle, |
| &importedStream, releaser.get()); |
| if (error != HWC3::Error::None) { |
| LOG_LAYER_COMMAND_ERROR(display, layer, error); |
| mCommandResults->addError(error); |
| return; |
| } |
| |
| error = layer->setSidebandStream(importedStream); |
| if (error != HWC3::Error::None) { |
| LOG_LAYER_COMMAND_ERROR(display, layer, error); |
| mCommandResults->addError(error); |
| } |
| } |
| |
| void ComposerClient::executeLayerCommandSetLayerSourceCrop(Display* display, Layer* layer, |
| const common::FRect& sourceCrop) { |
| DEBUG_LOG("%s", __FUNCTION__); |
| |
| auto error = layer->setSourceCrop(sourceCrop); |
| if (error != HWC3::Error::None) { |
| LOG_LAYER_COMMAND_ERROR(display, layer, error); |
| mCommandResults->addError(error); |
| } |
| } |
| |
| void ComposerClient::executeLayerCommandSetLayerTransform(Display* display, Layer* layer, |
| const ParcelableTransform& transform) { |
| DEBUG_LOG("%s", __FUNCTION__); |
| |
| auto error = layer->setTransform(transform.transform); |
| if (error != HWC3::Error::None) { |
| LOG_LAYER_COMMAND_ERROR(display, layer, error); |
| mCommandResults->addError(error); |
| } |
| } |
| |
| void ComposerClient::executeLayerCommandSetLayerVisibleRegion( |
| Display* display, Layer* layer, const std::vector<std::optional<common::Rect>>& visibleRegion) { |
| DEBUG_LOG("%s", __FUNCTION__); |
| |
| auto error = layer->setVisibleRegion(visibleRegion); |
| if (error != HWC3::Error::None) { |
| LOG_LAYER_COMMAND_ERROR(display, layer, error); |
| mCommandResults->addError(error); |
| } |
| } |
| |
| void ComposerClient::executeLayerCommandSetLayerZOrder(Display* display, Layer* layer, |
| const ZOrder& zOrder) { |
| DEBUG_LOG("%s", __FUNCTION__); |
| |
| auto error = layer->setZOrder(zOrder.z); |
| if (error != HWC3::Error::None) { |
| LOG_LAYER_COMMAND_ERROR(display, layer, error); |
| mCommandResults->addError(error); |
| } |
| } |
| |
| void ComposerClient::executeLayerCommandSetLayerPerFrameMetadata( |
| Display* display, Layer* layer, |
| const std::vector<std::optional<PerFrameMetadata>>& perFrameMetadata) { |
| DEBUG_LOG("%s", __FUNCTION__); |
| |
| auto error = layer->setPerFrameMetadata(perFrameMetadata); |
| if (error != HWC3::Error::None) { |
| LOG_LAYER_COMMAND_ERROR(display, layer, error); |
| mCommandResults->addError(error); |
| } |
| } |
| |
| void ComposerClient::executeLayerCommandSetLayerColorTransform( |
| Display* display, Layer* layer, const std::vector<float>& colorTransform) { |
| DEBUG_LOG("%s", __FUNCTION__); |
| |
| auto error = layer->setColorTransform(colorTransform); |
| if (error != HWC3::Error::None) { |
| LOG_LAYER_COMMAND_ERROR(display, layer, error); |
| mCommandResults->addError(error); |
| } |
| } |
| |
| void ComposerClient::executeLayerCommandSetLayerBrightness(Display* display, Layer* layer, |
| const LayerBrightness& brightness) { |
| DEBUG_LOG("%s", __FUNCTION__); |
| |
| auto error = layer->setBrightness(brightness.brightness); |
| if (error != HWC3::Error::None) { |
| LOG_LAYER_COMMAND_ERROR(display, layer, error); |
| mCommandResults->addError(error); |
| } |
| } |
| |
| void ComposerClient::executeLayerCommandSetLayerPerFrameMetadataBlobs( |
| Display* display, Layer* layer, |
| const std::vector<std::optional<PerFrameMetadataBlob>>& perFrameMetadataBlob) { |
| DEBUG_LOG("%s", __FUNCTION__); |
| |
| auto error = layer->setPerFrameMetadataBlobs(perFrameMetadataBlob); |
| if (error != HWC3::Error::None) { |
| LOG_LAYER_COMMAND_ERROR(display, layer, error); |
| mCommandResults->addError(error); |
| } |
| } |
| |
| Display* ComposerClient::getDisplay(int64_t displayId) { |
| auto it = mDisplays.find(displayId); |
| if (it == mDisplays.end()) { |
| ALOGE("%s: no display:%" PRIu64, __FUNCTION__, displayId); |
| return nullptr; |
| } |
| return it->second.get(); |
| } |
| |
| HWC3::Error ComposerClient::createDisplaysLocked() { |
| DEBUG_LOG("%s", __FUNCTION__); |
| |
| if (!mComposer) { |
| ALOGE("%s composer not initialized!", __FUNCTION__); |
| return HWC3::Error::NoResources; |
| } |
| |
| std::vector<DisplayMultiConfigs> displays; |
| |
| HWC3::Error error = findDisplays(mComposer->getDrmPresenter(), &displays); |
| if (error != HWC3::Error::None) { |
| ALOGE("%s failed to find display configs", __FUNCTION__); |
| return error; |
| } |
| |
| for (const auto& iter : displays) { |
| error = createDisplayLocked(iter.displayId, iter.activeConfigId, iter.configs); |
| if (error != HWC3::Error::None) { |
| ALOGE("%s failed to create display from config", __FUNCTION__); |
| return error; |
| } |
| } |
| |
| return HWC3::Error::None; |
| } |
| |
| HWC3::Error ComposerClient::createDisplayLocked(int64_t displayId, int32_t activeConfigId, |
| const std::vector<DisplayConfig>& configs) { |
| DEBUG_LOG("%s", __FUNCTION__); |
| |
| if (!mComposer) { |
| ALOGE("%s composer not initialized!", __FUNCTION__); |
| return HWC3::Error::NoResources; |
| } |
| |
| auto display = std::make_unique<Display>(mComposer, displayId); |
| if (display == nullptr) { |
| ALOGE("%s failed to allocate display", __FUNCTION__); |
| return HWC3::Error::NoResources; |
| } |
| |
| HWC3::Error error = display->init(configs, activeConfigId); |
| if (error != HWC3::Error::None) { |
| ALOGE("%s failed to initialize display:%" PRIu64, __FUNCTION__, displayId); |
| return error; |
| } |
| |
| error = mComposer->onDisplayCreate(display.get()); |
| if (error != HWC3::Error::None) { |
| ALOGE("%s failed to register display:%" PRIu64 " with composer", __FUNCTION__, displayId); |
| return error; |
| } |
| |
| display->setPowerMode(PowerMode::ON); |
| |
| DEBUG_LOG("%s: adding display:%" PRIu64, __FUNCTION__, displayId); |
| mDisplays.emplace(displayId, std::move(display)); |
| |
| error = mResources->addPhysicalDisplay(displayId); |
| if (error != HWC3::Error::None) { |
| ALOGE("%s failed to initialize display:%" PRIu64 " resources", __FUNCTION__, displayId); |
| return error; |
| } |
| |
| return HWC3::Error::None; |
| } |
| |
| HWC3::Error ComposerClient::destroyDisplaysLocked() { |
| DEBUG_LOG("%s", __FUNCTION__); |
| |
| std::vector<int64_t> displayIds; |
| for (const auto& [displayId, _] : mDisplays) { |
| displayIds.push_back(displayId); |
| } |
| for (const int64_t displayId : displayIds) { |
| destroyDisplayLocked(displayId); |
| } |
| |
| return HWC3::Error::None; |
| } |
| |
| HWC3::Error ComposerClient::destroyDisplayLocked(int64_t displayId) { |
| DEBUG_LOG("%s display:%" PRId64, __FUNCTION__, displayId); |
| |
| auto it = mDisplays.find(displayId); |
| if (it == mDisplays.end()) { |
| ALOGE("%s: display:%" PRId64 " no such display?", __FUNCTION__, displayId); |
| return HWC3::Error::BadDisplay; |
| } |
| |
| Display* display = it->second.get(); |
| |
| display->setPowerMode(PowerMode::OFF); |
| |
| HWC3::Error error = mComposer->onDisplayDestroy(it->second.get()); |
| if (error != HWC3::Error::None) { |
| ALOGE("%s: display:%" PRId64 " failed to destroy with frame composer", __FUNCTION__, |
| displayId); |
| } |
| |
| error = mResources->removeDisplay(displayId); |
| if (error != HWC3::Error::None) { |
| ALOGE("%s: display:%" PRId64 " failed to destroy with resources", __FUNCTION__, displayId); |
| } |
| |
| mDisplays.erase(it); |
| |
| return HWC3::Error::None; |
| } |
| |
| HWC3::Error ComposerClient::handleHotplug(bool connected, uint32_t id, uint32_t width, |
| uint32_t height, uint32_t dpiX, uint32_t dpiY, |
| uint32_t refreshRate) { |
| if (!mCallbacks) { |
| return HWC3::Error::None; |
| } |
| |
| const int64_t displayId = static_cast<int64_t>(id); |
| |
| if (connected) { |
| const int32_t configId = static_cast<int32_t>(id); |
| const std::vector<DisplayConfig> configs = {DisplayConfig( |
| configId, static_cast<int>(width), static_cast<int>(height), static_cast<int>(dpiX), |
| static_cast<int>(dpiY), static_cast<int>(refreshRate))}; |
| { |
| std::unique_lock<std::mutex> lock(mStateMutex); |
| createDisplayLocked(displayId, configId, configs); |
| } |
| |
| ALOGI("Connecting display:%" PRIu32 " w:%" PRIu32 " h:%" PRIu32 " dpiX:%" PRIu32 |
| " dpiY %" PRIu32 "fps %" PRIu32, |
| id, width, height, dpiX, dpiY, refreshRate); |
| mCallbacks->onHotplug(displayId, /*connected=*/true); |
| } else { |
| ALOGI("Disconnecting display:%" PRIu64, displayId); |
| mCallbacks->onHotplug(displayId, /*connected=*/false); |
| |
| Display* display = getDisplay(displayId); |
| if (display != nullptr) { |
| std::unique_lock<std::mutex> lock(mStateMutex); |
| destroyDisplayLocked(displayId); |
| } |
| } |
| |
| return HWC3::Error::None; |
| } |
| |
| } // namespace aidl::android::hardware::graphics::composer3::impl |