Android显示系统——Transaction基础功能

Transaction基础功能

Transaction是应用与SurfaceFlinger交流的方式之一,应用通过打开一个Transaction,然后设置各种setXXX操作,最后通过apply把所有的设定操作提交给SurfaceFlinger进行处理。

Transaction最常用的使用方法(套路)一般如下:

Transaction t;
t.setLayer(mSurfaceControl, 0x7fffffff)
    .show(mSurfaceControl)
    .apply();

Java层的Transaction定义位于base\core\java\android\view\SurfaceControl.java文件中。先来看Transaction提供了不同类型的构造函数,做开发者在不同的场景使用。

public Transaction() { // 由系统自动生成一个全新的Transaction
    this(nativeCreateTransaction());
}

private Transaction(long nativeObject) { // 根据nativeObject生成一个Transaction,这里nativeObject指一个已经存在的Trnansaction对象
    mNativeObject = nativeObject;
    mFreeNativeResources = sRegistry.registerNativeAllocation(this, mNativeObject); // 这里主要用于内存Transaction管理,不需要重点关注
}

private Transaction(Parcel in) { // 根据一个已经存在的Parcel对象创建一个Transaction对象
    readFromParcel(in);
}

对应Native侧C++的实现分别为:

// 第一种方式,创建一个全新的Transaction
SurfaceComposerClient::Transaction::Transaction() {
    mId = generateId(); // 自动生成一个Transaction id
}

std::atomic<uint32_t> idCounter = 0; // 查看aosp代码可知,idCounter代表系统已经创建过的Transaction数量
int64_t generateId() {
    return (((int64_t)getpid()) << 32) | ++idCounter;
}

// 第二种方式,根据已经一个已有的Transaction对象生成一个新的Trnasaction对象
SurfaceComposerClient::Transaction::Transaction(const Transaction& other)
      : mId(other.mId),
        mForceSynchronous(other.mForceSynchronous),
        mTransactionNestCount(other.mTransactionNestCount),
        mAnimation(other.mAnimation),
        mEarlyWakeupStart(other.mEarlyWakeupStart),
        mEarlyWakeupEnd(other.mEarlyWakeupEnd),
        mContainsBuffer(other.mContainsBuffer),
        mDesiredPresentTime(other.mDesiredPresentTime),
        mIsAutoTimestamp(other.mIsAutoTimestamp),
        mFrameTimelineInfo(other.mFrameTimelineInfo),
        mApplyToken(other.mApplyToken) {
    mDisplayStates = other.mDisplayStates;
    mComposerStates = other.mComposerStates;
    mInputWindowCommands = other.mInputWindowCommands;
    mListenerCallbacks = other.mListenerCallbacks;
}

// 第三种方式,根据parcel传递过来的信息创建一个新的Transaction对象
std::unique_ptr<SurfaceComposerClient::Transaction>
SurfaceComposerClient::Transaction::createFromParcel(const Parcel* parcel) {
    auto transaction = std::make_unique<Transaction>();
    if (transaction->readFromParcel(parcel) == NO_ERROR) {
        return transaction;
    }
    return nullptr;
}

status_t SurfaceComposerClient::Transaction::readFromParcel(const Parcel* parcel) {
    const uint32_t forceSynchronous = parcel->readUint32();
    // ......
    sp<IBinder> applyToken;
    parcel->readNullableStrongBinder(&applyToken);
    // ......
    mApplyToken = applyToken;
    return NO_ERROR;
}

下面重点来看Transaction都可以做哪些事情,即setXXX方法都有哪些。

1. Display相关的

操作 入参 说明
setDisplayDecoration 指定surface是否需要使用display decoration optimizations,主要是让SystemUI圆角走硬件RC通道
setDisplayFlags 指定display的一些flags标记,这些flag都是display相关的,不是surface相关的
setDisplayLayerStack 指定display上显示哪个layerStack
setDisplayProjection * orientation:指定屏幕的方向
* layerStackRect:窗口坐标系中的一块区域
* display:指定屏幕上的一块区域,这个区域是旋转orientation后的
指定将layersStackRect区域以orientation方向投影到屏幕的displayRect区域
setDisplaySize 指定屏幕的宽和高
setDisplaySurface 指定屏幕上显示哪个Surface

