2016-02-03 37 views
8

Próbuję przesłać małą tablicę zmiennoprzecinkową jako teksturę OpenGL ES 2.0 i odczytać ją w celu lepszego zrozumienia GPGPU. Próbuję to zrobić na GPU SGX 530 na TI OMAP3 ARM SoC.OpenGL ES 2 Jak renderować teksturę i wyodrębnić dane dla testu GPGPU

Śledzę ten przewodnik: enter link description here

Moje kodu aktualnie tworzy i zapełnia 2 tablice float, a następnie tworzy "pass through" shaderów tak:

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

} 

ja spróbuje Prześlij teksturę do procesora graficznego, wyrenderuj go do bufora ramki i odczytaj go w następujący sposób:

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

} 

Wygląda na wezwanie do losowania to:

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

} 

Wszystko kompiluje i działa, ale moje dane wyjściowe wygląda następująco:

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

Jak mogę złożyć z powrotem i przeczytaj mój tekst prawidłowo? Dzięki!

Odpowiedz

1

ja spróbuje przedstawić fakturę do GPU i odczytać go z powrotem jak to

[...]

Więc oczywiste jest, że nie jestem „coraz” bufor z powrotem OpenGL. Spodziewam się, że będzie zawierał wersje 1.5, ponieważ czytam teksturę z glReadPixels w mojej tablicy dataY.

Dlaczego oczywiście nie powinien to być bufor zwrotny, który czytasz?

Nigdy nie renderujesz tekstury do bufora kolorów, więc odczytanie z bufora kolorów nigdy nie zwróci danych tekstury.

Oryginalny kod wykorzystuje obiekty bufora ramki, aby uzyskać dostęp do tekstury jako bufora kolorów, który w tym scenariuszu będzie miał całkowicie inną wartość semantyczną (nadal jest to jednak w większości bezużyteczny test porównawczy). Zauważ, że większość rzeczywistych urządzeń ES2 obsługuje także GL_OES_framebuffer_object extension, więc możesz to pojęciowo przenieść.

+1

Obsługa standardu FBO jest standardem w ES 2.0. Nie ma potrzeby rozszerzenia. –

3

Pokazany kod nie ma wywołania typu "przeciągnij", który użyłby tekstury i wyrenderował do domyślnego bufora kolorów (wywołanie takie jak glDrawElements). GlReadPixels czyta z domyślnego bufora ramki. Może on zostać zmieniony w OpenGLES2 użyciu GL_COLOR_ATTACHMENT0, nie GL_COLOR_ATTACHMENT0_EXT

Dla większości urządzeń TI ze wsparciem bufora ramki/nullws wsparcia, można użyć kodu profilowania na poniższy link. Poniższy kod testuje niektóre scenariusze GPGPU, w tym wykrywanie krawędzi, konwersję kolorów i używanie FBO. Odnosi się do wezwań do testów 11, 17

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

BTW, chipsety produkcji OMAP3 mają (miały) SGX530 GPU SGX540 nie. SGX540/warianty są używane w chipsetach OMAP4. Byłbyś bardzo szczęśliwy, gdybyś miał wariant produkcyjny OMAP3 z SGX540 :) Możesz to potwierdzić w bootlogach lub w wersji debugującej sterowników PVR.

Należy również wspomnieć, z której płyty/platformy korzysta się.

+1

Tak, masz rację :) I CPU to DM3730 z SGX530. Dzięki za link, spróbuję to jak najszybciej. – PhilBot

4

Masz kilka problemów z tym kodem. Głównym z nich jest to, że ES 2.0 nie obsługuje tekstur pływających. Konkretnie:

  • GL_FLOAT nie jest ważny jako typu argument glTexImage2D() i glTexSubImage2D(). Musi to być GL_UNSIGNED_BYTE lub jedna z różnych opcji GL_UNSIGNED_SHORT_*.
  • Jedynym Format/typ kombinacja dla glReadPixels() obsługiwanym we wszystkich implementacjach jest GL_RGBA/GL_UNSIGNED_BYTE. Istnieje druga zależna od implementacji kombinacja, którą możesz wykonać.
  • Jak już inni zauważyli, próbujesz wypełnić teksturę danymi, a następnie odczytujesz dane z bieżącego bufora ramki. Więc nawet jeśli obie operacje używają poprawnych argumentów, nadal nie otrzymasz danych.

Zdecydowanie zaleca się sprawdzenie dokumentacji przed ślepo próbą przekazania argumentów, które mogą, ale nie muszą być ważne dla wywołań interfejsu API. The man pages to dobry początek. Użyj także glGetError(), która zwróci kody błędów, jeśli wykonasz nieprawidłowe połączenia.

Wdrożenia mogą obsługiwać rozszerzenia, które dodają obsługę niektórych funkcji, których szukasz. Na przykład. OES_texture_float dodaje obsługę tekstur zmiennoprzecinkowych. Zanim jednak spróbujesz ich użyć, musisz sprawdzić obecność tych rozszerzeń.