Skip to main content

Subclassing Graphics2D to provide XRender acceleration?

4 replies [Last post]
dcbw
Offline
Joined: 2006-02-14
Points: 0

On Linux it appears that Java2D/Graphics2D doesn't do anything at all to accelerate 2D graphics when OpenGL isn't present. I'm targeting a platform that doesn't have any 3D capabilities, but provides some 2D acceleration exposed via XRENDER and possibly EXA in the near future.

I need antialiasing, but turning AA on with a Graphics2D gives me something like 1/2 FPS animation. Cairo on the same machine is around 20 - 30 FPS doing the same types of tests, because it can access the 2D acceleration features of the card through its X11 driver.

So I'd like to do something like subclassing Graphics2D to talk to Cairo via JNI to actually get acceptable graphics performance since OpenGL is out of the question.

Is this possible? Is there a better method to get Java2D with AA sped up to an acceptable level by using native 2D acceleartion?

Reply viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.
dcbw
Offline
Joined: 2006-02-14
Points: 0

grr, yay for formatting.

http://www.bigw.org/~dan/foo.java

campbell
Offline
Joined: 2003-06-24
Points: 0

> I need antialiasing, but turning AA on with a
> Graphics2D gives me something like 1/2 FPS animation.
> Cairo on the same machine is around 20 - 30 FPS
> S doing the same types of tests, because it can
> access the 2D acceleration features of the card
> through its X11 driver.
>

Really? 1/2 fps? Could you give me more specifics about the machine you're testing on (video card, CPU, etc)? Perhaps more importantly, what kind of rendering destination does your app use? If you're rendering directly to the screen or to an XDBE backbuffer, then I could understand the poor performance, but not if you're rendering to the Swing backbuffer or a VolatileImage or BufferedImage. If you're using Swing or a VolatileImage, one thing you could try is -Dsun.java2d.pmoffscreen=false, which may help performance if there's a lot of AA or translucent rendering in your app.

> So I'd like to do something like subclassing
> Graphics2D to talk to Cairo via JNI to actually get
> acceptable graphics performance since OpenGL is out
> of the question.
>
> Is this possible? Is there a better method to get
> Java2D with AA sped up to an acceptable level by
> using native 2D acceleartion?

Well, it's not as simple as subclassing Graphics2D. There is an open RFE to use more XRender for things like AA and compositing:
http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6307603

It would be nice to make targetted use of XRender in our X11 pipeline, but there are some issues with XRender not being accelerated on all systems, and in some cases may be slower than what we can provide with our software loops. And while you could use Cairo, I think of that API as offering very similar functionality to what's already provided in Java2D, so it would be yet another layer to go through, which is why I'd prefer to see targetted use of XRender instead. We currently put more focus on the OGL pipeline because it offers more bang for its buck, although I understand it may not be supported on all video cards.

Anyway, with a little work, it should be possible to extend our existing X11Renderer code to handle things like non-opaque colors via XRender. Also, an XRender-based implementation of MaskFill (similar to our OGLMaskFill impl) would go a long way to improving AA performance for X11 destinations. If you'd be interested in working on these ideas, you could download the latest Mustang sources and start hacking pretty quickly. I'd be glad to provide assistance, since this is a worthwhile project and something we were hoping to investigate for Dolphin.

Thanks,
Chris

dcbw
Offline
Joined: 2006-02-14
Points: 0

Maybe I'm just not aware of how to make the drawing work acceptably... The main draw loop is pretty much this:

public void paint(Graphics g) {
super.paint(g);

Date startDate = new Date();
long start = startDate.getTime();
long iters = 8000;

createBufferStrategy(2);
BufferStrategy bufferStrategy = getBufferStrategy();

int num_rects = 10;
MyRect[] rects = new MyRect[num_rects];
for (int i = 0; i < num_rects; i++) {
int rx = (int)(Math.random() * 400);
int ry = (int)(Math.random() * 200);
int rw = (int)(Math.random() * 200) + 20;
int rh = (int)(Math.random() * 200) + 20;
rects[i] = new MyRect(rx, ry, rw, rh);
rects[i].setBounds(20, 5, 460, 630);
}

for (int index = 1; index <= iters; index++) {
Graphics2D g2 = (Graphics2D) bufferStrategy.getDrawGraphics();

g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
//g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_OFF);
g2.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_SPEED);

if (!bufferStrategy.contentsLost()) {
g2.setColor(Color.yellow);
g2.fillRect(0, 0, 640, 480);

for (int i = 0; i < num_rects; i++) {
rects[i].draw(g2);
rects[i].advance();
}
}
bufferStrategy.show();
g2.dispose();
}

Date endDate = new Date();
long end = endDate.getTime();
long t = end - start;
System.out.println("Time is " + t + ", FPS is " + (iters / (double)(t / 1000)));
System.exit(0);
}

So we're drawing in a tight loop, attempting _not_ to use any intelligence behind the scenes that Java2D might be trying to do. I'm just trying to get representative FPS for how fast Java2D draws stuff with AA on this machine. If there's an app that would do this, or a better way to figure out the speed this machine draws at, I'm all ears.

The machine has shared VRAM BTW, so I don't think using managed images gains me anything. It's not like there's a bottleneck between GPU RAM and system RAM since they are both the same thing.

campbell
Offline
Joined: 2003-06-24
Points: 0

In your code you are using createBufferStrategy(2), which will attempt to use XDBE to provide a "flip" BufferStrategy. Since the backbuffer will reside in hardware, it's quite possible for things like AA and blending to be relatively slow (until Java2D starts leveraging XRender, which would certainly help in this case).

Also, you are measuring the cost of the buffer swap operation (BufferStrategy.show()), which will be synced to your monitor's refresh rate. So in your case, you're drawing 10 rects per frame, and 8000 total frames. If your monitor is at 60 Hz, it would take 133 seconds for this testcase to complete.

What does your Cairo app look like? Is it using XDBE? If not, then it's not an apples to apples comparison.

BTW, I'm not sure what MyRect is, but antialiasing typically has no effect on filled rectangles, so perhaps rendering circles or something like that would be a better test.

I'd suggest you use a "blit" BufferStrategy, which will not be vsynced and will therefore be a better comparison against your Cairo testcase:
ImageCaps icaps = new ImageCapabilities(true);
BufferCapabilities bcaps = new BufferCapabilties(icaps, icaps, null);
createBufferStrategy(2, bcaps);

> I'm just trying to get representative FPS for how fast Java2D draws stuff
> with AA on this machine. If there's an app that would do this, or a better
> way to figure out the speed this machine draws at, I'm all ears.

If you're just interested in a Java2D benchmarking app, there are some instructions on how to get J2DBench here:
http://192.18.37.44/forums/index.php?topic=8084.0

Thanks,
Chris