| /* |
| * Copyright (c) 2003, 2008, Oracle and/or its affiliates. All rights reserved. |
| * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
| * |
| * This code is free software; you can redistribute it and/or modify it |
| * under the terms of the GNU General Public License version 2 only, as |
| * published by the Free Software Foundation. Oracle designates this |
| * particular file as subject to the "Classpath" exception as provided |
| * by Oracle in the LICENSE file that accompanied this code. |
| * |
| * This code is distributed in the hope that it will be useful, but WITHOUT |
| * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
| * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
| * version 2 for more details (a copy is included in the LICENSE file that |
| * accompanied this code). |
| * |
| * You should have received a copy of the GNU General Public License version |
| * 2 along with this work; if not, write to the Free Software Foundation, |
| * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
| * |
| * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
| * or visit www.oracle.com if you need additional information or have any |
| * questions. |
| */ |
| |
| package sun.awt.image; |
| |
| import java.awt.Color; |
| import java.awt.Graphics; |
| import java.awt.GraphicsConfiguration; |
| import java.awt.GraphicsEnvironment; |
| import java.awt.ImageCapabilities; |
| import java.awt.image.BufferedImage; |
| import java.awt.image.VolatileImage; |
| import sun.awt.DisplayChangedListener; |
| import sun.awt.image.SunVolatileImage; |
| import sun.java2d.SunGraphicsEnvironment; |
| import sun.java2d.SurfaceData; |
| import sun.java2d.loops.CompositeType; |
| import static sun.java2d.pipe.hw.AccelSurface.*; |
| |
| /** |
| * This SurfaceManager variant manages an accelerated volatile surface, if it |
| * is possible to create that surface. If there is limited accelerated |
| * memory, or if the volatile surface disappears due to an operating system |
| * event, the VolatileSurfaceManager will attempt to restore the |
| * accelerated surface. If that fails, a system memory surface will be |
| * created in its place. |
| */ |
| public abstract class VolatileSurfaceManager |
| extends SurfaceManager |
| implements DisplayChangedListener |
| { |
| /** |
| * A reference to the VolatileImage whose contents are being managed. |
| */ |
| protected SunVolatileImage vImg; |
| |
| /** |
| * The accelerated SurfaceData object. |
| */ |
| protected SurfaceData sdAccel; |
| |
| /** |
| * The software-based SurfaceData object. Only create when first asked |
| * to (otherwise it is a waste of memory as it will only be used in |
| * situations of surface loss). |
| */ |
| protected SurfaceData sdBackup; |
| |
| /** |
| * The current SurfaceData object. |
| */ |
| protected SurfaceData sdCurrent; |
| |
| /** |
| * A record-keeping object. This keeps track of which SurfaceData was |
| * in use during the last call to validate(). This lets us see whether |
| * the SurfaceData object has changed since then and allows us to return |
| * the correct returnCode to the user in the validate() call. |
| */ |
| protected SurfaceData sdPrevious; |
| |
| /** |
| * Tracks loss of surface contents; queriable by user to see whether |
| * contents need to be restored. |
| */ |
| protected boolean lostSurface; |
| |
| /** |
| * Context for extra initialization parameters. |
| */ |
| protected Object context; |
| |
| protected VolatileSurfaceManager(SunVolatileImage vImg, Object context) { |
| this.vImg = vImg; |
| this.context = context; |
| |
| GraphicsEnvironment ge = |
| GraphicsEnvironment.getLocalGraphicsEnvironment(); |
| // We could have a HeadlessGE at this point, so double-check before |
| // assuming anything. |
| if (ge instanceof SunGraphicsEnvironment) { |
| ((SunGraphicsEnvironment)ge).addDisplayChangedListener(this); |
| } |
| } |
| |
| /** |
| * This init function is separate from the constructor because the |
| * things we are doing here necessitate the object's existence. |
| * Otherwise, we end up calling into a subclass' overridden method |
| * during construction, before that subclass is completely constructed. |
| */ |
| public void initialize() { |
| if (isAccelerationEnabled()) { |
| sdAccel = initAcceleratedSurface(); |
| if (sdAccel != null) { |
| sdCurrent = sdAccel; |
| } |
| } |
| // only initialize the backup surface for images with unforced |
| // acceleration type |
| if (sdCurrent == null && |
| vImg.getForcedAccelSurfaceType() == UNDEFINED) |
| { |
| sdCurrent = getBackupSurface(); |
| } |
| } |
| |
| public SurfaceData getPrimarySurfaceData() { |
| return sdCurrent; |
| } |
| |
| /** |
| * Returns true if acceleration is enabled. If not, we simply use the |
| * backup SurfaceData object and return quickly from most methods |
| * in this class. |
| */ |
| protected abstract boolean isAccelerationEnabled(); |
| |
| /** |
| * Get the image ready for rendering. This method is called to make |
| * sure that the accelerated SurfaceData exists and is |
| * ready to be used. Users call this method prior to any set of |
| * rendering to or from the image, to make sure the image is ready |
| * and compatible with the given GraphicsConfiguration. |
| * |
| * The image may not be "ready" if either we had problems creating |
| * it in the first place (e.g., there was no space in vram) or if |
| * the surface became lost (e.g., some other app or the OS caused |
| * vram surfaces to be removed). |
| * |
| * Note that we want to return RESTORED in any situation where the |
| * SurfaceData is different than it was last time. So whether it's |
| * software or hardware, if we have a different SurfaceData object, |
| * then the contents have been altered and we must reflect that |
| * change to the user. |
| */ |
| public int validate(GraphicsConfiguration gc) { |
| int returnCode = VolatileImage.IMAGE_OK; |
| boolean lostSurfaceTmp = lostSurface; |
| lostSurface = false; |
| |
| if (isAccelerationEnabled()) { |
| if (!isConfigValid(gc)) { |
| // If we're asked to render to a different device than the |
| // one we were created under, return INCOMPATIBLE error code. |
| // Note that a null gc simply ignores the incompatibility |
| // issue |
| returnCode = VolatileImage.IMAGE_INCOMPATIBLE; |
| } else if (sdAccel == null) { |
| // We either had problems creating the surface or the display |
| // mode changed and we nullified the old one. Try it again. |
| sdAccel = initAcceleratedSurface(); |
| if (sdAccel != null) { |
| // set the current SurfaceData to accelerated version |
| sdCurrent = sdAccel; |
| // we don't need the system memory surface anymore, so |
| // let's release it now (it can always be restored later) |
| sdBackup = null; |
| returnCode = VolatileImage.IMAGE_RESTORED; |
| } else { |
| sdCurrent = getBackupSurface(); |
| } |
| } else if (sdAccel.isSurfaceLost()) { |
| try { |
| restoreAcceleratedSurface(); |
| // set the current SurfaceData to accelerated version |
| sdCurrent = sdAccel; |
| // restoration successful: accel surface no longer lost |
| sdAccel.setSurfaceLost(false); |
| // we don't need the system memory surface anymore, so |
| // let's release it now (it can always be restored later) |
| sdBackup = null; |
| returnCode = VolatileImage.IMAGE_RESTORED; |
| } catch (sun.java2d.InvalidPipeException e) { |
| // Set the current SurfaceData to software version so that |
| // drawing can continue. Note that we still have |
| // the lostAccelSurface flag set so that we will continue |
| // to attempt to restore the accelerated surface. |
| sdCurrent = getBackupSurface(); |
| } |
| } else if (lostSurfaceTmp) { |
| // Something else triggered this loss/restoration. Could |
| // be a palette change that didn't require a SurfaceData |
| // recreation but merely a re-rendering of the pixels. |
| returnCode = VolatileImage.IMAGE_RESTORED; |
| } |
| } else if (sdAccel != null) { |
| // if the "acceleration enabled" state changed to disabled, |
| // switch to software surface |
| sdCurrent = getBackupSurface(); |
| sdAccel = null; |
| returnCode = VolatileImage.IMAGE_RESTORED; |
| } |
| |
| if ((returnCode != VolatileImage.IMAGE_INCOMPATIBLE) && |
| (sdCurrent != sdPrevious)) |
| { |
| // contents have changed - return RESTORED to user |
| sdPrevious = sdCurrent; |
| returnCode = VolatileImage.IMAGE_RESTORED; |
| } |
| |
| if (returnCode == VolatileImage.IMAGE_RESTORED) { |
| // clear the current surface with the background color, |
| // only if the surface has been restored |
| initContents(); |
| } |
| |
| return returnCode; |
| } |
| |
| /** |
| * Returns true if rendering data was lost since the last validate call. |
| * |
| * @see java.awt.image.VolatileImage#contentsLost |
| */ |
| public boolean contentsLost() { |
| return lostSurface; |
| } |
| |
| /** |
| * Creates a new accelerated surface that is compatible with the |
| * current GraphicsConfiguration. Returns the new accelerated |
| * SurfaceData object, or null if the surface creation was not successful. |
| * |
| * Platform-specific subclasses should initialize an accelerated |
| * surface (e.g. a DirectDraw surface on Windows, an OpenGL pbuffer, |
| * or an X11 pixmap). |
| */ |
| protected abstract SurfaceData initAcceleratedSurface(); |
| |
| /** |
| * Creates a software-based surface (of type BufImgSurfaceData). |
| * The software representation is only created when needed, which |
| * is only during some situation in which the hardware surface |
| * cannot be allocated. This allows apps to at least run, |
| * albeit more slowly than they would otherwise. |
| */ |
| protected SurfaceData getBackupSurface() { |
| if (sdBackup == null) { |
| BufferedImage bImg = vImg.getBackupImage(); |
| // Sabotage the acceleration capabilities of the BufImg surface |
| SunWritableRaster.stealTrackable(bImg |
| .getRaster() |
| .getDataBuffer()).setUntrackable(); |
| sdBackup = BufImgSurfaceData.createData(bImg); |
| } |
| return sdBackup; |
| } |
| |
| /** |
| * Set contents of the current SurfaceData to default state (i.e. clear |
| * the background). |
| */ |
| public void initContents() { |
| // images with forced acceleration type may have a null sdCurrent |
| // because we do not create a backup surface for them |
| if (sdCurrent != null) { |
| Graphics g = vImg.createGraphics(); |
| g.clearRect(0, 0, vImg.getWidth(), vImg.getHeight()); |
| g.dispose(); |
| } |
| } |
| |
| /** |
| * Called from a SurfaceData object, indicating that our |
| * accelerated surface has been lost and should be restored (perhaps |
| * using a backup system memory surface). Returns the newly restored |
| * primary SurfaceData object. |
| */ |
| public SurfaceData restoreContents() { |
| return getBackupSurface(); |
| } |
| |
| /** |
| * If the accelerated surface is the current SurfaceData for this manager, |
| * sets the variable lostSurface to true, which indicates that something |
| * happened to the image under management. This variable is used in the |
| * validate method to tell the caller that the surface contents need to |
| * be restored. |
| */ |
| public void acceleratedSurfaceLost() { |
| if (isAccelerationEnabled() && (sdCurrent == sdAccel)) { |
| lostSurface = true; |
| } |
| } |
| |
| /** |
| * Restore sdAccel in case it was lost. Do nothing in this |
| * default case; platform-specific implementations may do more in |
| * this situation as appropriate. |
| */ |
| protected void restoreAcceleratedSurface() { |
| } |
| |
| /** |
| * Called from SunGraphicsEnv when there has been a display mode change. |
| * Note that we simply invalidate hardware surfaces here; we do not |
| * attempt to recreate or re-render them. This is to avoid threading |
| * conflicts with the native toolkit and associated threads. Instead, |
| * we just nullify the old surface data object and wait for a future |
| * method in the rendering process to recreate the surface. |
| */ |
| public void displayChanged() { |
| if (!isAccelerationEnabled()) { |
| return; |
| } |
| lostSurface = true; |
| if (sdAccel != null) { |
| // First, nullify the software surface. This guards against |
| // using a SurfaceData that was created in a different |
| // display mode. |
| sdBackup = null; |
| sdCurrent = getBackupSurface(); |
| // Now, invalidate the old hardware-based SurfaceData |
| SurfaceData oldData = sdAccel; |
| sdAccel = null; |
| oldData.invalidate(); |
| } |
| // Update graphicsConfig for the vImg in case it changed due to |
| // this display change event |
| vImg.updateGraphicsConfig(); |
| } |
| |
| /** |
| * When device palette changes, need to force a new copy |
| * of the image into our hardware cache to update the |
| * color indices of the pixels (indexed mode only). |
| */ |
| public void paletteChanged() { |
| lostSurface = true; |
| } |
| |
| /** |
| * Called by validate() to see whether the GC passed in is ok for |
| * rendering to. This generic implementation checks to see |
| * whether the GC is either null or is from the same |
| * device as the one that this image was created on. Platform- |
| * specific implementations may perform other checks as |
| * appropriate. |
| */ |
| protected boolean isConfigValid(GraphicsConfiguration gc) { |
| return ((gc == null) || |
| (gc.getDevice() == vImg.getGraphicsConfig().getDevice())); |
| } |
| |
| @Override |
| public ImageCapabilities getCapabilities(GraphicsConfiguration gc) { |
| if (isConfigValid(gc)) { |
| return isAccelerationEnabled() ? |
| new AcceleratedImageCapabilities() : |
| new ImageCapabilities(false); |
| } |
| return super.getCapabilities(gc); |
| } |
| |
| private class AcceleratedImageCapabilities |
| extends ImageCapabilities |
| { |
| AcceleratedImageCapabilities() { |
| super(false); |
| } |
| @Override |
| public boolean isAccelerated() { |
| return (sdCurrent == sdAccel); |
| } |
| @Override |
| public boolean isTrueVolatile() { |
| return isAccelerated(); |
| } |
| } |
| |
| /** |
| * Releases any associated hardware memory for this image by |
| * calling flush on sdAccel. This method forces a lostSurface |
| * situation so any future operations on the image will need to |
| * revalidate the image first. |
| */ |
| public void flush() { |
| lostSurface = true; |
| SurfaceData oldSD = sdAccel; |
| sdAccel = null; |
| if (oldSD != null) { |
| oldSD.flush(); |
| } |
| } |
| } |