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 return cc::FakeOutputSurface::Create3d(context
.Pass());
147 return use_null_output_surface_
149 : make_scoped_ptr(new cc::FailureOutputSurface(false));
152 // Force a new output surface to be created.
153 void SynchronousComposite() {
154 layer_tree_host()->DidLoseOutputSurface();
156 base::TimeTicks some_time
;
157 layer_tree_host()->Composite(some_time
);
160 void RequestNewOutputSurface() override
{
162 ++num_requests_since_last_success_
;
163 RenderWidgetCompositor::RequestNewOutputSurface();
166 void DidInitializeOutputSurface() override
{
167 if (last_create_was_fallback_
)
168 ++num_fallback_successes_
;
172 if (num_requests_
== expected_requests_
) {
175 num_requests_since_last_success_
= 0;
176 RenderWidgetCompositor::DidInitializeOutputSurface();
177 // Post the synchronous composite task so that it is not called
178 // reentrantly as a part of RequestNewOutputSurface.
179 base::ThreadTaskRunnerHandle::Get()->PostTask(
181 base::Bind(&RenderWidgetCompositorOutputSurface::SynchronousComposite
,
182 base::Unretained(this)));
186 void DidFailToInitializeOutputSurface() override
{
188 if (num_requests_
== expected_requests_
) {
193 RenderWidgetCompositor::DidFailToInitializeOutputSurface();
196 void SetUp(bool use_null_output_surface
,
197 int num_failures_before_success
,
198 int expected_successes
,
199 int expected_fallback_succeses
) {
200 use_null_output_surface_
= use_null_output_surface
;
201 num_failures_before_success_
= num_failures_before_success
;
202 expected_successes_
= expected_successes
;
203 expected_fallback_successes_
= expected_fallback_succeses
;
204 expected_requests_
= num_failures_before_success_
+ expected_successes_
+
205 expected_fallback_successes_
;
208 void EndTest() { base::MessageLoop::current()->Quit(); }
211 EXPECT_EQ(num_failures_before_success_
, num_failures_
);
212 EXPECT_EQ(expected_successes_
, num_successes_
);
213 EXPECT_EQ(expected_fallback_successes_
, num_fallback_successes_
);
214 EXPECT_EQ(expected_requests_
, num_requests_
);
218 int num_failures_before_success_
;
219 int expected_successes_
;
220 int expected_fallback_successes_
;
221 int expected_requests_
;
223 int num_requests_since_last_success_
;
225 int num_fallback_successes_
;
227 bool last_create_was_fallback_
;
228 bool use_null_output_surface_
;
230 DISALLOW_COPY_AND_ASSIGN(RenderWidgetCompositorOutputSurface
);
233 class RenderWidgetCompositorOutputSurfaceTest
: public testing::Test
{
235 RenderWidgetCompositorOutputSurfaceTest()
236 : render_widget_(make_scoped_refptr(new RenderWidgetOutputSurface
)),
237 compositor_deps_(make_scoped_ptr(new FakeCompositorDependencies
)) {
238 render_widget_compositor_
.reset(new RenderWidgetCompositorOutputSurface(
239 render_widget_
.get(), compositor_deps_
.get()));
240 render_widget_compositor_
->Initialize();
241 render_widget_
->SetCompositor(render_widget_compositor_
.get());
244 void RunTest(bool use_null_output_surface
,
245 int num_failures_before_success
,
246 int expected_successes
,
247 int expected_fallback_succeses
) {
248 render_widget_compositor_
->SetUp(
249 use_null_output_surface
, num_failures_before_success
,
250 expected_successes
, expected_fallback_succeses
);
251 render_widget_compositor_
->StartCompositor();
252 base::ThreadTaskRunnerHandle::Get()->PostTask(
254 base::Bind(&RenderWidgetCompositorOutputSurface::SynchronousComposite
,
255 base::Unretained(render_widget_compositor_
.get())));
256 base::MessageLoop::current()->Run();
257 render_widget_compositor_
->AfterTest();
261 base::MessageLoop ye_olde_message_loope_
;
262 MockRenderThread render_thread_
;
263 scoped_refptr
<RenderWidgetOutputSurface
> render_widget_
;
264 scoped_ptr
<FakeCompositorDependencies
> compositor_deps_
;
265 scoped_ptr
<RenderWidgetCompositorOutputSurface
> render_widget_compositor_
;
268 DISALLOW_COPY_AND_ASSIGN(RenderWidgetCompositorOutputSurfaceTest
);
271 scoped_ptr
<cc::OutputSurface
> RenderWidgetOutputSurface::CreateOutputSurface(
273 return compositor_
->CreateOutputSurface(fallback
);
276 void RenderWidgetOutputSurface::SetCompositor(
277 RenderWidgetCompositorOutputSurface
* compositor
) {
278 compositor_
= compositor
;
281 TEST_F(RenderWidgetCompositorOutputSurfaceTest
, SucceedOnce
) {
282 RunTest(false, 0, 1, 0);
285 TEST_F(RenderWidgetCompositorOutputSurfaceTest
, SucceedTwice
) {
286 RunTest(false, 0, 2, 0);
289 TEST_F(RenderWidgetCompositorOutputSurfaceTest
, FailOnceNull
) {
291 RenderWidgetCompositor::OUTPUT_SURFACE_RETRIES_BEFORE_FALLBACK
>= 2,
292 "Adjust the values of this test if this fails");
293 RunTest(true, 1, 1, 0);
296 TEST_F(RenderWidgetCompositorOutputSurfaceTest
, FailOnceBind
) {
298 RenderWidgetCompositor::OUTPUT_SURFACE_RETRIES_BEFORE_FALLBACK
>= 2,
299 "Adjust the values of this test if this fails");
300 RunTest(false, 1, 1, 0);
303 TEST_F(RenderWidgetCompositorOutputSurfaceTest
, FallbackSuccessNull
) {
304 RunTest(true, RenderWidgetCompositor::OUTPUT_SURFACE_RETRIES_BEFORE_FALLBACK
,
308 TEST_F(RenderWidgetCompositorOutputSurfaceTest
, FallbackSuccessBind
) {
309 RunTest(false, RenderWidgetCompositor::OUTPUT_SURFACE_RETRIES_BEFORE_FALLBACK
,
313 TEST_F(RenderWidgetCompositorOutputSurfaceTest
, FallbackSuccessNormalSuccess
) {
314 // The first success is a fallback, but the next should not be a fallback.
315 RunTest(false, RenderWidgetCompositor::OUTPUT_SURFACE_RETRIES_BEFORE_FALLBACK
,
320 } // namespace content