Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/windows/classes/sun/java2d/d3d/D3DGraphicsDevice.java
32288 views
/*1* Copyright (c) 2007, 2008, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425package sun.java2d.d3d;2627import java.awt.Dialog;28import java.awt.DisplayMode;29import java.awt.Frame;30import java.awt.GraphicsConfiguration;31import java.awt.Rectangle;32import java.awt.Toolkit;33import java.awt.Window;34import java.awt.event.WindowAdapter;35import java.awt.event.WindowEvent;36import java.awt.event.WindowListener;37import java.awt.peer.WindowPeer;38import java.util.ArrayList;39import sun.awt.Win32GraphicsDevice;40import sun.awt.windows.WWindowPeer;41import sun.java2d.pipe.hw.ContextCapabilities;42import sun.java2d.windows.WindowsFlags;43import static sun.java2d.pipe.BufferedOpCodes.*;44import static sun.java2d.d3d.D3DContext.D3DContextCaps.*;45import sun.java2d.d3d.D3DContext.D3DContextCaps;4647/**48* This class implements D3D-specific functionality, such as fullscreen49* exclusive mode and display changes. It is kept separate from50* Win32GraphicsDevice to help avoid overburdening the parent class.51*/52public class D3DGraphicsDevice extends Win32GraphicsDevice {53private D3DContext context;5455private static boolean d3dAvailable;5657private ContextCapabilities d3dCaps;5859private static native boolean initD3D();6061static {62// loading the library doesn't help because we need the63// toolkit thread running, so we have to call getDefaultToolkit()64Toolkit.getDefaultToolkit();65d3dAvailable = initD3D();66if (d3dAvailable) {67// we don't use pixel formats for the d3d pipeline68pfDisabled = true;69sun.misc.PerfCounter.getD3DAvailable().set(1);70} else {71sun.misc.PerfCounter.getD3DAvailable().set(0);72}73}7475/**76* Used to construct a Direct3D-enabled GraphicsDevice.77*78* @return a D3DGraphicsDevice if it could be created79* successfully, null otherwise.80*/81public static D3DGraphicsDevice createDevice(int screen) {82if (!d3dAvailable) {83return null;84}8586ContextCapabilities d3dCaps = getDeviceCaps(screen);87// could not initialize the device successfully88if ((d3dCaps.getCaps() & CAPS_DEVICE_OK) == 0) {89if (WindowsFlags.isD3DVerbose()) {90System.out.println("Could not enable Direct3D pipeline on " +91"screen " + screen);92}93return null;94}95if (WindowsFlags.isD3DVerbose()) {96System.out.println("Direct3D pipeline enabled on screen " + screen);97}9899D3DGraphicsDevice gd = new D3DGraphicsDevice(screen, d3dCaps);100return gd;101}102103private static native int getDeviceCapsNative(int screen);104private static native String getDeviceIdNative(int screen);105private static ContextCapabilities getDeviceCaps(final int screen) {106ContextCapabilities d3dCaps = null;107D3DRenderQueue rq = D3DRenderQueue.getInstance();108rq.lock();109try {110class Result {111int caps;112String id;113};114final Result res = new Result();115rq.flushAndInvokeNow(new Runnable() {116public void run() {117res.caps = getDeviceCapsNative(screen);118res.id = getDeviceIdNative(screen);119}120});121d3dCaps = new D3DContextCaps(res.caps, res.id);122} finally {123rq.unlock();124}125126return d3dCaps != null ? d3dCaps : new D3DContextCaps(CAPS_EMPTY, null);127}128129public final boolean isCapPresent(int cap) {130return ((d3dCaps.getCaps() & cap) != 0);131}132133private D3DGraphicsDevice(int screennum, ContextCapabilities d3dCaps) {134super(screennum);135descString = "D3DGraphicsDevice[screen="+screennum;136this.d3dCaps = d3dCaps;137context = new D3DContext(D3DRenderQueue.getInstance(), this);138}139140public boolean isD3DEnabledOnDevice() {141return isValid() && isCapPresent(CAPS_DEVICE_OK);142}143144/**145* Returns true if d3d pipeline has been successfully initialized.146* @return true if d3d pipeline is initialized, false otherwise147*/148public static boolean isD3DAvailable() {149return d3dAvailable;150}151152/**153* Return the owning Frame for a given Window. Used in setFSWindow below154* to set the properties of the owning Frame when a Window goes155* into fullscreen mode.156*/157private Frame getToplevelOwner(Window w) {158Window owner = w;159while (owner != null) {160owner = owner.getOwner();161if (owner instanceof Frame) {162return (Frame) owner;163}164}165// could get here if passed Window is an owner-less Dialog166return null;167}168169private boolean fsStatus;170private Rectangle ownerOrigBounds = null;171private boolean ownerWasVisible;172private Window realFSWindow;173private WindowListener fsWindowListener;174private boolean fsWindowWasAlwaysOnTop;175private static native boolean enterFullScreenExclusiveNative(int screen,176long hwnd);177178@Override179protected void enterFullScreenExclusive(final int screen, WindowPeer wp)180{181final WWindowPeer wpeer = (WWindowPeer)realFSWindow.getPeer();182183D3DRenderQueue rq = D3DRenderQueue.getInstance();184rq.lock();185try {186rq.flushAndInvokeNow(new Runnable() {187public void run() {188long hwnd = wpeer.getHWnd();189if (hwnd == 0l) {190// window is disposed191fsStatus = false;192return;193}194fsStatus = enterFullScreenExclusiveNative(screen, hwnd);195}196});197} finally {198rq.unlock();199}200if (!fsStatus) {201super.enterFullScreenExclusive(screen, wp);202}203}204205private static native boolean exitFullScreenExclusiveNative(int screen);206@Override207protected void exitFullScreenExclusive(final int screen, WindowPeer w) {208if (fsStatus) {209D3DRenderQueue rq = D3DRenderQueue.getInstance();210rq.lock();211try {212rq.flushAndInvokeNow(new Runnable() {213public void run() {214exitFullScreenExclusiveNative(screen);215}216});217} finally {218rq.unlock();219}220} else {221super.exitFullScreenExclusive(screen, w);222}223}224225/**226* WindowAdapter class for the full-screen frame, responsible for227* restoring the devices. This is important to do because unless the device228* is restored it will not go back into the FS mode once alt+tabbed out.229* This is a problem for windows for which we do not do any d3d-related230* operations (like when we disabled on-screen rendering).231*232* REMIND: we create an instance per each full-screen device while a single233* instance would suffice (but requires more management).234*/235private static class D3DFSWindowAdapter extends WindowAdapter {236@Override237public void windowDeactivated(WindowEvent e) {238D3DRenderQueue.getInstance().restoreDevices();239}240@Override241public void windowActivated(WindowEvent e) {242D3DRenderQueue.getInstance().restoreDevices();243}244}245246@Override247protected void addFSWindowListener(Window w) {248// if the window is not a toplevel (has an owner) we have to use the249// real toplevel to enter the full-screen mode with (4933099).250if (!(w instanceof Frame) && !(w instanceof Dialog) &&251(realFSWindow = getToplevelOwner(w)) != null)252{253ownerOrigBounds = realFSWindow.getBounds();254WWindowPeer fp = (WWindowPeer)realFSWindow.getPeer();255256ownerWasVisible = realFSWindow.isVisible();257Rectangle r = w.getBounds();258// we use operations on peer instead of component because calling259// them on component will take the tree lock260fp.reshape(r.x, r.y, r.width, r.height);261fp.setVisible(true);262} else {263realFSWindow = w;264}265266fsWindowWasAlwaysOnTop = realFSWindow.isAlwaysOnTop();267((WWindowPeer)realFSWindow.getPeer()).setAlwaysOnTop(true);268269fsWindowListener = new D3DFSWindowAdapter();270realFSWindow.addWindowListener(fsWindowListener);271}272273@Override274protected void removeFSWindowListener(Window w) {275realFSWindow.removeWindowListener(fsWindowListener);276fsWindowListener = null;277278/**279* Bug 4933099: There is some funny-business to deal with when this280* method is called with a Window instead of a Frame. See 4836744281* for more information on this. One side-effect of our workaround282* for the problem is that the owning Frame of a Window may end283* up getting resized during the fullscreen process. When we284* return from fullscreen mode, we should resize the Frame to285* its original size (just like the Window is being resized286* to its original size in GraphicsDevice).287*/288WWindowPeer wpeer = (WWindowPeer)realFSWindow.getPeer();289if (wpeer != null) {290if (ownerOrigBounds != null) {291// if the window went into fs mode before it was realized it292// could have (0,0) dimensions293if (ownerOrigBounds.width == 0) ownerOrigBounds.width = 1;294if (ownerOrigBounds.height == 0) ownerOrigBounds.height = 1;295wpeer.reshape(ownerOrigBounds.x, ownerOrigBounds.y,296ownerOrigBounds.width, ownerOrigBounds.height);297if (!ownerWasVisible) {298wpeer.setVisible(false);299}300ownerOrigBounds = null;301}302if (!fsWindowWasAlwaysOnTop) {303wpeer.setAlwaysOnTop(false);304}305}306307realFSWindow = null;308}309310private static native DisplayMode getCurrentDisplayModeNative(int screen);311@Override312protected DisplayMode getCurrentDisplayMode(final int screen) {313D3DRenderQueue rq = D3DRenderQueue.getInstance();314rq.lock();315try {316class Result {317DisplayMode dm = null;318};319final Result res = new Result();320rq.flushAndInvokeNow(new Runnable() {321public void run() {322res.dm = getCurrentDisplayModeNative(screen);323}324});325if (res.dm == null) {326return super.getCurrentDisplayMode(screen);327}328return res.dm;329} finally {330rq.unlock();331}332}333private static native void configDisplayModeNative(int screen, long hwnd,334int width, int height,335int bitDepth,336int refreshRate);337@Override338protected void configDisplayMode(final int screen, final WindowPeer w,339final int width, final int height,340final int bitDepth, final int refreshRate)341{342// we entered fs mode via gdi343if (!fsStatus) {344super.configDisplayMode(screen, w, width, height, bitDepth,345refreshRate);346return;347}348349final WWindowPeer wpeer = (WWindowPeer)realFSWindow.getPeer();350351// REMIND: we do this before we switch the display mode, so352// the dimensions may be exceeding the dimensions of the screen,353// is this a problem?354355// update the bounds of the owner frame356if (getFullScreenWindow() != realFSWindow) {357Rectangle screenBounds = getDefaultConfiguration().getBounds();358wpeer.reshape(screenBounds.x, screenBounds.y, width, height);359}360361D3DRenderQueue rq = D3DRenderQueue.getInstance();362rq.lock();363try {364rq.flushAndInvokeNow(new Runnable() {365public void run() {366long hwnd = wpeer.getHWnd();367if (hwnd == 0l) {368// window is disposed369return;370}371// REMIND: do we really need a window here?372// we should probably just use the current one373configDisplayModeNative(screen, hwnd, width, height,374bitDepth, refreshRate);375}376});377} finally {378rq.unlock();379}380}381382private static native void enumDisplayModesNative(int screen,383ArrayList modes);384@Override385protected void enumDisplayModes(final int screen, final ArrayList modes) {386D3DRenderQueue rq = D3DRenderQueue.getInstance();387rq.lock();388try {389rq.flushAndInvokeNow(new Runnable() {390public void run() {391enumDisplayModesNative(screen, modes);392}393});394if (modes.size() == 0) {395modes.add(getCurrentDisplayModeNative(screen));396}397} finally {398rq.unlock();399}400}401402private static native long getAvailableAcceleratedMemoryNative(int screen);403@Override404public int getAvailableAcceleratedMemory() {405D3DRenderQueue rq = D3DRenderQueue.getInstance();406rq.lock();407try {408class Result {409long mem = 0L;410};411final Result res = new Result();412rq.flushAndInvokeNow(new Runnable() {413public void run() {414res.mem = getAvailableAcceleratedMemoryNative(getScreen());415}416});417return (int)res.mem;418} finally {419rq.unlock();420}421}422423@Override424public GraphicsConfiguration[] getConfigurations() {425if (configs == null) {426if (isD3DEnabledOnDevice()) {427defaultConfig = getDefaultConfiguration();428if (defaultConfig != null) {429configs = new GraphicsConfiguration[1];430configs[0] = defaultConfig;431return configs.clone();432}433}434}435return super.getConfigurations();436}437438@Override439public GraphicsConfiguration getDefaultConfiguration() {440if (defaultConfig == null) {441if (isD3DEnabledOnDevice()) {442defaultConfig = new D3DGraphicsConfig(this);443} else {444defaultConfig = super.getDefaultConfiguration();445}446}447return defaultConfig;448}449450private static native boolean isD3DAvailableOnDeviceNative(int screen);451// REMIND: this method is not used now, we use caps instead452public static boolean isD3DAvailableOnDevice(final int screen) {453if (!d3dAvailable) {454return false;455}456457// REMIND: should we cache the result per device somehow,458// and then reset and retry it on display change?459D3DRenderQueue rq = D3DRenderQueue.getInstance();460rq.lock();461try {462class Result {463boolean avail = false;464};465final Result res = new Result();466rq.flushAndInvokeNow(new Runnable() {467public void run() {468res.avail = isD3DAvailableOnDeviceNative(screen);469}470});471return res.avail;472} finally {473rq.unlock();474}475}476477D3DContext getContext() {478return context;479}480481ContextCapabilities getContextCapabilities() {482return d3dCaps;483}484485@Override486public void displayChanged() {487super.displayChanged();488// REMIND: make sure this works when the device is lost and we don't489// disable d3d too eagerly490if (d3dAvailable) {491d3dCaps = getDeviceCaps(getScreen());492}493}494495@Override496protected void invalidate(int defaultScreen) {497super.invalidate(defaultScreen);498// REMIND: this is a bit excessive, isD3DEnabledOnDevice will return499// false anyway because the device is invalid500d3dCaps = new D3DContextCaps(CAPS_EMPTY, null);501}502}503504505