What differences in OpenGl rendering are there between the Atrix 4G and other Android phones?
The reason I'm asking this is that our app (The Elements) runs fine on a Droid and a Nexus One, our two test phones, but not correctly on our recently acquired Atrix 4G. What draws is a skewed version of what should draw, with all the colors being replaced with alternating lines of cyan, magenta, and yellow (approximately), which leads us to believe that one of the primary colors for the sand particles that should show up is missing based on which line it's on. I'm sorry for the unclear description, we had images but since this account doesn't have 10 reputation we couldn't post them.
Here is the code of our gl.c file, which does the texturing and rendering:
/*
* gl.c
* --------------------------
* Defines the gl rendering and initialization
* functions appInit, appDeinit, and appRender.
*/
#include "gl.h"
#include <android/log.h>
unsigned int textureID;
float vertices[] =
{0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f};
float texture[] =
{0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f};
unsigned char indices[] =
{0, 1, 3, 0, 3, 2};
int texWidth = 1, texHeight = 1;
void glInit()
{
//Set some properties
glShadeModel(GL_FLAT);
glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_FASTEST);
//Generate the new texture
glGenTextures(1, &textureID);
//Bind the texture
glBindTexture(GL_TEXTURE_2D, textureID);
//Enable 2D texturing
glEnable(GL_TEXTURE_2D);
//Disable depth testing
glDisable(GL_DEPTH_TEST);
//Enable the vertex and coord arrays
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
//Set tex params
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
//Set up texWidth and texHeight texHeight, 0, GL_RGB, GL_UNSIGNED_BYTE, emptyPixels);
//Free the dummy array
free(emptyPixels);
//Set the pointers
glVertexPointer(2, GL_FLOAT, 0, vertices);
glTexCoordPointer(2, GL_FLOAT, 0, texture);
}
void glRender()
{
//Check for changes in screen dimensions or work dimensions and handle them
if(dimensionsChanged)
{
vertices[2] = (float) screenWidth;
vertices[5] = (float) screenHeight;
vertices[6] = (float) screenWidth;
vertices[7] = (float) screenHeight;
texture[2] = (float) workWidth/texWidth;
texture[5] = (float) workHeight/texHeight;
texture[6] = (float) workWidth/texWidth;
texture[7] = (float) workHeight/texHeight;
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
if (!flipped)
{
glOrthof(0, screenWidth, screenHeight, 0, -1, 1); //--Device
}
else
{
glOrthof(0, screenWidth, 0, -screenHeight, -1, 1); //--Emulator
}
dimensionsChanged = FALSE;
zoomChanged = FALSE;
}
else if(zoomChanged)
{
texture[2] = (float) workWidth/texWidth;
texture[5] = (float) workHeight/texHeight;
texture[6] = (float) wo开发者_运维百科rkWidth/texWidth;
texture[7] = (float) workHeight/texHeight;
zoomChanged = FALSE;
}
//__android_log_write(ANDROID_LOG_INFO, "TheElements", "updateview begin");
UpdateView();
//__android_log_write(ANDROID_LOG_INFO, "TheElements", "updateview end");
//Clear the screen
glClear(GL_COLOR_BUFFER_BIT);
//Sub the work portion of the tex
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, workWidth, workHeight, GL_RGB, GL_UNSIGNED_BYTE, colors);
//Actually draw the rectangle with the text on it
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_BYTE, indices);
}
Any ideas as to what the difference is between the Atrix 4G and other phones in terms of OpenGL or why our app is doing what it is in general are much appreciated! Thanks in advance.
Here is an example of what it looks like: http://imgur.com/Oyw64
I know it's a bit late to reply, but the real reason you're seeing the mixed colors is due to OpenGL's scanline packing alignment -- not due to any driver bug or power-of-two sized texture issue.
Your glTexSubImage2D
call is sending data in GL_RGB
format, so I'm guessing your colors
buffer is 3 bytes per pixel. Odds are the Droid and Nexus One phones have a default pack alignment of 1, but the Tegra 2 defaults to an alignment of 4. This means your 3 byte array can become misaligned with what the driver expects after every scanline, and a byte or two will be skipped for the next scanline, resulting in the colors you see. The reason why this works with a power-of-two sized texture is because your buffer just happens to be aligned properly for the next scanline. Basically this is the same issue as loading BMPs, where each scanline has to be padded to 4 bytes, regardless of the bit depth of the image.
You can explicitly disable any alignment packing by calling glPixelStorei(GL_PACK_ALIGNMENT, 1);
. Note that changing this only affects the way OpenGL interprets your texture data, so there is no rendering performance penalty for changing this value. When the texture is sent to the graphics subsystem, the scanlines are stored in whatever format is optimal for the hardware, but the driver still has to know how to unpack your data properly. However, since you are changing the texture data every frame, instead of the driver being able to do one memcpy()
to upload the entire texture, it will have to do TextureHeight *memcpy()
s in order to upload it. This is not likely to be a major bottleneck, but if you are looking for the best performance, you may want to query the driver's default pack alignment on startup using glGetIntegerv(GL_PACK_ALIGNMENT, &align);
and adjust your buffer accordingly at runtime.
Here's the specification on glPixelStore() for reference.
Ok, we finally found the actual problem. It turns out that glSubTexImage2D() actually requires the WIDTH to be a power of two, but not the height, for some GPUs including the Tegra 2. We though that it was only the texture that needed to be a power of two and that's where we were wrong. We're going to have to do a bit of recoding, but hopefully this will work out in the end (AT LAST!!).
The Atrix 4G is the first prominent phone that uses Nvidia's Tegra GPU. As such, it has an entirely different OpenGL implementation than previous Android devices. Either you are observing a bug Tegra hardware+software combination, or your application was relying on undefined behavior and you were getting lucky on other devices.
You may want to file a bug report with Nvidia.
精彩评论