This works ok, but I noticed a significant frame rate drop when the window gets bigger.

Back in the days when I used DirectDraw, I usually just did something like this this:1. ddsSecondary->Lock()2. Copied the pixels3. ddsSecondary->Unlock()4. ddsPrimary->Blt(...)and that always worked fine, regardless of the window size.

I assume the difference is that in my Java code, the surface remains locked. What can I do to improve performance?

Thanks for your help, I did some reading and added BufferStrategies to my app. But it appears the problem is related to the scaling inside drawImage(...). Here's a test app: (assumes your desktop is 32 bpp)

Note how everything slows down as the window gets bigger. I guess this is because the dd surface for that BufferedImage must remain locked at all times since Java allows me to access its pixels directly at any time.

Is there a better way to use a BufferStrategy and still get direct access to the pixels?Or is there a way to "unlock" the BufferedImage so that drawImage(...) can be hardware accelerated?Or did I just misunderstand everything and now I'm looking like an idiot?

You don't manipulate pixels in Java. Doing so is going to get you all the performance of glDrawPixles. i.e. Absolutely horrible performance.

What you want is to blit your images directly (as if they were polygon surfaces), then apply transformations for scaling, rotation, and special effects. This will then get shunted down the Direct3D/OpenGL pipeline to be rendered directly onto the backbuffer in Video RAM.

For maximum performance, make sure you acquire an image that matches the depth and memory organization of the backbuffer before rendering. Otherwise Java will convert the image to the native format every time you need to render the image. As you can imagine, this is EXTREMELY slow. As a result, you'll usually want to create a loader that automatically copies the image data into new images of the proper format. Such a loader is available here:

That's the whole point - I do need to manipulate pixels directly, hence the topic "Software rendering". I know this is not normal but in this case I really need to do it. I've got all the pixels ready and I just need to blit them to the primary surface as fast as possible.

WIth DirectDraw, I just did the regular [lock, copy pixels, unlock] thing and that way I could use hardware accelerated blits for that surface but still access its pixels directly for a limited time (during the lock). Is there absolutely no way to do this with Java?I assume calling "((DataBufferInt) image.getRaster().getDataBuffer()).getData();" results in hardware acccelerated blits being disabled since from that point on I can access the pixels directly at any time, so the surface is most likely moved out of VRAM. What I want is to tell Java "Ok, I don't need direct access to the pixels anymore" so that I can have hardware acceleration enabled again for that surface. How can I do that?

It's inefficient to access the Video RAM pixel by pixel. The result would be tons of unnecessary bandwidth on the line. Thus Java copies the entire buffer when it's done. What you're doing is pretty close to the fastest thing available . A few helpful hints:

Create a Graphics Configuration compatible image for your backbuffer the same way I pointed to above.(i.e. BufferedImage buffer = gc.createCompatibleImage(width, height); ) This will prevent Java from having to convert the image data.

Set the BufferCapabilities to BufferCapabilities.FlipContents.PRIOR to save time during flips.

That's about as fast as you're going to get. You should be able to get 60 or so FPS, though.

Keep in mind that this is all going through a 3D API, so pixel level performance is not intended to be fast.

Perhaps if you could tell us more about why you specifically *need* pixel level rendering, we could offer more suggestions? Quite a few new Java Game programmers don't realize the things that can be done without access to the pixel level.

Perhaps if you could tell us more about why you specifically *need* pixel level rendering, we could offer more suggestions? Quite a few new Java Game programmers don't realize the things that can be done without access to the pixel level.

Perhaps if you could tell us more about why you specifically *need* pixel level rendering, we could offer more suggestions? Quite a few new Java Game programmers don't realize the things that can be done without access to the pixel level.

I'm writing a console emulator (NES/Famicom). All pixels are generated by the GPU emulator, I'm afraid there's no way to use hardware acceleration in this case. On each frame, the GPU emits a 256x240 image. I need to use hardware acceleration when blitting that image to screen.

Quote

Performance is not too bad using this method, i am able to get ~300fps with a 512*384 img just clearing it and drawing it to the screen every frame.

It works, but for a big window this method is several times slower than using hardware accleration for that blit. That's why I'm looking for alternatives...

I'm writing a console emulator (NES/Famicom). All pixels are generated by the GPU emulator, I'm afraid there's no way to use hardware acceleration in this case.

That's not actually true. The NES/Famicom contained sprite hardware. By rendering the sprite slivers to correctly sized buffered images, you could potentially accelerate the process. Especially if you cached sprite/tile values. It's a lot more complicated method than a straightup NTSC GPU emulator, though.

