Hi,
I face a strange bug on ATI cards on ubuntu.
I setup the clamping options like this:
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
and I expect to see the edge lines repeated whenever I used a texture coordinate outside [0,1]. However, this is what I get when rendering a full screen quad using a texture containing 4 colored squares (what u see in the middle) with texture coordinates from -0.1 to 1.1:
http://db.tt/pihAURK
So it seems like the edges are indeed repeated but somehow faded out.
Next I attached a screenshot of the same aplication on a NVIDIA card (apart of the graphic card all the other conditions are the same):
http://db.tt/5wkKK0J
Here it is impossible to notice the edge of the texture, as expected.
Setup: ATI HD 5870 on Ubuntu 10.04 x64 with ati-driver-installer-11-5-x86.x86_64.run. Same bug also on ATI HD 6870 and also with ati-driver-installer-11-2-x86.x86_64.run
Any ideas?
Thanks!
I will take a look.
we can not duplicate the issue on Ubantu 10.10 with HD5850, the code piece:
void init(void)
{
glClearColor(0.0,0.0,0.0,0.0);
glShadeModel(GL_FLAT);
glEnable(GL_DEPTH_TEST);
glPixelStorei(GL_UNPACK_ALIGNMENT,1);
glGenTextures(1, &texName);
glBindTexture(GL_TEXTURE_2D,texName);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_CLAMP);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_CLAMP);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_NEAREST);
glTexImage2D(GL_TEXTURE_2D,0,GL_RGBA,checkImageWidth,checkImageHeight,0,GL_RGBA,GL_UNSIGNED_BYTE,checkImage);
}
void display(void)
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glEnable(GL_TEXTURE_2D);
glTexEnvf(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE,GL_REPLACE);
glBindTexture(GL_TEXTURE_2D,texName);
glBegin(GL_QUADS);
glTexCoord2f(-0.1,-0.1);glVertex3f(-2.0,-1.0,0.0);
glTexCoord2f(-0.1,1.1);glVertex3f(-2.0,1.0,0.0);
glTexCoord2f(1.1,1.1);glVertex3f(0.0,1.0,0.0);
glTexCoord2f(1.1,-0.1);glVertex3f(0.0,-1.0,0.0);
glEnd();
glFlush();
glDisable(GL_TEXTURE_2D);
glutPostRedisplay();
}
can you paster your source code if it's different form yours?
Thanks for the reply!
I did compare my code with yours and the only difference was in the texture filters: I used GL_LINEAR and you used GL_NEAREST. If I use "nearest" too, the texture is rendered corectly.
Could you please try with GL_LINEAR?
Can you paste your code? It's difficault for us to guess what you have done.
for example, I don't kown your texture size, window size, etc.
// to build: g++ -Wall test.cpp -lGL -lGLU
#include <stdlib.h>
#include <stdio.h>
#include <GL/glx.h>
#include <GL/glu.h>
//-----------------------------------------------------------------------------
// DEFINES
//-----------------------------------------------------------------------------
#define SCREEN_WIDTH 640
#define SCREEN_HEIGHT 480
#define TEXTURE_WIDTH 256
#define TEXTURE_HEIGHT 256
//-----------------------------------------------------------------------------
// GLOBALS
//-----------------------------------------------------------------------------
Display* g_pDisplay = NULL;
Window g_window;
GLXContext g_windowContext;
GLuint g_testTextureID = 0;
struct Vertex
{
float tu, tv;
float x, y, z;
};
Vertex g_cubeVertices[] =
{
{ -0.1f,-0.1f, -1.0f,-1.0f, 1.0f },
{ 1.1f,-0.1f, 1.0f,-1.0f, 1.0f },
{ 1.1f,1.1f, 1.0f, 1.0f, 1.0f },
{ -0.1f,1.1f, -1.0f, 1.0f, 1.0f },
{ 1.0f,0.0f, -1.0f,-1.0f,-1.0f },
{ 1.0f,1.0f, -1.0f, 1.0f,-1.0f },
{ 0.0f,1.0f, 1.0f, 1.0f,-1.0f },
{ 0.0f,0.0f, 1.0f,-1.0f,-1.0f },
{ 0.0f,1.0f, -1.0f, 1.0f,-1.0f },
{ 0.0f,0.0f, -1.0f, 1.0f, 1.0f },
{ 1.0f,0.0f, 1.0f, 1.0f, 1.0f },
{ 1.0f,1.0f, 1.0f, 1.0f,-1.0f },
{ 1.0f,1.0f, -1.0f,-1.0f,-1.0f },
{ 0.0f,1.0f, 1.0f,-1.0f,-1.0f },
{ 0.0f,0.0f, 1.0f,-1.0f, 1.0f },
{ 1.0f,0.0f, -1.0f,-1.0f, 1.0f },
{ 1.0f,0.0f, 1.0f,-1.0f,-1.0f },
{ 1.0f,1.0f, 1.0f, 1.0f,-1.0f },
{ 0.0f,1.0f, 1.0f, 1.0f, 1.0f },
{ 0.0f,0.0f, 1.0f,-1.0f, 1.0f },
{ 0.0f,0.0f, -1.0f,-1.0f,-1.0f },
{ 1.0f,0.0f, -1.0f,-1.0f, 1.0f },
{ 1.0f,1.0f, -1.0f, 1.0f, 1.0f },
{ 0.0f,1.0f, -1.0f, 1.0f,-1.0f }
};
struct BMPImage
{
int width;
int height;
char *data;
};
//-----------------------------------------------------------------------------
// PROTOTYPES
//-----------------------------------------------------------------------------
void init(void);
void render(void);
void shutDown(void);
//-----------------------------------------------------------------------------
// Name: main()
// Desc:
//-----------------------------------------------------------------------------
int main( int argc, char **argv )
{
// Open a connection to the X server
g_pDisplay = XOpenDisplay( NULL );
if( g_pDisplay == NULL )
exit(1);
int doubleBufferVisual[] =
{
GLX_RGBA, // Needs to support OpenGL
GLX_DEPTH_SIZE, 16, // Needs to support a 16 bit depth buffer
GLX_DOUBLEBUFFER, // Needs to support double-buffering
None // end of list
};
// Try for the double-bufferd visual first
XVisualInfo* visualInfo = glXChooseVisual( g_pDisplay, DefaultScreen(g_pDisplay), doubleBufferVisual );
if( visualInfo == NULL )
exit(1);
// Create an OpenGL rendering context
g_windowContext = glXCreateContext( g_pDisplay, visualInfo, NULL, GL_TRUE ); // Direct rendering if possible
if( g_windowContext == NULL )
exit(1);
// Create an X colormap since we're probably not using the default visual
Colormap colorMap;
colorMap = XCreateColormap( g_pDisplay,
RootWindow(g_pDisplay, visualInfo->screen),
visualInfo->visual,
AllocNone );
XSetWindowAttributes winAttr;
winAttr.colormap = colorMap;
winAttr.border_pixel = 0;
winAttr.event_mask = ExposureMask |
VisibilityChangeMask |
KeyPressMask |
KeyReleaseMask |
ButtonPressMask |
ButtonReleaseMask |
PointerMotionMask |
StructureNotifyMask |
SubstructureNotifyMask |
FocusChangeMask;
// Create an X window with the selected visual
g_window = XCreateWindow( g_pDisplay, RootWindow(g_pDisplay, visualInfo->screen),
0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, 0, visualInfo->depth, InputOutput,
visualInfo->visual, CWBorderPixel | CWColormap | CWEventMask,
&winAttr );
XSetStandardProperties( g_pDisplay, g_window,
"OpenGL - GL_CLAMP test",
"opengl_clamp_test", None, argv, argc, NULL );
glXMakeCurrent( g_pDisplay, g_window, g_windowContext );
XMapWindow( g_pDisplay, g_window );
init();
while (true)
render();
shutDown();
XDestroyWindow( g_pDisplay, g_window );
XCloseDisplay( g_pDisplay );
}
//-----------------------------------------------------------------------------
// Name: getBitmapImageData()
// Desc: Simply image loader for 24 bit BMP files.
//-----------------------------------------------------------------------------
bool getBitmapImageData(const char *pFileName, BMPImage *pImage )
{
FILE *pFile = NULL;
unsigned short nNumPlanes;
unsigned short nNumBPP;
int i;
if( (pFile = fopen(pFileName, "rb") ) == NULL )
return false;
// Seek forward to width and height info
fseek( pFile, 18, SEEK_CUR );
if( (i = fread(&pImage->width, 4, 1, pFile) ) != 1 )
return false;
if( (i = fread(&pImage->height, 4, 1, pFile) ) != 1 )
return false;
if( (fread(&nNumPlanes, 2, 1, pFile) ) != 1 )
return false;
if( nNumPlanes != 1 )
return false;
if( (i = fread(&nNumBPP, 2, 1, pFile)) != 1 )
return false;
if( nNumBPP != 24 )
return false;
// Seek forward to image data
fseek( pFile, 24, SEEK_CUR );
// Calculate the image's total size in bytes. Note how we multiply the
// result of (width * height) by 3. This is becuase a 24 bit color BMP
// file will give you 3 bytes per pixel.
int nTotalImagesize = (pImage->width * pImage->height) * 3;
pImage->data = (char*) malloc( nTotalImagesize );
if( (i = fread(pImage->data, nTotalImagesize, 1, pFile) ) != 1 )
return false;
//
// Finally, rearrange BGR to RGB
//
char charTemp;
for( i = 0; i < nTotalImagesize; i += 3 )
{
charTemp = pImage->data;
pImage->data = pImage->data[i+2];
pImage->data[i+2] = charTemp;
}
return true;
}
//-----------------------------------------------------------------------------
// Name: init()
// Desc: Init OpenGL context for rendering
//-----------------------------------------------------------------------------
void init( void )
{
glXMakeCurrent( g_pDisplay, g_window, g_windowContext );
glClearColor( 1.0f, 1.0f, 1.0f, 1.0f );
glShadeModel(GL_FLAT);
glEnable(GL_TEXTURE_2D);
glEnable(GL_DEPTH_TEST);
glMatrixMode( GL_PROJECTION );
glLoadIdentity();
gluPerspective( 45.0f, SCREEN_WIDTH / SCREEN_HEIGHT, 0.1f, 10.0f );
BMPImage textureImage;
getBitmapImageData("clamptest.bmp", &textureImage);
glPixelStorei(GL_UNPACK_ALIGNMENT,1);
glGenTextures( 1, &g_testTextureID );
glBindTexture( GL_TEXTURE_2D, g_testTextureID );
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
// bad clamp
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
// good clamp
//glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST );
//glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST );
glTexImage2D( GL_TEXTURE_2D, 0, 3, textureImage.width, textureImage.height, 0, GL_RGB, GL_UNSIGNED_BYTE, textureImage.data );
free(textureImage.data);
glMatrixMode( GL_MODELVIEW );
glLoadIdentity();
glTranslatef( 0.0f, 0.0f, -5.0f );
}
//-----------------------------------------------------------------------------
// Name: render()
// Desc: Called when the GLX window is ready to render
//-----------------------------------------------------------------------------
void render( void )
{
glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
glBindTexture( GL_TEXTURE_2D, g_testTextureID );
glInterleavedArrays( GL_T2F_V3F, 0, g_cubeVertices );
glDrawArrays( GL_QUADS, 0, 4 );
glXSwapBuffers( g_pDisplay, g_window ); // Buffer swap does implicit glFlush
}
//-----------------------------------------------------------------------------
// Name: shutDown()
// Desc:
//-----------------------------------------------------------------------------
void shutDown( void )
{
glDeleteTextures( 1, &g_testTextureID );
if( g_windowContext != NULL )
{
// Release the context
glXMakeCurrent( g_pDisplay, None, NULL );
// Delete the context
glXDestroyContext( g_pDisplay, g_windowContext );
g_windowContext = NULL;
}
}
I was trying to tell you that the only difference is in GL_NEAREST, everything else is the same. The window ssize or texture size are not important, it happens all the time. Find bellow the full code of a test scenario. If you give me an email I can send you the zip file with the texture and teh make file.
It's proved to be not a bug of AMD card. Please refer to the OpenGL 2.1 spec, because the GL_CLAMP is depricated since OpenGL 3.0.
when you are using GL_CLAMP, the texture coordinate will be clampled to half pixel over the boundary, and you specifed GL_LINEAR fileter, the border color will be used to generate the color where textue coordinate is not in 0.0 and 1.0.
I will take a look.