ATI Radeon bug report

I’ve found what I assume to be a bug in the OpenGL driver or underlying hardware.

hardware/software version concerned:
The issue concerns the original Radeon series of chips (pre 8500) and has only been verified on this earlier series (Radeon 32 DDR to be exact), using the officialy released 4.13.9009 driverset on Windows 98SE.

description of issue:
When the third texture environment is configured to perform a DOT3 operation, the results of this operation are wrong. More specifically, the output of the DOT3 operation is not even a scalar but a full ‘funky’ color result. This happens only on the third texture environment.

reproduction of issue:
I have attached C source code for a minimal application, using the glut library, that can visually demonstrate the issue.

The application activates GL_COMBINE_ARB for all three texture units.
The application then configures the texture environment pipeline to perform decal texturing on the first environment, passthrough on the second and the DOT3 operation on the third texture environment. The same texture referenced on the first environment is used as a dummy texture for the second and third environments.

With the space bar the user can cycle the position of the dot3 operation in the pipeline through the environments to observe the results of different configurations.
These configs should all yield the same result, but they don’t

configurations that can be cycled through:

Dot3 on tex env 2 (default configuration):
env0 does replace operation with source=texture, operand=source_color
env1 does replace operation with source=previous, operand=source_color
env2 does DOT3_RGB_ARB operation with sources=previous,previous, operands=source_color,source_color

Dot3 on tex env 0:
env0 does DOT3_RGB_ARB operation with sources=texture,texture, operands=source_color,source_color
env1 does replace operation with source=previous, operand=source_color
env2 does replace operation with source=previous, operand=source_color

Dot3 on tex env 1:
env0 does replace operation with source=texture, operand=source_color
env1 does DOT3_RGB_ARB operation with sources=texture,texture, operands=source_color,source_color
env2 does replace operation with source=previous, operand=source_color

I still hope I’m wrong

//Demonstrates a flaw in Dot3 operations on the ATI Radeon's (original) third texture environment
//Flaw can be reproduced on Win98SE systems with the official driver set 4.13.9009
//version number of ATIICDXX.DLL is 6.13.10.6014
//reported GL version is 1.3.2454

//Make sure to link with glut

#include <windows.h>
#include <gl/gl.h>
#include <gl/glati.h>
#include <gl/glu.h>
#include <gl/glut.h>
#include <stdio.h>
#include <malloc.h>

char description[64];

PFNGLACTIVETEXTUREARBPROC glActiveTextureARB;

static unsigned char* texture_data=NULL;
static GLuint tex_obj=0;
static int dot_unit=2;

void
init_gl_stuff()
{
	glActiveTextureARB=(PFNGLACTIVETEXTUREARBPROC)wglGetProcAddress("glActiveTextureARB");

	glClearColor(0.0f,0.0f,0.0f,0.0f);
	glGenTextures(1,&tex_obj);
	texture_data=(unsigned char*)malloc(64*64*3);
	//generate nice texture
	for (int x=0;x<64;++x)
	{
		for (int y=0;y<64;++y)
		{
			texture_data[(x+64*y)*3]=(unsigned char)4*x;
			texture_data[(x+64*y)*3+1]=(unsigned char)4*y;
			texture_data[(x+64*y)*3+2]=(unsigned char)255-x-y;
		}
	}
	glBindTexture(GL_TEXTURE_2D,tex_obj);
	glTexImage2D(GL_TEXTURE_2D,0,GL_RGB,64,64,0,GL_RGB,GL_UNSIGNED_BYTE,texture_data);
	free(texture_data);
	texture_data=NULL;
//mipmaps not required for this demonstration
	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_EXT);
	glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_CLAMP_TO_EDGE_EXT);

	//whip up a minimum projection
	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();
	gluOrtho2D(0,640,480,0);

