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/resources/texture_mailbox.h" 15 #include "cc/test/paths.h" 16 #include "cc/test/pixel_comparator.h" 17 #include "cc/test/pixel_test_output_surface.h" 18 #include "cc/test/pixel_test_software_output_device.h" 19 #include "cc/test/pixel_test_utils.h" 20 #include "cc/test/test_in_process_context_provider.h" 21 #include "cc/trees/layer_tree_impl.h" 22 #include "gpu/command_buffer/client/gl_in_process_context.h" 23 #include "gpu/command_buffer/client/gles2_implementation.h" 24 25 using gpu::gles2::GLES2Interface; 26 27 namespace cc { 28 29 LayerTreePixelTest::LayerTreePixelTest() 30 : pixel_comparator_(new ExactPixelComparator(true)), 31 test_type_(GL_WITH_DEFAULT), 32 pending_texture_mailbox_callbacks_(0), 33 impl_side_painting_(true) {} 34 35 LayerTreePixelTest::~LayerTreePixelTest() {} 36 37 scoped_ptr<OutputSurface> LayerTreePixelTest::CreateOutputSurface( 38 bool fallback) { 39 gfx::Size surface_expansion_size(40, 60); 40 scoped_ptr<PixelTestOutputSurface> output_surface; 41 42 switch (test_type_) { 43 case SOFTWARE_WITH_DEFAULT: 44 case SOFTWARE_WITH_BITMAP: { 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( 51 software_output_device.PassAs<SoftwareOutputDevice>())); 52 break; 53 } 54 55 case GL_WITH_DEFAULT: 56 case GL_WITH_BITMAP: { 57 output_surface = make_scoped_ptr( 58 new PixelTestOutputSurface(new TestInProcessContextProvider)); 59 break; 60 } 61 } 62 63 output_surface->set_surface_expansion_size(surface_expansion_size); 64 return output_surface.PassAs<OutputSurface>(); 65 } 66 67 void LayerTreePixelTest::CommitCompleteOnThread(LayerTreeHostImpl* impl) { 68 LayerTreeImpl* commit_tree = 69 impl->pending_tree() ? impl->pending_tree() : impl->active_tree(); 70 if (commit_tree->source_frame_number() != 0) 71 return; 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 CommandLine* cmd = 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(), 135 scoped_ptr<SingleReleaseCallback>()); 136 } 137 138 TryEndTest(); 139 } 140 141 void LayerTreePixelTest::TryEndTest() { 142 if (!result_bitmap_) 143 return; 144 if (pending_texture_mailbox_callbacks_) 145 return; 146 LayerTreeTest::EndTest(); 147 } 148 149 scoped_refptr<SolidColorLayer> LayerTreePixelTest:: 150 CreateSolidColorLayerWithBorder( 151 const gfx::Rect& rect, SkColor color, 152 int border_width, SkColor border_color) { 153 scoped_refptr<SolidColorLayer> layer = CreateSolidColorLayer(rect, color); 154 scoped_refptr<SolidColorLayer> border_top = CreateSolidColorLayer( 155 gfx::Rect(0, 0, rect.width(), border_width), border_color); 156 scoped_refptr<SolidColorLayer> border_left = CreateSolidColorLayer( 157 gfx::Rect(0, 158 border_width, 159 border_width, 160 rect.height() - border_width * 2), 161 border_color); 162 scoped_refptr<SolidColorLayer> border_right = 163 CreateSolidColorLayer(gfx::Rect(rect.width() - border_width, 164 border_width, 165 border_width, 166 rect.height() - border_width * 2), 167 border_color); 168 scoped_refptr<SolidColorLayer> border_bottom = CreateSolidColorLayer( 169 gfx::Rect(0, rect.height() - border_width, rect.width(), border_width), 170 border_color); 171 layer->AddChild(border_top); 172 layer->AddChild(border_left); 173 layer->AddChild(border_right); 174 layer->AddChild(border_bottom); 175 return layer; 176 } 177 178 scoped_refptr<TextureLayer> LayerTreePixelTest::CreateTextureLayer( 179 const gfx::Rect& rect, const SkBitmap& bitmap) { 180 scoped_refptr<TextureLayer> layer = TextureLayer::CreateForMailbox(NULL); 181 layer->SetIsDrawable(true); 182 layer->SetBounds(rect.size()); 183 layer->SetPosition(rect.origin()); 184 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()); 190 191 texture_layers_.push_back(layer); 192 pending_texture_mailbox_callbacks_++; 193 return layer; 194 } 195 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 RunTest(true, false, impl_side_painting_); 205 } 206 207 void LayerTreePixelTest::RunPixelTestWithReadbackTarget( 208 PixelTestType test_type, 209 scoped_refptr<Layer> content_root, 210 Layer* target, 211 base::FilePath file_name) { 212 test_type_ = test_type; 213 content_root_ = content_root; 214 readback_target_ = target; 215 ref_file_ = file_name; 216 RunTest(true, false, impl_side_painting_); 217 } 218 219 void LayerTreePixelTest::SetupTree() { 220 scoped_refptr<Layer> root = Layer::Create(); 221 root->SetBounds(content_root_->bounds()); 222 root->AddChild(content_root_); 223 layer_tree_host()->SetRootLayer(root); 224 LayerTreeTest::SetupTree(); 225 } 226 227 scoped_ptr<SkBitmap> LayerTreePixelTest::CopyTextureMailboxToBitmap( 228 const gfx::Size& size, 229 const TextureMailbox& texture_mailbox) { 230 DCHECK(texture_mailbox.IsTexture()); 231 if (!texture_mailbox.IsTexture()) 232 return scoped_ptr<SkBitmap>(); 233 234 scoped_ptr<gpu::GLInProcessContext> context = CreateTestInProcessContext(); 235 GLES2Interface* gl = context->GetImplementation(); 236 237 if (texture_mailbox.sync_point()) 238 gl->WaitSyncPointCHROMIUM(texture_mailbox.sync_point()); 239 240 GLuint texture_id = 0; 241 gl->GenTextures(1, &texture_id); 242 gl->BindTexture(GL_TEXTURE_2D, texture_id); 243 gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); 244 gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); 245 gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); 246 gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); 247 gl->ConsumeTextureCHROMIUM(texture_mailbox.target(), texture_mailbox.name()); 248 gl->BindTexture(GL_TEXTURE_2D, 0); 249 250 GLuint fbo = 0; 251 gl->GenFramebuffers(1, &fbo); 252 gl->BindFramebuffer(GL_FRAMEBUFFER, fbo); 253 gl->FramebufferTexture2D( 254 GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture_id, 0); 255 EXPECT_EQ(static_cast<unsigned>(GL_FRAMEBUFFER_COMPLETE), 256 gl->CheckFramebufferStatus(GL_FRAMEBUFFER)); 257 258 scoped_ptr<uint8[]> pixels(new uint8[size.GetArea() * 4]); 259 gl->ReadPixels(0, 260 0, 261 size.width(), 262 size.height(), 263 GL_RGBA, 264 GL_UNSIGNED_BYTE, 265 pixels.get()); 266 267 gl->DeleteFramebuffers(1, &fbo); 268 gl->DeleteTextures(1, &texture_id); 269 270 scoped_ptr<SkBitmap> bitmap(new SkBitmap); 271 bitmap->allocN32Pixels(size.width(), size.height()); 272 273 uint8* out_pixels = static_cast<uint8*>(bitmap->getPixels()); 274 275 size_t row_bytes = size.width() * 4; 276 size_t total_bytes = size.height() * row_bytes; 277 for (size_t dest_y = 0; dest_y < total_bytes; dest_y += row_bytes) { 278 // Flip Y axis. 279 size_t src_y = total_bytes - dest_y - row_bytes; 280 // Swizzle OpenGL -> Skia byte order. 281 for (size_t x = 0; x < row_bytes; x += 4) { 282 out_pixels[dest_y + x + SK_R32_SHIFT/8] = pixels.get()[src_y + x + 0]; 283 out_pixels[dest_y + x + SK_G32_SHIFT/8] = pixels.get()[src_y + x + 1]; 284 out_pixels[dest_y + x + SK_B32_SHIFT/8] = pixels.get()[src_y + x + 2]; 285 out_pixels[dest_y + x + SK_A32_SHIFT/8] = pixels.get()[src_y + x + 3]; 286 } 287 } 288 289 return bitmap.Pass(); 290 } 291 292 void LayerTreePixelTest::ReleaseTextureMailbox( 293 scoped_ptr<gpu::GLInProcessContext> context, 294 uint32 texture, 295 uint32 sync_point, 296 bool lost_resource) { 297 GLES2Interface* gl = context->GetImplementation(); 298 if (sync_point) 299 gl->WaitSyncPointCHROMIUM(sync_point); 300 gl->DeleteTextures(1, &texture); 301 pending_texture_mailbox_callbacks_--; 302 TryEndTest(); 303 } 304 305 void LayerTreePixelTest::CopyBitmapToTextureMailboxAsTexture( 306 const SkBitmap& bitmap, 307 TextureMailbox* texture_mailbox, 308 scoped_ptr<SingleReleaseCallback>* release_callback) { 309 DCHECK_GT(bitmap.width(), 0); 310 DCHECK_GT(bitmap.height(), 0); 311 312 scoped_ptr<gpu::GLInProcessContext> context = CreateTestInProcessContext(); 313 GLES2Interface* gl = context->GetImplementation(); 314 315 GLuint texture_id = 0; 316 gl->GenTextures(1, &texture_id); 317 gl->BindTexture(GL_TEXTURE_2D, texture_id); 318 gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); 319 gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); 320 gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); 321 gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); 322 323 DCHECK_EQ(kN32_SkColorType, bitmap.colorType()); 324 325 { 326 SkAutoLockPixels lock(bitmap); 327 328 size_t row_bytes = bitmap.width() * 4; 329 size_t total_bytes = bitmap.height() * row_bytes; 330 331 scoped_ptr<uint8[]> gl_pixels(new uint8[total_bytes]); 332 uint8* bitmap_pixels = static_cast<uint8*>(bitmap.getPixels()); 333 334 for (size_t y = 0; y < total_bytes; y += row_bytes) { 335 // Flip Y axis. 336 size_t src_y = total_bytes - y - row_bytes; 337 // Swizzle Skia -> OpenGL byte order. 338 for (size_t x = 0; x < row_bytes; x += 4) { 339 gl_pixels.get()[y + x + 0] = bitmap_pixels[src_y + x + SK_R32_SHIFT/8]; 340 gl_pixels.get()[y + x + 1] = bitmap_pixels[src_y + x + SK_G32_SHIFT/8]; 341 gl_pixels.get()[y + x + 2] = bitmap_pixels[src_y + x + SK_B32_SHIFT/8]; 342 gl_pixels.get()[y + x + 3] = bitmap_pixels[src_y + x + SK_A32_SHIFT/8]; 343 } 344 } 345 346 gl->TexImage2D(GL_TEXTURE_2D, 347 0, 348 GL_RGBA, 349 bitmap.width(), 350 bitmap.height(), 351 0, 352 GL_RGBA, 353 GL_UNSIGNED_BYTE, 354 gl_pixels.get()); 355 } 356 357 gpu::Mailbox mailbox; 358 gl->GenMailboxCHROMIUM(mailbox.name); 359 gl->ProduceTextureCHROMIUM(GL_TEXTURE_2D, mailbox.name); 360 gl->BindTexture(GL_TEXTURE_2D, 0); 361 uint32 sync_point = gl->InsertSyncPointCHROMIUM(); 362 363 *texture_mailbox = TextureMailbox(mailbox, GL_TEXTURE_2D, sync_point); 364 *release_callback = SingleReleaseCallback::Create( 365 base::Bind(&LayerTreePixelTest::ReleaseTextureMailbox, 366 base::Unretained(this), 367 base::Passed(&context), 368 texture_id)); 369 } 370 371 } // namespace cc 372