浏览器-08 chromium 渲染2

Chromium 硬件加速合成

  • 一个网页通常可以包?很多层,例如有透明效果的节点, Canvas节点等,这些节点都可以是页面中的一层,这些层的内容最后组成一个可视化的网页内容;
  • 在没有硬件加速的情况下,浏览器通常是依赖于CPU来渲染生成网页的内容,大致的做法是遍历这些层,然后按照顺序把这些层的内容依次绘制在一个内部存储空间上,最后把这个内部表示显示出来,这种做法就是软件渲染;
  • WebKit中对于渲染所做的一些基础设施,包括Render树和RenderLayer树,对于每一个RenderLayer,可以为其单独创建一块内部存储,这些存储会被用来保存该层中的内容,浏览器最后会把这些所有的层通过GPU合成起来,形成最终网页渲染的内容,这就是硬件加速合成;

Canvas2D及其实现

CanvasRenderingContext2D 介绍
  • CanvasRenderingContext2D2d图形绘制的上下文对象,其提供了用于绘制2d图形的 API;该对象由JavaScript代码创建后,JavaScript便可以调用它的 API 在画布上绘制图形;这些API主要的作用就是在画布上绘制点,线,矩形,弧形,图片等等,除此之外,还提供了这些绘制的样式和合成效果等;
WebKit 和 Chromium 的支持
  • W3C定义了2D context标准的草案, 这些接口保存在IDL文件中;WebKit根据这IDL来直接生成相关的C++类的代码,这些类包括 CanvasRenderingContext2D,CanvasPattern, CanvasGradient, ImageData, TextMetrics等, 它们 和标准中的接口一一对应;
  • Canvas2D上下文类的具体绘制动作由实现平台决定, 其由软件或者硬件来完成取决于移植;
  • WebKi端:
    * HTMLCanvasElement:DOM中的对应着HTML5canvas元素,该类包?有关为2D或者3D context服务的相关接口,主要的作用创建JS使用的上下文对象,绘图的平台无关的GraphicsContext对象,后端存储的buffer;
    * GraphicsContext:WebKit的平台无关的上下文类,用于绘制工作,具体调用平台相关的上下文类来实现绘制;
    * PlatformGraphicsContext:平台绘制上下文类,不同的平台有不同的实现,在chromium中是PlatformContextSkia;
    * ImageBuffer:WebKit平台无关后端存储类,不同平台会定义不同的结构,在chromium中会使用SkCanvas;
    * RenderHTMLCanvas:RenderObject的子类,为canvas而设计的;
  • Chromium端:
    * PlatformContextSkia:Chromium中的PlatformGraphicsContext类;
    * SkCanvas:skia画布,包?所有的绘制状态,使用SkDevice来绘制图形;
    * SkDevice:设备类,包?一个SkBitmap作为后端,利用光栅扫描算法来生成像素值保存于后端存储中,用于软件绘制方案;
    * SkGpuDevice:设备类,包?一个绘制的目标对象,通过GrContext来绘制,其利用硬件加速的GL库来绘制2D图形;
    * GrContext:GPU绘制的上下文类,包?一个平台相关的3D上下文成员;
    * Canvas2DLayerChromium:LayerChromium的子类,包?一个硬件加速的Canvas2D层;
  • Chromium中的Canvas2D的绘制操作的实现都是由图形库skia来完成,这里包括软件和硬件加速实现,chromium所要做的就是把WebKit中的调用交给skia来执行并和自己的绘制模型和硬件加速机制集成起来;
Canvas 2D的软件实现
//例子
<canvas id='mycanvas' width=80 height=100></canvas>

<script type='text/javascript'>
  var canvas = docuemnt.getElementById('mycanvas');
  var ctx = canvas.getContenxt('2d');
  ctx.fillStyle = '#FF0000';
  ctx.fillRect(0,0,80,100);
</script>
  • 首先,当执行到JS代码中的canvas.getContext时,WebKit通过V8 JS绑定会调用HTMLCanvasElement.getContext;
    * 该函数根据传入的参数来决定创建2D或者3D的上下文对象;
    * 在这里, CanvasRenderingContext2D对象会被创建;
    * 此时其他有关的对象例如ImageBuffer,GraphicsContext等不会被创建,直到后面使用到时才会被创建,这是WebKit的做事原则;
  • 其次,当设置fillStyle属性时,WebKit同样通过V8 JS绑定调用CanvasRenderingContext2D.setFillStyle,在这种情形下,2D上下文对象会开始创建相关对象;
    • 当执行JSfillRect时,CanvasRenderingContext2D调用GraphicsContext来完成绘制;
    • 这两个类是WebKit的基础类,GraphicsContext需要有不同移植来具体实现绘制工作,在chromium中,这就是PlatformContextSkia;
    • 该类是一个转接口,调用skia来绘制,SkCanvas根据之前设定的样式,由SkDevice利用光栅扫描法来计算生成相应的像素值,结果保存在一个SkBitmap中;
  • 最后,当fillRect操作调用完成之后,会安排一个Invalidate相关区域的命令;
    * 而后,当该命令被执行了,WebKit会遍历RenderLayer依次绘制RenderObject的内容,当绘制Canvas元素时,会把之前Canvas绘制在SkBitmap的内容绘制到网页的 Bitmap;
