Roll src/third_party/WebKit dbf9be3:8d6c3d5 (svn 202308:202312)
[chromium-blink-merge.git] / gpu / config / gpu_info_collector_android.cc
blobc6d9b19456a6176714fded5252f1405cb6697e1d
1 // 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.
5 #include "gpu/config/gpu_info_collector.h"
7 #include "base/android/build_info.h"
8 #include "base/command_line.h"
9 #include "base/files/file_path.h"
10 #include "base/logging.h"
11 #include "base/native_library.h"
12 #include "base/strings/string_number_conversions.h"
13 #include "base/strings/string_piece.h"
14 #include "base/strings/string_split.h"
15 #include "base/strings/string_util.h"
16 #include "base/strings/stringprintf.h"
17 #include "ui/gl/egl_util.h"
18 #include "ui/gl/gl_bindings.h"
19 #include "ui/gl/gl_context.h"
20 #include "ui/gl/gl_surface.h"
22 namespace {
24 std::pair<std::string, size_t> GetVersionFromString(
25 const std::string& version_string,
26 size_t begin = 0) {
27 begin = version_string.find_first_of("0123456789", begin);
28 if (begin == std::string::npos)
29 return std::make_pair("", std::string::npos);
31 size_t end = version_string.find_first_not_of("01234567890.", begin);
32 std::string sub_string;
33 if (end != std::string::npos)
34 sub_string = version_string.substr(begin, end - begin);
35 else
36 sub_string = version_string.substr(begin);
37 std::vector<std::string> pieces = base::SplitString(
38 sub_string, ".", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
39 if (pieces.size() >= 2)
40 return std::make_pair(pieces[0] + "." + pieces[1], end);
41 else
42 return std::make_pair("", end);
45 std::string GetDriverVersionFromString(const std::string& version_string) {
46 // We expect that android GL_VERSION strings will be of a form
47 // similar to: "OpenGL ES 2.0 V@6.0 AU@ (CL@2946718)" where the
48 // first match to [0-9][0-9.]* is the OpenGL ES version number, and
49 // the second match to [0-9][0-9.]* is the driver version (in this
50 // case, 6.0).
51 // It is currently assumed that the driver version has at least one
52 // period in it, and only the first two components are significant.
53 size_t begin = GetVersionFromString(version_string).second;
54 if (begin == std::string::npos)
55 return "0";
57 std::pair<std::string, size_t> driver_version =
58 GetVersionFromString(version_string, begin);
59 if (driver_version.first == "")
60 return "0";
62 return driver_version.first;
65 gpu::CollectInfoResult CollectDriverInfo(gpu::GPUInfo* gpu_info) {
66 // Go through the process of loading GL libs and initializing an EGL
67 // context so that we can get GL vendor/version/renderer strings.
68 base::NativeLibrary gles_library, egl_library;
69 base::NativeLibraryLoadError error;
70 gles_library =
71 base::LoadNativeLibrary(base::FilePath("libGLESv2.so"), &error);
72 if (!gles_library)
73 LOG(FATAL) << "Failed to load libGLESv2.so";
75 egl_library = base::LoadNativeLibrary(base::FilePath("libEGL.so"), &error);
76 if (!egl_library)
77 LOG(FATAL) << "Failed to load libEGL.so";
79 typedef void* (*eglGetProcAddressProc)(const char* name);
81 auto eglGetProcAddressFn = reinterpret_cast<eglGetProcAddressProc>(
82 base::GetFunctionPointerFromNativeLibrary(egl_library,
83 "eglGetProcAddress"));
84 if (!eglGetProcAddressFn)
85 LOG(FATAL) << "eglGetProcAddress not found.";
87 auto get_func = [eglGetProcAddressFn, gles_library, egl_library](
88 const char* name) {
89 void *proc;
90 proc = base::GetFunctionPointerFromNativeLibrary(egl_library, name);
91 if (proc)
92 return proc;
93 proc = base::GetFunctionPointerFromNativeLibrary(gles_library, name);
94 if (proc)
95 return proc;
96 proc = eglGetProcAddressFn(name);
97 if (proc)
98 return proc;
99 LOG(FATAL) << "Failed to look up " << name;
100 return (void *)nullptr;
103 #define LOOKUP_FUNC(x) auto x##Fn = reinterpret_cast<gfx::x##Proc>(get_func(#x))
105 LOOKUP_FUNC(eglGetError);
106 LOOKUP_FUNC(eglQueryString);
107 LOOKUP_FUNC(eglGetCurrentContext);
108 LOOKUP_FUNC(eglGetCurrentDisplay);
109 LOOKUP_FUNC(eglGetCurrentSurface);
110 LOOKUP_FUNC(eglGetDisplay);
111 LOOKUP_FUNC(eglInitialize);
112 LOOKUP_FUNC(eglChooseConfig);
113 LOOKUP_FUNC(eglCreateContext);
114 LOOKUP_FUNC(eglCreatePbufferSurface);
115 LOOKUP_FUNC(eglMakeCurrent);
116 LOOKUP_FUNC(eglDestroySurface);
117 LOOKUP_FUNC(eglDestroyContext);
119 LOOKUP_FUNC(glGetString);
120 LOOKUP_FUNC(glGetIntegerv);
122 #undef LOOKUP_FUNC
124 EGLDisplay curr_display = eglGetCurrentDisplayFn();
125 EGLContext curr_context = eglGetCurrentContextFn();
126 EGLSurface curr_draw_surface = eglGetCurrentSurfaceFn(EGL_DRAW);
127 EGLSurface curr_read_surface = eglGetCurrentSurfaceFn(EGL_READ);
129 EGLDisplay temp_display = EGL_NO_DISPLAY;
130 EGLContext temp_context = EGL_NO_CONTEXT;
131 EGLSurface temp_surface = EGL_NO_SURFACE;
133 const EGLint kConfigAttribs[] = {
134 EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
135 EGL_SURFACE_TYPE, EGL_PBUFFER_BIT,
136 EGL_NONE};
137 const EGLint kContextAttribs[] = {
138 EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_EXT,
139 EGL_LOSE_CONTEXT_ON_RESET_EXT,
140 EGL_CONTEXT_CLIENT_VERSION, 2,
141 EGL_NONE};
142 const EGLint kSurfaceAttribs[] = {
143 EGL_WIDTH, 1,
144 EGL_HEIGHT, 1,
145 EGL_NONE};
147 EGLint major, minor;
149 EGLConfig config;
150 EGLint num_configs;
152 auto errorstr = [eglGetErrorFn]() {
153 uint32_t err = eglGetErrorFn();
154 return base::StringPrintf("%s (%x)", ui::GetEGLErrorString(err), err);
157 temp_display = eglGetDisplayFn(EGL_DEFAULT_DISPLAY);
159 if (temp_display == EGL_NO_DISPLAY) {
160 LOG(FATAL) << "failed to get display. " << errorstr();
163 eglInitializeFn(temp_display, &major, &minor);
165 bool egl_create_context_robustness_supported =
166 strstr(reinterpret_cast<const char*>(
167 eglQueryStringFn(temp_display, EGL_EXTENSIONS)),
168 "EGL_EXT_create_context_robustness") != NULL;
170 if (!eglChooseConfigFn(temp_display, kConfigAttribs, &config, 1,
171 &num_configs)) {
172 LOG(FATAL) << "failed to choose an egl config. " << errorstr();
175 temp_context = eglCreateContextFn(
176 temp_display, config, EGL_NO_CONTEXT,
177 kContextAttribs + (egl_create_context_robustness_supported ? 0 : 2));
178 if (temp_context == EGL_NO_CONTEXT) {
179 LOG(FATAL)
180 << "failed to create a temporary context for fetching driver strings. "
181 << errorstr();
184 temp_surface =
185 eglCreatePbufferSurfaceFn(temp_display, config, kSurfaceAttribs);
187 if (temp_surface == EGL_NO_SURFACE) {
188 eglDestroyContextFn(temp_display, temp_context);
189 LOG(FATAL)
190 << "failed to create a pbuffer surface for fetching driver strings. "
191 << errorstr();
194 eglMakeCurrentFn(temp_display, temp_surface, temp_surface, temp_context);
196 gpu_info->gl_vendor = reinterpret_cast<const char*>(glGetStringFn(GL_VENDOR));
197 gpu_info->gl_version =
198 reinterpret_cast<const char*>(glGetStringFn(GL_VERSION));
199 gpu_info->gl_renderer =
200 reinterpret_cast<const char*>(glGetStringFn(GL_RENDERER));
201 gpu_info->gl_extensions =
202 reinterpret_cast<const char*>(glGetStringFn(GL_EXTENSIONS));
204 GLint max_samples = 0;
205 glGetIntegervFn(GL_MAX_SAMPLES, &max_samples);
206 gpu_info->max_msaa_samples = base::IntToString(max_samples);
208 bool supports_robustness =
209 gpu_info->gl_extensions.find("GL_EXT_robustness") != std::string::npos ||
210 gpu_info->gl_extensions.find("GL_KHR_robustness") != std::string::npos ||
211 gpu_info->gl_extensions.find("GL_ARB_robustness") != std::string::npos;
213 if (supports_robustness) {
214 glGetIntegervFn(
215 GL_RESET_NOTIFICATION_STRATEGY_ARB,
216 reinterpret_cast<GLint*>(&gpu_info->gl_reset_notification_strategy));
219 std::string glsl_version_string =
220 reinterpret_cast<const char*>(glGetStringFn(GL_SHADING_LANGUAGE_VERSION));
222 std::string glsl_version = GetVersionFromString(glsl_version_string).first;
223 gpu_info->pixel_shader_version = glsl_version;
224 gpu_info->vertex_shader_version = glsl_version;
226 if (curr_display != EGL_NO_DISPLAY &&
227 curr_context != EGL_NO_CONTEXT) {
228 eglMakeCurrentFn(curr_display, curr_draw_surface, curr_read_surface,
229 curr_context);
230 } else {
231 eglMakeCurrentFn(temp_display, EGL_NO_SURFACE, EGL_NO_SURFACE,
232 EGL_NO_CONTEXT);
235 eglDestroySurfaceFn(temp_display, temp_surface);
236 eglDestroyContextFn(temp_display, temp_context);
238 return gpu::kCollectInfoSuccess;
243 namespace gpu {
245 CollectInfoResult CollectContextGraphicsInfo(GPUInfo* gpu_info) {
246 /// TODO(tobiasjs) Check if CollectGraphicsInfo in gpu_main.cc
247 /// really only needs basic graphics info on all platforms, and if
248 /// so switch it to using that and make this the NOP that it really
249 /// should be, to avoid potential double collection of info.
250 return CollectBasicGraphicsInfo(gpu_info);
253 CollectInfoResult CollectGpuID(uint32* vendor_id, uint32* device_id) {
254 DCHECK(vendor_id && device_id);
255 *vendor_id = 0;
256 *device_id = 0;
257 return kCollectInfoNonFatalFailure;
260 CollectInfoResult CollectBasicGraphicsInfo(GPUInfo* gpu_info) {
261 gpu_info->can_lose_context = false;
263 gpu_info->machine_model_name =
264 base::android::BuildInfo::GetInstance()->model();
266 // Create a short-lived context on the UI thread to collect the GL strings.
267 // Make sure we restore the existing context if there is one.
268 CollectInfoResult result = CollectDriverInfo(gpu_info);
269 if (result == kCollectInfoSuccess)
270 result = CollectDriverInfoGL(gpu_info);
271 gpu_info->basic_info_state = result;
272 gpu_info->context_info_state = result;
273 return result;
276 CollectInfoResult CollectDriverInfoGL(GPUInfo* gpu_info) {
277 gpu_info->driver_version = GetDriverVersionFromString(
278 gpu_info->gl_version);
279 gpu_info->gpu.vendor_string = gpu_info->gl_vendor;
280 gpu_info->gpu.device_string = gpu_info->gl_renderer;
281 return kCollectInfoSuccess;
284 void MergeGPUInfo(GPUInfo* basic_gpu_info,
285 const GPUInfo& context_gpu_info) {
286 MergeGPUInfoGL(basic_gpu_info, context_gpu_info);
289 } // namespace gpu