OpenGL ES for iOS - 6

OpenGL ES 設(shè)計(jì)指南

現(xiàn)在您已經(jīng)掌握了在 iOS 應(yīng)用程序中使用 OpenGL ES 的基礎(chǔ)知識(shí)克伊,請(qǐng)使用本章中的信息來(lái)幫助您設(shè)計(jì)應(yīng)用程序的渲染引擎以獲得更好的性能酥郭。本章介紹渲染器設(shè)計(jì)的關(guān)鍵概念;后面的章節(jié)通過(guò)特定的最佳實(shí)踐和性能技術(shù)對(duì)此信息進(jìn)行了擴(kuò)展愿吹。

如何可視化 OpenGL ES

本節(jié)描述了可視化 OpenGL ES 設(shè)計(jì)的兩個(gè)視角:作為客戶(hù)端-服務(wù)器架構(gòu)和作為管道不从。這兩種觀點(diǎn)都有助于規(guī)劃和評(píng)估應(yīng)用程序的架構(gòu)。

OpenGL ES 作為客戶(hù)端-服務(wù)器架構(gòu)

圖 6-1 將 OpenGL ES 可視化為客戶(hù)端-服務(wù)器架構(gòu)犁跪。您的應(yīng)用程序?qū)顟B(tài)更改椿息、紋理和頂點(diǎn)數(shù)據(jù)以及渲染命令傳達(dá)給 OpenGL ES 客戶(hù)端】姥埽客戶(hù)端將此數(shù)據(jù)轉(zhuǎn)換為圖形硬件可以理解的格式寝优,并將它們轉(zhuǎn)發(fā)給 GPU。這些進(jìn)程會(huì)增加應(yīng)用程序的圖形性能開(kāi)銷(xiāo)枫耳。


Figure 6 - 1

實(shí)現(xiàn)出色的性能需要仔細(xì)管理這種開(kāi)銷(xiāo)乏矾。一個(gè)設(shè)計(jì)良好的應(yīng)用程序會(huì)減少它對(duì) OpenGL ES 的調(diào)用頻率,使用適合硬件的數(shù)據(jù)格式來(lái)最小化轉(zhuǎn)換成本迁杨,并仔細(xì)管理自身和 OpenGL ES 之間的數(shù)據(jù)流钻心。

OpenGL ES 作為圖形管道

圖 6-2 將 OpenGL ES 可視化為圖形管道。您的應(yīng)用程序配置圖形管道仑最,然后執(zhí)行繪圖命令以沿管道發(fā)送頂點(diǎn)數(shù)據(jù)扔役。管道的后續(xù)階段運(yùn)行頂點(diǎn)著色器來(lái)處理頂點(diǎn)數(shù)據(jù),將頂點(diǎn)組裝成圖元警医,將圖元光柵化成片段,運(yùn)行片段著色器來(lái)計(jì)算每個(gè)片段的顏色和深度值,并將片段混合到幀緩沖區(qū)中以進(jìn)行顯示预皇。


Figure 6 - 2

使用管道作為思維模型來(lái)確定您的應(yīng)用程序執(zhí)行哪些工作來(lái)生成新框架侈玄。您的渲染器設(shè)計(jì)包括編寫(xiě)著色器程序來(lái)處理管道的頂點(diǎn)和片段階段,組織您提供給這些程序的頂點(diǎn)和紋理數(shù)據(jù),以及配置驅(qū)動(dòng)管道固定功能階段的 OpenGL ES 狀態(tài)機(jī)。

圖形管道中的各個(gè)階段可以同時(shí)計(jì)算它們的結(jié)果——例如邦鲫,您的應(yīng)用程序可能會(huì)準(zhǔn)備新的圖元旱捧,而圖形硬件的不同部分對(duì)先前提交的幾何體執(zhí)行頂點(diǎn)和片段計(jì)算。但是喉悴,后期階段取決于早期階段的輸出。如果任何流水線(xiàn)階段執(zhí)行太多工作或執(zhí)行太慢,則其他流水線(xiàn)階段將閑置治唤,直到最慢的階段完成其工作。精心設(shè)計(jì)的應(yīng)用程序會(huì)根據(jù)圖形硬件功能平衡每個(gè)流水線(xiàn)階段執(zhí)行的工作糙申。

  • 重要提示:當(dāng)您調(diào)整應(yīng)用程序的性能時(shí)宾添,第一步通常是確定它在哪個(gè)階段遇到瓶頸,以及原因柜裸。

OpenGL ES 版本和渲染器架構(gòu)

iOS 支持三個(gè)版本的 OpenGL ES缕陕。較新的版本提供了更大的靈活性,允許您在不影響性能的情況下實(shí)現(xiàn)包含高質(zhì)量視覺(jué)效果的渲染算法疙挺。

