This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

Bad texture mapping on OMAP3530

Other Parts Discussed in Thread: OMAP3530

Hello.  I have an application that draws terrain by mapping textures onto triangles using fixed OpenGL-ES 1.x functions on Linux on an OMAP3530.  The triangles are rotated into view based on the orientation of the viewer.  When I do this, I see texture magnification errors.  I've confirmed the same thing happens on a Beagleboard with the latest Beagle graphics SDK from TI.  (The other board is a Gumstix Overo Water with the 3.00.00.09 SDK).  In the first image below using the GL_NEAREST mag filter, the problem is obvious.  The alternating color pattern should line up everywhere.  The second, correct image is from an Intel GPU.  The errors change with slight changes to the view.  With GL_LINEAR and small rotations in the model matrix, the drawing errors make the terrain look like it's jumping around.

This is what I'm seeing:

This is what it should look like: (output from a completely different GPU)

I don't know where to report problems with the graphics.  I need to get this fixed or find a workaround.

I created a test application that renders the test image from one of the demos in the PowerVR SDK framework.  Basically I create a 512x512 texture and draw it as a bunch of triangles with shared edges.  With ANIMATE defined the drawing errors jump around.

#include <GLES/egl.h>

#include "PVRShell.h"
#include "OGLESTools.h"

// Size of the texture we create
#define TEX_SIZE        512

class OGLESTexturing : public PVRShell
{
    // Texture handle
    GLuint    m_uiTexture;

    int vertex_count;
    struct vertex_t {
        VERTTYPE x, y, z;
    } *pfVertices;
    struct texcoord_t {
        VERTTYPE s, t;
    } *pfTexCoord;

public:
    virtual bool InitApplication();
    virtual bool InitView();
    virtual bool ReleaseView();
    virtual bool QuitApplication();
    virtual bool RenderScene();
    void init_vertex(int i, int x, int y, int z)
    {
        pfVertices[i].x = f2vt(x);
        pfVertices[i].y = f2vt(y);
        pfVertices[i].z = f2vt(z);
        pfTexCoord[i].s = f2vt(x/512.f);
        pfTexCoord[i].t = f2vt(y/512.f);
    }
};

bool OGLESTexturing::InitApplication()
{
    const int span = 4;
    vertex_count = (512/span)*(512/span)*6;
    pfVertices = new vertex_t[vertex_count];
    pfTexCoord = new texcoord_t[vertex_count];
    int i = 0;
    for (int y = 0; y < 512; y += span) {
        for (int x = 0; x < 512; x += span) {
            int z1 = x%(span*2)>=span ? 1024 : 0;
            int z2 = (x+span)%(span*2)>=span ? 1024 : 0;
            init_vertex(i++, x, y+span, z1);
            init_vertex(i++, x, y, z1);
            init_vertex(i++, x+span, y+span, z2);
            init_vertex(i++, x+span, y+span, z2);
            init_vertex(i++, x, y, z1);
            init_vertex(i++, x+span, y, z2);
        }
    }

    return true;
}

bool OGLESTexturing::QuitApplication()
{
    delete [] pfVertices;
    delete [] pfTexCoord;
    return true;
}

bool OGLESTexturing::InitView()
{
    // Sets the clear color
    myglClearColor(0, 0, 0, 0);

    // Enables texturing
    glEnable(GL_TEXTURE_2D);
    // The problem occurs with or without depth testing and culling
    glEnable(GL_DEPTH_TEST);
    glDepthFunc(GL_LESS);
    glFrontFace(GL_CCW);
    glEnable(GL_CULL_FACE);

    // Allocates one texture handle
    glGenTextures(1, &m_uiTexture);

    // Binds this texture handle so we can load the data into it
    glBindTexture(GL_TEXTURE_2D, m_uiTexture);

    // Creates the data as a 8bits integer array (8bits per component)
    GLubyte* pTexData = new GLubyte[TEX_SIZE*TEX_SIZE*3];
    for (int i = 0; i < TEX_SIZE*TEX_SIZE*3; ) {
        pTexData[i++] = 0;
        pTexData[i++] = 255;
        pTexData[i++] = 255;

        if (i < TEX_SIZE*TEX_SIZE*3) {
            pTexData[i++] = 255;
            pTexData[i++] = 0;
            pTexData[i++] = 255;
        }

        if (i < TEX_SIZE*TEX_SIZE*3) {
            pTexData[i++] = 255;
            pTexData[i++] = 255;
            pTexData[i++] = 0;
        }
    }

    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, TEX_SIZE, TEX_SIZE, 0, GL_RGB, GL_UNSIGNED_BYTE, pTexData);

    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_NEAREST );
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST );

    // Deletes the texture data, it's now in OpenGL memory
    delete [] pTexData;

    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    myglFrustum(f2vt(-0.039f), f2vt(0.039f),
        f2vt(-0.02925f), f2vt(0.02925f),
        f2vt(0.1f), f2vt(5.0f));
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();

    glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);

    return true;
}

bool OGLESTexturing::ReleaseView()
{
    // Frees the texture
    glDeleteTextures(1, &m_uiTexture);

    return true;
}

bool OGLESTexturing::RenderScene()
{
    // Clears the color buffer
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
#ifdef ANIMATE
    unsigned long tick = PVRShellGetTime()%10000;
    myglRotate(f2vt(tick*2.f/10000), 0.0, 0.0, 1.0);
#endif // ANIMATE
    myglRotate(f2vt(-90), f2vt(1.0f), 0, 0);
    myglTranslate(f2vt(-505*(60.f/1200.f)), f2vt(0.2f), f2vt(-0.2f));
    myglScale(f2vt(60.f/1200.f), f2vt(60.f/1200.f), f2vt(1.f/6000.f));

    // Pass the vertex data
    glEnableClientState(GL_VERTEX_ARRAY);
    glVertexPointer(3,VERTTYPEENUM,0,pfVertices);

    // Pass the texture coordinates data
    glEnableClientState(GL_TEXTURE_COORD_ARRAY);
    glTexCoordPointer(2,VERTTYPEENUM,0,pfTexCoord);

    // Draws a non-indexed triangle array
    glDrawArrays(GL_TRIANGLES, 0, vertex_count);

    return true;
}

PVRShell* NewDemo()
{
    return new OGLESTexturing();
}

  • Jeff,

    You have posted the queston in the correct place.  Your picture is very interesting in that the mapping looks correct in the up->down direction but incorrect in the front->back direction.  We will get back to you once we have run your application and can recreate the effect you describe.

    Darren

  • Jeff,

    Looking through your code you are basically creating a 1x1 pixel blocks of alternating colors and then scaling that texture up significantly.  What I think is happening is you are hitting the limit of the scaling precision of the embedded GPU hardware and hence you start to see errors.  The other GPU may be able to scale up higher which is why the output looks better.  If you look at your screenshot as the texture is scaled less the errors start to reduce - basically the only solution is to scale the texture less, or possibly prescale the texture for high levels of magnification.

    Darren

  • The test application scales more than my real application by 2 to 3 times.  I just created a simple program to highlight the problem seen in my much more complex program.

    I've been looking to see what makes the errors significant, and the source seems to be precision in the texture coordinates.  Smaller coordinates in the same texture (closer to 0) and smaller textures (128x128) seem to help in the test application.  Usually you want large textures rather than many small textures, but smaller textures may be the only option.  I don't think prescaling is going to be practical due to the memory requirements.

    I also had the opportunity to run some tests on a netbook with a GMA500 (SGX 535) GPU.  It has similar errors, but they're much smaller and not significant.  If the 535 processes more bits in its texture coordinates, that would confirm this.