1

I'm trying to render a 512x512 texture on a square on Android using OpenGL. My program works fine when I use the emulator, but if I use a Nexus 7 (the old one), glGetError() returns 1282. This happens after I call glUseProgram in my render loop. GLUtils.getEGLErrorString says error 1282 corresponds to error 0x502, which stands for GL_INVALID_OPERATION.

I've tried the solutions mentioned in this answer, this answer and this article. I've tried putting my texture in drawable-nodpi and I've also made sure my texture size is a power of two. I also tried putting my texture in res/raw and following the alternate method of loading the texture but that didn't work either.

Could someone point me in the right direction?

If there is anything I can do to improve my question, please let me know!

My shaders:

      private final String vertexShaderCode =
      // This matrix member variable provides a hook to manipulate
      // the coordinates of the objects that use this vertex shader
      "uniform mat4 uMVPMatrix;" +

      // Per-vertex texture coordinate info we will pass in
      "attribute vec2 a_TexCoordinate;" +
      // This will be passed into the fragment shader
      "varying vec2 v_TexCoordinate;" +

      "attribute vec4 vPosition;" +
      "void main() {" +
      // the matrix must be included as a modifier of gl_Position
      "  gl_Position = vPosition * uMVPMatrix;" +
      "  v_TexCoordinate = a_TexCoordinate;" +      
      "}";


      private final String fragmentShaderCode =
      // The input texture
      "uniform sampler2D u_Texture;" +
      // Interpolated texture coordinate per fragment
      "varying vec2 v_TexCoordinate;" +
      "precision mediump float;" +
      "uniform vec4 vColor;" +
      "void main() {" +
      "  gl_FragColor = (vColor * texture2D(u_Texture, v_TexCoordinate));" +
      "}";

My draw call:

 public void draw(float[] mvpMatrix) {
    GLES20.glUseProgram(shaderProgramHandle);

    // POSITION INFO - Get a handle to the position attribute in the shader and
    // associate the vertices with it
    int vPositionHandle = GLES20.glGetAttribLocation(shaderProgramHandle, "vPosition");
    GLES20.glEnableVertexAttribArray(vPositionHandle);
    GLES20.glVertexAttribPointer(
        vPositionHandle,
        COORDS_PER_VERTEX,
        GLES20.GL_FLOAT,
        false,
        COORDS_PER_VERTEX * BYTES_PER_COORD, 
        vertexBuffer);

    // COLOR INFO - Get a handle to the color attribute in the shader and associate
    // the color with it
    int vColorHandle = GLES20.glGetUniformLocation(shaderProgramHandle, "vColor");
    GLES20.glUniform4fv(vColorHandle, 1, vertexColor, 0);

    // TRANSFORM INFO - Get a handle to the MVP matrix uniform in the shader and
    // associate the MVP matrix with it
    int uMVPHandle = GLES20.glGetUniformLocation(shaderProgramHandle, "uMVPMatrix");
    GLES20.glUniformMatrix4fv(uMVPHandle, 1, false, mvpMatrix, 0);

    // TEXTURE INFO
    int texCoordinateHandle = GLES20.glGetAttribLocation(shaderProgramHandle, "a_TexCoordinate");
    GLES20.glEnableVertexAttribArray(texCoordinateHandle);
    GLES20.glVertexAttribPointer(
        texCoordinateHandle,
        COORDS_PER_TEX, 
        GLES20.GL_FLOAT,
        false,
        0,
        textureCoordinatesBuffer);
    int texUniformHandle = GLES20.glGetUniformLocation(shaderProgramHandle, "u_Texture");
//     Set the active texture unit to texture unit 0
    GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
//     Bind the texture to this unit
    GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureDataHandle);
//     Tell the texture uniform sampler to use this texture in the shader
//     by binding to texture unit 0
    GLES20.glUniform1i(texUniformHandle, 0);

    // Draw the square
    GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, vertices.length / 3);

    // Cleanup
    GLES20.glDisableVertexAttribArray(vPositionHandle);
    GLES20.glDisableVertexAttribArray(texCoordinateHandle);
  }

