| /* |
| * Copyright 2005-2006 Sun Microsystems, Inc. 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. Sun designates this |
| * particular file as subject to the "Classpath" exception as provided |
| * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, |
| * CA 95054 USA or visit www.sun.com if you need additional information or |
| * have any questions. |
| */ |
| |
| package sun.java2d.d3d; |
| |
| import java.awt.AlphaComposite; |
| import java.awt.Composite; |
| import java.awt.GraphicsEnvironment; |
| import java.awt.geom.AffineTransform; |
| import sun.awt.Win32GraphicsDevice; |
| import sun.java2d.InvalidPipeException; |
| import sun.java2d.SurfaceData; |
| import sun.java2d.pipe.Region; |
| import sun.java2d.windows.WindowsFlags; |
| |
| public class D3DContext { |
| |
| public static final int NO_CONTEXT_FLAGS = 0; |
| /** |
| * Used in D3DBlitLoops: if the source surface is opaque |
| * alpha blending can be turned off on the native level |
| * (if there's no ea), thus improving performance. |
| */ |
| public static final int SRC_IS_OPAQUE = 1; |
| |
| /** |
| * This is a list of capabilities supported by the device this |
| * context is associated with. |
| * @see getDeviceCaps |
| */ |
| public static final int J2D_D3D_FAILURE = (0 << 0); |
| /** |
| * Device supports depth buffer for d3d render targets |
| */ |
| public static final int J2D_D3D_DEPTH_SURFACE_OK = (1 << 0); |
| /** |
| * Device supports creation of plain d3d surfaces |
| */ |
| public static final int J2D_D3D_PLAIN_SURFACE_OK = (1 << 1); |
| /** |
| * Device supports creation of opaque textures |
| */ |
| public static final int J2D_D3D_OP_TEXTURE_SURFACE_OK = (1 << 2); |
| /** |
| * Device supports creation of bitmask textures |
| */ |
| public static final int J2D_D3D_BM_TEXTURE_SURFACE_OK = (1 << 3); |
| /** |
| * Device supports creation of translucent textures |
| */ |
| public static final int J2D_D3D_TR_TEXTURE_SURFACE_OK = (1 << 4); |
| /** |
| * Device supports creation of opaque render-to-textures |
| */ |
| public static final int J2D_D3D_OP_RTT_SURFACE_OK = (1 << 5); |
| /** |
| * Device can render lines correctly (no pixelization issues) |
| */ |
| public static final int J2D_D3D_LINES_OK = (1 << 6); |
| /** |
| * Device supports texture mapping (no pixelization issues) |
| */ |
| public static final int J2D_D3D_TEXTURE_BLIT_OK = (1 << 7); |
| /** |
| * Device supports texture mapping with transforms (no pixelization issues) |
| */ |
| public static final int J2D_D3D_TEXTURE_TRANSFORM_OK = (1 << 8); |
| /** |
| * Device can render clipped lines correctly. |
| */ |
| public static final int J2D_D3D_LINE_CLIPPING_OK = (1 << 9); |
| /** |
| * Device has all hw capabilities the d3d pipeline requires |
| */ |
| public static final int J2D_D3D_DEVICE_OK = (1 <<10); |
| /** |
| * Device supports all necessary texture formats required by d3d pipeline |
| */ |
| public static final int J2D_D3D_PIXEL_FORMATS_OK = (1 <<11); |
| /** |
| * Device supports geometry transformations |
| */ |
| public static final int J2D_D3D_SET_TRANSFORM_OK = (1 <<12); |
| /** |
| * The device is not from a list of known bad devices |
| * (see D3DRuntimeTest.cpp) |
| */ |
| public static final int J2D_D3D_HW_OK = (1 <<13); |
| /** |
| * Direct3D pipeline is enabled on this device |
| */ |
| public static final int J2D_D3D_ENABLED_OK = (1 <<14); |
| |
| /** |
| * The lock object used to synchronize access to the native windowing |
| * system layer. Note that rendering methods should always synchronize on |
| * D3DContext.LOCK before calling the D3DContext.getContext() method, |
| * or any other method that invokes native D3d commands. |
| * REMIND: in D3D case we should really be synchronizing on per-device |
| * basis. |
| */ |
| static Object LOCK; |
| |
| private Win32GraphicsDevice gd; |
| private boolean valid; |
| |
| protected long nativeContext; |
| private SurfaceData validatedDstData; |
| private Region validatedClip; |
| private Composite validatedComp; |
| private int validatedPixel; |
| private int validatedFlags; |
| private boolean xformInUse; |
| // validated transform's data |
| private double vScaleX, vScaleY, vShearX, vShearY, vTransX, vTransY; |
| |
| private int deviceCaps; |
| |
| private native void setRenderTarget(long pCtx, long pDst); |
| private native void setClip(long pCtx, long pDst, Region clip, boolean isRect, |
| int x1, int y1, int x2, int y2); |
| private native void resetClip(long pCtx, long pDst); |
| private native void resetComposite(long pCtx); |
| private native void setAlphaComposite(long pCtx, int rule, |
| float extraAlpha, int flags); |
| private native void setTransform(long pCtx, long pDst, |
| AffineTransform xform, |
| double m00, double m10, double m01, |
| double m11, double m02, double m12); |
| private native void resetTransform(long pCtx, long pDst); |
| private native void setColor(long pCtx, int pixel, int flags); |
| private native long initNativeContext(int screen); |
| private native int getNativeDeviceCaps(long pCtx); |
| |
| static { |
| if (!GraphicsEnvironment.isHeadless()) { |
| LOCK = D3DContext.class; |
| } |
| } |
| |
| public D3DContext(Win32GraphicsDevice gd) { |
| this.gd = gd; |
| reinitNativeContext(); |
| } |
| |
| /** |
| * Reinitializes the context by retrieving a pointer to the native |
| * D3DContext object, and resetting the device caps. |
| */ |
| void reinitNativeContext() { |
| nativeContext = initNativeContext(gd.getScreen()); |
| deviceCaps = nativeContext != 0L ? |
| getNativeDeviceCaps(nativeContext) : J2D_D3D_FAILURE; |
| valid = ((deviceCaps & J2D_D3D_ENABLED_OK) != 0); |
| if (WindowsFlags.isD3DVerbose()) { |
| if (valid) { |
| System.out.println("Direct3D pipeline enabled on screen " + |
| gd.getScreen()); |
| } else { |
| System.out.println("Could not enable Direct3D pipeline on " + |
| "screen " + gd.getScreen() + |
| ". Device Caps: " + |
| Integer.toHexString(deviceCaps)); |
| } |
| } |
| } |
| |
| /** |
| * Invalidates this context by resetting its status: the validated |
| * destination surface, and a pointer to the native context. |
| * This method is called in the following cases: |
| * - if a surface loss situation is detected at the native level |
| * during any of the validation methods (setClip, setRenderTarget etc) |
| * and an InvalidPipeException is thrown. |
| * This situation happens when there was a surface loss, but |
| * there were no display change event (like in case of command prompt |
| * going fullscreen). |
| * - as part of surface restoration when a surface is the current |
| * target surface for this context. Since surface restoration |
| * resets the depth buffer contents, we need to make sure the clip |
| * is reset, and since the target surface is reset, we'll set a new |
| * clip the next time we attempt to render to the target surface. |
| * - when a display change occurs, the native D3DContext object is |
| * released and recreated as part of primary surface recreation. |
| * At the time of the release, the java D3DContext object need to be |
| * invalidated because a new D3D device is created and the target |
| * surface will need to be reset. |
| * |
| * Invalidation of the context causes its revalidation the next time |
| * someone tries to get the D3DContext for rendering or creating a new |
| * surface. |
| * |
| * @see #reinitNativeContext |
| */ |
| private void invalidateContext() { |
| valid = false; |
| nativeContext = 0L; |
| validatedDstData = null; |
| // We don't set deviceCaps to J2D_D3D_FAILURE here because |
| // it will prevent from creating d3d surfaces, which means that |
| // we'll never get a chance to continue using d3d after a single |
| // invalidation event (for example, a display change). |
| } |
| |
| /** |
| * Fetches the D3DContext associated with the current |
| * thread/GraphicsConfig pair, validates the context using the given |
| * parameters, then returns the handle to the native context object. |
| * Most rendering operations will call this method first in order to |
| * prepare the native D3d layer before issuing rendering commands. |
| */ |
| static long getContext(SurfaceData srcData, |
| SurfaceData dstData, |
| Region clip, Composite comp, |
| AffineTransform xform, |
| int pixel, int flags) |
| { |
| if (dstData instanceof D3DSurfaceData == false) { |
| throw new InvalidPipeException("Incorrect destination surface"); |
| } |
| |
| D3DContext d3dc = ((D3DSurfaceData)dstData).getContext(); |
| try { |
| d3dc.validate(srcData, dstData, clip, comp, xform, pixel, flags); |
| } catch (InvalidPipeException e) { |
| d3dc.invalidateContext(); |
| // note that we do not propagate the exception. Once the context |
| // is invalidated, any d3d rendering operations are noops, and |
| // we are waiting for the primary surface restoration, which |
| // happens when VolatileImage is validated. At this point |
| // the native D3DContext will be reinitialized, and the next |
| // time around validation of the context will succeed. |
| // Throwing the exception here will do no good, since the |
| // destination surface (which is associated with a VolatileImage |
| // or a BufferStrategy) will not be restored until VI.validate() |
| // is called by the rendering thread. |
| } |
| return d3dc.getNativeContext(); |
| } |
| |
| public int getDeviceCaps() { |
| return deviceCaps; |
| } |
| |
| boolean isRTTSupported() { |
| return ((deviceCaps & J2D_D3D_OP_RTT_SURFACE_OK) != 0); |
| } |
| |
| /** |
| * Returns a handle to the native D3DContext structure associated with |
| * this object. |
| */ |
| long getNativeContext() { |
| return nativeContext; |
| } |
| |
| /** |
| * Validates the given parameters against the current state for this |
| * context. If this context is not current, it will be made current |
| * for the given source and destination surfaces, and the viewport will |
| * be updated. Then each part of the context state (clip, composite, |
| * etc.) is checked against the previous value. If the value has changed |
| * since the last call to validate(), it will be updated accordingly. |
| */ |
| private void validate(SurfaceData srcData, SurfaceData dstData, |
| Region clip, Composite comp, AffineTransform xform, |
| int pixel, int flags) |
| { |
| boolean updateClip = false; |
| |
| if ((srcData != null && !srcData.isValid()) || !dstData.isValid() || |
| dstData.getNativeOps() == 0L || dstData.isSurfaceLost()) |
| { |
| throw new InvalidPipeException("Invalid surface"); |
| } |
| |
| if (!valid) { |
| // attempt to reinitialize the context. If the device has been |
| // reset, the following calls to setRenderTarget/setClip will |
| // succeed and not throw InvalidPipeException. |
| reinitNativeContext(); |
| } |
| |
| if (dstData != validatedDstData) { |
| // invalidate pixel and clip (so they will be updated below) |
| validatedPixel = ~pixel; |
| updateClip = true; |
| |
| // update the viewport |
| long pDst = dstData.getNativeOps(); |
| setRenderTarget(nativeContext, pDst); |
| |
| // keep the reference to the old data until we set the |
| // new one on the native level, preventing it from being disposed |
| SurfaceData tmpData = dstData; |
| validatedDstData = dstData; |
| tmpData = null; |
| } |
| // it's better to use dstData instead of validatedDstData because |
| // the latter may be set to null via invalidateContext at any moment. |
| long pDest = dstData.getNativeOps(); |
| |
| // validate clip |
| if ((clip != validatedClip) || updateClip) { |
| if (clip != null) { |
| /** |
| * It's cheaper to make this check than set clip every time. |
| * |
| * Set the new clip only if: |
| * - we were asked to do it (updateClip == true) |
| * - no clip was set before |
| * - if both the old and the new clip are shapes |
| * - if they're both rectangular but don't represent |
| * the same rectangle |
| */ |
| if (updateClip || |
| validatedClip == null || |
| !(validatedClip.isRectangular() && clip.isRectangular()) || |
| ((clip.getLoX() != validatedClip.getLoX() || |
| clip.getLoY() != validatedClip.getLoY() || |
| clip.getHiX() != validatedClip.getHiX() || |
| clip.getHiY() != validatedClip.getHiY()))) |
| { |
| setClip(nativeContext, pDest, |
| clip, clip.isRectangular(), |
| clip.getLoX(), clip.getLoY(), |
| clip.getHiX(), clip.getHiY()); |
| } |
| } else { |
| resetClip(nativeContext, pDest); |
| } |
| validatedClip = clip; |
| } |
| |
| if ((comp != validatedComp) || (flags != validatedFlags)) { |
| // invalidate pixel |
| validatedPixel = ~pixel; |
| validatedComp = comp; |
| if (comp != null) { |
| AlphaComposite ac = (AlphaComposite)comp; |
| setAlphaComposite(nativeContext, ac.getRule(), |
| ac.getAlpha(), flags); |
| } else { |
| resetComposite(nativeContext); |
| } |
| } |
| |
| // validate transform |
| if (xform == null) { |
| if (xformInUse) { |
| resetTransform(nativeContext, pDest); |
| xformInUse = false; |
| vScaleX = vScaleY = 1.0; |
| vShearX = vShearY = vTransX = vTransY = 0.0; |
| } |
| } else { |
| double nScaleX = xform.getScaleX(); |
| double nScaleY = xform.getScaleY(); |
| double nShearX = xform.getShearX(); |
| double nShearY = xform.getShearY(); |
| double nTransX = xform.getTranslateX(); |
| double nTransY = xform.getTranslateY(); |
| |
| if (nTransX != vTransX || nTransY != vTransY || |
| nScaleX != vScaleX || nScaleY != vScaleY || |
| nShearX != vShearX || nShearY != vShearY) |
| { |
| setTransform(nativeContext, pDest, |
| xform, |
| nScaleX, nShearY, nShearX, nScaleY, |
| nTransX, nTransY); |
| vScaleX = nScaleX; |
| vScaleY = nScaleY; |
| vShearX = nShearX; |
| vShearY = nShearY; |
| vTransX = nTransY; |
| vTransY = nTransY; |
| xformInUse = true; |
| } |
| } |
| |
| // validate pixel |
| if (pixel != validatedPixel) { |
| validatedPixel = pixel; |
| setColor(nativeContext, pixel, flags); |
| } |
| |
| // save flags for later comparison |
| validatedFlags = flags; |
| |
| // mark dstData dirty |
| dstData.markDirty(); |
| } |
| } |