Home | History | Annotate | Download | only in output
      1 // Copyright 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 "cc/output/output_surface.h"
      6 
      7 #include "base/test/test_simple_task_runner.h"
      8 #include "cc/output/managed_memory_policy.h"
      9 #include "cc/output/output_surface_client.h"
     10 #include "cc/output/software_output_device.h"
     11 #include "cc/test/fake_output_surface.h"
     12 #include "cc/test/fake_output_surface_client.h"
     13 #include "cc/test/scheduler_test_common.h"
     14 #include "cc/test/test_context_provider.h"
     15 #include "cc/test/test_web_graphics_context_3d.h"
     16 #include "gpu/GLES2/gl2extchromium.h"
     17 #include "testing/gtest/include/gtest/gtest.h"
     18 #include "ui/gfx/frame_time.h"
     19 
     20 namespace cc {
     21 namespace {
     22 
     23 class TestOutputSurface : public OutputSurface {
     24  public:
     25   explicit TestOutputSurface(scoped_refptr<ContextProvider> context_provider)
     26       : OutputSurface(context_provider),
     27         retroactive_begin_impl_frame_deadline_enabled_(false),
     28         override_retroactive_period_(false) {}
     29 
     30   explicit TestOutputSurface(scoped_ptr<SoftwareOutputDevice> software_device)
     31       : OutputSurface(software_device.Pass()),
     32         retroactive_begin_impl_frame_deadline_enabled_(false),
     33         override_retroactive_period_(false) {}
     34 
     35   TestOutputSurface(scoped_refptr<ContextProvider> context_provider,
     36                     scoped_ptr<SoftwareOutputDevice> software_device)
     37       : OutputSurface(context_provider, software_device.Pass()),
     38         retroactive_begin_impl_frame_deadline_enabled_(false),
     39         override_retroactive_period_(false) {}
     40 
     41   bool InitializeNewContext3d(
     42       scoped_refptr<ContextProvider> new_context_provider) {
     43     return InitializeAndSetContext3d(new_context_provider,
     44                                      scoped_refptr<ContextProvider>());
     45   }
     46 
     47   using OutputSurface::ReleaseGL;
     48 
     49   void OnVSyncParametersChangedForTesting(base::TimeTicks timebase,
     50                                           base::TimeDelta interval) {
     51     OnVSyncParametersChanged(timebase, interval);
     52   }
     53 
     54   void BeginImplFrameForTesting() {
     55     OutputSurface::BeginImplFrame(BeginFrameArgs::CreateExpiredForTesting());
     56   }
     57 
     58   void DidSwapBuffersForTesting() {
     59     DidSwapBuffers();
     60   }
     61 
     62   int pending_swap_buffers() {
     63     return pending_swap_buffers_;
     64   }
     65 
     66   void OnSwapBuffersCompleteForTesting() {
     67     OnSwapBuffersComplete();
     68   }
     69 
     70   void EnableRetroactiveBeginImplFrameDeadline(
     71       bool enable,
     72       bool override_retroactive_period,
     73       base::TimeDelta period_override) {
     74     retroactive_begin_impl_frame_deadline_enabled_ = enable;
     75     override_retroactive_period_ = override_retroactive_period;
     76     retroactive_period_override_ = period_override;
     77   }
     78 
     79  protected:
     80   virtual void PostCheckForRetroactiveBeginImplFrame() OVERRIDE {
     81     // For testing purposes, we check immediately rather than posting a task.
     82     CheckForRetroactiveBeginImplFrame();
     83   }
     84 
     85   virtual base::TimeTicks RetroactiveBeginImplFrameDeadline() OVERRIDE {
     86     if (retroactive_begin_impl_frame_deadline_enabled_) {
     87       if (override_retroactive_period_) {
     88         return skipped_begin_impl_frame_args_.frame_time +
     89                retroactive_period_override_;
     90       } else {
     91         return OutputSurface::RetroactiveBeginImplFrameDeadline();
     92       }
     93     }
     94     return base::TimeTicks();
     95   }
     96 
     97   bool retroactive_begin_impl_frame_deadline_enabled_;
     98   bool override_retroactive_period_;
     99   base::TimeDelta retroactive_period_override_;
    100 };
    101 
    102 class TestSoftwareOutputDevice : public SoftwareOutputDevice {
    103  public:
    104   TestSoftwareOutputDevice();
    105   virtual ~TestSoftwareOutputDevice();
    106 
    107   // Overriden from cc:SoftwareOutputDevice
    108   virtual void DiscardBackbuffer() OVERRIDE;
    109   virtual void EnsureBackbuffer() OVERRIDE;
    110 
    111   int discard_backbuffer_count() { return discard_backbuffer_count_; }
    112   int ensure_backbuffer_count() { return ensure_backbuffer_count_; }
    113 
    114  private:
    115   int discard_backbuffer_count_;
    116   int ensure_backbuffer_count_;
    117 };
    118 
    119 TestSoftwareOutputDevice::TestSoftwareOutputDevice()
    120     : discard_backbuffer_count_(0), ensure_backbuffer_count_(0) {}
    121 
    122 TestSoftwareOutputDevice::~TestSoftwareOutputDevice() {}
    123 
    124 void TestSoftwareOutputDevice::DiscardBackbuffer() {
    125   SoftwareOutputDevice::DiscardBackbuffer();
    126   discard_backbuffer_count_++;
    127 }
    128 
    129 void TestSoftwareOutputDevice::EnsureBackbuffer() {
    130   SoftwareOutputDevice::EnsureBackbuffer();
    131   ensure_backbuffer_count_++;
    132 }
    133 
    134 TEST(OutputSurfaceTest, ClientPointerIndicatesBindToClientSuccess) {
    135   TestOutputSurface output_surface(TestContextProvider::Create());
    136   EXPECT_FALSE(output_surface.HasClient());
    137 
    138   FakeOutputSurfaceClient client;
    139   EXPECT_TRUE(output_surface.BindToClient(&client));
    140   EXPECT_TRUE(output_surface.HasClient());
    141   EXPECT_FALSE(client.deferred_initialize_called());
    142 
    143   // Verify DidLoseOutputSurface callback is hooked up correctly.
    144   EXPECT_FALSE(client.did_lose_output_surface_called());
    145   output_surface.context_provider()->Context3d()->loseContextCHROMIUM(
    146       GL_GUILTY_CONTEXT_RESET_ARB, GL_INNOCENT_CONTEXT_RESET_ARB);
    147   EXPECT_TRUE(client.did_lose_output_surface_called());
    148 }
    149 
    150 TEST(OutputSurfaceTest, ClientPointerIndicatesBindToClientFailure) {
    151   scoped_refptr<TestContextProvider> context_provider =
    152       TestContextProvider::Create();
    153 
    154   // Lose the context so BindToClient fails.
    155   context_provider->UnboundTestContext3d()->set_context_lost(true);
    156 
    157   TestOutputSurface output_surface(context_provider);
    158   EXPECT_FALSE(output_surface.HasClient());
    159 
    160   FakeOutputSurfaceClient client;
    161   EXPECT_FALSE(output_surface.BindToClient(&client));
    162   EXPECT_FALSE(output_surface.HasClient());
    163 }
    164 
    165 class OutputSurfaceTestInitializeNewContext3d : public ::testing::Test {
    166  public:
    167   OutputSurfaceTestInitializeNewContext3d()
    168       : context_provider_(TestContextProvider::Create()),
    169         output_surface_(
    170             scoped_ptr<SoftwareOutputDevice>(new SoftwareOutputDevice)) {}
    171 
    172  protected:
    173   void BindOutputSurface() {
    174     EXPECT_TRUE(output_surface_.BindToClient(&client_));
    175     EXPECT_TRUE(output_surface_.HasClient());
    176   }
    177 
    178   void InitializeNewContextExpectFail() {
    179     EXPECT_FALSE(output_surface_.InitializeNewContext3d(context_provider_));
    180     EXPECT_TRUE(output_surface_.HasClient());
    181 
    182     EXPECT_FALSE(output_surface_.context_provider());
    183     EXPECT_TRUE(output_surface_.software_device());
    184   }
    185 
    186   scoped_refptr<TestContextProvider> context_provider_;
    187   TestOutputSurface output_surface_;
    188   FakeOutputSurfaceClient client_;
    189 };
    190 
    191 TEST_F(OutputSurfaceTestInitializeNewContext3d, Success) {
    192   BindOutputSurface();
    193   EXPECT_FALSE(client_.deferred_initialize_called());
    194 
    195   EXPECT_TRUE(output_surface_.InitializeNewContext3d(context_provider_));
    196   EXPECT_TRUE(client_.deferred_initialize_called());
    197   EXPECT_EQ(context_provider_, output_surface_.context_provider());
    198 
    199   EXPECT_FALSE(client_.did_lose_output_surface_called());
    200   context_provider_->Context3d()->loseContextCHROMIUM(
    201       GL_GUILTY_CONTEXT_RESET_ARB, GL_INNOCENT_CONTEXT_RESET_ARB);
    202   EXPECT_TRUE(client_.did_lose_output_surface_called());
    203 
    204   output_surface_.ReleaseGL();
    205   EXPECT_FALSE(output_surface_.context_provider());
    206 }
    207 
    208 TEST_F(OutputSurfaceTestInitializeNewContext3d, Context3dMakeCurrentFails) {
    209   BindOutputSurface();
    210 
    211   context_provider_->UnboundTestContext3d()->set_context_lost(true);
    212   InitializeNewContextExpectFail();
    213 }
    214 
    215 TEST_F(OutputSurfaceTestInitializeNewContext3d, ClientDeferredInitializeFails) {
    216   BindOutputSurface();
    217   client_.set_deferred_initialize_result(false);
    218   InitializeNewContextExpectFail();
    219 }
    220 
    221 TEST(OutputSurfaceTest, BeginImplFrameEmulation) {
    222   TestOutputSurface output_surface(TestContextProvider::Create());
    223   EXPECT_FALSE(output_surface.HasClient());
    224 
    225   FakeOutputSurfaceClient client;
    226   EXPECT_TRUE(output_surface.BindToClient(&client));
    227   EXPECT_TRUE(output_surface.HasClient());
    228   EXPECT_FALSE(client.deferred_initialize_called());
    229 
    230   // Initialize BeginImplFrame emulation
    231   scoped_refptr<base::TestSimpleTaskRunner> task_runner =
    232       new base::TestSimpleTaskRunner;
    233   bool throttle_frame_production = true;
    234   const base::TimeDelta display_refresh_interval =
    235       BeginFrameArgs::DefaultInterval();
    236 
    237   output_surface.InitializeBeginImplFrameEmulation(
    238       task_runner.get(),
    239       throttle_frame_production,
    240       display_refresh_interval);
    241 
    242   output_surface.SetMaxFramesPending(2);
    243   output_surface.EnableRetroactiveBeginImplFrameDeadline(
    244       false, false, base::TimeDelta());
    245 
    246   // We should start off with 0 BeginImplFrames
    247   EXPECT_EQ(client.begin_impl_frame_count(), 0);
    248   EXPECT_EQ(output_surface.pending_swap_buffers(), 0);
    249 
    250   // We should not have a pending task until a BeginImplFrame has been
    251   // requested.
    252   EXPECT_FALSE(task_runner->HasPendingTask());
    253   output_surface.SetNeedsBeginImplFrame(true);
    254   EXPECT_TRUE(task_runner->HasPendingTask());
    255 
    256   // BeginImplFrame should be called on the first tick.
    257   task_runner->RunPendingTasks();
    258   EXPECT_EQ(client.begin_impl_frame_count(), 1);
    259   EXPECT_EQ(output_surface.pending_swap_buffers(), 0);
    260 
    261   // BeginImplFrame should not be called when there is a pending BeginImplFrame.
    262   task_runner->RunPendingTasks();
    263   EXPECT_EQ(client.begin_impl_frame_count(), 1);
    264   EXPECT_EQ(output_surface.pending_swap_buffers(), 0);
    265 
    266   // SetNeedsBeginImplFrame should clear the pending BeginImplFrame after
    267   // a SwapBuffers.
    268   output_surface.DidSwapBuffersForTesting();
    269   output_surface.SetNeedsBeginImplFrame(true);
    270   EXPECT_EQ(client.begin_impl_frame_count(), 1);
    271   EXPECT_EQ(output_surface.pending_swap_buffers(), 1);
    272   task_runner->RunPendingTasks();
    273   EXPECT_EQ(client.begin_impl_frame_count(), 2);
    274   EXPECT_EQ(output_surface.pending_swap_buffers(), 1);
    275 
    276   // BeginImplFrame should be throttled by pending swap buffers.
    277   output_surface.DidSwapBuffersForTesting();
    278   output_surface.SetNeedsBeginImplFrame(true);
    279   EXPECT_EQ(client.begin_impl_frame_count(), 2);
    280   EXPECT_EQ(output_surface.pending_swap_buffers(), 2);
    281   task_runner->RunPendingTasks();
    282   EXPECT_EQ(client.begin_impl_frame_count(), 2);
    283   EXPECT_EQ(output_surface.pending_swap_buffers(), 2);
    284 
    285   // SwapAck should decrement pending swap buffers and unblock BeginImplFrame
    286   // again.
    287   output_surface.OnSwapBuffersCompleteForTesting();
    288   EXPECT_EQ(client.begin_impl_frame_count(), 2);
    289   EXPECT_EQ(output_surface.pending_swap_buffers(), 1);
    290   task_runner->RunPendingTasks();
    291   EXPECT_EQ(client.begin_impl_frame_count(), 3);
    292   EXPECT_EQ(output_surface.pending_swap_buffers(), 1);
    293 
    294   // Calling SetNeedsBeginImplFrame again indicates a swap did not occur but
    295   // the client still wants another BeginImplFrame.
    296   output_surface.SetNeedsBeginImplFrame(true);
    297   task_runner->RunPendingTasks();
    298   EXPECT_EQ(client.begin_impl_frame_count(), 4);
    299   EXPECT_EQ(output_surface.pending_swap_buffers(), 1);
    300 
    301   // Disabling SetNeedsBeginImplFrame should prevent further BeginImplFrames.
    302   output_surface.SetNeedsBeginImplFrame(false);
    303   task_runner->RunPendingTasks();
    304   EXPECT_FALSE(task_runner->HasPendingTask());
    305   EXPECT_EQ(client.begin_impl_frame_count(), 4);
    306   EXPECT_EQ(output_surface.pending_swap_buffers(), 1);
    307 }
    308 
    309 TEST(OutputSurfaceTest, OptimisticAndRetroactiveBeginImplFrames) {
    310   TestOutputSurface output_surface(TestContextProvider::Create());
    311   EXPECT_FALSE(output_surface.HasClient());
    312 
    313   FakeOutputSurfaceClient client;
    314   EXPECT_TRUE(output_surface.BindToClient(&client));
    315   EXPECT_TRUE(output_surface.HasClient());
    316   EXPECT_FALSE(client.deferred_initialize_called());
    317 
    318   output_surface.SetMaxFramesPending(2);
    319   output_surface.EnableRetroactiveBeginImplFrameDeadline(
    320       true, false, base::TimeDelta());
    321 
    322   // Optimistically injected BeginImplFrames should be throttled if
    323   // SetNeedsBeginImplFrame is false...
    324   output_surface.SetNeedsBeginImplFrame(false);
    325   output_surface.BeginImplFrameForTesting();
    326   EXPECT_EQ(client.begin_impl_frame_count(), 0);
    327   // ...and retroactively triggered by a SetNeedsBeginImplFrame.
    328   output_surface.SetNeedsBeginImplFrame(true);
    329   EXPECT_EQ(client.begin_impl_frame_count(), 1);
    330 
    331   // Optimistically injected BeginImplFrames should be throttled by pending
    332   // BeginImplFrames...
    333   output_surface.BeginImplFrameForTesting();
    334   EXPECT_EQ(client.begin_impl_frame_count(), 1);
    335   // ...and retroactively triggered by a SetNeedsBeginImplFrame.
    336   output_surface.SetNeedsBeginImplFrame(true);
    337   EXPECT_EQ(client.begin_impl_frame_count(), 2);
    338   // ...or retroactively triggered by a Swap.
    339   output_surface.BeginImplFrameForTesting();
    340   EXPECT_EQ(client.begin_impl_frame_count(), 2);
    341   output_surface.DidSwapBuffersForTesting();
    342   output_surface.SetNeedsBeginImplFrame(true);
    343   EXPECT_EQ(client.begin_impl_frame_count(), 3);
    344   EXPECT_EQ(output_surface.pending_swap_buffers(), 1);
    345 
    346   // Optimistically injected BeginImplFrames should be by throttled by pending
    347   // swap buffers...
    348   output_surface.DidSwapBuffersForTesting();
    349   output_surface.SetNeedsBeginImplFrame(true);
    350   EXPECT_EQ(client.begin_impl_frame_count(), 3);
    351   EXPECT_EQ(output_surface.pending_swap_buffers(), 2);
    352   output_surface.BeginImplFrameForTesting();
    353   EXPECT_EQ(client.begin_impl_frame_count(), 3);
    354   // ...and retroactively triggered by OnSwapBuffersComplete
    355   output_surface.OnSwapBuffersCompleteForTesting();
    356   EXPECT_EQ(client.begin_impl_frame_count(), 4);
    357 }
    358 
    359 TEST(OutputSurfaceTest,
    360      RetroactiveBeginImplFrameDoesNotDoubleTickWhenEmulating) {
    361   scoped_refptr<TestContextProvider> context_provider =
    362       TestContextProvider::Create();
    363 
    364   TestOutputSurface output_surface(context_provider);
    365   EXPECT_FALSE(output_surface.HasClient());
    366 
    367   FakeOutputSurfaceClient client;
    368   EXPECT_TRUE(output_surface.BindToClient(&client));
    369   EXPECT_TRUE(output_surface.HasClient());
    370   EXPECT_FALSE(client.deferred_initialize_called());
    371 
    372   base::TimeDelta big_interval = base::TimeDelta::FromSeconds(10);
    373 
    374   // Initialize BeginImplFrame emulation
    375   scoped_refptr<base::TestSimpleTaskRunner> task_runner =
    376       new base::TestSimpleTaskRunner;
    377   bool throttle_frame_production = true;
    378   const base::TimeDelta display_refresh_interval = big_interval;
    379 
    380   output_surface.InitializeBeginImplFrameEmulation(
    381       task_runner.get(),
    382       throttle_frame_production,
    383       display_refresh_interval);
    384 
    385   // We need to subtract an epsilon from Now() because some platforms have
    386   // a slow clock.
    387   output_surface.OnVSyncParametersChangedForTesting(
    388       gfx::FrameTime::Now() - base::TimeDelta::FromSeconds(1), big_interval);
    389 
    390   output_surface.SetMaxFramesPending(2);
    391   output_surface.EnableRetroactiveBeginImplFrameDeadline(
    392       true, true, big_interval);
    393 
    394   // We should start off with 0 BeginImplFrames
    395   EXPECT_EQ(client.begin_impl_frame_count(), 0);
    396   EXPECT_EQ(output_surface.pending_swap_buffers(), 0);
    397 
    398   // The first SetNeedsBeginImplFrame(true) should start a retroactive
    399   // BeginImplFrame.
    400   EXPECT_FALSE(task_runner->HasPendingTask());
    401   output_surface.SetNeedsBeginImplFrame(true);
    402   EXPECT_TRUE(task_runner->HasPendingTask());
    403   EXPECT_GT(task_runner->NextPendingTaskDelay(), big_interval / 2);
    404   EXPECT_EQ(client.begin_impl_frame_count(), 1);
    405 
    406   output_surface.SetNeedsBeginImplFrame(false);
    407   EXPECT_TRUE(task_runner->HasPendingTask());
    408   EXPECT_EQ(client.begin_impl_frame_count(), 1);
    409 
    410   // The second SetNeedBeginImplFrame(true) should not retroactively start a
    411   // BeginImplFrame if the timestamp would be the same as the previous
    412   // BeginImplFrame.
    413   output_surface.SetNeedsBeginImplFrame(true);
    414   EXPECT_TRUE(task_runner->HasPendingTask());
    415   EXPECT_EQ(client.begin_impl_frame_count(), 1);
    416 }
    417 
    418 TEST(OutputSurfaceTest, MemoryAllocation) {
    419   scoped_refptr<TestContextProvider> context_provider =
    420       TestContextProvider::Create();
    421 
    422   TestOutputSurface output_surface(context_provider);
    423 
    424   FakeOutputSurfaceClient client;
    425   EXPECT_TRUE(output_surface.BindToClient(&client));
    426 
    427   ManagedMemoryPolicy policy(0);
    428   policy.bytes_limit_when_visible = 1234;
    429   policy.priority_cutoff_when_visible =
    430       gpu::MemoryAllocation::CUTOFF_ALLOW_REQUIRED_ONLY;
    431 
    432   context_provider->SetMemoryAllocation(policy);
    433   EXPECT_EQ(1234u, client.memory_policy().bytes_limit_when_visible);
    434   EXPECT_EQ(gpu::MemoryAllocation::CUTOFF_ALLOW_REQUIRED_ONLY,
    435             client.memory_policy().priority_cutoff_when_visible);
    436 
    437   policy.priority_cutoff_when_visible =
    438       gpu::MemoryAllocation::CUTOFF_ALLOW_EVERYTHING;
    439   context_provider->SetMemoryAllocation(policy);
    440   EXPECT_EQ(gpu::MemoryAllocation::CUTOFF_ALLOW_EVERYTHING,
    441             client.memory_policy().priority_cutoff_when_visible);
    442 
    443   // 0 bytes limit should be ignored.
    444   policy.bytes_limit_when_visible = 0;
    445   context_provider->SetMemoryAllocation(policy);
    446   EXPECT_EQ(1234u, client.memory_policy().bytes_limit_when_visible);
    447 }
    448 
    449 TEST(OutputSurfaceTest, SoftwareOutputDeviceBackbufferManagement) {
    450   TestSoftwareOutputDevice* software_output_device =
    451       new TestSoftwareOutputDevice();
    452 
    453   // TestOutputSurface now owns software_output_device and has responsibility to
    454   // free it.
    455   scoped_ptr<TestSoftwareOutputDevice> p(software_output_device);
    456   TestOutputSurface output_surface(p.PassAs<SoftwareOutputDevice>());
    457 
    458   EXPECT_EQ(0, software_output_device->ensure_backbuffer_count());
    459   EXPECT_EQ(0, software_output_device->discard_backbuffer_count());
    460 
    461   output_surface.EnsureBackbuffer();
    462   EXPECT_EQ(1, software_output_device->ensure_backbuffer_count());
    463   EXPECT_EQ(0, software_output_device->discard_backbuffer_count());
    464   output_surface.DiscardBackbuffer();
    465 
    466   EXPECT_EQ(1, software_output_device->ensure_backbuffer_count());
    467   EXPECT_EQ(1, software_output_device->discard_backbuffer_count());
    468 }
    469 
    470 }  // namespace
    471 }  // namespace cc
    472