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.
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_switches.h"
21 #include "content/public/test/browser_test_utils.h"
22 #include "gpu/config/gpu_feature_type.h"
23 #include "gpu/config/gpu_info.h"
24 #include "gpu/config/gpu_test_config.h"
25 #include "net/base/net_util.h"
26 #include "ui/gl/gl_implementation.h"
28 #if defined(OS_MACOSX)
29 #include "ui/gl/io_surface_support_mac.h"
33 #include "base/win/windows_version.h"
36 using content::GpuDataManager;
37 using gpu::GpuFeatureType;
38 using trace_analyzer::Query;
39 using trace_analyzer::TraceAnalyzer;
40 using trace_analyzer::TraceEventVector;
44 const char kSwapBuffersEvent[] = "SwapBuffers";
45 const char kAcceleratedCanvasCreationEvent[] = "Canvas2DLayerBridgeCreation";
46 const char kWebGLCreationEvent[] = "DrawingBufferCreation";
48 class GpuFeatureTest : public InProcessBrowserTest {
50 GpuFeatureTest() : category_patterns_("test_gpu") {}
52 virtual void SetUp() OVERRIDE {
53 // We expect to use real GL contexts for these tests.
56 InProcessBrowserTest::SetUp();
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");
65 virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE {
66 command_line->AppendSwitch(switches::kDisablePopupBlocking);
67 command_line->AppendSwitchASCII(switches::kWindowSize, "400,300");
70 void SetupBlacklist(const std::string& json_blacklist) {
71 gpu::GPUInfo gpu_info;
72 GpuDataManager::GetInstance()->InitializeForTesting(
73 json_blacklist, gpu_info);
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,
80 #if defined(OS_LINUX) && !defined(NDEBUG)
81 // Bypass tests on GPU Linux Debug bots.
82 if (gfx::GetGLImplementation() != gfx::kGLImplementationOSMesaGL)
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();
91 content::DOMMessageQueue message_queue;
93 ui_test_utils::NavigateToURLWithDisposition(
94 browser(), net::FilePathToFileURL(test_path),
95 NEW_FOREGROUND_TAB, ui_test_utils::BROWSER_TEST_NONE);
97 ui_test_utils::NavigateToURL(
98 browser(), net::FilePathToFileURL(test_path));
102 // Wait for message indicating the test has finished running.
103 ASSERT_TRUE(message_queue.WaitForMessage(&result));
105 EXPECT_STREQ(expected_reply, result.c_str());
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)
117 #if defined(OS_MACOSX)
118 // Bypass tests on Mac OSX 10.5 bots (IOSurfaceSupport is now required).
119 if (!IOSurfaceSupport::Initialize())
123 ASSERT_TRUE(tracing::BeginTracing(category_patterns_));
125 // Have to use a new tab for the blacklist to work.
126 RunTest(url, NULL, true);
128 ASSERT_TRUE(tracing::EndTracing(&trace_events_json_));
130 analyzer_.reset(TraceAnalyzer::Create(trace_events_json_));
131 analyzer_->AssociateBeginEndEvents();
132 TraceEventVector events;
138 analyzer_->FindEvents(Query::EventNameIs(event_name), &events);
141 EXPECT_GT(event_count, 0U);
143 EXPECT_EQ(event_count, 0U);
146 // Trigger a resize of the chrome window, and use tracing to wait for the
147 // given |wait_event|.
148 bool ResizeAndWait(const gfx::Rect& new_bounds,
149 const char* category_patterns,
150 const char* wait_category,
151 const char* wait_event) {
152 if (!tracing::BeginTracingWithWatch(category_patterns, wait_category,
155 browser()->window()->SetBounds(new_bounds);
156 if (!tracing::WaitForWatchEvent(base::TimeDelta()))
158 if (!tracing::EndTracing(&trace_events_json_))
160 analyzer_.reset(TraceAnalyzer::Create(trace_events_json_));
161 analyzer_->AssociateBeginEndEvents();
166 base::FilePath gpu_test_dir_;
167 scoped_ptr<TraceAnalyzer> analyzer_;
168 std::string category_patterns_;
169 std::string trace_events_json_;
172 #if defined(OS_WIN) || defined(ADDRESS_SANITIZER) || defined(USE_AURA)
173 // This test is flaky on Windows. http://crbug.com/177113
174 // Also fails under AddressSanitizer. http://crbug.com/185178
175 // It fundamentally doesn't test the right thing on Aura.
176 // http://crbug.com/280675
177 #define MAYBE_AcceleratedCompositingAllowed DISABLED_AcceleratedCompositingAllowed
179 #define MAYBE_AcceleratedCompositingAllowed AcceleratedCompositingAllowed
182 IN_PROC_BROWSER_TEST_F(GpuFeatureTest, MAYBE_AcceleratedCompositingAllowed) {
183 EXPECT_FALSE(GpuDataManager::GetInstance()->IsFeatureBlacklisted(
184 gpu::GPU_FEATURE_TYPE_ACCELERATED_COMPOSITING));
186 const base::FilePath url(FILE_PATH_LITERAL("feature_compositing.html"));
187 RunEventTest(url, kSwapBuffersEvent, true);
190 class AcceleratedCompositingBlockedTest : public GpuFeatureTest {
192 virtual void SetUpInProcessBrowserTestFixture() OVERRIDE {
193 GpuFeatureTest::SetUpInProcessBrowserTestFixture();
194 const std::string json_blacklist =
196 " \"name\": \"gpu blacklist\",\n"
197 " \"version\": \"1.0\",\n"
202 " \"accelerated_compositing\"\n"
207 SetupBlacklist(json_blacklist);
211 #if defined(USE_AURA)
212 // Compositing is always on for Aura.
213 #define MAYBE_AcceleratedCompositingBlocked DISABLED_AcceleratedCompositingBlocked
215 #define MAYBE_AcceleratedCompositingBlocked AcceleratedCompositingBlocked
218 IN_PROC_BROWSER_TEST_F(AcceleratedCompositingBlockedTest,
219 MAYBE_AcceleratedCompositingBlocked) {
220 EXPECT_TRUE(GpuDataManager::GetInstance()->IsFeatureBlacklisted(
221 gpu::GPU_FEATURE_TYPE_ACCELERATED_COMPOSITING));
223 const base::FilePath url(FILE_PATH_LITERAL("feature_compositing.html"));
224 RunEventTest(url, kSwapBuffersEvent, false);
227 class AcceleratedCompositingTest : public GpuFeatureTest {
229 virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE {
230 GpuFeatureTest::SetUpCommandLine(command_line);
231 command_line->AppendSwitch(switches::kDisableAcceleratedCompositing);
235 #if defined(USE_AURA)
236 // Compositing is always on for Aura.
237 #define MAYBE_AcceleratedCompositingDisabled DISABLED_AcceleratedCompositingDisabled
239 #define MAYBE_AcceleratedCompositingDisabled AcceleratedCompositingDisabled
242 IN_PROC_BROWSER_TEST_F(AcceleratedCompositingTest,
243 MAYBE_AcceleratedCompositingDisabled) {
244 // Compositing is always on for Windows Aura.
245 const base::FilePath url(FILE_PATH_LITERAL("feature_compositing.html"));
246 RunEventTest(url, kSwapBuffersEvent, false);
249 // Times out: http://crbug.com/166060
250 IN_PROC_BROWSER_TEST_F(GpuFeatureTest, DISABLED_WebGLAllowed) {
251 EXPECT_FALSE(GpuDataManager::GetInstance()->IsFeatureBlacklisted(
252 gpu::GPU_FEATURE_TYPE_WEBGL));
254 const base::FilePath url(FILE_PATH_LITERAL("feature_webgl.html"));
255 RunEventTest(url, kWebGLCreationEvent, true);
258 IN_PROC_BROWSER_TEST_F(GpuFeatureTest, WebGLBlocked) {
259 const std::string json_blacklist =
261 " \"name\": \"gpu blacklist\",\n"
262 " \"version\": \"1.0\",\n"
272 SetupBlacklist(json_blacklist);
273 EXPECT_TRUE(GpuDataManager::GetInstance()->IsFeatureBlacklisted(
274 gpu::GPU_FEATURE_TYPE_WEBGL));
276 const base::FilePath url(FILE_PATH_LITERAL("feature_webgl.html"));
277 RunEventTest(url, kWebGLCreationEvent, false);
280 class WebGLTest : public GpuFeatureTest {
282 virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE {
283 GpuFeatureTest::SetUpCommandLine(command_line);
284 #if !defined(OS_ANDROID)
285 // On Android, WebGL is disabled by default
286 command_line->AppendSwitch(switches::kDisableExperimentalWebGL);
291 IN_PROC_BROWSER_TEST_F(WebGLTest, WebGLDisabled) {
292 const base::FilePath url(FILE_PATH_LITERAL("feature_webgl.html"));
293 RunEventTest(url, kWebGLCreationEvent, false);
296 IN_PROC_BROWSER_TEST_F(GpuFeatureTest, MultisamplingAllowed) {
297 EXPECT_FALSE(GpuDataManager::GetInstance()->IsFeatureBlacklisted(
298 gpu::GPU_FEATURE_TYPE_MULTISAMPLING));
300 // Multisampling is not supported if running on top of osmesa.
301 if (gfx::GetGLImplementation() != gfx::kGLImplementationOSMesaGL)
304 // Linux Intel uses mesa driver, where multisampling is not supported.
305 // Multisampling is also not supported on virtualized mac os.
306 std::vector<std::string> configs;
307 configs.push_back("LINUX INTEL");
308 configs.push_back("MAC VMWARE");
309 if (gpu::GPUTestBotConfig::CurrentConfigMatches(configs))
312 const base::FilePath url(FILE_PATH_LITERAL("feature_multisampling.html"));
313 RunTest(url, "\"TRUE\"", true);
316 IN_PROC_BROWSER_TEST_F(GpuFeatureTest, MultisamplingBlocked) {
317 // Multisampling fails on virtualized mac os.
318 if (gpu::GPUTestBotConfig::CurrentConfigMatches("MAC VMWARE"))
321 const std::string json_blacklist =
323 " \"name\": \"gpu blacklist\",\n"
324 " \"version\": \"1.0\",\n"
329 " \"multisampling\"\n"
334 SetupBlacklist(json_blacklist);
335 EXPECT_TRUE(GpuDataManager::GetInstance()->IsFeatureBlacklisted(
336 gpu::GPU_FEATURE_TYPE_MULTISAMPLING));
338 const base::FilePath url(FILE_PATH_LITERAL("feature_multisampling.html"));
339 RunTest(url, "\"FALSE\"", true);
342 class WebGLMultisamplingTest : public GpuFeatureTest {
344 virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE {
345 GpuFeatureTest::SetUpCommandLine(command_line);
346 command_line->AppendSwitch(switches::kDisableGLMultisampling);
350 IN_PROC_BROWSER_TEST_F(WebGLMultisamplingTest, MultisamplingDisabled) {
351 // Multisampling fails on virtualized mac os.
352 if (gpu::GPUTestBotConfig::CurrentConfigMatches("MAC VMWARE"))
355 const base::FilePath url(FILE_PATH_LITERAL("feature_multisampling.html"));
356 RunTest(url, "\"FALSE\"", true);
359 IN_PROC_BROWSER_TEST_F(GpuFeatureTest, Canvas2DAllowed) {
360 // Accelerated canvas 2D is not supported on XP.
361 if (gpu::GPUTestBotConfig::CurrentConfigMatches("XP"))
366 BLACKLISTED, // Disabled via the blacklist.
367 DISABLED, // Not disabled via the blacklist, but expected to be disabled
369 } expected_state = ENABLED;
370 #if defined(OS_LINUX) && !defined(OS_CHROMEOS)
371 // Blacklist rule #24 disables accelerated_2d_canvas on Linux.
372 expected_state = BLACKLISTED;
373 #elif defined(OS_WIN)
374 // Blacklist rule #67 disables accelerated_2d_canvas on XP.
375 if (base::win::GetVersion() < base::win::VERSION_VISTA)
376 expected_state = BLACKLISTED;
379 #if defined(USE_AURA)
380 // Canvas 2D is always disabled in software compositing mode, make sure it is
381 // marked as such if it wasn't blacklisted already.
382 if (expected_state == ENABLED &&
383 !content::GpuDataManager::GetInstance()->CanUseGpuBrowserCompositor()) {
384 expected_state = DISABLED;
388 EXPECT_EQ(expected_state == BLACKLISTED,
389 GpuDataManager::GetInstance()->IsFeatureBlacklisted(
390 gpu::GPU_FEATURE_TYPE_ACCELERATED_2D_CANVAS));
392 const base::FilePath url(FILE_PATH_LITERAL("feature_canvas2d.html"));
393 RunEventTest(url, kAcceleratedCanvasCreationEvent, expected_state == ENABLED);
396 IN_PROC_BROWSER_TEST_F(GpuFeatureTest, Canvas2DBlocked) {
397 const std::string json_blacklist =
399 " \"name\": \"gpu blacklist\",\n"
400 " \"version\": \"1.0\",\n"
405 " \"accelerated_2d_canvas\"\n"
410 SetupBlacklist(json_blacklist);
411 EXPECT_TRUE(GpuDataManager::GetInstance()->IsFeatureBlacklisted(
412 gpu::GPU_FEATURE_TYPE_ACCELERATED_2D_CANVAS));
414 const base::FilePath url(FILE_PATH_LITERAL("feature_canvas2d.html"));
415 RunEventTest(url, kAcceleratedCanvasCreationEvent, false);
418 class Canvas2DDisabledTest : public GpuFeatureTest {
420 virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE {
421 GpuFeatureTest::SetUpCommandLine(command_line);
422 command_line->AppendSwitch(switches::kDisableAccelerated2dCanvas);
426 IN_PROC_BROWSER_TEST_F(Canvas2DDisabledTest, Canvas2DDisabled) {
427 const base::FilePath url(FILE_PATH_LITERAL("feature_canvas2d.html"));
428 RunEventTest(url, kAcceleratedCanvasCreationEvent, false);
431 IN_PROC_BROWSER_TEST_F(GpuFeatureTest,
432 CanOpenPopupAndRenderWithWebGLCanvas) {
433 const base::FilePath url(FILE_PATH_LITERAL("webgl_popup.html"));
434 RunTest(url, "\"SUCCESS\"", false);
438 IN_PROC_BROWSER_TEST_F(GpuFeatureTest,
439 DISABLED_CanOpenPopupAndRenderWith2DCanvas) {
440 const base::FilePath url(FILE_PATH_LITERAL("canvas_popup.html"));
441 RunTest(url, "\"SUCCESS\"", false);
444 class ThreadedCompositorTest : public GpuFeatureTest {
446 virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE {
447 GpuFeatureTest::SetUpCommandLine(command_line);
448 command_line->AppendSwitch(switches::kEnableThreadedCompositing);
452 // http://crbug.com/157985
453 IN_PROC_BROWSER_TEST_F(ThreadedCompositorTest, DISABLED_ThreadedCompositor) {
454 const base::FilePath url(FILE_PATH_LITERAL("feature_compositing.html"));
455 RunEventTest(url, kSwapBuffersEvent, true);
459 #if defined(OS_WIN) || defined(OS_CHROMEOS) || defined(OS_MACOSX)
460 // http://crbug.com/162343: flaky on Windows and Mac, failing on ChromiumOS.
461 #define MAYBE_RafNoDamage DISABLED_RafNoDamage
463 #define MAYBE_RafNoDamage RafNoDamage
465 IN_PROC_BROWSER_TEST_F(GpuFeatureTest, MAYBE_RafNoDamage) {
466 category_patterns_ = "-test_*";
467 const base::FilePath url(FILE_PATH_LITERAL("feature_raf_no_damage.html"));
470 if (!analyzer_.get())
473 // Search for matching name on begin event or async_begin event (any begin).
475 (Query::EventPhaseIs(TRACE_EVENT_PHASE_BEGIN) ||
476 Query::EventPhaseIs(TRACE_EVENT_PHASE_ASYNC_BEGIN)) &&
477 Query::EventNameIs("___RafWithNoDamage___");
478 TraceEventVector events;
479 size_t num_events = analyzer_->FindEvents(query_raf, &events);
481 trace_analyzer::RateStats stats;
482 trace_analyzer::RateStatsOptions stats_options;
483 stats_options.trim_min = stats_options.trim_max = num_events / 10;
484 EXPECT_TRUE(trace_analyzer::GetRateStats(events, &stats, &stats_options));
486 LOG(INFO) << "Number of RAFs: " << num_events <<
487 " Mean: " << stats.mean_us <<
488 " Min: " << stats.min_us <<
489 " Max: " << stats.max_us <<
490 " StdDev: " << stats.standard_deviation_us;
492 // Expect that the average time between RAFs is more than 15ms. That will
493 // indicate that the renderer is not simply spinning on RAF.
494 EXPECT_GT(stats.mean_us, 15000.0);
496 // Print out the trace events upon error to debug failures.
497 if (stats.mean_us <= 15000.0) {
498 fprintf(stderr, "\n\nTRACE JSON:\n\n%s\n\n", trace_events_json_.c_str());
502 #if defined(OS_MACOSX)
503 IN_PROC_BROWSER_TEST_F(GpuFeatureTest, IOSurfaceReuse) {
504 if (!IOSurfaceSupport::Initialize())
507 const base::FilePath url(
508 FILE_PATH_LITERAL("feature_compositing_static.html"));
509 base::FilePath test_path = gpu_test_dir_.Append(url);
510 ASSERT_TRUE(base::PathExists(test_path))
511 << "Missing test file: " << test_path.value();
513 ui_test_utils::NavigateToURL(browser(), net::FilePathToFileURL(test_path));
515 gfx::Rect bounds = browser()->window()->GetBounds();
516 gfx::Rect new_bounds = bounds;
518 const char* create_event = "IOSurfaceImageTransportSurface::CreateIOSurface";
519 const char* resize_event = "IOSurfaceImageTransportSurface::OnResize";
520 const char* draw_event = "CompositingIOSurfaceMac::DrawIOSurface";
521 Query find_creates = Query::MatchBeginName(create_event);
522 Query find_resizes = Query::MatchBeginName(resize_event) &&
523 Query::EventHasNumberArg("old_width") &&
524 Query::EventHasNumberArg("new_width");
525 Query find_draws = Query::MatchBeginName(draw_event) &&
526 Query::EventHasNumberArg("scale");
528 const int roundup = 64;
529 // A few resize values assuming a roundup of 64 pixels. The test will resize
530 // by these values one at a time and verify that CreateIOSurface only happens
531 // when the rounded width changes.
532 int offsets[] = { 1, roundup - 1, roundup, roundup + 1, 2*roundup};
533 int num_offsets = static_cast<int>(arraysize(offsets));
534 int w_start = bounds.width();
536 for (int offset_i = 0; offset_i < num_offsets; ++offset_i) {
537 new_bounds.set_width(w_start + offsets[offset_i]);
538 ASSERT_TRUE(ResizeAndWait(new_bounds, "gpu", "gpu", resize_event));
540 TraceEventVector resize_events;
541 analyzer_->FindEvents(find_resizes, &resize_events);
542 for (size_t resize_i = 0; resize_i < resize_events.size(); ++resize_i) {
543 const trace_analyzer::TraceEvent* resize = resize_events[resize_i];
544 // Was a create allowed:
545 int old_width = resize->GetKnownArgAsInt("old_width");
546 int new_width = resize->GetKnownArgAsInt("new_width");
547 bool expect_create = (old_width/roundup != new_width/roundup ||
549 int expected_creates = expect_create ? 1 : 0;
551 // Find the create event inside this resize event (if any). This will
552 // determine if the resize triggered a reallocation of the IOSurface.
553 double begin_time = resize->timestamp;
554 double end_time = begin_time + resize->GetAbsTimeToOtherEvent();
555 Query find_this_create = find_creates &&
556 Query::EventTime() >= Query::Double(begin_time) &&
557 Query::EventTime() <= Query::Double(end_time);
558 TraceEventVector create_events;
559 int num_creates = static_cast<int>(analyzer_->FindEvents(find_this_create,
561 EXPECT_EQ(expected_creates, num_creates);
563 // For debugging failures, print out the width and height of each resize:
566 "%d (resize offset %d): IOSurface width %d -> %d; Creates %d "
567 "Expected %d", offset_i, offsets[offset_i],
568 old_width, new_width, num_creates, expected_creates);