// Copyright (c) 2012 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "gpu/config/gpu_info_collector.h" #include #include #include #include #include #include "base/memory/raw_ptr.h" #include "base/strings/string_split.h" #include "build/build_config.h" #include "gpu/config/gpu_info.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" #include "ui/gl/gl_context_stub.h" #include "ui/gl/gl_display.h" #include "ui/gl/gl_implementation.h" #include "ui/gl/gl_mock.h" #include "ui/gl/gl_surface_stub.h" #include "ui/gl/gl_utils.h" #include "ui/gl/init/gl_factory.h" #include "ui/gl/test/gl_surface_test_support.h" using ::gl::MockGLInterface; using ::testing::Return; using ::testing::SetArgPointee; using ::testing::_; namespace { // Allows testing of all configurations on all operating systems. enum MockedOperatingSystemKind { kMockedAndroid, kMockedLinux, kMockedMacOSX, kMockedWindows }; } // anonymous namespace namespace gpu { static const MockedOperatingSystemKind kMockedOperatingSystemKinds[] = { kMockedAndroid, kMockedLinux, kMockedMacOSX, kMockedWindows }; class GPUInfoCollectorTest : public testing::Test, public ::testing::WithParamInterface { public: GPUInfoCollectorTest() = default; ~GPUInfoCollectorTest() override = default; void SetUp() override { testing::Test::SetUp(); gl::SetGLGetProcAddressProc(gl::MockGLInterface::GetGLProcAddress); display_ = gl::GLSurfaceTestSupport::InitializeOneOffWithMockBindings(); gl_ = std::make_unique<::testing::StrictMock<::gl::MockGLInterface>>(); ::gl::MockGLInterface::SetGLInterface(gl_.get()); switch (GetParam()) { case kMockedAndroid: { test_values_.gpu.vendor_id = 0; // not implemented test_values_.gpu.device_id = 0; // not implemented test_values_.gpu.driver_vendor = ""; // not implemented test_values_.gpu.driver_version = "14.0"; test_values_.pixel_shader_version = "1.00"; test_values_.vertex_shader_version = "1.00"; test_values_.gl_renderer = "Adreno (TM) 320"; test_values_.gl_vendor = "Qualcomm"; test_values_.gl_version = "OpenGL ES 2.0 V@14.0 AU@04.02 (CL@3206)"; test_values_.gl_extensions = "GL_OES_packed_depth_stencil GL_EXT_texture_format_BGRA8888 " "GL_EXT_read_format_bgra GL_EXT_multisampled_render_to_texture"; gl_shading_language_version_ = "1.00"; break; } case kMockedLinux: { test_values_.gpu.vendor_id = 0x10de; test_values_.gpu.device_id = 0x0658; test_values_.gpu.driver_vendor = "NVIDIA"; test_values_.gpu.driver_version = "195.36.24"; test_values_.pixel_shader_version = "1.50"; test_values_.vertex_shader_version = "1.50"; test_values_.gl_renderer = "Quadro FX 380/PCI/SSE2"; test_values_.gl_vendor = "NVIDIA Corporation"; test_values_.gl_version = "3.2.0 NVIDIA 195.36.24"; test_values_.gl_extensions = "GL_OES_packed_depth_stencil GL_EXT_texture_format_BGRA8888 " "GL_EXT_read_format_bgra"; gl_shading_language_version_ = "1.50 NVIDIA via Cg compiler"; break; } case kMockedMacOSX: { test_values_.gpu.vendor_id = 0x10de; test_values_.gpu.device_id = 0x0640; test_values_.gpu.driver_vendor = "NVIDIA"; test_values_.gpu.driver_version = "1.6.18"; test_values_.pixel_shader_version = "1.20"; test_values_.vertex_shader_version = "1.20"; test_values_.gl_renderer = "NVIDIA GeForce GT 120 OpenGL Engine"; test_values_.gl_vendor = "NVIDIA Corporation"; test_values_.gl_version = "2.1 NVIDIA-1.6.18"; test_values_.gl_extensions = "GL_OES_packed_depth_stencil GL_EXT_texture_format_BGRA8888 " "GL_EXT_read_format_bgra GL_EXT_framebuffer_multisample"; gl_shading_language_version_ = "1.20 "; break; } case kMockedWindows: { test_values_.gpu.vendor_id = 0x10de; test_values_.gpu.device_id = 0x0658; test_values_.gpu.driver_vendor = ""; // not implemented test_values_.gpu.driver_version = ""; test_values_.pixel_shader_version = "1.40"; test_values_.vertex_shader_version = "1.40"; test_values_.gl_renderer = "Quadro FX 380/PCI/SSE2"; test_values_.gl_vendor = "NVIDIA Corporation"; test_values_.gl_version = "3.1.0"; test_values_.gl_extensions = "GL_OES_packed_depth_stencil GL_EXT_texture_format_BGRA8888 " "GL_EXT_read_format_bgra"; gl_shading_language_version_ = "1.40 NVIDIA via Cg compiler"; break; } default: { NOTREACHED(); break; } } // Need to make a context current so that WillUseGLGetStringForExtensions // can be called context_ = new gl::GLContextStub; context_->SetExtensionsString(test_values_.gl_extensions.c_str()); context_->SetGLVersionString(test_values_.gl_version.c_str()); surface_ = new gl::GLSurfaceStub; context_->MakeCurrent(surface_.get()); EXPECT_CALL(*gl_, GetString(GL_VERSION)) .WillRepeatedly(Return(reinterpret_cast( test_values_.gl_version.c_str()))); EXPECT_CALL(*gl_, GetString(GL_RENDERER)) .WillRepeatedly(Return(reinterpret_cast( test_values_.gl_renderer.c_str()))); // Now that that expectation is set up, we can call this helper function. if (gl::WillUseGLGetStringForExtensions()) { EXPECT_CALL(*gl_, GetString(GL_EXTENSIONS)) .WillRepeatedly(Return(reinterpret_cast( test_values_.gl_extensions.c_str()))); } else { split_extensions_.clear(); split_extensions_ = base::SplitString( test_values_.gl_extensions, " ", base::KEEP_WHITESPACE, base::SPLIT_WANT_NONEMPTY); EXPECT_CALL(*gl_, GetIntegerv(GL_NUM_EXTENSIONS, _)) .WillRepeatedly(SetArgPointee<1>(split_extensions_.size())); for (size_t ii = 0; ii < split_extensions_.size(); ++ii) { EXPECT_CALL(*gl_, GetStringi(GL_EXTENSIONS, ii)) .WillRepeatedly(Return(reinterpret_cast( split_extensions_[ii].c_str()))); } } EXPECT_CALL(*gl_, GetString(GL_SHADING_LANGUAGE_VERSION)) .WillRepeatedly(Return(reinterpret_cast( gl_shading_language_version_))); EXPECT_CALL(*gl_, GetString(GL_VENDOR)) .WillRepeatedly(Return(reinterpret_cast( test_values_.gl_vendor.c_str()))); EXPECT_CALL(*gl_, GetString(GL_RENDERER)) .WillRepeatedly(Return(reinterpret_cast( test_values_.gl_renderer.c_str()))); EXPECT_CALL(*gl_, GetIntegerv(GL_MAX_SAMPLES, _)) .WillOnce(SetArgPointee<1>(8)) .RetiresOnSaturation(); } void TearDown() override { ::gl::MockGLInterface::SetGLInterface(nullptr); gl_.reset(); gl::GLSurfaceTestSupport::ShutdownGL(display_); testing::Test::TearDown(); } protected: // Use StrictMock to make 100% sure we know how GL will be called. std::unique_ptr<::testing::StrictMock<::gl::MockGLInterface>> gl_; GPUInfo test_values_; scoped_refptr context_; scoped_refptr surface_; const char* gl_shading_language_version_ = nullptr; // Persistent storage is needed for the split extension string. std::vector split_extensions_; raw_ptr display_ = nullptr; }; INSTANTIATE_TEST_SUITE_P(GPUConfig, GPUInfoCollectorTest, ::testing::ValuesIn(kMockedOperatingSystemKinds)); // TODO(rlp): Test the vendor and device id collection if deemed necessary as // it involves several complicated mocks for each platform. // TODO(kbr): This test still has platform-dependent behavior because // CollectDriverInfoGL behaves differently per platform. This should // be fixed. TEST_P(GPUInfoCollectorTest, CollectGraphicsInfoGL) { GPUInfo gpu_info; CollectGraphicsInfoGL(&gpu_info, gl::GetDefaultDisplay()); #if BUILDFLAG(IS_WIN) if (GetParam() == kMockedWindows) { EXPECT_EQ(test_values_.gpu.driver_vendor, gpu_info.gpu.driver_vendor); // Skip testing the driver version on Windows because it's // obtained from the bot's registry. } #elif BUILDFLAG(IS_MAC) if (GetParam() == kMockedMacOSX) { EXPECT_EQ(test_values_.gpu.driver_vendor, gpu_info.gpu.driver_vendor); EXPECT_EQ(test_values_.gpu.driver_version, gpu_info.gpu.driver_version); } #elif BUILDFLAG(IS_ANDROID) if (GetParam() == kMockedAndroid) { EXPECT_EQ(test_values_.gpu.driver_vendor, gpu_info.gpu.driver_vendor); EXPECT_EQ(test_values_.gpu.driver_version, gpu_info.gpu.driver_version); } #else // BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) if (GetParam() == kMockedLinux) { EXPECT_EQ(test_values_.gpu.driver_vendor, gpu_info.gpu.driver_vendor); EXPECT_EQ(test_values_.gpu.driver_version, gpu_info.gpu.driver_version); } #endif EXPECT_EQ(test_values_.pixel_shader_version, gpu_info.pixel_shader_version); EXPECT_EQ(test_values_.vertex_shader_version, gpu_info.vertex_shader_version); EXPECT_EQ(test_values_.gl_version, gpu_info.gl_version); EXPECT_EQ(test_values_.gl_renderer, gpu_info.gl_renderer); EXPECT_EQ(test_values_.gl_vendor, gpu_info.gl_vendor); EXPECT_EQ(test_values_.gl_extensions, gpu_info.gl_extensions); } TEST(MultiGPUsTest, IdentifyActiveGPU0) { GPUInfo::GPUDevice nvidia_gpu; nvidia_gpu.vendor_id = 0x10de; nvidia_gpu.device_id = 0x0df8; GPUInfo::GPUDevice intel_gpu; intel_gpu.vendor_id = 0x8086; intel_gpu.device_id = 0x0416; GPUInfo gpu_info; gpu_info.gpu = nvidia_gpu; gpu_info.secondary_gpus.push_back(intel_gpu); EXPECT_FALSE(gpu_info.gpu.active); EXPECT_FALSE(gpu_info.secondary_gpus[0].active); IdentifyActiveGPU(&gpu_info); EXPECT_FALSE(gpu_info.gpu.active); EXPECT_FALSE(gpu_info.secondary_gpus[0].active); gpu_info.gl_vendor = "Intel Open Source Technology Center"; gpu_info.gl_renderer = "Mesa DRI Intel(R) Haswell Mobile"; IdentifyActiveGPU(&gpu_info); EXPECT_FALSE(gpu_info.gpu.active); EXPECT_TRUE(gpu_info.secondary_gpus[0].active); gpu_info.gl_vendor = "NVIDIA Corporation"; gpu_info.gl_renderer = "Quadro 600/PCIe/SSE2"; IdentifyActiveGPU(&gpu_info); EXPECT_TRUE(gpu_info.gpu.active); EXPECT_FALSE(gpu_info.secondary_gpus[0].active); } TEST(MultiGPUsTest, IdentifyActiveGPU1) { GPUInfo::GPUDevice nvidia_gpu; nvidia_gpu.vendor_id = 0x10de; nvidia_gpu.device_id = 0x0de1; GPUInfo::GPUDevice intel_gpu; intel_gpu.vendor_id = 0x8086; intel_gpu.device_id = 0x040a; GPUInfo gpu_info; gpu_info.gpu = intel_gpu; gpu_info.secondary_gpus.push_back(nvidia_gpu); EXPECT_FALSE(gpu_info.gpu.active); EXPECT_FALSE(gpu_info.secondary_gpus[0].active); IdentifyActiveGPU(&gpu_info); EXPECT_FALSE(gpu_info.gpu.active); EXPECT_FALSE(gpu_info.secondary_gpus[0].active); gpu_info.gl_vendor = "nouveau"; IdentifyActiveGPU(&gpu_info); EXPECT_FALSE(gpu_info.gpu.active); EXPECT_TRUE(gpu_info.secondary_gpus[0].active); } TEST(MultiGPUsTest, IdentifyActiveGPU2) { GPUInfo::GPUDevice nvidia_gpu; nvidia_gpu.vendor_id = 0x10de; nvidia_gpu.device_id = 0x0de1; GPUInfo::GPUDevice intel_gpu; intel_gpu.vendor_id = 0x8086; intel_gpu.device_id = 0x040a; GPUInfo gpu_info; gpu_info.gpu = intel_gpu; gpu_info.secondary_gpus.push_back(nvidia_gpu); EXPECT_FALSE(gpu_info.gpu.active); EXPECT_FALSE(gpu_info.secondary_gpus[0].active); IdentifyActiveGPU(&gpu_info); EXPECT_FALSE(gpu_info.gpu.active); EXPECT_FALSE(gpu_info.secondary_gpus[0].active); gpu_info.gl_vendor = "Intel"; IdentifyActiveGPU(&gpu_info); EXPECT_TRUE(gpu_info.gpu.active); EXPECT_FALSE(gpu_info.secondary_gpus[0].active); } TEST(MultiGPUsTest, IdentifyActiveGPU3) { GPUInfo::GPUDevice nvidia_gpu; nvidia_gpu.vendor_id = 0x10de; nvidia_gpu.device_id = 0x0de1; GPUInfo::GPUDevice intel_gpu; intel_gpu.vendor_id = 0x8086; intel_gpu.device_id = 0x040a; GPUInfo::GPUDevice amd_gpu; amd_gpu.vendor_id = 0x1002; amd_gpu.device_id = 0x6779; GPUInfo gpu_info; gpu_info.gpu = intel_gpu; gpu_info.secondary_gpus.push_back(nvidia_gpu); gpu_info.secondary_gpus.push_back(amd_gpu); EXPECT_FALSE(gpu_info.gpu.active); EXPECT_FALSE(gpu_info.secondary_gpus[0].active); EXPECT_FALSE(gpu_info.secondary_gpus[1].active); IdentifyActiveGPU(&gpu_info); EXPECT_FALSE(gpu_info.gpu.active); EXPECT_FALSE(gpu_info.secondary_gpus[0].active); EXPECT_FALSE(gpu_info.secondary_gpus[1].active); gpu_info.gl_vendor = "X.Org"; gpu_info.gl_renderer = "AMD R600"; IdentifyActiveGPU(&gpu_info); EXPECT_FALSE(gpu_info.gpu.active); EXPECT_FALSE(gpu_info.secondary_gpus[0].active); EXPECT_TRUE(gpu_info.secondary_gpus[1].active); } TEST(MultiGPUsTest, IdentifyActiveGPU4) { GPUInfo::GPUDevice nvidia_gpu; nvidia_gpu.vendor_id = 0x10de; nvidia_gpu.device_id = 0x0de1; GPUInfo gpu_info; gpu_info.gpu = nvidia_gpu; EXPECT_FALSE(gpu_info.gpu.active); IdentifyActiveGPU(&gpu_info); EXPECT_TRUE(gpu_info.gpu.active); gpu_info.gl_vendor = "nouveau"; IdentifyActiveGPU(&gpu_info); EXPECT_TRUE(gpu_info.gpu.active); } TEST(MultiGPUsTest, IdentifyActiveGPUAvoidFalseMatch) { // Verify that "Corporation" won't be matched with "ati". GPUInfo::GPUDevice amd_gpu; amd_gpu.vendor_id = 0x1002; amd_gpu.device_id = 0x0df8; GPUInfo::GPUDevice intel_gpu; intel_gpu.vendor_id = 0x8086; intel_gpu.device_id = 0x0416; GPUInfo gpu_info; gpu_info.gpu = amd_gpu; gpu_info.secondary_gpus.push_back(intel_gpu); gpu_info.gl_vendor = "Google Corporation"; gpu_info.gl_renderer = "Chrome GPU Team"; IdentifyActiveGPU(&gpu_info); EXPECT_FALSE(gpu_info.gpu.active); EXPECT_FALSE(gpu_info.secondary_gpus[0].active); } } // namespace gpu