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 
  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 
  70 void D3DPipelineManager::DeleteInstance()
  71 {
  72     J2dTraceLn(J2D_TRACE_INFO, "D3DPPLM::DeleteInstance()");
  73     SAFE_DELETE(pMgr);
  74 }
  75 
  76 D3DPipelineManager * D3DPipelineManager::GetInstance(void)
  77 {
  78     return pMgr;
  79 }
  80 
  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 
  92 D3DPipelineManager::~D3DPipelineManager(void)
  93 {
  94     J2dTraceLn(J2D_TRACE_INFO, "D3DPPLM::~D3DPipelineManager()");
  95     ReleaseD3D();
  96 }
  97 
  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.
 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 
 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 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
 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 
 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 
 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
 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
 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 
 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
 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 
 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 
 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 
 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 
 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 
 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
 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 
 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 
 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 
 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 
 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 
 935 D3DInitializer::D3DInitializer()
 936     : bComInitialized(false), pAdapterIniters(NULL)
 937 {
 938 }
 939 
 940 D3DInitializer::~D3DInitializer()
 941 {
 942     if (pAdapterIniters) {
 943         delete[] pAdapterIniters;
 944     }
 945 }
 946 
 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 
 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 
 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 
 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  */
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