aboutsummaryrefslogtreecommitdiff
path: root/src/windows/classes/sun/java2d/d3d/D3DGraphicsDevice.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/windows/classes/sun/java2d/d3d/D3DGraphicsDevice.java')
-rw-r--r--src/windows/classes/sun/java2d/d3d/D3DGraphicsDevice.java500
1 files changed, 500 insertions, 0 deletions
diff --git a/src/windows/classes/sun/java2d/d3d/D3DGraphicsDevice.java b/src/windows/classes/sun/java2d/d3d/D3DGraphicsDevice.java
new file mode 100644
index 000000000..a4334b42f
--- /dev/null
+++ b/src/windows/classes/sun/java2d/d3d/D3DGraphicsDevice.java
@@ -0,0 +1,500 @@
+/*
+ * Copyright 2007-2008 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.Dialog;
+import java.awt.DisplayMode;
+import java.awt.Frame;
+import java.awt.GraphicsConfiguration;
+import java.awt.Rectangle;
+import java.awt.Toolkit;
+import java.awt.Window;
+import java.awt.event.WindowAdapter;
+import java.awt.event.WindowEvent;
+import java.awt.event.WindowListener;
+import java.awt.peer.WindowPeer;
+import java.util.ArrayList;
+import sun.awt.Win32GraphicsDevice;
+import sun.awt.windows.WWindowPeer;
+import sun.java2d.pipe.hw.ContextCapabilities;
+import sun.java2d.windows.WindowsFlags;
+import static sun.java2d.pipe.BufferedOpCodes.*;
+import static sun.java2d.d3d.D3DContext.D3DContextCaps.*;
+import sun.java2d.d3d.D3DContext.D3DContextCaps;
+
+/**
+ * This class implements D3D-specific functionality, such as fullscreen
+ * exclusive mode and display changes. It is kept separate from
+ * Win32GraphicsDevice to help avoid overburdening the parent class.
+ */
+public class D3DGraphicsDevice extends Win32GraphicsDevice {
+ private D3DContext context;
+
+ private static boolean d3dAvailable;
+
+ private ContextCapabilities d3dCaps;
+
+ private static native boolean initD3D();
+
+ static {
+ // loading the library doesn't help because we need the
+ // toolkit thread running, so we have to call getDefaultToolkit()
+ Toolkit.getDefaultToolkit();
+ d3dAvailable = initD3D();
+ if (d3dAvailable) {
+ // we don't use pixel formats for the d3d pipeline
+ pfDisabled = true;
+ }
+ }
+
+ /**
+ * Used to construct a Direct3D-enabled GraphicsDevice.
+ *
+ * @return a D3DGraphicsDevice if it could be created
+ * successfully, null otherwise.
+ */
+ public static D3DGraphicsDevice createDevice(int screen) {
+ if (!d3dAvailable) {
+ return null;
+ }
+
+ ContextCapabilities d3dCaps = getDeviceCaps(screen);
+ // could not initialize the device successfully
+ if ((d3dCaps.getCaps() & CAPS_DEVICE_OK) == 0) {
+ if (WindowsFlags.isD3DVerbose()) {
+ System.out.println("Could not enable Direct3D pipeline on " +
+ "screen " + screen);
+ }
+ return null;
+ }
+ if (WindowsFlags.isD3DVerbose()) {
+ System.out.println("Direct3D pipeline enabled on screen " + screen);
+ }
+
+ D3DGraphicsDevice gd = new D3DGraphicsDevice(screen, d3dCaps);
+ return gd;
+ }
+
+ private static native int getDeviceCapsNative(int screen);
+ private static native String getDeviceIdNative(int screen);
+ private static ContextCapabilities getDeviceCaps(final int screen) {
+ ContextCapabilities d3dCaps = null;
+ D3DRenderQueue rq = D3DRenderQueue.getInstance();
+ rq.lock();
+ try {
+ class Result {
+ int caps;
+ String id;
+ };
+ final Result res = new Result();
+ rq.flushAndInvokeNow(new Runnable() {
+ public void run() {
+ res.caps = getDeviceCapsNative(screen);
+ res.id = getDeviceIdNative(screen);
+ }
+ });
+ d3dCaps = new D3DContextCaps(res.caps, res.id);
+ } finally {
+ rq.unlock();
+ }
+
+ return d3dCaps != null ? d3dCaps : new D3DContextCaps(CAPS_EMPTY, null);
+ }
+
+ public final boolean isCapPresent(int cap) {
+ return ((d3dCaps.getCaps() & cap) != 0);
+ }
+
+ private D3DGraphicsDevice(int screennum, ContextCapabilities d3dCaps) {
+ super(screennum);
+ descString = "D3DGraphicsDevice[screen="+screennum;
+ this.d3dCaps = d3dCaps;
+ context = new D3DContext(D3DRenderQueue.getInstance(), this);
+ }
+
+ public boolean isD3DEnabledOnDevice() {
+ return isValid() && isCapPresent(CAPS_DEVICE_OK);
+ }
+
+ /**
+ * Returns true if d3d pipeline has been successfully initialized.
+ * @return true if d3d pipeline is initialized, false otherwise
+ */
+ public static boolean isD3DAvailable() {
+ return d3dAvailable;
+ }
+
+ /**
+ * Return the owning Frame for a given Window. Used in setFSWindow below
+ * to set the properties of the owning Frame when a Window goes
+ * into fullscreen mode.
+ */
+ private Frame getToplevelOwner(Window w) {
+ Window owner = w;
+ while (owner != null) {
+ owner = owner.getOwner();
+ if (owner instanceof Frame) {
+ return (Frame) owner;
+ }
+ }
+ // could get here if passed Window is an owner-less Dialog
+ return null;
+ }
+
+ private boolean fsStatus;
+ private Rectangle ownerOrigBounds = null;
+ private boolean ownerWasVisible;
+ private Window realFSWindow;
+ private WindowListener fsWindowListener;
+ private boolean fsWindowWasAlwaysOnTop;
+ private static native boolean enterFullScreenExclusiveNative(int screen,
+ long hwnd);
+
+ @Override
+ protected void enterFullScreenExclusive(final int screen, WindowPeer wp)
+ {
+ final WWindowPeer wpeer = (WWindowPeer)realFSWindow.getPeer();
+
+ D3DRenderQueue rq = D3DRenderQueue.getInstance();
+ rq.lock();
+ try {
+ rq.flushAndInvokeNow(new Runnable() {
+ public void run() {
+ long hwnd = wpeer.getHWnd();
+ if (hwnd == 0l) {
+ // window is disposed
+ fsStatus = false;
+ return;
+ }
+ fsStatus = enterFullScreenExclusiveNative(screen, hwnd);
+ }
+ });
+ } finally {
+ rq.unlock();
+ }
+ if (!fsStatus) {
+ super.enterFullScreenExclusive(screen, wp);
+ }
+ }
+
+ private static native boolean exitFullScreenExclusiveNative(int screen);
+ @Override
+ protected void exitFullScreenExclusive(final int screen, WindowPeer w) {
+ if (fsStatus) {
+ D3DRenderQueue rq = D3DRenderQueue.getInstance();
+ rq.lock();
+ try {
+ rq.flushAndInvokeNow(new Runnable() {
+ public void run() {
+ exitFullScreenExclusiveNative(screen);
+ }
+ });
+ } finally {
+ rq.unlock();
+ }
+ } else {
+ super.exitFullScreenExclusive(screen, w);
+ }
+ }
+
+ /**
+ * WindowAdapter class for the full-screen frame, responsible for
+ * restoring the devices. This is important to do because unless the device
+ * is restored it will not go back into the FS mode once alt+tabbed out.
+ * This is a problem for windows for which we do not do any d3d-related
+ * operations (like when we disabled on-screen rendering).
+ *
+ * REMIND: we create an instance per each full-screen device while a single
+ * instance would suffice (but requires more management).
+ */
+ private static class D3DFSWindowAdapter extends WindowAdapter {
+ @Override
+ public void windowDeactivated(WindowEvent e) {
+ D3DRenderQueue.getInstance().restoreDevices();
+ }
+ @Override
+ public void windowActivated(WindowEvent e) {
+ D3DRenderQueue.getInstance().restoreDevices();
+ }
+ }
+
+ @Override
+ protected void addFSWindowListener(Window w) {
+ // if the window is not a toplevel (has an owner) we have to use the
+ // real toplevel to enter the full-screen mode with (4933099).
+ if (!(w instanceof Frame) && !(w instanceof Dialog) &&
+ (realFSWindow = getToplevelOwner(w)) != null)
+ {
+ ownerOrigBounds = realFSWindow.getBounds();
+ WWindowPeer fp = (WWindowPeer)realFSWindow.getPeer();
+
+ ownerWasVisible = realFSWindow.isVisible();
+ Rectangle r = w.getBounds();
+ // we use operations on peer instead of component because calling
+ // them on component will take the tree lock
+ fp.reshape(r.x, r.y, r.width, r.height);
+ fp.setVisible(true);
+ } else {
+ realFSWindow = w;
+ }
+
+ fsWindowWasAlwaysOnTop = realFSWindow.isAlwaysOnTop();
+ ((WWindowPeer)realFSWindow.getPeer()).setAlwaysOnTop(true);
+
+ fsWindowListener = new D3DFSWindowAdapter();
+ realFSWindow.addWindowListener(fsWindowListener);
+ }
+
+ @Override
+ protected void removeFSWindowListener(Window w) {
+ realFSWindow.removeWindowListener(fsWindowListener);
+ fsWindowListener = null;
+
+ /**
+ * Bug 4933099: There is some funny-business to deal with when this
+ * method is called with a Window instead of a Frame. See 4836744
+ * for more information on this. One side-effect of our workaround
+ * for the problem is that the owning Frame of a Window may end
+ * up getting resized during the fullscreen process. When we
+ * return from fullscreen mode, we should resize the Frame to
+ * its original size (just like the Window is being resized
+ * to its original size in GraphicsDevice).
+ */
+ WWindowPeer wpeer = (WWindowPeer)realFSWindow.getPeer();
+ if (wpeer != null) {
+ if (ownerOrigBounds != null) {
+ // if the window went into fs mode before it was realized it
+ // could have (0,0) dimensions
+ if (ownerOrigBounds.width == 0) ownerOrigBounds.width = 1;
+ if (ownerOrigBounds.height == 0) ownerOrigBounds.height = 1;
+ wpeer.reshape(ownerOrigBounds.x, ownerOrigBounds.y,
+ ownerOrigBounds.width, ownerOrigBounds.height);
+ if (!ownerWasVisible) {
+ wpeer.setVisible(false);
+ }
+ ownerOrigBounds = null;
+ }
+ if (!fsWindowWasAlwaysOnTop) {
+ wpeer.setAlwaysOnTop(false);
+ }
+ }
+
+ realFSWindow = null;
+ }
+
+ private static native DisplayMode getCurrentDisplayModeNative(int screen);
+ @Override
+ protected DisplayMode getCurrentDisplayMode(final int screen) {
+ D3DRenderQueue rq = D3DRenderQueue.getInstance();
+ rq.lock();
+ try {
+ class Result {
+ DisplayMode dm = null;
+ };
+ final Result res = new Result();
+ rq.flushAndInvokeNow(new Runnable() {
+ public void run() {
+ res.dm = getCurrentDisplayModeNative(screen);
+ }
+ });
+ if (res.dm == null) {
+ return super.getCurrentDisplayMode(screen);
+ }
+ return res.dm;
+ } finally {
+ rq.unlock();
+ }
+ }
+ private static native void configDisplayModeNative(int screen, long hwnd,
+ int width, int height,
+ int bitDepth,
+ int refreshRate);
+ @Override
+ protected void configDisplayMode(final int screen, final WindowPeer w,
+ final int width, final int height,
+ final int bitDepth, final int refreshRate)
+ {
+ // we entered fs mode via gdi
+ if (!fsStatus) {
+ super.configDisplayMode(screen, w, width, height, bitDepth,
+ refreshRate);
+ return;
+ }
+
+ final WWindowPeer wpeer = (WWindowPeer)realFSWindow.getPeer();
+
+ // REMIND: we do this before we switch the display mode, so
+ // the dimensions may be exceeding the dimensions of the screen,
+ // is this a problem?
+
+ // update the bounds of the owner frame
+ if (getFullScreenWindow() != realFSWindow) {
+ Rectangle screenBounds = getDefaultConfiguration().getBounds();
+ wpeer.reshape(screenBounds.x, screenBounds.y, width, height);
+ }
+
+ D3DRenderQueue rq = D3DRenderQueue.getInstance();
+ rq.lock();
+ try {
+ rq.flushAndInvokeNow(new Runnable() {
+ public void run() {
+ long hwnd = wpeer.getHWnd();
+ if (hwnd == 0l) {
+ // window is disposed
+ return;
+ }
+ // REMIND: do we really need a window here?
+ // we should probably just use the current one
+ configDisplayModeNative(screen, hwnd, width, height,
+ bitDepth, refreshRate);
+ }
+ });
+ } finally {
+ rq.unlock();
+ }
+ }
+
+ private static native void enumDisplayModesNative(int screen,
+ ArrayList modes);
+ @Override
+ protected void enumDisplayModes(final int screen, final ArrayList modes) {
+ D3DRenderQueue rq = D3DRenderQueue.getInstance();
+ rq.lock();
+ try {
+ rq.flushAndInvokeNow(new Runnable() {
+ public void run() {
+ enumDisplayModesNative(screen, modes);
+ }
+ });
+ if (modes.size() == 0) {
+ modes.add(getCurrentDisplayModeNative(screen));
+ }
+ } finally {
+ rq.unlock();
+ }
+ }
+
+ private static native long getAvailableAcceleratedMemoryNative(int screen);
+ @Override
+ public int getAvailableAcceleratedMemory() {
+ D3DRenderQueue rq = D3DRenderQueue.getInstance();
+ rq.lock();
+ try {
+ class Result {
+ long mem = 0L;
+ };
+ final Result res = new Result();
+ rq.flushAndInvokeNow(new Runnable() {
+ public void run() {
+ res.mem = getAvailableAcceleratedMemoryNative(getScreen());
+ }
+ });
+ return (int)res.mem;
+ } finally {
+ rq.unlock();
+ }
+ }
+
+ @Override
+ public GraphicsConfiguration[] getConfigurations() {
+ if (configs == null) {
+ if (isD3DEnabledOnDevice()) {
+ defaultConfig = getDefaultConfiguration();
+ if (defaultConfig != null) {
+ configs = new GraphicsConfiguration[1];
+ configs[0] = defaultConfig;
+ return configs;
+ }
+ }
+ }
+ return super.getConfigurations();
+ }
+
+ @Override
+ public GraphicsConfiguration getDefaultConfiguration() {
+ if (defaultConfig == null) {
+ if (isD3DEnabledOnDevice()) {
+ defaultConfig = new D3DGraphicsConfig(this);
+ } else {
+ defaultConfig = super.getDefaultConfiguration();
+ }
+ }
+ return defaultConfig;
+ }
+
+ private static native boolean isD3DAvailableOnDeviceNative(int screen);
+ // REMIND: this method is not used now, we use caps instead
+ public static boolean isD3DAvailableOnDevice(final int screen) {
+ if (!d3dAvailable) {
+ return false;
+ }
+
+ // REMIND: should we cache the result per device somehow,
+ // and then reset and retry it on display change?
+ D3DRenderQueue rq = D3DRenderQueue.getInstance();
+ rq.lock();
+ try {
+ class Result {
+ boolean avail = false;
+ };
+ final Result res = new Result();
+ rq.flushAndInvokeNow(new Runnable() {
+ public void run() {
+ res.avail = isD3DAvailableOnDeviceNative(screen);
+ }
+ });
+ return res.avail;
+ } finally {
+ rq.unlock();
+ }
+ }
+
+ D3DContext getContext() {
+ return context;
+ }
+
+ ContextCapabilities getContextCapabilities() {
+ return d3dCaps;
+ }
+
+ @Override
+ public void displayChanged() {
+ super.displayChanged();
+ // REMIND: make sure this works when the device is lost and we don't
+ // disable d3d too eagerly
+ if (d3dAvailable) {
+ d3dCaps = getDeviceCaps(getScreen());
+ }
+ }
+
+ @Override
+ protected void invalidate(int defaultScreen) {
+ super.invalidate(defaultScreen);
+ // REMIND: this is a bit excessive, isD3DEnabledOnDevice will return
+ // false anyway because the device is invalid
+ d3dCaps = new D3DContextCaps(CAPS_EMPTY, null);
+ }
+}