2013-07-01 2 views
10

J'ai un problème très difficile à créer un programme de shader sur Android. quand je l'appelle glCreateShader ou glCreateProgram chaque renvoie toujours 0.glCreateShader et glCreateProgram échouent sur Android

J'ai couvert toutes mes bases en ce qui concerne le dépannage:

  • J'ai vérifié pour assurer que j'avais un contexte de OGL (je fais, je l'ai testé ceci en effaçant le tampon de trame avec différentes couleurs, qui a fonctionné).

  • J'ai essayé glGetError mais il n'a rien retourné (GL_NO_ERROR)

Je ne suis pas un expert opengl ou Android, donc je ne sais pas de quelque chose d'autre qui pourrait être la cause.

J'ai utilisé mon application sur une tablette Nexus 7 et j'utilise OpenGL ES 2.0, et je cible la dernière version d'Android (version 17).

Enfin, je dois mon code pour montrer ainsi:

Voici mon code boilerplate qui met en place l'application:

public class Platform implements ILinkable<Activity> { 
    class GameLoop extends GLSurfaceView implements GLSurfaceView.Renderer { 
     class Graphics2D implements IGraphics2D { 
      int width = 0; 
      int height = 0; 

      public void setWidth (int width) { this.width = width; } 
      public void setHeight(int height) { this.height = height; } 

      public int getWidth() { return width; } 
      public int getHeight() { return height; } 
     } 

     class Time implements ITime { 
      float frametime = 0; 
      float totaltime = 0; 
      long temptime = 0; 
      boolean running = true; 

      public void beginTimeCount() { 
       temptime = System.nanoTime(); 
      } 

      public void endTimeCount() { 
       frametime = (System.nanoTime() - temptime)/1000000; 
       totaltime += frametime; 
      } 

      public float getFrameTime() { return frametime; } 
      public float getTotalTime() { return totaltime; } 
     } 

     Graphics2D graphics2d = new Graphics2D(); 
     Time  time  = new Time(); 
     boolean running = true; 

     public GameLoop(Context context) { 
      super(context); 

      setEGLContextClientVersion(2); 
      setRenderer(this); 
      //setRenderMode(GLSurfaceView.RENDERMODE_WHEN_DIRTY); 
     } 

     public void onSurfaceCreated(GL10 unused, EGLConfig config) { 
      GLES20.glClearColor(0.5f, 0.0f, 0.5f, 1.0f); 
     } 

     public void onDrawFrame(GL10 unused) { 
      if (running) { 
       time.beginTimeCount(); 

       for (IUpdateable u : Platform.this.root.update) 
        u.onUpdate(time); 

       GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT); 
       for (IDrawable2D d : Platform.this.root.draw2d) { 
        d.onDraw2D(graphics2d); 
       } 

       for (IDrawable3D d : Platform.this.root.draw3d) 
        d.onDraw3D(); 

       time.endTimeCount(); 
      } 
     } 

     public void onSurfaceChanged(GL10 unused, int width, int height) { 
      GLES20.glViewport(0,0, width, height); 
      graphics2d.setWidth(width); 
      graphics2d.setHeight(height); 
      for (IDrawable2D d : Platform.this.root.draw2d) 
       d.onSize2D(graphics2d); 
     } 

     public void onPause() { 
      super.onPause(); 
      running = false; 
     } 

     public void onResume() { 
      super.onResume(); 
      running = true; 
     } 
    } 

    private GameLoop gameloop; 
    public Node root; 

    public Platform() { 
     this.root = new Node(); 
    } 

    public void link(Activity activity) { 
     this.gameloop = new GameLoop(activity); 
     activity.requestWindowFeature(Window.FEATURE_NO_TITLE); 
     activity.setContentView(this.gameloop); 
    } 

    public void unlink(Activity activity) { 
     this.gameloop = null; 
     activity.setContentView(null); 
    } 
} 

et c'est l'activité principale:

public class MainActivity extends Activity { 

    private Game game; 
    private Platform platform; 

    public MainActivity() { 
     platform = new Platform(); 
     game = new Game(); 
    } 

    public void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 
     platform.link(this); 
     game.link(platform.root); 
     game.onStart(); 
    } 

    public void onDestroy() { 
     super.onDestroy(); 
     game.onStop(); 
     game.unlink(platform.root); 
     platform.unlink(this); 
    } 
} 

et c'est le code qui crée les shaders et le programme:

public static int loadShader(int shaderType, String source) throws FmtException { 
    int[] gotVar = new int[]{ 0 }; 
    int shader = GLES20.glCreateShader(shaderType); 

    if (shader == 0) 
     throw new FmtException(FmtException.GLES,"could not create shader: %s",getError()); 

    GLES20.glShaderSource(shader, source); 
    GLES20.glCompileShader(shader); 

    GLES20.glGetShaderiv(shader, GLES20.GL_COMPILE_STATUS, gotVar, 0); 
    if (gotVar[0] == 0) { 
     GLES20.glGetShaderiv(shader, GLES20.GL_INFO_LOG_LENGTH, gotVar, 0); 
     if (gotVar[0] != 0) { 
      GLES20.glDeleteShader(shader); 
      throw new FmtException(FmtException.GLES, "could not compile shader %d:\n%s\n",shaderType, GLES20.glGetShaderInfoLog(shader)); 
     } 
    } 

    return shader; 
} 

public static int createProgram(String pVertexSource, String pFragmentSource) throws FmtException { 
    int[] gotVar = new int[]{ GLES20.GL_FALSE }; 
    int vertexShader = loadShader(GLES20.GL_VERTEX_SHADER, pVertexSource); 
    int pixelShader = loadShader(GLES20.GL_FRAGMENT_SHADER, pFragmentSource); 

    int program = GLES20.glCreateProgram(); 
    if (program == 0) 
     throw new FmtException(FmtException.GLES, "could not create program: %s",getError()); 


    GLES20.glAttachShader(program, vertexShader); 
    GLES20.glAttachShader(program, pixelShader); 
    GLES20.glLinkProgram(program); 

    GLES20.glGetProgramiv(program, GLES20.GL_LINK_STATUS, gotVar, 0); 
    if (gotVar[0] != GLES20.GL_TRUE) { 
     GLES20.glGetProgramiv(program, GLES20.GL_INFO_LOG_LENGTH, gotVar, 0); 
     if (gotVar[0] != 0) { 
      GLES20.glDeleteProgram(program); 
      throw new FmtException(FmtException.GLES, "could not link program:\n%s\n", GLES20.glGetProgramInfoLog(program)); 
     } 
    } 

    return program; 
} 

toute aide ou suggestion serait grandement appréciée.

+3

Où voulez-vous appeler 'createProgram()' dans votre code? Je sais pertinemment que 'createProgram()' renvoie 0 lorsqu'il est appelé en dehors du thread GL. – Reigertje

+0

@Brianberg Il est appelé dans la méthode onStart() de la classe Game, il est donc appelé dans la méthode onCreate() de MainActivity. – Jim

+9

Oui, c'est hors du thread GL. Assurez-vous que toutes les méthodes de GLES20 sont appelées dans le thread GL - sinon elles ne fonctionnent pas. C'est dans 'onSurfaceChanged()', 'onSurfaceCreated()' et/ou 'onDrawFrame()'. – Reigertje

Répondre

23

Pour ceux qui cherchent la réponse, elle est cachée dans les commentaires. Je récite @Reigertje des commentaires.

appels Shader doivent être dans un fil de GL qui est onSurfaceChanged(), onSurfaceCreated() ou onDrawFrame()

Questions connexes