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