2
|
1 |
/*
|
|
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 |
|
|
26 |
package sun.java2d.d3d;
|
|
27 |
|
|
28 |
import java.awt.AlphaComposite;
|
|
29 |
import java.awt.Composite;
|
|
30 |
import java.awt.GraphicsEnvironment;
|
|
31 |
import java.awt.geom.AffineTransform;
|
|
32 |
import sun.awt.Win32GraphicsDevice;
|
|
33 |
import sun.java2d.InvalidPipeException;
|
|
34 |
import sun.java2d.SurfaceData;
|
|
35 |
import sun.java2d.pipe.Region;
|
|
36 |
import sun.java2d.windows.WindowsFlags;
|
|
37 |
|
|
38 |
public 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 |
}
|