HTMLCanvasElement对应h5的canvas元素。
解析网页遇到canvas元素会创建HTMLCanvasElement实例。
Canvas可以支持2d和3d图形的绘制。
HTMLCanvasElement提供了getContext()接口,返回图形绘制的上下文对象,
对于2d图形返回的是CanvasRenderingContext2D。
CanvasRenderingContext2D提供了网页可调用的所有绘制动作。
CanvasRenderingContext2D的所有绘制命令都转接给了
HTMLCanvasElement::drawingContext()提供的绘制上下文。
HTMLCanvasElement是整个Canvas实现的入口。
我们从这里入手理出2dCanvas的硬件绘制及硬件渲染架构。
一.硬件绘制的实现结构
硬件绘制是指,网页调用的绘制动作,通过HTMLCanvasElement
转给skia库,skia库通过调用GPU命令完成实际的绘制操作。
软件绘制是指skia库在cpu上完成绘制操作。
完成硬件绘制需要:
1.建立HTMLCanvasElement与skia库的GrContext(skia硬件绘制上下文)之间的联系。
2.建立skia库GrContext与GPU之间的联系。
3.创建保存硬件绘制结果的Texture.
完成这3件事,网页调用HTMLCanvasElement的绘制命令经由Skia库调用
实际的GPU操作绘制到保存绘制结果的Texture上。
1.建立HTMLCanvasElement与skia库的GrContext(硬件绘制上下文)之间的联系。
Skia的GrContext封装在webkit::gpu:: GrContextForWebGraphicsContext3D类中。
创建过程如下图:
GrContext是在Canvas2DLayerBridge::create中被创建并保存在SkGpuDevice中。
GrContext创建过程涉及的类图:
GrContext是在Canvas2DLayerBridge::create中被创建并保存在SkGpuDevice中。
GrContext创建过程涉及的类图grcontextwrap.jpg。
CanvasRenderingContext2D的绘制动作转接给刚刚创建的GrContext的过程
(以CanvasRenderingContext2D的fillRect()为例),可以分为三步(A,B,C):
A.CanvasRenderingContext2D::fillRect()--->Canvas2DLayerBridge::create()
中创建的SkDeferredCanvas::drawRect()。
CanvasRenderingContext2D的fillRect()通过HTMLCanvasElement::drawingContext()
传给了ImageBuffer中创建的GraphicsContext,GraphicContext又进一步调用
它包含的SkCanvas::drawRect().GraphicContext包含的SkCanvas是
Canvas2DLayerBridge中创建的SkDeferredCanvas。
这个过程中涉及到的类图:
B.SkDeferredCanvas::drawRect()--->DeferredDevice:: fImmediateCanvas::drawRect()
SkDeferredCanvas::drawRect()调用的是SkDefferdCanvas创建的DeferredDevice中
包含的成员变量SkCanvas* fImmediateCanvas的drawRect().我们看这个fImmediateCanvas的来源.
SkDefferdCanvas创建时传入了SkSurface_Gpu实例作为参数。
SkDeferredCanvas::Create()中以SkSurface_Gpu为参数创建了DeferredDevice。
并将这个DeferredDevice传递给了SkCanvas.可以通过SkCanvas的getDevice()
接口得到DeferredDevice实例。所以DeferredDevice成员变量SkCanvas* fImmediateCanvas是
在SkSurface_Gpu::onNewCanvas()中创建的SkCanvas,并传入了SkGpuDevice作为参数。
这个过程涉及的类图:
C.DeferredDevice:: fImmediateCanvas::drawRect()--->SkCanvas::drawRect().
接下来看以SkGpuDevice为参数创建的SkCanvas的drawRect()的执行流程。
到这,终于看到,CanvasRenderingContext2D的绘制动作转给了GrContext。
2.建立skia库GrContext与GPU之间的联系。
由GrContext的创建过程我们知道GrContetxt被封装在GrContextForWebGraphicsContext3D实例中。
GrContextForWebGraphicsContext3D的构造函数中传入了
WebGraphicsContext3DCommandBufferImpl实例。
chromium for android GPU进程结构分析我们知道,
WebGraphicsContext3DCommandBufferImpl是与GPU进程(线程)通信的入口。
GrContextForWebGraphicsContext3D的构造函数中
GrContext与WebGraphicsContext3DCommandBufferImpl的关联是通过GrGLInterface建立的。
GrGLInterface包含与opengl es对应的接口。
WebGraphicsContext3DCommandBufferImpl::createGrGLInterface()调用
skia_bindings::CreateCommandBufferSkiaGLBinding()生成GrGLInterface,
并将GrGLInterface包含的接口绑定到WebGraphicsContext3DCommandBufferImpl对应的接口上。
GrGlInterface被传给了GrContext.这样在GrContext中通过GrGlInterface调用的操作
实际调用的是WebGraphicsContext3DCommandBufferImpl的gl操作,
并由WebGraphicsContext3DCommandBufferImpl通过CommandBuffer结构调用到
实际的GPU进程(线程中)中提给的真正gl操作。参见chromium for android GPU进程结构分析。
下图是GrContext::drawRect()调用到WebGraphicsContext3DCommandBufferImpl的gl操作的过程:
3.创建保存硬件绘制结果的Texture.
以下是具体创建过程:
这个texture由GrGpuGL::onCreateTexture()调用WebGraphicsContext3DCommandBufferImpl
接口GenTextures()生成,并保存在GrGLTexture实例中。
二.2dcanvas硬件渲染架构