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 TestSoftwareOutputDevice
: public SoftwareOutputDevice
{
36 TestSoftwareOutputDevice() {}
38 gfx::Rect
damage_rect() const { return damage_rect_
; }
39 gfx::Size
viewport_pixel_size() const { return viewport_pixel_size_
; }
42 class DisplayTest
: public testing::Test
{
45 : factory_(&manager_
, &empty_client_
),
46 software_output_device_(nullptr),
47 task_runner_(new base::NullTaskRunner
) {}
50 void SetUpContext(scoped_ptr
<TestWebGraphicsContext3D
> context
) {
52 output_surface_
= FakeOutputSurface::Create3d(
53 TestContextProvider::Create(context
.Pass()));
55 scoped_ptr
<TestSoftwareOutputDevice
> output_device(
56 new TestSoftwareOutputDevice
);
57 software_output_device_
= output_device
.get();
58 output_surface_
= FakeOutputSurface::CreateSoftware(output_device
.Pass());
60 shared_bitmap_manager_
.reset(new TestSharedBitmapManager
);
61 output_surface_ptr_
= output_surface_
.get();
64 void SubmitFrame(RenderPassList
* pass_list
, SurfaceId surface_id
) {
65 scoped_ptr
<DelegatedFrameData
> frame_data(new DelegatedFrameData
);
66 pass_list
->swap(frame_data
->render_pass_list
);
68 scoped_ptr
<CompositorFrame
> frame(new CompositorFrame
);
69 frame
->delegated_frame_data
= frame_data
.Pass();
71 factory_
.SubmitFrame(surface_id
, frame
.Pass(),
72 SurfaceFactory::DrawCallback());
75 SurfaceManager manager_
;
76 EmptySurfaceFactoryClient empty_client_
;
77 SurfaceFactory factory_
;
78 TestSoftwareOutputDevice
* software_output_device_
;
79 scoped_ptr
<FakeOutputSurface
> output_surface_
;
80 FakeOutputSurface
* output_surface_ptr_
;
81 FakeBeginFrameSource fake_begin_frame_source_
;
82 scoped_refptr
<base::NullTaskRunner
> task_runner_
;
83 scoped_ptr
<SharedBitmapManager
> shared_bitmap_manager_
;
86 class TestDisplayClient
: public DisplayClient
{
88 TestDisplayClient() {}
89 ~TestDisplayClient() override
{}
91 void CommitVSyncParameters(base::TimeTicks timebase
,
92 base::TimeDelta interval
) override
{}
93 void OutputSurfaceLost() override
{}
94 void SetMemoryPolicy(const ManagedMemoryPolicy
& policy
) override
{}
97 class TestDisplayScheduler
: public DisplayScheduler
{
99 TestDisplayScheduler(DisplaySchedulerClient
* client
,
100 BeginFrameSource
* begin_frame_source
,
101 base::NullTaskRunner
* task_runner
)
102 : DisplayScheduler(client
, begin_frame_source
, task_runner
, 1),
104 display_resized_(false),
105 has_new_root_surface(false),
108 ~TestDisplayScheduler() override
{}
110 void DisplayResized() override
{ display_resized_
= true; }
112 void SetNewRootSurface(SurfaceId root_surface_id
) override
{
113 has_new_root_surface
= true;
116 void SurfaceDamaged(SurfaceId surface_id
) override
{
121 void DidSwapBuffers() override
{ swapped
= true; }
123 void ResetDamageForTest() {
125 display_resized_
= false;
126 has_new_root_surface
= false;
130 bool display_resized_
;
131 bool has_new_root_surface
;
135 void CopyCallback(bool* called
, scoped_ptr
<CopyOutputResult
> result
) {
139 // Check that frame is damaged and swapped only under correct conditions.
140 TEST_F(DisplayTest
, DisplayDamaged
) {
141 SetUpContext(nullptr);
142 TestDisplayClient client
;
143 RendererSettings settings
;
144 settings
.partial_swap_enabled
= true;
145 settings
.finish_rendering_on_resize
= true;
146 Display
display(&client
, &manager_
, shared_bitmap_manager_
.get(), nullptr,
149 TestDisplayScheduler
scheduler(&display
, &fake_begin_frame_source_
,
151 display
.Initialize(output_surface_
.Pass(), &scheduler
);
153 SurfaceId
surface_id(7u);
154 EXPECT_FALSE(scheduler
.damaged
);
155 EXPECT_FALSE(scheduler
.has_new_root_surface
);
156 display
.SetSurfaceId(surface_id
, 1.f
);
157 EXPECT_FALSE(scheduler
.damaged
);
158 EXPECT_FALSE(scheduler
.display_resized_
);
159 EXPECT_TRUE(scheduler
.has_new_root_surface
);
161 scheduler
.ResetDamageForTest();
162 display
.Resize(gfx::Size(100, 100));
163 EXPECT_FALSE(scheduler
.damaged
);
164 EXPECT_TRUE(scheduler
.display_resized_
);
165 EXPECT_FALSE(scheduler
.has_new_root_surface
);
167 factory_
.Create(surface_id
);
169 // First draw from surface should have full damage.
170 RenderPassList pass_list
;
171 scoped_ptr
<RenderPass
> pass
= RenderPass::Create();
172 pass
->output_rect
= gfx::Rect(0, 0, 100, 100);
173 pass
->damage_rect
= gfx::Rect(10, 10, 1, 1);
174 pass
->id
= RenderPassId(1, 1);
175 pass_list
.push_back(pass
.Pass());
177 scheduler
.ResetDamageForTest();
178 SubmitFrame(&pass_list
, surface_id
);
179 EXPECT_TRUE(scheduler
.damaged
);
180 EXPECT_FALSE(scheduler
.display_resized_
);
181 EXPECT_FALSE(scheduler
.has_new_root_surface
);
183 EXPECT_FALSE(scheduler
.swapped
);
184 EXPECT_EQ(0u, output_surface_ptr_
->num_sent_frames());
185 display
.DrawAndSwap();
186 EXPECT_TRUE(scheduler
.swapped
);
187 EXPECT_EQ(1u, output_surface_ptr_
->num_sent_frames());
188 EXPECT_EQ(gfx::Size(100, 100),
189 software_output_device_
->viewport_pixel_size());
190 EXPECT_EQ(gfx::Rect(0, 0, 100, 100), software_output_device_
->damage_rect());
193 // Only damaged portion should be swapped.
194 pass
= RenderPass::Create();
195 pass
->output_rect
= gfx::Rect(0, 0, 100, 100);
196 pass
->damage_rect
= gfx::Rect(10, 10, 1, 1);
197 pass
->id
= RenderPassId(1, 1);
199 pass_list
.push_back(pass
.Pass());
200 scheduler
.ResetDamageForTest();
201 SubmitFrame(&pass_list
, surface_id
);
202 EXPECT_TRUE(scheduler
.damaged
);
203 EXPECT_FALSE(scheduler
.display_resized_
);
204 EXPECT_FALSE(scheduler
.has_new_root_surface
);
206 scheduler
.swapped
= false;
207 display
.DrawAndSwap();
208 EXPECT_TRUE(scheduler
.swapped
);
209 EXPECT_EQ(2u, output_surface_ptr_
->num_sent_frames());
210 EXPECT_EQ(gfx::Size(100, 100),
211 software_output_device_
->viewport_pixel_size());
212 EXPECT_EQ(gfx::Rect(10, 10, 1, 1), software_output_device_
->damage_rect());
216 // Pass has no damage so shouldn't be swapped.
217 pass
= RenderPass::Create();
218 pass
->output_rect
= gfx::Rect(0, 0, 100, 100);
219 pass
->damage_rect
= gfx::Rect(10, 10, 0, 0);
220 pass
->id
= RenderPassId(1, 1);
222 pass_list
.push_back(pass
.Pass());
223 scheduler
.ResetDamageForTest();
224 SubmitFrame(&pass_list
, surface_id
);
225 EXPECT_TRUE(scheduler
.damaged
);
226 EXPECT_FALSE(scheduler
.display_resized_
);
227 EXPECT_FALSE(scheduler
.has_new_root_surface
);
229 scheduler
.swapped
= false;
230 display
.DrawAndSwap();
231 EXPECT_TRUE(scheduler
.swapped
);
232 EXPECT_EQ(2u, output_surface_ptr_
->num_sent_frames());
236 // Pass is wrong size so shouldn't be swapped.
237 pass
= RenderPass::Create();
238 pass
->output_rect
= gfx::Rect(0, 0, 99, 99);
239 pass
->damage_rect
= gfx::Rect(10, 10, 10, 10);
240 pass
->id
= RenderPassId(1, 1);
242 pass_list
.push_back(pass
.Pass());
243 scheduler
.ResetDamageForTest();
244 SubmitFrame(&pass_list
, surface_id
);
245 EXPECT_TRUE(scheduler
.damaged
);
246 EXPECT_FALSE(scheduler
.display_resized_
);
247 EXPECT_FALSE(scheduler
.has_new_root_surface
);
249 scheduler
.swapped
= false;
250 display
.DrawAndSwap();
251 EXPECT_TRUE(scheduler
.swapped
);
252 EXPECT_EQ(2u, output_surface_ptr_
->num_sent_frames());
256 // Pass has copy output request so should be swapped.
257 pass
= RenderPass::Create();
258 pass
->output_rect
= gfx::Rect(0, 0, 100, 100);
259 pass
->damage_rect
= gfx::Rect(10, 10, 0, 0);
260 bool copy_called
= false;
261 pass
->copy_requests
.push_back(CopyOutputRequest::CreateRequest(
262 base::Bind(&CopyCallback
, ©_called
)));
263 pass
->id
= RenderPassId(1, 1);
265 pass_list
.push_back(pass
.Pass());
266 scheduler
.ResetDamageForTest();
267 SubmitFrame(&pass_list
, surface_id
);
268 EXPECT_TRUE(scheduler
.damaged
);
269 EXPECT_FALSE(scheduler
.display_resized_
);
270 EXPECT_FALSE(scheduler
.has_new_root_surface
);
272 scheduler
.swapped
= false;
273 display
.DrawAndSwap();
274 EXPECT_TRUE(scheduler
.swapped
);
275 EXPECT_EQ(3u, output_surface_ptr_
->num_sent_frames());
276 EXPECT_TRUE(copy_called
);
279 // Pass has latency info so should be swapped.
281 pass
= RenderPass::Create();
282 pass
->output_rect
= gfx::Rect(0, 0, 100, 100);
283 pass
->damage_rect
= gfx::Rect(10, 10, 0, 0);
284 pass
->id
= RenderPassId(1, 1);
286 pass_list
.push_back(pass
.Pass());
287 scheduler
.ResetDamageForTest();
288 scoped_ptr
<DelegatedFrameData
> frame_data(new DelegatedFrameData
);
289 pass_list
.swap(frame_data
->render_pass_list
);
291 scoped_ptr
<CompositorFrame
> frame(new CompositorFrame
);
292 frame
->delegated_frame_data
= frame_data
.Pass();
293 frame
->metadata
.latency_info
.push_back(ui::LatencyInfo());
295 factory_
.SubmitFrame(surface_id
, frame
.Pass(),
296 SurfaceFactory::DrawCallback());
297 EXPECT_TRUE(scheduler
.damaged
);
298 EXPECT_FALSE(scheduler
.display_resized_
);
299 EXPECT_FALSE(scheduler
.has_new_root_surface
);
301 scheduler
.swapped
= false;
302 display
.DrawAndSwap();
303 EXPECT_TRUE(scheduler
.swapped
);
304 EXPECT_EQ(4u, output_surface_ptr_
->num_sent_frames());
307 // Resize should cause a swap if no frame was swapped at the previous size.
309 scheduler
.swapped
= false;
310 display
.Resize(gfx::Size(200, 200));
311 EXPECT_FALSE(scheduler
.swapped
);
312 EXPECT_EQ(4u, output_surface_ptr_
->num_sent_frames());
314 pass
= RenderPass::Create();
315 pass
->output_rect
= gfx::Rect(0, 0, 200, 200);
316 pass
->damage_rect
= gfx::Rect(10, 10, 10, 10);
317 pass
->id
= RenderPassId(1, 1);
319 pass_list
.push_back(pass
.Pass());
320 scheduler
.ResetDamageForTest();
321 scoped_ptr
<DelegatedFrameData
> frame_data(new DelegatedFrameData
);
322 pass_list
.swap(frame_data
->render_pass_list
);
324 scoped_ptr
<CompositorFrame
> frame(new CompositorFrame
);
325 frame
->delegated_frame_data
= frame_data
.Pass();
327 factory_
.SubmitFrame(surface_id
, frame
.Pass(),
328 SurfaceFactory::DrawCallback());
329 EXPECT_TRUE(scheduler
.damaged
);
330 EXPECT_FALSE(scheduler
.display_resized_
);
331 EXPECT_FALSE(scheduler
.has_new_root_surface
);
333 scheduler
.swapped
= false;
334 display
.Resize(gfx::Size(100, 100));
335 EXPECT_TRUE(scheduler
.swapped
);
336 EXPECT_EQ(5u, output_surface_ptr_
->num_sent_frames());
339 factory_
.Destroy(surface_id
);
342 class MockedContext
: public TestWebGraphicsContext3D
{
344 MOCK_METHOD0(shallowFinishCHROMIUM
, void());
347 TEST_F(DisplayTest
, Finish
) {
348 scoped_ptr
<MockedContext
> context(new MockedContext());
349 MockedContext
* context_ptr
= context
.get();
350 SetUpContext(context
.Pass());
352 EXPECT_CALL(*context_ptr
, shallowFinishCHROMIUM()).Times(0);
353 TestDisplayClient client
;
354 RendererSettings settings
;
355 settings
.partial_swap_enabled
= true;
356 settings
.finish_rendering_on_resize
= true;
357 Display
display(&client
, &manager_
, shared_bitmap_manager_
.get(), nullptr,
360 TestDisplayScheduler
scheduler(&display
, &fake_begin_frame_source_
,
362 display
.Initialize(output_surface_
.Pass(), &scheduler
);
364 SurfaceId
surface_id(7u);
365 display
.SetSurfaceId(surface_id
, 1.f
);
367 display
.Resize(gfx::Size(100, 100));
368 factory_
.Create(surface_id
);
371 RenderPassList pass_list
;
372 scoped_ptr
<RenderPass
> pass
= RenderPass::Create();
373 pass
->output_rect
= gfx::Rect(0, 0, 100, 100);
374 pass
->damage_rect
= gfx::Rect(10, 10, 1, 1);
375 pass
->id
= RenderPassId(1, 1);
376 pass_list
.push_back(pass
.Pass());
378 SubmitFrame(&pass_list
, surface_id
);
381 display
.DrawAndSwap();
383 // First resize and draw shouldn't finish.
384 testing::Mock::VerifyAndClearExpectations(context_ptr
);
386 EXPECT_CALL(*context_ptr
, shallowFinishCHROMIUM());
387 display
.Resize(gfx::Size(150, 150));
388 testing::Mock::VerifyAndClearExpectations(context_ptr
);
390 // Another resize without a swap doesn't need to finish.
391 EXPECT_CALL(*context_ptr
, shallowFinishCHROMIUM()).Times(0);
392 display
.Resize(gfx::Size(200, 200));
393 testing::Mock::VerifyAndClearExpectations(context_ptr
);
395 EXPECT_CALL(*context_ptr
, shallowFinishCHROMIUM()).Times(0);
397 RenderPassList pass_list
;
398 scoped_ptr
<RenderPass
> pass
= RenderPass::Create();
399 pass
->output_rect
= gfx::Rect(0, 0, 200, 200);
400 pass
->damage_rect
= gfx::Rect(10, 10, 1, 1);
401 pass
->id
= RenderPassId(1, 1);
402 pass_list
.push_back(pass
.Pass());
404 SubmitFrame(&pass_list
, surface_id
);
407 display
.DrawAndSwap();
409 testing::Mock::VerifyAndClearExpectations(context_ptr
);
411 EXPECT_CALL(*context_ptr
, shallowFinishCHROMIUM());
412 display
.Resize(gfx::Size(250, 250));
413 testing::Mock::VerifyAndClearExpectations(context_ptr
);
415 factory_
.Destroy(surface_id
);