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 */ 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 */ 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 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 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 // Since we are not creating hwnd with WS_EX_TOPMOST flag, so Windowed flag 182 // needs to be TRUE for fullscreen window 183 newParams.Windowed = TRUE; 184 newParams.BackBufferCount = 1; 185 newParams.BackBufferFormat = dm.Format; 186 newParams.FullScreen_RefreshRateInHz = dm.RefreshRate; 187 newParams.BackBufferWidth = dm.Width; 188 newParams.BackBufferHeight = dm.Height; 189 newParams.PresentationInterval = D3DPRESENT_INTERVAL_DEFAULT; 190 newParams.SwapEffect = D3DSWAPEFFECT_DISCARD; 191 192 res = pCtx->ConfigureContext(&newParams); 193 D3DRQ_MarkLostIfNeeded(res, D3DRQ_GetCurrentDestination()); 194 return SUCCEEDED(res); 195 } 196 197 /* 198 * Class: sun_java2d_d3d_D3DGraphicsDevice 199 * Method: exitFullScreenExclusiveNative 200 * Signature: (I)V 201 */ 202 JNIEXPORT jboolean JNICALL 203 Java_sun_java2d_d3d_D3DGraphicsDevice_exitFullScreenExclusiveNative 204 (JNIEnv *env, jclass gdc, jint gdiScreen) 205 { 206 HRESULT res; 207 D3DPipelineManager *pMgr; 208 D3DContext *pCtx; 209 D3DPRESENT_PARAMETERS newParams, *pCurParams; 210 UINT adapter; 211 212 J2dTraceLn(J2D_TRACE_INFO, "D3DGD_exitFullScreenExclusiveNative"); 213 214 RETURN_STATUS_IF_NULL(pMgr = D3DPipelineManager::GetInstance(), JNI_FALSE); 215 adapter = pMgr->GetAdapterOrdinalForScreen(gdiScreen); 216 217 if (FAILED(res = pMgr->GetD3DContext(adapter, &pCtx))) { 218 D3DRQ_MarkLostIfNeeded(res, D3DRQ_GetCurrentDestination()); 219 return JNI_FALSE; 220 } 221 222 pCurParams = pCtx->GetPresentationParams(); 223 224 newParams = *pCurParams; 225 // we're exiting fs, the device window can be 0 226 newParams.hDeviceWindow = 0; 227 newParams.Windowed = TRUE; 228 newParams.BackBufferFormat = D3DFMT_UNKNOWN; 229 newParams.BackBufferCount = 1; 230 newParams.FullScreen_RefreshRateInHz = 0; 231 newParams.BackBufferWidth = 0; 232 newParams.BackBufferHeight = 0; 233 newParams.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE; 234 newParams.SwapEffect = D3DSWAPEFFECT_COPY; 235 236 res = pCtx->ConfigureContext(&newParams); 237 D3DRQ_MarkLostIfNeeded(res, D3DRQ_GetCurrentDestination()); 238 239 // exited fs, update current focus window 240 // note that we call this after this adapter exited fs mode so that 241 // the rest of the adapters can be reset 242 pMgr->SetFSFocusWindow(adapter, 0); 243 244 return SUCCEEDED(res); 245 } 246 247 /* 248 * Class: sun_java2d_d3d_D3DGraphicsDevice 249 * Method: configDisplayModeNative 250 * Signature: (IJIIII)V 251 */ 252 JNIEXPORT void JNICALL 253 Java_sun_java2d_d3d_D3DGraphicsDevice_configDisplayModeNative 254 (JNIEnv *env, jclass gdc, jint gdiScreen, jlong window, 255 jint width, jint height, jint bitDepth, jint refreshRate) 256 { 257 HRESULT res; 258 D3DPipelineManager *pMgr; 259 D3DContext *pCtx; 260 D3DPRESENT_PARAMETERS newParams, *pCurParams; 261 UINT adapter; 262 263 J2dTraceLn(J2D_TRACE_INFO, "D3DGD_configDisplayModeNative"); 264 265 RETURN_IF_NULL(pMgr = D3DPipelineManager::GetInstance()); 266 adapter = pMgr->GetAdapterOrdinalForScreen(gdiScreen); 267 268 if (FAILED(res = pMgr->GetD3DContext(adapter, &pCtx))) { 269 D3DRQ_MarkLostIfNeeded(res, D3DRQ_GetCurrentDestination()); 270 return; 271 } 272 273 pCurParams = pCtx->GetPresentationParams(); 274 275 newParams = *pCurParams; 276 newParams.BackBufferWidth = width; 277 newParams.BackBufferHeight = height; 278 newParams.FullScreen_RefreshRateInHz = refreshRate; 279 newParams.PresentationInterval = D3DPRESENT_INTERVAL_DEFAULT; 280 // we leave the swap effect so that it's more likely 281 // to be the one user selected initially 282 // newParams.SwapEffect = D3DSWAPEFFECT_DISCARD; 283 284 if (bitDepth == 32) { 285 newParams.BackBufferFormat = D3DFMT_X8R8G8B8; 286 } else if (bitDepth == 16) { 287 UINT modeNum; 288 D3DDISPLAYMODE mode; 289 IDirect3D9 *pd3d9; 290 UINT modesCount; 291 292 RETURN_IF_NULL(pd3d9 = pMgr->GetD3DObject()); 293 294 modesCount = pd3d9->GetAdapterModeCount(adapter, D3DFMT_R5G6B5); 295 if (modesCount == 0) { 296 modesCount = pd3d9->GetAdapterModeCount(adapter, D3DFMT_X1R5G5B5); 297 } 298 299 newParams.BackBufferFormat = D3DFMT_UNKNOWN; 300 for (modeNum = 0; modeNum < modesCount; modeNum++) { 301 if (SUCCEEDED(pd3d9->EnumAdapterModes(adapter, D3DFMT_R5G6B5, 302 modeNum, &mode))) 303 { 304 if (mode.Width == width && mode.Height == height && 305 mode.RefreshRate == refreshRate) 306 { 307 // prefer 565 over 555 308 if (mode.Format == D3DFMT_R5G6B5) { 309 newParams.BackBufferFormat = D3DFMT_R5G6B5; 310 break; 311 } else if (mode.Format == D3DFMT_X1R5G5B5) { 312 newParams.BackBufferFormat = D3DFMT_X1R5G5B5; 313 } 314 } 315 } 316 } 317 if (newParams.BackBufferFormat == D3DFMT_UNKNOWN) { 318 J2dRlsTraceLn(J2D_TRACE_ERROR, 319 "D3DGD_configDisplayModeNative: no 16-bit formats"); 320 return; 321 } 322 } else { 323 J2dRlsTraceLn1(J2D_TRACE_ERROR, 324 "D3DGD_configDisplayModeNative: unsupported depth: %d", 325 bitDepth); 326 return; 327 } 328 329 J2dTraceLn4(J2D_TRACE_VERBOSE, " changing to dm: %dx%dx%d@%d", 330 newParams.BackBufferWidth, newParams.BackBufferHeight, 331 bitDepth, refreshRate); 332 J2dTraceLn1(J2D_TRACE_VERBOSE, " selected backbuffer format: %d", 333 newParams.BackBufferFormat); 334 335 res = pCtx->ConfigureContext(&newParams); 336 if (SUCCEEDED(res)) { 337 // the full screen window doesn't receive WM_SIZE event when 338 // the display mode changes (it does get resized though) so we need to 339 // generate the event ourselves 340 ::SendMessage(newParams.hDeviceWindow, WM_SIZE, width, height); 341 } 342 D3DRQ_MarkLostIfNeeded(res, D3DRQ_GetCurrentDestination()); 343 } 344 345 346 /* 347 * Class: sun_java2d_d3d_D3DGraphicsDevice 348 * Method: getCurrentDisplayModeNative 349 * Signature: (I)Ljava/awt/DisplayMode; 350 */ 351 JNIEXPORT jobject JNICALL 352 Java_sun_java2d_d3d_D3DGraphicsDevice_getCurrentDisplayModeNative 353 (JNIEnv *env, jclass gdc, jint gdiScreen) 354 { 355 D3DPipelineManager *pMgr; 356 IDirect3D9 *pd3d9; 357 jobject ret = NULL; 358 D3DDISPLAYMODE mode; 359 UINT adapter; 360 361 J2dTraceLn(J2D_TRACE_INFO, "D3DGD_getCurrentDisplayModeNative"); 362 363 RETURN_STATUS_IF_NULL(pMgr = D3DPipelineManager::GetInstance(), NULL); 364 RETURN_STATUS_IF_NULL(pd3d9 = pMgr->GetD3DObject(), NULL); 365 adapter = pMgr->GetAdapterOrdinalForScreen(gdiScreen); 366 367 if (SUCCEEDED(pd3d9->GetAdapterDisplayMode(adapter, &mode))) { 368 int bitDepth = -1; 369 // these are the only three valid screen formats 370 switch (mode.Format) { 371 case D3DFMT_X8R8G8B8: bitDepth = 32; break; 372 case D3DFMT_R5G6B5: 373 case D3DFMT_X1R5G5B5: bitDepth = 16; break; 374 } 375 J2dTraceLn4(J2D_TRACE_VERBOSE, 376 " current dm: %dx%dx%d@%d", 377 mode.Width, mode.Height, bitDepth, mode.RefreshRate); 378 ret = CreateDisplayMode(env, mode.Width, mode.Height, bitDepth, 379 mode.RefreshRate); 380 } 381 return ret; 382 } 383 384 /* 385 * Class: sun_java2d_d3d_D3DGraphicsDevice 386 * Method: enumDisplayModesNative 387 * Signature: (ILjava/util/ArrayList;)V 388 */ 389 JNIEXPORT void JNICALL 390 Java_sun_java2d_d3d_D3DGraphicsDevice_enumDisplayModesNative 391 (JNIEnv *env, jclass gdc, jint gdiScreen, jobject arrayList) 392 { 393 D3DPipelineManager *pMgr; 394 IDirect3D9 *pd3d9; 395 jobject ret = NULL; 396 D3DDISPLAYMODE mode; 397 UINT formatNum, modeNum, modesCount; 398 UINT adapter; 399 // EnumAdapterModes treats 555 and 565 formats as equivalents 400 static D3DFORMAT formats[] = 401 { D3DFMT_X8R8G8B8, D3DFMT_R5G6B5 }; 402 403 J2dTraceLn(J2D_TRACE_INFO, "D3DGD_enumDisplayModesNative"); 404 405 RETURN_IF_NULL(pMgr = D3DPipelineManager::GetInstance()); 406 RETURN_IF_NULL(pd3d9 = pMgr->GetD3DObject()); 407 adapter = pMgr->GetAdapterOrdinalForScreen(gdiScreen); 408 409 for (formatNum = 0; formatNum < (sizeof formats)/(sizeof *formats); formatNum++) { 410 modesCount = pd3d9->GetAdapterModeCount(adapter, formats[formatNum]); 411 for (modeNum = 0; modeNum < modesCount; modeNum++) { 412 if (SUCCEEDED(pd3d9->EnumAdapterModes(adapter, formats[formatNum], 413 modeNum, &mode))) 414 { 415 int bitDepth = -1; 416 // these are the only three valid screen formats, 417 // 30-bit is returned as X8R8G8B8 418 switch (mode.Format) { 419 case D3DFMT_X8R8G8B8: bitDepth = 32; break; 420 case D3DFMT_R5G6B5: 421 case D3DFMT_X1R5G5B5: bitDepth = 16; break; 422 } 423 J2dTraceLn4(J2D_TRACE_VERBOSE, " found dm: %dx%dx%d@%d", 424 mode.Width, mode.Height, bitDepth,mode.RefreshRate); 425 addDisplayMode(env, arrayList, mode.Width, mode.Height, 426 bitDepth, mode.RefreshRate); 427 } 428 } 429 } 430 } 431 432 /* 433 * Class: sun_java2d_d3d_D3DGraphicsDevice 434 * Method: getAvailableAcceleratedMemoryNative 435 * Signature: (I)J 436 */ 437 JNIEXPORT jlong JNICALL 438 Java_sun_java2d_d3d_D3DGraphicsDevice_getAvailableAcceleratedMemoryNative 439 (JNIEnv *env, jclass gdc, jint gdiScreen) 440 { 441 // REMIND: looks like Direct3D provides information about texture memory 442 // only via IDirect3DDevice9::GetAvailableTextureMem, however, it 443 // seems to report the same amount as direct draw used to. 444 HRESULT res; 445 D3DPipelineManager *pMgr; 446 D3DContext *pCtx; 447 IDirect3DDevice9 *pd3dDevice; 448 UINT adapter; 449 450 J2dTraceLn(J2D_TRACE_INFO, "D3DGD_getAvailableAcceleratedMemoryNative"); 451 452 RETURN_STATUS_IF_NULL(pMgr = D3DPipelineManager::GetInstance(), 0L); 453 adapter = pMgr->GetAdapterOrdinalForScreen(gdiScreen); 454 455 if (FAILED(res = pMgr->GetD3DContext(adapter, &pCtx))) { 456 D3DRQ_MarkLostIfNeeded(res, D3DRQ_GetCurrentDestination()); 457 return 0L; 458 } 459 RETURN_STATUS_IF_NULL(pd3dDevice = pCtx->Get3DDevice(), 0L); 460 461 UINT mem = pd3dDevice->GetAvailableTextureMem(); 462 J2dTraceLn1(J2D_TRACE_VERBOSE, " available memory=%d", mem); 463 return mem; 464 } 465 466 /* 467 * Class: sun_java2d_d3d_D3DGraphicsDevice 468 * Method: isD3DAvailableOnDeviceNative 469 * Signature: (I)Z 470 */ 471 JNIEXPORT jboolean JNICALL 472 Java_sun_java2d_d3d_D3DGraphicsDevice_isD3DAvailableOnDeviceNative 473 (JNIEnv *env, jclass gdc, jint gdiScreen) 474 { 475 HRESULT res; 476 D3DPipelineManager *pMgr; 477 D3DContext *pCtx; 478 UINT adapter; 479 480 J2dTraceLn(J2D_TRACE_INFO, "D3DGD_isD3DAvailableOnDeviceNative"); 481 482 RETURN_STATUS_IF_NULL(pMgr = D3DPipelineManager::GetInstance(), JNI_FALSE); 483 adapter = pMgr->GetAdapterOrdinalForScreen(gdiScreen); 484 485 if (FAILED(res = pMgr->GetD3DContext(adapter, &pCtx))) { 486 D3DRQ_MarkLostIfNeeded(res, D3DRQ_GetCurrentDestination()); 487 return JNI_FALSE; 488 } 489 490 return JNI_TRUE; 491 } 492 493 } // extern "C"