配置OpenGL ES上下文
OpenGL ES的每個實現(xiàn)都提供了一種創(chuàng)建渲染上下文以管理OpenGL ES規(guī)范所需狀態(tài)的方法孙咪。通過在上下文中放置此狀態(tài),多個應用程序可以輕松共享圖形硬件巡语,而不會干擾對方的狀態(tài)翎蹈。
本章詳細介紹了如何在iOS上創(chuàng)建和配置上下文。
EAGL是iOS實現(xiàn)的OpenGL ES渲染上下文
在您的應用程序可以調(diào)用任何OpenGL ES函數(shù)之前男公,必須初始化一個EAGLContext對象荤堪。 EAGLContext類還提供了將OpenGL ES內(nèi)容與Core Animation集成的方法合陵。
當前上下文是OpenGL ES函數(shù)調(diào)用的目標
iOS應用程序中的每個線程都具有當前上下文;當您調(diào)用OpenGL ES函數(shù)時,這是通過調(diào)用更改其狀態(tài)的上下文。
要設(shè)置線程的當前上下文嗡载,請在該線程上執(zhí)行時調(diào)用EAGLContext類方法setCurrentContext梅猿。
[EAGLContext setCurrentContext: myContext];
調(diào)用EAGLContext類方法currentContext以檢索線程的當前上下文。
注意:如果您的應用程序主動在同一線程上的兩個或多個上下文之間切換低剔,請在設(shè)置新的上下文作為當前上下文之前調(diào)用glFlush函數(shù)。這樣可以確保先前提交的命令及時傳遞給圖形硬件肮塞。
OpenGL ES持有對當前上下文對應的EAGLContext對象的強引用襟齿。 (如果使用手動引用計數(shù),OpenGL ES會保留此對象枕赵。)當調(diào)用setCurrentContext:方法來更改當前上下文時猜欺,OpenGL ES不再引用上一個上下文。 (如果您使用手動引用計數(shù)拷窜,OpenGL ES將釋放EAGLContext對象开皿。)為防止當不在當前上下文時EAGLContext對象被釋放,您的應用程序必須保持強制引用(或保留)這些對象装黑。
每個上下文都針對特定版本的OpenGL ES
EAGLContext對象只支持一個版本的OpenGL ES副瀑。例如,為OpenGL ES 1.1編寫的代碼與OpenGL ES 2.0或3.0上下文不兼容恋谭。使用核心OpenGL ES 2.0功能的代碼與OpenGL ES 3.0上下文兼容糠睡,為OpenGL ES 2.0擴展設(shè)計的代碼通常可以在OpenGL ES 3.0上下文中進行微小更改疚颊。許多新的OpenGL ES 3.0功能和增加的硬件功能需要OpenGL ES 3.0上下文狈孔。
當您創(chuàng)建并初始化EAGLContext對象時,您的應用程序?qū)Q定要支持的OpenGL ES版本材义。如果設(shè)備不支持所需版本的OpenGL ES均抽,initWithAPI:方法返回nil。您的應用程序必須進行測試其掂,以確保上下文在使用之前已初始化成功油挥。
為了支持OpenGL ES的多個版本作為應用程序中的渲染選項,您應該首先嘗試初始化要定位的最新版本的渲染上下文款熬。如果返回的對象為nil深寥,則初始化舊版本的上下文。清單2-1演示了如何做到這一點贤牛。
EAGLContext* CreateBestEAGLContext()
{
EAGLContext *context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES3];
if (context == nil) {
context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2];
}
return context;
}
上下文的API屬性指出上下文支持的OpenGL ES版本惋鹅。您的應用程序應測試上下文的API屬性并使用它來選擇正確的渲染路徑。實現(xiàn)此行為的常見模式是為每個渲染路徑創(chuàng)建一個類殉簸。您的應用程序在初始化時測試上下文并創(chuàng)建一次渲染器闰集。
EAGL共享組管理上下文的OpenGL ES對象
盡管上下文保持OpenGL ES狀態(tài)沽讹,但它并不直接管理OpenGL ES對象。相反武鲁,OpenGL ES對象由EAGLSharegroup對象創(chuàng)建和維護爽雄。每個上下文都包含一個EAGLSharegroup對象,它將對象創(chuàng)建委托給沐鼠。
當兩個或多個上下文引用相同的共享組時盲链,共享組的優(yōu)點變得明顯,如圖2-1所示迟杂。當多個上下文連接到公共共享組時,由任何上下文創(chuàng)建的OpenGL ES對象可用于所有上下文;如果綁定到與創(chuàng)建它相同的上下文上的相同對象標識符本慕,則引用同一個OpenGL ES對象排拷。移動設(shè)備上的資源通常很少;在多個上下文中創(chuàng)建相同內(nèi)容的多個副本是浪費的。共享共享資源可以更好地利用設(shè)備上可用的圖形資源锅尘。
一個共享組是一個不透明的對象;它沒有您的應用可以調(diào)用的方法或?qū)傩约嗲狻J褂胹haregroup對象的上下文保持強有力的參考。
在兩種具體情況下藤违,共享組最有用
- 當上下文之間共享的大部分資源是不變的浪腐。
- 當您希望您的應用程序能夠在除渲染器的主線程之外的線程上創(chuàng)建新的OpenGL ES對象。在這種情況下顿乒,第二個上下文在單獨的線程上運行议街,專門用于獲取數(shù)據(jù)和創(chuàng)建資源。在資源被加載之后璧榄,第一個上下文可以綁定到對象并立即使用它特漩。 GLKTextureLoader類使用此模式提供異步紋理加載。
要創(chuàng)建引用同一個共享組的多個上下文骨杂,首先通過調(diào)用initWithAPI:將為上下文自動創(chuàng)建一個共享組涂身。第二個和更晚的上下文通過調(diào)用initWithAPI:sharegroup:方法來初始化為使用第一個上下文的共享組。清單2-2顯示了如何工作搓蚪。第一個上下文使用清單2-1中定義的方便函數(shù)創(chuàng)建蛤售。第二個上下文通過從第一個上下文提取API版本和共享組來創(chuàng)建。
重要提示:與同一共享組相關(guān)聯(lián)的所有上下文都必須使用與初始上下文相同版本的OpenGL ES API
EAGLContext* firstContext = CreateBestEAGLContext();
EAGLContext* secondContext = [[EAGLContext alloc] initWithAPI:[firstContext API] sharegroup: [firstContext sharegroup]];
當共享組由多個上下文共享時妒潭,應用程序有責任管理OpenGL ES對象的狀態(tài)更改悴能。規(guī)則如下:
- 如果對象未被修改,您的應用程序可以同時訪問跨多個上下文的對象杜耙。
- 當對象被發(fā)送到上下文的命令修改時搜骡,對象不得在任何其他上下文中被讀取或修改。
- 修改對象后佑女,所有上下文都必須重新綁定對象以查看更改记靡。如果上下文在綁定它之前引用它谈竿,則對象的內(nèi)容是未定義的。
以下是您的應用程序應該更新OpenGL ES對象的步驟:
- 在可能使用對象的每個上下文上調(diào)用glFlush摸吠。
- 在要修改對象的上下文中空凸,調(diào)用一個或多個OpenGL ES函數(shù)來更改對象。
- 在接收到狀態(tài)修改命令的上下文中調(diào)用glFlush寸痢。
- 在其他上下文中呀洲,重新綁定對象標識符。
注意:共享對象的另一種方法是使用單個渲染上下文啼止,但使用多個目標幀緩沖區(qū)道逗。在渲染時,您的應用程序會綁定相應的幀緩沖區(qū)献烦,并根據(jù)需要呈現(xiàn)其幀滓窍。因為所有OpenGL ES對象都是從單個上下文中引用的,所以它們會看到相同的OpenGL ES數(shù)據(jù)巩那。此模式使用較少的資源吏夯,但僅適用于可以仔細控制上下文狀態(tài)的單線程應用程序