blob: 44df9f1550b2b73ed58c3bc6b994130cbaca8498 [file] [log] [blame]
[email protected]c9e2cbbb2012-05-12 21:17:271// Copyright (c) 2012 The Chromium Authors. All rights reserved.
[email protected]7004d7eb2011-01-21 00:27:532// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
[email protected]d7b5cc72013-05-23 20:05:005#include "gpu/config/gpu_info_collector.h"
[email protected]7004d7eb2011-01-21 00:27:536
avif15d60a2015-12-21 17:06:337#include <stddef.h>
8#include <stdint.h>
9
[email protected]7004d7eb2011-01-21 00:27:5310#include <string>
11#include <vector>
12
[email protected]7004d7eb2011-01-21 00:27:5313#include "base/logging.h"
[email protected]c9e2cbbb2012-05-12 21:17:2714#include "base/memory/scoped_ptr.h"
senorblanco930f690f2015-09-18 16:18:0315#include "base/metrics/sparse_histogram.h"
[email protected]f4390962013-06-11 07:29:2216#include "base/strings/string_number_conversions.h"
[email protected]b9e7c479f2013-04-12 04:33:2417#include "base/strings/string_piece.h"
[email protected]27c05732013-02-15 21:55:4918#include "base/strings/string_split.h"
zmo7c7ee3e2015-12-09 23:00:3219#include "base/strings/string_util.h"
primiano05dadf012015-01-28 13:10:3220#include "base/trace_event/trace_event.h"
[email protected]c9e2cbbb2012-05-12 21:17:2721#include "ui/gl/gl_bindings.h"
22#include "ui/gl/gl_context.h"
[email protected]45895032013-05-30 17:06:4323#include "ui/gl/gl_implementation.h"
[email protected]c9e2cbbb2012-05-12 21:17:2724#include "ui/gl/gl_surface.h"
j.isorce246d1be52015-12-03 21:53:3625#include "ui/gl/gl_version_info.h"
[email protected]7004d7eb2011-01-21 00:27:5326
27namespace {
28
[email protected]fbe20372011-06-01 01:46:3829scoped_refptr<gfx::GLSurface> InitializeGLSurface() {
30 scoped_refptr<gfx::GLSurface> surface(
[email protected]772aa832014-05-30 01:27:4731 gfx::GLSurface::CreateOffscreenGLSurface(gfx::Size()));
[email protected]7cd76fd2013-06-02 21:11:1132 if (!surface.get()) {
[email protected]ffae4022011-05-12 22:54:2933 LOG(ERROR) << "gfx::GLContext::CreateOffscreenGLSurface failed";
[email protected]7004d7eb2011-01-21 00:27:5334 return NULL;
35 }
[email protected]ffae4022011-05-12 22:54:2936
[email protected]fbe20372011-06-01 01:46:3837 return surface;
[email protected]f62a5ab2011-05-23 20:34:1538}
39
[email protected]fbe20372011-06-01 01:46:3840scoped_refptr<gfx::GLContext> InitializeGLContext(gfx::GLSurface* surface) {
[email protected]f62a5ab2011-05-23 20:34:1541
[email protected]7196e012011-06-16 20:54:5342 scoped_refptr<gfx::GLContext> context(
[email protected]276f89062011-10-13 22:55:5043 gfx::GLContext::CreateGLContext(NULL,
44 surface,
[email protected]56403c22012-10-04 18:27:0445 gfx::PreferIntegratedGpu));
[email protected]7cd76fd2013-06-02 21:11:1146 if (!context.get()) {
[email protected]ffae4022011-05-12 22:54:2947 LOG(ERROR) << "gfx::GLContext::CreateGLContext failed";
48 return NULL;
49 }
50
[email protected]f62a5ab2011-05-23 20:34:1551 if (!context->MakeCurrent(surface)) {
[email protected]7004d7eb2011-01-21 00:27:5352 LOG(ERROR) << "gfx::GLContext::MakeCurrent() failed";
[email protected]7004d7eb2011-01-21 00:27:5353 return NULL;
54 }
[email protected]7004d7eb2011-01-21 00:27:5355
[email protected]fbe20372011-06-01 01:46:3856 return context;
[email protected]7004d7eb2011-01-21 00:27:5357}
58
59std::string GetGLString(unsigned int pname) {
60 const char* gl_string =
61 reinterpret_cast<const char*>(glGetString(pname));
62 if (gl_string)
63 return std::string(gl_string);
[email protected]007b3f82013-04-09 08:46:4564 return std::string();
[email protected]7004d7eb2011-01-21 00:27:5365}
66
[email protected]6cc8ece62011-03-14 20:05:4767// Return a version string in the format of "major.minor".
68std::string GetVersionFromString(const std::string& version_string) {
[email protected]7004d7eb2011-01-21 00:27:5369 size_t begin = version_string.find_first_of("0123456789");
70 if (begin != std::string::npos) {
71 size_t end = version_string.find_first_not_of("01234567890.", begin);
72 std::string sub_string;
73 if (end != std::string::npos)
74 sub_string = version_string.substr(begin, end - begin);
75 else
76 sub_string = version_string.substr(begin);
brettw26dab8f02015-08-08 00:28:4777 std::vector<std::string> pieces = base::SplitString(
78 sub_string, ".", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
[email protected]6cc8ece62011-03-14 20:05:4779 if (pieces.size() >= 2)
80 return pieces[0] + "." + pieces[1];
[email protected]7004d7eb2011-01-21 00:27:5381 }
[email protected]007b3f82013-04-09 08:46:4582 return std::string();
[email protected]7004d7eb2011-01-21 00:27:5383}
84
zmo7c7ee3e2015-12-09 23:00:3285// Return the array index of the found name, or return -1.
86int StringContainsName(
87 const std::string& str, const std::string* names, size_t num_names) {
88 std::vector<std::string> tokens = base::SplitString(
89 str, " .,()-_", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
90 for (size_t ii = 0; ii < tokens.size(); ++ii) {
91 for (size_t name_index = 0; name_index < num_names; ++name_index) {
92 if (tokens[ii] == names[name_index])
93 return name_index;
94 }
95 }
96 return -1;
97}
98
[email protected]7004d7eb2011-01-21 00:27:5399} // namespace anonymous
100
[email protected]d7b5cc72013-05-23 20:05:00101namespace gpu {
[email protected]7004d7eb2011-01-21 00:27:53102
[email protected]0e8cac72014-03-22 00:37:18103CollectInfoResult CollectGraphicsInfoGL(GPUInfo* gpu_info) {
[email protected]aa328c72013-05-03 10:55:43104 TRACE_EVENT0("startup", "gpu_info_collector::CollectGraphicsInfoGL");
[email protected]93389042014-02-11 03:46:52105 DCHECK_NE(gfx::GetGLImplementation(), gfx::kGLImplementationNone);
[email protected]f62a5ab2011-05-23 20:34:15106
[email protected]fbe20372011-06-01 01:46:38107 scoped_refptr<gfx::GLSurface> surface(InitializeGLSurface());
[email protected]0e8cac72014-03-22 00:37:18108 if (!surface.get()) {
109 LOG(ERROR) << "Could not create surface for info collection.";
110 return kCollectInfoFatalFailure;
111 }
[email protected]f62a5ab2011-05-23 20:34:15112
[email protected]fbe20372011-06-01 01:46:38113 scoped_refptr<gfx::GLContext> context(InitializeGLContext(surface.get()));
[email protected]0e8cac72014-03-22 00:37:18114 if (!context.get()) {
115 LOG(ERROR) << "Could not create context for info collection.";
116 return kCollectInfoFatalFailure;
117 }
[email protected]7004d7eb2011-01-21 00:27:53118
[email protected]a61508e52011-03-08 17:59:42119 gpu_info->gl_renderer = GetGLString(GL_RENDERER);
120 gpu_info->gl_vendor = GetGLString(GL_VENDOR);
kbr53edb992015-08-06 01:16:29121 gpu_info->gl_extensions = gfx::GetGLExtensionsFromCurrentContext();
[email protected]39c542622014-05-07 22:16:36122 gpu_info->gl_version = GetGLString(GL_VERSION);
[email protected]4df0884f2012-12-17 21:10:09123 std::string glsl_version_string = GetGLString(GL_SHADING_LANGUAGE_VERSION);
j.isorce246d1be52015-12-03 21:53:36124
125 gfx::GLVersionInfo gl_info(gpu_info->gl_version.c_str(),
126 gpu_info->gl_renderer.c_str(),
127 gpu_info->gl_extensions.c_str());
senorblancob7a64d52015-04-08 16:59:02128 GLint max_samples = 0;
j.isorce246d1be52015-12-03 21:53:36129 if (gl_info.IsAtLeastGL(3, 0) || gl_info.IsAtLeastGLES(3, 0) ||
130 gpu_info->gl_extensions.find("GL_ANGLE_framebuffer_multisample") !=
131 std::string::npos ||
132 gpu_info->gl_extensions.find("GL_APPLE_framebuffer_multisample") !=
133 std::string::npos ||
134 gpu_info->gl_extensions.find("GL_EXT_framebuffer_multisample") !=
135 std::string::npos ||
136 gpu_info->gl_extensions.find("GL_EXT_multisampled_render_to_texture") !=
137 std::string::npos ||
138 gpu_info->gl_extensions.find("GL_NV_framebuffer_multisample") !=
139 std::string::npos) {
140 glGetIntegerv(GL_MAX_SAMPLES, &max_samples);
141 }
riceaa01edead2015-07-01 15:56:50142 gpu_info->max_msaa_samples = base::IntToString(max_samples);
senorblanco930f690f2015-09-18 16:18:03143 UMA_HISTOGRAM_SPARSE_SLOWLY("GPU.MaxMSAASampleCount", max_samples);
[email protected]45895032013-05-30 17:06:43144
145 gfx::GLWindowSystemBindingInfo window_system_binding_info;
146 if (GetGLWindowSystemBindingInfo(&window_system_binding_info)) {
147 gpu_info->gl_ws_vendor = window_system_binding_info.vendor;
148 gpu_info->gl_ws_version = window_system_binding_info.version;
149 gpu_info->gl_ws_extensions = window_system_binding_info.extensions;
[email protected]0e8cac72014-03-22 00:37:18150 gpu_info->direct_rendering = window_system_binding_info.direct_rendering;
[email protected]45895032013-05-30 17:06:43151 }
152
[email protected]6c7784e2013-08-01 22:41:28153 bool supports_robustness =
154 gpu_info->gl_extensions.find("GL_EXT_robustness") != std::string::npos ||
dongseong.hwange1cb2aa2015-02-11 09:33:33155 gpu_info->gl_extensions.find("GL_KHR_robustness") != std::string::npos ||
[email protected]6c7784e2013-08-01 22:41:28156 gpu_info->gl_extensions.find("GL_ARB_robustness") != std::string::npos;
157 if (supports_robustness) {
158 glGetIntegerv(GL_RESET_NOTIFICATION_STRATEGY_ARB,
159 reinterpret_cast<GLint*>(&gpu_info->gl_reset_notification_strategy));
160 }
161
[email protected]2436a6b2012-04-13 21:08:51162 // TODO(kbr): remove once the destruction of a current context automatically
163 // clears the current context.
164 context->ReleaseCurrent(surface.get());
165
[email protected]6cc8ece62011-03-14 20:05:47166 std::string glsl_version = GetVersionFromString(glsl_version_string);
[email protected]a61508e52011-03-08 17:59:42167 gpu_info->pixel_shader_version = glsl_version;
168 gpu_info->vertex_shader_version = glsl_version;
[email protected]7004d7eb2011-01-21 00:27:53169
zmo7c7ee3e2015-12-09 23:00:32170 IdentifyActiveGPU(gpu_info);
[email protected]4df0884f2012-12-17 21:10:09171 return CollectDriverInfoGL(gpu_info);
172}
173
[email protected]d7b5cc72013-05-23 20:05:00174void MergeGPUInfoGL(GPUInfo* basic_gpu_info,
175 const GPUInfo& context_gpu_info) {
[email protected]4df0884f2012-12-17 21:10:09176 DCHECK(basic_gpu_info);
zmo7c7ee3e2015-12-09 23:00:32177 // Copy over GPUs because which one is active could change.
178 basic_gpu_info->gpu = context_gpu_info.gpu;
179 basic_gpu_info->secondary_gpus = context_gpu_info.secondary_gpus;
180
[email protected]4df0884f2012-12-17 21:10:09181 basic_gpu_info->gl_renderer = context_gpu_info.gl_renderer;
182 basic_gpu_info->gl_vendor = context_gpu_info.gl_vendor;
[email protected]4df0884f2012-12-17 21:10:09183 basic_gpu_info->gl_version = context_gpu_info.gl_version;
[email protected]39c542622014-05-07 22:16:36184 basic_gpu_info->gl_extensions = context_gpu_info.gl_extensions;
[email protected]4df0884f2012-12-17 21:10:09185 basic_gpu_info->pixel_shader_version =
186 context_gpu_info.pixel_shader_version;
187 basic_gpu_info->vertex_shader_version =
188 context_gpu_info.vertex_shader_version;
senorblancob7a64d52015-04-08 16:59:02189 basic_gpu_info->max_msaa_samples =
190 context_gpu_info.max_msaa_samples;
[email protected]45895032013-05-30 17:06:43191 basic_gpu_info->gl_ws_vendor = context_gpu_info.gl_ws_vendor;
192 basic_gpu_info->gl_ws_version = context_gpu_info.gl_ws_version;
193 basic_gpu_info->gl_ws_extensions = context_gpu_info.gl_ws_extensions;
[email protected]6c7784e2013-08-01 22:41:28194 basic_gpu_info->gl_reset_notification_strategy =
195 context_gpu_info.gl_reset_notification_strategy;
[email protected]4df0884f2012-12-17 21:10:09196
197 if (!context_gpu_info.driver_vendor.empty())
198 basic_gpu_info->driver_vendor = context_gpu_info.driver_vendor;
199 if (!context_gpu_info.driver_version.empty())
200 basic_gpu_info->driver_version = context_gpu_info.driver_version;
201
202 basic_gpu_info->can_lose_context = context_gpu_info.can_lose_context;
203 basic_gpu_info->sandboxed = context_gpu_info.sandboxed;
[email protected]0e8cac72014-03-22 00:37:18204 basic_gpu_info->direct_rendering = context_gpu_info.direct_rendering;
bajonese3677b642015-07-25 00:41:56205 basic_gpu_info->in_process_gpu = context_gpu_info.in_process_gpu;
zmo84eae5e2014-09-05 01:36:23206 basic_gpu_info->context_info_state = context_gpu_info.context_info_state;
[email protected]4df0884f2012-12-17 21:10:09207 basic_gpu_info->initialization_time = context_gpu_info.initialization_time;
liberato575877902015-12-10 17:16:26208 basic_gpu_info->video_decode_accelerator_capabilities =
209 context_gpu_info.video_decode_accelerator_capabilities;
wuchengli79808322014-09-23 05:58:14210 basic_gpu_info->video_encode_accelerator_supported_profiles =
211 context_gpu_info.video_encode_accelerator_supported_profiles;
henryhsu74f6ef12015-07-23 08:34:37212 basic_gpu_info->jpeg_decode_accelerator_supported =
213 context_gpu_info.jpeg_decode_accelerator_supported;
[email protected]7004d7eb2011-01-21 00:27:53214}
215
zmo7c7ee3e2015-12-09 23:00:32216void IdentifyActiveGPU(GPUInfo* gpu_info) {
217 const std::string kNVidiaName = "nvidia";
218 const std::string kIntelName = "intel";
219 const std::string kAMDName = "amd";
220 const std::string kATIName = "ati";
221 const std::string kVendorNames[] = {
222 kNVidiaName, kIntelName, kAMDName, kATIName};
223
avif15d60a2015-12-21 17:06:33224 const uint32_t kNVidiaID = 0x10de;
225 const uint32_t kIntelID = 0x8086;
226 const uint32_t kAMDID = 0x1002;
227 const uint32_t kATIID = 0x1002;
228 const uint32_t kVendorIDs[] = {kNVidiaID, kIntelID, kAMDID, kATIID};
zmo7c7ee3e2015-12-09 23:00:32229
230 DCHECK(gpu_info);
231 if (gpu_info->secondary_gpus.size() == 0)
232 return;
233
avif15d60a2015-12-21 17:06:33234 uint32_t active_vendor_id = 0;
zmo7c7ee3e2015-12-09 23:00:32235 if (!gpu_info->gl_vendor.empty()) {
236 std::string gl_vendor_lower = base::ToLowerASCII(gpu_info->gl_vendor);
237 int index = StringContainsName(
238 gl_vendor_lower, kVendorNames, arraysize(kVendorNames));
239 if (index >= 0) {
240 active_vendor_id = kVendorIDs[index];
241 }
242 }
243 if (active_vendor_id == 0 && !gpu_info->gl_renderer.empty()) {
244 std::string gl_renderer_lower = base::ToLowerASCII(gpu_info->gl_renderer);
245 int index = StringContainsName(
246 gl_renderer_lower, kVendorNames, arraysize(kVendorNames));
247 if (index >= 0) {
248 active_vendor_id = kVendorIDs[index];
249 }
250 }
251 if (active_vendor_id == 0) {
252 // We fail to identify the GPU vendor through GL_VENDOR/GL_RENDERER.
253 return;
254 }
255 gpu_info->gpu.active = false;
256 for (size_t ii = 0; ii < gpu_info->secondary_gpus.size(); ++ii)
257 gpu_info->secondary_gpus[ii].active = false;
258
259 // TODO(zmo): if two GPUs are from the same vendor, this code will always
260 // set the first GPU as active, which could be wrong.
261 if (active_vendor_id == gpu_info->gpu.vendor_id) {
262 gpu_info->gpu.active = true;
263 return;
264 }
265 for (size_t ii = 0; ii < gpu_info->secondary_gpus.size(); ++ii) {
266 if (active_vendor_id == gpu_info->secondary_gpus[ii].vendor_id) {
267 gpu_info->secondary_gpus[ii].active = true;
268 return;
269 }
270 }
271}
272
[email protected]d7b5cc72013-05-23 20:05:00273} // namespace gpu
[email protected]7004d7eb2011-01-21 00:27:53274