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