Skip to main content

Java2D FullScreenWindow performance

26 replies [Last post]
galilei
Offline
Joined: 2006-08-02
Points: 0

Hi,

I am using setFullScreenWindow().
With JRE 1.5.x it works well (30-50 FPS),
with Mustang-JRE the same code result in less than 5 FPS and sometimes bad quality.

Reply viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.
trembovetski
Offline
Joined: 2003-12-31
Points: 0

What is the platform you're running on (windows/linux/solaris)? What Mustang build?

What's the video board?

Could you provide a test app?

Thanks,
Dmitri
Java2D Team

galilei
Offline
Joined: 2006-08-02
Points: 0

Win XP SP2, Mustang Build92

Ati Radeon X1600 Pro

I´ll try to sent you the app per email.

trembovetski
Offline
Joined: 2003-12-31
Points: 0

Most likely the problem is with the Direct3D pipeline. Could you try running your app with -Dsun.java2d.d3d=false ?

Thanks,
Dmitri

galilei
Offline
Joined: 2006-08-02
Points: 0

Hi,

i tried following:

// FullScreenWindow:
-> CreateVolatileImage needs 5 secs longer to provide first frame than JDK 1.5,
and has appr. 20 secs rendering probs ( black rectangle instead of JPEG, unexspected lines by scrolling, ...),
but after that time / some scrolling the pipeline seems to do its job and 30 fps.

FullScreenWindow:
-> the problems occure too and do not stop, less than 5 fps

with d3d = false:
-> less probs but less than 5 fps, too.
no big differences compared to D3D-Pipeline
-> FullScreenWindow seems not to use Direct3D-Pipeline in Mustang

trembovetski
Offline
Joined: 2003-12-31
Points: 0

Could you provide a test case, or a snippet of your code which does the rendering?

Do you use BufferStrategy or VolatileImage for back-buffering?

Thanks,
Dmitri

galilei
Offline
Joined: 2006-08-02
Points: 0

private static Graphics2D g,p;
private static VolatileImage Puffer;
static boolean geladen, gestartet;
private Rectangle
A1024 = new Rectangle(0,0,1024,768),
A1280 = new Rectangle(0,0,1280,1024),
Start = new Rectangle(200,200,400,400),
Auflösung = Start;
private static GraphicsEnvironment Grafikumgebung;
private static GraphicsDevice Grafikausgabe;
private static DisplayMode Auflösung1024, Auflösung1280, Anzeige;
private static Element Fokus;
private static RenderingHints niedrigeQualität, hoheQualität, Qualität;
private Ansicht sicht;

[b]this choose DisplayMode[/b]
private static void ermittleoptimalenGrafikmodus(){
Grafikumgebung =
GraphicsEnvironment.getLocalGraphicsEnvironment();
Grafikausgabe = Grafikumgebung.getDefaultScreenDevice();
for(DisplayMode Modus : Grafikausgabe.getDisplayModes()){
// System.out.println(Modus.getWidth()+" * "+Modus.getHeight()+" Farbtiefe: "+
// Modus.getBitDepth()+" Bit Bildrate: "+Modus.getRefreshRate()+" Hz");
if(Modus.getWidth() == 1024 && Modus.getHeight() == 768){
if(Auflösung1024 == null) Auflösung1024 = Modus;
if(Auflösung1024.getBitDepth() < Modus.getBitDepth()) Auflösung1024 = Modus;
if(Auflösung1024.getBitDepth() == Modus.getBitDepth() &&
Auflösung1024.getRefreshRate() < Modus.getRefreshRate()) Auflösung1024 = Modus;
}
if(Modus.getWidth() == 1280 && Modus.getHeight() == 1024){
if(Auflösung1280 == null) Auflösung1280 = Modus;
if(Auflösung1280.getBitDepth() < Modus.getBitDepth()) Auflösung1280 = Modus;
if(Auflösung1280.getBitDepth() == Modus.getBitDepth() &&
Auflösung1280.getRefreshRate() < Modus.getRefreshRate()) Auflösung1280 = Modus;
}
}
}

