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