diff --git a/panda/src/display/displayInformation.cxx b/panda/src/display/displayInformation.cxx index f329d13689..aa29822191 100644 --- a/panda/src/display/displayInformation.cxx +++ b/panda/src/display/displayInformation.cxx @@ -30,6 +30,12 @@ DisplayInformation:: if (_display_mode_array != NULL) { delete _display_mode_array; } + if (_cpu_id_data != NULL) { + delete _cpu_id_data; + } + if (_cpu_brand_string != NULL) { + delete _cpu_brand_string; + } } //////////////////////////////////////////////////////////////////// @@ -94,8 +100,20 @@ DisplayInformation() { _vendor_id = 0; _device_id = 0; - + + _cpu_id_version = 1; + _cpu_id_size = 0; + _cpu_id_data = 0; + + _cpu_vendor_string = 0; + _cpu_brand_string = 0; + _cpu_version_information = 0; + _cpu_brand_index = 0; + + _cpu_frequency = 0; + _get_memory_information_function = 0; + _cpu_time_function = 0; } //////////////////////////////////////////////////////////////////// @@ -413,3 +431,123 @@ int DisplayInformation:: get_device_id() { return _device_id; } + +//////////////////////////////////////////////////////////////////// +// Function: DisplayInformation::get_cpu_id_version +// Access: Published +// Description: +//////////////////////////////////////////////////////////////////// +int DisplayInformation:: +get_cpu_id_version() { + return _cpu_id_version; +} + +//////////////////////////////////////////////////////////////////// +// Function: DisplayInformation::get_cpu_id_size +// Access: Published +// Description: Returns the number of 32-bit values for cpu id +// binary data. +//////////////////////////////////////////////////////////////////// +int DisplayInformation:: +get_cpu_id_size() { + return _cpu_id_size; +} + +//////////////////////////////////////////////////////////////////// +// Function: DisplayInformation::get_cpu_id_data +// Access: Published +// Description: Returns part of cpu id binary data based on the +// index. +//////////////////////////////////////////////////////////////////// +unsigned int DisplayInformation:: +get_cpu_id_data(int index) { + unsigned int data; + + data = 0; + if (index >= 0 && index < _cpu_id_size) { + data = _cpu_id_data [index]; + } + + return data; +} + +//////////////////////////////////////////////////////////////////// +// Function: DisplayInformation::get_cpu_vendor_string +// Access: Published +// Description: +//////////////////////////////////////////////////////////////////// +char *DisplayInformation:: +get_cpu_vendor_string() { + char *string; + + string = _cpu_vendor_string; + if (string == 0) { + string = ""; + } + + return string; +} + +//////////////////////////////////////////////////////////////////// +// Function: DisplayInformation::get_cpu_brand_string +// Access: Published +// Description: +//////////////////////////////////////////////////////////////////// +char *DisplayInformation:: +get_cpu_brand_string() { + char *string; + + string = _cpu_brand_string; + if (string == 0) { + string = ""; + } + + return string; +} + +//////////////////////////////////////////////////////////////////// +// Function: DisplayInformation::get_cpu_version_information +// Access: Published +// Description: +//////////////////////////////////////////////////////////////////// +unsigned int DisplayInformation:: +get_cpu_version_information() { + return _cpu_version_information; +} + +//////////////////////////////////////////////////////////////////// +// Function: DisplayInformation::get_cpu_brand_index +// Access: Published +// Description: +//////////////////////////////////////////////////////////////////// +unsigned int DisplayInformation:: +get_cpu_brand_index() { + return _cpu_brand_index; +} + +//////////////////////////////////////////////////////////////////// +// Function: DisplayInformation::get_cpu_frequency +// Access: Published +// Description: +//////////////////////////////////////////////////////////////////// +PN_uint64 DisplayInformation:: +get_cpu_frequency() { + return _cpu_frequency; +} + +//////////////////////////////////////////////////////////////////// +// Function: DisplayInformation::get_cpu_time +// Access: Published +// Description: +//////////////////////////////////////////////////////////////////// +PN_uint64 DisplayInformation:: +get_cpu_time() { + PN_uint64 cpu_time; + + cpu_time = 0; + if (_cpu_time_function) { + cpu_time = _cpu_time_function(); + } + + return cpu_time; +} diff --git a/panda/src/display/displayInformation.h b/panda/src/display/displayInformation.h index 90d7fe96b1..527d272755 100644 --- a/panda/src/display/displayInformation.h +++ b/panda/src/display/displayInformation.h @@ -85,6 +85,18 @@ PUBLISHED: int get_vendor_id(); int get_device_id(); + + int get_cpu_id_version(); + int get_cpu_id_size(); + unsigned int get_cpu_id_data(int index); + + char *get_cpu_vendor_string(); + char *get_cpu_brand_string(); + unsigned int get_cpu_version_information(); + unsigned int get_cpu_brand_index(); + + PN_uint64 get_cpu_frequency(); + PN_uint64 get_cpu_time(); public: DetectionState _state; @@ -116,8 +128,20 @@ public: int _vendor_id; int _device_id; + + int _cpu_id_version; + int _cpu_id_size; + unsigned int *_cpu_id_data; + + char *_cpu_vendor_string; + char *_cpu_brand_string; + unsigned int _cpu_version_information; + unsigned int _cpu_brand_index; + PN_uint64 _cpu_frequency; + void (*_get_memory_information_function) (DisplayInformation *display_information); + PN_uint64 (*_cpu_time_function) (void); }; #endif diff --git a/panda/src/windisplay/winGraphicsPipe.cxx b/panda/src/windisplay/winGraphicsPipe.cxx index 65150dfbe8..58702c8dcb 100644 --- a/panda/src/windisplay/winGraphicsPipe.cxx +++ b/panda/src/windisplay/winGraphicsPipe.cxx @@ -100,6 +100,547 @@ void get_memory_information (DisplayInformation *display_information) } } +typedef union +{ + PN_uint64 long_integer; +} +LONG_INTEGER; + +PN_uint64 cpu_time_function (void) { + LONG_INTEGER long_integer; + LONG_INTEGER *long_integer_pointer; + + long_integer_pointer = &long_integer; + + __asm + { + mov ebx,[long_integer_pointer] + rdtsc + mov [ebx + 0], eax + mov [ebx + 4], edx + } + + return long_integer.long_integer; +} + +typedef union +{ + struct + { + union + { + struct + { + unsigned char al; + unsigned char ah; + }; + unsigned int eax; + }; + unsigned int ebx; + unsigned int ecx; + unsigned int edx; + }; +} +CPU_ID_REGISTERS; + +typedef struct +{ + union + { + struct + { + int maximum_cpu_id_input; + char cpu_vendor [16]; + }; + + CPU_ID_REGISTERS cpu_id_registers_0; + }; + + union + { + CPU_ID_REGISTERS cpu_id_registers_1; + + struct + { + // eax + union + { + unsigned int eax; + unsigned int version_information; + struct + { + unsigned int stepping_id : 4; + unsigned int model : 4; + unsigned int family : 4; + unsigned int processor_type : 2; + unsigned int reserved_0 : 2; + unsigned int extended_model_id : 4; + unsigned int extended_family_id : 8; + unsigned int reserved_1 : 4; + }; + }; + + // ebx + union + { + unsigned int ebx; + struct + { + unsigned int brand_index : 8; + unsigned int clflush : 8; + unsigned int maximum_logical_processors : 8; + unsigned int initial_apic_id : 8; + }; + }; + + // ecx + union + { + unsigned int ecx; + struct + { + unsigned int sse3 : 1; + unsigned int reserved_1_to_2 : 2; + unsigned int monitor : 1; + unsigned int ds_cpl : 1; + unsigned int vmx : 1; + unsigned int reserved_6 : 1; + unsigned int est : 1; + unsigned int tm2 : 1; + unsigned int reserved_9 : 1; + unsigned int cnxt_id : 1; + unsigned int reserved_11_to_12 : 2; + unsigned int cmpxchg16b : 1; + unsigned int xtpr_disable : 1; + unsigned int reserved_15_to_31 : 17; + }; + }; + + // edx + union + { + unsigned int edx; + struct + { + unsigned int fpu : 1; + unsigned int vme : 1; + unsigned int de : 1; + unsigned int pse : 1; + unsigned int tsc : 1; + unsigned int msr : 1; + unsigned int pae : 1; + unsigned int mce : 1; + unsigned int cx8 : 1; + unsigned int apic : 1; + unsigned int reserved_10 : 1; + unsigned int sep : 1; + unsigned int mtrr : 1; + unsigned int pge : 1; + unsigned int mca : 1; + unsigned int cmov : 1; + unsigned int pat : 1; + unsigned int pse_36 : 1; + unsigned int psn : 1; + unsigned int cflush : 1; + unsigned int reserved_20 : 1; + unsigned int ds : 1; + unsigned int acpi : 1; + unsigned int mmx : 1; + unsigned int fxsr : 1; + unsigned int sse : 1; + unsigned int sse2 : 1; + unsigned int ss : 1; + unsigned int htt : 1; + unsigned int tm : 1; + unsigned int reserved_30 : 1; + unsigned int pbe : 1; + }; + }; + }; + }; + + #define MAXIMUM_2 8 + #define MAXIMUM_CHARACTERS (MAXIMUM_2 * sizeof (CPU_ID_REGISTERS)) + + union + { + CPU_ID_REGISTERS cpu_id_registers_2; + unsigned char character_array_2 [MAXIMUM_CHARACTERS]; + CPU_ID_REGISTERS cpu_id_registers_2_array [MAXIMUM_2]; + }; + + union + { + CPU_ID_REGISTERS cpu_id_registers_0x80000000; + }; + + union + { + CPU_ID_REGISTERS cpu_id_registers_0x80000001; + }; + + union + { + char cpu_brand_string [sizeof (CPU_ID_REGISTERS) * 3]; + struct + { + CPU_ID_REGISTERS cpu_id_registers_0x80000002; + CPU_ID_REGISTERS cpu_id_registers_0x80000003; + CPU_ID_REGISTERS cpu_id_registers_0x80000004; + }; + }; + + union + { + struct + { + // eax + union + { + unsigned int eax; + }; + + // ebx + union + { + unsigned int ebx; + }; + + // ecx + union + { + unsigned int ecx; + struct + { + unsigned int l1_data_cache_line_size : 8; + unsigned int l1_data_reserved_8_to_15 : 8; + unsigned int l1_data_associativity : 8; + unsigned int l1_data_cache_size : 8; + }; + }; + + // edx + union + { + unsigned int edx; + struct + { + unsigned int l1_code_cache_line_size : 8; + unsigned int l1_code_reserved_8_to_15 : 8; + unsigned int l1_code_associativity : 8; + unsigned int l1_code_cache_size : 8; + }; + }; + }; + CPU_ID_REGISTERS cpu_id_registers_0x80000005; + }; + + union + { + struct + { + // eax + union + { + unsigned int eax; + }; + + // ebx + union + { + unsigned int ebx; + }; + + // ecx + union + { + unsigned int ecx; + struct + { + unsigned int l2_cache_line_size : 8; + unsigned int l2_reserved_8_to_11 : 4; + unsigned int l2_associativity : 4; + unsigned int l2_cache_size : 16; + }; + }; + + // edx + union + { + unsigned int edx; + }; + }; + CPU_ID_REGISTERS cpu_id_registers_0x80000006; + }; + + union + { + struct + { + // eax + union + { + unsigned int eax; + }; + + // ebx + union + { + unsigned int ebx; + }; + + // ecx + union + { + unsigned int ecx; + }; + + // edx + union + { + unsigned int edx; + }; + }; + CPU_ID_REGISTERS cpu_id_registers_0x80000008; + }; + + unsigned int cache_line_size; + unsigned int log_base_2_cache_line_size; +} +CPU_ID; + +typedef struct +{ + CPU_ID_REGISTERS cpu_id_registers_0; + CPU_ID_REGISTERS cpu_id_registers_1; + + CPU_ID_REGISTERS cpu_id_registers_0x80000000; + CPU_ID_REGISTERS cpu_id_registers_0x80000001; + CPU_ID_REGISTERS cpu_id_registers_0x80000002; + CPU_ID_REGISTERS cpu_id_registers_0x80000003; + CPU_ID_REGISTERS cpu_id_registers_0x80000004; + + CPU_ID_REGISTERS cpu_id_registers_0x80000006; + + CPU_ID_REGISTERS cpu_id_registers_0x80000008; +} +CPU_ID_BINARY_DATA; + +typedef struct +{ + union + { + CPU_ID_BINARY_DATA cpu_binary_data; + unsigned int data_array [sizeof (CPU_ID_BINARY_DATA) / 4]; + }; +} +CPU_ID_BINARY_DATA_ARRAY; + +void cpu_id_to_cpu_id_binary_data (CPU_ID *cpu_id, CPU_ID_BINARY_DATA *cpu_id_binary_data) { + + cpu_id_binary_data -> cpu_id_registers_0 = cpu_id -> cpu_id_registers_0; + cpu_id_binary_data -> cpu_id_registers_1 = cpu_id -> cpu_id_registers_1; + cpu_id_binary_data -> cpu_id_registers_0x80000000 = cpu_id -> cpu_id_registers_0x80000000; + cpu_id_binary_data -> cpu_id_registers_0x80000001 = cpu_id -> cpu_id_registers_0x80000001; + cpu_id_binary_data -> cpu_id_registers_0x80000002 = cpu_id -> cpu_id_registers_0x80000002; + cpu_id_binary_data -> cpu_id_registers_0x80000003 = cpu_id -> cpu_id_registers_0x80000003; + cpu_id_binary_data -> cpu_id_registers_0x80000004 = cpu_id -> cpu_id_registers_0x80000004; + cpu_id_binary_data -> cpu_id_registers_0x80000006 = cpu_id -> cpu_id_registers_0x80000006; + cpu_id_binary_data -> cpu_id_registers_0x80000008 = cpu_id -> cpu_id_registers_0x80000008; +} + +void cpu_id_binary_data_to_cpu_id (CPU_ID_BINARY_DATA *cpu_id_binary_data, CPU_ID *cpu_id) { + + memset (cpu_id, 0, sizeof (CPU_ID)); + + cpu_id -> cpu_id_registers_0 = cpu_id_binary_data -> cpu_id_registers_0; + cpu_id -> cpu_id_registers_1 = cpu_id_binary_data -> cpu_id_registers_1; + cpu_id -> cpu_id_registers_0x80000000 = cpu_id_binary_data -> cpu_id_registers_0x80000000; + cpu_id -> cpu_id_registers_0x80000001 = cpu_id_binary_data -> cpu_id_registers_0x80000001; + cpu_id -> cpu_id_registers_0x80000002 = cpu_id_binary_data -> cpu_id_registers_0x80000002; + cpu_id -> cpu_id_registers_0x80000003 = cpu_id_binary_data -> cpu_id_registers_0x80000003; + cpu_id -> cpu_id_registers_0x80000004 = cpu_id_binary_data -> cpu_id_registers_0x80000004; + cpu_id -> cpu_id_registers_0x80000006 = cpu_id_binary_data -> cpu_id_registers_0x80000006; + cpu_id -> cpu_id_registers_0x80000008 = cpu_id_binary_data -> cpu_id_registers_0x80000008; +} + +int cpuid (int input_eax, CPU_ID_REGISTERS *cpu_id_registers) { + int state; + + state = false; + __try + { + if (input_eax == 0) { + // the order of ecx and edx is swapped when saved to make a proper vendor string + __asm + { + mov eax, [input_eax] + mov edi, [cpu_id_registers] + + cpuid + + mov [edi + 0], eax + mov [edi + 4], ebx + mov [edi + 8], edx + mov [edi + 12], ecx + } + } + else { + __asm + { + mov eax, [input_eax] + mov edi, [cpu_id_registers] + + cpuid + + mov [edi + 0], eax + mov [edi + 4], ebx + mov [edi + 8], ecx + mov [edi + 12], edx + } + } + + state = true; + } + __except (1) + { + state = false; + } + + return state; +} + +void parse_cpu_id (CPU_ID *cpu_id) { + + printf ("CPUID\n"); + printf (" vendor = %s \n", cpu_id -> cpu_vendor); + printf (" brand string %s \n", cpu_id -> cpu_brand_string); + printf (" maximum_cpu_id_input = %u \n", cpu_id -> maximum_cpu_id_input); + printf (" maximum extended information = 0x%X \n", cpu_id -> cpu_id_registers_0x80000000.eax); + + printf (" MMX = %u \n", cpu_id -> mmx); + printf (" SSE = %u \n", cpu_id -> sse); + printf (" SSE2 = %u \n", cpu_id -> sse2); + printf (" SSE3 = %u \n", cpu_id -> sse3); + + printf (" EST = %u \n", cpu_id -> est); + + if (cpu_id -> maximum_cpu_id_input >= 1) { + printf (" version_information \n"); + printf (" stepping_id %u \n", cpu_id -> stepping_id); + printf (" model %u \n", cpu_id -> model); + printf (" family %u \n", cpu_id -> family); + printf (" processor_type %u \n", cpu_id -> processor_type); + printf (" extended_model_id %u \n", cpu_id -> extended_model_id); + printf (" extended_family_id %u \n", cpu_id -> extended_family_id); + + printf (" brand_index %u \n", cpu_id -> brand_index); + printf (" clflush %u \n", cpu_id -> clflush); + printf (" maximum_logical_processors %u \n", cpu_id -> maximum_logical_processors); + printf (" initial_apic_id %u \n", cpu_id -> initial_apic_id); + +// printf (" cache_line_size %u \n", cpu_id -> cache_line_size); +// printf (" log_base_2_cache_line_size %u \n", cpu_id -> log_base_2_cache_line_size); + } + + if (cpu_id -> cpu_id_registers_0x80000000.eax >= 0x80000005) { + printf (" l1_data_cache_line_size %d \n", cpu_id -> l1_data_cache_line_size); + printf (" l1_data_associativity %d \n", cpu_id -> l1_data_associativity); + printf (" l1_data_cache_size %dK \n", cpu_id -> l1_data_cache_size); + + printf (" l1_code_cache_line_size %d \n", cpu_id -> l1_code_cache_line_size); + printf (" l1_code_associativity %d \n", cpu_id -> l1_code_associativity); + printf (" l1_code_cache_size %dK \n", cpu_id -> l1_code_cache_size); + } + + if (cpu_id -> cpu_id_registers_0x80000000.eax >= 0x80000006) { + printf (" l2_cache_line_size %d \n", cpu_id -> l2_cache_line_size); + printf (" l2_associativity %d \n", cpu_id -> l2_associativity); + printf (" l2_cache_size %dK \n", cpu_id -> l2_cache_size); + } +} + +int initialize_cpu_id (CPU_ID *cpu_id) { + + int state; + int debug; + + state = false; + debug = false; + memset (cpu_id, 0, sizeof (CPU_ID)); + + if (cpuid (0, &cpu_id -> cpu_id_registers_0)) { + if (cpu_id -> maximum_cpu_id_input >= 1) { + cpuid (1, &cpu_id -> cpu_id_registers_1); + } + if (cpu_id -> maximum_cpu_id_input >= 2) { + unsigned int index; + + cpuid (2, &cpu_id -> cpu_id_registers_2); + if (debug) { + printf (" al = %u \n", cpu_id -> cpu_id_registers_2.al); + } + + for (index = 1; index < cpu_id -> cpu_id_registers_2.al && index < MAXIMUM_2; index++) { + cpuid (2, &cpu_id -> cpu_id_registers_2_array [index]); + } + + for (index = 1; index < MAXIMUM_CHARACTERS; index++) { + if (cpu_id -> character_array_2 [index]) { + if (debug) { + printf (" cache/TLB byte = %X \n", cpu_id -> character_array_2 [index]); + } + switch (cpu_id -> character_array_2 [index]) + { + case 0x0A: + case 0x0C: + cpu_id -> cache_line_size = 32; + cpu_id -> log_base_2_cache_line_size = 5; + break; + + case 0x2C: + case 0x60: + case 0x66: + case 0x67: + case 0x68: + cpu_id -> cache_line_size = 64; + cpu_id -> log_base_2_cache_line_size = 6; + break; + } + } + } + } + + cpuid (0x80000000, &cpu_id -> cpu_id_registers_0x80000000); + + if (cpu_id -> cpu_id_registers_0x80000000.eax >= 0x80000001) { + cpuid (0x80000001, &cpu_id -> cpu_id_registers_0x80000001); + } + + if (cpu_id -> cpu_id_registers_0x80000000.eax >= 0x80000004) { + cpuid (0x80000002, &cpu_id -> cpu_id_registers_0x80000002); + cpuid (0x80000003, &cpu_id -> cpu_id_registers_0x80000003); + cpuid (0x80000004, &cpu_id -> cpu_id_registers_0x80000004); + } + + if (cpu_id -> cpu_id_registers_0x80000000.eax >= 0x80000005) { + cpuid (0x80000005, &cpu_id -> cpu_id_registers_0x80000005); + } + + if (cpu_id -> cpu_id_registers_0x80000000.eax >= 0x80000006) { + cpuid (0x80000006, &cpu_id -> cpu_id_registers_0x80000006); + } + + if (cpu_id -> cpu_id_registers_0x80000000.eax >= 0x80000008) { + cpuid (0x80000008, &cpu_id -> cpu_id_registers_0x80000008); + } + + state = true; + } + + return state; +} + //////////////////////////////////////////////////////////////////// // Function: WinGraphicsPipe::Constructor // Access: Public @@ -109,6 +650,7 @@ WinGraphicsPipe:: WinGraphicsPipe() { bool state; + char string [512]; state = false; _supported_types = OT_window | OT_fullscreen_window; @@ -141,9 +683,104 @@ WinGraphicsPipe() { state = true; } #endif - + // set callback for memory function _display_information -> _get_memory_information_function = get_memory_information; + + // set callback for cpu time function + _display_information -> _cpu_time_function = cpu_time_function; + + // determine CPU frequency + PN_uint64 time; + PN_uint64 end_time; + LARGE_INTEGER counter; + LARGE_INTEGER end; + LARGE_INTEGER frequency; + + time = 0; + end_time = 0; + counter.QuadPart = 0; + end.QuadPart = 0; + frequency.QuadPart = 0; + + int priority; + HANDLE thread; + + windisplay_cat.info() << "begin QueryPerformanceFrequency\n"; + + thread = GetCurrentThread(); + priority = GetThreadPriority (thread); + SetThreadPriority(thread, THREAD_PRIORITY_TIME_CRITICAL); + + if (QueryPerformanceFrequency(&frequency)) { + if (frequency.QuadPart > 0) { + if (QueryPerformanceCounter (&counter)) { + time = cpu_time_function(); + end.QuadPart = counter.QuadPart + frequency.QuadPart; + while (QueryPerformanceCounter (&counter) && counter.QuadPart < end.QuadPart) { + + } + end_time = cpu_time_function(); + + _display_information -> _cpu_frequency = end_time - time; + } + } + } + + SetThreadPriority(thread, priority); + + sprintf (string, "QueryPerformanceFrequency: %I64d\n", frequency.QuadPart); + windisplay_cat.info() << string; + sprintf (string, "CPU frequency: %I64d\n", _display_information -> _cpu_frequency); + windisplay_cat.info() << string; + + // CPUID + int debug; + CPU_ID cpu_id; + + debug = false; + + windisplay_cat.info() << "start CPU ID\n"; + + if (initialize_cpu_id (&cpu_id)) { + CPU_ID_BINARY_DATA *cpu_id_binary_data; + + cpu_id_binary_data = new (CPU_ID_BINARY_DATA); + if (cpu_id_binary_data) { + cpu_id_to_cpu_id_binary_data (&cpu_id, cpu_id_binary_data); + _display_information -> _cpu_id_size = sizeof (CPU_ID_BINARY_DATA) / sizeof (unsigned int); + _display_information -> _cpu_id_data = (unsigned int *) cpu_id_binary_data; + + _display_information -> _cpu_vendor_string = strdup(cpu_id.cpu_vendor); + _display_information -> _cpu_brand_string = strdup(cpu_id.cpu_brand_string); + _display_information -> _cpu_version_information = cpu_id.version_information; + _display_information -> _cpu_brand_index = cpu_id.brand_index; + + if (debug) { + printf ("%X|", _display_information -> _cpu_id_version); + + int index; + for (index = 0; index < _display_information -> _cpu_id_size; index++) { + unsigned int data; + + data = _display_information -> _cpu_id_data [index]; + + printf ("%X", data); + if (index < (_display_information -> _cpu_id_size - 1)) + { + printf ("|"); + } + } + printf ("\n"); + } + } + + if (debug) { + parse_cpu_id (&cpu_id); + } + } + + windisplay_cat.info() << "end CPU ID\n"; if (state) {