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