blob: faeb664b63c9985e7e60b39b9c0266fafa7dfe05 [file] [log] [blame]
[email protected]3b7efa42012-02-08 19:41:441// Copyright (c) 2012 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
[email protected]d7b5cc72013-05-23 20:05:005#include "gpu/config/gpu_info_collector.h"
[email protected]3b7efa42012-02-08 19:41:446
avif15d60a2015-12-21 17:06:337#include <stddef.h>
8#include <stdint.h>
9
[email protected]33eeba7b92013-02-06 01:47:0310#include "base/android/build_info.h"
kkinnunenef49d532016-02-03 07:47:0011#include "base/android/jni_android.h"
[email protected]f34ffdf22012-12-15 00:41:2712#include "base/command_line.h"
tobiasjsca238b3b2015-06-24 22:53:5413#include "base/files/file_path.h"
[email protected]3b7efa42012-02-08 19:41:4414#include "base/logging.h"
tobiasjsca238b3b2015-06-24 22:53:5415#include "base/native_library.h"
[email protected]f4390962013-06-11 07:29:2216#include "base/strings/string_number_conversions.h"
[email protected]b9e7c479f2013-04-12 04:33:2417#include "base/strings/string_piece.h"
[email protected]27c05732013-02-15 21:55:4918#include "base/strings/string_split.h"
[email protected]f4390962013-06-11 07:29:2219#include "base/strings/string_util.h"
tobiasjsca238b3b2015-06-24 22:53:5420#include "base/strings/stringprintf.h"
j.isorce47305c8a2016-08-17 14:35:0121#include "gpu/config/gpu_switches.h"
tobiasjsca238b3b2015-06-24 22:53:5422#include "ui/gl/egl_util.h"
[email protected]1a212472013-10-01 01:40:4823#include "ui/gl/gl_bindings.h"
24#include "ui/gl/gl_context.h"
25#include "ui/gl/gl_surface.h"
[email protected]bd4d2f732012-11-19 22:19:3626
27namespace {
28
tobiasjsca238b3b2015-06-24 22:53:5429std::pair<std::string, size_t> GetVersionFromString(
30 const std::string& version_string,
31 size_t begin = 0) {
32 begin = version_string.find_first_of("0123456789", begin);
33 if (begin == std::string::npos)
34 return std::make_pair("", std::string::npos);
35
36 size_t end = version_string.find_first_not_of("01234567890.", begin);
37 std::string sub_string;
38 if (end != std::string::npos)
39 sub_string = version_string.substr(begin, end - begin);
40 else
41 sub_string = version_string.substr(begin);
brettw26dab8f02015-08-08 00:28:4742 std::vector<std::string> pieces = base::SplitString(
43 sub_string, ".", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
tobiasjsca238b3b2015-06-24 22:53:5444 if (pieces.size() >= 2)
45 return std::make_pair(pieces[0] + "." + pieces[1], end);
46 else
47 return std::make_pair("", end);
48}
49
[email protected]bd4d2f732012-11-19 22:19:3650std::string GetDriverVersionFromString(const std::string& version_string) {
tobiasjsf9268962015-06-05 12:38:1151 // We expect that android GL_VERSION strings will be of a form
52 // similar to: "OpenGL ES 2.0 [email protected] AU@ (CL@2946718)" where the
53 // first match to [0-9][0-9.]* is the OpenGL ES version number, and
54 // the second match to [0-9][0-9.]* is the driver version (in this
55 // case, 6.0).
56 // It is currently assumed that the driver version has at least one
57 // period in it, and only the first two components are significant.
tobiasjsca238b3b2015-06-24 22:53:5458 size_t begin = GetVersionFromString(version_string).second;
[email protected]bd4d2f732012-11-19 22:19:3659 if (begin == std::string::npos)
60 return "0";
[email protected]bd4d2f732012-11-19 22:19:3661
tobiasjsca238b3b2015-06-24 22:53:5462 std::pair<std::string, size_t> driver_version =
63 GetVersionFromString(version_string, begin);
64 if (driver_version.first == "")
[email protected]bd4d2f732012-11-19 22:19:3665 return "0";
tobiasjsca238b3b2015-06-24 22:53:5466
67 return driver_version.first;
[email protected]bd4d2f732012-11-19 22:19:3668}
69
tobiasjsca238b3b2015-06-24 22:53:5470gpu::CollectInfoResult CollectDriverInfo(gpu::GPUInfo* gpu_info) {
71 // Go through the process of loading GL libs and initializing an EGL
72 // context so that we can get GL vendor/version/renderer strings.
73 base::NativeLibrary gles_library, egl_library;
74 base::NativeLibraryLoadError error;
75 gles_library =
76 base::LoadNativeLibrary(base::FilePath("libGLESv2.so"), &error);
77 if (!gles_library)
78 LOG(FATAL) << "Failed to load libGLESv2.so";
[email protected]1a212472013-10-01 01:40:4879
tobiasjsca238b3b2015-06-24 22:53:5480 egl_library = base::LoadNativeLibrary(base::FilePath("libEGL.so"), &error);
81 if (!egl_library)
82 LOG(FATAL) << "Failed to load libEGL.so";
[email protected]1a212472013-10-01 01:40:4883
tobiasjsca238b3b2015-06-24 22:53:5484 typedef void* (*eglGetProcAddressProc)(const char* name);
[email protected]1a212472013-10-01 01:40:4885
tobiasjsca238b3b2015-06-24 22:53:5486 auto eglGetProcAddressFn = reinterpret_cast<eglGetProcAddressProc>(
87 base::GetFunctionPointerFromNativeLibrary(egl_library,
88 "eglGetProcAddress"));
89 if (!eglGetProcAddressFn)
90 LOG(FATAL) << "eglGetProcAddress not found.";
[email protected]1a212472013-10-01 01:40:4891
tobiasjsca238b3b2015-06-24 22:53:5492 auto get_func = [eglGetProcAddressFn, gles_library, egl_library](
93 const char* name) {
94 void *proc;
95 proc = base::GetFunctionPointerFromNativeLibrary(egl_library, name);
96 if (proc)
97 return proc;
98 proc = base::GetFunctionPointerFromNativeLibrary(gles_library, name);
99 if (proc)
100 return proc;
101 proc = eglGetProcAddressFn(name);
102 if (proc)
103 return proc;
104 LOG(FATAL) << "Failed to look up " << name;
105 return (void *)nullptr;
106 };
[email protected]1a212472013-10-01 01:40:48107
kylechar7a463842016-05-26 14:46:12108#define LOOKUP_FUNC(x) auto x##Fn = reinterpret_cast<gl::x##Proc>(get_func(#x))
tobiasjsca238b3b2015-06-24 22:53:54109
110 LOOKUP_FUNC(eglGetError);
111 LOOKUP_FUNC(eglQueryString);
112 LOOKUP_FUNC(eglGetCurrentContext);
113 LOOKUP_FUNC(eglGetCurrentDisplay);
114 LOOKUP_FUNC(eglGetCurrentSurface);
115 LOOKUP_FUNC(eglGetDisplay);
116 LOOKUP_FUNC(eglInitialize);
117 LOOKUP_FUNC(eglChooseConfig);
118 LOOKUP_FUNC(eglCreateContext);
119 LOOKUP_FUNC(eglCreatePbufferSurface);
120 LOOKUP_FUNC(eglMakeCurrent);
121 LOOKUP_FUNC(eglDestroySurface);
122 LOOKUP_FUNC(eglDestroyContext);
123
124 LOOKUP_FUNC(glGetString);
125 LOOKUP_FUNC(glGetIntegerv);
126
127#undef LOOKUP_FUNC
128
129 EGLDisplay curr_display = eglGetCurrentDisplayFn();
130 EGLContext curr_context = eglGetCurrentContextFn();
131 EGLSurface curr_draw_surface = eglGetCurrentSurfaceFn(EGL_DRAW);
132 EGLSurface curr_read_surface = eglGetCurrentSurfaceFn(EGL_READ);
133
134 EGLDisplay temp_display = EGL_NO_DISPLAY;
135 EGLContext temp_context = EGL_NO_CONTEXT;
136 EGLSurface temp_surface = EGL_NO_SURFACE;
137
138 const EGLint kConfigAttribs[] = {
139 EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
140 EGL_SURFACE_TYPE, EGL_PBUFFER_BIT,
141 EGL_NONE};
142 const EGLint kContextAttribs[] = {
143 EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_EXT,
144 EGL_LOSE_CONTEXT_ON_RESET_EXT,
145 EGL_CONTEXT_CLIENT_VERSION, 2,
146 EGL_NONE};
147 const EGLint kSurfaceAttribs[] = {
148 EGL_WIDTH, 1,
149 EGL_HEIGHT, 1,
150 EGL_NONE};
151
152 EGLint major, minor;
153
154 EGLConfig config;
155 EGLint num_configs;
156
157 auto errorstr = [eglGetErrorFn]() {
158 uint32_t err = eglGetErrorFn();
159 return base::StringPrintf("%s (%x)", ui::GetEGLErrorString(err), err);
160 };
161
162 temp_display = eglGetDisplayFn(EGL_DEFAULT_DISPLAY);
163
164 if (temp_display == EGL_NO_DISPLAY) {
165 LOG(FATAL) << "failed to get display. " << errorstr();
166 }
167
168 eglInitializeFn(temp_display, &major, &minor);
169
170 bool egl_create_context_robustness_supported =
171 strstr(reinterpret_cast<const char*>(
172 eglQueryStringFn(temp_display, EGL_EXTENSIONS)),
173 "EGL_EXT_create_context_robustness") != NULL;
174
175 if (!eglChooseConfigFn(temp_display, kConfigAttribs, &config, 1,
176 &num_configs)) {
177 LOG(FATAL) << "failed to choose an egl config. " << errorstr();
178 }
179
180 temp_context = eglCreateContextFn(
181 temp_display, config, EGL_NO_CONTEXT,
182 kContextAttribs + (egl_create_context_robustness_supported ? 0 : 2));
183 if (temp_context == EGL_NO_CONTEXT) {
184 LOG(FATAL)
185 << "failed to create a temporary context for fetching driver strings. "
186 << errorstr();
187 }
188
189 temp_surface =
190 eglCreatePbufferSurfaceFn(temp_display, config, kSurfaceAttribs);
191
192 if (temp_surface == EGL_NO_SURFACE) {
193 eglDestroyContextFn(temp_display, temp_context);
194 LOG(FATAL)
195 << "failed to create a pbuffer surface for fetching driver strings. "
196 << errorstr();
197 }
198
199 eglMakeCurrentFn(temp_display, temp_surface, temp_surface, temp_context);
200
201 gpu_info->gl_vendor = reinterpret_cast<const char*>(glGetStringFn(GL_VENDOR));
202 gpu_info->gl_version =
203 reinterpret_cast<const char*>(glGetStringFn(GL_VERSION));
204 gpu_info->gl_renderer =
205 reinterpret_cast<const char*>(glGetStringFn(GL_RENDERER));
206 gpu_info->gl_extensions =
207 reinterpret_cast<const char*>(glGetStringFn(GL_EXTENSIONS));
208
j.isorce47305c8a2016-08-17 14:35:01209 base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
210 if (command_line->HasSwitch(switches::kGpuTestingGLVendor)) {
211 gpu_info->gl_vendor =
212 command_line->GetSwitchValueASCII(switches::kGpuTestingGLVendor);
213 }
214 if (command_line->HasSwitch(switches::kGpuTestingGLRenderer)) {
215 gpu_info->gl_renderer =
216 command_line->GetSwitchValueASCII(switches::kGpuTestingGLRenderer);
217 }
218 if (command_line->HasSwitch(switches::kGpuTestingGLVersion)) {
219 gpu_info->gl_version =
220 command_line->GetSwitchValueASCII(switches::kGpuTestingGLVersion);
221 }
222
tobiasjsca238b3b2015-06-24 22:53:54223 GLint max_samples = 0;
224 glGetIntegervFn(GL_MAX_SAMPLES, &max_samples);
riceaa01edead2015-07-01 15:56:50225 gpu_info->max_msaa_samples = base::IntToString(max_samples);
tobiasjsca238b3b2015-06-24 22:53:54226
227 bool supports_robustness =
228 gpu_info->gl_extensions.find("GL_EXT_robustness") != std::string::npos ||
229 gpu_info->gl_extensions.find("GL_KHR_robustness") != std::string::npos ||
230 gpu_info->gl_extensions.find("GL_ARB_robustness") != std::string::npos;
231
232 if (supports_robustness) {
233 glGetIntegervFn(
234 GL_RESET_NOTIFICATION_STRATEGY_ARB,
235 reinterpret_cast<GLint*>(&gpu_info->gl_reset_notification_strategy));
236 }
237
davve4af61ccf2015-10-09 07:51:24238 std::string glsl_version_string;
239 if (const char* glsl_version_cstring = reinterpret_cast<const char*>(
240 glGetStringFn(GL_SHADING_LANGUAGE_VERSION)))
241 glsl_version_string = glsl_version_cstring;
tobiasjsca238b3b2015-06-24 22:53:54242
243 std::string glsl_version = GetVersionFromString(glsl_version_string).first;
244 gpu_info->pixel_shader_version = glsl_version;
245 gpu_info->vertex_shader_version = glsl_version;
246
247 if (curr_display != EGL_NO_DISPLAY &&
248 curr_context != EGL_NO_CONTEXT) {
249 eglMakeCurrentFn(curr_display, curr_draw_surface, curr_read_surface,
250 curr_context);
251 } else {
252 eglMakeCurrentFn(temp_display, EGL_NO_SURFACE, EGL_NO_SURFACE,
253 EGL_NO_CONTEXT);
254 }
255
256 eglDestroySurfaceFn(temp_display, temp_surface);
257 eglDestroyContextFn(temp_display, temp_context);
258
259 return gpu::kCollectInfoSuccess;
[email protected]1a212472013-10-01 01:40:48260}
261
[email protected]bd4d2f732012-11-19 22:19:36262}
[email protected]3b7efa42012-02-08 19:41:44263
[email protected]d7b5cc72013-05-23 20:05:00264namespace gpu {
[email protected]3b7efa42012-02-08 19:41:44265
[email protected]0e8cac72014-03-22 00:37:18266CollectInfoResult CollectContextGraphicsInfo(GPUInfo* gpu_info) {
tobiasjsca238b3b2015-06-24 22:53:54267 /// TODO(tobiasjs) Check if CollectGraphicsInfo in gpu_main.cc
268 /// really only needs basic graphics info on all platforms, and if
269 /// so switch it to using that and make this the NOP that it really
270 /// should be, to avoid potential double collection of info.
[email protected]289126f2013-05-17 00:12:38271 return CollectBasicGraphicsInfo(gpu_info);
[email protected]3b7efa42012-02-08 19:41:44272}
273
avif15d60a2015-12-21 17:06:33274CollectInfoResult CollectGpuID(uint32_t* vendor_id, uint32_t* device_id) {
[email protected]12e74bb2013-02-07 22:08:44275 DCHECK(vendor_id && device_id);
276 *vendor_id = 0;
277 *device_id = 0;
zmo84eae5e2014-09-05 01:36:23278 return kCollectInfoNonFatalFailure;
[email protected]12e74bb2013-02-07 22:08:44279}
280
[email protected]0e8cac72014-03-22 00:37:18281CollectInfoResult CollectBasicGraphicsInfo(GPUInfo* gpu_info) {
kkinnunenef49d532016-02-03 07:47:00282 // When command buffer is compiled as a standalone library, the process might
283 // not have a Java environment.
284 if (base::android::IsVMInitialized()) {
285 gpu_info->machine_model_name =
286 base::android::BuildInfo::GetInstance()->model();
287 }
[email protected]289126f2013-05-17 00:12:38288
[email protected]bd4d2f732012-11-19 22:19:36289 // Create a short-lived context on the UI thread to collect the GL strings.
[email protected]1a212472013-10-01 01:40:48290 // Make sure we restore the existing context if there is one.
tobiasjsca238b3b2015-06-24 22:53:54291 CollectInfoResult result = CollectDriverInfo(gpu_info);
292 if (result == kCollectInfoSuccess)
293 result = CollectDriverInfoGL(gpu_info);
zmo84eae5e2014-09-05 01:36:23294 gpu_info->basic_info_state = result;
295 gpu_info->context_info_state = result;
296 return result;
[email protected]3b7efa42012-02-08 19:41:44297}
298
[email protected]0e8cac72014-03-22 00:37:18299CollectInfoResult CollectDriverInfoGL(GPUInfo* gpu_info) {
[email protected]bd4d2f732012-11-19 22:19:36300 gpu_info->driver_version = GetDriverVersionFromString(
[email protected]39c542622014-05-07 22:16:36301 gpu_info->gl_version);
[email protected]53d6c602013-10-14 11:50:36302 gpu_info->gpu.vendor_string = gpu_info->gl_vendor;
303 gpu_info->gpu.device_string = gpu_info->gl_renderer;
[email protected]0e8cac72014-03-22 00:37:18304 return kCollectInfoSuccess;
[email protected]3b7efa42012-02-08 19:41:44305}
306
[email protected]d7b5cc72013-05-23 20:05:00307void MergeGPUInfo(GPUInfo* basic_gpu_info,
308 const GPUInfo& context_gpu_info) {
[email protected]4df0884f2012-12-17 21:10:09309 MergeGPUInfoGL(basic_gpu_info, context_gpu_info);
310}
311
[email protected]d7b5cc72013-05-23 20:05:00312} // namespace gpu