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 12 const char kOsVersion[] = "10.6.4"; 13 const uint32 kIntelVendorId = 0x8086; 14 const uint32 kIntelDeviceId = 0x0166; // 3rd Gen Core Graphics 15 const uint32 kNvidiaVendorId = 0x10de; 16 const uint32 kNvidiaDeviceId = 0x0fd5; // GeForce GT 650M 17 18 #define LONG_STRING_CONST(...) #__VA_ARGS__ 19 20 #define EXPECT_EMPTY_SET(feature_set) EXPECT_EQ(0u, feature_set.size()) 21 #define EXPECT_SINGLE_FEATURE(feature_set, feature) \ 22 EXPECT_TRUE(feature_set.size() == 1 && feature_set.count(feature) == 1) 23 24 namespace gpu { 25 26 enum TestFeatureType { 27 TEST_FEATURE_0 = 1, 28 TEST_FEATURE_1 = 1 << 2, 29 TEST_FEATURE_2 = 1 << 3, 30 }; 31 32 class GpuControlListTest : public testing::Test { 33 public: 34 GpuControlListTest() { } 35 36 virtual ~GpuControlListTest() { } 37 38 const GPUInfo& gpu_info() const { 39 return gpu_info_; 40 } 41 42 GpuControlList* Create() { 43 GpuControlList* rt = new GpuControlList(); 44 rt->AddSupportedFeature("test_feature_0", TEST_FEATURE_0); 45 rt->AddSupportedFeature("test_feature_1", TEST_FEATURE_1); 46 rt->AddSupportedFeature("test_feature_2", TEST_FEATURE_2); 47 return rt; 48 } 49 50 protected: 51 virtual void SetUp() { 52 gpu_info_.gpu.vendor_id = kNvidiaVendorId; 53 gpu_info_.gpu.device_id = 0x0640; 54 gpu_info_.driver_vendor = "NVIDIA"; 55 gpu_info_.driver_version = "1.6.18"; 56 gpu_info_.driver_date = "7-14-2009"; 57 gpu_info_.machine_model = "MacBookPro 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 72 TEST_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 80 TEST_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 100 TEST_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 "number": "10.6.4" 114 } 115 }, 116 "vendor_id": "0x10de", 117 "device_id": ["0x0640"], 118 "driver_version": { 119 "op": "=", 120 "number": "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 150 TEST_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 197 TEST_F(GpuControlListTest, ChromeVersionEntry) { 198 const std::string browser_version_json = LONG_STRING_CONST( 199 { 200 "name": "gpu control list", 201 "version": "0.1", 202 "entries": [ 203 { 204 "id": 1, 205 "browser_version": { 206 "op": ">=", 207 "number": "10" 208 }, 209 "features": [ 210 "test_feature_0" 211 ] 212 } 213 ] 214 } 215 ); 216 scoped_ptr<GpuControlList> control_list9(Create()); 217 EXPECT_TRUE(control_list9->LoadList( 218 "9.0", browser_version_json, GpuControlList::kAllOs)); 219 std::set<int> features = control_list9->MakeDecision( 220 GpuControlList::kOsWin, kOsVersion, gpu_info()); 221 EXPECT_EMPTY_SET(features); 222 223 scoped_ptr<GpuControlList> control_list10(Create()); 224 EXPECT_TRUE(control_list10->LoadList( 225 "10.0", browser_version_json, GpuControlList::kAllOs)); 226 features = control_list10->MakeDecision( 227 GpuControlList::kOsWin, kOsVersion, gpu_info()); 228 EXPECT_SINGLE_FEATURE(features, TEST_FEATURE_0); 229 } 230 231 TEST_F(GpuControlListTest, UnknownField) { 232 const std::string unknown_field_json = LONG_STRING_CONST( 233 { 234 "name": "gpu control list", 235 "version": "0.1", 236 "entries": [ 237 { 238 "id": 1, 239 "unknown_field": 0, 240 "features": [ 241 "test_feature_1" 242 ] 243 }, 244 { 245 "id": 2, 246 "features": [ 247 "test_feature_0" 248 ] 249 } 250 ] 251 } 252 ); 253 scoped_ptr<GpuControlList> control_list(Create()); 254 255 EXPECT_TRUE(control_list->LoadList( 256 unknown_field_json, GpuControlList::kAllOs)); 257 EXPECT_EQ(1u, control_list->num_entries()); 258 EXPECT_TRUE(control_list->contains_unknown_fields()); 259 std::set<int> features = control_list->MakeDecision( 260 GpuControlList::kOsWin, kOsVersion, gpu_info()); 261 EXPECT_SINGLE_FEATURE(features, TEST_FEATURE_0); 262 } 263 264 TEST_F(GpuControlListTest, UnknownExceptionField) { 265 const std::string unknown_exception_field_json = LONG_STRING_CONST( 266 { 267 "name": "gpu control list", 268 "version": "0.1", 269 "entries": [ 270 { 271 "id": 1, 272 "unknown_field": 0, 273 "features": [ 274 "test_feature_2" 275 ] 276 }, 277 { 278 "id": 2, 279 "exceptions": [ 280 { 281 "unknown_field": 0 282 } 283 ], 284 "features": [ 285 "test_feature_1" 286 ] 287 }, 288 { 289 "id": 3, 290 "features": [ 291 "test_feature_0" 292 ] 293 } 294 ] 295 } 296 ); 297 scoped_ptr<GpuControlList> control_list(Create()); 298 299 EXPECT_TRUE(control_list->LoadList( 300 unknown_exception_field_json, GpuControlList::kAllOs)); 301 EXPECT_EQ(1u, control_list->num_entries()); 302 EXPECT_TRUE(control_list->contains_unknown_fields()); 303 std::set<int> features = control_list->MakeDecision( 304 GpuControlList::kOsWin, kOsVersion, gpu_info()); 305 EXPECT_SINGLE_FEATURE(features, TEST_FEATURE_0); 306 } 307 308 TEST_F(GpuControlListTest, DisabledEntry) { 309 const std::string disabled_json = LONG_STRING_CONST( 310 { 311 "name": "gpu control list", 312 "version": "0.1", 313 "entries": [ 314 { 315 "id": 1, 316 "disabled": true, 317 "features": [ 318 "test_feature_0" 319 ] 320 } 321 ] 322 } 323 ); 324 scoped_ptr<GpuControlList> control_list(Create()); 325 EXPECT_TRUE(control_list->LoadList(disabled_json, GpuControlList::kAllOs)); 326 std::set<int> features = control_list->MakeDecision( 327 GpuControlList::kOsWin, kOsVersion, gpu_info()); 328 EXPECT_EMPTY_SET(features); 329 std::vector<uint32> flag_entries; 330 control_list->GetDecisionEntries(&flag_entries, false); 331 EXPECT_EQ(0u, flag_entries.size()); 332 control_list->GetDecisionEntries(&flag_entries, true); 333 EXPECT_EQ(1u, flag_entries.size()); 334 } 335 336 TEST_F(GpuControlListTest, NeedsMoreInfoForExceptions) { 337 const std::string json = LONG_STRING_CONST( 338 { 339 "name": "gpu control list", 340 "version": "0.1", 341 "entries": [ 342 { 343 "id": 1, 344 "os": { 345 "type": "linux" 346 }, 347 "vendor_id": "0x8086", 348 "exceptions": [ 349 { 350 "gl_renderer": { 351 "op": "contains", 352 "value": "mesa" 353 } 354 } 355 ], 356 "features": [ 357 "test_feature_0" 358 ] 359 } 360 ] 361 } 362 ); 363 GPUInfo gpu_info; 364 gpu_info.gpu.vendor_id = kIntelVendorId; 365 366 scoped_ptr<GpuControlList> control_list(Create()); 367 EXPECT_TRUE(control_list->LoadList(json, GpuControlList::kAllOs)); 368 369 // The case this entry does not apply. 370 std::set<int> features = control_list->MakeDecision( 371 GpuControlList::kOsMacosx, kOsVersion, gpu_info); 372 EXPECT_EMPTY_SET(features); 373 EXPECT_FALSE(control_list->needs_more_info()); 374 375 // The case this entry might apply, but need more info. 376 features = control_list->MakeDecision( 377 GpuControlList::kOsLinux, kOsVersion, gpu_info); 378 EXPECT_EMPTY_SET(features); 379 EXPECT_TRUE(control_list->needs_more_info()); 380 381 // The case we have full info, and the exception applies (so the entry 382 // does not apply). 383 gpu_info.gl_renderer = "mesa"; 384 features = control_list->MakeDecision( 385 GpuControlList::kOsLinux, kOsVersion, gpu_info); 386 EXPECT_EMPTY_SET(features); 387 EXPECT_FALSE(control_list->needs_more_info()); 388 389 // The case we have full info, and this entry applies. 390 gpu_info.gl_renderer = "my renderer"; 391 features = control_list->MakeDecision(GpuControlList::kOsLinux, kOsVersion, 392 gpu_info); 393 EXPECT_SINGLE_FEATURE(features, TEST_FEATURE_0); 394 EXPECT_FALSE(control_list->needs_more_info()); 395 } 396 397 TEST_F(GpuControlListTest, IgnorableEntries) { 398 // If an entry will not change the control_list decisions, then it should not 399 // trigger the needs_more_info flag. 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 "features": [ 412 "test_feature_0" 413 ] 414 }, 415 { 416 "id": 2, 417 "os": { 418 "type": "linux" 419 }, 420 "vendor_id": "0x8086", 421 "driver_version": { 422 "op": "<", 423 "number": "10.7" 424 }, 425 "features": [ 426 "test_feature_0" 427 ] 428 } 429 ] 430 } 431 ); 432 GPUInfo gpu_info; 433 gpu_info.gpu.vendor_id = kIntelVendorId; 434 435 scoped_ptr<GpuControlList> control_list(Create()); 436 EXPECT_TRUE(control_list->LoadList(json, GpuControlList::kAllOs)); 437 std::set<int> features = control_list->MakeDecision( 438 GpuControlList::kOsLinux, kOsVersion, gpu_info); 439 EXPECT_SINGLE_FEATURE(features, TEST_FEATURE_0); 440 EXPECT_FALSE(control_list->needs_more_info()); 441 } 442 443 TEST_F(GpuControlListTest, ExceptionWithoutVendorId) { 444 const std::string json = LONG_STRING_CONST( 445 { 446 "name": "gpu control list", 447 "version": "0.1", 448 "entries": [ 449 { 450 "id": 1, 451 "os": { 452 "type": "linux" 453 }, 454 "vendor_id": "0x8086", 455 "exceptions": [ 456 { 457 "device_id": ["0x2a06"], 458 "driver_version": { 459 "op": ">=", 460 "number": "8.1" 461 } 462 }, 463 { 464 "device_id": ["0x2a02"], 465 "driver_version": { 466 "op": ">=", 467 "number": "9.1" 468 } 469 } 470 ], 471 "features": [ 472 "test_feature_0" 473 ] 474 } 475 ] 476 } 477 ); 478 GPUInfo gpu_info; 479 gpu_info.gpu.vendor_id = kIntelVendorId; 480 gpu_info.gpu.device_id = 0x2a02; 481 gpu_info.driver_version = "9.1"; 482 483 scoped_ptr<GpuControlList> control_list(Create()); 484 EXPECT_TRUE(control_list->LoadList(json, GpuControlList::kAllOs)); 485 486 std::set<int> features = control_list->MakeDecision( 487 GpuControlList::kOsLinux, kOsVersion, gpu_info); 488 EXPECT_EMPTY_SET(features); 489 490 gpu_info.driver_version = "9.0"; 491 features = control_list->MakeDecision( 492 GpuControlList::kOsLinux, kOsVersion, gpu_info); 493 EXPECT_SINGLE_FEATURE(features, TEST_FEATURE_0); 494 } 495 496 } // namespace gpu 497 498