OLD | NEW |
| (Empty) |
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. | |
4 | |
5 #include "cc/test/layer_tree_pixel_test.h" | |
6 | |
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" | |
25 | |
26 using gpu::gles2::GLES2Interface; | |
27 | |
28 namespace cc { | |
29 | |
30 LayerTreePixelTest::LayerTreePixelTest() | |
31 : pixel_comparator_(new ExactPixelComparator(true)), | |
32 test_type_(PIXEL_TEST_GL), | |
33 pending_texture_mailbox_callbacks_(0), | |
34 impl_side_painting_(true) { | |
35 } | |
36 | |
37 LayerTreePixelTest::~LayerTreePixelTest() {} | |
38 | |
39 scoped_ptr<OutputSurface> LayerTreePixelTest::CreateOutputSurface() { | |
40 gfx::Size surface_expansion_size(40, 60); | |
41 scoped_ptr<PixelTestOutputSurface> output_surface; | |
42 | |
43 switch (test_type_) { | |
44 case PIXEL_TEST_SOFTWARE: { | |
45 scoped_ptr<PixelTestSoftwareOutputDevice> software_output_device( | |
46 new PixelTestSoftwareOutputDevice); | |
47 software_output_device->set_surface_expansion_size( | |
48 surface_expansion_size); | |
49 output_surface = make_scoped_ptr( | |
50 new PixelTestOutputSurface(software_output_device.Pass())); | |
51 break; | |
52 } | |
53 case PIXEL_TEST_GL: { | |
54 bool flipped_output_surface = false; | |
55 output_surface = make_scoped_ptr(new PixelTestOutputSurface( | |
56 new TestInProcessContextProvider, new TestInProcessContextProvider, | |
57 flipped_output_surface)); | |
58 break; | |
59 } | |
60 } | |
61 | |
62 output_surface->set_surface_expansion_size(surface_expansion_size); | |
63 return output_surface.Pass(); | |
64 } | |
65 | |
66 void LayerTreePixelTest::WillActivateTreeOnThread(LayerTreeHostImpl* impl) { | |
67 if (impl->sync_tree()->source_frame_number() != 0) | |
68 return; | |
69 | |
70 DirectRenderer* renderer = static_cast<DirectRenderer*>(impl->renderer()); | |
71 renderer->SetEnlargePassTextureAmountForTesting(enlarge_texture_amount_); | |
72 | |
73 gfx::Rect viewport = impl->DeviceViewport(); | |
74 // The viewport has a 0,0 origin without external influence. | |
75 EXPECT_EQ(gfx::Point().ToString(), viewport.origin().ToString()); | |
76 // Be that influence! | |
77 viewport += gfx::Vector2d(20, 10); | |
78 bool resourceless_software_draw = false; | |
79 gfx::Transform identity = gfx::Transform(); | |
80 impl->SetExternalDrawConstraints(identity, | |
81 viewport, | |
82 viewport, | |
83 viewport, | |
84 identity, | |
85 resourceless_software_draw); | |
86 EXPECT_EQ(viewport.ToString(), impl->DeviceViewport().ToString()); | |
87 } | |
88 | |
89 scoped_ptr<CopyOutputRequest> LayerTreePixelTest::CreateCopyOutputRequest() { | |
90 return CopyOutputRequest::CreateBitmapRequest( | |
91 base::Bind(&LayerTreePixelTest::ReadbackResult, base::Unretained(this))); | |
92 } | |
93 | |
94 void LayerTreePixelTest::ReadbackResult(scoped_ptr<CopyOutputResult> result) { | |
95 ASSERT_TRUE(result->HasBitmap()); | |
96 result_bitmap_ = result->TakeBitmap().Pass(); | |
97 EndTest(); | |
98 } | |
99 | |
100 void LayerTreePixelTest::BeginTest() { | |
101 Layer* target = readback_target_ ? readback_target_ | |
102 : layer_tree_host()->root_layer(); | |
103 target->RequestCopyOfOutput(CreateCopyOutputRequest().Pass()); | |
104 PostSetNeedsCommitToMainThread(); | |
105 } | |
106 | |
107 void LayerTreePixelTest::AfterTest() { | |
108 base::FilePath test_data_dir; | |
109 EXPECT_TRUE(PathService::Get(CCPaths::DIR_TEST_DATA, &test_data_dir)); | |
110 base::FilePath ref_file_path = test_data_dir.Append(ref_file_); | |
111 | |
112 base::CommandLine* cmd = base::CommandLine::ForCurrentProcess(); | |
113 if (cmd->HasSwitch(switches::kCCRebaselinePixeltests)) | |
114 EXPECT_TRUE(WritePNGFile(*result_bitmap_, ref_file_path, true)); | |
115 EXPECT_TRUE(MatchesPNGFile(*result_bitmap_, | |
116 ref_file_path, | |
117 *pixel_comparator_)); | |
118 } | |
119 | |
120 scoped_refptr<SolidColorLayer> LayerTreePixelTest::CreateSolidColorLayer( | |
121 const gfx::Rect& rect, SkColor color) { | |
122 scoped_refptr<SolidColorLayer> layer = SolidColorLayer::Create(); | |
123 layer->SetIsDrawable(true); | |
124 layer->SetBounds(rect.size()); | |
125 layer->SetPosition(rect.origin()); | |
126 layer->SetBackgroundColor(color); | |
127 return layer; | |
128 } | |
129 | |
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); | |
135 } | |
136 | |
137 TryEndTest(); | |
138 } | |
139 | |
140 void LayerTreePixelTest::TryEndTest() { | |
141 if (!result_bitmap_) | |
142 return; | |
143 if (pending_texture_mailbox_callbacks_) | |
144 return; | |
145 LayerTreeTest::EndTest(); | |
146 } | |
147 | |
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( | |
156 gfx::Rect(0, | |
157 border_width, | |
158 border_width, | |
159 rect.height() - border_width * 2), | |
160 border_color); | |
161 scoped_refptr<SolidColorLayer> border_right = | |
162 CreateSolidColorLayer(gfx::Rect(rect.width() - border_width, | |
163 border_width, | |
164 border_width, | |
165 rect.height() - border_width * 2), | |
166 border_color); | |
167 scoped_refptr<SolidColorLayer> border_bottom = CreateSolidColorLayer( | |
168 gfx::Rect(0, rect.height() - border_width, rect.width(), border_width), | |
169 border_color); | |
170 layer->AddChild(border_top); | |
171 layer->AddChild(border_left); | |
172 layer->AddChild(border_right); | |
173 layer->AddChild(border_bottom); | |
174 return layer; | |
175 } | |
176 | |
177 scoped_refptr<TextureLayer> LayerTreePixelTest::CreateTextureLayer( | |
178 const gfx::Rect& rect, const SkBitmap& bitmap) { | |
179 scoped_refptr<TextureLayer> layer = TextureLayer::CreateForMailbox(NULL); | |
180 layer->SetIsDrawable(true); | |
181 layer->SetBounds(rect.size()); | |
182 layer->SetPosition(rect.origin()); | |
183 | |
184 TextureMailbox texture_mailbox; | |
185 scoped_ptr<SingleReleaseCallback> release_callback; | |
186 CopyBitmapToTextureMailboxAsTexture( | |
187 bitmap, &texture_mailbox, &release_callback); | |
188 layer->SetTextureMailbox(texture_mailbox, release_callback.Pass()); | |
189 | |
190 texture_layers_.push_back(layer); | |
191 pending_texture_mailbox_callbacks_++; | |
192 return layer; | |
193 } | |
194 | |
195 void LayerTreePixelTest::RunPixelTest( | |
196 PixelTestType test_type, | |
197 scoped_refptr<Layer> content_root, | |
198 base::FilePath file_name) { | |
199 test_type_ = test_type; | |
200 content_root_ = content_root; | |
201 readback_target_ = NULL; | |
202 ref_file_ = file_name; | |
203 bool threaded = true; | |
204 RunTest(threaded, false, impl_side_painting_); | |
205 } | |
206 | |
207 void LayerTreePixelTest::RunSingleThreadedPixelTest( | |
208 PixelTestType test_type, | |
209 scoped_refptr<Layer> content_root, | |
210 base::FilePath file_name) { | |
211 test_type_ = test_type; | |
212 content_root_ = content_root; | |
213 readback_target_ = NULL; | |
214 ref_file_ = file_name; | |
215 bool threaded = false; | |
216 RunTest(threaded, false, impl_side_painting_); | |
217 } | |
218 | |
219 void LayerTreePixelTest::RunPixelTestWithReadbackTarget( | |
220 PixelTestType test_type, | |
221 scoped_refptr<Layer> content_root, | |
222 Layer* target, | |
223 base::FilePath file_name) { | |
224 test_type_ = test_type; | |
225 content_root_ = content_root; | |
226 readback_target_ = target; | |
227 ref_file_ = file_name; | |
228 RunTest(true, false, impl_side_painting_); | |
229 } | |
230 | |
231 void LayerTreePixelTest::SetupTree() { | |
232 scoped_refptr<Layer> root = Layer::Create(); | |
233 root->SetBounds(content_root_->bounds()); | |
234 root->AddChild(content_root_); | |
235 layer_tree_host()->SetRootLayer(root); | |
236 LayerTreeTest::SetupTree(); | |
237 } | |
238 | |
239 scoped_ptr<SkBitmap> LayerTreePixelTest::CopyTextureMailboxToBitmap( | |
240 const gfx::Size& size, | |
241 const TextureMailbox& texture_mailbox) { | |
242 DCHECK(texture_mailbox.IsTexture()); | |
243 if (!texture_mailbox.IsTexture()) | |
244 return nullptr; | |
245 | |
246 scoped_ptr<gpu::GLInProcessContext> context = CreateTestInProcessContext(); | |
247 GLES2Interface* gl = context->GetImplementation(); | |
248 | |
249 if (texture_mailbox.sync_point()) | |
250 gl->WaitSyncPointCHROMIUM(texture_mailbox.sync_point()); | |
251 | |
252 GLuint texture_id = 0; | |
253 gl->GenTextures(1, &texture_id); | |
254 gl->BindTexture(GL_TEXTURE_2D, texture_id); | |
255 gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); | |
256 gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); | |
257 gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); | |
258 gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); | |
259 gl->ConsumeTextureCHROMIUM(texture_mailbox.target(), texture_mailbox.name()); | |
260 gl->BindTexture(GL_TEXTURE_2D, 0); | |
261 | |
262 GLuint fbo = 0; | |
263 gl->GenFramebuffers(1, &fbo); | |
264 gl->BindFramebuffer(GL_FRAMEBUFFER, fbo); | |
265 gl->FramebufferTexture2D( | |
266 GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture_id, 0); | |
267 EXPECT_EQ(static_cast<unsigned>(GL_FRAMEBUFFER_COMPLETE), | |
268 gl->CheckFramebufferStatus(GL_FRAMEBUFFER)); | |
269 | |
270 scoped_ptr<uint8[]> pixels(new uint8[size.GetArea() * 4]); | |
271 gl->ReadPixels(0, | |
272 0, | |
273 size.width(), | |
274 size.height(), | |
275 GL_RGBA, | |
276 GL_UNSIGNED_BYTE, | |
277 pixels.get()); | |
278 | |
279 gl->DeleteFramebuffers(1, &fbo); | |
280 gl->DeleteTextures(1, &texture_id); | |
281 | |
282 scoped_ptr<SkBitmap> bitmap(new SkBitmap); | |
283 bitmap->allocN32Pixels(size.width(), size.height()); | |
284 | |
285 uint8* out_pixels = static_cast<uint8*>(bitmap->getPixels()); | |
286 | |
287 size_t row_bytes = size.width() * 4; | |
288 size_t total_bytes = size.height() * row_bytes; | |
289 for (size_t dest_y = 0; dest_y < total_bytes; dest_y += row_bytes) { | |
290 // Flip Y axis. | |
291 size_t src_y = total_bytes - dest_y - row_bytes; | |
292 // Swizzle OpenGL -> Skia byte order. | |
293 for (size_t x = 0; x < row_bytes; x += 4) { | |
294 out_pixels[dest_y + x + SK_R32_SHIFT/8] = pixels.get()[src_y + x + 0]; | |
295 out_pixels[dest_y + x + SK_G32_SHIFT/8] = pixels.get()[src_y + x + 1]; | |
296 out_pixels[dest_y + x + SK_B32_SHIFT/8] = pixels.get()[src_y + x + 2]; | |
297 out_pixels[dest_y + x + SK_A32_SHIFT/8] = pixels.get()[src_y + x + 3]; | |
298 } | |
299 } | |
300 | |
301 return bitmap.Pass(); | |
302 } | |
303 | |
304 void LayerTreePixelTest::ReleaseTextureMailbox( | |
305 scoped_ptr<gpu::GLInProcessContext> context, | |
306 uint32 texture, | |
307 uint32 sync_point, | |
308 bool lost_resource) { | |
309 GLES2Interface* gl = context->GetImplementation(); | |
310 if (sync_point) | |
311 gl->WaitSyncPointCHROMIUM(sync_point); | |
312 gl->DeleteTextures(1, &texture); | |
313 pending_texture_mailbox_callbacks_--; | |
314 TryEndTest(); | |
315 } | |
316 | |
317 void LayerTreePixelTest::CopyBitmapToTextureMailboxAsTexture( | |
318 const SkBitmap& bitmap, | |
319 TextureMailbox* texture_mailbox, | |
320 scoped_ptr<SingleReleaseCallback>* release_callback) { | |
321 DCHECK_GT(bitmap.width(), 0); | |
322 DCHECK_GT(bitmap.height(), 0); | |
323 | |
324 scoped_ptr<gpu::GLInProcessContext> context = CreateTestInProcessContext(); | |
325 GLES2Interface* gl = context->GetImplementation(); | |
326 | |
327 GLuint texture_id = 0; | |
328 gl->GenTextures(1, &texture_id); | |
329 gl->BindTexture(GL_TEXTURE_2D, texture_id); | |
330 gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); | |
331 gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); | |
332 gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); | |
333 gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); | |
334 | |
335 DCHECK_EQ(kN32_SkColorType, bitmap.colorType()); | |
336 | |
337 { | |
338 SkAutoLockPixels lock(bitmap); | |
339 | |
340 size_t row_bytes = bitmap.width() * 4; | |
341 size_t total_bytes = bitmap.height() * row_bytes; | |
342 | |
343 scoped_ptr<uint8[]> gl_pixels(new uint8[total_bytes]); | |
344 uint8* bitmap_pixels = static_cast<uint8*>(bitmap.getPixels()); | |
345 | |
346 for (size_t y = 0; y < total_bytes; y += row_bytes) { | |
347 // Flip Y axis. | |
348 size_t src_y = total_bytes - y - row_bytes; | |
349 // Swizzle Skia -> OpenGL byte order. | |
350 for (size_t x = 0; x < row_bytes; x += 4) { | |
351 gl_pixels.get()[y + x + 0] = bitmap_pixels[src_y + x + SK_R32_SHIFT/8]; | |
352 gl_pixels.get()[y + x + 1] = bitmap_pixels[src_y + x + SK_G32_SHIFT/8]; | |
353 gl_pixels.get()[y + x + 2] = bitmap_pixels[src_y + x + SK_B32_SHIFT/8]; | |
354 gl_pixels.get()[y + x + 3] = bitmap_pixels[src_y + x + SK_A32_SHIFT/8]; | |
355 } | |
356 } | |
357 | |
358 gl->TexImage2D(GL_TEXTURE_2D, | |
359 0, | |
360 GL_RGBA, | |
361 bitmap.width(), | |
362 bitmap.height(), | |
363 0, | |
364 GL_RGBA, | |
365 GL_UNSIGNED_BYTE, | |
366 gl_pixels.get()); | |
367 } | |
368 | |
369 gpu::Mailbox mailbox; | |
370 gl->GenMailboxCHROMIUM(mailbox.name); | |
371 gl->ProduceTextureCHROMIUM(GL_TEXTURE_2D, mailbox.name); | |
372 gl->BindTexture(GL_TEXTURE_2D, 0); | |
373 uint32 sync_point = gl->InsertSyncPointCHROMIUM(); | |
374 | |
375 *texture_mailbox = TextureMailbox(mailbox, GL_TEXTURE_2D, sync_point); | |
376 *release_callback = SingleReleaseCallback::Create( | |
377 base::Bind(&LayerTreePixelTest::ReleaseTextureMailbox, | |
378 base::Unretained(this), | |
379 base::Passed(&context), | |
380 texture_id)); | |
381 } | |
382 | |
383 } // namespace cc | |
OLD | NEW |