WebGL離屏畫(huà)不出來(lái)
原因:
當(dāng)前的GLContext不是預(yù)期的,導(dǎo)致FBO綁定的不對(duì)
繪制某一張圖時(shí)時(shí)黑色的
原因:
WebGL和ES2中NPOT(non-power-of-two)的紋理并不是完全支持,NPOT的紋理環(huán)繞方式只能用GL_CLAMP_TO_EDGE,紋理過(guò)濾只能用GL_NEAREST或GL_LINEAR,且不能用mipmap。如果紋理參數(shù)設(shè)置了不支持的類(lèi)型,shader在采樣時(shí)會(huì)直接輸出黑色,且無(wú)任何報(bào)錯(cuò)。
進(jìn)入小游戲屏幕一直閃
原因:JS的不合理調(diào)用,開(kāi)發(fā)商在適配屏幕比例后會(huì)一直設(shè)置寬高并清空FBO,導(dǎo)致閃屏。
WebGL畫(huà)不出某一張圖像
原因:我們的紋理數(shù)據(jù)默認(rèn)是預(yù)乘Alpha的。WebGL可以設(shè)置紋理存儲(chǔ)方式為unPremultiplyAlpha,這時(shí)要把紋理數(shù)據(jù)的alpha通道逆預(yù)乘,才能保證shader中輸出的結(jié)果正確。
WebGL渲染偶先字體亂碼
原因:在切換場(chǎng)景時(shí),WebGL紋理對(duì)象被釋放,但JS GC時(shí)刪除紋理的操作命令發(fā)生在了離屏Canvas2D上下文,導(dǎo)致刪除了有用的紋理(舉例該紋理句柄為7號(hào)),之后離屏Canvas2D在創(chuàng)建新的紋理時(shí),OpenGL會(huì)從復(fù)用池里返回句柄7號(hào),這導(dǎo)致JS在操作7號(hào)紋理時(shí),其實(shí)GPU上的紋理并不是開(kāi)發(fā)商預(yù)期的。
WebGL渲染黑屏
原因:WebGL綁定FBO或者RBO時(shí),會(huì)傳一個(gè)Undefined來(lái)回到默認(rèn)的RBO。這時(shí)本地解析JSObject時(shí)會(huì)解成0,這在OpenGL中相當(dāng)于解綁了FBO。所以當(dāng)JS調(diào)用bindFramebuffer/bindRenderbuffer時(shí),JS傳Undefined、null Native會(huì)綁定FBO\RBO為默認(rèn)對(duì)象。
渲染圖像花屏
原因:在JS中,開(kāi)發(fā)商在Canvas2D的環(huán)境創(chuàng)建了JSImage,但在WebGL環(huán)境也使用了,由于在Native兩種環(huán)境不屬于同一個(gè)GLContext,改成共享紋理解決。
復(fù)用紋理黑屏
原因:復(fù)用紋理使用glCopyTexSubImage2D, 復(fù)制的目標(biāo)紋理要有內(nèi)存,不能只有句柄。
OpenGL的局部更新操作,都要求目標(biāo)對(duì)象已經(jīng)有內(nèi)存空間。
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
glReadBuffer(GL_COLOR_ATTACHMENT0);
glActiveTexture(GL_TEXTURE0);
targetTexture->resetTextureStorage();
targetTexture->bindToTarget(bindTarget);
glTexImage2D(bindTarget, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
glCopyTexSubImage2D(target, level, 0, 0, 0, 0, width, height);
glBindFramebuffer(GL_FRAMEBUFFER, oldFbo);
glBindTexture(GL_TEXTURE_2D, targetTexture->textureId());
Draw call Crash
原因:頂點(diǎn)數(shù)據(jù)或索引數(shù)據(jù)傳的有問(wèn)題, 上下文被污染,其他上下文的操作修改頂點(diǎn)數(shù)據(jù),導(dǎo)致頂點(diǎn)數(shù)據(jù)非預(yù)期。
畫(huà)出的紋理不對(duì),不是目標(biāo)紋理,而是上一幀用到的紋理
原因:用戶創(chuàng)建了多個(gè)sharedCanvas,但SharedCanvas只支持單例,所以只有第一個(gè)有對(duì)應(yīng)的GPU紋理,由于我們的紋理是懶加載,當(dāng)數(shù)據(jù)源沒(méi)有數(shù)據(jù)時(shí),沒(méi)有繼續(xù)調(diào)用TexImage2d,bindTexture, 導(dǎo)致這一幀的綁定紋理是上一幀的。改為解綁解決。
JS引擎設(shè)置低于60的幀率時(shí),渲染是閃屏
原因:Egret引擎的做法是在60幀的RenderTicker之上,自己封裝一個(gè)調(diào)用Ticker, skip幀來(lái)達(dá)到控制幀率的效果。由于WebGL默認(rèn)是preserveDrawingBubffer=false, 所以有DrawCall的話,在Skip的時(shí)間里,native是一直保持空rbo的狀態(tài)。
Draw Call Crash & 模型扭曲
原因:JS傳過(guò)來(lái)的多個(gè)TypedArray是基于同一個(gè)ArrayBuffer做不同偏移得到的,而Native在解TypedArray指針時(shí)沒(méi)有加上這個(gè)偏移量,導(dǎo)致從加載到OpenGL Buffer內(nèi)容不符合預(yù)期,模型頂點(diǎn)的位置、紋理坐標(biāo)全是錯(cuò)誤數(shù)據(jù),多次調(diào)用Draw Call后,由于頂點(diǎn)數(shù)據(jù)不符合預(yù)期,導(dǎo)致GPU driver IOAF error code4 (GPU Hang Error).
轉(zhuǎn)場(chǎng)動(dòng)畫(huà)黑屏、花屏
原因:在JS層傳錯(cuò)了FBO ID,導(dǎo)致上屏的FBO COLOR_ATTACHMENT的RBO被改成錯(cuò)誤的。
轉(zhuǎn)場(chǎng)動(dòng)畫(huà)后渲染黑屏
原因:在轉(zhuǎn)場(chǎng)后開(kāi)發(fā)商使用WebGL解綁WebGL RBO,由于native會(huì)判斷如果是-1的話綁定默認(rèn)的RBO。
但從JSC取值是是取double類(lèi)型,OpenGL傳參時(shí)是GLuint,double的-1轉(zhuǎn)無(wú)符號(hào)是0,導(dǎo)致錯(cuò)誤。
渲染偶現(xiàn)的黑屏、花屏,報(bào)錯(cuò)Execution of the command buffer was aborted due to an error during execution.
原因:開(kāi)發(fā)商記住了編譯后的的uniform、vertexAttrib的slot, 并在之后使用。
在iOS的PVR架構(gòu)GPU下,一些沒(méi)有用到的shader變量會(huì)被優(yōu)化掉,開(kāi)發(fā)商會(huì)一直試圖對(duì)一個(gè)不存在的Uniform、vertexAttrib傳值,而在Native解他們的slot時(shí),會(huì)導(dǎo)致解除的ID不代表真正想要的那個(gè)Uniform、vertexAttrib。
開(kāi)發(fā)商一直對(duì)shader變量傳錯(cuò)誤的值,導(dǎo)致Execution of the command buffer was aborted due to an error during execution.錯(cuò)誤。
解決方案:
每次寫(xiě)shader變量時(shí)確認(rèn)是否可用。
內(nèi)存問(wèn)題
原因:開(kāi)發(fā)商會(huì)出現(xiàn)不主動(dòng)調(diào)delete刪除OpenGL對(duì)象,導(dǎo)致大量OpenGL對(duì)象堆積在GPU,這部分的內(nèi)存占用是算在VM里的,其實(shí)CPU的占用并不多。
解決方案:
在GC時(shí)主動(dòng)刪除OpenGL對(duì)象解決。
渲染偶現(xiàn)的Crash
原因:為了優(yōu)化內(nèi)存管理,當(dāng)JS GC時(shí)我們會(huì)刪除對(duì)應(yīng)的OpenGL對(duì)象,GC回收不可控.
當(dāng)deleteBuffer后,Buffer在GC之前,buffer的ID由OpenGL復(fù)用返回給了其他createBuffer,會(huì)導(dǎo)致GC時(shí)刪除的是有用的Buffer, 導(dǎo)致頂點(diǎn)數(shù)據(jù)錯(cuò)誤,最終導(dǎo)致Crash.
解決方案:
deleteBuffer后清除本地的管理類(lèi)解決。
渲染偶現(xiàn)的花屏
原因:為了優(yōu)化內(nèi)存管理,當(dāng)JS GC時(shí)我們會(huì)刪除對(duì)應(yīng)的OpenGL對(duì)象,GC回收時(shí)機(jī)不可控.
但開(kāi)發(fā)商預(yù)期在createTexture返回的對(duì)象, 在BindTexture后,即使在GC后已綁定的texture依然可用,這是WebGL的一個(gè)特征。
解決方案:
優(yōu)化了內(nèi)存管理釋放規(guī)則解決。
小游戲顯存中存在重復(fù)的紋理
原因:開(kāi)發(fā)商的一些不規(guī)范行為會(huì)導(dǎo)致顯存中存在重復(fù)的紋理,如第三方引擎會(huì)自動(dòng)將小游戲所用的圖像資源合成一個(gè)大的紋理圖集,這樣方便管理和提高渲染效率,但開(kāi)發(fā)商在JS層持有住了所有圖像,導(dǎo)致GPU里存在大量的冗余紋理。
解決方案:
1.實(shí)現(xiàn)紋理的LRU緩存,淘汰的紋理保存到沙盒里,使用時(shí)再恢復(fù)到GPU。
2.加載紋理盡量復(fù)用,如texImage2D的最后一個(gè)參數(shù)是image或Canvas,會(huì)直接復(fù)用紋理。
小游戲死鎖卡住
原因:JS core 的JSContext會(huì)在創(chuàng)建它的線程創(chuàng)建JS虛擬機(jī),虛擬機(jī)會(huì)在這個(gè)現(xiàn)場(chǎng)添加自己的JS runloop。在需要在其他線程移步執(zhí)行此JSContext中的JS代碼時(shí),會(huì)有一定概率死鎖。
解決方案:
JSContext的創(chuàng)建、執(zhí)行代碼全部都放在一個(gè)線程完成。
渲染過(guò)程Crash,掛在紋理GL命令
原因:我們的開(kāi)放數(shù)據(jù)域和主域是分別獨(dú)立的線程,但JS的sharedCanvas在兩個(gè)域都可以訪問(wèn),導(dǎo)致它在底層的不同OpenGL context之間產(chǎn)生競(jìng)爭(zhēng),導(dǎo)致偶先的Crash。
解決方案:
在上層做邏輯保護(hù),加GPU鎖,避免同一份GPU資源在不同OpenGL context中產(chǎn)生競(jìng)爭(zhēng)問(wèn)題。