APP移植到小米Pad上的Crash分析

最近APP計劃適配小米Pad,直接拿線上的code build,發現啓動時CRASH,而且是必現的。線上code我們都發布了很多個版本了,怎麼會有這種問題呢?

CRASH問題

Eclipse看logcat輸出,最終定位到OpenGL的一次draw call函數上:

gl.glColor4f(bodyColor4f[0], bodyColor4f[1], bodyColor4f[2], bodyColor4f[3]);
	// set vertices
	gl.glVertexPointer(3, GL10.GL_FLOAT, 0, mVerticesBuffer);
	gl.glDisable(GL10.GL_TEXTURE_2D);
	// draw
	gl.glDrawArrays(GL10.GL_TRIANGLE_FAN, 0, CIRCLE_VERTEX_SIZE);
	gl.glEnable(GL10.GL_TEXTURE_2D);
gl.glColor4f(1, 1, 1, 1);
問題發生在glDrawArrays函數處。這段code是繪製一處半透明的圓圈。

問題分析

所有手機上運行都沒問題,唯獨小米Pad,因此猜想:這段代碼一定沒有問題,只不過不夠嚴謹。進一步懷疑是OpenGL狀態管理的不嚴謹

進一步分析:這段代碼使用顏色數組模式繪製一個圓,因此glDrawArrays前禁掉了GL_TEXTURE_2D,繪製完成後開啓GL_TEXTURE_2D。因此將懷疑的範圍進一步縮小到頂點數組的模式狀態。

glDrawArrays時候,雖然禁掉了GL_TEXTURE_2D,但是GL_TEXTURE_COORD_ARRAY 還處於激活狀態。這段代碼通過顏色模式繪製圓,glVertexPointer只上傳了頂點的位置和顏色數據,但是GL_COLOR_ARRAY和GL_VERTEX_ARRAY,GL_TEXTURE_COORD_ARRAY都處於激活狀態,GL 如果檢查不夠嚴格(沒有考慮當前GL_TEXTURE_2D是否激活),仍然按三個狀態去取每個頂點的位置、顏色、紋理數據,此時就導致顯存Buffer的越界,從而導致CRASH。

驗證分析

在glDrawArrays前顯示禁掉頂點紋理座標數組,繪製完成後開啓。

gl.glColor4f(bodyColor4f[0], bodyColor4f[1], bodyColor4f[2], bodyColor4f[3]);
	// set vertices
	gl.glVertexPointer(3, GL10.GL_FLOAT, 0, mVerticesBuffer);
	gl.glDisable(GL10.GL_TEXTURE_2D);	
	gl.glDisable(GL_TEXTURE_COORD_ARRAY);		// dizuo open
	// draw
	gl.glDrawArrays(GL10.GL_TRIANGLE_FAN, 0, CIRCLE_VERTEX_SIZE);
	gl.glEnable(GL10.GL_TEXTURE_2D);
	gl.glEnable(GL_TEXTURE_COORD_ARRAY);		// dizuo close
gl.glColor4f(1, 1, 1, 1);
再次Build,運行OK。 跟之前分析的完全一致。。

進一步反思:

手機上爲何沒有CRASH?

手機上對這種不嚴謹行爲做法:OpenGL取頂點數據的時候,結合了當前GL_TEXTURE_2D的狀態,紋理沒有激活就不取紋理頂點數據,不管glVertexPointer到底實際是否傳了紋理數據。。。

因此,OpenGL開發還是要顯式管理狀態。否則一些莫名其妙地CRASH就不請自來了。。。


更多OpenGL常見錯誤總結:http://blog.csdn.net/ryfdizuo/article/details/9961143


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章