OpenGL ES 3.0

OpenGL ES 3.0 是 iOS 7 中的新功能扛邑。您的應(yīng)用程序可以使用 OpenGL ES 3.0 中引入的功能來(lái)實(shí)現(xiàn)高級(jí)圖形編程技術(shù)(以前只能在桌面級(jí)硬件和游戲控制臺(tái)上使用),以獲得更快的圖形性能和引人注目的視覺(jué)效果铐然。

下面重點(diǎn)介紹了 OpenGL ES 3.0 的一些關(guān)鍵特性鹿榜。有關(guān)完整概述,請(qǐng)參閱 OpenGL ES API 注冊(cè)表中的 OpenGL ES 3.0 規(guī)范锦爵。

OpenGL ES 著色語(yǔ)言版本 3.0

GLSL ES 3.0 添加了新功能舱殿,例如統(tǒng)一塊、32 位整數(shù)和附加整數(shù)運(yùn)算险掀,用于在頂點(diǎn)和片段著色器程序中執(zhí)行更通用的計(jì)算任務(wù)沪袭。要在著色器程序中使用新語(yǔ)言,您的著色器源代碼必須以 #version 330 es 指令開(kāi)頭樟氢。 OpenGL ES 3.0 上下文與為 OpenGL ES 2.0 編寫(xiě)的著色器保持兼容冈绊。

有關(guān)更多詳細(xì)信息,請(qǐng)參閱 OpenGL ES API 注冊(cè)表中的采用 OpenGL ES 著色語(yǔ)言 3.0 版和 OpenGL ES 著色語(yǔ)言 3.0 規(guī)范埠啃。

多個(gè)渲染目標(biāo)

通過(guò)啟用多個(gè)渲染目標(biāo)死宣,您可以創(chuàng)建同時(shí)寫(xiě)入多個(gè)幀緩沖區(qū)附件的片段著色器。

此功能支持使用高級(jí)渲染算法碴开,例如延遲著色毅该,其中您的應(yīng)用程序首先渲染到一組紋理以存儲(chǔ)幾何數(shù)據(jù)博秫,然后執(zhí)行一個(gè)或多個(gè)從這些紋理讀取的著色傳遞并執(zhí)行照明計(jì)算以輸出最終圖片。由于這種方法預(yù)先計(jì)算了光照計(jì)算的輸入眶掌,因此向場(chǎng)景中添加大量光照的增量性能成本要小得多挡育。延遲著色算法需要多個(gè)渲染目標(biāo)支持,如圖 6-3 所示朴爬,以實(shí)現(xiàn)合理的性能即寒。否則,渲染到多個(gè)紋理需要對(duì)每個(gè)紋理進(jìn)行單獨(dú)的繪制過(guò)程召噩。


Figure 6-3

除了創(chuàng)建幀緩沖區(qū)對(duì)象中描述的過(guò)程之外母赵,您還可以設(shè)置多個(gè)渲染目標(biāo)。您不是為幀緩沖區(qū)創(chuàng)建單一顏色的附件具滴,而是創(chuàng)建多個(gè)附件凹嘲。然后,調(diào)用 glDrawBuffers 函數(shù)來(lái)指定在渲染中使用哪些幀緩沖區(qū)附件抵蚊,如清單 6-1 所示施绎。

// Attach (previously created) textures to the framebuffer.
glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, _colorTexture, 0);
glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D, _positionTexture, 0);
glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT2, GL_TEXTURE_2D, _normalTexture, 0);
glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, _depthTexture, 0);
 
// Specify the framebuffer attachments for rendering.
GLenum targets[] = {GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1, GL_COLOR_ATTACHMENT2};
glDrawBuffers(3, targets);

當(dāng)您的應(yīng)用程序發(fā)出繪圖命令時(shí),您的片段著色器會(huì)確定為每個(gè)渲染目標(biāo)中的每個(gè)像素輸出什么顏色(或非顏色數(shù)據(jù))贞绳。清單 6-2 顯示了一個(gè)基本的片段著色器谷醉,它通過(guò)分配位置與清單 6-1 中設(shè)置的位置匹配的片段輸出變量來(lái)渲染多個(gè)目標(biāo)。

#version 300 es
 
uniform lowp sampler2D myTexture;
in mediump vec2 texCoord;
in mediump vec4 position;
in mediump vec3 normal;
 
layout(location = 0) out lowp vec4 colorData;
layout(location = 1) out mediump vec4 positionData;
layout(location = 2) out mediump vec4 normalData;
 
void main()
{
    colorData = texture(myTexture, texCoord);
    positionData = position;
    normalData = vec4(normalize(normal), 1.0);
}

