diff options
author | tobiasjs <tobiasjs@chromium.org> | 2015-06-22 19:56:53 -0700 |
---|---|---|
committer | Commit bot <commit-bot@chromium.org> | 2015-06-23 02:57:31 +0000 |
commit | 2a111821c550ff0237c97fd4a6caf01175f08af6 (patch) | |
tree | 4ce47004ac575947a91883ab9f601545cb923928 | |
parent | e3599a679d6a9ba80fecc1fa371a8c5f51803ed0 (diff) | |
download | chromium_src-2a111821c550ff0237c97fd4a6caf01175f08af6.zip chromium_src-2a111821c550ff0237c97fd4a6caf01175f08af6.tar.gz chromium_src-2a111821c550ff0237c97fd4a6caf01175f08af6.tar.bz2 |
Implement self-contained gpu data collection on Android
By removing the dependency of gpu data collection on
gfx::GLSurface::InitializeOneOff() (and hence complete iniitalization of
gl bindings and extensions), the initialization flow can be simplified
and potentially delayed.
This also fixes the incorrect behaviour of extension blacklisting in
Android WebViews, where the decision regarding what to blacklist is only
made after extensions are loaded and made available.
BUG=462553,32629,499928
Review URL: https://codereview.chromium.org/1172003002
Cr-Commit-Position: refs/heads/master@{#335617}
-rw-r--r-- | android_webview/browser/aw_browser_main_parts.cc | 3 | ||||
-rw-r--r-- | content/browser/browser_main_loop.cc | 32 | ||||
-rw-r--r-- | content/gpu/gpu_child_thread.cc | 8 | ||||
-rw-r--r-- | content/renderer/render_frame_impl.cc | 16 | ||||
-rw-r--r-- | gpu/config/gpu_info_collector_android.cc | 260 | ||||
-rw-r--r-- | ui/gl/egl_util.cc | 25 | ||||
-rw-r--r-- | ui/gl/egl_util.h | 3 |
7 files changed, 246 insertions, 101 deletions
diff --git a/android_webview/browser/aw_browser_main_parts.cc b/android_webview/browser/aw_browser_main_parts.cc index 4e5548e..dc75d4b 100644 --- a/android_webview/browser/aw_browser_main_parts.cc +++ b/android_webview/browser/aw_browser_main_parts.cc @@ -27,6 +27,7 @@ #include "ui/base/layout.h" #include "ui/base/resource/resource_bundle.h" #include "ui/base/ui_base_paths.h" +#include "ui/gl/gl_surface.h" namespace android_webview { @@ -103,6 +104,8 @@ void AwBrowserMainParts::PreMainMessageLoopRun() { media::SetMediaClientAndroid( new AwMediaClientAndroid(AwResource::GetConfigKeySystemUuidMapping())); + gfx::GLSurface::InitializeOneOff(); + // This is needed for WebView Classic backwards compatibility // See crbug.com/298495 content::SetMaxURLChars(20 * 1024 * 1024); diff --git a/content/browser/browser_main_loop.cc b/content/browser/browser_main_loop.cc index 1752f3b..623278e 100644 --- a/content/browser/browser_main_loop.cc +++ b/content/browser/browser_main_loop.cc @@ -683,19 +683,7 @@ int BrowserMainLoop::PreCreateThreads() { // It's unsafe to append the gpu command line switches to the global // CommandLine::ForCurrentProcess object after threads are created. if (UsingInProcessGpu()) { - bool initialize_gpu_data_manager = true; -#if defined(OS_ANDROID) - if (!gfx::GLSurface::InitializeOneOff()) { - // Single-process Android WebView supports no gpu. - LOG(ERROR) << "GLSurface::InitializeOneOff failed"; - initialize_gpu_data_manager = false; - } -#endif - - // Initialize the GpuDataManager before we set up the MessageLoops because - // otherwise we'll trigger the assertion about doing IO on the UI thread. - if (initialize_gpu_data_manager) - GpuDataManagerImpl::GetInstance()->Initialize(); + GpuDataManagerImpl::GetInstance()->Initialize(); } #if !defined(OS_IOS) && (!defined(GOOGLE_CHROME_BUILD) || defined(OS_ANDROID)) @@ -1113,29 +1101,15 @@ int BrowserMainLoop::BrowserThreadsStarted() { #if !defined(OS_IOS) HistogramSynchronizer::GetInstance(); - - // GpuDataManager for in-process initialized in PreCreateThreads. - bool initialize_gpu_data_manager = !UsingInProcessGpu(); #if defined(OS_ANDROID) // Up the priority of the UI thread. base::PlatformThread::SetThreadPriority(base::PlatformThread::CurrentHandle(), base::ThreadPriority::DISPLAY); - - // On Android, GLSurface::InitializeOneOff() must be called before - // initalizing the GpuDataManagerImpl as it uses the GL bindings. - // TODO(sievers): Shouldn't need to init full bindings to determine GL - // version/vendor strings. crbug.com/326295 - if (initialize_gpu_data_manager) { - // Note InitializeOneOff is not safe either for in-process gpu after - // creating threads, since it may race with the gpu thread. - if (!gfx::GLSurface::InitializeOneOff()) { - LOG(FATAL) << "GLSurface::InitializeOneOff failed"; - } - } #endif - if (initialize_gpu_data_manager) + if (!UsingInProcessGpu()) { GpuDataManagerImpl::GetInstance()->Initialize(); + } bool always_uses_gpu = true; bool established_gpu_channel = false; diff --git a/content/gpu/gpu_child_thread.cc b/content/gpu/gpu_child_thread.cc index 1279936..916d88a 100644 --- a/content/gpu/gpu_child_thread.cc +++ b/content/gpu/gpu_child_thread.cc @@ -89,14 +89,10 @@ GpuChildThread::GpuChildThread(const InProcessChildThreadParams& params) switches::kSingleProcess) || base::CommandLine::ForCurrentProcess()->HasSwitch( switches::kInProcessGPU)); -#if !defined(OS_ANDROID) - // For single process and in-process GPU mode, we need to load and - // initialize the GL implementation and locate the GL entry points here. - // On Android, GLSurface::InitializeOneOff() is called from BrowserMainLoop - // before getting here. crbug.com/326295 + if (!gfx::GLSurface::InitializeOneOff()) VLOG(1) << "gfx::GLSurface::InitializeOneOff failed"; -#endif + g_thread_safe_sender.Get() = thread_safe_sender(); } diff --git a/content/renderer/render_frame_impl.cc b/content/renderer/render_frame_impl.cc index 9c76355..3424ece 100644 --- a/content/renderer/render_frame_impl.cc +++ b/content/renderer/render_frame_impl.cc @@ -4881,19 +4881,21 @@ WebMediaPlayer* RenderFrameImpl::CreateAndroidWebMediaPlayer( WebMediaPlayerClient* client, media::MediaPermission* media_permission, blink::WebContentDecryptionModule* initial_cdm) { - GpuChannelHost* gpu_channel_host = - RenderThreadImpl::current()->EstablishGpuChannelSync( - CAUSE_FOR_GPU_LAUNCH_VIDEODECODEACCELERATOR_INITIALIZE); - if (!gpu_channel_host) { - LOG(ERROR) << "Failed to establish GPU channel for media player"; - return NULL; - } scoped_refptr<StreamTextureFactory> stream_texture_factory; if (SynchronousCompositorFactory* factory = SynchronousCompositorFactory::GetInstance()) { stream_texture_factory = factory->CreateStreamTextureFactory(routing_id_); } else { + GpuChannelHost* gpu_channel_host = + RenderThreadImpl::current()->EstablishGpuChannelSync( + CAUSE_FOR_GPU_LAUNCH_VIDEODECODEACCELERATOR_INITIALIZE); + + if (!gpu_channel_host) { + LOG(ERROR) << "Failed to establish GPU channel for media player"; + return NULL; + } + scoped_refptr<cc_blink::ContextProviderWebContext> context_provider = RenderThreadImpl::current()->SharedMainThreadContextProvider(); 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; diff --git a/ui/gl/egl_util.cc b/ui/gl/egl_util.cc index 1151737..17d91d1 100644 --- a/ui/gl/egl_util.cc +++ b/ui/gl/egl_util.cc @@ -15,39 +15,46 @@ namespace ui { -// Returns the last EGL error as a string. -const char* GetLastEGLErrorString() { - EGLint error = eglGetError(); +const char* GetEGLErrorString(uint32_t error) { switch (error) { case EGL_SUCCESS: return "EGL_SUCCESS"; + case EGL_NOT_INITIALIZED: + return "EGL_NOT_INITIALIZED"; case EGL_BAD_ACCESS: return "EGL_BAD_ACCESS"; case EGL_BAD_ALLOC: return "EGL_BAD_ALLOC"; case EGL_BAD_ATTRIBUTE: return "EGL_BAD_ATTRIBUTE"; - case EGL_BAD_CONTEXT: - return "EGL_BAD_CONTEXT"; case EGL_BAD_CONFIG: return "EGL_BAD_CONFIG"; + case EGL_BAD_CONTEXT: + return "EGL_BAD_CONTEXT"; case EGL_BAD_CURRENT_SURFACE: return "EGL_BAD_CURRENT_SURFACE"; case EGL_BAD_DISPLAY: return "EGL_BAD_DISPLAY"; - case EGL_BAD_SURFACE: - return "EGL_BAD_SURFACE"; case EGL_BAD_MATCH: return "EGL_BAD_MATCH"; - case EGL_BAD_PARAMETER: - return "EGL_BAD_PARAMETER"; case EGL_BAD_NATIVE_PIXMAP: return "EGL_BAD_NATIVE_PIXMAP"; case EGL_BAD_NATIVE_WINDOW: return "EGL_BAD_NATIVE_WINDOW"; + case EGL_BAD_PARAMETER: + return "EGL_BAD_PARAMETER"; + case EGL_BAD_SURFACE: + return "EGL_BAD_SURFACE"; + case EGL_CONTEXT_LOST: + return "EGL_CONTEXT_LOST"; default: return "UNKNOWN"; } } +// Returns the last EGL error as a string. +const char* GetLastEGLErrorString() { + return GetEGLErrorString(eglGetError()); +} + } // namespace ui diff --git a/ui/gl/egl_util.h b/ui/gl/egl_util.h index 0ef9095..e2b2ffc 100644 --- a/ui/gl/egl_util.h +++ b/ui/gl/egl_util.h @@ -5,10 +5,13 @@ #ifndef UI_GL_EGL_UTIL_H_ #define UI_GL_EGL_UTIL_H_ +#include "base/basictypes.h" #include "ui/gl/gl_export.h" namespace ui { +GL_EXPORT const char* GetEGLErrorString(uint32_t error); + // Returns the last EGL error as a string. GL_EXPORT const char* GetLastEGLErrorString(); |