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
相关推荐
alexhilton9 小时前
Jetpack Compose内部的不同节点类型
android·kotlin·android jetpack
Frank_HarmonyOS10 小时前
Android中四大组件之一的Activity的启动模式
android
似霰10 小时前
HIDL Hal 开发笔记7----简单 HIDL HAL 实现
android·framework·hal
用户20187928316714 小时前
📚 Android Settings系统:图书馆管理员的故事
android
青莲84314 小时前
Android 事件分发机制 - 事件流向详解
android·前端·面试
火柴就是我14 小时前
学习一些常用的混合模式之BlendMode. dst_atop
android·flutter
火柴就是我15 小时前
学习一些常用的混合模式之BlendMode. dstIn
android·flutter
ganshenml16 小时前
【Android】 开发四角版本全解析:AS、AGP、Gradle 与 JDK 的配套关系
android·java·开发语言
我命由我1234516 小时前
Kotlin 运算符 - == 运算符与 === 运算符
android·java·开发语言·java-ee·kotlin·android studio·android-studio
摘星编程17 小时前
【RAG+LLM实战指南】如何用检索增强生成破解AI幻觉难题?
android·人工智能