當我們在說硬件加速渲染霍狰,具體指的是什么?

不管Anddoid iOS 還是Web前端 隨著UI圖形界面的發(fā)展饰及,或多或少甚至經(jīng)常聽到硬件加速這個術(shù)語蚓耽。當通過設(shè)置某個參數(shù),界面滑動效率變好了旋炒。我們都會說硬件加速起作用了步悠。但是終究什么是硬件加速,又加速了什么瘫镇?大多數(shù)人估計還是一知半解鼎兽,網(wǎng)上相關(guān)資料也是比較少的,所以我們今天來探討一下神秘的硬件加速铣除。

1. 計算機成像的原理

計算機和顯示器之間通過特定驅(qū)動協(xié)議通信谚咬,程序需要做的事情只是繪制出需要顯示的位圖(一般由RGBA三個8位次像素組成二維數(shù)組,格式可以通過協(xié)議互相協(xié)商尚粘。具體看硬件支持什么格式择卦,比如Alpha通道對屏幕顯示就沒什么用),然后通過系統(tǒng)驅(qū)動接口把二進制數(shù)據(jù)發(fā)送給顯示器(比如linux的 /dev/fb0 設(shè)備符號郎嫁,directFB等等)秉继,由顯示器的硬件把顏色顯示到屏幕上去。

所以程序要做的事情就是快速生成當前需要上屏的位圖泽铛。那么可能有人要問了 "我玩的3D游戲感覺好像不是這樣的吧尚辑?",實際上現(xiàn)有的3D渲染方式第一步就是把3D位置數(shù)據(jù)轉(zhuǎn)化成2D平面數(shù)據(jù)盔腔。

2. 位圖生成的原理

問題的關(guān)鍵 在于程序如何生成這個位圖杠茬,主流的生成算法主要有2種:
?1. 基于線性掃描算法(目前基本上和用戶直接有交互的UI系統(tǒng),全是基于這個算法)
?2. 光線跟蹤算法(主要用來渲染真實世界弛随,比如大家看的變形金剛電影就是采用此類算法渲染的瓢喉,渲染單幀的時間可能非常非常長)

這里主要討論線性掃描算法,光線跟蹤算法以后有機會慢慢討論舀透。

image

比如程序需要繪制上面這樣的三角形栓票,算法很簡單:

void draw(rgba** buffer, int width, int height) {
    for (int i = 0; i < width; ++i) {
        for (int j = 0; j < height; ++j) {
            if (is_position_in_path_region(i, j)) {
                buffer[i][j] = rgba(0, 0, 0, 1);
            }
        }
    }
}

當然這是一個簡單的繪制,那么如果我們要繪制一個半透明的三角形(三角形背后已經(jīng)有一個紅色的圓)應(yīng)該咋辦盐杂?


image
rgba draw_color = rgba(0, 0, 0, 0.5);
void draw(rgba** buffer, int width, int height) {
    float alpha = draw_color.a;
    for (int i = 0; i < width; ++i) {
        for (int j = 0; j < height; ++j) {
            if (is_position_in_path_region(i, j)) {
                rgba back_color = get_current_back_color(i, j);
                rgba blend_color;
                blend_color.r = (1 - alpha) * draw_color.r + alpha * back_color.r;
                blend_color.g = (1 - alpha) * draw_color.g + alpha * back_color.g;
                blend_color.b = (1 - alpha) * draw_color.b + alpha * back_color.b;
                buffer[i][j] = blend_color;
            }
        }
    }
}

上面的算法解釋了AlphaBlend(通過Alpha通道做顏色融合)逗载,上下這2段代碼表達了簡單的像素染色的算法哆窿。由于此類算法通常都是類似這樣的一個循環(huán),這個過程類似于掃描儀的掃描過程厉斟,所以又叫線掃描像素填充挚躯。由于位圖主要提供給光柵顯示器顯示使用,所以位圖又叫光柵圖擦秽,那么生成光柵圖的算法過程又叫光柵化過程码荔。綜上所述整個過程又叫做線掃描光柵化

