| /* |
| * 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, // |
| int32_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, 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::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::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, 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::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; |
| } |
| |
| 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; |
| } |
| |
| 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) { |
| std::unique_lock<std::mutex> lock(mStateMutex); |
| |
| if (!mCallbacks) { |
| return HWC3::Error::None; |
| } |
| |
| const int64_t displayId = static_cast<int64_t>(id); |
| |
| Display* display = getDisplay(displayId); |
| if (display != nullptr) { |
| ALOGI("Disconnecting display:%" PRIu64, displayId); |
| mCallbacks->onHotplug(displayId, /*connected=*/false); |
| |
| destroyDisplayLocked(displayId); |
| } |
| |
| 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))}; |
| |
| 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); |
| } |
| |
| return HWC3::Error::None; |
| } |
| |
| } // namespace aidl::android::hardware::graphics::composer3::impl |