Counter Strike : Global Offensive Source Code
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.

290 lines
6.4 KiB

  1. //========= Copyright 1996-2005, Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose: win32 dependant ASM code for CPU capability detection
  4. //
  5. // $Workfile: $
  6. // $NoKeywords: $
  7. //=============================================================================//
  8. #if defined( POSIX )
  9. #else // POSIX
  10. // NOTE: This has to be the last file included!
  11. #include "tier0/memdbgon.h"
  12. #if defined( _X360 )
  13. bool CheckMMXTechnology(void) { return false; }
  14. bool CheckSSETechnology(void) { return false; }
  15. bool CheckSSE2Technology(void) { return false; }
  16. bool Check3DNowTechnology(void) { return false; }
  17. #elif defined( _M_X64 )
  18. bool CheckMMXTechnology(void) { return true; }
  19. bool CheckSSETechnology(void) { return true; }
  20. bool CheckSSE2Technology(void) { return true; }
  21. bool Check3DNowTechnology(void) { return false; }
  22. #elif defined( _WIN32 ) && !defined( _X360 )
  23. #pragma optimize( "", off )
  24. #pragma warning( disable: 4800 ) //'int' : forcing value to bool 'true' or 'false' (performance warning)
  25. // stuff from windows.h
  26. #ifndef EXCEPTION_EXECUTE_HANDLER
  27. #define EXCEPTION_EXECUTE_HANDLER 1
  28. #endif
  29. bool CheckMMXTechnology(void)
  30. {
  31. int retval = true;
  32. unsigned int RegEDX = 0;
  33. #ifdef CPUID
  34. _asm pushad;
  35. #endif
  36. __try
  37. {
  38. _asm
  39. {
  40. #ifdef CPUID
  41. xor edx, edx // Clue the compiler that EDX is about to be used.
  42. #endif
  43. mov eax, 1 // set up CPUID to return processor version and features
  44. // 0 = vendor string, 1 = version info, 2 = cache info
  45. CPUID // code bytes = 0fh, 0a2h
  46. mov RegEDX, edx // features returned in edx
  47. }
  48. }
  49. __except(EXCEPTION_EXECUTE_HANDLER)
  50. {
  51. retval = false;
  52. }
  53. // If CPUID not supported, then certainly no MMX extensions.
  54. if (retval)
  55. {
  56. if (RegEDX & 0x800000) // bit 23 is set for MMX technology
  57. {
  58. __try
  59. {
  60. // try executing the MMX instruction "emms"
  61. _asm EMMS
  62. }
  63. __except(EXCEPTION_EXECUTE_HANDLER)
  64. {
  65. retval = false;
  66. }
  67. }
  68. else
  69. retval = false; // processor supports CPUID but does not support MMX technology
  70. // if retval == 0 here, it means the processor has MMX technology but
  71. // floating-point emulation is on; so MMX technology is unavailable
  72. }
  73. #ifdef CPUID
  74. _asm popad;
  75. #endif
  76. return retval;
  77. }
  78. bool CheckSSETechnology(void)
  79. {
  80. int retval = true;
  81. unsigned int RegEDX = 0;
  82. #ifdef CPUID
  83. _asm pushad;
  84. #endif
  85. // Do we have support for the CPUID function?
  86. __try
  87. {
  88. _asm
  89. {
  90. #ifdef CPUID
  91. xor edx, edx // Clue the compiler that EDX is about to be used.
  92. #endif
  93. mov eax, 1 // set up CPUID to return processor version and features
  94. // 0 = vendor string, 1 = version info, 2 = cache info
  95. CPUID // code bytes = 0fh, 0a2h
  96. mov RegEDX, edx // features returned in edx
  97. }
  98. }
  99. __except(EXCEPTION_EXECUTE_HANDLER)
  100. {
  101. retval = false;
  102. }
  103. // If CPUID not supported, then certainly no SSE extensions.
  104. if (retval)
  105. {
  106. // Do we have support for SSE in this processor?
  107. if ( RegEDX & 0x2000000L ) // bit 25 is set for SSE technology
  108. {
  109. // Make sure that SSE is supported by executing an inline SSE instruction
  110. // BUGBUG, FIXME - Visual C Version 6.0 does not support SSE inline code YET (No macros from Intel either)
  111. // Fix this if VC7 supports inline SSE instructinons like "xorps" as shown below.
  112. #if 1
  113. __try
  114. {
  115. _asm
  116. {
  117. // Attempt execution of a SSE instruction to make sure OS supports SSE FPU context switches
  118. xorps xmm0, xmm0
  119. // This will work on Win2k+ (Including masking SSE FPU exception to "normalized" values)
  120. // This will work on Win98+ (But no "masking" of FPU exceptions provided)
  121. }
  122. }
  123. __except(EXCEPTION_EXECUTE_HANDLER)
  124. #endif
  125. {
  126. retval = false;
  127. }
  128. }
  129. else
  130. retval = false;
  131. }
  132. #ifdef CPUID
  133. _asm popad;
  134. #endif
  135. return retval;
  136. }
  137. bool CheckSSE2Technology(void)
  138. {
  139. int retval = true;
  140. unsigned int RegEDX = 0;
  141. #ifdef CPUID
  142. _asm pushad;
  143. #endif
  144. // Do we have support for the CPUID function?
  145. __try
  146. {
  147. _asm
  148. {
  149. #ifdef CPUID
  150. xor edx, edx // Clue the compiler that EDX is about to be used.
  151. #endif
  152. mov eax, 1 // set up CPUID to return processor version and features
  153. // 0 = vendor string, 1 = version info, 2 = cache info
  154. CPUID // code bytes = 0fh, 0a2h
  155. mov RegEDX, edx // features returned in edx
  156. }
  157. }
  158. __except(EXCEPTION_EXECUTE_HANDLER)
  159. {
  160. retval = false;
  161. }
  162. // If CPUID not supported, then certainly no SSE extensions.
  163. if (retval)
  164. {
  165. // Do we have support for SSE in this processor?
  166. if ( RegEDX & 0x04000000 ) // bit 26 is set for SSE2 technology
  167. {
  168. // Make sure that SSE is supported by executing an inline SSE instruction
  169. __try
  170. {
  171. _asm
  172. {
  173. // Attempt execution of a SSE2 instruction to make sure OS supports SSE FPU context switches
  174. xorpd xmm0, xmm0
  175. }
  176. }
  177. __except(EXCEPTION_EXECUTE_HANDLER)
  178. {
  179. retval = false;
  180. }
  181. }
  182. else
  183. retval = false;
  184. }
  185. #ifdef CPUID
  186. _asm popad;
  187. #endif
  188. return retval;
  189. }
  190. bool Check3DNowTechnology(void)
  191. {
  192. int retval = true;
  193. unsigned int RegEAX = 0;
  194. #ifdef CPUID
  195. _asm pushad;
  196. #endif
  197. // First see if we can execute CPUID at all
  198. __try
  199. {
  200. _asm
  201. {
  202. #ifdef CPUID
  203. // xor edx, edx // Clue the compiler that EDX is about to be used.
  204. #endif
  205. mov eax, 0x80000000 // setup CPUID to return whether AMD >0x80000000 function are supported.
  206. // 0x80000000 = Highest 0x80000000+ function, 0x80000001 = 3DNow support
  207. CPUID // code bytes = 0fh, 0a2h
  208. mov RegEAX, eax // result returned in eax
  209. }
  210. }
  211. __except(EXCEPTION_EXECUTE_HANDLER)
  212. {
  213. retval = false;
  214. }
  215. // If CPUID not supported, then there is definitely no 3DNow support
  216. if (retval)
  217. {
  218. // Are there any "higher" AMD CPUID functions?
  219. if (RegEAX > 0x80000000L )
  220. {
  221. __try
  222. {
  223. _asm
  224. {
  225. mov eax, 0x80000001 // setup to test for CPU features
  226. CPUID // code bytes = 0fh, 0a2h
  227. shr edx, 31 // If bit 31 is set, we have 3DNow support!
  228. mov retval, edx // Save the return value for end of function
  229. }
  230. }
  231. __except(EXCEPTION_EXECUTE_HANDLER)
  232. {
  233. retval = false;
  234. }
  235. }
  236. else
  237. {
  238. // processor supports CPUID but does not support AMD CPUID functions
  239. retval = false;
  240. }
  241. }
  242. #ifdef CPUID
  243. _asm popad;
  244. #endif
  245. return retval;
  246. }
  247. #pragma optimize( "", on )
  248. #endif // _WIN32
  249. #endif // POSIX