001: /*
002: * Copyright 2003-2007 Sun Microsystems, Inc. All Rights Reserved.
003: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
004: *
005: * This code is free software; you can redistribute it and/or modify it
006: * under the terms of the GNU General Public License version 2 only, as
007: * published by the Free Software Foundation. Sun designates this
008: * particular file as subject to the "Classpath" exception as provided
009: * by Sun in the LICENSE file that accompanied this code.
010: *
011: * This code is distributed in the hope that it will be useful, but WITHOUT
012: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
013: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
014: * version 2 for more details (a copy is included in the LICENSE file that
015: * accompanied this code).
016: *
017: * You should have received a copy of the GNU General Public License version
018: * 2 along with this work; if not, write to the Free Software Foundation,
019: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
020: *
021: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
022: * CA 95054 USA or visit www.sun.com if you need additional information or
023: * have any questions.
024: */
025:
026: package sun.awt.image;
027:
028: import java.awt.Color;
029: import java.awt.Graphics;
030: import java.awt.GraphicsConfiguration;
031: import java.awt.GraphicsEnvironment;
032: import java.awt.ImageCapabilities;
033: import java.awt.image.BufferedImage;
034: import java.awt.image.VolatileImage;
035: import sun.awt.DisplayChangedListener;
036: import sun.awt.image.SunVolatileImage;
037: import sun.java2d.SunGraphicsEnvironment;
038: import sun.java2d.SurfaceData;
039: import sun.java2d.loops.CompositeType;
040:
041: /**
042: * This SurfaceManager variant manages an accelerated volatile surface, if it
043: * is possible to create that surface. If there is limited accelerated
044: * memory, or if the volatile surface disappears due to an operating system
045: * event, the VolatileSurfaceManager will attempt to restore the
046: * accelerated surface. If that fails, a system memory surface will be
047: * created in its place.
048: */
049: public abstract class VolatileSurfaceManager extends SurfaceManager
050: implements DisplayChangedListener {
051: /**
052: * A reference to the VolatileImage whose contents are being managed.
053: */
054: protected SunVolatileImage vImg;
055:
056: /**
057: * The accelerated SurfaceData object.
058: */
059: protected SurfaceData sdAccel;
060:
061: /**
062: * The software-based SurfaceData object. Only create when first asked
063: * to (otherwise it is a waste of memory as it will only be used in
064: * situations of surface loss).
065: */
066: protected SurfaceData sdBackup;
067:
068: /**
069: * The current SurfaceData object.
070: */
071: protected SurfaceData sdCurrent;
072:
073: /**
074: * A record-keeping object. This keeps track of which SurfaceData was
075: * in use during the last call to validate(). This lets us see whether
076: * the SurfaceData object has changed since then and allows us to return
077: * the correct returnCode to the user in the validate() call.
078: */
079: protected SurfaceData sdPrevious;
080:
081: /**
082: * Tracks loss of surface contents; queriable by user to see whether
083: * contents need to be restored.
084: */
085: protected boolean lostSurface;
086:
087: /**
088: * Context for extra initialization parameters.
089: */
090: protected Object context;
091:
092: protected VolatileSurfaceManager(SunVolatileImage vImg,
093: Object context) {
094: this .vImg = vImg;
095: this .context = context;
096:
097: GraphicsEnvironment ge = GraphicsEnvironment
098: .getLocalGraphicsEnvironment();
099: // We could have a HeadlessGE at this point, so double-check before
100: // assuming anything.
101: if (ge instanceof SunGraphicsEnvironment) {
102: ((SunGraphicsEnvironment) ge)
103: .addDisplayChangedListener(this );
104: }
105: }
106:
107: /**
108: * This init function is separate from the constructor because the
109: * things we are doing here necessitate the object's existence.
110: * Otherwise, we end up calling into a subclass' overridden method
111: * during construction, before that subclass is completely constructed.
112: */
113: public void initialize() {
114: if (isAccelerationEnabled()) {
115: sdAccel = initAcceleratedSurface();
116: if (sdAccel != null) {
117: sdCurrent = sdAccel;
118: }
119: }
120: if (sdCurrent == null) {
121: sdCurrent = getBackupSurface();
122: }
123: }
124:
125: public SurfaceData getPrimarySurfaceData() {
126: return sdCurrent;
127: }
128:
129: /**
130: * Returns true if acceleration is enabled. If not, we simply use the
131: * backup SurfaceData object and return quickly from most methods
132: * in this class.
133: */
134: protected abstract boolean isAccelerationEnabled();
135:
136: /**
137: * Get the image ready for rendering. This method is called to make
138: * sure that the accelerated SurfaceData exists and is
139: * ready to be used. Users call this method prior to any set of
140: * rendering to or from the image, to make sure the image is ready
141: * and compatible with the given GraphicsConfiguration.
142: *
143: * The image may not be "ready" if either we had problems creating
144: * it in the first place (e.g., there was no space in vram) or if
145: * the surface became lost (e.g., some other app or the OS caused
146: * vram surfaces to be removed).
147: *
148: * Note that we want to return RESTORED in any situation where the
149: * SurfaceData is different than it was last time. So whether it's
150: * software or hardware, if we have a different SurfaceData object,
151: * then the contents have been altered and we must reflect that
152: * change to the user.
153: */
154: public int validate(GraphicsConfiguration gc) {
155: int returnCode = VolatileImage.IMAGE_OK;
156: boolean lostSurfaceTmp = lostSurface;
157: lostSurface = false;
158:
159: if (isAccelerationEnabled()) {
160: if (!isConfigValid(gc)) {
161: // If we're asked to render to a different device than the
162: // one we were created under, return INCOMPATIBLE error code.
163: // Note that a null gc simply ignores the incompatibility
164: // issue
165: returnCode = VolatileImage.IMAGE_INCOMPATIBLE;
166: } else if (sdAccel == null) {
167: // We either had problems creating the surface or the display
168: // mode changed and we nullified the old one. Try it again.
169: sdAccel = initAcceleratedSurface();
170: if (sdAccel != null) {
171: // set the current SurfaceData to accelerated version
172: sdCurrent = sdAccel;
173: // we don't need the system memory surface anymore, so
174: // let's release it now (it can always be restored later)
175: sdBackup = null;
176: returnCode = VolatileImage.IMAGE_RESTORED;
177: } else {
178: sdCurrent = getBackupSurface();
179: }
180: } else if (sdAccel.isSurfaceLost()) {
181: try {
182: restoreAcceleratedSurface();
183: // set the current SurfaceData to accelerated version
184: sdCurrent = sdAccel;
185: // restoration successful: accel surface no longer lost
186: sdAccel.setSurfaceLost(false);
187: // we don't need the system memory surface anymore, so
188: // let's release it now (it can always be restored later)
189: sdBackup = null;
190: returnCode = VolatileImage.IMAGE_RESTORED;
191: } catch (sun.java2d.InvalidPipeException e) {
192: // Set the current SurfaceData to software version so that
193: // drawing can continue. Note that we still have
194: // the lostAccelSurface flag set so that we will continue
195: // to attempt to restore the accelerated surface.
196: sdCurrent = getBackupSurface();
197: }
198: } else if (lostSurfaceTmp) {
199: // Something else triggered this loss/restoration. Could
200: // be a palette change that didn't require a SurfaceData
201: // recreation but merely a re-rendering of the pixels.
202: returnCode = VolatileImage.IMAGE_RESTORED;
203: }
204: } else if (sdAccel != null) {
205: // if the "acceleration enabled" state changed to disabled,
206: // switch to software surface
207: sdCurrent = getBackupSurface();
208: sdAccel = null;
209: returnCode = VolatileImage.IMAGE_RESTORED;
210: }
211:
212: if ((returnCode != VolatileImage.IMAGE_INCOMPATIBLE)
213: && (sdCurrent != sdPrevious)) {
214: // contents have changed - return RESTORED to user
215: sdPrevious = sdCurrent;
216: returnCode = VolatileImage.IMAGE_RESTORED;
217: }
218:
219: if (returnCode == VolatileImage.IMAGE_RESTORED) {
220: // clear the current surface with the background color,
221: // only if the surface has been restored
222: initContents();
223: }
224:
225: return returnCode;
226: }
227:
228: /**
229: * Returns true if rendering data was lost since the last validate call.
230: *
231: * @see java.awt.image.VolatileImage#contentsLost
232: */
233: public boolean contentsLost() {
234: return lostSurface;
235: }
236:
237: /**
238: * Creates a new accelerated surface that is compatible with the
239: * current GraphicsConfiguration. Returns the new accelerated
240: * SurfaceData object, or null if the surface creation was not successful.
241: *
242: * Platform-specific subclasses should initialize an accelerated
243: * surface (e.g. a DirectDraw surface on Windows, an OpenGL pbuffer,
244: * or an X11 pixmap).
245: */
246: protected abstract SurfaceData initAcceleratedSurface();
247:
248: /**
249: * Creates a software-based surface (of type BufImgSurfaceData).
250: * The software representation is only created when needed, which
251: * is only during some situation in which the hardware surface
252: * cannot be allocated. This allows apps to at least run,
253: * albeit more slowly than they would otherwise.
254: */
255: protected SurfaceData getBackupSurface() {
256: if (sdBackup == null) {
257: BufferedImage bImg = vImg.getBackupImage();
258: // Sabotage the acceleration capabilities of the BufImg surface
259: SunWritableRaster.stealTrackable(
260: bImg.getRaster().getDataBuffer()).setUntrackable();
261: sdBackup = BufImgSurfaceData.createData(bImg);
262: }
263: return sdBackup;
264: }
265:
266: /**
267: * Set contents of the current SurfaceData to default state (i.e. clear
268: * the background).
269: */
270: public void initContents() {
271: Graphics g = vImg.createGraphics();
272: g.clearRect(0, 0, vImg.getWidth(), vImg.getHeight());
273: g.dispose();
274: }
275:
276: /**
277: * Called from a SurfaceData object, indicating that our
278: * accelerated surface has been lost and should be restored (perhaps
279: * using a backup system memory surface). Returns the newly restored
280: * primary SurfaceData object.
281: */
282: public SurfaceData restoreContents() {
283: return getBackupSurface();
284: }
285:
286: /**
287: * If the accelerated surface is the current SurfaceData for this manager,
288: * sets the variable lostSurface to true, which indicates that something
289: * happened to the image under management. This variable is used in the
290: * validate method to tell the caller that the surface contents need to
291: * be restored.
292: */
293: public void acceleratedSurfaceLost() {
294: if (isAccelerationEnabled() && (sdCurrent == sdAccel)) {
295: lostSurface = true;
296: }
297: }
298:
299: /**
300: * Restore sdAccel in case it was lost. Do nothing in this
301: * default case; platform-specific implementations may do more in
302: * this situation as appropriate.
303: */
304: protected void restoreAcceleratedSurface() {
305: }
306:
307: /**
308: * Called from SunGraphicsEnv when there has been a display mode change.
309: * Note that we simply invalidate hardware surfaces here; we do not
310: * attempt to recreate or re-render them. This is to avoid threading
311: * conflicts with the native toolkit and associated threads. Instead,
312: * we just nullify the old surface data object and wait for a future
313: * method in the rendering process to recreate the surface.
314: */
315: public void displayChanged() {
316: if (!isAccelerationEnabled()) {
317: return;
318: }
319: lostSurface = true;
320: if (sdAccel != null) {
321: // First, nullify the software surface. This guards against
322: // using a SurfaceData that was created in a different
323: // display mode.
324: sdBackup = null;
325: sdCurrent = getBackupSurface();
326: // Now, invalidate the old hardware-based SurfaceData
327: SurfaceData oldData = sdAccel;
328: sdAccel = null;
329: oldData.invalidate();
330: }
331: // Update graphicsConfig for the vImg in case it changed due to
332: // this display change event
333: vImg.updateGraphicsConfig();
334: }
335:
336: /**
337: * When device palette changes, need to force a new copy
338: * of the image into our hardware cache to update the
339: * color indices of the pixels (indexed mode only).
340: */
341: public void paletteChanged() {
342: lostSurface = true;
343: }
344:
345: /**
346: * Called by validate() to see whether the GC passed in is ok for
347: * rendering to. This generic implementation checks to see
348: * whether the GC is either null or is from the same
349: * device as the one that this image was created on. Platform-
350: * specific implementations may perform other checks as
351: * appropriate.
352: */
353: protected boolean isConfigValid(GraphicsConfiguration gc) {
354: return ((gc == null) || (gc.getDevice() == vImg
355: .getGraphicsConfig().getDevice()));
356: }
357:
358: @Override
359: public ImageCapabilities getCapabilities(GraphicsConfiguration gc) {
360: if (isConfigValid(gc)) {
361: return isAccelerationEnabled() ? new AcceleratedImageCapabilities()
362: : new ImageCapabilities(false);
363: }
364: return super .getCapabilities(gc);
365: }
366:
367: private class AcceleratedImageCapabilities extends
368: ImageCapabilities {
369: AcceleratedImageCapabilities() {
370: super (false);
371: }
372:
373: @Override
374: public boolean isAccelerated() {
375: return (sdCurrent == sdAccel);
376: }
377:
378: @Override
379: public boolean isTrueVolatile() {
380: return isAccelerated();
381: }
382: }
383:
384: /**
385: * Releases any associated hardware memory for this image by
386: * calling flush on sdAccel. This method forces a lostSurface
387: * situation so any future operations on the image will need to
388: * revalidate the image first.
389: */
390: public void flush() {
391: lostSurface = true;
392: SurfaceData oldSD = sdAccel;
393: sdAccel = null;
394: if (oldSD != null) {
395: oldSD.flush();
396: }
397: }
398: }
|