多個(gè)渲染目標(biāo)也可用于其他高級(jí)圖形技術(shù)冈闭,例如實(shí)時(shí)反射俱尼、屏幕空間環(huán)境遮擋和體積照明。

轉(zhuǎn)換反饋

圖形硬件使用針對(duì)矢量處理優(yōu)化的高度并行化架構(gòu)萎攒。您可以通過(guò)新的變換反饋功能更好地利用此硬件遇八,該功能可讓您將頂點(diǎn)著色器的輸出捕獲到 GPU 內(nèi)存中的緩沖區(qū)對(duì)象中。您可以從一個(gè)渲染通道捕獲數(shù)據(jù)以用于另一個(gè)渲染通道耍休,或者禁用部分圖形管道并使用變換反饋進(jìn)行通用計(jì)算刃永。

一種受益于變換反饋的技術(shù)是動(dòng)畫(huà)粒子效果。渲染粒子系統(tǒng)的一般架構(gòu)如圖 6-4 所示羊精。首先斯够,應(yīng)用程序設(shè)置粒子模擬的初始狀態(tài)。然后喧锦,對(duì)于渲染的每一幀读规,應(yīng)用程序都會(huì)運(yùn)行一個(gè)模擬步驟,更新每個(gè)模擬粒子的位置燃少、方向和速度束亏,然后繪制代表粒子當(dāng)前狀態(tài)的視覺(jué)資產(chǎn)。


Figure 6-4

傳統(tǒng)上阵具,實(shí)現(xiàn)粒子系統(tǒng)的應(yīng)用程序在 CPU 上運(yùn)行其模擬碍遍,將模擬結(jié)果存儲(chǔ)在頂點(diǎn)緩沖區(qū)中以用于渲染粒子藝術(shù)定铜。但是,將頂點(diǎn)緩沖區(qū)的內(nèi)容傳輸?shù)?GPU 內(nèi)存非常耗時(shí)雀久。通過(guò)優(yōu)化現(xiàn)代 GPU 硬件中可用的并行架構(gòu)的能力宿稀,轉(zhuǎn)換反饋可以更有效地解決問(wèn)題趁舀。

借助變換反饋赖捌,您可以設(shè)計(jì)渲染引擎以更有效地解決此問(wèn)題。圖 6-5 顯示了您的應(yīng)用程序如何配置 OpenGL ES 圖形管道以實(shí)現(xiàn)粒子系統(tǒng)動(dòng)畫(huà)的概述矮烹。由于 OpenGL ES 將每個(gè)粒子及其狀態(tài)表示為一個(gè)頂點(diǎn)越庇,因此 GPU 的頂點(diǎn)著色器階段可以同時(shí)運(yùn)行多個(gè)粒子的模擬。由于包含粒子狀態(tài)數(shù)據(jù)的頂點(diǎn)緩沖區(qū)在幀之間重復(fù)使用奉狈,因此將數(shù)據(jù)傳輸?shù)?GPU 內(nèi)存的昂貴過(guò)程僅在初始化時(shí)發(fā)生一次卤唉。


Figure 6-5
  • 在初始化時(shí),創(chuàng)建一個(gè)頂點(diǎn)緩沖區(qū)并用包含模擬中所有粒子初始狀態(tài)的數(shù)據(jù)填充它仁期。

  • 在 GLSL 頂點(diǎn)著色器程序中實(shí)現(xiàn)您的粒子模擬桑驱,并通過(guò)繪制包含粒子位置數(shù)據(jù)的頂點(diǎn)緩沖區(qū)的內(nèi)容來(lái)每幀運(yùn)行它。

    • 要在啟用變換反饋的情況下進(jìn)行渲染跛蛋,請(qǐng)調(diào)用 glBeginTransformFeedback 函數(shù)熬的。 (在恢復(fù)正常繪圖之前調(diào)用 glEndTransformFeedback()。)
    • 使用 glTransformFeedbackVaryings 函數(shù)指定變換反饋應(yīng)捕獲哪些著色器輸出赊级,并使用 glBindBufferBase 或 glBindBufferRange 函數(shù)和 GL_TRANSFORM_FEEDBACK_BUFFER 緩沖區(qū)類(lèi)型指定它們將被捕獲到的緩沖區(qū)押框。
    • 通過(guò)調(diào)用 glEnable(GL_RASTERIZER_DISCARD) 禁用光柵化(以及管道的后續(xù)階段)。
  • 要渲染模擬結(jié)果以供顯示理逊,請(qǐng)使用包含粒子位置的頂點(diǎn)緩沖區(qū)作為第二次繪制過(guò)程的輸入橡伞,再次啟用光柵化(和管道的其余部分)并使用適合渲染應(yīng)用程序視覺(jué)內(nèi)容的頂點(diǎn)和片段著色器。

  • 在下一幀上兑徘,使用上一幀模擬步驟輸出的頂點(diǎn)緩沖區(qū)作為下一個(gè)模擬步驟的輸入。

