Windows plugin versions

I’ve been having a lot of trouble with performance of my applet on Windows which seems to be largely related to the version of the plugin I’m running. Is this a known issue? Has anybody else noticed this and found a solution.

My framerate is substantially better using the 1.4.0 version of the plugin than with later versions. In fact my framerate is best using 1.4.0 of both the plugin and the jre, although I have odd stuttering at some points. With the 1.40 plugin and the latest jre both framerate and smoothness seem reasonable. With the 1.4.1 (or 1.4.2) plugin and the 1.4.2 jre everything is smooth but my framerate goes to Hell.

Thanks for any info (or rumors, or theories…)
eli curtz

It really depends on what your applet is doing, what kind of rendering it does.

In 1.4.1 we’ve added acceleration of some primitives through d3d, may be it’s causing some problems.

Try using -Dsun.java2d.d3d=false in the plugin control panel, see if it helps.

Alternatively, it could be a problem with our punting mechanism (search Java2D forum for more info).
Try -Dsun.java2d.ddforcevram=true, see if it helps.

Have you tried profiling the app?

Neither of the plugin switches seems to make a difference. Neither does -Dsun.java2d.noddraw=true. Should it be reporting that DirectDraw has been disabled? (It doesn’t)

I’ve just started profiling in the last few days, but the results aren’t very informative. Most of my top calls are in java.awt.image.DirectColorModel, which hasn’t changed at all between 1.4 and 1.4.2 according to the source with the sdks. I also tried turning on the logging for java2d and came up with a basically identical series of calls in both cases.

My best clue so far is that if I use -Dsun.java2d.noddraw=true on the 1.4.0 version the performance drops to that of 1.4.2. Is it possible the DirectDraw acceleration is off in 1.4.2? How can I tell?

thanks,
eli

Eli,

It does sound like you might be running without ddraw/d3d acceleration on the 1.4.2 version (although I don’t know off-hand why that would be).

One way to get more information on what’s happening inside java2d is to use the tracing utility. This is done by using the command-line flag:
-Dsun.java2d.trace=[log, count, help, out, …]
Play with this in an application (especially getting the “out” option to work, which spits the output into a file that you specify). Then specify the flag in the plugin control panel and see what output you get.

What you want is to use the “count” and “out” flags, which will spit the final primitive count into the output file. You should see things like Win32BlitLoops, Win32DDRenderer, and Win32D3dRenderer. But if you are not using hw acceleration, then you will not see these class names in the output.

Let us know what you find out. Also, let us your your system configuration (especially the OS and graphics card). And a test app would be nice if it gets down to tracking down the problem here.

Chet.
Java2D

I don’t see any differeces in the traces for the different versions I’m trying. Neither 1.4.0, 1.4.0 with the -Dsun.java2d.noddraw=true flag, nor 1.4.2 shows any calls to Win32XXXX, although there are the calls to “Short 565 RGB DirectDraw”. A typical result of the counts trace gives me:

1721 calls to sun.java2d.loops.MaskBlit::MaskBlit(IntArgb, SrcOver, Ushort565Rgb)
972 calls to sun.java2d.loops.DrawGlyphList::DrawGlyphList(OpaqueColor, SrcNoEa, AnyInt)
1721 calls to sun.java2d.loops.Blit$GeneralMaskBlit::Blit(IntArgb, SrcOverNoEa, “Short 565 RGB DirectDraw”)
2 calls to sun.java2d.loops.FillRect::FillRect(OpaqueColor, SrcNoEa, AnyShort)
3 calls to GDIFillRect
1917 calls to sun.java2d.loops.Blit$GeneralMaskBlit::Blit(IntArgb, SrcOverNoEa, IntArgb)
1917 calls to sun.java2d.loops.MaskBlit::MaskBlit(IntArgb, SrcOver, IntArgb)
8253 total calls to 7 different primitives

I managed to get a 98 machine up and running today and it does NOT show this same difference between 1.4.0 and 1.4.2, so it’s looking like an XP issue. We have XP on just about all the machines here, and it has been noticed on every PC I’ve tried, so a variety of video cards and settings.

