Pixel manipulation with bufferstrategy.

It being used internally makes no argument. Ask Microsoft how much undocumented functionality is in use under their Operating System. Most software frameworks do this, as I’ve already pointed out. The difference is you aren’t maintaining your development platform and thus you shouldn’t make assumptions because Oracle isn’t going to contact you when they’ve refactored code.

But whatever, I yield. While it is not functionality that will likely change, it is definitely accessing protected data buffers (which was why my initial assumption was made)

Using instanceof is in essence against OOP practice. So is casting down to get functionality that was intentionally unexposed.

@Jeremy - oh, you’re back! :stuck_out_tongue:

a) This isn’t going to change because the Java2D team have been recommending this approach for over a decade. The DataBuffer is specified to be of TYPE_INT - to be nitpicky it might have been better if they had specified this meant DataBufferInt or subclass.

b) I’ve already posted a link earlier which shows how to build a BufferedImage from an int[], and therefore is the absolutely safe way to do this following the spec to the letter.

I was not aware that this was being encouraged by the Java2D team, I asked if it was earlier and no one responded, is this true? Internal usage != encouraged usage.

You shouldn’t ever construct a buffered image (at least for your backbuffer) the way you describe if you plan on rendering it to a graphics object. It won’t be guaranteed to be compatible with the device. Hence why the entire process is abstracted via createCompatibleImage of the corresponding GraphicsConfiguration.

Albeit, that point is moot anyway since I can’t find anywhere in the doc that says anything that guarantees this isn’t wrapped etc…

@Jeremy - you’ve changed your reply since I first read it! :emo:

Anyway, I disagree with Riven’s fallback in this case, as it requires writing an unnecessary code path that will not be required. If you want a clean way to do this without breaking encapsulation, then wrap the pixel array into an image as below. This way you don’t access any ‘protected’ data and fully follow the spec. It also protects you from two other issues you’ll never see in practice - data offset and scanline.


int[] pixels = new int[width * height];
DataBufferInt db = new DataBufferInt(pixels, pixels.length);
ColorModel cm = ColorModel.getRGBdefault();
WritableRaster raster = Raster.createPackedRaster(db, width, height, width, cm.getMasks(), null);
BufferedImage image = new BufferedImage(cm, raster, false, null);
// play with pixel array as you want

Load of rubbish! createCompatibleImage() just means you have an image in the same color model as the screen, and so is (theoretically) faster to draw to the screen. If you’re doing direct pixel manipulation you want a guaranteed color model to work with. Drawing to the screen is only a small part of the overhead, and there are optimized paths for converting default RGB color models.

That’s Java! It’s pass-by-reference by default, which means if anything accepts a mutable object, it should respond to changes in that object. This is used all over the JRE - eg. passing models into Swing components. Anything that has pass-by-value semantics, which being Java means cloning or otherwise copying data, says so in the documentation.

I’ve been doing loads of stuff with direct pixel manipulation for over ten years - I’m glad you’ve popped up to tell me it doesn’t work! :stuck_out_tongue:

It does drastically increase performance (from my experience) but it depends on the environment. Creating a compatible image also allows it to be hardware accelerated where optimal - definitely something you want for your backbuffer (ofcourse doing software based per-pixel operations on your backbuffer throws that out the window anyways.)

Fair point, and this does make sense. I haven’t been programming in Java in particular long enough to know of the special points it makes regarding this in the javadoc.

I’m not telling you that it doesn’t work. My point consists of two arguments:

  • Software shaders are not practical for a real-time render loop in most games where rendering is already an expensive operation.
  • You are hacking your way into an object’s hidden data.

The second argument was for an older code snippet, the code snippet you just presented I haven’t got a problem with.

All BufferedImages can be “managed” - cached in video memory. You don’t need to use createCompatibleImage for this.

Rendering into a BufferedImage is not hardware accelerated. You don’t want to be using them for a back buffer! createCompatibleVolatileImage maybe. Or use a BufferStrategy which will do that under the hood.

If your rendering is that expensive, you’d be a fool to be using Java2D to start with! :wink: They’re perfectly “practical” for simple things and specific use cases, and also potentially as a learning tool.

How else would you apply a post-processing software-shader effect to the data rendered on the backbuffer?

I am pretty sure that not ‘every’ bufferedimage is managed, you have to go through a particular process to acquire a managed buffered image, but correct me if I am mistaken:
https://weblogs.java.net/blog/chet/archive/2003/08/bufferedimage_a_1.html

It’s the required abstraction in Java2D that makes doing things its not supposed to do slow, if you use Java2D properly and you don’t need to travel down those optimization routes not offered by Java2D (i.e, hardware shader) then your code should in theory perform just as optimally if you did the same in OpenGl (in theory better because the JRE can make educated decisions based on the platform regarding which rendering APIs to use)

Note that that post is from 2003. Things have changed, and my understanding is that BufferedImages are managed by default, until you do some illegal operation, usually involving their Rasters, etc.

I think many will agree with me when I say that OpenGL is far faster for just about any operation in J2D, not mention the operations not in the J2D API.

