Substition for glTexImage1D in OpenGL es 3.0? - android

I am trying to port the OpenGL code into OpenGL ES 3.0 code on Android.
However, the function "glTexImage1D" and "GL_TEXTURE_1D" are not defined in
OpenGL ES 2.0 specification. Is there any substitute for that?
My Android phone support 16 texture units, and the implementation of GLSL shader on a personal computer needs to loop-up via 1D texture.
Therefore, the most possible way is to substitute with "glTexImage2D" and "GL_TEXTURE_2D" ?
#include <GL/glut.h>
GLuint tex = 0;
void init()
{
glGenTextures(1, &tex);
glBindTexture(GL_TEXTURE_1D, tex);
glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
//
unsigned char buf[32 * 4];
for (size_t i = 0; i < sizeof(buf); i += 4)
{
buf[i + 0] = rand() % 255;
buf[i + 1] = rand() % 255;
buf[i + 2] = rand() % 255;
buf[i + 3] = 255;
}
glTexImage1D(GL_TEXTURE_1D, 0, 4, sizeof(buf) / 4, 0, GL_RGBA, GL_UNSIGNED_BYTE, buf);
}
void display()
{
glClear(GL_COLOR_BUFFER_BIT);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(-2, 2, -2, 2, -1, 1);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glEnable(GL_TEXTURE_1D);
glBindTexture(GL_TEXTURE_1D, tex);
glColor3ub(255, 255, 255);
glLineWidth(10);
glBegin(GL_LINES);
glTexCoord1i(0);
glVertex2i(-1, -1);
glTexCoord1i(1);
glVertex2i(1, 1);
glEnd();
glutSwapBuffers();
}
int main(int argc, char **argv)
{
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE);
glutInitWindowSize(640, 480);
glutCreateWindow("GLUT");
glutDisplayFunc(display);
init();
glutMainLoop();
return 0;
}

Yes, just use Texture2D and 2D texture with a height of 1.

Thanks,
#include <GL/glut.h>
GLuint tex = 0;
void init()
{
unsigned char buf[ 32 * 4];
for (size_t i = 0; i < sizeof(buf); i += 4)
{
buf[ i + 0] = rand() % 255;
buf[ i + 1] = rand() % 255;
buf[ i + 2] = rand() % 255;
buf[ i + 3] = 255;
}
glGenTextures(1, &tex);
glBindTexture(GL_TEXTURE_2D, tex);
glPixelStorei(GL_UNPACK_ALIGNMENT, 1); // 4 or 8
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 32, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, buf);
}
void display()
{
glClear(GL_COLOR_BUFFER_BIT);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(-2, 2, -2, 2, -1, 1);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
/*
glEnable(GL_TEXTURE_1D);
glBindTexture(GL_TEXTURE_1D, tex);
*/
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, tex);
glColor3ub(255, 255, 255);
glLineWidth(10);
glBegin(GL_LINES);
glTexCoord1i(0);
glVertex2i(-1, -1);
glTexCoord1i(1);
glVertex2i(1, 1);
glEnd();
glutSwapBuffers();
}
int main(int argc, char **argv)
{
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE);
glutInitWindowSize(640, 480);
glutCreateWindow("GLUT");
glutDisplayFunc(display);
init();
glutMainLoop();
return 0;
}

Related

opengl es 3 glBlitFramebuffer - copying one texture into another

