Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mobile
Path: blob/master/src/java.desktop/windows/classes/sun/java2d/d3d/D3DGraphicsDevice.java
41159 views
1
/*
2
* Copyright (c) 2007, 2019, Oracle and/or its affiliates. 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. Oracle designates this
8
* particular file as subject to the "Classpath" exception as provided
9
* by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22
* or visit www.oracle.com if you need additional information or have any
23
* questions.
24
*/
25
26
package sun.java2d.d3d;
27
28
import java.awt.Dialog;
29
import java.awt.DisplayMode;
30
import java.awt.Frame;
31
import java.awt.GraphicsConfiguration;
32
import java.awt.Rectangle;
33
import java.awt.Toolkit;
34
import java.awt.Window;
35
import java.awt.event.WindowAdapter;
36
import java.awt.event.WindowEvent;
37
import java.awt.event.WindowListener;
38
import java.awt.peer.WindowPeer;
39
import java.util.ArrayList;
40
41
import sun.awt.AWTAccessor;
42
import sun.awt.AWTAccessor.ComponentAccessor;
43
import sun.awt.Win32GraphicsDevice;
44
import sun.awt.windows.WWindowPeer;
45
import sun.java2d.d3d.D3DContext.D3DContextCaps;
46
import sun.java2d.pipe.hw.ContextCapabilities;
47
import sun.java2d.windows.WindowsFlags;
48
49
import static sun.java2d.d3d.D3DContext.D3DContextCaps.CAPS_DEVICE_OK;
50
import static sun.java2d.d3d.D3DContext.D3DContextCaps.CAPS_EMPTY;
51
52
/**
53
* This class implements D3D-specific functionality, such as fullscreen
54
* exclusive mode and display changes. It is kept separate from
55
* Win32GraphicsDevice to help avoid overburdening the parent class.
56
*/
57
public final class D3DGraphicsDevice extends Win32GraphicsDevice {
58
private D3DContext context;
59
60
private static boolean d3dAvailable;
61
62
private ContextCapabilities d3dCaps;
63
64
private static native boolean initD3D();
65
66
static {
67
// loading the library doesn't help because we need the
68
// toolkit thread running, so we have to call getDefaultToolkit()
69
Toolkit.getDefaultToolkit();
70
d3dAvailable = initD3D();
71
if (d3dAvailable) {
72
// we don't use pixel formats for the d3d pipeline
73
pfDisabled = true;
74
}
75
}
76
77
/**
78
* Used to construct a Direct3D-enabled GraphicsDevice.
79
*
80
* @return a D3DGraphicsDevice if it could be created
81
* successfully, null otherwise.
82
*/
83
public static D3DGraphicsDevice createDevice(int screen) {
84
if (!d3dAvailable) {
85
return null;
86
}
87
88
ContextCapabilities d3dCaps = getDeviceCaps(screen);
89
// could not initialize the device successfully
90
if ((d3dCaps.getCaps() & CAPS_DEVICE_OK) == 0) {
91
if (WindowsFlags.isD3DVerbose()) {
92
System.out.println("Could not enable Direct3D pipeline on " +
93
"screen " + screen);
94
}
95
return null;
96
}
97
if (WindowsFlags.isD3DVerbose()) {
98
System.out.println("Direct3D pipeline enabled on screen " + screen);
99
}
100
101
D3DGraphicsDevice gd = new D3DGraphicsDevice(screen, d3dCaps);
102
return gd;
103
}
104
105
private static native int getDeviceCapsNative(int screen);
106
private static native String getDeviceIdNative(int screen);
107
private static ContextCapabilities getDeviceCaps(final int screen) {
108
ContextCapabilities d3dCaps = null;
109
D3DRenderQueue rq = D3DRenderQueue.getInstance();
110
rq.lock();
111
try {
112
class Result {
113
int caps;
114
String id;
115
};
116
final Result res = new Result();
117
rq.flushAndInvokeNow(new Runnable() {
118
public void run() {
119
res.caps = getDeviceCapsNative(screen);
120
res.id = getDeviceIdNative(screen);
121
}
122
});
123
d3dCaps = new D3DContextCaps(res.caps, res.id);
124
} finally {
125
rq.unlock();
126
}
127
128
return d3dCaps != null ? d3dCaps : new D3DContextCaps(CAPS_EMPTY, null);
129
}
130
131
public final boolean isCapPresent(int cap) {
132
return ((d3dCaps.getCaps() & cap) != 0);
133
}
134
135
private D3DGraphicsDevice(int screennum, ContextCapabilities d3dCaps) {
136
super(screennum);
137
descString = "D3DGraphicsDevice[screen="+screennum;
138
this.d3dCaps = d3dCaps;
139
context = new D3DContext(D3DRenderQueue.getInstance(), this);
140
}
141
142
public boolean isD3DEnabledOnDevice() {
143
return isValid() && isCapPresent(CAPS_DEVICE_OK);
144
}
145
146
/**
147
* Returns true if d3d pipeline has been successfully initialized.
148
* @return true if d3d pipeline is initialized, false otherwise
149
*/
150
public static boolean isD3DAvailable() {
151
return d3dAvailable;
152
}
153
154
/**
155
* Return the owning Frame for a given Window. Used in setFSWindow below
156
* to set the properties of the owning Frame when a Window goes
157
* into fullscreen mode.
158
*/
159
private Frame getToplevelOwner(Window w) {
160
Window owner = w;
161
while (owner != null) {
162
owner = owner.getOwner();
163
if (owner instanceof Frame) {
164
return (Frame) owner;
165
}
166
}
167
// could get here if passed Window is an owner-less Dialog
168
return null;
169
}
170
171
private boolean fsStatus;
172
private Rectangle ownerOrigBounds = null;
173
private boolean ownerWasVisible;
174
private Window realFSWindow;
175
private WindowListener fsWindowListener;
176
private boolean fsWindowWasAlwaysOnTop;
177
private static native boolean enterFullScreenExclusiveNative(int screen,
178
long hwnd);
179
180
@Override
181
protected void enterFullScreenExclusive(final int screen, WindowPeer wp)
182
{
183
final WWindowPeer wpeer = AWTAccessor.getComponentAccessor()
184
.getPeer(realFSWindow);
185
D3DRenderQueue rq = D3DRenderQueue.getInstance();
186
rq.lock();
187
try {
188
rq.flushAndInvokeNow(new Runnable() {
189
public void run() {
190
long hwnd = wpeer.getHWnd();
191
if (hwnd == 0l) {
192
// window is disposed
193
fsStatus = false;
194
return;
195
}
196
fsStatus = enterFullScreenExclusiveNative(screen, hwnd);
197
}
198
});
199
} finally {
200
rq.unlock();
201
}
202
if (!fsStatus) {
203
super.enterFullScreenExclusive(screen, wp);
204
}
205
}
206
207
private static native boolean exitFullScreenExclusiveNative(int screen);
208
@Override
209
protected void exitFullScreenExclusive(final int screen, WindowPeer w) {
210
if (fsStatus) {
211
D3DRenderQueue rq = D3DRenderQueue.getInstance();
212
rq.lock();
213
try {
214
rq.flushAndInvokeNow(new Runnable() {
215
public void run() {
216
exitFullScreenExclusiveNative(screen);
217
}
218
});
219
} finally {
220
rq.unlock();
221
}
222
} else {
223
super.exitFullScreenExclusive(screen, w);
224
}
225
}
226
227
/**
228
* WindowAdapter class for the full-screen frame, responsible for
229
* restoring the devices. This is important to do because unless the device
230
* is restored it will not go back into the FS mode once alt+tabbed out.
231
* This is a problem for windows for which we do not do any d3d-related
232
* operations (like when we disabled on-screen rendering).
233
*
234
* REMIND: we create an instance per each full-screen device while a single
235
* instance would suffice (but requires more management).
236
*/
237
private static class D3DFSWindowAdapter extends WindowAdapter {
238
@Override
239
@SuppressWarnings("static")
240
public void windowDeactivated(WindowEvent e) {
241
D3DRenderQueue.getInstance().restoreDevices();
242
}
243
@Override
244
@SuppressWarnings("static")
245
public void windowActivated(WindowEvent e) {
246
D3DRenderQueue.getInstance().restoreDevices();
247
}
248
}
249
250
@Override
251
protected void addFSWindowListener(Window w) {
252
// if the window is not a toplevel (has an owner) we have to use the
253
// real toplevel to enter the full-screen mode with (4933099).
254
final ComponentAccessor acc = AWTAccessor.getComponentAccessor();
255
if (!(w instanceof Frame) && !(w instanceof Dialog) &&
256
(realFSWindow = getToplevelOwner(w)) != null)
257
{
258
ownerOrigBounds = realFSWindow.getBounds();
259
WWindowPeer fp = acc.getPeer(realFSWindow);
260
ownerWasVisible = realFSWindow.isVisible();
261
Rectangle r = w.getBounds();
262
// we use operations on peer instead of component because calling
263
// them on component will take the tree lock
264
fp.reshape(r.x, r.y, r.width, r.height);
265
fp.setVisible(true);
266
} else {
267
realFSWindow = w;
268
}
269
270
fsWindowWasAlwaysOnTop = realFSWindow.isAlwaysOnTop();
271
((WWindowPeer) acc.getPeer(realFSWindow)).setAlwaysOnTop(true);
272
273
fsWindowListener = new D3DFSWindowAdapter();
274
realFSWindow.addWindowListener(fsWindowListener);
275
}
276
277
@Override
278
protected void removeFSWindowListener(Window w) {
279
realFSWindow.removeWindowListener(fsWindowListener);
280
fsWindowListener = null;
281
282
/**
283
* Bug 4933099: There is some funny-business to deal with when this
284
* method is called with a Window instead of a Frame. See 4836744
285
* for more information on this. One side-effect of our workaround
286
* for the problem is that the owning Frame of a Window may end
287
* up getting resized during the fullscreen process. When we
288
* return from fullscreen mode, we should resize the Frame to
289
* its original size (just like the Window is being resized
290
* to its original size in GraphicsDevice).
291
*/
292
final WWindowPeer wpeer = AWTAccessor.getComponentAccessor()
293
.getPeer(realFSWindow);
294
if (wpeer != null) {
295
if (ownerOrigBounds != null) {
296
// if the window went into fs mode before it was realized it
297
// could have (0,0) dimensions
298
if (ownerOrigBounds.width == 0) ownerOrigBounds.width = 1;
299
if (ownerOrigBounds.height == 0) ownerOrigBounds.height = 1;
300
wpeer.reshape(ownerOrigBounds.x, ownerOrigBounds.y,
301
ownerOrigBounds.width, ownerOrigBounds.height);
302
if (!ownerWasVisible) {
303
wpeer.setVisible(false);
304
}
305
ownerOrigBounds = null;
306
}
307
if (!fsWindowWasAlwaysOnTop) {
308
wpeer.setAlwaysOnTop(false);
309
}
310
}
311
312
realFSWindow = null;
313
}
314
315
private static native DisplayMode getCurrentDisplayModeNative(int screen);
316
@Override
317
protected DisplayMode getCurrentDisplayMode(final int screen) {
318
D3DRenderQueue rq = D3DRenderQueue.getInstance();
319
rq.lock();
320
try {
321
class Result {
322
DisplayMode dm = null;
323
};
324
final Result res = new Result();
325
rq.flushAndInvokeNow(new Runnable() {
326
public void run() {
327
res.dm = getCurrentDisplayModeNative(screen);
328
}
329
});
330
if (res.dm == null) {
331
return super.getCurrentDisplayMode(screen);
332
}
333
return res.dm;
334
} finally {
335
rq.unlock();
336
}
337
}
338
private static native void configDisplayModeNative(int screen, long hwnd,
339
int width, int height,
340
int bitDepth,
341
int refreshRate);
342
@Override
343
protected void configDisplayMode(final int screen, final WindowPeer w,
344
final int width, final int height,
345
final int bitDepth, final int refreshRate)
346
{
347
// we entered fs mode via gdi
348
if (!fsStatus) {
349
super.configDisplayMode(screen, w, width, height, bitDepth,
350
refreshRate);
351
return;
352
}
353
final WWindowPeer wpeer = AWTAccessor.getComponentAccessor()
354
.getPeer(realFSWindow);
355
356
// REMIND: we do this before we switch the display mode, so
357
// the dimensions may be exceeding the dimensions of the screen,
358
// is this a problem?
359
360
// update the bounds of the owner frame
361
if (getFullScreenWindow() != realFSWindow) {
362
Rectangle screenBounds = getDefaultConfiguration().getBounds();
363
wpeer.reshape(screenBounds.x, screenBounds.y, width, height);
364
}
365
366
D3DRenderQueue rq = D3DRenderQueue.getInstance();
367
rq.lock();
368
try {
369
rq.flushAndInvokeNow(new Runnable() {
370
public void run() {
371
long hwnd = wpeer.getHWnd();
372
if (hwnd == 0l) {
373
// window is disposed
374
return;
375
}
376
// REMIND: do we really need a window here?
377
// we should probably just use the current one
378
configDisplayModeNative(screen, hwnd, width, height,
379
bitDepth, refreshRate);
380
}
381
});
382
} finally {
383
rq.unlock();
384
}
385
}
386
387
private static native void enumDisplayModesNative(int screen,
388
ArrayList<DisplayMode> modes);
389
@Override
390
protected void enumDisplayModes(final int screen, final ArrayList<DisplayMode> modes) {
391
D3DRenderQueue rq = D3DRenderQueue.getInstance();
392
rq.lock();
393
try {
394
rq.flushAndInvokeNow(new Runnable() {
395
public void run() {
396
enumDisplayModesNative(screen, modes);
397
}
398
});
399
if (modes.size() == 0) {
400
modes.add(getCurrentDisplayModeNative(screen));
401
}
402
} finally {
403
rq.unlock();
404
}
405
}
406
407
private static native long getAvailableAcceleratedMemoryNative(int screen);
408
@Override
409
public int getAvailableAcceleratedMemory() {
410
D3DRenderQueue rq = D3DRenderQueue.getInstance();
411
rq.lock();
412
try {
413
class Result {
414
long mem = 0L;
415
};
416
final Result res = new Result();
417
rq.flushAndInvokeNow(new Runnable() {
418
public void run() {
419
res.mem = getAvailableAcceleratedMemoryNative(getScreen());
420
}
421
});
422
return (int)res.mem;
423
} finally {
424
rq.unlock();
425
}
426
}
427
428
@Override
429
public GraphicsConfiguration[] getConfigurations() {
430
if (configs == null) {
431
if (isD3DEnabledOnDevice()) {
432
defaultConfig = getDefaultConfiguration();
433
if (defaultConfig != null) {
434
configs = new GraphicsConfiguration[1];
435
configs[0] = defaultConfig;
436
return configs.clone();
437
}
438
}
439
}
440
return super.getConfigurations();
441
}
442
443
@Override
444
public GraphicsConfiguration getDefaultConfiguration() {
445
if (defaultConfig == null) {
446
if (isD3DEnabledOnDevice()) {
447
defaultConfig = new D3DGraphicsConfig(this);
448
} else {
449
defaultConfig = super.getDefaultConfiguration();
450
}
451
}
452
return defaultConfig;
453
}
454
455
private static native boolean isD3DAvailableOnDeviceNative(int screen);
456
// REMIND: this method is not used now, we use caps instead
457
public static boolean isD3DAvailableOnDevice(final int screen) {
458
if (!d3dAvailable) {
459
return false;
460
}
461
462
// REMIND: should we cache the result per device somehow,
463
// and then reset and retry it on display change?
464
D3DRenderQueue rq = D3DRenderQueue.getInstance();
465
rq.lock();
466
try {
467
class Result {
468
boolean avail = false;
469
};
470
final Result res = new Result();
471
rq.flushAndInvokeNow(new Runnable() {
472
public void run() {
473
res.avail = isD3DAvailableOnDeviceNative(screen);
474
}
475
});
476
return res.avail;
477
} finally {
478
rq.unlock();
479
}
480
}
481
482
D3DContext getContext() {
483
return context;
484
}
485
486
ContextCapabilities getContextCapabilities() {
487
return d3dCaps;
488
}
489
490
@Override
491
public void displayChanged() {
492
super.displayChanged();
493
// REMIND: make sure this works when the device is lost and we don't
494
// disable d3d too eagerly
495
if (d3dAvailable) {
496
d3dCaps = getDeviceCaps(getScreen());
497
}
498
}
499
500
@Override
501
protected void invalidate(int defaultScreen) {
502
super.invalidate(defaultScreen);
503
// REMIND: this is a bit excessive, isD3DEnabledOnDevice will return
504
// false anyway because the device is invalid
505
d3dCaps = new D3DContextCaps(CAPS_EMPTY, null);
506
}
507
}
508
509