diff options
Diffstat (limited to 'src/windows/native/sun/java2d/d3d/D3DPipelineManager.cpp')
-rw-r--r-- | src/windows/native/sun/java2d/d3d/D3DPipelineManager.cpp | 936 |
1 files changed, 936 insertions, 0 deletions
diff --git a/src/windows/native/sun/java2d/d3d/D3DPipelineManager.cpp b/src/windows/native/sun/java2d/d3d/D3DPipelineManager.cpp new file mode 100644 index 000000000..f0838dd56 --- /dev/null +++ b/src/windows/native/sun/java2d/d3d/D3DPipelineManager.cpp @@ -0,0 +1,936 @@ +/* + * Copyright 2007-2008 Sun Microsystems, Inc. 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. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.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 = ::LoadLibrary(TEXT("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; + JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2); + + pMgr = D3DPipelineManager::GetInstance(); + RETURN_IF_NULL(pMgr); + hMon = pMgr->pd3d9->GetAdapterMonitor(adapter); + gdiScreen = AwtWin32GraphicsDevice::GetScreenFromMHND((MHND)hMon); + + JNU_CallStaticMethodByName(env, NULL, + "sun/java2d/pipe/hw/AccelDeviceEventNotifier", + "eventOccured", "(II)V", + gdiScreen, eventType); +} + +UINT D3DPipelineManager::GetAdapterOrdinalForScreen(jint gdiScreen) +{ + MHND mHnd = AwtWin32GraphicsDevice::GetMonitor(gdiScreen); + if (mHnd == (MHND)0) { + return D3DADAPTER_DEFAULT; + } + return GetAdapterOrdinalByHmon((HMONITOR)mHnd); +} + +// static +HRESULT D3DPipelineManager::HandleAdaptersChange(HMONITOR *pMHNDs, UINT monNum) +{ + HRESULT res = S_OK; + BOOL bResetD3D = FALSE, bFound; + + D3DPipelineManager *pMgr = D3DPipelineManager::GetInstance(); + RETURN_STATUS_IF_NULL(pMHNDs, 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 (pMHNDs[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_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.dwSize = 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.dwFlags & 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 or newer\n"); + currentOS = OS_VISTA; + } else { + J2dRlsTrace(J2D_TRACE_INFO, "OS_WINSERV_2008 or newer\n"); + currentOS = OS_WINSERV_2008; + } + } 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, (PMONITOR_INFO)&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; +} |