可以從變換反饋中受益的其他圖形編程技術(shù)包括骨架動(dòng)畫(huà)(也稱(chēng)為蒙皮)和光線(xiàn)行進(jìn)羡洛。

OpenGL ES 2.0

OpenGL ES 2.0 提供了具有可編程著色器的靈活圖形管道挂脑,可用于所有當(dāng)前的 iOS 設(shè)備。 OpenGL ES 3.0 規(guī)范中正式引入的許多功能可通過(guò) OpenGL ES 2.0 擴(kuò)展提供給 iOS 設(shè)備翘县,因此您可以實(shí)現(xiàn)許多高級(jí)圖形編程技術(shù)最域,同時(shí)與大多數(shù)設(shè)備保持兼容。

OpenGL ES 1.1

OpenGL ES 1.1 僅提供基本的固定功能圖形管道锈麸。 iOS 支持 OpenGL ES 1.1 主要是為了向后兼容镀脂。如果您正在維護(hù) OpenGL ES 1.1 應(yīng)用程序,請(qǐng)考慮為較新的 OpenGL ES 版本更新您的代碼忘伞。

設(shè)計(jì)高性能 OpenGL ES 應(yīng)用程序

總而言之薄翅,一個(gè)設(shè)計(jì)良好的 OpenGL ES 應(yīng)用程序需要:

  • 利用 OpenGL ES 管道中的并行性沙兰。
  • 管理應(yīng)用程序和圖形硬件之間的數(shù)據(jù)流。

圖 6-6 建議了使用 OpenGL ES 為顯示器執(zhí)行動(dòng)畫(huà)的應(yīng)用程序的流程翘魄。


Figure6-6

當(dāng)應(yīng)用程序啟動(dòng)時(shí)鼎天,它所做的第一件事就是初始化在應(yīng)用程序的生命周期內(nèi)不打算更改的資源。理想情況下暑竟,應(yīng)用程序?qū)⑦@些資源封裝到 OpenGL ES 對(duì)象中斋射。目標(biāo)是創(chuàng)建可以在應(yīng)用程序運(yùn)行時(shí)(甚至是應(yīng)用程序生命周期的一部分,例如游戲關(guān)卡的持續(xù)時(shí)間)保持不變的任何對(duì)象但荤,以增加初始化時(shí)間來(lái)?yè)Q取更好的渲染性能罗岖。復(fù)雜的命令或狀態(tài)更改應(yīng)替換為可與單個(gè)函數(shù)調(diào)用一起使用的 OpenGL ES 對(duì)象。例如腹躁,配置固定功能管道可能需要進(jìn)行數(shù)十次函數(shù)調(diào)用桑包。相反,在初始化時(shí)編譯圖形著色器纺非,并在運(yùn)行時(shí)通過(guò)單個(gè)函數(shù)調(diào)用切換到它哑了。創(chuàng)建或修改成本高昂的 OpenGL ES 對(duì)象幾乎總是應(yīng)創(chuàng)建為靜態(tài)對(duì)象。

渲染循環(huán)處理您打算渲染到 OpenGL ES 上下文的所有項(xiàng)目烧颖,然后將結(jié)果呈現(xiàn)給顯示器弱左。在動(dòng)畫(huà)場(chǎng)景中,每幀都會(huì)更新一些數(shù)據(jù)倒信。在圖 6-6 所示的內(nèi)部渲染循環(huán)中科贬,應(yīng)用程序在更新渲染資源(在此過(guò)程中創(chuàng)建或修改 OpenGL ES 對(duì)象)和提交使用這些資源的繪圖命令之間交替進(jìn)行。這個(gè)內(nèi)循環(huán)的目標(biāo)是平衡工作負(fù)載鳖悠,使 CPU 和 GPU 并行工作榜掌,防止應(yīng)用程序和 OpenGL ES 同時(shí)訪(fǎng)問(wèn)相同的資源。在 iOS 上乘综,當(dāng)修改不是在幀的開(kāi)始或結(jié)束時(shí)執(zhí)行時(shí)憎账,修改 OpenGL ES 對(duì)象可能會(huì)很昂貴。

