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"
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 MockRenderThread render_thread_
;
61 scoped_refptr
<TestRenderWidget
> render_widget_
;
62 scoped_ptr
<FakeCompositorDependencies
> compositor_deps_
;
63 scoped_ptr
<RenderWidgetCompositor
> render_widget_compositor_
;
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_
,
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
{
91 RenderWidgetOutputSurface() : compositor_(NULL
) {}
92 void SetCompositor(RenderWidgetCompositorOutputSurface
* compositor
);
94 scoped_ptr
<cc::OutputSurface
> CreateOutputSurface(bool fallback
) override
;
97 ~RenderWidgetOutputSurface() override
{}
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
{
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),
121 num_requests_since_last_success_(0),
123 num_fallback_successes_(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
,
134 last_create_was_fallback_
= fallback
;
135 bool success
= num_failures_
>= num_failures_before_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_
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
{
158 ++num_requests_since_last_success_
;
159 RenderWidgetCompositor::RequestNewOutputSurface();
162 void DidInitializeOutputSurface() override
{
163 if (last_create_was_fallback_
)
164 ++num_fallback_successes_
;
168 if (num_requests_
== expected_requests_
) {
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(
177 base::Bind(&RenderWidgetCompositorOutputSurface::SynchronousComposite
,
178 base::Unretained(this)));
182 void DidFailToInitializeOutputSurface() override
{
184 if (num_requests_
== expected_requests_
) {
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(); }
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_
);
214 int num_failures_before_success_
;
215 int expected_successes_
;
216 int expected_fallback_successes_
;
217 int expected_requests_
;
219 int num_requests_since_last_success_
;
221 int num_fallback_successes_
;
223 bool last_create_was_fallback_
;
224 bool use_null_output_surface_
;
226 DISALLOW_COPY_AND_ASSIGN(RenderWidgetCompositorOutputSurface
);
229 class RenderWidgetCompositorOutputSurfaceTest
: public testing::Test
{
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(
252 base::Bind(&RenderWidgetCompositorOutputSurface::SynchronousComposite
,
253 base::Unretained(render_widget_compositor_
.get())));
254 base::MessageLoop::current()->Run();
255 render_widget_compositor_
->AfterTest();
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_
;
266 DISALLOW_COPY_AND_ASSIGN(RenderWidgetCompositorOutputSurfaceTest
);
269 scoped_ptr
<cc::OutputSurface
> RenderWidgetOutputSurface::CreateOutputSurface(
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
) {
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
) {
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
,
306 TEST_F(RenderWidgetCompositorOutputSurfaceTest
, FallbackSuccessBind
) {
307 RunTest(false, RenderWidgetCompositor::OUTPUT_SURFACE_RETRIES_BEFORE_FALLBACK
,
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
,
318 } // namespace content