满堂花醉三千客,一剑霜寒十四洲。这篇文章主要讲述Android WebView执行GPU命令的过程分析相关的知识,希望能为你提供帮助。
android WebView使用的Chromium引擎,
虽然没有自己的GPU进程或者线程,
但是却可以执行GPU命令。原来,
Android WebView会给它提供一个In-Process Command Buffer GL接口。通过这个接口,
Chromium引擎就可以将GPU命令提交给App的Render Thread执行。本文接下来就详细分析Android WebView执行GPU命令的过程。
老罗的新浪微博:
http://weibo.com/shengyangluo,
欢迎关注!
《Android系统源代码情景分析》一书正在进击的程序员网(
http://0xcc0xcd.com)
中连载,
点击进入!
从前面Chromium硬件加速渲染的OpenGL命令执行过程分析这篇文章可以知道,
Chromium渲染引擎在有自己的GPU进程或者线程的情况下,
是通过一个Command Buffer GL接口执行GPU命令的。这个Command Buffer GL接口通过一个GLES2Implementation类描述。Android WebView给Chromium引擎提供的In-Process Command Buffer GL接口,
同样是通过GLES2Implementation类描述的。这样,
Chromium渲染引擎就不用关心它发出的GPU命令是如何执行的。
在Chromium渲染引擎中,
需要执行GPU命令的是Render端和Browser端。Render端执行GPU命令是为渲染网页的UI,
而Browser端执行GPU命令是为了将Render端渲染的网页UI合成显示在屏幕上。对Android WebView来说,
它的Render端会将网页抽象成一个CC Layer Tree,
然后使用一个Synchronous Compositor将它渲染在一个Synchronous Compositor Output Surface上,
如图1所示:
文章图片
图1 Android WebView的Render端渲染网页UI的示意图
Android WebView的Browser端同样会将自己要合成的UI抽象为一个CC Layer Tree, 然后使用一个Hardware Renderer将它渲染在一个Parent Output Surface上, 如图2所示:
文章图片
图2 Android WebView的Browser端合成网页UI的示意图
Browser端的CC Layer Tree比较特别, 它只有两个节点。一个是根节点, 另一个是根节点的子节点, 称为Delegated Render Layer, 它要渲染的内容来自于Render端的渲染输出。从前面Chromium硬件加速渲染的UI合成过程分析一文可以知道, Render端的渲染输出是一系列的Render Pass。每一个Render Pass都包含了若干个纹理。这些纹理是在Render端光栅化网页时产生的。Browser端的Hardware Renderer所要做的事情就是将这些纹理渲染在屏幕上。这个过程也就是Browser端合成网页UI的过程。
不管是Render端, 还是Browser端, 当它们执行GPU命令的时候, 都是通过GLES2Implementation类描述的一个In-Process Command Buffer GL接口写入到一个Command Buffer中去的。只不过在Android WebView的情况下, 这些GPU命令会被一个DeferredGpuCommandService服务提交给App的Render Thread执行, 如图3所示:
文章图片
图3 Android WebView执行GPU命令的过程
Render端和Browser端将要执行的GPU命令写入到Command Buffer之后, 就会请求DeferredGpuCommandService服务在App的Render Thread中调度执行一个Task。这个Task绑定了InProcessCommandBuffer类的成员函数FlushOnGpuThread。InProcessCommandBuffer类的成员函数FlushOnGpuThread又是通过一个Gpu Scheduler按照上下文来执行请求的GPU命令, 并且这些GPU命令在执行之前, 先要经过一个GLES2 Decoder进行解码。这个过程可以参考前面Chromium硬件加速渲染的OpenGL命令执行过程分析一文。
对于Browser端来说, 它本来就是在App的Render Thread中请求执行GPU命令的。这时候DeferredGpuCommandService服务会直接在当前线程中调用InProcessCommandBuffer类的成员函数FlushOnGpuThread, 以便执行请求的GPU命令。
对于Render端来说, 它在两种情景下需要请求执行GPU命令。第一种情景是光栅化网页的UI, 第二种情景是绘制网页的UI。这两种情景都是发生在Render端的Compositor线程中。关于Render端的Compositor线程, 以及网页UI的光栅化和绘制操作, 可以参考前面Chromium网页渲染机制简要介绍和学习计划这个系列的文章。
上述两种情景都会将要执行的GPU操作抽象为一个DrawGLFunctor对象。对于第一个情景, DrawGLFunctor对象会通过App的UI线程直接提交给App的Render Thread。App的Render Thread再通知该DrawGLFunctor对象执行GPU操作。
对于第二个情景, DrawGLFunctor对象会被App的UI线程封装为一个DrawFunctorOp操作, 并且写入到App UI的Display List中。 接下来App的UI线程会将Display List同步给App的Render Thread。随后这个Display List就会被App的Render Thread通过一个OpenGL Renderer进行Replay, 这时候Display List中包含的DrawFunctorOp操作就会被执行。在执行的过程中, 与它关联的DrawGLFunctor对象获得通知。DrawGLFunctor对象获得通知以后就会执行之前Render端请求的GPU操作了。
DrawGLFunctor对象在执行GPU操作的时候, 会调用到一个DrawGL函数。这个DrawGL函数是Android WebView在启动Chromium渲染引擎时注册的。它在执行的过程中, 就会通过Browser端的Hardware Renderer通知DeferredGpuCommandService服务执行此前请求调度的Task。这时候InProcessCommandBuffer类的成员函数FlushOnGpuThread就会被调用, 这时候Render端之前请求的GPU命令就会被执行。
接下来, 我们就结合源码, 分析Chromium渲染引擎的Render端和Browser端创建In-Process Command Buffer GL接口的过程, 以及以Render端使用GPU光栅化网页的过程为例, 分析Chromium渲染引擎通过In-Process Command Buffer GL接口执行GPU命令的过程。不过, 在分析这些过程之前, 我们首先分析Android WebView向Chromium渲染引擎注册DrawGL函数的过程。这个过程发生在Android WebView启动Chromium渲染引擎的Browser端的过程中。
从前面Android WebView启动Chromium渲染引擎的过程分析一文可以知道, Android WebView在启动Chromium渲染引擎的Browser端的过程中, 会调用到WebViewChromiumFactoryProvider类的成员函数startChromiumLocked, 如下所示:
public class WebViewChromiumFactoryProvider implements WebViewFactoryProvider {
......private void startChromiumLocked() {
......initPlatSupportLibrary();
AwBrowserProcess.start(ActivityThread.currentApplication());
......
}......
}
这个函数定义在文件frameworks/webview/chromium/java/com/android/webview/chromium/WebViewChromiumFactoryProvider.java中。
在调用AwBrowserProcess类的静态成员函数start动Chromium渲染引擎的Browser端之前, WebViewChromiumFactoryProvider类的成员函数startChromiumLocked先会调用成员函数initPlatSupportLibrary向Chromium渲染引擎注册一个DrawGL函数, 如下所示:
public class WebViewChromiumFactoryProvider implements WebViewFactoryProvider {
......private void initPlatSupportLibrary() {
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的实现如下所示:
public class AwContents {
......public static long getAwDrawGLFunction() {
return nativeGetAwDrawGLFunction();
}......
}
这个函数定义在文件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实现, 如下所示:
__attribute__((visibility("
default"
)))
jlong
Java_com_android_org_chromium_android_1webview_AwContents_nativeGetAwDrawGLFunction(JNIEnv*
env, jclass jcaller) {
return GetAwDrawGLFunction(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函数, 如下所示:
static jlong GetAwDrawGLFunction(JNIEnv* env, jclass) {
return reinterpret_cast<
intptr_t>
(&
DrawGLFunction);
}
这个函数定义在文件external/chromium_org/android_webview/native/aw_contents.cc中。
函数GetAwDrawGLFunction返回的是定义在同文件中的函数DrawGLFunction。这个函数的地址将会返回到前面分析的WebViewChromiumFactoryProvider类的成员函数initPlatSupportLibrary向Chromium, 后者再调用DrawGLFunctor类的静态成员函数setChromiumAwDrawGLFunction将它注册到Chromium渲染引擎中, 如下所示:
class DrawGLFunctor {
......public static void setChromiumAwDrawGLFunction(long functionPointer) {
nativeSetChromiumAwDrawGLFunction(functionPointer);
}......
}
这个函数定义在文件frameworks/webview/chromium/java/com/android/webview/chromium/DrawGLFunctor.java中。
DrawGLFunctor类的静态成员函数setChromiumAwDrawGLFunction调用另外一个静态成员函数nativeSetChromiumAwDrawGLFunction将前面获得的函数DrawGLFunction注册在Chromium渲染引擎中。
DrawGLFunctor类的静态成员函数nativeSetChromiumAwDrawGLFunction是一个JNI方法, 它由C+ + 层的函数SetChromiumAwDrawGLFunction实现, 如下所示:
AwDrawGLFunction* g_aw_drawgl_function =
NULL;
......void SetChromiumAwDrawGLFunction(JNIEnv*, jclass, jlong draw_function) {
g_aw_drawgl_function =
reinterpret_cast<
AwDrawGLFunction*>
(draw_function);
}
这个函数定义在文件frameworks/webview/chromium/plat_support/draw_gl_functor.cpp中。
【Android WebView执行GPU命令的过程分析】函数SetChromiumAwDrawGLFunction将参数draw_function描述的函数DrawGLFunction的地址保存在全局变量g_aw_drawgl_function中。这样, Android WebView就在启动Chromium渲染引擎的Browser端的过程中, 向Chromium渲染引擎注册了一个DrawGL函数。
接下来, 我们分析Chromium渲染引擎为Render端创建In-Process Command Buffer GL接口的过程。Chromium渲染引擎为Render端创建的In-Process Command Buffer GL接口是封装在绘图表面( Output Surface) 里面的。在Chromium中, 每一个网页都关联一个Output Surface。在分析Render端的In-Process Command Buffer GL接口的创建之前, 我们首先分析网页的Output Surface的创建过程。
从前面Chromium网页绘图表面( Output Surface) 创建过程分析和Chromium的GPU进程启动过程分析这两篇文章可以知道, Render端在加载了网页之后, 会为网页创建一个绘图表面, 即一个Output Surface, 最终是通过调用RenderWidget类的成员函数CreateOutputSurface进行创建的, 如下所示:
scoped_ptr<
cc::OutputSurface>
RenderWidget::CreateOutputSurface(bool fallback) {
......#if defined(OS_ANDROID)
if (SynchronousCompositorFactory* factory =
SynchronousCompositorFactory::GetInstance()) {
return factory->
CreateOutputSurface(routing_id());
}
#endif......
}
这个函数定义在文件external/chromium_org/content/renderer/render_widget.cc中。
在Android平台上, RenderWidget类的成员函数CreateOutputSurface首先会调用SynchronousCompositorFactory类的静态成员函数GetInstance检查当前进程是否存在一个用来创建Output Surface的工厂对象。如果存在, 那么就会调用它的成员函数CreateOutputSurface为当前加载的网页创建一个Output Surface。
SynchronousCompositorFactory类的静态成员函数GetInstance的实现如下所示:
SynchronousCompositorFactory* g_instance =
NULL;
......void SynchronousCompositorFactory::SetInstance(
SynchronousCompositorFactory* instance) {
......g_instance =
instance;
}SynchronousCompositorFactory* SynchronousCompositorFactory::GetInstance() {
return g_instance;
}
这两个函数定义在文件external/chromium_org/content/renderer/android/synchronous_compositor_factory.cc。
SynchronousCompositorFactory类的静态成员函数GetInstance返回的是全局变量g_instance指向的一个SynchronousCompositorFactoryImpl对象。这个SynchronousCompositorFactoryImpl对象是通过SynchronousCompositorFactory类的静态成员数SetInstance设置给全局变量g_instance的。
这个SynchronousCompositorFactoryImpl对象是什么时候设置给全局变量g_instance的呢? 回忆前面Android WebView启动Chromium渲染引擎的过程分析一文, Android WebView在启动Chromium渲染引擎的过程, 会创建一个DeferredGpuCommandService服务, 并且将这个DeferredGpuCommandService服务保存在一个SynchronousCompositorFactoryImpl对象的成员变量service_中。这个SynchronousCompositorFactoryImpl对象在创建的过程中, 就会通过调用SynchronousCompositorFactory类的静态成员数SetInstance将自己保存在上述全局变量g_instance中, 如下所示:
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为当前正在加载的网页创建一个Output Surface, 如下所示:
scoped_ptr<
cc::OutputSurface>
SynchronousCompositorFactoryImpl::CreateOutputSurface(int routing_id) {
scoped_ptr<
SynchronousCompositorOutputSurface>
output_surface(
new SynchronousCompositorOutputSurface(routing_id));
return output_surface.PassAs<
cc::OutputSurface>
();
}
这个函数定义在文件external/chromium_org/content/browser/android/in_process/synchronous_compositor_factory_impl.cc中。
SynchronousCompositorFactoryImpl类的成员函数CreateOutputSurface创建一个类型为Synchronous Compositor的Output Surface返回给调用者。从前面Chromium网页绘图表面( Output Surface) 创建过程分析一文可以知道, 这个Synchronous Compositor Output Surface将会返回给ThreadProxy类的成员函数CreateAndInitializeOutputSurface, 如下所示:
void ThreadProxy::CreateAndInitializeOutputSurface() {
......scoped_ptr<
OutputSurface>
output_surface =
layer_tree_host()->
CreateOutputSurface();
if (output_surface) {
Proxy::ImplThreadTaskRunner()->
PostTask(
FROM_HERE,
base::Bind(&
ThreadProxy::InitializeOutputSurfaceOnImplThread,
impl_thread_weak_ptr_,
base::Passed(&
output_surface)));
return;
}......
}
这个函数定义在文件external/chromium_org/cc/trees/thread_proxy.cc中。
ThreadProxy类的成员函数CreateAndInitializeOutputSurface又会将这个Synchronous Compositor Output Surface传递给Render端的Compositor线程, 让后者对它进行初始化。这个初始化操作是通过在Render端的Compositor线程中调用ThreadProxy类的成员函数InitializeOutputSurfaceOnImplThread实现的。
从前面Chromium网页绘图表面( Output Surface) 创建过程分析一文可以知道, ThreadProxy类的成员函数InitializeOutputSurfaceOnImplThread在初始化Synchronous Compositor Output Surface的过程中, 会调用它的成员函数BindToClient, 表示它已经被设置给一个网页使用。
SynchronousCompositorOutputSurface类的成员函数BindToClient的实现如下所示:
bool SynchronousCompositorOutputSurface::BindToClient(
cc::OutputSurfaceClient* surface_client) {
......SynchronousCompositorOutputSurfaceDelegate* delegate =
GetDelegate();
if (delegate)
delegate->
DidBindOutputSurface(this);
return true;
}
这个函数定义在文件external/chromium_org/content/browser/android/in_process/synchronous_compositor_output_surface.cc中。
SynchronousCompositorOutputSurface类的成员函数BindToClient会调用另外一个成员函数GetDelegate获得一个Delegate对象, 如下所示:
SynchronousCompositorOutputSurfaceDelegate*
SynchronousCompositorOutputSurface::GetDelegate() {
return SynchronousCompositorImpl::FromRoutingID(routing_id_);
}
这个函数定义在文件external/chromium_org/content/browser/android/in_process/synchronous_compositor_output_surface.cc中。
SynchronousCompositorOutputSurface类的成员函数GetDelegate通过调用SynchronousCompositorImpl类的静态成员函数FromRoutingID获得一个Delegate对象, 如下所示:
SynchronousCompositorImpl* SynchronousCompositorImpl::FromRoutingID(
int routing_id) {
return FromID(GetInProcessRendererId(), routing_id);
}
这个函数定义在文件external/chromium_org/content/browser/android/in_process/synchronous_compositor_impl.cc中。
SynchronousCompositorImpl类的静态成员函数FromRoutingID首先会调用静态成员函数GetInProcessRendererId获得当前正在处理的Render端的ID。有了这个ID之后, 连同参数routing_id描述的网页ID, 传递给SynchronousCompositorImpl类的另外一个静态成员函数FromID, 如下所示:
SynchronousCompositorImpl* SynchronousCompositorImpl::FromID(int process_id,
int routing_id) {
......
RenderViewHost* rvh =
RenderViewHost::FromID(process_id, routing_id);
......
WebContents* contents =
WebContents::FromRenderViewHost(rvh);
......
return FromWebContents(contents);
}
这个函数定义在文件external/chromium_org/content/browser/android/in_process/synchronous_compositor_impl.cc中。
SynchronousCompositorImpl类的静态成员函数FromID首先通过调用RenderViewHost类的静态成员函数FromID获得与参数process_id和routing_id对应的一个RenderViewHost对象。这个RenderViewHost对象用来在Browser端描述的一个网页。这个网页就是当前正在Android WebView中加载的网页。
获得了与当前正在加载的网页对应的RenderViewHost对象之后, 就可以调用WebContents类的静态成员函数FromRenderViewHost获得一个WebContents对象。在Chromium中, 每一个网页在Content层又都是通过一个WebContents对象描述的。这个WebContents对象的创建过程可以参考前面Android WebView启动Chromium渲染引擎的过程分析一文。
获得了用来描述当前正在加载的网页的WebContents对象之后, SynchronousCompositorImpl类的静态成员函数FromID就可以调用另外一个静态成员函数FromWebContents获得一个SynchronousCompositorImpl对象。这个SynchronousCompositorImpl对象的创建过程可以参考前面Android WebView启动Chromium渲染引擎的过程分析一文, 它是负责用来渲染在Android WebView中加载的网页的UI的。
SynchronousCompositorImpl类的静态成员函数FromID最后会将获得的SynchronousCompositorImpl对象返回给调用者, 也就是前面分析的SynchronousCompositorOutputSurface类的成员函数BindToClient。SynchronousCompositorOutputSurface类的成员函数BindToClient接下来会调用这个SynchronousCompositorImpl对象的成员函数DidBindOutputSurface, 表示它现在已经与一个Synchronous Compositor Output Surface建立了绑定关系, 这样以后它就可以将网页的UI渲染在这个Synchronous Compositor Output Surface之上。
SynchronousCompositorImpl类的成员函数DidBindOutputSurface的实现如下所示:
void SynchronousCompositorImpl::DidBindOutputSurface(
SynchronousCompositorOutputSurface* output_surface) {
......
output_surface_ =
output_surface;
if (compositor_client_)
compositor_client_->
DidInitializeCompositor(this);
}
这个函数定义在文件external/chromium_org/content/browser/android/in_process/synchronous_compositor_impl.cc中。
SynchronousCompositorImpl类的成员函数DidBindOutputSurface首先将参数output_surface描述的Synchronous Compositor Output Surface保存在成员变量output_surface_中。
从前面Android WebView启动Chromium渲染引擎的过程分析一文可以知道, SynchronousCompositorImpl类的成员变量compositor_client_指向的是一个BrowserViewRenderer对象。SynchronousCompositorImpl类的成员函数DidBindOutputSurface最后会调用这个BrowserViewRenderer对象的成员函数DidInitializeCompositor, 表示Chromium渲染引擎已经为它创建了一个用来渲染网页UI的Synchronous Compositor, 如下所示:
void BrowserViewRenderer::DidInitializeCompositor(
content::SynchronousCompositor* compositor) {
......compositor_ =
compositor;
}
这个函数定义在文件external/chromium_org/android_webview/browser/browser_view_renderer.cc中。
BrowserViewRenderer类的成员函数DidInitializeCompositor会将参数compositor指向的一个SynchronousCompositorImpl对象保存在成员变量compositor_中。
这一步执行完成之后, Chromium渲染引擎就为在Render端加载的网页创建了一个Synchronous Compositor Output Surface, 并且会将这个Synchronous Compositor Output Surface设置给一个Synchronous Compositor。这个Synchronous Compositor又会设置给一个BrowserViewRenderer对象。这个BrowserViewRenderer对象负责绘制Android WebView的UI。
接下来我们就开始分析Chromium渲染引擎为Render端创建In-Process Command Buffer GL接口的过程。这个In-Process Command Buffer GL接口是在Android WebView第一次执行硬件加速渲染之前创建的。从前面Android WebView启动Chromium渲染引擎的过程分析一文可以知道, Android WebView每次被绘制时, 它在Chromium的android_webview模块中对应的AwContents对象的成员函数OnDraw都会被调用, 如下所示:
bool AwContents::OnDraw(JNIEnv* env,
jobject obj,
jobject canvas,
jboolean is_hardware_accelerated,
jint scroll_x,
jint scroll_y,
jint visible_left,
jint visible_top,
jint visible_right,
jint visible_bottom) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
if (is_hardware_accelerated)
InitializeHardwareDrawIfNeeded();
return browser_view_renderer_.OnDraw(
canvas,
is_hardware_accelerated,
gfx::Vector2d(scroll_x, scroll_y),
gfx::Rect(visible_left,
visible_top,
visible_right - visible_left,
visible_bottom - visible_top));
}
这个函数定义在文件external/chromium_org/android_webview/native/aw_contents.cc。
如果执行的是硬件加速渲染, 那么AwContents类的成员函数OnDraw首先会调用另外一个成员函数InitializeHardwareDrawIfNeeded检查当前是否已经创建了一个DeferredGpuCommandService服务。如果还没有创建, 那么就会进行创建。这个DeferredGpuCommandService服务的创建过程可以参考前面Android WebView启动Chromium渲染引擎的过程分析一文。
AwContents类的成员函数OnDraw接下来会调用成员变量browser_view_renderer_描述的一个BrowserViewRenderer对象的成员函数OnDraw执行硬件加速渲染, 如下所示:
bool BrowserViewRenderer::OnDraw(jobject java_canvas,
bool is_hardware_canvas,
const gfx::Vector2d&
scroll,
const gfx::Rect&
global_visible_rect) {
......if (is_hardware_canvas &
&
attached_to_window_)
return OnDrawHardware(java_canvas);
// Perform a software draw
return OnDrawSoftware(java_canvas);
}
这个函数定义在文件external/chromium_org/android_webview/browser/browser_view_renderer.cc中。
在执行硬件加速渲染的情况下, BrowserViewRenderer对象的成员函数OnDraw会调用成员函数OnDrawHardware对Android WebView进行绘制, 如下所示:
bool BrowserViewRenderer::OnDrawHardware(jobject java_canvas) {
......if (!hardware_enabled_) {
hardware_enabled_ =
compositor_->
InitializeHwDraw();
......
}......scoped_ptr<
DrawGLInput>
draw_gl_input(new DrawGLInput);
......scoped_ptr<
cc::CompositorFrame>
frame =
compositor_->
DemandDrawHw(surface_size,
gfx::Transform(),
viewport,
clip,
viewport_rect_for_tile_priority,
transform_for_tile_priority);
......shared_renderer_state_->
SetDrawGLInput(draw_gl_input.Pass());
......
return client_->
RequestDrawGL(java_canvas, false);
}
这个函数定义在文件external/chromium_org/android_webview/browser/browser_view_renderer.cc中。
当BrowserViewRenderer类的成员变量hardware_enabled_的值等于false时, 表示Android WebView是第一次启用硬件加速渲染。在这种情况下, BrowserViewRenderer类的函数OnDraw首先会初始化一个硬件加速渲染环境, 然后再对Android WebView进行绘制。
从前面的分析可以知道, BrowserViewRenderer类的成员变量compositor_指向的是一个SynchronousCompositorImpl对象。BrowserViewRenderer类的函数OnDraw就是通过调用这个SynchronousCompositorImpl对象的成员函数InitializeHwDraw初始化一个硬件加速渲染环境的。在初始化这个硬件加速渲染环境的过程中, 就会创建一个In-Process Command Buffer GL接口。
接下来, 我们就继续分析SynchronousCompositorImpl类的成员函数InitializeHwDraw初始化创建In-Process Command Buffer GL接口的过程。在接下来一篇文章中, 我们再分析BrowserViewRenderer类的函数OnDraw绘制Android WebView的过程。
SynchronousCompositorImpl类的成员函数InitializeHwDraw的实现如下所示:
base::LazyInstance<
SynchronousCompositorFactoryImpl>
::Leaky g_factory =
LAZY_INSTANCE_INITIALIZER;
......bool SynchronousCompositorImpl::InitializeHwDraw() {
......scoped_refptr<
cc::ContextProvider>
onscreen_context =
g_factory.Get().CreateOnscreenContextProviderForCompositorThread();
bool success =
output_surface_->
InitializeHwDraw(onscreen_context);
......
return success;
}
这个函数定义在文件external/chromium_org/content/browser/android/in_process/synchronous_compositor_impl.cc中。
全局变量指向的就是前面提到的用来为网页创建Output Surface的SynchronousCompositorFactoryImpl对象。SynchronousCompositorImpl类的成员函数InitializeHwDraw调用这个SynchronousCompositorFactoryImpl对象的成员函数CreateOnscreenContextProviderForCompositorThread创建一个硬件加速渲染环境。
创建出来的硬件加速渲染环境是通过一个ContextProviderInProcess对象描述的。这个ContextProviderInProcess对象又会设置给SynchronousCompositorImpl类的成员变量output_surface_描述的一个Synchronous Compositor Output Surface。Synchronous Compositor Output Surface有了硬件加速渲染环境之后, 就可以执行GPU命令了。
接下来, 我们首先分析SynchronousCompositorFactoryImpl类的成员函数CreateOnscreenContextProviderForCompositorThread创建硬件加速渲染环境的过程, 如下所示:
scoped_refptr<
cc::ContextProvider>
SynchronousCompositorFactoryImpl::
CreateOnscreenContextProviderForCompositorThread() {
......
return webkit::gpu::ContextProviderInProcess::Create(
WrapContext(CreateContext(service_, share_context_.get())),
"
Child-Compositor"
);
}
这个函数定义在文件external/chromium_org/content/browser/android/in_process/synchronous_compositor_factory_impl.cc中。
SynchronousCompositorFactoryImpl类的成员函数CreateOnscreenContextProviderForCompositorThread首先调有函数CreateContext创建一个In-Process Command Buffer GL接口, 然后再调用另外一个函数WrapContext将这个In-Process Command Buffer GL接口封装在一个WebGraphicsContext3DInProcessCommandBufferImpl对象, 最后调用ContextProviderInProcess类的静态成员函数Create将该WebGraphicsContext3DInProcessCommandBufferImpl对象封装在一个ContextProviderInProcess对象中。
从前面Android WebView启动Chromium渲染引擎的过程分析一文可以知道, SynchronousCompositorFactoryImpl类的成员变量service_指向的就是一个DeferredGpuCommandService服务。函数CreateContext在创建In-Process Command Buffer GL接口的时候, 会使用到这个DeferredGpuCommandService服务, 如下所示:
scoped_ptr<
gpu::GLInProcessContext>
CreateContext(
scoped_refptr<
gpu::InProcessCommandBuffer::Service>
service,
gpu::GLInProcessContext* share_context) {
......scoped_ptr<
gpu::GLInProcessContext>
context(
gpu::GLInProcessContext::Create(service,
NULL /* surface */,
false /* is_offscreen */,
gfx::kNullAcceleratedWidget,
gfx::Size(1, 1),
share_context,
false /* share_resources */,
in_process_attribs,
gpu_preference));
return context.Pass();
}
这个函数定义在文件external/chromium_org/content/browser/android/in_process/synchronous_compositor_factory_impl.cc中。
函数调用GLInProcessContext类的静态成员函数Create创建了一个In-Process Command Buffer GL接口, 如下所示:
GLInProcessContext* GLInProcessContext::Create(
scoped_refptr<
gpu::InProcessCommandBuffer::Service>
service,
scoped_refptr<
gfx::GLSurface>
surface,
bool is_offscreen,
gfx::AcceleratedWidget window,
const gfx::Size&
size,
GLInProcessContext* share_context,
bool use_global_share_group,
const GLInProcessContextAttribs&
attribs,
gfx::GpuPreference gpu_preference) {
......scoped_ptr<
GLInProcessContextImpl>
context(new GLInProcessContextImpl());
if (!context->
Initialize(surface,
is_offscreen,
use_global_share_group,
share_context,
window,
size,
attribs,
gpu_preference,
service))
return NULL;
return context.release();
}
这个函数定义在文件external/chromium_org/gpu/command_buffer/client/gl_in_process_context.cc中。
GLInProcessContext类的静态成员函数Create首先创建了一个GLInProcessContextImpl对象, 然后调用这个GLInProcessContextImpl对象的成员函数Initialize对其进行初始化。在初始化的过程中, 就会创建一个In-Process Command Buffer GL接口, 如下所示:
bool GLInProcessContextImpl::Initialize(
scoped_refptr<
gfx::GLSurface>
surface,
bool is_offscreen,
bool use_global_share_group,
GLInProcessContext* share_context,
gfx::AcceleratedWidget window,
const gfx::Size&
size,
const GLInProcessContextAttribs&
attribs,
gfx::GpuPreference gpu_preference,
const scoped_refptr<
InProcessCommandBuffer::Service>
&
service) {
......command_buffer_.reset(new InProcessCommandBuffer(service));
......if (!command_buffer_->
Initialize(surface,
is_offscreen,
window,
size,
attrib_vector,
gpu_preference,
wrapped_callback,
share_command_buffer)) {
......
return false;
}// Create the GLES2 helper, which writes the command buffer protocol.
gles2_helper_.reset(new gles2::GLES2CmdHelper(command_buffer_.get()));
......// Create the object exposing the OpenGL API.
gles2_implementation_.reset(new gles2::GLES2Implementation(
gles2_helper_.get(),
share_group,
transfer_buffer_.get(),
bind_generates_resources,
attribs.lose_context_when_out_of_memory >
0,
command_buffer_.get()));
......return true;
}
这个函数定义在文件external/chromium_org/gpu/command_buffer/client/gl_in_process_context.cc中。
GLInProcessContextImpl类的成员函数Initialize创建In-Process Command Buffer GL接口的过程与前面Chromium硬件加速渲染的OpenGL命令执行过程分析一文提到的Command Buffer GL接口的创建过程是类似的。首先是创建一个Command Buffer, 然后再将该Command Buffer封装在一个GLES2CmdHelper对象中。以后通过个GLES2CmdHelper对象就可以将要执行的GPU命令写入到它封装的Command Buffer中去。最后又会使用前面封装得到的GLES2CmdHelper对象创建一个GLES2Implementation对象。这个GLES2Implementation对象就用来描述的一个In-Process Command Buffer GL或者Command Buffer GL接口。
In-Process Command Buffer GL接口与Command Buffer GL接口的最大区别就在于它们使用了不同的Command Buffer。In-Process Command Buffer GL使用的Command Buffer是一个In-Process Command Buffer, 而Command Buffer GL接口使用的Command Buffer是一个Command Buffer Proxy。In-Process Command Buffer会将要执行的GPU命令发送给App的Render Thread处理, 而Command Buffer Proxy会将要执行的GPU命令发送给Chromium的GPU进程/线程处理。
接下来, 我们就重点分析In-Process Command Buffer的创建过程, 以便后面可以更好地理解它是怎么将要执行的GPU命令发送给App的Render Thread处理的。
从前面的调用过程可以知道, 参数service描述的是一个DeferredGpuCommandService服务。这个DeferredGpuCommandService服务将会用来创建In-Process Command Buffer, 如下所示:
InProcessCommandBuffer::InProcessCommandBuffer(
const scoped_refptr<
Service>
&
service)
: ......,
service_(service.get() ? service : GetDefaultService()),
...... {
......
}
这个函数定义在文件external/chromium_org/gpu/command_buffer/service/in_process_command_buffer.cc中。
在创建In-Process Command Buffer的过程中, 如果指定了一个Service, 那么以后就会通过这个Service执行GPU命令。在我们这个情景中, 指定的Service即为一个DeferredGpuCommandService服务。因此, 这时候InProcessCommandBuffer类的成员变量service_指向的是一个DeferredGpuCommandService服务。
如果在创建In-Process Command Buffer的过程中, 没有指定一个Service, 那么InProcessCommandBuffer的构造函数就会通过调用另外一个成员函数GetDefaultService获得一个默认的Service, 用来执行GPU命令。这个默认的Service实际上就是一个自行创建的GPU线程。
回到GLInProcessContextImpl类的成员函数Initialize中, 它创建了一个In-Process Command Buffer之后, 接下来还会调用这个InProcessCommandBuffer类的成员函数Initialize对它进行初始化, 如下所示:
bool InProcessCommandBuffer::Initialize(
scoped_refptr<
gfx::GLSurface>
surface,
bool is_offscreen,
gfx::AcceleratedWidget window,
const gfx::Size&
size,
const std::vector<
int32>
&
attribs,
gfx::GpuPreference gpu_preference,
const base::Closure&
context_lost_callback,
InProcessCommandBuffer* share_group) {
......gpu::Capabilities capabilities;
InitializeOnGpuThreadParams params(is_offscreen,
window,
size,
attribs,
gpu_preference,
&
capabilities,
share_group);
base::Callback<
bool(void)>
init_task =
base::Bind(&
InProcessCommandBuffer::InitializeOnGpuThread,
base::Unretained(this),
params);
base::WaitableEvent completion(true, false);
bool result =
false;
QueueTask(
base::Bind(&
RunTaskWithResult<
bool>
, init_task, &
result, &
completion));
completion.Wait();
......
return result;
}
这个函数定义在文件external/chromium_org/gpu/command_buffer/service/in_process_command_buffer.cc中。
InProcessCommandBuffer类的成员函数Initialize所做的事情就是通过成员变量service_指向的DeferredGpuCommandService服务请求在App的Render Thread中调用InProcessCommandBuffer类的成员函数InitializeOnGpuThread, 以便对当前正在创建的In-Process Command Buffer进行初始化。
后面分析Render端执行的GPU命令的过程时, 我们就会清楚地看到DeferredGpuCommandService服务是如何请求在App的Render Thread执行一个操作的。现在我们主要关注In-Process Command Buffer的初始化过程, 也就是InProcessCommandBuffer类的成员函数InitializeOnGpuThread的实现, 如下所示:
bool InProcessCommandBuffer::InitializeOnGpuThread(
const InitializeOnGpuThreadParams&
params) {
......scoped_ptr<
CommandBufferService>
command_buffer(
new CommandBufferService(transfer_buffer_manager_.get()));
command_buffer->
SetPutOffsetChangeCallback(base::Bind(
&
InProcessCommandBuffer::PumpCommands, gpu_thread_weak_ptr_));
......decoder_.reset(gles2::GLES2Decoder::Create(
params.context_group
? params.context_group->
decoder_->
GetContextGroup()
: new gles2::ContextGroup(NULL,
NULL,
NULL,
service_->
shader_translator_cache(),
NULL,
bind_generates_resource)));
gpu_scheduler_.reset(
new GpuScheduler(command_buffer.get(), decoder_.get(), decoder_.get()));
......
command_buffer_ =
command_buffer.Pass();
decoder_->
set_engine(gpu_scheduler_.get());
......
}
这个函数定义在文件external/chromium_org/gpu/command_buffer/service/in_process_command_buffer.cc中。
InProcessCommandBuffer类的成员函数InitializeOnGpuThread首先是创建了一个Command Buffer Service, 并且保存在成员变量command_buffer_中。这个Command Buffer Service负责管理Command Buffer的状态, 例如第一个等待执行的GPU命令的位置, 以及最新写入的GPU命令的位置, 等等。
InProcessCommandBuffer类的成员函数InitializeOnGpuThread创建了一个Command Buffer Service, 会调用它的成员函数SetPutOffsetChangeCallback, 用来设置一个Put Offset Change Callback, 如下所示:
void CommandBufferService::SetPutOffsetChangeCallback(
const base::Closure&
callback) {
put_offset_change_callback_ =
callback;
}
这个函数定义在文件external/chromium_org/gpu/command_buffer/service/command_buffer_service.cc中。
这个Callback指定为当前正在创建的In-Process Command Buffer的成员函数PumpCommands。当我们往Command Buffer写入了新的GPU命令时, 这个Callback就会被执行, 也就是InProcessCommandBuffer类的成员函数PumpCommands会被调用。
InProcessCommandBuffer类的成员函数PumpCommands在调用的过程中, 就会通过一个Gpu Scheduler和一个GLES2 Decoder执行新写入到Command Buffer中的GPU命令。Gpu Scheduler在执行一个GPU命令之前, 会将当前的OpenGL上下文切换至该GPU命令所属的OpenGL上下文, 这样它就可以同时支持多个OpenGL上下文。GLES2 Decoder负责从Command Buffer中解析出每一个待执行的GPU命令及其携带的参数, 这样就可以通过调用对应的OpenGL函数执行它们。关于Gpu Scheduler和一个GLES2 Decoder执行GPU命令的过程, 可以参考前面Chromium硬件加速渲染的OpenGL命令执行过程分析一文。
回到前面分析的InProcessCommandBuffer类的成员函数InitializeOnGpuThread中, 上述Gpu Scheduler和GLES2 Decoder也是在InProcessCommandBuffer类的成员函数InitializeOnGpuThread中创建的。创建出来之后, 就分别保存在InProcessCommandBuffer类的成员变量gpu_scheduler_和decoder_中。
这一步执行完成后, 回到前面分析的SynchronousCompositorFactoryImpl类的成员函数CreateOnscreenContextProviderForCompositorThread中, 这时候它就获得了一个In-Process Command Buffer GL接口。这个In-Process Command Buffer GL接口是封装在一个GLInProcessContextImpl对象中的。这个GLInProcessContextImpl对象接下来又会通过函数WrapContext封装在一个WebGraphicsContext3DInProcessCommandBufferImpl对象中, 如下所示:
scoped_ptr<
WebGraphicsContext3DInProcessCommandBufferImpl>
WrapContext(
scoped_ptr<
gpu::GLInProcessContext>
context) {
......return scoped_ptr<
WebGraphicsContext3DInProcessCommandBufferImpl>
(
WebGraphicsContext3DInProcessCommandBufferImpl::WrapContext(
context.Pass(), GetDefaultAttribs()));
}
这个函数定义在文件external/chromium_org/content/browser/android/in_process/synchronous_compositor_factory_impl.cc中。
函数WrapContext通过调用WebGraphicsContext3DInProcessCommandBufferImpl类的静态成员函数WrapContext将一个GLInProcessContextImpl对象封装在一个WebGraphicsContext3DInProcessCommandBufferImpl对象中, 如下所示:
scoped_ptr<
WebGraphicsContext3DInProcessCommandBufferImpl>
WebGraphicsContext3DInProcessCommandBufferImpl::WrapContext(
scoped_ptr<
::gpu::GLInProcessContext>
context,
const blink::WebGraphicsContext3D::Attributes&
attributes) {
bool lose_context_when_out_of_memory =
false;
// Not used.
bool is_offscreen =
true;
// Not used.
return make_scoped_ptr(new WebGraphicsContext3DInProcessCommandBufferImpl(
context.Pass(),
attributes,
lose_context_when_out_of_memory,
is_offscreen,
gfx::kNullAcceleratedWidget /* window. Not used. */));
}
这个函数定义在文件external/chromium_org/webkit/common/gpu/webgraphicscontext3d_in_process_command_buffer_impl.cc中。
WebGraphicsContext3DInProcessCommandBufferImpl类的构造函数会将要封装的GLInProcessContextImpl对象保存在成员变量context_中, 如下所示:
WebGraphicsContext3DInProcessCommandBufferImpl::
WebGraphicsContext3DInProcessCommandBufferImpl(
scoped_ptr<
::gpu::GLInProcessContext>
context,
const blink::WebGraphicsContext3D::Attributes&
attributes,
bool lose_context_when_out_of_memory,
bool is_offscreen,
gfx::AcceleratedWidget window)
: ......,
context_(context.Pass()) {
......
}
这个函数定义在文件external/chromium_org/webkit/common/gpu/webgraphicscontext3d_in_process_command_buffer_impl.cc中。
这一步执行完成后, 继续回到前面分析的SynchronousCompositorFactoryImpl类的成员函数CreateOnscreenContextProviderForCompositorThread中, 这时候它就获得了一个WebGraphicsContext3DInProcessCommandBufferImpl对象。这个WebGraphicsContext3DInProcessCommandBufferImpl对象通过一个GLInProcessContextImpl对象间接地保存了前面创建的In-Process Command Buffer GL接口
SynchronousCompositorFactoryImpl类的成员函数CreateOnscreenContextProviderForCompositorThread最后又会调用ContextProviderInProcess类的静态成员函数Create将上述WebGraphicsContext3DInProcessCommandBufferImpl对象封装在一个ContextProviderInProcess对象中, 如下所示:
scoped_refptr<
ContextProviderInProcess>
ContextProviderInProcess::Create(
scoped_ptr<
WebGraphicsContext3DInProcessCommandBufferImpl>
context3d,
const std::string&
debug_name) {
......
return new ContextProviderInProcess(context3d.Pass(), debug_name);
}
这个函数定义在文件external/chromium_org/webkit/common/gpu/context_provider_in_process.cc中。
ContextProviderInProcess对象会将要封装的WebGraphicsContext3DInProcessCommandBufferImpl对象保存在成员变量context_中, 如下所示:
ContextProviderInProcess::ContextProviderInProcess(
scoped_ptr<
WebGraphicsContext3DInProcessCommandBufferImpl>
context3d,
const std::string&
debug_name)
: context3d_(context3d.Pass()),
...... {
......
}
这个函数定义在文件external/chromium_org/webkit/common/gpu/context_provider_in_process.cc中。
这一步执行完成后, SynchronousCompositorImpl类的成员函数InitializeHwDraw, 这时候它就是初始化了一个硬件加速渲染环境。这个硬件加速渲染环境就是通过前面创建的ContextProviderInProcess对象描述。这个ContextProviderInProcess对象接来会设置给SynchronousCompositorImpl类的成员变量output_surface_描述的一个Synchronous Compositor Output Surface。这是通过调用SynchronousCompositorOutputSurface类的成员函数InitializeHwDraw实现的, 如下所示:
bool SynchronousCompositorOutputSurface::InitializeHwDraw(
scoped_refptr<
cc::ContextProvider>
onscreen_context_provider) {
......return InitializeAndSetContext3d(onscreen_context_provider);
}
这个函数定义在文件external/chromium_org/content/browser/android/in_process/synchronous_compositor_output_surface.cc中。
SynchronousCompositorOutputSurface类的成员函数InitializeHwDraw会调用另外一个成员函数InitializeAndSetContext3d将参数onscreen_context_provider指向的ContextProviderInProcess对象保存在内部。以后通过这个ContextProviderInProcess对象, 就可以获得前面创建的In-Process Command Buffer GL接口了。
SynchronousCompositorOutputSurface类的成员函数InitializeAndSetContext3d是从父类OutputSurface继承下来的, 它的实现如下所示:
bool OutputSurface::InitializeAndSetContext3d(
scoped_refptr<
ContextProvider>
context_provider) {
......bool success =
false;
if (context_provider->
BindToCurrentThread()) {
context_provider_ =
context_provider;
......
success =
true;
}......return success;
}
这个函数定义在文件external/chromium_org/cc/output/output_surface.cc中。
OutputSurface类的成员函数InitializeAndSetContext3d首先会调用参数context_provider指向的ContextProviderInProcess对象的成员函数BindToCurrentThread将其引用的In-Process Command Buffer GL接口设置为当前线程所使用的GL接口。当前线程即为Render端的Compositor线程。有了这个GL接口之后, Render端的Compositor线程就可以执行GPU操作了。
成功将参数context_provider指向的ContextProviderInProcess对象引用的In-Process Command Buffer GL接口设置为当前线程所使用的GL接口之后, 该ContextProviderInProcess对象就会保存在OutputSurface类的成员变量context_provider_中。
接下来我们继续分析ContextProviderInProcess类的成员函数BindToCurrentThread为当前线程设置Process Command Buffer GL接口的过程, 如下所示:
bool ContextProviderInProcess::BindToCurrentThread() {
......if (!context3d_->
makeContextCurrent())
return false;
......
return true;
}
这个函数定义在文件external/chromium_org/webkit/common/gpu/context_provider_in_process.cc中。
从前面的分析可以知道, ContextProviderInProcess类的成员变量context3d_指向的是一个WebGraphicsContext3DInProcessCommandBufferImpl对象。ContextProviderInProcess类的成员函数BindToCurrentThread会调用这个WebGraphicsContext3DInProcessCommandBufferImpl对象的成员函数makeContextCurrent将前面创建的In-Process Command Buffer GL接口设置为当前线程所使用的GL接口, 如下所示:
bool WebGraphicsContext3DInProcessCommandBufferImpl::makeContextCurrent() {
if (!MaybeInitializeGL())
return false;
::gles2::SetGLContext(GetGLInterface());
return context_ &
&
!isContextLost();
}
这个函数定义在文件external/chromium_org/webkit/common/gpu/webgraphicscontext3d_in_process_command_buffer_impl.cc中。
WebGraphicsContext3DInProcessCommandBufferImpl类的成员函数makeContextCurrent首先调用成员函数MaybeInitializeGL检查是否已经为当前线程初始化过GL接口了。如果还没有初始化, 那么就会进行初始化, 如下所示:
bool WebGraphicsContext3DInProcessCommandBufferImpl::MaybeInitializeGL() {
if (initialized_)
return true;
......real_gl_ =
context_->
GetImplementation();
setGLInterface(real_gl_);
......initialized_ =
true;
return true;
}
这个函数定义在文件external/chromium_org/webkit/common/gpu/webgraphicscontext3d_in_process_command_buffer_impl.cc中。
当WebGraphicsContext3DInProcessCommandBufferImpl类的成员变量initialized_的值等于true的时候, 就表示当前线程初始化过GL接口了。另一方面, 如果当前线程还没有初始化过GL接口, 那么WebGraphicsContext3DInProcessCommandBufferImpl类的成员函数MaybeInitializeGL就会进行初始化。
从前面的分析可以知道, WebGraphicsContext3DInProcessCommandBufferImpl类的成员变量context_指向的是一个GLInProcessContextImpl对象。调用这个GLInProcessContextImpl对象的成员函数可以获得它内部封装一个GLES2Implementation对象。这个GLES2Implementation对象描述的就是一个In-Process Command Buffer GL接口。
WebGraphicsContext3DInProcessCommandBufferImpl类的成员函数MaybeInitializeGL获得了上述In-Process Command Buffer GL接口之后, 会调用另外一个成员函数setGLInterface将其保存起来。
WebGraphicsContext3DInProcessCommandBufferImpl类的成员函数setGLInterface是从父类WebGraphicsContext3DImpl继承下来的, 它的实现如下所示:
class WEBKIT_GPU_EXPORT WebGraphicsContext3DImpl
: public NON_EXPORTED_BASE(blink::WebGraphicsContext3D) {
public:
......::gpu::gles2::GLES2Interface* GetGLInterface() {
return gl_;
} protected:
......void setGLInterface(::gpu::gles2::GLES2Interface* gl) {
gl_ =
gl;
}......::gpu::gles2::GLES2Interface* gl_;
......
};
这个函数定义在文件external/chromium_org/webkit/common/gpu/webgraphicscontext3d_impl.h中。
WebGraphicsContext3DImpl类的成员函数setGLInterface将参数描述的In-Process Command Buffer GL接口保存在成员变量gl_中。这个In-Process Command Buffer GL接口可以通过调用WebGraphicsContext3DImpl类的另外一个成员函数GetGLInterface获得。
这一步执行完成后, 回到前面分析的WebGraphicsContext3DInProcessCommandBufferImpl类的成员函数makeContextCurrent, 它接下来又会调用从父类WebGraphicsContext3DImpl继承下来的成员函数GetGLInterface获得前面所保存的In-Process Command Buffer GL接口, 并且将该In-Process Command Buffer GL接口设置为当前线程的GL接口, 也就是OpenGL调用接口。这是通过调用函数gles2::SetGLContext实现的, 如下所示:
static gpu::ThreadLocalKey g_gl_context_key;
......
gpu::gles2::GLES2Interface* GetGLContext() {
return static_cast<
gpu::gles2::GLES2Interface*>
(
gpu::ThreadLocalGetValue(g_gl_context_key));
}
void SetGLContext(gpu::gles2::GLES2Interface* context) {
gpu::ThreadLocalSetValue(g_gl_context_key, context);
}
这两个函数定义在文件external/chromium_org/gpu/command_buffer/client/gles2_lib.cc中。
参数context描述的In-Process Command Buffer GL接口将被保存在全局变量g_gl_context_key所描述的一个线程局部储存中, 作为当前线程所使用的OpenGL接口。以后通过调用另外一个函数gles2::GetGLContext就可以获得保存在这个线程局部储存中的In-Process Command Buffer GL接口。
这一步执行完成后, 以后Render端的Compositor线程直接调用OpenGL函数glXXX时, 就会通过In-Process Command Buffer GL接口执行指定的GPU的操作。从OpenGL函数glXXX调用到In-Process Command Buffer GL接口的原理可以参考前面Chromium网页GPU光栅化原理分析一文。
Render端的Compositor线程除了可以通过OpenGL函数glXXX使用In-Process Command Buffer GL接口, 还可以通过它为网页创建的Synchronous Compositor Output Surface使用In-Process Command Buffer GL接口。接下来, 我们就以Render端的Compositor线程执行GPU光栅化操作为例, 说明它执行GPU命令的过程。
从前面Chromium网页GPU光栅化原理分析一文可以知道, 当Render端的Compositor线程是通过一个Skia Canvas对网页UI进行GPU光栅化操作的。这个Skia Canvas又是通过一个类型为SkSurface_Gpu的Skia Surface获得的。这个类型为SkSurface_Gpu的Skia Surface是通过调用DirectRasterBuffer类的成员函数CreateSurface创建的, 如下所示:
skia::RefPtr<
SkSurface>
ResourceProvider::DirectRasterBuffer::CreateSurface() {
skia::RefPtr<
SkSurface>
surface;
switch (resource()->
type) {
case GLTexture: {
......
class GrContext* gr_context =
resource_provider()->
GrContext();
if (gr_context) {
GrBackendTextureDesc desc;
......
skia::RefPtr<
GrTexture>
gr_texture =
skia::AdoptRef(gr_context->
wrapBackendTexture(desc));
......surface =
skia::AdoptRef(SkSurface::NewRenderTargetDirect(
gr_texture->
asRenderTarget(), text_render_mode));
}
break;
}
......
}
return surface;
}
这个函数定义在文件external/chromium_org/cc/resources/resource_provider.cc中。
DirectRasterBuffer类的成员函数CreateSurface的详细实现可以参考前面Chromium网页GPU光栅化原理分析一文。这里我们所关注的重点是它通过调用ResourceProvider类的成员函数GrContext获得一个In-Process Command Buffer GL接口的过程。这个In-Process Command Buffer GL接口会传递给这里所创建的类型为SkSurface_Gpu的Skia Surface。有了In-Process Command Buffer GL接口之后, 类型为SkSurface_Gpu的Skia Surface就可以通过GPU对网页的UI进行光栅化了。
DirectRasterBuffer类的成员函数CreateSurface首先是调用成员函数resource_provider获得一个ResourceProvider对象。这个ResourceProvider对象负责管理网页在渲染过程中所要使用到的资源。有这个Resou
推荐阅读
- Android快速开发偷懒必备,一句话搞定所有ViewGroup的Adapter . 支持自定义ViewGroup
- Android碎片Fragment总结
- Android实现多点触控,自由缩放图片
- Android自定义组件
- unity发布安卓 截图保存到本地
- Android种使用Notification实现通知管理以及自定义通知栏(示例四)
- 微信小程序wx.uploadFile在安卓手机上面the same task is working问题解决
- cocos2dx的android版FileUtils的坑
- Android性能优化之内存泄漏