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 SubmitCompositorFrame(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_
.SubmitCompositorFrame(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 SubmitCompositorFrame(&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 SubmitCompositorFrame(&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 SubmitCompositorFrame(&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 SubmitCompositorFrame(&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 // Previous frame wasn't swapped, so next swap should have full damage.
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 pass
->id
= RenderPassId(1, 1);
262 pass_list
.push_back(pass
.Pass());
263 scheduler
.ResetDamageForTest();
264 SubmitCompositorFrame(&pass_list
, surface_id
);
265 EXPECT_TRUE(scheduler
.damaged
);
266 EXPECT_FALSE(scheduler
.display_resized_
);
267 EXPECT_FALSE(scheduler
.has_new_root_surface
);
269 scheduler
.swapped
= false;
270 display
.DrawAndSwap();
271 EXPECT_TRUE(scheduler
.swapped
);
272 EXPECT_EQ(3u, output_surface_ptr_
->num_sent_frames());
273 EXPECT_EQ(gfx::Rect(0, 0, 100, 100),
274 software_output_device_
->damage_rect());
278 // Pass has copy output request so should be swapped.
279 pass
= RenderPass::Create();
280 pass
->output_rect
= gfx::Rect(0, 0, 100, 100);
281 pass
->damage_rect
= gfx::Rect(10, 10, 0, 0);
282 bool copy_called
= false;
283 pass
->copy_requests
.push_back(CopyOutputRequest::CreateRequest(
284 base::Bind(&CopyCallback
, ©_called
)));
285 pass
->id
= RenderPassId(1, 1);
287 pass_list
.push_back(pass
.Pass());
288 scheduler
.ResetDamageForTest();
289 SubmitCompositorFrame(&pass_list
, surface_id
);
290 EXPECT_TRUE(scheduler
.damaged
);
291 EXPECT_FALSE(scheduler
.display_resized_
);
292 EXPECT_FALSE(scheduler
.has_new_root_surface
);
294 scheduler
.swapped
= false;
295 display
.DrawAndSwap();
296 EXPECT_TRUE(scheduler
.swapped
);
297 EXPECT_EQ(4u, output_surface_ptr_
->num_sent_frames());
298 EXPECT_TRUE(copy_called
);
301 // Pass has latency info so should be swapped.
303 pass
= RenderPass::Create();
304 pass
->output_rect
= gfx::Rect(0, 0, 100, 100);
305 pass
->damage_rect
= gfx::Rect(10, 10, 0, 0);
306 pass
->id
= RenderPassId(1, 1);
308 pass_list
.push_back(pass
.Pass());
309 scheduler
.ResetDamageForTest();
310 scoped_ptr
<DelegatedFrameData
> frame_data(new DelegatedFrameData
);
311 pass_list
.swap(frame_data
->render_pass_list
);
313 scoped_ptr
<CompositorFrame
> frame(new CompositorFrame
);
314 frame
->delegated_frame_data
= frame_data
.Pass();
315 frame
->metadata
.latency_info
.push_back(ui::LatencyInfo());
317 factory_
.SubmitCompositorFrame(surface_id
, frame
.Pass(),
318 SurfaceFactory::DrawCallback());
319 EXPECT_TRUE(scheduler
.damaged
);
320 EXPECT_FALSE(scheduler
.display_resized_
);
321 EXPECT_FALSE(scheduler
.has_new_root_surface
);
323 scheduler
.swapped
= false;
324 display
.DrawAndSwap();
325 EXPECT_TRUE(scheduler
.swapped
);
326 EXPECT_EQ(5u, output_surface_ptr_
->num_sent_frames());
329 // Resize should cause a swap if no frame was swapped at the previous size.
331 scheduler
.swapped
= false;
332 display
.Resize(gfx::Size(200, 200));
333 EXPECT_FALSE(scheduler
.swapped
);
334 EXPECT_EQ(5u, output_surface_ptr_
->num_sent_frames());
336 pass
= RenderPass::Create();
337 pass
->output_rect
= gfx::Rect(0, 0, 200, 200);
338 pass
->damage_rect
= gfx::Rect(10, 10, 10, 10);
339 pass
->id
= RenderPassId(1, 1);
341 pass_list
.push_back(pass
.Pass());
342 scheduler
.ResetDamageForTest();
343 scoped_ptr
<DelegatedFrameData
> frame_data(new DelegatedFrameData
);
344 pass_list
.swap(frame_data
->render_pass_list
);
346 scoped_ptr
<CompositorFrame
> frame(new CompositorFrame
);
347 frame
->delegated_frame_data
= frame_data
.Pass();
349 factory_
.SubmitCompositorFrame(surface_id
, frame
.Pass(),
350 SurfaceFactory::DrawCallback());
351 EXPECT_TRUE(scheduler
.damaged
);
352 EXPECT_FALSE(scheduler
.display_resized_
);
353 EXPECT_FALSE(scheduler
.has_new_root_surface
);
355 scheduler
.swapped
= false;
356 display
.Resize(gfx::Size(100, 100));
357 EXPECT_TRUE(scheduler
.swapped
);
358 EXPECT_EQ(6u, output_surface_ptr_
->num_sent_frames());
361 factory_
.Destroy(surface_id
);
364 class MockedContext
: public TestWebGraphicsContext3D
{
366 MOCK_METHOD0(shallowFinishCHROMIUM
, void());
369 TEST_F(DisplayTest
, Finish
) {
370 scoped_ptr
<MockedContext
> context(new MockedContext());
371 MockedContext
* context_ptr
= context
.get();
372 SetUpContext(context
.Pass());
374 EXPECT_CALL(*context_ptr
, shallowFinishCHROMIUM()).Times(0);
375 TestDisplayClient client
;
376 RendererSettings settings
;
377 settings
.partial_swap_enabled
= true;
378 settings
.finish_rendering_on_resize
= true;
379 Display
display(&client
, &manager_
, shared_bitmap_manager_
.get(), nullptr,
382 TestDisplayScheduler
scheduler(&display
, &fake_begin_frame_source_
,
384 display
.Initialize(output_surface_
.Pass(), &scheduler
);
386 SurfaceId
surface_id(7u);
387 display
.SetSurfaceId(surface_id
, 1.f
);
389 display
.Resize(gfx::Size(100, 100));
390 factory_
.Create(surface_id
);
393 RenderPassList pass_list
;
394 scoped_ptr
<RenderPass
> pass
= RenderPass::Create();
395 pass
->output_rect
= gfx::Rect(0, 0, 100, 100);
396 pass
->damage_rect
= gfx::Rect(10, 10, 1, 1);
397 pass
->id
= RenderPassId(1, 1);
398 pass_list
.push_back(pass
.Pass());
400 SubmitCompositorFrame(&pass_list
, surface_id
);
403 display
.DrawAndSwap();
405 // First resize and draw shouldn't finish.
406 testing::Mock::VerifyAndClearExpectations(context_ptr
);
408 EXPECT_CALL(*context_ptr
, shallowFinishCHROMIUM());
409 display
.Resize(gfx::Size(150, 150));
410 testing::Mock::VerifyAndClearExpectations(context_ptr
);
412 // Another resize without a swap doesn't need to finish.
413 EXPECT_CALL(*context_ptr
, shallowFinishCHROMIUM()).Times(0);
414 display
.Resize(gfx::Size(200, 200));
415 testing::Mock::VerifyAndClearExpectations(context_ptr
);
417 EXPECT_CALL(*context_ptr
, shallowFinishCHROMIUM()).Times(0);
419 RenderPassList pass_list
;
420 scoped_ptr
<RenderPass
> pass
= RenderPass::Create();
421 pass
->output_rect
= gfx::Rect(0, 0, 200, 200);
422 pass
->damage_rect
= gfx::Rect(10, 10, 1, 1);
423 pass
->id
= RenderPassId(1, 1);
424 pass_list
.push_back(pass
.Pass());
426 SubmitCompositorFrame(&pass_list
, surface_id
);
429 display
.DrawAndSwap();
431 testing::Mock::VerifyAndClearExpectations(context_ptr
);
433 EXPECT_CALL(*context_ptr
, shallowFinishCHROMIUM());
434 display
.Resize(gfx::Size(250, 250));
435 testing::Mock::VerifyAndClearExpectations(context_ptr
);
437 factory_
.Destroy(surface_id
);