Canvas 2D的硬件加速实现
  • 首先,硬件加速需要创建更多的对象和设施,主要有两点
    * 会为Canvas元素创建一个新的RenderLayer及其相应GraphicsLayer,Canvas2DLayerChromium,CCLayerImpl 等;
    * 因为利用GL来渲染,所以为skiaSkCanvas创建一个SkGpuDevice, GrTexture, GrContext来使用GL绘制2D图形,同时,跟合成器一样, 也会创建3D的上下文对象- WebGraphicsContext3DCommandBufferImpl, 将skiaGrContext, GrTexture等对gl调用转发给GPU进程;
  • 其次,当调用fillRect时,canvas的内容由SkCanvas调用SkGpuDevice将其绘制在Texture,当这些GL的操作都通过WebGraphicsContext3DCommandBufferImpl交给 GPU进程来完成绘制,会请求一个更新某个区域的任务;
  • 最后,更新请求会调度合成操作,其首先调用Canvas2DLayerImpl::paintContentsIfDirty绘制自己,然后将CanvasTexture合成起来生成网页内容;

WebGL及其实现

  • canvas中同样也可以绘制3D图形,也就是Canvas3D或者称为WebGL;是一个被HTML Canvas元素创建的用来3D渲染的上下文接口;
  • 2D3D是互斥的,不能同时在同一个canvas中操作它们;
概述
//例子
<canvas id='mywebGl' width=100 height=100></canvas>

<script type='text/javascript'>
  var canvas = document.getElementById('mywebGl');
  var gl = canvas.getContext('experimental-webgl');
  gl.clearColor(1.0,0.0,0.0,1.0);
  gl.clear(gl.COLOR_BUFFER_BIT);
</script>
  • Canvas 2D不同的是,WebGL没有软件渲染和硬件加速两种模式, 它仅在硬件加速开启的情况下才能运行,因为它依赖于3D的图形库;
WebGL 的渲染过程
  • JavaScript的代码通过HTML Canvas对象创建3D上下文时,WebGL模块便为其创建一个绘制3D图形用的上下文对象,该对象在GPU进程中会有一个实际的OpenGL ES的上下文对象对应;同时,DrawingBuffer对象也会被创建;
  • DrawingBuffer会同时创建了一个帧缓冲区对象,用于存储该WebGL绘制的内容,同时获取用于合成的纹理对象,WebGL模块会获取这些对象的ID信息;
  • JavaScript的调用上下文对象的绘制图形代码被V8解析后,利用V8的绑定机制,会调用相应的WebGLRenderingContext对象的Callback函数,这些函数把它们转换成内部的Commands, 通过IPC机制传给GPU进程,GPU进程在之前创建好的上下文对象,完成实际的绘制工作;在这过程中,有两点值得关注, * 很多命令需要同步,这会有很大的开销; * 很多情况下,JavaScript需要操作各种图片资源,所以需要将它们共享给GPU进程,同时将它们上载到GPU`的内存,因而开销比较大;
  • GPU进程执行renderer进程发送过来的命令,调用GL库函数把计算结果内容更新存储到帧缓冲区中,前面这四步在解析JavaScript时,同时执行;之后,它会调度一个任务,请求更新一个矩形区域;
  • 从这步开始,合成器发起合成,当由任何变化或者更新网页的请求时都会触发它;合成器要求每层去更新自己的发生变化的部分,这需要尽可能的快,以避免大幅地影响一次网页的绘制工作;WebGL此时会准备绘制内容或者 更新内容到帧缓冲区中,同时把内容拷贝到纹理对象中去,以备合成器所使用;
  • 因为WebGL的纹理对象是在这些GL的上下文对象中共享的,WebGL模块切换到合成器的上下文对象环境中,将它的纹理对象根据变换绘制到该环境中的帧缓冲区中去,完成对该层的合成;
  • 当所有层次的绘制完成后,最后一步就是交换前后端的缓冲区,来显示合成完的内容;

转载于:https://www.cnblogs.com/jinkspeng/p/5046523.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值