//set all three texture environments to COMBINE_ARB operation, select same sources and operands
	
	//tex environment0 will do decal texturing
	glEnable(GL_TEXTURE_2D);
	glTexEnvi(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE,GL_COMBINE_ARB);
	glTexEnvi(GL_TEXTURE_ENV,GL_COMBINE_RGB_ARB,GL_REPLACE);
	glTexEnvi(GL_TEXTURE_ENV,GL_SOURCE0_RGB_ARB,GL_TEXTURE);
	glTexEnvi(GL_TEXTURE_ENV,GL_OPERAND0_RGB_ARB,GL_SRC_COLOR);
	glTexEnvi(GL_TEXTURE_ENV,GL_SOURCE1_RGB_ARB,GL_TEXTURE);
	glTexEnvi(GL_TEXTURE_ENV,GL_OPERAND1_RGB_ARB,GL_SRC_COLOR);

	//tex environment1 will pass through
	glActiveTextureARB(GL_TEXTURE1_ARB);
	glBindTexture(GL_TEXTURE_2D,tex_obj);
	glEnable(GL_TEXTURE_2D);
	glTexEnvi(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE,GL_COMBINE_ARB);
	glTexEnvi(GL_TEXTURE_ENV,GL_COMBINE_RGB_ARB,GL_REPLACE);
	glTexEnvi(GL_TEXTURE_ENV,GL_SOURCE0_RGB_ARB,GL_PREVIOUS_ARB);
	glTexEnvi(GL_TEXTURE_ENV,GL_OPERAND0_RGB_ARB,GL_SRC_COLOR);
	glTexEnvi(GL_TEXTURE_ENV,GL_SOURCE1_RGB_ARB,GL_PREVIOUS_ARB);
	glTexEnvi(GL_TEXTURE_ENV,GL_OPERAND1_RGB_ARB,GL_SRC_COLOR);

	//tex environment2 will perform the dot3 operation
	glActiveTextureARB(GL_TEXTURE2_ARB);
	glBindTexture(GL_TEXTURE_2D,tex_obj);
	glEnable(GL_TEXTURE_2D);
	glTexEnvi(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE,GL_COMBINE_ARB);
	glTexEnvi(GL_TEXTURE_ENV,GL_COMBINE_RGB_ARB,GL_DOT3_RGB_ARB);
	glTexEnvi(GL_TEXTURE_ENV,GL_SOURCE0_RGB_ARB,GL_PREVIOUS_ARB);
	glTexEnvi(GL_TEXTURE_ENV,GL_OPERAND0_RGB_ARB,GL_SRC_COLOR);
	glTexEnvi(GL_TEXTURE_ENV,GL_SOURCE1_RGB_ARB,GL_PREVIOUS_ARB);
	glTexEnvi(GL_TEXTURE_ENV,GL_OPERAND1_RGB_ARB,GL_SRC_COLOR);
}

int
cleanup()
{
	if (tex_obj)
	{
		glDeleteTextures(1,&tex_obj);
		tex_obj=0;
	}
	return(0);
}

void
display()
{
	glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
	glBegin(GL_QUADS);
		glTexCoord2f(0.0f,0.0f);
		glVertex2f(0.0f,0.0f);
		glTexCoord2f(1.0f,0.0f);
		glVertex2f(320.0f,0.0f);
		glTexCoord2f(1.0f,1.0f);
		glVertex2f(320.0f,320.0f);
		glTexCoord2f(0.0f,1.0f);
		glVertex2f(0.0f,320.0f);
	glEnd();

	glutSwapBuffers();
	return;
}

