aboutsummaryrefslogtreecommitdiff
path: root/src/windows/native/sun/java2d/d3d/D3DPipelineManager.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/windows/native/sun/java2d/d3d/D3DPipelineManager.cpp')
-rw-r--r--src/windows/native/sun/java2d/d3d/D3DPipelineManager.cpp936
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;
+}