此內(nèi)部循環(huán)的一個(gè)重要目標(biāo)是避免將數(shù)據(jù)從 OpenGL ES 復(fù)制回應(yīng)用程序卡辰。將結(jié)果從 GPU 復(fù)制到 CPU 可能非常慢胞皱。如果復(fù)制的數(shù)據(jù)稍后也用作渲染當(dāng)前幀的過(guò)程的一部分,如中間渲染循環(huán)所示九妈,您的應(yīng)用程序會(huì)阻塞反砌,直到完成所有先前提交的繪圖命令。

在應(yīng)用程序提交框架中所需的所有繪圖命令后萌朱,它會(huì)將結(jié)果呈現(xiàn)到屏幕上宴树。非交互式應(yīng)用程序會(huì)將最終圖像復(fù)制到應(yīng)用程序內(nèi)存中以進(jìn)行進(jìn)一步處理。

最后晶疼,當(dāng)您的應(yīng)用程序準(zhǔn)備退出時(shí)酒贬,或完成一項(xiàng)主要任務(wù)時(shí)又憨,它會(huì)釋放 OpenGL ES 對(duì)象,以便為自身或其他應(yīng)用程序提供額外的資源锭吨。
總結(jié)一下這個(gè)設(shè)計(jì)的重要特征:

  • 在可行時(shí)創(chuàng)建靜態(tài)資源蠢莺。
  • 內(nèi)部渲染循環(huán)在修改動(dòng)態(tài)資源和提交渲染命令之間交替。盡量避免修改動(dòng)態(tài)資源零如,除非在幀的開(kāi)頭或結(jié)尾躏将。
  • 避免將中間渲染結(jié)果讀回您的應(yīng)用程序。
  • 本章的其余部分提供了有用的 OpenGL ES 編程技術(shù)來(lái)實(shí)現(xiàn)此渲染循環(huán)的功能埠况。后面的章節(jié)將演示如何將這些通用技術(shù)應(yīng)用于 OpenGL ES 編程的特定領(lǐng)域耸携。

避免同步和刷新操作

OpenGL ES 規(guī)范不需要立即執(zhí)行命令的實(shí)現(xiàn)棵癣。通常辕翰,命令排隊(duì)到命令緩沖區(qū)并在稍后由硬件執(zhí)行。通常狈谊,OpenGL ES 會(huì)等待應(yīng)用程序?qū)⒃S多命令排入隊(duì)列喜命,然后再將命令發(fā)送到硬件——批處理通常更有效。但是河劝,某些 OpenGL ES 函數(shù)必須立即刷新命令緩沖區(qū)壁榕。其他函數(shù)不僅刷新命令緩沖區(qū),而且在返回對(duì)應(yīng)用程序的控制之前阻塞直到先前提交的命令完成赎瞎。僅在需要該行為時(shí)才使用刷新和同步命令牌里。過(guò)度使用刷新或同步命令可能會(huì)導(dǎo)致您的應(yīng)用程序在等待硬件完成渲染時(shí)停頓。

這些情況需要 OpenGL ES 將命令緩沖區(qū)提交給硬件執(zhí)行务甥。

  • 函數(shù) glFlush 將命令緩沖區(qū)發(fā)送到圖形硬件牡辽。它阻塞直到命令提交給硬件,但不等待命令完成執(zhí)行敞临。
  • 函數(shù) glFinish 刷新命令緩沖區(qū)态辛,然后等待所有先前提交的命令在圖形硬件上完成執(zhí)行。
  • 檢索幀緩沖區(qū)內(nèi)容的函數(shù)(例如 glReadPixels)也會(huì)等待提交的命令完成挺尿。
  • 命令緩沖區(qū)已滿(mǎn)奏黑。

有效地使用 glFlush

在某些桌面 OpenGL 實(shí)現(xiàn)中,定期調(diào)用 glFlush 函數(shù)來(lái)有效地平衡 CPU 和 GPU 工作可能很有用编矾,但在 iOS 中并非如此熟史。 iOS 圖形硬件實(shí)現(xiàn)的 Tile-Based Deferred Rendering 算法依賴(lài)于一次緩沖場(chǎng)景中的所有頂點(diǎn)數(shù)據(jù),因此可以對(duì)其進(jìn)行優(yōu)化處理以去除隱藏表面窄俏。通常蹂匹,只有兩種情況下 OpenGL ES 應(yīng)用程序應(yīng)該調(diào)用 glFlush 或 glFinish 函數(shù)。

  • 當(dāng)您的應(yīng)用程序移至后臺(tái)時(shí)裆操,您應(yīng)該刷新命令緩沖區(qū)怒详,因?yàn)楫?dāng)您的應(yīng)用程序在后臺(tái)時(shí)在 GPU 上執(zhí)行 OpenGL ES 命令會(huì)導(dǎo)致 iOS 終止您的應(yīng)用程序炉媒。 (請(qǐng)參閱實(shí)現(xiàn)多任務(wù)感知 OpenGL ES 應(yīng)用程序。)
  • 如果您的應(yīng)用程序在多個(gè)上下文之間共享 OpenGL ES 對(duì)象(例如頂點(diǎn)緩沖區(qū)或紋理)昆烁,您應(yīng)該調(diào)用 glFlush 函數(shù)來(lái)同步對(duì)這些資源的訪(fǎng)問(wèn)吊骤。例如,您應(yīng)該在一個(gè)上下文中加載頂點(diǎn)數(shù)據(jù)后調(diào)用 glFlush 函數(shù)静尼,以確保其內(nèi)容已準(zhǔn)備好被另一個(gè)上下文檢索白粉。當(dāng)與其他 iOS API(例如 Core Image)共享 OpenGL ES 對(duì)象時(shí),此建議也適用鼠渺。