Obviously I need to get together a test application as our full app is way too much to expect anyone to look at. I’ll do that ASAP and post it somewhere for people to try.

Thanks for all the feedback, I’ll let everyone know when my test app is ready.
eli

Quick question: are you using Nvidia drivers? …
which are famously broken in DirectDraw of late?

Cas :slight_smile:

with noddraw=true it’s expected not to have any DDraw primitives. Have you tried w/o setting noddraw=true?

Since it works fine on w98 and not on XP on the same hw, it does sound like a driver issue.

Many apologies for disappearing on this thread, I had to get caught up on content coding before I could go back to engine tuning.

Here’s some applet code which is a much simplified version of our current rendering scheme and shows better performance on 1.4.0 then on 1.4.2 (at least on Windows XP.)


/* 
 j2dTestApplet.java
*/

package forceandmotion;

import java.awt.*;
import java.awt.event.*;
import java.awt.image.*;
import java.applet.*;

public class j2dTestApplet extends java.applet.Applet {
      Canvas testCanvas = null;
      Image testImage = null;
      Image backImage = null;

      public j2dTestApplet() {
      }

      // Get applet information
      public String getAppletInfo() {
            return "Java 2D Test Applet";
      }

      // Initialize the applet
      public void init() {
        String javaVersion = System.getProperty("java.version");
        
        System.out.println("Java Version = " + javaVersion);
        System.out.println("Java Class Version = " + System.getProperty("java.class.version"));

        System.out.println("Java VM Specification Name = " + System.getProperty("java.vm.specification.name"));
        System.out.println("Java VM Specification Version = " + System.getProperty("java.vm.specification.version"));
        System.out.println("Java VM Version = " + System.getProperty("java.vm.version"));
        System.out.println("OS Name = " + System.getProperty("os.name"));
        System.out.println("OS Version = " + System.getProperty("os.version"));
        System.out.println("");

            setIgnoreRepaint(true);
            
            try {
                  initComponents();
            }
            catch (Exception e) {
                  e.printStackTrace();
            }
      }

      // Initialize the components
      public void initComponents() throws Exception {
            // the following code sets the frame's initial state
            setLayout(null);
            setLocation(new java.awt.Point(0, 0));

            setSize(new java.awt.Dimension(600, 600));
            
            testCanvas = new Canvas();
            this.add("Center", testCanvas);
            testCanvas.setSize(new java.awt.Dimension(600, 600));
            testCanvas.setIgnoreRepaint(true);
            testCanvas.show();
//            testCanvas.createBufferStrategy(2);
            this.show();

            java.net.URL codebase = getCodeBase();
            Image gifImage = getImage(codebase, "duke.gif");
            
        MediaTracker tracker = new MediaTracker(this);
        try {
            tracker.addImage(gifImage, 0);
            tracker.waitForID(0);
            if (tracker.isErrorAny())
                throw new Exception("Couldn't find duke.gif");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        
        int width = gifImage.getWidth(this);
        int height = gifImage.getHeight(this);
        testImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
        backImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
        testImage.getGraphics().drawImage(gifImage, 0, 0, null);
      }

      // Run the applet
      public void start() {
            long startTime = System.currentTimeMillis();
            for (int frame = 0; frame < 5000; frame++)
            {
                  //BufferStrategy strategy = testCanvas.getBufferStrategy();
                  Graphics graphics = testCanvas.getGraphics();//strategy.getDrawGraphics();
                  graphics.fillRect(0,0,300,300);
                  backImage.getGraphics().drawImage(testImage, 0, 0, null);
                  graphics.drawImage(backImage, 0, 0, null);
                  graphics.dispose();
                  //strategy.show();
                  getToolkit().sync();
            }
            long stopTime = System.currentTimeMillis();
            System.out.println("elapsed time for 5,000 frames = " + (stopTime - startTime));
      }
      
      // Don't paint
      public void paint(Graphics g) {
      }
}

The problem appears to be copying OUT of the BufferedImage. If I don’t add the extra step (which we use for compositing all our junk in our own offscreen image) then I see better performance under 1.4.2.

I hope I didn’t lose everybody’s interest. Any insight out there? It seems to resemble the issues that people were reporting with DDraw surfaces, but I have tried using the switch to turn that off…

Thanks in advance,
eli

Aha! I think I have it (a little sample code goes a long way here…)

I got your app running here and I think I know what’s going on. In particular, I know why you’re seeing differences between 1.4.0 and 1.4.2 and between ddraw and noddraw.

it’s all because of the cursor flicker…

From jdk1.2 up through 1.4.0, we used ddraw when we needed to copy bits from some system memory surface (a non-ddraw/VRAM image) to the screen. We would lock the screen, copy the bits, and unlock the screen. This performed better than non-ddraw approaches, but had the side-effect of sometimes causing flashing on the desktop. this got particularly annoying with win2k and XP, where things like translucent fading menus and non-hw cursors (due to translucent drop shadows and color cursors) would flicker when we did our stuff (because they would disappear during the lock and reappear after we unlocked).

In 1.4.1, we found a way around this problem. By using GDI, we would (mostly, except for Matrox; I’ve still seen some cursor flickering artifacts there, but I’ve seen it with many other apps on those boards as well) avoid the flicker. And by cleverly arranging the GDI copy routine, we would be able to retain most of the performance of our ddraw copies as well. I say mostly because it can perform almost as fast as ddraw in some situations, but in others it can be significantly slower (10, 20, 30%, whatever). But we decided to take that hit for these copies because:

