WebGL为不同的平台/硬件提供了统一的封装,屏蔽了OpenGL ES2.0在各平台差异。后续我们会继续谈谈OpenGL ES2.0在Android/iOS平台的更多差异。这回我们分析WebKit的源码,谈谈WebGL与Cavans不同,WebGL又多做了哪些呢,性能提升在哪里呢。
我们可以使用多种方式来绘制图形【本文以iOS版本的WebKit为例】DOM+CSS:为前端提供了强大图形渲染技术,门槛低上手快,对硬件要求较高。
Canvas2D:元素本身并没有绘制能力,它仅仅是2D图形的容器,必须使用脚本来完成实际的绘图任务。getContext('2d') 方法可返回一个对象CanvasRenderingContext(后续简称canvas),该对象提供了用于在画布上绘图的方法和属性,可用于在画布上绘制图片、文本、图形、颜色等,并提供常见的图形转换API,进行图片的缩放、旋转、像素再加工能力,最终通过OpenGL渲染到屏幕上。
Canvas3D:同2D一样,本身没有渲染能力,通过getContext('webgl')方法可以返回一个基于OpenGL ES2.0上下文的对象WebGLRenderingContext(后续简称webgl),通过webgl可以直接访问GPU硬件资源,对码农要求更高,优化空间更大。
对应GraphicsContext.cpp中的
void GraphicsContext::drawNativeImage(imagePtr, imageSize, styleColorSpace, destRect, srcRect, op, blendMode, orientation) { ······ // Flip the coords. CGContextTranslateCTM(context, 0, adjustedDestRect.height()); CGContextScaleCTM(context, 1, -1); // Adjust the color space. image = Image::imageWithColorSpace(image.get(), styleColorSpace); // Draw the image. CGContextDrawImage(context, adjustedDestRect, image.get()); CGContextRestoreGState(context); ······ }在《 07. WebApp2.0时代启程:倒立者赢,从CPU到GPU,一张图片的旅行 》中,这里不重新做说明了。
它在iOS中已经深入的融合到UIView和UILayer框架中,架构图如下:
js代码
gl.bindTexture(gl.TEXTURE_2D, texID);在WebKit中对应于C++代码:
void GraphicsContext3D::bindTexture(GC3Denum target, Platform3DObject texture) { makeContextCurrent(); if (m_state.activeTexture == GL_TEXTURE0 && target == GL_TEXTURE_2D) m_state.boundTexture0 = texture; ::glBindTexture(target, texture); }CPU在RAM中处理完图片后,仍需要上传到GPU中才可以显示,同时,GPU图形渲染速度比CPU提升10倍以上。
而WebGL需要负责的代码实现:
gl.bindTexture(gl.TEXTURE_2D, texture._glTextures[gl.id]); gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, texture.premultipliedAlpha); gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, texture.source); gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, texture.scaleMode === CONST.SCALE_MODES.LINEAR ? gl.LINEAR : gl.NEAREST);使用 fillText(),在画布上写文本 "Hello world!" 和 "w3school.com.cn":JS代码为:
var canvas=document.getElementById("myCanvas"); var ctx=canvas.getContext("2d"); ctx.font="20px Georgia"; ctx.fillText("Hello World!",10,50); ctx.font="30px Verdana"; // 创建渐变 var gradient=ctx.createLinearGradient(0,0,c.width,0); gradient.addColorStop("0","magenta"); gradient.addColorStop("0.5","blue"); gradient.addColorStop("1.0","red"); // 用渐变填色 ctx.fillStyle=gradient; ctx.fillText("w3school.com.cn",10,90);WebGL无此API,WebKit也是通过FreeType通过CPU来实现文字的加载与渲染。如果需要渲染文字,需要生成一个Canvas对象,在Canvas绘制完成之后,在直接渲染到WebGL空间。
多个Canvas实例可以轻松切换,因为在CPU中他只是一个静态的Bitmap。而WebGL上线文最好只有一个,切换上线文需要更改GPU硬件管线的状态和flushbuffer,频繁的切换会消耗大量的CPU资源。
CPU需要将渲染好的内存Bitmap上传给GPU,然后通过display link到屏幕上。WebGL避免了CPU到GPU的大量的数据传输,只需要发送指令给GPU即可。
支持vertexArray和IndiceArray,多个精灵共享一张文理,只需要将vertext数据缓冲到顶点数据,通过glDrawElements可以一次批量渲染。
Canvas的API每次都是同步操作,每次渲染必然同步到framebuffer中,不利于性能优化。WebGL可以自定义渲染机制和时机
我们将谈谈WebGL的纹理格式转换,也是WebGL区别于OpenGL ES2.0最大的区别。
