Javascript如何实现GPU加速?

一、什么是Javascript实现GPU加速?

CPU与GPU设计目标不同,导致它们之间内部结构差异很大。 CPU需要应对通用场景,内部结构非常复杂。 而GPU往往面向数据类型统一,且相互无依赖的计算。 所以,我们在Web上实现3D场景时,通常使用WebGL利用GPU运算(大量顶点)。 但是,如果只是通用的计算场景呢?比如处理图片中大量像素信息,我们有办法使用GPU资源吗?这正是本文要讲的,GPU通用计算,简称GPGPU。

二、实例演示:色块识别。

如下图所示,我们识别图片中彩虹糖色块,给糖果添加表情。

2.1、实例地址(打开页面后,依次点击按钮“使用CPU计算”、“使用GPU计算”):

http://tgideas.qq.com/2018/brucewan/gpgpu.html

2.2、运行代码:

var rgb2hsv = function(r, g, b) {
    var max = Math.max(r, g, b), min = Math.min(r, g, b),
        d = max - min,
        h,
        s = (max === 0 ? 0 : d / max),
        v = max / 255;
        switch (max) {        
        case min: h = 0; break;        
        case r: h = (g - b) + d * (g < b ? 6: 0); h /= 6 * d; break;        
        case g: h = (b - r) + d * 2; h /= 6 * d; break;        
        case b: h = (r - g) + d * 4; h /= 6 * d; break;
    }    
     return {
        h: self.hueIndexs[parseInt(h*360)],
        s: s,
        v: v
    }
};

运行次数:262144次

2.3、测试结论:

实例中,我们分别使用GPU和CPU进行色相转换(防止光线影响识别准确度),其余步骤均一致。

测试平台

测试结论

PC

GPU较CPU优势较少

iOS

GPU较CPU优势较少

Android

vivoX20(运行10次平均)CPU:770ms,GPU:270GPU较CPU快2.85倍三星S7(运行10次平均)CPU:982ms,GPU:174msGPU较CPU快5.64倍

2.4、使用GPGPU意义:

GPU与CPU数据传输过程,与GPU实际运算耗时相当,所以使用GPU运算传输成本过高,实测在Android中具有较大优势。

本测试案例是从webAR项目中抽取,需要实时跟踪用户摄像头处理视频流(256*256),使用GPU计算意义非常大,否则无法实现实时跟踪。

三、如何实现GPU通用计算?

3.1、首先,我们通过一张流程图,演示原理:

3.2、实现:

3.2.1、创建顶点着色器,只是传递了贴图坐标。

attribute vec4 position;
varying vec2 vCoord;void main() {
    vCoord = position.xy * 0.5 + 0.5;
    gl_Position = position;
}

3.2.2、创建片元着色器,根据贴图坐标贴图。

precision highp float;
varying vec2 vCoord;
uniform sampler2D map;void main(void) {
    vec4 color = texture2D(map, vCoord);
    gl_FragColor = color;
}

3.3.3、根据如上着色器代码,创建程序对象,变量code是我们要传入的用于计算的代码。

// 绑定并编译着色器程序var vertexShaderSource = '...';
var fragmentShaderSource = '...' + code + '...';
var vertexShader = gl.createShader(gl.VERTEX_SHADER);
gl.shaderSource(vertexShader, vertexShaderSource);
gl.compileShader(vertexShader);
var fragmentShader = gl.createShader(gl.FRAGMENT_SHADER);
gl.shaderSource(fragmentShader, fragmentShaderSource);
gl.compileShader(fragmentShader);  
              
// 创建程序对象
var program = gl.createProgram();
gl.attachShader(program, vertexShader);
gl.attachShader(program, fragmentShader);
gl.linkProgram(program);
gl.useProgram(program);

3.3.4、传入顶点数据,创建一个面覆盖整个画布。

// 顶点数据传输
var vertices = new Float32Array([-1.0, 1.0, -1.0, -1.0, 1.0, -1.0, 1.0, 1.0]);
var vertexBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer);
gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW);
var aPosition = gl.getAttribLocation(program, 'position');
gl.vertexAttribPointer(aPosition, 2, gl.FLOAT, false, 0, 0);
gl.enableVertexAttribArray(aPosition);

3.3.5、传入原始数据,本例中传入我要处理的图像数据,作为贴图,最终绘制到屏幕。

var gl = this.gl;
var program = this.program;
var texture = gl.createTexture();
var uMap = gl.getUniformLocation(program, 'map');

gl.activeTexture(gl.TEXTURE0);
gl.bindTexture(gl.TEXTURE_2D, texture);

gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, canvas);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
gl.generateMipmap(gl.TEXTURE_2D);

gl.uniform1i(uMap, 0);      
          
// 绘制
gl.clearColor(0, 0, 0, 1);
gl.clear(gl.COLOR_BUFFER_BIT);
gl.drawArrays(gl.TRIANGLE_FAN, 0, 4);

3.3.6、从最终绘制的画面上,获取颜色信息作为最终处理结果数据。

var pixels = new Uint8Array(gl.drawingBufferWidth * gl.drawingBufferHeight * 4);
gl.readPixels(0, 0, gl.drawingBufferWidth, gl.drawingBufferHeight, gl.RGBA, gl.UNSIGNED_BYTE, pixels);

3.3.7、完整代码: http://tgideas.qq.com/2018/brucewan/gpu.js

其实清楚原理后,整体实现比较简单。 但是对于不了解WebGL的同学来说,理解上有一定难度,我后续准备写一个系列的WebGL教程,有兴趣的同学可以关注。

四、有无现成类库?

大家可以看到,我实现的gpu.js中,并没有将javascript转换成着色器语言(类C),而是用户直接传入着色器代码。但是github上已有将javascript转换为着色器语言的库。 https://github.com/gpujs/gpu.js

为什么我没有直接使用呢? 1、简单的使用,2k可以实现的代码,不想引入200k的库; 2、数据输入输出可以由自己灵活控制; 3、着色器语言很简单,特别只是使用基础运算逻辑的代码,没必要由库从Javascript转换。

没有WebGL基础的同学,建议直接使用https://github.com/gpujs/gpu.js,从本文理解整体逻辑; 有一定基础的同学,建议由http://tgideas.qq.com/2018/brucewan/gpu.js自己定制,更为灵活。

如果您觉得我们的内容还不错,就请转发到朋友圈,和小伙伴一起分享吧~

原文发布于微信公众号 - 腾讯Bugly(weixinBugly)

原文发表时间:2018-06-14

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏算法+

半径无关快速高斯模糊实现(附完整C代码)

之前,俺也发过不少快速高斯模糊算法. 俺一般认为,只要处理一千六百万像素彩色图片,在2.2GHz的CPU上单核单线程超过1秒的算法,都是不快的. 之前发的几个算...

4567
来自专栏落影的专栏

Metal入门教程(三)摄像头采集渲染

前面的教程介绍了如何绘制一张图片和如何把图片显示到3D物体上并进行三维变换,这次介绍如何用Metal渲染摄像头采集到的图像。

1822
来自专栏恰同学骚年

OOAD利器之UML基础

UML:Unified Modeling Language,即统一建模语言,简单地说就是一种有特殊用处的语言。本文是我初步学习UML的学习笔记,对于我们菜鸟码农...

622
来自专栏张善友的专栏

C#数学计算包 Math.NET

Math.NET的目标是为提供一款自身包含清晰框架的符号运算和数学运算/科学运算,它是C#开发的开源类库。Math.NET含了一个支持线性代数的解析器,分析复杂...

2205
来自专栏万波的专栏

解剖 WebGL & Three.js 工作原理

本文主要通过两方面来解剖 WebGL & Three.js :WebGL背后的工作原理和以Three.js为例,讲述框架在背后扮演什么样的角色,希望对大家学习有...

1.6K2
来自专栏cs

统一建模语言-UML

伪cs专业,也是无语,还要经常作图。 貌似计算机期刊文章,系统设计需要它。 什么是UML? 百度百科 Unified Modeling Language ...

1934
来自专栏程序员互动联盟

【计算机基本概念】如何理解计算机显存?

显存,也被叫做帧缓存,它的作用是用来存储显卡芯片处理过或者即将提取的渲染数据。如同计算机的内存一样,显存是用来存储要处理的图形信息的部件。 如同计算机的内存一样...

3065
来自专栏开源FPGA

基于FPGA的有限状态机浅析

  前言:状态机大法好,状态机几乎可以实现一切时序逻辑电路。 有限状态机(Finite State Machine, FSM),根据状态机的输出是否与输入有关,...

2768
来自专栏IT派

常用python组件包

$ pip list Package Version ---------------------- ------------- a...

842
来自专栏编程

软件测试之Fuzzing和基于属性的测试

基于属性的测试技术,是指编写对你的代码来说为真的逻辑语句(即“属性”),然后使用自动化工具来生成测试输入(一般来说,是指某种特定类型的随机生成输入数据),并观察...

1840

扫码关注云+社区