gl_version_info.cc 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362
  1. // Copyright 2014 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #include "ui/gl/gl_version_info.h"
  5. #include <map>
  6. #include <vector>
  7. #include "base/check_op.h"
  8. #include "base/notreached.h"
  9. #include "base/strings/strcat.h"
  10. #include "base/strings/string_split.h"
  11. #include "base/strings/string_util.h"
  12. #include "base/version.h"
  13. namespace {
  14. bool DesktopCoreCommonCheck(
  15. bool is_es, unsigned major_version, unsigned minor_version) {
  16. return (!is_es &&
  17. ((major_version == 3 && minor_version >= 2) ||
  18. major_version > 3));
  19. }
  20. static bool disable_es3_for_testing = false;
  21. } // namespace
  22. namespace gl {
  23. GLVersionInfo::GLVersionInfo(const char* version_str,
  24. const char* renderer_str,
  25. const gfx::ExtensionSet& extensions) {
  26. Initialize(version_str, renderer_str, extensions);
  27. }
  28. void GLVersionInfo::Initialize(const char* version_str,
  29. const char* renderer_str,
  30. const gfx::ExtensionSet& extensions) {
  31. if (version_str) {
  32. ParseVersionString(version_str);
  33. ParseDriverInfo(version_str);
  34. }
  35. // ANGLE's version string does not contain useful information for
  36. // GLVersionInfo. If we are going to parse the version string and we're using
  37. // ANGLE, we must also parse ANGLE's renderer string, which contains the
  38. // driver's version string.
  39. DCHECK(renderer_str || driver_vendor != "ANGLE");
  40. if (renderer_str) {
  41. std::string renderer_string = std::string(renderer_str);
  42. is_angle = base::StartsWith(renderer_str, "ANGLE",
  43. base::CompareCase::SENSITIVE);
  44. is_mesa = base::StartsWith(renderer_str, "Mesa",
  45. base::CompareCase::SENSITIVE);
  46. if (is_angle) {
  47. is_angle_swiftshader =
  48. renderer_string.find("SwiftShader Device") != std::string::npos;
  49. is_angle_vulkan = renderer_string.find("Vulkan") != std::string::npos;
  50. is_angle_metal = renderer_string.find("ANGLE Metal") != std::string::npos;
  51. }
  52. is_swiftshader = base::StartsWith(renderer_str, "Google SwiftShader",
  53. base::CompareCase::SENSITIVE);
  54. // An ANGLE renderer string contains "Direct3D9", "Direct3DEx", or
  55. // "Direct3D11" on D3D backends.
  56. is_d3d = renderer_string.find("Direct3D") != std::string::npos;
  57. // (is_d3d should only be possible if is_angle is true.)
  58. DCHECK(!is_d3d || is_angle);
  59. if (is_angle && driver_vendor == "ANGLE")
  60. ExtractDriverVendorANGLE(renderer_str);
  61. }
  62. is_desktop_core_profile =
  63. DesktopCoreCommonCheck(is_es, major_version, minor_version) &&
  64. !gfx::HasExtension(extensions, "GL_ARB_compatibility");
  65. is_es3_capable = IsES3Capable(extensions);
  66. // Post-fixup in case the user requested disabling ES3 capability
  67. // for testing purposes.
  68. if (disable_es3_for_testing) {
  69. is_es3_capable = false;
  70. if (is_es) {
  71. major_version = 2;
  72. minor_version = 0;
  73. is_es2 = true;
  74. is_es3 = false;
  75. } else {
  76. major_version = 3;
  77. minor_version = 2;
  78. }
  79. }
  80. }
  81. void GLVersionInfo::ParseVersionString(const char* version_str) {
  82. // Make sure the outputs are always initialized.
  83. major_version = 0;
  84. minor_version = 0;
  85. is_es = false;
  86. is_es2 = false;
  87. is_es3 = false;
  88. if (!version_str)
  89. return;
  90. base::StringPiece lstr(version_str);
  91. constexpr base::StringPiece kESPrefix = "OpenGL ES ";
  92. if (base::StartsWith(lstr, kESPrefix, base::CompareCase::SENSITIVE)) {
  93. is_es = true;
  94. lstr.remove_prefix(kESPrefix.size());
  95. }
  96. std::vector<base::StringPiece> pieces = base::SplitStringPiece(
  97. lstr, " -()@", base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY);
  98. if (pieces.size() == 0) {
  99. // This should never happen, but let's just tolerate bad driver behavior.
  100. return;
  101. }
  102. if (is_es) {
  103. // Desktop GL doesn't specify the GL_VERSION format, but ES spec requires
  104. // the string to be in the format of "OpenGL ES major.minor other_info".
  105. DCHECK_LE(3u, pieces[0].size());
  106. if (pieces[0].size() > 0 && pieces[0].back() == 'V') {
  107. // On Nexus 6 with Android N, GL_VERSION string is not spec compliant.
  108. // There is no space between "3.1" and "V@104.0".
  109. pieces[0].remove_suffix(1);
  110. }
  111. }
  112. std::string gl_version(pieces[0]);
  113. base::Version version(gl_version);
  114. if (version.IsValid()) {
  115. if (version.components().size() >= 1) {
  116. major_version = version.components()[0];
  117. }
  118. if (version.components().size() >= 2) {
  119. minor_version = version.components()[1];
  120. }
  121. if (is_es) {
  122. if (major_version == 2)
  123. is_es2 = true;
  124. if (major_version == 3)
  125. is_es3 = true;
  126. }
  127. }
  128. }
  129. void GLVersionInfo::ParseDriverInfo(const char* version_str) {
  130. if (!version_str)
  131. return;
  132. base::StringPiece lstr(version_str);
  133. constexpr base::StringPiece kESPrefix = "OpenGL ES ";
  134. if (base::StartsWith(lstr, kESPrefix, base::CompareCase::SENSITIVE)) {
  135. lstr.remove_prefix(kESPrefix.size());
  136. }
  137. std::vector<base::StringPiece> pieces = base::SplitStringPiece(
  138. lstr, " -()@", base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY);
  139. if (pieces.size() == 0) {
  140. // This should never happen, but let's just tolerate bad driver behavior.
  141. return;
  142. }
  143. if (is_es) {
  144. // Desktop GL doesn't specify the GL_VERSION format, but ES spec requires
  145. // the string to be in the format of "OpenGL ES major.minor other_info".
  146. DCHECK_LE(3u, pieces[0].size());
  147. if (pieces[0].size() > 0 && pieces[0].back() == 'V') {
  148. // On Nexus 6 with Android N, GL_VERSION string is not spec compliant.
  149. // There is no space between "3.1" and "V@104.0".
  150. pieces[0].remove_suffix(1);
  151. }
  152. }
  153. if (pieces.size() == 1)
  154. return;
  155. // Map key strings to driver vendors. We assume the key string is followed by
  156. // the driver version.
  157. const std::map<base::StringPiece, base::StringPiece> kVendors = {
  158. {"ANGLE", "ANGLE"}, {"Mesa", "Mesa"}, {"INTEL", "INTEL"},
  159. {"NVIDIA", "NVIDIA"}, {"ATI", "ATI"}, {"FireGL", "FireGL"},
  160. {"Chromium", "Chromium"}, {"APPLE", "APPLE"}, {"AMD", "AMD"},
  161. {"Metal", "Apple"}};
  162. for (size_t ii = 1; ii < pieces.size(); ++ii) {
  163. for (auto vendor : kVendors) {
  164. if (pieces[ii] == vendor.first) {
  165. driver_vendor.assign(vendor.second.data(), vendor.second.size());
  166. if (ii + 1 < pieces.size())
  167. driver_version.assign(pieces[ii + 1].data(), pieces[ii + 1].size());
  168. return;
  169. }
  170. }
  171. }
  172. if (pieces.size() == 2) {
  173. if (pieces[1][0] == 'V')
  174. pieces[1].remove_prefix(1);
  175. driver_version.assign(pieces[1].data(), pieces[1].size());
  176. return;
  177. }
  178. constexpr base::StringPiece kMaliPrefix = "v1.r";
  179. if (base::StartsWith(pieces[1], kMaliPrefix, base::CompareCase::SENSITIVE)) {
  180. // Mali drivers: v1.r12p0-04rel0.44f2946824bb8739781564bffe2110c9
  181. pieces[1].remove_prefix(kMaliPrefix.size());
  182. std::vector<base::StringPiece> numbers = base::SplitStringPiece(
  183. pieces[1], "p", base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY);
  184. if (numbers.size() != 2)
  185. return;
  186. std::vector<base::StringPiece> parts = base::SplitStringPiece(
  187. pieces[2], ".", base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY);
  188. if (parts.size() != 2)
  189. return;
  190. driver_vendor = "ARM";
  191. driver_version = base::StrCat({numbers[0], ".", numbers[1], ".", parts[0]});
  192. return;
  193. }
  194. for (size_t ii = 1; ii < pieces.size(); ++ii) {
  195. if (pieces[ii].find('.') != std::string::npos) {
  196. driver_version.assign(pieces[ii].data(), pieces[ii].size());
  197. return;
  198. }
  199. }
  200. }
  201. void GLVersionInfo::ExtractDriverVendorANGLE(const char* renderer_str) {
  202. DCHECK(renderer_str);
  203. DCHECK(is_angle);
  204. DCHECK_EQ("ANGLE", driver_vendor);
  205. base::StringPiece rstr(renderer_str);
  206. DCHECK(base::StartsWith(rstr, "ANGLE (", base::CompareCase::SENSITIVE));
  207. rstr = rstr.substr(sizeof("ANGLE (") - 1, rstr.size() - sizeof("ANGLE ("));
  208. // ANGLE's renderer string returns a format matching ANGLE (GL_VENDOR,
  209. // GL_RENDERER, GL_VERSION)
  210. std::vector<base::StringPiece> gl_strings = base::SplitStringPiece(
  211. rstr, ",", base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY);
  212. // The 3rd part of the renderer string contains the native driver's version
  213. // string. We should parse it here to override anything parsed from ANGLE's
  214. // GL_VERSION string, which only contains information about the ANGLE version.
  215. if (gl_strings.size() >= 3) {
  216. // The first part of the renderer string contains the native driver's
  217. // vendor string.
  218. driver_vendor.assign(gl_strings[0].data(), gl_strings[0].size());
  219. std::string native_version_str;
  220. base::TrimString(gl_strings[2], ")", &native_version_str);
  221. ParseDriverInfo(native_version_str.c_str());
  222. return;
  223. }
  224. if (base::StartsWith(rstr, "Vulkan ", base::CompareCase::SENSITIVE)) {
  225. size_t pos = rstr.find('(');
  226. if (pos != std::string::npos)
  227. rstr = rstr.substr(pos + 1, rstr.size() - 2);
  228. }
  229. if (is_angle_swiftshader) {
  230. DCHECK(base::StartsWith(rstr, "SwiftShader", base::CompareCase::SENSITIVE));
  231. driver_vendor = "ANGLE (Google)";
  232. }
  233. if (is_angle_metal) {
  234. DCHECK(base::StartsWith(rstr, "ANGLE Metal", base::CompareCase::SENSITIVE));
  235. }
  236. if (base::StartsWith(rstr, "NVIDIA ", base::CompareCase::SENSITIVE))
  237. driver_vendor = "ANGLE (NVIDIA)";
  238. else if (base::StartsWith(rstr, "Radeon ", base::CompareCase::SENSITIVE))
  239. driver_vendor = "ANGLE (AMD)";
  240. else if (base::StartsWith(rstr, "Intel", base::CompareCase::SENSITIVE)) {
  241. std::vector<base::StringPiece> pieces = base::SplitStringPiece(
  242. rstr, ",", base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY);
  243. for (size_t ii = 0; ii < pieces.size(); ++ii) {
  244. if (base::StartsWith(pieces[ii], "Intel(R) ",
  245. base::CompareCase::SENSITIVE)) {
  246. driver_vendor = "ANGLE (Intel)";
  247. break;
  248. }
  249. }
  250. }
  251. }
  252. bool GLVersionInfo::IsES3Capable(const gfx::ExtensionSet& extensions) const {
  253. // Version ES3 capable without extensions needed.
  254. if (IsAtLeastGLES(3, 0) || IsAtLeastGL(4, 2)) {
  255. return true;
  256. }
  257. // Don't try supporting ES3 on ES2, or desktop before 3.3.
  258. if (is_es || !IsAtLeastGL(3, 3)) {
  259. return false;
  260. }
  261. bool has_transform_feedback =
  262. (IsAtLeastGL(4, 0) ||
  263. gfx::HasExtension(extensions, "GL_ARB_transform_feedback2"));
  264. // This code used to require the GL_ARB_gpu_shader5 extension in order to
  265. // have support for dynamic indexing of sampler arrays, which was
  266. // optionally supported in ESSL 1.00. However, since this is expressly
  267. // forbidden in ESSL 3.00, and some desktop drivers (specifically
  268. // Mesa/Gallium on AMD GPUs) don't support it, we no longer require it.
  269. // tex storage is available in core spec since GL 4.2.
  270. bool has_tex_storage =
  271. gfx::HasExtension(extensions, "GL_ARB_texture_storage");
  272. // TODO(cwallez) check for texture related extensions. See crbug.com/623577
  273. return (has_transform_feedback && has_tex_storage);
  274. }
  275. void GLVersionInfo::DisableES3ForTesting() {
  276. disable_es3_for_testing = true;
  277. }
  278. bool GLVersionInfo::IsVersionSubstituted() const {
  279. // This is the only reason we're changing versions right now
  280. return disable_es3_for_testing;
  281. }
  282. GLVersionInfo::VersionStrings GLVersionInfo::GetFakeVersionStrings(
  283. unsigned major,
  284. unsigned minor) const {
  285. VersionStrings result;
  286. if (is_es) {
  287. if (major == 2) {
  288. result.gl_version = "OpenGL ES 2.0";
  289. result.glsl_version = "OpenGL ES GLSL ES 1.00";
  290. } else if (major == 3) {
  291. result.gl_version = "OpenGL ES 3.0";
  292. result.glsl_version = "OpenGL ES GLSL ES 3.00";
  293. } else {
  294. NOTREACHED();
  295. }
  296. } else {
  297. if (major == 4 && minor == 1) {
  298. result.gl_version = "4.1";
  299. result.glsl_version = "4.10";
  300. } else if (major == 4 && minor == 0) {
  301. result.gl_version = "4.0";
  302. result.glsl_version = "4.00";
  303. } else if (major == 3 && minor == 3) {
  304. result.gl_version = "3.3";
  305. result.glsl_version = "3.30";
  306. } else if (major == 3 && minor == 2) {
  307. result.gl_version = "3.2";
  308. result.glsl_version = "1.50";
  309. } else if (major == 3 && minor == 1) {
  310. result.gl_version = "3.1";
  311. result.glsl_version = "1.40";
  312. } else if (major == 3 && minor == 0) {
  313. result.gl_version = "3.0";
  314. result.glsl_version = "1.30";
  315. } else if (major == 2 && minor == 1) {
  316. result.gl_version = "2.1";
  317. result.glsl_version = "1.20";
  318. } else if (major == 2 && minor == 0) {
  319. result.gl_version = "2.0";
  320. result.glsl_version = "1.10";
  321. } else {
  322. NOTREACHED();
  323. }
  324. }
  325. return result;
  326. }
  327. } // namespace gl