1 /* 2 * Copyright (c) 2007, 2010, 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 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 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 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 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 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 < 3; 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 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 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"