Android窗口Surface简介

创建流程

  • 应用程序窗口对应一个Surface(Surface.java)
  • Surface由每个应用进程的ViewRootImpl持有
  • Surface最初初始化为一个空Surface
  • Surface的初始化发生在第一次relayoutWindow
css 复制代码
[View.invalidate]  
    ↓  
[逐级传递到 ViewRootImpl]  
    ↓  
[ViewRootImpl.scheduleTraversals()]  
    ↓  
[插入同步屏障,注册 VSYNC 回调]  
    ↓  
[VSYNC 信号到达 → 执行 doTraversal() → performTraversals() → relayoutWindow]
    ↓
[执行updateBlastSurfaceIfNeeded()]
    ↓
[创建BLASTBufferQueue → mBlastBufferQueue.createSurface() → mSurface.transferFrom(blastSurface)]

接下来分析Java层BLASTBufferQueue的createSurface创建流程

BLASTBufferQueue.createSurface

  • Java层的createSurface对应到jni中的nativeGetSurface
  • jni层中,通过BLASTBufferQueue::getSurface获取Surface
  • 在BLASTBufferQueue::getSurface中创建并返回了一个BBQSurface
c++ 复制代码
sp<Surface> BLASTBufferQueue::getSurface(bool includeSurfaceControlHandle) {
    std::lock_guard _lock{mMutex};
    sp<IBinder> scHandle = nullptr;
    if (includeSurfaceControlHandle && mSurfaceControl) {
        scHandle = mSurfaceControl->getHandle();
    }
    return new BBQSurface(mProducer, true, scHandle, this);
}
  • BBQSurface关联了BBQ中的生产者、SurfaceControl、还有BBQ自己本身
  • Java层窗口对应的Surface在native层包装的是BBQSurface

将Surface设置给hwui

  • 接着上一节,在performTraversals()中创建Surface后,接着会进行更新Surface
c++ 复制代码
private void performTraversals() {
    ...
    } else if ((surfaceReplaced || surfaceSizeChanged || updateSurfaceNeeded)
                        && mSurfaceHolder == null
                        && mAttachInfo.mThreadedRenderer != null
                        && mSurface.isValid()) {
        mFullRedrawNeeded = true;
        try {
            // Need to do updateSurface (which leads to CanvasContext::setSurface and
            // re-create the EGLSurface) if either the Surface changed (as indicated by
            // generation id), or WindowManager changed the surface size. The latter is
            // because on some chips, changing the consumer side's BufferQueue size may
            // not take effect immediately unless we create a new EGLSurface.
            // Note that frame size change doesn't always imply surface size change (eg.
            // drag resizing uses fullscreen surface), need to check surfaceSizeChanged
            // flag from WindowManager.
            mAttachInfo.mThreadedRenderer.updateSurface(mSurface);
        } catch (OutOfResourcesException e) {
            handleOutOfResourcesException(e);
            mLastPerformTraversalsSkipDrawReason = "oom_update_surface";
            return;
        }
    }
}
  • 从java层一层层调用到SkiaPipeline
  • 需要注意的一点是在jni层,会将Surface转成ANativeWindow,在hwui模块中只能感知到ANativeWindow的存在
  • 在skiapipeline中根据opengl、vulkan后端,区分不同的流程(Android15中已经默认走vulkan)
    • (opengl),在SkiaOpenGLPipeline中调用setSurface,然后是EglManager.createSurace将ANativeWindow转成EGLSurface

渲染

  • 还有一条非常隐蔽的线,在SkiaPipeline renderFrame渲染每帧内容时,用的是SkSurface,SkSurface与EGLSurface的关联是源码中看不到的
  • 在SkiaPipeline中通过MakeFromBackendRenderTarget创建SkSurface时,需要传入GrBackendRenderTarget(封装了 EGLSurface 的帧缓冲区对象 FBO
相关推荐
2501_9159090630 分钟前
全面解析iOS应用上架到App Store的完整流程与关键注意事项
android·macos·ios·小程序·uni-app·cocoa·iphone
淡淡的香烟3 小时前
AndroidAI使用心得
android
chjif3 小时前
Android 设备管控开发实战:无障碍如何准确识别当前前台 App?
android
chjif3 小时前
Android 设备管控开发实战:企业受控终端的 DNS 域名策略实现
android·华为·harmonyos
c238565 小时前
MySQL 基础用法(下):查询进阶与核心特性
android·c语言·c++·mysql
math_hongfan5 小时前
鸿蒙Agent高级技能自定义开发:自定义意图服务/能力注册/Agent技能编排/服务插件开发实战
android·学习·华为·harmonyos·鸿蒙
2501_915106326 小时前
iOS 证书类型及作用说明 账号证书与签名配置的完整解读
android·ios·小程序·https·uni-app·iphone·webview
九皇叔叔7 小时前
RHEL9 安装 MySQL 8.4.11.LTS 版本
android·mysql·adb
海兰7 小时前
【数据库】tdsql(MySQL )的事务隔离级别
android·数据库·mysql
哆啦A梦z7 小时前
Android BLE 实战:从小米手环 7 踩坑到完整连接框架
android