1 minute read

参考Android P AOSP源码,对HWC合成分析了解

1. 显示屏Display

显示屏Display是合成的另一个重要单元,系统可以有多个显示设备,并且在正常系统操作期间可以添加/删除显示设备。该添加/删除操作可以对应HWC设备的热插拔请求,或者应客户端的请求进行,这允许创建虚拟显示设备,其内容会渲染到离屏缓冲区(而不是物理显示设备)。

可以通过Dump SF查看display的layer信息,同时也可以根据layerstack异同判断多个display是否用的同一个layer。

HWC中,SurfaceFlinger中创建的Layer,在合成开始时,将被指定到每个Display上,此后合成过程中,每个Display合成指定给自己的Layer。

SurfaceFlinger前端,每个显示屏用DisplayDevice类描述,在后端显示数据用DisplayData描述。而在HWC2的Client端,定义了Display类进行描述。对于HWC2服务端则用hwc2_display_t描述,他只是一个序号,Vendor具体实现时,才具体的去管理Display的信息。

HWC2提供相应函数来确定给定显示屏的属性,在不同配置(例如4K/1080分辨率)和颜色模式(例如Native颜色或者真彩sRGB)之间切换,以及打开/关闭显示设备或者将其切换到低功率模式(如果支持)。

2. HWC设备composerDevice

Note: 注意显示屏Display和合成设备的区别,HWC合成设备只有一个,定义在头文件:

//hardware/libhardware/include/hardware/hwcomposer2.h
typedef struct hwc2_device {
    struct hw_device_t common;

    void (*getCapabilities)(struct hwc2_device* device, uint32_t* outCount,
            int32_t* /*hwc2_capability_t*/ outCapabilities);

    hwc2_function_pointer_t (*getFunction)(struct hwc2_device* device,
            int32_t /*hwc2_function_descriptor_t*/ descriptor);
} hwc2_device_t;

2.1. HWC合成服务

hardware/interfaces/graphics/composer/2.1/default这个HWC的的默认服务。SurfaceFlinger初始化时,可以通过属性debug.sf.hwc_service_name来制定,默认为default。在编译时,manifest.xml中配置的也是default。

//frameworks/native/services/surfaceflinger/SurfaceFlinger.cpp
std::string getHwcServiceName() {
    char value[PROPERTY_VALUE_MAX] = {};
    property_get("debug.sf.hwc_service_name", value, "default");
    ALOGI("Using HWComposer service: '%s'", value);
    return std::string(value);
}

HWC服务分两部分:

  1. 可以执行程序android.hardware.graphics.composer@2.1-service(在目录/vendor/bin/hw/)

其main函数如下,通过defaultPassthroughServiceImplementation函数注册IComposer服务。

//hardware/interfaces/graphics/composer/2.1/default/service.cpp
int main() {
    // the conventional HAL might start binder services
    android::ProcessState::initWithDriver("/dev/vndbinder");
    android::ProcessState::self()->setThreadPoolMaxThreadCount(4);
    android::ProcessState::self()->startThreadPool();

    // same as SF main thread
    struct sched_param param = {0};
    param.sched_priority = 2;
    if (sched_setscheduler(0, SCHED_FIFO | SCHED_RESET_ON_FORK,
                &param) != 0) {
        ALOGE("Couldn't set SCHED_FIFO: %d", errno);
    }

    return defaultPassthroughServiceImplementation<IComposer>(4);
}

对应.rc文件:

service vendor.hwcomposer-2-1 /vendor/bin/hw/android.hardware.graphics.composer@2.1-service
    class hal animation
    user system
    group graphics drmrpc
    capabilities SYS_NICE
    onrestart restart surfaceflinger
  1. 实现库android.hardware.graphics.composer@2.1-impl.so

hwc的执行程序中,注册的IComposer,将调到对应的FETCH函数,FETCH函数实现及是so库中。FETCH如下:

IComposer* HIDL_FETCH_IComposer(const char*)
{
    const hw_module_t* module = nullptr;
    int err = hw_get_module(HWC_HARDWARE_MODULE_ID, &module);
    if (err) {
        ALOGI("falling back to FB HAL");
        err = hw_get_module(GRALLOC_HARDWARE_MODULE_ID, &module);
    }
    if (err) {
        ALOGE("failed to get hwcomposer or fb module");
        return nullptr;
    }

    return new HwcHal(module);
}

FETCH函数中,才正在去加载Vendor的实现,通过统一的接口hw_get_module根据IDHWC_HARDWARE_MODULE_ID去加载。加载完成后,创建HAL描述类似HwcHal。

HwcHal::HwcHal(const hw_module_t* module)
    : mDevice(nullptr), mDispatch(), mMustValidateDisplay(true), mAdapter() {
    uint32_t majorVersion;
    if (module->id && strcmp(module->id, GRALLOC_HARDWARE_MODULE_ID) == 0) {
        majorVersion = initWithFb(module);
    } else {
        majorVersion = initWithHwc(module);
    }

    initCapabilities();
    if (majorVersion >= 2 && hasCapability(HWC2_CAPABILITY_PRESENT_FENCE_IS_NOT_RELIABLE)) {
        ALOGE("Present fence must be reliable from HWC2 on.");
        abort();
    }

    initDispatch();
}

如果是FrameBuffer驱动,通过initWithFb初始化。如果是HWC驱动,通过initWithHwc初始化。我们需要的是HWC2的接口,如果不是HWC2的HAl实现,那么需要做适配。


3. Client和Server的通信

SurfaceFlinger和HWC服务之间,很多函数,并没有直接的调用,而是通过Buffer的读写来实现调用和参数的传递的。所以,Client端和Server端通信,基本通过以下相关的途径:

  • 通过IComposerClient.hal接口
  • 通过IComposer.hal接口
  • 通过command Buffer

Server端回调Client端,通过IComposerCallback.hal接口。

hal接口的方式,其本质就是Binder。又加了一个command Buffer的方式,其实这是为了解决Binder通信慢的问题。

3.1. HWC2中Fence的更改

HWC 2.0 中同步栅栏的含义相对于以前版本的HAL已有很大的改变。

在 HWC v1.x 中,释放Fence和退出Fence是推测性的。在帧 N 中检索到的Buffer的释放Fence或显示设备的退出Fence不会先于在帧 N + 1 中检索到的Fence变为触发状态。换句话说,该Fence的含义是“不再需要您为帧 N 提供的Buffer内容”。这是推测性的,因为在理论上,SurfaceFlinger 在帧 N 之后的一段不确定的时间内可能无法再次运行,这将使得这些栅栏在该时间段内不会变为触发状态。

在 HWC 2.0 中,释放Fence和退出Fence是非推测性的。在帧 N 中检索到的释放Fence或退出Fence,将在相关Buffer的内容替换帧 N - 1 中缓冲区的内容后立即变为触发状态,或者换句话说,该Fence的含义是“您为帧 N 提供的缓冲区内容现在已经替代以前的内容”。这是非推测性的,因为在硬件呈现此帧的内容之后,该栅栏应该在 presentDisplay 被调用后立即变为触发状态。

Notes: 关于Fence同步机制需要单独拎出来梳理学习。


4. 参考

  • 转载夕月风大佬博客: https://www.jianshu.com/p/824a9ddf68b9
  • 参考源码: http://aosp.opersys.com/xref/android-10.0.0_r14/

Leave a comment