zoukankan      html  css  js  c++  java
  • Javascript如何实现GPU加速?

    欢迎大家前往腾讯云+社区,获取更多腾讯海量技术实践干货哦~

    本文由腾讯Bugly发表于云+社区专栏

    1. 什么是Javascript实现GPU加速?

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

    2. 实例演示:色块识别

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

    img

    img

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

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

    img

    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进行色相转换(防止光线影响识别准确度),其余步骤均一致。

    2.4 使用GPGPU意义

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

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

    3. 如何实现GPU通用计算?

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

    img

    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教程,有兴趣的同学可以关注。

    4. 有无现成类库?

    大家可以看到,我实现的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 自己定制,更为灵活。

    问答
    是否有一种方法以编程方式测试浏览器GPU加速?
    相关阅读
    有哪些主流的科学计算可以利用GPU加速?
    如何使用JavaScript实现GPU加速神经网络
    CPU与GPU区别大揭秘

    **此文已由作者授权腾讯云+社区发布,原文链接:https://cloud.tencent.com/developer/article/1148782?fromSource=waitui **

    欢迎大家前往腾讯云+社区或关注云加社区微信公众号(QcloudCommunity),第一时间获取更多海量技术实践干货哦~

  • 相关阅读:
    VysorPro助手
    Play 2D games on Pixel running Android Nougat (N7.1.2) with Daydream View VR headset
    Play 2D games on Nexus 6P running Android N7.1.1 with Daydream View VR headset
    Native SBS for Android
    ADB和Fastboot最新版的谷歌官方下载链接
    How do I install Daydream on my phone?
    Daydream Controller手柄数据的解析
    蓝牙BLE传输性能及延迟分析
    VR(虚拟现实)开发资源汇总
    Android(Java)控制GPIO的方法及耗时分析
  • 原文地址:https://www.cnblogs.com/qcloud1001/p/9263272.html
Copyright © 2011-2022 走看看