void
keyboard(unsigned char key,int x,int y)
{
	//check for spacebar
	if (key!=0x20) return;

	//flip the switch
	++dot_unit;
	if (dot_unit==3) dot_unit=0;

	//reassign texture environments
	switch (dot_unit)
	{
	default:
	case(0):
		glActiveTextureARB(GL_TEXTURE0_ARB);
		glTexEnvi(GL_TEXTURE_ENV,GL_COMBINE_RGB_ARB,GL_DOT3_RGB_ARB);
		glActiveTextureARB(GL_TEXTURE1_ARB);
		glTexEnvi(GL_TEXTURE_ENV,GL_COMBINE_RGB_ARB,GL_REPLACE);
		glActiveTextureARB(GL_TEXTURE2_ARB);
		glTexEnvi(GL_TEXTURE_ENV,GL_COMBINE_RGB_ARB,GL_REPLACE);
		break;
	case(1):
		glActiveTextureARB(GL_TEXTURE0_ARB);
		glTexEnvi(GL_TEXTURE_ENV,GL_COMBINE_RGB_ARB,GL_REPLACE);
		glActiveTextureARB(GL_TEXTURE1_ARB);
		glTexEnvi(GL_TEXTURE_ENV,GL_COMBINE_RGB_ARB,GL_DOT3_RGB_ARB);
		glActiveTextureARB(GL_TEXTURE2_ARB);
		glTexEnvi(GL_TEXTURE_ENV,GL_COMBINE_RGB_ARB,GL_REPLACE);
		break;
	case(2):
		glActiveTextureARB(GL_TEXTURE0_ARB);
		glTexEnvi(GL_TEXTURE_ENV,GL_COMBINE_RGB_ARB,GL_REPLACE);
		glActiveTextureARB(GL_TEXTURE1_ARB);
		glTexEnvi(GL_TEXTURE_ENV,GL_COMBINE_RGB_ARB,GL_REPLACE);
		glActiveTextureARB(GL_TEXTURE2_ARB);
		glTexEnvi(GL_TEXTURE_ENV,GL_COMBINE_RGB_ARB,GL_DOT3_RGB_ARB);
		break;
	}

//update description
	sprintf(description,"Dot3 operation on texture environment%u",dot_unit);

	glutSetWindowTitle(description);

	glutPostRedisplay();
}

int
main(int argc,char** argv)
{
	sprintf(description,"Press space to reassign texture environments");

	glutInit(&argc,argv);
	glutInitWindowSize(640,480);
	glutInitDisplayMode(GLUT_RGBA|GLUT_DOUBLE);

	glutCreateWindow(description);

	init_gl_stuff();

	glutDisplayFunc(display);
	glutKeyboardFunc(keyboard);

	onexit(cleanup);

	glutMainLoop();

	return(0);
}

Oh, and I’d like to see verification or … err … the opposite of verification from Radeon8500 users

[This message has been edited by zeckensack (edited 03-02-2002).]

Correct me if I’m wrong, but don’t you still need to specify texture coords for ALL TMU’s?

Correct me if I’m wrong, but don’t you still need to specify texture coords for ALL TMU’s?

The spec only mandates that textures must be bound to the environments. Texture coordinates should have some default value (though I can’t find it in the spec right now …). Not that I actually referenced any textures in the later environments anyway …

However, I’ve just slapped multitexture coordinates in and the result is still exactly the same - still wrong

[This message has been edited by zeckensack (edited 03-02-2002).]

NitroGL: A followup

The initial values of s, t, and r of the current texture coordinates
are zero;
Found on page 21 (page 33 in Acrobat Reader) of glspec1.3.pdf.

Originally posted by zeckensack:
[b] [quote]Correct me if I’m wrong, but don’t you still need to specify texture coords for ALL TMU’s?

The spec only mandates that textures must be bound to the environments. Texture coordinates should have some default value (though I can’t find it in the spec right now …). Not that I actually referenced any textures in the later environments anyway …

However, I’ve just slapped multitexture coordinates in and the result is still exactly the same - still wrong

[This message has been edited by zeckensack (edited 03-02-2002).][/b][/QUOTE]

Hmm… It probably is a driver bug then.

You sure send a report to devrel@ati.com

I’ve seen this problem occur as well. I’ve been learning opengl for a couple months now, going through nehe tutorials, redbook, radeon sdk examples, etc, so I figured it was a problem with my code. But when I changed my code so dot3 occurred in GL_TEXTURE1_ARB instead of GL_TEXTURE2_ARB, I got the expected results rather than a strangely colored mess.

The example above demonstrates the problem on my Radeon 7200. I’ve got an 8500 on the way, I’ll try the above example code on it when it arrives.