409 lines · 15.3 KB · Java
RawDownload
/* * 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();        }    }}