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 "components/scheduler/renderer/renderer_scheduler.h"
11 #include "content/public/test/mock_render_thread.h"
12 #include "content/renderer/render_widget.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"
25 class MockWebWidget
: public blink::WebWidget
{
27 MOCK_METHOD1(beginFrame
, void(const blink::WebBeginFrameArgs
& args
));
30 class TestRenderWidget
: public RenderWidget
{
33 : RenderWidget(blink::WebPopupTypeNone
,
34 blink::WebScreenInfo(),
38 webwidget_
= &mock_webwidget_
;
41 MockWebWidget mock_webwidget_
;
44 ~TestRenderWidget() override
{ webwidget_
= NULL
; }
46 DISALLOW_COPY_AND_ASSIGN(TestRenderWidget
);
49 class RenderWidgetCompositorTest
: public testing::Test
{
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
{}
60 base::MessageLoop loop_
;
61 MockRenderThread render_thread_
;
62 scoped_refptr
<TestRenderWidget
> render_widget_
;
63 scoped_ptr
<FakeCompositorDependencies
> compositor_deps_
;
64 scoped_ptr
<RenderWidgetCompositor
> render_widget_compositor_
;
67 DISALLOW_COPY_AND_ASSIGN(RenderWidgetCompositorTest
);
70 TEST_F(RenderWidgetCompositorTest
, BeginMainFrame
) {
71 base::TimeTicks
frame_time(base::TimeTicks() +
72 base::TimeDelta::FromSeconds(1));
73 base::TimeTicks
deadline(base::TimeTicks() + base::TimeDelta::FromSeconds(2));
74 base::TimeDelta
interval(base::TimeDelta::FromSeconds(3));
75 cc::BeginFrameArgs
args(
76 cc::BeginFrameArgs::Create(BEGINFRAME_FROM_HERE
, frame_time
, deadline
,
77 interval
, cc::BeginFrameArgs::NORMAL
));
79 EXPECT_CALL(render_widget_
->mock_webwidget_
,
81 Field(&blink::WebBeginFrameArgs::lastFrameTimeMonotonic
, 1),
82 Field(&blink::WebBeginFrameArgs::deadline
, 2),
83 Field(&blink::WebBeginFrameArgs::interval
, 3))));
85 render_widget_compositor_
->BeginMainFrame(args
);
88 class RenderWidgetCompositorOutputSurface
;
90 class RenderWidgetOutputSurface
: public TestRenderWidget
{
92 RenderWidgetOutputSurface() : compositor_(NULL
) {}
93 void SetCompositor(RenderWidgetCompositorOutputSurface
* compositor
);
95 scoped_ptr
<cc::OutputSurface
> CreateOutputSurface(bool fallback
) override
;
98 ~RenderWidgetOutputSurface() override
{}
101 RenderWidgetCompositorOutputSurface
* compositor_
;
103 DISALLOW_COPY_AND_ASSIGN(RenderWidgetOutputSurface
);
106 // Verify that failing to create an output surface will cause the compositor
107 // to attempt to repeatedly create another output surface. After enough
108 // failures, verify that it attempts to create a fallback output surface.
109 // The use null output surface parameter allows testing whether failures
110 // from RenderWidget (couldn't create an output surface) vs failures from
111 // the compositor (couldn't bind the output surface) are handled identically.
112 class RenderWidgetCompositorOutputSurface
: public RenderWidgetCompositor
{
114 RenderWidgetCompositorOutputSurface(RenderWidget
* widget
,
115 CompositorDependencies
* compositor_deps
)
116 : RenderWidgetCompositor(widget
, compositor_deps
),
117 num_failures_before_success_(0),
118 expected_successes_(0),
119 expected_fallback_successes_(0),
120 expected_requests_(0),
122 num_requests_since_last_success_(0),
124 num_fallback_successes_(0),
126 last_create_was_fallback_(false),
127 use_null_output_surface_(true) {}
129 using RenderWidgetCompositor::Initialize
;
131 scoped_ptr
<cc::OutputSurface
> CreateOutputSurface(bool fallback
) {
132 EXPECT_EQ(num_requests_since_last_success_
>
133 OUTPUT_SURFACE_RETRIES_BEFORE_FALLBACK
,
135 last_create_was_fallback_
= fallback
;
136 bool success
= num_failures_
>= num_failures_before_success_
;
138 scoped_ptr
<cc::TestWebGraphicsContext3D
> context
=
139 cc::TestWebGraphicsContext3D::Create();
140 // Image support required for synchronous compositing.
141 context
->set_support_image(true);
142 return cc::FakeOutputSurface::Create3d(context
.Pass());
144 return use_null_output_surface_
146 : make_scoped_ptr(new cc::FailureOutputSurface(false));
149 // Force a new output surface to be created.
150 void SynchronousComposite() {
151 layer_tree_host()->DidLoseOutputSurface();
153 base::TimeTicks some_time
;
154 layer_tree_host()->Composite(some_time
);
157 void RequestNewOutputSurface() override
{
159 ++num_requests_since_last_success_
;
160 RenderWidgetCompositor::RequestNewOutputSurface();
163 void DidInitializeOutputSurface() override
{
164 if (last_create_was_fallback_
)
165 ++num_fallback_successes_
;
169 if (num_requests_
== expected_requests_
) {
172 num_requests_since_last_success_
= 0;
173 RenderWidgetCompositor::DidInitializeOutputSurface();
174 // Post the synchronous composite task so that it is not called
175 // reentrantly as a part of RequestNewOutputSurface.
176 base::MessageLoop::current()->PostTask(
178 base::Bind(&RenderWidgetCompositorOutputSurface::SynchronousComposite
,
179 base::Unretained(this)));
183 void DidFailToInitializeOutputSurface() override
{
185 if (num_requests_
== expected_requests_
) {
190 RenderWidgetCompositor::DidFailToInitializeOutputSurface();
193 void SetUp(bool use_null_output_surface
,
194 int num_failures_before_success
,
195 int expected_successes
,
196 int expected_fallback_succeses
) {
197 use_null_output_surface_
= use_null_output_surface
;
198 num_failures_before_success_
= num_failures_before_success
;
199 expected_successes_
= expected_successes
;
200 expected_fallback_successes_
= expected_fallback_succeses
;
201 expected_requests_
= num_failures_before_success_
+ expected_successes_
+
202 expected_fallback_successes_
;
205 void EndTest() { base::MessageLoop::current()->Quit(); }
208 EXPECT_EQ(num_failures_before_success_
, num_failures_
);
209 EXPECT_EQ(expected_successes_
, num_successes_
);
210 EXPECT_EQ(expected_fallback_successes_
, num_fallback_successes_
);
211 EXPECT_EQ(expected_requests_
, num_requests_
);
215 int num_failures_before_success_
;
216 int expected_successes_
;
217 int expected_fallback_successes_
;
218 int expected_requests_
;
220 int num_requests_since_last_success_
;
222 int num_fallback_successes_
;
224 bool last_create_was_fallback_
;
225 bool use_null_output_surface_
;
227 DISALLOW_COPY_AND_ASSIGN(RenderWidgetCompositorOutputSurface
);
230 class RenderWidgetCompositorOutputSurfaceTest
: public testing::Test
{
232 RenderWidgetCompositorOutputSurfaceTest()
233 : render_widget_(make_scoped_refptr(new RenderWidgetOutputSurface
)),
234 compositor_deps_(make_scoped_ptr(new FakeCompositorDependencies
)) {
235 // Required in order to call the synchronous LayerTreeHost::Composite.
236 compositor_deps_
->set_use_single_thread_scheduler(false);
237 render_widget_compositor_
.reset(new RenderWidgetCompositorOutputSurface(
238 render_widget_
.get(), compositor_deps_
.get()));
239 render_widget_compositor_
->Initialize();
240 render_widget_
->SetCompositor(render_widget_compositor_
.get());
243 void RunTest(bool use_null_output_surface
,
244 int num_failures_before_success
,
245 int expected_successes
,
246 int expected_fallback_succeses
) {
247 render_widget_compositor_
->SetUp(
248 use_null_output_surface
, num_failures_before_success
,
249 expected_successes
, expected_fallback_succeses
);
250 render_widget_compositor_
->StartCompositor();
251 base::MessageLoop::current()->PostTask(
253 base::Bind(&RenderWidgetCompositorOutputSurface::SynchronousComposite
,
254 base::Unretained(render_widget_compositor_
.get())));
255 base::MessageLoop::current()->Run();
256 render_widget_compositor_
->AfterTest();
260 base::MessageLoop ye_olde_message_loope_
;
261 MockRenderThread render_thread_
;
262 scoped_refptr
<RenderWidgetOutputSurface
> render_widget_
;
263 scoped_ptr
<FakeCompositorDependencies
> compositor_deps_
;
264 scoped_ptr
<RenderWidgetCompositorOutputSurface
> render_widget_compositor_
;
267 DISALLOW_COPY_AND_ASSIGN(RenderWidgetCompositorOutputSurfaceTest
);
270 scoped_ptr
<cc::OutputSurface
> RenderWidgetOutputSurface::CreateOutputSurface(
272 return compositor_
->CreateOutputSurface(fallback
);
275 void RenderWidgetOutputSurface::SetCompositor(
276 RenderWidgetCompositorOutputSurface
* compositor
) {
277 compositor_
= compositor
;
280 TEST_F(RenderWidgetCompositorOutputSurfaceTest
, SucceedOnce
) {
281 RunTest(false, 0, 1, 0);
284 TEST_F(RenderWidgetCompositorOutputSurfaceTest
, SucceedTwice
) {
285 RunTest(false, 0, 2, 0);
288 TEST_F(RenderWidgetCompositorOutputSurfaceTest
, FailOnceNull
) {
290 RenderWidgetCompositor::OUTPUT_SURFACE_RETRIES_BEFORE_FALLBACK
>= 2,
291 "Adjust the values of this test if this fails");
292 RunTest(true, 1, 1, 0);
295 TEST_F(RenderWidgetCompositorOutputSurfaceTest
, FailOnceBind
) {
297 RenderWidgetCompositor::OUTPUT_SURFACE_RETRIES_BEFORE_FALLBACK
>= 2,
298 "Adjust the values of this test if this fails");
299 RunTest(false, 1, 1, 0);
302 TEST_F(RenderWidgetCompositorOutputSurfaceTest
, FallbackSuccessNull
) {
303 RunTest(true, RenderWidgetCompositor::OUTPUT_SURFACE_RETRIES_BEFORE_FALLBACK
,
307 TEST_F(RenderWidgetCompositorOutputSurfaceTest
, FallbackSuccessBind
) {
308 RunTest(false, RenderWidgetCompositor::OUTPUT_SURFACE_RETRIES_BEFORE_FALLBACK
,
312 TEST_F(RenderWidgetCompositorOutputSurfaceTest
, FallbackSuccessNormalSuccess
) {
313 // The first success is a fallback, but the next should not be a fallback.
314 RunTest(false, RenderWidgetCompositor::OUTPUT_SURFACE_RETRIES_BEFORE_FALLBACK
,
319 } // namespace content