« None Shall Pass! | Main | Spike! »

glBufferSubData

Yesterday was spent debugging until two in the morning trying to diagnose a drawing artifact which occured only on Intel-native builds of GC4 when animating colors on a static 3D model defined using an implicit surface equation using OpenGL vertex buffer objects. The image above started out, correctly, as a solid red sphere. When animating the colors using the GC slider, the top of the sphere did not change, remaining red. The middle of the sphere animated correctly. The bottom of the sphere animated but rgb color values (a,b,c) would display shifted as (b,c,a).

At first I suspected a synchronization bug in the new code which implements the data decomposition breaking apart function evaluation across multiple cores for parallel execution. I did find bugs there, but not this one. Since the problem occurs only on Intel-native builds, I suspected a byte-swapping, or endian error. Reviewing hundreds of lines of code did find a few endian bugs, but again, none related to this problem. A friend with far more OpenGL experience stayed up with me over instant messaging until one in the morning with diagnostic advice to instrument the code looking for hints, and helped me interpret the clues to narrow the search. Eventually we focussed on the one line of code which implements the instruction to update the VBO color data each frame of the animation:

 glBufferSubData(GL_ARRAY_BUFFER, offset, size, data);

Several hours then ensued verifying that the offset, size, and color data being passed were reasonable and correct, and that the VBO itself was correctly configured. Everything checked out, however, and no further hints presented themself. I knew it was time to go to sleep, when upon googling relevant keywords to see if anyone else out there has encountered similar problems, the number one hit for my search critera was a thread I started in 2004 on the Apple Mac-OpenGL mailing list seeking help to diagnose a different bug involving color arrays in VBOs in precisely these same lines of code when I originally wrote them working on GC 3.5!

As has often been the case, after a long frustrating day of unsuccessful approaches and apparently fruitless investigation, I woke up a few hours later eager to try one more test. I replaced the call to glBufferSubData with a sequence of calls that I would have expected to produce identical results:

 GLubyte* dest = glMapBuffer(GL_ARRAY_BUFFER, GL_WRITE_ONLY);
 dest += colorOffset;

 for (int i = 0; i < fNumVertices; i++) {
   *(ColorArrayElement*)dest = colorArray[i];
   dest += sizeof(ColorArrayElement);
   }
		
 GLboolean success = glUnmapBuffer(GL_ARRAY_BUFFER);

The code above copies the same buffer to the same place, but does so explicitly by mapping the buffer to memory and copying it an element at a time. It, however, works, eliminating the artifact. The difference may be due to a lack of understanding of the OpenGL API on my part or it may be caused by a bug elsewhere in my code. I know there are still many. It could even be a bug in the OpenGL implemention. I asked the Mac-OpenGL list and a response moments later clarified part of it. (If glBufferSubData operated asynchronously, the behavior might be explained as a synchronization error in GC. However, it is synchronous.)

When I was developing Graphing Calcualtor 3.5 in 2004, it's combined use of vertex buffer obects, full screen anti-aliasing, and GPU fragment programs generated on the fly from equations put me on the bleeding edge of OpenGL new feature adoption. I spent many months debugging to distinguish between GC bugs due to my own carelessness or lack of understanding, OpenGL driver bugs (in Apple's GL software layer), OpenGL driver bugs or hardware bugs in ATI and nVidias hardware and software. While each OpenGL feature on its own generally works as advertised, sometimes combining the newer features in ways that have not been tested can lead to surprising results.

Of all the many e-mail lists to which I subscribe, Mac-OpenGL has, by far, the best signal-to-noise ratio. I'm frequently impressed by the quality, speed, and friendliness of response on deeply technical and tricky issues. Even more amazing, the numerous Apple folks who post there do so on their own time and initiative as a public service to the developer community. Thank you!