JDK-4833528 : InternalException, "not yet implemented" thrown with CustomComposite
  • Type: Bug
  • Component: client-libs
  • Sub-Component: 2d
  • Affected Version: 1.4.0,1.4.1,1.4.2
  • Priority: P4
  • Status: Open
  • Resolution: Unresolved
  • OS: windows_nt,windows_xp
  • CPU: x86
  • Submitted: 2003-03-17
  • Updated: 2018-09-05
Description
Name: rmT116609			Date: 03/17/2003


FULL PRODUCT VERSION :
java version "1.4.1_02"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.4.1_02-b06)
Java HotSpot(TM) Client VM (build 1.4.1_02-b06, mixed mode)

FULL OS VERSION :
Microsoft Windows XP [Version 5.1.2600]

EXTRA RELEVANT SYSTEM CONFIGURATION :
ATI Rage Mobility 7200


A DESCRIPTION OF THE PROBLEM :
Exception dump:
java.lang.InternalError: not implemented yet
   at sun.awt.windows.Win32OffScreenSurfaceData.getRaster
   at sun.java2d.pipe.GeneralCompositePipe.renderPathTile
   at sun.java2d.pipe.TextRenderer.drawGlyphList
   at sun.java2d.pipe.GlyphListPipe.drawGlyphVector
   at sun.java2d.SunGraphics2D.drawGlyphVector

Our Code:


STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Run the sample code as java -cp . Test

EXPECTED VERSUS ACTUAL BEHAVIOR :
The string should render without exception.
An exception is thrown, see Error Messages

ERROR MESSAGES/STACK TRACES THAT OCCUR :
Exception dump:
java.lang.InternalError: not implemented yet
   at sun.awt.windows.Win32OffScreenSurfaceData.getRaster
   at sun.java2d.pipe.GeneralCompositePipe.renderPathTile
   at sun.java2d.pipe.TextRenderer.drawGlyphList
   at sun.java2d.pipe.GlyphListPipe.drawGlyphVector
   at sun.java2d.SunGraphics2D.drawGlyphVector


REPRODUCIBILITY :
This bug can be reproduced always.

---------- BEGIN SOURCE ----------
import java.awt.*;
import java.awt.image.*;
import java.awt.font.*;
import java.awt.geom.*;
import javax.swing.*;

public class Test
{
   public static void main(String[] args)
   {
      TestPanel panel = new TestPanel();
      JDialog dialog = new JDialog();
      dialog.getContentPane().add(panel);
      dialog.setSize(400,400);
      dialog.setVisible(true);
   }
}

class TestPanel extends JPanel
{
   /** We override the paint method to handle all painting our selves */
   public void paint(Graphics p_graphics)
   {
      // Convert the passing graphics to the Graphics2D object that is must be
      Graphics2D g = (Graphics2D)p_graphics;
      
      // Get the size we are working with
      Dimension size = getSize();
      
      // Render the page
      g.setComposite(ORComposite.DEFAULT);

      String testString = "Testing String...";
      float x = 20;
      float advance = 0.10f;
      FontRenderContext frc = g.getFontRenderContext();
      Font font = g.getFont();
      char[] c = new char[1];
      for (int i = 0; i < testString.length(); i++)
      {
         c[0] = testString.charAt(i);
         GlyphVector gv = font.createGlyphVector(frc, c);
         g.drawGlyphVector(gv, x, 20);
         x += advance;
      }
   }
}

/** Returns the CompositeContext that will correctly
 * handle summing the source and destination pixels in a way that mirrors ink
 * being put down on a page. The standard composites could not support this
 * behavior since we are not working with semi-transparent color and using
 * the alpha channel was not going to work. */
class ORComposite implements Composite
{ 
   /** Only one of these is, so a static object is creatd. */
   public final static ORComposite DEFAULT = new ORComposite();
   
   /** Create the CompositeContext that will be used. It keeps no state, so
    * we really only need one of them. Since this class is a Singleton, there
    * will only be one instance of CompositContext created as only one
    * Composite is created */
   private final ORCompositeContext m_context = new ORCompositeContext();
   
   /** The class is a singleton, so the constuctor is hidden as a private. */
   private ORComposite()
   {
   }
  
   /** Return the composite the implements the ink paradigm */
   public CompositeContext createContext(ColorModel p_sCM, ColorModel p_dCM,
                                         RenderingHints p_hints)
   {
      return m_context;
   }

