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