I'm trying to copy a texture into another using 'glBlitFramebuffer', I'm working on the classic open gl example hello-gl2 from android ndk-samples. I changed the shaders to support texture and i can correctly render a textured triangle. I also changed the opengl es version requested on the java side so to request opengl-es3 and i updated the Cmakelists file to link the right library. After calling glBlitFramebuffer(0,0,tw, th, 0, 0, tw, th, GL_COLOR_BUFFER_BIT, GL_LINEAR); i get the after blitTexture glBlitFramebuffer() glError (0x502) error. What is the root cause for that?
Code I use:
To generate the textures:
void createTexture(GLuint &tex, int width, int height, int r){
int rowlen = width * 3;
unsigned char buf[width*3*height];
for (int i=0; i<rowlen; i+=3)
for (int j=0; j<height; j++) {
int col = ((int (i/(3*r))) + (int (j/r)))%2;
buf[i+j*rowlen] = buf[i+1+j*rowlen] = buf[i+2+j*rowlen] = col * 255;
}
glGenTextures(1, &tex);
glBindTexture(GL_TEXTURE_2D, tex);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, buf);
// set the texture wrapping/filtering options (on the currently bound texture object)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
LOGI("DEBUG C++ Texture created [%d]", tex);
}
to setup the framebuffer:
bool SetupFramebuffer(GLuint tex, int width, int height)
{
if (fb == 0)
{
glGenFramebuffers(1, &fb);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fb);
glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
GL_TEXTURE_2D, tex, 0);
GLenum status = glCheckFramebufferStatus(GL_DRAW_FRAMEBUFFER);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
if (status != GL_FRAMEBUFFER_COMPLETE)
{
LOGE("Incomplete frame buffer object!");
return false;
}
LOGI("Created FBO %d for texture %d.",
fb, tex);
}
return true;
}
to build the array of textures inside the setupGraphics function:
createTexture(tex, tw, th, 6);
for (int i = 0; i<25; i++) createTexture(aniTex[i], tw, th, 3+i);
SetupFramebuffer(tex, tw, th);
and finally to blit the framebuffer:
const GLenum attachment[1] = { GL_COLOR_ATTACHMENT0 };
void blitTexture() {
static int time = 0;
glBindFramebuffer(GL_FRAMEBUFFER, fb);
checkGlError("blitTexture glBindFramebuffer");
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1,
GL_TEXTURE_2D, aniTex[time], 0);
checkGlError("blitTexture glFramebufferTexture2D");
glReadBuffer(GL_COLOR_ATTACHMENT1);
checkGlError("blitTexture glReadBuffer");
glDrawBuffers(1, attachment);
checkGlError("blitTexture glDrawBuffers");
GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
if (status != GL_FRAMEBUFFER_COMPLETE) LOGE("Incomplete frame buffer object!");
glBlitFramebuffer(0,0,tw, th, 0, 0, tw, th, GL_COLOR_BUFFER_BIT, GL_LINEAR);
checkGlError("blitTexture glBlitFramebuffer");
int samples;
glGetFramebufferParameteriv(GL_READ_FRAMEBUFFER, GL_FRAMEBUFFER_DEFAULT_SAMPLES, &samples);
LOGI("SAMPLES draw buffer %d", samples);
time = ++time%25;
}
full project can be found here: https://github.com/AndrewBloom/BlitFramebufferExample

The bitmap generated by freetype2 on android, the text will repeat, how to solve it

