Source code of Windows XP (NT5)
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.

469 lines
13 KiB

  1. /*==========================================================================;
  2. *
  3. * Copyright (C) 1995 Microsoft Corporation. All Rights Reserved.
  4. *
  5. * File: dlld3d.cpp
  6. * Content: Direct3D startup
  7. *
  8. ***************************************************************************/
  9. #include "pch.cpp"
  10. #pragma hdrstop
  11. //---------------------------------------------------------------------
  12. //
  13. // Flags to identify CPUs and CPU features
  14. //
  15. //---------------------------------------------------------------------
  16. // MMX available
  17. #define D3DCPU_MMX 0x00000001L
  18. // FCOMI and CMOV are both supported
  19. #define D3DCPU_FCOMICMOV 0x00000002L
  20. // Reads block until satisfied
  21. #define D3DCPU_BLOCKINGREAD 0x00000004L
  22. // Extended 3D support available
  23. #define D3DCPU_X3D 0x00000008L
  24. // Pentium II CPU
  25. #define D3DCPU_PII 0x000000010L
  26. // Streaming SIMD Extensions (aka Katmai) CPU
  27. #define D3DCPU_SSE 0x000000020L
  28. //#define __D3D_PSGP_DLL__
  29. //---------------------------------------------------------------------
  30. //
  31. // Global variables
  32. //
  33. //---------------------------------------------------------------------
  34. HINSTANCE hGeometryDLL = NULL;
  35. LPD3DFE_CONTEXTCREATE pfnFEContextCreate = NULL; // Used when PSGP is DLL
  36. char szCPUString[13];
  37. DWORD dwCPUFamily, dwCPUFeatures;
  38. void SetMostRecentApp(void);
  39. #ifdef _X86_
  40. // --------------------------------------------------------------------------
  41. // Here's a routine helps us determine if we should try MMX or not
  42. // --------------------------------------------------------------------------
  43. BOOL _asm_isMMX()
  44. {
  45. DWORD retval;
  46. _asm
  47. {
  48. xor eax,eax ; Clear out eax for return value
  49. pushad ; CPUID trashes lots - save everything
  50. mov eax,1 ; Check for MMX support
  51. ;;; We need to upgrade our compiler
  52. ;;; CPUID == 0f,a2
  53. _emit 0x0f
  54. _emit 0xa2
  55. test edx,00800000h ; Set flags before restoring registers
  56. popad ; Restore everything
  57. setnz al ; Set return value
  58. mov retval, eax
  59. };
  60. return retval;
  61. }
  62. #endif
  63. static int isMMX = -1;
  64. BOOL
  65. isMMXprocessor(void)
  66. {
  67. HKEY hKey;
  68. if ( RegOpenKey( HKEY_LOCAL_MACHINE,
  69. RESPATH_D3D,
  70. &hKey) == ERROR_SUCCESS)
  71. {
  72. DWORD dwType;
  73. DWORD dwValue;
  74. DWORD dwSize = 4;
  75. if ( RegQueryValueEx( hKey, "DisableMMX", NULL, &dwType,
  76. (LPBYTE) &dwValue, &dwSize) == ERROR_SUCCESS &&
  77. dwType == REG_DWORD &&
  78. dwValue != 0)
  79. {
  80. RegCloseKey( hKey );
  81. isMMX = 0;
  82. return FALSE;
  83. }
  84. RegCloseKey( hKey );
  85. }
  86. if (isMMX < 0)
  87. {
  88. isMMX = FALSE;
  89. #ifdef _X86_
  90. D3D_WARN(4, "Executing processor detection code (benign first-chance exception possible)" );
  91. #ifndef WIN95
  92. {
  93. // GetSystemInfo is not broken on WinNT.
  94. SYSTEM_INFO si;
  95. GetSystemInfo(&si);
  96. if (si.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_INTEL &&
  97. si.wProcessorLevel >= 5)
  98. {
  99. #endif
  100. __try
  101. {
  102. if( _asm_isMMX() )
  103. {
  104. // Emit an emms instruction.
  105. // This file needs to compile for non-Pentium
  106. // processors
  107. // so we can't use use inline asm since we're in the
  108. // wrong
  109. // processor mode.
  110. __asm __emit 0xf;
  111. __asm __emit 0x77;
  112. isMMX = TRUE;
  113. D3D_INFO(4, "MMX detected");
  114. }
  115. }
  116. __except(GetExceptionCode() == STATUS_ILLEGAL_INSTRUCTION ?
  117. EXCEPTION_EXECUTE_HANDLER :
  118. EXCEPTION_CONTINUE_SEARCH)
  119. {
  120. }
  121. #ifndef WIN95
  122. }
  123. }
  124. #endif
  125. #endif
  126. }
  127. return isMMX;
  128. }
  129. #ifdef _X86_
  130. //---------------------------------------------------------------------
  131. BOOL IsWin95(void)
  132. {
  133. #ifdef WIN95 // and Win98...
  134. OSVERSIONINFO osvi;
  135. ZeroMemory(&osvi, sizeof(osvi));
  136. osvi.dwOSVersionInfoSize = sizeof(osvi);
  137. if (!GetVersionEx(&osvi))
  138. {
  139. D3D_INFO(1,"GetVersionEx failed - assuming Win95");
  140. return TRUE;
  141. }
  142. if ( VER_PLATFORM_WIN32_WINDOWS == osvi.dwPlatformId )
  143. {
  144. if( ( osvi.dwMajorVersion > 4UL ) ||
  145. ( ( osvi.dwMajorVersion == 4UL ) &&
  146. ( osvi.dwMinorVersion >= 10UL ) &&
  147. ( LOWORD( osvi.dwBuildNumber ) >= 1373 ) ) )
  148. {
  149. // is Win98
  150. D3D_INFO(2,"Detected Win98");
  151. return FALSE;
  152. }
  153. else
  154. {
  155. // is Win95
  156. D3D_INFO(2,"Detected Win95");
  157. return TRUE;
  158. }
  159. }
  160. else if ( VER_PLATFORM_WIN32_NT == osvi.dwPlatformId )
  161. {
  162. D3D_INFO(2,"Detected WinNT");
  163. return FALSE;
  164. }
  165. D3D_INFO(2,"OS Detection failed");
  166. return TRUE;
  167. #else
  168. return FALSE;
  169. #endif // WIN95
  170. }
  171. //---------------------------------------------------------------------
  172. //
  173. // void GetProcessorFamily(LPDWORD lpdwFamily);
  174. //
  175. // Passes back 3, 4, 5, 6 for 386, 486, Pentium, PPro class machines
  176. //
  177. #pragma optimize("", off)
  178. void
  179. GetProcessorFamily(LPDWORD lpdwFamily, LPDWORD lpdwCPUFeatures)
  180. {
  181. SYSTEM_INFO si;
  182. __int64 start, end, freq;
  183. int flags,family;
  184. int time;
  185. int clocks;
  186. DWORD oldclass;
  187. HANDLE hprocess;
  188. // guilty until proven otherwise
  189. *lpdwCPUFeatures = D3DCPU_BLOCKINGREAD;
  190. if ( isMMXprocessor() )
  191. {
  192. *lpdwCPUFeatures |= D3DCPU_MMX;
  193. }
  194. ZeroMemory(&si, sizeof(si));
  195. GetSystemInfo(&si);
  196. //Set the family. If wProcessorLevel is not specified, dig it out of dwProcessorType
  197. //Because wProcessor level is not implemented on Win95
  198. if (si.wProcessorLevel)
  199. {
  200. *lpdwFamily=si.wProcessorLevel;
  201. }
  202. else
  203. {
  204. //Ok, we're on Win95
  205. switch (si.dwProcessorType)
  206. {
  207. case PROCESSOR_INTEL_386:
  208. *lpdwFamily=3;
  209. break;
  210. case PROCESSOR_INTEL_486:
  211. *lpdwFamily=4;
  212. break;
  213. default:
  214. *lpdwFamily=0;
  215. break;
  216. }
  217. }
  218. //
  219. // make sure this is a INTEL Pentium (or clone) or higher.
  220. //
  221. if (si.wProcessorArchitecture != PROCESSOR_ARCHITECTURE_INTEL)
  222. return;
  223. if (si.dwProcessorType < PROCESSOR_INTEL_PENTIUM)
  224. return;
  225. //
  226. // see if this chip supports rdtsc before using it.
  227. //
  228. __try
  229. {
  230. _asm
  231. {
  232. xor eax,eax
  233. _emit 00fh ;; CPUID
  234. _emit 0a2h
  235. mov dword ptr szCPUString,ebx
  236. mov dword ptr szCPUString+8,ecx
  237. mov dword ptr szCPUString+4,edx
  238. mov byte ptr szCPUString+12,0
  239. mov eax,1
  240. _emit 00Fh ;; CPUID
  241. _emit 0A2h
  242. mov flags,edx
  243. mov family,eax
  244. }
  245. }
  246. __except(1)
  247. {
  248. flags = 0;
  249. }
  250. //check for support of CPUID and fail
  251. if (!(flags & 0x10))
  252. return;
  253. // fcomi and FPU features both set
  254. if ( (flags&(1<<15)) && (flags & (1<<0)) )
  255. {
  256. D3D_INFO(2, "Pentium Pro CPU features (fcomi, cmov) detected");
  257. *lpdwCPUFeatures |= D3DCPU_FCOMICMOV;
  258. }
  259. //If we don't have a family, set it now
  260. //Family is bits 11:8 of eax from CPU, with eax=1
  261. if (!(*lpdwFamily))
  262. {
  263. *lpdwFamily=(family& 0x0F00) >> 8;
  264. }
  265. // not aware of any non-Intel processors w/non blocking reads
  266. if ( (! strcmp(szCPUString, "GenuineIntel")) &&
  267. *lpdwFamily > 5)
  268. {
  269. *lpdwCPUFeatures &= ~D3DCPU_BLOCKINGREAD;
  270. }
  271. return;
  272. }
  273. #pragma optimize("", on)
  274. #endif // _X86_
  275. #ifndef WIN95 // and Win98, WinME
  276. //---------------------------------------------------------------------
  277. BOOL bVBSwapEnabled = TRUE, bVBSwapWorkaround = FALSE;
  278. void SetVBSwapStatus(void)
  279. {
  280. OSVERSIONINFOEX osvi;
  281. ZeroMemory(&osvi, sizeof(osvi));
  282. osvi.dwOSVersionInfoSize = sizeof(osvi);
  283. if (!GetVersionEx((LPOSVERSIONINFO)&osvi))
  284. {
  285. D3D_INFO(1,"GetVersionEx failed - turning off VB swapping");
  286. bVBSwapEnabled = FALSE;
  287. return;
  288. }
  289. if ( VER_PLATFORM_WIN32_NT == osvi.dwPlatformId )
  290. {
  291. if (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 0) // Check if Win2K Gold (2195)
  292. {
  293. if (osvi.wServicePackMajor == 0) // No service pack
  294. {
  295. D3D_INFO(1, "Win2K Gold detected - turning off VB swapping");
  296. bVBSwapEnabled = FALSE;
  297. }
  298. else
  299. {
  300. D3D_INFO(1, "Win2K SP1 or above detected - enabling VB swap workaround");
  301. bVBSwapEnabled = FALSE;
  302. bVBSwapWorkaround = TRUE;
  303. }
  304. }
  305. else // Whistler and above
  306. {
  307. /* ASSUMPTION: NO WORKAROUND NEEDED */
  308. }
  309. }
  310. else
  311. {
  312. // Should never get here
  313. DPF_ERR("OS Detection failed - turning off VB swapping");
  314. bVBSwapEnabled = FALSE;
  315. return;
  316. }
  317. }
  318. #endif // WIN95
  319. extern "C" BOOL APIENTRY D3DDllMain( HMODULE hModule,
  320. DWORD ul_reason_for_call,
  321. LPVOID lpReserved );
  322. BOOL APIENTRY
  323. D3DDllMain( HMODULE hModule,
  324. DWORD ul_reason_for_call,
  325. LPVOID lpReserved )
  326. {
  327. HKEY hKey;
  328. LONG lRet;
  329. DWORD dwType, dwSize;
  330. char filename[_MAX_PATH];
  331. switch( ul_reason_for_call )
  332. {
  333. case DLL_PROCESS_ATTACH:
  334. #ifdef _X86_
  335. GetProcessorFamily(&dwCPUFamily, &dwCPUFeatures);
  336. D3D_INFO(3, "dwCPUFamily = %d, dwCPUFeatures = %d",
  337. dwCPUFamily, dwCPUFeatures);
  338. D3D_INFO(3, "szCPUString = %s", szCPUString);
  339. #endif
  340. // SSE (aka Katmai) does not work on Win95, so see if we are on
  341. // Win95 and disable
  342. #ifdef WIN95
  343. {
  344. BOOL bIsWin95 = IsWin95();
  345. if ((dwCPUFeatures & D3DCPU_SSE) && bIsWin95)
  346. {
  347. D3D_INFO(1,"Disabling <Streaming SIMD Extension> support on Win95");
  348. dwCPUFeatures &= ~D3DCPU_SSE;
  349. }
  350. }
  351. // We need to workaround VB problems on Win2K
  352. #else
  353. SetVBSwapStatus();
  354. #endif
  355. #ifdef __D3D_PSGP_DLL__
  356. lRet = RegOpenKey( HKEY_LOCAL_MACHINE, RESPATH_D3D, &hKey );
  357. if ( lRet == ERROR_SUCCESS )
  358. {
  359. dwSize = sizeof(filename);
  360. lRet = RegQueryValueEx(hKey,
  361. "GeometryDriver",
  362. NULL,
  363. &dwType,
  364. (LPBYTE) filename,
  365. &dwSize);
  366. if (lRet == ERROR_SUCCESS && dwType == REG_SZ)
  367. {
  368. hGeometryDLL = LoadLibrary(filename);
  369. if (hGeometryDLL)
  370. {
  371. pfnFEContextCreate = (LPD3DFE_CONTEXTCREATE) GetProcAddress(hGeometryDLL, "FEContextCreate");
  372. }
  373. }
  374. RegCloseKey( hKey );
  375. }
  376. #endif //__D3D_PSGP_DLL__
  377. // Set the app name to reg.
  378. SetMostRecentApp();
  379. break;
  380. case DLL_PROCESS_DETACH:
  381. if (NULL != hGeometryDLL)
  382. FreeLibrary(hGeometryDLL);
  383. break;
  384. default:
  385. ;
  386. }
  387. return TRUE;
  388. }
  389. // --------------------------------------------------------------------------
  390. // This function is called at process attach time to put the name of current
  391. // app to registry.
  392. // --------------------------------------------------------------------------
  393. void SetMostRecentApp(void)
  394. {
  395. char fname[_MAX_PATH] = "\0";
  396. char name[_MAX_PATH] = "\0";
  397. int i;
  398. HKEY hKey;
  399. HANDLE hFile;
  400. // Find out what process we are dealing with
  401. hFile = GetModuleHandle( NULL );
  402. GetModuleFileName( (HINSTANCE)hFile, fname, sizeof( fname ) );
  403. //DPF( 3, "full name = %s", fname );
  404. i = strlen( fname )-1;
  405. while( i >=0 && fname[i] != '\\' )
  406. {
  407. i--;
  408. }
  409. i++;
  410. strcpy( name, &fname[i] );
  411. //DPF( 3, "name = %s", name );
  412. // Now write the name into some known place
  413. if( !RegCreateKey( HKEY_LOCAL_MACHINE,
  414. RESPATH_D3D "\\" REGSTR_KEY_LASTAPP, &hKey ) )
  415. {
  416. RegSetValueEx(hKey, REGSTR_VAL_DDRAW_NAME, 0, REG_SZ, (LPBYTE)name, strlen(name)+1);
  417. RegCloseKey(hKey);
  418. }
  419. }