output_surface_unittest.cc revision a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7
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
20namespace cc {
21namespace {
22
23class 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
102class 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
119TestSoftwareOutputDevice::TestSoftwareOutputDevice()
120    : discard_backbuffer_count_(0), ensure_backbuffer_count_(0) {}
121
122TestSoftwareOutputDevice::~TestSoftwareOutputDevice() {}
123
124void TestSoftwareOutputDevice::DiscardBackbuffer() {
125  SoftwareOutputDevice::DiscardBackbuffer();
126  discard_backbuffer_count_++;
127}
128
129void TestSoftwareOutputDevice::EnsureBackbuffer() {
130  SoftwareOutputDevice::EnsureBackbuffer();
131  ensure_backbuffer_count_++;
132}
133
134TEST(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
150TEST(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
165class 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
191TEST_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
208TEST_F(OutputSurfaceTestInitializeNewContext3d, Context3dMakeCurrentFails) {
209  BindOutputSurface();
210
211  context_provider_->UnboundTestContext3d()->set_context_lost(true);
212  InitializeNewContextExpectFail();
213}
214
215TEST_F(OutputSurfaceTestInitializeNewContext3d, ClientDeferredInitializeFails) {
216  BindOutputSurface();
217  client_.set_deferred_initialize_result(false);
218  InitializeNewContextExpectFail();
219}
220
221TEST(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
309TEST(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
359TEST(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
418TEST(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
449TEST(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