1 // Copyright 2015 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 "base/test/null_task_runner.h"
6 #include "cc/output/compositor_frame.h"
7 #include "cc/output/copy_output_result.h"
8 #include "cc/output/delegated_frame_data.h"
9 #include "cc/quads/render_pass.h"
10 #include "cc/resources/shared_bitmap_manager.h"
11 #include "cc/surfaces/display.h"
12 #include "cc/surfaces/display_client.h"
13 #include "cc/surfaces/surface.h"
14 #include "cc/surfaces/surface_factory.h"
15 #include "cc/surfaces/surface_factory_client.h"
16 #include "cc/surfaces/surface_id_allocator.h"
17 #include "cc/surfaces/surface_manager.h"
18 #include "cc/test/fake_output_surface.h"
19 #include "cc/test/scheduler_test_common.h"
20 #include "cc/test/test_shared_bitmap_manager.h"
21 #include "testing/gmock/include/gmock/gmock.h"
22 #include "testing/gtest/include/gtest/gtest.h"
24 using testing::AnyNumber
;
29 class EmptySurfaceFactoryClient
: public SurfaceFactoryClient
{
31 void ReturnResources(const ReturnedResourceArray
& resources
) override
{}
34 class DisplayTest
: public testing::Test
{
36 DisplayTest() : factory_(&manager_
, &empty_client_
) {}
39 void SetUpContext(scoped_ptr
<TestWebGraphicsContext3D
> context
) {
41 output_surface_
= FakeOutputSurface::Create3d(
42 TestContextProvider::Create(context
.Pass()));
44 output_surface_
= FakeOutputSurface::CreateSoftware(
45 make_scoped_ptr(new SoftwareOutputDevice
));
47 shared_bitmap_manager_
.reset(new TestSharedBitmapManager
);
48 output_surface_ptr_
= output_surface_
.get();
51 void SubmitFrame(RenderPassList
* pass_list
, SurfaceId surface_id
) {
52 scoped_ptr
<DelegatedFrameData
> frame_data(new DelegatedFrameData
);
53 pass_list
->swap(frame_data
->render_pass_list
);
55 scoped_ptr
<CompositorFrame
> frame(new CompositorFrame
);
56 frame
->delegated_frame_data
= frame_data
.Pass();
58 factory_
.SubmitFrame(surface_id
, frame
.Pass(),
59 SurfaceFactory::DrawCallback());
62 SurfaceManager manager_
;
63 EmptySurfaceFactoryClient empty_client_
;
64 SurfaceFactory factory_
;
65 scoped_ptr
<FakeOutputSurface
> output_surface_
;
66 FakeOutputSurface
* output_surface_ptr_
;
67 FakeBeginFrameSource fake_begin_frame_source_
;
68 scoped_ptr
<SharedBitmapManager
> shared_bitmap_manager_
;
71 class TestDisplayClient
: public DisplayClient
{
73 TestDisplayClient() {}
74 ~TestDisplayClient() override
{}
76 void CommitVSyncParameters(base::TimeTicks timebase
,
77 base::TimeDelta interval
) override
{}
78 void OutputSurfaceLost() override
{}
79 void SetMemoryPolicy(const ManagedMemoryPolicy
& policy
) override
{}
82 class TestDisplayScheduler
: public DisplayScheduler
{
84 TestDisplayScheduler(DisplaySchedulerClient
* client
,
85 BeginFrameSource
* begin_frame_source
)
86 : DisplayScheduler(client
,
88 make_scoped_refptr(new base::NullTaskRunner
),
91 entire_display_damaged(false),
94 ~TestDisplayScheduler() override
{}
96 void EntireDisplayDamaged(SurfaceId root_surface_id
) override
{
97 entire_display_damaged
= true;
100 void SurfaceDamaged(SurfaceId surface_id
) override
{
105 void DidSwapBuffers() override
{ swapped
= true; }
107 void ResetDamageForTest() {
109 entire_display_damaged
= false;
113 bool entire_display_damaged
;
117 void CopyCallback(bool* called
, scoped_ptr
<CopyOutputResult
> result
) {
121 // Check that frame is damaged and swapped only under correct conditions.
122 TEST_F(DisplayTest
, DisplayDamaged
) {
123 SetUpContext(nullptr);
124 TestDisplayClient client
;
125 RendererSettings settings
;
126 settings
.partial_swap_enabled
= true;
127 settings
.finish_rendering_on_resize
= true;
128 Display
display(&client
, &manager_
, shared_bitmap_manager_
.get(), nullptr,
131 TestDisplayScheduler
scheduler(&display
, &fake_begin_frame_source_
);
132 display
.Initialize(output_surface_
.Pass(), &scheduler
);
134 SurfaceId
surface_id(7u);
135 EXPECT_FALSE(scheduler
.damaged
);
136 EXPECT_FALSE(scheduler
.entire_display_damaged
);
137 display
.SetSurfaceId(surface_id
, 1.f
);
138 EXPECT_FALSE(scheduler
.damaged
);
139 EXPECT_TRUE(scheduler
.entire_display_damaged
);
141 scheduler
.ResetDamageForTest();
142 display
.Resize(gfx::Size(100, 100));
143 EXPECT_FALSE(scheduler
.damaged
);
144 EXPECT_TRUE(scheduler
.entire_display_damaged
);
146 factory_
.Create(surface_id
);
148 // First draw from surface should have full damage.
149 RenderPassList pass_list
;
150 scoped_ptr
<RenderPass
> pass
= RenderPass::Create();
151 pass
->output_rect
= gfx::Rect(0, 0, 100, 100);
152 pass
->damage_rect
= gfx::Rect(10, 10, 1, 1);
153 pass
->id
= RenderPassId(1, 1);
154 pass_list
.push_back(pass
.Pass());
156 scheduler
.ResetDamageForTest();
157 SubmitFrame(&pass_list
, surface_id
);
158 EXPECT_TRUE(scheduler
.damaged
);
159 EXPECT_FALSE(scheduler
.entire_display_damaged
);
161 EXPECT_FALSE(scheduler
.swapped
);
162 EXPECT_EQ(0u, output_surface_ptr_
->num_sent_frames());
163 display
.DrawAndSwap();
164 EXPECT_TRUE(scheduler
.swapped
);
165 EXPECT_EQ(1u, output_surface_ptr_
->num_sent_frames());
166 SoftwareFrameData
* software_data
=
167 output_surface_ptr_
->last_sent_frame().software_frame_data
.get();
168 ASSERT_NE(nullptr, software_data
);
169 EXPECT_EQ(gfx::Size(100, 100).ToString(), software_data
->size
.ToString());
170 EXPECT_EQ(gfx::Rect(0, 0, 100, 100).ToString(),
171 software_data
->damage_rect
.ToString());
174 // Only damaged portion should be swapped.
175 pass
= RenderPass::Create();
176 pass
->output_rect
= gfx::Rect(0, 0, 100, 100);
177 pass
->damage_rect
= gfx::Rect(10, 10, 1, 1);
178 pass
->id
= RenderPassId(1, 1);
180 pass_list
.push_back(pass
.Pass());
181 scheduler
.ResetDamageForTest();
182 SubmitFrame(&pass_list
, surface_id
);
183 EXPECT_TRUE(scheduler
.damaged
);
184 EXPECT_FALSE(scheduler
.entire_display_damaged
);
186 scheduler
.swapped
= false;
187 display
.DrawAndSwap();
188 EXPECT_TRUE(scheduler
.swapped
);
189 EXPECT_EQ(2u, output_surface_ptr_
->num_sent_frames());
191 output_surface_ptr_
->last_sent_frame().software_frame_data
.get();
192 ASSERT_NE(nullptr, software_data
);
193 EXPECT_EQ(gfx::Size(100, 100).ToString(), software_data
->size
.ToString());
194 EXPECT_EQ(gfx::Rect(10, 10, 1, 1).ToString(),
195 software_data
->damage_rect
.ToString());
199 // Pass has no damage so shouldn't be swapped.
200 pass
= RenderPass::Create();
201 pass
->output_rect
= gfx::Rect(0, 0, 100, 100);
202 pass
->damage_rect
= gfx::Rect(10, 10, 0, 0);
203 pass
->id
= RenderPassId(1, 1);
205 pass_list
.push_back(pass
.Pass());
206 scheduler
.ResetDamageForTest();
207 SubmitFrame(&pass_list
, surface_id
);
208 EXPECT_TRUE(scheduler
.damaged
);
209 EXPECT_FALSE(scheduler
.entire_display_damaged
);
211 scheduler
.swapped
= false;
212 display
.DrawAndSwap();
213 EXPECT_TRUE(scheduler
.swapped
);
214 EXPECT_EQ(2u, output_surface_ptr_
->num_sent_frames());
218 // Pass is wrong size so shouldn't be swapped.
219 pass
= RenderPass::Create();
220 pass
->output_rect
= gfx::Rect(0, 0, 99, 99);
221 pass
->damage_rect
= gfx::Rect(10, 10, 10, 10);
222 pass
->id
= RenderPassId(1, 1);
224 pass_list
.push_back(pass
.Pass());
225 scheduler
.ResetDamageForTest();
226 SubmitFrame(&pass_list
, surface_id
);
227 EXPECT_TRUE(scheduler
.damaged
);
228 EXPECT_FALSE(scheduler
.entire_display_damaged
);
230 scheduler
.swapped
= false;
231 display
.DrawAndSwap();
232 EXPECT_TRUE(scheduler
.swapped
);
233 EXPECT_EQ(2u, output_surface_ptr_
->num_sent_frames());
237 // Pass has copy output request so should be swapped.
238 pass
= RenderPass::Create();
239 pass
->output_rect
= gfx::Rect(0, 0, 100, 100);
240 pass
->damage_rect
= gfx::Rect(10, 10, 0, 0);
241 bool copy_called
= false;
242 pass
->copy_requests
.push_back(CopyOutputRequest::CreateRequest(
243 base::Bind(&CopyCallback
, ©_called
)));
244 pass
->id
= RenderPassId(1, 1);
246 pass_list
.push_back(pass
.Pass());
247 scheduler
.ResetDamageForTest();
248 SubmitFrame(&pass_list
, surface_id
);
249 EXPECT_TRUE(scheduler
.damaged
);
250 EXPECT_FALSE(scheduler
.entire_display_damaged
);
252 scheduler
.swapped
= false;
253 display
.DrawAndSwap();
254 EXPECT_TRUE(scheduler
.swapped
);
255 EXPECT_EQ(3u, output_surface_ptr_
->num_sent_frames());
256 EXPECT_TRUE(copy_called
);
259 // Pass has latency info so should be swapped.
261 pass
= RenderPass::Create();
262 pass
->output_rect
= gfx::Rect(0, 0, 100, 100);
263 pass
->damage_rect
= gfx::Rect(10, 10, 0, 0);
264 pass
->id
= RenderPassId(1, 1);
266 pass_list
.push_back(pass
.Pass());
267 scheduler
.ResetDamageForTest();
268 scoped_ptr
<DelegatedFrameData
> frame_data(new DelegatedFrameData
);
269 pass_list
.swap(frame_data
->render_pass_list
);
271 scoped_ptr
<CompositorFrame
> frame(new CompositorFrame
);
272 frame
->delegated_frame_data
= frame_data
.Pass();
273 frame
->metadata
.latency_info
.push_back(ui::LatencyInfo());
275 factory_
.SubmitFrame(surface_id
, frame
.Pass(),
276 SurfaceFactory::DrawCallback());
277 EXPECT_TRUE(scheduler
.damaged
);
278 EXPECT_FALSE(scheduler
.entire_display_damaged
);
280 scheduler
.swapped
= false;
281 display
.DrawAndSwap();
282 EXPECT_TRUE(scheduler
.swapped
);
283 EXPECT_EQ(4u, output_surface_ptr_
->num_sent_frames());
286 // Resize should cause a swap if no frame was swapped at the previous size.
288 scheduler
.swapped
= false;
289 display
.Resize(gfx::Size(200, 200));
290 EXPECT_FALSE(scheduler
.swapped
);
291 EXPECT_EQ(4u, output_surface_ptr_
->num_sent_frames());
293 pass
= RenderPass::Create();
294 pass
->output_rect
= gfx::Rect(0, 0, 200, 200);
295 pass
->damage_rect
= gfx::Rect(10, 10, 10, 10);
296 pass
->id
= RenderPassId(1, 1);
298 pass_list
.push_back(pass
.Pass());
299 scheduler
.ResetDamageForTest();
300 scoped_ptr
<DelegatedFrameData
> frame_data(new DelegatedFrameData
);
301 pass_list
.swap(frame_data
->render_pass_list
);
303 scoped_ptr
<CompositorFrame
> frame(new CompositorFrame
);
304 frame
->delegated_frame_data
= frame_data
.Pass();
306 factory_
.SubmitFrame(surface_id
, frame
.Pass(),
307 SurfaceFactory::DrawCallback());
308 EXPECT_TRUE(scheduler
.damaged
);
309 EXPECT_FALSE(scheduler
.entire_display_damaged
);
311 scheduler
.swapped
= false;
312 display
.Resize(gfx::Size(100, 100));
313 EXPECT_TRUE(scheduler
.swapped
);
314 EXPECT_EQ(5u, output_surface_ptr_
->num_sent_frames());
317 factory_
.Destroy(surface_id
);
320 class MockedContext
: public TestWebGraphicsContext3D
{
322 MOCK_METHOD0(shallowFinishCHROMIUM
, void());
325 TEST_F(DisplayTest
, Finish
) {
326 scoped_ptr
<MockedContext
> context(new MockedContext());
327 MockedContext
* context_ptr
= context
.get();
328 SetUpContext(context
.Pass());
330 EXPECT_CALL(*context_ptr
, shallowFinishCHROMIUM()).Times(0);
331 TestDisplayClient client
;
332 RendererSettings settings
;
333 settings
.partial_swap_enabled
= true;
334 settings
.finish_rendering_on_resize
= true;
335 Display
display(&client
, &manager_
, shared_bitmap_manager_
.get(), nullptr,
338 TestDisplayScheduler
scheduler(&display
, &fake_begin_frame_source_
);
339 display
.Initialize(output_surface_
.Pass(), &scheduler
);
341 SurfaceId
surface_id(7u);
342 display
.SetSurfaceId(surface_id
, 1.f
);
344 display
.Resize(gfx::Size(100, 100));
345 factory_
.Create(surface_id
);
348 RenderPassList pass_list
;
349 scoped_ptr
<RenderPass
> pass
= RenderPass::Create();
350 pass
->output_rect
= gfx::Rect(0, 0, 100, 100);
351 pass
->damage_rect
= gfx::Rect(10, 10, 1, 1);
352 pass
->id
= RenderPassId(1, 1);
353 pass_list
.push_back(pass
.Pass());
355 SubmitFrame(&pass_list
, surface_id
);
358 display
.DrawAndSwap();
360 // First resize and draw shouldn't finish.
361 testing::Mock::VerifyAndClearExpectations(context_ptr
);
363 EXPECT_CALL(*context_ptr
, shallowFinishCHROMIUM());
364 display
.Resize(gfx::Size(150, 150));
365 testing::Mock::VerifyAndClearExpectations(context_ptr
);
367 // Another resize without a swap doesn't need to finish.
368 EXPECT_CALL(*context_ptr
, shallowFinishCHROMIUM()).Times(0);
369 display
.Resize(gfx::Size(200, 200));
370 testing::Mock::VerifyAndClearExpectations(context_ptr
);
372 EXPECT_CALL(*context_ptr
, shallowFinishCHROMIUM()).Times(0);
374 RenderPassList pass_list
;
375 scoped_ptr
<RenderPass
> pass
= RenderPass::Create();
376 pass
->output_rect
= gfx::Rect(0, 0, 200, 200);
377 pass
->damage_rect
= gfx::Rect(10, 10, 1, 1);
378 pass
->id
= RenderPassId(1, 1);
379 pass_list
.push_back(pass
.Pass());
381 SubmitFrame(&pass_list
, surface_id
);
384 display
.DrawAndSwap();
386 testing::Mock::VerifyAndClearExpectations(context_ptr
);
388 EXPECT_CALL(*context_ptr
, shallowFinishCHROMIUM());
389 display
.Resize(gfx::Size(250, 250));
390 testing::Mock::VerifyAndClearExpectations(context_ptr
);
392 factory_
.Destroy(surface_id
);