I use FreeType 2.10.2 to render text on Android. Now the bitmap is generated, but there are multiple (4) repeated texts. The picture is as follows:
The rendered text is "G", where the black range is the size of the bitmap, but there is a problem. First, there are four "G" in the bitmap, and then the text "G" does not fill the entire bitmap. I don't know why this is, here is the code:
int initTexture() {
if (init) return -1;
FT_Face face;
FT_Library ft;
FT_Init_FreeType(&ft);
FT_New_Face(ft, fontPathNativeString, 0, &face);
FT_Set_Pixel_Sizes(face, 0, 12 * 12);
FT_ULong wChar = textUnicodeString[0];
FT_Load_Char(face, wChar, FT_LOAD_DEFAULT);
FT_GlyphSlot glyph = face->glyph;
FT_Render_Glyph(glyph, FT_RENDER_MODE_NORMAL);
glActiveTexture(GL_TEXTURE0);
GLuint texture;
glGenTextures(1, &texture);
glBindTexture(GL_TEXTURE_2D, texture);
glTexImage2D(
GL_TEXTURE_2D,
0,
GL_RGBA,
face->glyph->bitmap.width,
face->glyph->bitmap.rows,
0,
GL_RGBA,
GL_UNSIGNED_BYTE,
face->glyph->bitmap.buffer
);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
characterTextureID = texture;
GLfloat xpos = 0 + face->glyph->bitmap_left;
GLfloat ypos = 500 + (face->glyph->bitmap.rows - face->glyph->bitmap_top);
GLfloat scale = 5.0f;
GLfloat w = face->glyph->bitmap.width / surfaceWidth * scale;
GLfloat h = face->glyph->bitmap.rows * scale / surfaceHeight;
xpos = (xpos - surfaceWidth) / surfaceWidth;
ypos = (surfaceHeight - ypos) / surfaceHeight;
GLfloat vertices[24] = {
xpos, ypos, 0.0f, 0.0f,
xpos, ypos - h, 0.0f, 1.0f,
xpos + w, ypos - h, 1.0f, 1.0f,
xpos, ypos, 0.0f, 0.0f,
xpos + w, ypos - h, 1.0f, 1.0f,
xpos + w, ypos, 1.0f, 0.0f
};
glGenBuffers(1, &VBO);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * 6 * 4, vertices, GL_STATIC_DRAW);
FT_Done_Face(face);
FT_Done_FreeType(ft);
init = 1;
return 0;
}
JNIEXPORT void JNICALL
Java_me_excq_androidopengles20demo_chapters11_MyRenderer02_drawFrame(JNIEnv *env, jobject thiz) {
initTexture();
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glClear(GL_COLOR_BUFFER_BIT);
glClearColor(0.3f, 0.5f, 1.0f, 0.0f);
glUseProgram(programID);
glUniform3f(glGetUniformLocation(programID, "ourTextColor"), 0.5, 0.8, 0.2);
GLuint vertexHandle = (GLuint) glGetAttribLocation(programID, "vertex");
glEnableVertexAttribArray(vertexHandle);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glVertexAttribPointer(vertexHandle, 4, GL_FLOAT, GL_FALSE, 4 * sizeof(GLfloat), 0);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, characterTextureID);
glDrawArrays(GL_TRIANGLES, 0, 6);
glDisableVertexAttribArray(vertexHandle);
}
and my vertex shader code is:
attribute vec4 vertex;
varying vec2 outTexCoord;
void main() {
gl_Position = vec4(vertex.xy, 0.0, 1.0);
outTexCoord = vertex.zw;
}
I wrote it according to this tutorial(LearnOpenGL - Text Rendering), but I don’t know why this happens, how can I solve it?
Thank you.
If you closely look at the image, then you can see, that the 4 characters are different:
What seems to be 4 characters, actually is 1 character, splitted in parts.
The issue is caused by the fact, that FT_Render_Glyph generates an image, with 1 channel rather than an RGBA image. Hence the format argument to glTexImage2D hast to be GL_RED, GL_LUMINANCE or GL_ALPHA:
glTexImage2D(
GL_TEXTURE_2D,
0,
GL_RED,
face->glyph->bitmap.width,
face->glyph->bitmap.rows,
0,
GL_RED,
GL_UNSIGNED_BYTE,
face->glyph->bitmap.buffer
);

Freetype Library gives triple textures and weird symbols

