Home | History | Annotate | Download | only in test
      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(kPMColor_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