1 /*
2 * Copyright (c) 2007, 2016, 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 "D3DBadHardware.h"
27 #include "D3DPipelineManager.h"
28 #include "D3DRenderQueue.h"
29 #include "WindowsFlags.h"
30 #include "awt_Win32GraphicsDevice.h"
31
32 // state of the adapter prior to initialization
33 #define CONTEXT_NOT_INITED 0
34 // this state is set if adapter initialization had failed
35 #define CONTEXT_INIT_FAILED (-1)
36 // this state is set if adapter was successfully created
37 #define CONTEXT_CREATED 1
38
39 static BOOL bNoHwCheck = (getenv("J2D_D3D_NO_HWCHECK") != NULL);
40
41 D3DPipelineManager *D3DPipelineManager::pMgr = NULL;
42
43
CreateInstance(void)44 D3DPipelineManager * D3DPipelineManager::CreateInstance(void)
45 {
46 if (!IsD3DEnabled() ||
47 FAILED((D3DPipelineManager::CheckOSVersion())) ||
48 FAILED((D3DPipelineManager::GDICheckForBadHardware())))
49 {
50 return NULL;
51 }
52
53 if (pMgr == NULL) {
54 pMgr = new D3DPipelineManager();
55 if (FAILED(pMgr->InitD3D())) {
56 SAFE_DELETE(pMgr);
57 }
58 } else {
59 // this should never happen so to be on the safe side do not
60 // use this unexpected pointer, do not try to release it, just null
61 // it out and fail safely
62 J2dRlsTraceLn1(J2D_TRACE_ERROR,
63 "D3DPPLM::CreateInstance: unexpected instance: 0x%x,"\
64 " abort.", pMgr);
65 pMgr = NULL;
66 }
67 return pMgr;
68 }
69
DeleteInstance()70 void D3DPipelineManager::DeleteInstance()
71 {
72 J2dTraceLn(J2D_TRACE_INFO, "D3DPPLM::DeleteInstance()");
73 SAFE_DELETE(pMgr);
74 }
75
GetInstance(void)76 D3DPipelineManager * D3DPipelineManager::GetInstance(void)
77 {
78 return pMgr;
79 }
80
D3DPipelineManager(void)81 D3DPipelineManager::D3DPipelineManager(void)
82 {
83 pd3d9 = NULL;
84 hLibD3D9 = NULL;
85 pAdapters = NULL;
86 adapterCount = 0;
87 currentFSFocusAdapter = -1;
88 defaultFocusWindow = 0;
89 devType = SelectDeviceType();
90 }
91
~D3DPipelineManager(void)92 D3DPipelineManager::~D3DPipelineManager(void)
93 {
94 J2dTraceLn(J2D_TRACE_INFO, "D3DPPLM::~D3DPipelineManager()");
95 ReleaseD3D();
96 }
97
ReleaseD3D(void)98 HRESULT D3DPipelineManager::ReleaseD3D(void)
99 {
100 J2dTraceLn(J2D_TRACE_INFO, "D3DPPLM::ReleaseD3D()");
101
102 ReleaseAdapters();
103
104 SAFE_RELEASE(pd3d9);
105
106 if (hLibD3D9 != NULL) {
107 ::FreeLibrary(hLibD3D9);
108 hLibD3D9 = NULL;
109 }
110
111 return S_OK;
112 }
113
114 // Creates a Direct3D9 object and initializes adapters.
115 // If succeeded, returns S_OK, otherwise returns the error code.
InitD3D(void)116 HRESULT D3DPipelineManager::InitD3D(void)
117 {
118 typedef IDirect3D9 * WINAPI FnDirect3DCreate9(UINT SDKVersion);
119
120 hLibD3D9 = JDK_LoadSystemLibrary("d3d9.dll");
121 if (hLibD3D9 == NULL) {
122 J2dRlsTraceLn(J2D_TRACE_ERROR, "InitD3D: no d3d9.dll");
123 return E_FAIL;
124 }
125
126 FnDirect3DCreate9 *d3dcreate9 = NULL;
127 d3dcreate9 = (FnDirect3DCreate9*)
128 ::GetProcAddress(hLibD3D9, "Direct3DCreate9");
129 if (d3dcreate9 == NULL) {
130 J2dRlsTraceLn(J2D_TRACE_ERROR, "InitD3D: no Direct3DCreate9");
131 ::FreeLibrary(hLibD3D9);
132 return E_FAIL;
133 }
134
135 pd3d9 = d3dcreate9(D3D_SDK_VERSION);
136 if (pd3d9 == NULL) {
137 J2dRlsTraceLn(J2D_TRACE_ERROR,
138 "InitD3D: unable to create IDirect3D9 object");
139 ::FreeLibrary(hLibD3D9);
140 return E_FAIL;
141 }
142
143 HRESULT res;
144 if (FAILED(res = InitAdapters())) {
145 J2dRlsTraceLn(J2D_TRACE_ERROR, "InitD3D: failed to init adapters");
146 ReleaseD3D();
147 return res;
148 }
149
150 return S_OK;
151 }
152
ReleaseAdapters()153 HRESULT D3DPipelineManager::ReleaseAdapters()
154 {
155 J2dTraceLn(J2D_TRACE_INFO, "D3DPPLM::ReleaseAdapters()");
156
157 D3DRQ_ResetCurrentContextAndDestination();
158 if (pAdapters != NULL) {
159 for (UINT i = 0; i < adapterCount; i++) {
160 if (pAdapters[i].pd3dContext != NULL) {
161 delete pAdapters[i].pd3dContext;
162 }
163 }
164 delete[] pAdapters;
165 pAdapters = NULL;
166 }
167 if (defaultFocusWindow != 0) {
168 DestroyWindow(defaultFocusWindow);
169 UnregisterClass(L"D3DFocusWindow", GetModuleHandle(NULL));
170 defaultFocusWindow = 0;
171 }
172 currentFSFocusAdapter = -1;
173 return S_OK;
174 }
175
GetAdapterOrdinalForScreen(jint gdiScreen)176 UINT D3DPipelineManager::GetAdapterOrdinalForScreen(jint gdiScreen)
177 {
178 HMONITOR mHnd = AwtWin32GraphicsDevice::GetMonitor(gdiScreen);
179 if (mHnd == (HMONITOR)0) {
180 return D3DADAPTER_DEFAULT;
181 }
182 return GetAdapterOrdinalByHmon((HMONITOR)mHnd);
183 }
184
185 // static
HandleAdaptersChange(HMONITOR * pHMONITORs,UINT monNum)186 HRESULT D3DPipelineManager::HandleAdaptersChange(HMONITOR *pHMONITORs, UINT monNum)
187 {
188 HRESULT res = S_OK;
189 BOOL bResetD3D = FALSE, bFound;
190
191 D3DPipelineManager *pMgr = D3DPipelineManager::GetInstance();
192 RETURN_STATUS_IF_NULL(pHMONITORs, E_FAIL);
193 if (pMgr == NULL) {
194 // NULL pMgr is valid when the pipeline is not enabled or if it hasn't
195 // been created yet
196 return S_OK;
197 }
198 RETURN_STATUS_IF_NULL(pMgr->pAdapters, E_FAIL);
199 RETURN_STATUS_IF_NULL(pMgr->pd3d9, E_FAIL);
200
201 J2dTraceLn(J2D_TRACE_INFO, "D3DPPLM::HandleAdaptersChange");
202
203 if (monNum != pMgr->adapterCount) {
204 J2dTraceLn2(J2D_TRACE_VERBOSE,
205 " number of adapters changed (old=%d, new=%d)",
206 pMgr->adapterCount, monNum);
207 bResetD3D = TRUE;
208 } else {
209 for (UINT i = 0; i < pMgr->adapterCount; i++) {
210 HMONITOR hMon = pMgr->pd3d9->GetAdapterMonitor(i);
211 if (hMon == (HMONITOR)0x0) {
212 J2dTraceLn1(J2D_TRACE_VERBOSE, " adapter %d: removed", i);
213 bResetD3D = TRUE;
214 break;
215 }
216 bFound = FALSE;
217 for (UINT mon = 0; mon < monNum; mon++) {
218 if (pHMONITORs[mon] == hMon) {
219 J2dTraceLn3(J2D_TRACE_VERBOSE,
220 " adapter %d: found hmnd[%d]=0x%x", i, mon, hMon);
221 bFound = TRUE;
222 break;
223 }
224 }
225 if (!bFound) {
226 J2dTraceLn2(J2D_TRACE_VERBOSE,
227 " adapter %d: could not find hmnd=0x%x "\
228 "in the list of new hmnds", i, hMon);
229 bResetD3D = TRUE;
230 break;
231 }
232 }
233 }
234
235 if (bResetD3D) {
236 J2dTraceLn(J2D_TRACE_VERBOSE, " adapters changed: resetting d3d");
237 pMgr->ReleaseD3D();
238 res = pMgr->InitD3D();
239 }
240 return res;
241 }
242
HandleLostDevices()243 HRESULT D3DPipelineManager::HandleLostDevices()
244 {
245 J2dTraceLn(J2D_TRACE_INFO, "D3DPPLM::HandleLostDevices()");
246 BOOL bAllClear = TRUE;
247
248 HWND hwnd = GetCurrentFocusWindow();
249 if (hwnd != defaultFocusWindow) {
250 // we're in full-screen mode
251 WINDOWPLACEMENT wp;
252 ::ZeroMemory(&wp, sizeof(WINDOWPLACEMENT));
253 wp.length = sizeof(WINDOWPLACEMENT);
254 ::GetWindowPlacement(hwnd, &wp);
255
256 // Only attempt to restore the devices if we're in full-screen mode
257 // and the fs window is active; sleep otherwise.
258 // Restoring a window while minimized causes problems on Vista:
259 // sometimes we restore the window too quickly and it pops up back from
260 // minimized state when the device is restored.
261 //
262 // WARNING: this is a sleep on the Toolkit thread! We may reconsider
263 // this if we find any issues later.
264 if ((wp.showCmd & SW_SHOWMINNOACTIVE) && !(wp.showCmd & SW_SHOWNORMAL)){
265 static DWORD prevCallTime = 0;
266 J2dTraceLn(J2D_TRACE_VERBOSE, " fs focus window is minimized");
267 DWORD currentTime = ::GetTickCount();
268 if ((currentTime - prevCallTime) < 100) {
269 J2dTraceLn(J2D_TRACE_VERBOSE, " tight loop detected, sleep");
270 ::Sleep(100);
271 }
272 prevCallTime = currentTime;
273 return D3DERR_DEVICELOST;
274 }
275 }
276 if (pAdapters != NULL) {
277 for (UINT i = 0; i < adapterCount; i++) {
278 if (pAdapters[i].pd3dContext != NULL) {
279 J2dTraceLn1(J2D_TRACE_VERBOSE,
280 " HandleLostDevices: checking adapter %d", i);
281 D3DContext *d3dc = pAdapters[i].pd3dContext;
282 if (FAILED(d3dc->CheckAndResetDevice())) {
283 bAllClear = FALSE;
284 }
285 }
286 }
287 }
288 return bAllClear ? S_OK : D3DERR_DEVICELOST;
289 }
290
InitAdapters()291 HRESULT D3DPipelineManager::InitAdapters()
292 {
293 HRESULT res = E_FAIL;
294
295 J2dTraceLn(J2D_TRACE_INFO, "D3DPPLM::InitAdapters()");
296 if (pAdapters != NULL) {
297 ReleaseAdapters();
298 }
299
300 adapterCount = pd3d9->GetAdapterCount();
301 pAdapters = new D3DAdapter[adapterCount];
302 if (pAdapters == NULL) {
303 J2dRlsTraceLn(J2D_TRACE_ERROR, "InitAdapters: out of memory");
304 adapterCount = 0;
305 return E_FAIL;
306 }
307 ZeroMemory(pAdapters, adapterCount * sizeof(D3DAdapter));
308
309 res = CheckAdaptersInfo();
310 RETURN_STATUS_IF_FAILED(res);
311
312 currentFSFocusAdapter = -1;
313 if (CreateDefaultFocusWindow() == 0) {
314 return E_FAIL;
315 }
316
317 return S_OK;
318 }
319
320 // static
321 HRESULT
CheckOSVersion()322 D3DPipelineManager::CheckOSVersion()
323 {
324 // require Windows XP or newer client-class OS
325 if (IS_WINVER_ATLEAST(5, 1) &&
326 !D3DPPLM_OsVersionMatches(OS_WINSERV_2008R2|OS_WINSERV_2008|
327 OS_WINSERV_2003))
328 {
329 J2dTraceLn(J2D_TRACE_INFO,
330 "D3DPPLM::CheckOSVersion: Windows XP or newer client-classs"\
331 " OS detected, passed");
332 return S_OK;
333 }
334 J2dRlsTraceLn(J2D_TRACE_ERROR,
335 "D3DPPLM::CheckOSVersion: Windows 2000 or earlier (or a "\
336 "server) OS detected, failed");
337 if (bNoHwCheck) {
338 J2dRlsTraceLn(J2D_TRACE_WARNING,
339 " OS check overridden via J2D_D3D_NO_HWCHECK");
340 return S_OK;
341 }
342 return E_FAIL;
343 }
344
345 // static
346 HRESULT
GDICheckForBadHardware()347 D3DPipelineManager::GDICheckForBadHardware()
348 {
349 DISPLAY_DEVICE dd;
350 dd.cb = sizeof(DISPLAY_DEVICE);
351
352 int failedDevices = 0;
353 int attachedDevices = 0;
354 int i = 0;
355 WCHAR *id;
356 WCHAR vendorId[5];
357 WCHAR deviceId[5];
358 DWORD dwDId, dwVId;
359
360 J2dTraceLn(J2D_TRACE_INFO, "D3DPPLM::GDICheckForBadHardware");
361
362 // i<20 is to guard against buggy drivers
363 while (EnumDisplayDevices(NULL, i, &dd, 0) && i < 20) {
364 if (dd.StateFlags & DISPLAY_DEVICE_ATTACHED_TO_DESKTOP) {
365 attachedDevices++;
366 id = dd.DeviceID;
367 if (wcslen(id) > 21) {
368 // get vendor ID
369 wcsncpy(vendorId, id+8, 4);
370 int args1 = swscanf(vendorId, L"%X", &dwVId);
371
372 // get device ID
373 wcsncpy(deviceId, id+17, 4);
374 int args2 = swscanf(deviceId, L"%X", &dwDId);
375
376 if (args1 == 1 && args2 == 1) {
377 J2dTraceLn2(J2D_TRACE_VERBOSE,
378 " device: vendorID=0x%04x, deviceId=0x%04x",
379 dwVId, dwDId);
380 // since we don't have a driver version here we will
381 // just ask to ignore the version for now; bad hw
382 // entries with specific drivers information will be
383 // processed later when d3d is initialized and we can
384 // obtain a driver version
385 if (FAILED(CheckForBadHardware(dwVId, dwDId, MAX_VERSION))){
386 failedDevices++;
387 }
388 }
389 }
390 }
391
392 i++;
393 }
394
395 if (failedDevices == attachedDevices) {
396 J2dRlsTraceLn(J2D_TRACE_ERROR,
397 "D3DPPLM::GDICheckForBadHardware: no suitable devices found");
398 return E_FAIL;
399 }
400
401 return S_OK;
402 }
403
D3DPPLM_OsVersionMatches(USHORT osInfo)404 BOOL D3DPPLM_OsVersionMatches(USHORT osInfo) {
405 static USHORT currentOS = OS_UNDEFINED;
406
407 if (currentOS == OS_UNDEFINED) {
408 BOOL bVersOk;
409 OSVERSIONINFOEX osvi;
410
411 ZeroMemory(&osvi, sizeof(OSVERSIONINFOEX));
412 osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
413
414 bVersOk = GetVersionEx((OSVERSIONINFO *) &osvi);
415
416 J2dRlsTrace(J2D_TRACE_INFO, "[I] OS Version = ");
417 if (bVersOk && osvi.dwPlatformId == VER_PLATFORM_WIN32_NT &&
418 osvi.dwMajorVersion > 4)
419 {
420 if (osvi.dwMajorVersion >= 6 && osvi.dwMinorVersion == 0) {
421 if (osvi.wProductType == VER_NT_WORKSTATION) {
422 J2dRlsTrace(J2D_TRACE_INFO, "OS_VISTA\n");
423 currentOS = OS_VISTA;
424 } else {
425 J2dRlsTrace(J2D_TRACE_INFO, "OS_WINSERV_2008\n");
426 currentOS = OS_WINSERV_2008;
427 }
428 } else if (osvi.dwMajorVersion >= 6 && osvi.dwMinorVersion >= 1) {
429 if (osvi.wProductType == VER_NT_WORKSTATION) {
430 J2dRlsTrace(J2D_TRACE_INFO, "OS_WINDOWS7 or newer\n");
431 currentOS = OS_WINDOWS7;
432 } else {
433 J2dRlsTrace(J2D_TRACE_INFO, "OS_WINSERV_2008R2 or newer\n");
434 currentOS = OS_WINSERV_2008R2;
435 }
436 } else if (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 2) {
437 if (osvi.wProductType == VER_NT_WORKSTATION) {
438 J2dRlsTrace(J2D_TRACE_INFO, "OS_WINXP_64\n");
439 currentOS = OS_WINXP_64;
440 } else {
441 J2dRlsTrace(J2D_TRACE_INFO, "OS_WINSERV_2003\n");
442 currentOS = OS_WINSERV_2003;
443 }
444 } else if (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 1) {
445 J2dRlsTrace(J2D_TRACE_INFO, "OS_WINXP ");
446 currentOS = OS_WINXP;
447 if (osvi.wSuiteMask & VER_SUITE_PERSONAL) {
448 J2dRlsTrace(J2D_TRACE_INFO, "Home\n");
449 } else {
450 J2dRlsTrace(J2D_TRACE_INFO, "Pro\n");
451 }
452 } else {
453 J2dRlsTrace2(J2D_TRACE_INFO,
454 "OS_UNKNOWN: dwMajorVersion=%d dwMinorVersion=%d\n",
455 osvi.dwMajorVersion, osvi.dwMinorVersion);
456 currentOS = OS_UNKNOWN;
457 }
458 } else {
459 if (bVersOk) {
460 J2dRlsTrace2(J2D_TRACE_INFO,
461 "OS_UNKNOWN: dwPlatformId=%d dwMajorVersion=%d\n",
462 osvi.dwPlatformId, osvi.dwMajorVersion);
463 } else {
464 J2dRlsTrace(J2D_TRACE_INFO,"OS_UNKNOWN: GetVersionEx failed\n");
465 }
466 currentOS = OS_UNKNOWN;
467 }
468 }
469 return (currentOS & osInfo);
470 }
471
472 // static
473 HRESULT
CheckForBadHardware(DWORD vId,DWORD dId,LONGLONG version)474 D3DPipelineManager::CheckForBadHardware(DWORD vId, DWORD dId, LONGLONG version)
475 {
476 DWORD vendorId, deviceId;
477 UINT adapterInfo = 0;
478
479 J2dTraceLn(J2D_TRACE_INFO, "D3DPPLM::CheckForBadHardware");
480
481 while ((vendorId = badHardware[adapterInfo].VendorId) != 0x0000 &&
482 (deviceId = badHardware[adapterInfo].DeviceId) != 0x0000)
483 {
484 if (vendorId == vId && (deviceId == dId || deviceId == ALL_DEVICEIDS)) {
485 LONGLONG goodVersion = badHardware[adapterInfo].DriverVersion;
486 USHORT osInfo = badHardware[adapterInfo].OsInfo;
487 // the hardware check fails if:
488 // - we have an entry for this OS and
489 // - hardware is bad for all driver versions (NO_VERSION), or
490 // we have a driver version which is older than the
491 // minimum required for this OS
492 if (D3DPPLM_OsVersionMatches(osInfo) &&
493 (goodVersion == NO_VERSION || version < goodVersion))
494 {
495 J2dRlsTraceLn2(J2D_TRACE_ERROR,
496 "D3DPPLM::CheckForBadHardware: found matching "\
497 "hardware: VendorId=0x%04x DeviceId=0x%04x",
498 vendorId, deviceId);
499 if (goodVersion != NO_VERSION) {
500 // this was a match by the driver version
501 LARGE_INTEGER li;
502 li.QuadPart = goodVersion;
503 J2dRlsTraceLn(J2D_TRACE_ERROR,
504 " bad driver found, device disabled");
505 J2dRlsTraceLn4(J2D_TRACE_ERROR,
506 " update your driver to at "\
507 "least version %d.%d.%d.%d",
508 HIWORD(li.HighPart), LOWORD(li.HighPart),
509 HIWORD(li.LowPart), LOWORD(li.LowPart));
510 } else {
511 // this was a match by the device (no good driver for this
512 // device)
513 J2dRlsTraceLn(J2D_TRACE_ERROR,
514 "D3DPPLM::CheckForBadHardware: bad hardware "\
515 "found, device disabled");
516 }
517 if (!bNoHwCheck) {
518 return D3DERR_INVALIDDEVICE;
519 }
520 J2dRlsTraceLn(J2D_TRACE_WARNING, " Warning: hw/driver match "\
521 "overridden (via J2D_D3D_NO_HWCHECK)");
522 }
523 }
524 adapterInfo++;
525 }
526
527 return S_OK;
528 }
529
CheckAdaptersInfo()530 HRESULT D3DPipelineManager::CheckAdaptersInfo()
531 {
532 D3DADAPTER_IDENTIFIER9 aid;
533 UINT failedAdaptersCount = 0;
534
535 J2dRlsTraceLn(J2D_TRACE_INFO, "CheckAdaptersInfo");
536 J2dRlsTraceLn(J2D_TRACE_INFO, "------------------");
537 for (UINT Adapter = 0; Adapter < adapterCount; Adapter++) {
538
539 if (FAILED(pd3d9->GetAdapterIdentifier(Adapter, 0, &aid))) {
540 pAdapters[Adapter].state = CONTEXT_INIT_FAILED;
541 failedAdaptersCount++;
542 continue;
543 }
544
545 J2dRlsTraceLn1(J2D_TRACE_INFO, "Adapter Ordinal : %d", Adapter);
546 J2dRlsTraceLn1(J2D_TRACE_INFO, "Adapter Handle : 0x%x",
547 pd3d9->GetAdapterMonitor(Adapter));
548 J2dRlsTraceLn1(J2D_TRACE_INFO, "Description : %s",
549 aid.Description);
550 J2dRlsTraceLn2(J2D_TRACE_INFO, "GDI Name, Driver : %s, %s",
551 aid.DeviceName, aid.Driver);
552 J2dRlsTraceLn1(J2D_TRACE_INFO, "Vendor Id : 0x%04x",
553 aid.VendorId);
554 J2dRlsTraceLn1(J2D_TRACE_INFO, "Device Id : 0x%04x",
555 aid.DeviceId);
556 J2dRlsTraceLn1(J2D_TRACE_INFO, "SubSys Id : 0x%x",
557 aid.SubSysId);
558 J2dRlsTraceLn4(J2D_TRACE_INFO, "Driver Version : %d.%d.%d.%d",
559 HIWORD(aid.DriverVersion.HighPart),
560 LOWORD(aid.DriverVersion.HighPart),
561 HIWORD(aid.DriverVersion.LowPart),
562 LOWORD(aid.DriverVersion.LowPart));
563 J2dRlsTrace3(J2D_TRACE_INFO,
564 "[I] GUID : {%08X-%04X-%04X-",
565 aid.DeviceIdentifier.Data1,
566 aid.DeviceIdentifier.Data2,
567 aid.DeviceIdentifier.Data3);
568 J2dRlsTrace4(J2D_TRACE_INFO, "%02X%02X-%02X%02X",
569 aid.DeviceIdentifier.Data4[0],
570 aid.DeviceIdentifier.Data4[1],
571 aid.DeviceIdentifier.Data4[2],
572 aid.DeviceIdentifier.Data4[3]);
573 J2dRlsTrace4(J2D_TRACE_INFO, "%02X%02X%02X%02X}\n",
574 aid.DeviceIdentifier.Data4[4],
575 aid.DeviceIdentifier.Data4[5],
576 aid.DeviceIdentifier.Data4[6],
577 aid.DeviceIdentifier.Data4[7]);
578
579 if (FAILED(CheckForBadHardware(aid.VendorId, aid.DeviceId,
580 aid.DriverVersion.QuadPart)) ||
581 FAILED(CheckDeviceCaps(Adapter)) ||
582 FAILED(D3DEnabledOnAdapter(Adapter)))
583 {
584 pAdapters[Adapter].state = CONTEXT_INIT_FAILED;
585 failedAdaptersCount++;
586 }
587 J2dRlsTraceLn(J2D_TRACE_INFO, "------------------");
588 }
589
590 if (failedAdaptersCount == adapterCount) {
591 J2dRlsTraceLn(J2D_TRACE_ERROR,
592 "D3DPPLM::CheckAdaptersInfo: no suitable adapters found");
593 return E_FAIL;
594 }
595
596 return S_OK;
597 }
598
SelectDeviceType()599 D3DDEVTYPE D3DPipelineManager::SelectDeviceType()
600 {
601 char *pRas = getenv("J2D_D3D_RASTERIZER");
602 D3DDEVTYPE dtype = D3DDEVTYPE_HAL;
603 if (pRas != NULL) {
604 J2dRlsTrace(J2D_TRACE_WARNING, "[W] D3DPPLM::SelectDeviceType: ");
605 if (strncmp(pRas, "ref", 3) == 0 || strncmp(pRas, "rgb", 3) == 0) {
606 J2dRlsTrace(J2D_TRACE_WARNING, "ref rasterizer selected");
607 dtype = D3DDEVTYPE_REF;
608 } else if (strncmp(pRas, "hal",3) == 0 || strncmp(pRas, "tnl",3) == 0) {
609 J2dRlsTrace(J2D_TRACE_WARNING, "hal rasterizer selected");
610 dtype = D3DDEVTYPE_HAL;
611 } else if (strncmp(pRas, "nul", 3) == 0) {
612 J2dRlsTrace(J2D_TRACE_WARNING, "nullref rasterizer selected");
613 dtype = D3DDEVTYPE_NULLREF;
614 } else {
615 J2dRlsTrace1(J2D_TRACE_WARNING,
616 "unknown rasterizer: %s, only (ref|hal|nul) "\
617 "supported, hal selected instead", pRas);
618 }
619 J2dRlsTrace(J2D_TRACE_WARNING, "\n");
620 }
621 return dtype;
622 }
623
624 #define CHECK_CAP(FLAG, CAP) \
625 do { \
626 if (!((FLAG)&CAP)) { \
627 J2dRlsTraceLn2(J2D_TRACE_ERROR, \
628 "D3DPPLM::CheckDeviceCaps: adapter %d: Failed "\
629 "(cap %s not supported)", \
630 adapter, #CAP); \
631 return E_FAIL; \
632 } \
633 } while (0)
634
CheckDeviceCaps(UINT adapter)635 HRESULT D3DPipelineManager::CheckDeviceCaps(UINT adapter)
636 {
637 HRESULT res;
638 D3DCAPS9 d3dCaps;
639
640 J2dTraceLn(J2D_TRACE_INFO, "D3DPPLM::CheckDeviceCaps");
641
642 res = pd3d9->GetDeviceCaps(adapter, devType, &d3dCaps);
643 RETURN_STATUS_IF_FAILED(res);
644
645 CHECK_CAP(d3dCaps.DevCaps, D3DDEVCAPS_DRAWPRIMTLVERTEX);
646
647 // by requiring hardware tnl we are hoping for better drivers quality
648 if (!IsD3DForced()) {
649 // fail if not hw tnl unless d3d was forced
650 CHECK_CAP(d3dCaps.DevCaps, D3DDEVCAPS_HWTRANSFORMANDLIGHT);
651 }
652 if (d3dCaps.DeviceType == D3DDEVTYPE_HAL) {
653 CHECK_CAP(d3dCaps.DevCaps, D3DDEVCAPS_HWRASTERIZATION);
654 }
655
656 CHECK_CAP(d3dCaps.RasterCaps, D3DPRASTERCAPS_SCISSORTEST);
657
658 CHECK_CAP(d3dCaps.Caps3, D3DCAPS3_ALPHA_FULLSCREEN_FLIP_OR_DISCARD);
659
660 CHECK_CAP(d3dCaps.PrimitiveMiscCaps, D3DPMISCCAPS_CULLNONE);
661 CHECK_CAP(d3dCaps.PrimitiveMiscCaps, D3DPMISCCAPS_BLENDOP);
662 CHECK_CAP(d3dCaps.PrimitiveMiscCaps, D3DPMISCCAPS_MASKZ);
663
664 CHECK_CAP(d3dCaps.ZCmpCaps, D3DPCMPCAPS_ALWAYS);
665 CHECK_CAP(d3dCaps.ZCmpCaps, D3DPCMPCAPS_LESS);
666
667 CHECK_CAP(d3dCaps.SrcBlendCaps, D3DPBLENDCAPS_ZERO);
668 CHECK_CAP(d3dCaps.SrcBlendCaps, D3DPBLENDCAPS_ONE);
669 CHECK_CAP(d3dCaps.SrcBlendCaps, D3DPBLENDCAPS_SRCALPHA);
670 CHECK_CAP(d3dCaps.SrcBlendCaps, D3DPBLENDCAPS_DESTALPHA);
671 CHECK_CAP(d3dCaps.SrcBlendCaps, D3DPBLENDCAPS_INVSRCALPHA);
672 CHECK_CAP(d3dCaps.SrcBlendCaps, D3DPBLENDCAPS_INVDESTALPHA);
673
674 CHECK_CAP(d3dCaps.DestBlendCaps, D3DPBLENDCAPS_ZERO);
675 CHECK_CAP(d3dCaps.DestBlendCaps, D3DPBLENDCAPS_ONE);
676 CHECK_CAP(d3dCaps.DestBlendCaps, D3DPBLENDCAPS_SRCALPHA);
677 CHECK_CAP(d3dCaps.DestBlendCaps, D3DPBLENDCAPS_DESTALPHA);
678 CHECK_CAP(d3dCaps.DestBlendCaps, D3DPBLENDCAPS_INVSRCALPHA);
679 CHECK_CAP(d3dCaps.DestBlendCaps, D3DPBLENDCAPS_INVDESTALPHA);
680
681 CHECK_CAP(d3dCaps.TextureAddressCaps, D3DPTADDRESSCAPS_CLAMP);
682 CHECK_CAP(d3dCaps.TextureAddressCaps, D3DPTADDRESSCAPS_WRAP);
683
684 CHECK_CAP(d3dCaps.TextureOpCaps, D3DTEXOPCAPS_MODULATE);
685
686 if (d3dCaps.PixelShaderVersion < D3DPS_VERSION(2,0) && !IsD3DForced()) {
687 J2dRlsTraceLn1(J2D_TRACE_ERROR,
688 "D3DPPLM::CheckDeviceCaps: adapter %d: Failed "\
689 "(pixel shaders 2.0 required)", adapter);
690 return E_FAIL;
691 }
692
693 J2dRlsTraceLn1(J2D_TRACE_INFO,
694 "D3DPPLM::CheckDeviceCaps: adapter %d: Passed", adapter);
695 return S_OK;
696 }
697
698
D3DEnabledOnAdapter(UINT adapter)699 HRESULT D3DPipelineManager::D3DEnabledOnAdapter(UINT adapter)
700 {
701 HRESULT res;
702 D3DDISPLAYMODE dm;
703
704 res = pd3d9->GetAdapterDisplayMode(adapter, &dm);
705 RETURN_STATUS_IF_FAILED(res);
706
707 res = pd3d9->CheckDeviceType(adapter, devType, dm.Format, dm.Format, TRUE);
708 if (FAILED(res)) {
709 J2dRlsTraceLn1(J2D_TRACE_ERROR,
710 "D3DPPLM::D3DEnabledOnAdapter: no " \
711 "suitable d3d device on adapter %d", adapter);
712 }
713
714 return res;
715 }
716
GetAdapterOrdinalByHmon(HMONITOR hMon)717 UINT D3DPipelineManager::GetAdapterOrdinalByHmon(HMONITOR hMon)
718 {
719 UINT ret = D3DADAPTER_DEFAULT;
720
721 if (pd3d9 != NULL) {
722 UINT adapterCount = pd3d9->GetAdapterCount();
723 for (UINT adapter = 0; adapter < adapterCount; adapter++) {
724 HMONITOR hm = pd3d9->GetAdapterMonitor(adapter);
725 if (hm == hMon) {
726 ret = adapter;
727 break;
728 }
729 }
730 }
731 return ret;
732 }
733
734 D3DFORMAT
GetMatchingDepthStencilFormat(UINT adapterOrdinal,D3DFORMAT adapterFormat,D3DFORMAT renderTargetFormat)735 D3DPipelineManager::GetMatchingDepthStencilFormat(UINT adapterOrdinal,
736 D3DFORMAT adapterFormat,
737 D3DFORMAT renderTargetFormat)
738 {
739 static D3DFORMAT formats[] =
740 { D3DFMT_D16, D3DFMT_D32, D3DFMT_D24S8, D3DFMT_D24X8 };
741 D3DFORMAT newFormat = D3DFMT_UNKNOWN;
742 HRESULT res;
743 for (int i = 0; i < 4; i++) {
744 res = pd3d9->CheckDeviceFormat(adapterOrdinal,
745 devType, adapterFormat, D3DUSAGE_DEPTHSTENCIL,
746 D3DRTYPE_SURFACE, formats[i]);
747 if (FAILED(res)) continue;
748
749 res = pd3d9->CheckDepthStencilMatch(adapterOrdinal,
750 devType, adapterFormat, renderTargetFormat, formats[i]);
751 if (FAILED(res)) continue;
752 newFormat = formats[i];
753 break;
754 }
755 return newFormat;
756 }
757
CreateDefaultFocusWindow()758 HWND D3DPipelineManager::CreateDefaultFocusWindow()
759 {
760 UINT adapterOrdinal = D3DADAPTER_DEFAULT;
761
762 J2dTraceLn1(J2D_TRACE_INFO,
763 "D3DPPLM::CreateDefaultFocusWindow: adapter=%d",
764 adapterOrdinal);
765
766 if (defaultFocusWindow != 0) {
767 J2dRlsTraceLn(J2D_TRACE_WARNING,
768 "D3DPPLM::CreateDefaultFocusWindow: "\
769 "existing default focus window!");
770 return defaultFocusWindow;
771 }
772
773 WNDCLASS wc;
774 ZeroMemory(&wc, sizeof(WNDCLASS));
775 wc.hInstance = GetModuleHandle(NULL);
776 wc.lpfnWndProc = DefWindowProc;
777 wc.lpszClassName = L"D3DFocusWindow";
778 if (RegisterClass(&wc) == 0) {
779 J2dRlsTraceLn(J2D_TRACE_ERROR,
780 "D3DPPLM::CreateDefaultFocusWindow: "\
781 "error registering window class");
782 return 0;
783 }
784
785 MONITORINFO mi;
786 ZeroMemory(&mi, sizeof(MONITORINFO));
787 mi.cbSize = sizeof(MONITORINFO);
788 HMONITOR hMon = pd3d9->GetAdapterMonitor(adapterOrdinal);
789 if (hMon == 0 || !GetMonitorInfo(hMon, (LPMONITORINFO)&mi)) {
790 J2dRlsTraceLn1(J2D_TRACE_ERROR,
791 "D3DPPLM::CreateDefaultFocusWindow: "\
792 "error getting monitor info for adapter=%d", adapterOrdinal);
793 return 0;
794 }
795
796 HWND hWnd = CreateWindow(L"D3DFocusWindow", L"D3DFocusWindow", WS_POPUP,
797 mi.rcMonitor.left, mi.rcMonitor.top, 1, 1,
798 NULL, NULL, GetModuleHandle(NULL), NULL);
799 if (hWnd == 0) {
800 J2dRlsTraceLn(J2D_TRACE_ERROR,
801 "D3DPPLM::CreateDefaultFocusWindow: CreateWindow failed");
802 } else {
803 J2dTraceLn2(J2D_TRACE_INFO,
804 " Created default focus window %x for adapter %d",
805 hWnd, adapterOrdinal);
806 defaultFocusWindow = hWnd;
807 }
808 return hWnd;
809 }
810
GetCurrentFocusWindow()811 HWND D3DPipelineManager::GetCurrentFocusWindow()
812 {
813 J2dTraceLn(J2D_TRACE_INFO, "D3DPPLM::GetCurrentFocusWindow");
814 if (currentFSFocusAdapter < 0) {
815 J2dTraceLn1(J2D_TRACE_VERBOSE,
816 " no fs windows, using default focus window=0x%x",
817 defaultFocusWindow);
818 return defaultFocusWindow;
819 }
820 J2dTraceLn1(J2D_TRACE_VERBOSE, " using fs window=0x%x",
821 pAdapters[currentFSFocusAdapter].fsFocusWindow);
822 return pAdapters[currentFSFocusAdapter].fsFocusWindow;
823 }
824
SetFSFocusWindow(UINT adapterOrdinal,HWND hWnd)825 HWND D3DPipelineManager::SetFSFocusWindow(UINT adapterOrdinal, HWND hWnd)
826 {
827 J2dTraceLn2(J2D_TRACE_INFO,"D3DPPLM::SetFSFocusWindow hwnd=0x%x adapter=%d",
828 hWnd, adapterOrdinal);
829
830 HWND prev = pAdapters[adapterOrdinal].fsFocusWindow;
831 pAdapters[adapterOrdinal].fsFocusWindow = hWnd;
832 if (currentFSFocusAdapter < 0) {
833 J2dTraceLn(J2D_TRACE_VERBOSE, " first full-screen window");
834 // first fs window
835 currentFSFocusAdapter = adapterOrdinal;
836 // REMIND: we might want to reset the rest of the context here as well
837 // like we do when the an adapter exits fs mode; currently they will
838 // be reset sometime later
839 } else {
840 // there's already a fs window
841 if (currentFSFocusAdapter == adapterOrdinal) {
842 // it's current fs window => we're exiting fs mode on this adapter;
843 // look for a new fs focus window
844 if (hWnd == 0) {
845 UINT i;
846 currentFSFocusAdapter = -1;
847 for (i = 0; i < adapterCount; i++) {
848 if (pAdapters[i].fsFocusWindow != 0) {
849 J2dTraceLn1(J2D_TRACE_VERBOSE,
850 " adapter %d is still in fs mode", i);
851 currentFSFocusAdapter = i;
852 break;
853 }
854 }
855 // we have to reset all devices any time current focus device
856 // exits fs mode, and also to prevent some of them being left in
857 // a lost state when the last device exits fs - when non-last
858 // adapters exit fs mode they would not be able to create the
859 // device and will be put in a lost state forever
860 HRESULT res;
861 J2dTraceLn(J2D_TRACE_VERBOSE,
862 " adapter exited full-screen, reset all adapters");
863 for (i = 0; i < adapterCount; i++) {
864 if (pAdapters[i].pd3dContext != NULL) {
865 res = pAdapters[i].pd3dContext->ResetContext();
866 D3DRQ_MarkLostIfNeeded(res,
867 D3DRQ_GetCurrentDestination());
868 }
869 }
870 } else {
871 J2dTraceLn1(J2D_TRACE_WARNING,
872 "D3DPM::SetFSFocusWindow: setting the fs "\
873 "window again for adapter %d", adapterOrdinal);
874 }
875 }
876 }
877 return prev;
878 }
879
GetD3DContext(UINT adapterOrdinal,D3DContext ** ppd3dContext)880 HRESULT D3DPipelineManager::GetD3DContext(UINT adapterOrdinal,
881 D3DContext **ppd3dContext)
882 {
883 J2dTraceLn(J2D_TRACE_INFO, "D3DPPLM::GetD3DContext");
884
885 HRESULT res = S_OK;
886 if (adapterOrdinal < 0 || adapterOrdinal >= adapterCount ||
887 pAdapters == NULL ||
888 pAdapters[adapterOrdinal].state == CONTEXT_INIT_FAILED)
889 {
890 J2dRlsTraceLn1(J2D_TRACE_ERROR,
891 "D3DPPLM::GetD3DContext: invalid parameters or "\
892 "failed init for adapter %d", adapterOrdinal);
893 *ppd3dContext = NULL;
894 return E_FAIL;
895 }
896
897 if (pAdapters[adapterOrdinal].state == CONTEXT_NOT_INITED) {
898 D3DContext *pCtx = NULL;
899
900 if (pAdapters[adapterOrdinal].pd3dContext != NULL) {
901 J2dTraceLn1(J2D_TRACE_ERROR, " non-null context in "\
902 "uninitialized adapter %d", adapterOrdinal);
903 res = E_FAIL;
904 } else {
905 J2dTraceLn1(J2D_TRACE_VERBOSE,
906 " initializing context for adapter %d",adapterOrdinal);
907
908 if (SUCCEEDED(res = D3DEnabledOnAdapter(adapterOrdinal))) {
909 res = D3DContext::CreateInstance(pd3d9, adapterOrdinal, &pCtx);
910 if (FAILED(res)) {
911 J2dRlsTraceLn1(J2D_TRACE_ERROR,
912 "D3DPPLM::GetD3DContext: failed to create context "\
913 "for adapter=%d", adapterOrdinal);
914 }
915 } else {
916 J2dRlsTraceLn1(J2D_TRACE_ERROR,
917 "D3DPPLM::GetContext: no d3d on adapter %d",adapterOrdinal);
918 }
919 }
920 pAdapters[adapterOrdinal].state =
921 SUCCEEDED(res) ? CONTEXT_CREATED : CONTEXT_INIT_FAILED;
922 pAdapters[adapterOrdinal].pd3dContext = pCtx;
923 }
924 *ppd3dContext = pAdapters[adapterOrdinal].pd3dContext;
925 return res;
926 }
927
928
929 //==============================================================
930 // D3DInitializer
931 //==============================================================
932
933 D3DInitializer D3DInitializer::theInstance;
934
D3DInitializer()935 D3DInitializer::D3DInitializer()
936 : bComInitialized(false), pAdapterIniters(NULL)
937 {
938 }
939
~D3DInitializer()940 D3DInitializer::~D3DInitializer()
941 {
942 if (pAdapterIniters) {
943 delete[] pAdapterIniters;
944 }
945 }
946
InitImpl()947 void D3DInitializer::InitImpl()
948 {
949 J2dRlsTraceLn(J2D_TRACE_INFO, "D3DInitializer::InitImpl");
950 if (SUCCEEDED(::CoInitialize(NULL))) {
951 bComInitialized = true;
952 }
953 D3DPipelineManager *pMgr = D3DPipelineManager::CreateInstance();
954 if (pMgr != NULL) {
955 // init adapters if we are preloading
956 if (AwtToolkit::GetInstance().GetPreloadThread().OnPreloadThread()) {
957 UINT adapterCount = pMgr->adapterCount;
958
959 pAdapterIniters = new D3DAdapterInitializer[adapterCount];
960 for (UINT i=0; i<adapterCount; i++) {
961 pAdapterIniters[i].setAdapter(i);
962 AwtToolkit::GetInstance().GetPreloadThread().AddAction(&pAdapterIniters[i]);
963 }
964 }
965 }
966 }
967
CleanImpl(bool reInit)968 void D3DInitializer::CleanImpl(bool reInit)
969 {
970 J2dRlsTraceLn1(J2D_TRACE_INFO, "D3DInitializer::CleanImpl (%s)",
971 reInit ? "RELAUNCH" : "normal");
972 D3DPipelineManager::DeleteInstance();
973 if (bComInitialized) {
974 CoUninitialize();
975 }
976 }
977
978
InitImpl()979 void D3DInitializer::D3DAdapterInitializer::InitImpl()
980 {
981 J2dRlsTraceLn1(J2D_TRACE_INFO, "D3DAdapterInitializer::InitImpl(%d) started", adapter);
982
983 D3DPipelineManager *pMgr = D3DPipelineManager::GetInstance();
984 if (pMgr == NULL) {
985 return;
986 }
987
988 D3DContext *pd3dContext;
989 pMgr->GetD3DContext(adapter, &pd3dContext);
990
991 J2dRlsTraceLn1(J2D_TRACE_INFO, "D3DAdapterInitializer::InitImpl(%d) finished", adapter);
992 }
993
CleanImpl(bool reInit)994 void D3DInitializer::D3DAdapterInitializer::CleanImpl(bool reInit)
995 {
996 // nothing to do - D3DPipelineManager cleans adapters
997 }
998
999
1000 extern "C" {
1001 /*
1002 * Export function to start D3D preloading
1003 * (called from java/javaw - see src/windows/bin/java-md.c)
1004 */
preloadD3D()1005 __declspec(dllexport) int preloadD3D()
1006 {
1007 J2dRlsTraceLn(J2D_TRACE_INFO, "AWT warmup: preloadD3D");
1008 AwtToolkit::GetInstance().GetPreloadThread().AddAction(&D3DInitializer::GetInstance());
1009 return 1;
1010 }
1011
1012 }
1013
1014