Android WebView执行GPU命令的过程分析.docx
- 文档编号:3086796
- 上传时间:2023-05-05
- 格式:DOCX
- 页数:85
- 大小:42.76KB
Android WebView执行GPU命令的过程分析.docx
《Android WebView执行GPU命令的过程分析.docx》由会员分享,可在线阅读,更多相关《Android WebView执行GPU命令的过程分析.docx(85页珍藏版)》请在冰点文库上搜索。
AndroidWebView执行GPU命令的过程分析
AndroidWebView执行GPU命令的过程分析
AndroidWebView使用的Chromium引擎,虽然没有自己的GPU进程或者线程,但是却可以执行GPU命令。
原来,AndroidWebView会给它提供一个In-ProcessCommandBufferGL接口。
通过这个接口,Chromium引擎就可以将GPU命令提交给App的RenderThread执行。
本文接下来就详细分析AndroidWebView执行GPU命令的过程。
从前面Chromium硬件加速渲染的OpenGL命令执行过程分析这篇文章可以知道,Chromium渲染引擎在有自己的GPU进程或者线程的情况下,是通过一个CommandBufferGL接口执行GPU命令的。
这个CommandBufferGL接口通过一个GLES2Implementation类描述。
AndroidWebView给Chromium引擎提供的In-ProcessCommandBufferGL接口,同样是通过GLES2Implementation类描述的。
这样,Chromium渲染引擎就不用关心它发出的GPU命令是如何执行的。
在Chromium渲染引擎中,需要执行GPU命令的是Render端和Browser端。
Render端执行GPU命令是为渲染网页的UI,而Browser端执行GPU命令是为了将Render端渲染的网页UI合成显示在屏幕上。
对AndroidWebView来说,它的Render端会将网页抽象成一个CCLayerTree,然后使用一个SynchronousCompositor将它渲染在一个SynchronousCompositorOutputSurface上
AndroidWebView的Browser端同样会将自己要合成的UI抽象为一个CCLayerTree,然后使用一个HardwareRenderer将它渲染在一个ParentOutputSurface上
Browser端的CCLayerTree比较特别,它只有两个节点。
一个是根节点,另一个是根节点的子节点,称为DelegatedRenderLayer,它要渲染的内容来自于Render端的渲染输出。
从前面Chromium硬件加速渲染的UI合成过程分析一文可以知道,Render端的渲染输出是一系列的RenderPass。
每一个RenderPass都包含了若干个纹理。
这些纹理是在Render端光栅化网页时产生的。
Browser端的HardwareRenderer所要做的事情就是将这些纹理渲染在屏幕上。
这个过程也就是Browser端合成网页UI的过程。
不管是Render端,还是Browser端,当它们执行GPU命令的时候,都是通过GLES2Implementation类描述的一个In-ProcessCommandBufferGL接口写入到一个CommandBuffer中去的。
只不过在AndroidWebView的情况下,这些GPU命令会被一个DeferredGpuCommandService服务提交给App的RenderThread执行
Render端和Browser端将要执行的GPU命令写入到CommandBuffer之后,就会请求DeferredGpuCommandService服务在App的RenderThread中调度执行一个Task。
这个Task绑定了InProcessCommandBuffer类的成员函数FlushOnGpuThread。
InProcessCommandBuffer类的成员函数FlushOnGpuThread又是通过一个GpuScheduler按照上下文来执行请求的GPU命令,并且这些GPU命令在执行之前,先要经过一个GLES2Decoder进行解码。
这个过程可以参考前面Chromium硬件加速渲染的OpenGL命令执行过程分析一文。
对于Browser端来说,它本来就是在App的RenderThread中请求执行GPU命令的。
这时候DeferredGpuCommandService服务会直接在当前线程中调用InProcessCommandBuffer类的成员函数FlushOnGpuThread,以便执行请求的GPU命令。
对于Render端来说,它在两种情景下需要请求执行GPU命令。
第一种情景是光栅化网页的UI,第二种情景是绘制网页的UI。
这两种情景都是发生在Render端的Compositor线程中。
关于Render端的Compositor线程,以及网页UI的光栅化和绘制操作,可以参考前面Chromium网页渲染机制简要介绍和学习计划这个系列的文章。
上述两种情景都会将要执行的GPU操作抽象为一个DrawGLFunctor对象。
对于第一个情景,DrawGLFunctor对象会通过App的UI线程直接提交给App的RenderThread。
App的RenderThread再通知该DrawGLFunctor对象执行GPU操作。
对于第二个情景,DrawGLFunctor对象会被App的UI线程封装为一个DrawFunctorOp操作,并且写入到AppUI的DisplayList中。
接下来App的UI线程会将DisplayList同步给App的RenderThread。
随后这个DisplayList就会被App的RenderThread通过一个OpenGLRenderer进行Replay,这时候DisplayList中包含的DrawFunctorOp操作就会被执行。
在执行的过程中,与它关联的DrawGLFunctor对象获得通知。
DrawGLFunctor对象获得通知以后就会执行之前Render端请求的GPU操作了。
DrawGLFunctor对象在执行GPU操作的时候,会调用到一个DrawGL函数。
这个DrawGL函数是AndroidWebView在启动Chromium渲染引擎时注册的。
它在执行的过程中,就会通过Browser端的HardwareRenderer通知DeferredGpuCommandService服务执行此前请求调度的Task。
这时候InProcessCommandBuffer类的成员函数FlushOnGpuThread就会被调用,这时候Render端之前请求的GPU命令就会被执行。
接下来,我们就结合源码,分析Chromium渲染引擎的Render端和Browser端创建In-ProcessCommandBufferGL接口的过程,以及以Render端使用GPU光栅化网页的过程为例,分析Chromium渲染引擎通过In-ProcessCommandBufferGL接口执行GPU命令的过程。
不过,在分析这些过程之前,我们首先分析AndroidWebView向Chromium渲染引擎注册DrawGL函数的过程。
这个过程发生在AndroidWebView启动Chromium渲染引擎的Browser端的过程中。
从前面AndroidWebView启动Chromium渲染引擎的过程分析一文可以知道,AndroidWebView在启动Chromium渲染引擎的Browser端的过程中,会调用到WebViewChromiumFactoryProvider类的成员函数startChromiumLocked,如下所示:
[java]viewplaincopy在CODE上查看代码片派生到我的代码片
publicclassWebViewChromiumFactoryProviderimplementsWebViewFactoryProvider{
......
privatevoidstartChromiumLocked(){
......
initPlatSupportLibrary();
AwBrowserProcess.start(ActivityThread.currentApplication());
......
}
......
}
这个函数定义在文件frameworks/webview/chromium/java/com/android/webview/chromium/WebViewChromiumFactoryProvider.java中。
在调用AwBrowserProcess类的静态成员函数start动Chromium渲染引擎的Browser端之前,WebViewChromiumFactoryProvider类的成员函数startChromiumLocked先会调用成员函数initPlatSupportLibrary向Chromium渲染引擎注册一个DrawGL函数,如下所示:
[java]viewplaincopy在CODE上查看代码片派生到我的代码片
publicclassWebViewChromiumFactoryProviderimplementsWebViewFactoryProvider{
......
privatevoidinitPlatSupportLibrary(){
DrawGLFunctor.setChromiumAwDrawGLFunction(AwContents.getAwDrawGLFunction());
......
}
......
}
这个函数定义在文件frameworks/webview/chromium/Java/com/android/webview/chromium/WebViewChromiumFactoryProvider.java中。
WebViewChromiumFactoryProvider类的成员函数startChromiumLocked首先会调用AwContents类的静态成员函数getAwDrawGLFunction获得要注册的DrawGL函数,然后再调用DrawGLFunctor类的静态成员函数setChromiumAwDrawGLFunction将它注册到Chromium渲染引擎中。
接下来,我们首先分析AwContents类的静态成员函数getAwDrawGLFunction获取要注册的DrawGL函数的过程,然后再分析DrawGLFunctor类的静态成员函数setChromiumAwDrawGLFunction注册DrawGL函数到Chromium渲染引擎的过程。
AwContents类的静态成员函数getAwDrawGLFunction的实现如下所示:
[java]viewplaincopy在CODE上查看代码片派生到我的代码片
publicclassAwContents{
......
publicstaticlonggetAwDrawGLFunction(){
returnnativeGetAwDrawGLFunction();
}
......
}
这个函数定义在文件external/chromium_org/android_webview/java/src/org/chromium/android_webview/AwContents.java中。
AwContents类的静态成员函数getAwDrawGLFunction调用另外一个静态成员函数AwContents类的静态成员函数获取要注册的的DrawGL函数的过程。
AwContents类的静态成员函数AwContents类的静态成员函数是一个JNI方法,它由C++层的函数Java_com_android_org_chromium_android_1webview_AwContents_nativeGetAwDrawGLFunction实现,如下所示:
[cpp]viewplaincopy在CODE上查看代码片派生到我的代码片
__attribute__((visibility("default")))
jlong
Java_com_android_org_chromium_android_1webview_AwContents_nativeGetAwDrawGLFunction(JNIEnv*
env,jclassjcaller){
returnGetAwDrawGLFunction(env,jcaller);
}
这个函数定义在文件out/target/product/generic/obj/GYP/shared_intermediates/android_webview/jni/AwContents_jni.h中。
函数Java_com_android_org_chromium_android_1webview_AwContents_nativeGetAwDrawGLFunction又通过调用另外一个函数GetAwDrawGLFunction获取要注册的DrawGL函数,如下所示:
[cpp]viewplaincopy在CODE上查看代码片派生到我的代码片
staticjlongGetAwDrawGLFunction(JNIEnv*env,jclass){
returnreinterpret_cast
}
这个函数定义在文件external/chromium_org/android_webview/native/aw_contents.cc中。
函数GetAwDrawGLFunction返回的是定义在同文件中的函数DrawGLFunction。
这个函数的地址将会返回到前面分析的WebViewChromiumFactoryProvider类的成员函数initPlatSupportLibrary向Chromium,后者再调用DrawGLFunctor类的静态成员函数setChromiumAwDrawGLFunction将它注册到Chromium渲染引擎中,如下所示:
[java]viewplaincopy在CODE上查看代码片派生到我的代码片
classDrawGLFunctor{
......
publicstaticvoidsetChromiumAwDrawGLFunction(longfunctionPointer){
nativeSetChromiumAwDrawGLFunction(functionPointer);
}
......
}
这个函数定义在文件frameworks/webview/chromium/java/com/android/webview/chromium/DrawGLFunctor.java中。
DrawGLFunctor类的静态成员函数setChromiumAwDrawGLFunction调用另外一个静态成员函数nativeSetChromiumAwDrawGLFunction将前面获得的函数DrawGLFunction注册在Chromium渲染引擎中。
DrawGLFunctor类的静态成员函数nativeSetChromiumAwDrawGLFunction是一个JNI方法,它由C++层的函数SetChromiumAwDrawGLFunction实现,如下所示:
[cpp]viewplaincopy在CODE上查看代码片派生到我的代码片
AwDrawGLFunction*g_aw_drawgl_function=NULL;
......
voidSetChromiumAwDrawGLFunction(JNIEnv*,jclass,jlongdraw_function){
g_aw_drawgl_function=reinterpret_cast
}
这个函数定义在文件frameworks/webview/chromium/plat_support/draw_gl_functor.cpp中。
函数SetChromiumAwDrawGLFunction将参数draw_function描述的函数DrawGLFunction的地址保存在全局变量g_aw_drawgl_function中。
这样,AndroidWebView就在启动Chromium渲染引擎的Browser端的过程中,向Chromium渲染引擎注册了一个DrawGL函数。
接下来,我们分析Chromium渲染引擎为Render端创建In-ProcessCommandBufferGL接口的过程。
Chromium渲染引擎为Render端创建的In-ProcessCommandBufferGL接口是封装在绘图表面(OutputSurface)里面的。
在Chromium中,每一个网页都关联一个OutputSurface。
在分析Render端的In-ProcessCommandBufferGL接口的创建之前,我们首先分析网页的OutputSurface的创建过程。
从前面Chromium网页绘图表面(OutputSurface)创建过程分析和Chromium的GPU进程启动过程分析这两篇文章可以知道,Render端在加载了网页之后,会为网页创建一个绘图表面,即一个OutputSurface,最终是通过调用RenderWidget类的成员函数CreateOutputSurface进行创建的,如下所示:
[cpp]viewplaincopy在CODE上查看代码片派生到我的代码片
scoped_ptr : OutputSurface>RenderWidget: : CreateOutputSurface(boolfallback){ ...... #ifdefined(OS_ANDROID) if(SynchronousCompositorFactory*factory= SynchronousCompositorFactory: : GetInstance()){ returnfactory->CreateOutputSurface(routing_id()); } #endif ...... } 这个函数定义在文件external/chromium_org/content/renderer/render_widget.cc中。 在Android平台上,RenderWidget类的成员函数CreateOutputSurface首先会调用SynchronousCompositorFactory类的静态成员函数GetInstance检查当前进程是否存在一个用来创建OutputSurface的工厂对象。 如果存在,那么就会调用它的成员函数CreateOutputSurface为当前加载的网页创建一个OutputSurface。 SynchronousCompositorFactory类的静态成员函数GetInstance的实现如下所示: [cpp]viewplaincopy在CODE上查看代码片派生到我的代码片 SynchronousCompositorFactory*g_instance=NULL; ...... voidSynchronousCompositorFactory: : SetInstance( SynchronousCompositorFactory*instance){ ...... g_instance=instance; } SynchronousCompositorFactory*SynchronousCompositorFactory: : GetInstance(){ returng_instance; } 这两个函数定义在文件external/chromium_org/content/renderer/android/synchronous_compositor_factory.cc。 SynchronousCompositorFactory类的静态成员函数GetInstance返回的是全局变量g_instance指向的一个SynchronousCompositorFactoryImpl对象。 这个SynchronousCompositorFactoryImpl对象是通过SynchronousCompositorFactory类的静态成员数SetInstance设置给全局变量g_instance的。 这个SynchronousCompositorFactoryImpl对象是什么时候设置给全局变量g_instance的呢? 回忆前面AndroidWebView启动Chromium渲染引擎的过程分析一文,AndroidWebView在启动Chromium渲染引擎的过程,会创建一个DeferredGpuCommandService服务,并且将这个DeferredGpuCommandService服务保存在一个SynchronousCompositorFactoryImpl对象的成员变量service_中。 这个SynchronousCompositorFactoryImpl对象在创建的过程中,就会通过调用SynchronousCompositorFactory类的静态成员数SetInstance将自己保存在上述全局变量g_instance中,如下所示: [cpp]viewplaincopy在CODE上查看代码片派生到我的代码片 SynchronousCompositorFactoryImpl: : SynchronousCompositorFactoryImpl() : record_full_layer_(true), num_hardware_compositors_(0){ SynchronousCompositorFactory: : SetInstance(this); } 这个函数定义在文件external/chromium_org/content/browser/android/in_process/synchronous_compositor_factory_impl.cc中。 回到前面分析的RenderWidget类的成员函数CreateOutputSurface中,这时候它调用SynchronousCompositorFactory类的静态成员函数GetInstance就会获得一个SynchronousCompositorFactoryImpl对象。 有了这个SynchronousCompositorFactoryImpl对象之后,RenderWidget类的成员函数CreateOutputSurface就会调用它的成员函数CreateOutputSurface为当前正在加载的网页创建一个OutputSurface,如下所示: [cpp]viewplaincopy在CODE上查看代码片派生到我的代码片 scoped_ptr : OutputSurface> Sync
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- Android WebView执行GPU命令的过程分析 WebView 执行 GPU 命令 过程 分析