The fix is pretty straightforward: we should really be calling glFinish() from
Toolkit.sync(), which synchronously forces all operations in hardware to be flushed
to the screen (this is a blocking call). I have hesitated doing this in the past
mainly because of the SwingMark microbenchmark, which issues a ton of calls to
Toolkit.sync() when taking measurements. So if we start making lots of calls to
glFinish(), the reported SwingMark performance will drop quite a bit (around 10%,
depending on the board could be more). To make matters worse, we currently have
some smart code in OGLRenderQueue.sync() that avoids flushing the RenderQueue
if it's currently empty. If we change sync() to now add a SYNC opcode and flush
the queue no matter what, it will mean that SwingMark will likely be causing even
more thread switching for each repaint: once to flush the current queue and copy
the Swing backbuffer to the screen, and then again to process the SYNC opcode and
call glFinish(). So really we're making an already artificial benchmark with
artificially good numbers and making them worse; for this reason, I'm not too
concerned with this particular downside.
Actually, in my measurements so far I haven't seen a significant drop in
SwingMark with this change in place; it ranges anywhere from "in the noise"
to a 3-4% "slowdown". As discussed above, all this change is doing is making
benchmark results more accurate and predictable, so any slowdown shouldn't be
considered an actual performance loss (since "real applications" don't have a
need to call Toolkit.sync() anyway).
J2DBench results now have very small variance, as expected (that was one of
the goals of this fix after all).