blob: b41de7b34e9d57b060f731a7c05f8801b7735c88 [file] [log] [blame]
J. Duke319a3b92007-12-01 00:00:00 +00001/*
2 * Copyright 2005-2006 Sun Microsystems, Inc. All Rights Reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Sun designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Sun in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
22 * CA 95054 USA or visit www.sun.com if you need additional information or
23 * have any questions.
24 */
25
26package sun.java2d.d3d;
27
28import java.awt.AlphaComposite;
29import java.awt.Composite;
30import java.awt.GraphicsEnvironment;
31import java.awt.geom.AffineTransform;
32import sun.awt.Win32GraphicsDevice;
33import sun.java2d.InvalidPipeException;
34import sun.java2d.SurfaceData;
35import sun.java2d.pipe.Region;
36import sun.java2d.windows.WindowsFlags;
37
38public class D3DContext {
39
40 public static final int NO_CONTEXT_FLAGS = 0;
41 /**
42 * Used in D3DBlitLoops: if the source surface is opaque
43 * alpha blending can be turned off on the native level
44 * (if there's no ea), thus improving performance.
45 */
46 public static final int SRC_IS_OPAQUE = 1;
47
48 /**
49 * This is a list of capabilities supported by the device this
50 * context is associated with.
51 * @see getDeviceCaps
52 */
53 public static final int J2D_D3D_FAILURE = (0 << 0);
54 /**
55 * Device supports depth buffer for d3d render targets
56 */
57 public static final int J2D_D3D_DEPTH_SURFACE_OK = (1 << 0);
58 /**
59 * Device supports creation of plain d3d surfaces
60 */
61 public static final int J2D_D3D_PLAIN_SURFACE_OK = (1 << 1);
62 /**
63 * Device supports creation of opaque textures
64 */
65 public static final int J2D_D3D_OP_TEXTURE_SURFACE_OK = (1 << 2);
66 /**
67 * Device supports creation of bitmask textures
68 */
69 public static final int J2D_D3D_BM_TEXTURE_SURFACE_OK = (1 << 3);
70 /**
71 * Device supports creation of translucent textures
72 */
73 public static final int J2D_D3D_TR_TEXTURE_SURFACE_OK = (1 << 4);
74 /**
75 * Device supports creation of opaque render-to-textures
76 */
77 public static final int J2D_D3D_OP_RTT_SURFACE_OK = (1 << 5);
78 /**
79 * Device can render lines correctly (no pixelization issues)
80 */
81 public static final int J2D_D3D_LINES_OK = (1 << 6);
82 /**
83 * Device supports texture mapping (no pixelization issues)
84 */
85 public static final int J2D_D3D_TEXTURE_BLIT_OK = (1 << 7);
86 /**
87 * Device supports texture mapping with transforms (no pixelization issues)
88 */
89 public static final int J2D_D3D_TEXTURE_TRANSFORM_OK = (1 << 8);
90 /**
91 * Device can render clipped lines correctly.
92 */
93 public static final int J2D_D3D_LINE_CLIPPING_OK = (1 << 9);
94 /**
95 * Device has all hw capabilities the d3d pipeline requires
96 */
97 public static final int J2D_D3D_DEVICE_OK = (1 <<10);
98 /**
99 * 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, vTransY;
138
139 private int deviceCaps;
140
141 private native void setRenderTarget(long pCtx, long pDst);
142 private native void setClip(long pCtx, long pDst, Region clip, boolean isRect,
143 int x1, int y1, int x2, int y2);
144 private native void resetClip(long pCtx, long pDst);
145 private native void resetComposite(long pCtx);
146 private native void setAlphaComposite(long pCtx, int rule,
147 float extraAlpha, int flags);
148 private native void setTransform(long pCtx, long pDst,
149 AffineTransform xform,
150 double m00, double m10, double m01,
151 double m11, double m02, double m12);
152 private native void resetTransform(long pCtx, long pDst);
153 private native void setColor(long pCtx, int pixel, int flags);
154 private native long initNativeContext(int screen);
155 private native int getNativeDeviceCaps(long pCtx);
156
157 static {
158 if (!GraphicsEnvironment.isHeadless()) {
159 LOCK = D3DContext.class;
160 }
161 }
162
163 public D3DContext(Win32GraphicsDevice gd) {
164 this.gd = gd;
165 reinitNativeContext();
166 }
167
168 /**
169 * Reinitializes the context by retrieving a pointer to the native
170 * D3DContext object, and resetting the device caps.
171 */
172 void reinitNativeContext() {
173 nativeContext = initNativeContext(gd.getScreen());
174 deviceCaps = nativeContext != 0L ?
175 getNativeDeviceCaps(nativeContext) : J2D_D3D_FAILURE;
176 valid = ((deviceCaps & J2D_D3D_ENABLED_OK) != 0);
177 if (WindowsFlags.isD3DVerbose()) {
178 if (valid) {
179 System.out.println("Direct3D pipeline enabled on screen " +
180 gd.getScreen());
181 } else {
182 System.out.println("Could not enable Direct3D pipeline on " +
183 "screen " + gd.getScreen() +
184 ". Device Caps: " +
185 Integer.toHexString(deviceCaps));
186 }
187 }
188 }
189
190 /**
191 * Invalidates this context by resetting its status: the validated
192 * destination surface, and a pointer to the native context.
193 * This method is called in the following cases:
194 * - if a surface loss situation is detected at the native level
195 * during any of the validation methods (setClip, setRenderTarget etc)
196 * and an InvalidPipeException is thrown.
197 * This situation happens when there was a surface loss, but
198 * there were no display change event (like in case of command prompt
199 * going fullscreen).
200 * - as part of surface restoration when a surface is the current
201 * target surface for this context. Since surface restoration
202 * resets the depth buffer contents, we need to make sure the clip
203 * is reset, and since the target surface is reset, we'll set a new
204 * clip the next time we attempt to render to the target surface.
205 * - when a display change occurs, the native D3DContext object is
206 * released and recreated as part of primary surface recreation.
207 * At the time of the release, the java D3DContext object need to be
208 * invalidated because a new D3D device is created and the target
209 * surface will need to be reset.
210 *
211 * Invalidation of the context causes its revalidation the next time
212 * someone tries to get the D3DContext for rendering or creating a new
213 * surface.
214 *
215 * @see #reinitNativeContext
216 */
217 private void invalidateContext() {
218 valid = false;
219 nativeContext = 0L;
220 validatedDstData = null;
221 // We don't set deviceCaps to J2D_D3D_FAILURE here because
222 // it will prevent from creating d3d surfaces, which means that
223 // we'll never get a chance to continue using d3d after a single
224 // invalidation event (for example, a display change).
225 }
226
227 /**
228 * Fetches the D3DContext associated with the current
229 * thread/GraphicsConfig pair, validates the context using the given
230 * parameters, then returns the handle to the native context object.
231 * Most rendering operations will call this method first in order to
232 * prepare the native D3d layer before issuing rendering commands.
233 */
234 static long getContext(SurfaceData srcData,
235 SurfaceData dstData,
236 Region clip, Composite comp,
237 AffineTransform xform,
238 int pixel, int flags)
239 {
240 if (dstData instanceof D3DSurfaceData == false) {
241 throw new InvalidPipeException("Incorrect destination surface");
242 }
243
244 D3DContext d3dc = ((D3DSurfaceData)dstData).getContext();
245 try {
246 d3dc.validate(srcData, dstData, clip, comp, xform, pixel, flags);
247 } catch (InvalidPipeException e) {
248 d3dc.invalidateContext();
249 // note that we do not propagate the exception. Once the context
250 // is invalidated, any d3d rendering operations are noops, and
251 // we are waiting for the primary surface restoration, which
252 // happens when VolatileImage is validated. At this point
253 // the native D3DContext will be reinitialized, and the next
254 // time around validation of the context will succeed.
255 // Throwing the exception here will do no good, since the
256 // destination surface (which is associated with a VolatileImage
257 // or a BufferStrategy) will not be restored until VI.validate()
258 // is called by the rendering thread.
259 }
260 return d3dc.getNativeContext();
261 }
262
263 public int getDeviceCaps() {
264 return deviceCaps;
265 }
266
267 boolean isRTTSupported() {
268 return ((deviceCaps & J2D_D3D_OP_RTT_SURFACE_OK) != 0);
269 }
270
271 /**
272 * Returns a handle to the native D3DContext structure associated with
273 * this object.
274 */
275 long getNativeContext() {
276 return nativeContext;
277 }
278
279 /**
280 * Validates the given parameters against the current state for this
281 * context. If this context is not current, it will be made current
282 * for the given source and destination surfaces, and the viewport will
283 * be updated. Then each part of the context state (clip, composite,
284 * etc.) is checked against the previous value. If the value has changed
285 * since the last call to validate(), it will be updated accordingly.
286 */
287 private void validate(SurfaceData srcData, SurfaceData dstData,
288 Region clip, Composite comp, AffineTransform xform,
289 int pixel, int flags)
290 {
291 boolean updateClip = false;
292
293 if ((srcData != null && !srcData.isValid()) || !dstData.isValid() ||
294 dstData.getNativeOps() == 0L || dstData.isSurfaceLost())
295 {
296 throw new InvalidPipeException("Invalid surface");
297 }
298
299 if (!valid) {
300 // attempt to reinitialize the context. If the device has been
301 // reset, the following calls to setRenderTarget/setClip will
302 // succeed and not throw InvalidPipeException.
303 reinitNativeContext();
304 }
305
306 if (dstData != validatedDstData) {
307 // invalidate pixel and clip (so they will be updated below)
308 validatedPixel = ~pixel;
309 updateClip = true;
310
311 // update the viewport
312 long pDst = dstData.getNativeOps();
313 setRenderTarget(nativeContext, pDst);
314
315 // keep the reference to the old data until we set the
316 // new one on the native level, preventing it from being disposed
317 SurfaceData tmpData = dstData;
318 validatedDstData = dstData;
319 tmpData = null;
320 }
321 // it's better to use dstData instead of validatedDstData because
322 // the latter may be set to null via invalidateContext at any moment.
323 long pDest = dstData.getNativeOps();
324
325 // validate clip
326 if ((clip != validatedClip) || updateClip) {
327 if (clip != null) {
328 /**
329 * It's cheaper to make this check than set clip every time.
330 *
331 * Set the new clip only if:
332 * - we were asked to do it (updateClip == true)
333 * - no clip was set before
334 * - if both the old and the new clip are shapes
335 * - if they're both rectangular but don't represent
336 * the same rectangle
337 */
338 if (updateClip ||
339 validatedClip == null ||
340 !(validatedClip.isRectangular() && clip.isRectangular()) ||
341 ((clip.getLoX() != validatedClip.getLoX() ||
342 clip.getLoY() != validatedClip.getLoY() ||
343 clip.getHiX() != validatedClip.getHiX() ||
344 clip.getHiY() != validatedClip.getHiY())))
345 {
346 setClip(nativeContext, pDest,
347 clip, clip.isRectangular(),
348 clip.getLoX(), clip.getLoY(),
349 clip.getHiX(), clip.getHiY());
350 }
351 } else {
352 resetClip(nativeContext, pDest);
353 }
354 validatedClip = clip;
355 }
356
357 if ((comp != validatedComp) || (flags != validatedFlags)) {
358 // invalidate pixel
359 validatedPixel = ~pixel;
360 validatedComp = comp;
361 if (comp != null) {
362 AlphaComposite ac = (AlphaComposite)comp;
363 setAlphaComposite(nativeContext, ac.getRule(),
364 ac.getAlpha(), flags);
365 } else {
366 resetComposite(nativeContext);
367 }
368 }
369
370 // validate transform
371 if (xform == null) {
372 if (xformInUse) {
373 resetTransform(nativeContext, pDest);
374 xformInUse = false;
375 vScaleX = vScaleY = 1.0;
376 vShearX = vShearY = vTransX = vTransY = 0.0;
377 }
378 } else {
379 double nScaleX = xform.getScaleX();
380 double nScaleY = xform.getScaleY();
381 double nShearX = xform.getShearX();
382 double nShearY = xform.getShearY();
383 double nTransX = xform.getTranslateX();
384 double nTransY = xform.getTranslateY();
385
386 if (nTransX != vTransX || nTransY != vTransY ||
387 nScaleX != vScaleX || nScaleY != vScaleY ||
388 nShearX != vShearX || nShearY != vShearY)
389 {
390 setTransform(nativeContext, pDest,
391 xform,
392 nScaleX, nShearY, nShearX, nScaleY,
393 nTransX, nTransY);
394 vScaleX = nScaleX;
395 vScaleY = nScaleY;
396 vShearX = nShearX;
397 vShearY = nShearY;
398 vTransX = nTransY;
399 vTransY = nTransY;
400 xformInUse = true;
401 }
402 }
403
404 // validate pixel
405 if (pixel != validatedPixel) {
406 validatedPixel = pixel;
407 setColor(nativeContext, pixel, flags);
408 }
409
410 // save flags for later comparison
411 validatedFlags = flags;
412
413 // mark dstData dirty
414 dstData.markDirty();
415 }
416}