1// Copyright (c) 2013 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 <vector> 6 7#include "base/memory/scoped_ptr.h" 8#include "gpu/config/gpu_control_list.h" 9#include "gpu/config/gpu_info.h" 10#include "testing/gtest/include/gtest/gtest.h" 11 12const char kOsVersion[] = "10.6.4"; 13const uint32 kIntelVendorId = 0x8086; 14const uint32 kNvidiaVendorId = 0x10de; 15const uint32 kAmdVendorId = 0x10de; 16 17#define LONG_STRING_CONST(...) #__VA_ARGS__ 18 19#define EXPECT_EMPTY_SET(feature_set) EXPECT_EQ(0u, feature_set.size()) 20#define EXPECT_SINGLE_FEATURE(feature_set, feature) \ 21 EXPECT_TRUE(feature_set.size() == 1 && feature_set.count(feature) == 1) 22 23namespace gpu { 24 25enum TestFeatureType { 26 TEST_FEATURE_0 = 1, 27 TEST_FEATURE_1 = 1 << 2, 28 TEST_FEATURE_2 = 1 << 3, 29}; 30 31class GpuControlListTest : public testing::Test { 32 public: 33 GpuControlListTest() { } 34 35 virtual ~GpuControlListTest() { } 36 37 const GPUInfo& gpu_info() const { 38 return gpu_info_; 39 } 40 41 GpuControlList* Create() { 42 GpuControlList* rt = new GpuControlList(); 43 rt->AddSupportedFeature("test_feature_0", TEST_FEATURE_0); 44 rt->AddSupportedFeature("test_feature_1", TEST_FEATURE_1); 45 rt->AddSupportedFeature("test_feature_2", TEST_FEATURE_2); 46 return rt; 47 } 48 49 protected: 50 virtual void SetUp() { 51 gpu_info_.gpu.vendor_id = kNvidiaVendorId; 52 gpu_info_.gpu.device_id = 0x0640; 53 gpu_info_.driver_vendor = "NVIDIA"; 54 gpu_info_.driver_version = "1.6.18"; 55 gpu_info_.driver_date = "7-14-2009"; 56 gpu_info_.machine_model_name = "MacBookPro"; 57 gpu_info_.machine_model_version = "7.1"; 58 gpu_info_.gl_vendor = "NVIDIA Corporation"; 59 gpu_info_.gl_renderer = "NVIDIA GeForce GT 120 OpenGL Engine"; 60 gpu_info_.performance_stats.graphics = 5.0; 61 gpu_info_.performance_stats.gaming = 5.0; 62 gpu_info_.performance_stats.overall = 5.0; 63 } 64 65 virtual void TearDown() { 66 } 67 68 private: 69 GPUInfo gpu_info_; 70}; 71 72TEST_F(GpuControlListTest, DefaultControlListSettings) { 73 scoped_ptr<GpuControlList> control_list(Create()); 74 // Default control list settings: all feature are allowed. 75 std::set<int> features = control_list->MakeDecision( 76 GpuControlList::kOsMacosx, kOsVersion, gpu_info()); 77 EXPECT_EMPTY_SET(features); 78} 79 80TEST_F(GpuControlListTest, EmptyControlList) { 81 // Empty list: all features are allowed. 82 const std::string empty_list_json = LONG_STRING_CONST( 83 { 84 "name": "gpu control list", 85 "version": "2.5", 86 "entries": [ 87 ] 88 } 89 ); 90 scoped_ptr<GpuControlList> control_list(Create()); 91 92 EXPECT_TRUE(control_list->LoadList(empty_list_json, 93 GpuControlList::kAllOs)); 94 EXPECT_EQ("2.5", control_list->version()); 95 std::set<int> features = control_list->MakeDecision( 96 GpuControlList::kOsMacosx, kOsVersion, gpu_info()); 97 EXPECT_EMPTY_SET(features); 98} 99 100TEST_F(GpuControlListTest, DetailedEntryAndInvalidJson) { 101 // exact setting. 102 const std::string exact_list_json = LONG_STRING_CONST( 103 { 104 "name": "gpu control list", 105 "version": "0.1", 106 "entries": [ 107 { 108 "id": 5, 109 "os": { 110 "type": "macosx", 111 "version": { 112 "op": "=", 113 "value": "10.6.4" 114 } 115 }, 116 "vendor_id": "0x10de", 117 "device_id": ["0x0640"], 118 "driver_version": { 119 "op": "=", 120 "value": "1.6.18" 121 }, 122 "features": [ 123 "test_feature_0" 124 ] 125 } 126 ] 127 } 128 ); 129 scoped_ptr<GpuControlList> control_list(Create()); 130 131 EXPECT_TRUE(control_list->LoadList(exact_list_json, GpuControlList::kAllOs)); 132 std::set<int> features = control_list->MakeDecision( 133 GpuControlList::kOsMacosx, kOsVersion, gpu_info()); 134 EXPECT_SINGLE_FEATURE(features, TEST_FEATURE_0); 135 136 // Invalid json input should not change the current control_list settings. 137 const std::string invalid_json = "invalid"; 138 139 EXPECT_FALSE(control_list->LoadList(invalid_json, GpuControlList::kAllOs)); 140 features = control_list->MakeDecision( 141 GpuControlList::kOsMacosx, kOsVersion, gpu_info()); 142 EXPECT_SINGLE_FEATURE(features, TEST_FEATURE_0); 143 std::vector<uint32> entries; 144 control_list->GetDecisionEntries(&entries, false); 145 ASSERT_EQ(1u, entries.size()); 146 EXPECT_EQ(5u, entries[0]); 147 EXPECT_EQ(5u, control_list->max_entry_id()); 148} 149 150TEST_F(GpuControlListTest, VendorOnAllOsEntry) { 151 // ControlList a vendor on all OS. 152 const std::string vendor_json = LONG_STRING_CONST( 153 { 154 "name": "gpu control list", 155 "version": "0.1", 156 "entries": [ 157 { 158 "id": 1, 159 "vendor_id": "0x10de", 160 "features": [ 161 "test_feature_0" 162 ] 163 } 164 ] 165 } 166 ); 167 scoped_ptr<GpuControlList> control_list(Create()); 168 169 // ControlList entries won't be filtered to the current OS only upon loading. 170 EXPECT_TRUE(control_list->LoadList(vendor_json, GpuControlList::kAllOs)); 171 std::set<int> features = control_list->MakeDecision( 172 GpuControlList::kOsMacosx, kOsVersion, gpu_info()); 173 EXPECT_SINGLE_FEATURE(features, TEST_FEATURE_0); 174 features = control_list->MakeDecision( 175 GpuControlList::kOsWin, kOsVersion, gpu_info()); 176 EXPECT_SINGLE_FEATURE(features, TEST_FEATURE_0); 177 features = control_list->MakeDecision( 178 GpuControlList::kOsLinux, kOsVersion, gpu_info()); 179 EXPECT_SINGLE_FEATURE(features, TEST_FEATURE_0); 180#if defined(OS_WIN) || defined(OS_LINUX) || defined(OS_MACOSX) || \ 181 defined(OS_OPENBSD) 182 // ControlList entries will be filtered to the current OS only upon loading. 183 EXPECT_TRUE(control_list->LoadList( 184 vendor_json, GpuControlList::kCurrentOsOnly)); 185 features = control_list->MakeDecision( 186 GpuControlList::kOsMacosx, kOsVersion, gpu_info()); 187 EXPECT_SINGLE_FEATURE(features, TEST_FEATURE_0); 188 features = control_list->MakeDecision( 189 GpuControlList::kOsWin, kOsVersion, gpu_info()); 190 EXPECT_SINGLE_FEATURE(features, TEST_FEATURE_0); 191 features = control_list->MakeDecision( 192 GpuControlList::kOsLinux, kOsVersion, gpu_info()); 193 EXPECT_SINGLE_FEATURE(features, TEST_FEATURE_0); 194#endif 195} 196 197TEST_F(GpuControlListTest, UnknownField) { 198 const std::string unknown_field_json = LONG_STRING_CONST( 199 { 200 "name": "gpu control list", 201 "version": "0.1", 202 "entries": [ 203 { 204 "id": 1, 205 "unknown_field": 0, 206 "features": [ 207 "test_feature_1" 208 ] 209 }, 210 { 211 "id": 2, 212 "features": [ 213 "test_feature_0" 214 ] 215 } 216 ] 217 } 218 ); 219 scoped_ptr<GpuControlList> control_list(Create()); 220 221 EXPECT_FALSE(control_list->LoadList( 222 unknown_field_json, GpuControlList::kAllOs)); 223} 224 225TEST_F(GpuControlListTest, UnknownExceptionField) { 226 const std::string unknown_exception_field_json = LONG_STRING_CONST( 227 { 228 "name": "gpu control list", 229 "version": "0.1", 230 "entries": [ 231 { 232 "id": 1, 233 "unknown_field": 0, 234 "features": [ 235 "test_feature_2" 236 ] 237 }, 238 { 239 "id": 2, 240 "exceptions": [ 241 { 242 "unknown_field": 0 243 } 244 ], 245 "features": [ 246 "test_feature_1" 247 ] 248 }, 249 { 250 "id": 3, 251 "features": [ 252 "test_feature_0" 253 ] 254 } 255 ] 256 } 257 ); 258 scoped_ptr<GpuControlList> control_list(Create()); 259 260 EXPECT_FALSE(control_list->LoadList( 261 unknown_exception_field_json, GpuControlList::kAllOs)); 262} 263 264TEST_F(GpuControlListTest, DisabledEntry) { 265 const std::string disabled_json = LONG_STRING_CONST( 266 { 267 "name": "gpu control list", 268 "version": "0.1", 269 "entries": [ 270 { 271 "id": 1, 272 "disabled": true, 273 "features": [ 274 "test_feature_0" 275 ] 276 } 277 ] 278 } 279 ); 280 scoped_ptr<GpuControlList> control_list(Create()); 281 EXPECT_TRUE(control_list->LoadList(disabled_json, GpuControlList::kAllOs)); 282 std::set<int> features = control_list->MakeDecision( 283 GpuControlList::kOsWin, kOsVersion, gpu_info()); 284 EXPECT_EMPTY_SET(features); 285 std::vector<uint32> flag_entries; 286 control_list->GetDecisionEntries(&flag_entries, false); 287 EXPECT_EQ(0u, flag_entries.size()); 288 control_list->GetDecisionEntries(&flag_entries, true); 289 EXPECT_EQ(1u, flag_entries.size()); 290} 291 292TEST_F(GpuControlListTest, NeedsMoreInfoForExceptions) { 293 const std::string json = LONG_STRING_CONST( 294 { 295 "name": "gpu control list", 296 "version": "0.1", 297 "entries": [ 298 { 299 "id": 1, 300 "os": { 301 "type": "linux" 302 }, 303 "vendor_id": "0x8086", 304 "exceptions": [ 305 { 306 "gl_renderer": { 307 "op": "contains", 308 "value": "mesa" 309 } 310 } 311 ], 312 "features": [ 313 "test_feature_0" 314 ] 315 } 316 ] 317 } 318 ); 319 GPUInfo gpu_info; 320 gpu_info.gpu.vendor_id = kIntelVendorId; 321 322 scoped_ptr<GpuControlList> control_list(Create()); 323 EXPECT_TRUE(control_list->LoadList(json, GpuControlList::kAllOs)); 324 325 // The case this entry does not apply. 326 std::set<int> features = control_list->MakeDecision( 327 GpuControlList::kOsMacosx, kOsVersion, gpu_info); 328 EXPECT_EMPTY_SET(features); 329 EXPECT_FALSE(control_list->needs_more_info()); 330 331 // The case this entry might apply, but need more info. 332 features = control_list->MakeDecision( 333 GpuControlList::kOsLinux, kOsVersion, gpu_info); 334 EXPECT_EMPTY_SET(features); 335 EXPECT_TRUE(control_list->needs_more_info()); 336 337 // The case we have full info, and the exception applies (so the entry 338 // does not apply). 339 gpu_info.gl_renderer = "mesa"; 340 features = control_list->MakeDecision( 341 GpuControlList::kOsLinux, kOsVersion, gpu_info); 342 EXPECT_EMPTY_SET(features); 343 EXPECT_FALSE(control_list->needs_more_info()); 344 345 // The case we have full info, and this entry applies. 346 gpu_info.gl_renderer = "my renderer"; 347 features = control_list->MakeDecision(GpuControlList::kOsLinux, kOsVersion, 348 gpu_info); 349 EXPECT_SINGLE_FEATURE(features, TEST_FEATURE_0); 350 EXPECT_FALSE(control_list->needs_more_info()); 351} 352 353TEST_F(GpuControlListTest, IgnorableEntries) { 354 // If an entry will not change the control_list decisions, then it should not 355 // trigger the needs_more_info flag. 356 const std::string json = LONG_STRING_CONST( 357 { 358 "name": "gpu control list", 359 "version": "0.1", 360 "entries": [ 361 { 362 "id": 1, 363 "os": { 364 "type": "linux" 365 }, 366 "vendor_id": "0x8086", 367 "features": [ 368 "test_feature_0" 369 ] 370 }, 371 { 372 "id": 2, 373 "os": { 374 "type": "linux" 375 }, 376 "vendor_id": "0x8086", 377 "driver_version": { 378 "op": "<", 379 "value": "10.7" 380 }, 381 "features": [ 382 "test_feature_0" 383 ] 384 } 385 ] 386 } 387 ); 388 GPUInfo gpu_info; 389 gpu_info.gpu.vendor_id = kIntelVendorId; 390 391 scoped_ptr<GpuControlList> control_list(Create()); 392 EXPECT_TRUE(control_list->LoadList(json, GpuControlList::kAllOs)); 393 std::set<int> features = control_list->MakeDecision( 394 GpuControlList::kOsLinux, kOsVersion, gpu_info); 395 EXPECT_SINGLE_FEATURE(features, TEST_FEATURE_0); 396 EXPECT_FALSE(control_list->needs_more_info()); 397} 398 399TEST_F(GpuControlListTest, ExceptionWithoutVendorId) { 400 const std::string json = LONG_STRING_CONST( 401 { 402 "name": "gpu control list", 403 "version": "0.1", 404 "entries": [ 405 { 406 "id": 1, 407 "os": { 408 "type": "linux" 409 }, 410 "vendor_id": "0x8086", 411 "exceptions": [ 412 { 413 "device_id": ["0x2a06"], 414 "driver_version": { 415 "op": ">=", 416 "value": "8.1" 417 } 418 }, 419 { 420 "device_id": ["0x2a02"], 421 "driver_version": { 422 "op": ">=", 423 "value": "9.1" 424 } 425 } 426 ], 427 "features": [ 428 "test_feature_0" 429 ] 430 } 431 ] 432 } 433 ); 434 GPUInfo gpu_info; 435 gpu_info.gpu.vendor_id = kIntelVendorId; 436 gpu_info.gpu.device_id = 0x2a02; 437 gpu_info.driver_version = "9.1"; 438 439 scoped_ptr<GpuControlList> control_list(Create()); 440 EXPECT_TRUE(control_list->LoadList(json, GpuControlList::kAllOs)); 441 442 std::set<int> features = control_list->MakeDecision( 443 GpuControlList::kOsLinux, kOsVersion, gpu_info); 444 EXPECT_EMPTY_SET(features); 445 446 gpu_info.driver_version = "9.0"; 447 features = control_list->MakeDecision( 448 GpuControlList::kOsLinux, kOsVersion, gpu_info); 449 EXPECT_SINGLE_FEATURE(features, TEST_FEATURE_0); 450} 451 452TEST_F(GpuControlListTest, AMDSwitchable) { 453 GPUInfo gpu_info; 454 gpu_info.amd_switchable = true; 455 gpu_info.gpu.vendor_id = kAmdVendorId; 456 gpu_info.gpu.device_id = 0x6760; 457 GPUInfo::GPUDevice integrated_gpu; 458 integrated_gpu.vendor_id = kIntelVendorId; 459 integrated_gpu.device_id = 0x0116; 460 gpu_info.secondary_gpus.push_back(integrated_gpu); 461 462 { // amd_switchable_discrete entry 463 const std::string json= LONG_STRING_CONST( 464 { 465 "name": "gpu control list", 466 "version": "0.1", 467 "entries": [ 468 { 469 "id": 1, 470 "os": { 471 "type": "win" 472 }, 473 "multi_gpu_style": "amd_switchable_discrete", 474 "features": [ 475 "test_feature_0" 476 ] 477 } 478 ] 479 } 480 ); 481 482 scoped_ptr<GpuControlList> control_list(Create()); 483 EXPECT_TRUE(control_list->LoadList(json, GpuControlList::kAllOs)); 484 485 // Integrated GPU is active 486 gpu_info.gpu.active = false; 487 gpu_info.secondary_gpus[0].active = true; 488 std::set<int> features = control_list->MakeDecision( 489 GpuControlList::kOsWin, kOsVersion, gpu_info); 490 EXPECT_EMPTY_SET(features); 491 492 // Discrete GPU is active 493 gpu_info.gpu.active = true; 494 gpu_info.secondary_gpus[0].active = false; 495 features = control_list->MakeDecision( 496 GpuControlList::kOsWin, kOsVersion, gpu_info); 497 EXPECT_SINGLE_FEATURE(features, TEST_FEATURE_0); 498 } 499 500 { // amd_switchable_integrated entry 501 const std::string json= LONG_STRING_CONST( 502 { 503 "name": "gpu control list", 504 "version": "0.1", 505 "entries": [ 506 { 507 "id": 1, 508 "os": { 509 "type": "win" 510 }, 511 "multi_gpu_style": "amd_switchable_integrated", 512 "features": [ 513 "test_feature_0" 514 ] 515 } 516 ] 517 } 518 ); 519 520 scoped_ptr<GpuControlList> control_list(Create()); 521 EXPECT_TRUE(control_list->LoadList(json, GpuControlList::kAllOs)); 522 523 // Discrete GPU is active 524 gpu_info.gpu.active = true; 525 gpu_info.secondary_gpus[0].active = false; 526 std::set<int> features = control_list->MakeDecision( 527 GpuControlList::kOsWin, kOsVersion, gpu_info); 528 EXPECT_EMPTY_SET(features); 529 530 // Integrated GPU is active 531 gpu_info.gpu.active = false; 532 gpu_info.secondary_gpus[0].active = true; 533 features = control_list->MakeDecision( 534 GpuControlList::kOsWin, kOsVersion, gpu_info); 535 EXPECT_SINGLE_FEATURE(features, TEST_FEATURE_0); 536 537 // For non AMD switchable 538 gpu_info.amd_switchable = false; 539 features = control_list->MakeDecision( 540 GpuControlList::kOsWin, kOsVersion, gpu_info); 541 EXPECT_EMPTY_SET(features); 542 } 543} 544 545} // namespace gpu 546 547