Home | History | Annotate | Download | only in gpu
      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
    501