天天看點

html5 gpu加速,javascript如何實作gpu加速?

javascript如何實作gpu加速?下面本篇文章給大家介紹一下。有一定的參考價值,有需要的朋友可以參考一下,希望對大家有所幫助。

html5 gpu加速,javascript如何實作gpu加速?

一、什麼是Javascript實作GPU加速?

CPU與GPU設計目标不同,導緻它們之間内部結構差異很大。

CPU需要應對通用場景,内部結構非常複雜。

而GPU往往面向資料類型統一,且互相無依賴的計算。

是以,我們在Web上實作3D場景時,通常使用WebGL利用GPU運算(大量頂點)。

但是,如果隻是通用的計算場景呢?比如處理圖檔中大量像素資訊,我們有辦法使用GPU資源嗎?這正是本文要講的,GPU通用計算,簡稱GPGPU。

二、執行個體示範:色塊識别。

如下圖所示,我們識别圖檔中彩虹糖色塊,給糖果添加表情。

html5 gpu加速,javascript如何實作gpu加速?
html5 gpu加速,javascript如何實作gpu加速?

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進行色相轉換(防止光線影響識别準确度),其餘步驟均一緻。測試平台測試結論

PCGPU較CPU優勢較少

iOSGPU較CPU優勢較少

AndroidvivoX20(運作10次平均)

CPU:770ms,GPU:270

GPU較CPU快2.85倍

三星S7(運作10次平均)

CPU:982ms,GPU:174ms

GPU較CPU快5.64倍

2.4、使用GPGPU意義:

GPU與CPU資料傳輸過程,與GPU實際運算耗時相當,是以使用GPU運算傳輸成本過高,實測在Android中具有較大優勢。

本測試案例是從webAR項目中抽取,需要實時跟蹤使用者攝像頭處理視訊流(256*256),使用GPU計算意義非常大,否則無法實作實時跟蹤。

三、如何實作GPU通用計算?

3.1、首先,我們通過一張流程圖,示範原理:

html5 gpu加速,javascript如何實作gpu加速?

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自己定制,更為靈活。

另外,這個元件我沒打算深度封裝,也沒打算維護……嗯,就這樣。

更多web前端開發知識,請查閱 HTML中文網 !!