1 /*
2 * Copyright (c) 2007, 2011, 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 #include "sun_java2d_d3d_D3DGraphicsDevice.h"
27 #include "D3DGraphicsDevice.h"
28 #include "D3DPipelineManager.h"
29 #include "D3DRenderQueue.h"
30 #include "Trace.h"
31 #include "awt_Toolkit.h"
32 #include "awt_Window.h"
33
34 extern jobject CreateDisplayMode(JNIEnv* env, jint width, jint height,
35 jint bitDepth, jint refreshRate);
36 extern void addDisplayMode(JNIEnv* env, jobject arrayList, jint width,
37 jint height, jint bitDepth, jint refreshRate);
38
39 extern "C" {
40 /*
41 * Class: sun_java2d_d3d_D3DGraphicsDevice
42 * Method: initD3D
43 * Signature: ()Z
44 */
Java_sun_java2d_d3d_D3DGraphicsDevice_initD3D(JNIEnv * env,jclass)45 JNIEXPORT jboolean JNICALL Java_sun_java2d_d3d_D3DGraphicsDevice_initD3D
46 (JNIEnv *env, jclass)
47 {
48 J2dTraceLn(J2D_TRACE_INFO, "D3DGD_initD3D");
49
50 jboolean result = D3DInitializer::GetInstance().EnsureInited()
51 ? JNI_TRUE : JNI_FALSE;
52 J2dTraceLn1(J2D_TRACE_INFO, "D3DGD_initD3D: result=%x", result);
53 return result;
54 }
55
56 /*
57 * Class: sun_java2d_d3d_D3DGraphicsDevice
58 * Method: getDeviceIdNative
59 * Signature: (I)Ljava/lang/String;
60 */
Java_sun_java2d_d3d_D3DGraphicsDevice_getDeviceIdNative(JNIEnv * env,jclass d3dsdc,jint gdiScreen)61 JNIEXPORT jstring JNICALL Java_sun_java2d_d3d_D3DGraphicsDevice_getDeviceIdNative
62 (JNIEnv *env, jclass d3dsdc, jint gdiScreen)
63 {
64 D3DPipelineManager *pMgr;
65 UINT adapter;
66 D3DADAPTER_IDENTIFIER9 aid;
67 IDirect3D9 *pd3d9;
68
69 J2dTraceLn(J2D_TRACE_INFO, "D3DGD_getDeviceIdNative");
70
71 pMgr = D3DPipelineManager::GetInstance();
72 RETURN_STATUS_IF_NULL(pMgr, NULL);
73 pd3d9 = pMgr->GetD3DObject();
74 RETURN_STATUS_IF_NULL(pd3d9, NULL);
75
76 adapter = pMgr->GetAdapterOrdinalForScreen(gdiScreen);
77 if (FAILED(pd3d9->GetAdapterIdentifier(adapter, 0, &aid))) {
78 return NULL;
79 }
80
81 // ('%d.' will take no more than 6+1 chars since we are printing a WORD)
82 // AAAA&BBBB MAX_DEVICE_IDENTIFIER_STRING (%d.%d.%d.%d)0
83 size_t len = (4+1+4 +1+MAX_DEVICE_IDENTIFIER_STRING+1 +1+(6+1)*4+1 +1);
84 WCHAR *pAdapterId = new WCHAR[len];
85 RETURN_STATUS_IF_NULL(pAdapterId, NULL);
86
87 _snwprintf(pAdapterId, len, L"%x&%x %S (%d.%d.%d.%d)",
88 0xffff & aid.VendorId, 0xffff & aid.DeviceId, aid.Description,
89 HIWORD(aid.DriverVersion.HighPart),
90 LOWORD(aid.DriverVersion.HighPart),
91 HIWORD(aid.DriverVersion.LowPart),
92 LOWORD(aid.DriverVersion.LowPart));
93 // _snwprintf doesn't add 0 at the end if the formatted string didn't fit
94 // in the buffer so we have to make sure it is null terminated
95 pAdapterId[len-1] = (WCHAR)0;
96
97 J2dTraceLn1(J2D_TRACE_VERBOSE, " id=%S", pAdapterId);
98
99 jstring ret = JNU_NewStringPlatform(env, pAdapterId);
100
101 delete[] pAdapterId;
102
103 return ret;
104 }
105
106 /*
107 * Class: sun_java2d_d3d_D3DGraphicsDevice
108 * Method: getDeviceCapsNative
109 * Signature: (I)I
110 */
111 JNIEXPORT jint JNICALL
Java_sun_java2d_d3d_D3DGraphicsDevice_getDeviceCapsNative(JNIEnv * env,jclass d3dsdc,jint gdiScreen)112 Java_sun_java2d_d3d_D3DGraphicsDevice_getDeviceCapsNative
113 (JNIEnv *env, jclass d3dsdc, jint gdiScreen)
114 {
115 D3DPipelineManager *pMgr;
116 D3DContext *pCtx;
117 UINT adapter;
118
119 J2dRlsTraceLn(J2D_TRACE_INFO, "D3DGD_getDeviceCapsNative");
120
121 pMgr = D3DPipelineManager::GetInstance();
122 RETURN_STATUS_IF_NULL(pMgr, CAPS_EMPTY);
123 adapter = pMgr->GetAdapterOrdinalForScreen(gdiScreen);
124
125 if (FAILED(pMgr->GetD3DContext(adapter, &pCtx))) {
126 J2dRlsTraceLn1(J2D_TRACE_ERROR,
127 "D3DGD_getDeviceCapsNative: device %d disabled", adapter);
128 return CAPS_EMPTY;
129 }
130 return pCtx->GetContextCaps();
131 }
132
133 /*
134 * Class: sun_java2d_d3d_D3DGraphicsDevice
135 * Method: enterFullScreenExclusiveNative
136 * Signature: (IJ)V
137 */
138 JNIEXPORT jboolean JNICALL
Java_sun_java2d_d3d_D3DGraphicsDevice_enterFullScreenExclusiveNative(JNIEnv * env,jclass gdc,jint gdiScreen,jlong window)139 Java_sun_java2d_d3d_D3DGraphicsDevice_enterFullScreenExclusiveNative
140 (JNIEnv *env, jclass gdc, jint gdiScreen, jlong window)
141 {
142 HRESULT res;
143 D3DPipelineManager *pMgr;
144 D3DContext *pCtx;
145 HWND hWnd;
146 AwtWindow *w;
147 D3DPRESENT_PARAMETERS newParams, *pCurParams;
148 D3DDISPLAYMODE dm;
149 UINT adapter;
150
151 J2dTraceLn(J2D_TRACE_INFO, "D3DGD_enterFullScreenExclusiveNative");
152
153 RETURN_STATUS_IF_NULL(pMgr = D3DPipelineManager::GetInstance(), JNI_FALSE);
154 adapter = pMgr->GetAdapterOrdinalForScreen(gdiScreen);
155
156 if (FAILED(res = pMgr->GetD3DContext(adapter, &pCtx))) {
157 D3DRQ_MarkLostIfNeeded(res, D3DRQ_GetCurrentDestination());
158 return JNI_FALSE;
159 }
160
161 w = (AwtWindow *)AwtComponent::GetComponent((HWND)window);
162 if (w == NULL || !::IsWindow(hWnd = w->GetTopLevelHWnd())) {
163 J2dTraceLn(J2D_TRACE_WARNING,
164 "D3DGD_enterFullScreenExclusiveNative: disposed window");
165 return JNI_FALSE;
166 }
167
168 // REMIND: should we also move the non-topleve window from
169 // being on top here (it's moved to front in GraphicsDevice.setFSW())?
170
171 pCtx->Get3DObject()->GetAdapterDisplayMode(adapter, &dm);
172 pCurParams = pCtx->GetPresentationParams();
173
174 // let the mananger know that we're entering the fs mode, it will
175 // set the proper current focus window for us, which ConfigureContext will
176 // use when creating the device
177 pMgr->SetFSFocusWindow(adapter, hWnd);
178
179 newParams = *pCurParams;
180 newParams.hDeviceWindow = hWnd;
181 newParams.Windowed = FALSE;
182 newParams.BackBufferCount = 1;
183 newParams.BackBufferFormat = dm.Format;
184 newParams.FullScreen_RefreshRateInHz = dm.RefreshRate;
185 newParams.BackBufferWidth = dm.Width;
186 newParams.BackBufferHeight = dm.Height;
187 newParams.PresentationInterval = D3DPRESENT_INTERVAL_DEFAULT;
188 newParams.SwapEffect = D3DSWAPEFFECT_DISCARD;
189
190 res = pCtx->ConfigureContext(&newParams);
191 D3DRQ_MarkLostIfNeeded(res, D3DRQ_GetCurrentDestination());
192 return SUCCEEDED(res);
193 }
194
195 /*
196 * Class: sun_java2d_d3d_D3DGraphicsDevice
197 * Method: exitFullScreenExclusiveNative
198 * Signature: (I)V
199 */
200 JNIEXPORT jboolean JNICALL
Java_sun_java2d_d3d_D3DGraphicsDevice_exitFullScreenExclusiveNative(JNIEnv * env,jclass gdc,jint gdiScreen)201 Java_sun_java2d_d3d_D3DGraphicsDevice_exitFullScreenExclusiveNative
202 (JNIEnv *env, jclass gdc, jint gdiScreen)
203 {
204 HRESULT res;
205 D3DPipelineManager *pMgr;
206 D3DContext *pCtx;
207 D3DPRESENT_PARAMETERS newParams, *pCurParams;
208 UINT adapter;
209
210 J2dTraceLn(J2D_TRACE_INFO, "D3DGD_exitFullScreenExclusiveNative");
211
212 RETURN_STATUS_IF_NULL(pMgr = D3DPipelineManager::GetInstance(), JNI_FALSE);
213 adapter = pMgr->GetAdapterOrdinalForScreen(gdiScreen);
214
215 if (FAILED(res = pMgr->GetD3DContext(adapter, &pCtx))) {
216 D3DRQ_MarkLostIfNeeded(res, D3DRQ_GetCurrentDestination());
217 return JNI_FALSE;
218 }
219
220 pCurParams = pCtx->GetPresentationParams();
221
222 newParams = *pCurParams;
223 // we're exiting fs, the device window can be 0
224 newParams.hDeviceWindow = 0;
225 newParams.Windowed = TRUE;
226 newParams.BackBufferFormat = D3DFMT_UNKNOWN;
227 newParams.BackBufferCount = 1;
228 newParams.FullScreen_RefreshRateInHz = 0;
229 newParams.BackBufferWidth = 0;
230 newParams.BackBufferHeight = 0;
231 newParams.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE;
232 newParams.SwapEffect = D3DSWAPEFFECT_COPY;
233
234 res = pCtx->ConfigureContext(&newParams);
235 D3DRQ_MarkLostIfNeeded(res, D3DRQ_GetCurrentDestination());
236
237 // exited fs, update current focus window
238 // note that we call this after this adapter exited fs mode so that
239 // the rest of the adapters can be reset
240 pMgr->SetFSFocusWindow(adapter, 0);
241
242 return SUCCEEDED(res);
243 }
244
245 /*
246 * Class: sun_java2d_d3d_D3DGraphicsDevice
247 * Method: configDisplayModeNative
248 * Signature: (IJIIII)V
249 */
250 JNIEXPORT void JNICALL
Java_sun_java2d_d3d_D3DGraphicsDevice_configDisplayModeNative(JNIEnv * env,jclass gdc,jint gdiScreen,jlong window,jint width,jint height,jint bitDepth,jint refreshRate)251 Java_sun_java2d_d3d_D3DGraphicsDevice_configDisplayModeNative
252 (JNIEnv *env, jclass gdc, jint gdiScreen, jlong window,
253 jint width, jint height, jint bitDepth, jint refreshRate)
254 {
255 HRESULT res;
256 D3DPipelineManager *pMgr;
257 D3DContext *pCtx;
258 D3DPRESENT_PARAMETERS newParams, *pCurParams;
259 UINT adapter;
260
261 J2dTraceLn(J2D_TRACE_INFO, "D3DGD_configDisplayModeNative");
262
263 RETURN_IF_NULL(pMgr = D3DPipelineManager::GetInstance());
264 adapter = pMgr->GetAdapterOrdinalForScreen(gdiScreen);
265
266 if (FAILED(res = pMgr->GetD3DContext(adapter, &pCtx))) {
267 D3DRQ_MarkLostIfNeeded(res, D3DRQ_GetCurrentDestination());
268 return;
269 }
270
271 pCurParams = pCtx->GetPresentationParams();
272
273 newParams = *pCurParams;
274 newParams.BackBufferWidth = width;
275 newParams.BackBufferHeight = height;
276 newParams.FullScreen_RefreshRateInHz = refreshRate;
277 newParams.PresentationInterval = D3DPRESENT_INTERVAL_DEFAULT;
278 // we leave the swap effect so that it's more likely
279 // to be the one user selected initially
280 // newParams.SwapEffect = D3DSWAPEFFECT_DISCARD;
281
282 if (bitDepth == 32) {
283 newParams.BackBufferFormat = D3DFMT_X8R8G8B8;
284 } else if (bitDepth == 16) {
285 UINT modeNum;
286 D3DDISPLAYMODE mode;
287 IDirect3D9 *pd3d9;
288 UINT modesCount;
289
290 RETURN_IF_NULL(pd3d9 = pMgr->GetD3DObject());
291
292 modesCount = pd3d9->GetAdapterModeCount(adapter, D3DFMT_R5G6B5);
293 if (modesCount == 0) {
294 modesCount = pd3d9->GetAdapterModeCount(adapter, D3DFMT_X1R5G5B5);
295 }
296
297 newParams.BackBufferFormat = D3DFMT_UNKNOWN;
298 for (modeNum = 0; modeNum < modesCount; modeNum++) {
299 if (SUCCEEDED(pd3d9->EnumAdapterModes(adapter, D3DFMT_R5G6B5,
300 modeNum, &mode)))
301 {
302 if (mode.Width == width && mode.Height == height &&
303 mode.RefreshRate == refreshRate)
304 {
305 // prefer 565 over 555
306 if (mode.Format == D3DFMT_R5G6B5) {
307 newParams.BackBufferFormat = D3DFMT_R5G6B5;
308 break;
309 } else if (mode.Format == D3DFMT_X1R5G5B5) {
310 newParams.BackBufferFormat = D3DFMT_X1R5G5B5;
311 }
312 }
313 }
314 }
315 if (newParams.BackBufferFormat == D3DFMT_UNKNOWN) {
316 J2dRlsTraceLn(J2D_TRACE_ERROR,
317 "D3DGD_configDisplayModeNative: no 16-bit formats");
318 return;
319 }
320 } else {
321 J2dRlsTraceLn1(J2D_TRACE_ERROR,
322 "D3DGD_configDisplayModeNative: unsupported depth: %d",
323 bitDepth);
324 return;
325 }
326
327 J2dTraceLn4(J2D_TRACE_VERBOSE, " changing to dm: %dx%dx%d@%d",
328 newParams.BackBufferWidth, newParams.BackBufferHeight,
329 bitDepth, refreshRate);
330 J2dTraceLn1(J2D_TRACE_VERBOSE, " selected backbuffer format: %d",
331 newParams.BackBufferFormat);
332
333 res = pCtx->ConfigureContext(&newParams);
334 if (SUCCEEDED(res)) {
335 // the full screen window doesn't receive WM_SIZE event when
336 // the display mode changes (it does get resized though) so we need to
337 // generate the event ourselves
338 ::SendMessage(newParams.hDeviceWindow, WM_SIZE, width, height);
339 }
340 D3DRQ_MarkLostIfNeeded(res, D3DRQ_GetCurrentDestination());
341 }
342
343
344 /*
345 * Class: sun_java2d_d3d_D3DGraphicsDevice
346 * Method: getCurrentDisplayModeNative
347 * Signature: (I)Ljava/awt/DisplayMode;
348 */
349 JNIEXPORT jobject JNICALL
Java_sun_java2d_d3d_D3DGraphicsDevice_getCurrentDisplayModeNative(JNIEnv * env,jclass gdc,jint gdiScreen)350 Java_sun_java2d_d3d_D3DGraphicsDevice_getCurrentDisplayModeNative
351 (JNIEnv *env, jclass gdc, jint gdiScreen)
352 {
353 D3DPipelineManager *pMgr;
354 IDirect3D9 *pd3d9;
355 jobject ret = NULL;
356 D3DDISPLAYMODE mode;
357 UINT adapter;
358
359 J2dTraceLn(J2D_TRACE_INFO, "D3DGD_getCurrentDisplayModeNative");
360
361 RETURN_STATUS_IF_NULL(pMgr = D3DPipelineManager::GetInstance(), NULL);
362 RETURN_STATUS_IF_NULL(pd3d9 = pMgr->GetD3DObject(), NULL);
363 adapter = pMgr->GetAdapterOrdinalForScreen(gdiScreen);
364
365 if (SUCCEEDED(pd3d9->GetAdapterDisplayMode(adapter, &mode))) {
366 int bitDepth = -1;
367 // these are the only three valid screen formats
368 switch (mode.Format) {
369 case D3DFMT_X8R8G8B8: bitDepth = 32; break;
370 case D3DFMT_R5G6B5:
371 case D3DFMT_X1R5G5B5: bitDepth = 16; break;
372 }
373 J2dTraceLn4(J2D_TRACE_VERBOSE,
374 " current dm: %dx%dx%d@%d",
375 mode.Width, mode.Height, bitDepth, mode.RefreshRate);
376 ret = CreateDisplayMode(env, mode.Width, mode.Height, bitDepth,
377 mode.RefreshRate);
378 }
379 return ret;
380 }
381
382 /*
383 * Class: sun_java2d_d3d_D3DGraphicsDevice
384 * Method: enumDisplayModesNative
385 * Signature: (ILjava/util/ArrayList;)V
386 */
387 JNIEXPORT void JNICALL
Java_sun_java2d_d3d_D3DGraphicsDevice_enumDisplayModesNative(JNIEnv * env,jclass gdc,jint gdiScreen,jobject arrayList)388 Java_sun_java2d_d3d_D3DGraphicsDevice_enumDisplayModesNative
389 (JNIEnv *env, jclass gdc, jint gdiScreen, jobject arrayList)
390 {
391 D3DPipelineManager *pMgr;
392 IDirect3D9 *pd3d9;
393 jobject ret = NULL;
394 D3DDISPLAYMODE mode;
395 UINT formatNum, modeNum, modesCount;
396 UINT adapter;
397 // EnumAdapterModes treats 555 and 565 formats as equivalents
398 static D3DFORMAT formats[] =
399 { D3DFMT_X8R8G8B8, D3DFMT_R5G6B5 };
400
401 J2dTraceLn(J2D_TRACE_INFO, "D3DGD_enumDisplayModesNative");
402
403 RETURN_IF_NULL(pMgr = D3DPipelineManager::GetInstance());
404 RETURN_IF_NULL(pd3d9 = pMgr->GetD3DObject());
405 adapter = pMgr->GetAdapterOrdinalForScreen(gdiScreen);
406
407 for (formatNum = 0; formatNum < (sizeof formats)/(sizeof *formats); formatNum++) {
408 modesCount = pd3d9->GetAdapterModeCount(adapter, formats[formatNum]);
409 for (modeNum = 0; modeNum < modesCount; modeNum++) {
410 if (SUCCEEDED(pd3d9->EnumAdapterModes(adapter, formats[formatNum],
411 modeNum, &mode)))
412 {
413 int bitDepth = -1;
414 // these are the only three valid screen formats,
415 // 30-bit is returned as X8R8G8B8
416 switch (mode.Format) {
417 case D3DFMT_X8R8G8B8: bitDepth = 32; break;
418 case D3DFMT_R5G6B5:
419 case D3DFMT_X1R5G5B5: bitDepth = 16; break;
420 }
421 J2dTraceLn4(J2D_TRACE_VERBOSE, " found dm: %dx%dx%d@%d",
422 mode.Width, mode.Height, bitDepth,mode.RefreshRate);
423 addDisplayMode(env, arrayList, mode.Width, mode.Height,
424 bitDepth, mode.RefreshRate);
425 }
426 }
427 }
428 }
429
430 /*
431 * Class: sun_java2d_d3d_D3DGraphicsDevice
432 * Method: getAvailableAcceleratedMemoryNative
433 * Signature: (I)J
434 */
435 JNIEXPORT jlong JNICALL
Java_sun_java2d_d3d_D3DGraphicsDevice_getAvailableAcceleratedMemoryNative(JNIEnv * env,jclass gdc,jint gdiScreen)436 Java_sun_java2d_d3d_D3DGraphicsDevice_getAvailableAcceleratedMemoryNative
437 (JNIEnv *env, jclass gdc, jint gdiScreen)
438 {
439 // REMIND: looks like Direct3D provides information about texture memory
440 // only via IDirect3DDevice9::GetAvailableTextureMem, however, it
441 // seems to report the same amount as direct draw used to.
442 HRESULT res;
443 D3DPipelineManager *pMgr;
444 D3DContext *pCtx;
445 IDirect3DDevice9 *pd3dDevice;
446 UINT adapter;
447
448 J2dTraceLn(J2D_TRACE_INFO, "D3DGD_getAvailableAcceleratedMemoryNative");
449
450 RETURN_STATUS_IF_NULL(pMgr = D3DPipelineManager::GetInstance(), 0L);
451 adapter = pMgr->GetAdapterOrdinalForScreen(gdiScreen);
452
453 if (FAILED(res = pMgr->GetD3DContext(adapter, &pCtx))) {
454 D3DRQ_MarkLostIfNeeded(res, D3DRQ_GetCurrentDestination());
455 return 0L;
456 }
457 RETURN_STATUS_IF_NULL(pd3dDevice = pCtx->Get3DDevice(), 0L);
458
459 UINT mem = pd3dDevice->GetAvailableTextureMem();
460 J2dTraceLn1(J2D_TRACE_VERBOSE, " available memory=%d", mem);
461 return mem;
462 }
463
464 /*
465 * Class: sun_java2d_d3d_D3DGraphicsDevice
466 * Method: isD3DAvailableOnDeviceNative
467 * Signature: (I)Z
468 */
469 JNIEXPORT jboolean JNICALL
Java_sun_java2d_d3d_D3DGraphicsDevice_isD3DAvailableOnDeviceNative(JNIEnv * env,jclass gdc,jint gdiScreen)470 Java_sun_java2d_d3d_D3DGraphicsDevice_isD3DAvailableOnDeviceNative
471 (JNIEnv *env, jclass gdc, jint gdiScreen)
472 {
473 HRESULT res;
474 D3DPipelineManager *pMgr;
475 D3DContext *pCtx;
476 UINT adapter;
477
478 J2dTraceLn(J2D_TRACE_INFO, "D3DGD_isD3DAvailableOnDeviceNative");
479
480 RETURN_STATUS_IF_NULL(pMgr = D3DPipelineManager::GetInstance(), JNI_FALSE);
481 adapter = pMgr->GetAdapterOrdinalForScreen(gdiScreen);
482
483 if (FAILED(res = pMgr->GetD3DContext(adapter, &pCtx))) {
484 D3DRQ_MarkLostIfNeeded(res, D3DRQ_GetCurrentDestination());
485 return JNI_FALSE;
486 }
487
488 return JNI_TRUE;
489 }
490
491 } // extern "C"
492