GPUImageFramebuffer

總述

從總體上來講它是容納一個(gè)紋理的容器。這個(gè)類寫得太別的散,讓人一眼看不出什么主旨要義來,可能是因?yàn)樽髡呦褡屵@個(gè)類處理太多東西了。它接收一個(gè)紋理和這個(gè)紋理的大小,然后經(jīng)過一番處理然后生成一個(gè)什么東西,雖然主要就是個(gè)圖片而已。此外,它還涉及到2個(gè)重要的操作,一個(gè)是內(nèi)存上的控制,一個(gè)是并發(fā)上的控制。

內(nèi)部構(gòu)成

GLuint framebuffer:這個(gè)就是緩沖區(qū)的實(shí)質(zhì),它就是緩沖區(qū)。
CVPixelBufferRef renderTarget:它就是渲染的目標(biāo)。
CVOpenGLESTextureRef renderTexture:這是需要被渲染的紋理。
NSUInteger readLockCount: 這個(gè)應(yīng)該是讀寫鎖,好像是說只要這個(gè)緩沖區(qū)被讀取它就不能被更改,所以上個(gè)鎖。
NSUInteger framebufferReferenceCount:這就是那個(gè)引用計(jì)數(shù),每個(gè)對(duì)象的引用計(jì)數(shù)。這個(gè)類似OC對(duì)象的引用計(jì)數(shù)。
BOOL referenceCountingDisabled:這個(gè)是引用計(jì)數(shù)的開關(guān)。
-(void)generateFramebuffer:用來生成一個(gè)緩沖區(qū),這里面的過程就比較復(fù)雜了。
-(void)generateTexture:用來生成一個(gè)紋理,內(nèi)部使用的。
-(void)destroyFramebuffer:用于銷毀幀緩沖區(qū)。
這里還有兩個(gè)C語言的回調(diào)dataProviderReleaseCallback和dataProviderUnlockCallback。

generateTexture

從這個(gè)名字就可以看出來它是用來生成紋理的,具體是怎么生成紋理的,全是都用OpenGL ES 2.0來生成的。這里面首先是要選擇一個(gè)待激活的紋理單元,紋理單元的數(shù)量至少是8個(gè)。然后是生成紋理的名字,用一個(gè)數(shù)組來存儲(chǔ)存儲(chǔ)生成的名字,有幾個(gè)名字?jǐn)?shù)組的元素個(gè)數(shù)就是幾個(gè)。接下來是要把名字和激活的紋理單元綁定,我想這個(gè)過程就是給紋理單元命名吧。最后是把紋理以某種方式映射成像素。反正全都是OpenGL ES的操作。

generateFramebuffer

這個(gè)就是生成幀緩沖區(qū),整個(gè)過程都是同步執(zhí)行的。在OpenGL ES中生成幀緩沖區(qū)和生成紋理有點(diǎn)相似。首先指定一下上下文,然后就是幀緩沖區(qū)的專屬部分了。首先要生成幀緩沖區(qū)的名字,一個(gè)幀緩沖區(qū)配一個(gè)名字。然后通過名字把對(duì)應(yīng)的幀緩沖區(qū)綁定到某目標(biāo)上去。須知與設(shè)備有關(guān)的一個(gè)屬性是在iOS 5.0及以上所有的幀緩沖區(qū)都是備份在紋理的緩存中,所以該方法的邏輯進(jìn)行到這都需要進(jìn)行一個(gè)判斷,如果是支持備份的話,是一種處理,否則是另一種處理方式。
如果是支持這種特性的,首先要獲取紋理的緩存,這個(gè)緩存是CVOpenGLESTextureCacheRef類型的。然后用一個(gè)可變字典去獲取屬性,然后把這些屬性賦值給一個(gè)不可變字典。在這個(gè)過程中,有一個(gè)error對(duì)象,這就好像是一個(gè)異常對(duì)象一樣,從該對(duì)象中可以獲取錯(cuò)誤信息。前半過程已經(jīng)處理完了,這一段就是獲取屬性,獲取完了以后就釋放臨時(shí)的變量。接下來是純的OpenGL ES的處理過程,簡單就是獲取當(dāng)前的紋理,并從當(dāng)前的紋理獲取幀緩沖區(qū)。
如果不支持特性,此時(shí)就代表該設(shè)備不支持從紋理緩存獲取幀緩沖區(qū)。那就新生成1個(gè)紋理,然后通過這個(gè)紋理獲取幀緩沖區(qū)。
這兩個(gè)分支都走完以后,就獲取緩沖區(qū)的狀態(tài),最后是綁定紋理,但是為什么最后要綁定紋理呢?

