Leaked source code of windows server 2003
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.

588 lines
17 KiB

  1. /*==========================================================================;
  2. *
  3. * Copyright (C) 1995 Microsoft Corporation. All Rights Reserved.
  4. *
  5. * File: dlld3d.cpp
  6. * Content: Direct3D startup
  7. *@@BEGIN_MSINTERNAL
  8. *
  9. * History:
  10. * Date By Reason
  11. * ==== == ======
  12. * 05/11/95 stevela Initial rev with this header.
  13. * 21/11/95 colinmc Added Direct3D interface ID.
  14. * 07/12/95 stevela Merged Colin's changes.
  15. * 10/12/95 stevela Removed AGGREGATE_D3D.
  16. * 02/03/96 colinmc Minor build fix.
  17. *@@END_MSINTERNAL
  18. *
  19. ***************************************************************************/
  20. #include "pch.cpp"
  21. #pragma hdrstop
  22. /*
  23. * Define the Direct3D IIDs.
  24. */
  25. #undef DPF_MODNAME
  26. #define DPF_MODNAME "Direct3D Startup"
  27. DPF_DECLARE(Direct3D);
  28. #ifdef WIN95
  29. LPVOID lpWin16Lock;
  30. #endif
  31. DWORD dwD3DTriBatchSize, dwTriBatchSize, dwLineBatchSize;
  32. DWORD dwHWBufferSize, dwHWMaxTris, dwHWFewVertices;
  33. HINSTANCE hGeometryDLL = NULL;
  34. LPD3DFE_CONTEXTCREATE pfnFEContextCreate;
  35. char szCPUString[13];
  36. DWORD dwCPUFamily, dwCPUFeatures;
  37. #ifdef _X86_
  38. extern HRESULT D3DAPI pii_FEContextCreate(DWORD dwFlags, LPD3DFE_PVFUNCS *lpLeafFuncs);
  39. extern HRESULT D3DAPI katmai_FEContextCreate(DWORD dwFlags, LPD3DFE_PVFUNCS *lpLeafFuncs);
  40. extern LPD3DFE_CONTEXTCREATE px3DContextCreate;
  41. #endif
  42. void SetMostRecentApp(void);
  43. #ifdef _X86_
  44. // --------------------------------------------------------------------------
  45. // Here's a routine helps us determine if we should try MMX or not
  46. // --------------------------------------------------------------------------
  47. BOOL _asm_isMMX()
  48. {
  49. DWORD retval;
  50. _asm
  51. {
  52. xor eax,eax ; Clear out eax for return value
  53. pushad ; CPUID trashes lots - save everything
  54. mov eax,1 ; Check for MMX support
  55. ;;; We need to upgrade our compiler
  56. ;;; CPUID == 0f,a2
  57. _emit 0x0f
  58. _emit 0xa2
  59. test edx,00800000h ; Set flags before restoring registers
  60. popad ; Restore everything
  61. setnz al ; Set return value
  62. mov retval, eax
  63. };
  64. return retval;
  65. }
  66. #endif
  67. static int isMMX = -1;
  68. BOOL
  69. isMMXprocessor(void)
  70. {
  71. HKEY hKey;
  72. if ( RegOpenKey( HKEY_LOCAL_MACHINE,
  73. RESPATH_D3D,
  74. &hKey) == ERROR_SUCCESS)
  75. {
  76. DWORD dwType;
  77. DWORD dwValue;
  78. DWORD dwSize = 4;
  79. if ( RegQueryValueEx( hKey, "DisableMMX", NULL, &dwType, (LPBYTE) &dwValue, &dwSize) == ERROR_SUCCESS &&
  80. dwType == REG_DWORD &&
  81. dwValue != 0)
  82. {
  83. RegCloseKey( hKey );
  84. isMMX = 0;
  85. return FALSE;
  86. }
  87. RegCloseKey( hKey );
  88. }
  89. if (isMMX < 0)
  90. {
  91. isMMX = FALSE;
  92. #ifdef _X86_
  93. D3D_WARN(1, "Executing processor detection code (benign first-chance exception possible)" );
  94. #ifndef WIN95
  95. {
  96. // GetSystemInfo is not broken on WinNT.
  97. SYSTEM_INFO si;
  98. GetSystemInfo(&si);
  99. if (si.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_INTEL &&
  100. si.wProcessorLevel >= 5)
  101. {
  102. #endif
  103. __try
  104. {
  105. if( _asm_isMMX() )
  106. {
  107. // Emit an emms instruction.
  108. // This file needs to compile for non-Pentium
  109. // processors
  110. // so we can't use use inline asm since we're in the
  111. // wrong
  112. // processor mode.
  113. __asm __emit 0xf;
  114. __asm __emit 0x77;
  115. isMMX = TRUE;
  116. D3D_INFO(1, "MMX detected");
  117. }
  118. }
  119. __except(GetExceptionCode() == STATUS_ILLEGAL_INSTRUCTION ?
  120. EXCEPTION_EXECUTE_HANDLER :
  121. EXCEPTION_CONTINUE_SEARCH)
  122. {
  123. }
  124. #ifndef WIN95
  125. }
  126. }
  127. #endif
  128. #endif
  129. }
  130. return isMMX;
  131. }
  132. #ifdef _X86_
  133. extern BOOL isX3Dprocessor(void);
  134. //---------------------------------------------------------------------
  135. // Detects PentiumII/Katmai processor
  136. //
  137. #pragma optimize("", off)
  138. #define CPUID _asm _emit 0x0f _asm _emit 0xa2
  139. BOOL IsPentiumIIProcessor(void)
  140. {
  141. DWORD RegisterEAX;
  142. char VendorId[12];
  143. const char IntelId[13]="GenuineIntel";
  144. __try
  145. {
  146. _asm {
  147. xor eax,eax
  148. CPUID
  149. mov RegisterEAX, eax
  150. mov dword ptr VendorId, ebx
  151. mov dword ptr VendorId+4, edx
  152. mov dword ptr VendorId+8, ecx
  153. }
  154. } __except (1)
  155. {
  156. return FALSE;
  157. }
  158. // make sure EAX is > 0 which means the chip
  159. // supports a value of 1 which is the chip info
  160. if (RegisterEAX == 0)
  161. return FALSE;
  162. // make sure chip is "GenuineIntel"
  163. for (int i=0; i<12; i++)
  164. if (VendorId[i] != IntelId[i])
  165. return FALSE;
  166. __try
  167. {
  168. _asm {
  169. mov eax, 1
  170. CPUID
  171. mov RegisterEAX, eax
  172. }
  173. } __except (1)
  174. {
  175. return FALSE;
  176. }
  177. // EAX[3:0] = stepping id
  178. // EAX[7:4] = model = 0001 (Pentium Pro), 0011 and 0101 (Pentium II)
  179. // EAX[11:8] = family = 0110
  180. // EAX[13:12] = processor type = 00
  181. if ((RegisterEAX & 0x3F00) != 0x0600) // test for processor type & family
  182. return FALSE;
  183. RegisterEAX = (RegisterEAX & 0xf0); // test for model
  184. if (RegisterEAX >= 0x30) // add RegisterEAX == 0x10 for Pentium Pro
  185. return TRUE;
  186. else
  187. return FALSE;
  188. }
  189. BOOL IsKatmaiProcessor(void)
  190. {
  191. DWORD RegisterEAX;
  192. char VendorId[12];
  193. const char IntelId[13]="GenuineIntel";
  194. __try
  195. {
  196. _asm {
  197. xor eax,eax
  198. CPUID
  199. mov RegisterEAX, eax
  200. mov dword ptr VendorId, ebx
  201. mov dword ptr VendorId+4, edx
  202. mov dword ptr VendorId+8, ecx
  203. }
  204. } __except (1)
  205. {
  206. return FALSE;
  207. }
  208. // make sure EAX is > 0 which means the chip
  209. // supports a value >=1. 1 = chip info
  210. if (RegisterEAX == 0)
  211. return FALSE;
  212. // make sure chip is "GenuineIntel"
  213. for (int i=0; i<12; i++)
  214. if (VendorId[i] != IntelId[i])
  215. return FALSE;
  216. // this CPUID can't fail if the above test passed
  217. _asm {
  218. mov eax, 1
  219. CPUID
  220. mov RegisterEAX, eax
  221. }
  222. // EAX[3:0] = stepping id
  223. // EAX[7:4] = model = 0001 (Pentium Pro), 0011 and 0101 (Pentium II)
  224. // EAX[11:8] = family = 0110
  225. // EAX[13:12] = processor type = 00
  226. RegisterEAX = (RegisterEAX & 0x3FF0); // test for model
  227. if (RegisterEAX >= 0x670) // Katmai or newer
  228. return TRUE;
  229. else
  230. return FALSE;
  231. }
  232. #pragma optimize("", on)
  233. #ifdef WIN95 // and Win98...
  234. //---------------------------------------------------------------------
  235. BOOL
  236. IsWin95(void)
  237. {
  238. OSVERSIONINFO osvi;
  239. ZeroMemory(&osvi, sizeof(osvi));
  240. osvi.dwOSVersionInfoSize = sizeof(osvi);
  241. if (!GetVersionEx(&osvi))
  242. {
  243. D3D_INFO(1,"GetVersionEx failed - assuming Win95");
  244. return TRUE;
  245. }
  246. if ( VER_PLATFORM_WIN32_WINDOWS == osvi.dwPlatformId )
  247. {
  248. if( ( osvi.dwMajorVersion > 4UL ) ||
  249. ( ( osvi.dwMajorVersion == 4UL ) &&
  250. ( osvi.dwMinorVersion >= 10UL ) &&
  251. ( LOWORD( osvi.dwBuildNumber ) >= 1373 ) ) )
  252. {
  253. // is Win98
  254. D3D_INFO(2,"Detected Win98");
  255. return FALSE;
  256. }
  257. else
  258. {
  259. // is Win95
  260. D3D_INFO(2,"Detected Win95");
  261. return TRUE;
  262. }
  263. }
  264. else if ( VER_PLATFORM_WIN32_NT == osvi.dwPlatformId )
  265. {
  266. D3D_INFO(2,"Detected WinNT");
  267. return FALSE;
  268. }
  269. D3D_INFO(2,"OS Detection failed");
  270. return TRUE;
  271. }
  272. #endif // WIN95
  273. //---------------------------------------------------------------------
  274. //
  275. // void GetProcessorFamily(LPDWORD lpdwFamily);
  276. //
  277. // Passes back 3, 4, 5, 6 for 386, 486, Pentium, PPro class machines
  278. //
  279. #pragma optimize("", off)
  280. void
  281. GetProcessorFamily(LPDWORD lpdwFamily, LPDWORD lpdwCPUFeatures)
  282. {
  283. SYSTEM_INFO si;
  284. __int64 start, end, freq;
  285. int flags,family;
  286. int time;
  287. int clocks;
  288. DWORD oldclass;
  289. HANDLE hprocess;
  290. // guilty until proven otherwise
  291. *lpdwCPUFeatures = D3DCPU_BLOCKINGREAD;
  292. if ( isMMXprocessor() )
  293. {
  294. *lpdwCPUFeatures |= D3DCPU_MMX;
  295. }
  296. ZeroMemory(&si, sizeof(si));
  297. GetSystemInfo(&si);
  298. //Set the family. If wProcessorLevel is not specified, dig it out of dwProcessorType
  299. //Because wProcessor level is not implemented on Win95
  300. if (si.wProcessorLevel)
  301. {
  302. *lpdwFamily=si.wProcessorLevel;
  303. }
  304. else
  305. {
  306. //Ok, we're on Win95
  307. switch (si.dwProcessorType)
  308. {
  309. case PROCESSOR_INTEL_386:
  310. *lpdwFamily=3;
  311. break;
  312. case PROCESSOR_INTEL_486:
  313. *lpdwFamily=4;
  314. break;
  315. default:
  316. *lpdwFamily=0;
  317. break;
  318. }
  319. }
  320. //
  321. // make sure this is a INTEL Pentium (or clone) or higher.
  322. //
  323. if (si.wProcessorArchitecture != PROCESSOR_ARCHITECTURE_INTEL)
  324. return;
  325. if (si.dwProcessorType < PROCESSOR_INTEL_PENTIUM)
  326. return;
  327. //
  328. // see if this chip supports rdtsc before using it.
  329. //
  330. __try
  331. {
  332. _asm
  333. {
  334. xor eax,eax
  335. _emit 00fh ;; CPUID
  336. _emit 0a2h
  337. mov dword ptr szCPUString,ebx
  338. mov dword ptr szCPUString+8,ecx
  339. mov dword ptr szCPUString+4,edx
  340. mov byte ptr szCPUString+12,0
  341. mov eax,1
  342. _emit 00Fh ;; CPUID
  343. _emit 0A2h
  344. mov flags,edx
  345. mov family,eax
  346. }
  347. }
  348. __except(1)
  349. {
  350. flags = 0;
  351. }
  352. //check for support of CPUID and fail
  353. if (!(flags & 0x10))
  354. return;
  355. // fcomi and FPU features both set
  356. if ( (flags&(1<<15)) && (flags & (1<<0)) )
  357. {
  358. D3D_INFO(2, "Pentium Pro CPU features (fcomi, cmov) detected");
  359. *lpdwCPUFeatures |= D3DCPU_FCOMICMOV;
  360. }
  361. //If we don't have a family, set it now
  362. //Family is bits 11:8 of eax from CPU, with eax=1
  363. if (!(*lpdwFamily))
  364. {
  365. *lpdwFamily=(family& 0x0F00) >> 8;
  366. }
  367. // not aware of any non-Intel processors w/non blocking reads
  368. if ( (! strcmp(szCPUString, "GenuineIntel")) &&
  369. *lpdwFamily > 5)
  370. {
  371. *lpdwCPUFeatures &= ~D3DCPU_BLOCKINGREAD;
  372. }
  373. if ( isX3Dprocessor() )
  374. {
  375. D3D_INFO(2, "X3D Processor detected for PSGP");
  376. *lpdwCPUFeatures |= D3DCPU_X3D;
  377. }
  378. if ( IsPentiumIIProcessor() )
  379. {
  380. D3D_INFO(2, "PentiumII Processor detected for PSGP");
  381. *lpdwCPUFeatures |= D3DCPU_PII;
  382. }
  383. if ( IsKatmaiProcessor() )
  384. {
  385. D3D_INFO(2, "Katmai Processor detected for PSGP");
  386. *lpdwCPUFeatures |= D3DCPU_KATMAI;
  387. }
  388. return;
  389. }
  390. #pragma optimize("", on)
  391. #endif // _X86_
  392. BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved)
  393. {
  394. HKEY hKey;
  395. LONG lRet;
  396. DWORD dwType, dwSize = sizeof(dwHWFewVertices);
  397. char filename[_MAX_PATH];
  398. switch( ul_reason_for_call ) {
  399. case DLL_PROCESS_ATTACH:
  400. DisableThreadLibraryCalls( hModule );
  401. DPFINIT();
  402. MemInit();
  403. #ifdef WIN95
  404. GetpWin16Lock(&lpWin16Lock);
  405. #endif
  406. #ifdef _X86_
  407. GetProcessorFamily(&dwCPUFamily, &dwCPUFeatures);
  408. D3D_INFO(3, "dwCPUFamily = %d, dwCPUFeatures = %d", dwCPUFamily, dwCPUFeatures);
  409. D3D_INFO(3, "szCPUString = %s", szCPUString);
  410. #endif
  411. #ifdef WIN95 // and Win98...
  412. // Katmai NI does not work on Win95, so see if we are on Win95 and disable
  413. //
  414. {
  415. BOOL bIsWin95 = IsWin95();
  416. if ((dwCPUFeatures & D3DCPU_KATMAI) && bIsWin95)
  417. {
  418. D3D_INFO(1,"Disabling KNI support on Win95");
  419. dwCPUFeatures &= ~D3DCPU_KATMAI;
  420. }
  421. }
  422. #endif
  423. #ifdef _X86_
  424. if ( dwCPUFeatures & D3DCPU_X3D )
  425. pfnFEContextCreate = px3DContextCreate;
  426. else if ( dwCPUFeatures & D3DCPU_KATMAI )
  427. pfnFEContextCreate = katmai_FEContextCreate;
  428. else if ( dwCPUFeatures & D3DCPU_PII )
  429. pfnFEContextCreate = pii_FEContextCreate;
  430. #endif
  431. // Unfounded default value. 128*40 (vertex+D3DTRIANGLE struct)=5K
  432. // The assumption is that the primary cache hasn't got much better
  433. // to do than contain the vertex and index data.
  434. dwD3DTriBatchSize = 80;
  435. // Work item: do something more intelligent here than assume that
  436. // MMX-enabled processors have twice as much primary cache.
  437. if ( isMMXprocessor() )
  438. dwD3DTriBatchSize *= 2;
  439. dwTriBatchSize = (dwD3DTriBatchSize * 4) / 3;
  440. dwLineBatchSize = dwD3DTriBatchSize * 2;
  441. dwHWBufferSize = dwD3DTriBatchSize * (sizeof(D3DTLVERTEX) + sizeof(D3DTRIANGLE));
  442. dwHWMaxTris = dwD3DTriBatchSize;
  443. lRet = RegOpenKey( HKEY_LOCAL_MACHINE, RESPATH_D3D, &hKey );
  444. if ( lRet == ERROR_SUCCESS )
  445. {
  446. lRet = RegQueryValueEx(hKey,
  447. "FewVertices",
  448. NULL,
  449. &dwType,
  450. (LPBYTE) &dwHWFewVertices,
  451. &dwSize);
  452. if (lRet != ERROR_SUCCESS ||
  453. dwType != REG_DWORD ||
  454. dwHWFewVertices < 4 ||
  455. dwHWFewVertices > 128)
  456. dwHWFewVertices = 24;
  457. // disabling 'GeometryDriver' DLL interface until it is less abusable...
  458. #if 0
  459. dwSize = sizeof(filename);
  460. lRet = RegQueryValueEx(hKey,
  461. "GeometryDriver",
  462. NULL,
  463. &dwType,
  464. (LPBYTE) filename,
  465. &dwSize);
  466. if (lRet == ERROR_SUCCESS && dwType == REG_SZ)
  467. {
  468. hGeometryDLL = LoadLibrary(filename);
  469. if (hGeometryDLL)
  470. {
  471. pfnFEContextCreate = (LPD3DFE_CONTEXTCREATE) GetProcAddress(hGeometryDLL, "FEContextCreate");
  472. }
  473. }
  474. #endif
  475. RegCloseKey( hKey );
  476. }
  477. else
  478. {
  479. dwHWFewVertices = 24;
  480. }
  481. // Set the app name to reg.
  482. SetMostRecentApp();
  483. break;
  484. case DLL_PROCESS_DETACH:
  485. MemFini();
  486. if (NULL != hGeometryDLL)
  487. FreeLibrary(hGeometryDLL);
  488. break;
  489. default:
  490. ;
  491. }
  492. return TRUE;
  493. }
  494. // --------------------------------------------------------------------------
  495. // This function is called at process attach time to put the name of current
  496. // app to registry.
  497. // --------------------------------------------------------------------------
  498. void SetMostRecentApp(void)
  499. {
  500. char fname[_MAX_PATH];
  501. char name[_MAX_PATH];
  502. int i;
  503. HKEY hKey;
  504. HANDLE hFile;
  505. // Find out what process we are dealing with
  506. hFile = GetModuleHandle( NULL );
  507. GetModuleFileName( (HINSTANCE)hFile, fname, sizeof( fname ) );
  508. DPF( 3, "full name = %s", fname );
  509. i = strlen( fname )-1;
  510. while( i >=0 && fname[i] != '\\' )
  511. {
  512. i--;
  513. }
  514. i++;
  515. strcpy( name, &fname[i] );
  516. DPF( 3, "name = %s", name );
  517. // Now write the name into some known place
  518. if( !RegCreateKey( HKEY_LOCAL_MACHINE,
  519. RESPATH_D3D "\\" REGSTR_KEY_LASTAPP, &hKey ) )
  520. {
  521. RegSetValueEx(hKey, REGSTR_VAL_DDRAW_NAME, 0, REG_SZ, (LPBYTE)name, strlen(name)+1);
  522. RegCloseKey(hKey);
  523. }
  524. }