Android 硬件加速流程和源码分析(二)

Android 硬件加速流程和源码分析(一)

Android 硬件加速流程和源码分析(二)

Android 硬件加速流程和源码分析(三)

Android 硬件加速流程和源码分析(四)

Android 硬件加速流程和源码分析(五)

2. 硬件加速整体概览和相关主要类

以下所有源码的链接都是Android 9(api 28),因为http://androidxref.com/这个网站看源码相对比较方便,但是这个网站的Android源码只更新到了Android 9 api28, 下面粘贴出来的代码的版本有部分可能高于api28.

2.1 页面刷新的开始

要讲清楚硬件加速得从View的绘制讲起,先简单来看下view的绘制流程:
ViewRootImpl 是View树的顶点, 一个window 对应一个ViewRootImpl,WindowManagerGlobal 中

ArrayList<ViewRootImpl> mRoots..包含每个窗口的ViewRootImpl

简单看下ViewRootImpl是如何执行到绘制draw()方法开始硬件加速绘制的:

[图片上传失败...(image-aae906-1647012614049)]

当页面根布局requestLayout()/invalidata()或者其他需要变化后需要更新页面视图
时,首先会调用ViewRootImpl的scheduleTraversals()执行遍历,编舞者Choreographer会post一个遍历任务TraversalRunnable,然后一步步调用到ViewRootImpl的draw(boolean fullRedrawNeeded)方法开始从根布局的刷新视图.

ViewRootImpl#draw(boolean fullRedrawNeeded)


