blob: 2098435022a94a39959181882906cd3a00a3104e [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"
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