Hi Jessica, we found this problem too and it’s very very disappointing. A real world desktop application on JDK 7 or 8 on a Mac doesn’t perform well - it’s tooo slow and we can’t ship our software with JDK 7 or 8 using BufferedImages. In our opinion JDK7/8 is not ready to release on Mac! But it is released! So why I can’t find thousand of bug reports concerning „BufferedImages on JDK7/8 on Mac are not hardware accelerated“????
Jessica, did you find any solution for the problem? Maybe there is a property to enable the VolatileImage backed BufferedImage? Best, Tobi Am 24.06.2013 um 20:09 schrieb Jessica Finley <jfin...@tech4learning.com>: > Hiya folks, > > I've run into a couple of problems with OpenJDK on Mac. Firstly, and what > started me down this path, is the performance of rendering BufferedImages > seems to have really tanked. It's as if they are not supported by hardware > anymore (from vague references I've seen around the web, I understand that > BufferedImages are supposed to be hardware accelerated.. and based on the > performance on Windows (java 7) and Mac Java 6, I can believe that). In > OpenJDK 7 and 8, rendering lots of BufferedImages causes performance to truly > and horribly suffer on certain Macs (the Macs with the low end graphics cards > really seem to show this, but it's noticeable on all Macs I've tested on). > > In an effort to speed up our software, I started using VolatileImages instead > of BufferedImages in certain places and it has brought performance up to > awesome. However, I noticed the problem that I describe in Sun Bug Id: > 9004409. When I paint VolatileImage.getSnapshot() to either the screen > graphics or to a BufferedImage, the transparent pixels are rendered > incorrectly - they have black values instead of transparent values, as if the > transparent pixels were first rendered over a solid black background and then > the result is what is copied out to the BufferedImage. > > Now, if I render the VolatileImage directly to the screen graphics, I don't > see the problem, but any way I can figure out how to render the VolatileImage > to or as a BufferedImage results in incorrect transparent pixels. > > Below is a sample program that demonstrates the problem and compares it to > BufferedImages which always render correctly. > > This problem only occurs on Mac Java 7 and 8… all works as expected on > Windows Java 7 and Mac Java 6. > > Any thoughts on this? Is there a work around anyone knows of? Also, am I > correct in my conjecture that BufferedImages are supposed to be hardware > accelerated, but they are not in OpenJDK? > > Thanks for your time, > Jess > > ---------------------------------------- > > import java.awt.AlphaComposite; > import java.awt.BorderLayout; > import java.awt.Color; > import java.awt.Dimension; > import java.awt.Graphics2D; > import java.awt.GraphicsConfiguration; > import java.awt.GraphicsEnvironment; > import java.awt.GridBagConstraints; > import java.awt.GridBagLayout; > import java.awt.Insets; > import java.awt.Transparency; > import java.awt.event.ActionEvent; > import java.awt.event.ActionListener; > import java.awt.image.BufferedImage; > import java.awt.image.VolatileImage; > > import javax.swing.JButton; > import javax.swing.JFrame; > import javax.swing.JLabel; > import javax.swing.JPanel; > import javax.swing.SwingUtilities; > > /** > * Shows the difference between the painting of a translucent BufferedImage > and a translucent > * VolatileImage. > * > * > * On Java 6, this works fine. On Java 7, the VolatileImages are not painted > correctly, when painted > * onto a BufferedImage prior to being painted to screen graphics. > * > * @author jfinley > * > */ > public class PaintTest { > > public PaintTest() { > > JPanel bufferedImagePanel = new JPanel() { > protected void paintComponent(java.awt.Graphics g) { > super.paintComponent(g); > BufferedImage image = getBufferedImage(); > g.drawImage(image, 0, 0, null); > }; > }; > > JPanel bufferedImagePanel2 = new JPanel() { > protected void paintComponent(java.awt.Graphics g) { > super.paintComponent(g); > BufferedImage bImage = getBufferedImage(); > > BufferedImage image = new BufferedImage(100, > 100, BufferedImage.TYPE_INT_ARGB); > Graphics2D g2 = image.createGraphics(); > > //not really necessary, but in there for > completeness > g2.setComposite(AlphaComposite.Clear); > g2.setColor(new Color(255, 255, 255, 0)); > g2.fillRect(0,0, image.getWidth(), > image.getHeight()); > > g2.setComposite(AlphaComposite.SrcOver); > g2.drawImage(bImage, 0, 0, null); > g2.dispose(); > > g.drawImage(image, 0, 0, null); > }; > }; > > JPanel volatileImagePanel = new JPanel() { > protected void paintComponent(java.awt.Graphics g) { > super.paintComponent(g); > VolatileImage vImage = getVolatileImage(); > > /** > * If we draw the VolatileImage directly to g, > it works fine... but > * if we draw VolatileImage.getSnapshot(), or > otherwise convert the VolatileImage > * to a buffered image, we get the black halo > funk of death. > */ > g.drawImage(vImage, 0, 0, null); //works > //g.drawImage(vImage.getSnapshot(), 0, 0, > null); //black halo funk of death > }; > }; > > JPanel volatileImagePanel2 = new JPanel() { > protected void paintComponent(java.awt.Graphics g) { > super.paintComponent(g); > VolatileImage vImage = getVolatileImage(); > > /** > * If we draw the VolatileImage directly to g, > it works fine... but > * if we draw VolatileImage.getSnapshot(), or > otherwise convert the VolatileImage > * to a buffered image, we get the black halo > funk of death. > */ > //g.drawImage(vImage, 0, 0, null); //works > g.drawImage(vImage.getSnapshot(), 0, 0, null); > //black halo funk of death > }; > }; > > JPanel volatileImagePanel3 = new JPanel() { > protected void paintComponent(java.awt.Graphics g) { > super.paintComponent(g); > VolatileImage vImage = getVolatileImage(); > > /** > * If we draw the VolatileImage directly to g, > it works fine... but > * if we draw VolatileImage.getSnapshot(), or > otherwise convert the VolatileImage > * to a buffered image, we get the black halo > funk of death. > */ > //g.drawImage(vImage, 0, 0, null); //works > //g.drawImage(vImage.getSnapshot(), 0, 0, > null); //black halo funk of death > > BufferedImage image = new BufferedImage(100, > 100, BufferedImage.TYPE_INT_ARGB); > Graphics2D g2 = image.createGraphics(); > > //not really necessary, but in there for > completeness > g2.setComposite(AlphaComposite.Clear); > g2.setColor(new Color(255, 255, 255, 0)); > g2.fillRect(0,0, image.getWidth(), > image.getHeight()); > > g2.setComposite(AlphaComposite.SrcOver); > g2.drawImage(vImage, 0, 0, null); > g2.dispose(); > > g.drawImage(image, 0, 0, null); > }; > }; > > final JPanel mainPanel = new JPanel(new GridBagLayout()); > GridBagConstraints gbc = new GridBagConstraints(0, 1, 1, 1, 0, > 0, > GridBagConstraints.CENTER, > GridBagConstraints.BOTH, new Insets(0, 0, 0, 0), 0, 0); > > mainPanel.add(new JLabel("Direct to g"), gbc); > gbc.gridy++; > mainPanel.add(new JLabel("BufferImage Proxy"), gbc); > gbc.gridy++; > mainPanel.add(new JLabel("BufferImage Proxy 2"), gbc); > > gbc.gridx = 1; gbc.gridy = 0; > mainPanel.add(new JLabel("BufferedImages"), gbc); > gbc.gridx++; > mainPanel.add(new JLabel("VolatileImages"), gbc); > > gbc.gridx = 1; gbc.gridy = 1; gbc.weightx = 1; gbc.weighty = 1; > mainPanel.add(bufferedImagePanel, gbc); > gbc.gridy++; > mainPanel.add(bufferedImagePanel2, gbc); > gbc.gridx = 2; gbc.gridy = 1; > mainPanel.add(volatileImagePanel, gbc); > gbc.gridy++; > mainPanel.add(volatileImagePanel2, gbc); > gbc.gridy++; > mainPanel.add(volatileImagePanel3, gbc); > > > JButton repaintButton = new JButton("Repaint"); > repaintButton.addActionListener(new ActionListener(){ > public void actionPerformed(ActionEvent e) { > mainPanel.repaint(); > } > }); > > gbc.gridx = 1; gbc.gridy++; gbc.gridwidth = 2; gbc.weighty = 0; > mainPanel.add(repaintButton, gbc); > > > JFrame mainFrame = new JFrame("O.M.G."); > mainFrame.getContentPane().setLayout(new BorderLayout()); > mainFrame.getContentPane().add(mainPanel, BorderLayout.CENTER); > mainFrame.setPreferredSize(new Dimension(400, 400)); > mainFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); > mainFrame.pack(); > mainFrame.setVisible(true); > > } > > private BufferedImage getBufferedImage() { > BufferedImage image = new BufferedImage(100, 100, > BufferedImage.TRANSLUCENT); > Graphics2D g = image.createGraphics(); > > //not really necessary, in here for completeness > g.setComposite(AlphaComposite.Clear); > g.setColor(new Color(255, 255, 255, 0)); > g.fillRect(0,0, image.getWidth(), image.getHeight()); > > g.setComposite(AlphaComposite.SrcOver); > g.setColor(new Color(255, 0, 0, 128)); > g.fillRect(10, 10, image.getWidth()-20, image.getHeight()-20); > > g.dispose(); > return image; > } > > private VolatileImage getVolatileImage() { > GraphicsConfiguration gc = > GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice().getDefaultConfiguration(); > VolatileImage vImage = gc.createCompatibleVolatileImage(100, > 100, Transparency.TRANSLUCENT); > Graphics2D g = vImage.createGraphics(); > > //necessary, as VolatileImages start out filled opaque white > g.setComposite(AlphaComposite.Clear); > g.setColor(new Color(255, 255, 255, 0)); > g.fillRect(0,0, vImage.getWidth(), vImage.getHeight()); > > g.setComposite(AlphaComposite.SrcOver); > g.setColor(new Color(255, 0, 0, 128)); > g.fillRect(10, 10, vImage.getWidth()-20, vImage.getHeight()-20); > > g.dispose(); > return vImage; > } > > public static void main(String[] args) { > SwingUtilities.invokeLater(new Runnable(){ > public void run() { > new PaintTest(); > } > }); > } > }