private boolean draw(boolean fullRedrawNeeded){
        ...
        if(mAttachInfo.mThreadedRenderer!=null&&mAttachInfo.mThreadedRenderer.isEnabled()){
                    ...
                 //硬件加速
                    mAttachInfo.mThreadedRenderer.draw(mView,mAttachInfo,this);
        }else{
                //不启用硬件加速
                    if(!drawSoftware(surface,mAttachInfo,xOffset,yOffset,
                            ...
                    }
        }
        ...
     }

在 ViewRootImpl的draw方法中会根据设置启用或者不启用硬件加速绘制当前页面, mThreadedRenderer.isEnabled()会在ThreadedRenderer初始化时默认设置为true.

   boolean initialize(Surface surface) throws OutOfResourcesException {
            ... 
        mInitialized = true;
        updateEnabledState(surface);
        ...
    }
   private void updateEnabledState(Surface surface) {
        if (surface == null || !surface.isValid()) {
            setEnabled(false);
        } else {
            setEnabled(mInitialized);
        }
    }
    boolean isEnabled() {
        return mEnabled;
    }
    void setEnabled(boolean enabled) {
        mEnabled = enabled;
    }

所以一般情况下,硬件加速是默认开启的.

2.2 硬件加速时序

硬件加速的时序从java层到native层,整个时序大概如下:

[图片上传失败...(image-e9ae89-1647012614049)]

一个图一行显示不下,继续

[图片上传失败...(image-ed832f-1647012614049)]

ViewRootImpl 调用到ThreadedRenderer渲染器,ThreadedRenderer在主线程调用updateRootDisplayList(view,callbacks)完成显示列表 DisplayList的更新. DisplayList的更新是从ThreadedRenderer中mRootNode调用beginRecording(..)开始的,mRootNode就是ViewRootImpl 调用setView() 设置的根布局的RenderNode. RecordingCanvas用于记录暂存的显示列表DisplayList. 显示列表更新后需要同步和绘制显示列表,通过jni调用到native层的RenderProxy,接着调用DrawFrameTask的postAndWait()提交一个绘制帧任务到渲染线程RenderThread. 在DrawFrameTask的run方法中会调用调用到CanvasContext.cpp进行显示列表的同步和绘制.

在ViewRootImpl中选择了硬件加速绘制后,进入渲染器ThreadRenderer的绘制逻辑,接下来就是两个比较重要的步骤,更新displayList同步并绘制帧

ThreadedRenderer#draw(mView, mAttachInfo, this)

   void draw(View view,AttachInfo attachInfo,DrawCallbacks callbacks){
                ...
        //1.记录并更新显示列表(在MainThread)
        updateRootDisplayList(view,callbacks);
        ...
        //2. 同步&绘制帧
                    //api28 这里是直接调用native方法:
         int syncResult = nSyncAndDrawFrame(mNativeProxy, frameInfo, frameInfo.length);
            //api29开始 如下
            //int syncResult=syncAndDrawFrame(choreographer.mFrameInfo);
                // 然后再在HardwareRenderer中调用native方法nSyncAndDrawFrame
        ...
        }

2.3 相关类介绍

硬件加速绘制流程中涉及到了很多类,从java 到native层 ,整个流程比较复杂,下面简单罗列下几个比较重要的关键类及其作用.

2.3.1 ThreadedRenderer.java

渲染器, 作用是通过 native层的 android_view_ThreadedRenderer.cpp 创建一个RenderProxy 代理渲染线程, 管理渲染线程RenderThread 中的native层上下文(CanvasContext.cpp) , ThreadedRenderer中大部分方法是同步的

public final class ThreadedRenderer {
        ...
   //native层的渲染代理RendProxy
    private long mNativeProxy;
    //根节点   
    private RenderNode mRootNode;
  
   ThreadedRenderer(Context context, boolean translucent, String name) {
         ...
        long rootNodePtr = nCreateRootRenderNode();
            //创建渲染根节点
        mRootNode = RenderNode.adopt(rootNodePtr);
   }

api29 开始ThreadedRenderer中部分代码移动到了HardwareRenderer,整体变化不大

public final class ThreadedRenderer extends HardwareRenderer {
  ...
}
public class HardwareRenderer {
  ...
    //ThreadedRenderer 中的mRootNode 是渲染根节点
    protected RenderNode mRootNode;

2.3.2 RenderNode

image.png

View 树和RenderNode树的对应关系如图, 视图层的一个View对应硬件加速渲染的一个RenderNode,java层的renderNode持有native层的renderNode的指针 ,native层的renderNode 包含一个displayList和其他相关属性,displayList记录了每个View在硬件加速下的绘制步骤,在native层一个绘制步骤用一个RecordedOp表示.

native层RenderNode中相关的定义如下,带mStaging前缀的变量表示是view发生的变化,需要更新到下次显示的.

RenderNode.cpp

RenderNode.h

242      //用于标记View属性是否变化
243    uint32_t mDirtyPropertyFields;
244    RenderProperties mProperties;
                //待同步属性 透明/缩放/xy....    
245    RenderProperties mStagingProperties;
            ...
       //一些属性了就要更新mDisplayList;
251    bool mNeedsDisplayListSync;
252     
        //displayList 用于记录硬件加速绘制过程  
253    DisplayList* mDisplayList;
            //待同步   
254    DisplayList* mStagingDisplayList;

259    // Owned by RT. Lifecycle is managed by prepareTree(), with the exception
260    // being in ~RenderNode() which may happen on any thread.
         //离屏渲染Buffer ,TextureView或者做硬件加速动画的View作为一个layer进行离屏渲染时不为null  
261    OffscreenBuffer* mLayer = nullptr;
            ... 
private:
                //被移除的RenderNode,   
390    FatVector<sp<RenderNode>, 10> mMarked;
            //用于记录绘制信息同步结果
391    TreeInfo* mTreeInfo;

View对应的硬件加速绘制步骤的记录从java层的RenderNode.java开始, start()和end()分表表示一个view的硬件加速绘制过程记录的开始和结束,绘制的每一个动作被记录到了RenderNode中RecordingCanvas中的DisplayList中,api29后start()和end()被beginRecording() 和endRecording()替代

RenderNode.java api28

    public DisplayListCanvas start(int width, int height) {
        return DisplayListCanvas.obtain(this, width, height);
    }
    public void end(DisplayListCanvas canvas) {
        long displayList = canvas.finishRecording();
        nSetDisplayList(mNativeRenderNode, displayList);
        canvas.recycle();
    }

RenderNode.java api29

//下面代码是api30 ,和 api28中源码有些不一样,流程基本一样
public final class RenderNode {
    //RecodringCanvas 用于记录view硬件加速绘制操作
      private RecordingCanvas mCurrentRecordingCanvas;
    ...
    //native层的RenderNode
    public final long mNativeRenderNode;
    ...

    //开始记录View硬件加速绘制步骤,  得到一个RecordingCanvas用于记录view绘制操作
    public @NonNull RecordingCanvas beginRecording(int width, int height) {
                ....
        mCurrentRecordingCanvas = RecordingCanvas.obtain(this, width, height);
        return mCurrentRecordingCanvas;
    }

        //结束记录View硬件加速绘制步骤
    public void endRecording() {
        RecordingCanvas canvas = mCurrentRecordingCanvas;
        mCurrentRecordingCanvas = null;
        //这一步的动作是把RecordingCanvas中的displayList设置给native RenderNode中的
        //mStagingDisplayList,mStagingDisplayList用于页面下一次刷新时展示到屏幕
        long displayList = canvas.finishRecording();
        //look here!!! nSetDisplayList 在干啥?? 
        nSetDisplayList(mNativeRenderNode, displayList);
        canvas.recycle();
    }
  • 接着看下RenderNode的 end()/endRecording()方法中 RecordingCanvas 调动finishRecording()的后续

从上可以看出java层的RenderNode开始start()/startRecording时获取到了一个RecordingCanvas,end()/endRecording()时 RecordingCanvas调用 finishRecording 返回一个native层 DisplayList的指针的long

151static jlong android_view_DisplayListCanvas_finishRecording(jlong canvasPtr) {
152    Canvas* canvas = reinterpret_cast<Canvas*>(canvasPtr);
              //把DisplayList指针转为long返回给java层
153    return reinterpret_cast<jlong>(canvas->finishRecording()); 
154}

注:reinterpret_cast 用于进行各种不同类型的指针之间、不同类型的引用之间以及指针和能容纳指针的整数类型之间的转换,

canvas->finishRecording() 实际的调用者类型是RecordingCanvas或者SkiaRecordingCanvas,Android 9中默认是SkiaRecordingCanvas

RecordingCanvas::finishRecording()

46 DisplayList* RecordingCanvas::finishRecording() {
47    restoreToCount(1);
48    mPaintMap.clear();
49    mRegionMap.clear();
50    mPathMap.clear();
51    DisplayList* displayList = mDisplayList;
52    mDisplayList = nullptr;
53    mSkiaCanvasProxy.reset(nullptr);
54    return displayList;
55}

SkiaRecordingCanvas::finishRecording()

 uirenderer::DisplayList* SkiaRecordingCanvas::finishRecording() {
51    // close any existing chunks if necessary
52    insertReorderBarrier(false);
53    mRecorder.restoreToCount(1);
54    return mDisplayList.release();
55}

在RecordingCanvas.h源码中可以看到头文件中定义的私有成员变量 DisplayList* mDisplayList,这个变量是RecordingCanvas中最重要的一个变量

RecordingCanvas.h

36 namespace android {
37 namespace uirenderer {
   ...
43 class ANDROID_API RecordingCanvas : public Canvas, public CanvasStateClient {
   ... 
50 public:
51    RecordingCanvas(size_t width, size_t height);
  
199 private:
      ...
      //这里可以看到头文件中定义的私有变量mDisplayList
313    DisplayList* mDisplayList = nullptr;
           ...

以上代码可以看出native层 RecordingCanvas 如何返回一个DisplayList

  • 接着看下 RecordingCanvas 返回的DisplayList的使用,也就是java层的RenderNode 的endRecording()方法中nSetDisplayList 在干啥?

RenderNode.java#endRecording() 会调用到android_view_RenderNode.cpp然后调用到native层的RenderNode::setStagingDisplayList(DisplayList* displayList)

70void RenderNode::setStagingDisplayList(DisplayList* displayList) {
71    ...
72    mNeedsDisplayListSync = true;
73    delete mStagingDisplayList;
      //待同步DisplayList,下次屏幕刷新时展示
74    mStagingDisplayList = displayList;
75}

可以看出 java层的RenderNode结束绘制时通过 canvas.finishRecording() 得到一个 displayList ,然后赋值给native层的renderNode的mStagingDisplayList字段,而mStagingDisplayList就是下次屏幕刷新时需要绘制出来的内容.

2.3.3 RecordingCanvas

RecordingCanvas见名知意 是用来记录硬件加速绘制动作的画布. api28后,java层的 RecordingCanvas最终继承于BaseCanvas,BaseRecordingCanvas中对BaseCanvas进行了扩展.硬件加速过程中,某个View对应native层的RecordingCanvas/SkiaRecordingCanvas的作用就是用DisplayList记录下硬件加速的绘制过程,然后把记录完成的DisplayList返回给该view的RenderNode,相当于充当一个临时的画布容器记录绘制过程.

Android 28时RenderNode中的RecordingCanvas实际类型是DisplayListCanvas

api28

public final class DisplayListCanvas extends RecordingCanvas {
    ...
        private DisplayListCanvas(@NonNull RenderNode node, int width, int height) {
        super(nCreateDisplayListCanvas(node.mNativeRenderNode, width, height));
    }
  ...
    @CriticalNative
    private static native long nCreateDisplayListCanvas(long node, int width, int height);
}

public class RecordingCanvas extends Canvas {
  ...
}

api29及以后

public final class RecordingCanvas extends DisplayListCanvas {
    ...
    protected RecordingCanvas(@NonNull RenderNode node, int width, int height) {
        super(nCreateDisplayListCanvas(node.mNativeRenderNode, width, height));
      ...
    }
  
    @CriticalNative
    private static native long nCreateDisplayListCanvas(long node, int width, int height);
    ...
}

public abstract class DisplayListCanvas extends BaseRecordingCanvas {
    protected DisplayListCanvas(long nativeCanvas) {
        super(nativeCanvas);
    }
    ...
}  
  
public class BaseRecordingCanvas extends Canvas {
    public BaseRecordingCanvas(long nativeCanvas) {
        super(nativeCanvas);
    }
    ...
}
public class Canvas extends BaseCanvas {
    
  public Canvas(long nativeCanvas) {
    //这里可以看出java层的Canvas/DisplayListCanvas/RecordingCanvas持有native层的Canvas的一个指针
    mNativeCanvasWrapper = nativeCanvas;
        ...
}

以上代码可以看出java层的RecordingCanvas持有native层的canvas指针.

接着往下native层的RecordingCanvas的生成

android_view_DisplayListCanvas_createDisplayListCanvas

118 static jlong android_view_DisplayListCanvas_createDisplayListCanvas(jlong renderNodePtr,
119        jint width, jint height) {
120    RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
121    return reinterpret_cast<jlong>(Canvas::create_recording_canvas(width, height, renderNode));
122}

Canvas::create_recording_canvas(..)

31 Canvas* Canvas::create_recording_canvas(int width, int height, uirenderer::RenderNode* renderNode) {
32    if (uirenderer::Properties::isSkiaEnabled()) { //android 9 isSkiaEnabled()默认为true
33        return new uirenderer::skiapipeline::SkiaRecordingCanvas(renderNode, width, height);
34    }
35    return new uirenderer::RecordingCanvas(width, height);
36}

Properties::isSkiaEnabled()

219 bool Properties::isSkiaEnabled() {
220    auto renderType = getRenderPipelineType();
221    return RenderPipelineType::SkiaGL == renderType || RenderPipelineType::SkiaVulkan == renderType;
222}

可以看出native层的SkiaRecordingCanvas创建时会把RenderNode作为构造参数,RecordingCanvas则无需

SkiaRecordingCanvas.h

27/**
28 * A SkiaCanvas implementation that records drawing operations for deferred rendering backed by a
29 * SkLiteRecorder and a SkiaDisplayList.
30 */
31 class SkiaRecordingCanvas : public SkiaCanvas {
32public:
33    explicit SkiaRecordingCanvas(uirenderer::RenderNode* renderNode, int width, int height) {
34        initDisplayList(renderNode, width, height);
35    }
36

78 private:
79    SkLiteRecorder mRecorder;
80    std::unique_ptr<SkiaDisplayList> mDisplayList;

RecordingCanvas.h头文件中可以看到定义了私有变量DisplayList* mDisplayList.

SkiaRecordingCanvas.h头文件中定义了std::unique_ptr<SkiaDisplayList> mDisplayList.

SkiaDisplayList继承于 DisplayList.

所以,java层的 RecordingCanvas 继承于BaseCanvas,重写了部分绘制方法,持有一个native层的RecordingCanvas的指针,开启硬件加速时绘制的动作会被记录到native层RecordingCanvas的DisplayList中. native层会根据手机系统的设置Properties::isSkiaEnabled()创建一个RecordingCanvas 或者 SkiaRecordingCanvas.

Skia api硬件加速时:

SkiaRecordingCanvas 和 其父类 SkCanvas 中的drawXXX()方法都会调用到 SkLiteRecorderSkLiteRecorder::onDrawXXX(..)方法, 接着调用SkLiteDL的相关SkLiteDL::drawXXX(..)方法.比如drawText

SkLiteDL::drawText(...)

638 void SkLiteDL::drawText(const void* text, size_t bytes,
639                        SkScalar x, SkScalar y, const SkPaint& paint) {
640    void* pod = this->push<DrawText>(bytes, bytes, x, y, paint);
641    copy_v(pod, (const char*)text,bytes);
642}

Android 10的时候 SkiaRecordingCanvas中mRecorder又由SkLiteRecorder变成了 RecordingCanvas,随着Android版本的升级,Skia在硬件加速中的戏份越来愈多. 这部分不详细分析了.

2.3.4 DisplayList

显示列表DisplayList存在于RecordingCanvas 和 RenderNode中. Displaylist是RecordingCanvas的私有变量,因为DisplayList类定义了friend class RecordingCanvas(c++友元类,可以直接访问类内部私有和protected成员),所以RecordingCanvas可以直接访问DisplayList的私有变量比如chunks,ops,children,DisplayList是RenderNode中用于记录View硬件加速绘制步骤的一个容器,记录了自己和 child View硬件加速绘制记录, 每一记录用一个RecordedOp(别名是BaseOpType)表示.

DisplayList.cpp

DisplayList.h

        // 所有类型的绘制记录
        typedef RecordedOp BaseOpType;  //BaseOpType 就是 RecordedOp
        //用于记录一个child RenderNode
60  typedef RenderNodeOp NodeOpType;

75 class DisplayList {
        //定义friend class, RecordingCanvas可以直接访问DisplayList私有变量
76    friend class RecordingCanvas;
77
78 public:
        //一个chunk可能是一个RecordedOp, 也可能是连着几个RecordedOp
79    struct Chunk {
80        // range of included ops in DisplayList::ops()
81        size_t beginOpIndex; 
82        size_t endOpIndex;
84        // range of included children in DisplayList::children()
85        size_t beginChildIndex;
86        size_t endChildIndex;
                //当view重绘时,view对应的RenderNode中的DisplayList的chunk需要重新排序
88        // whether children with non-zero Z in the chunk should be reordered
89        bool reorderChildren;
90              ...
93    };
95       ...
             ...
135 private:
        //chunks存在的意义在于 View在Z方向是有高度的, displayList的元素最终是以chunk为单位在Z方向排序的
136    LsaVector<Chunk> chunks;
        //RecordedOp集合,自己的绘制动作RecordedOp,包含所有children
137    LsaVector<BaseOpType*> ops;
         //子View的RenderNode,对RenderNode的子node遍历从这里取     
140    LsaVector<NodeOpType*> children;

        //硬件渲染时drawBitmap的集合,会处理成一个纹理,在`DisplayList::prepareListAndChildren()`中上传到GPU
143    LsaVector<sk_sp<Bitmap>> bitmapResources;
            //一些复杂的绘制命令,用RecordedOp表示不了,用函数指针表示
  151   LsaVector<FunctorContainer> functors;
                ...
160};

DisplayList.h中定义的变量 LsaVector<BaseOpType*> ops;可以看到类型是BaseOpType(也就是RecordedOp),DislplayList的私有变量LsaVector<NodeOpType*> children中保存的是View的子view的RenderNode, LsaVector<BaseOpType*> ops保存RenderNode自己和child的绘制记录. 因为view 在z方向是有层级的,子view和父view的绘制先后不一定,到了绘制这一步时,是以LsaVector<Chunk> chunks中的顺序来进行绘制的,chunk是排序后的绘制单位 ,chunk记录了绘制动作RecordedOp的起始位置. LsaVector<FunctorContainer> functors表示一些复杂的GL绘制命令, 在RecordingCanvas::callDrawGLFunction中添加到DisplayList中.

在启用Skia进行硬件加速绘制时,DisPlayList的真实类型是 SkiaDisplayList.h.

2.3.5 RecordedOp

RecordedOp表示DisplayList中一个硬件加速的绘制过程, 有很多继承类型, RecordedOp.h中定义的各种RecordedOp的继承类型,每种类型的RecordedOp对应java层canvas api在硬件加速时的一个drawxxx()方法.

RecordedOp.h

struct RenderNodeOp : RecordedOp {
185    RenderNodeOp(BASE_PARAMS_PAINTLESS, RenderNode* renderNode)
186            : SUPER_PAINTLESS(RenderNodeOp), renderNode(renderNode) {}
        //!!!!这里可以看出RenderNodeOp 内部保存了renderNode的指针
187    RenderNode* renderNode;  // not const, since drawing modifies it
            ...
199};
200
201////////////////////////////////////////////////////////////////////////////////////////////////////
202// Standard Ops  其他的......
203////////////////////////////////////////////////////////////////////////////////////////////////////
204
205 struct ArcOp : RecordedOp {
206    ArcOp(BASE_PARAMS, float startAngle, float sweepAngle, bool useCenter)
207            : SUPER(ArcOp), startAngle(startAngle), sweepAngle(sweepAngle), useCenter(useCenter) {}
208    const float startAngle;
209    const float sweepAngle;
210    const bool useCenter;
211};
212
213 struct BitmapOp : RecordedOp {
214    BitmapOp(BASE_PARAMS, Bitmap* bitmap) : SUPER(BitmapOp), bitmap(bitmap) {}
215    Bitmap* bitmap;
216};
217
            ...

RenderNode和DisplayList和 RecordedOp的关系如下

image.png

对应每个view,都与其对应有一个RenderNode,RenderNode中记录了view各种属性,RenderNode的mDisplayList中记录了硬件加速时画布的绘制记录,displayList的ops包含所有的绘制记录,children集合是子View的RenderNodeOp的集合,一个RenderNodeOp对应一个子View的RenderNode.

2.3.6 RenderThread

硬件加速渲染线程,同UI线程一样,全局只有一个实例. 显示列表DisplayList的更新在主线程,同步和绘制在渲染线程.

RenderThread.h

RenderThread.cpp

2.3.7 CanvasContext

画布上下文,连接全局的EGL上下文和渲染surface,一个Surface对应一个CanvasContext.

CanvasContext.h

62// This per-renderer class manages the bridge between the global EGL context
63// and the render surface.
64// TODO: Rename to Renderer or some other per-window, top-level manager
65 class CanvasContext : public IFrameCallback {
            ....
214     //渲染线程      
215    RenderThread& mRenderThread;
        //需要渲染的surface
216    sp<Surface> mNativeSurface;
            //是否需要更新
225    bool mIsDirty = false;

        //需要单独作为一个帧缓冲对象FBO(frame buffer objexct)进行渲染的RenderNode集合,包含 TextureView 和 做动画设置LAYER_TYPE_HARDWARE且调用了buildLayer的View
248    LayerUpdateQueue mLayerUpdateQueue;
249    std::unique_ptr<AnimationContext> mAnimationContext;
250     //mRenderNodes包含当前window对应的RootRenderNode,多窗口模式可能还包含其他的RenderNode   
251    std::vector<sp<RenderNode>> mRenderNodes;
252
253    FrameInfo* mCurrentFrameInfo = nullptr;
                
259    std::set<RenderNode*> mPrefetchedLayers;
260
271    std::vector<sp<FuncTask>> mFrameFences;
272    sp<TaskProcessor<bool>> mFrameWorkProcessor;
        //渲染管道 OpenGL 或者 SkiaGL啥的   
273    std::unique_ptr<IRenderPipeline> mRenderPipeline;
274
275    std::vector<std::function<void(int64_t)>> mFrameCompleteCallbacks;
            ...

通常情况下CanvasContext的mRenderNodes集合中是只有一个元素,即当前Window的RootRenderNode. 多窗口模式下可能有多个. LayerUpdateQueue mLayerUpdateQueue是需要单独作为一个帧缓冲对象FBO(frame buffer objexct)进行渲染的RenderNode集合(包含 TextureView 和 做动画设置LAYER_TYPE_HARDWARE且调用了buildLayer的View).

2.3.8 EGL

官网介绍

https://www.khronos.org/egl

Native Platform Interface

EGL™ is an interface between Khronos rendering APIs such as OpenGL ES or OpenVG and the underlying native platform window system. It handles graphics context management, surface/buffer binding, and rendering synchronization and enables high-performance, accelerated, mixed-mode 2D and 3D rendering using other Khronos APIs. EGL also provides interop capability between Khronos to enable efficient transfer of data between APIs – for example between a video subsystem running OpenMAX AL and a GPU running OpenGL ES.

然后...有道翻一下:

EGL™是Khronos渲染api(如OpenGL ES或OpenVG)与底层本机平台窗口系统之间的接口。它处理:

  • 图形上下文管理
  • 表面/缓冲区绑定和渲染同步,并使用其他Khronos api支持高性能、加速、混合模式的2D和3D渲染
  • EGL还提供了在Khronos之间的互操作能力,以实现api之间的数据高效传输——例如在运行OpenMAX AL的视频子系统和运行OpenGL ES的GPU之间。

简言之就是连接渲染apinative窗口系统间的接口.

Android 关于EGL的介绍

Android 使用 OpenGL ES (GLES) API 渲染图形。为了创建 GLES 上下文并为 GLES 渲染提供窗口系统,Android 使用 EGL 库。GLES 调用用于渲染纹理多边形,而 EGL 调用用于将渲染放到屏幕上。

在使用 GLES 进行绘制之前,您需要创建 GL 上下文。在 EGL 中,这意味着要创建一个 EGLContext 和一个 EGLSurface。 GLES 操作适用于当前上下文,该上下文通过线程局部存储访问,而不是作为参数进行传递。渲染代码应该在当前 GLES 线程(而不是界面线程)上执行。

.

Android 硬件加速流程和源码分析(一)

Android 硬件加速流程和源码分析(二)

Android 硬件加速流程和源码分析(三)

Android 硬件加速流程和源码分析(四)

Android 硬件加速流程和源码分析(五)

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,835评论 4 364
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,598评论 1 295
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 109,569评论 0 244
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,159评论 0 213
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,533评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,710评论 1 222
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,923评论 2 313
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,674评论 0 203
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,421评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,622评论 2 245
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,115评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,428评论 2 254
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,114评论 3 238
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,097评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,875评论 0 197
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,753评论 2 276
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,649评论 2 271

推荐阅读更多精彩内容