1,背景:android pad項目中使用到google實景(panorama)的項目,該項目中應用到opengl的一些底層,該問題就是opengl底層出現問題時的表現。
2,症狀:在項目中有兩個activity(a,b,b為實景,通過a來啟動),如果a,b在AndroidManifest.xml均關閉硬件加速( android:hardwareAccelerated="false")則實景可用,但a開硬件加速,b關閉硬件加速的話,則b中的實景不可用,表現為只展示圖片,不能隨着角度滾動展示。
3,問題的解釋:
(1)question: am new to both openGL and android development so please forgive me if my question is very trivial.
I am trying to build a simple little app that takes input from the user in three EditTexts representing a 0 - 100% value for each component of a RGB color to be displayed in a GLSurfaceView.
The catch is that I need this to use openGL ES 2.0 and I need to pass the data into the shading program using a uniform value so that once I get it working I can move on to what I am really trying to accomplish.
Upon running what I have written I can get the GLSurfaceView to correctly display the first solid color, but whenever I change any of the values and make calls to rebuild the uniform slot in the shading program I get this error in the LogCat:
ERROR/libEGL(14316): call to OpenGL ES API with no current context (logged once per thread)
and of course the GLSurfaceView remains the initial color.
I've been searching all over for a solution to this problem and as best I can tell I might need to be setting up an EGLContext somewhere before setting my renderer. However, I don't see anything in the API demos about this, and the only information I can find online was written before GLSurfaceView was even available.
Do I need to set up an EGLContext still or have I missed something else?
Additional info that may help:
-used an XML file to set up the UI (and as far as I can tell doing it in code doesn't help)
-having the same trouble when I try to load in a new texture from the sd card in a seperate program. I can get the first texture to work fine, but when using the same method to load the second I get the same error and nothing changes.
answer: You're not calling it from the OpenGL thread. If a different thread is trying to do something with OpenGL, queue that up and call it during your OpenGL thread instead.
(2)
這里使用到了線程局部存儲機制,這是一個什么東東呢?
概念:線程局部存儲(Thread Local Storage,TLS)用來將數據與一個正在執行的指定線程關聯起來。
進程中的全局變量與函數內定義的靜態(static)變量,是各個線程都可以訪問的共享變量。在一個線程修改的內存內容,對所有線程都生效。這是一個優點也是一個缺點。說它是優點,線程的數據交換變得非常快捷。說它是缺點,一個線程死掉了,其它線程也性命不保; 多個線程訪問共享數據,需要昂貴的同步開銷,也容易造成同步相關的BUG。
如果需要在一個線程內部的各個函數調用都能訪問、但其它線程不能訪問的變量(被稱為static memory local to a thread 線程局部靜態變量),就需要新的機制來實現。這就是TLS。
功能:它主要是為了避免多個線程同時訪存同一全局變量或者靜態變量時所導致的沖突,尤其是多個線程同時需要修改這一變量時。為了解決這個問題,我們可以通過TLS機制,為每一個使用該全局變量的線程都提供一個變量值的副本,每一個線程均可以獨立地改變自己的副本,而不會和其它線程的副本沖突。從線程的角度看,就好像每一個線程都完全擁有該變量。而從全局變量的角度上來看,就好像一個全局變量被克隆成了多份副本,而每一份副本都可以被一個線程獨立地改變。
好了,介紹完畢,下面介紹系統中代碼如何體現的:
由於OpenGL是一個其於上下文Context 環境開發的,所以每個線程需要保存自已的運行環境,如果沒有的話則會報錯:
"call to OpenGL ES API with no current context logged once per thread"
4,解決辦法:
在com.android.panoramagl.iphone.EAGLContext文件中修改紅色位置,然后重新jar在項目中引用。
public static boolean setCurrentContext(EAGLContext context)
{
try
{
EGL10 egl = (EGL10)EGLContext.getEGL();
if(context == null)
egl.eglMakeCurrent(currentContext == null ? egl.eglGetCurrentDisplay() : currentContext.getDisplay(), EGL10.EGL_NO_SURFACE, EGL10.EGL_NO_SURFACE, EGL10.EGL_NO_CONTEXT);
else //if(currentContext != context)
{
egl.eglMakeCurrent(context.getDisplay(), context.getSurface(), context.getSurface(), context.getContext());
currentContext = context;
}
return true;
}
catch(Exception ex)
{
Log.e("setCurrentContext", "Error can't setCurrentContext:" + ex.getMessage());
}
return false;
}
5,個人解釋:
出錯的地方時因為調用setCurrentContext(EAGLContext context)這個方法,第一次調用沒問題,第二次調用有問題。可能是因為context在多線程環境中,第一次調用中context發生了改變,需要在以后調用前重新設置context。總之個人解釋是猜測,好歹問題已解決,具體緣由望高手解答。
