Odds and Ends
- Today I finally grokked how the Java2D Image API could be implemented. Basically the biggest problem (to me) always has been the BufferedImage constructor, which allowed BIes of all kinds to be created. What about image formats that are not supported by the native rendering engine? How are we supposed to render into that? Well, the solution would be to have 2 buffers like:
RE --> nBuffer < -- > jBuffer <-- Java2D API
where the native buffer has a format that is supported by the RE and the java buffer (I call it so, it is not required to have that in Java, could be any memory area thanks to the fine DataBuffer abstraction) holds the data in the requested ColorModel/SampleModel. Well, the obvious problem here is when to sync the data and what to sync. Fortunately (that’s what I discovered today), BufferedImage implements WritableRenderedImage, which provides a couple of methods to grab the buffer for writing and release it. This is find, as it provides very nice syncpoints.One remaining obstactle is when the RE does not support a super-format (I call it like this. For instance, ARGB8888 is a superformat of RGB565) of the requested format. For instance, when the RE only supports ARGB1888 (which is the case for one system I am currently implementing this API for) but the app requires ARGB8888. How is the RE supposed to render into that. The API is a little weak in this respect as it doesn’t allow to reject the request. The only real solution would be to have a Java only renderer do the rendering, but this is very ugly for several reasons: The rendering would be noticably different and noticably slow (well the latter isn’t that bad. what do you expect when you request something not supported by the HW). Any comments and ideas on this are very appreciated.All in all, nowadays I feel about Java2D almost like I feel about NIO: Quite confusing for the start, but once things are sorted out and have found their place in the mind-picture, it seems relativly well thought out and nice. Only problem with Java2D probably is that it carries quite some cruft from the <= AWT1.1 days, which makes it even more confusing.
- Today a collegue pointed me to this, makes my mind boggle. I copy it into here as a riddle to solve. So please make up your mind and find out what this is supposed to do. And yes, this is legal C code compilable by GCC.
switch ( count % 8 ) /* count > 0 assumed */ { case 0: do { *to++ = *from++; case 7: *to++ = *from++; case 6: *to++ = *from++; case 5: *to++ = *from++; case 4: *to++ = *from++; case 3: *to++ = *from++; case 2: *to++ = *from++; case 1: *to++ = *from++; } while (( count -= 8 ) > 0); } - Found an interesting JSR: Application Framework for Swing Gotta have a deeper look at it ASAP.
January 31st, 2007 at 12:52 am
The riddle is known as Duff’s Device, as per its inventor, Tom Duff. See http://en.wikipedia.org/wiki/Duff’s_device. It’s a real classic, but actually very useful for low-level stuff. And it’s used surprisingly often.
January 31st, 2007 at 5:35 am
It took me a little while to determine what the smiley should be, but it seems to simply copy count bytes from the memory location starting at from to the memory location starting at to. It is a loop unrolling construct. I’ve got to say that I have never seen a do while loop embedded in a switch statement before. The only reason for the switch statement is to make sure you don’t copy too many times the last time through the loop.
January 31st, 2007 at 8:53 am
The C snippet you have posted is known as “Duff’s Device“.
January 31st, 2007 at 1:22 pm
Oh funny. I shouldn’t post without at least verifying once
Three correct answers anyway, great! What’s to add? The original code had *to = *from++ because it copied into one memory mapped I/O register (yay!). It must be noted that this code snipped is rather old, the technique makes a lot of sense in assembly (heck, I remember myself doing this on C64 for speedy drawing code), but for C you would rather let the C compiler do this for you for C loops ( -funroll-loops on GCC). Here is the orginal Usenet post from Tom Duff from 1984.
January 31st, 2007 at 11:30 pm
Regarding the technique: you may find that pulling the image from vram-based hw-accelerated surface to a java-based representation will be very slow - this is especially true on AGP/PCI, less so on PCIx boards.
Also, what to do if you’re running in a headless environment - like a server generating images (maps,etc)? You’d still need a reasonably fast fall-back mechanism.
Dmitri
February 1st, 2007 at 12:26 am
Dmitri, well my idea is not to have a BI in HW accelerated vram, but instead in a memory area that can be supported (through whatever means) by, e.g., Cairo. Cairo supports rendering into an arbitrary memory area (so presumably it’s not actually performed by HW, but instead by an optimized software renderer), but basically only ARGB8888. In GNU Classpath we could do rendering using a Java pipeline (which actually is quite fast — I did put quite some time in it to optimize hell out of it, without any allocations, using fixed-point arithmetics and very fast algorithms). But my general feeling to having two separate renderers do the rendering was that it would result in inconsisten rendering on different surfaces. But after reading your email (kind thanks again) it seems like this is what we should probably do too.
February 1st, 2007 at 11:32 am
[…] On a completely different note, I was slightly wrong with my last picture of the inner workings of BufferedImage. Dmitri from Sun’s Java2D team was so kind to explain in detail how this is supposed to work and how it works in their implementation (thanks Dmitri). Having two buffers and syncing them is supposedly not the way to go. My intention with this has been that we would have only one rendering engine doing all the rendering, but this is probably wishful thinking. If I understood Dmitri correctly there are (at least) 3 renderers for Java2D in Sun’s impl, one HW accelerated for Windows and VolatileImages, and 2 software renderers for BufferedImages (one generic and one with specialized impls for the known formats). […]