| 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 |