Home | History | Annotate | Download | only in output
      1 // Copyright 2012 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/output/software_renderer.h"
      6 
      7 #include "base/run_loop.h"
      8 #include "cc/output/compositor_frame_metadata.h"
      9 #include "cc/output/copy_output_request.h"
     10 #include "cc/output/copy_output_result.h"
     11 #include "cc/output/software_output_device.h"
     12 #include "cc/quads/render_pass.h"
     13 #include "cc/quads/render_pass_draw_quad.h"
     14 #include "cc/quads/solid_color_draw_quad.h"
     15 #include "cc/quads/tile_draw_quad.h"
     16 #include "cc/test/animation_test_common.h"
     17 #include "cc/test/fake_output_surface.h"
     18 #include "cc/test/fake_output_surface_client.h"
     19 #include "cc/test/geometry_test_utils.h"
     20 #include "cc/test/render_pass_test_common.h"
     21 #include "cc/test/render_pass_test_utils.h"
     22 #include "cc/test/test_shared_bitmap_manager.h"
     23 #include "testing/gmock/include/gmock/gmock.h"
     24 #include "testing/gtest/include/gtest/gtest.h"
     25 #include "third_party/skia/include/core/SkCanvas.h"
     26 
     27 namespace cc {
     28 namespace {
     29 
     30 class SoftwareRendererTest : public testing::Test, public RendererClient {
     31  public:
     32   void InitializeRenderer(
     33       scoped_ptr<SoftwareOutputDevice> software_output_device) {
     34     output_surface_ = FakeOutputSurface::CreateSoftware(
     35         software_output_device.Pass());
     36     CHECK(output_surface_->BindToClient(&output_surface_client_));
     37 
     38     shared_bitmap_manager_.reset(new TestSharedBitmapManager());
     39     resource_provider_ = ResourceProvider::Create(output_surface_.get(),
     40                                                   shared_bitmap_manager_.get(),
     41                                                   NULL,
     42                                                   0,
     43                                                   false,
     44                                                   1,
     45                                                   false);
     46     renderer_ = SoftwareRenderer::Create(
     47         this, &settings_, output_surface_.get(), resource_provider());
     48   }
     49 
     50   ResourceProvider* resource_provider() const {
     51     return resource_provider_.get();
     52   }
     53 
     54   SoftwareRenderer* renderer() const { return renderer_.get(); }
     55 
     56   // RendererClient implementation.
     57   virtual void SetFullRootLayerDamage() OVERRIDE {}
     58 
     59   scoped_ptr<SkBitmap> DrawAndCopyOutput(RenderPassList* list,
     60                                          float device_scale_factor,
     61                                          gfx::Rect device_viewport_rect) {
     62     scoped_ptr<SkBitmap> bitmap_result;
     63     base::RunLoop loop;
     64 
     65     list->back()->copy_requests.push_back(
     66         CopyOutputRequest::CreateBitmapRequest(
     67             base::Bind(&SoftwareRendererTest::SaveBitmapResult,
     68                        base::Unretained(&bitmap_result),
     69                        loop.QuitClosure())));
     70 
     71     renderer()->DrawFrame(list,
     72                           device_scale_factor,
     73                           device_viewport_rect,
     74                           device_viewport_rect,
     75                           false);
     76     loop.Run();
     77     return bitmap_result.Pass();
     78   }
     79 
     80   static void SaveBitmapResult(scoped_ptr<SkBitmap>* bitmap_result,
     81                                const base::Closure& quit_closure,
     82                                scoped_ptr<CopyOutputResult> result) {
     83     DCHECK(result->HasBitmap());
     84     *bitmap_result = result->TakeBitmap();
     85     quit_closure.Run();
     86   }
     87 
     88  protected:
     89   LayerTreeSettings settings_;
     90   FakeOutputSurfaceClient output_surface_client_;
     91   scoped_ptr<FakeOutputSurface> output_surface_;
     92   scoped_ptr<SharedBitmapManager> shared_bitmap_manager_;
     93   scoped_ptr<ResourceProvider> resource_provider_;
     94   scoped_ptr<SoftwareRenderer> renderer_;
     95 };
     96 
     97 TEST_F(SoftwareRendererTest, SolidColorQuad) {
     98   gfx::Size outer_size(100, 100);
     99   gfx::Size inner_size(98, 98);
    100   gfx::Rect outer_rect(outer_size);
    101   gfx::Rect inner_rect(gfx::Point(1, 1), inner_size);
    102   gfx::Rect visible_rect(gfx::Point(1, 2), gfx::Size(98, 97));
    103 
    104   InitializeRenderer(make_scoped_ptr(new SoftwareOutputDevice));
    105 
    106   RenderPassId root_render_pass_id = RenderPassId(1, 1);
    107   scoped_ptr<TestRenderPass> root_render_pass = TestRenderPass::Create();
    108   root_render_pass->SetNew(
    109       root_render_pass_id, outer_rect, outer_rect, gfx::Transform());
    110   SharedQuadState* shared_quad_state =
    111       root_render_pass->CreateAndAppendSharedQuadState();
    112   shared_quad_state->SetAll(gfx::Transform(),
    113                             outer_size,
    114                             outer_rect,
    115                             outer_rect,
    116                             false,
    117                             1.0,
    118                             SkXfermode::kSrcOver_Mode,
    119                             0);
    120   SolidColorDrawQuad* inner_quad =
    121       root_render_pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>();
    122   inner_quad->SetNew(
    123       shared_quad_state, inner_rect, inner_rect, SK_ColorCYAN, false);
    124   inner_quad->visible_rect = visible_rect;
    125   SolidColorDrawQuad* outer_quad =
    126       root_render_pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>();
    127   outer_quad->SetNew(
    128       shared_quad_state, outer_rect, outer_rect, SK_ColorYELLOW, false);
    129 
    130   RenderPassList list;
    131   list.push_back(root_render_pass.PassAs<RenderPass>());
    132 
    133   float device_scale_factor = 1.f;
    134   gfx::Rect device_viewport_rect(outer_size);
    135   scoped_ptr<SkBitmap> output =
    136       DrawAndCopyOutput(&list, device_scale_factor, device_viewport_rect);
    137   EXPECT_EQ(outer_rect.width(), output->info().fWidth);
    138   EXPECT_EQ(outer_rect.width(), output->info().fHeight);
    139 
    140   EXPECT_EQ(SK_ColorYELLOW, output->getColor(0, 0));
    141   EXPECT_EQ(SK_ColorYELLOW,
    142             output->getColor(outer_size.width() - 1, outer_size.height() - 1));
    143   EXPECT_EQ(SK_ColorYELLOW, output->getColor(1, 1));
    144   EXPECT_EQ(SK_ColorCYAN, output->getColor(1, 2));
    145   EXPECT_EQ(SK_ColorCYAN,
    146             output->getColor(inner_size.width() - 1, inner_size.height() - 1));
    147 }
    148 
    149 TEST_F(SoftwareRendererTest, TileQuad) {
    150   gfx::Size outer_size(100, 100);
    151   gfx::Size inner_size(98, 98);
    152   gfx::Rect outer_rect(outer_size);
    153   gfx::Rect inner_rect(gfx::Point(1, 1), inner_size);
    154   InitializeRenderer(make_scoped_ptr(new SoftwareOutputDevice));
    155 
    156   ResourceProvider::ResourceId resource_yellow =
    157       resource_provider()->CreateResource(
    158           outer_size,
    159           GL_CLAMP_TO_EDGE,
    160           ResourceProvider::TextureHintImmutable,
    161           RGBA_8888);
    162   ResourceProvider::ResourceId resource_cyan =
    163       resource_provider()->CreateResource(
    164           inner_size,
    165           GL_CLAMP_TO_EDGE,
    166           ResourceProvider::TextureHintImmutable,
    167           RGBA_8888);
    168 
    169   SkBitmap yellow_tile;
    170   yellow_tile.allocN32Pixels(outer_size.width(), outer_size.height());
    171   yellow_tile.eraseColor(SK_ColorYELLOW);
    172 
    173   SkBitmap cyan_tile;
    174   cyan_tile.allocN32Pixels(inner_size.width(), inner_size.height());
    175   cyan_tile.eraseColor(SK_ColorCYAN);
    176 
    177   resource_provider()->SetPixels(
    178       resource_yellow,
    179       static_cast<uint8_t*>(yellow_tile.getPixels()),
    180       gfx::Rect(outer_size),
    181       gfx::Rect(outer_size),
    182       gfx::Vector2d());
    183   resource_provider()->SetPixels(resource_cyan,
    184                                  static_cast<uint8_t*>(cyan_tile.getPixels()),
    185                                  gfx::Rect(inner_size),
    186                                  gfx::Rect(inner_size),
    187                                  gfx::Vector2d());
    188 
    189   gfx::Rect root_rect = outer_rect;
    190 
    191   RenderPassId root_render_pass_id = RenderPassId(1, 1);
    192   scoped_ptr<TestRenderPass> root_render_pass = TestRenderPass::Create();
    193   root_render_pass->SetNew(
    194       root_render_pass_id, root_rect, root_rect, gfx::Transform());
    195   SharedQuadState* shared_quad_state =
    196       root_render_pass->CreateAndAppendSharedQuadState();
    197   shared_quad_state->SetAll(gfx::Transform(),
    198                             outer_size,
    199                             outer_rect,
    200                             outer_rect,
    201                             false,
    202                             1.0,
    203                             SkXfermode::kSrcOver_Mode,
    204                             0);
    205   TileDrawQuad* inner_quad =
    206       root_render_pass->CreateAndAppendDrawQuad<TileDrawQuad>();
    207   inner_quad->SetNew(shared_quad_state,
    208                      inner_rect,
    209                      inner_rect,
    210                      inner_rect,
    211                      resource_cyan,
    212                      gfx::RectF(inner_size),
    213                      inner_size,
    214                      false);
    215   TileDrawQuad* outer_quad =
    216       root_render_pass->CreateAndAppendDrawQuad<TileDrawQuad>();
    217   outer_quad->SetNew(shared_quad_state,
    218                      outer_rect,
    219                      outer_rect,
    220                      outer_rect,
    221                      resource_yellow,
    222                      gfx::RectF(outer_size),
    223                      outer_size,
    224                      false);
    225 
    226   RenderPassList list;
    227   list.push_back(root_render_pass.PassAs<RenderPass>());
    228 
    229   float device_scale_factor = 1.f;
    230   gfx::Rect device_viewport_rect(outer_size);
    231   scoped_ptr<SkBitmap> output =
    232       DrawAndCopyOutput(&list, device_scale_factor, device_viewport_rect);
    233   EXPECT_EQ(outer_rect.width(), output->info().fWidth);
    234   EXPECT_EQ(outer_rect.width(), output->info().fHeight);
    235 
    236   EXPECT_EQ(SK_ColorYELLOW, output->getColor(0, 0));
    237   EXPECT_EQ(SK_ColorYELLOW,
    238             output->getColor(outer_size.width() - 1, outer_size.height() - 1));
    239   EXPECT_EQ(SK_ColorCYAN, output->getColor(1, 1));
    240   EXPECT_EQ(SK_ColorCYAN,
    241             output->getColor(inner_size.width() - 1, inner_size.height() - 1));
    242 }
    243 
    244 TEST_F(SoftwareRendererTest, TileQuadVisibleRect) {
    245   gfx::Size tile_size(100, 100);
    246   gfx::Rect tile_rect(tile_size);
    247   gfx::Rect visible_rect = tile_rect;
    248   visible_rect.Inset(1, 2, 3, 4);
    249   InitializeRenderer(make_scoped_ptr(new SoftwareOutputDevice));
    250 
    251   ResourceProvider::ResourceId resource_cyan =
    252       resource_provider()->CreateResource(
    253           tile_size,
    254           GL_CLAMP_TO_EDGE,
    255           ResourceProvider::TextureHintImmutable,
    256           RGBA_8888);
    257 
    258   SkBitmap cyan_tile;  // The lowest five rows are yellow.
    259   cyan_tile.allocN32Pixels(tile_size.width(), tile_size.height());
    260   cyan_tile.eraseColor(SK_ColorCYAN);
    261   cyan_tile.eraseArea(
    262       SkIRect::MakeLTRB(
    263           0, visible_rect.bottom() - 1, tile_rect.width(), tile_rect.bottom()),
    264       SK_ColorYELLOW);
    265 
    266   resource_provider()->SetPixels(resource_cyan,
    267                                  static_cast<uint8_t*>(cyan_tile.getPixels()),
    268                                  gfx::Rect(tile_size),
    269                                  gfx::Rect(tile_size),
    270                                  gfx::Vector2d());
    271 
    272   gfx::Rect root_rect(tile_size);
    273 
    274   RenderPassId root_render_pass_id = RenderPassId(1, 1);
    275   scoped_ptr<TestRenderPass> root_render_pass = TestRenderPass::Create();
    276   root_render_pass->SetNew(
    277       root_render_pass_id, root_rect, root_rect, gfx::Transform());
    278   SharedQuadState* shared_quad_state =
    279       root_render_pass->CreateAndAppendSharedQuadState();
    280   shared_quad_state->SetAll(gfx::Transform(),
    281                             tile_size,
    282                             tile_rect,
    283                             tile_rect,
    284                             false,
    285                             1.0,
    286                             SkXfermode::kSrcOver_Mode,
    287                             0);
    288   TileDrawQuad* quad =
    289       root_render_pass->CreateAndAppendDrawQuad<TileDrawQuad>();
    290   quad->SetNew(shared_quad_state,
    291                tile_rect,
    292                tile_rect,
    293                tile_rect,
    294                resource_cyan,
    295                gfx::RectF(tile_size),
    296                tile_size,
    297                false);
    298   quad->visible_rect = visible_rect;
    299 
    300   RenderPassList list;
    301   list.push_back(root_render_pass.PassAs<RenderPass>());
    302 
    303   float device_scale_factor = 1.f;
    304   gfx::Rect device_viewport_rect(tile_size);
    305   scoped_ptr<SkBitmap> output =
    306       DrawAndCopyOutput(&list, device_scale_factor, device_viewport_rect);
    307   EXPECT_EQ(tile_rect.width(), output->info().fWidth);
    308   EXPECT_EQ(tile_rect.width(), output->info().fHeight);
    309 
    310   // Check portion of tile not in visible rect isn't drawn.
    311   const unsigned int kTransparent = SK_ColorTRANSPARENT;
    312   EXPECT_EQ(kTransparent, output->getColor(0, 0));
    313   EXPECT_EQ(kTransparent,
    314             output->getColor(tile_rect.width() - 1, tile_rect.height() - 1));
    315   EXPECT_EQ(kTransparent,
    316             output->getColor(visible_rect.x() - 1, visible_rect.y() - 1));
    317   EXPECT_EQ(kTransparent,
    318             output->getColor(visible_rect.right(), visible_rect.bottom()));
    319   // Ensure visible part is drawn correctly.
    320   EXPECT_EQ(SK_ColorCYAN, output->getColor(visible_rect.x(), visible_rect.y()));
    321   EXPECT_EQ(
    322       SK_ColorCYAN,
    323       output->getColor(visible_rect.right() - 2, visible_rect.bottom() - 2));
    324   // Ensure last visible line is correct.
    325   EXPECT_EQ(
    326       SK_ColorYELLOW,
    327       output->getColor(visible_rect.right() - 1, visible_rect.bottom() - 1));
    328 }
    329 
    330 TEST_F(SoftwareRendererTest, ShouldClearRootRenderPass) {
    331   float device_scale_factor = 1.f;
    332   gfx::Rect device_viewport_rect(0, 0, 100, 100);
    333 
    334   settings_.should_clear_root_render_pass = false;
    335   InitializeRenderer(make_scoped_ptr(new SoftwareOutputDevice));
    336 
    337   RenderPassList list;
    338 
    339   // Draw a fullscreen green quad in a first frame.
    340   RenderPassId root_clear_pass_id(1, 0);
    341   TestRenderPass* root_clear_pass = AddRenderPass(
    342       &list, root_clear_pass_id, device_viewport_rect, gfx::Transform());
    343   AddQuad(root_clear_pass, device_viewport_rect, SK_ColorGREEN);
    344 
    345   renderer()->DecideRenderPassAllocationsForFrame(list);
    346 
    347   scoped_ptr<SkBitmap> output =
    348       DrawAndCopyOutput(&list, device_scale_factor, device_viewport_rect);
    349   EXPECT_EQ(device_viewport_rect.width(), output->info().fWidth);
    350   EXPECT_EQ(device_viewport_rect.width(), output->info().fHeight);
    351 
    352   EXPECT_EQ(SK_ColorGREEN, output->getColor(0, 0));
    353   EXPECT_EQ(SK_ColorGREEN,
    354             output->getColor(device_viewport_rect.width() - 1,
    355                              device_viewport_rect.height() - 1));
    356 
    357   list.clear();
    358 
    359   // Draw a smaller magenta rect without filling the viewport in a separate
    360   // frame.
    361   gfx::Rect smaller_rect(20, 20, 60, 60);
    362 
    363   RenderPassId root_smaller_pass_id(2, 0);
    364   TestRenderPass* root_smaller_pass = AddRenderPass(
    365       &list, root_smaller_pass_id, device_viewport_rect, gfx::Transform());
    366   AddQuad(root_smaller_pass, smaller_rect, SK_ColorMAGENTA);
    367 
    368   renderer()->DecideRenderPassAllocationsForFrame(list);
    369 
    370   output = DrawAndCopyOutput(&list, device_scale_factor, device_viewport_rect);
    371   EXPECT_EQ(device_viewport_rect.width(), output->info().fWidth);
    372   EXPECT_EQ(device_viewport_rect.width(), output->info().fHeight);
    373 
    374   // If we didn't clear, the borders should still be green.
    375   EXPECT_EQ(SK_ColorGREEN, output->getColor(0, 0));
    376   EXPECT_EQ(SK_ColorGREEN,
    377             output->getColor(device_viewport_rect.width() - 1,
    378                              device_viewport_rect.height() - 1));
    379 
    380   EXPECT_EQ(SK_ColorMAGENTA,
    381             output->getColor(smaller_rect.x(), smaller_rect.y()));
    382   EXPECT_EQ(
    383       SK_ColorMAGENTA,
    384       output->getColor(smaller_rect.right() - 1, smaller_rect.bottom() - 1));
    385 }
    386 
    387 TEST_F(SoftwareRendererTest, RenderPassVisibleRect) {
    388   float device_scale_factor = 1.f;
    389   gfx::Rect device_viewport_rect(0, 0, 100, 100);
    390   InitializeRenderer(make_scoped_ptr(new SoftwareOutputDevice));
    391 
    392   RenderPassList list;
    393 
    394   // Pass drawn as inner quad is magenta.
    395   gfx::Rect smaller_rect(20, 20, 60, 60);
    396   RenderPassId smaller_pass_id(2, 1);
    397   TestRenderPass* smaller_pass =
    398       AddRenderPass(&list, smaller_pass_id, smaller_rect, gfx::Transform());
    399   AddQuad(smaller_pass, smaller_rect, SK_ColorMAGENTA);
    400 
    401   // Root pass is green.
    402   RenderPassId root_clear_pass_id(1, 0);
    403   TestRenderPass* root_clear_pass = AddRenderPass(
    404       &list, root_clear_pass_id, device_viewport_rect, gfx::Transform());
    405   AddRenderPassQuad(root_clear_pass, smaller_pass);
    406   AddQuad(root_clear_pass, device_viewport_rect, SK_ColorGREEN);
    407 
    408   // Interior pass quad has smaller visible rect.
    409   gfx::Rect interior_visible_rect(30, 30, 40, 40);
    410   root_clear_pass->quad_list.front()->visible_rect = interior_visible_rect;
    411 
    412   renderer()->DecideRenderPassAllocationsForFrame(list);
    413 
    414   scoped_ptr<SkBitmap> output =
    415       DrawAndCopyOutput(&list, device_scale_factor, device_viewport_rect);
    416   EXPECT_EQ(device_viewport_rect.width(), output->info().fWidth);
    417   EXPECT_EQ(device_viewport_rect.width(), output->info().fHeight);
    418 
    419   EXPECT_EQ(SK_ColorGREEN, output->getColor(0, 0));
    420   EXPECT_EQ(SK_ColorGREEN,
    421             output->getColor(device_viewport_rect.width() - 1,
    422                              device_viewport_rect.height() - 1));
    423 
    424   // Part outside visible rect should remain green.
    425   EXPECT_EQ(SK_ColorGREEN,
    426             output->getColor(smaller_rect.x(), smaller_rect.y()));
    427   EXPECT_EQ(
    428       SK_ColorGREEN,
    429       output->getColor(smaller_rect.right() - 1, smaller_rect.bottom() - 1));
    430 
    431   EXPECT_EQ(
    432       SK_ColorMAGENTA,
    433       output->getColor(interior_visible_rect.x(), interior_visible_rect.y()));
    434   EXPECT_EQ(SK_ColorMAGENTA,
    435             output->getColor(interior_visible_rect.right() - 1,
    436                              interior_visible_rect.bottom() - 1));
    437 }
    438 
    439 }  // namespace
    440 }  // namespace cc
    441