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/geometry_test_utils.h" 17 #include "cc/test/render_pass_test_common.h" 18 #include "cc/test/render_pass_test_utils.h" 19 #include "testing/gmock/include/gmock/gmock.h" 20 #include "testing/gtest/include/gtest/gtest.h" 21 #include "third_party/skia/include/core/SkCanvas.h" 22 #include "third_party/skia/include/core/SkDevice.h" 23 24 namespace cc { 25 namespace { 26 27 class SoftwareRendererTest : public testing::Test, public RendererClient { 28 public: 29 SoftwareRendererTest() : should_clear_root_render_pass_(true) {} 30 31 void InitializeRenderer( 32 scoped_ptr<SoftwareOutputDevice> software_output_device) { 33 output_surface_ = FakeOutputSurface::CreateSoftware( 34 software_output_device.Pass()); 35 resource_provider_ = ResourceProvider::Create(output_surface_.get(), 0); 36 renderer_ = SoftwareRenderer::Create( 37 this, output_surface_.get(), resource_provider()); 38 } 39 40 ResourceProvider* resource_provider() const { 41 return resource_provider_.get(); 42 } 43 44 SoftwareRenderer* renderer() const { return renderer_.get(); } 45 46 void set_viewport(gfx::Rect viewport) { 47 viewport_ = viewport; 48 } 49 50 void set_should_clear_root_render_pass(bool clear_root_render_pass) { 51 should_clear_root_render_pass_ = clear_root_render_pass; 52 } 53 54 // RendererClient implementation. 55 virtual gfx::Rect DeviceViewport() const OVERRIDE { 56 return viewport_; 57 } 58 virtual float DeviceScaleFactor() const OVERRIDE { 59 return 1.f; 60 } 61 virtual const LayerTreeSettings& Settings() const OVERRIDE { 62 return settings_; 63 } 64 virtual void SetFullRootLayerDamage() OVERRIDE {} 65 virtual bool HasImplThread() const OVERRIDE { return false; } 66 virtual bool ShouldClearRootRenderPass() const OVERRIDE { 67 return should_clear_root_render_pass_; 68 } 69 virtual CompositorFrameMetadata MakeCompositorFrameMetadata() const OVERRIDE { 70 return CompositorFrameMetadata(); 71 } 72 virtual bool AllowPartialSwap() const OVERRIDE { 73 return true; 74 } 75 virtual bool ExternalStencilTestEnabled() const OVERRIDE { return false; } 76 77 protected: 78 scoped_ptr<FakeOutputSurface> output_surface_; 79 scoped_ptr<ResourceProvider> resource_provider_; 80 scoped_ptr<SoftwareRenderer> renderer_; 81 gfx::Rect viewport_; 82 LayerTreeSettings settings_; 83 bool should_clear_root_render_pass_; 84 }; 85 86 TEST_F(SoftwareRendererTest, SolidColorQuad) { 87 gfx::Size outer_size(100, 100); 88 gfx::Size inner_size(98, 98); 89 gfx::Rect outer_rect(outer_size); 90 gfx::Rect inner_rect(gfx::Point(1, 1), inner_size); 91 set_viewport(gfx::Rect(outer_size)); 92 93 InitializeRenderer(make_scoped_ptr(new SoftwareOutputDevice)); 94 95 scoped_ptr<SharedQuadState> shared_quad_state = SharedQuadState::Create(); 96 shared_quad_state->SetAll( 97 gfx::Transform(), outer_size, outer_rect, outer_rect, false, 1.0); 98 RenderPass::Id root_render_pass_id = RenderPass::Id(1, 1); 99 scoped_ptr<TestRenderPass> root_render_pass = TestRenderPass::Create(); 100 root_render_pass->SetNew( 101 root_render_pass_id, outer_rect, outer_rect, gfx::Transform()); 102 scoped_ptr<SolidColorDrawQuad> outer_quad = SolidColorDrawQuad::Create(); 103 outer_quad->SetNew( 104 shared_quad_state.get(), outer_rect, SK_ColorYELLOW, false); 105 scoped_ptr<SolidColorDrawQuad> inner_quad = SolidColorDrawQuad::Create(); 106 inner_quad->SetNew(shared_quad_state.get(), inner_rect, SK_ColorCYAN, false); 107 root_render_pass->AppendQuad(inner_quad.PassAs<DrawQuad>()); 108 root_render_pass->AppendQuad(outer_quad.PassAs<DrawQuad>()); 109 110 RenderPassList list; 111 list.push_back(root_render_pass.PassAs<RenderPass>()); 112 renderer()->DrawFrame(&list); 113 114 SkBitmap output; 115 output.setConfig(SkBitmap::kARGB_8888_Config, 116 DeviceViewport().width(), 117 DeviceViewport().height()); 118 output.allocPixels(); 119 renderer()->GetFramebufferPixels(output.getPixels(), outer_rect); 120 121 EXPECT_EQ(SK_ColorYELLOW, output.getColor(0, 0)); 122 EXPECT_EQ(SK_ColorYELLOW, 123 output.getColor(outer_size.width() - 1, outer_size.height() - 1)); 124 EXPECT_EQ(SK_ColorCYAN, output.getColor(1, 1)); 125 EXPECT_EQ(SK_ColorCYAN, 126 output.getColor(inner_size.width() - 1, inner_size.height() - 1)); 127 } 128 129 TEST_F(SoftwareRendererTest, TileQuad) { 130 gfx::Size outer_size(100, 100); 131 gfx::Size inner_size(98, 98); 132 gfx::Rect outer_rect(outer_size); 133 gfx::Rect inner_rect(gfx::Point(1, 1), inner_size); 134 set_viewport(gfx::Rect(outer_size)); 135 InitializeRenderer(make_scoped_ptr(new SoftwareOutputDevice)); 136 137 ResourceProvider::ResourceId resource_yellow = 138 resource_provider()->CreateResource( 139 outer_size, GL_RGBA, ResourceProvider::TextureUsageAny); 140 ResourceProvider::ResourceId resource_cyan = 141 resource_provider()->CreateResource( 142 inner_size, GL_RGBA, ResourceProvider::TextureUsageAny); 143 144 SkBitmap yellow_tile; 145 yellow_tile.setConfig( 146 SkBitmap::kARGB_8888_Config, outer_size.width(), outer_size.height()); 147 yellow_tile.allocPixels(); 148 yellow_tile.eraseColor(SK_ColorYELLOW); 149 150 SkBitmap cyan_tile; 151 cyan_tile.setConfig( 152 SkBitmap::kARGB_8888_Config, inner_size.width(), inner_size.height()); 153 cyan_tile.allocPixels(); 154 cyan_tile.eraseColor(SK_ColorCYAN); 155 156 resource_provider()->SetPixels( 157 resource_yellow, 158 static_cast<uint8_t*>(yellow_tile.getPixels()), 159 gfx::Rect(outer_size), 160 gfx::Rect(outer_size), 161 gfx::Vector2d()); 162 resource_provider()->SetPixels(resource_cyan, 163 static_cast<uint8_t*>(cyan_tile.getPixels()), 164 gfx::Rect(inner_size), 165 gfx::Rect(inner_size), 166 gfx::Vector2d()); 167 168 gfx::Rect root_rect = DeviceViewport(); 169 170 scoped_ptr<SharedQuadState> shared_quad_state = SharedQuadState::Create(); 171 shared_quad_state->SetAll( 172 gfx::Transform(), outer_size, outer_rect, outer_rect, false, 1.0); 173 RenderPass::Id root_render_pass_id = RenderPass::Id(1, 1); 174 scoped_ptr<TestRenderPass> root_render_pass = TestRenderPass::Create(); 175 root_render_pass->SetNew( 176 root_render_pass_id, root_rect, root_rect, gfx::Transform()); 177 scoped_ptr<TileDrawQuad> outer_quad = TileDrawQuad::Create(); 178 outer_quad->SetNew(shared_quad_state.get(), 179 outer_rect, 180 outer_rect, 181 resource_yellow, 182 gfx::RectF(outer_size), 183 outer_size, 184 false); 185 scoped_ptr<TileDrawQuad> inner_quad = TileDrawQuad::Create(); 186 inner_quad->SetNew(shared_quad_state.get(), 187 inner_rect, 188 inner_rect, 189 resource_cyan, 190 gfx::RectF(inner_size), 191 inner_size, 192 false); 193 root_render_pass->AppendQuad(inner_quad.PassAs<DrawQuad>()); 194 root_render_pass->AppendQuad(outer_quad.PassAs<DrawQuad>()); 195 196 RenderPassList list; 197 list.push_back(root_render_pass.PassAs<RenderPass>()); 198 renderer()->DrawFrame(&list); 199 200 SkBitmap output; 201 output.setConfig(SkBitmap::kARGB_8888_Config, 202 DeviceViewport().width(), 203 DeviceViewport().height()); 204 output.allocPixels(); 205 renderer()->GetFramebufferPixels(output.getPixels(), outer_rect); 206 207 EXPECT_EQ(SK_ColorYELLOW, output.getColor(0, 0)); 208 EXPECT_EQ(SK_ColorYELLOW, 209 output.getColor(outer_size.width() - 1, outer_size.height() - 1)); 210 EXPECT_EQ(SK_ColorCYAN, output.getColor(1, 1)); 211 EXPECT_EQ(SK_ColorCYAN, 212 output.getColor(inner_size.width() - 1, inner_size.height() - 1)); 213 } 214 215 TEST_F(SoftwareRendererTest, ShouldClearRootRenderPass) { 216 gfx::Rect viewport_rect(0, 0, 100, 100); 217 set_viewport(viewport_rect); 218 set_should_clear_root_render_pass(false); 219 InitializeRenderer(make_scoped_ptr(new SoftwareOutputDevice)); 220 221 RenderPassList list; 222 223 SkBitmap output; 224 output.setConfig(SkBitmap::kARGB_8888_Config, 225 viewport_rect.width(), 226 viewport_rect.height()); 227 output.allocPixels(); 228 229 // Draw a fullscreen green quad in a first frame. 230 RenderPass::Id root_clear_pass_id(1, 0); 231 TestRenderPass* root_clear_pass = AddRenderPass( 232 &list, root_clear_pass_id, viewport_rect, gfx::Transform()); 233 AddQuad(root_clear_pass, viewport_rect, SK_ColorGREEN); 234 235 renderer()->DecideRenderPassAllocationsForFrame(list); 236 renderer()->DrawFrame(&list); 237 renderer()->GetFramebufferPixels(output.getPixels(), viewport_rect); 238 239 EXPECT_EQ(SK_ColorGREEN, output.getColor(0, 0)); 240 EXPECT_EQ(SK_ColorGREEN, 241 output.getColor(viewport_rect.width() - 1, viewport_rect.height() - 1)); 242 243 list.clear(); 244 245 // Draw a smaller magenta rect without filling the viewport in a separate 246 // frame. 247 gfx::Rect smaller_rect(20, 20, 60, 60); 248 249 RenderPass::Id root_smaller_pass_id(2, 0); 250 TestRenderPass* root_smaller_pass = AddRenderPass( 251 &list, root_smaller_pass_id, viewport_rect, gfx::Transform()); 252 AddQuad(root_smaller_pass, smaller_rect, SK_ColorMAGENTA); 253 254 renderer()->DecideRenderPassAllocationsForFrame(list); 255 renderer()->DrawFrame(&list); 256 renderer()->GetFramebufferPixels(output.getPixels(), viewport_rect); 257 258 // If we didn't clear, the borders should still be green. 259 EXPECT_EQ(SK_ColorGREEN, output.getColor(0, 0)); 260 EXPECT_EQ(SK_ColorGREEN, 261 output.getColor(viewport_rect.width() - 1, viewport_rect.height() - 1)); 262 263 EXPECT_EQ(SK_ColorMAGENTA, 264 output.getColor(smaller_rect.x(), smaller_rect.y())); 265 EXPECT_EQ(SK_ColorMAGENTA, 266 output.getColor(smaller_rect.right() - 1, smaller_rect.bottom() - 1)); 267 } 268 269 } // namespace 270 } // namespace cc 271