blob: 0f9daca714186ddd9b9466af323f62558f66ae26 [file] [log] [blame]
/*
* Copyright (c) 2007, 2008, 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 = ::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::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_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 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, (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;
}