Bug 1858921 - Part 6: Remove unused default template arguments r=sfink
[gecko.git] / dom / canvas / SanitizeRenderer.cpp
blob3e7a7cfce2a46bd2351c36c4fdd7eb70f6573064
1 /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 #include "mozilla/gfx/Logging.h"
7 #include "mozilla/IntegerRange.h"
9 #include <functional>
10 #include <regex>
11 #include <string>
13 namespace mozilla {
14 namespace webgl {
16 static bool Contains(const std::string& str, const std::string& part) {
17 return str.find(part) != size_t(-1);
20 /**
21 * Narrow renderer string space down to representative replacements.
22 * E.g. "GeForce RTX 3090" => "GeForce GTX 980"
24 * For example strings:
25 * https://hackmd.io/Ductv3pQTMej74gbveD4yw
27 static std::string ChooseDeviceReplacement(const std::string& str) {
28 if (str.find("llvmpipe") == 0) return "llvmpipe";
29 if (str.find("Apple") == 0) return "Apple M1";
31 std::smatch m;
33 // -
35 if (Contains(str, "AMD ") || Contains(str, "FirePro") ||
36 Contains(str, "Radeon")) {
37 static const std::string RADEON_HD_3000 = "Radeon HD 3200 Graphics";
38 static const std::string RADEON_HD_5850 = "Radeon HD 5850";
39 static const std::string RADEON_R9_290 = "Radeon R9 200 Series";
41 const auto RADEON_D3D_FL10_1 = RADEON_HD_3000;
42 const auto RADEON_GCN_GEN2 = RADEON_R9_290; // GCN Gen2
44 if (Contains(str, "Vega")) {
45 return RADEON_R9_290;
47 if (Contains(str, "VII")) {
48 return RADEON_R9_290;
50 if (Contains(str, "Fury")) {
51 return RADEON_R9_290;
53 static const std::regex kRadeon(
54 "Radeon.*?((R[579X]|HD) )?([0-9][0-9][0-9]+)");
55 if (std::regex_search(str, m, kRadeon)) {
56 const auto& rxOrHd = m.str(2);
57 const auto modelNum = stoul(m.str(3));
58 if (rxOrHd == "HD") {
59 if (modelNum >= 5000) {
60 return RADEON_HD_5850;
62 if (modelNum >= 3000) {
63 return RADEON_HD_3000; // FL10_1
65 // HD 2000 is FL10_0, but webgl2 needs 10_1, so claim "old".
66 return RADEON_D3D_FL10_1;
68 // R5/7/9/X
69 return RADEON_R9_290;
71 static const std::regex kFirePro("FirePro.*?([VDW])[0-9][0-9][0-9]+");
72 if (std::regex_search(str, m, kFirePro)) {
73 const auto& vdw = m.str(1);
74 if (vdw == "V") {
75 return RADEON_HD_3000; // FL10_1
77 return RADEON_R9_290;
80 if (Contains(str, "RENOIR")) {
81 return RADEON_R9_290;
83 if (Contains(str, "ARUBA")) {
84 return RADEON_HD_5850;
87 return RADEON_D3D_FL10_1;
90 // -
92 static const std::string GEFORCE_8800 = "GeForce 8800 GTX";
93 static const std::string GEFORCE_480 = "GeForce GTX 480";
94 static const std::string GEFORCE_980 = "GeForce GTX 980";
96 if (Contains(str, "NVIDIA") || Contains(str, "GeForce") ||
97 Contains(str, "Quadro")) {
98 auto ret = std::invoke([&]() {
99 static const std::regex kGeForce("GeForce.*?([0-9][0-9][0-9]+)");
100 if (std::regex_search(str, m, kGeForce)) {
101 const auto modelNum = stoul(m.str(1));
102 if (modelNum >= 8000) {
103 // Tesla+: D3D10.0, SM4.0
104 return GEFORCE_8800;
106 if (modelNum >= 900) {
107 // Maxwell Gen2+: D3D12 FL12_1
108 return GEFORCE_980;
110 if (modelNum >= 400) {
111 // Fermi+: D3D12 FL11_0
112 return GEFORCE_480;
114 // Tesla+: D3D10.0, SM4.0
115 return GEFORCE_8800;
118 static const std::regex kQuadro("Quadro.*?([KMPVT]?)[0-9][0-9][0-9]+");
119 if (std::regex_search(str, m, kQuadro)) {
120 if (Contains(str, "RTX")) return GEFORCE_980;
121 const auto archLetter = m.str(1);
122 if (!archLetter.empty()) {
123 switch (archLetter[0]) {
124 case 'M': // Maxwell
125 case 'P': // Pascal
126 case 'V': // Volta
127 case 'T': // Turing, mobile-only
128 return GEFORCE_980;
129 case 'K': // Kepler
130 default:
131 return GEFORCE_480;
134 return GEFORCE_8800;
137 /* Similarities for Titans:
138 * 780
139 * * GeForce GTX TITAN
140 * * -
141 * * Black
142 * * Z
143 * 980
144 * * GeForce GTX TITAN X
145 * 1080
146 * * Nvidia TITAN X
147 * * Nvidia TITAN Xp
148 * * Nvidia TITAN V
149 * 2080
150 * * Nvidia TITAN RTX
152 static const std::regex kTitan("TITAN( [BZXVR])?");
153 if (std::regex_search(str, m, kTitan)) {
154 char letter = ' ';
155 const auto sub = m.str(1);
156 if (sub.length()) {
157 letter = sub[1];
159 switch (letter) {
160 case ' ':
161 case 'B':
162 case 'Z':
163 return GEFORCE_480;
164 default:
165 return GEFORCE_980;
168 // CI has str:"Tesla M60"
169 if (Contains(str, "Tesla")) return GEFORCE_8800;
171 return GEFORCE_8800; // Unknown, but NV.
173 // On ANGLE: NVIDIA GeForce RTX 3070...
174 // On WGL: GeForce RTX 3070...
175 if (str.find("NVIDIA") == 0) {
176 ret = "NVIDIA " + ret;
178 return ret;
181 static const std::regex kNouveau("NV(1?[0-9A-F][0-9A-F])");
182 if (std::regex_match(str, m, kNouveau)) {
183 const auto modelNum = stoul(m.str(1), nullptr, 16);
184 // https://nouveau.freedesktop.org/CodeNames.html#NV110
185 if (modelNum >= 0x120) return GEFORCE_980;
186 if (modelNum >= 0xC0) return GEFORCE_480;
187 return GEFORCE_8800;
190 // -
192 if (Contains(str, "Intel")) {
193 static const std::string HD_GRAPHICS = "Intel(R) HD Graphics";
194 static const std::string HD_GRAPHICS_400 = "Intel(R) HD Graphics 400";
195 static const std::string INTEL_945GM = "Intel 945GM";
197 static const std::regex kIntelHD("Intel.*Graphics( P?([0-9][0-9][0-9]+))?");
198 if (std::regex_search(str, m, kIntelHD)) {
199 if (m.str(1).empty()) {
200 return HD_GRAPHICS;
202 const auto modelNum = stoul(m.str(2));
203 if (modelNum >= 5000) {
204 return HD_GRAPHICS_400;
206 if (modelNum >= 1000) {
207 return HD_GRAPHICS;
209 return HD_GRAPHICS_400;
212 return INTEL_945GM;
215 // -
217 static const std::regex kAdreno("Adreno.*?([0-9][0-9][0-9]+)");
218 if (std::regex_search(str, m, kAdreno)) {
219 const auto modelNum = stoul(m.str(1));
220 if (modelNum >= 600) {
221 return "Adreno (TM) 650";
223 if (modelNum >= 500) {
224 return "Adreno (TM) 540";
226 if (modelNum >= 400) {
227 return "Adreno (TM) 430";
229 if (modelNum >= 300) {
230 return "Adreno (TM) 330";
232 return "Adreno (TM) 225";
235 static const std::regex kMali("Mali.*?([0-9][0-9]+)");
236 if (std::regex_search(str, m, kMali)) {
237 const auto modelNum = stoul(m.str(1));
238 if (modelNum >= 800) {
239 return "Mali-T880";
241 if (modelNum >= 700) {
242 return "Mali-T760";
244 if (modelNum >= 600) {
245 return "Mali-T628";
247 if (modelNum >= 400) {
248 return "Mali-400 MP";
250 return "Mali-G51";
253 if (Contains(str, "PowerVR")) {
254 if (Contains(str, "Rogue")) {
255 return "PowerVR Rogue G6200";
257 return "PowerVR SGX 540";
260 if (Contains(str, "Vivante")) return "Vivante GC1000";
261 if (Contains(str, "VideoCore")) return "VideoCore IV HW";
262 if (Contains(str, "Tegra")) return "NVIDIA Tegra";
264 // -
266 static const std::string D3D_WARP = "Microsoft Basic Render Driver";
267 if (Contains(str, D3D_WARP)) return str;
269 gfxCriticalNote << "Couldn't sanitize RENDERER device: " << str;
270 return "Generic Renderer";
273 // -
275 std::string SanitizeRenderer(const std::string& str) {
276 std::smatch m;
278 // e.g. "ANGLE (AMD, AMD Radeon(TM) Graphics Direct3D11 vs_5_0 ps_5_0,
279 // D3D11-27.20.1020.2002)"
280 static const std::regex kReAngle(
281 "ANGLE [(]([^,]*), ([^,]*)( Direct3D[^,]*), .*[)]");
282 if (std::regex_match(str, m, kReAngle)) {
283 const auto& vendor = m.str(1);
284 const auto& renderer = m.str(2);
285 const auto& d3d_suffix = m.str(3);
287 const auto renderer2 = ChooseDeviceReplacement(renderer);
288 return std::string("ANGLE (") + vendor + ", " + renderer2 + d3d_suffix +
289 ")";
290 } else if (Contains(str, "ANGLE")) {
291 gfxCriticalError() << "Failed to parse ANGLE renderer: " << str;
294 static const std::regex kReOpenglEngine("(.*) OpenGL Engine");
295 static const std::regex kRePcieSse2("(.*)(/PCIe?/SSE2)");
296 static const std::regex kReStandard("(.*)( [(].*[)])");
297 if (std::regex_match(str, m, kReOpenglEngine)) {
298 const auto& dev = m.str(1);
299 const auto dev2 = ChooseDeviceReplacement(dev);
300 return dev2;
302 if (std::regex_match(str, m, kRePcieSse2)) {
303 const auto& dev = m.str(1);
304 const auto dev2 = ChooseDeviceReplacement(dev);
305 return dev2 + m.str(2);
307 if (std::regex_match(str, m, kReStandard)) {
308 const auto& dev = m.str(1);
309 const auto dev2 = ChooseDeviceReplacement(dev);
310 return dev2;
313 const auto& dev = str;
314 const auto dev2 = ChooseDeviceReplacement(dev);
315 return dev2;
318 }; // namespace webgl
319 }; // namespace mozilla