Friday, January 23, 2009

error C1019: scalar Boolean expression expected

While working on my GPU raytracer, I've come across the following Cg error a few times: error C1019: scalar Boolean expression expected. Weirdly, it only threw this error on the machines at school (the Cg shader code is compiled at run-time). Though the line numbers don't make this clear, the problem code appears to be this:

float4 val = readFloat4FromTexture();
if (val != float4(1,1,1,1)) {
...
}


I haven't investigated why this works at home and not school (different Cg compiler versions?), but I fixed it by changing to this:

...
if (val.x != 1 && val.y != 1 && val.z != 1 && val.w != 1) {
...
}


I wasn't able to find *anything* about the error on Google or in the Cg documentation, so hopefully this is useful if anyone else has this problem.

Wednesday, January 7, 2009

Getting useful errors from Cg

Since Cg programs are compiled at the program's runtime, you must catch Cg compile and runtime errors from within your program. Here's how:

First, you will need a callback. Cg will call this function whenver there is an error. Example:

void MyErrorCallback(void) {
CGerror error = cgGetError();
const char* errorString = cgGetErrorString(cgGetError());
printf("Cg error: %s\n", errorString);

// check for compiler errors
if (error == CG_COMPILER_ERROR)
printf("%s\n", cgGetLastListing(context));
}


Next, you need to set the callback:
cgSetErrorCallback(MyErrorCallback);

Now you should get more useful output when Cg has problems.

And easy way to make for loops unrollable

Cg will let you use for loops in your shaders, but only if they can be unrolled. Though it loses you the performance benefits of loop unrolling, you can make a for loop unrollable by moving the guard (or "are we done yet?" check) into the loop body.

For example:

int arr[] = {2, 1, 3};
for (int i = 1; i < arr[0]; i ++) {
doStuff(arr[i]);
}

That snippet gives an error like this when you try to compile it:
frag.cg(71) : error C5013: profile does not support "for" statements and "for" could not be unrolled.

Instead, try the following:

int arr[] = {2, 1, 3};
for (int i = 1; i < MAX_LEN; i ++) {
doStuff(arr[i]);
if (i == arr[0])
break;
}


EDIT:
Or better yet, just do this:

int arr[] = {2, 1, 3};
for (int i = 1; i < MAX_LEN && i < arr[0]; i ++) {
doStuff(arr[i]);
if (i == arr[0])
break;
}


Note that I found order to be important (it didn't like arr[0] before MAX_LEN).

Saturday, January 3, 2009

Custom command keybindings in Gnome

Gnome (or, more precisely, Metacity), will let you create 12 custom key bindings. That is, you can set 12 custom commands that are triggered by a given key sequence.

This is done in Configuration Editor (System Tools -> Configuration Editor; enable it in "Edit Menu" if it isn't there). The first custom command is set with /apps/metacity/global_keybindings/run_command_1. The associated keybinding is set with /apps/metacity/keybinding_commands/command_1.