Tips: 上面的算法主要是把簡單的圖形光柵化感挥,那么實際情況存在的形狀非常之多缩搅。那么如何能表達那么多復(fù)制的圖形(比如螺旋圓環(huán))。工業(yè)上存在眾多曲線擬合算法触幼,用來擬合各種復(fù)雜曲線硼瓣。其中最好用的數(shù)學(xué)曲線叫做貝塞爾曲線(貝塞爾曲線并不是貝塞爾發(fā)明的,只是貝塞爾首次在論文里面提出使用這個曲線來擬合工業(yè)圖形)置谦。所以常規(guī)我們都喜歡使用貝塞爾曲線來描述圖形盛撑,描述一個圖形只要存儲該圖形的貝塞爾參數(shù)就可以了,并且曲線是由通過公式計算出來的巩螃,所以可以無限放縮(所以圖形又叫矢量圖形蜕青,矢量是2D的靈魂钧敞,貝塞爾曲線又是矢量的靈魂)。

</br>

3. 位圖生成算法性能問題

通過上面的矢量掃描填充算法谅阿,我們很容易的發(fā)現(xiàn)了有2個可能會出現(xiàn)的性能問題:
?1. 大量的循環(huán)處理半哟,每個涉及的像素都要處理一遍(按照現(xiàn)在手機的分辨率,算算一幀有多少要處理的)
?2. 顏色融合其實就是浮點數(shù)插值算法签餐,對每個次像素都要做寓涨,運算量巨大

那么如何解決這2個問題?
?1. 對于像素太多的問題贱田,最好的辦法就是臟區(qū)域渲染缅茉。用人類話來說就是每次渲染的時候,最大化的在上一幀的基礎(chǔ)上面進行男摧,對本次這幀沒有變化的像素來說直接忽略處理。
?2. 對于浮點數(shù)運算太多译打,可以通過多媒體指令來加速耗拓。比如:ARM Neon Intel MMX SSE 等等。以ARM為例,ARM有 16個通用計算寄存器奏司,16個Neon指令寄存器乔询,16個VFP高精度浮點數(shù)運算加速器。其中Neon指令可以讓程序在一個指令周期里面計算8個浮點數(shù)的運算韵洋,理想的情況下相當于比傳統(tǒng)的浮點運算性能提升了8倍竿刁。當然這些指令主要就是用來處理多媒體的黄锤,所以又叫多媒體指令 也叫 SIMD指令(Single Instruction Multiple Data,單指令多數(shù)據(jù)流食拜,Android的底層繪圖庫就有基于Neon的優(yōu)化器鸵熟,我也嘗試過用SSE指令優(yōu)化Windows平臺API AlphaBlend函數(shù))。

那么這些都被叫做傳統(tǒng)方法负甸,那么硬件加速具體用的是什么方式來加速這個過程的流强?

4. 圖形硬件和硬件的渲染方式

傳統(tǒng)的圖形硬件主要指的是GPU,渲染接口主要有5種:

title 常規(guī)
Opengl 基本在所有平臺都能用呻待,基于狀態(tài)機的接口設(shè)計也是醉了
Metal 水果公司獨有的打月,其他平臺別指望了
Vulkan 新版的圖形接口,未來可能取代Opengl
DirectX Windows平臺特有的圖形接口
OpenVG 專注于矢量加速的硬件接口蚕捉,基本上沒啥人用

就拿Android來說吧奏篙,作為操作系統(tǒng)需要兼容各種硬件。硬件接口比較通用的就是OpenGL(其實早些年SGL在定義硬件的標準的時候迫淹,2D和3D是分開定義报破,2D用OpenVG加速,3D用OpenGL加速千绪。只是后面OpenVG沒有成為事實標準)充易,Windows是基于DX3D接口實現(xiàn)的,但是原理也是類似荸型。

那么硬件究竟是如何利用Opengl接口操作硬件來加速光柵化過程盹靴?這個要看看Opengl定義的規(guī)范了。

5. Opengl的渲染加速的原理

首先Opengl只能渲染 直線 三角形(之所以硬件指定是三角形瑞妇。 主要是因為光柵化也就是插值的過程, 當多邊形是凸多邊形的時候最容易處理稿静,硬件也只支持凸多邊形的插值。 三角形在三維變換后任然是凸多邊形, 而四邊形或者更高邊數(shù)的形狀在變換后可能會出現(xiàn)凹多邊形辕狰。其次其他形狀都可以細分成三角形改备。)。

