'Why does GLES20.glCreateShader always returns 0?

I'm trying to make an OpenGL ES app in android using java and I have run in a major issue:

GLES20.glCreateShader(type) (type beeing GLES20.GL_VERTEX_SHADER or GLES20.GL_FRAGMENT_SHADER) always returns 0.

For clarity, here's the code of my glSurfaceView :

//Warning: I'm no where near finished 
//and cleanup needs to be made once I get it working.
//If something looks weird or makes no sense, it's part of debugging or testing

public class renderer implements GLSurfaceView.Renderer{
    
    private Object obj;
    public StaticShader shader;
    private Object ball;
    
    private int bytePerFloat = 4;
    private int stride = 3*bytePerFloat; //#of elements * bpf
    
    private int positionOffset = 0;
    private int positionSize = 3;
    
    //private int colorOffset = 3;
    //private int colorSize = 4;
    
    private ObjectLoader objectLoader;
    private AssetManager assets;
    private Context context;
    
    //The important part is from here...

    renderer(AssetManager a, Context b){
      assets = a;
      context = b;
    }
    
    public void onSurfaceCreated(GL10 gl, EGLConfig config){
        
        shader = new StaticShader(assets, context);
        
        float[] verts = 
        {
            //x,y,z
            //r,g,b,a
            0.5f,0.5f,0.0f,
            
            0.5f,-0.5f,0.0f,
            
            -0.5f,-0.5f,0.0f,
            
            -0.5f,0.5f,0.0f
        };
        
        int[] indices = {
          0,1,3,
          3,1,2
        };
        
        //obj = new Object(verts,indices,shader,bytePerFloat);
        //ball = objectLoader.LoadFromFile("ball.obj",shader, bytePerFloat);
    }
    
    //... To here
    
    public void onSurfaceChanged(GL10 gl, int width, int height){
        GLES20.glViewport(0,0,width,height);
    }
    
    public void onDrawFrame(GL10 gl){
        GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);
        if(shader.isCompiled && shader.hasFoundFile && shader.canReadFile){
            GLES20.glClearColor(0.0f,1.0f,0.0f,1.0f);
        }else{
            GLES20.glClearColor(1.0f,0.0f,0.0f,1.0f);
        }
        //render(obj);
        //render(ball);
    }
    
    private void render(Object object){
      try{
        object.getShader().start();
        
        GLES30.glBindVertexArray(object.getVaoID());
        GLES30.glEnableVertexAttribArray(0);
        
        GLES30.glDrawElements(GLES20.GL_TRIANGLES, object.getVertCount(), GLES30.GL_UNSIGNED_INT,0);
        
        GLES30.glDisableVertexAttribArray(0);
        GLES30.glBindVertexArray(0);
        
        object.getShader().stop();
      }catch(Exception e){
        
      }
    }
}

StaticShader basically implements ShaderProgram for now:

public abstract class ShaderProgram {
  
  private int programID;
  private int vertexShaderID;
  private int fragmentShaderID;
  
  public boolean hasFoundFile = true;
  public boolean isCompiled = true;
  public boolean canReadFile = true;
  
  public ShaderProgram (AssetManager assets, Context context, String vertexFile, String fragmentFile){
    
    //int shdID = GLES20.glCreateShader(GLES20.GL_VERTEX_SHADER);
    //Toast.makeText(context,Integer.toString(shdID),Toast.LENGTH_LONG).show();
    //Toast.makeText(context,EGL14.eglGetCurrentContext().toString(),Toast.LENGTH_LONG).show();
 
    //ShaderID = loadShader(assets, context, vertexFile, GLES20.GL_VERTEX_SHADER);
    //fragmentShaderID = loadShader(assets,context, fragmentFile, GLES20.GL_FRAGMENT_SHADER);
    
    programID = GLES20.glCreateProgram();
    GLES20.glAttachShader(programID, vertexShaderID);
    GLES20.glAttachShader(programID, fragmentShaderID);
    GLES20.glLinkProgram(programID);
    GLES20.glValidateProgram(programID);
  }
  
  public void start(){
    GLES20.glUseProgram(programID);
  }
  
  public void stop(){
    GLES20.glUseProgram(0);
  }
  
  protected abstract void bindAttributes();
  
  protected void bindAttribute(int attribute, String variableName){
    GLES20.glBindAttribLocation(programID, attribute, variableName);
  }
  
  private int loadShader(AssetManager assets, Context context,String fileName, int type){
    int shaderID = 0;
    try{
      InputStream file = assets.open(fileName);
      Scanner scan = new Scanner(file);
      String code = new String();
      while(scan.hasNext()){
        code = new String(code + scan.nextLine() + "/n");
      }
      
      shaderID = GLES20.glCreateShader(type);
      //GLES20.glShaderSource(shaderID, code);
      //Toast.makeText(context,Integer.toString(shaderID),Toast.LENGTH_LONG).show();
      //GLES20.glCompileShader(shaderID);
      int[] compileStatus = new int[1];
      GLES20.glGetShaderiv(shaderID,GLES20.GL_COMPILE_STATUS,compileStatus,0);
      if(compileStatus[0] == 0){
        //Toast.makeText(context,GLES20.glGetShaderInfoLog(),Toast.LENGTH_LONG).show();
        GLES20.glDeleteShader(shaderID);
        isCompiled = false;
      }
    }catch(FileNotFoundException e){
      hasFoundFile = false;
    }catch(IOException e){
      canReadFile = false;
    }catch(Exception e){
      isCompiled = false;
    }
   
    
    return shaderID;
    
  }
}

And here's the launcher class:

public class MainActivity extends Activity {
    
    private renderer surface;
    private GLSurfaceView surfaceView;
    private int STORAGE_PERMISSION_CODE = 1;
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        surfaceView = new GLSurfaceView(this);
        surfaceView.setEGLContextClientVersion(2);
        surface = new renderer(getAssets(),getApplicationContext());
        surfaceView.setRenderer(surface);
        setContentView(surfaceView);
    }
    
    protected void onPause(){
        super.onPause();
        surfaceView.onPause();
    }
    
    protected void onResume(){
        super.onResume();
        surfaceView.onResume();
    }

}


Solution 1:[1]

glGetError says GL_NO_ERROR and I call the the function in the initialisation of a class made in the initialisation of the glSurfaceView. I'm not using onSurfaceCreated, because I need the AssetManager and the Context of the app

This is your problem I think. glSurfaceView's OpenGLES context is only bound to the GLThread. You really need to have all your OpenGLES code downstream from one of glSurfaceView.Renderer's functions e.g. onSurfaceCreated or onDrawFrame.

The function eglGetCurrentContext can tell you if there's an OpenGLES context bound to the current thread. Calling any OpenGLES functions without a context will result in bugs that aren't reported through glGetError. In debug builds, I check both the context and glGetError on every single OpenGLES call.

I'm not aware of any real obstacle to using AssetManager and Context on the GLThread.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Columbo