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