Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

OpenGL ES 2 How To Render to Texture and Extract Data for GPGPU Test

I am attempting to submit a small float array as an OpenGL ES 2.0 Texture and read it back in order to understand GPGPU better. I am attempting to do this on the SGX 530 GPU on a TI OMAP3 ARM SoC.

I've been following this guide: enter link description here

My code currently creates and populates 2 float arrays, and then creates "pass through" shaders like this:

void GLWidget::initializeGL()
{

    // Max texture size in each direction
    int maxSize;
    glGetIntegerv(GL_MAX_TEXTURE_SIZE,&maxSize);
    texSize = sqrt(maxSize);
    texSize = 2;
    qDebug() << "GL_MAX_TEXTURE_SIZE " << maxSize << " SQRT " << texSize;

    // Define input and output arrays of RGBA format with each channel being u8
    m_Format = 4;
    dataX = (quint8*)malloc(m_Format*texSize*texSize*sizeof(quint8));
    dataY = (quint8*)malloc(m_Format*texSize*texSize*sizeof(quint8));

    // Setup some dummy data
    int arraySize = m_Format*texSize*texSize;
    qDebug() << "Array Size: " << arraySize;
    for (int i = 0; i < arraySize ; i++) {
        dataX[i] = i;
    }

    for (int i = 0; i < arraySize ; i++) {
        dataY[i] = 0;
    }

    QGLShader *vshader = new QGLShader(QGLShader::Vertex);
    const char *vsrc =
            "attribute highp vec4 vertex;\n"
            "attribute highp vec4 texCoord;\n"
            "varying vec2 texc;\n"
            "void main(void)\n"
            "{\n"
            "    gl_Position = vertex;\n"
            "    texc = texCoord.xy;\n"
            "}\n";
    vshader->compileSourceCode(vsrc);

    QGLShader *fshader = new QGLShader(QGLShader::Fragment);
    const char *fsrc =
            "varying highp vec2 texc;\n"
            "uniform sampler2D tex;\n"
            "void main(void)\n"
            "{\n"
            "    gl_FragColor = texture2D(tex, texc);\n"
            "}\n";
    fshader->compileSourceCode(fsrc);

    program.addShader(vshader);
    program.addShader(fshader);
    program.link();

    vertexAttr = program.attributeLocation("vertex");
    texCoordAttr = program.attributeLocation("texCoord");
    textureUniform = program.uniformLocation("tex");

}

I then attempt to submit the texture to the GPU, render it to a framebuffer, and read it back like this:

void GLWidget::renderToScene()
{

    // Bind and configure a texture
    glActiveTexture(GL_TEXTURE0);
    glGenTextures(1, &m_hTexture);
    glBindTexture(GL_TEXTURE_2D, m_hTexture);
    glUniform1i(textureUniform, 0);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, texSize, texSize, 0, GL_RGBA, GL_UNSIGNED_BYTE, dataX); // Allocate buffer to hold RGBA with 8 bytes each

    // Generate handles for Frame Buffer Object
    glGenFramebuffers(1, &m_hFBO);

    // Switch the render target to the current FBO to update the texture map
    glBindFramebuffer(GL_FRAMEBUFFER, m_hFBO);

    qDebug() << "Data before roundtrip:";
    int arraySize = m_Format*texSize*texSize;
    for (int i = 0 ; i < arraySize ; i++)
        qDebug() << dataX[i];

    // FBO attachment is complete?
    if (glCheckFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE)
    {

        qDebug() << "Frame buffer is present...";
        glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, m_hTexture, 0);
        //glTexSubImage2D(GL_TEXTURE_2D,0,0,0,texSize,texSize, GL_RGBA,GL_UNSIGNED_BYTE,dataX); // pixel data is RGBA and each channel u8

        static const GLfloat squareVertices[] = {
            -1.0f, -1.0f,
            1.0f, -1.0f,
            -1.0f,  1.0f,
            1.0f,  1.0f,
        };

        static const GLfloat textureVertices[] = {
            1.0f, 1.0f,
            1.0f, 0.0f,
            0.0f,  1.0f,
            0.0f,  0.0f,
        };

        // ensure no VBOs or IBOs are bound
        glBindBuffer(GL_ARRAY_BUFFER, 0);
        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);

        // Set pointers to the arrays
        glVertexAttribPointer(ATTRIB_VERTEX, 2, GL_FLOAT, 0, 0, squareVertices);
        glEnableVertexAttribArray(ATTRIB_VERTEX);
        glVertexAttribPointer(ATTRIB_TEXTUREPOSITON, 2, GL_FLOAT, 0, 0, textureVertices);
        glEnableVertexAttribArray(ATTRIB_TEXTUREPOSITON);

        glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);

        glDisableVertexAttribArray(ATTRIB_VERTEX);
        glDisableVertexAttribArray(ATTRIB_TEXTUREPOSITON);

    }

    qDebug() << "Zero data:";
    for (int i = 0; i < arraySize ; i++)
        qDebug() << dataY[i];

    // GPGPU Extract
    glReadPixels(0, 0, texSize, texSize, GL_RGBA,GL_UNSIGNED_BYTE,dataY);

    // print out results
    qDebug() << "Data after roundtrip:";
    for (int i = 0; i < arraySize ; i++)
        qDebug() << dataY[i];

    // Unbind the FBO so rendering will return to the main buffer.
    glBindFramebuffer(GL_FRAMEBUFFER, 0);

    qDebug() << "Done...";
    sleep(60000);

}

