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 25namespace cc { 26namespace { 27 28class 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 59TEST_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 117TEST_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 219TEST_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 312TEST_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 379TEST_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