Jas Jas - 5 months ago 27
Android Question

Android gl no current context

I am trying to load some shaders and render a hello world triangle with an android GLSurfaceView and C++ using the official NDK. However I get the error "call to OpenGL ES API with no current context". Here is my simple single file java (note this is the only java code in the entire project) side context creation code from google's tutorial:

class GLESRenderer implements GLSurfaceView.Renderer
{
static {
System.loadLibrary("native_code");
}
private native void ntInit();
private native void ntRender();
private native void ntUpdateScreen(int width, int height);

public void onSurfaceCreated(GL10 unused, EGLConfig config) {
ntInit(); // LOAD SHADERS AND VBO DATA!!!!
}

public void onDrawFrame(GL10 unused) {
ntRender(); // DRAW USING SHADERS AND VBO DATA!!!!
}

public void onSurfaceChanged(GL10 unused, int width, int height) {
ntUpdateScreen(width, height); // UPDATE SCREEN!!!
}
}

class GLES_SurfaceView extends GLSurfaceView {

private final GLESRenderer mRenderer;

public GLES_SurfaceView(Context context){
super(context);
setEGLContextClientVersion(2);
mRenderer = new GLESRenderer();
setRenderer(mRenderer);
}
}

public class Main extends Activity {

private GLSurfaceView mGLView;

@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mGLView = new GLES_SurfaceView(this);

if(Build.VERSION.SDK_INT < 16) {
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
} else {
View decorView = getWindow().getDecorView();
decorView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_FULLSCREEN | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN);

ActionBar bar = getActionBar();
if(bar != null)
bar.hide();
}
setContentView(mGLView);
}
}


Many other stack overflow questions (none of which use the NDK, so they are probably different problems) suggest that this is a threading issue, but this code clearly calls the native functions from the GLSurfaceView.Renderer, so I am pretty sure this is not a thread issue.

Furthermore, multiple tutorials use this same approach for rendering using opengl and the NDK. For example: Intel's tutorial, and learnopengles's tutorial.

Thus I think there is something wrong in my context creation

Jas Jas
Answer

Forgot to answer this question. This problem occurred because of C++'s default constructor system. Before my OpenGL context was created, I was loading my "native_code" library. My native shader classes however had default constructors which made OpenGL calls to initialize themselves. Something like this:

class LightingShader
{
    LightingShader()
    {
        glCreateShader(...) // BAD TO CALL OPENGL HERE WITHOUT CONTEXT CREATED
        ....
    }
};

....
LightingShader light_shader; // <- GLOBAL VARIABLE, DEFAULT CONSTRUCTOR CALLED!!!!

So basically when they library was loaded, the C++ shaders were automatically getting their constructors called. And this library was called before OpenGL was initialized! I fixed this by removing the default constructor and instead using a function which returned the object instead:

class LightingShader
{
    LightingShader getLightingShaderInstance()
    {
        glCreateShader(...)
        ....
    }
};

Thus it was a sneaky bug hidden in bad object oriented design on my part.