blob: 2ae2499867b1b39283b899f991a7e02f238a86ef [file] [log] [blame]
/*
* 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"
#include "Time.h"
namespace aidl::android::hardware::graphics::composer3::impl {
namespace {
#define GET_DISPLAY_OR_RETURN_ERROR() \
std::shared_ptr<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::lock_guard<std::mutex> lock(mDisplaysMutex);
destroyDisplaysLocked();
if (mOnClientDestroyed) {
mOnClientDestroyed();
}
}
HWC3::Error ComposerClient::init() {
DEBUG_LOG("%s", __FUNCTION__);
HWC3::Error error = HWC3::Error::None;
std::lock_guard<std::mutex> lock(mDisplaysMutex);
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);
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);
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__);
CommandResultWriter commandResults(commandResultPayloads);
for (const DisplayCommand& command : commands) {
executeDisplayCommand(commandResults, command);
commandResults.nextCommand();
}
return ToBinderStatus(HWC3::Error::None);
}
ndk::ScopedAStatus ComposerClient::getActiveConfig(int64_t displayId, int32_t* config) {
DEBUG_LOG("%s", __FUNCTION__);
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__);
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__);
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__);
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__);
GET_DISPLAY_OR_RETURN_ERROR();
return ToBinderStatus(display->getDisplayConfigs(outConfigs));
}
ndk::ScopedAStatus ComposerClient::getDisplayConnectionType(int64_t displayId,
DisplayConnectionType* outType) {
DEBUG_LOG("%s", __FUNCTION__);
GET_DISPLAY_OR_RETURN_ERROR();
return ToBinderStatus(display->getDisplayConnectionType(outType));
}
ndk::ScopedAStatus ComposerClient::getDisplayIdentificationData(
int64_t displayId, DisplayIdentification* outIdentification) {
DEBUG_LOG("%s", __FUNCTION__);
GET_DISPLAY_OR_RETURN_ERROR();
return ToBinderStatus(display->getDisplayIdentificationData(outIdentification));
}
ndk::ScopedAStatus ComposerClient::getDisplayName(int64_t displayId, std::string* outName) {
DEBUG_LOG("%s", __FUNCTION__);
GET_DISPLAY_OR_RETURN_ERROR();
return ToBinderStatus(display->getDisplayName(outName));
}
ndk::ScopedAStatus ComposerClient::getDisplayVsyncPeriod(int64_t displayId,
int32_t* outVsyncPeriod) {
DEBUG_LOG("%s", __FUNCTION__);
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__);
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__);
GET_DISPLAY_OR_RETURN_ERROR();
return ToBinderStatus(display->getDisplayedContentSamplingAttributes(outAttributes));
}
ndk::ScopedAStatus ComposerClient::getDisplayPhysicalOrientation(
int64_t displayId, common::Transform* outOrientation) {
DEBUG_LOG("%s", __FUNCTION__);
GET_DISPLAY_OR_RETURN_ERROR();
return ToBinderStatus(display->getDisplayPhysicalOrientation(outOrientation));
}
ndk::ScopedAStatus ComposerClient::getHdrCapabilities(int64_t displayId,
HdrCapabilities* outCapabilities) {
DEBUG_LOG("%s", __FUNCTION__);
GET_DISPLAY_OR_RETURN_ERROR();
return ToBinderStatus(display->getHdrCapabilities(outCapabilities));
}
ndk::ScopedAStatus ComposerClient::getOverlaySupport(OverlayProperties* /*properties*/) {
DEBUG_LOG("%s", __FUNCTION__);
return ToBinderStatus(HWC3::Error::Unsupported);
}
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__);
GET_DISPLAY_OR_RETURN_ERROR();
return ToBinderStatus(display->getPerFrameMetadataKeys(outKeys));
}
ndk::ScopedAStatus ComposerClient::getReadbackBufferAttributes(
int64_t displayId, ReadbackBufferAttributes* outAttributes) {
DEBUG_LOG("%s", __FUNCTION__);
GET_DISPLAY_OR_RETURN_ERROR();
return ToBinderStatus(display->getReadbackBufferAttributes(outAttributes));
}
ndk::ScopedAStatus ComposerClient::getReadbackBufferFence(
int64_t displayId, ndk::ScopedFileDescriptor* outAcquireFence) {
DEBUG_LOG("%s", __FUNCTION__);
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__);
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__);
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__);
GET_DISPLAY_OR_RETURN_ERROR();
return ToBinderStatus(display->getDecorationSupport(outSupport));
}
ndk::ScopedAStatus ComposerClient::registerCallback(
const std::shared_ptr<IComposerCallback>& callback) {
DEBUG_LOG("%s", __FUNCTION__);
const bool isFirstRegisterCallback = mCallbacks == nullptr;
mCallbacks = callback;
{
std::lock_guard<std::mutex> lock(mDisplaysMutex);
for (auto& [_, display] : mDisplays) {
display->registerCallback(callback);
}
}
if (isFirstRegisterCallback) {
std::vector<int64_t> displayIds;
{
std::lock_guard<std::mutex> lock(mDisplaysMutex);
for (auto& [displayId, _] : mDisplays) {
displayIds.push_back(displayId);
}
}
for (auto displayId : displayIds) {
DEBUG_LOG("%s initial registration, hotplug connecting display:%" PRIu64, __FUNCTION__,
displayId);
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);
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);
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);
GET_DISPLAY_OR_RETURN_ERROR();
return ToBinderStatus(display->setBootConfig(configId));
}
ndk::ScopedAStatus ComposerClient::clearBootDisplayConfig(int64_t displayId) {
DEBUG_LOG("%s display:%" PRIu64, __FUNCTION__, displayId);
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);
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__);
GET_DISPLAY_OR_RETURN_ERROR();
return ToBinderStatus(display->setAutoLowLatencyMode(on));
}
ndk::ScopedAStatus ComposerClient::setClientTargetSlotCount(int64_t displayId, int32_t count) {
DEBUG_LOG("%s", __FUNCTION__);
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__);
GET_DISPLAY_OR_RETURN_ERROR();
return ToBinderStatus(display->setColorMode(mode, intent));
}
ndk::ScopedAStatus ComposerClient::setContentType(int64_t displayId, ContentType type) {
DEBUG_LOG("%s", __FUNCTION__);
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__);
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__);
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__);
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__);
GET_DISPLAY_OR_RETURN_ERROR();
return ToBinderStatus(display->setVsyncEnabled(enabled));
}
ndk::ScopedAStatus ComposerClient::setIdleTimerEnabled(int64_t displayId, int32_t timeoutMs) {
DEBUG_LOG("%s", __FUNCTION__);
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::ScopedAStatus ComposerClient::getDisplayConfigurations(
int64_t displayId, int32_t /*maxFrameIntervalNs*/,
std::vector<DisplayConfiguration>* outDisplayConfig) {
DEBUG_LOG("%s", __FUNCTION__);
GET_DISPLAY_OR_RETURN_ERROR();
return ToBinderStatus(display->getDisplayConfigurations(outDisplayConfig));
}
ndk::ScopedAStatus ComposerClient::notifyExpectedPresent(
int64_t displayId, const ClockMonotonicTimestamp& /*expectedPresentTime*/,
int32_t /*frameIntervalNs*/) {
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, commandResults, display, layer, field, funcName) \
do { \
if (layerCmd.field) { \
ComposerClient::executeLayerCommandSetLayer##funcName(commandResults, display, layer, \
*layerCmd.field); \
} \
} while (0)
#define DISPATCH_DISPLAY_COMMAND(displayCmd, commandResults, display, field, funcName) \
do { \
if (displayCmd.field) { \
executeDisplayCommand##funcName(commandResults, display, *displayCmd.field); \
} \
} while (0)
#define DISPATCH_DISPLAY_BOOL_COMMAND(displayCmd, commandResults, display, field, funcName) \
do { \
if (displayCmd.field) { \
executeDisplayCommand##funcName(commandResults, display); \
} \
} while (0)
#define DISPATCH_DISPLAY_BOOL_COMMAND_AND_DATA(displayCmd, commandResults, display, field, data, \
funcName) \
do { \
if (displayCmd.field) { \
executeDisplayCommand##funcName(commandResults, 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(CommandResultWriter& commandResults,
const DisplayCommand& displayCommand) {
std::shared_ptr<Display> display = getDisplay(displayCommand.display);
if (display == nullptr) {
commandResults.addError(HWC3::Error::BadDisplay);
return;
}
for (const LayerCommand& layerCmd : displayCommand.layers) {
executeLayerCommand(commandResults, *display, layerCmd);
}
DISPATCH_DISPLAY_COMMAND(displayCommand, commandResults, *display, colorTransformMatrix,
SetColorTransform);
DISPATCH_DISPLAY_COMMAND(displayCommand, commandResults, *display, brightness, SetBrightness);
DISPATCH_DISPLAY_COMMAND(displayCommand, commandResults, *display, clientTarget,
SetClientTarget);
DISPATCH_DISPLAY_COMMAND(displayCommand, commandResults, *display, virtualDisplayOutputBuffer,
SetOutputBuffer);
DISPATCH_DISPLAY_BOOL_COMMAND_AND_DATA(displayCommand, commandResults, *display,
validateDisplay, expectedPresentTime, ValidateDisplay);
DISPATCH_DISPLAY_BOOL_COMMAND(displayCommand, commandResults, *display, acceptDisplayChanges,
AcceptDisplayChanges);
DISPATCH_DISPLAY_BOOL_COMMAND(displayCommand, commandResults, *display, presentDisplay,
PresentDisplay);
DISPATCH_DISPLAY_BOOL_COMMAND_AND_DATA(displayCommand, commandResults, *display,
presentOrValidateDisplay, expectedPresentTime,
PresentOrValidateDisplay);
}
void ComposerClient::executeLayerCommand(CommandResultWriter& commandResults, Display& display,
const LayerCommand& layerCommand) {
Layer* layer = display.getLayer(layerCommand.layer);
if (layer == nullptr) {
commandResults.addError(HWC3::Error::BadLayer);
return;
}
DISPATCH_LAYER_COMMAND(layerCommand, commandResults, display, layer, cursorPosition,
CursorPosition);
DISPATCH_LAYER_COMMAND(layerCommand, commandResults, display, layer, buffer, Buffer);
DISPATCH_LAYER_COMMAND(layerCommand, commandResults, display, layer, damage, SurfaceDamage);
DISPATCH_LAYER_COMMAND(layerCommand, commandResults, display, layer, blendMode, BlendMode);
DISPATCH_LAYER_COMMAND(layerCommand, commandResults, display, layer, color, Color);
DISPATCH_LAYER_COMMAND(layerCommand, commandResults, display, layer, composition, Composition);
DISPATCH_LAYER_COMMAND(layerCommand, commandResults, display, layer, dataspace, Dataspace);
DISPATCH_LAYER_COMMAND(layerCommand, commandResults, display, layer, displayFrame,
DisplayFrame);
DISPATCH_LAYER_COMMAND(layerCommand, commandResults, display, layer, planeAlpha, PlaneAlpha);
DISPATCH_LAYER_COMMAND(layerCommand, commandResults, display, layer, sidebandStream,
SidebandStream);
DISPATCH_LAYER_COMMAND(layerCommand, commandResults, display, layer, sourceCrop, SourceCrop);
DISPATCH_LAYER_COMMAND(layerCommand, commandResults, display, layer, transform, Transform);
DISPATCH_LAYER_COMMAND(layerCommand, commandResults, display, layer, visibleRegion,
VisibleRegion);
DISPATCH_LAYER_COMMAND(layerCommand, commandResults, display, layer, z, ZOrder);
DISPATCH_LAYER_COMMAND(layerCommand, commandResults, display, layer, colorTransform,
ColorTransform);
DISPATCH_LAYER_COMMAND(layerCommand, commandResults, display, layer, brightness, Brightness);
DISPATCH_LAYER_COMMAND(layerCommand, commandResults, display, layer, perFrameMetadata,
PerFrameMetadata);
DISPATCH_LAYER_COMMAND(layerCommand, commandResults, display, layer, perFrameMetadataBlob,
PerFrameMetadataBlobs);
DISPATCH_LAYER_COMMAND(layerCommand, commandResults, display, layer, luts,
Luts);
}
void ComposerClient::executeDisplayCommandSetColorTransform(CommandResultWriter& commandResults,
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);
commandResults.addError(error);
}
}
void ComposerClient::executeDisplayCommandSetBrightness(CommandResultWriter& commandResults,
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);
commandResults.addError(error);
}
}
void ComposerClient::executeDisplayCommandSetClientTarget(CommandResultWriter& commandResults,
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);
commandResults.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);
commandResults.addError(error);
return;
}
}
void ComposerClient::executeDisplayCommandSetOutputBuffer(CommandResultWriter& commandResults,
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);
commandResults.addError(error);
return;
}
error = display.setOutputBuffer(importedBuffer, buffer.fence);
if (error != HWC3::Error::None) {
LOG_DISPLAY_COMMAND_ERROR(display, error);
commandResults.addError(error);
return;
}
}
void ComposerClient::executeDisplayCommandValidateDisplay(
CommandResultWriter& commandResults, 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);
commandResults.addError(error);
}
DisplayChanges changes;
error = display.validate(&changes);
if (error != HWC3::Error::None) {
LOG_DISPLAY_COMMAND_ERROR(display, error);
commandResults.addError(error);
} else {
commandResults.addChanges(changes);
}
mResources->setDisplayMustValidateState(display.getId(), false);
}
void ComposerClient::executeDisplayCommandAcceptDisplayChanges(CommandResultWriter& commandResults,
Display& display) {
DEBUG_LOG("%s", __FUNCTION__);
auto error = display.acceptChanges();
if (error != HWC3::Error::None) {
LOG_DISPLAY_COMMAND_ERROR(display, error);
commandResults.addError(error);
}
}
void ComposerClient::executeDisplayCommandPresentOrValidateDisplay(
CommandResultWriter& commandResults, 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);
commandResults.addError(error);
}
DisplayChanges changes;
error = display.validate(&changes);
if (error != HWC3::Error::None) {
LOG_DISPLAY_COMMAND_ERROR(display, error);
commandResults.addError(error);
} else {
const int64_t displayId = display.getId();
commandResults.addChanges(changes);
commandResults.addPresentOrValidateResult(displayId, PresentOrValidate::Result::Validated);
}
mResources->setDisplayMustValidateState(display.getId(), false);
}
void ComposerClient::executeDisplayCommandPresentDisplay(CommandResultWriter& commandResults,
Display& display) {
DEBUG_LOG("%s", __FUNCTION__);
if (mResources->mustValidateDisplay(display.getId())) {
ALOGE("%s: display:%" PRIu64 " not validated", __FUNCTION__, display.getId());
commandResults.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);
commandResults.addError(error);
} else {
const int64_t displayId = display.getId();
commandResults.addPresentFence(displayId, std::move(displayFence));
commandResults.addReleaseFences(displayId, std::move(layerFences));
}
}
void ComposerClient::executeLayerCommandSetLayerCursorPosition(
CommandResultWriter& commandResults, 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);
commandResults.addError(error);
}
}
void ComposerClient::executeLayerCommandSetLayerBuffer(CommandResultWriter& commandResults,
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);
commandResults.addError(error);
return;
}
error = layer->setBuffer(importedBuffer, buffer.fence);
if (error != HWC3::Error::None) {
LOG_LAYER_COMMAND_ERROR(display, layer, error);
commandResults.addError(error);
}
}
void ComposerClient::executeLayerCommandSetLayerSurfaceDamage(
CommandResultWriter& commandResults, 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);
commandResults.addError(error);
}
}
void ComposerClient::executeLayerCommandSetLayerBlendMode(CommandResultWriter& commandResults,
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);
commandResults.addError(error);
}
}
void ComposerClient::executeLayerCommandSetLayerColor(CommandResultWriter& commandResults,
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);
commandResults.addError(error);
}
}
void ComposerClient::executeLayerCommandSetLayerComposition(
CommandResultWriter& commandResults, 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);
commandResults.addError(error);
}
}
void ComposerClient::executeLayerCommandSetLayerDataspace(CommandResultWriter& commandResults,
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);
commandResults.addError(error);
}
}
void ComposerClient::executeLayerCommandSetLayerDisplayFrame(CommandResultWriter& commandResults,
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);
commandResults.addError(error);
}
}
void ComposerClient::executeLayerCommandSetLayerPlaneAlpha(CommandResultWriter& commandResults,
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);
commandResults.addError(error);
}
}
void ComposerClient::executeLayerCommandSetLayerSidebandStream(
CommandResultWriter& commandResults, 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);
commandResults.addError(error);
return;
}
error = layer->setSidebandStream(importedStream);
if (error != HWC3::Error::None) {
LOG_LAYER_COMMAND_ERROR(display, layer, error);
commandResults.addError(error);
}
}
void ComposerClient::executeLayerCommandSetLayerSourceCrop(CommandResultWriter& commandResults,
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);
commandResults.addError(error);
}
}
void ComposerClient::executeLayerCommandSetLayerTransform(CommandResultWriter& commandResults,
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);
commandResults.addError(error);
}
}
void ComposerClient::executeLayerCommandSetLayerVisibleRegion(
CommandResultWriter& commandResults, 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);
commandResults.addError(error);
}
}
void ComposerClient::executeLayerCommandSetLayerZOrder(CommandResultWriter& commandResults,
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);
commandResults.addError(error);
}
}
void ComposerClient::executeLayerCommandSetLayerPerFrameMetadata(
CommandResultWriter& commandResults, 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);
commandResults.addError(error);
}
}
void ComposerClient::executeLayerCommandSetLayerColorTransform(
CommandResultWriter& commandResults, 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);
commandResults.addError(error);
}
}
void ComposerClient::executeLayerCommandSetLayerBrightness(CommandResultWriter& commandResults,
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);
commandResults.addError(error);
}
}
void ComposerClient::executeLayerCommandSetLayerPerFrameMetadataBlobs(
CommandResultWriter& commandResults, 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);
commandResults.addError(error);
}
}
void ComposerClient::executeLayerCommandSetLayerLuts(CommandResultWriter& /*commandResults*/,
Display& /*display*/, Layer* /*layer*/,
const std::vector<std::optional<Lut>>& /*luts*/) {
DEBUG_LOG("%s", __FUNCTION__);
//TODO(b/358188835)
}
std::shared_ptr<Display> ComposerClient::getDisplay(int64_t displayId) {
std::lock_guard<std::mutex> lock(mDisplaysMutex);
auto it = mDisplays.find(displayId);
if (it == mDisplays.end()) {
ALOGE("%s: no display:%" PRIu64, __FUNCTION__, displayId);
return nullptr;
}
return it->second;
}
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_shared<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 refreshRateHz) {
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);
int32_t vsyncPeriodNanos = HertzToPeriodNanos(refreshRateHz);
const std::vector<DisplayConfig> configs = {
DisplayConfig(configId, static_cast<int>(width), static_cast<int>(height),
static_cast<int>(dpiX), static_cast<int>(dpiY), vsyncPeriodNanos)};
{
std::lock_guard<std::mutex> lock(mDisplaysMutex);
createDisplayLocked(displayId, configId, configs);
}
ALOGI("Hotplug connecting display:%" PRIu32 " w:%" PRIu32 " h:%" PRIu32 " dpiX:%" PRIu32
" dpiY %" PRIu32 "fps %" PRIu32,
id, width, height, dpiX, dpiY, refreshRateHz);
mCallbacks->onHotplug(displayId, /*connected=*/true);
} else {
ALOGI("Hotplug disconnecting display:%" PRIu64, displayId);
mCallbacks->onHotplug(displayId, /*connected=*/false);
{
std::lock_guard<std::mutex> lock(mDisplaysMutex);
destroyDisplayLocked(displayId);
}
}
return HWC3::Error::None;
}
} // namespace aidl::android::hardware::graphics::composer3::impl