002.HWC 接口分析
2025/10/6大约 15 分钟
1. HWC3 AIDL 接口分析
HWC HAL 作为一个 HAL 模块,通过 Binder 服务向 SurfaceFlinger 提供了使用接口。这些接口通过 AIDL 文件定义:
- IComposer.aidl:HWC 直接提供的 Binder 服务
- IComposerClient.aidl:HWC 通过匿名 Binder 提供的 Binder 服务
SurfaceFlinger 向 HWC 注册了一个 Binder 回调,用于接收 HWC 事件通知,该回调协议通过 AIDL 文件定义:
- IComposerCallback.aidl:HWC 事件通知回调接口
1.1 IComposer.aidl 接口分析
// /hardware/interfaces/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/IComposer.aidl
package android.hardware.graphics.composer3;
@VintfStability
interface IComposer {
android.hardware.graphics.composer3.IComposerClient createClient();
android.hardware.graphics.composer3.Capability[] getCapabilities();
const int EX_NO_RESOURCES = 6;
}
getCapabilities 用于获取 HWC 支持的能力, 返回的 Capability 是一个枚举类型,枚举值定义在 Capability.aidl
中。
// /hardware/interfaces/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/Capability.aidl
enum Capability {
// 作为默认值或错误状态的标识
INVALID = 0,
// 支持侧带流(Sideband Stream)处理能力,允许硬件直接处理视频流,无需通过 SurfaceFlinger
SIDEBAND_STREAM = 1,
// 跳过客户端颜色变换处理,HWC 可以直接在硬件层面处理颜色空间转换
SKIP_CLIENT_COLOR_TRANSFORM = 2,
// 当硬件无法提供可靠的同步信号时设置此标志
PRESENT_FENCE_IS_NOT_RELIABLE = 3,
// - 原本用于跳过 HWC 的验证阶段以提升性能,现在默认启用,不再需要显式设置
/**
* @deprecated - enabled by default.
*/
SKIP_VALIDATE = 4,
//支持启动时显示配置
BOOT_DISPLAY_CONFIG = 5,
// HDR 输出转换配置支持
HDR_OUTPUT_CONVERSION_CONFIG = 6,
// 刷新率变化回调调试支持
REFRESH_RATE_CHANGED_CALLBACK_DEBUG = 7,
// 图层生命周期批处理命令支持
LAYER_LIFECYCLE_BATCH_COMMAND = 8,
}
createClient 用于获取 HWC 的匿名 Binder 服务 IComposerClient,该服务是一个匿名 Binder 服务,其能力定义在 IComposerClient.aidl
文件中。
1.2 IComposerClient.aidl 接口分析
IComposerClient.aidl
定义了 HWC 进程中匿名 Binder 服务 IComposerClient 向 SurfaceFlinger 提供的主要的功能,其定义如下:
// /hardware/interfaces/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/IComposerClient.aidl
package android.hardware.graphics.composer3;
@VintfStability
interface IComposerClient {
long createLayer(long display, int bufferSlotCount);
android.hardware.graphics.composer3.VirtualDisplay createVirtualDisplay(int width, int height, android.hardware.graphics.common.PixelFormat formatHint, int outputBufferSlotCount);
void destroyLayer(long display, long layer);
void destroyVirtualDisplay(long display);
android.hardware.graphics.composer3.CommandResultPayload[] execut eCommands(in android.hardware.graphics.composer3.DisplayCommand[] commands);
int getActiveConfig(long display);
android.hardware.graphics.composer3.ColorMode[] getColorModes(long display);
float[] getDataspaceSaturationMatrix(android.hardware.graphics.common.Dataspace dataspace);
/**
* @deprecated use getDisplayConfigurations instead. Returns a display attribute value for a particular display configuration. For legacy support getDisplayAttribute should return valid values for any requested DisplayAttribute, and for all of the configs obtained either through getDisplayConfigs or getDisplayConfigurations.
*/
int getDisplayAttribute(long display, int config, android.hardware.graphics.composer3.DisplayAttribute attribute);
android.hardware.graphics.composer3.DisplayCapability[] getDisplayCapabilities(long display);
/**
* @deprecated use getDisplayConfigurations instead. For legacy support getDisplayConfigs should return at least one valid config. All the configs returned from the getDisplayConfigs should also be returned from getDisplayConfigurations.
*/
int[] getDisplayConfigs(long display);
android.hardware.graphics.composer3.DisplayConnectionType getDisplayConnectionType(long display);
android.hardware.graphics.composer3.DisplayIdentification getDisplayIdentificationData(long display);
String getDisplayName(long display);
int getDisplayVsyncPeriod(long display);
android.hardware.graphics.composer3.DisplayContentSample getDisplayedContentSample(long display, long maxFrames, long timestamp);
android.hardware.graphics.composer3.DisplayContentSamplingAttributes getDisplayedContentSamplingAttributes(long display);
android.hardware.graphics.common.Transform getDisplayPhysicalOrientation(long display);
android.hardware.graphics.composer3.HdrCapabilities getHdrCapabilities(long display);
int getMaxVirtualDisplayCount();
android.hardware.graphics.composer3.PerFrameMetadataKey[] getPerFrameMetadataKeys(long display);
android.hardware.graphics.composer3.ReadbackBufferAttributes getReadbackBufferAttributes(long display);
@nullable ParcelFileDescriptor getReadbackBufferFence(long display);
android.hardware.graphics.composer3.RenderIntent[] getRenderIntents(long display, android.hardware.graphics.composer3.ColorMode mode);
android.hardware.graphics.composer3.ContentType[] getSupportedContentTypes(long display);
@nullable android.hardware.graphics.common.DisplayDecorationSupport getDisplayDecorationSupport(long display);
void registerCallback(in android.hardware.graphics.composer3.IComposerCallback callback);
void setActiveConfig(long display, int config);
android.hardware.graphics.composer3.VsyncPeriodChangeTimeline setActiveConfigWithConstraints(long display, int config, in android.hardware.graphics.composer3.VsyncPeriodChangeConstraints vsyncPeriodChangeConstraints);
void setBootDisplayConfig(long display, int config);
void clearBootDisplayConfig(long display);
int getPreferredBootDisplayConfig(long display);
void setAutoLowLatencyMode(long display, boolean on);
void setClientTargetSlotCount(long display, int clientTargetSlotCount);
void setColorMode(long display, android.hardware.graphics.composer3.ColorMode mode, android.hardware.graphics.composer3.RenderIntent intent);
void setContentType(long display, android.hardware.graphics.composer3.ContentType type);
void setDisplayedContentSamplingEnabled(long display, boolean enable, android.hardware.graphics.composer3.FormatColorComponent componentMask, long maxFrames);
void setPowerMode(long display, android.hardware.graphics.composer3.PowerMode mode);
void setReadbackBuffer(long display, in android.hardware.common.NativeHandle buffer, in @nullable ParcelFileDescriptor releaseFence);
void setVsyncEnabled(long display, boolean enabled);
void setIdleTimerEnabled(long display, int timeoutMs);
android.hardware.graphics.composer3.OverlayProperties getOverlaySupport();
android.hardware.graphics.common.HdrConversionCapability[] getHdrConversionCapabilities();
android.hardware.graphics.common.Hdr setHdrConversionStrategy(in android.hardware.graphics.common.HdrConversionStrategy conversionStrategy);
void setRefreshRateChangedCallbackDebugEnabled(long display, boolean enabled);
android.hardware.graphics.composer3.DisplayConfiguration[] getDisplayConfigurations(long display, int maxFrameIntervalNs);
oneway void notifyExpectedPresent(long display, in android.hardware.graphics.composer3.ClockMonotonicTimestamp expectedPresentTime, int frameIntervalNs);
int getMaxLayerPictureProfiles(long display);
oneway void startHdcpNegotiation(long display, in android.hardware.drm.HdcpLevels levels);
android.hardware.graphics.composer3.Luts[] getLuts(long display, in android.hardware.graphics.composer3.Buffer[] buffers);
const int EX_BAD_CONFIG = 1;
const int EX_BAD_DISPLAY = 2;
const int EX_BAD_LAYER = 3;
const int EX_BAD_PARAMETER = 4;
const int EX_RESERVED = 5;
const int EX_NO_RESOURCES = 6;
const int EX_NOT_VALIDATED = 7;
const int EX_UNSUPPORTED = 8;
const int EX_SEAMLESS_NOT_ALLOWED = 9;
const int EX_SEAMLESS_NOT_POSSIBLE = 10;
const int EX_CONFIG_FAILED = 11;
const int EX_PICTURE_PROFILE_MAX_EXCEEDED = 12;
const int INVALID_CONFIGURATION = 0x7fffffff;
}
内部定义的接口可分为以下几类:
- 命令执行,绝大部分操作都是通过
android.hardware.graphics.composer3.CommandResultPayload[] executeCommands(in android.hardware.graphics.composer3.DisplayCommand[] commands);
函数执行 - 图层管理函数
long createLayer(long display, int bufferSlotCount)
void destroyLayer(long display, long layer);
- 虚拟显示管理
- createVirtualDisplay
- destroyVirtualDisplay
- 显示配置管理
- getActiveConfig / setActiveConfigWithConstraints
- getDisplayConfigurations
- setActiveConfigWithConstraints
- 颜色和显示质量管理
- getColorModes / setColorMode
- getHdrCapabilities
- getDataspaceSaturationMatrix
- 电源管理
- setPowerMode
- 同步和时序控制
- setVsyncEnabled
- getDisplayVsyncPeriod
- notifyExpectedPresent
- 回调注册
- registerCallback
- 高级功能
- getOverlaySupport
- setAutoLowLatencyMode
- getHdrConversionCapabilities() / setHdrConversionStrategy
- 调试和诊断
* setRefreshRateChangedCallbackDebugEnabled
* getDisplayedContentSample
口还定义了一系列错误码常量:
- EX_BAD_CONFIG - 配置错误
- EX_BAD_DISPLAY - 显示设备错误
- EX_BAD_LAYER - 图层错误
- EX_NO_RESOURCES - 资源不足
- EX_UNSUPPORTED - 不支持的操作
IComposerClient 接口是 Android 图形系统的核心组件,它提供了完整的显示设备管理、图层合成、颜色管理、电源控制等功能。通过这个接口,Android系统能够高效地管理各种显示设备,支持多显示器、HDR、高刷新率等现代显示技术,同时保证良好的性能和用户体验。
1.3 IComposerCallback.aidl 接口分析
ComposerCallback.aidl
定义了 HWC HAL 层向 SurfaceFlinger 回调的接口。该接口包含 8 个回调方法,用于通知显示设备状态变化、垂直同步事件和其他重要的图形系统事件。
// /hardware/interfaces/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/IComposerCallback.aidl
package android.hardware.graphics.composer3;
@VintfStability
interface IComposerCallback {
/**
* 已弃用,建议使用 onHotplugEvent 替代
*/
void onHotplug(long display, boolean connected);
/**
参数说明:
- display : 显示设备 ID
- connected : 布尔值,表示设备是连接 (true) 还是断开 (false)
触发场景: 当外部显示设备(如 HDMI 显示器、USB-C 显示器)物理连接或断开时触发
作用:HAL 层检测到硬件连接状态变化时主动调用此回调,通知 SurfaceFlinger 显示设备的热插拔状态变化
*/
oneway void onRefresh(long display);
/**
参数说明:
- display : 显示设备 ID
触发场景: 当显示设备支持无缝模式切换(如刷新率变化、分辨率变化)时触发
作用: 当 HWC 检测到某个显示设备(由 display参数标识)能够支持无缝切换到一种新的显示模式(例如分辨率、刷新率的改变)时,通过此回调函数主动通知上层的 SurfaceFlinger,无需黑屏或闪烁
*/
oneway void onSeamlessPossible(long display);
/**
参数说明:
- display : 产生垂直同步信号的显示设备 ID
- timestamp : 垂直同步信号的时间戳(纳秒)
- vsyncPeriodNanos : 垂直同步周期(纳秒)
触发场景: 每当显示设备产生垂直同步信号时触发,通常以固定频率(如 60Hz、90Hz、120Hz)
作用: 为 SurfaceFlinger 提供精确的显示时序信息,用于同步渲染和合成操作,确保流畅的动画和视频播放
*/
oneway void onVsync(long display, long timestamp, int vsyncPeriodNanos);
/**
参数说明:
- display : 显示设备 ID
- updatedTimeline : `VsyncPeriodChangeTimeline.aidl` 结构,包含:
- newVsyncAppliedTimeNanos : 新垂直同步周期生效的时间
- refreshRequired : 是否需要刷新
- refreshTimeNanos : 刷新时间
触发场景: 当显示设备的垂直同步周期发生变化时触发,如动态刷新率切换
*/
oneway void onVsyncPeriodTimingChanged(long display, in android.hardware.graphics.composer3.VsyncPeriodChangeTimeline updatedTimeline);
/**
参数说明:
- display : 进入空闲状态的显示设备 ID
触发场景: 当显示设备进入空闲状态,不再需要频繁的垂直同步信号时触发,HAL 层检测到显示内容静止或系统进入省电模式时调用
*/
oneway void onVsyncIdle(long display);
/**
参数说明:
- data : `RefreshRateChangedDebugData.aidl` 结构,包含:
- display : 显示设备 ID
- vsyncPeriodNanos : 垂直同步周期(纳秒)
- refreshPeriodNanos : 刷新周期(纳秒)
触发场景: 当刷新率发生变化时触发,主要用于调试和性能分析
*/
oneway void onRefreshRateChangedDebug(in android.hardware.graphics.composer3.RefreshRateChangedDebugData data);
/*
参数说明:
- display : 显示设备 ID
- event : `DisplayHotplugEvent.aidl` 枚举,包含:
- CONNECTED : 设备连接
- DISCONNECTED : 设备断开
- ERROR_UNKNOWN : 未知错误
- ERROR_INCOMPATIBLE_CABLE : 不兼容的线缆
- ERROR_TOO_MANY_DISPLAYS : 显示设备过多
- ERROR_LINK_UNSTABLE : 连接不稳定
触发场景:当显示设备热插拔事件发生时触发,替代已弃用的 onHotplug 方法
*/
void onHotplugEvent(long display, android.hardware.graphics.common.DisplayHotplugEvent event);
/*
参数说明:
- display : 显示设备 ID
- levels : HDCP(高带宽数字内容保护)级别信息
触发场景: 当显示设备的 HDCP 保护级别发生变化时触发,用于数字版权管理和内容保护
*/
oneway void onHdcpLevelsChanged(long display, in android.hardware.drm.HdcpLevels levels);
}
2. HWC3 AIDL 接口的封装
ComposerClientWriter:
// /hardware/interfaces/graphics/composer/aidl/include/android/hardware/graphics/composer3/ComposerClientWriter.h
#pragma once
#include <algorithm>
#include <limits>
#include <memory>
#include <vector>
#include <inttypes.h>
#include <string.h>
#include <aidl/android/hardware/graphics/common/BlendMode.h>
#include <aidl/android/hardware/graphics/common/ColorTransform.h>
#include <aidl/android/hardware/graphics/common/FRect.h>
#include <aidl/android/hardware/graphics/common/Rect.h>
#include <aidl/android/hardware/graphics/common/Transform.h>
#include <aidl/android/hardware/graphics/composer3/Color.h>
#include <aidl/android/hardware/graphics/composer3/Composition.h>
#include <aidl/android/hardware/graphics/composer3/DisplayBrightness.h>
#include <aidl/android/hardware/graphics/composer3/DisplayCommand.h>
#include <aidl/android/hardware/graphics/composer3/LayerBrightness.h>
#include <aidl/android/hardware/graphics/composer3/LayerLifecycleBatchCommandType.h>
#include <aidl/android/hardware/graphics/composer3/Luts.h>
#include <aidl/android/hardware/graphics/composer3/PerFrameMetadata.h>
#include <aidl/android/hardware/graphics/composer3/PerFrameMetadataBlob.h>
#include <log/log.h>
#include <sync/sync.h>
#include <aidlcommonsupport/NativeHandle.h>
using aidl::android::hardware::graphics::common::BlendMode;
using aidl::android::hardware::graphics::common::ColorTransform;
using aidl::android::hardware::graphics::common::Dataspace;
using aidl::android::hardware::graphics::common::FRect;
using aidl::android::hardware::graphics::common::Rect;
using aidl::android::hardware::graphics::common::Transform;
using namespace aidl::android::hardware::graphics::composer3;
using aidl::android::hardware::common::NativeHandle;
namespace aidl::android::hardware::graphics::composer3 {
using PictureProfileId = decltype(LayerCommand().pictureProfileId);
class ComposerClientWriter final {
public:
static constexpr std::optional<ClockMonotonicTimestamp> kNoTimestamp = std::nullopt;
explicit ComposerClientWriter(int64_t display) : mDisplay(display) { reset(); }
~ComposerClientWriter() { reset(); }
ComposerClientWriter(ComposerClientWriter&&) = default;
ComposerClientWriter(const ComposerClientWriter&) = delete;
ComposerClientWriter& operator=(const ComposerClientWriter&) = delete;
void setColorTransform(int64_t display, const float* matrix) {
std::vector<float> matVec;
matVec.reserve(16);
matVec.assign(matrix, matrix + 16);
getDisplayCommand(display).colorTransformMatrix.emplace(std::move(matVec));
}
void setDisplayBrightness(int64_t display, float brightness, float brightnessNits) {
getDisplayCommand(display).brightness.emplace(
DisplayBrightness{.brightness = brightness, .brightnessNits = brightnessNits});
}
void setDisplayPictureProfileId(int64_t display, PictureProfileId pictureProfileId) {
getDisplayCommand(display).pictureProfileId = pictureProfileId;
}
void setClientTarget(int64_t display, uint32_t slot, const native_handle_t* target,
int acquireFence, Dataspace dataspace, const std::vector<Rect>& damage,
float hdrSdrRatio) {
ClientTarget clientTargetCommand;
clientTargetCommand.buffer = getBufferCommand(slot, target, acquireFence);
clientTargetCommand.dataspace = dataspace;
clientTargetCommand.damage.assign(damage.begin(), damage.end());
clientTargetCommand.hdrSdrRatio = hdrSdrRatio;
getDisplayCommand(display).clientTarget.emplace(std::move(clientTargetCommand));
}
void setOutputBuffer(int64_t display, uint32_t slot, const native_handle_t* buffer,
int releaseFence) {
getDisplayCommand(display).virtualDisplayOutputBuffer.emplace(
getBufferCommand(slot, buffer, releaseFence));
}
void setLayerLifecycleBatchCommandType(int64_t display, int64_t layer,
LayerLifecycleBatchCommandType cmd) {
getLayerCommand(display, layer).layerLifecycleBatchCommandType = cmd;
}
void setNewBufferSlotCount(int64_t display, int64_t layer, int32_t newBufferSlotToCount) {
getLayerCommand(display, layer).newBufferSlotCount = newBufferSlotToCount;
}
void validateDisplay(int64_t display,
std::optional<ClockMonotonicTimestamp> expectedPresentTime,
int32_t frameIntervalNs) {
auto& command = getDisplayCommand(display);
command.expectedPresentTime = expectedPresentTime;
command.validateDisplay = true;
command.frameIntervalNs = frameIntervalNs;
}
void presentOrvalidateDisplay(int64_t display,
std::optional<ClockMonotonicTimestamp> expectedPresentTime,
int32_t frameIntervalNs) {
auto& command = getDisplayCommand(display);
command.expectedPresentTime = expectedPresentTime;
command.presentOrValidateDisplay = true;
command.frameIntervalNs = frameIntervalNs;
}
void acceptDisplayChanges(int64_t display) {
getDisplayCommand(display).acceptDisplayChanges = true;
}
void presentDisplay(int64_t display) { getDisplayCommand(display).presentDisplay = true; }
void setLayerCursorPosition(int64_t display, int64_t layer, int32_t x, int32_t y) {
common::Point cursorPosition;
cursorPosition.x = x;
cursorPosition.y = y;
getLayerCommand(display, layer).cursorPosition.emplace(std::move(cursorPosition));
}
void setLayerBuffer(int64_t display, int64_t layer, uint32_t slot,
const native_handle_t* buffer, int acquireFence) {
getLayerCommand(display, layer).buffer = getBufferCommand(slot, buffer, acquireFence);
}
void setLayerBufferWithNewCommand(int64_t display, int64_t layer, uint32_t slot,
const native_handle_t* buffer, int acquireFence) {
flushLayerCommand();
getLayerCommand(display, layer).buffer = getBufferCommand(slot, buffer, acquireFence);
flushLayerCommand();
}
void setLayerBufferSlotsToClear(int64_t display, int64_t layer,
const std::vector<uint32_t>& slotsToClear) {
getLayerCommand(display, layer)
.bufferSlotsToClear.emplace(slotsToClear.begin(), slotsToClear.end());
}
void setLayerSurfaceDamage(int64_t display, int64_t layer, const std::vector<Rect>& damage) {
getLayerCommand(display, layer).damage.emplace(damage.begin(), damage.end());
}
void setLayerBlendMode(int64_t display, int64_t layer, BlendMode mode) {
ParcelableBlendMode parcelableBlendMode;
parcelableBlendMode.blendMode = mode;
getLayerCommand(display, layer).blendMode.emplace(std::move(parcelableBlendMode));
}
void setLayerColor(int64_t display, int64_t layer, Color color) {
getLayerCommand(display, layer).color.emplace(std::move(color));
}
void setLayerCompositionType(int64_t display, int64_t layer, Composition type) {
ParcelableComposition compositionPayload;
compositionPayload.composition = type;
getLayerCommand(display, layer).composition.emplace(std::move(compositionPayload));
}
void setLayerDataspace(int64_t display, int64_t layer, Dataspace dataspace) {
ParcelableDataspace dataspacePayload;
dataspacePayload.dataspace = dataspace;
getLayerCommand(display, layer).dataspace.emplace(std::move(dataspacePayload));
}
void setLayerDisplayFrame(int64_t display, int64_t layer, const Rect& frame) {
getLayerCommand(display, layer).displayFrame.emplace(frame);
}
void setLayerPlaneAlpha(int64_t display, int64_t layer, float alpha) {
PlaneAlpha planeAlpha;
planeAlpha.alpha = alpha;
getLayerCommand(display, layer).planeAlpha.emplace(std::move(planeAlpha));
}
void setLayerSidebandStream(int64_t display, int64_t layer, const native_handle_t* stream) {
NativeHandle handle;
if (stream) handle = ::android::dupToAidl(stream);
getLayerCommand(display, layer).sidebandStream.emplace(std::move(handle));
}
void setLayerSourceCrop(int64_t display, int64_t layer, const FRect& crop) {
getLayerCommand(display, layer).sourceCrop.emplace(crop);
}
void setLayerTransform(int64_t display, int64_t layer, Transform transform) {
ParcelableTransform transformPayload;
transformPayload.transform = transform;
getLayerCommand(display, layer).transform.emplace(std::move(transformPayload));
}
void setLayerVisibleRegion(int64_t display, int64_t layer, const std::vector<Rect>& visible) {
getLayerCommand(display, layer).visibleRegion.emplace(visible.begin(), visible.end());
}
void setLayerZOrder(int64_t display, int64_t layer, uint32_t z) {
ZOrder zorder;
zorder.z = static_cast<int32_t>(z);
getLayerCommand(display, layer).z.emplace(std::move(zorder));
}
void setLayerPerFrameMetadata(int64_t display, int64_t layer,
const std::vector<PerFrameMetadata>& metadataVec) {
getLayerCommand(display, layer)
.perFrameMetadata.emplace(metadataVec.begin(), metadataVec.end());
}
void setLayerColorTransform(int64_t display, int64_t layer, const float* matrix) {
getLayerCommand(display, layer).colorTransform.emplace(matrix, matrix + 16);
}
void setLayerPerFrameMetadataBlobs(int64_t display, int64_t layer,
const std::vector<PerFrameMetadataBlob>& metadata) {
getLayerCommand(display, layer)
.perFrameMetadataBlob.emplace(metadata.begin(), metadata.end());
}
void setLayerBrightness(int64_t display, int64_t layer, float brightness) {
getLayerCommand(display, layer)
.brightness.emplace(LayerBrightness{.brightness = brightness});
}
void setLayerBlockingRegion(int64_t display, int64_t layer, const std::vector<Rect>& blocking) {
getLayerCommand(display, layer).blockingRegion.emplace(blocking.begin(), blocking.end());
}
void setLayerLuts(int64_t display, int64_t layer, Luts& luts) {
getLayerCommand(display, layer).luts.emplace(std::move(luts));
}
void setLayerPictureProfileId(int64_t display, int64_t layer,
PictureProfileId pictureProfileId) {
getLayerCommand(display, layer).pictureProfileId = pictureProfileId;
}
std::vector<DisplayCommand> takePendingCommands() {
flushLayerCommand();
flushDisplayCommand();
std::vector<DisplayCommand> moved = std::move(mCommands);
mCommands.clear();
return moved;
}
private:
std::optional<DisplayCommand> mDisplayCommand;
std::optional<LayerCommand> mLayerCommand;
std::vector<DisplayCommand> mCommands;
const int64_t mDisplay;
Buffer getBufferCommand(uint32_t slot, const native_handle_t* bufferHandle, int fence) {
Buffer bufferCommand;
bufferCommand.slot = static_cast<int32_t>(slot);
if (bufferHandle) bufferCommand.handle.emplace(::android::dupToAidl(bufferHandle));
if (fence > 0) bufferCommand.fence = ::ndk::ScopedFileDescriptor(fence);
return bufferCommand;
}
void flushLayerCommand() {
if (mLayerCommand.has_value()) {
mDisplayCommand->layers.emplace_back(std::move(*mLayerCommand));
mLayerCommand.reset();
}
}
void flushDisplayCommand() {
if (mDisplayCommand.has_value()) {
mCommands.emplace_back(std::move(*mDisplayCommand));
mDisplayCommand.reset();
}
}
DisplayCommand& getDisplayCommand(int64_t display) {
if (!mDisplayCommand.has_value() || mDisplayCommand->display != display) {
LOG_ALWAYS_FATAL_IF(display != mDisplay);
flushLayerCommand();
flushDisplayCommand();
mDisplayCommand.emplace();
mDisplayCommand->display = display;
}
return *mDisplayCommand;
}
LayerCommand& getLayerCommand(int64_t display, int64_t layer) {
getDisplayCommand(display);
if (!mLayerCommand.has_value() || mLayerCommand->layer != layer) {
flushLayerCommand();
mLayerCommand.emplace();
mLayerCommand->layer = layer;
}
return *mLayerCommand;
}
void reset() {
mDisplayCommand.reset();
mLayerCommand.reset();
mCommands.clear();
}
};
} // namespace aidl::android::hardware::graphics::composer3
// /hardware/interfaces/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/DisplayCommand.aidl
package android.hardware.graphics.composer3;
@VintfStability
parcelable DisplayCommand {
long display;
android.hardware.graphics.composer3.LayerCommand[] layers;
@nullable float[] colorTransformMatrix;
@nullable android.hardware.graphics.composer3.DisplayBrightness brightness;
@nullable android.hardware.graphics.composer3.ClientTarget clientTarget;
@nullable android.hardware.graphics.composer3.Buffer virtualDisplayOutputBuffer;
@nullable android.hardware.graphics.composer3.ClockMonotonicTimestamp expectedPresentTime;
boolean validateDisplay;
boolean acceptDisplayChanges;
boolean presentDisplay;
boolean presentOrValidateDisplay;
}
// /hardware/interfaces/graphics/composer/aidl/android/hardware/graphics/composer3/LayerCommand.aidl
@VintfStability
parcelable LayerCommand {
/**
* The layer which this commands refers to.
* @see IComposer.createLayer
*/
long layer;
/**
* Sets the position of a cursor layer.
*
* The position of a cursor layer can be updated without a validate/present display
* sequence if that layer was marked as Composition.CURSOR and validation previously succeeded
* (i.e., the device didn't request a composition).
*/
@nullable Point cursorPosition;
/**
* Sets the buffer handle to be displayed for this layer. If the buffer
* properties set at allocation time (width, height, format, and usage)
* have not changed since the previous frame, it is not necessary to call
* validateDisplay before calling presentDisplay unless new state needs to
* be validated in the interim.
*
* Also provides a file descriptor referring to an acquire sync fence
* object, which must be signaled when it is safe to read from the given
* buffer. If it is already safe to read from the buffer, an empty handle
* may be passed instead.
*
* This function must return NONE and have no other effect if called for a
* layer with a composition type of Composition.SOLID_COLOR (because it
* has no buffer) or Composition.SIDEBAND or Composition.CLIENT (because
* synchronization and buffer updates for these layers are handled
* elsewhere).
*/
@nullable Buffer buffer;
/**
* Provides the region of the source buffer which has been modified since
* the last frame. This region does not need to be validated before
* calling presentDisplay.
*
* Once set through this function, the damage region remains the same
* until a subsequent call to this function.
*
* If damage is non-empty, then it may be assumed that any portion of the
* source buffer not covered by one of the rects has not been modified
* this frame. If damage is empty, then the whole source buffer must be
* treated as if it has been modified.
*
* If the layer's contents are not modified relative to the prior frame,
* damage must contain exactly one empty rect([0, 0, 0, 0]).
*
* The damage rects are relative to the pre-transformed buffer, and their
* origin is the top-left corner. They must not exceed the dimensions of
* the latched buffer.
*/
@nullable Rect[] damage;
/**
* Sets the blend mode of the given layer.
*/
@nullable ParcelableBlendMode blendMode;
/**
* Sets the color of the given layer. If the composition type of the layer
* is not Composition.SOLID_COLOR, this call must succeed and have no
* other effect.
*/
@nullable Color color;
/**
* Sets the desired composition type of the given layer. During
* validateDisplay, the device may request changes to the composition
* types of any of the layers as described in the definition of
* Composition above.
*/
@nullable ParcelableComposition composition;
/**
* Sets the dataspace of the layer.
*
* The dataspace provides more information about how to interpret the buffer
* or solid color, such as the encoding standard and color transform.
*
* See the values of ParcelableDataspace for more information.
*/
@nullable ParcelableDataspace dataspace;
/**
* Sets the display frame (the portion of the display covered by a layer)
* of the given layer. This frame must not exceed the display dimensions.
*/
@nullable Rect displayFrame;
/**
* Sets an alpha value (a floating point value in the range [0.0, 1.0])
* which will be applied to the whole layer. It can be conceptualized as a
* preprocessing step which applies the following function:
* if (blendMode == BlendMode.PREMULTIPLIED)
* out.rgb = in.rgb * planeAlpha
* out.a = in.a * planeAlpha
*
* If the device does not support this operation on a layer which is
* marked Composition.DEVICE, it must request a composition type change
* to Composition.CLIENT upon the next validateDisplay call.
*
*/
@nullable PlaneAlpha planeAlpha;
/**
* Sets the sideband stream for this layer. If the composition type of the
* given layer is not Composition.SIDEBAND, this call must succeed and
* have no other effect.
*/
@nullable NativeHandle sidebandStream;
/**
* Sets the source crop (the portion of the source buffer which will fill
* the display frame) of the given layer. This crop rectangle must not
* exceed the dimensions of the latched buffer.
*
* If the device is not capable of supporting a true float source crop
* (i.e., it will truncate or round the floats to integers), it must set
* this layer to Composition.CLIENT when crop is non-integral for the
* most accurate rendering.
*
* If the device cannot support float source crops, but still wants to
* handle the layer, it must use the following code (or similar) to
* convert to an integer crop:
* intCrop.left = (int) ceilf(crop.left);
* intCrop.top = (int) ceilf(crop.top);
* intCrop.right = (int) floorf(crop.right);
* intCrop.bottom = (int) floorf(crop.bottom);
*/
@nullable FRect sourceCrop;
/**
* Sets the transform (rotation/flip) of the given layer.
*/
@nullable ParcelableTransform transform;
/**
* Specifies the portion of the layer that is visible, including portions
* under translucent areas of other layers. The region is in screen space,
* and must not exceed the dimensions of the screen.
*/
@nullable Rect[] visibleRegion;
/**
* Sets the desired Z order (height) of the given layer. A layer with a
* greater Z value occludes a layer with a lesser Z value.
*/
@nullable ZOrder z;
/**
* Sets a matrix for color transform which will be applied on this layer
* before composition.
*
* If the device is not capable of apply the matrix on this layer, it must force
* this layer to client composition during VALIDATE_DISPLAY.
*
* The matrix provided is an affine color transformation of the following
* form:
*
* |r.r r.g r.b 0|
* |g.r g.g g.b 0|
* |b.r b.g b.b 0|
* |Tr Tg Tb 1|
*
* This matrix must be provided in row-major form:
*
* {r.r, r.g, r.b, 0, g.r, ...}.
*
* Given a matrix of this form and an input color [R_in, G_in, B_in],
* the input color must first be converted to linear space
* [R_linear, G_linear, B_linear], then the output linear color
* [R_out_linear, G_out_linear, B_out_linear] will be:
*
* R_out_linear = R_linear * r.r + G_linear * g.r + B_linear * b.r + Tr
* G_out_linear = R_linear * r.g + G_linear * g.g + B_linear * b.g + Tg
* B_out_linear = R_linear * r.b + G_linear * g.b + B_linear * b.b + Tb
*
* [R_out_linear, G_out_linear, B_out_linear] must then be converted to
* gamma space: [R_out, G_out, B_out] before blending.
*/
@nullable float[] colorTransform;
/**
* Sets the desired brightness for the layer. This is intended to be used for instance when
* presenting an SDR layer alongside HDR content. The HDR content will be presented at the
* display brightness in nits, and accordingly SDR content shall be dimmed according to the
* provided brightness ratio.
*/
@nullable LayerBrightness brightness;
/**
* Sets the PerFrameMetadata for the display. This metadata must be used
* by the implementation to better tone map content to that display.
*
* This is a command that may be called every frame.
*/
@nullable PerFrameMetadata[] perFrameMetadata;
/**
* This command sends metadata that may be used for tone-mapping the
* associated layer. The metadata structure follows a {key, blob}
* format (see the PerFrameMetadataBlob struct). All keys must be
* returned by a prior call to getPerFrameMetadataKeys and must
* be part of the list of keys associated with blob-type metadata
* (see PerFrameMetadataKey).
*
* This command may be called every frame.
*/
@nullable PerFrameMetadataBlob[] perFrameMetadataBlob;
/**
* Specifies a region of the layer that is transparent and may be skipped
* by the DPU, e.g. using a blocking region, in order to save power. This
* is only a hint, so the composition of the layer must look the same
* whether or not this region is skipped.
*
* The region is in screen space and must not exceed the dimensions of
* the screen.
*/
@nullable Rect[] blockingRegion;
/**
* Specifies which buffer slots should be cleared of buffer references
* because these buffers will no longer be used and the memory should
* be freed.
*/
@nullable int[] bufferSlotsToClear;
/**
* Specifies if this layer command is on type modify, create or destroy.
* This command is replacing the older IComposerClient.createLayer and destroyLayer
* and making it more efficient with reduced aidls to the HAL.
* The HAL will report the errors by setting CommandResultPayload::CommandError.
*/
LayerLifecycleBatchCommandType layerLifecycleBatchCommandType;
/**
* Specifies the number of buffer slot to be reserved.
*/
int newBufferSlotCount;
/**
* Sets the lut(s) for the layer.
*/
@nullable Luts luts;
/**
* If the display has multiple per-layer picture processing pipelines, then this value is used
* to look up a picture profile which defines the parameters used when configuring a
* picture-processing pipeline for this layer, enhancing the quality of the buffer contents. If
* the server doesn't recognize this profile, it must continue with composition and ignore
* this value. If the value is zero, then the no picture processing must be applied.
*
* Note that the client will never send a DisplayCommand.pictureProfileId if
* IComposerClient.getMaxLayerPictureProfiles is non-zero. Picture profiles will only be
* specified on a per-layer basis.
*
* @see IComposerClient.getMaxLayerPictureProfiles
* @see DisplayCommand.pictureProfileId
*/
long pictureProfileId;
}
// /hardware/interfaces/graphics/composer/aidl/android/hardware/graphics/composer3/ClientTarget.aidl
@VintfStability
parcelable ClientTarget {
/**
* Client target Buffer
*/
Buffer buffer;
/**
* The dataspace of the buffer, as described in LayerCommand.dataspace.
*/
Dataspace dataspace;
/**
* The surface damage regions.
*/
Rect[] damage;
/**
* The HDR/SDR ratio.
* Only meaningful for extended_range client targets to communicate the amount of HDR heaedroom
* inside the client target. For floating point client targets, this means that for each color
* channel the maximum SDR luminance is 1.0, and the maximum display relative luminance is
* the hdrSdrRatio.
* Note that this ratio is meant to be >= 1.0.
*/
float hdrSdrRatio = 1.0f;
}