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
39static BOOL bNoHwCheck = (getenv("J2D_D3D_NO_HWCHECK") != NULL);
40
41D3DPipelineManager *D3DPipelineManager::pMgr = NULL;
42
43
44D3DPipelineManager * 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
70void D3DPipelineManager::DeleteInstance()
71{
72    J2dTraceLn(J2D_TRACE_INFO, "D3DPPLM::DeleteInstance()");
73    SAFE_DELETE(pMgr);
74}
75
76D3DPipelineManager * D3DPipelineManager::GetInstance(void)
77{
78    return pMgr;
79}
80
81D3DPipelineManager::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
92D3DPipelineManager::~D3DPipelineManager(void)
93{
94    J2dTraceLn(J2D_TRACE_INFO, "D3DPPLM::~D3DPipelineManager()");
95    ReleaseD3D();
96}
97
98HRESULT 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.
116HRESULT 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
153HRESULT 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
176UINT 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
186HRESULT 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
243HRESULT 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
291HRESULT 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
321HRESULT
322D3DPipelineManager::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
346HRESULT
347D3DPipelineManager::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
404BOOL 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
473HRESULT
474D3DPipelineManager::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
530HRESULT 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
599D3DDEVTYPE 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
635HRESULT 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
699HRESULT 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
717UINT 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
734D3DFORMAT
735D3DPipelineManager::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
758HWND 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
811HWND 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
825HWND 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
880HRESULT 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
933D3DInitializer D3DInitializer::theInstance;
934
935D3DInitializer::D3DInitializer()
936    : bComInitialized(false), pAdapterIniters(NULL)
937{
938}
939
940D3DInitializer::~D3DInitializer()
941{
942    if (pAdapterIniters) {
943        delete[] pAdapterIniters;
944    }
945}
946
947void 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
968void 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
979void 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
994void D3DInitializer::D3DAdapterInitializer::CleanImpl(bool reInit)
995{
996    // nothing to do - D3DPipelineManager cleans adapters
997}
998
999
1000extern "C" {
1001/*
1002 * Export function to start D3D preloading
1003 * (called from java/javaw - see src/windows/bin/java-md.c)
1004 */
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