歡迎你們前往騰訊雲+社區,獲取更多騰訊海量技術實踐乾貨哦~javascript
本文由 騰訊Bugly發表於 雲+社區專欄
CPU與GPU設計目標不一樣,致使它們之間內部結構差別很大。 CPU須要應對通用場景,內部結構很是複雜。 而GPU每每面向數據類型統一,且相互無依賴的計算。 因此,咱們在Web上實現3D場景時,一般使用WebGL利用GPU運算(大量頂點)。 可是,若是隻是通用的計算場景呢?好比處理圖片中大量像素信息,咱們有辦法使用GPU資源嗎?這正是本文要講的,GPU通用計算,簡稱GPGPU。html
以下圖所示,咱們識別圖片中彩虹糖色塊,給糖果添加表情。java
http://tgideas.qq.com/2018/br...git
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次github
實例中,咱們分別使用GPU和CPU進行色相轉換(防止光線影響識別準確度),其他步驟均一致。web
GPU與CPU數據傳輸過程,與GPU實際運算耗時至關,因此使用GPU運算傳輸成本太高,實測在Android中具備較大優點。編程
本測試案例是從webAR項目中抽取,須要實時跟蹤用戶攝像頭處理視頻流(256*256),使用GPU計算意義很是大,不然沒法實現實時跟蹤。canvas
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/br...
其實清楚原理後,總體實現比較簡單。 可是對於不瞭解WebGL的同窗來講,理解上有必定難度,我後續準備寫一個系列的WebGL教程,有興趣的同窗能夠關注。
你們能夠看到,我實現的gpu.js中,並無將javascript轉換成着色器語言(類C),而是用戶直接傳入着色器代碼。可是github上已有將javascript轉換爲着色器語言的庫。 https://github.com/gpujs/gpu.js
爲何我沒有直接使用呢?
沒有WebGL基礎的同窗,建議直接使用https://github.com/gpujs/gpu.js ,從本文理解總體邏輯; 有必定基礎的同窗,建議由http://tgideas.qq.com/2018/br... 本身定製,更爲靈活。
問答
是否有一種方法以編程方式測試瀏覽器GPU加速?
相關閱讀
有哪些主流的科學計算能夠利用GPU加速?
如何使用JavaScript實現GPU加速神經網絡
CPU與GPU區別大揭祕
此文已由做者受權騰訊雲+社區發佈,原文連接:https://cloud.tencent.com/dev...
歡迎你們前往騰訊雲+社區或關注雲加社區微信公衆號(QcloudCommunity),第一時間獲取更多海量技術實踐乾貨哦~