避免查詢(xún) OpenGL ES 狀態(tài)

對(duì) glGet*() 的調(diào)用鸭巴,包括 glGetError(),可能需要 OpenGL ES 在檢索任何狀態(tài)變量之前執(zhí)行先前的命令拦盹。這種同步迫使圖形硬件與 CPU 同步運(yùn)行鹃祖,從而減少并行的機(jī)會(huì)。為避免這種情況普舆,請(qǐng)維護(hù)您自己需要查詢(xún)的任何狀態(tài)的副本恬口,并直接訪(fǎng)問(wèn)它,而不是調(diào)用 OpenGL ES沼侣。

發(fā)生錯(cuò)誤時(shí)祖能,OpenGL ES 會(huì)設(shè)置錯(cuò)誤標(biāo)志。這些和其他錯(cuò)誤出現(xiàn)在 Xcode 中的 OpenGL ES 幀調(diào)試器或儀器中的 OpenGL ES 分析器中蛾洛。您應(yīng)該使用這些工具而不是 glGetError 函數(shù)养铸,如果頻繁調(diào)用會(huì)降低性能。其他查詢(xún)轧膘,例如 glCheckFramebufferStatus()钞螟、glGetProgramInfoLog() 和 glValidateProgram() 通常也僅在開(kāi)發(fā)和調(diào)試時(shí)有用。您應(yīng)該在應(yīng)用的發(fā)布版本中省略對(duì)這些函數(shù)的調(diào)用扶供。

使用 OpenGL ES 管理您的資源

許多 OpenGL 數(shù)據(jù)可以直接存儲(chǔ)在 OpenGL ES 渲染上下文及其關(guān)聯(lián)的共享組對(duì)象中筛圆。 OpenGL ES 實(shí)現(xiàn)可以自由地將數(shù)據(jù)轉(zhuǎn)換為最適合圖形硬件的格式。這可以顯著提高性能椿浓,尤其是對(duì)于不經(jīng)常更改的數(shù)據(jù)太援。您的應(yīng)用程序還可以向 OpenGL ES 提供有關(guān)它打算如何使用數(shù)據(jù)的提示。 OpenGL ES 實(shí)現(xiàn)可以使用這些提示來(lái)更有效地處理數(shù)據(jù)扳碍。例如提岔,靜態(tài)數(shù)據(jù)可能被放置在圖形處理器可以輕松獲取的內(nèi)存中,甚至可以放入專(zhuān)用的圖形內(nèi)存中笋敞。

使用雙緩沖避免資源沖突

當(dāng)您的應(yīng)用程序和 OpenGL ES 同時(shí)訪(fǎng)問(wèn) OpenGL ES 對(duì)象時(shí)碱蒙,就會(huì)發(fā)生資源沖突。當(dāng)一個(gè)參與者嘗試修改另一個(gè)正在使用的 OpenGL ES 對(duì)象時(shí),他們可能會(huì)阻塞赛惩,直到該對(duì)象不再使用哀墓。一旦他們開(kāi)始修改對(duì)象其他參與者在修改完成之前可能無(wú)法訪(fǎng)問(wèn)該對(duì)象∨缂妫或者篮绰,OpenGL ES 可以隱式復(fù)制對(duì)象,以便兩個(gè)參與者可以繼續(xù)執(zhí)行命令季惯。任何一個(gè)選項(xiàng)都是安全的吠各,但每個(gè)選項(xiàng)最終都可能成為您的應(yīng)用程序的瓶頸。圖 6-7 顯示了這個(gè)問(wèn)題勉抓。在此示例中贾漏,有一個(gè)紋理對(duì)象,OpenGL ES 和您的應(yīng)用程序都希望使用它藕筋。當(dāng)應(yīng)用程序嘗試更改紋理時(shí)纵散,它必須等待之前提交的繪圖命令完成——CPU 與 GPU 同步