The draw call looks like this:

void GLWidget::draw() {

    glClearColor(0.1f, 0.1f, 0.2f, 1.0f);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    glFrontFace(GL_CW);
    glCullFace(GL_FRONT);
    glEnable(GL_CULL_FACE);
    glEnable(GL_DEPTH_TEST);

    // Draw
    program.bind();
    renderToScene();
    program.release();

    glDisable(GL_DEPTH_TEST);
    glDisable(GL_CULL_FACE);

    swapBuffers();

}

Everything compiles and runs, but my data output looks like this:

Found SGX/MBX driver, enabling FullClearOnEveryFrame 
Found v1.4 driver, enabling brokenTexSubImage 
Found non-Nokia v1.4 driver, enabling brokenFBOReadBack 
GL_MAX_TEXTURE_SIZE  2048  SQRT  2 
Array Size:  16 
Data before roundtrip: 
0 
1 
2 
3 
4 
5 
6 
7 
8 
9 
10 
11 
12 
13 
14 
15 
Zero data: 
0 
0 
0 
0 
0 
0 
0 
0 
0 
0 
0 
0 
0 
0 
0 
0 
Data after roundtrip: 
0 
0 
0 
0 
0 
0 
0 
0 
0 
0 
0 
0 
0 
0 
0 
0 
Done... 

How can I submit and read back my text properly? Thanks!

like image 521
PhilBot Avatar asked Feb 03 '16 20:02

PhilBot


1 Answers

You got a number of issues with this code. The main one being that ES 2.0 does not support float textures. Specifically:

  • GL_FLOAT is not valid as the type argument of glTexImage2D() and glTexSubImage2D(). This needs to be GL_UNSIGNED_BYTE, or one of various GL_UNSIGNED_SHORT_* options.
  • The only format/type combination for glReadPixels() supported across all implementations is GL_RGBA/GL_UNSIGNED_BYTE. There is a second implementation dependent combination you can query.
  • As others already pointed out, you're attempting to fill a texture with data, and then reading data from the current framebuffer. So even if both operations used valid arguments, you still would not get the data.

I would strongly recommend that you check some documentation before blindly trying to pass arguments that may or may not be valid to API calls. The man pages are a good start. Also, use glGetError(), which will return error codes if you make invalid calls.

Implementations can support extensions that add support for some of the functionality you're looking for. E.g. OES_texture_float adds support for float textures. But you need to check for the presence of these extensions before attempting to use them.

like image 166
Reto Koradi Avatar answered Oct 25 '22 17:10

Reto Koradi