'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 |