1 // Copyright 2013 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 "cc/test/layer_tree_pixel_test.h"
7 #include "base/command_line.h"
8 #include "base/path_service.h"
9 #include "cc/base/switches.h"
10 #include "cc/layers/solid_color_layer.h"
11 #include "cc/layers/texture_layer.h"
12 #include "cc/output/copy_output_request.h"
13 #include "cc/output/copy_output_result.h"
14 #include "cc/output/direct_renderer.h"
15 #include "cc/resources/texture_mailbox.h"
16 #include "cc/test/paths.h"
17 #include "cc/test/pixel_comparator.h"
18 #include "cc/test/pixel_test_output_surface.h"
19 #include "cc/test/pixel_test_software_output_device.h"
20 #include "cc/test/pixel_test_utils.h"
21 #include "cc/test/test_in_process_context_provider.h"
22 #include "cc/trees/layer_tree_impl.h"
23 #include "gpu/command_buffer/client/gl_in_process_context.h"
24 #include "gpu/command_buffer/client/gles2_implementation.h"
26 using gpu::gles2::GLES2Interface
;
30 LayerTreePixelTest::LayerTreePixelTest()
31 : pixel_comparator_(new ExactPixelComparator(true)),
32 test_type_(PIXEL_TEST_GL
),
33 pending_texture_mailbox_callbacks_(0) {
36 LayerTreePixelTest::~LayerTreePixelTest() {}
38 scoped_ptr
<OutputSurface
> LayerTreePixelTest::CreateOutputSurface() {
39 gfx::Size
surface_expansion_size(40, 60);
40 scoped_ptr
<PixelTestOutputSurface
> output_surface
;
43 case PIXEL_TEST_SOFTWARE
: {
44 scoped_ptr
<PixelTestSoftwareOutputDevice
> software_output_device(
45 new PixelTestSoftwareOutputDevice
);
46 software_output_device
->set_surface_expansion_size(
47 surface_expansion_size
);
48 output_surface
= make_scoped_ptr(
49 new PixelTestOutputSurface(software_output_device
.Pass()));
53 bool flipped_output_surface
= false;
54 output_surface
= make_scoped_ptr(new PixelTestOutputSurface(
55 new TestInProcessContextProvider
, new TestInProcessContextProvider
,
56 flipped_output_surface
));
61 output_surface
->set_surface_expansion_size(surface_expansion_size
);
62 return output_surface
.Pass();
65 void LayerTreePixelTest::WillActivateTreeOnThread(LayerTreeHostImpl
* impl
) {
66 if (impl
->sync_tree()->source_frame_number() != 0)
69 DirectRenderer
* renderer
= static_cast<DirectRenderer
*>(impl
->renderer());
70 renderer
->SetEnlargePassTextureAmountForTesting(enlarge_texture_amount_
);
72 gfx::Rect viewport
= impl
->DeviceViewport();
73 // The viewport has a 0,0 origin without external influence.
74 EXPECT_EQ(gfx::Point().ToString(), viewport
.origin().ToString());
76 viewport
+= gfx::Vector2d(20, 10);
77 bool resourceless_software_draw
= false;
78 gfx::Transform identity
= gfx::Transform();
79 impl
->SetExternalDrawConstraints(identity
,
84 resourceless_software_draw
);
85 EXPECT_EQ(viewport
.ToString(), impl
->DeviceViewport().ToString());
88 scoped_ptr
<CopyOutputRequest
> LayerTreePixelTest::CreateCopyOutputRequest() {
89 return CopyOutputRequest::CreateBitmapRequest(
90 base::Bind(&LayerTreePixelTest::ReadbackResult
, base::Unretained(this)));
93 void LayerTreePixelTest::ReadbackResult(scoped_ptr
<CopyOutputResult
> result
) {
94 ASSERT_TRUE(result
->HasBitmap());
95 result_bitmap_
= result
->TakeBitmap().Pass();
99 void LayerTreePixelTest::BeginTest() {
100 Layer
* target
= readback_target_
? readback_target_
101 : layer_tree_host()->root_layer();
102 target
->RequestCopyOfOutput(CreateCopyOutputRequest().Pass());
103 PostSetNeedsCommitToMainThread();
106 void LayerTreePixelTest::AfterTest() {
107 base::FilePath test_data_dir
;
108 EXPECT_TRUE(PathService::Get(CCPaths::DIR_TEST_DATA
, &test_data_dir
));
109 base::FilePath ref_file_path
= test_data_dir
.Append(ref_file_
);
111 base::CommandLine
* cmd
= base::CommandLine::ForCurrentProcess();
112 if (cmd
->HasSwitch(switches::kCCRebaselinePixeltests
))
113 EXPECT_TRUE(WritePNGFile(*result_bitmap_
, ref_file_path
, true));
114 EXPECT_TRUE(MatchesPNGFile(*result_bitmap_
,
116 *pixel_comparator_
));
119 scoped_refptr
<SolidColorLayer
> LayerTreePixelTest::CreateSolidColorLayer(
120 const gfx::Rect
& rect
, SkColor color
) {
121 scoped_refptr
<SolidColorLayer
> layer
=
122 SolidColorLayer::Create(layer_settings());
123 layer
->SetIsDrawable(true);
124 layer
->SetBounds(rect
.size());
125 layer
->SetPosition(rect
.origin());
126 layer
->SetBackgroundColor(color
);
130 void LayerTreePixelTest::EndTest() {
131 // Drop TextureMailboxes on the main thread so that they can be cleaned up and
132 // the pending callbacks will fire.
133 for (size_t i
= 0; i
< texture_layers_
.size(); ++i
) {
134 texture_layers_
[i
]->SetTextureMailbox(TextureMailbox(), nullptr);
140 void LayerTreePixelTest::TryEndTest() {
143 if (pending_texture_mailbox_callbacks_
)
145 LayerTreeTest::EndTest();
148 scoped_refptr
<SolidColorLayer
> LayerTreePixelTest::
149 CreateSolidColorLayerWithBorder(
150 const gfx::Rect
& rect
, SkColor color
,
151 int border_width
, SkColor border_color
) {
152 scoped_refptr
<SolidColorLayer
> layer
= CreateSolidColorLayer(rect
, color
);
153 scoped_refptr
<SolidColorLayer
> border_top
= CreateSolidColorLayer(
154 gfx::Rect(0, 0, rect
.width(), border_width
), border_color
);
155 scoped_refptr
<SolidColorLayer
> border_left
= CreateSolidColorLayer(
159 rect
.height() - border_width
* 2),
161 scoped_refptr
<SolidColorLayer
> border_right
=
162 CreateSolidColorLayer(gfx::Rect(rect
.width() - border_width
,
165 rect
.height() - border_width
* 2),
167 scoped_refptr
<SolidColorLayer
> border_bottom
= CreateSolidColorLayer(
168 gfx::Rect(0, rect
.height() - border_width
, rect
.width(), border_width
),
170 layer
->AddChild(border_top
);
171 layer
->AddChild(border_left
);
172 layer
->AddChild(border_right
);
173 layer
->AddChild(border_bottom
);
177 scoped_refptr
<TextureLayer
> LayerTreePixelTest::CreateTextureLayer(
178 const gfx::Rect
& rect
, const SkBitmap
& bitmap
) {
179 scoped_refptr
<TextureLayer
> layer
=
180 TextureLayer::CreateForMailbox(layer_settings(), NULL
);
181 layer
->SetIsDrawable(true);
182 layer
->SetBounds(rect
.size());
183 layer
->SetPosition(rect
.origin());
185 TextureMailbox texture_mailbox
;
186 scoped_ptr
<SingleReleaseCallback
> release_callback
;
187 CopyBitmapToTextureMailboxAsTexture(
188 bitmap
, &texture_mailbox
, &release_callback
);
189 layer
->SetTextureMailbox(texture_mailbox
, release_callback
.Pass());
191 texture_layers_
.push_back(layer
);
192 pending_texture_mailbox_callbacks_
++;
196 void LayerTreePixelTest::RunPixelTest(
197 PixelTestType test_type
,
198 scoped_refptr
<Layer
> content_root
,
199 base::FilePath file_name
) {
200 test_type_
= test_type
;
201 content_root_
= content_root
;
202 readback_target_
= NULL
;
203 ref_file_
= file_name
;
204 bool threaded
= true;
205 RunTest(threaded
, false);
208 void LayerTreePixelTest::RunSingleThreadedPixelTest(
209 PixelTestType test_type
,
210 scoped_refptr
<Layer
> content_root
,
211 base::FilePath file_name
) {
212 test_type_
= test_type
;
213 content_root_
= content_root
;
214 readback_target_
= NULL
;
215 ref_file_
= file_name
;
216 bool threaded
= false;
217 RunTest(threaded
, false);
220 void LayerTreePixelTest::RunPixelTestWithReadbackTarget(
221 PixelTestType test_type
,
222 scoped_refptr
<Layer
> content_root
,
224 base::FilePath file_name
) {
225 test_type_
= test_type
;
226 content_root_
= content_root
;
227 readback_target_
= target
;
228 ref_file_
= file_name
;
229 RunTest(true, false);
232 void LayerTreePixelTest::SetupTree() {
233 scoped_refptr
<Layer
> root
= Layer::Create(layer_settings());
234 root
->SetBounds(content_root_
->bounds());
235 root
->AddChild(content_root_
);
236 layer_tree_host()->SetRootLayer(root
);
237 LayerTreeTest::SetupTree();
240 scoped_ptr
<SkBitmap
> LayerTreePixelTest::CopyTextureMailboxToBitmap(
241 const gfx::Size
& size
,
242 const TextureMailbox
& texture_mailbox
) {
243 DCHECK(texture_mailbox
.IsTexture());
244 if (!texture_mailbox
.IsTexture())
247 scoped_ptr
<gpu::GLInProcessContext
> context
= CreateTestInProcessContext();
248 GLES2Interface
* gl
= context
->GetImplementation();
250 if (texture_mailbox
.sync_point())
251 gl
->WaitSyncPointCHROMIUM(texture_mailbox
.sync_point());
253 GLuint texture_id
= 0;
254 gl
->GenTextures(1, &texture_id
);
255 gl
->BindTexture(GL_TEXTURE_2D
, texture_id
);
256 gl
->TexParameteri(GL_TEXTURE_2D
, GL_TEXTURE_MIN_FILTER
, GL_LINEAR
);
257 gl
->TexParameteri(GL_TEXTURE_2D
, GL_TEXTURE_MAG_FILTER
, GL_LINEAR
);
258 gl
->TexParameteri(GL_TEXTURE_2D
, GL_TEXTURE_WRAP_S
, GL_CLAMP_TO_EDGE
);
259 gl
->TexParameteri(GL_TEXTURE_2D
, GL_TEXTURE_WRAP_T
, GL_CLAMP_TO_EDGE
);
260 gl
->ConsumeTextureCHROMIUM(texture_mailbox
.target(), texture_mailbox
.name());
261 gl
->BindTexture(GL_TEXTURE_2D
, 0);
264 gl
->GenFramebuffers(1, &fbo
);
265 gl
->BindFramebuffer(GL_FRAMEBUFFER
, fbo
);
266 gl
->FramebufferTexture2D(
267 GL_FRAMEBUFFER
, GL_COLOR_ATTACHMENT0
, GL_TEXTURE_2D
, texture_id
, 0);
268 EXPECT_EQ(static_cast<unsigned>(GL_FRAMEBUFFER_COMPLETE
),
269 gl
->CheckFramebufferStatus(GL_FRAMEBUFFER
));
271 scoped_ptr
<uint8
[]> pixels(new uint8
[size
.GetArea() * 4]);
280 gl
->DeleteFramebuffers(1, &fbo
);
281 gl
->DeleteTextures(1, &texture_id
);
283 scoped_ptr
<SkBitmap
> bitmap(new SkBitmap
);
284 bitmap
->allocN32Pixels(size
.width(), size
.height());
286 uint8
* out_pixels
= static_cast<uint8
*>(bitmap
->getPixels());
288 size_t row_bytes
= size
.width() * 4;
289 size_t total_bytes
= size
.height() * row_bytes
;
290 for (size_t dest_y
= 0; dest_y
< total_bytes
; dest_y
+= row_bytes
) {
292 size_t src_y
= total_bytes
- dest_y
- row_bytes
;
293 // Swizzle OpenGL -> Skia byte order.
294 for (size_t x
= 0; x
< row_bytes
; x
+= 4) {
295 out_pixels
[dest_y
+ x
+ SK_R32_SHIFT
/8] = pixels
.get()[src_y
+ x
+ 0];
296 out_pixels
[dest_y
+ x
+ SK_G32_SHIFT
/8] = pixels
.get()[src_y
+ x
+ 1];
297 out_pixels
[dest_y
+ x
+ SK_B32_SHIFT
/8] = pixels
.get()[src_y
+ x
+ 2];
298 out_pixels
[dest_y
+ x
+ SK_A32_SHIFT
/8] = pixels
.get()[src_y
+ x
+ 3];
302 return bitmap
.Pass();
305 void LayerTreePixelTest::ReleaseTextureMailbox(
306 scoped_ptr
<gpu::GLInProcessContext
> context
,
309 bool lost_resource
) {
310 GLES2Interface
* gl
= context
->GetImplementation();
312 gl
->WaitSyncPointCHROMIUM(sync_point
);
313 gl
->DeleteTextures(1, &texture
);
314 pending_texture_mailbox_callbacks_
--;
318 void LayerTreePixelTest::CopyBitmapToTextureMailboxAsTexture(
319 const SkBitmap
& bitmap
,
320 TextureMailbox
* texture_mailbox
,
321 scoped_ptr
<SingleReleaseCallback
>* release_callback
) {
322 DCHECK_GT(bitmap
.width(), 0);
323 DCHECK_GT(bitmap
.height(), 0);
325 scoped_ptr
<gpu::GLInProcessContext
> context
= CreateTestInProcessContext();
326 GLES2Interface
* gl
= context
->GetImplementation();
328 GLuint texture_id
= 0;
329 gl
->GenTextures(1, &texture_id
);
330 gl
->BindTexture(GL_TEXTURE_2D
, texture_id
);
331 gl
->TexParameteri(GL_TEXTURE_2D
, GL_TEXTURE_MIN_FILTER
, GL_LINEAR
);
332 gl
->TexParameteri(GL_TEXTURE_2D
, GL_TEXTURE_MAG_FILTER
, GL_LINEAR
);
333 gl
->TexParameteri(GL_TEXTURE_2D
, GL_TEXTURE_WRAP_S
, GL_CLAMP_TO_EDGE
);
334 gl
->TexParameteri(GL_TEXTURE_2D
, GL_TEXTURE_WRAP_T
, GL_CLAMP_TO_EDGE
);
336 DCHECK_EQ(kN32_SkColorType
, bitmap
.colorType());
339 SkAutoLockPixels
lock(bitmap
);
341 size_t row_bytes
= bitmap
.width() * 4;
342 size_t total_bytes
= bitmap
.height() * row_bytes
;
344 scoped_ptr
<uint8
[]> gl_pixels(new uint8
[total_bytes
]);
345 uint8
* bitmap_pixels
= static_cast<uint8
*>(bitmap
.getPixels());
347 for (size_t y
= 0; y
< total_bytes
; y
+= row_bytes
) {
349 size_t src_y
= total_bytes
- y
- row_bytes
;
350 // Swizzle Skia -> OpenGL byte order.
351 for (size_t x
= 0; x
< row_bytes
; x
+= 4) {
352 gl_pixels
.get()[y
+ x
+ 0] = bitmap_pixels
[src_y
+ x
+ SK_R32_SHIFT
/8];
353 gl_pixels
.get()[y
+ x
+ 1] = bitmap_pixels
[src_y
+ x
+ SK_G32_SHIFT
/8];
354 gl_pixels
.get()[y
+ x
+ 2] = bitmap_pixels
[src_y
+ x
+ SK_B32_SHIFT
/8];
355 gl_pixels
.get()[y
+ x
+ 3] = bitmap_pixels
[src_y
+ x
+ SK_A32_SHIFT
/8];
359 gl
->TexImage2D(GL_TEXTURE_2D
,
370 gpu::Mailbox mailbox
;
371 gl
->GenMailboxCHROMIUM(mailbox
.name
);
372 gl
->ProduceTextureCHROMIUM(GL_TEXTURE_2D
, mailbox
.name
);
373 gl
->BindTexture(GL_TEXTURE_2D
, 0);
374 uint32 sync_point
= gl
->InsertSyncPointCHROMIUM();
376 *texture_mailbox
= TextureMailbox(mailbox
, GL_TEXTURE_2D
, sync_point
);
377 *release_callback
= SingleReleaseCallback::Create(
378 base::Bind(&LayerTreePixelTest::ReleaseTextureMailbox
,
379 base::Unretained(this),
380 base::Passed(&context
),
384 void LayerTreePixelTest::Finish() {
385 scoped_ptr
<gpu::GLInProcessContext
> context
= CreateTestInProcessContext();
386 GLES2Interface
* gl
= context
->GetImplementation();