I’m getting nuts over this really weird bug in the image rendering in my applet
I’m using a VolatileImage as a backbuffer, and rendering to it from ordinary images, with and without alpha channels. With the background (w/o alpha) enabled, the FPS is extremely bad, but when I turn it off, the framerate skyrockets. If I play around, disabling most of the tile layers, and then enable the background, the FPS is about the same as with all layers except the background. When I re-enable the foreground, the FPS get really bad, as in the start. This could be normal, if not for the following: when I then disable the foreground, the framerate doesn’t come back as expected, it stays as if nothing had happened. This must be some weird internal blitting strategy of the VolatileImage… I’ve disabled all timing code, so it’s not the inaccuracy of the timer coming into play.
Has anyone else experienced this? I really hope there is a workaround, as I can’t predict the behaviour of the rendering at all… ??? ??? ???
it seems the bug comes into play when there are many transparent images on-screen. Seems like it’s disabling acceleration then.
I’ve recently replaced my graphics card, with the same behaviour both before & after, so it’s unlikely thats what’s causing the bug.
For the rendering I’m using Graphics.drawImage(Image,dx1,dy1,dx2,dy2,sx1,sy1,sx2,sy2,ImageObserver)
Some more info:
Only the backbuffer is a VolaTileImage, created with Component.createVolatileImage(int,int). The other images I blit are png images created with Toolkit.getImage, with (mostly) 1-bit alpha channels.
Could someone try to reproduce the bug, so I can be sure it’s not my system that’s influencing this? The applet is here:
http://www.idi.ntnu.no/~erlinga/vibug/frogma.php
Try pressing these keys, in the order given, pressing key Up to jump in between (to see the performance):
(startup: very slow)
1 (disables background -> fast)
2 (disables 1st object layer)
3 (disables ‘middle ground’ tile layer)
9 (disables status info)
1 (enable background. notice it becomes slow)
5 (disable 2d object layer)
6 (disable player layer - notice how the speed comes back)
5
6 (turning these back on doesn’t reduce the performance!!)
4 (enable collision detection tiles)
that is: 1,2,3,9,1,5,6,5,6,4
After this, the performance should still be high. But if you now move the player down, so you can see the monsters, the water, etc., the performance suddenly drops back down.
Isn’t this really weird? It seems as though the VolatileImage will change its blitting strategy/accelleration if transparency above a certain amount is encountered when rendering. The water tiles have every other pixel transparent, to avoid using semi-transparency.
Hrm, I just get a grey screen and “Class FrogmaApplet not found”.
Uhmm. I forgot I compiled it with 1.4.1_01… It’s recompiled with 1.4.0 now… Try again
I get the same bad frame rate when I followed the instructions…
What’s causing it I have no idea…
Hrm, still didn’t work - looks like my browser plugin has broken. Works fine through Appletviewer though!
Yep, I see the same slow down - it’s not just your system.
[quote]Isn’t this really weird? It seems as though the VolatileImage will change its blitting strategy/accelleration if transparency above a certain amount is encountered when rendering. The water tiles have every other pixel transparent, to avoid using semi-transparency.
[/quote]
I had the exact same problem in a project I’m working on. You can’t have small non-contiguous areas of transparency in your graphics. I think what happens is this: When an image has contigous areas of transparency the video drivers can optimize the bits. When you have say evey other pixel transparent then the driver has to switch to some internal mode for each pixel. You’ll find this is true even when it isn’t every other pixel. For instance I had a tile of a tree that had a number of small bumps (tranparent pixels) in the top of the graphic. As soon as I filled in the bumps the performance went way up.
Whoa, thats a weird one. I used the old-skool ‘mesh’ technique for fake shadows a while ago and didn’t notice anything like this happening ??? On the other hand, this was using automatic images, not Volatile, so this could be related in some way (although it sounds more like a driver issue to me).
Seems I have to stay with normal Images in windowed mode then. Using semi-transparency would be too slow anyway. Using normal Images is much faster than using VolatileImages with slowdown.
There’s an application version of the game using fullscreen, I haven’t had any problems with it there. In the windowed level editor, though, I have the same problem. If the drivers can cope with it in fullscreen mode, why can’t they do it in windowed? ??? ??? ???
Let us know but I would be extreemly surprised if you get high frames in windowed mode when using a buffer strategy or even your own buffer flipping. And without either of those it is going to flash like crazy.
I fixed the problem!
The problem was that I was using images with an 8 bit alpha channel (loaded directly from png files). I found some code I wrote earlier to make 1 bit alpha images from 8 bit ones, and used it. The problem went away! It’s really fast now
I’m sure this code could be a lot better (and of course lots more optimized), but if anyone wants to have a look, here it is:
public Image create1bitAlpha(Image src){
PixelGrabber pg;
MemoryImageSource memSrc;
Image retImg;
ColorModel colModel;
int[] pix;
int w=src.getWidth(null);
int h=src.getHeight(null);
int rgb,alpha;
pix = new int[w*h];
pg = new PixelGrabber(src,0,0,w,h,pix,0,w);
try{
pg.grabPixels();
}catch(InterruptedException e){
System.out.println("Unable to create 1bit alpha: couldn't grab pixels from image.");
return null;
}
// Fix alpha channel:
for(int i=0;i<pix.length;i++){
rgb = pix[i];
alpha = (rgb>>24)&0xFF;
if(alpha==255){
alpha = 1;
}else{
alpha = 0;
rgb=0;
}
pix[i] = (rgb&0x00FFFFFF)|(alpha<<24);
}
// Create an image out of it:
colModel = new DirectColorModel(Color.black.getColorSpace(),32,0x00FF0000,0x0000FF00,0x0000FF,0x01000000,true,DataBuffer.TYPE_INT);
memSrc = new MemoryImageSource(w,h,colModel,pix,0,w);
retImg = createImage(memSrc);
memSrc.newPixels();
return retImg;
}
(I dont’ know how to format the code nicely here, or even if it can be done… may not look nice)
I think this could be done a bit easier - just create a 1-bit transparent image (for example, using GraphicsConfiguration.createCompatibleImage(w, h, Transparency.BITMASK)) and copy your original image onto it. It should be faster.
But how do I copy the whole image w/alpha channel onto it? I’m a n00b in this, so could anyone tell me how I would do that? If I use the normal drawImage methods, the alpha channel wouldn’t be copied, it would be used to modify the rgb channels as usual? The alpha channel in the destination image wouldn’t be modified?
here ya go, this will maintain the alpha channel of the source image.
Graphics g = autoImage.getGraphics();
g.setComposite(AlphaComposite.Src);
g.drawImage(sourceImage,0,0,null);
g.dispose();
that must be the 10 squilianth time i’ve posted that code ;D
Thanx!!! ;D
The easier code didn’t work as expected… I get the same slowdown on the second level in the game, perhaps it’s because the alpha values are rounded differently? Also, when I do this in fullscreen mode, it gets 10 times slower than before… Seems like I’ll have to use LWJGL for the fullscreen version.