  • the flicker was pretty horrid and lots of people were complaining about it
  • with the advent of VolatileImage and other images being cached in VRAM and copied using ddraw blits, the amount of screen-lock situations was hugely decreased.

Your app is running into this issue. I don’t know what numbers you are seeing, but when I ran the app on my desktop system here (XP with a Matrox g550 card), I got about 1800 ms for the vanilla app and about 1400 when I re-enabled ddraw screen locking.

(Note: if you want to make this work on your system, the 2 flags to use are:
-Dsun.java2d.ddlock=true
-Dsun.java2d.gdiblit=false
)

So I believe that this is the performance difference you are seeing between 1.4 and 142.

The other question here is: why aren’t you getting hw-accelerated images? There are a couple of reasons for this:

  1. You are creating ARGB images. This means that unless you enable d3d translucency (as of 141_02 and 142 via the -Dsun.java2d.translaccel flag) you will never see this type of image hw-accelerated. Even though the images only contain bitmask-transparent data (from the duke.gif image), we still see them as fully-translucent images and they fall into our translucent-copy routines.
    If all you want is transparent-background (vs translucent) images, then either use the image you created to begin with (from the duke.gif image) or call GraphicsConfig.createCompatibleImage(w,h,Transparency.BITMASK)
    to get a transparent image. We should be able to cache that image as a ddraw/VRAM image and accelerate it.

  2. Even if you do enable hw acceleration for translucency, you’re still out of luck here. This is because your are copying the images directly to the screen. D3d has this lovely delusion that it owns the screen. so now matter what you tell DirectX about a window, the clip region of the desktop, etc., d3d will blast its bits wherever it wants to. So if we enabled d3d-texture ops to the screen you could, for example, copy your sprites all over any overlapping windows on the desktop. That didn’t seem very professional, so we only enable d3d operations if you tell us to (using the flag) AND if you are copying to an accelerated offscreen image (ala the Swing back buffer). So in this case, you might want to create a VolatileImage back buffer (or use the BufferStrategy buffer) and draw the sprites to that buffer before then copying the buffer to the screen. (Just one more caveat: some translucency operations can cause us to punt an offscreen ddraw surface out of vram and mess up this d3d acceleration scheme; if you enable d3d acceleration, also us the -Dsun.java2d.ddforcevram=true flag to tell us to leave the back buffer in vram no matter what).

Make sense?

Good luck,
Chet.