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/trees/layer_tree_impl.h"
     21 #include "ui/gl/gl_implementation.h"
     22 #include "webkit/common/gpu/context_provider_in_process.h"
     23 #include "webkit/common/gpu/webgraphicscontext3d_in_process_command_buffer_impl.h"
     24 
     25 namespace cc {
     26 
     27 LayerTreePixelTest::LayerTreePixelTest()
     28     : pixel_comparator_(new ExactPixelComparator(true)),
     29       test_type_(GL_WITH_DEFAULT),
     30       pending_texture_mailbox_callbacks_(0),
     31       impl_side_painting_(true) {}
     32 
     33 LayerTreePixelTest::~LayerTreePixelTest() {}
     34 
     35 scoped_ptr<OutputSurface> LayerTreePixelTest::CreateOutputSurface(
     36     bool fallback) {
     37   gfx::Size surface_expansion_size(40, 60);
     38   scoped_ptr<PixelTestOutputSurface> output_surface;
     39 
     40   switch (test_type_) {
     41     case SOFTWARE_WITH_DEFAULT:
     42     case SOFTWARE_WITH_BITMAP: {
     43       scoped_ptr<PixelTestSoftwareOutputDevice> software_output_device(
     44           new PixelTestSoftwareOutputDevice);
     45       software_output_device->set_surface_expansion_size(
     46           surface_expansion_size);
     47       output_surface = make_scoped_ptr(
     48           new PixelTestOutputSurface(
     49               software_output_device.PassAs<SoftwareOutputDevice>()));
     50       break;
     51     }
     52 
     53     case GL_WITH_DEFAULT:
     54     case GL_WITH_BITMAP: {
     55       CHECK(gfx::InitializeGLBindings(gfx::kGLImplementationOSMesaGL));
     56 
     57       using webkit::gpu::ContextProviderInProcess;
     58       output_surface = make_scoped_ptr(new PixelTestOutputSurface(
     59           ContextProviderInProcess::CreateOffscreen()));
     60       break;
     61     }
     62   }
     63 
     64   output_surface->set_surface_expansion_size(surface_expansion_size);
     65   return output_surface.PassAs<OutputSurface>();
     66 }
     67 
     68 scoped_refptr<ContextProvider> LayerTreePixelTest::OffscreenContextProvider() {
     69   scoped_refptr<webkit::gpu::ContextProviderInProcess> provider =
     70       webkit::gpu::ContextProviderInProcess::CreateOffscreen();
     71   CHECK(provider.get());
     72   return provider;
     73 }
     74 
     75 void LayerTreePixelTest::CommitCompleteOnThread(LayerTreeHostImpl* impl) {
     76   LayerTreeImpl* commit_tree =
     77       impl->pending_tree() ? impl->pending_tree() : impl->active_tree();
     78   if (commit_tree->source_frame_number() != 0)
     79     return;
     80 
     81   gfx::Rect viewport = impl->DeviceViewport();
     82   // The viewport has a 0,0 origin without external influence.
     83   EXPECT_EQ(gfx::Point().ToString(), viewport.origin().ToString());
     84   // Be that influence!
     85   viewport += gfx::Vector2d(20, 10);
     86   impl->SetExternalDrawConstraints(gfx::Transform(), viewport, viewport, true);
     87   EXPECT_EQ(viewport.ToString(), impl->DeviceViewport().ToString());
     88 }
     89 
     90 scoped_ptr<CopyOutputRequest> LayerTreePixelTest::CreateCopyOutputRequest() {
     91   return CopyOutputRequest::CreateBitmapRequest(
     92       base::Bind(&LayerTreePixelTest::ReadbackResult, base::Unretained(this)));
     93 }
     94 
     95 void LayerTreePixelTest::ReadbackResult(scoped_ptr<CopyOutputResult> result) {
     96   ASSERT_TRUE(result->HasBitmap());
     97   result_bitmap_ = result->TakeBitmap().Pass();
     98   EndTest();
     99 }
    100 
    101 void LayerTreePixelTest::BeginTest() {
    102   Layer* target = readback_target_ ? readback_target_
    103                                    : layer_tree_host()->root_layer();
    104   target->RequestCopyOfOutput(CreateCopyOutputRequest().Pass());
    105   PostSetNeedsCommitToMainThread();
    106 }
    107 
    108 void LayerTreePixelTest::AfterTest() {
    109   base::FilePath test_data_dir;
    110   EXPECT_TRUE(PathService::Get(CCPaths::DIR_TEST_DATA, &test_data_dir));
    111   base::FilePath ref_file_path = test_data_dir.Append(ref_file_);
    112 
    113   CommandLine* cmd = CommandLine::ForCurrentProcess();
    114   if (cmd->HasSwitch(switches::kCCRebaselinePixeltests))
    115     EXPECT_TRUE(WritePNGFile(*result_bitmap_, ref_file_path, true));
    116 
    117   EXPECT_TRUE(MatchesPNGFile(*result_bitmap_,
    118                              ref_file_path,
    119                              *pixel_comparator_));
    120 }
    121 
    122 scoped_refptr<SolidColorLayer> LayerTreePixelTest::CreateSolidColorLayer(
    123     gfx::Rect rect, SkColor color) {
    124   scoped_refptr<SolidColorLayer> layer = SolidColorLayer::Create();
    125   layer->SetIsDrawable(true);
    126   layer->SetAnchorPoint(gfx::PointF());
    127   layer->SetBounds(rect.size());
    128   layer->SetPosition(rect.origin());
    129   layer->SetBackgroundColor(color);
    130   return layer;
    131 }
    132 
    133 void LayerTreePixelTest::EndTest() {
    134   // Drop TextureMailboxes on the main thread so that they can be cleaned up and
    135   // the pending callbacks will fire.
    136   for (size_t i = 0; i < texture_layers_.size(); ++i) {
    137     texture_layers_[i]->SetTextureMailbox(TextureMailbox(),
    138                                           scoped_ptr<SingleReleaseCallback>());
    139   }
    140 
    141   TryEndTest();
    142 }
    143 
    144 void LayerTreePixelTest::TryEndTest() {
    145   if (!result_bitmap_)
    146     return;
    147   if (pending_texture_mailbox_callbacks_)
    148     return;
    149   LayerTreeTest::EndTest();
    150 }
    151 
    152 scoped_refptr<SolidColorLayer> LayerTreePixelTest::
    153     CreateSolidColorLayerWithBorder(
    154         gfx::Rect rect, SkColor color, int border_width, SkColor border_color) {
    155   scoped_refptr<SolidColorLayer> layer = CreateSolidColorLayer(rect, color);
    156   scoped_refptr<SolidColorLayer> border_top = CreateSolidColorLayer(
    157       gfx::Rect(0, 0, rect.width(), border_width), border_color);
    158   scoped_refptr<SolidColorLayer> border_left = CreateSolidColorLayer(
    159       gfx::Rect(0,
    160                 border_width,
    161                 border_width,
    162                 rect.height() - border_width * 2),
    163       border_color);
    164   scoped_refptr<SolidColorLayer> border_right =
    165       CreateSolidColorLayer(gfx::Rect(rect.width() - border_width,
    166                                       border_width,
    167                                       border_width,
    168                                       rect.height() - border_width * 2),
    169                             border_color);
    170   scoped_refptr<SolidColorLayer> border_bottom = CreateSolidColorLayer(
    171       gfx::Rect(0, rect.height() - border_width, rect.width(), border_width),
    172       border_color);
    173   layer->AddChild(border_top);
    174   layer->AddChild(border_left);
    175   layer->AddChild(border_right);
    176   layer->AddChild(border_bottom);
    177   return layer;
    178 }
    179 
    180 scoped_refptr<TextureLayer> LayerTreePixelTest::CreateTextureLayer(
    181     gfx::Rect rect, const SkBitmap& bitmap) {
    182   scoped_refptr<TextureLayer> layer = TextureLayer::CreateForMailbox(NULL);
    183   layer->SetIsDrawable(true);
    184   layer->SetAnchorPoint(gfx::PointF());
    185   layer->SetBounds(rect.size());
    186   layer->SetPosition(rect.origin());
    187 
    188   TextureMailbox texture_mailbox;
    189   scoped_ptr<SingleReleaseCallback> release_callback;
    190   CopyBitmapToTextureMailboxAsTexture(
    191       bitmap, &texture_mailbox, &release_callback);
    192   layer->SetTextureMailbox(texture_mailbox, release_callback.Pass());
    193 
    194   texture_layers_.push_back(layer);
    195   pending_texture_mailbox_callbacks_++;
    196   return layer;
    197 }
    198 
    199 void LayerTreePixelTest::RunPixelTest(
    200     PixelTestType test_type,
    201     scoped_refptr<Layer> content_root,
    202     base::FilePath file_name) {
    203   test_type_ = test_type;
    204   content_root_ = content_root;
    205   readback_target_ = NULL;
    206   ref_file_ = file_name;
    207   RunTest(true, false, impl_side_painting_);
    208 }
    209 
    210 void LayerTreePixelTest::RunPixelTestWithReadbackTarget(
    211     PixelTestType test_type,
    212     scoped_refptr<Layer> content_root,
    213     Layer* target,
    214     base::FilePath file_name) {
    215   test_type_ = test_type;
    216   content_root_ = content_root;
    217   readback_target_ = target;
    218   ref_file_ = file_name;
    219   RunTest(true, false, impl_side_painting_);
    220 }
    221 
    222 void LayerTreePixelTest::SetupTree() {
    223   scoped_refptr<Layer> root = Layer::Create();
    224   root->SetBounds(content_root_->bounds());
    225   root->AddChild(content_root_);
    226   layer_tree_host()->SetRootLayer(root);
    227   LayerTreeTest::SetupTree();
    228 }
    229 
    230 scoped_ptr<SkBitmap> LayerTreePixelTest::CopyTextureMailboxToBitmap(
    231     gfx::Size size,
    232     const TextureMailbox& texture_mailbox) {
    233   DCHECK(texture_mailbox.IsTexture());
    234   if (!texture_mailbox.IsTexture())
    235     return scoped_ptr<SkBitmap>();
    236 
    237   using webkit::gpu::WebGraphicsContext3DInProcessCommandBufferImpl;
    238   scoped_ptr<blink::WebGraphicsContext3D> context3d(
    239       WebGraphicsContext3DInProcessCommandBufferImpl::CreateOffscreenContext(
    240           blink::WebGraphicsContext3D::Attributes()));
    241 
    242   EXPECT_TRUE(context3d->makeContextCurrent());
    243 
    244   if (texture_mailbox.sync_point())
    245     context3d->waitSyncPoint(texture_mailbox.sync_point());
    246 
    247   unsigned texture_id = context3d->createTexture();
    248   context3d->bindTexture(GL_TEXTURE_2D, texture_id);
    249   context3d->texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    250   context3d->texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    251   context3d->texParameteri(
    252       GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    253   context3d->texParameteri(
    254       GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
    255   context3d->consumeTextureCHROMIUM(texture_mailbox.target(),
    256                                     texture_mailbox.data());
    257   context3d->bindTexture(GL_TEXTURE_2D, 0);
    258 
    259   unsigned fbo = context3d->createFramebuffer();
    260   context3d->bindFramebuffer(GL_FRAMEBUFFER, fbo);
    261   context3d->framebufferTexture2D(GL_FRAMEBUFFER,
    262                                   GL_COLOR_ATTACHMENT0,
    263                                   GL_TEXTURE_2D,
    264                                   texture_id,
    265                                   0);
    266   EXPECT_EQ(static_cast<unsigned>(GL_FRAMEBUFFER_COMPLETE),
    267             context3d->checkFramebufferStatus(GL_FRAMEBUFFER));
    268 
    269   scoped_ptr<uint8[]> pixels(new uint8[size.GetArea() * 4]);
    270   context3d->readPixels(0,
    271                         0,
    272                         size.width(),
    273                         size.height(),
    274                         GL_RGBA,
    275                         GL_UNSIGNED_BYTE,
    276                         pixels.get());
    277 
    278   context3d->deleteFramebuffer(fbo);
    279   context3d->deleteTexture(texture_id);
    280 
    281   scoped_ptr<SkBitmap> bitmap(new SkBitmap);
    282   bitmap->setConfig(SkBitmap::kARGB_8888_Config,
    283                     size.width(),
    284                     size.height());
    285   bitmap->allocPixels();
    286 
    287   scoped_ptr<SkAutoLockPixels> lock(new SkAutoLockPixels(*bitmap));
    288   uint8* out_pixels = static_cast<uint8*>(bitmap->getPixels());
    289 
    290   size_t row_bytes = size.width() * 4;
    291   size_t total_bytes = size.height() * row_bytes;
    292   for (size_t dest_y = 0; dest_y < total_bytes; dest_y += row_bytes) {
    293     // Flip Y axis.
    294     size_t src_y = total_bytes - dest_y - row_bytes;
    295     // Swizzle OpenGL -> Skia byte order.
    296     for (size_t x = 0; x < row_bytes; x += 4) {
    297       out_pixels[dest_y + x + SK_R32_SHIFT/8] = pixels.get()[src_y + x + 0];
    298       out_pixels[dest_y + x + SK_G32_SHIFT/8] = pixels.get()[src_y + x + 1];
    299       out_pixels[dest_y + x + SK_B32_SHIFT/8] = pixels.get()[src_y + x + 2];
    300       out_pixels[dest_y + x + SK_A32_SHIFT/8] = pixels.get()[src_y + x + 3];
    301     }
    302   }
    303 
    304   return bitmap.Pass();
    305 }
    306 
    307 void LayerTreePixelTest::ReleaseTextureMailbox(
    308     scoped_ptr<blink::WebGraphicsContext3D> context3d,
    309     uint32 texture,
    310     uint32 sync_point,
    311     bool lost_resource) {
    312   if (sync_point)
    313     context3d->waitSyncPoint(sync_point);
    314   context3d->deleteTexture(texture);
    315   pending_texture_mailbox_callbacks_--;
    316   TryEndTest();
    317 }
    318 
    319 void LayerTreePixelTest::CopyBitmapToTextureMailboxAsTexture(
    320     const SkBitmap& bitmap,
    321     TextureMailbox* texture_mailbox,
    322     scoped_ptr<SingleReleaseCallback>* release_callback) {
    323   DCHECK_GT(bitmap.width(), 0);
    324   DCHECK_GT(bitmap.height(), 0);
    325 
    326   CHECK(gfx::InitializeGLBindings(gfx::kGLImplementationOSMesaGL));
    327 
    328   using webkit::gpu::WebGraphicsContext3DInProcessCommandBufferImpl;
    329   scoped_ptr<blink::WebGraphicsContext3D> context3d(
    330       WebGraphicsContext3DInProcessCommandBufferImpl::CreateOffscreenContext(
    331           blink::WebGraphicsContext3D::Attributes()));
    332 
    333   EXPECT_TRUE(context3d->makeContextCurrent());
    334 
    335   unsigned texture_id = context3d->createTexture();
    336   context3d->bindTexture(GL_TEXTURE_2D, texture_id);
    337   context3d->texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    338   context3d->texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    339   context3d->texParameteri(
    340       GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    341   context3d->texParameteri(
    342       GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
    343 
    344   DCHECK_EQ(SkBitmap::kARGB_8888_Config, bitmap.getConfig());
    345 
    346   {
    347     SkAutoLockPixels lock(bitmap);
    348 
    349     size_t row_bytes = bitmap.width() * 4;
    350     size_t total_bytes = bitmap.height() * row_bytes;
    351 
    352     scoped_ptr<uint8[]> gl_pixels(new uint8[total_bytes]);
    353     uint8* bitmap_pixels = static_cast<uint8*>(bitmap.getPixels());
    354 
    355     for (size_t y = 0; y < total_bytes; y += row_bytes) {
    356       // Flip Y axis.
    357       size_t src_y = total_bytes - y - row_bytes;
    358       // Swizzle Skia -> OpenGL byte order.
    359       for (size_t x = 0; x < row_bytes; x += 4) {
    360         gl_pixels.get()[y + x + 0] = bitmap_pixels[src_y + x + SK_R32_SHIFT/8];
    361         gl_pixels.get()[y + x + 1] = bitmap_pixels[src_y + x + SK_G32_SHIFT/8];
    362         gl_pixels.get()[y + x + 2] = bitmap_pixels[src_y + x + SK_B32_SHIFT/8];
    363         gl_pixels.get()[y + x + 3] = bitmap_pixels[src_y + x + SK_A32_SHIFT/8];
    364       }
    365     }
    366 
    367     context3d->texImage2D(GL_TEXTURE_2D,
    368                           0,
    369                           GL_RGBA,
    370                           bitmap.width(),
    371                           bitmap.height(),
    372                           0,
    373                           GL_RGBA,
    374                           GL_UNSIGNED_BYTE,
    375                           gl_pixels.get());
    376   }
    377 
    378   gpu::Mailbox mailbox;
    379   context3d->genMailboxCHROMIUM(mailbox.name);
    380   context3d->produceTextureCHROMIUM(GL_TEXTURE_2D, mailbox.name);
    381   context3d->bindTexture(GL_TEXTURE_2D, 0);
    382   uint32 sync_point = context3d->insertSyncPoint();
    383 
    384   *texture_mailbox = TextureMailbox(mailbox, sync_point);
    385   *release_callback = SingleReleaseCallback::Create(
    386       base::Bind(&LayerTreePixelTest::ReleaseTextureMailbox,
    387                  base::Unretained(this),
    388                  base::Passed(&context3d),
    389                  texture_id));
    390 }
    391 
    392 }  // namespace cc
    393