destroyFramebuffer

很顯然嘛,這就是用來釋放幀緩沖區(qū)用的。它是同步處理的,處理的過程是這樣的。首先獲取上下文,然后如果緩沖區(qū)不空的話就釋放幀緩沖區(qū)。接下來的處理過程也分兩種情況,就是如果設(shè)備支持紋理緩存和不支持紋理緩存的情況,另外還有一個(gè)判斷條件是是否允許丟失幀緩沖區(qū)。
如果支持并且還不支持丟失幀緩沖區(qū)的話,那就釋放渲染目標(biāo)和渲染的紋理。
否則,直接就刪除紋理即可。

activateFramebuffer

激活幀緩沖區(qū)用的,但是這里面的實(shí)現(xiàn)極其簡單,就兩句話。它首先是要把幀緩沖區(qū)綁定到指定目標(biāo)上面,然后是要把這個(gè)幀緩沖區(qū)轉(zhuǎn)換成一個(gè)size大小的圖片紋理,由此可見幀緩沖區(qū)最終要被轉(zhuǎn)換成一個(gè)size的,而且轉(zhuǎn)換的步驟就在此處啊,不過這個(gè)size具體是多大,它決定于類外部的設(shè)置。

幀緩沖區(qū)的引用計(jì)數(shù)機(jī)制

這個(gè)就是參考了OC對(duì)象的引用計(jì)數(shù)機(jī)制,概述一下就是這個(gè)緩沖區(qū)被引用的話,引用計(jì)數(shù)就+1,放棄引用,引用計(jì)數(shù)就-1,減到0以后,按照oc的機(jī)制的話是釋放對(duì)象,但是在GPUImage中則是把幀緩沖區(qū)歸還到幀緩沖區(qū)的緩存中。

lock

它是手動(dòng)增加引用計(jì)數(shù)的方法。它先檢查是否禁用了引用計(jì)數(shù),如果禁用了,就什么都不做直接返回,否則把該緩沖區(qū)的引用計(jì)數(shù)+1.

unlock

這是手動(dòng)減少引用計(jì)數(shù)的方法。如果引用計(jì)數(shù)被禁用了,就直接返回。如果引用計(jì)數(shù)沒有被減的時(shí)候就已經(jīng)是0,則會(huì)觸發(fā)斷言,而不是直接歸還到緩存中去。

clearAllLocks

這個(gè)沒啥好說的,就是清空引用計(jì)數(shù),但是它沒有歸還幀緩沖區(qū)。

disableReferenceCounting

禁用引用計(jì)數(shù)。

enableReferenceCounting

激活引用計(jì)數(shù)。

圖像捕捉

就是說從幀緩沖區(qū)能夠計(jì)算出圖像。

dataProviderReleaseCallback

釋放數(shù)據(jù),一個(gè)C語言的語法,看上去有點(diǎn)類似于內(nèi)聯(lián)函數(shù)。這是一個(gè)回調(diào),傳進(jìn)來的數(shù)據(jù)就是希望被釋放的數(shù)據(jù)。

dataProviderUnlockCallback

