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 "base/location.h"
8 #include "base/single_thread_task_runner.h"
9 #include "base/thread_task_runner_handle.h"
10 #include "cc/output/begin_frame_args.h"
11 #include "cc/test/failure_output_surface.h"
12 #include "cc/trees/layer_tree_host.h"
13 #include "components/scheduler/renderer/renderer_scheduler.h"
14 #include "content/public/test/mock_render_thread.h"
15 #include "content/renderer/render_widget.h"
16 #include "content/test/fake_compositor_dependencies.h"
17 #include "content/test/fake_renderer_scheduler.h"
18 #include "testing/gmock/include/gmock/gmock.h"
19 #include "testing/gtest/include/gtest/gtest.h"
20 #include "third_party/WebKit/public/platform/WebScreenInfo.h"
28 class MockWebWidget
: public blink::WebWidget
{
30 MOCK_METHOD1(beginFrame
, void(const blink::WebBeginFrameArgs
& args
));
33 class TestRenderWidget
: public RenderWidget
{
36 : RenderWidget(blink::WebPopupTypeNone
,
37 blink::WebScreenInfo(),
41 webwidget_
= &mock_webwidget_
;
44 MockWebWidget mock_webwidget_
;
47 ~TestRenderWidget() override
{ webwidget_
= NULL
; }
49 DISALLOW_COPY_AND_ASSIGN(TestRenderWidget
);
52 class RenderWidgetCompositorTest
: public testing::Test
{
54 RenderWidgetCompositorTest()
55 : render_widget_(make_scoped_refptr(new TestRenderWidget())),
56 compositor_deps_(make_scoped_ptr(new FakeCompositorDependencies
)),
57 render_widget_compositor_(
58 RenderWidgetCompositor::Create(render_widget_
.get(),
59 compositor_deps_
.get())) {}
60 ~RenderWidgetCompositorTest() override
{}
63 base::MessageLoop loop_
;
64 MockRenderThread render_thread_
;
65 scoped_refptr
<TestRenderWidget
> render_widget_
;
66 scoped_ptr
<FakeCompositorDependencies
> compositor_deps_
;
67 scoped_ptr
<RenderWidgetCompositor
> render_widget_compositor_
;
70 DISALLOW_COPY_AND_ASSIGN(RenderWidgetCompositorTest
);
73 TEST_F(RenderWidgetCompositorTest
, BeginMainFrame
) {
74 base::TimeTicks
frame_time(base::TimeTicks() +
75 base::TimeDelta::FromSeconds(1));
76 base::TimeTicks
deadline(base::TimeTicks() + base::TimeDelta::FromSeconds(2));
77 base::TimeDelta
interval(base::TimeDelta::FromSeconds(3));
78 cc::BeginFrameArgs
args(
79 cc::BeginFrameArgs::Create(BEGINFRAME_FROM_HERE
, frame_time
, deadline
,
80 interval
, cc::BeginFrameArgs::NORMAL
));
82 EXPECT_CALL(render_widget_
->mock_webwidget_
,
84 Field(&blink::WebBeginFrameArgs::lastFrameTimeMonotonic
, 1),
85 Field(&blink::WebBeginFrameArgs::deadline
, 2),
86 Field(&blink::WebBeginFrameArgs::interval
, 3))));
88 render_widget_compositor_
->BeginMainFrame(args
);
91 class RenderWidgetCompositorOutputSurface
;
93 class RenderWidgetOutputSurface
: public TestRenderWidget
{
95 RenderWidgetOutputSurface() : compositor_(NULL
) {}
96 void SetCompositor(RenderWidgetCompositorOutputSurface
* compositor
);
98 scoped_ptr
<cc::OutputSurface
> CreateOutputSurface(bool fallback
) override
;
101 ~RenderWidgetOutputSurface() override
{}
104 RenderWidgetCompositorOutputSurface
* compositor_
;
106 DISALLOW_COPY_AND_ASSIGN(RenderWidgetOutputSurface
);
109 // Verify that failing to create an output surface will cause the compositor
110 // to attempt to repeatedly create another output surface. After enough
111 // failures, verify that it attempts to create a fallback output surface.
112 // The use null output surface parameter allows testing whether failures
113 // from RenderWidget (couldn't create an output surface) vs failures from
114 // the compositor (couldn't bind the output surface) are handled identically.
115 class RenderWidgetCompositorOutputSurface
: public RenderWidgetCompositor
{
117 RenderWidgetCompositorOutputSurface(RenderWidget
* widget
,
118 CompositorDependencies
* compositor_deps
)
119 : RenderWidgetCompositor(widget
, compositor_deps
),
120 num_failures_before_success_(0),
121 expected_successes_(0),
122 expected_fallback_successes_(0),
123 expected_requests_(0),
125 num_requests_since_last_success_(0),
127 num_fallback_successes_(0),
129 last_create_was_fallback_(false),
130 use_null_output_surface_(true) {}
132 using RenderWidgetCompositor::Initialize
;
134 scoped_ptr
<cc::OutputSurface
> CreateOutputSurface(bool fallback
) {
135 EXPECT_EQ(num_requests_since_last_success_
>
136 OUTPUT_SURFACE_RETRIES_BEFORE_FALLBACK
,
138 last_create_was_fallback_
= fallback
;
139 bool success
= num_failures_
>= num_failures_before_success_
;
141 scoped_ptr
<cc::TestWebGraphicsContext3D
> context
=
142 cc::TestWebGraphicsContext3D::Create();
143 // Image support required for synchronous compositing.
144 context
->set_support_image(true);
145 // Create delegating surface so that max_pending_frames = 1.
146 return cc::FakeOutputSurface::CreateDelegating3d(context
.Pass());
148 return use_null_output_surface_
150 : make_scoped_ptr(new cc::FailureOutputSurface(true));
153 // Force a new output surface to be created.
154 void SynchronousComposite() {
155 layer_tree_host()->DidLoseOutputSurface();
157 base::TimeTicks some_time
;
158 layer_tree_host()->Composite(some_time
);
161 void RequestNewOutputSurface() override
{
163 ++num_requests_since_last_success_
;
164 RenderWidgetCompositor::RequestNewOutputSurface();
167 void DidInitializeOutputSurface() override
{
168 if (last_create_was_fallback_
)
169 ++num_fallback_successes_
;
173 if (num_requests_
== expected_requests_
) {
176 num_requests_since_last_success_
= 0;
177 RenderWidgetCompositor::DidInitializeOutputSurface();
178 // Post the synchronous composite task so that it is not called
179 // reentrantly as a part of RequestNewOutputSurface.
180 base::ThreadTaskRunnerHandle::Get()->PostTask(
182 base::Bind(&RenderWidgetCompositorOutputSurface::SynchronousComposite
,
183 base::Unretained(this)));
187 void DidFailToInitializeOutputSurface() override
{
189 if (num_requests_
== expected_requests_
) {
194 RenderWidgetCompositor::DidFailToInitializeOutputSurface();
197 void SetUp(bool use_null_output_surface
,
198 int num_failures_before_success
,
199 int expected_successes
,
200 int expected_fallback_succeses
) {
201 use_null_output_surface_
= use_null_output_surface
;
202 num_failures_before_success_
= num_failures_before_success
;
203 expected_successes_
= expected_successes
;
204 expected_fallback_successes_
= expected_fallback_succeses
;
205 expected_requests_
= num_failures_before_success_
+ expected_successes_
+
206 expected_fallback_successes_
;
209 void EndTest() { base::MessageLoop::current()->Quit(); }
212 EXPECT_EQ(num_failures_before_success_
, num_failures_
);
213 EXPECT_EQ(expected_successes_
, num_successes_
);
214 EXPECT_EQ(expected_fallback_successes_
, num_fallback_successes_
);
215 EXPECT_EQ(expected_requests_
, num_requests_
);
219 int num_failures_before_success_
;
220 int expected_successes_
;
221 int expected_fallback_successes_
;
222 int expected_requests_
;
224 int num_requests_since_last_success_
;
226 int num_fallback_successes_
;
228 bool last_create_was_fallback_
;
229 bool use_null_output_surface_
;
231 DISALLOW_COPY_AND_ASSIGN(RenderWidgetCompositorOutputSurface
);
234 class RenderWidgetCompositorOutputSurfaceTest
: public testing::Test
{
236 RenderWidgetCompositorOutputSurfaceTest()
237 : render_widget_(make_scoped_refptr(new RenderWidgetOutputSurface
)),
238 compositor_deps_(make_scoped_ptr(new FakeCompositorDependencies
)) {
239 render_widget_compositor_
.reset(new RenderWidgetCompositorOutputSurface(
240 render_widget_
.get(), compositor_deps_
.get()));
241 render_widget_compositor_
->Initialize();
242 render_widget_
->SetCompositor(render_widget_compositor_
.get());
245 void RunTest(bool use_null_output_surface
,
246 int num_failures_before_success
,
247 int expected_successes
,
248 int expected_fallback_succeses
) {
249 render_widget_compositor_
->SetUp(
250 use_null_output_surface
, num_failures_before_success
,
251 expected_successes
, expected_fallback_succeses
);
252 render_widget_compositor_
->StartCompositor();
253 base::ThreadTaskRunnerHandle::Get()->PostTask(
255 base::Bind(&RenderWidgetCompositorOutputSurface::SynchronousComposite
,
256 base::Unretained(render_widget_compositor_
.get())));
257 base::MessageLoop::current()->Run();
258 render_widget_compositor_
->AfterTest();
262 base::MessageLoop ye_olde_message_loope_
;
263 MockRenderThread render_thread_
;
264 scoped_refptr
<RenderWidgetOutputSurface
> render_widget_
;
265 scoped_ptr
<FakeCompositorDependencies
> compositor_deps_
;
266 scoped_ptr
<RenderWidgetCompositorOutputSurface
> render_widget_compositor_
;
269 DISALLOW_COPY_AND_ASSIGN(RenderWidgetCompositorOutputSurfaceTest
);
272 scoped_ptr
<cc::OutputSurface
> RenderWidgetOutputSurface::CreateOutputSurface(
274 return compositor_
->CreateOutputSurface(fallback
);
277 void RenderWidgetOutputSurface::SetCompositor(
278 RenderWidgetCompositorOutputSurface
* compositor
) {
279 compositor_
= compositor
;
282 TEST_F(RenderWidgetCompositorOutputSurfaceTest
, SucceedOnce
) {
283 RunTest(false, 0, 1, 0);
286 TEST_F(RenderWidgetCompositorOutputSurfaceTest
, SucceedTwice
) {
287 RunTest(false, 0, 2, 0);
290 TEST_F(RenderWidgetCompositorOutputSurfaceTest
, FailOnceNull
) {
292 RenderWidgetCompositor::OUTPUT_SURFACE_RETRIES_BEFORE_FALLBACK
>= 2,
293 "Adjust the values of this test if this fails");
294 RunTest(true, 1, 1, 0);
297 TEST_F(RenderWidgetCompositorOutputSurfaceTest
, FailOnceBind
) {
299 RenderWidgetCompositor::OUTPUT_SURFACE_RETRIES_BEFORE_FALLBACK
>= 2,
300 "Adjust the values of this test if this fails");
301 RunTest(false, 1, 1, 0);
304 TEST_F(RenderWidgetCompositorOutputSurfaceTest
, FallbackSuccessNull
) {
305 RunTest(true, RenderWidgetCompositor::OUTPUT_SURFACE_RETRIES_BEFORE_FALLBACK
,
309 TEST_F(RenderWidgetCompositorOutputSurfaceTest
, FallbackSuccessBind
) {
310 RunTest(false, RenderWidgetCompositor::OUTPUT_SURFACE_RETRIES_BEFORE_FALLBACK
,
314 TEST_F(RenderWidgetCompositorOutputSurfaceTest
, FallbackSuccessNormalSuccess
) {
315 // The first success is a fallback, but the next should not be a fallback.
316 RunTest(false, RenderWidgetCompositor::OUTPUT_SURFACE_RETRIES_BEFORE_FALLBACK
,
321 } // namespace content