3

So I am following one of the simplest examples I could find on transform feedback, here, and converting it to Android/Java, but Android seems to be missing the glGetBufferSubData function available in OpenGL ES 3.0.

I've tried searching the Android Source to see if this method is used when calling another method under the JNI, but I am not sure I am even looking in the correct place for that.

If this function doesn't exist how can I read the data out from the transform feedback? I've looked at glGetTransformfeedbackVarying, glGetBufferPointerv and glReadBuffer but none seem to do what I want.

Here is my code:

import com.harmonicprocesses.penelopefree.openGL.MyGLRenderer;
import android.opengl.GLES30;
import android.util.Log;

import java.nio.ByteBuffer;
import java.nio.FloatBuffer;

/**
* Created by izzy on 6/24/15.
*/
public class TransformFeedback {


// Vertex shader
private final String vertexShaderSrc =

        "in float inValue;\n" +
        "out float outValue;\n" +

        "void main() {\n" +
        "    outValue = sqrt(inValue);\n" +
        "}\n";

private final int mProgram;


public TransformFeedback{

    // Compile shader
    int vertexShader = MyGLRenderer.loadShader(GLES30.GL_VERTEX_SHADER,
            vertexShaderSrc);

    // Create program and specify transform feedback variables
    mProgram = GLES30.glCreateProgram();
    GLES30.glAttachShader(mProgram, vertexShader);

    //const GLchar* feedbackVaryings[] = { "outValue" };
    GLES30.glTransformFeedbackVaryings(mProgram, 1, {"outValue"}, GLES30.GL_INTERLEAVED_ATTRIBS);

    GLES30.glLinkProgram(mProgram);
    GLES30.glUseProgram(mProgram);

    // Create VAO
    int[] vao = new int[1];
    GLES30.glGenVertexArrays(1, vao, 0);
    GLES30.glBindVertexArray(vao[0]);

    // Create input VBO and vertex format
    int bufferLength = 5 * 4; //5 floats 4 bytes each
    ByteBuffer bb = ByteBuffer.allocateDirect(bufferLength);
    FloatBuffer data = bb.asFloatBuffer();
    float[] floatData = { 1.0f, 2.0f, 3.0f, 4.0f, 5.0f };
    data.put(floatData);
    data.position(0);


    int[] vbo = new int[1];
    GLES30.glGenBuffers(1, vbo, 0);
    GLES30.glBindBuffer(GLES30.GL_ARRAY_BUFFER, vbo[0]);
    GLES30.glBufferData(GLES30.GL_ARRAY_BUFFER, bufferLength, data, GLES30.GL_STATIC_DRAW);

    int inputAttrib = GLES30.glGetAttribLocation(mProgram, "inValue");
    GLES30.glEnableVertexAttribArray(inputAttrib);
    GLES30.glVertexAttribPointer(inputAttrib, 1, GLES30.GL_FLOAT, false, 0, 0);

    // Create transform feedback buffer
    int[] tbo = new int[1];
    GLES30.glGenBuffers(1, tbo, 0);
    GLES30.glBindBuffer(GLES30.GL_ARRAY_BUFFER, tbo[0]);
    GLES30.glBufferData(GLES30.GL_ARRAY_BUFFER, bufferLength, null, GLES30.GL_STATIC_READ);

    // Perform feedback transform
    GLES30.glEnable(GLES30.GL_RASTERIZER_DISCARD);

    GLES30.glBindBufferBase(GLES30.GL_TRANSFORM_FEEDBACK_BUFFER, 0, tbo[0]);

    GLES30.glBeginTransformFeedback(GLES30.GL_POINTS);
    GLES30.glDrawArrays(GLES30.GL_POINTS, 0, 5);
    GLES30.glEndTransformFeedback();

    GLES30.glDisable(GLES30.GL_RASTERIZER_DISCARD);

    GLES30.glFlush();

    // Fetch and print results
    float feedback[] = new float[5];
    GLES30.glGetBufferSubData(GLES30.GL_TRANSFORM_FEEDBACK_BUFFER, 0, bufferLength, feedback);

    Log.e("TransformFeedback", String.format("%f %f %f %f %f\n", feedback[0], feedback[1], feedback[2], feedback[3], feedback[4]));

}

My final implementation won't need to read the data out necessarily, just use it in the shader on the next pass(feedback). But this really is the first step.

genpfault
  • 51,148
  • 11
  • 85
  • 139
HPP
  • 1,074
  • 1
  • 13
  • 28

1 Answers1

2

glGetBufferSubData() is not available in ES 3.0, or ES 3.1 for that matter. So there is nothing missing in the Android Java bindings in this case.

The function to use for reading back buffer data in ES 3.0 is glMapBufferRange() . In the C/C++ bindings, this returns a pointer to CPU readable memory containing the buffer content. Don't forget to call glUnmapBuffer() when you're done reading.

In the Android Java bindings, the function returns an object of type Buffer. Since you can't directly read from a buffer, you'll have to cast it to a ByteBuffer first. This is not really documented, but my answer here explains why I believe this type cast is safe: Safe usage of glMapBufferRange() on Android/Java.

Community
  • 1
  • 1
Reto Koradi
  • 53,228
  • 8
  • 93
  • 133
  • Cool, I've been trying to use that function but I get problems compiling the shader. Am I looking at the wrong specification? https://www.khronos.org/registry/gles/#specs3 , it shows both `glGetBufferSubData`, and the `in` `out` storage qualifiers... – HPP Jun 27 '15 at 22:16
  • no, I was wrong the specification doesn't show `GetBufferSubData`. I swear this was different yesterday... The GLSL es 3.00.4 spec section 3.7 shows `in` `out` qualifiers and `varying` and `attribute` as 'reserved for future use', but I suppose that is another question. – HPP Jun 27 '15 at 22:25
  • @HPP The GLSL that goes with ES 2.0 uses `attribute`/`varying`. With ES 3.0, that became `in`/`out`, matching recent versions of full OpenGL. – Reto Koradi Jun 27 '15 at 22:35
  • ya so if I am using `in`/ `out` and getting compiling errors I must not have set the EGL context to 3.0 correctly right? – HPP Jun 27 '15 at 22:56
  • 1
    @HPP You'll also need `#version 300 es` at the start of the shader code. – Reto Koradi Jun 28 '15 at 00:56
  • 1
    I am getting all zeros out the mapped buffer, any thoughts? http://stackoverflow.com/q/31095601/2476328 – HPP Jun 29 '15 at 18:33