對字母A的圖形做三角剖分

當程序需要繪制一個多邊形的時候蔓倍,首先需要將這個多邊形剖分成多個三角形悬钳,這個過程被稱之為三角剖分(剖分算法分2大類,幾何剖分點云剖分)偶翅。被剖分出來的三角形默勾,提交給顯卡。顯卡對每個三角形的掃描填充和像素融合處理是像素間無關(guān)的所以這類運算完全可以并行處理聚谁。GPU的并行處理每個三角形和三角形的像素染色母剥,每個渲染流水稱之為渲染管線。CPU在處理的過程中每次最多操作一個像素,而顯卡每次可能有幾千上萬甚至十萬的管線并行計算环疼,其次顯然的浮點數(shù)運算性能比CPU高非常多习霹。這個就是顯卡為什么能夠加速這個過程。

Android的HWUI的源碼中摘抄了一段:
Code Path: android / platform / frameworks / base / master / . / libs / hwui / PathTessellator.h

/*
 * Copyright (C) 2012 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
#ifndef ANDROID_HWUI_PATH_TESSELLATOR_H
#define ANDROID_HWUI_PATH_TESSELLATOR_H
#include "Matrix.h"
#include "Rect.h"
#include "Vertex.h"
#include "VertexBuffer.h"
#include <algorithm>
#include <vector>
class SkPath;
class SkPaint;
namespace android {
namespace uirenderer {
/**
 * Structure used for threshold values in outline path tessellation.
 *
 * TODO: PaintInfo should store one of this object, and initialized all values in constructor
 * depending on its type (point, line or path).
 */
