summaryrefslogtreecommitdiffstats
path: root/gpu/config/gpu_info_collector_android.cc
diff options
context:
space:
mode:
Diffstat (limited to 'gpu/config/gpu_info_collector_android.cc')
-rw-r--r--gpu/config/gpu_info_collector_android.cc260
1 files changed, 210 insertions, 50 deletions
diff --git a/gpu/config/gpu_info_collector_android.cc b/gpu/config/gpu_info_collector_android.cc
index d05e85b..ce14f03 100644
--- a/gpu/config/gpu_info_collector_android.cc
+++ b/gpu/config/gpu_info_collector_android.cc
@@ -6,17 +6,42 @@
#include "base/android/build_info.h"
#include "base/command_line.h"
+#include "base/files/file_path.h"
#include "base/logging.h"
+#include "base/native_library.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_piece.h"
#include "base/strings/string_split.h"
#include "base/strings/string_util.h"
+#include "base/strings/stringprintf.h"
+#include "ui/gl/egl_util.h"
#include "ui/gl/gl_bindings.h"
#include "ui/gl/gl_context.h"
#include "ui/gl/gl_surface.h"
namespace {
+std::pair<std::string, size_t> GetVersionFromString(
+ const std::string& version_string,
+ size_t begin = 0) {
+ begin = version_string.find_first_of("0123456789", begin);
+ if (begin == std::string::npos)
+ return std::make_pair("", std::string::npos);
+
+ size_t end = version_string.find_first_not_of("01234567890.", begin);
+ std::string sub_string;
+ if (end != std::string::npos)
+ sub_string = version_string.substr(begin, end - begin);
+ else
+ sub_string = version_string.substr(begin);
+ std::vector<std::string> pieces;
+ base::SplitString(sub_string, '.', &pieces);
+ if (pieces.size() >= 2)
+ return std::make_pair(pieces[0] + "." + pieces[1], end);
+ else
+ return std::make_pair("", end);
+}
+
std::string GetDriverVersionFromString(const std::string& version_string) {
// We expect that android GL_VERSION strings will be of a form
// similar to: "OpenGL ES 2.0 V@6.0 AU@ (CL@2946718)" where the
@@ -25,62 +50,192 @@ std::string GetDriverVersionFromString(const std::string& version_string) {
// case, 6.0).
// It is currently assumed that the driver version has at least one
// period in it, and only the first two components are significant.
- size_t begin = version_string.find_first_of("0123456789");
+ size_t begin = GetVersionFromString(version_string).second;
if (begin == std::string::npos)
return "0";
- size_t end = version_string.find_first_not_of("01234567890.", begin);
- // Extract number of the form "%d.%d"
- begin = version_string.find_first_of("0123456789", end);
- if (begin == std::string::npos)
- return "0";
- end = version_string.find_first_not_of("01234567890.", begin);
- std::string sub_string;
- if (end != std::string::npos)
- sub_string = version_string.substr(begin, end - begin);
- else
- sub_string = version_string.substr(begin);
- std::vector<std::string> pieces;
- base::SplitString(sub_string, '.', &pieces);
- if (pieces.size() < 2)
+ std::pair<std::string, size_t> driver_version =
+ GetVersionFromString(version_string, begin);
+ if (driver_version.first == "")
return "0";
- return pieces[0] + "." + pieces[1];
-}
-class ScopedRestoreNonOwnedEGLContext {
- public:
- ScopedRestoreNonOwnedEGLContext();
- ~ScopedRestoreNonOwnedEGLContext();
-
- private:
- EGLContext context_;
- EGLDisplay display_;
- EGLSurface draw_surface_;
- EGLSurface read_surface_;
-};
-
-ScopedRestoreNonOwnedEGLContext::ScopedRestoreNonOwnedEGLContext()
- : context_(EGL_NO_CONTEXT),
- display_(EGL_NO_DISPLAY),
- draw_surface_(EGL_NO_SURFACE),
- read_surface_(EGL_NO_SURFACE) {
- // This should only used to restore a context that is not created or owned by
- // Chromium native code, but created by Android system itself.
- DCHECK(!gfx::GLContext::GetCurrent());
-
- context_ = eglGetCurrentContext();
- display_ = eglGetCurrentDisplay();
- draw_surface_ = eglGetCurrentSurface(EGL_DRAW);
- read_surface_ = eglGetCurrentSurface(EGL_READ);
+ return driver_version.first;
}
-ScopedRestoreNonOwnedEGLContext::~ScopedRestoreNonOwnedEGLContext() {
- if (context_ == EGL_NO_CONTEXT || display_ == EGL_NO_DISPLAY ||
- draw_surface_ == EGL_NO_SURFACE || read_surface_ == EGL_NO_SURFACE)
- return;
+gpu::CollectInfoResult CollectDriverInfo(gpu::GPUInfo* gpu_info) {
+ // Go through the process of loading GL libs and initializing an EGL
+ // context so that we can get GL vendor/version/renderer strings.
+ base::NativeLibrary gles_library, egl_library;
+ base::NativeLibraryLoadError error;
+ gles_library =
+ base::LoadNativeLibrary(base::FilePath("libGLESv2.so"), &error);
+ if (!gles_library)
+ LOG(FATAL) << "Failed to load libGLESv2.so";
+
+ egl_library = base::LoadNativeLibrary(base::FilePath("libEGL.so"), &error);
+ if (!egl_library)
+ LOG(FATAL) << "Failed to load libEGL.so";
+
+ typedef void* (*eglGetProcAddressProc)(const char* name);
+
+ auto eglGetProcAddressFn = reinterpret_cast<eglGetProcAddressProc>(
+ base::GetFunctionPointerFromNativeLibrary(egl_library,
+ "eglGetProcAddress"));
+ if (!eglGetProcAddressFn)
+ LOG(FATAL) << "eglGetProcAddress not found.";
+
+ auto get_func = [eglGetProcAddressFn, gles_library, egl_library](
+ const char* name) {
+ void *proc;
+ proc = base::GetFunctionPointerFromNativeLibrary(egl_library, name);
+ if (proc)
+ return proc;
+ proc = base::GetFunctionPointerFromNativeLibrary(gles_library, name);
+ if (proc)
+ return proc;
+ proc = eglGetProcAddressFn(name);
+ if (proc)
+ return proc;
+ LOG(FATAL) << "Failed to look up " << name;
+ return (void *)nullptr;
+ };
+
+#define LOOKUP_FUNC(x) auto x##Fn = reinterpret_cast<gfx::x##Proc>(get_func(#x))
+
+ LOOKUP_FUNC(eglGetError);
+ LOOKUP_FUNC(eglQueryString);
+ LOOKUP_FUNC(eglGetCurrentContext);
+ LOOKUP_FUNC(eglGetCurrentDisplay);
+ LOOKUP_FUNC(eglGetCurrentSurface);
+ LOOKUP_FUNC(eglGetDisplay);
+ LOOKUP_FUNC(eglInitialize);
+ LOOKUP_FUNC(eglChooseConfig);
+ LOOKUP_FUNC(eglCreateContext);
+ LOOKUP_FUNC(eglCreatePbufferSurface);
+ LOOKUP_FUNC(eglMakeCurrent);
+ LOOKUP_FUNC(eglDestroySurface);
+ LOOKUP_FUNC(eglDestroyContext);
+
+ LOOKUP_FUNC(glGetString);
+ LOOKUP_FUNC(glGetIntegerv);
+
+#undef LOOKUP_FUNC
+
+ EGLDisplay curr_display = eglGetCurrentDisplayFn();
+ EGLContext curr_context = eglGetCurrentContextFn();
+ EGLSurface curr_draw_surface = eglGetCurrentSurfaceFn(EGL_DRAW);
+ EGLSurface curr_read_surface = eglGetCurrentSurfaceFn(EGL_READ);
+
+ EGLDisplay temp_display = EGL_NO_DISPLAY;
+ EGLContext temp_context = EGL_NO_CONTEXT;
+ EGLSurface temp_surface = EGL_NO_SURFACE;
+
+ const EGLint kConfigAttribs[] = {
+ EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
+ EGL_SURFACE_TYPE, EGL_PBUFFER_BIT,
+ EGL_NONE};
+ const EGLint kContextAttribs[] = {
+ EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_EXT,
+ EGL_LOSE_CONTEXT_ON_RESET_EXT,
+ EGL_CONTEXT_CLIENT_VERSION, 2,
+ EGL_NONE};
+ const EGLint kSurfaceAttribs[] = {
+ EGL_WIDTH, 1,
+ EGL_HEIGHT, 1,
+ EGL_NONE};
+
+ EGLint major, minor;
+
+ EGLConfig config;
+ EGLint num_configs;
+
+ auto errorstr = [eglGetErrorFn]() {
+ uint32_t err = eglGetErrorFn();
+ return base::StringPrintf("%s (%x)", ui::GetEGLErrorString(err), err);
+ };
+
+ temp_display = eglGetDisplayFn(EGL_DEFAULT_DISPLAY);
+
+ if (temp_display == EGL_NO_DISPLAY) {
+ LOG(FATAL) << "failed to get display. " << errorstr();
+ }
+
+ eglInitializeFn(temp_display, &major, &minor);
+
+ bool egl_create_context_robustness_supported =
+ strstr(reinterpret_cast<const char*>(
+ eglQueryStringFn(temp_display, EGL_EXTENSIONS)),
+ "EGL_EXT_create_context_robustness") != NULL;
+
+ if (!eglChooseConfigFn(temp_display, kConfigAttribs, &config, 1,
+ &num_configs)) {
+ LOG(FATAL) << "failed to choose an egl config. " << errorstr();
+ }
+
+ temp_context = eglCreateContextFn(
+ temp_display, config, EGL_NO_CONTEXT,
+ kContextAttribs + (egl_create_context_robustness_supported ? 0 : 2));
+ if (temp_context == EGL_NO_CONTEXT) {
+ LOG(FATAL)
+ << "failed to create a temporary context for fetching driver strings. "
+ << errorstr();
+ }
+
+ temp_surface =
+ eglCreatePbufferSurfaceFn(temp_display, config, kSurfaceAttribs);
+
+ if (temp_surface == EGL_NO_SURFACE) {
+ eglDestroyContextFn(temp_display, temp_context);
+ LOG(FATAL)
+ << "failed to create a pbuffer surface for fetching driver strings. "
+ << errorstr();
+ }
+
+ eglMakeCurrentFn(temp_display, temp_surface, temp_surface, temp_context);
+
+ gpu_info->gl_vendor = reinterpret_cast<const char*>(glGetStringFn(GL_VENDOR));
+ gpu_info->gl_version =
+ reinterpret_cast<const char*>(glGetStringFn(GL_VERSION));
+ gpu_info->gl_renderer =
+ reinterpret_cast<const char*>(glGetStringFn(GL_RENDERER));
+ gpu_info->gl_extensions =
+ reinterpret_cast<const char*>(glGetStringFn(GL_EXTENSIONS));
+
+ GLint max_samples = 0;
+ glGetIntegervFn(GL_MAX_SAMPLES, &max_samples);
+ gpu_info->max_msaa_samples = base::StringPrintf("%d", max_samples);
+
+ bool supports_robustness =
+ gpu_info->gl_extensions.find("GL_EXT_robustness") != std::string::npos ||
+ gpu_info->gl_extensions.find("GL_KHR_robustness") != std::string::npos ||
+ gpu_info->gl_extensions.find("GL_ARB_robustness") != std::string::npos;
+
+ if (supports_robustness) {
+ glGetIntegervFn(
+ GL_RESET_NOTIFICATION_STRATEGY_ARB,
+ reinterpret_cast<GLint*>(&gpu_info->gl_reset_notification_strategy));
+ }
+
+ std::string glsl_version_string =
+ reinterpret_cast<const char*>(glGetStringFn(GL_SHADING_LANGUAGE_VERSION));
+
+ std::string glsl_version = GetVersionFromString(glsl_version_string).first;
+ gpu_info->pixel_shader_version = glsl_version;
+ gpu_info->vertex_shader_version = glsl_version;
+
+ if (curr_display != EGL_NO_DISPLAY &&
+ curr_context != EGL_NO_CONTEXT) {
+ eglMakeCurrentFn(curr_display, curr_draw_surface, curr_read_surface,
+ curr_context);
+ } else {
+ eglMakeCurrentFn(temp_display, EGL_NO_SURFACE, EGL_NO_SURFACE,
+ EGL_NO_CONTEXT);
+ }
+
+ eglDestroySurfaceFn(temp_display, temp_surface);
+ eglDestroyContextFn(temp_display, temp_context);
- if (!eglMakeCurrent(display_, draw_surface_, read_surface_, context_))
- LOG(WARNING) << "Failed to restore EGL context";
+ return gpu::kCollectInfoSuccess;
}
}
@@ -88,6 +243,10 @@ ScopedRestoreNonOwnedEGLContext::~ScopedRestoreNonOwnedEGLContext() {
namespace gpu {
CollectInfoResult CollectContextGraphicsInfo(GPUInfo* gpu_info) {
+ /// TODO(tobiasjs) Check if CollectGraphicsInfo in gpu_main.cc
+ /// really only needs basic graphics info on all platforms, and if
+ /// so switch it to using that and make this the NOP that it really
+ /// should be, to avoid potential double collection of info.
return CollectBasicGraphicsInfo(gpu_info);
}
@@ -106,8 +265,9 @@ CollectInfoResult CollectBasicGraphicsInfo(GPUInfo* gpu_info) {
// Create a short-lived context on the UI thread to collect the GL strings.
// Make sure we restore the existing context if there is one.
- ScopedRestoreNonOwnedEGLContext restore_context;
- CollectInfoResult result = CollectGraphicsInfoGL(gpu_info);
+ CollectInfoResult result = CollectDriverInfo(gpu_info);
+ if (result == kCollectInfoSuccess)
+ result = CollectDriverInfoGL(gpu_info);
gpu_info->basic_info_state = result;
gpu_info->context_info_state = result;
return result;