备注:

  • LayerStack是一个标识,用于唯一标识一组按z轴大小排序的layer的集合,一个layer只能被绑定到一个LayerStack中,但一个LayerStack可以关联到多个Display中,即多个Display显示同一个LayersStack的layers,也就是这些display显示的内容是完全一样的,镜像的。

2. Surface相关的

2.1 setBuffer

setBuffer有4个重载函数

  1. setBuffer(SurfaceControl sc, GraphicBuffer buffer)
  2. setBuffer(@NonNull SurfaceControl sc, @Nullable HardwareBuffer buffer)
  3. setBuffer(@NonNull SurfaceControl sc, @Nullable HardwareBuffer buffer, @Nullable SyncFence fence)
  4. setBuffer(@NonNull SurfaceControl sc, @Nullable HardwareBuffer buffer, @Nullable SyncFence fence, @Nullable Consumer releaseCallback)

4个函数的作用均为更新surface要显示的buffer,但存在如下差异:

  • 第(1)个只能用于类型为FX_SURFACE_BLAST的SurfaceControl。
  • 第(2)个函数中,该buffer只能以HardwareBuffer#USAGE_COMPOSER_OVERLAY类型进行申请,而以HardwareBuffer#USAGE_GPU_SAMPLED_IMAGE申请的buffer会可能会走GPU合成。
  • 第(3)个函数与第(2)函数要求相同,但多了一个fence参数,如果fence参数为空或无效,则与第(2)个函数功能完全相同。该函数在设置要显示的buffer的同时,传入了一个presentation fence参数,主要目的是为了提升性能体验。指定了有效的fence参数后,只有等GPU完成了该Buffer的绘制后,这个transaction才能被SurfaceFlinger处理,否则SurfaceFlinger会一起等待,一起等到GPU绘制完成或者等待超时。例如,假设应用该buffer连同fence(该fence由android.opengl.EGLExt#eglDupNativeFenceFDANDROID(EGLDisplay, EGLSync)创建)一同传递给GPU进行处理,即允许transaction的下发和Buffer内容的绘制可以同时并行进行,合成器则需要等待该fence被signaled后才会将该Buffer进行合成送给Display进行显示。如果在同一个transaction中指定了多个Buffer,则在合成器合成送显之前,这些buffer的fence必须都被signaled后,合成器才能进行这一次的送显操作,主要目的是为了保证同步处理,即保证这些buffer是在一帧中被处理并送显的。
  • 第(4)个函数在第(3)个函数的基础上,又加了一个releaseCallback参数。releaseCallback的主要目的是让producer知道什么可以可以放心重复使用该Buffer,这种用法主要是用于连续使用transaction进行setBuffer的操作场景场景。应用端想重复使用这个buffer,则必须等待该releaseCallback函数被SurfaceFlinger回调后(,此时表明该buffer已经在服务端处理完成并释放掉了)。换句话讲,即应用端可以通过releaseCallback回调函数知道该buffer何时被SurfaceFlinger处理完成了,以此为基础来做一些其他事情。

2.2 setFrameRate

  1. setFrameRate(@NonNull SurfaceControl sc, @FloatRange(from = 0.0) float frameRate, @Surface.FrameRateCompatibility int compatibility)
  2. setFrameRate(@NonNull SurfaceControl sc, @FloatRange(from = 0.0) float frameRate, @Surface.FrameRateCompatibility int compatibility, @Surface.ChangeFrameRateStrategy int changeFrameRateStrategy)
  3. setFrameRateSelectionPriority(@NonNull SurfaceControl sc, int priority)

现今的手机产品,一般都会支持多个不同的刷新率,如60Hz,90Hz,120Hz及144Hz等。一般情况下,系统会根据不同的场景来选择合适的刷新率。改变刷新率,意思着改变了帧间隔时长,这样一般会影响Choreographer的回调节奏,但对于media codec这种则没有任何影响。

这三个函数是应用设置刷新率相关的,简单说明如下:

  • 第(1)个setFrameRate设定该surface预期的刷新速率(或帧率),compatibility表示surface指定的帧率如何与系统当前的帧率兼容,一般有两种方式:FRAME_RATE_COMPATIBILITY_DEFAULT表示不需要继承当前surface的限制,当系统选择了app请求之外的刷新率时,app会以系统选择的刷新率继续运行,该模式一般用于游戏和普通UI场等非Video场景;RAME_RATE_COMPATIBILITY_FIXED_SOURCE模式表示surface的内容应该控制固定frame rate进行显示,如video一般是固定刷新率,当系统选择了app指定之外的刷新率时,app需要pull down或采取一些其他措施来适应系统的刷新节奏,可能会出现长短帧的情况,用户体验不好,该模式主要适用于video场景。还有一种只有系统有权限使用的模式FRAME_RATE_COMPATIBILITY_EXACT,表示当前surface属于高刷新黑名单,需要系统确定采用某个刷新率进行刷新。
  • 第(2)个在第(1)基础上又添加了一个ChangeFrameRateStrategy参数,该参数表示该surface请求的帧率变更是否是无疑平滑切换的(无视觉中断的),用户不可感知的,若frameRate参数为0,则此参数无效。frameRate参数为0时,表示app会接受系统的帧率决策,如果应用未调用此接口,则默认策略即是如此。

2.3 其他函数

操作 入参 说明
setAlpha 指定surface的alhpa值,如果alpha值大于0,系统会根据alpha值将该surface会与其(z轴)下面的surface进行混合处理
setAnimationTransaction 指定此transaction为一个动画transaction,暂未研究SurfaceFlinger如何处理animaton transaction
setBackgroundBlurRadius 设定模糊背景的半径范围
setBlurRegions 指定surface的哪个区域应该做模糊处理
setBufferSize 指定默认buffer大小,如果SurfaceControl关联了一个surface,即buffer的默认大小即为dequeue出来的大小(surface的大小)
setBufferTransform 设置buffer的转换矩阵,与AttachedSurfaceControl#addOnBufferTransformHintChangedListener配合使用,可实现根据display orientation方向对buffer进行预旋转,避免在合成阶段再进行旋转,可减少GPU合成的概率,提升性能体验
setColor float[] color,三个元素的float数组,分别表现R、G、B 使用指定颜色填充Surface,若颜色值无效,则取消颜色填充
setColorSpace 设定SurfaceControl的颜色空间,当前支持的颜色空间为SRGB和Display P3,其他的颜色空间会被当作SRGB处理,此参数只能使用于FX_SURFACE_BLAST类型SurfaceControl
setColorSpaceAgnostic 设定surface的颜色空间不确定,若一个surface的颜色空间不确定,则其颜色在任何颜色空间都可以被解析
setColorTransform matrix为一个3x3的矩阵
translation为3个元素的vector
设定surface的颜色转换矩阵,在SurfaceComposerClient处会将这两个参数组合为一个4x4的矩阵colorTransform
setCornerRadius 设置SurfaceControl的圆角半径,半径的单位为pixcel
setCrop 限制surface及其子图层在指定的Rect区域内。Surface的大小会被忽略掉,只有crop和buffer size会参与surface边界的计算;如果surface即未指定crp也没有buffer,则以其父图层的bounds为边界
setDamageRegion 更新surface的脏区(即内容发生变化的区域),当一帧画面中只有一部分发生变化时,可以通过该函数指定脏区,这样在合成阶段只合成这一区域的内容,减少合成时的负载,典型场景如闪烁的光标或loading indicator。如果没有脏区为null,则相当于没有指定脏区,则会合成整个画面
setDataSpace 设定SurfaceControl的dataspace,这会决定(使用setBuffer(SurfaceControl, HardwareBuffer)设置的)buffer如何被显示出来
setDestationFrame SurfaceControl sc, @NonNull Rect destinationFram
setDestationFrame SurfaceControl sc, int width, int height
setDimmingEnabled 设定layer的亮度是否可以调节,默认值为true,表示layer的亮度可调。禁用此项,则强制layer的亮度不可调,如layer的白色像素与屏幕亮度一致。
setDropInputMode 指定SurfaceControl的input事件的drop mode,有三种模式:NONE,ALL,OBSCURED
setEarlyWakeStart 通知SurfaceFlinger接下下来的合成任务比较繁重,需要改变其offset,提前开始合成工作,尽可能的多留一些时间给合成过程
setEarlyWakeEnd 与setEarlyWakeStart作用相反,参考
setEarlyWakeStart 通知SurfaceFlinger接下下来的合成任务比较繁重,需要改变其offset,提前开始合成工作,尽可能的多留一些时间给合成过程
setFixedTransformHint 当layer及其子layer的方向与屏幕方向不一致时,由graphic producer指定一个固定的旋转hint。在不需要旋转固定方向时,调用者需要负责清理掉这个hint。当layer旋转时,这个transform hint用于防止分配一个不同大小的buffer。消费者可以选择指定这个hint以分配相同大小的buffer
setFocusedWindow 指定窗口为当前的焦点窗口,当窗口状态为不可focusable时,系统会将这个请求缓存起来直到窗口变得可focusable或者被其他请求覆盖掉
setFrameTimelineVsync 设定从choreographer处接收到的的frame timeline的vsync id
setGeometry 指定与surface关联的buffer如何被映射到父图层的坐标系中,在根据orientation指定的方向进行旋转后,系统会对source frame进行缩放操作以适配destination frame
setInputWindowInfo 设定输入窗口相关的info
setLayer 指定surfaceControl相对于其同级图层的z-order,若两个同级图层的z order相同且未定义,则z order为负数的surface会显示在其父surface下面
setLayerStack 指定surfacecontrol上的LayerStack
setMarix 设置SurfaceControl的Matrix,一般为dsdx,dtdx,dtdy,dsdy
setMetadata 设定surface的Metadata
setOpaque 指定surface是否为不透明的,即使pixel format被设置为translucent。该参数用于决定是否从 alpha通道采样不透明数据。调用setAlpha()函数设置的Plane-alpha仍然会影响合成时的混合效果,而不会考虑opaque设置。如果底层buffer无alpha channel,则相当于自动调用了setOpaque(true)。
setPosition 指定SurfaceControl相对于其父节点的位置
setRelativelayer 指定SurfaceControl相对参考目标
setScale 指定SurfaceControl基于(0,0)点进行大小缩放的倍数
setSecure 指定该surface是否为安全图层,安全图层截图和屏幕均不可见
setShadowRadius 指定surface周边绘制阴影的长度(阴影半径),若为0,则不绘制阴影。如果surface的圆角半径小于在screen bounds内,以阴影大小以圆角半径为准。阴影效果只能合适用有buffer的图层和color图层。如果在一个container图层上设置了radius参数,则会向下传递下一级的buffer或color图层,而不是传递给其子图层。
setSkipScreenshot 指定是否在screentshot的时候跳过此图层及其子图层
setStretchEffect 指定surface的回弹效果
setTransparentRegionHint 更新surface的透明区域
setTrustedOverlay 指定对于input而言,当前layer是否为trusted overlay
setVisibility 指定当前layer及其子图层是否可见
setWindowCrop 指定surface的及其子图层的bounds,此函数已被google标记为Deprecated,请使用setCrop替代
unsetColor 取消surface的填充色
unsetFixedTransformHint 与setFixedTransformHint作用相反
show 显示当前surface及其子图层
hide 隐藏当前surface及其子图层

备注:

  • 针对OPAQUE和alpha对合成的影响:
    • OPAQUE + alpha(1.0) == opaque composition
    • OPAQUE + alpha(0.x) == blended composition
    • OPAQUE + alpha(0.0) == no composition
    • !OPAQUE + alpha(1.0) == blended composition
    • !OPAQUE + alpha(0.x) == blended composition
    • OPAQUE + alpha(0.0) == no composition
posted @ 2023-07-08 23:49  TPrime.A  阅读(1259)  评论(0编辑  收藏  举报