Currently working on an android ndk/ opengl project and I'm trying to use freetype as my font rendering library, but I keep getting a weird error when I render text to the screen. Here is what it is showing for a few sample texts: (note: the bottom one is supposed to say "This is")
Setup:
void TextRenderer::SetupGlyphs(std::string fontPath, int size){
__android_log_print(ANDROID_LOG_INFO, "SetupGlyphs", "Font location: %s", fontPath.c_str());
if(shadersInitialized == 0)
CreateShader();
glUseProgram(this->shader);
// FreeType
FT_Library ft;
if (FT_Init_FreeType(&ft))
__android_log_print(ANDROID_LOG_INFO, "SetupGlyphs", "ERROR::FREETYPE: Could not init FreeType Library.");
FT_Face face;
if (FT_New_Face(ft, fontPath.c_str(), 0, &face))
__android_log_print(ANDROID_LOG_INFO, "SetupGlyphs", "ERROR::FREETYPE: Failed to load font: %s", fontPath.c_str());
FT_Set_Pixel_Sizes(face, 0, size);
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
for (GLubyte c = 0; c < 128; c++){
if(FT_Load_Char(face, c, FT_LOAD_RENDER)){
__android_log_print(ANDROID_LOG_INFO, "SetupGlyphs", "ERROR::FREETYPE: Failed to load Glyph");
continue;
}
GLuint texture;
glGenTextures(1, &texture);
glBindTexture(GL_TEXTURE_2D, texture);
glTexImage2D(
GL_TEXTURE_2D,
0,
GL_RGB,
face->glyph->bitmap.width,
face->glyph->bitmap.rows,
0,
GL_RGB,
GL_UNSIGNED_BYTE,
face->glyph->bitmap.buffer
);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
Character character = {
texture,
ivec2(face->glyph->bitmap.width, face->glyph->bitmap.rows),
ivec2(face->glyph->bitmap_left, face->glyph->bitmap_top),
static_cast<GLuint>(face->glyph->advance.x)
};
characters.insert(std::pair<GLchar, Character>(c, character));
}
glBindTexture(GL_TEXTURE_2D, 0);
FT_Done_Face(face);
FT_Done_FreeType(ft);
}
Rendering:
void TextRenderer::RenderTexts()
{
if(shadersInitialized == 0)
CreateShader();
// Activate corresponding render state
glUseProgram(this->shader);
GLuint projectionLocation = glGetUniformLocation(this->shader, "projection");
glUniformMatrix4fv(projectionLocation, 1, GL_FALSE, projectionMatrix);
for (int i=0; i<projects.size(); i++) {
ProjectLabel project = projects.at(i);
glUniform3f(glGetUniformLocation(this->shader, "textColor"), project.textColor.x, project.textColor.y, project.textColor.z);
glActiveTexture(GL_TEXTURE0);
GLuint vertexBuffer;
glGenBuffers(1, &vertexBuffer);
/* Set up the VBO for our vertex data */
glEnableVertexAttribArray(0);
glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);
glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 0, 0);
// Iterate through all characters
std::string::const_iterator c;
GLuint x = project.x;
for (c = project.text.begin(); c != project.text.end(); c++)
{
Character ch = characters[*c];
GLfloat xpos = x + ch.Bearing.x;
GLfloat ypos = project.y - (ch.Size.y - ch.Bearing.y);
GLfloat w = ch.Size.x;
GLfloat h = ch.Size.y;
// Update VBO for each character
GLfloat vertices[6*4] = {
xpos, ypos + h, 0.0, 0.0 ,
xpos, ypos, 0.0, 1.0 ,
xpos + w, ypos, 1.0, 1.0 ,
xpos, ypos + h, 0.0, 0.0 ,
xpos + w, ypos, 1.0, 1.0 ,
xpos + w, ypos + h, 1.0, 0.0
};
glBindTexture(GL_TEXTURE_2D, ch.TextureID);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_DYNAMIC_DRAW);
glDrawArrays(GL_TRIANGLES, 0, 6);
x += (ch.Advance / 64); // Bitshift by 6 to get value in pixels (2^6 = 64 (divide amount of 1/64th pixels by 64 to get amount of pixels))
}
glDisableVertexAttribArray(0);
}
glBindTexture(GL_TEXTURE_2D, 0);
}
So, to anyone that may find this post, scowering the web for hours on end, trying to figure out why everything looks funky, I found the answer. Freetype is not aligned (at least not in my project) through GL_RGB, instead is aligned through GL_LUMINANCE. By changing such things in glTexImage2D I solved on the above issues, as well as SIGABRT errors I was also getting.
TLDR;
glTexImage2D(
GL_TEXTURE_2D,
0,
GL_RGB, => GL_LUMINANCE
face->glyph->bitmap.width,
face->glyph->bitmap.rows,
0,
GL_RGB, => GL_LUMINANCE
GL_UNSIGNED_BYTE,
face->glyph->bitmap.buffer
);

