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 <stddef.h>
6 #include <stdint.h>
7
8 #include <memory>
9 #include <string>
10 #include <vector>
11
12 #include "base/strings/string_split.h"
13 #include "gpu/config/gpu_info.h"
14 #include "gpu/config/gpu_info_collector.h"
15 #include "testing/gmock/include/gmock/gmock.h"
16 #include "testing/gtest/include/gtest/gtest.h"
17 #include "ui/gl/gl_context_stub.h"
18 #include "ui/gl/gl_implementation.h"
19 #include "ui/gl/gl_mock.h"
20 #include "ui/gl/gl_surface_stub.h"
21 #include "ui/gl/init/gl_factory.h"
22 #include "ui/gl/test/gl_surface_test_support.h"
23
24 using ::gl::MockGLInterface;
25 using ::testing::Return;
26 using ::testing::SetArgPointee;
27 using ::testing::_;
28
29 namespace {
30
31 // Allows testing of all configurations on all operating systems.
32 enum MockedOperatingSystemKind {
33 kMockedAndroid,
34 kMockedLinux,
35 kMockedMacOSX,
36 kMockedWindows
37 };
38
39 } // anonymous namespace
40
41 namespace gpu {
42
43 static const MockedOperatingSystemKind kMockedOperatingSystemKinds[] = {
44 kMockedAndroid,
45 kMockedLinux,
46 kMockedMacOSX,
47 kMockedWindows
48 };
49
50 class GPUInfoCollectorTest
51 : public testing::Test,
52 public ::testing::WithParamInterface<MockedOperatingSystemKind> {
53 public:
54 GPUInfoCollectorTest() = default;
55 ~GPUInfoCollectorTest() override = default;
56
SetUp()57 void SetUp() override {
58 testing::Test::SetUp();
59 gl::SetGLGetProcAddressProc(gl::MockGLInterface::GetGLProcAddress);
60 gl::GLSurfaceTestSupport::InitializeOneOffWithMockBindings();
61 gl_.reset(new ::testing::StrictMock<::gl::MockGLInterface>());
62 ::gl::MockGLInterface::SetGLInterface(gl_.get());
63 switch (GetParam()) {
64 case kMockedAndroid: {
65 test_values_.gpu.vendor_id = 0; // not implemented
66 test_values_.gpu.device_id = 0; // not implemented
67 test_values_.gpu.driver_vendor = ""; // not implemented
68 test_values_.gpu.driver_version = "14.0";
69 test_values_.pixel_shader_version = "1.00";
70 test_values_.vertex_shader_version = "1.00";
71 test_values_.gl_renderer = "Adreno (TM) 320";
72 test_values_.gl_vendor = "Qualcomm";
73 test_values_.gl_version = "OpenGL ES 2.0 V@14.0 AU@04.02 (CL@3206)";
74 test_values_.gl_extensions =
75 "GL_OES_packed_depth_stencil GL_EXT_texture_format_BGRA8888 "
76 "GL_EXT_read_format_bgra GL_EXT_multisampled_render_to_texture";
77 gl_shading_language_version_ = "1.00";
78 break;
79 }
80 case kMockedLinux: {
81 test_values_.gpu.vendor_id = 0x10de;
82 test_values_.gpu.device_id = 0x0658;
83 test_values_.gpu.driver_vendor = "NVIDIA";
84 test_values_.gpu.driver_version = "195.36.24";
85 test_values_.pixel_shader_version = "1.50";
86 test_values_.vertex_shader_version = "1.50";
87 test_values_.gl_renderer = "Quadro FX 380/PCI/SSE2";
88 test_values_.gl_vendor = "NVIDIA Corporation";
89 test_values_.gl_version = "3.2.0 NVIDIA 195.36.24";
90 test_values_.gl_extensions =
91 "GL_OES_packed_depth_stencil GL_EXT_texture_format_BGRA8888 "
92 "GL_EXT_read_format_bgra";
93 gl_shading_language_version_ = "1.50 NVIDIA via Cg compiler";
94 break;
95 }
96 case kMockedMacOSX: {
97 test_values_.gpu.vendor_id = 0x10de;
98 test_values_.gpu.device_id = 0x0640;
99 test_values_.gpu.driver_vendor = "NVIDIA";
100 test_values_.gpu.driver_version = "1.6.18";
101 test_values_.pixel_shader_version = "1.20";
102 test_values_.vertex_shader_version = "1.20";
103 test_values_.gl_renderer = "NVIDIA GeForce GT 120 OpenGL Engine";
104 test_values_.gl_vendor = "NVIDIA Corporation";
105 test_values_.gl_version = "2.1 NVIDIA-1.6.18";
106 test_values_.gl_extensions =
107 "GL_OES_packed_depth_stencil GL_EXT_texture_format_BGRA8888 "
108 "GL_EXT_read_format_bgra GL_EXT_framebuffer_multisample";
109 gl_shading_language_version_ = "1.20 ";
110 break;
111 }
112 case kMockedWindows: {
113 test_values_.gpu.vendor_id = 0x10de;
114 test_values_.gpu.device_id = 0x0658;
115 test_values_.gpu.driver_vendor = ""; // not implemented
116 test_values_.gpu.driver_version = "";
117 test_values_.pixel_shader_version = "1.40";
118 test_values_.vertex_shader_version = "1.40";
119 test_values_.gl_renderer = "Quadro FX 380/PCI/SSE2";
120 test_values_.gl_vendor = "NVIDIA Corporation";
121 test_values_.gl_version = "3.1.0";
122 test_values_.gl_extensions =
123 "GL_OES_packed_depth_stencil GL_EXT_texture_format_BGRA8888 "
124 "GL_EXT_read_format_bgra";
125 gl_shading_language_version_ = "1.40 NVIDIA via Cg compiler";
126 break;
127 }
128 default: {
129 NOTREACHED();
130 break;
131 }
132 }
133
134 // Need to make a context current so that WillUseGLGetStringForExtensions
135 // can be called
136 context_ = new gl::GLContextStub;
137 context_->SetExtensionsString(test_values_.gl_extensions.c_str());
138 context_->SetGLVersionString(test_values_.gl_version.c_str());
139 surface_ = new gl::GLSurfaceStub;
140 context_->MakeCurrent(surface_.get());
141
142 EXPECT_CALL(*gl_, GetString(GL_VERSION))
143 .WillRepeatedly(Return(reinterpret_cast<const GLubyte*>(
144 test_values_.gl_version.c_str())));
145
146 // Now that that expectation is set up, we can call this helper function.
147 if (gl::WillUseGLGetStringForExtensions()) {
148 EXPECT_CALL(*gl_, GetString(GL_EXTENSIONS))
149 .WillRepeatedly(Return(reinterpret_cast<const GLubyte*>(
150 test_values_.gl_extensions.c_str())));
151 } else {
152 split_extensions_.clear();
153 split_extensions_ = base::SplitString(
154 test_values_.gl_extensions, " ",
155 base::KEEP_WHITESPACE, base::SPLIT_WANT_NONEMPTY);
156 EXPECT_CALL(*gl_, GetIntegerv(GL_NUM_EXTENSIONS, _))
157 .WillRepeatedly(SetArgPointee<1>(split_extensions_.size()));
158 for (size_t ii = 0; ii < split_extensions_.size(); ++ii) {
159 EXPECT_CALL(*gl_, GetStringi(GL_EXTENSIONS, ii))
160 .WillRepeatedly(Return(reinterpret_cast<const uint8_t*>(
161 split_extensions_[ii].c_str())));
162 }
163 }
164 EXPECT_CALL(*gl_, GetString(GL_SHADING_LANGUAGE_VERSION))
165 .WillRepeatedly(Return(reinterpret_cast<const GLubyte*>(
166 gl_shading_language_version_)));
167 EXPECT_CALL(*gl_, GetString(GL_VENDOR))
168 .WillRepeatedly(Return(reinterpret_cast<const GLubyte*>(
169 test_values_.gl_vendor.c_str())));
170 EXPECT_CALL(*gl_, GetString(GL_RENDERER))
171 .WillRepeatedly(Return(reinterpret_cast<const GLubyte*>(
172 test_values_.gl_renderer.c_str())));
173 EXPECT_CALL(*gl_, GetIntegerv(GL_MAX_SAMPLES, _))
174 .WillOnce(SetArgPointee<1>(8))
175 .RetiresOnSaturation();
176 }
177
TearDown()178 void TearDown() override {
179 ::gl::MockGLInterface::SetGLInterface(nullptr);
180 gl_.reset();
181 gl::init::ShutdownGL(false);
182
183 testing::Test::TearDown();
184 }
185
186 public:
187 // Use StrictMock to make 100% sure we know how GL will be called.
188 std::unique_ptr<::testing::StrictMock<::gl::MockGLInterface>> gl_;
189 GPUInfo test_values_;
190 scoped_refptr<gl::GLContextStub> context_;
191 scoped_refptr<gl::GLSurfaceStub> surface_;
192 const char* gl_shading_language_version_ = nullptr;
193
194 // Persistent storage is needed for the split extension string.
195 std::vector<std::string> split_extensions_;
196 };
197
198 INSTANTIATE_TEST_SUITE_P(GPUConfig,
199 GPUInfoCollectorTest,
200 ::testing::ValuesIn(kMockedOperatingSystemKinds));
201
202 // TODO(rlp): Test the vendor and device id collection if deemed necessary as
203 // it involves several complicated mocks for each platform.
204
205 // TODO(kbr): This test still has platform-dependent behavior because
206 // CollectDriverInfoGL behaves differently per platform. This should
207 // be fixed.
TEST_P(GPUInfoCollectorTest,CollectGraphicsInfoGL)208 TEST_P(GPUInfoCollectorTest, CollectGraphicsInfoGL) {
209 GPUInfo gpu_info;
210 CollectGraphicsInfoGL(&gpu_info);
211 #if defined(OS_WIN)
212 if (GetParam() == kMockedWindows) {
213 EXPECT_EQ(test_values_.gpu.driver_vendor, gpu_info.gpu.driver_vendor);
214 // Skip testing the driver version on Windows because it's
215 // obtained from the bot's registry.
216 }
217 #elif defined(OS_MACOSX)
218 if (GetParam() == kMockedMacOSX) {
219 EXPECT_EQ(test_values_.gpu.driver_vendor, gpu_info.gpu.driver_vendor);
220 EXPECT_EQ(test_values_.gpu.driver_version, gpu_info.gpu.driver_version);
221 }
222 #elif defined(OS_ANDROID)
223 if (GetParam() == kMockedAndroid) {
224 EXPECT_EQ(test_values_.gpu.driver_vendor, gpu_info.gpu.driver_vendor);
225 EXPECT_EQ(test_values_.gpu.driver_version, gpu_info.gpu.driver_version);
226 }
227 #else // defined (OS_LINUX)
228 if (GetParam() == kMockedLinux) {
229 EXPECT_EQ(test_values_.gpu.driver_vendor, gpu_info.gpu.driver_vendor);
230 EXPECT_EQ(test_values_.gpu.driver_version, gpu_info.gpu.driver_version);
231 }
232 #endif
233
234 EXPECT_EQ(test_values_.pixel_shader_version,
235 gpu_info.pixel_shader_version);
236 EXPECT_EQ(test_values_.vertex_shader_version,
237 gpu_info.vertex_shader_version);
238 EXPECT_EQ(test_values_.gl_version, gpu_info.gl_version);
239 EXPECT_EQ(test_values_.gl_renderer, gpu_info.gl_renderer);
240 EXPECT_EQ(test_values_.gl_vendor, gpu_info.gl_vendor);
241 EXPECT_EQ(test_values_.gl_extensions, gpu_info.gl_extensions);
242 }
243
TEST(MultiGPUsTest,IdentifyActiveGPU0)244 TEST(MultiGPUsTest, IdentifyActiveGPU0) {
245 GPUInfo::GPUDevice nvidia_gpu;
246 nvidia_gpu.vendor_id = 0x10de;
247 nvidia_gpu.device_id = 0x0df8;
248 GPUInfo::GPUDevice intel_gpu;
249 intel_gpu.vendor_id = 0x8086;
250 intel_gpu.device_id = 0x0416;
251
252 GPUInfo gpu_info;
253 gpu_info.gpu = nvidia_gpu;
254 gpu_info.secondary_gpus.push_back(intel_gpu);
255
256 EXPECT_FALSE(gpu_info.gpu.active);
257 EXPECT_FALSE(gpu_info.secondary_gpus[0].active);
258
259 IdentifyActiveGPU(&gpu_info);
260 EXPECT_FALSE(gpu_info.gpu.active);
261 EXPECT_FALSE(gpu_info.secondary_gpus[0].active);
262
263 gpu_info.gl_vendor = "Intel Open Source Technology Center";
264 gpu_info.gl_renderer = "Mesa DRI Intel(R) Haswell Mobile";
265 IdentifyActiveGPU(&gpu_info);
266 EXPECT_FALSE(gpu_info.gpu.active);
267 EXPECT_TRUE(gpu_info.secondary_gpus[0].active);
268
269 gpu_info.gl_vendor = "NVIDIA Corporation";
270 gpu_info.gl_renderer = "Quadro 600/PCIe/SSE2";
271 IdentifyActiveGPU(&gpu_info);
272 EXPECT_TRUE(gpu_info.gpu.active);
273 EXPECT_FALSE(gpu_info.secondary_gpus[0].active);
274 }
275
TEST(MultiGPUsTest,IdentifyActiveGPU1)276 TEST(MultiGPUsTest, IdentifyActiveGPU1) {
277 GPUInfo::GPUDevice nvidia_gpu;
278 nvidia_gpu.vendor_id = 0x10de;
279 nvidia_gpu.device_id = 0x0de1;
280 GPUInfo::GPUDevice intel_gpu;
281 intel_gpu.vendor_id = 0x8086;
282 intel_gpu.device_id = 0x040a;
283
284 GPUInfo gpu_info;
285 gpu_info.gpu = intel_gpu;
286 gpu_info.secondary_gpus.push_back(nvidia_gpu);
287
288 EXPECT_FALSE(gpu_info.gpu.active);
289 EXPECT_FALSE(gpu_info.secondary_gpus[0].active);
290
291 IdentifyActiveGPU(&gpu_info);
292 EXPECT_FALSE(gpu_info.gpu.active);
293 EXPECT_FALSE(gpu_info.secondary_gpus[0].active);
294
295 gpu_info.gl_vendor = "nouveau";
296 IdentifyActiveGPU(&gpu_info);
297 EXPECT_FALSE(gpu_info.gpu.active);
298 EXPECT_TRUE(gpu_info.secondary_gpus[0].active);
299 }
300
TEST(MultiGPUsTest,IdentifyActiveGPU2)301 TEST(MultiGPUsTest, IdentifyActiveGPU2) {
302 GPUInfo::GPUDevice nvidia_gpu;
303 nvidia_gpu.vendor_id = 0x10de;
304 nvidia_gpu.device_id = 0x0de1;
305 GPUInfo::GPUDevice intel_gpu;
306 intel_gpu.vendor_id = 0x8086;
307 intel_gpu.device_id = 0x040a;
308
309 GPUInfo gpu_info;
310 gpu_info.gpu = intel_gpu;
311 gpu_info.secondary_gpus.push_back(nvidia_gpu);
312
313 EXPECT_FALSE(gpu_info.gpu.active);
314 EXPECT_FALSE(gpu_info.secondary_gpus[0].active);
315
316 IdentifyActiveGPU(&gpu_info);
317 EXPECT_FALSE(gpu_info.gpu.active);
318 EXPECT_FALSE(gpu_info.secondary_gpus[0].active);
319
320 gpu_info.gl_vendor = "Intel";
321 IdentifyActiveGPU(&gpu_info);
322 EXPECT_TRUE(gpu_info.gpu.active);
323 EXPECT_FALSE(gpu_info.secondary_gpus[0].active);
324 }
325
TEST(MultiGPUsTest,IdentifyActiveGPU3)326 TEST(MultiGPUsTest, IdentifyActiveGPU3) {
327 GPUInfo::GPUDevice nvidia_gpu;
328 nvidia_gpu.vendor_id = 0x10de;
329 nvidia_gpu.device_id = 0x0de1;
330 GPUInfo::GPUDevice intel_gpu;
331 intel_gpu.vendor_id = 0x8086;
332 intel_gpu.device_id = 0x040a;
333 GPUInfo::GPUDevice amd_gpu;
334 amd_gpu.vendor_id = 0x1002;
335 amd_gpu.device_id = 0x6779;
336
337 GPUInfo gpu_info;
338 gpu_info.gpu = intel_gpu;
339 gpu_info.secondary_gpus.push_back(nvidia_gpu);
340 gpu_info.secondary_gpus.push_back(amd_gpu);
341
342 EXPECT_FALSE(gpu_info.gpu.active);
343 EXPECT_FALSE(gpu_info.secondary_gpus[0].active);
344 EXPECT_FALSE(gpu_info.secondary_gpus[1].active);
345
346 IdentifyActiveGPU(&gpu_info);
347 EXPECT_FALSE(gpu_info.gpu.active);
348 EXPECT_FALSE(gpu_info.secondary_gpus[0].active);
349 EXPECT_FALSE(gpu_info.secondary_gpus[1].active);
350
351 gpu_info.gl_vendor = "X.Org";
352 gpu_info.gl_renderer = "AMD R600";
353 IdentifyActiveGPU(&gpu_info);
354 EXPECT_FALSE(gpu_info.gpu.active);
355 EXPECT_FALSE(gpu_info.secondary_gpus[0].active);
356 EXPECT_TRUE(gpu_info.secondary_gpus[1].active);
357 }
358
TEST(MultiGPUsTest,IdentifyActiveGPU4)359 TEST(MultiGPUsTest, IdentifyActiveGPU4) {
360 GPUInfo::GPUDevice nvidia_gpu;
361 nvidia_gpu.vendor_id = 0x10de;
362 nvidia_gpu.device_id = 0x0de1;
363
364 GPUInfo gpu_info;
365 gpu_info.gpu = nvidia_gpu;
366
367 EXPECT_FALSE(gpu_info.gpu.active);
368
369 IdentifyActiveGPU(&gpu_info);
370 EXPECT_TRUE(gpu_info.gpu.active);
371
372 gpu_info.gl_vendor = "nouveau";
373 IdentifyActiveGPU(&gpu_info);
374 EXPECT_TRUE(gpu_info.gpu.active);
375 }
376
TEST(MultiGPUsTest,IdentifyActiveGPUAvoidFalseMatch)377 TEST(MultiGPUsTest, IdentifyActiveGPUAvoidFalseMatch) {
378 // Verify that "Corporation" won't be matched with "ati".
379 GPUInfo::GPUDevice amd_gpu;
380 amd_gpu.vendor_id = 0x1002;
381 amd_gpu.device_id = 0x0df8;
382 GPUInfo::GPUDevice intel_gpu;
383 intel_gpu.vendor_id = 0x8086;
384 intel_gpu.device_id = 0x0416;
385
386 GPUInfo gpu_info;
387 gpu_info.gpu = amd_gpu;
388 gpu_info.secondary_gpus.push_back(intel_gpu);
389
390 gpu_info.gl_vendor = "Google Corporation";
391 gpu_info.gl_renderer = "Chrome GPU Team";
392 IdentifyActiveGPU(&gpu_info);
393 EXPECT_FALSE(gpu_info.gpu.active);
394 EXPECT_FALSE(gpu_info.secondary_gpus[0].active);
395 }
396
397 } // namespace gpu
398