簡體   English   中英

OpenGL ES 2如何渲染紋理和提取數據以進行GPGPU測試

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

我試圖提交一個小浮點數組作為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");

}

然后我嘗試將紋理提交到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);

}

繪制調用如下所示:

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

}

一切都編譯並運行,但我的數據輸出如下所示:

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... 

如何正確提交和回讀我的文本? 謝謝!

您對此代碼有很多問題。 主要的一個是ES 2.0不支持浮動紋理。 特別:

  • GL_FLOAT無效作為glTexImage2D()glTexSubImage2D()類型參數。 這需要是GL_UNSIGNED_BYTE ,或者是各種GL_UNSIGNED_SHORT_*選項之一。
  • 所有實現支持glReadPixels()的唯一格式 / 類型組合是GL_RGBA / GL_UNSIGNED_BYTE 您可以查詢第二個與實現相關的組合。
  • 正如其他人已經指出的那樣,你試圖用數據填充紋理,然后從當前幀緩沖區讀取數據。 因此,即使兩個操作都使用了有效參數,您仍然無法獲取數據。

我強烈建議您在盲目嘗試傳遞可能對API調用有效或可能無效的參數之前檢查一些文檔。 手冊頁是一個好的開始。 另外,使用glGetError() ,如果進行無效調用,它將返回錯誤代碼。

實現可以支持擴展,以增加對您正在尋找的某些功能的支持。 例如, OES_texture_float添加了對浮動紋理的支持。 但是在嘗試使用這些擴展之前,您需要檢查這些擴展是否存在。

顯示的代碼沒有使用紋理和渲染到默認顏色緩沖區的繪制調用(像glDrawElements這樣的調用)。 glReadPixels從默認的Framebuffer中讀取。 可以使用GL_COLOR_ATTACHMENT0在OpenGLES2中更改它,而不是GL_COLOR_ATTACHMENT0_EXT

對於支持幀緩沖支持/ nullw的絕大多數TI器件,您可以使用下面鏈接中的分析代碼。 下面的代碼測試了一些GPGPU場景,包括邊緣檢測,顏色轉換和使用FBO。 請參閱測試11,17的調用

https://github.com/prabindh/sgxperf/blob/master/sgxperf_gles20_vg.cpp

順便說一下,OMAP3生產的芯片組有SGX530 GPU而不是SGX540。 SGX540 /變體用於OMAP4芯片組。 如果您使用SGX540生產OMAP3變體,那將非常幸運。您可以在bootlogs中或使用PVR驅動程序的調試版本進行確認。

還要提一下正在使用的板/平台。

然后我嘗試將紋理提交到GPU並像這樣讀回來

[...]

所以很明顯我沒有從OpenGL“獲取”緩沖區。 我希望它包含1.5,因為我正在使用glReadPixels將紋理讀回到我的dataY數組中。

為什么它顯然不是你正在讀回的后台緩沖區?

您永遠不會將紋理渲染到顏色緩沖區,因此從顏色緩沖區讀回將永遠不會返回紋理數據。

原始代碼使用framebuffer對象來訪問紋理作為顏色緩沖區,在這種情況下它將具有完全不同的語義(盡管如此,它仍然是一個無用的基准)。 請注意,大多數真實世界的ES2設備也支持GL_OES_framebuffer_object擴展 ,因此您可以從概念上移植它。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM