Monday, October 13, 2008

How I learnt to stop worrying and love AMD's shader compiler

Normally I just post about travel and other daily trivia here, but I feel the need to get some good old tech ranting in. So, normal people (i.e. non-nerds), feel free to stop reading now :-)

I've been trying to do some OpenGL development at home, with the ATI X1600 in my laptop, and I've managed to find 3 serious bugs within about an hour. Firstly, my program would just crash while trying to compile a shader. After tinkering with my program for a while to try and eliminate anything I might have broken, I started removing bits of the shader. And guess what? If you index an array with a ternary expression, it crashes the driver.

Ok, I can work around that by moving the ternary into a temporary variable. Fix a few genuine compilation errors, and get to this message:

Fragment shader failed to compile with the following errors:

Well, that's helpful. Would be more helpful if it was followed by a list of errors, as is traditional in such cases. However, by again randomly removing pieces of code, I determine that a loop with an indeterminate number of iterations will cause this. Some hardware doesn't actually support loops (it just unrolls them), so fine, I'll run up to the maximum number of iterations I might need, and just early-out once I hit the number I actually need. Even when unrolling, such hardware normally supports forward branches, since it can just conditionalise the instructions hit by the branch. But not this sorry excuse for a compiler, it just gives me the same error. However, if I wrap the loop body in an "if" statement, it's happy to forward branch there.

Now, I finally have both my shaders compiled, I'm ready to link! It's much harder to make linker errors than compiler errors, although I did accidentally end up not writing to a varying that I was reading and which the linker helpfully complained about. I fix that, and is was well. And if you believe that, you haven't been paying attention. Of course it isn't. In spite of the cheery "Fragment shader was successfully compiled to run on hardware" from the compiler, the linker now asserts that "Fragment Shader not supported by HW". Why not? Well, remember that ternary expression? It turns out that while refactoring it fixed the crash, it's still not supported. It appears that the fragment shader can't do dynamic indexing, at least on varying arrays. So, some more refactoring, to move the array lookup inside each branch of the ternary, and now it all compiles and links.

I haven't tried running it yet, of course. I'm not sure I want to.

No comments: