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
{
35 explicit TestRenderWidget(CompositorDependencies
* compositor_deps
)
36 : RenderWidget(compositor_deps
,
37 blink::WebPopupTypeNone
,
38 blink::WebScreenInfo(),
42 webwidget_
= &mock_webwidget_
;
45 MockWebWidget mock_webwidget_
;
48 ~TestRenderWidget() override
{ webwidget_
= NULL
; }
50 DISALLOW_COPY_AND_ASSIGN(TestRenderWidget
);
53 class RenderWidgetCompositorTest
: public testing::Test
{
55 RenderWidgetCompositorTest()
56 : compositor_deps_(new FakeCompositorDependencies
),
57 render_widget_(new TestRenderWidget(compositor_deps_
.get())),
58 render_widget_compositor_(
59 RenderWidgetCompositor::Create(render_widget_
.get(),
60 compositor_deps_
.get())) {}
61 ~RenderWidgetCompositorTest() override
{}
64 base::MessageLoop loop_
;
65 MockRenderThread render_thread_
;
66 scoped_ptr
<FakeCompositorDependencies
> compositor_deps_
;
67 scoped_refptr
<TestRenderWidget
> render_widget_
;
68 scoped_ptr
<RenderWidgetCompositor
> render_widget_compositor_
;
71 DISALLOW_COPY_AND_ASSIGN(RenderWidgetCompositorTest
);
74 TEST_F(RenderWidgetCompositorTest
, BeginMainFrame
) {
75 base::TimeTicks
frame_time(base::TimeTicks() +
76 base::TimeDelta::FromSeconds(1));
77 base::TimeTicks
deadline(base::TimeTicks() + base::TimeDelta::FromSeconds(2));
78 base::TimeDelta
interval(base::TimeDelta::FromSeconds(3));
79 cc::BeginFrameArgs
args(
80 cc::BeginFrameArgs::Create(BEGINFRAME_FROM_HERE
, frame_time
, deadline
,
81 interval
, cc::BeginFrameArgs::NORMAL
));
83 EXPECT_CALL(render_widget_
->mock_webwidget_
,
85 Field(&blink::WebBeginFrameArgs::lastFrameTimeMonotonic
, 1),
86 Field(&blink::WebBeginFrameArgs::deadline
, 2),
87 Field(&blink::WebBeginFrameArgs::interval
, 3))));
89 render_widget_compositor_
->BeginMainFrame(args
);
92 class RenderWidgetCompositorOutputSurface
;
94 class RenderWidgetOutputSurface
: public TestRenderWidget
{
96 explicit RenderWidgetOutputSurface(CompositorDependencies
* compositor_deps
)
97 : TestRenderWidget(compositor_deps
), compositor_(NULL
) {}
98 void SetCompositor(RenderWidgetCompositorOutputSurface
* compositor
);
100 scoped_ptr
<cc::OutputSurface
> CreateOutputSurface(bool fallback
) override
;
103 ~RenderWidgetOutputSurface() override
{}
106 RenderWidgetCompositorOutputSurface
* compositor_
;
108 DISALLOW_COPY_AND_ASSIGN(RenderWidgetOutputSurface
);
111 // Verify that failing to create an output surface will cause the compositor
112 // to attempt to repeatedly create another output surface. After enough
113 // failures, verify that it attempts to create a fallback output surface.
114 // The use null output surface parameter allows testing whether failures
115 // from RenderWidget (couldn't create an output surface) vs failures from
116 // the compositor (couldn't bind the output surface) are handled identically.
117 class RenderWidgetCompositorOutputSurface
: public RenderWidgetCompositor
{
119 RenderWidgetCompositorOutputSurface(RenderWidget
* widget
,
120 CompositorDependencies
* compositor_deps
)
121 : RenderWidgetCompositor(widget
, compositor_deps
),
122 num_failures_before_success_(0),
123 expected_successes_(0),
124 expected_fallback_successes_(0),
125 expected_requests_(0),
127 num_requests_since_last_success_(0),
129 num_fallback_successes_(0),
131 last_create_was_fallback_(false),
132 use_null_output_surface_(true) {}
134 using RenderWidgetCompositor::Initialize
;
136 scoped_ptr
<cc::OutputSurface
> CreateOutputSurface(bool fallback
) {
137 EXPECT_EQ(num_requests_since_last_success_
>
138 OUTPUT_SURFACE_RETRIES_BEFORE_FALLBACK
,
140 last_create_was_fallback_
= fallback
;
141 bool success
= num_failures_
>= num_failures_before_success_
;
143 scoped_ptr
<cc::TestWebGraphicsContext3D
> context
=
144 cc::TestWebGraphicsContext3D::Create();
145 // Image support required for synchronous compositing.
146 context
->set_support_image(true);
147 // Create delegating surface so that max_pending_frames = 1.
148 return cc::FakeOutputSurface::CreateDelegating3d(context
.Pass());
150 return use_null_output_surface_
152 : make_scoped_ptr(new cc::FailureOutputSurface(true));
155 // Force a new output surface to be created.
156 void SynchronousComposite() {
157 layer_tree_host()->DidLoseOutputSurface();
159 base::TimeTicks some_time
;
160 layer_tree_host()->Composite(some_time
);
163 void RequestNewOutputSurface() override
{
165 ++num_requests_since_last_success_
;
166 RenderWidgetCompositor::RequestNewOutputSurface();
169 void DidInitializeOutputSurface() override
{
170 if (last_create_was_fallback_
)
171 ++num_fallback_successes_
;
175 if (num_requests_
== expected_requests_
) {
178 num_requests_since_last_success_
= 0;
179 RenderWidgetCompositor::DidInitializeOutputSurface();
180 // Post the synchronous composite task so that it is not called
181 // reentrantly as a part of RequestNewOutputSurface.
182 base::ThreadTaskRunnerHandle::Get()->PostTask(
184 base::Bind(&RenderWidgetCompositorOutputSurface::SynchronousComposite
,
185 base::Unretained(this)));
189 void DidFailToInitializeOutputSurface() override
{
191 if (num_requests_
== expected_requests_
) {
196 RenderWidgetCompositor::DidFailToInitializeOutputSurface();
199 void SetUp(bool use_null_output_surface
,
200 int num_failures_before_success
,
201 int expected_successes
,
202 int expected_fallback_succeses
) {
203 use_null_output_surface_
= use_null_output_surface
;
204 num_failures_before_success_
= num_failures_before_success
;
205 expected_successes_
= expected_successes
;
206 expected_fallback_successes_
= expected_fallback_succeses
;
207 expected_requests_
= num_failures_before_success_
+ expected_successes_
+
208 expected_fallback_successes_
;
211 void EndTest() { base::MessageLoop::current()->Quit(); }
214 EXPECT_EQ(num_failures_before_success_
, num_failures_
);
215 EXPECT_EQ(expected_successes_
, num_successes_
);
216 EXPECT_EQ(expected_fallback_successes_
, num_fallback_successes_
);
217 EXPECT_EQ(expected_requests_
, num_requests_
);
221 int num_failures_before_success_
;
222 int expected_successes_
;
223 int expected_fallback_successes_
;
224 int expected_requests_
;
226 int num_requests_since_last_success_
;
228 int num_fallback_successes_
;
230 bool last_create_was_fallback_
;
231 bool use_null_output_surface_
;
233 DISALLOW_COPY_AND_ASSIGN(RenderWidgetCompositorOutputSurface
);
236 class RenderWidgetCompositorOutputSurfaceTest
: public testing::Test
{
238 RenderWidgetCompositorOutputSurfaceTest()
239 : compositor_deps_(new FakeCompositorDependencies
),
240 render_widget_(new RenderWidgetOutputSurface(compositor_deps_
.get())) {
241 render_widget_compositor_
.reset(new RenderWidgetCompositorOutputSurface(
242 render_widget_
.get(), compositor_deps_
.get()));
243 render_widget_compositor_
->Initialize();
244 render_widget_
->SetCompositor(render_widget_compositor_
.get());
247 void RunTest(bool use_null_output_surface
,
248 int num_failures_before_success
,
249 int expected_successes
,
250 int expected_fallback_succeses
) {
251 render_widget_compositor_
->SetUp(
252 use_null_output_surface
, num_failures_before_success
,
253 expected_successes
, expected_fallback_succeses
);
254 render_widget_compositor_
->StartCompositor();
255 base::ThreadTaskRunnerHandle::Get()->PostTask(
257 base::Bind(&RenderWidgetCompositorOutputSurface::SynchronousComposite
,
258 base::Unretained(render_widget_compositor_
.get())));
259 base::MessageLoop::current()->Run();
260 render_widget_compositor_
->AfterTest();
264 base::MessageLoop ye_olde_message_loope_
;
265 MockRenderThread render_thread_
;
266 scoped_ptr
<FakeCompositorDependencies
> compositor_deps_
;
267 scoped_refptr
<RenderWidgetOutputSurface
> render_widget_
;
268 scoped_ptr
<RenderWidgetCompositorOutputSurface
> render_widget_compositor_
;
271 DISALLOW_COPY_AND_ASSIGN(RenderWidgetCompositorOutputSurfaceTest
);
274 scoped_ptr
<cc::OutputSurface
> RenderWidgetOutputSurface::CreateOutputSurface(
276 return compositor_
->CreateOutputSurface(fallback
);
279 void RenderWidgetOutputSurface::SetCompositor(
280 RenderWidgetCompositorOutputSurface
* compositor
) {
281 compositor_
= compositor
;
284 TEST_F(RenderWidgetCompositorOutputSurfaceTest
, SucceedOnce
) {
285 RunTest(false, 0, 1, 0);
288 TEST_F(RenderWidgetCompositorOutputSurfaceTest
, SucceedTwice
) {
289 RunTest(false, 0, 2, 0);
292 TEST_F(RenderWidgetCompositorOutputSurfaceTest
, FailOnceNull
) {
294 RenderWidgetCompositor::OUTPUT_SURFACE_RETRIES_BEFORE_FALLBACK
>= 2,
295 "Adjust the values of this test if this fails");
296 RunTest(true, 1, 1, 0);
299 TEST_F(RenderWidgetCompositorOutputSurfaceTest
, FailOnceBind
) {
301 RenderWidgetCompositor::OUTPUT_SURFACE_RETRIES_BEFORE_FALLBACK
>= 2,
302 "Adjust the values of this test if this fails");
303 RunTest(false, 1, 1, 0);
306 TEST_F(RenderWidgetCompositorOutputSurfaceTest
, FallbackSuccessNull
) {
307 RunTest(true, RenderWidgetCompositor::OUTPUT_SURFACE_RETRIES_BEFORE_FALLBACK
,
311 TEST_F(RenderWidgetCompositorOutputSurfaceTest
, FallbackSuccessBind
) {
312 RunTest(false, RenderWidgetCompositor::OUTPUT_SURFACE_RETRIES_BEFORE_FALLBACK
,
316 TEST_F(RenderWidgetCompositorOutputSurfaceTest
, FallbackSuccessNormalSuccess
) {
317 // The first success is a fallback, but the next should not be a fallback.
318 RunTest(false, RenderWidgetCompositor::OUTPUT_SURFACE_RETRIES_BEFORE_FALLBACK
,
323 } // namespace content