OpenGL ES 2如何渲染纹理和提取数据以进行GPGPU测试

Phi*_*Bot 8 c++ linux qt opengl-es

我试图提交一个小浮点数组作为OpenGL ES 2.0纹理并读回来以更好地理解GPGPU.我试图在TI OMAP3 ARM SoC上的SGX 530 GPU上执行此操作.

我一直在关注本指南: 在此处输入链接说明

我的代码当前创建并填充2个浮点数组,然后像这样创建"传递"着色器:

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

}
Run Code Online (Sandbox Code Playgroud)

然后我尝试将纹理提交到GPU,将其渲染到帧缓冲区,然后将其读回:

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

}
Run Code Online (Sandbox Code Playgroud)

绘制调用如下所示:

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

}
Run Code Online (Sandbox Code Playgroud)

一切都编译并运行,但我的数据输出如下所示:

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... 
Run Code Online (Sandbox Code Playgroud)

如何正确提交和回读我的文本?谢谢!

der*_*ass 1

然后我尝试将纹理提交给 GPU 并像这样读回

[...]

所以很明显我没有从 OpenGL“获取”缓冲区。我希望它包含 1.5,因为我正在使用 glReadPixels 将纹理读回到我的 dataY 数组中。

为什么它显然不是您正在读回的后台缓冲区?

您永远不会将纹理渲染到颜色缓冲区,因此从颜色缓冲区读回将永远不会返回纹理数据。

原始代码使用帧缓冲区对象来访问纹理作为颜色缓冲区,在这种情况下,这将具有完全不同的语义(尽管它仍然是一个几乎无用的基准)。请注意,大多数现实世界的 ES2 设备也支持GL_OES_framebuffer_object扩展,因此您可以从概念上移植它。