glTranslatef/2D viewport setup issue

When i try glTranslatef(1,-1,0); it pushes my quad's lefthand corner to the center of the screen instead of what im trying to do, moving it 1 pixel to the left and 1 down. Im pretty sure this is because my viewport isnt set correctly but im unsure why. pic, view setup code and drawing code below.
setupView:
-(void)setupView:(GLView*)view
{
printf("setup view");
glClearColor(0,1,1, 1);
// Enable Smooth Shading, default not really needed.
glShadeModel(GL_SMOOTH);
// Depth buffer setup.
glClearDepthf(1.0f);
//enable textures.
glEnable(GL_TEXTURE_2D);
glHint(GL_PERSPECTIVE_CORRECTION_HINT,GL_FASTEST);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
CGRect rect = view.bounds;
glOrthof( 0,rect.size.width,-rect.size.height, 0, -1, 1 ) ;
glViewport(0, 0,rect.size.width,rect.size.height);
glMatrixMode(GL_PROJECTION);
// Bind the number of textures we need, in this case one.
glGenTextures(1, &texture[0]);
glBindTexture(GL_TEXTURE_2D, texture[0]);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameterf(GL_TEXTURE_2D, GL_GENERATE_MIPMAP,GL_TRUE);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glLoadIdentity();
NSString *path = [[NSBundle mainBundle] pathForResource:#"cm2" ofType:#"jpg"];
NSData *texData = [[NSData alloc] initWithContentsOfFile:path];
UIImage *image = [[UIImage alloc] initWithData:texData];
if (image == nil)
NSLog(#"Do real error checking here");
GLuint width = CGImageGetWidth(image.CGImage);
GLuint height = CGImageGetHeight(image.CGImage);
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
void *imageData = malloc( height * width * 4 );
CGContextRef context = CGBitmapContextCreate( imageData, width, height, 8, 4 * width, colorSpace, kCGImageAlphaPremultipliedLast | kCGBitmapByteOrder32Big );
// Flip the Y-axis
CGContextTranslateCTM (context, 0, height);
CGContextScaleCTM (context, 1.0, -1.0);
CGColorSpaceRelease( colorSpace );
CGContextClearRect( context, CGRectMake( 0, 0, width, height ) );
CGContextDrawImage( context, CGRectMake( 0, 0, width, height ), image.CGImage );
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, imageData);
CGContextRelease(context);
free(imageData);
[image release];
[texData release];
}
drawView:
- (void)drawView:(GLView*)view
{
//draw calls
glColor4f(1,1,1,1);
glClear(GL_COLOR_BUFFER_BIT);
glLoadIdentity();
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
static const Vertex3D vertices[] = {
{0, 0, 1}, //TL
{ 1024.0f,0, 1}, //TR
{0, -1024.0f, 1}, //BL
{ 1024.0f, -1024.0f, 1} //BR
};
static const GLfloat texCoords[] = {
0.0, 1.0,
1.0, 1.0,
0.0, 0.0,
1.0, 0.0
};
glTranslatef(1,-1, 1);
glScalef(scale,scale,1);
glBindTexture(GL_TEXTURE_2D, texture[0]);
glVertexPointer(3, GL_FLOAT, 0, vertices);
glTexCoordPointer(2, GL_FLOAT, 0, texCoords);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
glDisableClientState(GL_VERTEX_ARRAY);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
}
You need to first set up your viewport, then set the matrix mode to projection, then call glOrtho, like so:
glViewPort (0, 0, width, height);
glMatrixMode (GL_PROJECTION);
glLoadIdentity ();
glOrtho (0, width, 0, height, -1, 1); // Usually this is -width/2,width/2,-height/2,height/2
Also, you probably want to set the matrix mode to ModelView after that to draw your model.

Fastest 2D frame rate possible with android NDK, my try included, better options available?

Fastest 2D frame rate possible with android NDK, my try included, better options available?
I used the NDK and OpenGL ES 2.0 to display a frame as a texture on a GL_TRIANGLE_STRIP.
This was done on a HTC Desire, same hardware as Nexus One.
I tried to load multiple GL_RGBA textures and switch between the textures, because the normal fill rate with a single texture was disappointingly low:
1 texture: 4.78 fps
2 textures: 19.68 fps
3 textures: 20.18 fps
4 textures: 28.52 fps
5 textures: 29.01 fps
6 textures: 30.32 fps
I think even 30.32 fps RGBA is still too slow.
So is this the way to go to achieve the fastest 2D frame rate (with same quality)?
Any suggestions to speed it up?
Here is the relevant code, it is based on the hello-gl2 NDK example:
=== GL2JNIView.java :
init(false, 0, 0);
ConfigChooser(5, 6, 5, 0, depth, stencil);
=== gl_code.cpp :
#include <GLES2/gl2.h>
#include <GLES2/gl2ext.h>
#include <android/log.h>
#include <stdlib.h>
#include <time.h>
typedef unsigned char byte;
static int view_width, view_height;
static byte* framebuffer;
static int framebuffer_size;
static GLuint texture_id[6];
static const char* vertexSrc =
"precision highp float;\n"
"precision highp int;\n"
"attribute vec4 vertexCoords;\n"
"attribute vec2 textureCoords;\n"
"varying vec2 f_textureCoords;\n"
"void main() {\n"
" f_textureCoords = textureCoords;\n"
" gl_Position = vertexCoords;\n"
"}\n";
static const char* fragmentSrc =
"precision highp float;\n"
"precision highp int;\n"
"uniform sampler2D texture;\n"
"varying vec2 f_textureCoords;\n"
"void main() {\n"
" gl_FragColor = texture2D(texture, f_textureCoords);\n"
"}\n";
static GLuint shaderProgram;
static GLint attrib_vertexCoords;
static GLint attrib_textureCoords;
static GLint uniform_texture;
static const GLfloat vertexCoords[] = {-1.0, 1.0, -1.0, -1.0, 1.0, 1.0, 1.0, -1.0};
static const GLfloat textureCoords[] = {0.0, 0.0, 0.0, 1.0, 1.0, 0.0, 1.0, 1.0};
JNIEXPORT void JNICALL Java_com_android_gl2jni_GL2JNILib_init(JNIEnv * env, jobject obj, jint width, jint height) {
view_width = width;
view_height = height;
framebuffer_size = 4*view_width*view_height;
framebuffer = (byte*)calloc(framebuffer_size, sizeof(byte));
for (int i = 0; i < framebuffer_size; i++) framebuffer[i] = 0;
glViewport(0, 0, view_width, view_height);
glGenTextures(6, &texture_id[0]);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, texture_id[0]);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, view_width, view_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, framebuffer);
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, texture_id[1]);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, view_width, view_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, framebuffer);
glActiveTexture(GL_TEXTURE2);
glBindTexture(GL_TEXTURE_2D, texture_id[2]);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, view_width, view_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, framebuffer);
glActiveTexture(GL_TEXTURE3);
glBindTexture(GL_TEXTURE_2D, texture_id[3]);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, view_width, view_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, framebuffer);
glActiveTexture(GL_TEXTURE4);
glBindTexture(GL_TEXTURE_2D, texture_id[4]);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, view_width, view_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, framebuffer);
glActiveTexture(GL_TEXTURE5);
glBindTexture(GL_TEXTURE_2D, texture_id[5]);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, view_width, view_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, framebuffer);
shaderProgram = glCreateProgram();
GLuint vertexShader = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(vertexShader, 1, &vertexSrc, NULL);
glCompileShader(vertexShader);
glAttachShader(shaderProgram, vertexShader);
GLuint fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fragmentShader, 1, &fragmentSrc, NULL);
glCompileShader(fragmentShader);
glAttachShader(shaderProgram, fragmentShader);
glLinkProgram(shaderProgram);
glUseProgram(shaderProgram);
uniform_texture = glGetUniformLocation(shaderProgram, "texture");
glUniform1i(uniform_texture, 0);
attrib_vertexCoords = glGetAttribLocation(shaderProgram, "vertexCoords");
glEnableVertexAttribArray(attrib_vertexCoords);
glVertexAttribPointer(attrib_vertexCoords, 2, GL_FLOAT, GL_FALSE, 0, vertexCoords);
attrib_textureCoords = glGetAttribLocation(shaderProgram, "textureCoords");
glEnableVertexAttribArray(attrib_textureCoords);
glVertexAttribPointer(attrib_textureCoords, 2, GL_FLOAT, GL_FALSE, 0, textureCoords);
}
JNIEXPORT void JNICALL Java_com_android_gl2jni_GL2JNILib_step(JNIEnv * env, jobject obj) {
static int frame_count = 0;
static clock_t last_time = clock();
static int last_frame_count = 0;
frame_count++;
if (clock()-last_time > 1e7) {
__android_log_print(ANDROID_LOG_INFO, "libgl2jni", "fps: %f", ((float)frame_count-last_frame_count)/(clock()-last_time)*1e6);
last_time = clock();
last_frame_count = frame_count;
}
static byte val = 0;
val++;
if (val == 256) val = 0;
for (int i = 0; i < framebuffer_size; i++) framebuffer[i] = val;
int tst = frame_count%6;
if (tst == 0) {
glActiveTexture(GL_TEXTURE0);
} else if (tst == 1) {
glActiveTexture(GL_TEXTURE1);
} else if (tst == 2) {
glActiveTexture(GL_TEXTURE2);
} else if (tst == 3) {
glActiveTexture(GL_TEXTURE3);
} else if (tst == 4) {
glActiveTexture(GL_TEXTURE4);
} else if (tst == 5) {
glActiveTexture(GL_TEXTURE5);
}
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, view_width, view_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, framebuffer);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
}
I realize your question is rather old, and you've likely either solved it or moved onto something else, but I'll give a suggestion in case if anyone else comes across this.
First of all, glTexImage2D requires the graphics subsystem to perform a memory free and reallocation of the texture object every time you call it, since the texture parameters can change between calls. An optimized driver might look at the width, height and format, and if they are all the same then the reallocation could be skipped, but it's not likely that the Android driver implementers are actually doing this.
To avoid the texture reallocation completely, you can use glTexSubImage2D to replace the complete bitmap, or just a portion of it. If you combine this with your above texture buffering scheme, you should see a fairly large speed increase. You could even extend this to detect the modified areas of your display and only update the rectangular portions that have changed between frames.
To summarize, change your texture initialization code to call glTexImage2D with a NULL bitmap pointer, so OpenGL only allocates the memory for the texture and doesn't actually copy any data into it like so:
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, view_width, view_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
Then update every frame in your game loop with:
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, view_width, view_height, GL_RGBA, GL_UNSIGNED_BYTE, framebuffer);
Fastest possible onscreen frame rate is effectively capped by screen refresh rate, which is vendor-specific. My guess would be at least 60 Hz (60 frames per second).
Off-screen rendering is not capped by refresh-rate and depends on the intensity of computing you are performing. Endless loop with some gl code may run significantly faster than 60 Hz, or, for that matter, slower.

Categories

Resources