Quote

On each frame, the GPU emits a 256x240 image. I need to use hardware acceleration when blitting that image to screen. It works, but for a big window this method is several times slower than using hardware accleration for that blit.

Are you resizing the image before or during the render? Because I guarantee that the fastest method is to render to a 256x256 buffered image (just ignore the extra area) then scale it with the g.drawImage(image, x, y, width, height, null) method. That will transfer less data over the bus, and force the hardware to do the hard work for you.

I'm writing a console emulator (NES/Famicom). All pixels are generated by the GPU emulator, I'm afraid there's no way to use hardware acceleration in this case.

That's not actually true. The NES/Famicom contained sprite hardware. By rendering the sprite slivers to correctly sized buffered images, you could potentially accelerate the process. Especially if you cached sprite/tile values. It's a lot more complicated method than a straightup NTSC GPU emulator, though.

Yeah, I've thought about that too. I know it all may seem simple until you look closer into the tech details. But believe me, hardware rendering is not a good (or even fast) solution here. I'm 100% sure on this one.

Quote

Quote

On each frame, the GPU emits a 256x240 image. I need to use hardware acceleration when blitting that image to screen. It works, but for a big window this method is several times slower than using hardware accleration for that blit.

Are you resizing the image before or during the render? Because I guarantee that the fastest method is to render to a 256x256 buffered image (just ignore the extra area) then scale it with the g.drawImage(image, x, y, width, height, null) method. That will transfer less data over the bus, and force the hardware to do the hard work for you.

Yeah, that's exactly what I want to do - I want drawImage to be hw accelerated after I've set the pixels manually. Do you have any working example code? Could you modify this example so that it forces the hardware to do the hard work for me?

I get about 400 frames per second on my machine. I actually added "try {Thread.sleep( 8 );} catch(Exception e) {}" right after "bufferStrategy.show();" to lock it at 100FPS so I could appreciate the effect. (Ahh, lovely. ) Unless you're on a Mac, I wouldn't be surprised if you're seeing similar results.

Yeah, I get about 400fps too, but it's still not hw accelerated - it's using my precious cpu time to scale that image.If I resize the window to its smallest size, I get 1700 fps.If I maximize the window, the frame rate drops to 120fps.With hw acceleration, I believe we would see >1700fps no matter what the window size.

In my real app - which is somewhat more complex - these numbers are 250fps/90fps. This suggests that if I could have drawImage(...) hw accelerated, I could triple my app's performance.

1) set one of the system properties - sun.java2d.opengl=true, or sun.java2d.ddscale=true.2) perform all your per pixel operations to a BufferedImage compatible with the screen pixel format (obtained from createCompatibleImage)3) copy the image to a VolatileImage.4) blit the VolatileImage with a scaling transform, onto your BufferStrategy.

This *should* result in the scale being performed in hardware, not software.

Though tbh, this shouldn't be necessary - the scale *should* be getting done in hardware anyway. If scaling an unaccelerated BufferedImage, onto an accelerated surface means the scale is done in software, not hardware - I would consider it a bug in the java2d implementation.

publicclassTest{publicstaticvoidmain(String[] args)throwsException {System.setProperty("sun.java2d.ddscale","true");//System.setProperty("sun.java2d.opengl","true");// opengl pipeline doesn't work properly for me at all,// renders vsync'ed in a window, doesn't resize the BufferStrategy when the canvas is rescaled,// and causes a VM crash when I close the application down :S

Anon666, your code did the trick and everything works great now - I went from 90fps to 240fps in my app!!. Below is some more test code, you can try different stretch strategies by clicking the canvas.

I got the same fps without AffineTransform as I got with it. I have no idea why you didn't, it seems reasonable for drawImage to be hw accelerated for VolatileImages.

Since you're all big boys and girls and understand that flags aren't guaranteed to be supported forever, I'll post another version with some flags which have been there for a while. If you're curious what those flags mean, feel free to browse the jdk source code =)

Anon666, your code did the trick and everything works great now - I went from 90fps to 240fps in my app!!. SmileyBelow is some more test code, you can try different stretch strategies by clicking the canvas.

I got the same fps without AffineTransform as I got with it. I have no idea why you didn't, it seems reasonable for drawImage to be hw accelerated for VolatileImages. Undecided

java-gaming.org is not responsible for the content posted by its members, including references to external websites,
and other references that may or may not have a relation with our primarily
gaming and game production oriented community.
inquiries and complaints can be sent via email to the info‑account of the
company managing the website of java‑gaming.org