windows-nt/Source/XPSP1/NT/multimedia/directx/dxg/d3d8/fe/dlld3d.cpp
2020-09-26 16:20:57 +08:00

470 lines
13 KiB
C++

/*==========================================================================;
*
* Copyright (C) 1995 Microsoft Corporation. All Rights Reserved.
*
* File: dlld3d.cpp
* Content: Direct3D startup
*
***************************************************************************/
#include "pch.cpp"
#pragma hdrstop
//---------------------------------------------------------------------
//
// Flags to identify CPUs and CPU features
//
//---------------------------------------------------------------------
// MMX available
#define D3DCPU_MMX 0x00000001L
// FCOMI and CMOV are both supported
#define D3DCPU_FCOMICMOV 0x00000002L
// Reads block until satisfied
#define D3DCPU_BLOCKINGREAD 0x00000004L
// Extended 3D support available
#define D3DCPU_X3D 0x00000008L
// Pentium II CPU
#define D3DCPU_PII 0x000000010L
// Streaming SIMD Extensions (aka Katmai) CPU
#define D3DCPU_SSE 0x000000020L
//#define __D3D_PSGP_DLL__
//---------------------------------------------------------------------
//
// Global variables
//
//---------------------------------------------------------------------
HINSTANCE hGeometryDLL = NULL;
LPD3DFE_CONTEXTCREATE pfnFEContextCreate = NULL; // Used when PSGP is DLL
char szCPUString[13];
DWORD dwCPUFamily, dwCPUFeatures;
void SetMostRecentApp(void);
#ifdef _X86_
// --------------------------------------------------------------------------
// Here's a routine helps us determine if we should try MMX or not
// --------------------------------------------------------------------------
BOOL _asm_isMMX()
{
DWORD retval;
_asm
{
xor eax,eax ; Clear out eax for return value
pushad ; CPUID trashes lots - save everything
mov eax,1 ; Check for MMX support
;;; We need to upgrade our compiler
;;; CPUID == 0f,a2
_emit 0x0f
_emit 0xa2
test edx,00800000h ; Set flags before restoring registers
popad ; Restore everything
setnz al ; Set return value
mov retval, eax
};
return retval;
}
#endif
static int isMMX = -1;
BOOL
isMMXprocessor(void)
{
HKEY hKey;
if ( RegOpenKey( HKEY_LOCAL_MACHINE,
RESPATH_D3D,
&hKey) == ERROR_SUCCESS)
{
DWORD dwType;
DWORD dwValue;
DWORD dwSize = 4;
if ( RegQueryValueEx( hKey, "DisableMMX", NULL, &dwType,
(LPBYTE) &dwValue, &dwSize) == ERROR_SUCCESS &&
dwType == REG_DWORD &&
dwValue != 0)
{
RegCloseKey( hKey );
isMMX = 0;
return FALSE;
}
RegCloseKey( hKey );
}
if (isMMX < 0)
{
isMMX = FALSE;
#ifdef _X86_
D3D_WARN(4, "Executing processor detection code (benign first-chance exception possible)" );
#ifndef WIN95
{
// GetSystemInfo is not broken on WinNT.
SYSTEM_INFO si;
GetSystemInfo(&si);
if (si.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_INTEL &&
si.wProcessorLevel >= 5)
{
#endif
__try
{
if( _asm_isMMX() )
{
// Emit an emms instruction.
// This file needs to compile for non-Pentium
// processors
// so we can't use use inline asm since we're in the
// wrong
// processor mode.
__asm __emit 0xf;
__asm __emit 0x77;
isMMX = TRUE;
D3D_INFO(4, "MMX detected");
}
}
__except(GetExceptionCode() == STATUS_ILLEGAL_INSTRUCTION ?
EXCEPTION_EXECUTE_HANDLER :
EXCEPTION_CONTINUE_SEARCH)
{
}
#ifndef WIN95
}
}
#endif
#endif
}
return isMMX;
}
#ifdef _X86_
//---------------------------------------------------------------------
BOOL IsWin95(void)
{
#ifdef WIN95 // and Win98...
OSVERSIONINFO osvi;
ZeroMemory(&osvi, sizeof(osvi));
osvi.dwOSVersionInfoSize = sizeof(osvi);
if (!GetVersionEx(&osvi))
{
D3D_INFO(1,"GetVersionEx failed - assuming Win95");
return TRUE;
}
if ( VER_PLATFORM_WIN32_WINDOWS == osvi.dwPlatformId )
{
if( ( osvi.dwMajorVersion > 4UL ) ||
( ( osvi.dwMajorVersion == 4UL ) &&
( osvi.dwMinorVersion >= 10UL ) &&
( LOWORD( osvi.dwBuildNumber ) >= 1373 ) ) )
{
// is Win98
D3D_INFO(2,"Detected Win98");
return FALSE;
}
else
{
// is Win95
D3D_INFO(2,"Detected Win95");
return TRUE;
}
}
else if ( VER_PLATFORM_WIN32_NT == osvi.dwPlatformId )
{
D3D_INFO(2,"Detected WinNT");
return FALSE;
}
D3D_INFO(2,"OS Detection failed");
return TRUE;
#else
return FALSE;
#endif // WIN95
}
//---------------------------------------------------------------------
//
// void GetProcessorFamily(LPDWORD lpdwFamily);
//
// Passes back 3, 4, 5, 6 for 386, 486, Pentium, PPro class machines
//
#pragma optimize("", off)
void
GetProcessorFamily(LPDWORD lpdwFamily, LPDWORD lpdwCPUFeatures)
{
SYSTEM_INFO si;
__int64 start, end, freq;
int flags,family;
int time;
int clocks;
DWORD oldclass;
HANDLE hprocess;
// guilty until proven otherwise
*lpdwCPUFeatures = D3DCPU_BLOCKINGREAD;
if ( isMMXprocessor() )
{
*lpdwCPUFeatures |= D3DCPU_MMX;
}
ZeroMemory(&si, sizeof(si));
GetSystemInfo(&si);
//Set the family. If wProcessorLevel is not specified, dig it out of dwProcessorType
//Because wProcessor level is not implemented on Win95
if (si.wProcessorLevel)
{
*lpdwFamily=si.wProcessorLevel;
}
else
{
//Ok, we're on Win95
switch (si.dwProcessorType)
{
case PROCESSOR_INTEL_386:
*lpdwFamily=3;
break;
case PROCESSOR_INTEL_486:
*lpdwFamily=4;
break;
default:
*lpdwFamily=0;
break;
}
}
//
// make sure this is a INTEL Pentium (or clone) or higher.
//
if (si.wProcessorArchitecture != PROCESSOR_ARCHITECTURE_INTEL)
return;
if (si.dwProcessorType < PROCESSOR_INTEL_PENTIUM)
return;
//
// see if this chip supports rdtsc before using it.
//
__try
{
_asm
{
xor eax,eax
_emit 00fh ;; CPUID
_emit 0a2h
mov dword ptr szCPUString,ebx
mov dword ptr szCPUString+8,ecx
mov dword ptr szCPUString+4,edx
mov byte ptr szCPUString+12,0
mov eax,1
_emit 00Fh ;; CPUID
_emit 0A2h
mov flags,edx
mov family,eax
}
}
__except(1)
{
flags = 0;
}
//check for support of CPUID and fail
if (!(flags & 0x10))
return;
// fcomi and FPU features both set
if ( (flags&(1<<15)) && (flags & (1<<0)) )
{
D3D_INFO(2, "Pentium Pro CPU features (fcomi, cmov) detected");
*lpdwCPUFeatures |= D3DCPU_FCOMICMOV;
}
//If we don't have a family, set it now
//Family is bits 11:8 of eax from CPU, with eax=1
if (!(*lpdwFamily))
{
*lpdwFamily=(family& 0x0F00) >> 8;
}
// not aware of any non-Intel processors w/non blocking reads
if ( (! strcmp(szCPUString, "GenuineIntel")) &&
*lpdwFamily > 5)
{
*lpdwCPUFeatures &= ~D3DCPU_BLOCKINGREAD;
}
return;
}
#pragma optimize("", on)
#endif // _X86_
#ifndef WIN95 // and Win98, WinME
//---------------------------------------------------------------------
BOOL bVBSwapEnabled = TRUE, bVBSwapWorkaround = FALSE;
void SetVBSwapStatus(void)
{
OSVERSIONINFOEX osvi;
ZeroMemory(&osvi, sizeof(osvi));
osvi.dwOSVersionInfoSize = sizeof(osvi);
if (!GetVersionEx((LPOSVERSIONINFO)&osvi))
{
D3D_INFO(1,"GetVersionEx failed - turning off VB swapping");
bVBSwapEnabled = FALSE;
return;
}
if ( VER_PLATFORM_WIN32_NT == osvi.dwPlatformId )
{
if (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 0) // Check if Win2K Gold (2195)
{
if (osvi.wServicePackMajor == 0) // No service pack
{
D3D_INFO(1, "Win2K Gold detected - turning off VB swapping");
bVBSwapEnabled = FALSE;
}
else
{
D3D_INFO(1, "Win2K SP1 or above detected - enabling VB swap workaround");
bVBSwapEnabled = FALSE;
bVBSwapWorkaround = TRUE;
}
}
else // Whistler and above
{
/* ASSUMPTION: NO WORKAROUND NEEDED */
}
}
else
{
// Should never get here
DPF_ERR("OS Detection failed - turning off VB swapping");
bVBSwapEnabled = FALSE;
return;
}
}
#endif // WIN95
extern "C" BOOL APIENTRY D3DDllMain( HMODULE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved );
BOOL APIENTRY
D3DDllMain( HMODULE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved )
{
HKEY hKey;
LONG lRet;
DWORD dwType, dwSize;
char filename[_MAX_PATH];
switch( ul_reason_for_call )
{
case DLL_PROCESS_ATTACH:
#ifdef _X86_
GetProcessorFamily(&dwCPUFamily, &dwCPUFeatures);
D3D_INFO(3, "dwCPUFamily = %d, dwCPUFeatures = %d",
dwCPUFamily, dwCPUFeatures);
D3D_INFO(3, "szCPUString = %s", szCPUString);
#endif
// SSE (aka Katmai) does not work on Win95, so see if we are on
// Win95 and disable
#ifdef WIN95
{
BOOL bIsWin95 = IsWin95();
if ((dwCPUFeatures & D3DCPU_SSE) && bIsWin95)
{
D3D_INFO(1,"Disabling <Streaming SIMD Extension> support on Win95");
dwCPUFeatures &= ~D3DCPU_SSE;
}
}
// We need to workaround VB problems on Win2K
#else
SetVBSwapStatus();
#endif
#ifdef __D3D_PSGP_DLL__
lRet = RegOpenKey( HKEY_LOCAL_MACHINE, RESPATH_D3D, &hKey );
if ( lRet == ERROR_SUCCESS )
{
dwSize = sizeof(filename);
lRet = RegQueryValueEx(hKey,
"GeometryDriver",
NULL,
&dwType,
(LPBYTE) filename,
&dwSize);
if (lRet == ERROR_SUCCESS && dwType == REG_SZ)
{
hGeometryDLL = LoadLibrary(filename);
if (hGeometryDLL)
{
pfnFEContextCreate = (LPD3DFE_CONTEXTCREATE) GetProcAddress(hGeometryDLL, "FEContextCreate");
}
}
RegCloseKey( hKey );
}
#endif //__D3D_PSGP_DLL__
// Set the app name to reg.
SetMostRecentApp();
break;
case DLL_PROCESS_DETACH:
if (NULL != hGeometryDLL)
FreeLibrary(hGeometryDLL);
break;
default:
;
}
return TRUE;
}
// --------------------------------------------------------------------------
// This function is called at process attach time to put the name of current
// app to registry.
// --------------------------------------------------------------------------
void SetMostRecentApp(void)
{
char fname[_MAX_PATH] = "\0";
char name[_MAX_PATH] = "\0";
int i;
HKEY hKey;
HANDLE hFile;
// Find out what process we are dealing with
hFile = GetModuleHandle( NULL );
GetModuleFileName( (HINSTANCE)hFile, fname, sizeof( fname ) );
//DPF( 3, "full name = %s", fname );
i = strlen( fname )-1;
while( i >=0 && fname[i] != '\\' )
{
i--;
}
i++;
strcpy( name, &fname[i] );
//DPF( 3, "name = %s", name );
// Now write the name into some known place
if( !RegCreateKey( HKEY_LOCAL_MACHINE,
RESPATH_D3D "\\" REGSTR_KEY_LASTAPP, &hKey ) )
{
RegSetValueEx(hKey, REGSTR_VAL_DDRAW_NAME, 0, REG_SZ, (LPBYTE)name, strlen(name)+1);
RegCloseKey(hKey);
}
}