OLD | NEW |
| (Empty) |
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 "base/command_line.h" | |
6 #include "base/file_util.h" | |
7 #include "base/memory/scoped_ptr.h" | |
8 #include "base/path_service.h" | |
9 #include "base/strings/stringprintf.h" | |
10 #include "base/test/trace_event_analyzer.h" | |
11 #include "base/version.h" | |
12 #include "chrome/browser/ui/browser.h" | |
13 #include "chrome/browser/ui/browser_window.h" | |
14 #include "chrome/common/chrome_paths.h" | |
15 #include "chrome/common/chrome_switches.h" | |
16 #include "chrome/test/base/in_process_browser_test.h" | |
17 #include "chrome/test/base/tracing.h" | |
18 #include "chrome/test/base/ui_test_utils.h" | |
19 #include "content/public/browser/gpu_data_manager.h" | |
20 #include "content/public/common/content_client.h" | |
21 #include "content/public/common/content_switches.h" | |
22 #include "content/public/test/browser_test_utils.h" | |
23 #include "gpu/config/gpu_feature_type.h" | |
24 #include "gpu/config/gpu_info.h" | |
25 #include "gpu/config/gpu_test_config.h" | |
26 #include "net/base/filename_util.h" | |
27 #include "ui/gl/gl_implementation.h" | |
28 | |
29 #if defined(OS_WIN) | |
30 #include "base/win/windows_version.h" | |
31 #endif | |
32 | |
33 using content::GpuDataManager; | |
34 using gpu::GpuFeatureType; | |
35 using trace_analyzer::Query; | |
36 using trace_analyzer::TraceAnalyzer; | |
37 using trace_analyzer::TraceEventVector; | |
38 | |
39 namespace { | |
40 | |
41 const char kAcceleratedCanvasCreationEvent[] = "Canvas2DLayerBridgeCreation"; | |
42 const char kWebGLCreationEvent[] = "DrawingBufferCreation"; | |
43 | |
44 class FakeContentClient : public content::ContentClient { | |
45 }; | |
46 | |
47 class GpuFeatureTest : public InProcessBrowserTest { | |
48 public: | |
49 GpuFeatureTest() : category_patterns_("test_gpu") {} | |
50 | |
51 virtual void SetUp() OVERRIDE { | |
52 content::SetContentClient(&content_client_); | |
53 } | |
54 | |
55 virtual void TearDown() OVERRIDE { | |
56 content::SetContentClient(NULL); | |
57 } | |
58 | |
59 virtual void SetUpInProcessBrowserTestFixture() OVERRIDE { | |
60 base::FilePath test_dir; | |
61 ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &test_dir)); | |
62 gpu_test_dir_ = test_dir.AppendASCII("gpu"); | |
63 } | |
64 | |
65 virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE { | |
66 command_line->AppendSwitch(switches::kDisablePopupBlocking); | |
67 command_line->AppendSwitchASCII(switches::kWindowSize, "400,300"); | |
68 } | |
69 | |
70 void SetupBlacklist(const std::string& json_blacklist) { | |
71 gpu::GPUInfo gpu_info; | |
72 GpuDataManager::GetInstance()->InitializeForTesting( | |
73 json_blacklist, gpu_info); | |
74 } | |
75 | |
76 // If expected_reply is NULL, we don't check the reply content. | |
77 void RunTest(const base::FilePath& url, | |
78 const char* expected_reply, | |
79 bool new_tab) { | |
80 #if defined(OS_LINUX) && !defined(NDEBUG) | |
81 // Bypass tests on GPU Linux Debug bots. | |
82 if (gfx::GetGLImplementation() != gfx::kGLImplementationOSMesaGL) | |
83 return; | |
84 #endif | |
85 | |
86 base::FilePath test_path; | |
87 test_path = gpu_test_dir_.Append(url); | |
88 ASSERT_TRUE(base::PathExists(test_path)) | |
89 << "Missing test file: " << test_path.value(); | |
90 | |
91 content::DOMMessageQueue message_queue; | |
92 if (new_tab) { | |
93 ui_test_utils::NavigateToURLWithDisposition( | |
94 browser(), net::FilePathToFileURL(test_path), | |
95 NEW_FOREGROUND_TAB, ui_test_utils::BROWSER_TEST_NONE); | |
96 } else { | |
97 ui_test_utils::NavigateToURL( | |
98 browser(), net::FilePathToFileURL(test_path)); | |
99 } | |
100 | |
101 std::string result; | |
102 // Wait for message indicating the test has finished running. | |
103 ASSERT_TRUE(message_queue.WaitForMessage(&result)); | |
104 if (expected_reply) | |
105 EXPECT_STREQ(expected_reply, result.c_str()); | |
106 } | |
107 | |
108 // Open the URL and check the trace stream for the given event. | |
109 void RunEventTest(const base::FilePath& url, | |
110 const char* event_name = NULL, | |
111 bool event_expected = false) { | |
112 #if defined(OS_LINUX) && !defined(NDEBUG) | |
113 // Bypass tests on GPU Linux Debug bots. | |
114 if (gfx::GetGLImplementation() != gfx::kGLImplementationOSMesaGL) | |
115 return; | |
116 #endif | |
117 | |
118 ASSERT_TRUE(tracing::BeginTracing(category_patterns_)); | |
119 | |
120 // Have to use a new tab for the blacklist to work. | |
121 RunTest(url, NULL, true); | |
122 | |
123 ASSERT_TRUE(tracing::EndTracing(&trace_events_json_)); | |
124 | |
125 analyzer_.reset(TraceAnalyzer::Create(trace_events_json_)); | |
126 analyzer_->AssociateBeginEndEvents(); | |
127 TraceEventVector events; | |
128 | |
129 if (!event_name) | |
130 return; | |
131 | |
132 size_t event_count = | |
133 analyzer_->FindEvents(Query::EventNameIs(event_name), &events); | |
134 | |
135 if (event_expected) | |
136 EXPECT_GT(event_count, 0U); | |
137 else | |
138 EXPECT_EQ(event_count, 0U); | |
139 } | |
140 | |
141 // Trigger a resize of the chrome window, and use tracing to wait for the | |
142 // given |wait_event|. | |
143 bool ResizeAndWait(const gfx::Rect& new_bounds, | |
144 const char* category_patterns, | |
145 const char* wait_category, | |
146 const char* wait_event) { | |
147 if (!tracing::BeginTracingWithWatch(category_patterns, wait_category, | |
148 wait_event, 1)) | |
149 return false; | |
150 browser()->window()->SetBounds(new_bounds); | |
151 if (!tracing::WaitForWatchEvent(base::TimeDelta())) | |
152 return false; | |
153 if (!tracing::EndTracing(&trace_events_json_)) | |
154 return false; | |
155 analyzer_.reset(TraceAnalyzer::Create(trace_events_json_)); | |
156 analyzer_->AssociateBeginEndEvents(); | |
157 return true; | |
158 } | |
159 | |
160 protected: | |
161 base::FilePath gpu_test_dir_; | |
162 scoped_ptr<TraceAnalyzer> analyzer_; | |
163 std::string category_patterns_; | |
164 std::string trace_events_json_; | |
165 FakeContentClient content_client_; | |
166 }; | |
167 | |
168 class GpuFeaturePixelTest : public GpuFeatureTest { | |
169 protected: | |
170 virtual void SetUp() OVERRIDE { | |
171 EnablePixelOutput(); | |
172 GpuFeatureTest::SetUp(); | |
173 } | |
174 }; | |
175 | |
176 class GpuCompositingBlockedTest : public GpuFeatureTest { | |
177 public: | |
178 virtual void SetUpInProcessBrowserTestFixture() OVERRIDE { | |
179 GpuFeatureTest::SetUpInProcessBrowserTestFixture(); | |
180 const std::string json_blacklist = | |
181 "{\n" | |
182 " \"name\": \"gpu blacklist\",\n" | |
183 " \"version\": \"1.0\",\n" | |
184 " \"entries\": [\n" | |
185 " {\n" | |
186 " \"id\": 1,\n" | |
187 " \"features\": [\n" | |
188 " \"gpu_compositing\"\n" | |
189 " ]\n" | |
190 " }\n" | |
191 " ]\n" | |
192 "}"; | |
193 SetupBlacklist(json_blacklist); | |
194 } | |
195 }; | |
196 | |
197 IN_PROC_BROWSER_TEST_F(GpuCompositingBlockedTest, GpuCompositingBlocked) { | |
198 EXPECT_TRUE(GpuDataManager::GetInstance()->IsFeatureBlacklisted( | |
199 gpu::GPU_FEATURE_TYPE_GPU_COMPOSITING)); | |
200 } | |
201 | |
202 IN_PROC_BROWSER_TEST_F(GpuFeatureTest, WebGLAllowed) { | |
203 EXPECT_FALSE(GpuDataManager::GetInstance()->IsFeatureBlacklisted( | |
204 gpu::GPU_FEATURE_TYPE_WEBGL)); | |
205 | |
206 // The below times out: http://crbug.com/166060 | |
207 #if 0 | |
208 const base::FilePath url(FILE_PATH_LITERAL("feature_webgl.html")); | |
209 RunEventTest(url, kWebGLCreationEvent, true); | |
210 #endif | |
211 } | |
212 | |
213 IN_PROC_BROWSER_TEST_F(GpuFeatureTest, WebGLBlocked) { | |
214 const std::string json_blacklist = | |
215 "{\n" | |
216 " \"name\": \"gpu blacklist\",\n" | |
217 " \"version\": \"1.0\",\n" | |
218 " \"entries\": [\n" | |
219 " {\n" | |
220 " \"id\": 1,\n" | |
221 " \"features\": [\n" | |
222 " \"webgl\"\n" | |
223 " ]\n" | |
224 " }\n" | |
225 " ]\n" | |
226 "}"; | |
227 SetupBlacklist(json_blacklist); | |
228 EXPECT_TRUE(GpuDataManager::GetInstance()->IsFeatureBlacklisted( | |
229 gpu::GPU_FEATURE_TYPE_WEBGL)); | |
230 | |
231 const base::FilePath url(FILE_PATH_LITERAL("feature_webgl.html")); | |
232 RunEventTest(url, kWebGLCreationEvent, false); | |
233 } | |
234 | |
235 class WebGLTest : public GpuFeatureTest { | |
236 public: | |
237 virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE { | |
238 GpuFeatureTest::SetUpCommandLine(command_line); | |
239 #if !defined(OS_ANDROID) | |
240 // On Android, WebGL is disabled by default | |
241 command_line->AppendSwitch(switches::kDisableExperimentalWebGL); | |
242 #endif | |
243 } | |
244 }; | |
245 | |
246 IN_PROC_BROWSER_TEST_F(WebGLTest, WebGLDisabled) { | |
247 const base::FilePath url(FILE_PATH_LITERAL("feature_webgl.html")); | |
248 RunEventTest(url, kWebGLCreationEvent, false); | |
249 } | |
250 | |
251 // This test is oblivious to the fact that multisample could be blacklisted on | |
252 // some configurations. Previously disabled on GOOGLE_CHROME_BUILD and | |
253 // on OS_MACOSX: http://crbug.com/314745 | |
254 IN_PROC_BROWSER_TEST_F(GpuFeatureTest, DISABLED_MultisamplingAllowed) { | |
255 if (gpu::GPUTestBotConfig::GpuBlacklistedOnBot()) | |
256 return; | |
257 // Multisampling is not supported if running on top of osmesa. | |
258 if (gfx::GetGLImplementation() == gfx::kGLImplementationOSMesaGL) | |
259 return; | |
260 // Linux Intel uses mesa driver, where multisampling is not supported. | |
261 // Multisampling is also not supported on virtualized mac os. | |
262 std::vector<std::string> configs; | |
263 configs.push_back("LINUX INTEL"); | |
264 configs.push_back("MAC VMWARE"); | |
265 if (gpu::GPUTestBotConfig::CurrentConfigMatches(configs)) | |
266 return; | |
267 | |
268 const base::FilePath url(FILE_PATH_LITERAL("feature_multisampling.html")); | |
269 RunTest(url, "\"TRUE\"", true); | |
270 } | |
271 | |
272 class WebGLMultisamplingTest : public GpuFeatureTest { | |
273 public: | |
274 virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE { | |
275 GpuFeatureTest::SetUpCommandLine(command_line); | |
276 command_line->AppendSwitch("disable_multisampling"); | |
277 } | |
278 }; | |
279 | |
280 IN_PROC_BROWSER_TEST_F(WebGLMultisamplingTest, MultisamplingDisabled) { | |
281 // Multisampling fails on virtualized mac os. | |
282 if (gpu::GPUTestBotConfig::CurrentConfigMatches("MAC VMWARE")) | |
283 return; | |
284 | |
285 const base::FilePath url(FILE_PATH_LITERAL("feature_multisampling.html")); | |
286 RunTest(url, "\"FALSE\"", true); | |
287 } | |
288 | |
289 IN_PROC_BROWSER_TEST_F(GpuFeatureTest, Canvas2DAllowed) { | |
290 // Accelerated canvas 2D is not supported on XP. | |
291 if (gpu::GPUTestBotConfig::CurrentConfigMatches("XP")) | |
292 return; | |
293 | |
294 enum Canvas2DState { | |
295 ENABLED, | |
296 BLACKLISTED, // Disabled via the blacklist. | |
297 DISABLED, // Not disabled via the blacklist, but expected to be disabled | |
298 // by configuration. | |
299 } expected_state = ENABLED; | |
300 #if defined(OS_LINUX) && !defined(OS_CHROMEOS) | |
301 // Blacklist rule #24 disables accelerated_2d_canvas on Linux. | |
302 expected_state = BLACKLISTED; | |
303 #elif defined(OS_WIN) | |
304 // Blacklist rule #67 disables accelerated_2d_canvas on XP. | |
305 if (base::win::GetVersion() < base::win::VERSION_VISTA) | |
306 expected_state = BLACKLISTED; | |
307 #endif | |
308 | |
309 if (gpu::GPUTestBotConfig::GpuBlacklistedOnBot()) | |
310 expected_state = BLACKLISTED; | |
311 | |
312 #if defined(USE_AURA) | |
313 // Canvas 2D is always disabled in software compositing mode, make sure it is | |
314 // marked as such if it wasn't blacklisted already. | |
315 if (expected_state == ENABLED && | |
316 !content::GpuDataManager::GetInstance()->CanUseGpuBrowserCompositor()) { | |
317 expected_state = DISABLED; | |
318 } | |
319 #endif | |
320 | |
321 EXPECT_EQ(expected_state == BLACKLISTED, | |
322 GpuDataManager::GetInstance()->IsFeatureBlacklisted( | |
323 gpu::GPU_FEATURE_TYPE_ACCELERATED_2D_CANVAS)); | |
324 | |
325 const base::FilePath url(FILE_PATH_LITERAL("feature_canvas2d.html")); | |
326 RunEventTest(url, kAcceleratedCanvasCreationEvent, expected_state == ENABLED); | |
327 } | |
328 | |
329 IN_PROC_BROWSER_TEST_F(GpuFeatureTest, Canvas2DBlocked) { | |
330 const std::string json_blacklist = | |
331 "{\n" | |
332 " \"name\": \"gpu blacklist\",\n" | |
333 " \"version\": \"1.0\",\n" | |
334 " \"entries\": [\n" | |
335 " {\n" | |
336 " \"id\": 1,\n" | |
337 " \"features\": [\n" | |
338 " \"accelerated_2d_canvas\"\n" | |
339 " ]\n" | |
340 " }\n" | |
341 " ]\n" | |
342 "}"; | |
343 SetupBlacklist(json_blacklist); | |
344 EXPECT_TRUE(GpuDataManager::GetInstance()->IsFeatureBlacklisted( | |
345 gpu::GPU_FEATURE_TYPE_ACCELERATED_2D_CANVAS)); | |
346 | |
347 const base::FilePath url(FILE_PATH_LITERAL("feature_canvas2d.html")); | |
348 RunEventTest(url, kAcceleratedCanvasCreationEvent, false); | |
349 } | |
350 | |
351 class Canvas2DDisabledTest : public GpuFeatureTest { | |
352 public: | |
353 virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE { | |
354 GpuFeatureTest::SetUpCommandLine(command_line); | |
355 command_line->AppendSwitch(switches::kDisableAccelerated2dCanvas); | |
356 } | |
357 }; | |
358 | |
359 IN_PROC_BROWSER_TEST_F(Canvas2DDisabledTest, Canvas2DDisabled) { | |
360 const base::FilePath url(FILE_PATH_LITERAL("feature_canvas2d.html")); | |
361 RunEventTest(url, kAcceleratedCanvasCreationEvent, false); | |
362 } | |
363 | |
364 IN_PROC_BROWSER_TEST_F(GpuFeaturePixelTest, | |
365 CanOpenPopupAndRenderWithWebGLCanvas) { | |
366 if (gpu::GPUTestBotConfig::GpuBlacklistedOnBot()) | |
367 return; | |
368 | |
369 const base::FilePath url(FILE_PATH_LITERAL("webgl_popup.html")); | |
370 RunTest(url, "\"SUCCESS\"", false); | |
371 } | |
372 | |
373 // crbug.com/176466 | |
374 IN_PROC_BROWSER_TEST_F(GpuFeatureTest, | |
375 DISABLED_CanOpenPopupAndRenderWith2DCanvas) { | |
376 const base::FilePath url(FILE_PATH_LITERAL("canvas_popup.html")); | |
377 RunTest(url, "\"SUCCESS\"", false); | |
378 } | |
379 | |
380 #if defined(OS_WIN) || defined(OS_CHROMEOS) || defined(OS_MACOSX) | |
381 // http://crbug.com/162343: flaky on Windows and Mac, failing on ChromiumOS. | |
382 #define MAYBE_RafNoDamage DISABLED_RafNoDamage | |
383 #else | |
384 #define MAYBE_RafNoDamage RafNoDamage | |
385 #endif | |
386 IN_PROC_BROWSER_TEST_F(GpuFeatureTest, MAYBE_RafNoDamage) { | |
387 category_patterns_ = "-test_*"; | |
388 const base::FilePath url(FILE_PATH_LITERAL("feature_raf_no_damage.html")); | |
389 RunEventTest(url); | |
390 | |
391 if (!analyzer_.get()) | |
392 return; | |
393 | |
394 // Search for matching name on begin event or async_begin event (any begin). | |
395 Query query_raf = | |
396 (Query::EventPhaseIs(TRACE_EVENT_PHASE_BEGIN) || | |
397 Query::EventPhaseIs(TRACE_EVENT_PHASE_ASYNC_BEGIN)) && | |
398 Query::EventNameIs("___RafWithNoDamage___"); | |
399 TraceEventVector events; | |
400 size_t num_events = analyzer_->FindEvents(query_raf, &events); | |
401 | |
402 trace_analyzer::RateStats stats; | |
403 trace_analyzer::RateStatsOptions stats_options; | |
404 stats_options.trim_min = stats_options.trim_max = num_events / 10; | |
405 EXPECT_TRUE(trace_analyzer::GetRateStats(events, &stats, &stats_options)); | |
406 | |
407 LOG(INFO) << "Number of RAFs: " << num_events << | |
408 " Mean: " << stats.mean_us << | |
409 " Min: " << stats.min_us << | |
410 " Max: " << stats.max_us << | |
411 " StdDev: " << stats.standard_deviation_us; | |
412 | |
413 // Expect that the average time between RAFs is more than 15ms. That will | |
414 // indicate that the renderer is not simply spinning on RAF. | |
415 EXPECT_GT(stats.mean_us, 15000.0); | |
416 | |
417 // Print out the trace events upon error to debug failures. | |
418 if (stats.mean_us <= 15000.0) { | |
419 fprintf(stderr, "\n\nTRACE JSON:\n\n%s\n\n", trace_events_json_.c_str()); | |
420 } | |
421 } | |
422 | |
423 #if defined(OS_MACOSX) | |
424 IN_PROC_BROWSER_TEST_F(GpuFeatureTest, IOSurfaceReuse) { | |
425 if (gpu::GPUTestBotConfig::GpuBlacklistedOnBot()) | |
426 return; | |
427 | |
428 const base::FilePath url( | |
429 FILE_PATH_LITERAL("feature_compositing_static.html")); | |
430 base::FilePath test_path = gpu_test_dir_.Append(url); | |
431 ASSERT_TRUE(base::PathExists(test_path)) | |
432 << "Missing test file: " << test_path.value(); | |
433 | |
434 ui_test_utils::NavigateToURL(browser(), net::FilePathToFileURL(test_path)); | |
435 | |
436 LOG(INFO) << "did navigate"; | |
437 gfx::Rect bounds = browser()->window()->GetBounds(); | |
438 gfx::Rect new_bounds = bounds; | |
439 | |
440 const char* create_event = "IOSurfaceImageTransportSurface::CreateIOSurface"; | |
441 const char* resize_event = "IOSurfaceImageTransportSurface::OnResize"; | |
442 const char* draw_event = "CompositingIOSurfaceMac::DrawIOSurface"; | |
443 Query find_creates = Query::MatchBeginName(create_event); | |
444 Query find_resizes = Query::MatchBeginName(resize_event) && | |
445 Query::EventHasNumberArg("old_width") && | |
446 Query::EventHasNumberArg("new_width"); | |
447 Query find_draws = Query::MatchBeginName(draw_event) && | |
448 Query::EventHasNumberArg("scale"); | |
449 | |
450 const int roundup = 64; | |
451 // A few resize values assuming a roundup of 64 pixels. The test will resize | |
452 // by these values one at a time and verify that CreateIOSurface only happens | |
453 // when the rounded width changes. | |
454 int offsets[] = { 1, roundup - 1, roundup, roundup + 1, 2*roundup}; | |
455 int num_offsets = static_cast<int>(arraysize(offsets)); | |
456 int w_start = bounds.width(); | |
457 | |
458 for (int offset_i = 0; offset_i < num_offsets; ++offset_i) { | |
459 new_bounds.set_width(w_start + offsets[offset_i]); | |
460 LOG(INFO) << "before wait"; | |
461 ASSERT_TRUE(ResizeAndWait(new_bounds, "gpu", "gpu", resize_event)); | |
462 LOG(INFO) << "after wait"; | |
463 | |
464 TraceEventVector resize_events; | |
465 analyzer_->FindEvents(find_resizes, &resize_events); | |
466 LOG(INFO) << "num rezize events = " << resize_events.size(); | |
467 for (size_t resize_i = 0; resize_i < resize_events.size(); ++resize_i) { | |
468 const trace_analyzer::TraceEvent* resize = resize_events[resize_i]; | |
469 // Was a create allowed: | |
470 int old_width = resize->GetKnownArgAsInt("old_width"); | |
471 int new_width = resize->GetKnownArgAsInt("new_width"); | |
472 bool expect_create = (old_width/roundup != new_width/roundup || | |
473 old_width == 0); | |
474 int expected_creates = expect_create ? 1 : 0; | |
475 | |
476 // Find the create event inside this resize event (if any). This will | |
477 // determine if the resize triggered a reallocation of the IOSurface. | |
478 double begin_time = resize->timestamp; | |
479 double end_time = begin_time + resize->GetAbsTimeToOtherEvent(); | |
480 Query find_this_create = find_creates && | |
481 Query::EventTime() >= Query::Double(begin_time) && | |
482 Query::EventTime() <= Query::Double(end_time); | |
483 TraceEventVector create_events; | |
484 int num_creates = static_cast<int>(analyzer_->FindEvents(find_this_create, | |
485 &create_events)); | |
486 EXPECT_EQ(expected_creates, num_creates); | |
487 | |
488 // For debugging failures, print out the width and height of each resize: | |
489 LOG(INFO) << | |
490 base::StringPrintf( | |
491 "%d (resize offset %d): IOSurface width %d -> %d; Creates %d " | |
492 "Expected %d", offset_i, offsets[offset_i], | |
493 old_width, new_width, num_creates, expected_creates); | |
494 } | |
495 } | |
496 LOG(INFO) << "finished test"; | |
497 } | |
498 #endif | |
499 | |
500 } // namespace | |
OLD | NEW |