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!
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.glReadPixels()
supported across all implementations is GL_RGBA
/GL_UNSIGNED_BYTE
. There is a second implementation dependent combination you can query.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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With