Figure6-7

為了解決這個(gè)問(wèn)題,您的應(yīng)用程序可以在更改對(duì)象和使用它繪圖之間執(zhí)行額外的工作念逞。但是困食,如果您的應(yīng)用程序沒(méi)有可以執(zhí)行的額外工作,則應(yīng)明確創(chuàng)建兩個(gè)大小相同的對(duì)象翎承;當(dāng)一個(gè)參與者閱讀一個(gè)對(duì)象時(shí),另一個(gè)參與者修改另一個(gè)符匾。圖 6-8 說(shuō)明了雙緩沖方法叨咖。當(dāng) GPU 處理一個(gè)紋理時(shí),CPU 修改另一個(gè)紋理啊胶。初始啟動(dòng)后甸各,CPU 或 GPU 都沒(méi)有閑置。盡管顯示的是紋理焰坪,但該解決方案幾乎適用于任何類(lèi)型的 OpenGL ES 對(duì)象趣倾。
雙緩沖對(duì)于大多數(shù)應(yīng)用程序來(lái)說(shuō)已經(jīng)足夠了,但它要求兩個(gè)參與者大致在同一時(shí)間完成處理命令某饰。為避免阻塞儒恋,您可以添加更多緩沖區(qū);這實(shí)現(xiàn)了傳統(tǒng)的生產(chǎn)者-消費(fèi)者模型黔漂。如果生產(chǎn)者在消費(fèi)者完成處理命令之前完成诫尽,它會(huì)占用一個(gè)空閑緩沖區(qū)并繼續(xù)處理命令。在這種情況下炬守,生產(chǎn)者只有在消費(fèi)者嚴(yán)重落后時(shí)才會(huì)空閑牧嫉。

雙緩沖和三緩沖權(quán)衡消耗額外的內(nèi)存以防止管道停頓。額外使用內(nèi)存可能會(huì)對(duì)應(yīng)用程序的其他部分造成壓力。在 iOS 設(shè)備上酣藻,內(nèi)存可能很稀缺曹洽;您的設(shè)計(jì)可能需要在使用更多內(nèi)存與其他應(yīng)用程序優(yōu)化之間取得平衡。

注意 OpenGL ES 狀態(tài)

OpenGL ES 實(shí)現(xiàn)維護(hù)一組復(fù)雜的狀態(tài)數(shù)據(jù)辽剧,包括您使用 glEnable 或 glDisable 函數(shù)設(shè)置的開(kāi)關(guān)衣洁、當(dāng)前著色器程序及其統(tǒng)一變量、當(dāng)前綁定的紋理單元抖仅、當(dāng)前綁定的頂點(diǎn)緩沖區(qū)及其啟用的頂點(diǎn)屬性坊夫。硬件有一個(gè)當(dāng)前狀態(tài),它被懶惰地編譯和緩存撤卢。切換狀態(tài)的成本很高环凿,因此最好設(shè)計(jì)您的應(yīng)用程序以盡量減少狀態(tài)切換。

不要設(shè)置已經(jīng)設(shè)置的狀態(tài)放吩。功能一旦啟用智听,就不需要再次啟用。例如渡紫,如果您多次調(diào)用具有相同參數(shù)的 glUniform 函數(shù)到推,OpenGL ES 可能不會(huì)檢查是否已經(jīng)設(shè)置了相同的統(tǒng)一狀態(tài)。即使該值與當(dāng)前值相同惕澎,它也會(huì)簡(jiǎn)單地更新?tīng)顟B(tài)值莉测。

通過(guò)使用專(zhuān)用的設(shè)置或關(guān)閉例程而不是將此類(lèi)調(diào)用置于繪圖循環(huán)中,避免設(shè)置不必要的狀態(tài)唧喉。設(shè)置和關(guān)閉例程對(duì)于打開(kāi)和關(guān)閉實(shí)現(xiàn)特定視覺(jué)效果的功能也很有用捣卤,例如,在帶紋理的多邊形周?chē)L制線(xiàn)框輪廓時(shí)八孝。

使用 OpenGL ES 對(duì)象封裝狀態(tài)

為了減少狀態(tài)變化董朝,創(chuàng)建將多個(gè) OpenGL ES 狀態(tài)變化收集到一個(gè)可以與單個(gè)函數(shù)調(diào)用綁定的對(duì)象的對(duì)象。例如干跛,頂點(diǎn)數(shù)組對(duì)象將多個(gè)頂點(diǎn)屬性的配置存儲(chǔ)到單個(gè)對(duì)象中子姜。請(qǐng)參閱使用頂點(diǎn)數(shù)組對(duì)象合并頂點(diǎn)數(shù)組狀態(tài)更改。(VAO)

組織繪圖調(diào)用以最小化狀態(tài)更改

更改 OpenGL ES 狀態(tài)不會(huì)立即生效楼入。相反哥捕,當(dāng)您發(fā)出繪圖命令時(shí),OpenGL ES 會(huì)執(zhí)行使用一組狀態(tài)值進(jìn)行繪圖所需的工作浅辙。您可以通過(guò)最小化狀態(tài)更改來(lái)減少重新配置圖形管道所花費(fèi)的 CPU 時(shí)間扭弧。例如,在您的應(yīng)用程序中保留一個(gè)狀態(tài)向量记舆,并僅當(dāng)您的狀態(tài)在繪制調(diào)用之間發(fā)生變化時(shí)才設(shè)置相應(yīng)的 OpenGL ES 狀態(tài)鸽捻。另一個(gè)有用的算法是狀態(tài)排序——跟蹤您需要執(zhí)行的繪圖操作以及每個(gè)操作所需的狀態(tài)更改量,然后對(duì)它們進(jìn)行排序以連續(xù)使用相同的狀態(tài)執(zhí)行操作。

OpenGL ES 的 iOS 實(shí)現(xiàn)可以緩存它在狀態(tài)之間高效切換所需的一些配置數(shù)據(jù)御蒲,但每個(gè)唯一狀態(tài)集的初始配置需要更長(zhǎng)的時(shí)間衣赶。為了獲得一致的性能,您可以“預(yù)熱”您計(jì)劃在設(shè)置例程中使用的每個(gè)狀態(tài)集:

  • 啟用您計(jì)劃使用的狀態(tài)配置或著色器厚满。
  • 使用該狀態(tài)配置繪制少量頂點(diǎn)府瞄。
  • 刷新 OpenGL ES 上下文,以便不顯示在此預(yù)熱階段期間的繪圖碘箍。
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末遵馆,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子丰榴,更是在濱河造成了極大的恐慌货邓,老刑警劉巖,帶你破解...
    沈念sama閱讀 221,198評(píng)論 6 514
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件四濒,死亡現(xiàn)場(chǎng)離奇詭異换况,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)盗蟆,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,334評(píng)論 3 398
  • 文/潘曉璐 我一進(jìn)店門(mén)戈二,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人喳资,你說(shuō)我怎么就攤上這事觉吭。” “怎么了骨饿?”我有些...
    開(kāi)封第一講書(shū)人閱讀 167,643評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵亏栈,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我宏赘,道長(zhǎng),這世上最難降的妖魔是什么黎侈? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 59,495評(píng)論 1 296
  • 正文 為了忘掉前任察署,我火速辦了婚禮,結(jié)果婚禮上峻汉,老公的妹妹穿的比我還像新娘贴汪。我一直安慰自己,他們只是感情好休吠,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,502評(píng)論 6 397
  • 文/花漫 我一把揭開(kāi)白布扳埂。 她就那樣靜靜地躺著,像睡著了一般瘤礁。 火紅的嫁衣襯著肌膚如雪阳懂。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 52,156評(píng)論 1 308
  • 那天,我揣著相機(jī)與錄音岩调,去河邊找鬼巷燥。 笑死,一個(gè)胖子當(dāng)著我的面吹牛号枕,可吹牛的內(nèi)容都是我干的缰揪。 我是一名探鬼主播,決...
    沈念sama閱讀 40,743評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼葱淳,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼钝腺!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起赞厕,我...
    開(kāi)封第一講書(shū)人閱讀 39,659評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤艳狐,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后坑傅,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體僵驰,經(jīng)...
    沈念sama閱讀 46,200評(píng)論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,282評(píng)論 3 340
  • 正文 我和宋清朗相戀三年唁毒,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了蒜茴。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,424評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡浆西,死狀恐怖粉私,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情近零,我是刑警寧澤诺核,帶...
    沈念sama閱讀 36,107評(píng)論 5 349
  • 正文 年R本政府宣布,位于F島的核電站久信,受9級(jí)特大地震影響窖杀,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜裙士,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,789評(píng)論 3 333
  • 文/蒙蒙 一入客、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧腿椎,春花似錦桌硫、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 32,264評(píng)論 0 23
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至南用,卻和暖如春膀钠,著一層夾襖步出監(jiān)牢的瞬間掏湾,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,390評(píng)論 1 271
  • 我被黑心中介騙來(lái)泰國(guó)打工托修, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留忘巧,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,798評(píng)論 3 376
  • 正文 我出身青樓睦刃,卻偏偏與公主長(zhǎng)得像砚嘴,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子涩拙,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,435評(píng)論 2 359

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