[b]starting FullScreen [/b]
/**
* startet das Hauptfenster in der gewünschten Auflösung
* @param Auflösung (links,oben,breite,höhe)
*/
public void Hauptfensterstarten(boolean hoheAuflösung,
boolean hohequalität){
Auflösung = hoheAuflösung == true? A1280 : A1024;
Anzeige = hoheAuflösung == true? Auflösung1280 : Auflösung1024;
Qualität = hohequalität == true? hoheQualität : niedrigeQualität;
this.setBounds(Auflösung);
try{
Grafikausgabe.setFullScreenWindow(this);
Grafikausgabe.setDisplayMode(Anzeige);
}
catch(Exception e) {e.printStackTrace();}
}

[b] Double Buffering[/b]
/** zeichnen in der Pufferfläche (Double Buffering)*/
public void Pufferzeichnen(Rectangle auf){
Puffer = createVolatileImage(auf.width,auf.height);
do {
if (Puffer.validate(getGraphicsConfiguration()) ==
VolatileImage.IMAGE_INCOMPATIBLE)
{
Puffer = createVolatileImage(auf.width,auf.height);
}
p = Puffer.createGraphics();
PF.zeichneauf(p, this, Qualität);
if(sicht != null) sicht.zeichne();
p.dispose();
} while (Puffer.contentsLost());
}
[b] the Engine class PF manages access to p and operations like text, buttons, images in a style.
A class for each view extends class Ansicht does the rendering ...[/b]

[i] repaint is called by a TimerTask every 30 ms[/i]

/** Bildschirmausgabe*/
public void paint(Graphics g){
Mausposition();
Pufferzeichnen(Auflösung);
g.drawImage(Puffer, 0, 0,this);

}

trembovetski
Offline
Joined: 2003-12-31
Points: 0

From this code it looks like you're creating a VolatileImage on every repaint. That would exaust the video memory rather quickly (especially in 6.0).

Could you try doing it only once?

You would still need to call Puffer.validate(gc)
on every repaint as you do now, though.

Another problem is that you are not checking
whether the volatile image is lost after you copied it
to the screen.

Take a look at the updated javadoc for VolatileImage in Java 6 for an example of correct VolatileImage handling:
http://download.java.net/jdk6/docs/api/java/awt/image/VolatileImage.html
and restructure your code accordingly.

And yet another point: we advise not to use the
repainting mechanism in full-screen mode.
It is better to use what is called "active rendering":
http://java.sun.com/docs/books/tutorial/extra/fullscreen/rendering.html

Thank you,
Dmitri

galilei
Offline
Joined: 2006-08-02
Points: 0

Thanks for the tips.

with correct VolatileImage handling the quality probs are solved,
it improved the performance under JDK 1.5, too.

But with Mustang the frame-rate stays by 5 fps.
I´ll test active rendering with a render-loop-Thread instead of using TimerTask, perhaps TimerTask doesn´t work correctly.

galilei
Offline
Joined: 2006-08-02
Points: 0

