2013-07-01 6 views
10

У меня возникла очень сложная проблема при создании шейдерной программы на Android. когда я называю glCreateShader или glCreateProgram каждый всегда возвращает 0.glCreateShader и glCreateProgram fail на android

я покрыл все свои базы в отношении поиска и устранения неисправностей:

  • Я проверил, чтобы убедиться, что я имел контекст OGL (я делаю, я испытанной это путем очистки буфера кадра различными цветами, который работал).

  • Я попытался glGetError, но он не вернулся ничего (GL_NO_ERROR)

Я не OpenGL или андроид эксперт, так что я не знаю ни одной вещи еще, что может быть причиной этого.

Я запускаю свое приложение на планшете Nexus 7, и я использую OpenGL ES 2.0, и я нацелен на последнюю версию Android (версия 17).

Наконец, у меня есть свой код, чтобы показать, как хорошо:

Вот мой шаблонный код, который устанавливает приложение:

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); 
    } 
} 

и это является основным видом деятельности:

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); 
    } 
} 

, и это код, который создает шейдеры и программу:

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; 
} 

любая помощь или предложения были бы весьма признательны.

+3

Где бы вы назвали 'createProgram()' в код? Я знаю, что 'createProgram()' возвращает 0 при вызове вне потока GL. – Reigertje

+0

@Brianberg Он вызывается в методе класса Game onStart(), поэтому его вызывается в методе onCreate() MainActivity. – Jim

+9

Да, это вне резьбы GL. Убедитесь, что все методы из GLES20 вызывают в потоке GL, иначе они не работают. Это находится внутри 'onSurfaceChanged()', 'onSurfaceCreated()' и/или 'onDrawFrame()'. – Reigertje

ответ

23

Для тех, кто ищет ответ, он скрыт в комментариях. Я читаю @Reigertje из комментариев.

Shader вызовы должны быть в пределах GL потока, который является onSurfaceChanged(), onSurfaceCreated() или onDrawFrame()