15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include "gpu/config/gpu_info_collector.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <string>
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <vector>
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "base/debug/trace_event.h"
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/logging.h"
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/memory/scoped_ptr.h"
13868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/string_number_conversions.h"
14c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "base/strings/string_piece.h"
152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/strings/string_split.h"
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/gl/gl_bindings.h"
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/gl/gl_context.h"
18868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "ui/gl/gl_implementation.h"
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/gl/gl_surface.h"
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace {
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)scoped_refptr<gfx::GLSurface> InitializeGLSurface() {
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_refptr<gfx::GLSurface> surface(
257d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)      gfx::GLSurface::CreateOffscreenGLSurface(gfx::Size(1, 1)));
26868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  if (!surface.get()) {
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    LOG(ERROR) << "gfx::GLContext::CreateOffscreenGLSurface failed";
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return NULL;
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return surface;
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)scoped_refptr<gfx::GLContext> InitializeGLContext(gfx::GLSurface* surface) {
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_refptr<gfx::GLContext> context(
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      gfx::GLContext::CreateGLContext(NULL,
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                      surface,
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                      gfx::PreferIntegratedGpu));
40868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  if (!context.get()) {
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    LOG(ERROR) << "gfx::GLContext::CreateGLContext failed";
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return NULL;
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!context->MakeCurrent(surface)) {
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    LOG(ERROR) << "gfx::GLContext::MakeCurrent() failed";
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return NULL;
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return context;
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)std::string GetGLString(unsigned int pname) {
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const char* gl_string =
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      reinterpret_cast<const char*>(glGetString(pname));
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (gl_string)
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return std::string(gl_string);
58c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  return std::string();
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Return a version string in the format of "major.minor".
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)std::string GetVersionFromString(const std::string& version_string) {
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  size_t begin = version_string.find_first_of("0123456789");
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (begin != std::string::npos) {
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    size_t end = version_string.find_first_not_of("01234567890.", begin);
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    std::string sub_string;
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (end != std::string::npos)
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      sub_string = version_string.substr(begin, end - begin);
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    else
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      sub_string = version_string.substr(begin);
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    std::vector<std::string> pieces;
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    base::SplitString(sub_string, '.', &pieces);
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (pieces.size() >= 2)
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return pieces[0] + "." + pieces[1];
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
76c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  return std::string();
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace anonymous
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)namespace gpu {
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)bool CollectGraphicsInfoGL(GPUInfo* gpu_info) {
84c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  TRACE_EVENT0("startup", "gpu_info_collector::CollectGraphicsInfoGL");
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!gfx::GLSurface::InitializeOneOff()) {
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    LOG(ERROR) << "gfx::GLSurface::InitializeOneOff() failed";
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_refptr<gfx::GLSurface> surface(InitializeGLSurface());
91868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  if (!surface.get())
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_refptr<gfx::GLContext> context(InitializeGLContext(surface.get()));
95868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  if (!context.get())
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  gpu_info->gl_renderer = GetGLString(GL_RENDERER);
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  gpu_info->gl_vendor = GetGLString(GL_VENDOR);
1002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  gpu_info->gl_extensions = GetGLString(GL_EXTENSIONS);
1012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  gpu_info->gl_version_string = GetGLString(GL_VERSION);
1022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  std::string glsl_version_string = GetGLString(GL_SHADING_LANGUAGE_VERSION);
103868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
104868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  gfx::GLWindowSystemBindingInfo window_system_binding_info;
105868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  if (GetGLWindowSystemBindingInfo(&window_system_binding_info)) {
106868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    gpu_info->gl_ws_vendor = window_system_binding_info.vendor;
107868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    gpu_info->gl_ws_version = window_system_binding_info.version;
108868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    gpu_info->gl_ws_extensions = window_system_binding_info.extensions;
109868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  }
110868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
111a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  bool supports_robustness =
112a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      gpu_info->gl_extensions.find("GL_EXT_robustness") != std::string::npos ||
113a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      gpu_info->gl_extensions.find("GL_ARB_robustness") != std::string::npos;
114a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  if (supports_robustness) {
115a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    glGetIntegerv(GL_RESET_NOTIFICATION_STRATEGY_ARB,
116a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)        reinterpret_cast<GLint*>(&gpu_info->gl_reset_notification_strategy));
117a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  }
118a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // TODO(kbr): remove once the destruction of a current context automatically
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // clears the current context.
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  context->ReleaseCurrent(surface.get());
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  gpu_info->gl_version = GetVersionFromString(gpu_info->gl_version_string);
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string glsl_version = GetVersionFromString(glsl_version_string);
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  gpu_info->pixel_shader_version = glsl_version;
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  gpu_info->vertex_shader_version = glsl_version;
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return CollectDriverInfoGL(gpu_info);
1292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
13190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)void MergeGPUInfoGL(GPUInfo* basic_gpu_info,
13290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                    const GPUInfo& context_gpu_info) {
1332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(basic_gpu_info);
1342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  basic_gpu_info->gl_renderer = context_gpu_info.gl_renderer;
1352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  basic_gpu_info->gl_vendor = context_gpu_info.gl_vendor;
1362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  basic_gpu_info->gl_version_string = context_gpu_info.gl_version_string;
1372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  basic_gpu_info->gl_extensions = context_gpu_info.gl_extensions;
1382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  basic_gpu_info->gl_version = context_gpu_info.gl_version;
1392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  basic_gpu_info->pixel_shader_version =
1402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      context_gpu_info.pixel_shader_version;
1412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  basic_gpu_info->vertex_shader_version =
1422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      context_gpu_info.vertex_shader_version;
143868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  basic_gpu_info->gl_ws_vendor = context_gpu_info.gl_ws_vendor;
144868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  basic_gpu_info->gl_ws_version = context_gpu_info.gl_ws_version;
145868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  basic_gpu_info->gl_ws_extensions = context_gpu_info.gl_ws_extensions;
146a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  basic_gpu_info->gl_reset_notification_strategy =
147a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      context_gpu_info.gl_reset_notification_strategy;
1482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!context_gpu_info.driver_vendor.empty())
1502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    basic_gpu_info->driver_vendor = context_gpu_info.driver_vendor;
1512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!context_gpu_info.driver_version.empty())
1522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    basic_gpu_info->driver_version = context_gpu_info.driver_version;
1532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  basic_gpu_info->can_lose_context = context_gpu_info.can_lose_context;
1552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  basic_gpu_info->sandboxed = context_gpu_info.sandboxed;
1562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  basic_gpu_info->finalized = context_gpu_info.finalized;
1572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  basic_gpu_info->initialization_time = context_gpu_info.initialization_time;
1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
16090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)}  // namespace gpu
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
162