Panda3D
graphicsPipe.cxx
Go to the documentation of this file.
1 /**
2  * PANDA 3D SOFTWARE
3  * Copyright (c) Carnegie Mellon University. All rights reserved.
4  *
5  * All use of this software is subject to the terms of the revised BSD
6  * license. You should have received a copy of this license along
7  * with this source code in a file named "LICENSE."
8  *
9  * @file graphicsPipe.cxx
10  * @author mike
11  * @date 1997-01-09
12  */
13 
14 #include "graphicsPipe.h"
15 #include "graphicsWindow.h"
16 #include "graphicsBuffer.h"
17 #include "config_display.h"
18 #include "mutexHolder.h"
19 #include "displayInformation.h"
20 
21 #ifdef IS_LINUX
22 #include <sys/sysinfo.h>
23 #include <unistd.h>
24 #endif
25 
26 #if defined(IS_OSX) || defined(IS_FREEBSD)
27 #include <sys/sysctl.h>
28 #include <unistd.h>
29 #endif
30 
31 #ifdef _WIN32
32 #ifndef WIN32_LEAN_AND_MEAN
33 #define WIN32_LEAN_AND_MEAN 1
34 #endif
35 #include <windows.h>
36 #endif
37 
38 // CPUID is only available on i386 and x86-64 architectures.
39 #if defined(__i386) || defined(__x86_64__) || defined(_M_IX86) || defined(_M_X64)
40 
41 #if defined(__GNUC__) && !defined(__APPLE__)
42 // GCC and Clang offer a useful cpuid.h header.
43 #include <cpuid.h>
44 #endif
45 
46 #ifdef _MSC_VER
47 // MSVC has a __cpuid intrinsic.
48 #include <intrin.h>
49 #endif
50 
51 union cpuid_info {
52  char str[16];
53  struct {
54  uint32_t eax, ebx, ecx, edx;
55  };
56 };
57 
58 /**
59  * Returns the highest cpuid leaf that is supported by the CPU.
60  */
61 static inline uint32_t get_cpuid_max(uint32_t leaf) {
62 #if defined(__GNUC__) && !defined(__APPLE__)
63  return __get_cpuid_max(leaf, nullptr);
64 #elif defined(_MSC_VER)
65  uint32_t p[4] = {0};
66  __cpuid((int *)p, leaf);
67  return p[0];
68 #else
69  unsigned int eax = 0;
70  __asm__ ("cpuid\n\t"
71  : "=a" (eax)
72  : "0" (leaf));
73  return eax;
74 #endif
75 }
76 
77 /**
78  * Gets cpuid info for the given leaf.
79  */
80 static inline void get_cpuid(uint32_t leaf, cpuid_info &info) {
81 #if defined(__GNUC__) && !defined(__APPLE__)
82  __cpuid(leaf, info.eax, info.ebx, info.ecx, info.edx);
83 #elif defined(_MSC_VER)
84  __cpuid((int *)info.str, leaf);
85 #else
86  __asm__ ("cpuid\n\t"
87  : "=a" (info.eax), "=b" (info.ebx), "=c" (info.ecx), "=d" (info.edx)
88  : "0" (leaf));
89 #endif
90 }
91 #endif
92 
93 #ifdef IS_LINUX
94 /**
95  * Updates the current memory usage statistics in the DisplayInformation.
96  */
97 static void update_memory_info(DisplayInformation *info) {
98  struct sysinfo meminfo;
99  if (sysinfo(&meminfo) == 0) {
100  info->_physical_memory = meminfo.totalram;
101  info->_available_physical_memory = meminfo.freeram;
102  info->_page_file_size = meminfo.totalswap;
103  info->_available_page_file_size = meminfo.freeswap;
104  }
105 }
106 #endif
107 
108 TypeHandle GraphicsPipe::_type_handle;
109 
110 /**
111  *
112  */
113 GraphicsPipe::
114 GraphicsPipe() :
115  _lock("GraphicsPipe")
116 {
117  // Initially, we assume the GraphicsPipe is valid. A derived class should
118  // set this to false if it determines otherwise.
119  _is_valid = true;
120 
121  // A derived class must indicate the kinds of GraphicsOutput objects it can
122  // create.
123  _supported_types = 0;
124 
125  _display_width = 0;
126  _display_height = 0;
127 
128  _display_information = new DisplayInformation();
129 
130 #if defined(__i386) || defined(__x86_64__) || defined(_M_IX86) || defined(_M_X64)
131  cpuid_info info;
132  const uint32_t max_cpuid = get_cpuid_max(0);
133  const uint32_t max_extended = get_cpuid_max(0x80000000);
134 
135  if (max_cpuid >= 1) {
136  get_cpuid(0, info);
137  std::swap(info.ecx, info.edx);
138  _display_information->_cpu_vendor_string = std::string(info.str + 4, 12);
139 
140  get_cpuid(1, info);
141  _display_information->_cpu_version_information = info.eax;
142  _display_information->_cpu_brand_index = info.ebx & 0xff;
143  }
144 
145  if (max_extended >= 0x80000004) {
146  char brand[49];
147  get_cpuid(0x80000002, info);
148  memcpy(brand, info.str, 16);
149  get_cpuid(0x80000003, info);
150  memcpy(brand + 16, info.str, 16);
151  get_cpuid(0x80000004, info);
152  memcpy(brand + 32, info.str, 16);
153  brand[48] = 0;
154  _display_information->_cpu_brand_string = brand;
155  }
156 #endif
157 
158 #if defined(IS_OSX)
159  // macOS exposes a lot of useful information through sysctl.
160  size_t len = sizeof(uint64_t);
161  sysctlbyname("hw.memsize", &_display_information->_physical_memory, &len, nullptr, 0);
162  len = sizeof(uint64_t);
163  sysctlbyname("hw.cpufrequency", &_display_information->_cpu_frequency, &len, nullptr, 0);
164  len = sizeof(uint64_t);
165  sysctlbyname("hw.cpufrequency", &_display_information->_current_cpu_frequency, &len, nullptr, 0);
166  len = sizeof(uint64_t);
167  sysctlbyname("hw.cpufrequency_max", &_display_information->_maximum_cpu_frequency, &len, nullptr, 0);
168  len = sizeof(int);
169  sysctlbyname("hw.physicalcpu", &_display_information->_num_cpu_cores, &len, nullptr, 0);
170  len = sizeof(int);
171  sysctlbyname("hw.logicalcpu", &_display_information->_num_logical_cpus, &len, nullptr, 0);
172 
173 #elif defined(IS_LINUX)
174  _display_information->_get_memory_information_function = &update_memory_info;
175  update_memory_info(_display_information);
176 
177 #elif defined(IS_FREEBSD)
178  size_t len = sizeof(uint64_t);
179  sysctlbyname("hw.physmem", &_display_information->_physical_memory, &len, nullptr, 0);
180  len = sizeof(uint64_t);
181  sysctlbyname("vm.swap_total", &_display_information->_page_file_size, &len, nullptr, 0);
182 
183 #elif defined(_WIN32)
184  MEMORYSTATUSEX status;
185  status.dwLength = sizeof(MEMORYSTATUSEX);
186  if (GlobalMemoryStatusEx(&status)) {
187  _display_information->_physical_memory = status.ullTotalPhys;
188  _display_information->_available_physical_memory = status.ullAvailPhys;
189  _display_information->_page_file_size = status.ullTotalPageFile;
190  _display_information->_available_page_file_size = status.ullAvailPageFile;
191  _display_information->_process_virtual_memory = status.ullTotalVirtual;
192  _display_information->_available_process_virtual_memory = status.ullAvailVirtual;
193  _display_information->_memory_load = status.dwMemoryLoad;
194  }
195 #endif
196 
197 #if defined(IS_LINUX) || defined(IS_FREEBSD)
198  long nproc = sysconf(_SC_NPROCESSORS_CONF);
199  if (nproc > 0) {
200  _display_information->_num_logical_cpus = nproc;
201  }
202 #endif
203 }
204 
205 /**
206  *
207  */
208 GraphicsPipe::
209 ~GraphicsPipe() {
210  delete _display_information;
211 }
212 
213 /**
214  * Returns an indication of the thread in which this GraphicsPipe requires its
215  * window processing to be performed: typically either the app thread (e.g.
216  * X) or the draw thread (Windows).
217  */
218 GraphicsPipe::PreferredWindowThread
220  return PWT_draw;
221 }
222 
223 /**
224  * This is called when make_output() is used to create a
225  * CallbackGraphicsWindow. If the GraphicsPipe can construct a GSG that's not
226  * associated with any particular window object, do so now, assuming the
227  * correct graphics context has been set up externally.
228  */
229 PT(GraphicsStateGuardian) GraphicsPipe::
230 make_callback_gsg(GraphicsEngine *engine) {
231  return nullptr;
232 }
233 
234 /**
235  * Creates a new device for the pipe. Only DirectX uses this device, for
236  * other api's it is NULL.
237  */
238 PT(GraphicsDevice) GraphicsPipe::
239 make_device(void *scrn) {
240  display_cat.error()
241  << "make_device() unimplemented by " << get_type() << "\n";
242  return nullptr;
243 }
244 
245 /**
246  * This will be called in the draw thread (the same thread in which the GSG
247  * was created via make_gsg, above) to close the indicated GSG and free its
248  * associated graphics objects just before it is destructed. This method
249  * exists to provide a hook for the graphics pipe to do any necessary cleanup,
250  * if any.
251  */
252 void GraphicsPipe::
253 close_gsg(GraphicsStateGuardian *gsg) {
254  if (gsg != nullptr) {
255  gsg->close_gsg();
256  }
257 }
258 
259 /**
260  * Creates a new window on the pipe, if possible.
261  */
262 PT(GraphicsOutput) GraphicsPipe::
263 make_output(const std::string &name,
264  const FrameBufferProperties &fb_prop,
265  const WindowProperties &win_prop,
266  int flags,
267  GraphicsEngine *engine,
269  GraphicsOutput *host,
270  int retry,
271  bool &precertify) {
272  display_cat.error()
273  << get_type() << " cannot create buffers or windows.\n";
274  return nullptr;
275 }
276 
277 /**
278  * Gets the pipe's DisplayInformation.
279  */
280 DisplayInformation *GraphicsPipe::
281 get_display_information() {
282  return _display_information;
283 }
284 
285 /**
286  * Looks up the detailed CPU information and stores it in
287  * _display_information, if supported by the OS. This may take a second or
288  * two.
289  */
290 void GraphicsPipe::
292 }
This class contains various display information.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
virtual PreferredWindowThread get_preferred_window_thread() const
Returns an indication of the thread in which this GraphicsPipe requires its window processing to be p...
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
A container for the various kinds of properties we might ask to have on a graphics window before we o...
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
This is a base class for the various different classes that represent the result of a frame of render...
An abstract device object that is part of Graphics Pipe.
virtual void lookup_cpu_data()
Looks up the detailed CPU information and stores it in _display_information, if supported by the OS.
Encapsulates all the communication with a particular instance of a given rendering backend.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
This class is the main interface to controlling the render process.
TypeHandle is the identifier used to differentiate C++ class types.
Definition: typeHandle.h:81
A container for the various kinds of properties we might ask to have on a graphics frameBuffer before...
PT(GraphicsStateGuardian) GraphicsPipe
This is called when make_output() is used to create a CallbackGraphicsWindow.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.