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.另一种解决方式:
在Android项目中,开启设备的硬件加速的话,可能会解决这个问题。但具体的原因我研究完底层的调用后写出
具体做法:
在Android Mainfest 的applicaiton节点下添加
<application android:hardwareAccelerated="true">