Unknown error causing program to crash on ATI card

i am using some of the code from the Orange Book to do directional lighting, specifically this:

void DirectionalLight(in int i, in vec3 normal, inout vec4 ambient, inout vec4 diffuse, inout vec4 specular)
	float nDotVP;
	float nDotHV;
	float pf;
	nDotVP = max(0.0, dot(normal, normalize( vec3(uniLight[i].position) ) ) );	
	nDotHV = max(0.0, dot(normal, normalize(vryHalfVec[i])));
	if(nDotVP == 0.0)	
		pf = 0.0f;
		pf = pow(nDotHV, uniMaterial.shininess);

	ambient += uniLight[i].ambient;
	diffuse += uniLight[i].diffuse * nDotVP;
	specular += uniLight[i].specular * pf;	

It’s changed slightly from the original so as not to use any of the gl_ stuff, the vry are variables and uni are uniforms.

the line nDotHV = max(0.0, dot(normal, normalize(vryHalfVec[i])));

appears to be causing my program to crash on my ATI card, specifically vryHalfVec[i] if I remove the i and use vryHalfVec[0] it works fine, it works fine for any number up to MAX_LIGHTS when given explicitly, but does not work when I use i to access the array.

Even if I call DirectionalLight and give it 0 as the first parameter it crashes. even if i refer to vryHalfVec[i], i.e. putting vec3 temp = vryHalfVec[i]; somewhere in the function it crashes, however outside of this function, in the loop that is calling it i can use this syntax. i.e.

for(int i=0; i< MAX_LIGHTS; i++)
		if(uniLight[i].initialised == true)
			vec3 temp = vryHalfVec[i];
			DirectionalLight(i, vryNormal, ambient, diffuse, specular);

this does not crash, but moving vec3 temp = vryHalfVec[i]; inside the function it crashes.

Any thoughts? I’m half hoping i’ve made some really dumb error. It works fine on my Nvidia, and works fine on the ATI everwhere else so long as i don’t reference vryHalfVec using i in the direct lighting function :frowning:

When you say: “It crashes”, you mean “it does not compile” don’t you?

Indexing arrays is a real tough thing in GLSL. It works on Nvidia cards because the compiler uses a particular Cg profile specific to nvidia that make it compile.

Ati cards simply does not support array indexing with a variable depending of the Shader model supported. (AFAIK, it was still unsupported the glslang 1.3 spec)

The only solution is to index your array with a constant expression.

So if you want to keep your function, you have to write something like this:

if( i == 0 )
 vec3 temp = vryHalfVec[0];
if( i == 1 )
 vec3 temp = vryHalfVec[1];
if( i == 2 )
 vec3 temp = vryHalfVec[2];

It is working in the second code snippet because the compiler succeeded in unroll the loop and replaced i by its value depending on the loop iteration.

When i say it crashes i mean it crashes the whole window with a “send error report/don’t send error report” message before closing the window.

If I index the array with i or with a constant expression the GLSL compiler throws no errors :s

Thanks for the help though, very much apperciated. It looks like i’ll have to rewrite. :slight_smile:

as dletozeun said it should not crash. thou i had a crash once and this was caused because i did wrong string format to put it into the console for shader error information not the compiling itself. if your callstack ends up somewhere at ati2dvag.dll then it is a driver crash and an update is in order.

The crash does seem strange i thought it might be something else, however I can reference directly vryHalfVec[0] to vryHalfVec[MAX_LIGHTS-1] without any problems.

I’ve tested it on two ATi cards now and they both crash. I’ll try moving the source over and see what the debugger tells me.

do you have any crash report by any chance? its easy to know where to start if you know where it crashes thats why i referred to the callstack if you can run your code in debug mode.

Yes the callstack will help. I suppose that since the shader program is not supported by your hardware, it does not compile and the driver should fall back to fixed pipeline.

Maybe your application does not notice that the shader program link failed and continue to run to somewhere this issue may cause a crash. Debug and tracing the code will tell you.

Thanks for the continued help guys, I’ll have to give it a look this weekend. Some other stuff has come up :s I will post an update then.

James A. you should definitely have some sort of fallback if something is not supported (which can/will happen quite often!). the simplest vertex/fragment shader will do the job. good luck.

I do have some basic fallback shaders that just put out simple colour etc, but the code doesn’t detect any problems when compiling and linking the shader.

I ran through it using the debugger. the call stack at the crash shows references to atioglxx.dll

“but the code doesn’t detect any problems when compiling and linking the shader”
do you check the compile and link status? never had any problems detecting errors in shaders since the status return GL_FALSE on compile check, link check or validation check.

“the call stack at the crash shows references to atioglxx.dll”
atioglxx.dll is the ICD, means that you do something that causes the driver to crash. simple example to reproduce if you call glDrawElements with more indices passed then bound, which means your code is handling it wrong.

I have been checking the compile and link status with code like this:

if(m_compileStatusGL != GL_TRUE)
	char error[2056];
	GLsizei length = 0;
	glGetShaderInfoLog(m_handle,2056,&length, error);

with similar source for after I call glLinkProgram()to get GL_LINK_STATUS (with glGetProgramiv)

I wasn’t however checking the GL_VALIDATE_STATUS, which I have now added to my code, but it doesn’t seem to write any warning messages for the shader that crashes it.

It does report normal compile/link errors properly, if I write obviously incorrect code.

Interestingly, I have updated the OS of my ATi machine to Vista and the same incorrect source no longer crashes. It just doesn’t display the geometry it was applied to (without any errors/warnings from compile/link/validate stages). It still crashes on a different XP/Ati machine.

What an ICD?

ICD stands for Installed Client Driver.

By the way,

   char error[2056];
   GLsizei length = 0;
   glGetShaderInfoLog(m_handle,2056,&length, error);

is not very flexible.

you should get the infolog size with:

glGetShaderiv( m_handle, GL_INFO_LOG_LENGTH, &length );

wondering why no GL_FALSE there. try getting shader log even if GL_TRUE, maybe something there. also run some GL debugger like GLintercept with mode “break on GL errors”. install some new drivers on XP see if this crash is still reproduceable (recommend Omega drivers).