這也是個(gè)回調(diào),它用于把回調(diào)進(jìn)來的數(shù)據(jù)降低它的引用計(jì)數(shù)。因?yàn)檫@個(gè)幀緩沖區(qū)總是要綁定到一個(gè)目標(biāo)上的,你不能因?yàn)檫@個(gè)幀緩沖區(qū)不要了也不要這個(gè)與之綁定的目標(biāo)了,于是要先恢復(fù)它的渲染目標(biāo)。然后引用計(jì)數(shù)減一,然后,因?yàn)樗荒茉诒挥糜讷@取圖像了嘛,所以你需要把它從能用于獲取圖片的幀緩沖列表中刪除。

newCGImageFromFramebufferContents

它是能夠從幀緩沖區(qū)中獲取一個(gè)新的cg圖像。整個(gè)過程也是同步進(jìn)行的。首先是要獲取上下文。接下來是獲取生成圖片所需要的總的字節(jié)數(shù),這個(gè)字節(jié)數(shù)是圖像的寬度×高度×4,而這個(gè)寬度和高度是通過屬性外部設(shè)置的size。
如果設(shè)備是支持紋理緩存的話,它要從渲染目標(biāo)中獲取每行的像素的字節(jié)數(shù),再除以4,得到每行中的單元數(shù),至于什么單元,我就不知道了,然后寬度×高度×4,知道尺寸以后,要先把引用計(jì)數(shù)+1,然后讀取。獲取渲染目標(biāo)的地址,通過數(shù)據(jù)獲取數(shù)據(jù)的提供者,這些提供者是什么呀?然后把幀緩沖區(qū)添加入到可以獲取圖片的激活的圖像鏈表中。
如果設(shè)備不支持紋理緩存的話,則直接激活幀緩沖區(qū),然后通過屬性設(shè)置的size來獲取圖片的像素?cái)?shù)和字節(jié)數(shù),進(jìn)而得到數(shù)據(jù)提供者,然后幀緩沖區(qū)降低引用計(jì)數(shù)。
接下來,是從設(shè)備上獲取RGB顏色空間。
如果設(shè)備支持紋理緩存的話,通過上面的數(shù)據(jù)提供器還有RGB顏色空間并且使用渲染目標(biāo)就可以得到cg圖像。
如果設(shè)備不支持紋理緩存的話,就通過屬性size設(shè)置的數(shù)據(jù)來獲取cg圖像。
最后得到結(jié)果,就是一個(gè)cg圖像。

restoreRenderTarget

恢復(fù)渲染的目標(biāo)。這個(gè)實(shí)現(xiàn)很簡單,也是兩行代碼,就是在讀完以后降低它的引用計(jì)數(shù),并且釋放渲染目標(biāo)。

數(shù)據(jù)讀取機(jī)制

就是在讀取數(shù)據(jù),控制引用計(jì)數(shù)。就是在讀的時(shí)候引用計(jì)數(shù)+1,不讀的時(shí)候引用計(jì)數(shù)-1.

lockForReading

只有設(shè)備支持紋理緩存的時(shí)候,才進(jìn)行此操作,這里面涉及到了另外一個(gè)讀計(jì)數(shù),一開始的時(shí)候計(jì)數(shù)是0就先鎖定像素緩沖區(qū)的基址,然后讀計(jì)數(shù)+1.

unlockAfterReading

它也是只針對(duì)支持紋理緩存的設(shè)備而言的,讀計(jì)數(shù)減1,到了0以后就解鎖像素緩沖區(qū)的基址。

bytesPerRow

它返回圖像紋理每行的字節(jié)數(shù)。如果設(shè)備支持紋理,則只通過渲染目標(biāo)就可以得到每行的字節(jié)數(shù)。如果不是iPhone或者模擬器或者不支持紋理緩存,則返回通過屬性設(shè)置的size的寬度×4.

byteBuffer

就是通過渲染目標(biāo)獲取像素緩沖區(qū)的基址,之前要鎖定來讀取,之后要解鎖。

pixelBuffer

其實(shí)就是返回渲染目標(biāo),而對(duì)于非iPhone或者模擬器平臺(tái)則直接返回NULL。

texture

用于持久化輸入的紋理。

上一篇:分析GPUImage-GPUImageInput
下一篇:GPUImageFramebufferCache

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容