You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
589 lines
17 KiB
589 lines
17 KiB
/*==========================================================================;
|
|
*
|
|
* Copyright (C) 1995 Microsoft Corporation. All Rights Reserved.
|
|
*
|
|
* File: dlld3d.cpp
|
|
* Content: Direct3D startup
|
|
*@@BEGIN_MSINTERNAL
|
|
*
|
|
* History:
|
|
* Date By Reason
|
|
* ==== == ======
|
|
* 05/11/95 stevela Initial rev with this header.
|
|
* 21/11/95 colinmc Added Direct3D interface ID.
|
|
* 07/12/95 stevela Merged Colin's changes.
|
|
* 10/12/95 stevela Removed AGGREGATE_D3D.
|
|
* 02/03/96 colinmc Minor build fix.
|
|
*@@END_MSINTERNAL
|
|
*
|
|
***************************************************************************/
|
|
|
|
#include "pch.cpp"
|
|
#pragma hdrstop
|
|
|
|
/*
|
|
* Define the Direct3D IIDs.
|
|
*/
|
|
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "Direct3D Startup"
|
|
|
|
DPF_DECLARE(Direct3D);
|
|
|
|
#ifdef WIN95
|
|
LPVOID lpWin16Lock;
|
|
#endif
|
|
|
|
DWORD dwD3DTriBatchSize, dwTriBatchSize, dwLineBatchSize;
|
|
DWORD dwHWBufferSize, dwHWMaxTris, dwHWFewVertices;
|
|
HINSTANCE hGeometryDLL = NULL;
|
|
LPD3DFE_CONTEXTCREATE pfnFEContextCreate;
|
|
char szCPUString[13];
|
|
|
|
DWORD dwCPUFamily, dwCPUFeatures;
|
|
|
|
#ifdef _X86_
|
|
extern HRESULT D3DAPI pii_FEContextCreate(DWORD dwFlags, LPD3DFE_PVFUNCS *lpLeafFuncs);
|
|
extern HRESULT D3DAPI katmai_FEContextCreate(DWORD dwFlags, LPD3DFE_PVFUNCS *lpLeafFuncs);
|
|
extern LPD3DFE_CONTEXTCREATE px3DContextCreate;
|
|
#endif
|
|
|
|
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(1, "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(1, "MMX detected");
|
|
}
|
|
}
|
|
__except(GetExceptionCode() == STATUS_ILLEGAL_INSTRUCTION ?
|
|
EXCEPTION_EXECUTE_HANDLER :
|
|
EXCEPTION_CONTINUE_SEARCH)
|
|
{
|
|
}
|
|
#ifndef WIN95
|
|
}
|
|
|
|
}
|
|
#endif
|
|
#endif
|
|
}
|
|
return isMMX;
|
|
}
|
|
|
|
#ifdef _X86_
|
|
|
|
extern BOOL isX3Dprocessor(void);
|
|
//---------------------------------------------------------------------
|
|
// Detects PentiumII/Katmai processor
|
|
//
|
|
#pragma optimize("", off)
|
|
#define CPUID _asm _emit 0x0f _asm _emit 0xa2
|
|
|
|
BOOL IsPentiumIIProcessor(void)
|
|
{
|
|
DWORD RegisterEAX;
|
|
char VendorId[12];
|
|
const char IntelId[13]="GenuineIntel";
|
|
|
|
__try
|
|
{
|
|
_asm {
|
|
xor eax,eax
|
|
CPUID
|
|
mov RegisterEAX, eax
|
|
mov dword ptr VendorId, ebx
|
|
mov dword ptr VendorId+4, edx
|
|
mov dword ptr VendorId+8, ecx
|
|
}
|
|
} __except (1)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
// make sure EAX is > 0 which means the chip
|
|
// supports a value of 1 which is the chip info
|
|
if (RegisterEAX == 0)
|
|
return FALSE;
|
|
|
|
// make sure chip is "GenuineIntel"
|
|
for (int i=0; i<12; i++)
|
|
if (VendorId[i] != IntelId[i])
|
|
return FALSE;
|
|
|
|
__try
|
|
{
|
|
_asm {
|
|
mov eax, 1
|
|
CPUID
|
|
mov RegisterEAX, eax
|
|
}
|
|
} __except (1)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
// EAX[3:0] = stepping id
|
|
// EAX[7:4] = model = 0001 (Pentium Pro), 0011 and 0101 (Pentium II)
|
|
// EAX[11:8] = family = 0110
|
|
// EAX[13:12] = processor type = 00
|
|
if ((RegisterEAX & 0x3F00) != 0x0600) // test for processor type & family
|
|
return FALSE;
|
|
RegisterEAX = (RegisterEAX & 0xf0); // test for model
|
|
if (RegisterEAX >= 0x30) // add RegisterEAX == 0x10 for Pentium Pro
|
|
return TRUE;
|
|
else
|
|
return FALSE;
|
|
}
|
|
|
|
BOOL IsKatmaiProcessor(void)
|
|
{
|
|
DWORD RegisterEAX;
|
|
char VendorId[12];
|
|
const char IntelId[13]="GenuineIntel";
|
|
|
|
__try
|
|
{
|
|
_asm {
|
|
xor eax,eax
|
|
CPUID
|
|
mov RegisterEAX, eax
|
|
mov dword ptr VendorId, ebx
|
|
mov dword ptr VendorId+4, edx
|
|
mov dword ptr VendorId+8, ecx
|
|
}
|
|
} __except (1)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
// make sure EAX is > 0 which means the chip
|
|
// supports a value >=1. 1 = chip info
|
|
if (RegisterEAX == 0)
|
|
return FALSE;
|
|
|
|
// make sure chip is "GenuineIntel"
|
|
for (int i=0; i<12; i++)
|
|
if (VendorId[i] != IntelId[i])
|
|
return FALSE;
|
|
|
|
// this CPUID can't fail if the above test passed
|
|
_asm {
|
|
mov eax, 1
|
|
CPUID
|
|
mov RegisterEAX, eax
|
|
}
|
|
|
|
// EAX[3:0] = stepping id
|
|
// EAX[7:4] = model = 0001 (Pentium Pro), 0011 and 0101 (Pentium II)
|
|
// EAX[11:8] = family = 0110
|
|
// EAX[13:12] = processor type = 00
|
|
RegisterEAX = (RegisterEAX & 0x3FF0); // test for model
|
|
if (RegisterEAX >= 0x670) // Katmai or newer
|
|
return TRUE;
|
|
else
|
|
return FALSE;
|
|
}
|
|
|
|
#pragma optimize("", on)
|
|
|
|
#ifdef WIN95 // and Win98...
|
|
//---------------------------------------------------------------------
|
|
BOOL
|
|
IsWin95(void)
|
|
{
|
|
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;
|
|
}
|
|
#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;
|
|
}
|
|
|
|
if ( isX3Dprocessor() )
|
|
{
|
|
D3D_INFO(2, "X3D Processor detected for PSGP");
|
|
*lpdwCPUFeatures |= D3DCPU_X3D;
|
|
}
|
|
|
|
if ( IsPentiumIIProcessor() )
|
|
{
|
|
D3D_INFO(2, "PentiumII Processor detected for PSGP");
|
|
*lpdwCPUFeatures |= D3DCPU_PII;
|
|
}
|
|
|
|
if ( IsKatmaiProcessor() )
|
|
{
|
|
D3D_INFO(2, "Katmai Processor detected for PSGP");
|
|
*lpdwCPUFeatures |= D3DCPU_KATMAI;
|
|
}
|
|
return;
|
|
}
|
|
#pragma optimize("", on)
|
|
|
|
#endif // _X86_
|
|
|
|
BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved)
|
|
{
|
|
HKEY hKey;
|
|
LONG lRet;
|
|
DWORD dwType, dwSize = sizeof(dwHWFewVertices);
|
|
char filename[_MAX_PATH];
|
|
|
|
switch( ul_reason_for_call ) {
|
|
case DLL_PROCESS_ATTACH:
|
|
DisableThreadLibraryCalls( hModule );
|
|
DPFINIT();
|
|
MemInit();
|
|
#ifdef WIN95
|
|
GetpWin16Lock(&lpWin16Lock);
|
|
#endif
|
|
|
|
#ifdef _X86_
|
|
GetProcessorFamily(&dwCPUFamily, &dwCPUFeatures);
|
|
D3D_INFO(3, "dwCPUFamily = %d, dwCPUFeatures = %d", dwCPUFamily, dwCPUFeatures);
|
|
D3D_INFO(3, "szCPUString = %s", szCPUString);
|
|
#endif
|
|
|
|
#ifdef WIN95 // and Win98...
|
|
// Katmai NI does not work on Win95, so see if we are on Win95 and disable
|
|
//
|
|
{
|
|
BOOL bIsWin95 = IsWin95();
|
|
if ((dwCPUFeatures & D3DCPU_KATMAI) && bIsWin95)
|
|
{
|
|
D3D_INFO(1,"Disabling KNI support on Win95");
|
|
dwCPUFeatures &= ~D3DCPU_KATMAI;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
#ifdef _X86_
|
|
if ( dwCPUFeatures & D3DCPU_X3D )
|
|
pfnFEContextCreate = px3DContextCreate;
|
|
else if ( dwCPUFeatures & D3DCPU_KATMAI )
|
|
pfnFEContextCreate = katmai_FEContextCreate;
|
|
else if ( dwCPUFeatures & D3DCPU_PII )
|
|
pfnFEContextCreate = pii_FEContextCreate;
|
|
#endif
|
|
|
|
// Unfounded default value. 128*40 (vertex+D3DTRIANGLE struct)=5K
|
|
// The assumption is that the primary cache hasn't got much better
|
|
// to do than contain the vertex and index data.
|
|
dwD3DTriBatchSize = 80;
|
|
// Work item: do something more intelligent here than assume that
|
|
// MMX-enabled processors have twice as much primary cache.
|
|
if ( isMMXprocessor() )
|
|
dwD3DTriBatchSize *= 2;
|
|
dwTriBatchSize = (dwD3DTriBatchSize * 4) / 3;
|
|
dwLineBatchSize = dwD3DTriBatchSize * 2;
|
|
dwHWBufferSize = dwD3DTriBatchSize * (sizeof(D3DTLVERTEX) + sizeof(D3DTRIANGLE));
|
|
dwHWMaxTris = dwD3DTriBatchSize;
|
|
lRet = RegOpenKey( HKEY_LOCAL_MACHINE, RESPATH_D3D, &hKey );
|
|
if ( lRet == ERROR_SUCCESS )
|
|
{
|
|
lRet = RegQueryValueEx(hKey,
|
|
"FewVertices",
|
|
NULL,
|
|
&dwType,
|
|
(LPBYTE) &dwHWFewVertices,
|
|
&dwSize);
|
|
if (lRet != ERROR_SUCCESS ||
|
|
dwType != REG_DWORD ||
|
|
dwHWFewVertices < 4 ||
|
|
dwHWFewVertices > 128)
|
|
|
|
dwHWFewVertices = 24;
|
|
|
|
// disabling 'GeometryDriver' DLL interface until it is less abusable...
|
|
#if 0
|
|
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");
|
|
}
|
|
}
|
|
#endif
|
|
RegCloseKey( hKey );
|
|
}
|
|
else
|
|
{
|
|
dwHWFewVertices = 24;
|
|
}
|
|
// Set the app name to reg.
|
|
SetMostRecentApp();
|
|
break;
|
|
case DLL_PROCESS_DETACH:
|
|
MemFini();
|
|
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];
|
|
char name[_MAX_PATH];
|
|
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);
|
|
}
|
|
}
|