001: /*
002: * Copyright 2005-2006 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.java2d.d3d;
027:
028: import java.awt.AlphaComposite;
029: import java.awt.Composite;
030: import java.awt.GraphicsEnvironment;
031: import java.awt.geom.AffineTransform;
032: import sun.awt.Win32GraphicsDevice;
033: import sun.java2d.InvalidPipeException;
034: import sun.java2d.SurfaceData;
035: import sun.java2d.pipe.Region;
036: import sun.java2d.windows.WindowsFlags;
037:
038: public class D3DContext {
039:
040: public static final int NO_CONTEXT_FLAGS = 0;
041: /**
042: * Used in D3DBlitLoops: if the source surface is opaque
043: * alpha blending can be turned off on the native level
044: * (if there's no ea), thus improving performance.
045: */
046: public static final int SRC_IS_OPAQUE = 1;
047:
048: /**
049: * This is a list of capabilities supported by the device this
050: * context is associated with.
051: * @see getDeviceCaps
052: */
053: public static final int J2D_D3D_FAILURE = (0 << 0);
054: /**
055: * Device supports depth buffer for d3d render targets
056: */
057: public static final int J2D_D3D_DEPTH_SURFACE_OK = (1 << 0);
058: /**
059: * Device supports creation of plain d3d surfaces
060: */
061: public static final int J2D_D3D_PLAIN_SURFACE_OK = (1 << 1);
062: /**
063: * Device supports creation of opaque textures
064: */
065: public static final int J2D_D3D_OP_TEXTURE_SURFACE_OK = (1 << 2);
066: /**
067: * Device supports creation of bitmask textures
068: */
069: public static final int J2D_D3D_BM_TEXTURE_SURFACE_OK = (1 << 3);
070: /**
071: * Device supports creation of translucent textures
072: */
073: public static final int J2D_D3D_TR_TEXTURE_SURFACE_OK = (1 << 4);
074: /**
075: * Device supports creation of opaque render-to-textures
076: */
077: public static final int J2D_D3D_OP_RTT_SURFACE_OK = (1 << 5);
078: /**
079: * Device can render lines correctly (no pixelization issues)
080: */
081: public static final int J2D_D3D_LINES_OK = (1 << 6);
082: /**
083: * Device supports texture mapping (no pixelization issues)
084: */
085: public static final int J2D_D3D_TEXTURE_BLIT_OK = (1 << 7);
086: /**
087: * Device supports texture mapping with transforms (no pixelization issues)
088: */
089: public static final int J2D_D3D_TEXTURE_TRANSFORM_OK = (1 << 8);
090: /**
091: * Device can render clipped lines correctly.
092: */
093: public static final int J2D_D3D_LINE_CLIPPING_OK = (1 << 9);
094: /**
095: * Device has all hw capabilities the d3d pipeline requires
096: */
097: public static final int J2D_D3D_DEVICE_OK = (1 << 10);
098: /**
099: * Device supports all necessary texture formats required by d3d pipeline
100: */
101: public static final int J2D_D3D_PIXEL_FORMATS_OK = (1 << 11);
102: /**
103: * Device supports geometry transformations
104: */
105: public static final int J2D_D3D_SET_TRANSFORM_OK = (1 << 12);
106: /**
107: * The device is not from a list of known bad devices
108: * (see D3DRuntimeTest.cpp)
109: */
110: public static final int J2D_D3D_HW_OK = (1 << 13);
111: /**
112: * Direct3D pipeline is enabled on this device
113: */
114: public static final int J2D_D3D_ENABLED_OK = (1 << 14);
115:
116: /**
117: * The lock object used to synchronize access to the native windowing
118: * system layer. Note that rendering methods should always synchronize on
119: * D3DContext.LOCK before calling the D3DContext.getContext() method,
120: * or any other method that invokes native D3d commands.
121: * REMIND: in D3D case we should really be synchronizing on per-device
122: * basis.
123: */
124: static Object LOCK;
125:
126: private Win32GraphicsDevice gd;
127: private boolean valid;
128:
129: protected long nativeContext;
130: private SurfaceData validatedDstData;
131: private Region validatedClip;
132: private Composite validatedComp;
133: private int validatedPixel;
134: private int validatedFlags;
135: private boolean xformInUse;
136: // validated transform's data
137: private double vScaleX, vScaleY, vShearX, vShearY, vTransX,
138: vTransY;
139:
140: private int deviceCaps;
141:
142: private native void setRenderTarget(long pCtx, long pDst);
143:
144: private native void setClip(long pCtx, long pDst, Region clip,
145: boolean isRect, int x1, int y1, int x2, int y2);
146:
147: private native void resetClip(long pCtx, long pDst);
148:
149: private native void resetComposite(long pCtx);
150:
151: private native void setAlphaComposite(long pCtx, int rule,
152: float extraAlpha, int flags);
153:
154: private native void setTransform(long pCtx, long pDst,
155: AffineTransform xform, double m00, double m10, double m01,
156: double m11, double m02, double m12);
157:
158: private native void resetTransform(long pCtx, long pDst);
159:
160: private native void setColor(long pCtx, int pixel, int flags);
161:
162: private native long initNativeContext(int screen);
163:
164: private native int getNativeDeviceCaps(long pCtx);
165:
166: static {
167: if (!GraphicsEnvironment.isHeadless()) {
168: LOCK = D3DContext.class;
169: }
170: }
171:
172: public D3DContext(Win32GraphicsDevice gd) {
173: this .gd = gd;
174: reinitNativeContext();
175: }
176:
177: /**
178: * Reinitializes the context by retrieving a pointer to the native
179: * D3DContext object, and resetting the device caps.
180: */
181: void reinitNativeContext() {
182: nativeContext = initNativeContext(gd.getScreen());
183: deviceCaps = nativeContext != 0L ? getNativeDeviceCaps(nativeContext)
184: : J2D_D3D_FAILURE;
185: valid = ((deviceCaps & J2D_D3D_ENABLED_OK) != 0);
186: if (WindowsFlags.isD3DVerbose()) {
187: if (valid) {
188: System.out
189: .println("Direct3D pipeline enabled on screen "
190: + gd.getScreen());
191: } else {
192: System.out
193: .println("Could not enable Direct3D pipeline on "
194: + "screen "
195: + gd.getScreen()
196: + ". Device Caps: "
197: + Integer.toHexString(deviceCaps));
198: }
199: }
200: }
201:
202: /**
203: * Invalidates this context by resetting its status: the validated
204: * destination surface, and a pointer to the native context.
205: * This method is called in the following cases:
206: * - if a surface loss situation is detected at the native level
207: * during any of the validation methods (setClip, setRenderTarget etc)
208: * and an InvalidPipeException is thrown.
209: * This situation happens when there was a surface loss, but
210: * there were no display change event (like in case of command prompt
211: * going fullscreen).
212: * - as part of surface restoration when a surface is the current
213: * target surface for this context. Since surface restoration
214: * resets the depth buffer contents, we need to make sure the clip
215: * is reset, and since the target surface is reset, we'll set a new
216: * clip the next time we attempt to render to the target surface.
217: * - when a display change occurs, the native D3DContext object is
218: * released and recreated as part of primary surface recreation.
219: * At the time of the release, the java D3DContext object need to be
220: * invalidated because a new D3D device is created and the target
221: * surface will need to be reset.
222: *
223: * Invalidation of the context causes its revalidation the next time
224: * someone tries to get the D3DContext for rendering or creating a new
225: * surface.
226: *
227: * @see #reinitNativeContext
228: */
229: private void invalidateContext() {
230: valid = false;
231: nativeContext = 0L;
232: validatedDstData = null;
233: // We don't set deviceCaps to J2D_D3D_FAILURE here because
234: // it will prevent from creating d3d surfaces, which means that
235: // we'll never get a chance to continue using d3d after a single
236: // invalidation event (for example, a display change).
237: }
238:
239: /**
240: * Fetches the D3DContext associated with the current
241: * thread/GraphicsConfig pair, validates the context using the given
242: * parameters, then returns the handle to the native context object.
243: * Most rendering operations will call this method first in order to
244: * prepare the native D3d layer before issuing rendering commands.
245: */
246: static long getContext(SurfaceData srcData, SurfaceData dstData,
247: Region clip, Composite comp, AffineTransform xform,
248: int pixel, int flags) {
249: if (dstData instanceof D3DSurfaceData == false) {
250: throw new InvalidPipeException(
251: "Incorrect destination surface");
252: }
253:
254: D3DContext d3dc = ((D3DSurfaceData) dstData).getContext();
255: try {
256: d3dc.validate(srcData, dstData, clip, comp, xform, pixel,
257: flags);
258: } catch (InvalidPipeException e) {
259: d3dc.invalidateContext();
260: // note that we do not propagate the exception. Once the context
261: // is invalidated, any d3d rendering operations are noops, and
262: // we are waiting for the primary surface restoration, which
263: // happens when VolatileImage is validated. At this point
264: // the native D3DContext will be reinitialized, and the next
265: // time around validation of the context will succeed.
266: // Throwing the exception here will do no good, since the
267: // destination surface (which is associated with a VolatileImage
268: // or a BufferStrategy) will not be restored until VI.validate()
269: // is called by the rendering thread.
270: }
271: return d3dc.getNativeContext();
272: }
273:
274: public int getDeviceCaps() {
275: return deviceCaps;
276: }
277:
278: boolean isRTTSupported() {
279: return ((deviceCaps & J2D_D3D_OP_RTT_SURFACE_OK) != 0);
280: }
281:
282: /**
283: * Returns a handle to the native D3DContext structure associated with
284: * this object.
285: */
286: long getNativeContext() {
287: return nativeContext;
288: }
289:
290: /**
291: * Validates the given parameters against the current state for this
292: * context. If this context is not current, it will be made current
293: * for the given source and destination surfaces, and the viewport will
294: * be updated. Then each part of the context state (clip, composite,
295: * etc.) is checked against the previous value. If the value has changed
296: * since the last call to validate(), it will be updated accordingly.
297: */
298: private void validate(SurfaceData srcData, SurfaceData dstData,
299: Region clip, Composite comp, AffineTransform xform,
300: int pixel, int flags) {
301: boolean updateClip = false;
302:
303: if ((srcData != null && !srcData.isValid())
304: || !dstData.isValid() || dstData.getNativeOps() == 0L
305: || dstData.isSurfaceLost()) {
306: throw new InvalidPipeException("Invalid surface");
307: }
308:
309: if (!valid) {
310: // attempt to reinitialize the context. If the device has been
311: // reset, the following calls to setRenderTarget/setClip will
312: // succeed and not throw InvalidPipeException.
313: reinitNativeContext();
314: }
315:
316: if (dstData != validatedDstData) {
317: // invalidate pixel and clip (so they will be updated below)
318: validatedPixel = ~pixel;
319: updateClip = true;
320:
321: // update the viewport
322: long pDst = dstData.getNativeOps();
323: setRenderTarget(nativeContext, pDst);
324:
325: // keep the reference to the old data until we set the
326: // new one on the native level, preventing it from being disposed
327: SurfaceData tmpData = dstData;
328: validatedDstData = dstData;
329: tmpData = null;
330: }
331: // it's better to use dstData instead of validatedDstData because
332: // the latter may be set to null via invalidateContext at any moment.
333: long pDest = dstData.getNativeOps();
334:
335: // validate clip
336: if ((clip != validatedClip) || updateClip) {
337: if (clip != null) {
338: /**
339: * It's cheaper to make this check than set clip every time.
340: *
341: * Set the new clip only if:
342: * - we were asked to do it (updateClip == true)
343: * - no clip was set before
344: * - if both the old and the new clip are shapes
345: * - if they're both rectangular but don't represent
346: * the same rectangle
347: */
348: if (updateClip
349: || validatedClip == null
350: || !(validatedClip.isRectangular() && clip
351: .isRectangular())
352: || ((clip.getLoX() != validatedClip.getLoX()
353: || clip.getLoY() != validatedClip
354: .getLoY()
355: || clip.getHiX() != validatedClip
356: .getHiX() || clip.getHiY() != validatedClip
357: .getHiY()))) {
358: setClip(nativeContext, pDest, clip, clip
359: .isRectangular(), clip.getLoX(), clip
360: .getLoY(), clip.getHiX(), clip.getHiY());
361: }
362: } else {
363: resetClip(nativeContext, pDest);
364: }
365: validatedClip = clip;
366: }
367:
368: if ((comp != validatedComp) || (flags != validatedFlags)) {
369: // invalidate pixel
370: validatedPixel = ~pixel;
371: validatedComp = comp;
372: if (comp != null) {
373: AlphaComposite ac = (AlphaComposite) comp;
374: setAlphaComposite(nativeContext, ac.getRule(), ac
375: .getAlpha(), flags);
376: } else {
377: resetComposite(nativeContext);
378: }
379: }
380:
381: // validate transform
382: if (xform == null) {
383: if (xformInUse) {
384: resetTransform(nativeContext, pDest);
385: xformInUse = false;
386: vScaleX = vScaleY = 1.0;
387: vShearX = vShearY = vTransX = vTransY = 0.0;
388: }
389: } else {
390: double nScaleX = xform.getScaleX();
391: double nScaleY = xform.getScaleY();
392: double nShearX = xform.getShearX();
393: double nShearY = xform.getShearY();
394: double nTransX = xform.getTranslateX();
395: double nTransY = xform.getTranslateY();
396:
397: if (nTransX != vTransX || nTransY != vTransY
398: || nScaleX != vScaleX || nScaleY != vScaleY
399: || nShearX != vShearX || nShearY != vShearY) {
400: setTransform(nativeContext, pDest, xform, nScaleX,
401: nShearY, nShearX, nScaleY, nTransX, nTransY);
402: vScaleX = nScaleX;
403: vScaleY = nScaleY;
404: vShearX = nShearX;
405: vShearY = nShearY;
406: vTransX = nTransY;
407: vTransY = nTransY;
408: xformInUse = true;
409: }
410: }
411:
412: // validate pixel
413: if (pixel != validatedPixel) {
414: validatedPixel = pixel;
415: setColor(nativeContext, pixel, flags);
416: }
417:
418: // save flags for later comparison
419: validatedFlags = flags;
420:
421: // mark dstData dirty
422: dstData.markDirty();
423: }
424: }
|