You wouldn’t in this specific case, as you’d have to use the BufferedImage methodology above - you still don’t need a compatible image for that though.

Your information is about a decade too old! :wink: This changed in Java 1.5.

Nice theory! In practice, that’s not true. Java2D is a general purpose imaging API - it aims for compatibility across renderers that isn’t compatible with fast rendering (ie. pixel accuracy). You also have no idea what will be accelerated and what will be punted to the software loops - and direct pixel manipulation in Java can often outperform those software loops!

Found this:
http://docs.oracle.com/javase/7/docs/technotes/guides/2d/new_features.html

Which I hadn’t before noticed - this seems to make your point regarding managed images. A further google search than I thought it would be though I may have just not been googling the proper keywords.

In terms of performance comparison with Java2D and OpenGL - I don’t think it is ever fair to generalize the performance of an entire API to be slower than another. It really depends on what you are using it for. On Windows with poor OpenGL driver support (or none at all) you could experience incredibly poor frame rates using native OpenGL and higher framerates using D3D\DirectDraw via Java2D, and vise-versa. There are a lot of things you cannot do in Java2D that you can do in OpenGL, but if you need nothing more than Java2D there is no reason not to use it.

Anyways, it seems I’ve thrown us off topic.

And what it’s designed for!

There are many, but I’m not going to argue that further - just try reading this forum! ;D

People use Java because it abstracts them from hardware-level details - sure that isn’t always possible when it comes to developing games, but where it is it should be taken advantage of, it is one of the core concepts of Java. Write Once, Run Anywhere. Sure, occasionally we need native dependencies, but if you can avoid them you should.

I do like Java2D for it’s simplicity, and ease of use, little to no setup, etc.

[quote]if you need nothing more than Java2D there is no reason not to use it.
[/quote]
Indeed. And if you also need per-pixel manipulation, then use the databuffer method.

I just wrote a quick comparison between using drawLine() to a BufferedImage, then drawing it to screen (standard J2D), my int[] method, and, for fun, an interleaved byte[] method, to see if it’s any faster. See for yourself:
EDIT: Added setRGB() test
Quick n’ dirtyTM bench mark

Disclaimer: There may be many non-optimal things in that code, feel free to modify and show me. Also, this bench mark only tests writing to a backbuffer, not reading data back from it. That test would be even more embarrassing for J2D as that would compare array access to getRGB().

Post results! I’m curious!

Typical on my machine:

Rendering Test: 200 frames...
Time for drawLine(): 10.34 s
Time for setRGB(): 2.74 s
Time for int[]: 1.53 s
And for fun, time for byte[]: 1.44 s

@BurntPizza - do you find your results a surprise? Can your code draw angled lines or an oval? :wink: You’re comparing something designed for a specific purpose to a general purpose image library / rasterizer. Some things can be much faster using direct pixel manipulation because you can bypass a huge amount of indirection.

This is comparing rendering to a BufferedImage though, which is all software on the Graphics2D side as well. How about using a VolatileImage for the Graphics2D test? Still use BufferedImages for the others - that should might compare your pixel manipulation against the accelerated pipeline.

Interestingly, for game purposes, sprite blitting can be quite fast (as long as we’re not talking transformation or scaling), even using blending. See these blendmodes for example.

I agree, and no, I don’t find the result a surprise, it is what I expected.

A long time ago I wrote an ArrayGraphics class that had all the standard Graphics.drawXXX() and fillXXX() methods, based off Brensenham’s, etc, and used the int[] method. Was still much faster than equivalent J2D operations. I’ll see if I can find it and give it a reboot.

Also, thanks for the link, looks quite useful!

How much of the Graphics2D class did it support?

drawLine() (any brush size)
drawCircle() (filled or not)
drawRect() (filled or not)
drawPixel() (don’t have to explain)

That’s all I remember, only main thing I remember was missing was drawOval()

I think it’s harder to make a generalization like that. It depends on what you are using the per-pixel manipulation for. If you’re doing a bunch of different post-processing effects on a relatively large buffer in a real-time loop, it’s hopeless (for now.)

Are you measuring just the time it takes to render over a buffered image? Or that and the time it takes to render the actual image to the given surface? drawLine etc are hardware accelerated so they won’t force the JRE to give up accelerating the image, per pixel operations aren’t.

@Jeremy - drawLine() on a BufferedImage is not hardware accelerated, and the image is only cached in video memory the second time it’s drawn without being modified. Therefore it makes no difference to this test. This is why I suggested switching to VolatileImage where drawLine() may be accelerated.

Just tested using VolatileImage for the drawLine() test, still BufferedImage for others, results:

Rendering Test: 200 frames...
Using VolatileImage for drawLine() test, BufferedImage for others:
Time for drawLine(): 10.58 s
Time for setRGB(): 2.65 s
Time for int[]: 1.54 s
And for fun, time for byte[]: 1.44 s

VolatileImage created with [icode]GraphicsConfiguration.createCompatibleVolatileImage(w, h, new ImageCapabilities(true))[/icode]