Re-subimission of https://codereview.chromium.org/1041213003/
[chromium-blink-merge.git] / content / renderer / gpu / render_widget_compositor_unittest.cc
blob448fa1f5f0e677658d29f53bc40b7a5f9742ff6a
1 // Copyright 2014 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 "content/renderer/gpu/render_widget_compositor.h"
7 #include "cc/output/begin_frame_args.h"
8 #include "cc/test/failure_output_surface.h"
9 #include "cc/trees/layer_tree_host.h"
10 #include "content/public/test/mock_render_thread.h"
11 #include "content/renderer/render_widget.h"
12 #include "content/renderer/scheduler/renderer_scheduler.h"
13 #include "content/test/fake_compositor_dependencies.h"
14 #include "content/test/fake_renderer_scheduler.h"
15 #include "testing/gmock/include/gmock/gmock.h"
16 #include "testing/gtest/include/gtest/gtest.h"
17 #include "third_party/WebKit/public/platform/WebScreenInfo.h"
19 using testing::AllOf;
20 using testing::Field;
22 namespace content {
23 namespace {
25 class MockWebWidget : public blink::WebWidget {
26 public:
27 MOCK_METHOD1(beginFrame, void(const blink::WebBeginFrameArgs& args));
30 class TestRenderWidget : public RenderWidget {
31 public:
32 TestRenderWidget()
33 : RenderWidget(blink::WebPopupTypeNone,
34 blink::WebScreenInfo(),
35 true,
36 false,
37 false) {
38 webwidget_ = &mock_webwidget_;
41 MockWebWidget mock_webwidget_;
43 protected:
44 ~TestRenderWidget() override { webwidget_ = NULL; }
46 DISALLOW_COPY_AND_ASSIGN(TestRenderWidget);
49 class RenderWidgetCompositorTest : public testing::Test {
50 public:
51 RenderWidgetCompositorTest()
52 : render_widget_(make_scoped_refptr(new TestRenderWidget())),
53 compositor_deps_(make_scoped_ptr(new FakeCompositorDependencies)),
54 render_widget_compositor_(
55 RenderWidgetCompositor::Create(render_widget_.get(),
56 compositor_deps_.get())) {}
57 ~RenderWidgetCompositorTest() override {}
59 protected:
60 MockRenderThread render_thread_;
61 scoped_refptr<TestRenderWidget> render_widget_;
62 scoped_ptr<FakeCompositorDependencies> compositor_deps_;
63 scoped_ptr<RenderWidgetCompositor> render_widget_compositor_;
65 private:
66 DISALLOW_COPY_AND_ASSIGN(RenderWidgetCompositorTest);
69 TEST_F(RenderWidgetCompositorTest, BeginMainFrame) {
70 base::TimeTicks frame_time(base::TimeTicks() +
71 base::TimeDelta::FromSeconds(1));
72 base::TimeTicks deadline(base::TimeTicks() + base::TimeDelta::FromSeconds(2));
73 base::TimeDelta interval(base::TimeDelta::FromSeconds(3));
74 cc::BeginFrameArgs args(
75 cc::BeginFrameArgs::Create(BEGINFRAME_FROM_HERE, frame_time, deadline,
76 interval, cc::BeginFrameArgs::NORMAL));
78 EXPECT_CALL(render_widget_->mock_webwidget_,
79 beginFrame(AllOf(
80 Field(&blink::WebBeginFrameArgs::lastFrameTimeMonotonic, 1),
81 Field(&blink::WebBeginFrameArgs::deadline, 2),
82 Field(&blink::WebBeginFrameArgs::interval, 3))));
84 render_widget_compositor_->BeginMainFrame(args);
87 class RenderWidgetCompositorOutputSurface;
89 class RenderWidgetOutputSurface : public TestRenderWidget {
90 public:
91 RenderWidgetOutputSurface() : compositor_(NULL) {}
92 void SetCompositor(RenderWidgetCompositorOutputSurface* compositor);
94 scoped_ptr<cc::OutputSurface> CreateOutputSurface(bool fallback) override;
96 protected:
97 ~RenderWidgetOutputSurface() override {}
99 private:
100 RenderWidgetCompositorOutputSurface* compositor_;
102 DISALLOW_COPY_AND_ASSIGN(RenderWidgetOutputSurface);
105 // Verify that failing to create an output surface will cause the compositor
106 // to attempt to repeatedly create another output surface. After enough
107 // failures, verify that it attempts to create a fallback output surface.
108 // The use null output surface parameter allows testing whether failures
109 // from RenderWidget (couldn't create an output surface) vs failures from
110 // the compositor (couldn't bind the output surface) are handled identically.
111 class RenderWidgetCompositorOutputSurface : public RenderWidgetCompositor {
112 public:
113 RenderWidgetCompositorOutputSurface(RenderWidget* widget,
114 CompositorDependencies* compositor_deps)
115 : RenderWidgetCompositor(widget, compositor_deps),
116 num_failures_before_success_(0),
117 expected_successes_(0),
118 expected_fallback_successes_(0),
119 expected_requests_(0),
120 num_requests_(0),
121 num_requests_since_last_success_(0),
122 num_successes_(0),
123 num_fallback_successes_(0),
124 num_failures_(0),
125 last_create_was_fallback_(false),
126 use_null_output_surface_(true) {}
128 using RenderWidgetCompositor::Initialize;
130 scoped_ptr<cc::OutputSurface> CreateOutputSurface(bool fallback) {
131 EXPECT_EQ(num_requests_since_last_success_ >
132 OUTPUT_SURFACE_RETRIES_BEFORE_FALLBACK,
133 fallback);
134 last_create_was_fallback_ = fallback;
135 bool success = num_failures_ >= num_failures_before_success_;
136 if (success) {
137 scoped_ptr<cc::TestWebGraphicsContext3D> context =
138 cc::TestWebGraphicsContext3D::Create();
139 // Image support required for synchronous compositing.
140 context->set_support_image(true);
141 return cc::FakeOutputSurface::Create3d(context.Pass());
143 return use_null_output_surface_
144 ? nullptr
145 : make_scoped_ptr(new cc::FailureOutputSurface(false));
148 // Force a new output surface to be created.
149 void SynchronousComposite() {
150 layer_tree_host()->DidLoseOutputSurface();
152 base::TimeTicks some_time;
153 layer_tree_host()->Composite(some_time);
156 void RequestNewOutputSurface() override {
157 ++num_requests_;
158 ++num_requests_since_last_success_;
159 RenderWidgetCompositor::RequestNewOutputSurface();
162 void DidInitializeOutputSurface() override {
163 if (last_create_was_fallback_)
164 ++num_fallback_successes_;
165 else
166 ++num_successes_;
168 if (num_requests_ == expected_requests_) {
169 EndTest();
170 } else {
171 num_requests_since_last_success_ = 0;
172 RenderWidgetCompositor::DidInitializeOutputSurface();
173 // Post the synchronous composite task so that it is not called
174 // reentrantly as a part of RequestNewOutputSurface.
175 base::MessageLoop::current()->PostTask(
176 FROM_HERE,
177 base::Bind(&RenderWidgetCompositorOutputSurface::SynchronousComposite,
178 base::Unretained(this)));
182 void DidFailToInitializeOutputSurface() override {
183 ++num_failures_;
184 if (num_requests_ == expected_requests_) {
185 EndTest();
186 return;
189 RenderWidgetCompositor::DidFailToInitializeOutputSurface();
192 void SetUp(bool use_null_output_surface,
193 int num_failures_before_success,
194 int expected_successes,
195 int expected_fallback_succeses) {
196 use_null_output_surface_ = use_null_output_surface;
197 num_failures_before_success_ = num_failures_before_success;
198 expected_successes_ = expected_successes;
199 expected_fallback_successes_ = expected_fallback_succeses;
200 expected_requests_ = num_failures_before_success_ + expected_successes_ +
201 expected_fallback_successes_;
204 void EndTest() { base::MessageLoop::current()->Quit(); }
206 void AfterTest() {
207 EXPECT_EQ(num_failures_before_success_, num_failures_);
208 EXPECT_EQ(expected_successes_, num_successes_);
209 EXPECT_EQ(expected_fallback_successes_, num_fallback_successes_);
210 EXPECT_EQ(expected_requests_, num_requests_);
213 private:
214 int num_failures_before_success_;
215 int expected_successes_;
216 int expected_fallback_successes_;
217 int expected_requests_;
218 int num_requests_;
219 int num_requests_since_last_success_;
220 int num_successes_;
221 int num_fallback_successes_;
222 int num_failures_;
223 bool last_create_was_fallback_;
224 bool use_null_output_surface_;
226 DISALLOW_COPY_AND_ASSIGN(RenderWidgetCompositorOutputSurface);
229 class RenderWidgetCompositorOutputSurfaceTest : public testing::Test {
230 public:
231 RenderWidgetCompositorOutputSurfaceTest()
232 : render_widget_(make_scoped_refptr(new RenderWidgetOutputSurface)),
233 compositor_deps_(make_scoped_ptr(new FakeCompositorDependencies)) {
234 // Required in order to call the synchronous LayerTreeHost::Composite.
235 compositor_deps_->set_use_single_thread_scheduler(false);
236 render_widget_compositor_.reset(new RenderWidgetCompositorOutputSurface(
237 render_widget_.get(), compositor_deps_.get()));
238 render_widget_compositor_->Initialize();
239 render_widget_->SetCompositor(render_widget_compositor_.get());
242 void RunTest(bool use_null_output_surface,
243 int num_failures_before_success,
244 int expected_successes,
245 int expected_fallback_succeses) {
246 render_widget_compositor_->SetUp(
247 use_null_output_surface, num_failures_before_success,
248 expected_successes, expected_fallback_succeses);
249 render_widget_compositor_->StartCompositor();
250 base::MessageLoop::current()->PostTask(
251 FROM_HERE,
252 base::Bind(&RenderWidgetCompositorOutputSurface::SynchronousComposite,
253 base::Unretained(render_widget_compositor_.get())));
254 base::MessageLoop::current()->Run();
255 render_widget_compositor_->AfterTest();
258 protected:
259 base::MessageLoop ye_olde_message_loope_;
260 MockRenderThread render_thread_;
261 scoped_refptr<RenderWidgetOutputSurface> render_widget_;
262 scoped_ptr<FakeCompositorDependencies> compositor_deps_;
263 scoped_ptr<RenderWidgetCompositorOutputSurface> render_widget_compositor_;
265 private:
266 DISALLOW_COPY_AND_ASSIGN(RenderWidgetCompositorOutputSurfaceTest);
269 scoped_ptr<cc::OutputSurface> RenderWidgetOutputSurface::CreateOutputSurface(
270 bool fallback) {
271 return compositor_->CreateOutputSurface(fallback);
274 void RenderWidgetOutputSurface::SetCompositor(
275 RenderWidgetCompositorOutputSurface* compositor) {
276 compositor_ = compositor;
279 TEST_F(RenderWidgetCompositorOutputSurfaceTest, SucceedOnce) {
280 RunTest(false, 0, 1, 0);
283 TEST_F(RenderWidgetCompositorOutputSurfaceTest, SucceedTwice) {
284 RunTest(false, 0, 2, 0);
287 TEST_F(RenderWidgetCompositorOutputSurfaceTest, FailOnceNull) {
288 static_assert(
289 RenderWidgetCompositor::OUTPUT_SURFACE_RETRIES_BEFORE_FALLBACK >= 2,
290 "Adjust the values of this test if this fails");
291 RunTest(true, 1, 1, 0);
294 TEST_F(RenderWidgetCompositorOutputSurfaceTest, FailOnceBind) {
295 static_assert(
296 RenderWidgetCompositor::OUTPUT_SURFACE_RETRIES_BEFORE_FALLBACK >= 2,
297 "Adjust the values of this test if this fails");
298 RunTest(false, 1, 1, 0);
301 TEST_F(RenderWidgetCompositorOutputSurfaceTest, FallbackSuccessNull) {
302 RunTest(true, RenderWidgetCompositor::OUTPUT_SURFACE_RETRIES_BEFORE_FALLBACK,
303 0, 1);
306 TEST_F(RenderWidgetCompositorOutputSurfaceTest, FallbackSuccessBind) {
307 RunTest(false, RenderWidgetCompositor::OUTPUT_SURFACE_RETRIES_BEFORE_FALLBACK,
308 0, 1);
311 TEST_F(RenderWidgetCompositorOutputSurfaceTest, FallbackSuccessNormalSuccess) {
312 // The first success is a fallback, but the next should not be a fallback.
313 RunTest(false, RenderWidgetCompositor::OUTPUT_SURFACE_RETRIES_BEFORE_FALLBACK,
314 1, 1);
317 } // namespace
318 } // namespace content