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.
4
5#include "gpu/config/gpu_info_collector.h"
6
7#include <string>
8#include <vector>
9
10#include "base/debug/trace_event.h"
11#include "base/logging.h"
12#include "base/memory/scoped_ptr.h"
13#include "base/strings/string_number_conversions.h"
14#include "base/strings/string_piece.h"
15#include "base/strings/string_split.h"
16#include "ui/gl/gl_bindings.h"
17#include "ui/gl/gl_context.h"
18#include "ui/gl/gl_implementation.h"
19#include "ui/gl/gl_surface.h"
20
21namespace {
22
23scoped_refptr<gfx::GLSurface> InitializeGLSurface() {
24  scoped_refptr<gfx::GLSurface> surface(
25      gfx::GLSurface::CreateOffscreenGLSurface(gfx::Size()));
26  if (!surface.get()) {
27    LOG(ERROR) << "gfx::GLContext::CreateOffscreenGLSurface failed";
28    return NULL;
29  }
30
31  return surface;
32}
33
34scoped_refptr<gfx::GLContext> InitializeGLContext(gfx::GLSurface* surface) {
35
36  scoped_refptr<gfx::GLContext> context(
37      gfx::GLContext::CreateGLContext(NULL,
38                                      surface,
39                                      gfx::PreferIntegratedGpu));
40  if (!context.get()) {
41    LOG(ERROR) << "gfx::GLContext::CreateGLContext failed";
42    return NULL;
43  }
44
45  if (!context->MakeCurrent(surface)) {
46    LOG(ERROR) << "gfx::GLContext::MakeCurrent() failed";
47    return NULL;
48  }
49
50  return context;
51}
52
53std::string GetGLString(unsigned int pname) {
54  const char* gl_string =
55      reinterpret_cast<const char*>(glGetString(pname));
56  if (gl_string)
57    return std::string(gl_string);
58  return std::string();
59}
60
61// Return a version string in the format of "major.minor".
62std::string GetVersionFromString(const std::string& version_string) {
63  size_t begin = version_string.find_first_of("0123456789");
64  if (begin != std::string::npos) {
65    size_t end = version_string.find_first_not_of("01234567890.", begin);
66    std::string sub_string;
67    if (end != std::string::npos)
68      sub_string = version_string.substr(begin, end - begin);
69    else
70      sub_string = version_string.substr(begin);
71    std::vector<std::string> pieces;
72    base::SplitString(sub_string, '.', &pieces);
73    if (pieces.size() >= 2)
74      return pieces[0] + "." + pieces[1];
75  }
76  return std::string();
77}
78
79}  // namespace anonymous
80
81namespace gpu {
82
83CollectInfoResult CollectGraphicsInfoGL(GPUInfo* gpu_info) {
84  TRACE_EVENT0("startup", "gpu_info_collector::CollectGraphicsInfoGL");
85  DCHECK_NE(gfx::GetGLImplementation(), gfx::kGLImplementationNone);
86
87  scoped_refptr<gfx::GLSurface> surface(InitializeGLSurface());
88  if (!surface.get()) {
89    LOG(ERROR) << "Could not create surface for info collection.";
90    return kCollectInfoFatalFailure;
91  }
92
93  scoped_refptr<gfx::GLContext> context(InitializeGLContext(surface.get()));
94  if (!context.get()) {
95    LOG(ERROR) << "Could not create context for info collection.";
96    return kCollectInfoFatalFailure;
97  }
98
99  gpu_info->gl_renderer = GetGLString(GL_RENDERER);
100  gpu_info->gl_vendor = GetGLString(GL_VENDOR);
101  gpu_info->gl_extensions = GetGLString(GL_EXTENSIONS);
102  gpu_info->gl_version = GetGLString(GL_VERSION);
103  std::string glsl_version_string = GetGLString(GL_SHADING_LANGUAGE_VERSION);
104
105  gfx::GLWindowSystemBindingInfo window_system_binding_info;
106  if (GetGLWindowSystemBindingInfo(&window_system_binding_info)) {
107    gpu_info->gl_ws_vendor = window_system_binding_info.vendor;
108    gpu_info->gl_ws_version = window_system_binding_info.version;
109    gpu_info->gl_ws_extensions = window_system_binding_info.extensions;
110    gpu_info->direct_rendering = window_system_binding_info.direct_rendering;
111  }
112
113  bool supports_robustness =
114      gpu_info->gl_extensions.find("GL_EXT_robustness") != std::string::npos ||
115      gpu_info->gl_extensions.find("GL_ARB_robustness") != std::string::npos;
116  if (supports_robustness) {
117    glGetIntegerv(GL_RESET_NOTIFICATION_STRATEGY_ARB,
118        reinterpret_cast<GLint*>(&gpu_info->gl_reset_notification_strategy));
119  }
120
121  // TODO(kbr): remove once the destruction of a current context automatically
122  // clears the current context.
123  context->ReleaseCurrent(surface.get());
124
125  std::string glsl_version = GetVersionFromString(glsl_version_string);
126  gpu_info->pixel_shader_version = glsl_version;
127  gpu_info->vertex_shader_version = glsl_version;
128
129  return CollectDriverInfoGL(gpu_info);
130}
131
132void MergeGPUInfoGL(GPUInfo* basic_gpu_info,
133                    const GPUInfo& context_gpu_info) {
134  DCHECK(basic_gpu_info);
135  basic_gpu_info->gl_renderer = context_gpu_info.gl_renderer;
136  basic_gpu_info->gl_vendor = context_gpu_info.gl_vendor;
137  basic_gpu_info->gl_version = context_gpu_info.gl_version;
138  basic_gpu_info->gl_extensions = context_gpu_info.gl_extensions;
139  basic_gpu_info->pixel_shader_version =
140      context_gpu_info.pixel_shader_version;
141  basic_gpu_info->vertex_shader_version =
142      context_gpu_info.vertex_shader_version;
143  basic_gpu_info->gl_ws_vendor = context_gpu_info.gl_ws_vendor;
144  basic_gpu_info->gl_ws_version = context_gpu_info.gl_ws_version;
145  basic_gpu_info->gl_ws_extensions = context_gpu_info.gl_ws_extensions;
146  basic_gpu_info->gl_reset_notification_strategy =
147      context_gpu_info.gl_reset_notification_strategy;
148
149  if (!context_gpu_info.driver_vendor.empty())
150    basic_gpu_info->driver_vendor = context_gpu_info.driver_vendor;
151  if (!context_gpu_info.driver_version.empty())
152    basic_gpu_info->driver_version = context_gpu_info.driver_version;
153
154  basic_gpu_info->can_lose_context = context_gpu_info.can_lose_context;
155  basic_gpu_info->sandboxed = context_gpu_info.sandboxed;
156  basic_gpu_info->direct_rendering = context_gpu_info.direct_rendering;
157  basic_gpu_info->context_info_state = context_gpu_info.context_info_state;
158  basic_gpu_info->initialization_time = context_gpu_info.initialization_time;
159  basic_gpu_info->video_encode_accelerator_supported_profiles =
160      context_gpu_info.video_encode_accelerator_supported_profiles;
161}
162
163}  // namespace gpu
164
165