   /** Implements the idea of a composite that mirrors putting ink down on a
    * piece of paper. */
   class ORCompositeContext implements CompositeContext
   {
      /** There is state kept, so there is nothing to this function. */
      public void dispose()
      {
      }
  
      /** Do the work of composing the souce and the destination into the
       * output raster.
       * @see java.awt.CompositeContext#compose(Raster, Raster, WritableRaster)
       */
      public void compose(Raster p_srcIn, Raster p_dstIn,
                          WritableRaster p_dstOut)
      {
         // Walk the entire destination
         for (int x=0; x < p_dstOut.getWidth(); x++)
         {
            for (int y = 0; y < p_dstOut.getHeight(); y++)
            {
               //   Get the source pixels
               int[] src = new int[4];
               p_srcIn.getPixel(x, y, src);
            
               int[] dst = new int[4];
               p_dstIn.getPixel(x, y, dst);
             
               // Create a logaction for the result
               int[] result = new int[4];
            
               // OR the pixels together
               // We need to do the ^ 0xFFFFFF to invert the colors since the
               // screen sees 0xFFFFFF as white and 0x000000 as black, but we
               // want to sum up the underlying greyscales and make them
               // darker, as it would work with ink, so everything gets
               // inverted.
               result[0] = (src[0] ^ 0xFFFFFF) | (dst[0] ^ 0xFFFFFF);
               result[0] = result[0] ^ 0xFFFFFF;
               result[1] = (src[1] ^ 0xFFFFFF) | (dst[1] ^ 0xFFFFFF);
               result[1] = result[1] ^ 0xFFFFFF;
               result[2] = (src[2] ^ 0xFFFFFF) | (dst[2] ^ 0xFFFFFF);
               result[2] = result[2] ^ 0xFFFFFF;

               // Set the pixel with the values we have calulated
               p_dstOut.setPixel(x, y, result);
            }
         }
      }
   }
} 

---------- END SOURCE ----------

CUSTOMER SUBMITTED WORKAROUND :
Passing in sun.java2d.noddraw=true flag will work, but this is completely
unacceptabel as a work around since we cannot expect out client base to
be using the Java Control Panel to set this value, and we cannot set the
value from the Object tag used to load the applet.
(Review ID: 182679) 
======================================================================
###@###.### 10/21/04 14:52 GMT

Comments
WORK AROUND Perform custom composite operations on an image buffer instead of the screen. This workaround has several advantages: - The performance will not be hindered by slow readback of screen pixels from most modern accelerated graphics cards. - The correctness of the compositing algorithm will not depend on which mode the screen is in because the image buffer can be created with a known pixel format (by constructing a BufferedImage directly with a specified type). - And lastly, this bug will not be encountered.
11-06-2004

EVALUATION We currently don't have a way for our "SurfaceData" objects to supply the Raster needed for a Java level algorithm to directly modify them. We hope to fix this in the not too distant future, but it is important to note the caveats in the WorkAround field to realize that this bug fix may not be the solution that everyone wants in the long run and that they are better off moving to an offscreen buffer for their custom compositing operations for practical reasons that go beyond simply avoiding this bug. In particular, the supplied test case assumes a given pixel format in its operations and will fail miserably if the screen is in 256 color mode (producing random colors) or is a grayscale display. If the screen is in 16-bit color mode then the accuracy of the results will be less than optimal and will accumulate errors more quickly than operating on a 24 or 32-bit display. These issues can be worked around in the implementation of the custom composite, but such an effort would be a major undertaking to ensure compatibility with the many pixel formats that are possible to specify within our system. Further, the performance of reading the pixels back from the screen for most modern graphics cards is horrible - much worse than most developers might expect. Todays graphics cards are heavily geared towards a "write only" access model for the fastest possible gaming performance. I have little doubt that if we fixed this bug, the first thing that an implementor of a custom composite would do with the fixed runtime would be to switch to an offscreen image for performance reasons unless performance was of very little concern to them. There is even talk of a new breed of cards under development that will not have any capability to read pixels back from the screen. When running on any of those new cards we would actually be prevented from satisfying this request by the hardware we were running on. Given the many positive features of the primary workaround of using an offscreen image to do the custom compositing, we are not assigning a very high priority to fixing this bug and recommending that developers double buffer their custom composite operations. This bug serves more as a reminder that there is a theoretical hole in our implementation than an identification of a practical loss for the developers. ###@###.### 2003-09-15
15-09-2003