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