Improved CPU detection code.

This commit is contained in:
LoRd_MuldeR 2012-02-07 03:37:47 +01:00
parent 42a2bf73ec
commit 9db58c543f
6 changed files with 61 additions and 23 deletions

BIN
asm/cpu-detect.obj Normal file

Binary file not shown.

View File

@ -412,6 +412,14 @@ bool x264_is_prerelease(void)
return (VER_X264_PRE_RELEASE); return (VER_X264_PRE_RELEASE);
} }
/*
* CPUID prototype (actual function is in ASM code)
*/
extern "C"
{
void x264_cpu_cpuid(unsigned int op, unsigned int *eax, unsigned int *ebx, unsigned int *ecx, unsigned int *edx);
}
/* /*
* Detect CPU features * Detect CPU features
*/ */
@ -425,7 +433,7 @@ x264_cpu_t x264_detect_cpu_features(int argc, char **argv)
x264_cpu_t features; x264_cpu_t features;
SYSTEM_INFO systemInfo; SYSTEM_INFO systemInfo;
int CPUInfo[4] = {-1}; unsigned int CPUInfo[4];
char CPUIdentificationString[0x40]; char CPUIdentificationString[0x40];
char CPUBrandString[0x40]; char CPUBrandString[0x40];
@ -434,42 +442,49 @@ x264_cpu_t x264_detect_cpu_features(int argc, char **argv)
memset(CPUIdentificationString, 0, sizeof(CPUIdentificationString)); memset(CPUIdentificationString, 0, sizeof(CPUIdentificationString));
memset(CPUBrandString, 0, sizeof(CPUBrandString)); memset(CPUBrandString, 0, sizeof(CPUBrandString));
__cpuid(CPUInfo, 0); x264_cpu_cpuid(0, &CPUInfo[0], &CPUInfo[1], &CPUInfo[2], &CPUInfo[3]);
memcpy(CPUIdentificationString, &CPUInfo[1], sizeof(int)); memcpy(CPUIdentificationString, &CPUInfo[1], 4);
memcpy(CPUIdentificationString + 4, &CPUInfo[3], sizeof(int)); memcpy(CPUIdentificationString + 4, &CPUInfo[3], 4);
memcpy(CPUIdentificationString + 8, &CPUInfo[2], sizeof(int)); memcpy(CPUIdentificationString + 8, &CPUInfo[2], 4);
features.intel = (_stricmp(CPUIdentificationString, "GenuineIntel") == 0); features.intel = (_stricmp(CPUIdentificationString, "GenuineIntel") == 0);
strncpy_s(features.vendor, 0x40, CPUIdentificationString, _TRUNCATE); strncpy_s(features.vendor, 0x40, CPUIdentificationString, _TRUNCATE);
if(CPUInfo[0] >= 1) if(CPUInfo[0] >= 1)
{ {
__cpuid(CPUInfo, 1); x264_cpu_cpuid(1, &CPUInfo[0], &CPUInfo[1], &CPUInfo[2], &CPUInfo[3]);
features.mmx = (CPUInfo[3] & 0x800000) || false; features.mmx = (CPUInfo[3] & 0x800000U) || false;
features.sse = (CPUInfo[3] & 0x2000000) || false; features.sse = (CPUInfo[3] & 0x2000000U) || false;
features.sse2 = (CPUInfo[3] & 0x4000000) || false; features.sse2 = (CPUInfo[3] & 0x4000000U) || false;
features.ssse3 = (CPUInfo[2] & 0x200) || false; features.ssse3 = (CPUInfo[2] & 0x200U) || false;
features.sse3 = (CPUInfo[2] & 0x1) || false; features.sse3 = (CPUInfo[2] & 0x1U) || false;
features.ssse3 = (CPUInfo[2] & 0x200) || false; features.ssse3 = (CPUInfo[2] & 0x200U) || false;
features.stepping = CPUInfo[0] & 0xf; features.stepping = CPUInfo[0] & 0xf;
features.model = ((CPUInfo[0] >> 4) & 0xf) + (((CPUInfo[0] >> 16) & 0xf) << 4); features.model = ((CPUInfo[0] >> 4) & 0xf) + (((CPUInfo[0] >> 16) & 0xf) << 4);
features.family = ((CPUInfo[0] >> 8) & 0xf) + ((CPUInfo[0] >> 20) & 0xff); features.family = ((CPUInfo[0] >> 8) & 0xf) + ((CPUInfo[0] >> 20) & 0xff);
if(features.sse) features.mmx2 = true; //MMXEXT is a subset of SSE!
} }
__cpuid(CPUInfo, 0x80000000); x264_cpu_cpuid(0x80000000U, &CPUInfo[0], &CPUInfo[1], &CPUInfo[2], &CPUInfo[3]);
int nExIds = qMax<int>(qMin<int>(CPUInfo[0], 0x80000004), 0x80000000); unsigned int nExIds = qBound(0x80000000U, CPUInfo[0], 0x80000004U);
for(int i = 0x80000002; i <= nExIds; ++i) if((_stricmp(CPUIdentificationString, "AuthenticAMD") == 0) && (nExIds >= 0x80000001U))
{ {
__cpuid(CPUInfo, i); x264_cpu_cpuid(0x80000001U, &CPUInfo[0], &CPUInfo[1], &CPUInfo[2], &CPUInfo[3]);
features.mmx2 = features.mmx2 || (CPUInfo[3] & 0x00400000U);
}
for(unsigned int i = 0x80000002U; i <= nExIds; ++i)
{
x264_cpu_cpuid(i, &CPUInfo[0], &CPUInfo[1], &CPUInfo[2], &CPUInfo[3]);
switch(i) switch(i)
{ {
case 0x80000002: case 0x80000002U:
memcpy(CPUBrandString, CPUInfo, sizeof(CPUInfo)); memcpy(CPUBrandString, CPUInfo, sizeof(CPUInfo));
break; break;
case 0x80000003: case 0x80000003U:
memcpy(CPUBrandString + 16, CPUInfo, sizeof(CPUInfo)); memcpy(CPUBrandString + 16, CPUInfo, sizeof(CPUInfo));
break; break;
case 0x80000004: case 0x80000004U:
memcpy(CPUBrandString + 32, CPUInfo, sizeof(CPUInfo)); memcpy(CPUBrandString + 32, CPUInfo, sizeof(CPUInfo));
break; break;
} }
@ -517,11 +532,13 @@ x264_cpu_t x264_detect_cpu_features(int argc, char **argv)
{ {
if(!_stricmp("--force-cpu-no-64bit", argv[i])) { flag = true; features.x64 = false; } if(!_stricmp("--force-cpu-no-64bit", argv[i])) { flag = true; features.x64 = false; }
if(!_stricmp("--force-cpu-no-mmx", argv[i])) { flag = true; features.mmx = false; } if(!_stricmp("--force-cpu-no-mmx", argv[i])) { flag = true; features.mmx = false; }
if(!_stricmp("--force-cpu-no-mmx2", argv[i])) { flag = true; features.mmx2 = false; }
if(!_stricmp("--force-cpu-no-sse", argv[i])) { flag = true; features.sse = features.sse2 = features.sse3 = features.ssse3 = false; } if(!_stricmp("--force-cpu-no-sse", argv[i])) { flag = true; features.sse = features.sse2 = features.sse3 = features.ssse3 = false; }
if(!_stricmp("--force-cpu-no-intel", argv[i])) { flag = true; features.intel = false; } if(!_stricmp("--force-cpu-no-intel", argv[i])) { flag = true; features.intel = false; }
if(!_stricmp("--force-cpu-have-64bit", argv[i])) { flag = true; features.x64 = true; } if(!_stricmp("--force-cpu-have-64bit", argv[i])) { flag = true; features.x64 = true; }
if(!_stricmp("--force-cpu-have-mmx", argv[i])) { flag = true; features.mmx = true; } if(!_stricmp("--force-cpu-have-mmx", argv[i])) { flag = true; features.mmx = true; }
if(!_stricmp("--force-cpu-have-mmx2", argv[i])) { flag = true; features.mmx2 = true; }
if(!_stricmp("--force-cpu-have-sse", argv[i])) { flag = true; features.sse = features.sse2 = features.sse3 = features.ssse3 = true; } if(!_stricmp("--force-cpu-have-sse", argv[i])) { flag = true; features.sse = features.sse2 = features.sse3 = features.ssse3 = true; }
if(!_stricmp("--force-cpu-have-intel", argv[i])) { flag = true; features.intel = true; } if(!_stricmp("--force-cpu-have-intel", argv[i])) { flag = true; features.intel = true; }
} }

View File

@ -78,6 +78,7 @@ typedef struct
int count; int count;
bool x64; bool x64;
bool mmx; bool mmx;
bool mmx2;
bool sse; bool sse;
bool sse2; bool sse2;
bool sse3; bool sse3;

View File

@ -59,13 +59,22 @@ static int x264_main(int argc, char* argv[])
qDebug(" CPU vendor id : %s (Intel: %s)", cpuFeatures.vendor, X264_BOOL(cpuFeatures.intel)); qDebug(" CPU vendor id : %s (Intel: %s)", cpuFeatures.vendor, X264_BOOL(cpuFeatures.intel));
qDebug("CPU brand string : %s", cpuFeatures.brand); qDebug("CPU brand string : %s", cpuFeatures.brand);
qDebug(" CPU signature : Family: %d, Model: %d, Stepping: %d", cpuFeatures.family, cpuFeatures.model, cpuFeatures.stepping); qDebug(" CPU signature : Family: %d, Model: %d, Stepping: %d", cpuFeatures.family, cpuFeatures.model, cpuFeatures.stepping);
qDebug("CPU capabilities : MMX: %s, SSE: %s, SSE2: %s, SSE3: %s, SSSE3: %s, x64: %s", X264_BOOL(cpuFeatures.mmx), X264_BOOL(cpuFeatures.sse), X264_BOOL(cpuFeatures.sse2), X264_BOOL(cpuFeatures.sse3), X264_BOOL(cpuFeatures.ssse3), X264_BOOL(cpuFeatures.x64)); qDebug("CPU capabilities : MMX=%s, MMXEXT=%s, SSE=%s, SSE2=%s, SSE3=%s, SSSE3=%s, X64=%s", X264_BOOL(cpuFeatures.mmx), X264_BOOL(cpuFeatures.mmx2), X264_BOOL(cpuFeatures.sse), X264_BOOL(cpuFeatures.sse2), X264_BOOL(cpuFeatures.sse3), X264_BOOL(cpuFeatures.ssse3), X264_BOOL(cpuFeatures.x64));
qDebug(" Number of CPU's : %d\n", cpuFeatures.count); qDebug(" Number of CPU's : %d\n", cpuFeatures.count);
//Make sure this CPU can run x264 //Make sure this CPU can run x264 (requires MMX + MMXEXT/iSSE to run x264 with ASM enabled, additionally requires SSE1 for most x264 builds)
if(!(cpuFeatures.mmx && cpuFeatures.sse)) if(!(cpuFeatures.mmx && cpuFeatures.mmx2))
{ {
qFatal("Sorry, but this machine is not physically capable of running x264. Please get a CPU that supports at least the MMX and ISSE instruction sets!"); qFatal("Sorry, but this machine is not physically capable of running x264. Please get a CPU that supports at least the MMX and MMXEXT instruction sets!");
}
else if(!(cpuFeatures.mmx && cpuFeatures.sse))
{
qWarning("WARNING: System does not support SSE1, most x264 builds will not work !!!\n");
for(;;)
{
int ret = MessageBoxW(NULL, L"BIG FAT WARNING: This machine apparently does NOT support the SSE1 instruction set and thus probably will NOT be able to run x264!", L"Simple x264 Launcher", MB_ABORTRETRYIGNORE|MB_TOPMOST|MB_ICONEXCLAMATION);
if(ret == IDIGNORE) break; else if(ret == IDRETRY) continue; else return -1;
}
} }
//Initialize Qt //Initialize Qt

View File

@ -260,6 +260,9 @@ copy "$(SolutionDir)res\toolset\*.exe" "$(SolutionDir)bin\$(Configuration)\tools
<ItemGroup> <ItemGroup>
<ResourceCompile Include="x264_launcher.rc" /> <ResourceCompile Include="x264_launcher.rc" />
</ItemGroup> </ItemGroup>
<ItemGroup>
<Object Include="asm\cpu-detect.obj" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets"> <ImportGroup Label="ExtensionTargets">
</ImportGroup> </ImportGroup>

View File

@ -19,6 +19,9 @@
<Filter Include="Generated Files"> <Filter Include="Generated Files">
<UniqueIdentifier>{961e9f99-8107-45a2-984d-188819a67e8e}</UniqueIdentifier> <UniqueIdentifier>{961e9f99-8107-45a2-984d-188819a67e8e}</UniqueIdentifier>
</Filter> </Filter>
<Filter Include="Assembly">
<UniqueIdentifier>{2c9c8836-2259-4412-894e-7cc32bef99de}</UniqueIdentifier>
</Filter>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<None Include="ReadMe.txt" /> <None Include="ReadMe.txt" />
@ -142,4 +145,9 @@
<Filter>Resource Files</Filter> <Filter>Resource Files</Filter>
</ResourceCompile> </ResourceCompile>
</ItemGroup> </ItemGroup>
<ItemGroup>
<Object Include="asm\cpu-detect.obj">
<Filter>Assembly</Filter>
</Object>
</ItemGroup>
</Project> </Project>