GameOS: full display enumeration trace in gos-displays.txt
Motivation ---------- A tester's 3-display Intel integrated-graphics box (main + 2 MFDs on the iGPU, radar on a USB adapter) failed MFD bring-up with the second MFD panel returning DDERR_EXCLUSIVEMODEALREADYSET, while the same build works on a W4100 and on a Quadro. The old report showed only the final device list and role numbers, which was not enough to tell whether the cause was device count, capability, index shifting, or a duplicate assignment. The report now traces every stage of display discovery in the order the game performs it, so the cause can be read off the file instead of inferred. What gets logged ---------------- * Header: executable path, full command line, and the requested -tmfds / -tmon values already converted from the 1-based command-line form to the 0-based DirectDraw indices the code uses. That conversion is an easy off-by-one to miss: "-tmon 1,..." means device 0. * Windows desktop topology via EnumDisplayDevicesA + EnumDisplaySettingsA - every \\.\DISPLAYn adapter, its friendly name, attached/primary state and current mode. Stated explicitly so it can be compared against the DirectDraw order, which is NOT the same ordering. * Stage 1, enumeration callbacks: each callback as it fires, with driver description, driver name, GUID, and the HMONITOR resolved through GetMonitorInfoA to \\.\DISPLAYn plus desktop rect and primary flag. Entries with no HMONITOR are named as the primary-display-driver alias, noting that NumMonitors is not incremented for them. * Stage 2, capability check: per device ACCEPTED (with assigned index and whether a HAL was found) or REJECTED. * Device table printed THREE times - before the NULL-device merge, after it, and final. Each entry shows description, driver, DeviceGUID, guidDeviceIdentifier, vendor/device IDs, hardware-rasterizer flag and its monitor. Followed by an adapter grouping listing which device indices belong to the same physical card, since guidDeviceIdentifier identifies the ADAPTER and not the output - which is precisely why a single card and a mixed iGPU + USB adapter setup enumerate differently. * Stage 3, the NULL-device merge: whether the NumMonitors>=2 guard passed, which device matched the primary's adapter GUID, and every index shift printed individually. If nothing matches, it says so loudly - slot 0 then remains the alias and any role pointed at device 0 lands on the Windows primary monitor. * Stages 4-7, role selection: span / main / radar / MFD searches, each printing the device chosen AND the reason every skipped device was skipped. Then the -tmon overrides, each showing what auto-detection had chosen and what the override replaced it with, or why it was rejected. * Final summary: role -> device -> physical monitor, plus a consistency check that reports two roles landing on one device as an explicit CLASH, with the explanation that the second panel will fail with DDERR_EXCLUSIVEMODEALREADYSET. That is the suspected failure on the Intel box and nothing in the old log pointed at it. Fixes ----- * Monitor/device desync: the NULL-device merge shifted DeviceArray but nothing tracked which monitor each slot drove. g_ahDevMonitor[] is now shifted in lockstep; without this every monitor attribution after a merge would be off by one, i.e. confidently wrong rather than absent. * HMONITOR is now retained. The Ex enumeration callback is the only place the device-to-monitor association is available and it was being discarded, so videoDevices gained an hMonitor field and BufferDevice takes it. Behaviour --------- No functional change. Every condition, code path and assignment is unchanged - only logging was added, plus the monitor-array shift above. -tmon still applies each slot independently and still does not reject duplicates; the duplicate is now merely visible. Whether to make it an error is a separate decision, pending test results. Cost ---- Startup only. Nothing added is reachable from the frame loop, so there is no runtime cost of any kind. Roughly 255 writes for a 4-monitor pod, at ~25-130 ms total on a warm cache - inside the noise of FindVideoCards() itself, which creates DirectDraw objects and enumerates every display mode per device. Worst case is antivirus on-access scanning of each CreateFile, which could reach ~1 s; a folder exclusion removes it. Lines remain open-append-close so the report survives a hard crash during panel init, which is exactly when it is most needed. gos-fps.txt is the buffered log; this one deliberately is not. Portability ----------- GetMonitorInfoA and EnumDisplayDevicesA are resolved with GetProcAddress and the MONITORINFOEXA / DISPLAY_DEVICEA layouts are declared locally, so nothing depends on the 1998 SDK headers carrying multimon support. If the APIs are unavailable the report degrades gracefully instead of failing to build. ENUM_CURRENT_SETTINGS is defined defensively. Testing ------- Not yet built. Requires a rebuild of MW4.exe (Release + Profile) as this is CoreTech GameOS. Note the report is truncated on every launch - a failing run's log must be copied before relaunching. Co-authored-by: Claude Opus 5 (Anthropic) <noreply@anthropic.com> Co-authored-by: GitHub Copilot <copilot@github.com>
This commit is contained in:
co-authored by
Claude Opus 5
GitHub Copilot
parent
e912c58843
commit
2e85cd2066
@@ -38,6 +38,10 @@ typedef struct
|
||||
GUID GUID;
|
||||
char* lpDriverDescription;
|
||||
char* lpDriverName;
|
||||
// [displaylog] Which physical monitor this device drives. Only the Ex form of
|
||||
// the enumeration reports it, and it is the ONLY link between a DirectDraw
|
||||
// device index and a monitor the operator can actually identify.
|
||||
HMONITOR hMonitor;
|
||||
|
||||
} videoDevices;
|
||||
|
||||
@@ -271,12 +275,291 @@ BOOL CALLBACK DirectDrawEnumerateExCallback( GUID* lpGUID, LPSTR lpDriverDescrip
|
||||
BOOL CALLBACK DirectDrawEnumerateCallback( GUID* lpGUID, LPSTR lpDriverDescription, LPSTR lpDriverName, LPVOID );
|
||||
HRESULT CALLBACK EnumModesCallback2( LPDDSURFACEDESC2 lpDDSurfaceDesc, LPVOID lpContext );
|
||||
|
||||
//===========================================================================//
|
||||
// [displaylog] Progressive display-enumeration report -> gos-displays.txt
|
||||
//
|
||||
// Every stage of display discovery is written out as it happens: the Windows
|
||||
// desktop topology, each DirectDraw enumeration callback, the device table
|
||||
// before and after the NULL-device merge, every role-selection decision, and
|
||||
// the -tmon overrides. SPEW is compiled out of shipping builds, so without
|
||||
// this there is no way to tell why a panel opened on the wrong monitor - or on
|
||||
// the SAME monitor as another panel, which surfaces only as a DirectDraw error
|
||||
// that names neither the role nor the display.
|
||||
//
|
||||
// Each line is opened/appended/closed so the report survives a hard crash.
|
||||
//===========================================================================//
|
||||
|
||||
// Monitor driving each DeviceArray slot, kept in step through the NULL-device merge.
|
||||
static HMONITOR g_ahDevMonitor[8] = { 0,0,0,0,0,0,0,0 };
|
||||
// Index into BufferedDevices of the device DoEnum is currently checking.
|
||||
static int g_nEnumBufferedIndex = -1;
|
||||
|
||||
// Declared here so the report does not depend on the 1998 SDK's multimon headers;
|
||||
// layouts match MONITORINFOEXA and DISPLAY_DEVICEA exactly.
|
||||
typedef struct
|
||||
{
|
||||
DWORD cbSize;
|
||||
RECT rcMonitor;
|
||||
RECT rcWork;
|
||||
DWORD dwFlags;
|
||||
char szDevice[32];
|
||||
} DispLogMonitorInfo;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
DWORD cb;
|
||||
char DeviceName[32];
|
||||
char DeviceString[128];
|
||||
DWORD StateFlags;
|
||||
char DeviceID[128];
|
||||
char DeviceKey[128];
|
||||
} DispLogDisplayDevice;
|
||||
|
||||
typedef BOOL (WINAPI* PFNDISPLOGGETMONITORINFOA)( HMONITOR, DispLogMonitorInfo* );
|
||||
typedef BOOL (WINAPI* PFNDISPLOGENUMDISPLAYDEVICESA)( LPCSTR, DWORD, DispLogDisplayDevice*, DWORD );
|
||||
|
||||
|
||||
// The build toolchain predates these; define defensively rather than assume.
|
||||
#ifndef ENUM_CURRENT_SETTINGS
|
||||
#define ENUM_CURRENT_SETTINGS ((DWORD)-1)
|
||||
#endif
|
||||
|
||||
static PFNDISPLOGGETMONITORINFOA pfnDispLogGetMonitorInfoA = 0;
|
||||
static PFNDISPLOGENUMDISPLAYDEVICESA pfnDispLogEnumDisplayDevicesA = 0;
|
||||
static bool bDispLogApisResolved = false;
|
||||
|
||||
//
|
||||
// Resolved at run time: these APIs postdate the build toolchain's headers.
|
||||
//
|
||||
static void DispLogResolveApis()
|
||||
{
|
||||
if( bDispLogApisResolved )
|
||||
return;
|
||||
bDispLogApisResolved=true;
|
||||
HMODULE hUser=GetModuleHandleA( "user32.dll" );
|
||||
if( hUser )
|
||||
{
|
||||
pfnDispLogGetMonitorInfoA =(PFNDISPLOGGETMONITORINFOA)GetProcAddress( hUser, "GetMonitorInfoA" );
|
||||
pfnDispLogEnumDisplayDevicesA=(PFNDISPLOGENUMDISPLAYDEVICESA)GetProcAddress( hUser, "EnumDisplayDevicesA" );
|
||||
}
|
||||
}
|
||||
|
||||
static void DispLogPath( char* szPath )
|
||||
{
|
||||
char szDir[MAX_PATH];
|
||||
szDir[0]='\0';
|
||||
GetModuleFileNameA( NULL, szDir, sizeof(szDir) );
|
||||
char* pSlash=strrchr( szDir, '\\' );
|
||||
if( pSlash )
|
||||
*(pSlash+1)='\0';
|
||||
else
|
||||
szDir[0]='\0';
|
||||
sprintf( szPath, "%sgos-displays.txt", szDir );
|
||||
}
|
||||
|
||||
//
|
||||
// Append one line. Opened and closed per call so a crash cannot lose the tail.
|
||||
//
|
||||
static void DispLog( const char* fmt, ... )
|
||||
{
|
||||
char szPath[MAX_PATH];
|
||||
char szLine[1024];
|
||||
DWORD dwWritten=0;
|
||||
va_list ap;
|
||||
|
||||
DispLogPath( szPath );
|
||||
HANDLE hFile=CreateFileA( szPath, GENERIC_WRITE, FILE_SHARE_READ, NULL,
|
||||
OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL );
|
||||
if( hFile==INVALID_HANDLE_VALUE )
|
||||
return;
|
||||
SetFilePointer( hFile, 0, NULL, FILE_END );
|
||||
|
||||
va_start( ap, fmt );
|
||||
vsprintf( szLine, fmt, ap );
|
||||
va_end( ap );
|
||||
|
||||
WriteFile( hFile, szLine, (DWORD)strlen(szLine), &dwWritten, NULL );
|
||||
CloseHandle( hFile );
|
||||
}
|
||||
|
||||
//
|
||||
// Truncate the report at the start of a run.
|
||||
//
|
||||
static void DispLogReset()
|
||||
{
|
||||
char szPath[MAX_PATH];
|
||||
DispLogPath( szPath );
|
||||
HANDLE hFile=CreateFileA( szPath, GENERIC_WRITE, FILE_SHARE_READ, NULL,
|
||||
CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL );
|
||||
if( hFile!=INVALID_HANDLE_VALUE )
|
||||
CloseHandle( hFile );
|
||||
}
|
||||
|
||||
//
|
||||
// A zeroed GUID is not "no GUID" - it is how GameOS stores the NULL device that
|
||||
// DirectDraw reports first, which aliases whichever monitor Windows calls primary.
|
||||
// Saying so explicitly here has settled more than one wrong-monitor report.
|
||||
//
|
||||
static const char* DispLogGuid( const GUID* pG, char* szBuf )
|
||||
{
|
||||
GUID zero;
|
||||
if( !pG )
|
||||
{
|
||||
strcpy( szBuf, "NULL pointer = primary display driver (no dedicated GUID)" );
|
||||
return szBuf;
|
||||
}
|
||||
memset( &zero, 0, sizeof(zero) );
|
||||
if( 0==memcmp( pG, &zero, sizeof(GUID) ) )
|
||||
{
|
||||
strcpy( szBuf, "{00000000-0000-0000-0000-000000000000} ZERO = primary display driver alias" );
|
||||
return szBuf;
|
||||
}
|
||||
sprintf( szBuf, "{%08lX-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X}",
|
||||
(unsigned long)pG->Data1, (unsigned int)pG->Data2, (unsigned int)pG->Data3,
|
||||
pG->Data4[0], pG->Data4[1], pG->Data4[2], pG->Data4[3],
|
||||
pG->Data4[4], pG->Data4[5], pG->Data4[6], pG->Data4[7] );
|
||||
return szBuf;
|
||||
}
|
||||
|
||||
//
|
||||
// Resolve an HMONITOR to the name Windows uses for it, plus its desktop rectangle.
|
||||
// This is the bridge between a DirectDraw device index and a monitor the operator
|
||||
// can point at.
|
||||
//
|
||||
static const char* DispLogMonitorName( HMONITOR hm, char* szBuf )
|
||||
{
|
||||
DispLogMonitorInfo mi;
|
||||
DispLogResolveApis();
|
||||
if( !hm )
|
||||
{
|
||||
strcpy( szBuf, "(none reported - primary display driver alias)" );
|
||||
return szBuf;
|
||||
}
|
||||
if( !pfnDispLogGetMonitorInfoA )
|
||||
{
|
||||
sprintf( szBuf, "HMONITOR %p (GetMonitorInfoA unavailable)", hm );
|
||||
return szBuf;
|
||||
}
|
||||
memset( &mi, 0, sizeof(mi) );
|
||||
mi.cbSize=sizeof(mi);
|
||||
if( pfnDispLogGetMonitorInfoA( hm, &mi ) )
|
||||
sprintf( szBuf, "%-12s %ldx%ld at %ld,%ld%s",
|
||||
mi.szDevice,
|
||||
(long)(mi.rcMonitor.right-mi.rcMonitor.left),
|
||||
(long)(mi.rcMonitor.bottom-mi.rcMonitor.top),
|
||||
(long)mi.rcMonitor.left, (long)mi.rcMonitor.top,
|
||||
(mi.dwFlags & 1) ? " [WINDOWS PRIMARY]" : "" );
|
||||
else
|
||||
sprintf( szBuf, "HMONITOR %p (GetMonitorInfoA failed)", hm );
|
||||
return szBuf;
|
||||
}
|
||||
|
||||
//
|
||||
// Dump what Windows itself thinks is attached. Operators read monitor numbers off
|
||||
// Display Settings and assume -tmon takes them; it does not, it takes DirectDraw
|
||||
// device indices, and on multi-adapter machines the two orders differ.
|
||||
//
|
||||
static void DispLogWindowsTopology()
|
||||
{
|
||||
DispLogDisplayDevice dd;
|
||||
DWORD iAdapter;
|
||||
|
||||
DispLogResolveApis();
|
||||
DispLog( "\r\n--- Windows desktop topology -------------------------------------------\r\n" );
|
||||
DispLog( "Display Settings numbers monitors independently of the DirectDraw device\r\n"
|
||||
"order below. -tmon takes DIRECTDRAW indices, not Windows monitor numbers.\r\n"
|
||||
"Cross-reference using the \\\\.\\DISPLAYn name shown against each device.\r\n\r\n" );
|
||||
|
||||
if( !pfnDispLogEnumDisplayDevicesA )
|
||||
{
|
||||
DispLog( " EnumDisplayDevicesA unavailable - cannot report Windows topology.\r\n" );
|
||||
return;
|
||||
}
|
||||
|
||||
for( iAdapter=0; iAdapter<16; iAdapter++ )
|
||||
{
|
||||
DEVMODEA dm;
|
||||
memset( &dd, 0, sizeof(dd) );
|
||||
dd.cb=sizeof(dd);
|
||||
if( !pfnDispLogEnumDisplayDevicesA( NULL, iAdapter, &dd, 0 ) )
|
||||
break;
|
||||
|
||||
DispLog( " %-14s %s\r\n", dd.DeviceName, dd.DeviceString );
|
||||
DispLog( " state : %s%s\r\n",
|
||||
(dd.StateFlags & 0x00000001) ? "attached-to-desktop " : "NOT attached ",
|
||||
(dd.StateFlags & 0x00000004) ? "PRIMARY" : "" );
|
||||
|
||||
memset( &dm, 0, sizeof(dm) );
|
||||
dm.dmSize=sizeof(dm);
|
||||
if( EnumDisplaySettingsA( dd.DeviceName, ENUM_CURRENT_SETTINGS, &dm ) )
|
||||
DispLog( " mode : %lux%lu %lubpp @ %luHz\r\n",
|
||||
(unsigned long)dm.dmPelsWidth, (unsigned long)dm.dmPelsHeight,
|
||||
(unsigned long)dm.dmBitsPerPel, (unsigned long)dm.dmDisplayFrequency );
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Full device table. Printed before and after the NULL-device merge so an index
|
||||
// shift is visible rather than inferred.
|
||||
//
|
||||
static void DispLogDeviceTable( const char* szWhen )
|
||||
{
|
||||
char szG[192];
|
||||
char szDI[192];
|
||||
char szMon[192];
|
||||
DWORD iDev;
|
||||
|
||||
DispLog( "\r\n--- DirectDraw device table: %s (NumDevices=%d) ---\r\n",
|
||||
szWhen, (int)NumDevices );
|
||||
|
||||
for( iDev=0; iDev<NumDevices; iDev++ )
|
||||
{
|
||||
DispLog( " [%d] %s\r\n", (int)iDev, DeviceArray[iDev].DDid.szDescription );
|
||||
DispLog( " driver : %s\r\n", DeviceArray[iDev].DDid.szDriver );
|
||||
DispLog( " DeviceGUID : %s\r\n",
|
||||
DispLogGuid( &DeviceArray[iDev].DeviceGUID, szG ) );
|
||||
DispLog( " guidDeviceIdent : %s\r\n",
|
||||
DispLogGuid( &DeviceArray[iDev].DDid.guidDeviceIdentifier, szDI ) );
|
||||
DispLog( " vendor/device : %04lX / %04lX rev %lu\r\n",
|
||||
(unsigned long)DeviceArray[iDev].DDid.dwVendorId,
|
||||
(unsigned long)DeviceArray[iDev].DDid.dwDeviceId,
|
||||
(unsigned long)DeviceArray[iDev].DDid.dwRevision );
|
||||
DispLog( " hw_rasterizer : %s\r\n",
|
||||
(DeviceArray[iDev].D3DCaps.dwDevCaps & D3DDEVCAPS_HWRASTERIZATION) ? "yes" : "NO - cannot host a panel" );
|
||||
DispLog( " monitor : %s\r\n",
|
||||
DispLogMonitorName( g_ahDevMonitor[iDev], szMon ) );
|
||||
}
|
||||
|
||||
// guidDeviceIdentifier identifies the ADAPTER, not the output. Devices sharing
|
||||
// it are outputs of one card - which is exactly what the NULL-device merge keys
|
||||
// on, and why a mixed iGPU + USB adapter setup behaves differently to one card.
|
||||
DispLog( "\r\n Adapter grouping (devices sharing guidDeviceIdentifier are one card):\r\n" );
|
||||
{
|
||||
DWORD iOuter;
|
||||
for( iOuter=0; iOuter<NumDevices; iOuter++ )
|
||||
{
|
||||
DWORD iInner;
|
||||
bool bFirst=true;
|
||||
bool bAlreadyListed=false;
|
||||
for( iInner=0; iInner<iOuter; iInner++ )
|
||||
{
|
||||
if( DeviceArray[iInner].DDid.guidDeviceIdentifier==DeviceArray[iOuter].DDid.guidDeviceIdentifier )
|
||||
bAlreadyListed=true;
|
||||
}
|
||||
if( bAlreadyListed )
|
||||
continue;
|
||||
DispLog( " %-40s : devices", DeviceArray[iOuter].DDid.szDescription );
|
||||
for( iInner=0; iInner<NumDevices; iInner++ )
|
||||
{
|
||||
if( DeviceArray[iInner].DDid.guidDeviceIdentifier==DeviceArray[iOuter].DDid.guidDeviceIdentifier )
|
||||
{
|
||||
DispLog( "%s %d", bFirst ? "" : ",", (int)iInner );
|
||||
bFirst=false;
|
||||
}
|
||||
}
|
||||
DispLog( "\r\n" );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
//
|
||||
@@ -291,117 +574,125 @@ HRESULT CALLBACK EnumModesCallback2( LPDDSURFACEDESC2 lpDDSurfaceDesc, LPVOID lp
|
||||
//
|
||||
static void ApplyMonitorOverride(int slot, int* pTarget)
|
||||
{
|
||||
static const char* apszOverrideRole[4] = { "main", "radar", "mfd1", "mfd2" };
|
||||
int dev = g_naMonitorOverride[slot];
|
||||
if ((dev >= 0) && (dev < (int)NumDevices))
|
||||
if( dev < 0 )
|
||||
{
|
||||
DispLog( " %-5s : auto (kept device %d)\r\n", apszOverrideRole[slot], *pTarget );
|
||||
return;
|
||||
}
|
||||
if( dev < (int)NumDevices )
|
||||
{
|
||||
DispLog( " %-5s : device %d APPLIED (auto-detect had chosen %d)\r\n",
|
||||
apszOverrideRole[slot], dev, *pTarget );
|
||||
*pTarget = dev;
|
||||
}
|
||||
else
|
||||
{
|
||||
DispLog( " %-5s : device %d *** REJECTED - only %d device(s) exist, keeping %d ***\r\n",
|
||||
apszOverrideRole[slot], dev, (int)NumDevices, *pTarget );
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// [displaylog] Append one printf-style line to the display report.
|
||||
//
|
||||
static void EmitDisplayLine( HANDLE hFile, const char* fmt, ... )
|
||||
{
|
||||
char szLine[512];
|
||||
DWORD dwWritten=0;
|
||||
va_list ap;
|
||||
va_start( ap, fmt );
|
||||
vsprintf( szLine, fmt, ap );
|
||||
va_end( ap );
|
||||
WriteFile( hFile, szLine, (DWORD)strlen(szLine), &dwWritten, NULL );
|
||||
}
|
||||
|
||||
//
|
||||
// [displaylog] Write gos-displays.txt next to the executable, describing every
|
||||
// DirectDraw device GameOS found and which display role each one was assigned.
|
||||
//
|
||||
// This exists because there is no other way to see it: the SPEW macros are compiled
|
||||
// out of shipping builds, and a monitor that simply never lights up gives no clue
|
||||
// whether the device was missing, lacked hardware caps, or was assigned elsewhere.
|
||||
// [displaylog] Final summary: the role assignment, how each role maps back to a
|
||||
// physical monitor, and whether the assignment is self-consistent.
|
||||
//
|
||||
static void LogDisplayDevices()
|
||||
{
|
||||
char szDir[MAX_PATH];
|
||||
char szPath[MAX_PATH];
|
||||
static const char* apszRoleName[6] =
|
||||
{ "main ", "radar", "span ", "span2", "mfd1 ", "mfd2 " };
|
||||
int anRoleDev[6];
|
||||
char szMon[192];
|
||||
int iRole;
|
||||
|
||||
szDir[0]='\0';
|
||||
GetModuleFileNameA( NULL, szDir, sizeof(szDir) );
|
||||
char* pSlash=strrchr( szDir, '\\' );
|
||||
if( pSlash )
|
||||
*(pSlash+1)='\0';
|
||||
else
|
||||
szDir[0]='\0';
|
||||
sprintf( szPath, "%sgos-displays.txt", szDir );
|
||||
DispLogDeviceTable( "FINAL" );
|
||||
|
||||
HANDLE hFile=CreateFileA( szPath, GENERIC_WRITE, FILE_SHARE_READ, NULL,
|
||||
CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL );
|
||||
if( hFile==INVALID_HANDLE_VALUE )
|
||||
return;
|
||||
anRoleDev[0]=Environment.FullScreenDevice;
|
||||
anRoleDev[1]=g_nNonDualHead;
|
||||
anRoleDev[2]=g_nDualHead;
|
||||
anRoleDev[3]=g_nDualHead2;
|
||||
anRoleDev[4]=g_nMFD1;
|
||||
anRoleDev[5]=g_nMFD2;
|
||||
|
||||
EmitDisplayLine( hFile, "GameOS display device enumeration\r\n" );
|
||||
EmitDisplayLine( hFile, "=================================\r\n\r\n" );
|
||||
EmitDisplayLine( hFile, "NumDevices = %d (DeviceArray holds at most 8)\r\n", (int)NumDevices );
|
||||
EmitDisplayLine( hFile, "NumHWDevices = %d\r\n", (int)NumHWDevices );
|
||||
EmitDisplayLine( hFile, "NumMonitors = %d\r\n\r\n", (int)NumMonitors );
|
||||
DispLog( "\r\n--- Final role assignment ----------------------------------------------\r\n" );
|
||||
DispLog( " main (FullScreenDevice) = %d\r\n", Environment.FullScreenDevice );
|
||||
DispLog( " radar (g_nNonDualHead) = %d\r\n", g_nNonDualHead );
|
||||
DispLog( " span (g_nDualHead) = %d\r\n", g_nDualHead );
|
||||
DispLog( " span2 (g_nDualHead2) = %d\r\n", g_nDualHead2 );
|
||||
DispLog( " mfd1 (g_nMFD1) = %d\r\n", g_nMFD1 );
|
||||
DispLog( " mfd2 (g_nMFD2) = %d\r\n", g_nMFD2 );
|
||||
DispLog( " (-1 means the role was never assigned a device)\r\n" );
|
||||
|
||||
for( DWORD t0=0; t0<NumDevices; t0++ )
|
||||
DispLog( "\r\n Role -> device -> physical monitor:\r\n" );
|
||||
for( iRole=0; iRole<6; iRole++ )
|
||||
{
|
||||
EmitDisplayLine( hFile, " [%d] %-40s hw_rasterization=%s\r\n",
|
||||
(int)t0,
|
||||
DeviceArray[t0].DDid.szDescription,
|
||||
(DeviceArray[t0].D3DCaps.dwDevCaps & D3DDEVCAPS_HWRASTERIZATION) ? "yes" : "NO" );
|
||||
if( anRoleDev[iRole] < 0 || anRoleDev[iRole] >= (int)NumDevices )
|
||||
continue;
|
||||
DispLog( " %s -> device %d -> %s\r\n",
|
||||
apszRoleName[iRole], anRoleDev[iRole],
|
||||
DispLogMonitorName( g_ahDevMonitor[anRoleDev[iRole]], szMon ) );
|
||||
}
|
||||
|
||||
EmitDisplayLine( hFile, "\r\nAssigned roles (-1 means not found):\r\n" );
|
||||
EmitDisplayLine( hFile, " main (FullScreenDevice) = %d\r\n", Environment.FullScreenDevice );
|
||||
EmitDisplayLine( hFile, " radar (g_nNonDualHead) = %d\r\n", g_nNonDualHead );
|
||||
EmitDisplayLine( hFile, " span (g_nDualHead) = %d\r\n", g_nDualHead );
|
||||
EmitDisplayLine( hFile, " span2 (g_nDualHead2) = %d\r\n", g_nDualHead2 );
|
||||
EmitDisplayLine( hFile, " mfd1 (g_nMFD1) = %d\r\n", g_nMFD1 );
|
||||
EmitDisplayLine( hFile, " mfd2 (g_nMFD2) = %d\r\n", g_nMFD2 );
|
||||
|
||||
// Report what -tmon asked for and whether each slot could be honoured.
|
||||
//
|
||||
// Two roles on one device cannot work: the first takes exclusive fullscreen and
|
||||
// the second fails with DDERR_EXCLUSIVEMODEALREADYSET, an error that names
|
||||
// neither role. -tmon applies each slot independently and has no cross-check,
|
||||
// so a hand-written override is the usual way to get here.
|
||||
//
|
||||
DispLog( "\r\n--- Consistency check --------------------------------------------------\r\n" );
|
||||
{
|
||||
static const char* apszRole[4] = { "main", "radar", "mfd1", "mfd2" };
|
||||
bool bAny=false;
|
||||
for( int s=0; s<4; s++ )
|
||||
if( g_naMonitorOverride[s] >= 0 )
|
||||
bAny=true;
|
||||
if( bAny )
|
||||
bool bClash=false;
|
||||
int iA;
|
||||
for( iA=0; iA<6; iA++ )
|
||||
{
|
||||
EmitDisplayLine( hFile, "\r\n-tmon override:\r\n" );
|
||||
for( int s2=0; s2<4; s2++ )
|
||||
int iB;
|
||||
if( anRoleDev[iA] < 0 )
|
||||
continue;
|
||||
for( iB=iA+1; iB<6; iB++ )
|
||||
{
|
||||
int dev=g_naMonitorOverride[s2];
|
||||
if( dev < 0 )
|
||||
EmitDisplayLine( hFile, " %-5s : auto\r\n", apszRole[s2] );
|
||||
else if( dev < (int)NumDevices )
|
||||
EmitDisplayLine( hFile, " %-5s : device %d APPLIED\r\n", apszRole[s2], dev );
|
||||
else
|
||||
EmitDisplayLine( hFile, " %-5s : device %d *** REJECTED - only %d device(s) exist ***\r\n",
|
||||
apszRole[s2], dev, (int)NumDevices );
|
||||
if( anRoleDev[iB] < 0 )
|
||||
continue;
|
||||
if( anRoleDev[iA]==anRoleDev[iB] )
|
||||
{
|
||||
DispLog( " *** CLASH: %s and %s are BOTH on device %d ***\r\n",
|
||||
apszRoleName[iA], apszRoleName[iB], anRoleDev[iA] );
|
||||
bClash=true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if( bClash )
|
||||
DispLog( " Two roles cannot share one display. Whichever initialises second will\r\n"
|
||||
" fail with DDERR_EXCLUSIVEMODEALREADYSET because the first already holds\r\n"
|
||||
" exclusive fullscreen on that monitor. Fix the -tmon assignment, or drop\r\n"
|
||||
" -tmon entirely - auto-detection cannot produce a duplicate.\r\n" );
|
||||
else
|
||||
{
|
||||
EmitDisplayLine( hFile, "\r\n-tmon override: not supplied (all roles auto-detected)\r\n" );
|
||||
}
|
||||
DispLog( " No duplicate device assignments.\r\n" );
|
||||
|
||||
// Device 0 is the primary-display-driver slot. If the merge below did not
|
||||
// collapse it onto a real device it still aliases the Windows primary, so any
|
||||
// panel pointed at it lands on the main display's monitor.
|
||||
if( !g_ahDevMonitor[0] && NumDevices )
|
||||
DispLog( " *** WARNING: device 0 has no monitor of its own - it is still the primary\r\n"
|
||||
" display driver alias. Any role assigned to device 0 will open on the\r\n"
|
||||
" Windows primary monitor, whichever device that really is. ***\r\n" );
|
||||
}
|
||||
|
||||
// The decisive line: whether the MFD subsystem will initialise at all.
|
||||
EmitDisplayLine( hFile, "\r\nMFD mode (-tmfds) = %d\r\n", g_nTypeOfMFDs );
|
||||
DispLog( "\r\nMFD mode (-tmfds) = %d\r\n", g_nTypeOfMFDs );
|
||||
if( g_nTypeOfMFDs == 4 )
|
||||
{
|
||||
bool bOK = (g_nMFD1 != -1) && (g_nMFD2 != -1);
|
||||
EmitDisplayLine( hFile, "mode 4 requires BOTH mfd1 and mfd2: %s\r\n", bOK ? "OK" : "*** FAILED ***" );
|
||||
DispLog( "mode 4 requires BOTH mfd1 and mfd2: %s\r\n", bOK ? "OK" : "*** FAILED ***" );
|
||||
if( !bOK )
|
||||
EmitDisplayLine( hFile,
|
||||
DispLog(
|
||||
" -> IsMultimonitorAvaliable() returns false, so HSH_EnterFullScreen2()\r\n"
|
||||
" falls back to the single-secondary-monitor path and the two MFD\r\n"
|
||||
" displays are never opened. Four hardware-rasterizing DirectDraw\r\n"
|
||||
" devices are needed: main, radar, mfd1, mfd2.\r\n" );
|
||||
}
|
||||
|
||||
CloseHandle( hFile );
|
||||
DispLog( "\r\n--- Panel initialisation (DirectDraw results per display) --------------\r\n" );
|
||||
}
|
||||
|
||||
//
|
||||
@@ -417,49 +708,112 @@ void FindVideoCards()
|
||||
NumHWDevices=0;
|
||||
NumBuffered=0;
|
||||
pDeviceArray=DeviceArray;
|
||||
|
||||
// [displaylog] Start a fresh report for this run.
|
||||
memset( g_ahDevMonitor, 0, sizeof(g_ahDevMonitor) );
|
||||
DispLogReset();
|
||||
DispLog( "GameOS display enumeration report\r\n" );
|
||||
DispLog( "=================================\r\n" );
|
||||
DispLog( "Written by FindVideoCards() at startup, then appended to by each panel as\r\n" );
|
||||
DispLog( "it initialises. Read top to bottom: it follows the order the game does.\r\n" );
|
||||
{
|
||||
char szExe[MAX_PATH];
|
||||
szExe[0]='\0';
|
||||
GetModuleFileNameA( NULL, szExe, sizeof(szExe) );
|
||||
DispLog( "\r\nexecutable : %s\r\n", szExe );
|
||||
DispLog( "command line : %s\r\n", GetCommandLineA() );
|
||||
}
|
||||
DispLog( "requested : -tmfds %d -tmon %d,%d,%d,%d (0 = auto; values are 1-based\r\n"
|
||||
" on the command line and appear here already converted to\r\n"
|
||||
" 0-based DirectDraw device indices, -1 meaning auto)\r\n",
|
||||
g_nTypeOfMFDs,
|
||||
g_naMonitorOverride[0], g_naMonitorOverride[1],
|
||||
g_naMonitorOverride[2], g_naMonitorOverride[3] );
|
||||
|
||||
DispLogWindowsTopology();
|
||||
//
|
||||
// Disable all hardware devices?
|
||||
//
|
||||
if( gUseBlade )
|
||||
{
|
||||
DispLog( "\r\n*** gUseBlade set - hardware device enumeration skipped entirely. ***\r\n" );
|
||||
return;
|
||||
}
|
||||
//
|
||||
// Enumerate all D3D cards
|
||||
//
|
||||
DispLog( "\r\n--- Stage 1: DirectDraw enumeration callbacks ---------------------------\r\n" );
|
||||
gos_MathExceptions( 0,0 );
|
||||
wDirectDrawEnumerate(DirectDrawEnumerateCallback,DirectDrawEnumerateExCallback,0);
|
||||
gos_MathExceptions(1,0);
|
||||
DispLog( "\r\n %d device(s) buffered, NumMonitors=%d\r\n", (int)NumBuffered, (int)NumMonitors );
|
||||
//
|
||||
// Now test them all
|
||||
//
|
||||
DispLog( "\r\n--- Stage 2: capability check of each enumerated device ----------------\r\n" );
|
||||
CheckDevices();
|
||||
DispLog( "\r\n NumDevices=%d NumHWDevices=%d (DeviceArray holds at most 8)\r\n",
|
||||
(int)NumDevices, (int)NumHWDevices );
|
||||
|
||||
DispLogDeviceTable( "after enumeration, BEFORE the NULL-device merge" );
|
||||
//
|
||||
// On a multimonitor system remove the NULL device
|
||||
//
|
||||
DispLog( "\r\n--- Stage 3: NULL-device merge -----------------------------------------\r\n" );
|
||||
DispLog( "DirectDraw reports the primary display driver first, with no GUID. It is an\r\n"
|
||||
"ALIAS of whichever monitor Windows calls primary, not an extra output. It is\r\n"
|
||||
"collapsed onto the real device sharing its guidDeviceIdentifier (= same card),\r\n"
|
||||
"which shifts every later device index down by one.\r\n" );
|
||||
if( NumMonitors>=2 && NumDevices )
|
||||
{
|
||||
//
|
||||
// Find the real device GUID that matches the primary
|
||||
//
|
||||
DispLog( " guard NumMonitors(%d)>=2 && NumDevices(%d) : PASSED - merge will run\r\n",
|
||||
(int)NumMonitors, (int)NumDevices );
|
||||
bool bMerged=false;
|
||||
for( int t0=1; t0<NumDevices; t0++ )
|
||||
{
|
||||
if( DeviceArray[t0].DDid.guidDeviceIdentifier==DeviceArray[0].DDid.guidDeviceIdentifier )
|
||||
{
|
||||
DispLog( " device [%d] '%s' shares the primary's adapter GUID\r\n",
|
||||
t0, DeviceArray[t0].DDid.szDescription );
|
||||
DispLog( " -> copying it into slot 0 and shifting devices %d..%d down one\r\n",
|
||||
t0+1, (int)NumDevices-1 );
|
||||
DeviceArray[0]=DeviceArray[t0];
|
||||
g_ahDevMonitor[0]=g_ahDevMonitor[t0];
|
||||
while( t0+1<NumDevices )
|
||||
{
|
||||
DeviceArray[t0]=DeviceArray[t0+1];
|
||||
g_ahDevMonitor[t0]=g_ahDevMonitor[t0+1];
|
||||
DispLog( " device index %d is now what was index %d\r\n", t0, t0+1 );
|
||||
t0++;
|
||||
}
|
||||
NumDevices-=1;
|
||||
bMerged=true;
|
||||
}
|
||||
}
|
||||
if( !bMerged )
|
||||
DispLog( " *** no device shares the primary's adapter GUID - slot 0 REMAINS the\r\n"
|
||||
" NULL alias. Any role assigned to device 0 will open on the Windows\r\n"
|
||||
" primary monitor, which is probably also the main display. ***\r\n" );
|
||||
}
|
||||
else
|
||||
{
|
||||
DispLog( " guard NumMonitors(%d)>=2 && NumDevices(%d) : NOT met - merge SKIPPED.\r\n",
|
||||
(int)NumMonitors, (int)NumDevices );
|
||||
DispLog( " *** Device 0 is still the primary display driver alias. ***\r\n" );
|
||||
}
|
||||
|
||||
DispLogDeviceTable( "AFTER the NULL-device merge - these are the indices -tmon uses" );
|
||||
//
|
||||
// Make sure initial full screen device is valid. -1 means select 1st
|
||||
//
|
||||
DispLog( "\r\n--- Stage 4: automatic role selection ----------------------------------\r\n" );
|
||||
|
||||
// jcem - dual heads...
|
||||
{
|
||||
DispLog( " span search (a device offering a 1280x480 mode):\r\n" );
|
||||
for(int t0 = 0; t0 < NumDevices; t0++)
|
||||
{
|
||||
for( int t1=0; t1<sizeof(DeviceArray[0].Modes16) / sizeof(WORD); t1+=2 )
|
||||
@@ -469,65 +823,92 @@ void FindVideoCards()
|
||||
if (g_nDualHead == -1)
|
||||
{
|
||||
g_nDualHead = t0;
|
||||
DispLog( " device %d has 1280x480 -> g_nDualHead\r\n", t0 );
|
||||
}
|
||||
else if (g_nDualHead2 == -1)
|
||||
{
|
||||
g_nDualHead2 = t0;
|
||||
DispLog( " device %d has 1280x480 -> g_nDualHead2\r\n", t0 );
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if( g_nDualHead==-1 )
|
||||
DispLog( " no device offers 1280x480 (normal unless using spanned MFD mode 1/3)\r\n" );
|
||||
}
|
||||
// jcem
|
||||
//if( Environment.FullScreenDevice==-1 )
|
||||
{
|
||||
DispLog( " main search (first hardware rasterizer that is not a span device):\r\n" );
|
||||
for( int t0=0; t0<NumDevices; t0++ )
|
||||
{
|
||||
if( DeviceArray[t0].D3DCaps.dwDevCaps&D3DDEVCAPS_HWRASTERIZATION && (t0 != g_nDualHead) && (t0 != g_nDualHead2))
|
||||
{
|
||||
Environment.FullScreenDevice=t0;
|
||||
DispLog( " device %d selected as main\r\n", t0 );
|
||||
break;
|
||||
}
|
||||
DispLog( " device %d skipped (%s)\r\n", t0,
|
||||
(t0==g_nDualHead || t0==g_nDualHead2) ? "reserved as a span device" : "no hardware rasterizer" );
|
||||
}
|
||||
}
|
||||
if( Environment.FullScreenDevice>=NumDevices || Environment.FullScreenDevice<0 )
|
||||
{
|
||||
DispLog( " main device %d is out of range - forced to 0\r\n", Environment.FullScreenDevice );
|
||||
Environment.FullScreenDevice=0;
|
||||
}
|
||||
// jcem
|
||||
if (g_nDualHead != -1) {
|
||||
if (g_nDualHead2 != -1) {
|
||||
g_nNonDualHead = g_nDualHead2;
|
||||
DispLog( " radar : taken from g_nDualHead2 -> device %d\r\n", g_nNonDualHead );
|
||||
}
|
||||
}
|
||||
if (g_nNonDualHead == -1) {
|
||||
DispLog( " radar search (first hardware rasterizer that is not main or span):\r\n" );
|
||||
for( int t0=0; t0<NumDevices; t0++ )
|
||||
{
|
||||
if( (t0 != Environment.FullScreenDevice) && (t0 != g_nDualHead) && DeviceArray[t0].D3DCaps.dwDevCaps&D3DDEVCAPS_HWRASTERIZATION )
|
||||
{
|
||||
g_nNonDualHead = t0;
|
||||
DispLog( " device %d selected as radar\r\n", t0 );
|
||||
break;
|
||||
}
|
||||
DispLog( " device %d skipped (%s)\r\n", t0,
|
||||
(t0==Environment.FullScreenDevice) ? "already the main display" :
|
||||
(t0==g_nDualHead) ? "reserved as a span device" :
|
||||
"no hardware rasterizer" );
|
||||
}
|
||||
if( g_nNonDualHead==-1 )
|
||||
DispLog( " *** no device available for radar ***\r\n" );
|
||||
}
|
||||
// [tmon] Hard-assigned Main/Radar overrides. Applied BEFORE the mode 4 MFD search
|
||||
// below so that search still skips whichever devices the operator picked.
|
||||
DispLog( "\r\n--- Stage 5: -tmon overrides for main/radar ----------------------------\r\n" );
|
||||
ApplyMonitorOverride(0, &Environment.FullScreenDevice);
|
||||
ApplyMonitorOverride(1, &g_nNonDualHead);
|
||||
// Mode 4 (split dual 640x480): find two extra D3D devices beyond
|
||||
// FullScreenDevice and g_nNonDualHead. These need no special resolution.
|
||||
{
|
||||
int found = 0;
|
||||
DispLog( "\r\n--- Stage 6: mode 4 MFD search (two devices beyond main and radar) -----\r\n" );
|
||||
for (int t0 = 0; t0 < NumDevices && found < 2; t0++) {
|
||||
if (t0 == Environment.FullScreenDevice) continue;
|
||||
if (t0 == g_nNonDualHead) continue;
|
||||
if (t0 == Environment.FullScreenDevice) { DispLog( " device %d skipped (already the main display)\r\n", t0 ); continue; }
|
||||
if (t0 == g_nNonDualHead) { DispLog( " device %d skipped (already the radar)\r\n", t0 ); continue; }
|
||||
if (DeviceArray[t0].D3DCaps.dwDevCaps & D3DDEVCAPS_HWRASTERIZATION) {
|
||||
if (found == 0) g_nMFD1 = t0;
|
||||
else g_nMFD2 = t0;
|
||||
if (found == 0) { g_nMFD1 = t0; DispLog( " device %d selected as mfd1\r\n", t0 ); }
|
||||
else { g_nMFD2 = t0; DispLog( " device %d selected as mfd2\r\n", t0 ); }
|
||||
found++;
|
||||
} else {
|
||||
DispLog( " device %d skipped (no hardware rasterizer)\r\n", t0 );
|
||||
}
|
||||
}
|
||||
if( found<2 )
|
||||
DispLog( " only %d of the 2 required MFD devices were found\r\n", found );
|
||||
}
|
||||
// [tmon] Hard-assigned MFD overrides (only meaningful with -tmfds 4).
|
||||
DispLog( "\r\n--- Stage 7: -tmon overrides for mfd1/mfd2 -----------------------------\r\n" );
|
||||
ApplyMonitorOverride(2, &g_nMFD1);
|
||||
ApplyMonitorOverride(3, &g_nMFD2);
|
||||
// [displaylog] Write gos-displays.txt with the full enumeration and the role
|
||||
@@ -1329,11 +1710,24 @@ BOOL DoEnum( GUID* lpGUID, LPSTR lpDriverDescription, LPSTR lpDriverName )
|
||||
memset( &pDeviceArray->DeviceGUID, 0, sizeof( GUID ));
|
||||
}
|
||||
|
||||
// [displaylog] Capture the monitor before the slot index advances - the
|
||||
// enumeration is the only place the association is available.
|
||||
if( NumDevices<8 )
|
||||
g_ahDevMonitor[NumDevices]=
|
||||
( g_nEnumBufferedIndex>=0 && g_nEnumBufferedIndex<8 )
|
||||
? BufferedDevices[g_nEnumBufferedIndex].hMonitor : 0;
|
||||
DispLog( " result : ACCEPTED as DirectDraw device [%d]%s\r\n",
|
||||
(int)NumDevices, FoundHal ? " (HAL present)" : " (no HAL)" );
|
||||
|
||||
pDeviceArray++;
|
||||
NumDevices++;
|
||||
if( FoundHal )
|
||||
NumHWDevices++;
|
||||
}
|
||||
else
|
||||
{
|
||||
DispLog( " result : REJECTED - failed capability checks, no device index assigned\r\n" );
|
||||
}
|
||||
return (NumDevices<8) ? DDENUMRET_OK : DDENUMRET_CANCEL;
|
||||
}
|
||||
|
||||
@@ -1347,17 +1741,26 @@ void CheckDevices()
|
||||
{
|
||||
for( int t0=0; t0<NumBuffered; t0++ )
|
||||
{
|
||||
char szChkG[192];
|
||||
char szChkMon[192];
|
||||
// [displaylog] DoEnum has no access to the monitor handle; hand it the index.
|
||||
g_nEnumBufferedIndex=t0;
|
||||
DispLog( "\r\n checking buffered device %d : %s\r\n", t0, BufferedDevices[t0].lpDriverDescription );
|
||||
DispLog( " driver : %s\r\n", BufferedDevices[t0].lpDriverName );
|
||||
DispLog( " GUID : %s\r\n", DispLogGuid( BufferedDevices[t0].lpGUID, szChkG ) );
|
||||
DispLog( " monitor : %s\r\n", DispLogMonitorName( BufferedDevices[t0].hMonitor, szChkMon ) );
|
||||
DoEnum( BufferedDevices[ t0 ].lpGUID, BufferedDevices[ t0 ].lpDriverDescription, BufferedDevices[ t0 ].lpDriverName );
|
||||
gos_Free( BufferedDevices[ t0 ].lpDriverDescription );
|
||||
gos_Free( BufferedDevices[ t0 ].lpDriverName );
|
||||
}
|
||||
g_nEnumBufferedIndex=-1;
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// During enumeration, save all information in an array
|
||||
//
|
||||
BOOL BufferDevice( GUID* lpGUID, LPSTR lpDriverDescription, LPSTR lpDriverName )
|
||||
BOOL BufferDevice( GUID* lpGUID, LPSTR lpDriverDescription, LPSTR lpDriverName, HMONITOR hm )
|
||||
{
|
||||
if( lpGUID )
|
||||
{
|
||||
@@ -1369,6 +1772,8 @@ BOOL BufferDevice( GUID* lpGUID, LPSTR lpDriverDescription, LPSTR lpDriverName )
|
||||
BufferedDevices[ NumBuffered ].lpGUID=0;
|
||||
}
|
||||
|
||||
BufferedDevices[ NumBuffered ].hMonitor=hm;
|
||||
|
||||
BufferedDevices[ NumBuffered ].lpDriverDescription=(char*)gos_Malloc( strlen(lpDriverDescription)+1 );
|
||||
|
||||
BufferedDevices[ NumBuffered ].lpDriverName=(char*)gos_Malloc( strlen(lpDriverName)+1 );
|
||||
@@ -1392,16 +1797,29 @@ BOOL BufferDevice( GUID* lpGUID, LPSTR lpDriverDescription, LPSTR lpDriverName )
|
||||
//
|
||||
BOOL WINAPI DirectDrawEnumerateExCallback( GUID* lpGUID, LPSTR lpDriverDescription, LPSTR lpDriverName, LPVOID, HMONITOR hm )
|
||||
{
|
||||
char szCbG[128];
|
||||
char szCbMon[192];
|
||||
DispLog( " callback %d (Ex) : %s\r\n", (int)NumBuffered, lpDriverDescription ? lpDriverDescription : "(no description)" );
|
||||
DispLog( " driver : %s\r\n", lpDriverName ? lpDriverName : "(none)" );
|
||||
DispLog( " GUID : %s\r\n", DispLogGuid( lpGUID, szCbG ) );
|
||||
DispLog( " monitor : %s\r\n", DispLogMonitorName( hm, szCbMon ) );
|
||||
if( hm )
|
||||
NumMonitors++;
|
||||
return BufferDevice( lpGUID, lpDriverDescription, lpDriverName );
|
||||
else
|
||||
DispLog( " note : no HMONITOR - this entry is the primary display driver alias,\r\n"
|
||||
" not an independent output. NumMonitors is NOT incremented.\r\n" );
|
||||
return BufferDevice( lpGUID, lpDriverDescription, lpDriverName, hm );
|
||||
}
|
||||
//
|
||||
// Ddraw enumeration in Win95
|
||||
//
|
||||
BOOL WINAPI DirectDrawEnumerateCallback( GUID* lpGUID, LPSTR lpDriverDescription, LPSTR lpDriverName, LPVOID )
|
||||
{
|
||||
return BufferDevice( lpGUID, lpDriverDescription, lpDriverName );
|
||||
char szCbG[128];
|
||||
DispLog( " callback %d (legacy, no monitor info) : %s\r\n",
|
||||
(int)NumBuffered, lpDriverDescription ? lpDriverDescription : "(no description)" );
|
||||
DispLog( " GUID : %s\r\n", DispLogGuid( lpGUID, szCbG ) );
|
||||
return BufferDevice( lpGUID, lpDriverDescription, lpDriverName, 0 );
|
||||
}
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user