10 Replies Latest reply: Feb 25, 2011 10:00 AM by 834506 RSS

    Slower graphics in JVM 6u23 than 6u03 w/o AGP Texture Acceleration

    834506
      We have two workstations:

      OS: XP SP3
      Video HW: NVIDIA Quaddro cards
      dxdiag: DirectDraw, Direct3D, and AGP Texture Acceleration are enabled, and can be disabled
      JRE: 6u23

      We have a laptop:

      OS: XP SP3
      Video HW: integrated video device
      dxdiag: DirectDraw and Direct3D are enabled, AGP Texture Acceleration is disabled / greyed out
      JRE: 6u23

      It seems obvious that the laptop just doesn't have the hardware capability to handle AGP Texture Acceleration, which is no surprise.

      We notice on the laptop that when we click on a button within our application, and a large panel gets swapped out for a different one, there is a scanning repaint problem. What I mean is that panel A disappears, and panel B appears in its place, painting from left to right ("scanning"), and takes about two to four seconds to fully paint the new panel. The tabs also flicker in a strange way when we mouse over them. This doesn't happen on our workstations.

      On our workstations, if we disable AGP Texture Acceleration within the dxdiag app, the undesired behaviors exhibitted by the laptop do not occur. However, if we disable DirectDraw (and by extension Direct3D / AGP Texture Acceleration), we can see the same behavior on the workstations as we see on the laptop. This also occurs if we use the jvm arg -Dsun.java2d.noddraw=true.

      If we run our application on the laptop with the jvm arg -Dsun.java2d.d3d=false, or =true, the problems remain. If the laptop uses JRE 6u03 instead of 6u23, the problems go away. I haven't tried using the -Dsun.java2d.noddraw jvm arg on the laptop, but I will attempt to do so later today.

      I originally posted this in the Swing forums, thinking that it was more of a Swing related issue, but I believe the real problem is more Java2D related. Any assistance would be greatly appreciated.
        • 1. Re: Slower graphics in JVM 6u23 than 6u03 w/o AGP Texture Acceleration
          834506
          Minor Update:

          -Dsun.java2d.noddraw=true had no effect on the laptop. I thought that it may be a thrashing issue, where some things are being accelerated, while others are not. This does not appear to fix the issue, so I will try other jvm args when I get a chance.

          Edited by: 831503 on Jan 28, 2011 6:26 AM
          • 2. Re: Slower graphics in JVM 6u23 than 6u03 w/o AGP Texture Acceleration
            834506
            More updates:

            -Dsun.java2d.ddforcevram=true had no effect
            -Dsun.java2d.ddblit=false had no effect
            J2D_D3D_RASTERIZER set to ref, rgb, hal, tnl each had no effect
            J2D_D3D_NOALPHATEXTURE set to true had no effect
            • 3. Re: Slower graphics in JVM 6u23 than 6u03 w/o AGP Texture Acceleration
              834506
              I figured out the cause.

              http://www.java-gaming.org/index.php?action=printpage;topic=20404.0

              The JVM checks for Intel GPU hardware, and disables 3d acceleration, even if you use the JVM argument -Dsun.java2d.d3d=true. The laptop uses an Mobil Intel 4 Series Express Chipset. I overrode the hardware check with the environment variable J2D_D3D_NO_HWCHECK=true. This fixed the issue, but it is not recommended for normal use, as it can cause lockups or blue screen errors.

              I now know exactly why this problem was occuring, and we can tell our customers that they either need to get new hardware, or accept that their will be slow painting issues. I may install OpenGL software and try that pipeline, but for now I consider the problem resolved.

              I hope this thread helps someone else in the future.

              Edited by: 831503 on Feb 3, 2011 1:39 PM
              • 4. Re: Slower graphics in JVM 6u23 than 6u03 on Intel graphics hardware
                834506
                After giving this more thought, I don't think the problem is resolved. There still remains the question of why 6u03 on Intel graphics hardware is so much faster than 6u23 on Intel graphics hardware. In fact, it looks like the switch is between 6u07 and 6u10, but I could be wrong. I know that 6u10 enabled hardware acceleration by default, but that shouldn't make it slower on Intel graphics hardware, even if there is a hardcoded check for such hardware which disables the pipeline. That check has been there since 2007, at least (http://www.mail-archive.com/java2d-interest@capra.eng.sun.com/msg04858.html). Why would the newer JVM be slower? Is there another pipeline that 6u03 was using, that 6u23 no longer uses, which I can use on Intel graphics hardware?
                • 5. Re: Slower graphics in JVM 6u23 than 6u03 w/o AGP Texture Acceleration
                  834506
                  I narrowed down the problem a bit. It looks to be an issue with painting a ToolkitImage vs. a BufferedImage. This code returns a ToolkitImage:
                  URL fileURL = this.getClass.getResource(filePath);
                  ImageIcon imageIcon = new ImageIcon(fileURL);
                  Image image = imageIcon.getImage();
                  This code returns a BufferedImage:
                  Image image = ImageIO.read(new File(filePath));
                  Using the latest JRE, 6u23, with hardware acceleration turned off because the JVM doesn't like a Lenovo laptop with integrated Intel graphics hardware, the ToolkitImage takes 400x as long to paint. In fact, it takes 200ms, whereas the BufferedImage takes 0.5ms. This image is being tiled to create a background in my application, so the ToolkitImage is causing significant slowdown.

                  Does anyone know why a ToolkitImage would render so much slower than a BufferedImage on 6u23 without hardware acceleration?
                  • 6. Re: Slower graphics in JVM 6u23 than 6u03 w/o AGP Texture Acceleration
                    800119
                    Voodoo about what's accelerated under the hood and what's not in Java2D can be difficult to predict, as you have noticed. It'll vary from release to release, OS to OS, across hardware, etc.

                    In general, I believe the recommended means of creating a fast Image is creating a "compatible" image; something like this:
                    public Image createImage(String fileName) throws IOException {
                    
                         BufferedImage image = ImageIO.read(createURLFor(fileName));
                         int w = image.getWidth();
                         int h = image.getHeight();
                    
                         GraphicsConfiguration config = comp.getGraphicsConfiguration();
                         BufferedImage bi = config.createCompatibleImage(w, h);
                         Graphics2D g2d = bi.createGraphics();
                         try {
                              g2d.drawImage(image, 0, 0, null);
                         } finally {
                              g2d.dispose();
                         }
                    
                         return bi;
                    
                    }
                    where "comp" is some Component, such as your Canvas or JPanel. If you don't have access to that you can always use GraphicsEnvironment.getLocalGraphicsEnvironment().getDeaultScreenDevice().getDefaultConfiguration().

                    See if using Images created like above offer you a fast, stable framerate.
                    • 7. Re: Slower graphics in JVM 6u23 than 6u03 w/o AGP Texture Acceleration
                      834506
                      Thank you for the information, BoBear. I have question about this technique. The paint method in my application is overloaded, and I have access to the component (tab) I'm drawing the image on. When I create the Graphics2D object from the compatible BufferedImage object, and try to draw my other BufferedImage to it, the image that I'm trying to paint doesn't appear. am I doing this right?
                      public void paint(Graphics g) {
                         Image image = this.getTab().getBackgroundImage(); // Get the image to draw as a background for the tab
                      
                         int tabW = this.getTab().getPreferredSize().getWidth();
                         int tabH = this.getTab().getPreferredSize.getHeight();
                         int imgW = image.getWidth(this); // this is an ImageObserver
                         int imgH = image.getHeight(this);
                      
                         Graphics 2D g2d = this.getTab().getGraphicsConfiguration.createCompatibleImage(imgW, imgH).createGraphics();
                      
                         for (int x = 0; x < width; x += imgW){
                            for (int y = 0; y < height; y += imageH){
                               g2d.drawImage(img, x, y, this);
                            }
                         }
                      }
                      If I draw to the Graphics object g, the execution time of drawImage is problematically high. If I draw to the Graphics2D object g2d, the background image doesn't draw at all. Thank you in advance for your insight.
                      • 8. Re: Slower graphics in JVM 6u23 than 6u03 w/o AGP Texture Acceleration
                        800119
                        Actually, I was envisioning you using the method I gave as a utility method (you could make it static, for example, and shove it anywhere). Don't create images in your paint() override, that will be very slow as you have seen. Rather, use this method to set the returned Image as the image you're using for the background of your tab. Something like this:
                        // In your constructor:
                        this.getTab().setBackgroundImage(Utils.createImage("path/to/background.png"));
                        
                        // ...
                        
                        // Then in your paint override:
                        public void paint(Graphics g) {
                           Image image = this.getTab().getBackgroundImage();
                           int imgW = image.getWidth(this);
                           int imgH = image.getHeight(this);
                           for (int x=0; x<WIDTH; x+=imgW) {
                              for (int y=0; y<HEIGHT; y+=imgH) {
                                 g.drawImage(image, x, y, this);
                              }
                           }
                        }
                        Alternatively, if your tab (or JTabbedPane? not sure of the structure of your code) creates its own image, just have it call the static createImage() method itself when it is created, to set its background image member.
                        • 9. Re: Slower graphics in JVM 6u23 than 6u03 w/o AGP Texture Acceleration
                          834506
                          Thanks for the information, BoBear. It didn't solve my specific problem, but it did help with overall performance of my application. I think I found a solution to my specific problem, though.

                          The person who originally wrote the application used a loop around drawImage, which at the time was fine, but is now very expensive. The tab varies in width from instance to instance, so single-pixel width slices of the background image are drawn onto the tab every time the paint method is called. This means that every time I move the mouse over a tab, it has to draw the background image 100-200 times for each tab. What I did was modify the paint method to check the background image's width against that of the tab, and if they are not the same, I draw the background image slices onto another image which is the same width as the tab, then swap it in as the new background. This means that every time the paint method is called, the expensive drawImage method is called only once instead of 100+ times.
                          • 10. Re: Slower graphics in JVM 6u23 than 6u03 w/o AGP Texture Acceleration
                            834506
                            I have one more update to the tab flickering issue. The tabs are JPanels, not JTabbedPane, and there is a lot of customization to make these behave like tabs. To do so, the original developers wrote code to handle mouseEntered and mouseExited events. Unfortunately, they used this.getTab().getParent().paintAll(), rather than use this.getTab().getParent().repaint(). With older JREs, this was fine. With newer JREs that have 3D acceleration enabled, this causes a flickering effect. So the lesson here is, if the API designers say to do something, like use repaint() instead of calling paint() or paintAll() directly, do what they say.