struct PathApproximationInfo {
    PathApproximationInfo(float invScaleX, float invScaleY, float pixelThreshold)
        : thresholdSquared(pixelThreshold * pixelThreshold)
        , sqrInvScaleX(invScaleX * invScaleX)
        , sqrInvScaleY(invScaleY * invScaleY)
        , thresholdForConicQuads(pixelThreshold * std::min(invScaleX, invScaleY) / 2.0f) {
    };
    const float thresholdSquared;
    const float sqrInvScaleX;
    const float sqrInvScaleY;
    const float thresholdForConicQuads;
};
class PathTessellator {
public:
    /**
     * Populates scaleX and scaleY with the 'tessellation scale' of the transform - the effective X
     * and Y scales that tessellation will take into account when generating the 1.0 pixel thick
     * ramp.
     *
     * Two instances of the same shape (size, paint, etc.) will only generate the same vertices if
     * their tessellation scales are equal.
     */
    static void extractTessellationScales(const Matrix4& transform, float* scaleX, float* scaleY);
    /**
     * Populates a VertexBuffer with a tessellated approximation of the input convex path, as a single
     * triangle strip. Note: joins are not currently supported.
     *
     * @param path The path to be approximated
     * @param paint The paint the path will be drawn with, indicating AA, painting style
     *        (stroke vs fill), stroke width, stroke cap & join style, etc.
     * @param transform The transform the path is to be drawn with, used to drive stretch-aware path
     *        vertex approximation, and correct AA ramp offsetting.
     * @param vertexBuffer The output buffer
     */
    static void tessellatePath(const SkPath& path, const SkPaint* paint,
            const mat4& transform, VertexBuffer& vertexBuffer);
......

這段代碼就是HWUI中對路徑做的的三角剖分處理炫隶。

Opengl繪制幾何圖形存在的性能瓶頸 主要有以下3點:
?1. 三角剖分性能淋叶,如果我們需要繪制一個復(fù)雜的多邊形,那么首先需要把這個多邊形剖分成一個個三角形等限。這個剖發(fā)需要耗時
?2. 由于早期的GPU是作為外設(shè)鏈接到CPU上面的爸吮,所以GPU的RAM是和系統(tǒng)的內(nèi)存是分開的。所以數(shù)據(jù)需要通過系統(tǒng)BUS發(fā)送給顯卡望门,這過程也占據(jù)了大量的運行時間形娇。
?3. 每次提交一次渲染就做一次DrawCal,渲染的開始是管線重啟筹误。由于Opengl的API缺陷桐早,DrawCall非常貴重,DrawCall甚至一度被用來衡量軟件渲染的性能好壞厨剪。

Opengl繪制的優(yōu)勢 主要有以下3點:
?1. 硬件插值器實現(xiàn)的光柵化算法哄酝,性能飛快
?2. GPU天生的浮點數(shù)運算能力,在前后景圖Blend過程中可以飛快
?3. 硬件天生的并行運算特性

硬件就一定能加速么祷膳?
如果只是一個很簡單的圖形陶衅,那么CPU直接渲染的速度回更快。也就是:(CPU顏色填充時間 < 三角剖分的時間+數(shù)據(jù)通信的時間+GPU光柵的時間)直晨。比如Android的圖形基礎(chǔ)庫Skia就有基于Opengl的加速的優(yōu)化模塊搀军,Google給出了基于硬件加速后的API性能和CPU運算下的API的性能比較,你會發(fā)現(xiàn)并不是所有的繪制接口都有速度提升勇皇,甚至有部分API速度慢了十倍以上罩句。

以上就是硬件加速在傳統(tǒng)圖形界面中的位置,就目前來看硬件的確是加速了圖形的渲染敛摘,但是是不是所有場景都能加速门烂?硬件加速是不是圖形渲染的萬金油?還是要理解其中的原理兄淫,方能善用屯远。

版權(quán)所有,如有轉(zhuǎn)載請聯(lián)系我本人http://www.breakerror.com/archives/63-i.html

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末拖叙,一起剝皮案震驚了整個濱河市氓润,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌薯鳍,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,204評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異挖滤,居然都是意外死亡崩溪,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,091評論 3 395
  • 文/潘曉璐 我一進店門斩松,熙熙樓的掌柜王于貴愁眉苦臉地迎上來伶唯,“玉大人,你說我怎么就攤上這事惧盹∪樾遥” “怎么了?”我有些...
    開封第一講書人閱讀 164,548評論 0 354
  • 文/不壞的土叔 我叫張陵钧椰,是天一觀的道長粹断。 經(jīng)常有香客問我,道長嫡霞,這世上最難降的妖魔是什么瓶埋? 我笑而不...
    開封第一講書人閱讀 58,657評論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮诊沪,結(jié)果婚禮上养筒,老公的妹妹穿的比我還像新娘。我一直安慰自己端姚,他們只是感情好晕粪,可當我...
    茶點故事閱讀 67,689評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著渐裸,像睡著了一般巫湘。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上橄仆,一...
    開封第一講書人閱讀 51,554評論 1 305
  • 那天剩膘,我揣著相機與錄音,去河邊找鬼盆顾。 笑死怠褐,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的您宪。 我是一名探鬼主播奈懒,決...
    沈念sama閱讀 40,302評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼宪巨!你這毒婦竟也來了磷杏?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,216評論 0 276
  • 序言:老撾萬榮一對情侶失蹤捏卓,失蹤者是張志新(化名)和其女友劉穎极祸,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,661評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡遥金,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,851評論 3 336
  • 正文 我和宋清朗相戀三年浴捆,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片稿械。...
    茶點故事閱讀 39,977評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡选泻,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出美莫,到底是詐尸還是另有隱情页眯,我是刑警寧澤,帶...
    沈念sama閱讀 35,697評論 5 347
  • 正文 年R本政府宣布厢呵,位于F島的核電站窝撵,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏述吸。R本人自食惡果不足惜忿族,卻給世界環(huán)境...
    茶點故事閱讀 41,306評論 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望蝌矛。 院中可真熱鬧道批,春花似錦、人聲如沸入撒。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,898評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽茅逮。三九已至璃赡,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間献雅,已是汗流浹背碉考。 一陣腳步聲響...
    開封第一講書人閱讀 33,019評論 1 270
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留挺身,地道東北人侯谁。 一個月前我還...
    沈念sama閱讀 48,138評論 3 370
  • 正文 我出身青樓,卻偏偏與公主長得像章钾,于是被迫代替她去往敵國和親墙贱。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 44,927評論 2 355

推薦閱讀更多精彩內(nèi)容