/* * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ #include "D3DBadHardware.h" #include "D3DPipelineManager.h" #include "D3DRenderQueue.h" #include "WindowsFlags.h" #include "awt_Win32GraphicsDevice.h" // state of the adapter prior to initialization #define CONTEXT_NOT_INITED 0 // this state is set if adapter initialization had failed #define CONTEXT_INIT_FAILED (-1) // this state is set if adapter was successfully created #define CONTEXT_CREATED 1 static BOOL bNoHwCheck = (getenv("J2D_D3D_NO_HWCHECK") != NULL); D3DPipelineManager *D3DPipelineManager::pMgr = NULL; D3DPipelineManager * D3DPipelineManager::CreateInstance(void) { if (!IsD3DEnabled() || FAILED((D3DPipelineManager::CheckOSVersion())) || FAILED((D3DPipelineManager::GDICheckForBadHardware()))) { return NULL; } if (pMgr == NULL) { pMgr = new D3DPipelineManager(); if (FAILED(pMgr->InitD3D())) { SAFE_DELETE(pMgr); } } else { // this should never happen so to be on the safe side do not // use this unexpected pointer, do not try to release it, just null // it out and fail safely J2dRlsTraceLn1(J2D_TRACE_ERROR, "D3DPPLM::CreateInstance: unexpected instance: 0x%x,"\ " abort.", pMgr); pMgr = NULL; } return pMgr; } void D3DPipelineManager::DeleteInstance() { J2dTraceLn(J2D_TRACE_INFO, "D3DPPLM::DeleteInstance()"); SAFE_DELETE(pMgr); } D3DPipelineManager * D3DPipelineManager::GetInstance(void) { return pMgr; } D3DPipelineManager::D3DPipelineManager(void) { pd3d9 = NULL; hLibD3D9 = NULL; pAdapters = NULL; adapterCount = 0; currentFSFocusAdapter = -1; defaultFocusWindow = 0; devType = SelectDeviceType(); } D3DPipelineManager::~D3DPipelineManager(void) { J2dTraceLn(J2D_TRACE_INFO, "D3DPPLM::~D3DPipelineManager()"); ReleaseD3D(); } HRESULT D3DPipelineManager::ReleaseD3D(void) { J2dTraceLn(J2D_TRACE_INFO, "D3DPPLM::ReleaseD3D()"); ReleaseAdapters(); SAFE_RELEASE(pd3d9); if (hLibD3D9 != NULL) { ::FreeLibrary(hLibD3D9); hLibD3D9 = NULL; } return S_OK; } // Creates a Direct3D9 object and initializes adapters. // If succeeded, returns S_OK, otherwise returns the error code. HRESULT D3DPipelineManager::InitD3D(void) { typedef IDirect3D9 * WINAPI FnDirect3DCreate9(UINT SDKVersion); hLibD3D9 = JDK_LoadSystemLibrary("d3d9.dll"); if (hLibD3D9 == NULL) { J2dRlsTraceLn(J2D_TRACE_ERROR, "InitD3D: no d3d9.dll"); return E_FAIL; } FnDirect3DCreate9 *d3dcreate9 = NULL; d3dcreate9 = (FnDirect3DCreate9*) ::GetProcAddress(hLibD3D9, "Direct3DCreate9"); if (d3dcreate9 == NULL) { J2dRlsTraceLn(J2D_TRACE_ERROR, "InitD3D: no Direct3DCreate9"); ::FreeLibrary(hLibD3D9); return E_FAIL; } pd3d9 = d3dcreate9(D3D_SDK_VERSION); if (pd3d9 == NULL) { J2dRlsTraceLn(J2D_TRACE_ERROR, "InitD3D: unable to create IDirect3D9 object"); ::FreeLibrary(hLibD3D9); return E_FAIL; } HRESULT res; if (FAILED(res = InitAdapters())) { J2dRlsTraceLn(J2D_TRACE_ERROR, "InitD3D: failed to init adapters"); ReleaseD3D(); return res; } return S_OK; } HRESULT D3DPipelineManager::ReleaseAdapters() { J2dTraceLn(J2D_TRACE_INFO, "D3DPPLM::ReleaseAdapters()"); D3DRQ_ResetCurrentContextAndDestination(); if (pAdapters != NULL) { for (UINT i = 0; i < adapterCount; i++) { if (pAdapters[i].pd3dContext != NULL) { delete pAdapters[i].pd3dContext; } } delete[] pAdapters; pAdapters = NULL; } if (defaultFocusWindow != 0) { DestroyWindow(defaultFocusWindow); UnregisterClass(L"D3DFocusWindow", GetModuleHandle(NULL)); defaultFocusWindow = 0; } currentFSFocusAdapter = -1; return S_OK; } // static void D3DPipelineManager::NotifyAdapterEventListeners(UINT adapter, jint eventType) { HMONITOR hMon; int gdiScreen; D3DPipelineManager *pMgr; // fix for 6946559: if d3d preloading fails jmv may be NULL if (jvm == NULL) { return; } JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2); RETURN_IF_NULL(env); pMgr = D3DPipelineManager::GetInstance(); RETURN_IF_NULL(pMgr); hMon = pMgr->pd3d9->GetAdapterMonitor(adapter); /* * If we don't have devices initialized yet, no sense to clear them. */ if (!Devices::GetInstance()){ return; } gdiScreen = AwtWin32GraphicsDevice::GetScreenFromHMONITOR(hMon); JNU_CallStaticMethodByName(env, NULL, "sun/java2d/pipe/hw/AccelDeviceEventNotifier", "eventOccured", "(II)V", gdiScreen, eventType); } UINT D3DPipelineManager::GetAdapterOrdinalForScreen(jint gdiScreen) { HMONITOR mHnd = AwtWin32GraphicsDevice::GetMonitor(gdiScreen); if (mHnd == (HMONITOR)0) { return D3DADAPTER_DEFAULT; } return GetAdapterOrdinalByHmon((HMONITOR)mHnd); } // static HRESULT D3DPipelineManager::HandleAdaptersChange(HMONITOR *pHMONITORs, UINT monNum) { HRESULT res = S_OK; BOOL bResetD3D = FALSE, bFound; D3DPipelineManager *pMgr = D3DPipelineManager::GetInstance(); RETURN_STATUS_IF_NULL(pHMONITORs, E_FAIL); if (pMgr == NULL) { // NULL pMgr is valid when the pipeline is not enabled or if it hasn't // been created yet return S_OK; } RETURN_STATUS_IF_NULL(pMgr->pAdapters, E_FAIL); RETURN_STATUS_IF_NULL(pMgr->pd3d9, E_FAIL); J2dTraceLn(J2D_TRACE_INFO, "D3DPPLM::HandleAdaptersChange"); if (monNum != pMgr->adapterCount) { J2dTraceLn2(J2D_TRACE_VERBOSE, " number of adapters changed (old=%d, new=%d)", pMgr->adapterCount, monNum); bResetD3D = TRUE; } else { for (UINT i = 0; i < pMgr->adapterCount; i++) { HMONITOR hMon = pMgr->pd3d9->GetAdapterMonitor(i); if (hMon == (HMONITOR)0x0) { J2dTraceLn1(J2D_TRACE_VERBOSE, " adapter %d: removed", i); bResetD3D = TRUE; break; } bFound = FALSE; for (UINT mon = 0; mon < monNum; mon++) { if (pHMONITORs[mon] == hMon) { J2dTraceLn3(J2D_TRACE_VERBOSE, " adapter %d: found hmnd[%d]=0x%x", i, mon, hMon); bFound = TRUE; break; } } if (!bFound) { J2dTraceLn2(J2D_TRACE_VERBOSE, " adapter %d: could not find hmnd=0x%x "\ "in the list of new hmnds", i, hMon); bResetD3D = TRUE; break; } } } if (bResetD3D) { J2dTraceLn(J2D_TRACE_VERBOSE, " adapters changed: resetting d3d"); pMgr->ReleaseD3D(); res = pMgr->InitD3D(); } return res; } HRESULT D3DPipelineManager::HandleLostDevices() { J2dTraceLn(J2D_TRACE_INFO, "D3DPPLM::HandleLostDevices()"); BOOL bAllClear = TRUE; HWND hwnd = GetCurrentFocusWindow(); if (hwnd != defaultFocusWindow) { // we're in full-screen mode WINDOWPLACEMENT wp; ::ZeroMemory(&wp, sizeof(WINDOWPLACEMENT)); wp.length = sizeof(WINDOWPLACEMENT); ::GetWindowPlacement(hwnd, &wp); // Only attempt to restore the devices if we're in full-screen mode // and the fs window is active; sleep otherwise. // Restoring a window while minimized causes problems on Vista: // sometimes we restore the window too quickly and it pops up back from // minimized state when the device is restored. // // WARNING: this is a sleep on the Toolkit thread! We may reconsider // this if we find any issues later. if ((wp.showCmd & SW_SHOWMINNOACTIVE) && !(wp.showCmd & SW_SHOWNORMAL)){ static DWORD prevCallTime = 0; J2dTraceLn(J2D_TRACE_VERBOSE, " fs focus window is minimized"); DWORD currentTime = ::GetTickCount(); if ((currentTime - prevCallTime) < 100) { J2dTraceLn(J2D_TRACE_VERBOSE, " tight loop detected, sleep"); ::Sleep(100); } prevCallTime = currentTime; return D3DERR_DEVICELOST; } } if (pAdapters != NULL) { for (UINT i = 0; i < adapterCount; i++) { if (pAdapters[i].pd3dContext != NULL) { J2dTraceLn1(J2D_TRACE_VERBOSE, " HandleLostDevices: checking adapter %d", i); D3DContext *d3dc = pAdapters[i].pd3dContext; if (FAILED(d3dc->CheckAndResetDevice())) { bAllClear = FALSE; } } } } return bAllClear ? S_OK : D3DERR_DEVICELOST; } HRESULT D3DPipelineManager::InitAdapters() { HRESULT res = E_FAIL; J2dTraceLn(J2D_TRACE_INFO, "D3DPPLM::InitAdapters()"); if (pAdapters != NULL) { ReleaseAdapters(); } adapterCount = pd3d9->GetAdapterCount(); pAdapters = new D3DAdapter[adapterCount]; if (pAdapters == NULL) { J2dRlsTraceLn(J2D_TRACE_ERROR, "InitAdapters: out of memory"); adapterCount = 0; return E_FAIL; } ZeroMemory(pAdapters, adapterCount * sizeof(D3DAdapter)); res = CheckAdaptersInfo(); RETURN_STATUS_IF_FAILED(res); currentFSFocusAdapter = -1; if (CreateDefaultFocusWindow() == 0) { return E_FAIL; } return S_OK; } // static HRESULT D3DPipelineManager::CheckOSVersion() { // require Windows XP or newer client-class OS if (IS_WINVER_ATLEAST(5, 1) && !D3DPPLM_OsVersionMatches(OS_WINSERV_2008R2|OS_WINSERV_2008| OS_WINSERV_2003)) { J2dTraceLn(J2D_TRACE_INFO, "D3DPPLM::CheckOSVersion: Windows XP or newer client-classs"\ " OS detected, passed"); return S_OK; } J2dRlsTraceLn(J2D_TRACE_ERROR, "D3DPPLM::CheckOSVersion: Windows 2000 or earlier (or a "\ "server) OS detected, failed"); if (bNoHwCheck) { J2dRlsTraceLn(J2D_TRACE_WARNING, " OS check overridden via J2D_D3D_NO_HWCHECK"); return S_OK; } return E_FAIL; } // static HRESULT D3DPipelineManager::GDICheckForBadHardware() { DISPLAY_DEVICE dd; dd.cb = sizeof(DISPLAY_DEVICE); int failedDevices = 0; int attachedDevices = 0; int i = 0; WCHAR *id; WCHAR vendorId[5]; WCHAR deviceId[5]; DWORD dwDId, dwVId; J2dTraceLn(J2D_TRACE_INFO, "D3DPPLM::GDICheckForBadHardware"); // i<20 is to guard against buggy drivers while (EnumDisplayDevices(NULL, i, &dd, 0) && i < 20) { if (dd.StateFlags & DISPLAY_DEVICE_ATTACHED_TO_DESKTOP) { attachedDevices++; id = dd.DeviceID; if (wcslen(id) > 21) { // get vendor ID wcsncpy(vendorId, id+8, 4); int args1 = swscanf(vendorId, L"%X", &dwVId); // get device ID wcsncpy(deviceId, id+17, 4); int args2 = swscanf(deviceId, L"%X", &dwDId); if (args1 == 1 && args2 == 1) { J2dTraceLn2(J2D_TRACE_VERBOSE, " device: vendorID=0x%04x, deviceId=0x%04x", dwVId, dwDId); // since we don't have a driver version here we will // just ask to ignore the version for now; bad hw // entries with specific drivers information will be // processed later when d3d is initialized and we can // obtain a driver version if (FAILED(CheckForBadHardware(dwVId, dwDId, MAX_VERSION))){ failedDevices++; } } } } i++; } if (failedDevices == attachedDevices) { J2dRlsTraceLn(J2D_TRACE_ERROR, "D3DPPLM::GDICheckForBadHardware: no suitable devices found"); return E_FAIL; } return S_OK; } BOOL D3DPPLM_OsVersionMatches(USHORT osInfo) { static USHORT currentOS = OS_UNDEFINED; if (currentOS == OS_UNDEFINED) { BOOL bVersOk; OSVERSIONINFOEX osvi; ZeroMemory(&osvi, sizeof(OSVERSIONINFOEX)); osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX); bVersOk = GetVersionEx((OSVERSIONINFO *) &osvi); J2dRlsTrace(J2D_TRACE_INFO, "[I] OS Version = "); if (bVersOk && osvi.dwPlatformId == VER_PLATFORM_WIN32_NT && osvi.dwMajorVersion > 4) { if (osvi.dwMajorVersion >= 6 && osvi.dwMinorVersion == 0) { if (osvi.wProductType == VER_NT_WORKSTATION) { J2dRlsTrace(J2D_TRACE_INFO, "OS_VISTA\n"); currentOS = OS_VISTA; } else { J2dRlsTrace(J2D_TRACE_INFO, "OS_WINSERV_2008\n"); currentOS = OS_WINSERV_2008; } } else if (osvi.dwMajorVersion >= 6 && osvi.dwMinorVersion >= 1) { if (osvi.wProductType == VER_NT_WORKSTATION) { J2dRlsTrace(J2D_TRACE_INFO, "OS_WINDOWS7 or newer\n"); currentOS = OS_WINDOWS7; } else { J2dRlsTrace(J2D_TRACE_INFO, "OS_WINSERV_2008R2 or newer\n"); currentOS = OS_WINSERV_2008R2; } } else if (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 2) { if (osvi.wProductType == VER_NT_WORKSTATION) { J2dRlsTrace(J2D_TRACE_INFO, "OS_WINXP_64\n"); currentOS = OS_WINXP_64; } else { J2dRlsTrace(J2D_TRACE_INFO, "OS_WINSERV_2003\n"); currentOS = OS_WINSERV_2003; } } else if (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 1) { J2dRlsTrace(J2D_TRACE_INFO, "OS_WINXP "); currentOS = OS_WINXP; if (osvi.wSuiteMask & VER_SUITE_PERSONAL) { J2dRlsTrace(J2D_TRACE_INFO, "Home\n"); } else { J2dRlsTrace(J2D_TRACE_INFO, "Pro\n"); } } else { J2dRlsTrace2(J2D_TRACE_INFO, "OS_UNKNOWN: dwMajorVersion=%d dwMinorVersion=%d\n", osvi.dwMajorVersion, osvi.dwMinorVersion); currentOS = OS_UNKNOWN; } } else { if (bVersOk) { J2dRlsTrace2(J2D_TRACE_INFO, "OS_UNKNOWN: dwPlatformId=%d dwMajorVersion=%d\n", osvi.dwPlatformId, osvi.dwMajorVersion); } else { J2dRlsTrace(J2D_TRACE_INFO,"OS_UNKNOWN: GetVersionEx failed\n"); } currentOS = OS_UNKNOWN; } } return (currentOS & osInfo); } // static HRESULT D3DPipelineManager::CheckForBadHardware(DWORD vId, DWORD dId, LONGLONG version) { DWORD vendorId, deviceId; UINT adapterInfo = 0; J2dTraceLn(J2D_TRACE_INFO, "D3DPPLM::CheckForBadHardware"); while ((vendorId = badHardware[adapterInfo].VendorId) != 0x0000 && (deviceId = badHardware[adapterInfo].DeviceId) != 0x0000) { if (vendorId == vId && (deviceId == dId || deviceId == ALL_DEVICEIDS)) { LONGLONG goodVersion = badHardware[adapterInfo].DriverVersion; USHORT osInfo = badHardware[adapterInfo].OsInfo; // the hardware check fails if: // - we have an entry for this OS and // - hardware is bad for all driver versions (NO_VERSION), or // we have a driver version which is older than the // minimum required for this OS if (D3DPPLM_OsVersionMatches(osInfo) && (goodVersion == NO_VERSION || version < goodVersion)) { J2dRlsTraceLn2(J2D_TRACE_ERROR, "D3DPPLM::CheckForBadHardware: found matching "\ "hardware: VendorId=0x%04x DeviceId=0x%04x", vendorId, deviceId); if (goodVersion != NO_VERSION) { // this was a match by the driver version LARGE_INTEGER li; li.QuadPart = goodVersion; J2dRlsTraceLn(J2D_TRACE_ERROR, " bad driver found, device disabled"); J2dRlsTraceLn4(J2D_TRACE_ERROR, " update your driver to at "\ "least version %d.%d.%d.%d", HIWORD(li.HighPart), LOWORD(li.HighPart), HIWORD(li.LowPart), LOWORD(li.LowPart)); } else { // this was a match by the device (no good driver for this // device) J2dRlsTraceLn(J2D_TRACE_ERROR, "D3DPPLM::CheckForBadHardware: bad hardware "\ "found, device disabled"); } if (!bNoHwCheck) { return D3DERR_INVALIDDEVICE; } J2dRlsTraceLn(J2D_TRACE_WARNING, " Warning: hw/driver match "\ "overridden (via J2D_D3D_NO_HWCHECK)"); } } adapterInfo++; } return S_OK; } HRESULT D3DPipelineManager::CheckAdaptersInfo() { D3DADAPTER_IDENTIFIER9 aid; UINT failedAdaptersCount = 0; J2dRlsTraceLn(J2D_TRACE_INFO, "CheckAdaptersInfo"); J2dRlsTraceLn(J2D_TRACE_INFO, "------------------"); for (UINT Adapter = 0; Adapter < adapterCount; Adapter++) { if (FAILED(pd3d9->GetAdapterIdentifier(Adapter, 0, &aid))) { pAdapters[Adapter].state = CONTEXT_INIT_FAILED; failedAdaptersCount++; continue; } J2dRlsTraceLn1(J2D_TRACE_INFO, "Adapter Ordinal : %d", Adapter); J2dRlsTraceLn1(J2D_TRACE_INFO, "Adapter Handle : 0x%x", pd3d9->GetAdapterMonitor(Adapter)); J2dRlsTraceLn1(J2D_TRACE_INFO, "Description : %s", aid.Description); J2dRlsTraceLn2(J2D_TRACE_INFO, "GDI Name, Driver : %s, %s", aid.DeviceName, aid.Driver); J2dRlsTraceLn1(J2D_TRACE_INFO, "Vendor Id : 0x%04x", aid.VendorId); J2dRlsTraceLn1(J2D_TRACE_INFO, "Device Id : 0x%04x", aid.DeviceId); J2dRlsTraceLn1(J2D_TRACE_INFO, "SubSys Id : 0x%x", aid.SubSysId); J2dRlsTraceLn4(J2D_TRACE_INFO, "Driver Version : %d.%d.%d.%d", HIWORD(aid.DriverVersion.HighPart), LOWORD(aid.DriverVersion.HighPart), HIWORD(aid.DriverVersion.LowPart), LOWORD(aid.DriverVersion.LowPart)); J2dRlsTrace3(J2D_TRACE_INFO, "[I] GUID : {%08X-%04X-%04X-", aid.DeviceIdentifier.Data1, aid.DeviceIdentifier.Data2, aid.DeviceIdentifier.Data3); J2dRlsTrace4(J2D_TRACE_INFO, "%02X%02X-%02X%02X", aid.DeviceIdentifier.Data4[0], aid.DeviceIdentifier.Data4[1], aid.DeviceIdentifier.Data4[2], aid.DeviceIdentifier.Data4[3]); J2dRlsTrace4(J2D_TRACE_INFO, "%02X%02X%02X%02X}\n", aid.DeviceIdentifier.Data4[4], aid.DeviceIdentifier.Data4[5], aid.DeviceIdentifier.Data4[6], aid.DeviceIdentifier.Data4[7]); if (FAILED(CheckForBadHardware(aid.VendorId, aid.DeviceId, aid.DriverVersion.QuadPart)) || FAILED(CheckDeviceCaps(Adapter)) || FAILED(D3DEnabledOnAdapter(Adapter))) { pAdapters[Adapter].state = CONTEXT_INIT_FAILED; failedAdaptersCount++; } J2dRlsTraceLn(J2D_TRACE_INFO, "------------------"); } if (failedAdaptersCount == adapterCount) { J2dRlsTraceLn(J2D_TRACE_ERROR, "D3DPPLM::CheckAdaptersInfo: no suitable adapters found"); return E_FAIL; } return S_OK; } D3DDEVTYPE D3DPipelineManager::SelectDeviceType() { char *pRas = getenv("J2D_D3D_RASTERIZER"); D3DDEVTYPE dtype = D3DDEVTYPE_HAL; if (pRas != NULL) { J2dRlsTrace(J2D_TRACE_WARNING, "[W] D3DPPLM::SelectDeviceType: "); if (strncmp(pRas, "ref", 3) == 0 || strncmp(pRas, "rgb", 3) == 0) { J2dRlsTrace(J2D_TRACE_WARNING, "ref rasterizer selected"); dtype = D3DDEVTYPE_REF; } else if (strncmp(pRas, "hal",3) == 0 || strncmp(pRas, "tnl",3) == 0) { J2dRlsTrace(J2D_TRACE_WARNING, "hal rasterizer selected"); dtype = D3DDEVTYPE_HAL; } else if (strncmp(pRas, "nul", 3) == 0) { J2dRlsTrace(J2D_TRACE_WARNING, "nullref rasterizer selected"); dtype = D3DDEVTYPE_NULLREF; } else { J2dRlsTrace1(J2D_TRACE_WARNING, "unknown rasterizer: %s, only (ref|hal|nul) "\ "supported, hal selected instead", pRas); } J2dRlsTrace(J2D_TRACE_WARNING, "\n"); } return dtype; } #define CHECK_CAP(FLAG, CAP) \ do { \ if (!((FLAG)&CAP)) { \ J2dRlsTraceLn2(J2D_TRACE_ERROR, \ "D3DPPLM::CheckDeviceCaps: adapter %d: Failed "\ "(cap %s not supported)", \ adapter, #CAP); \ return E_FAIL; \ } \ } while (0) HRESULT D3DPipelineManager::CheckDeviceCaps(UINT adapter) { HRESULT res; D3DCAPS9 d3dCaps; J2dTraceLn(J2D_TRACE_INFO, "D3DPPLM::CheckDeviceCaps"); res = pd3d9->GetDeviceCaps(adapter, devType, &d3dCaps); RETURN_STATUS_IF_FAILED(res); CHECK_CAP(d3dCaps.DevCaps, D3DDEVCAPS_DRAWPRIMTLVERTEX); // by requiring hardware tnl we are hoping for better drivers quality if (!IsD3DForced()) { // fail if not hw tnl unless d3d was forced CHECK_CAP(d3dCaps.DevCaps, D3DDEVCAPS_HWTRANSFORMANDLIGHT); } if (d3dCaps.DeviceType == D3DDEVTYPE_HAL) { CHECK_CAP(d3dCaps.DevCaps, D3DDEVCAPS_HWRASTERIZATION); } CHECK_CAP(d3dCaps.RasterCaps, D3DPRASTERCAPS_SCISSORTEST); CHECK_CAP(d3dCaps.Caps3, D3DCAPS3_ALPHA_FULLSCREEN_FLIP_OR_DISCARD); CHECK_CAP(d3dCaps.PrimitiveMiscCaps, D3DPMISCCAPS_CULLNONE); CHECK_CAP(d3dCaps.PrimitiveMiscCaps, D3DPMISCCAPS_BLENDOP); CHECK_CAP(d3dCaps.PrimitiveMiscCaps, D3DPMISCCAPS_MASKZ); CHECK_CAP(d3dCaps.ZCmpCaps, D3DPCMPCAPS_ALWAYS); CHECK_CAP(d3dCaps.ZCmpCaps, D3DPCMPCAPS_LESS); CHECK_CAP(d3dCaps.SrcBlendCaps, D3DPBLENDCAPS_ZERO); CHECK_CAP(d3dCaps.SrcBlendCaps, D3DPBLENDCAPS_ONE); CHECK_CAP(d3dCaps.SrcBlendCaps, D3DPBLENDCAPS_SRCALPHA); CHECK_CAP(d3dCaps.SrcBlendCaps, D3DPBLENDCAPS_DESTALPHA); CHECK_CAP(d3dCaps.SrcBlendCaps, D3DPBLENDCAPS_INVSRCALPHA); CHECK_CAP(d3dCaps.SrcBlendCaps, D3DPBLENDCAPS_INVDESTALPHA); CHECK_CAP(d3dCaps.DestBlendCaps, D3DPBLENDCAPS_ZERO); CHECK_CAP(d3dCaps.DestBlendCaps, D3DPBLENDCAPS_ONE); CHECK_CAP(d3dCaps.DestBlendCaps, D3DPBLENDCAPS_SRCALPHA); CHECK_CAP(d3dCaps.DestBlendCaps, D3DPBLENDCAPS_DESTALPHA); CHECK_CAP(d3dCaps.DestBlendCaps, D3DPBLENDCAPS_INVSRCALPHA); CHECK_CAP(d3dCaps.DestBlendCaps, D3DPBLENDCAPS_INVDESTALPHA); CHECK_CAP(d3dCaps.TextureAddressCaps, D3DPTADDRESSCAPS_CLAMP); CHECK_CAP(d3dCaps.TextureAddressCaps, D3DPTADDRESSCAPS_WRAP); CHECK_CAP(d3dCaps.TextureOpCaps, D3DTEXOPCAPS_MODULATE); if (d3dCaps.PixelShaderVersion < D3DPS_VERSION(2,0) && !IsD3DForced()) { J2dRlsTraceLn1(J2D_TRACE_ERROR, "D3DPPLM::CheckDeviceCaps: adapter %d: Failed "\ "(pixel shaders 2.0 required)", adapter); return E_FAIL; } J2dRlsTraceLn1(J2D_TRACE_INFO, "D3DPPLM::CheckDeviceCaps: adapter %d: Passed", adapter); return S_OK; } HRESULT D3DPipelineManager::D3DEnabledOnAdapter(UINT adapter) { HRESULT res; D3DDISPLAYMODE dm; res = pd3d9->GetAdapterDisplayMode(adapter, &dm); RETURN_STATUS_IF_FAILED(res); res = pd3d9->CheckDeviceType(adapter, devType, dm.Format, dm.Format, TRUE); if (FAILED(res)) { J2dRlsTraceLn1(J2D_TRACE_ERROR, "D3DPPLM::D3DEnabledOnAdapter: no " \ "suitable d3d device on adapter %d", adapter); } return res; } UINT D3DPipelineManager::GetAdapterOrdinalByHmon(HMONITOR hMon) { UINT ret = D3DADAPTER_DEFAULT; if (pd3d9 != NULL) { UINT adapterCount = pd3d9->GetAdapterCount(); for (UINT adapter = 0; adapter < adapterCount; adapter++) { HMONITOR hm = pd3d9->GetAdapterMonitor(adapter); if (hm == hMon) { ret = adapter; break; } } } return ret; } D3DFORMAT D3DPipelineManager::GetMatchingDepthStencilFormat(UINT adapterOrdinal, D3DFORMAT adapterFormat, D3DFORMAT renderTargetFormat) { static D3DFORMAT formats[] = { D3DFMT_D16, D3DFMT_D32, D3DFMT_D24S8, D3DFMT_D24X8 }; D3DFORMAT newFormat = D3DFMT_UNKNOWN; HRESULT res; for (int i = 0; i < 4; i++) { res = pd3d9->CheckDeviceFormat(adapterOrdinal, devType, adapterFormat, D3DUSAGE_DEPTHSTENCIL, D3DRTYPE_SURFACE, formats[i]); if (FAILED(res)) continue; res = pd3d9->CheckDepthStencilMatch(adapterOrdinal, devType, adapterFormat, renderTargetFormat, formats[i]); if (FAILED(res)) continue; newFormat = formats[i]; break; } return newFormat; } HWND D3DPipelineManager::CreateDefaultFocusWindow() { UINT adapterOrdinal = D3DADAPTER_DEFAULT; J2dTraceLn1(J2D_TRACE_INFO, "D3DPPLM::CreateDefaultFocusWindow: adapter=%d", adapterOrdinal); if (defaultFocusWindow != 0) { J2dRlsTraceLn(J2D_TRACE_WARNING, "D3DPPLM::CreateDefaultFocusWindow: "\ "existing default focus window!"); return defaultFocusWindow; } WNDCLASS wc; ZeroMemory(&wc, sizeof(WNDCLASS)); wc.hInstance = GetModuleHandle(NULL); wc.lpfnWndProc = DefWindowProc; wc.lpszClassName = L"D3DFocusWindow"; if (RegisterClass(&wc) == 0) { J2dRlsTraceLn(J2D_TRACE_ERROR, "D3DPPLM::CreateDefaultFocusWindow: "\ "error registering window class"); return 0; } MONITORINFO mi; ZeroMemory(&mi, sizeof(MONITORINFO)); mi.cbSize = sizeof(MONITORINFO); HMONITOR hMon = pd3d9->GetAdapterMonitor(adapterOrdinal); if (hMon == 0 || !GetMonitorInfo(hMon, (LPMONITORINFO)&mi)) { J2dRlsTraceLn1(J2D_TRACE_ERROR, "D3DPPLM::CreateDefaultFocusWindow: "\ "error getting monitor info for adapter=%d", adapterOrdinal); return 0; } HWND hWnd = CreateWindow(L"D3DFocusWindow", L"D3DFocusWindow", 0, mi.rcMonitor.left, mi.rcMonitor.top, 1, 1, NULL, NULL, GetModuleHandle(NULL), NULL); if (hWnd == 0) { J2dRlsTraceLn(J2D_TRACE_ERROR, "D3DPPLM::CreateDefaultFocusWindow: CreateWindow failed"); } else { J2dTraceLn2(J2D_TRACE_INFO, " Created default focus window %x for adapter %d", hWnd, adapterOrdinal); defaultFocusWindow = hWnd; } return hWnd; } HWND D3DPipelineManager::GetCurrentFocusWindow() { J2dTraceLn(J2D_TRACE_INFO, "D3DPPLM::GetCurrentFocusWindow"); if (currentFSFocusAdapter < 0) { J2dTraceLn1(J2D_TRACE_VERBOSE, " no fs windows, using default focus window=0x%x", defaultFocusWindow); return defaultFocusWindow; } J2dTraceLn1(J2D_TRACE_VERBOSE, " using fs window=0x%x", pAdapters[currentFSFocusAdapter].fsFocusWindow); return pAdapters[currentFSFocusAdapter].fsFocusWindow; } HWND D3DPipelineManager::SetFSFocusWindow(UINT adapterOrdinal, HWND hWnd) { J2dTraceLn2(J2D_TRACE_INFO,"D3DPPLM::SetFSFocusWindow hwnd=0x%x adapter=%d", hWnd, adapterOrdinal); HWND prev = pAdapters[adapterOrdinal].fsFocusWindow; pAdapters[adapterOrdinal].fsFocusWindow = hWnd; if (currentFSFocusAdapter < 0) { J2dTraceLn(J2D_TRACE_VERBOSE, " first full-screen window"); // first fs window currentFSFocusAdapter = adapterOrdinal; // REMIND: we might want to reset the rest of the context here as well // like we do when the an adapter exits fs mode; currently they will // be reset sometime later } else { // there's already a fs window if (currentFSFocusAdapter == adapterOrdinal) { // it's current fs window => we're exiting fs mode on this adapter; // look for a new fs focus window if (hWnd == 0) { UINT i; currentFSFocusAdapter = -1; for (i = 0; i < adapterCount; i++) { if (pAdapters[i].fsFocusWindow != 0) { J2dTraceLn1(J2D_TRACE_VERBOSE, " adapter %d is still in fs mode", i); currentFSFocusAdapter = i; break; } } // we have to reset all devices any time current focus device // exits fs mode, and also to prevent some of them being left in // a lost state when the last device exits fs - when non-last // adapters exit fs mode they would not be able to create the // device and will be put in a lost state forever HRESULT res; J2dTraceLn(J2D_TRACE_VERBOSE, " adapter exited full-screen, reset all adapters"); for (i = 0; i < adapterCount; i++) { if (pAdapters[i].pd3dContext != NULL) { res = pAdapters[i].pd3dContext->ResetContext(); D3DRQ_MarkLostIfNeeded(res, D3DRQ_GetCurrentDestination()); } } } else { J2dTraceLn1(J2D_TRACE_WARNING, "D3DPM::SetFSFocusWindow: setting the fs "\ "window again for adapter %d", adapterOrdinal); } } } return prev; } HRESULT D3DPipelineManager::GetD3DContext(UINT adapterOrdinal, D3DContext **ppd3dContext) { J2dTraceLn(J2D_TRACE_INFO, "D3DPPLM::GetD3DContext"); HRESULT res = S_OK; if (adapterOrdinal < 0 || adapterOrdinal >= adapterCount || pAdapters == NULL || pAdapters[adapterOrdinal].state == CONTEXT_INIT_FAILED) { J2dRlsTraceLn1(J2D_TRACE_ERROR, "D3DPPLM::GetD3DContext: invalid parameters or "\ "failed init for adapter %d", adapterOrdinal); *ppd3dContext = NULL; return E_FAIL; } if (pAdapters[adapterOrdinal].state == CONTEXT_NOT_INITED) { D3DContext *pCtx = NULL; if (pAdapters[adapterOrdinal].pd3dContext != NULL) { J2dTraceLn1(J2D_TRACE_ERROR, " non-null context in "\ "uninitialized adapter %d", adapterOrdinal); res = E_FAIL; } else { J2dTraceLn1(J2D_TRACE_VERBOSE, " initializing context for adapter %d",adapterOrdinal); if (SUCCEEDED(res = D3DEnabledOnAdapter(adapterOrdinal))) { res = D3DContext::CreateInstance(pd3d9, adapterOrdinal, &pCtx); if (FAILED(res)) { J2dRlsTraceLn1(J2D_TRACE_ERROR, "D3DPPLM::GetD3DContext: failed to create context "\ "for adapter=%d", adapterOrdinal); } } else { J2dRlsTraceLn1(J2D_TRACE_ERROR, "D3DPPLM::GetContext: no d3d on adapter %d",adapterOrdinal); } } pAdapters[adapterOrdinal].state = SUCCEEDED(res) ? CONTEXT_CREATED : CONTEXT_INIT_FAILED; pAdapters[adapterOrdinal].pd3dContext = pCtx; } *ppd3dContext = pAdapters[adapterOrdinal].pd3dContext; return res; } //============================================================== // D3DInitializer //============================================================== D3DInitializer D3DInitializer::theInstance; D3DInitializer::D3DInitializer() : bComInitialized(false), pAdapterIniters(NULL) { } D3DInitializer::~D3DInitializer() { if (pAdapterIniters) { delete[] pAdapterIniters; } } void D3DInitializer::InitImpl() { J2dRlsTraceLn(J2D_TRACE_INFO, "D3DInitializer::InitImpl"); if (SUCCEEDED(::CoInitialize(NULL))) { bComInitialized = true; } D3DPipelineManager *pMgr = D3DPipelineManager::CreateInstance(); if (pMgr != NULL) { // init adapters if we are preloading if (AwtToolkit::GetInstance().GetPreloadThread().OnPreloadThread()) { UINT adapterCount = pMgr->adapterCount; pAdapterIniters = new D3DAdapterInitializer[adapterCount]; for (UINT i=0; iGetD3DContext(adapter, &pd3dContext); J2dRlsTraceLn1(J2D_TRACE_INFO, "D3DAdapterInitializer::InitImpl(%d) finished", adapter); } void D3DInitializer::D3DAdapterInitializer::CleanImpl(bool reInit) { // nothing to do - D3DPipelineManager cleans adapters } extern "C" { /* * Export function to start D3D preloading * (called from java/javaw - see src/windows/bin/java-md.c) */ __declspec(dllexport) int preloadD3D() { J2dRlsTraceLn(J2D_TRACE_INFO, "AWT warmup: preloadD3D"); AwtToolkit::GetInstance().GetPreloadThread().AddAction(&D3DInitializer::GetInstance()); return 1; } }