Skip to content

Commit 2a1a0e2

Browse files
committed
renderer: detect OpenGL hardware and driver vendor
Detect OpenGL hardware and driver vendor. Start to reuse this information.
1 parent b245b33 commit 2a1a0e2

File tree

6 files changed

+390
-2
lines changed

6 files changed

+390
-2
lines changed

src.cmake

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,8 @@ if (DAEMON_PARENT_SCOPE_DIR)
8787
endif()
8888

8989
set(RENDERERLIST
90+
${ENGINE_DIR}/renderer/DetectGLVendors.cpp
91+
${ENGINE_DIR}/renderer/DetectGLVendors.h
9092
${ENGINE_DIR}/renderer/gl_shader.cpp
9193
${ENGINE_DIR}/renderer/gl_shader.h
9294
${ENGINE_DIR}/renderer/iqm.h
Lines changed: 278 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,278 @@
1+
/*
2+
===========================================================================
3+
4+
Daemon BSD Source Code
5+
Copyright (c) 2024 Daemon Developers
6+
All rights reserved.
7+
8+
This file is part of the Daemon BSD Source Code (Daemon Source Code).
9+
10+
Redistribution and use in source and binary forms, with or without
11+
modification, are permitted provided that the following conditions are met:
12+
* Redistributions of source code must retain the above copyright
13+
notice, this list of conditions and the following disclaimer.
14+
* Redistributions in binary form must reproduce the above copyright
15+
notice, this list of conditions and the following disclaimer in the
16+
documentation and/or other materials provided with the distribution.
17+
* Neither the name of the Daemon developers nor the
18+
names of its contributors may be used to endorse or promote products
19+
derived from this software without specific prior written permission.
20+
21+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
22+
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
23+
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
24+
DISCLAIMED. IN NO EVENT SHALL DAEMON DEVELOPERS BE LIABLE FOR ANY
25+
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
26+
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
27+
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
28+
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29+
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
30+
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31+
32+
===========================================================================
33+
*/
34+
35+
#include "DetectGLVendors.h"
36+
37+
std::string GetGLHardwareVendorName( glHardwareVendor_t hardwareVendor )
38+
{
39+
static const std::string hardwareVendorNames[] = {
40+
"Unknown",
41+
"Software rasterizer",
42+
"API Translator",
43+
"Arm",
44+
"AMD/ATI",
45+
"Broadcom",
46+
"Intel",
47+
"Nvidia",
48+
"OutOfRange",
49+
};
50+
51+
int index = Util::ordinal( hardwareVendor );
52+
static constexpr size_t lastNameIndex = ARRAY_LEN( hardwareVendorNames ) - 1;
53+
static constexpr int lastEnumIndex = Util::ordinal( glHardwareVendor_t::NUM_HARDWARE_VENDORS );
54+
55+
static_assert( lastNameIndex == lastEnumIndex, "glHardwareVendor_t and hardwareVendorNames count mismatch" );
56+
ASSERT_GE( index, 0 );
57+
ASSERT_LT( index, lastEnumIndex );
58+
59+
index = ( index < 0 || index > lastEnumIndex ) ? lastNameIndex : index;
60+
61+
return hardwareVendorNames[ index ];
62+
}
63+
64+
std::string GetGLDriverVendorName( glDriverVendor_t driverVendor )
65+
{
66+
static const std::string driverVendorNames[] = {
67+
"Unknown",
68+
"AMD/ATI",
69+
"Intel",
70+
"Mesa",
71+
"Nvidia",
72+
"OutOfRange",
73+
};
74+
75+
int index = Util::ordinal( driverVendor );
76+
static constexpr size_t lastNameIndex = ARRAY_LEN( driverVendorNames ) - 1;
77+
static constexpr int lastEnumIndex = Util::ordinal( glDriverVendor_t::NUM_DRIVER_VENDORS );
78+
79+
static_assert( lastNameIndex == lastEnumIndex, "glDriverVendor_t and driverVendorNames count mismatch" );
80+
ASSERT_GE( index, 0 );
81+
ASSERT_LT( index, lastEnumIndex );
82+
83+
index = ( index < 0 || index > lastEnumIndex ) ? lastNameIndex : index;
84+
85+
return driverVendorNames[ index ];
86+
}
87+
88+
void DetectGLVendors(
89+
const std::string& vendorString,
90+
const std::string& versionString,
91+
const std::string& rendererString,
92+
glHardwareVendor_t& hardwareVendor,
93+
glDriverVendor_t& driverVendor )
94+
{
95+
hardwareVendor = glHardwareVendor_t::UNKNOWN;
96+
driverVendor = glDriverVendor_t::UNKNOWN;
97+
98+
// Those vendor strings are assumed to be unambiguous about both driver and hardware vendors.
99+
static const std::unordered_map<std::string, std::pair<glDriverVendor_t, glHardwareVendor_t>>
100+
vendorDriverHardware =
101+
{
102+
// Mesa AMD/ATI.
103+
{ "AMD", { glDriverVendor_t::MESA, glHardwareVendor_t::ATI } },
104+
{ "AMD inc.", { glDriverVendor_t::MESA, glHardwareVendor_t::ATI } },
105+
{ "X.Org R300 Project", { glDriverVendor_t::MESA, glHardwareVendor_t::ATI } },
106+
// Proprietary ATI or AMD drivers on all systems like Linux, Windows, and macOS: OGLP, Catalyst…
107+
{ "ATI Technologies Inc.", { glDriverVendor_t::ATI, glHardwareVendor_t::ATI } },
108+
// Proprietary Intel driver on macOS.
109+
{ "Intel Inc.", { glDriverVendor_t::INTEL, glHardwareVendor_t::INTEL } },
110+
// Mesa Intel.
111+
{ "Intel Open Source Technology Center", { glDriverVendor_t::MESA, glHardwareVendor_t::INTEL } },
112+
{ "Tungsten Graphics, Inc", { glDriverVendor_t::MESA, glHardwareVendor_t::INTEL } },
113+
// Mesa V3D and VC4 (Raspberry Pi).
114+
{ "Broadcom", { glDriverVendor_t::MESA, glHardwareVendor_t::BROADCOM } },
115+
// Mesa Panfrost, newer Panfrost uses "Mesa" instead.
116+
{ "Panfrost", { glDriverVendor_t::MESA, glHardwareVendor_t::ARM } },
117+
// Mesa Nvidia for supported OpenGL 2+ hardware.
118+
{ "nouveau", { glDriverVendor_t::MESA, glHardwareVendor_t::NVIDIA } },
119+
// Proprietary Nvidia drivers on all systems like Linux, Windows, and macOS.
120+
{ "NVIDIA Corporation", { glDriverVendor_t::NVIDIA, glHardwareVendor_t::NVIDIA } },
121+
// Mesa Amber also provides "Nouveau", but this is for unsupported pre-OpenGL 2 Nvidia.
122+
};
123+
124+
auto it = vendorDriverHardware.find( vendorString );
125+
if ( it != vendorDriverHardware.end() )
126+
{
127+
driverVendor = it->second.first;
128+
hardwareVendor = it->second.second;
129+
return;
130+
}
131+
132+
// This vendor string is used by at least two different Intel drivers.
133+
if ( vendorString == "Intel Corporation" )
134+
{
135+
if ( Str::IsPrefix( "SWR ", rendererString ) )
136+
{
137+
/* It is part of Mesa Amber, but was merged in Mesa lately after being an internal
138+
Intel product for years. It doesn't share much things with Mesa, and we better
139+
not assume it behaves the same as Mesa, it may even behave like Intel.
140+
We keep driverVendor as glDriverVendor_t::UNKNOWN on purpose. */
141+
hardwareVendor = glHardwareVendor_t::SOFTWARE;
142+
return;
143+
}
144+
else
145+
{
146+
driverVendor = glDriverVendor_t::MESA;
147+
hardwareVendor = glHardwareVendor_t::INTEL;
148+
return;
149+
}
150+
}
151+
152+
// This vendor string is used by at least two different Microsoft drivers.
153+
if ( vendorString == "Microsoft Corporation" )
154+
{
155+
/* The GL_VENDOR string can also be "Microsoft Corporation" with GL_RENDERER
156+
set to "GDI Generic" which is not Mesa and isn't supported (OpenGL 1.1). */
157+
if ( Str::IsPrefix( "DRD12 ", rendererString ) )
158+
{
159+
driverVendor = glDriverVendor_t::MESA;
160+
// OpenGL over Direct3D12 translation.
161+
hardwareVendor = glHardwareVendor_t::TRANSLATION;
162+
return;
163+
}
164+
}
165+
166+
/* Those substrings at the beginning of a renderer string are assumed to be unambiguous about
167+
both driver and hardware. */
168+
static const std::pair<std::string, glHardwareVendor_t> rendererMesaStartStringHardware[] = {
169+
// "Mesa DRI R200" exists for ATI but isn't supported.
170+
{ "Mesa DRI nv", glHardwareVendor_t::NVIDIA },
171+
{ "Mesa DRI Intel(R)", glHardwareVendor_t::INTEL },
172+
};
173+
174+
for ( auto& p : rendererMesaStartStringHardware )
175+
{
176+
if ( Str::IsPrefix( p.first, rendererString ) )
177+
{
178+
driverVendor = glDriverVendor_t::MESA;
179+
hardwareVendor = p.second;
180+
return;
181+
}
182+
}
183+
184+
// Those vendor strings are assumed to be unambiguous about being from Mesa drivers.
185+
static const std::string mesaVendors[] = {
186+
// Mesa.
187+
"Mesa",
188+
"Mesa Project",
189+
"Mesa/X.org",
190+
"X.Org",
191+
// Zink.
192+
"Collabora Ltd",
193+
// virgl.
194+
"Red Hat",
195+
// llvmpipe, softpipe, SVGA3D.
196+
"VMware, Inc.",
197+
};
198+
199+
for ( auto& s : mesaVendors )
200+
{
201+
if ( vendorString == s )
202+
{
203+
driverVendor = glDriverVendor_t::MESA;
204+
break;
205+
}
206+
}
207+
208+
/* This substring in a version string is assumed to be unambiguous about being from Mesa
209+
drivers. Mesa GL_VENDOR and GL_RENDERER strings are very fluid, but it is believed that
210+
GL_VERSION always contains the " Mesa " substring and that substring always means Mesa. */
211+
if ( driverVendor == glDriverVendor_t::UNKNOWN && versionString.find( " Mesa " ) != std::string::npos )
212+
{
213+
driverVendor = glDriverVendor_t::MESA;
214+
}
215+
216+
if ( driverVendor == glDriverVendor_t::MESA )
217+
{
218+
// This vendor string for a Mesa driver is assumed to be unambiguous about the hardware.
219+
if ( vendorString == "Intel" )
220+
{
221+
hardwareVendor = glHardwareVendor_t::INTEL;
222+
return;
223+
}
224+
225+
/* Those substrings at the beginning of a renderer string are assumed to be unambiguous about
226+
the hardware or underlying technology. */
227+
static const std::pair<std::string, glHardwareVendor_t> rendererStartStringHardware[] = {
228+
{ "ATI ", glHardwareVendor_t::ATI },
229+
{ "AMD ", glHardwareVendor_t::ATI },
230+
{ "i915 ", glHardwareVendor_t::INTEL },
231+
{ "NV", glHardwareVendor_t::NVIDIA },
232+
{ "Mali-", glHardwareVendor_t::ARM },
233+
// OpenGL over Vulkan translation.
234+
{ "zink ", glHardwareVendor_t::TRANSLATION },
235+
// Virtualization.
236+
{ "virgl", glHardwareVendor_t::TRANSLATION },
237+
};
238+
239+
for ( auto& p : rendererStartStringHardware )
240+
{
241+
if ( Str::IsPrefix( p.first, rendererString ) )
242+
{
243+
hardwareVendor = p.second;
244+
return;
245+
}
246+
}
247+
248+
/* Those substrings within a renderer string are assumed to be unambiguous about
249+
the underlying technology. */
250+
static const std::pair<std::string, glHardwareVendor_t> rendererSubStringHardware[] = {
251+
{ "Panfrost", glHardwareVendor_t::ARM },
252+
// Software rendering.
253+
{ "llvmpipe", glHardwareVendor_t::SOFTWARE },
254+
{ "softpipe", glHardwareVendor_t::SOFTWARE },
255+
// Virtualization.
256+
{ "SVGA3D", glHardwareVendor_t::TRANSLATION },
257+
};
258+
259+
for ( auto& p : rendererSubStringHardware )
260+
{
261+
if ( rendererString.find( p.first ) != std::string::npos )
262+
{
263+
hardwareVendor = p.second;
264+
return;
265+
}
266+
}
267+
}
268+
269+
/* As both proprietary Intel driver on Windows and Mesa may report "Intel",
270+
we rely on the fact Mesa is already detected to know it is the proprietary
271+
Windows driver if not Mesa. */
272+
if ( vendorString == "Intel" )
273+
{
274+
driverVendor = glDriverVendor_t::INTEL;
275+
hardwareVendor = glHardwareVendor_t::INTEL;
276+
return;
277+
}
278+
}

src/engine/renderer/DetectGLVendors.h

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
/*
2+
===========================================================================
3+
4+
Daemon BSD Source Code
5+
Copyright (c) 2024 Daemon Developers
6+
All rights reserved.
7+
8+
This file is part of the Daemon BSD Source Code (Daemon Source Code).
9+
10+
Redistribution and use in source and binary forms, with or without
11+
modification, are permitted provided that the following conditions are met:
12+
* Redistributions of source code must retain the above copyright
13+
notice, this list of conditions and the following disclaimer.
14+
* Redistributions in binary form must reproduce the above copyright
15+
notice, this list of conditions and the following disclaimer in the
16+
documentation and/or other materials provided with the distribution.
17+
* Neither the name of the Daemon developers nor the
18+
names of its contributors may be used to endorse or promote products
19+
derived from this software without specific prior written permission.
20+
21+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
22+
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
23+
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
24+
DISCLAIMED. IN NO EVENT SHALL DAEMON DEVELOPERS BE LIABLE FOR ANY
25+
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
26+
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
27+
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
28+
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29+
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
30+
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31+
32+
===========================================================================
33+
*/
34+
35+
// DetectGLVendors.h
36+
37+
#ifndef DETECT_OPENGL_VENDORS_H
38+
#define DETECT_OPENGL_VENDORS_H
39+
40+
#include "common/Assert.h"
41+
#include "common/Common.h"
42+
#include "qcommon/q_shared.h"
43+
44+
enum class glHardwareVendor_t
45+
{
46+
UNKNOWN,
47+
// Assumed to be slow (running on CPU).
48+
SOFTWARE,
49+
/* Assumed to be fast (running on GPU through a translation, like an OpenGL over Vulkan
50+
driver, or an OpenGL virtualization driver sending commands to an hypervisor. */
51+
TRANSLATION,
52+
// Assumed to be fast (running on GPU directly).
53+
ARM,
54+
ATI,
55+
BROADCOM,
56+
INTEL,
57+
NVIDIA,
58+
NUM_HARDWARE_VENDORS,
59+
};
60+
61+
enum class glDriverVendor_t
62+
{
63+
UNKNOWN,
64+
ATI,
65+
INTEL,
66+
MESA,
67+
NVIDIA,
68+
NUM_DRIVER_VENDORS,
69+
};
70+
71+
std::string GetGLHardwareVendorName( glHardwareVendor_t hardwareVendor );
72+
73+
std::string GetGLDriverVendorName( glDriverVendor_t driverVendor );
74+
75+
void DetectGLVendors(
76+
const std::string& vendorString,
77+
const std::string& versionString,
78+
const std::string& rendererString,
79+
glHardwareVendor_t& hardwareVendor,
80+
glDriverVendor_t& driverVendor );
81+
82+
#endif // DETECT_OPENGL_VENDORS_H

src/engine/renderer/tr_init.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
2323
// tr_init.c -- functions that are not called every frame
2424
#include "tr_local.h"
2525
#include "framework/CvarSystem.h"
26+
#include "DetectGLVendors.h"
2627
#include "Material.h"
2728

2829
glconfig_t glConfig;
@@ -900,6 +901,14 @@ ScreenshotCmd screenshotPNGRegistration("screenshotPNG", ssFormat_t::SSF_PNG, "p
900901
"fullscreen"
901902
};
902903

904+
Log::Notice( "%sOpenGL hardware vendor: %s",
905+
Color::ToString( Util::ordinal(glConfig2.hardwareVendor) ? Color::Green : Color::Yellow ),
906+
GetGLHardwareVendorName( glConfig2.hardwareVendor ) );
907+
908+
Log::Notice( "%sOpenGL driver vendor: %s",
909+
Color::ToString( Util::ordinal(glConfig2.driverVendor) ? Color::Green : Color::Yellow ),
910+
GetGLDriverVendorName( glConfig2.driverVendor ) );
911+
903912
Log::Notice("GL_VENDOR: %s", glConfig.vendor_string );
904913
Log::Notice("GL_RENDERER: %s", glConfig.renderer_string );
905914
Log::Notice("GL_VERSION: %s", glConfig.version_string );

0 commit comments

Comments
 (0)