Pyrogenesis  13997
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
wgfx.cpp
Go to the documentation of this file.
1 /* Copyright (c) 2010 Wildfire Games
2  *
3  * Permission is hereby granted, free of charge, to any person obtaining
4  * a copy of this software and associated documentation files (the
5  * "Software"), to deal in the Software without restriction, including
6  * without limitation the rights to use, copy, modify, merge, publish,
7  * distribute, sublicense, and/or sell copies of the Software, and to
8  * permit persons to whom the Software is furnished to do so, subject to
9  * the following conditions:
10  *
11  * The above copyright notice and this permission notice shall be included
12  * in all copies or substantial portions of the Software.
13  *
14  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
17  * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
18  * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
19  * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
20  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21  */
22 
23 /*
24  * graphics card detection on Windows.
25  */
26 
27 #include "precompiled.h"
28 #include "lib/sysdep/os/win/wgfx.h"
29 
30 #include "lib/sysdep/gfx.h"
33 #include "lib/sysdep/os/win/wmi.h"
34 
35 #if MSC_VERSION
36 #pragma comment(lib, "advapi32.lib") // registry
37 #endif
38 
39 
40 // note: this implementation doesn't require OpenGL to be initialized.
42 {
43  // rationale:
44  // - we could easily determine the 2d driver via EnumDisplaySettings,
45  // but we want to query the actual OpenGL driver. see
46  // http://www.opengl.org/discussion_boards/ubb/Forum3/HTML/009679.html ;
47  // in short, we need the exact OpenGL driver version because some
48  // driver packs (e.g. Omega) mix and match DLLs.
49  // - an alternative implementation would be to enumerate all
50  // DLLs loaded into the process, and check for a glBegin export.
51  // that requires toolhelp/PSAPI (a bit complicated) and telling
52  // ICD/opengl32.dll apart (not future-proof).
53  // - therefore, we stick with the OpenGLDrivers approach. since there is
54  // no good way to determine which of the subkeys (e.g. nvoglnt) is
55  // active (several may exist due to previously removed drivers),
56  // we just display all of them. it is obvious from looking at
57  // gfx_card which one is correct; we thus avoid driver-specific
58  // name checks and reporting incorrectly.
59 
60  wchar_t dllName[MAX_PATH+1];
61 
62  HKEY hkDrivers;
63  const wchar_t* key = L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\OpenGLDrivers";
64  // (we've received word of this failing on one WinXP system, but
65  // AppendDriverVersionsFromKnownFiles might still work.)
66  if(RegOpenKeyExW(HKEY_LOCAL_MACHINE, key, 0, KEY_READ, &hkDrivers) != 0)
67  return ERR::FAIL; // NOWARN (see above)
68 
69  // for each subkey (i.e. installed OpenGL driver):
70  for(DWORD i = 0; ; i++)
71  {
72  wchar_t driverName[32];
73  DWORD driverNameLength = ARRAY_SIZE(driverName);
74  const LONG err = RegEnumKeyExW(hkDrivers, i, driverName, &driverNameLength, 0, 0, 0, 0);
75  if(err == ERROR_NO_MORE_ITEMS)
76  {
77  if(i == 0)
78  {
79  RegCloseKey(hkDrivers);
80  return ERR::NOT_SUPPORTED; // NOWARN (ATI and NVidia don't create sub-keys on Windows 7)
81  }
82  break;
83  }
84  ENSURE(err == ERROR_SUCCESS);
85 
86  HKEY hkDriver;
87  if(RegOpenKeyExW(hkDrivers, driverName, 0, KEY_QUERY_VALUE, &hkDriver) == 0)
88  {
89  DWORD dllNameLength = ARRAY_SIZE(dllName)-5; // for ".dll"
90  if(RegQueryValueExW(hkDriver, L"Dll", 0, 0, (LPBYTE)dllName, &dllNameLength) == 0)
91  wdll_ver_Append(dllName, versionList);
92 
93  RegCloseKey(hkDriver);
94  }
95  }
96 
97  // for each value:
98  // (some old drivers, e.g. S3 Super Savage, store their ICD name in a
99  // single REG_SZ value. we therefore include those as well.)
100  for(DWORD i = 0; ; i++)
101  {
102  wchar_t name[100]; // we don't need this, but RegEnumValue fails otherwise.
103  DWORD nameLength = ARRAY_SIZE(name);
104  DWORD type;
105  DWORD dllNameLength = ARRAY_SIZE(dllName)-5; // for ".dll"
106  const DWORD err = RegEnumValueW(hkDrivers, i, name, &nameLength, 0, &type, (LPBYTE)dllName, &dllNameLength);
107  if(err == ERROR_NO_MORE_ITEMS)
108  break;
109  ENSURE(err == ERROR_SUCCESS);
110  if(type == REG_SZ)
111  wdll_ver_Append(dllName, versionList);
112  }
113 
114  RegCloseKey(hkDrivers);
115 
116  return INFO::OK;
117 }
118 
119 
121 {
122  // (check all known file names regardless of gfx_card, which may change and
123  // defeat our parsing. this takes about 5..10 ms)
124 
125  // NVidia
126  wdll_ver_Append(L"nvoglv64.dll", versionList);
127  wdll_ver_Append(L"nvoglv32.dll", versionList);
128  wdll_ver_Append(L"nvoglnt.dll", versionList);
129 
130  // ATI
131  wdll_ver_Append(L"atioglxx.dll", versionList);
132 
133  // Intel
134  wdll_ver_Append(L"ig4icd32.dll", versionList);
135  wdll_ver_Append(L"ig4icd64.dll", versionList);
136  wdll_ver_Append(L"iglicd32.dll", versionList);
137 }
138 
139 
140 Status wgfx_CardName(wchar_t* cardName, size_t numChars)
141 {
142  WmiInstances instances;
143  RETURN_STATUS_IF_ERR(wmi_GetClassInstances(L"Win32_VideoController", instances));
144  wchar_t* pos = cardName;
145  for(WmiInstances::iterator it = instances.begin(); it != instances.end(); ++it)
146  {
147  if((*it)[L"Availability"].intVal == 8) // offline
148  continue;
149  const int ret = swprintf_s(pos, numChars-(pos-cardName), L"%ls; ", (*it)[L"Caption"].bstrVal);
150  if(ret > 0)
151  pos += ret;
152  return INFO::OK;
153  }
154 
155  return ERR::FAIL; // no active card found
156 }
157 
158 
159 std::wstring wgfx_DriverInfo()
160 {
161  VersionList versionList;
162  if(AppendDriverVersionsFromRegistry(versionList) != INFO::OK) // (fails on Windows 7)
164  return versionList;
165 }
166 
167 
168 //-----------------------------------------------------------------------------
169 // direct implementations of some gfx functions
170 
171 namespace gfx {
172 
173 Status GetVideoMode(int* xres, int* yres, int* bpp, int* freq)
174 {
175  DEVMODE dm = { sizeof(dm) };
176 
177  if(!EnumDisplaySettings(0, ENUM_CURRENT_SETTINGS, &dm))
179 
180  // EnumDisplaySettings is documented to set the values of the following:
181  const DWORD expectedFlags = DM_PELSWIDTH|DM_PELSHEIGHT|DM_BITSPERPEL|DM_DISPLAYFREQUENCY|DM_DISPLAYFLAGS;
182  ENSURE((dm.dmFields & expectedFlags) == expectedFlags);
183 
184  if(xres)
185  *xres = (int)dm.dmPelsWidth;
186  if(yres)
187  *yres = (int)dm.dmPelsHeight;
188  if(bpp)
189  *bpp = (int)dm.dmBitsPerPel;
190  if(freq)
191  *freq = (int)dm.dmDisplayFrequency;
192 
193  return INFO::OK;
194 }
195 
196 
197 Status GetMonitorSize(int& width_mm, int& height_mm)
198 {
199  // (DC for the primary monitor's entire screen)
200  const HDC hDC = GetDC(0);
201  width_mm = GetDeviceCaps(hDC, HORZSIZE);
202  height_mm = GetDeviceCaps(hDC, VERTSIZE);
203  ReleaseDC(0, hDC);
204  return INFO::OK;
205 }
206 
207 } // namespace gfx
const Status OK
Definition: status.h:386
LIB_API Status GetVideoMode(int *xres, int *yres, int *bpp, int *freq)
(useful for choosing a new video mode)
Definition: android.cpp:47
int swprintf_s(wchar_t *buf, size_t max_chars, const wchar_t *fmt,...) WPRINTF_ARGS(3)
std::vector< WmiInstance > WmiInstances
Definition: wmi.h:42
#define ARRAY_SIZE(name)
const Status NOT_SUPPORTED
Definition: status.h:429
#define ENSURE(expr)
ensure the expression &lt;expr&gt; evaluates to non-zero.
Definition: debug.h:282
void wdll_ver_Append(const OsPath &pathname, VersionList &list)
Read DLL version information and append it to a string.
Definition: wdll_ver.cpp:85
Status wgfx_CardName(wchar_t *cardName, size_t numChars)
Definition: wgfx.cpp:140
static DEVMODE dm
Definition: wsdl.cpp:278
Status wmi_GetClassInstances(const wchar_t *className, WmiInstances &instances)
get all instances of the requested class.
Definition: wmi.cpp:106
unsigned long DWORD
Definition: wgl.h:56
pthread_key_t key
Definition: wpthread.cpp:140
i64 Status
Error handling system.
Definition: status.h:171
LIB_API Status GetMonitorSize(int &width_mm, int &height_mm)
(useful for determining aspect ratio)
Definition: wgfx.cpp:197
std::wstring VersionList
Definition: wdll_ver.h:32
static Status AppendDriverVersionsFromRegistry(VersionList &versionList)
Definition: wgfx.cpp:41
#define WARN_RETURN(status)
Definition: status.h:255
const Status FAIL
Definition: status.h:406
long LONG
Definition: wgl.h:55
std::wstring wgfx_DriverInfo()
Definition: wgfx.cpp:159
static void AppendDriverVersionsFromKnownFiles(VersionList &versionList)
Definition: wgfx.cpp:120
#define RETURN_STATUS_IF_ERR(expression)
Definition: status.h:276