[code]public class Fenster extends Frame implements MouseListener,
MouseWheelListener, MouseMotionListener,KeyListener {
private static final long serialVersionUID = 1L;
private static Graphics2D Schirm, Puffer;
private static BufferStrategy Pufferstrategie;
private Rectangle
A1024 = new Rectangle(0,0,1024,768),
A1280 = new Rectangle(0,0,1280,1024),
Start = new Rectangle(200,200,400,400),
Auflösung = A1024;
private static GraphicsEnvironment Grafikumgebung;
private static GraphicsDevice Grafikausgabe;
private static DisplayMode Auflösung1024, Auflösung1280, Anzeige;
private static Element Fokus;
private static RenderingHints niedrigeQualität, hoheQualität, Qualität;
private Ansicht sicht;
private static boolean geladen, gestartet;
[/code]
[b] this works on JDK 1.5 > 20 FPS[/b]
[code] private static void ermittleoptimalenGrafikmodus(){
Grafikumgebung =
GraphicsEnvironment.getLocalGraphicsEnvironment();
Grafikausgabe = Grafikumgebung.getDefaultScreenDevice();
for(DisplayMode Modus : Grafikausgabe.getDisplayModes()){
if(Modus.getWidth() == 1024 && Modus.getHeight() == 768){
if(Auflösung1024 == null) Auflösung1024 = Modus;
if(Auflösung1024.getBitDepth() < Modus.getBitDepth()) Auflösung1024 = Modus;
if(Auflösung1024.getBitDepth() == Modus.getBitDepth() &&
Auflösung1024.getRefreshRate() < Modus.getRefreshRate()) Auflösung1024 = Modus;
}
if(Modus.getWidth() == 1280 && Modus.getHeight() == 1024){
if(Auflösung1280 == null) Auflösung1280 = Modus;
if(Auflösung1280.getBitDepth() < Modus.getBitDepth()) Auflösung1280 = Modus;
if(Auflösung1280.getBitDepth() == Modus.getBitDepth() &&
Auflösung1280.getRefreshRate() < Modus.getRefreshRate()) Auflösung1280 = Modus;
}
}
}
private static void Renderqualität(){
niedrigeQualität = new RenderingHints(RenderingHints.KEY_ALPHA_INTERPOLATION,RenderingHints.VALUE_ALPHA_INTERPOLATION_SPEED);
niedrigeQualität.put(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_OFF);
niedrigeQualität.put(RenderingHints.KEY_RENDERING,RenderingHints.VALUE_RENDER_SPEED);
hoheQualität = new RenderingHints(RenderingHints.KEY_ALPHA_INTERPOLATION,RenderingHints.VALUE_ALPHA_INTERPOLATION_QUALITY);
hoheQualität.put(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_ON);
hoheQualität.put(RenderingHints.KEY_RENDERING,RenderingHints.VALUE_RENDER_QUALITY);
hoheQualität.put(RenderingHints.KEY_TEXT_ANTIALIASING,RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
}

/** erstellt das Fenster */
public Fenster() {
new PF();
Renderqualität();
Qualität = niedrigeQualität;
ermittleoptimalenGrafikmodus();
this.setTitle("Pfeffersack-Demo");
this.setLocation(200,200);
this.setSize(400,400);
this.setUndecorated(true);
this.setBackground(Farbe.dunkel.nutze());
this.setVisible(true);
Schirm = (Graphics2D) this.getGraphics();
PF.zeichneauf(Schirm,this,Qualität);
Auflösung = Start;
createBufferStrategy(2);
Pufferstrategie = getBufferStrategy();
Initialisierung();
}

/** Startfenster: laden aller Grafiken, Listener aktivieren*/
private void Initialisierung(){
System.gc();
for(Grafik b: Grafik.values()) Schirm.drawImage(b.nutze(),0,0,this);
for(int i = 0; i < 3120; i++){
for(int j = 0; j < 2170; j++) Schirm.drawImage(Grafik.Karte.nutze(),i,j,this);
}
this.addKeyListener(this);
this.addMouseListener(this);
try{
Thread.sleep(3000);
}
catch(InterruptedException e){e.printStackTrace();}
geladen = true;
System.gc();
this.addMouseMotionListener(this);
}
[/code]
[code]
private void rendern(){
Mausposition();
// Render single frame
do {
// The following loop ensures that the contents of the drawing buffer
// are consistent in case the underlying surface was recreated
do {
// Get a new graphics context every time through the loop
// to make sure the strategy is validated
Puffer = (Graphics2D) Pufferstrategie.getDrawGraphics();
Puffer.setRenderingHints(niedrigeQualität);

// Render to graphics
// ...
PF.zeichneauf(Puffer, this,Qualität);
if(sicht != null) sicht.zeichne();
// Dispose the graphics
Puffer.dispose();

// Repeat the rendering if the drawing buffer contents
// were restored
} while (Pufferstrategie.contentsRestored());

// Display the buffer
Pufferstrategie.show();

// Repeat the rendering if the drawing buffer was lost
} while (Pufferstrategie.contentsLost());
}
[/code]
[code]

/**
* veranlasst ein Neuzeichnen des Bildschirms
*
*/
public boolean neuzeichnen(){
rendern();
return true;
}

/** Bildschirmausgabe*/
public void paint(Graphics g){
if(!geladen){
g.drawImage(Grafik.Test.nutze(),150, 100, 100, 100, this);
g.setFont(Schrift.Titel.nutze());
((Graphics2D) g).setPaint(new Farbverlauf( new
Rectangle(100,200,200,40),Farbe.gelb,Farbe.gold,false).nutze());
g.drawString("lade Grafiken", 110, 250);
}
else rendern();
}

public void Hauptfensterstarten(boolean hoheAuflösung,
boolean hohequalität){
Auflösung = hoheAuflösung == true? A1280 : A1024;
Anzeige = hoheAuflösung == true? Auflösung1280 : Auflösung1024;
Qualität = hohequalität == true? hoheQualität : niedrigeQualität;
this.setBounds(Auflösung);
try{
Grafikausgabe.setFullScreenWindow(this);
Grafikausgabe.setDisplayMode(Anzeige);
}
catch(Exception e) {e.printStackTrace();}
gestartet = true;
}
[/code]
[b] if setFullScreen at Startup the //code behaves with JDK 1.5 like Mustang, 2 FPS
the main loop calls neuzeichnen() in both cases
[/b]
[code]
// /** Startfenster: laden aller Grafiken, Listener aktivieren*/
// private void Initialisierung(){
// System.gc();
// for(Grafik b: Grafik.values()) Schirm.drawImage(b.nutze(),0,0,this);
// for(int i = 0; i < 3120; i++){
// for(int j = 0; j < 2170; j++) Schirm.drawImage(Grafik.Karte.nutze(),i,j,this);
// }
// this.addKeyListener(this);
// this.addMouseListener(this);
// try{
// Thread.sleep(3000);
// }
// catch(InterruptedException e){e.printStackTrace();}
// System.gc();
// this.addMouseMotionListener(this);
//// this.addMouseWheelListener(this);
// }
// public Fenster(){
// new PF();
// this.setTitle("Pfeffersack-Demo");
// this.setUndecorated(true);
// this.setBackground(Farbe.dunkel.nutze());
//
// Renderqualität();
// Qualität = niedrigeQualität;
// ermittleoptimalenGrafikmodus();
// this.setBounds(Auflösung);
// try{
// Grafikausgabe.setFullScreenWindow(this);
// Grafikausgabe.setDisplayMode(Auflösung1024);
//
// }
// catch(Exception e) {e.printStackTrace();}
// sicht = new Ladeschirm();
// Schirm = (Graphics2D) this.getGraphics();
// createBufferStrategy(2);
// Pufferstrategie = getBufferStrategy();
// this.setVisible(true);
// Initialisierung();
// this.setIgnoreRepaint(true);
// }
//
// public boolean neuzeichnen(){
// rendern();
// return true;
// }
// public void rendern(){
// Mausposition();
// do {
// // The following loop ensures that the contents of the drawing buffer
// // are consistent in case the underlying surface was recreated
// do {
// // Get a new graphics context every time through the loop
// // to make sure the strategy is validated
// Puffer = (Graphics2D) Pufferstrategie.getDrawGraphics();
// Puffer.setRenderingHints(niedrigeQualität);
//
// // Render to graphics
// // ...
// PF.zeichneauf(Puffer, this,Qualität);
// sicht.zeichne();
// // Dispose the graphics
// Puffer.dispose();
//
// // Repeat the rendering if the drawing buffer contents
// // were restored
// } while (Pufferstrategie.contentsRestored());
//
// // Display the buffer
// Pufferstrategie.show();
//
// // Repeat the rendering if the drawing buffer was lost
// } while (Pufferstrategie.contentsLost());
// }
[/code]

Message was edited by: galilei

Message was edited by: galilei

trembovetski
Offline
Joined: 2003-12-31
Points: 0

It is really hard to understand the code. Could you please repost it between [ code ] and [ /code ] tags (with no spaces) .

So this code:
public static void main() {
System.err.println();
}

will look like this:
[code]
public static void main() {
System.err.println();
}
[/code]

Dmitri

galilei
Offline
Joined: 2006-08-02
Points: 0

I´ve resolved the problem now.
The low frame-rate was caused by a xxl-image.
Mustang seems to be more sensitive here.

trembovetski
Offline
Joined: 2003-12-31
Points: 0

Well, glad it worked out =)

Could you please elaborate on what was the problem?
What is an xxl-image (sorry for ignorance)?

Thanks,
Dmitri

galilei
Offline
Joined: 2006-08-02
Points: 0

The Image was a 3000 * 2000 pixel map, which was drawn at negative coordinates for scrolling. This worked in non-exklusive mode with JDK 1.5, and in exclusive mode, if started later (possibly if the image was loaded).
In exclusive mode / with Mustang this image delivers only 1-2 FPS, the avaiable memory or whatever per image seems to be limited,
with splitted map in 16 * 24 parts it works at > 25 frames per second.

trembovetski
Offline
Joined: 2003-12-31
Points: 0

OK, thanks for the explanation.

I'm still surprised that disabling the Direct3D pipeline in JDK 6 didn't help - it should have behaved the same as JDK 5 with d3d disabled.

But having such large image split up is definitely a good idea - we most likely were not able to cache it whole in video memory. Also, when splitting up consider using pieces with power of two dimensions (preferably square) - it works better with most video boards (and less video memory is wasted).

Thanks,
Dmitri

galilei
Offline
Joined: 2006-08-02
Points: 0

There seems to be a big difference berween JDK 1.5 and Mustang:

1.5:
System.currentTimeMillis() && .nanoTime() unable to deliver > 20 fps
.getAvaiableAcceleratedMemory() -> 318.434.240

Mustang:
System.nanoTime() does what expected
AccelaratedMemory is always - 1 (Radeon X600 Pro Win XP SP2)
Flag Dsun.java2d.d3d=true makes no difference

trembovetski
Offline
Joined: 2003-12-31
Points: 0

> AccelaratedMemory is always - 1 (Radeon X600 Pro Win XP SP2)

This is weird. This means that the acceleration has been disabled for some reason.

Could you run your application on Java 6 with J2D_TRACE_LEVEL=4 env. variable set and post the output?

Thanks,
Dmitri

galilei
Offline
Joined: 2006-08-02
Points: 0

SET J2D_TRACE_LEVEL=4 delivers no output,
wheter Mustang nor Java5

normal Dsun.java2d.trace=... shows that OpenGL - pipeline is used instead of d3d (d3d-flag is set true)

Are images accelerated, if bufferstrategy & active rendering & fullscreen are used ? Tested with JDK 1.5 the combination takes only appr. 3 MB VRAM - so 2 fps are not a surprise.

trembovetski
Offline
Joined: 2003-12-31
Points: 0

OK, I'm confused now.

J2D_TRACE_LEVEL=4 will not output anything on 5.0, that's true. But it should (and it does) print some output on 6.0.

Are you sure you're running the latest build of JDK6?

Please verify that the environment variable is set by running "set" command in windows cmd prompt.

So, for example, on my system:
[pre]
M:\re\1.6.0\latest\binaries\windows-i586\demo\jfc\SwingSet2>..\..\..\bin\java -version
java version "1.6.0-rc"
Java(TM) SE Runtime Environment (build 1.6.0-rc-b96)
Java HotSpot(TM) Client VM (build 1.6.0-rc-b96, mixed mode)

M:\re\1.6.0\latest\binaries\windows-i586\demo\jfc\SwingSet2>set J2D_TRACE_LEVEL=4

M:\re\1.6.0\latest\binaries\windows-i586\demo\jfc\SwingSet2>set | grep J2D
J2D_TRACE_LEVEL=4

M:\re\1.6.0\latest\binaries\windows-i586\demo\jfc\SwingSet2>..\..\..\bin\java -jar SwingSet2.jar
[ W] GetFlagValues: DDraw screen locking is disabled (W2K, XP+)
[ I] InitDirectX
[ V] CheckRegistry: Found Display Device 0: SAPPHIRE RADEON 9000 ATLANTIS PRO
[ I] CreateDevice: lpGUID=0xd3c520 hMon=0x10001
[ I] DDSetupDevice
[ I] DDraw::CreateDDPrimarySurface: back-buffers=0
[ V] DDSetupDevice: successfully created primary surface
[ V] DDSetupDevice: successfully setup ddraw device
[/pre]

galilei
Offline
Joined: 2006-08-02
Points: 0

Okay after reinstalling Mustang and ATI driver now it works:

[W] GetFlagValues: DDraw screen locking is disabled (W2K, XP+)
[I] InitDirectX
[V] CheckRegistry: Found Display Device 0: RADEON X1600 Series
[I] CreateDevice: lpGUID=0x3ed070 hMon=0x10001
[I] DDSetupDevice
[I] DDraw::CreateDDPrimarySurface: back-buffers=0
[V] DDSetupDevice: successfully created primary surface
[V] DDSetupDevice: successfully setup ddraw device
\Display0321605568
[I] D3DContext::D3DContext
[V] D3DUtils_SelectDeviceGUID: using TNL rasterizer
[I] D3DContext::CreateD3DDevice
[I] D3DContext::CreateAndTestD3DDevice
[I] D3DContext::InitD3DDevice: d3dDevice=Oxa3780
[V] D3DContext::CreateAndTestD3DDevice: D3D device creation/initialization successful
[W] TestRenderingResults: Quality test failed due to value ff000000 at (34, 0)
[I] CreateD3DDevice: tests PASSED, d3d enabled (forced: yes).

the other problem is still unsolved:
bufferstrategy doesn´t accelerate images rendered on it,
it delivers only 2 fps and some simple images takes 5 minutes to become visible

with JDK 1.5 preloading and only use the inner render do-loop for VolatileImage helps to get 22 fps without quality disadvantages,
with Mustang the trick does not work any more - the main loop counts 22 fps but only 2 are displayed

trembovetski
Offline
Joined: 2003-12-31
Points: 0

Do you get the 2fps performance with those large images you had originally, or with the tiled approach?

The Direct3D pipeline will not be able to accelerate images larger than certain size which depends on particular hardware. Typically they couldn't be larger than 1024x1024,
but could be even less.

Thank you,
Dmitri

galilei
Offline
Joined: 2006-08-02
Points: 0

with Mustang & buffer strategy always 2 fps, image format, size and number of images don´t matter
(tested BMP, JPG, PNG / one big, 128*128 tiles),

free acceleratedMemory stays at 303 MB, even small 32*32 pics takes up to 5 minutes to appear on screen.
if only one smal image is used, Double Buffering in Mustang lasts half a second in the VImg loops / bufferStrategy - method (this doesn´t depend on number & size of the images).

JDK 1.5 with Offscreen-Rendering puts the images after first loading in normal memory, so it provides 22 fps, where it seems to be limited by timer resolution

EDIT:
JDK 1.5 uses 25-30 MB more memory than Mustang,
every image is kept in memory after first loading.
Mustang doesn´t seem to buffer them, neither in memory nor in VRam.

Message was edited by: galilei

trembovetski
Offline
Joined: 2003-12-31
Points: 0

OK, I give up. Could you provide a standalone test?

Dmitri

galilei
Offline
Joined: 2006-08-02
Points: 0

http://www.st-kleist.de/Pfeffersack.exe
the demo jar (button "Demo starten", at the bottom of main view fps counted in loop,
free vram, memory usage)
http://www.st-kleist.de/Bilder.exe
the pictures (have to be in subdirectory "Bilder")
provided as 7Zip-self-extractor

galilei
Offline
Joined: 2006-08-02
Points: 0

well it seem´s to be a vram-acceleration prob:

if FLAG translaccel=true is set on JDK 1.5 there are 2fps, too. (vram 276 MB)
with false 22 fps(vram 303 MB)

on Mustang 2 fps (229 MB, 50 MB more)

is there a flag or something to stop java2d to try to put the image(s) into vram or to check what the pipeline tried to accelerate - but only wastes vram ?

trembovetski
Offline
Joined: 2003-12-31
Points: 0

The -Dsun.java2d.d3d=false is supposed to be this flag, but you're saying that it doesn't help.

Also, when I asked for a sample, I meant a simplified test case, with source code. Would you be able to provide one?

Thanks,
Dmtiri

galilei
Offline
Joined: 2006-08-02
Points: 0

After testing all operations,
i can report now that the bad guy was GradientPaint.
Fill some primitives with it on backbuffer and the frame rate slows down extremely.
drawString, draw... works well, when GradientPaint is used

Message was edited by: galilei