diff --git a/neo/CMakeLists.txt b/neo/CMakeLists.txt index 83dff706..45b50f89 100644 --- a/neo/CMakeLists.txt +++ b/neo/CMakeLists.txt @@ -632,7 +632,28 @@ file(GLOB TIMIDITY_INCLUDES libs/timidity/*.h) file(GLOB TIMIDITY_SOURCES libs/timidity/*.cpp) file(GLOB_RECURSE WIN32_INCLUDES sys/win32/*.h) -file(GLOB_RECURSE WIN32_SOURCES sys/win32/*.cpp) +#file(GLOB_RECURSE WIN32_SOURCES sys/win32/*.cpp) + +set(WIN32_SOURCES + sys/win32/win_achievements.cpp + sys/win32/win_glimp.cpp + sys/win32/win_input.cpp + sys/win32/win_localuser.cpp + sys/win32/win_main.cpp + sys/win32/win_net.cpp + sys/win32/win_qgl.cpp + sys/win32/win_savegame.cpp + sys/win32/win_session_local.cpp + sys/win32/win_shared.cpp + sys/win32/win_signin.cpp + sys/win32/win_snd.cpp + sys/win32/win_syscon.cpp + sys/win32/win_taskkeyhook.cpp + sys/win32/win_wndproc.cpp) + +if(MSVC) + list(APPEND WIN32_SOURCES sys/win32/win_cpu.cpp) +endif() set(WIN32_RESOURCES # sys/win32/rc/res/BEVEL.BMP @@ -986,11 +1007,18 @@ if(MSVC) wsock32.lib ) else() + + include_directories(libs/sdl/include) + link_directories(${CMAKE_CURRENT_SOURCE_DIR}/libs/sdl2/libmingw32) + list(APPEND RBDOOM3_SOURCES ${SYS_INCLUDES} ${SYS_SOURCES} ${STUBAUDIO_INCLUDES} ${STUBAUDIO_SOURCES}) # TODO: if WIN32 + #list(REMOVE_ITEM WIN32_SOURCES sys/win32/win_cpu.cpp) + list(APPEND WIN32_SOURCES sys/sdl/sdl_cpu.cpp) + list(APPEND RBDOOM3_SOURCES ${WIN32_INCLUDES} ${WIN32_SOURCES} ${WIN32_RESOURCES}) @@ -1012,5 +1040,6 @@ else() iphlpapi winmm wsock32.lib + SDL2 ) endif() diff --git a/neo/idlib/ParallelJobList_JobHeaders.h b/neo/idlib/ParallelJobList_JobHeaders.h index 94a9deec..7724b048 100644 --- a/neo/idlib/ParallelJobList_JobHeaders.h +++ b/neo/idlib/ParallelJobList_JobHeaders.h @@ -44,6 +44,22 @@ If you have questions concerning this license or the applicable additional terms #include #include +// RB begin +#if defined(__MINGW32__) +//#include // RB: missing __analysis_assume + +#ifndef __analysis_assume +#define __analysis_assume( x ) +#endif + +#include // DG: _alloca16 needs that + +// RB: added for missing uintptr_t with MinGW +#include + +#endif +// RB end + #include // for UINT_PTR #ifdef _MSC_VER #include diff --git a/neo/idlib/SoftwareCache.cpp b/neo/idlib/SoftwareCache.cpp index fa12555e..aafcfb47 100644 --- a/neo/idlib/SoftwareCache.cpp +++ b/neo/idlib/SoftwareCache.cpp @@ -3,6 +3,7 @@ Doom 3 BFG Edition GPL Source Code Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company. +Copyright (C) 2012 Robert Beckebans This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code"). @@ -26,6 +27,12 @@ If you have questions concerning this license or the applicable additional terms =========================================================================== */ +// RB: missing __analysis_assume +#if defined(__MINGW32__) +#include +#endif +// RB end + #include "ParallelJobList_JobHeaders.h" #ifdef _WIN32 diff --git a/neo/idlib/sys/sys_includes.h b/neo/idlib/sys/sys_includes.h index a494b1ae..42f04ae0 100644 --- a/neo/idlib/sys/sys_includes.h +++ b/neo/idlib/sys/sys_includes.h @@ -40,6 +40,8 @@ If you have questions concerning this license or the applicable additional terms ================================================================================================ */ +// RB: windows specific stuff should only be set on Windows +#if defined(_WIN32) #define _ATL_CSTRING_EXPLICIT_CONSTRUCTORS // prevent auto literal to string conversion @@ -66,11 +68,16 @@ If you have questions concerning this license or the applicable additional terms #define MAPVK_VSC_TO_VK_EX 3 #endif -// RB: no available with MinGW +// RB begin +#if defined(__MINGW32__) +//#include // RB: missing __analysis_assume +// including breaks some STL crap ... + #ifndef __analysis_assume #define __analysis_assume( x ) #endif +#endif // RB end #endif @@ -100,6 +107,9 @@ If you have questions concerning this license or the applicable additional terms #pragma warning(disable : 4996) // unsafe string operations #endif // _MSC_VER +#endif // #if defined(_WIN32) +// RB end + #include // no malloc.h on mac or unix #include // for qgl.h #undef FindText // fix namespace pollution diff --git a/neo/renderer/jobs/dynamicshadowvolume/DynamicShadowVolume.cpp b/neo/renderer/jobs/dynamicshadowvolume/DynamicShadowVolume.cpp index 8656c637..e2d0ae45 100644 --- a/neo/renderer/jobs/dynamicshadowvolume/DynamicShadowVolume.cpp +++ b/neo/renderer/jobs/dynamicshadowvolume/DynamicShadowVolume.cpp @@ -31,9 +31,6 @@ If you have questions concerning this license or the applicable additional terms #include "../../../idlib/sys/sys_intrinsics.h" #include "../../../idlib/geometry/DrawVert_intrinsics.h" -#ifdef _WIN32 -#include // DG: _alloca16 needs that -#endif static const __m128i vector_int_neg_one = _mm_set_epi32( -1, -1, -1, -1 ); diff --git a/neo/renderer/jobs/prelightshadowvolume/PreLightShadowVolume.cpp b/neo/renderer/jobs/prelightshadowvolume/PreLightShadowVolume.cpp index 1e86bc7a..ddd7e5f8 100644 --- a/neo/renderer/jobs/prelightshadowvolume/PreLightShadowVolume.cpp +++ b/neo/renderer/jobs/prelightshadowvolume/PreLightShadowVolume.cpp @@ -28,9 +28,6 @@ If you have questions concerning this license or the applicable additional terms #include "PreLightShadowVolume_local.h" -#ifdef _WIN32 // DG: malloc.h needed for _alloca16 -#include -#endif /* =================== PreLightShadowVolumeJob diff --git a/neo/renderer/jobs/staticshadowvolume/StaticShadowVolume.cpp b/neo/renderer/jobs/staticshadowvolume/StaticShadowVolume.cpp index 31a13611..044f07c7 100644 --- a/neo/renderer/jobs/staticshadowvolume/StaticShadowVolume.cpp +++ b/neo/renderer/jobs/staticshadowvolume/StaticShadowVolume.cpp @@ -28,10 +28,6 @@ If you have questions concerning this license or the applicable additional terms #include "StaticShadowVolume_local.h" -#ifdef _WIN32 // DG: malloc.h needed for _alloca16 -#include -#endif - /* =================== StaticShadowVolumeJob diff --git a/neo/sys/sdl/sdl_cpu.cpp b/neo/sys/sdl/sdl_cpu.cpp new file mode 100644 index 00000000..5ec0e654 --- /dev/null +++ b/neo/sys/sdl/sdl_cpu.cpp @@ -0,0 +1,1119 @@ +/* +=========================================================================== + +Doom 3 BFG Edition GPL Source Code +Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company. +Copyright (C) 2012 Robert Beckebans + +This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code"). + +Doom 3 BFG Edition Source Code is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +Doom 3 BFG Edition Source Code is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Doom 3 BFG Edition Source Code. If not, see . + +In addition, the Doom 3 BFG Edition Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 BFG Edition Source Code. If not, please request a copy in writing from id Software at the address below. + +If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA. + +=========================================================================== +*/ +#include + +#pragma hdrstop +#include "../../idlib/precompiled.h" + +#include "win_local.h" + +#pragma warning(disable:4740) // warning C4740: flow in or out of inline asm code suppresses global optimization +#pragma warning(disable:4731) // warning C4731: 'XXX' : frame pointer register 'ebx' modified by inline assembly code + +/* +============================================================== + + Clock ticks + +============================================================== +*/ + +/* +================ +Sys_GetClockTicks +================ +*/ +double Sys_GetClockTicks() { + + // RB begin +#if defined(_MSC_VER) + unsigned long lo, hi; + + __asm { + push ebx + xor eax, eax + cpuid + rdtsc + mov lo, eax + mov hi, edx + pop ebx + } + return (double ) lo + (double) 0xFFFFFFFF * hi; + +#elif defined(__GNUC__) && defined( __i386__ ) + unsigned long lo, hi; + + __asm__ __volatile__( + "push %%ebx\n" \ + "xor %%eax,%%eax\n" \ + "cpuid\n" \ + "rdtsc\n" \ + "mov %%eax,%0\n" \ + "mov %%edx,%1\n" \ + "pop %%ebx\n" + : "=r"( lo ), "=r"( hi ) ); + return ( double ) lo + ( double ) 0xFFFFFFFF * hi; +#else +#error unsupported CPU +#endif + // RB end + +#endif +} + +/* +================ +Sys_ClockTicksPerSecond +================ +*/ +double Sys_ClockTicksPerSecond() { + static double ticks = 0; +#if 0 + + if ( !ticks ) { + LARGE_INTEGER li; + QueryPerformanceFrequency( &li ); + ticks = li.QuadPart; + } + +#else + + if ( !ticks ) { + HKEY hKey; + LPBYTE ProcSpeed; + DWORD buflen, ret; + + if ( !RegOpenKeyEx( HKEY_LOCAL_MACHINE, "HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\0", 0, KEY_READ, &hKey ) ) { + ProcSpeed = 0; + buflen = sizeof( ProcSpeed ); + ret = RegQueryValueEx( hKey, "~MHz", NULL, NULL, (LPBYTE) &ProcSpeed, &buflen ); + // If we don't succeed, try some other spellings. + if ( ret != ERROR_SUCCESS ) { + ret = RegQueryValueEx( hKey, "~Mhz", NULL, NULL, (LPBYTE) &ProcSpeed, &buflen ); + } + if ( ret != ERROR_SUCCESS ) { + ret = RegQueryValueEx( hKey, "~mhz", NULL, NULL, (LPBYTE) &ProcSpeed, &buflen ); + } + RegCloseKey( hKey ); + if ( ret == ERROR_SUCCESS ) { + ticks = (double) ((unsigned long)ProcSpeed) * 1000000; + } + } + } + +#endif + return ticks; +} + + +/* +============================================================== + + CPU + +============================================================== +*/ + +/* +================ +HasCPUID +================ +*/ +static bool HasCPUID() { + __asm + { + pushfd // save eflags + pop eax + test eax, 0x00200000 // check ID bit + jz set21 // bit 21 is not set, so jump to set_21 + and eax, 0xffdfffff // clear bit 21 + push eax // save new value in register + popfd // store new value in flags + pushfd + pop eax + test eax, 0x00200000 // check ID bit + jz good + jmp err // cpuid not supported +set21: + or eax, 0x00200000 // set ID bit + push eax // store new value + popfd // store new value in EFLAGS + pushfd + pop eax + test eax, 0x00200000 // if bit 21 is on + jnz good + jmp err + } + +err: + return false; +good: + return true; +} + +#define _REG_EAX 0 +#define _REG_EBX 1 +#define _REG_ECX 2 +#define _REG_EDX 3 + +/* +================ +CPUID +================ +*/ +static void CPUID( int func, unsigned regs[4] ) { + unsigned regEAX, regEBX, regECX, regEDX; + + __asm pusha + __asm mov eax, func + __asm __emit 00fh + __asm __emit 0a2h + __asm mov regEAX, eax + __asm mov regEBX, ebx + __asm mov regECX, ecx + __asm mov regEDX, edx + __asm popa + + regs[_REG_EAX] = regEAX; + regs[_REG_EBX] = regEBX; + regs[_REG_ECX] = regECX; + regs[_REG_EDX] = regEDX; +} + + +/* +================ +IsAMD +================ +*/ +static bool IsAMD() { + char pstring[16]; + char processorString[13]; + + // get name of processor + CPUID( 0, ( unsigned int * ) pstring ); + processorString[0] = pstring[4]; + processorString[1] = pstring[5]; + processorString[2] = pstring[6]; + processorString[3] = pstring[7]; + processorString[4] = pstring[12]; + processorString[5] = pstring[13]; + processorString[6] = pstring[14]; + processorString[7] = pstring[15]; + processorString[8] = pstring[8]; + processorString[9] = pstring[9]; + processorString[10] = pstring[10]; + processorString[11] = pstring[11]; + processorString[12] = 0; + + if ( strcmp( processorString, "AuthenticAMD" ) == 0 ) { + return true; + } + return false; +} + +/* +================ +HasCMOV +================ +*/ +static bool HasCMOV() { + unsigned regs[4]; + + // get CPU feature bits + CPUID( 1, regs ); + + // bit 15 of EDX denotes CMOV existence + if ( regs[_REG_EDX] & ( 1 << 15 ) ) { + return true; + } + return false; +} + +/* +================ +Has3DNow +================ +*/ +static bool Has3DNow() { + unsigned regs[4]; + + // check AMD-specific functions + CPUID( 0x80000000, regs ); + if ( regs[_REG_EAX] < 0x80000000 ) { + return false; + } + + // bit 31 of EDX denotes 3DNow! support + CPUID( 0x80000001, regs ); + if ( regs[_REG_EDX] & ( 1 << 31 ) ) { + return true; + } + + return false; +} + +/* +================ +HasMMX +================ +*/ +static bool HasMMX() { + unsigned regs[4]; + + // get CPU feature bits + CPUID( 1, regs ); + + // bit 23 of EDX denotes MMX existence + if ( regs[_REG_EDX] & ( 1 << 23 ) ) { + return true; + } + return false; +} + +/* +================ +HasSSE +================ +*/ +static bool HasSSE() { + unsigned regs[4]; + + // get CPU feature bits + CPUID( 1, regs ); + + // bit 25 of EDX denotes SSE existence + if ( regs[_REG_EDX] & ( 1 << 25 ) ) { + return true; + } + return false; +} + +/* +================ +HasSSE2 +================ +*/ +static bool HasSSE2() { + unsigned regs[4]; + + // get CPU feature bits + CPUID( 1, regs ); + + // bit 26 of EDX denotes SSE2 existence + if ( regs[_REG_EDX] & ( 1 << 26 ) ) { + return true; + } + return false; +} + +/* +================ +HasSSE3 +================ +*/ +static bool HasSSE3() { + unsigned regs[4]; + + // get CPU feature bits + CPUID( 1, regs ); + + // bit 0 of ECX denotes SSE3 existence + if ( regs[_REG_ECX] & ( 1 << 0 ) ) { + return true; + } + return false; +} + +/* +================ +LogicalProcPerPhysicalProc +================ +*/ +#define NUM_LOGICAL_BITS 0x00FF0000 // EBX[23:16] Bit 16-23 in ebx contains the number of logical + // processors per physical processor when execute cpuid with + // eax set to 1 +static unsigned char LogicalProcPerPhysicalProc() { + unsigned int regebx = 0; + __asm { + mov eax, 1 + cpuid + mov regebx, ebx + } + return (unsigned char) ((regebx & NUM_LOGICAL_BITS) >> 16); +} + +/* +================ +GetAPIC_ID +================ +*/ +#define INITIAL_APIC_ID_BITS 0xFF000000 // EBX[31:24] Bits 24-31 (8 bits) return the 8-bit unique + // initial APIC ID for the processor this code is running on. + // Default value = 0xff if HT is not supported +static unsigned char GetAPIC_ID() { + unsigned int regebx = 0; + __asm { + mov eax, 1 + cpuid + mov regebx, ebx + } + return (unsigned char) ((regebx & INITIAL_APIC_ID_BITS) >> 24); +} + +/* +================ +CPUCount + + logicalNum is the number of logical CPU per physical CPU + physicalNum is the total number of physical processor + returns one of the HT_* flags +================ +*/ +#define HT_NOT_CAPABLE 0 +#define HT_ENABLED 1 +#define HT_DISABLED 2 +#define HT_SUPPORTED_NOT_ENABLED 3 +#define HT_CANNOT_DETECT 4 + +int CPUCount( int &logicalNum, int &physicalNum ) { + int statusFlag; + SYSTEM_INFO info; + + physicalNum = 1; + logicalNum = 1; + statusFlag = HT_NOT_CAPABLE; + + info.dwNumberOfProcessors = 0; + GetSystemInfo (&info); + + // Number of physical processors in a non-Intel system + // or in a 32-bit Intel system with Hyper-Threading technology disabled + physicalNum = info.dwNumberOfProcessors; + + unsigned char HT_Enabled = 0; + + logicalNum = LogicalProcPerPhysicalProc(); + + if ( logicalNum >= 1 ) { // > 1 doesn't mean HT is enabled in the BIOS + HANDLE hCurrentProcessHandle; + DWORD dwProcessAffinity; + DWORD dwSystemAffinity; + DWORD dwAffinityMask; + + // Calculate the appropriate shifts and mask based on the + // number of logical processors. + + unsigned char i = 1, PHY_ID_MASK = 0xFF, PHY_ID_SHIFT = 0; + + while( i < logicalNum ) { + i *= 2; + PHY_ID_MASK <<= 1; + PHY_ID_SHIFT++; + } + + hCurrentProcessHandle = GetCurrentProcess(); + GetProcessAffinityMask( hCurrentProcessHandle, &dwProcessAffinity, &dwSystemAffinity ); + + // Check if available process affinity mask is equal to the + // available system affinity mask + if ( dwProcessAffinity != dwSystemAffinity ) { + statusFlag = HT_CANNOT_DETECT; + physicalNum = -1; + return statusFlag; + } + + dwAffinityMask = 1; + while ( dwAffinityMask != 0 && dwAffinityMask <= dwProcessAffinity ) { + // Check if this CPU is available + if ( dwAffinityMask & dwProcessAffinity ) { + if ( SetProcessAffinityMask( hCurrentProcessHandle, dwAffinityMask ) ) { + unsigned char APIC_ID, LOG_ID, PHY_ID; + + Sleep( 0 ); // Give OS time to switch CPU + + APIC_ID = GetAPIC_ID(); + LOG_ID = APIC_ID & ~PHY_ID_MASK; + PHY_ID = APIC_ID >> PHY_ID_SHIFT; + + if ( LOG_ID != 0 ) { + HT_Enabled = 1; + } + } + } + dwAffinityMask = dwAffinityMask << 1; + } + + // Reset the processor affinity + SetProcessAffinityMask( hCurrentProcessHandle, dwProcessAffinity ); + + if ( logicalNum == 1 ) { // Normal P4 : HT is disabled in hardware + statusFlag = HT_DISABLED; + } else { + if ( HT_Enabled ) { + // Total physical processors in a Hyper-Threading enabled system. + physicalNum /= logicalNum; + statusFlag = HT_ENABLED; + } else { + statusFlag = HT_SUPPORTED_NOT_ENABLED; + } + } + } + return statusFlag; +} + +/* +================ +HasHTT +================ +*/ +static bool HasHTT() { + unsigned regs[4]; + int logicalNum, physicalNum, HTStatusFlag; + + // get CPU feature bits + CPUID( 1, regs ); + + // bit 28 of EDX denotes HTT existence + if ( !( regs[_REG_EDX] & ( 1 << 28 ) ) ) { + return false; + } + + HTStatusFlag = CPUCount( logicalNum, physicalNum ); + if ( HTStatusFlag != HT_ENABLED ) { + return false; + } + return true; +} + +/* +================ +HasHTT +================ +*/ +static bool HasDAZ() { + __declspec(align(16)) unsigned char FXSaveArea[512]; + unsigned char *FXArea = FXSaveArea; + DWORD dwMask = 0; + unsigned regs[4]; + + // get CPU feature bits + CPUID( 1, regs ); + + // bit 24 of EDX denotes support for FXSAVE + if ( !( regs[_REG_EDX] & ( 1 << 24 ) ) ) { + return false; + } + + memset( FXArea, 0, sizeof( FXSaveArea ) ); + + __asm { + mov eax, FXArea + FXSAVE [eax] + } + + dwMask = *(DWORD *)&FXArea[28]; // Read the MXCSR Mask + return ( ( dwMask & ( 1 << 6 ) ) == ( 1 << 6 ) ); // Return if the DAZ bit is set +} + +/* +================================================================================================ + + CPU + +================================================================================================ +*/ + +/* +======================== +CountSetBits +Helper function to count set bits in the processor mask. +======================== +*/ +DWORD CountSetBits( ULONG_PTR bitMask ) { + DWORD LSHIFT = sizeof( ULONG_PTR ) * 8 - 1; + DWORD bitSetCount = 0; + ULONG_PTR bitTest = (ULONG_PTR)1 << LSHIFT; + + for ( DWORD i = 0; i <= LSHIFT; i++ ) { + bitSetCount += ( ( bitMask & bitTest ) ? 1 : 0 ); + bitTest /= 2; + } + + return bitSetCount; +} + +typedef BOOL (WINAPI *LPFN_GLPI)( PSYSTEM_LOGICAL_PROCESSOR_INFORMATION, PDWORD ); + +enum LOGICAL_PROCESSOR_RELATIONSHIP_LOCAL { + localRelationProcessorCore, + localRelationNumaNode, + localRelationCache, + localRelationProcessorPackage +}; + +struct cpuInfo_t { + int processorPackageCount; + int processorCoreCount; + int logicalProcessorCount; + int numaNodeCount; + struct cacheInfo_t { + int count; + int associativity; + int lineSize; + int size; + } cacheLevel[3]; +}; + +/* +======================== +GetCPUInfo +======================== +*/ +bool GetCPUInfo( cpuInfo_t & cpuInfo ) { + PSYSTEM_LOGICAL_PROCESSOR_INFORMATION buffer = NULL; + PSYSTEM_LOGICAL_PROCESSOR_INFORMATION ptr = NULL; + PCACHE_DESCRIPTOR Cache; + LPFN_GLPI glpi; + BOOL done = FALSE; + DWORD returnLength = 0; + DWORD byteOffset = 0; + + memset( & cpuInfo, 0, sizeof( cpuInfo ) ); + + glpi = (LPFN_GLPI)GetProcAddress( GetModuleHandle(TEXT("kernel32")), "GetLogicalProcessorInformation" ); + if ( NULL == glpi ) { + idLib::Printf( "\nGetLogicalProcessorInformation is not supported.\n" ); + return 0; + } + + while ( !done ) { + DWORD rc = glpi( buffer, &returnLength ); + + if ( FALSE == rc ) { + if ( GetLastError() == ERROR_INSUFFICIENT_BUFFER ) { + if ( buffer ) { + free( buffer ); + } + + buffer = (PSYSTEM_LOGICAL_PROCESSOR_INFORMATION)malloc( returnLength ); + } else { + idLib::Printf( "Sys_CPUCount error: %d\n", GetLastError() ); + return false; + } + } else { + done = TRUE; + } + } + + ptr = buffer; + + while ( byteOffset + sizeof(SYSTEM_LOGICAL_PROCESSOR_INFORMATION) <= returnLength ) { + switch ( (LOGICAL_PROCESSOR_RELATIONSHIP_LOCAL) ptr->Relationship ) { + case localRelationProcessorCore: + cpuInfo.processorCoreCount++; + + // A hyperthreaded core supplies more than one logical processor. + cpuInfo.logicalProcessorCount += CountSetBits( ptr->ProcessorMask ); + break; + + case localRelationNumaNode: + // Non-NUMA systems report a single record of this type. + cpuInfo.numaNodeCount++; + break; + + case localRelationCache: + // Cache data is in ptr->Cache, one CACHE_DESCRIPTOR structure for each cache. + Cache = &ptr->Cache; + if ( Cache->Level >= 1 && Cache->Level <= 3 ) { + int level = Cache->Level - 1; + if ( cpuInfo.cacheLevel[level].count > 0 ) { + cpuInfo.cacheLevel[level].count++; + } else { + cpuInfo.cacheLevel[level].associativity = Cache->Associativity; + cpuInfo.cacheLevel[level].lineSize = Cache->LineSize; + cpuInfo.cacheLevel[level].size = Cache->Size; + } + } + break; + + case localRelationProcessorPackage: + // Logical processors share a physical package. + cpuInfo.processorPackageCount++; + break; + + default: + idLib::Printf( "Error: Unsupported LOGICAL_PROCESSOR_RELATIONSHIP value.\n" ); + break; + } + byteOffset += sizeof( SYSTEM_LOGICAL_PROCESSOR_INFORMATION ); + ptr++; + } + + free( buffer ); + + return true; +} + +/* +======================== +Sys_GetCPUCacheSize +======================== +*/ +void Sys_GetCPUCacheSize( int level, int & count, int & size, int & lineSize ) { + assert( level >= 1 && level <= 3 ); + cpuInfo_t cpuInfo; + + GetCPUInfo( cpuInfo ); + + count = cpuInfo.cacheLevel[level - 1].count; + size = cpuInfo.cacheLevel[level - 1].size; + lineSize = cpuInfo.cacheLevel[level - 1].lineSize; +} + +/* +======================== +Sys_CPUCount + +numLogicalCPUCores - the number of logical CPU per core +numPhysicalCPUCores - the total number of cores per package +numCPUPackages - the total number of packages (physical processors) +======================== +*/ +void Sys_CPUCount( int & numLogicalCPUCores, int & numPhysicalCPUCores, int & numCPUPackages ) { + cpuInfo_t cpuInfo; + GetCPUInfo( cpuInfo ); + + numPhysicalCPUCores = cpuInfo.processorCoreCount; + numLogicalCPUCores = cpuInfo.logicalProcessorCount; + numCPUPackages = cpuInfo.processorPackageCount; +} + +/* +================ +Sys_GetCPUId +================ +*/ +cpuid_t Sys_GetCPUId() { + int flags; + + // verify we're at least a Pentium or 486 with CPUID support + if ( !HasCPUID() ) { + return CPUID_UNSUPPORTED; + } + + // check for an AMD + if ( IsAMD() ) { + flags = CPUID_AMD; + } else { + flags = CPUID_INTEL; + } + + // check for Multi Media Extensions + if ( HasMMX() ) { + flags |= CPUID_MMX; + } + + // check for 3DNow! + if ( Has3DNow() ) { + flags |= CPUID_3DNOW; + } + + // check for Streaming SIMD Extensions + if ( HasSSE() ) { + flags |= CPUID_SSE | CPUID_FTZ; + } + + // check for Streaming SIMD Extensions 2 + if ( HasSSE2() ) { + flags |= CPUID_SSE2; + } + + // check for Streaming SIMD Extensions 3 aka Prescott's New Instructions + if ( HasSSE3() ) { + flags |= CPUID_SSE3; + } + + // check for Hyper-Threading Technology + if ( HasHTT() ) { + flags |= CPUID_HTT; + } + + // check for Conditional Move (CMOV) and fast floating point comparison (FCOMI) instructions + if ( HasCMOV() ) { + flags |= CPUID_CMOV; + } + + // check for Denormals-Are-Zero mode + if ( HasDAZ() ) { + flags |= CPUID_DAZ; + } + + return (cpuid_t)flags; +} + + +/* +=============================================================================== + + FPU + +=============================================================================== +*/ + +typedef struct bitFlag_s { + char * name; + int bit; +} bitFlag_t; + +static byte fpuState[128], *statePtr = fpuState; +static char fpuString[2048]; +static bitFlag_t controlWordFlags[] = { + { "Invalid operation", 0 }, + { "Denormalized operand", 1 }, + { "Divide-by-zero", 2 }, + { "Numeric overflow", 3 }, + { "Numeric underflow", 4 }, + { "Inexact result (precision)", 5 }, + { "Infinity control", 12 }, + { "", 0 } +}; +static char *precisionControlField[] = { + "Single Precision (24-bits)", + "Reserved", + "Double Precision (53-bits)", + "Double Extended Precision (64-bits)" +}; +static char *roundingControlField[] = { + "Round to nearest", + "Round down", + "Round up", + "Round toward zero" +}; +static bitFlag_t statusWordFlags[] = { + { "Invalid operation", 0 }, + { "Denormalized operand", 1 }, + { "Divide-by-zero", 2 }, + { "Numeric overflow", 3 }, + { "Numeric underflow", 4 }, + { "Inexact result (precision)", 5 }, + { "Stack fault", 6 }, + { "Error summary status", 7 }, + { "FPU busy", 15 }, + { "", 0 } +}; + +/* +=============== +Sys_FPU_PrintStateFlags +=============== +*/ +int Sys_FPU_PrintStateFlags( char *ptr, int ctrl, int stat, int tags, int inof, int inse, int opof, int opse ) { + int i, length = 0; + + length += sprintf( ptr+length, "CTRL = %08x\n" + "STAT = %08x\n" + "TAGS = %08x\n" + "INOF = %08x\n" + "INSE = %08x\n" + "OPOF = %08x\n" + "OPSE = %08x\n" + "\n", + ctrl, stat, tags, inof, inse, opof, opse ); + + length += sprintf( ptr+length, "Control Word:\n" ); + for ( i = 0; controlWordFlags[i].name[0]; i++ ) { + length += sprintf( ptr+length, " %-30s = %s\n", controlWordFlags[i].name, ( ctrl & ( 1 << controlWordFlags[i].bit ) ) ? "true" : "false" ); + } + length += sprintf( ptr+length, " %-30s = %s\n", "Precision control", precisionControlField[(ctrl>>8)&3] ); + length += sprintf( ptr+length, " %-30s = %s\n", "Rounding control", roundingControlField[(ctrl>>10)&3] ); + + length += sprintf( ptr+length, "Status Word:\n" ); + for ( i = 0; statusWordFlags[i].name[0]; i++ ) { + ptr += sprintf( ptr+length, " %-30s = %s\n", statusWordFlags[i].name, ( stat & ( 1 << statusWordFlags[i].bit ) ) ? "true" : "false" ); + } + length += sprintf( ptr+length, " %-30s = %d%d%d%d\n", "Condition code", (stat>>8)&1, (stat>>9)&1, (stat>>10)&1, (stat>>14)&1 ); + length += sprintf( ptr+length, " %-30s = %d\n", "Top of stack pointer", (stat>>11)&7 ); + + return length; +} + +/* +=============== +Sys_FPU_StackIsEmpty +=============== +*/ +bool Sys_FPU_StackIsEmpty() { + __asm { + mov eax, statePtr + fnstenv [eax] + mov eax, [eax+8] + xor eax, 0xFFFFFFFF + and eax, 0x0000FFFF + jz empty + } + return false; +empty: + return true; +} + +/* +=============== +Sys_FPU_ClearStack +=============== +*/ +void Sys_FPU_ClearStack() { + __asm { + mov eax, statePtr + fnstenv [eax] + mov eax, [eax+8] + xor eax, 0xFFFFFFFF + mov edx, (3<<14) + emptyStack: + mov ecx, eax + and ecx, edx + jz done + fstp st + shr edx, 2 + jmp emptyStack + done: + } +} + +/* +=============== +Sys_FPU_GetState + + gets the FPU state without changing the state +=============== +*/ +const char *Sys_FPU_GetState() { + double fpuStack[8] = { 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 }; + double *fpuStackPtr = fpuStack; + int i, numValues; + char *ptr; + + __asm { + mov esi, statePtr + mov edi, fpuStackPtr + fnstenv [esi] + mov esi, [esi+8] + xor esi, 0xFFFFFFFF + mov edx, (3<<14) + xor eax, eax + mov ecx, esi + and ecx, edx + jz done + fst qword ptr [edi+0] + inc eax + shr edx, 2 + mov ecx, esi + and ecx, edx + jz done + fxch st(1) + fst qword ptr [edi+8] + inc eax + fxch st(1) + shr edx, 2 + mov ecx, esi + and ecx, edx + jz done + fxch st(2) + fst qword ptr [edi+16] + inc eax + fxch st(2) + shr edx, 2 + mov ecx, esi + and ecx, edx + jz done + fxch st(3) + fst qword ptr [edi+24] + inc eax + fxch st(3) + shr edx, 2 + mov ecx, esi + and ecx, edx + jz done + fxch st(4) + fst qword ptr [edi+32] + inc eax + fxch st(4) + shr edx, 2 + mov ecx, esi + and ecx, edx + jz done + fxch st(5) + fst qword ptr [edi+40] + inc eax + fxch st(5) + shr edx, 2 + mov ecx, esi + and ecx, edx + jz done + fxch st(6) + fst qword ptr [edi+48] + inc eax + fxch st(6) + shr edx, 2 + mov ecx, esi + and ecx, edx + jz done + fxch st(7) + fst qword ptr [edi+56] + inc eax + fxch st(7) + done: + mov numValues, eax + } + + int ctrl = *(int *)&fpuState[0]; + int stat = *(int *)&fpuState[4]; + int tags = *(int *)&fpuState[8]; + int inof = *(int *)&fpuState[12]; + int inse = *(int *)&fpuState[16]; + int opof = *(int *)&fpuState[20]; + int opse = *(int *)&fpuState[24]; + + ptr = fpuString; + ptr += sprintf( ptr,"FPU State:\n" + "num values on stack = %d\n", numValues ); + for ( i = 0; i < 8; i++ ) { + ptr += sprintf( ptr, "ST%d = %1.10e\n", i, fpuStack[i] ); + } + + Sys_FPU_PrintStateFlags( ptr, ctrl, stat, tags, inof, inse, opof, opse ); + + return fpuString; +} + +/* +=============== +Sys_FPU_EnableExceptions +=============== +*/ +void Sys_FPU_EnableExceptions( int exceptions ) { + __asm { + mov eax, statePtr + mov ecx, exceptions + and cx, 63 + not cx + fnstcw word ptr [eax] + mov bx, word ptr [eax] + or bx, 63 + and bx, cx + mov word ptr [eax], bx + fldcw word ptr [eax] + } +} + +/* +=============== +Sys_FPU_SetPrecision +=============== +*/ +void Sys_FPU_SetPrecision( int precision ) { + short precisionBitTable[4] = { 0, 1, 3, 0 }; + short precisionBits = precisionBitTable[precision & 3] << 8; + short precisionMask = ~( ( 1 << 9 ) | ( 1 << 8 ) ); + + __asm { + mov eax, statePtr + mov cx, precisionBits + fnstcw word ptr [eax] + mov bx, word ptr [eax] + and bx, precisionMask + or bx, cx + mov word ptr [eax], bx + fldcw word ptr [eax] + } +} + +/* +================ +Sys_FPU_SetRounding +================ +*/ +void Sys_FPU_SetRounding( int rounding ) { + short roundingBitTable[4] = { 0, 1, 2, 3 }; + short roundingBits = roundingBitTable[rounding & 3] << 10; + short roundingMask = ~( ( 1 << 11 ) | ( 1 << 10 ) ); + + __asm { + mov eax, statePtr + mov cx, roundingBits + fnstcw word ptr [eax] + mov bx, word ptr [eax] + and bx, roundingMask + or bx, cx + mov word ptr [eax], bx + fldcw word ptr [eax] + } +} + +/* +================ +Sys_FPU_SetDAZ +================ +*/ +void Sys_FPU_SetDAZ( bool enable ) { + DWORD dwData; + + _asm { + movzx ecx, byte ptr enable + and ecx, 1 + shl ecx, 6 + STMXCSR dword ptr dwData + mov eax, dwData + and eax, ~(1<<6) // clear DAX bit + or eax, ecx // set the DAZ bit + mov dwData, eax + LDMXCSR dword ptr dwData + } +} + +/* +================ +Sys_FPU_SetFTZ +================ +*/ +void Sys_FPU_SetFTZ( bool enable ) { + DWORD dwData; + + _asm { + movzx ecx, byte ptr enable + and ecx, 1 + shl ecx, 15 + STMXCSR dword ptr dwData + mov eax, dwData + and eax, ~(1<<15) // clear FTZ bit + or eax, ecx // set the FTZ bit + mov dwData, eax + LDMXCSR dword ptr dwData + } +} diff --git a/neo/sys/win32/win_cpu.cpp b/neo/sys/win32/win_cpu.cpp index 65d819fb..274a572f 100644 --- a/neo/sys/win32/win_cpu.cpp +++ b/neo/sys/win32/win_cpu.cpp @@ -57,6 +57,8 @@ double Sys_GetClockTicks() { #else + // RB begin +#if defined(_MSC_VER) unsigned long lo, hi; __asm { @@ -70,6 +72,24 @@ double Sys_GetClockTicks() { } return (double ) lo + (double) 0xFFFFFFFF * hi; +#elif defined(__GNUC__) && defined( __i386__ ) + unsigned long lo, hi; + + __asm__ __volatile__( + "push %%ebx\n" \ + "xor %%eax,%%eax\n" \ + "cpuid\n" \ + "rdtsc\n" \ + "mov %%eax,%0\n" \ + "mov %%edx,%1\n" \ + "pop %%ebx\n" + : "=r"( lo ), "=r"( hi ) ); + return ( double ) lo + ( double ) 0xFFFFFFFF * hi; +#else +#error unsupported CPU +#endif + // RB end + #endif } diff --git a/neo/sys/win32/win_glimp.cpp b/neo/sys/win32/win_glimp.cpp index 57c424d2..6fd14f3e 100644 --- a/neo/sys/win32/win_glimp.cpp +++ b/neo/sys/win32/win_glimp.cpp @@ -882,6 +882,20 @@ void DumpAllDisplayDevices() common->Printf( "\n" ); } +// RB: moved out of R_GetModeListForDisplay +class idSort_VidMode : public idSort_Quick< vidMode_t, idSort_VidMode > +{ +public: + int Compare( const vidMode_t& a, const vidMode_t& b ) const + { + int wd = a.width - b.width; + int hd = a.height - b.height; + int fd = a.displayHz - b.displayHz; + return ( hd != 0 ) ? hd : ( wd != 0 ) ? wd : fd; + } +}; +// RB end + /* ==================== R_GetModeListForDisplay @@ -979,21 +993,9 @@ bool R_GetModeListForDisplay( const int requestedDisplayNum, idList& mode.displayHz = devmode.dmDisplayFrequency; modeList.AddUnique( mode ); } + if( modeList.Num() > 0 ) { - - class idSort_VidMode : public idSort_Quick< vidMode_t, idSort_VidMode > - { - public: - int Compare( const vidMode_t& a, const vidMode_t& b ) const - { - int wd = a.width - b.width; - int hd = a.height - b.height; - int fd = a.displayHz - b.displayHz; - return ( hd != 0 ) ? hd : ( wd != 0 ) ? wd : fd; - } - }; - // sort with lowest resolution first modeList.SortWithTemplate( idSort_VidMode() ); diff --git a/neo/sys/win32/win_input.cpp b/neo/sys/win32/win_input.cpp index 6373f496..8812ac98 100644 --- a/neo/sys/win32/win_input.cpp +++ b/neo/sys/win32/win_input.cpp @@ -3,6 +3,7 @@ Doom 3 BFG Edition GPL Source Code Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company. +Copyright (C) 2012 Robert Beckebans This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code"). @@ -683,34 +684,37 @@ int Sys_PollMouseInputEvents( int mouseEvents[MAX_MOUSE_EVENTS][2] ) } else { - // DG: FIXME: mingw doesn't like using the (rather ugly) DIMOFS_* macros in switch/case.. - switch( polled_didod[i].dwOfs ) + // RB: replaced switch enum for MinGW + int diaction = polled_didod[i].dwOfs; + + if( diaction == DIMOFS_X ) { - case DIMOFS_X: - mouseEvents[i][0] = M_DELTAX; - mouseEvents[i][1] = polled_didod[i].dwData; - Sys_QueEvent( SE_MOUSE, polled_didod[i].dwData, 0, 0, NULL, 0 ); - break; - case DIMOFS_Y: - mouseEvents[i][0] = M_DELTAY; - mouseEvents[i][1] = polled_didod[i].dwData; - Sys_QueEvent( SE_MOUSE, 0, polled_didod[i].dwData, 0, NULL, 0 ); - break; - case DIMOFS_Z: - mouseEvents[i][0] = M_DELTAZ; - mouseEvents[i][1] = ( int )polled_didod[i].dwData / WHEEL_DELTA; - { - const int value = ( int )polled_didod[i].dwData / WHEEL_DELTA; - const int key = value < 0 ? K_MWHEELDOWN : K_MWHEELUP; - const int iterations = abs( value ); - for( int i = 0; i < iterations; i++ ) - { - Sys_QueEvent( SE_KEY, key, true, 0, NULL, 0 ); - Sys_QueEvent( SE_KEY, key, false, 0, NULL, 0 ); - } - } - break; + mouseEvents[i][0] = M_DELTAX; + mouseEvents[i][1] = polled_didod[i].dwData; + Sys_QueEvent( SE_MOUSE, polled_didod[i].dwData, 0, 0, NULL, 0 ); } + else if( diaction == DIMOFS_Y ) + { + mouseEvents[i][0] = M_DELTAY; + mouseEvents[i][1] = polled_didod[i].dwData; + Sys_QueEvent( SE_MOUSE, 0, polled_didod[i].dwData, 0, NULL, 0 ); + } + else if( diaction == DIMOFS_Z ) + { + mouseEvents[i][0] = M_DELTAZ; + mouseEvents[i][1] = ( int )polled_didod[i].dwData / WHEEL_DELTA; + { + const int value = ( int )polled_didod[i].dwData / WHEEL_DELTA; + const int key = value < 0 ? K_MWHEELDOWN : K_MWHEELUP; + const int iterations = abs( value ); + for( int i = 0; i < iterations; i++ ) + { + Sys_QueEvent( SE_KEY, key, true, 0, NULL, 0 ); + Sys_QueEvent( SE_KEY, key, false, 0, NULL, 0 ); + } + } + } + // RB end } } diff --git a/neo/sys/win32/win_main.cpp b/neo/sys/win32/win_main.cpp index b79f56c1..53fcb668 100644 --- a/neo/sys/win32/win_main.cpp +++ b/neo/sys/win32/win_main.cpp @@ -1264,34 +1264,6 @@ void Win_Frame() { } } -extern "C" { void _chkstk( int size ); }; -void clrstk(); - -/* -==================== -TestChkStk -==================== -*/ -void TestChkStk() { - int buffer[0x1000]; - - buffer[0] = 1; -} - -/* -==================== -HackChkStk -==================== -*/ -void HackChkStk() { - DWORD old; - VirtualProtect( _chkstk, 6, PAGE_EXECUTE_READWRITE, &old ); - *(byte *)_chkstk = 0xe9; - *(int *)((int)_chkstk+1) = (int)clrstk - (int)_chkstk - 5; - - TestChkStk(); -} - /* ==================== GetExceptionCodeInfo @@ -1549,42 +1521,6 @@ int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLin return 0; } -/* -==================== -clrstk - -I tried to get the run time to call this at every function entry, but -==================== -*/ -static int parmBytes; -__declspec( naked ) void clrstk() { - // eax = bytes to add to stack - __asm { - mov [parmBytes],eax - neg eax ; compute new stack pointer in eax - add eax,esp - add eax,4 - xchg eax,esp - mov eax,dword ptr [eax] ; copy the return address - push eax - - ; clear to zero - push edi - push ecx - mov edi,esp - add edi,12 - mov ecx,[parmBytes] - shr ecx,2 - xor eax,eax - cld - rep stosd - pop ecx - pop edi - - ret - } -} - /* ================== idSysLocal::OpenURL diff --git a/neo/sys/win32/win_snd.cpp b/neo/sys/win32/win_snd.cpp index 3f90a7ba..22c76350 100644 --- a/neo/sys/win32/win_snd.cpp +++ b/neo/sys/win32/win_snd.cpp @@ -29,7 +29,9 @@ If you have questions concerning this license or the applicable additional terms #include "../../idlib/precompiled.h" // RB: not available on Windows 8 SDK -#if (_WIN32_WINNT < 0x0602 /*_WIN32_WINNT_WIN8*/) +#if defined(__MINGW32__) +#include +#elif (_WIN32_WINNT < 0x0602 /*_WIN32_WINNT_WIN8*/) #include #endif // RB end