I'm loading my texture in my implementation of GLSurfaceView.Renderer's onSurfaceCreated. Here is a snippet that shows how I'm loading the texture.

   int loadTexture(final Context context, final int resourceId) {
    final int[] textureHandle = new int[1];

    GLES20.glGenTextures(1, textureHandle, 0);
    Utils.checkGLError("glGenTextures");

    if (textureHandle[0] != 0) {
      final BitmapFactory.Options options = new BitmapFactory.Options();
      options.inScaled = false; // No pre-scalings
      // Read in the resource
      final Bitmap bitmap = BitmapFactory.decodeResource(
          context.getResources(),
          resourceId,
          options);
//      InputStream is = context.getResources().openRawResource(resourceId);
//      Bitmap bitmap = null;
//      try {
//        bitmap = BitmapFactory.decodeStream(is);
//      } finally {
//        //Always clear and close
//        try {
//          is.close();
//          is = null;
//        } catch (IOException e) {
//        }
//      }
      // Bind to the texture in OpenGL
      GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureHandle[0]);

      // Set filtering
      GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_LINEAR);
      GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR);
//      GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER,
//          GLES20.GL_NEAREST);
//      GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER,
//          GLES20.GL_NEAREST);
//      GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_S, 
//          GLES20.GL_CLAMP_TO_EDGE);
//      GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_T, 
//          GLES20.GL_CLAMP_TO_EDGE);
      // Load the bitmap into the bound texture.
      GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, bitmap, 0);

      // Recycle the bitmap, since its data has been loaded into OpenGL.
      bitmap.recycle();
    }

    if (textureHandle[0] == 0) {
      throw new RuntimeException("Error loading texture.");
    }

    return textureHandle[0];
  }
Community
  • 1
  • 1
vg1
  • 21
  • 3
  • All OpenGL enumerated constants (e.g. error codes) are base-16, for future reference. You will have great difficulty if you try to look up the decimal representation, but if you use hexadecimal you can find the token name immediately by looking for `0x...` in any text editor in `gl.h`, it will be in the form: `#define GL_... 0x...`. I realize you are using Java, but `gl.h` is easy to find [here](http://www.khronos.org/registry/gles/#specfiles), decimal OpenGL constant values on the other hand are anything but easy to find. – Andon M. Coleman Oct 12 '13 at 13:23
  • Does this program actually run fine in the simulator? I ask because `" gl_Position = vPosition * uMVPMatrix;" +` is not valid if you use column-major matrices like you are expected to in OpenGL. You should have the matrix on the l-hand side in this statement. – Andon M. Coleman Oct 12 '13 at 13:26
  • 1
    Onto the actual issue: `glUseProgram (...)` will most often generate `GL_INVALID_OPERATION` when you try to use a program that did not link properly. Look into Shader / Program info logs, they will tell you what is really going on here. See: [`glGetShaderInfoLog`](http://www.khronos.org/opengles/sdk/docs/man/xhtml/glGetShaderInfoLog.xml) and [`glGetProgramInfoLog`](http://www.khronos.org/opengles/sdk/docs/man/xhtml/glGetProgramInfoLog.xml). – Andon M. Coleman Oct 12 '13 at 13:36
  • @AndonM.Coleman: Yeah it just occurred to me that it's probably a good idea to use hex. – vg1 Oct 12 '13 at 15:16
  • @AndonM.Coleman: Thanks so much!! I fixed it! glGetShaderInfoLog and glGetProgramInfoLog were a big help!! I hadn't declared precision in the fragment shader correctly. I moved my declaration to the top of my program and it seems to work now. Re: matrix multiplication - Yeah it runs fine in the simulator and it seems too work on the device now. Hmm thats a good point. I wonder why it works? – vg1 Oct 12 '13 at 15:19
  • Good to hear, as far as the matrix working the only thing I can think of is that for some reason you actually have row-major matrices or have transposed them somehow. It is actually perfectly acceptable to do this in shader-based OpenGL, column-major matrices are a requirement for fixed-function, but since you have full control over the order you do multiplication in within shaders you can use either form. It has traditionally been the case that D3D was row-major and GL was column-major, so you could spot an HLSL shader vs. a GLSL shader immediately by the order the matrices were multiplied. – Andon M. Coleman Oct 12 '13 at 16:32

0 Answers0