3

I've been really struggling trying to get two different shader programs working. Each works fine alone, that's not the issue. But I can't seem to switch between them to use them on two different objects. I.e. I want to use shaderFOO on triangleFOO and shaderBAR on triangleBAR. From what I understand, it's not only possible but is supposed to be relatively simple.

I've been scouring the internet for help, but have come up with bupkis. For the sake of thoroughness, these are the links I've checked here on SO:

The following is my relevant code. I'll let the in-code comments do most the talking.

My onSurfaceCreated() method:

int textureHandle = -1;

@Override
public void onSurfaceCreated(GL10 unused, EGLConfig config) {

    // My ShaderLoader class handles all the attaching, binding, linking, etc
    // of my shaders. Any and all necessary shader handles are stored in these
    // objects.
    shaderFOO = new ShaderLoader(context, ShaderLoader.Type.TEXTURE);
    shaderBAR = new ShaderLoader(context, ShaderLoader.Type.COLOR);

    // If I don't call glUseProgram() here on one of my shaders,
    // no shader program is ever used...
    GLES20.glUseProgram(shaderFOO.getProgramHandle());

    textureHandle = TextureLoader.load(context, R.drawable.uvmap);

}

And here is onDrawFrame():

@Override
public void onDrawFrame(GL10 unused) {      
    GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT | GLES20.GL_DEPTH_BUFFER_BIT);

    // The glUseProgram() calls have no effect here, I don't understand why. 
    // The only time it seems to work is in onSurfaceCreated(). Debugging has
    // shown that the program handles are still valid at this point.
    GLES20.glUseProgram(shaderFOO.getProgramHandle());
    //Log.v(TAG, "err:" + GLES20.glGetError());  /* no help, returns 0 */
    renderFOO();

    GLES20.glUseProgram(shaderBAR.getProgramHandle());
    renderBAR();
}

And finally, both renderFOO() and renderBAR():

int textureUniformHandle = -1;
int textureCoordHandle = -1;

public void renderFOO() {
    textureUniformHandle = GLES20.glGetUniformLocation(shaderFOO.getProgramHandle(), "u_Texture");
    textureCoordHandle = GLES20.glGetAttribLocation(shaderFOO.getProgramHandle(), "a_TextureCoordinate");

    GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
    GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureHandle);
    GLES20.glUniform1i(textureUniformHandle, 0);

    GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, verticesFOOBufferHandle);
    GLES20.glEnableVertexAttribArray(shaderFOO.getPositionHandle());
    GLES20.glVertexAttribPointer(shaderFOO.getPositionHandle(), 3, GLES20.GL_FLOAT, false, 0, 0);

    GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, textureBufferHandle);
    GLES20.glEnableVertexAttribArray(textureCoordHandle);
    GLES20.glVertexAttribPointer(shaderFOO.getAttributeHandle(), 2, GLES20.GL_FLOAT, false, 0, 0);

    GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 0, 3);
}


public void renderBAR() {
    GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, verticesBARBufferHandle);
    GLES20.glEnableVertexAttribArray(shaderBAR.getPositionHandle());
    GLES20.glVertexAttribPointer(shaderBAR.getPositionHandle(), 3, GLES20.GL_FLOAT, false, 0, 0);

    GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, colorBufferHandle);
    GLES20.glEnableVertexAttribArray(shaderBAR.getAttributeHandle());
    GLES20.glVertexAttribPointer(shaderBAR.getAttributeHandle(), 3, GLES20.GL_FLOAT, false, 0, 0);

    GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, 0);

    GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 0, 3);
}

I've kept the setup as simple as possible. 6 verts, 2 triangles, one shader for each triangle. One shader uses color to render the triangle, the other uses texture. The only shader that ever works is the one (or the last one, if I call both) I call in the onSurfaceCreated() method.

So as I've said, each shader works fine alone, but I'm hitting a roadblock when trying to switch back and forth between the two.

Community
  • 1
  • 1
arkon
  • 2,209
  • 3
  • 27
  • 36
  • I'll typically use the Tracer tool in a situation like this: https://developer.android.com/studio/profile/gltracer.html Then you can 'walk' through the commands as they are executed and examine the output. I don't recal being able to examine the state, but it's been a while. – James Poag May 12 '17 at 00:57

1 Answers1

0

I don't seem to be able to comment so I'll post an answer instead.

What would fit with your symptoms is that your shaderFOO.getProgramHandle() and shaderBAR.getProgramHandle() might return the same, for example if the stored program handle is overwritten with subsequent calls.

Hard to say without the ShaderLoader class, however.

ovikoomikko
  • 577
  • 6
  • 11
  • The ShaderLoader handles the entire setup of the shader, it is immutable, and its sole purpose after creation is to store the integer-based handles that I need to refer to during rendering. (I.e. *getProgramHandle()* returns the handle stored from the *glCreateProgram()* call.) I've already debugged to ensure the shader handles are both preserved and different throughout the rendering life cycle. Also, as I pointed out, calls to *glUseProgram()* are ignored entirely in my *onDrawFrame()*, regardless of what shader I'm calling it on. – arkon Oct 07 '14 at 17:18
  • When you say ignored, do you mean that both triangles get rendered with texture OR with color? Or that the other one doesn't get rendered at all? I'd put _all_ the attributes and uniforms to the class for the sake of clarity. There is some confusion with at least textureCoordHandle and shaderFOO.getAttributeHandle() in renderFOO. – ovikoomikko Oct 07 '14 at 19:05