OLD | NEW |
(Empty) | |
| 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 NULL, |
| 43 0, |
| 44 false, |
| 45 1); |
| 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 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 RendererSettings 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.Pass()); |
| 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.height(), 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, GL_CLAMP_TO_EDGE, |
| 159 ResourceProvider::TEXTURE_HINT_IMMUTABLE, RGBA_8888); |
| 160 ResourceProvider::ResourceId resource_cyan = |
| 161 resource_provider()->CreateResource( |
| 162 inner_size, GL_CLAMP_TO_EDGE, |
| 163 ResourceProvider::TEXTURE_HINT_IMMUTABLE, RGBA_8888); |
| 164 |
| 165 SkBitmap yellow_tile; |
| 166 yellow_tile.allocN32Pixels(outer_size.width(), outer_size.height()); |
| 167 yellow_tile.eraseColor(SK_ColorYELLOW); |
| 168 |
| 169 SkBitmap cyan_tile; |
| 170 cyan_tile.allocN32Pixels(inner_size.width(), inner_size.height()); |
| 171 cyan_tile.eraseColor(SK_ColorCYAN); |
| 172 |
| 173 resource_provider()->CopyToResource( |
| 174 resource_yellow, static_cast<uint8_t*>(yellow_tile.getPixels()), |
| 175 outer_size); |
| 176 resource_provider()->CopyToResource( |
| 177 resource_cyan, static_cast<uint8_t*>(cyan_tile.getPixels()), inner_size); |
| 178 |
| 179 gfx::Rect root_rect = outer_rect; |
| 180 |
| 181 RenderPassId root_render_pass_id = RenderPassId(1, 1); |
| 182 scoped_ptr<TestRenderPass> root_render_pass = TestRenderPass::Create(); |
| 183 root_render_pass->SetNew( |
| 184 root_render_pass_id, root_rect, root_rect, gfx::Transform()); |
| 185 SharedQuadState* shared_quad_state = |
| 186 root_render_pass->CreateAndAppendSharedQuadState(); |
| 187 shared_quad_state->SetAll(gfx::Transform(), |
| 188 outer_size, |
| 189 outer_rect, |
| 190 outer_rect, |
| 191 false, |
| 192 1.0, |
| 193 SkXfermode::kSrcOver_Mode, |
| 194 0); |
| 195 TileDrawQuad* inner_quad = |
| 196 root_render_pass->CreateAndAppendDrawQuad<TileDrawQuad>(); |
| 197 inner_quad->SetNew(shared_quad_state, |
| 198 inner_rect, |
| 199 inner_rect, |
| 200 inner_rect, |
| 201 resource_cyan, |
| 202 gfx::RectF(inner_size), |
| 203 inner_size, |
| 204 false, |
| 205 false); |
| 206 TileDrawQuad* outer_quad = |
| 207 root_render_pass->CreateAndAppendDrawQuad<TileDrawQuad>(); |
| 208 outer_quad->SetNew(shared_quad_state, |
| 209 outer_rect, |
| 210 outer_rect, |
| 211 outer_rect, |
| 212 resource_yellow, |
| 213 gfx::RectF(outer_size), |
| 214 outer_size, |
| 215 false, |
| 216 false); |
| 217 |
| 218 RenderPassList list; |
| 219 list.push_back(root_render_pass.Pass()); |
| 220 |
| 221 float device_scale_factor = 1.f; |
| 222 gfx::Rect device_viewport_rect(outer_size); |
| 223 scoped_ptr<SkBitmap> output = |
| 224 DrawAndCopyOutput(&list, device_scale_factor, device_viewport_rect); |
| 225 EXPECT_EQ(outer_rect.width(), output->info().fWidth); |
| 226 EXPECT_EQ(outer_rect.height(), output->info().fHeight); |
| 227 |
| 228 EXPECT_EQ(SK_ColorYELLOW, output->getColor(0, 0)); |
| 229 EXPECT_EQ(SK_ColorYELLOW, |
| 230 output->getColor(outer_size.width() - 1, outer_size.height() - 1)); |
| 231 EXPECT_EQ(SK_ColorCYAN, output->getColor(1, 1)); |
| 232 EXPECT_EQ(SK_ColorCYAN, |
| 233 output->getColor(inner_size.width() - 1, inner_size.height() - 1)); |
| 234 } |
| 235 |
| 236 TEST_F(SoftwareRendererTest, TileQuadVisibleRect) { |
| 237 gfx::Size tile_size(100, 100); |
| 238 gfx::Rect tile_rect(tile_size); |
| 239 gfx::Rect visible_rect = tile_rect; |
| 240 visible_rect.Inset(1, 2, 3, 4); |
| 241 InitializeRenderer(make_scoped_ptr(new SoftwareOutputDevice)); |
| 242 |
| 243 ResourceProvider::ResourceId resource_cyan = |
| 244 resource_provider()->CreateResource( |
| 245 tile_size, GL_CLAMP_TO_EDGE, ResourceProvider::TEXTURE_HINT_IMMUTABLE, |
| 246 RGBA_8888); |
| 247 |
| 248 SkBitmap cyan_tile; // The lowest five rows are yellow. |
| 249 cyan_tile.allocN32Pixels(tile_size.width(), tile_size.height()); |
| 250 cyan_tile.eraseColor(SK_ColorCYAN); |
| 251 cyan_tile.eraseArea( |
| 252 SkIRect::MakeLTRB( |
| 253 0, visible_rect.bottom() - 1, tile_rect.width(), tile_rect.bottom()), |
| 254 SK_ColorYELLOW); |
| 255 |
| 256 resource_provider()->CopyToResource( |
| 257 resource_cyan, static_cast<uint8_t*>(cyan_tile.getPixels()), tile_size); |
| 258 |
| 259 gfx::Rect root_rect(tile_size); |
| 260 |
| 261 RenderPassId root_render_pass_id = RenderPassId(1, 1); |
| 262 scoped_ptr<TestRenderPass> root_render_pass = TestRenderPass::Create(); |
| 263 root_render_pass->SetNew( |
| 264 root_render_pass_id, root_rect, root_rect, gfx::Transform()); |
| 265 SharedQuadState* shared_quad_state = |
| 266 root_render_pass->CreateAndAppendSharedQuadState(); |
| 267 shared_quad_state->SetAll(gfx::Transform(), |
| 268 tile_size, |
| 269 tile_rect, |
| 270 tile_rect, |
| 271 false, |
| 272 1.0, |
| 273 SkXfermode::kSrcOver_Mode, |
| 274 0); |
| 275 TileDrawQuad* quad = |
| 276 root_render_pass->CreateAndAppendDrawQuad<TileDrawQuad>(); |
| 277 quad->SetNew(shared_quad_state, |
| 278 tile_rect, |
| 279 tile_rect, |
| 280 tile_rect, |
| 281 resource_cyan, |
| 282 gfx::RectF(tile_size), |
| 283 tile_size, |
| 284 false, |
| 285 false); |
| 286 quad->visible_rect = visible_rect; |
| 287 |
| 288 RenderPassList list; |
| 289 list.push_back(root_render_pass.Pass()); |
| 290 |
| 291 float device_scale_factor = 1.f; |
| 292 gfx::Rect device_viewport_rect(tile_size); |
| 293 scoped_ptr<SkBitmap> output = |
| 294 DrawAndCopyOutput(&list, device_scale_factor, device_viewport_rect); |
| 295 EXPECT_EQ(tile_rect.width(), output->info().fWidth); |
| 296 EXPECT_EQ(tile_rect.height(), output->info().fHeight); |
| 297 |
| 298 // Check portion of tile not in visible rect isn't drawn. |
| 299 const unsigned int kTransparent = SK_ColorTRANSPARENT; |
| 300 EXPECT_EQ(kTransparent, output->getColor(0, 0)); |
| 301 EXPECT_EQ(kTransparent, |
| 302 output->getColor(tile_rect.width() - 1, tile_rect.height() - 1)); |
| 303 EXPECT_EQ(kTransparent, |
| 304 output->getColor(visible_rect.x() - 1, visible_rect.y() - 1)); |
| 305 EXPECT_EQ(kTransparent, |
| 306 output->getColor(visible_rect.right(), visible_rect.bottom())); |
| 307 // Ensure visible part is drawn correctly. |
| 308 EXPECT_EQ(SK_ColorCYAN, output->getColor(visible_rect.x(), visible_rect.y())); |
| 309 EXPECT_EQ( |
| 310 SK_ColorCYAN, |
| 311 output->getColor(visible_rect.right() - 2, visible_rect.bottom() - 2)); |
| 312 // Ensure last visible line is correct. |
| 313 EXPECT_EQ( |
| 314 SK_ColorYELLOW, |
| 315 output->getColor(visible_rect.right() - 1, visible_rect.bottom() - 1)); |
| 316 } |
| 317 |
| 318 TEST_F(SoftwareRendererTest, ShouldClearRootRenderPass) { |
| 319 float device_scale_factor = 1.f; |
| 320 gfx::Rect device_viewport_rect(0, 0, 100, 100); |
| 321 |
| 322 settings_.should_clear_root_render_pass = false; |
| 323 InitializeRenderer(make_scoped_ptr(new SoftwareOutputDevice)); |
| 324 |
| 325 RenderPassList list; |
| 326 |
| 327 // Draw a fullscreen green quad in a first frame. |
| 328 RenderPassId root_clear_pass_id(1, 0); |
| 329 TestRenderPass* root_clear_pass = AddRenderPass( |
| 330 &list, root_clear_pass_id, device_viewport_rect, gfx::Transform()); |
| 331 AddQuad(root_clear_pass, device_viewport_rect, SK_ColorGREEN); |
| 332 |
| 333 renderer()->DecideRenderPassAllocationsForFrame(list); |
| 334 |
| 335 scoped_ptr<SkBitmap> output = |
| 336 DrawAndCopyOutput(&list, device_scale_factor, device_viewport_rect); |
| 337 EXPECT_EQ(device_viewport_rect.width(), output->info().fWidth); |
| 338 EXPECT_EQ(device_viewport_rect.height(), output->info().fHeight); |
| 339 |
| 340 EXPECT_EQ(SK_ColorGREEN, output->getColor(0, 0)); |
| 341 EXPECT_EQ(SK_ColorGREEN, |
| 342 output->getColor(device_viewport_rect.width() - 1, |
| 343 device_viewport_rect.height() - 1)); |
| 344 |
| 345 list.clear(); |
| 346 |
| 347 // Draw a smaller magenta rect without filling the viewport in a separate |
| 348 // frame. |
| 349 gfx::Rect smaller_rect(20, 20, 60, 60); |
| 350 |
| 351 RenderPassId root_smaller_pass_id(2, 0); |
| 352 TestRenderPass* root_smaller_pass = AddRenderPass( |
| 353 &list, root_smaller_pass_id, device_viewport_rect, gfx::Transform()); |
| 354 AddQuad(root_smaller_pass, smaller_rect, SK_ColorMAGENTA); |
| 355 |
| 356 renderer()->DecideRenderPassAllocationsForFrame(list); |
| 357 |
| 358 output = DrawAndCopyOutput(&list, device_scale_factor, device_viewport_rect); |
| 359 EXPECT_EQ(device_viewport_rect.width(), output->info().fWidth); |
| 360 EXPECT_EQ(device_viewport_rect.height(), output->info().fHeight); |
| 361 |
| 362 // If we didn't clear, the borders should still be green. |
| 363 EXPECT_EQ(SK_ColorGREEN, output->getColor(0, 0)); |
| 364 EXPECT_EQ(SK_ColorGREEN, |
| 365 output->getColor(device_viewport_rect.width() - 1, |
| 366 device_viewport_rect.height() - 1)); |
| 367 |
| 368 EXPECT_EQ(SK_ColorMAGENTA, |
| 369 output->getColor(smaller_rect.x(), smaller_rect.y())); |
| 370 EXPECT_EQ( |
| 371 SK_ColorMAGENTA, |
| 372 output->getColor(smaller_rect.right() - 1, smaller_rect.bottom() - 1)); |
| 373 } |
| 374 |
| 375 TEST_F(SoftwareRendererTest, RenderPassVisibleRect) { |
| 376 float device_scale_factor = 1.f; |
| 377 gfx::Rect device_viewport_rect(0, 0, 100, 100); |
| 378 InitializeRenderer(make_scoped_ptr(new SoftwareOutputDevice)); |
| 379 |
| 380 RenderPassList list; |
| 381 |
| 382 // Pass drawn as inner quad is magenta. |
| 383 gfx::Rect smaller_rect(20, 20, 60, 60); |
| 384 RenderPassId smaller_pass_id(2, 1); |
| 385 TestRenderPass* smaller_pass = |
| 386 AddRenderPass(&list, smaller_pass_id, smaller_rect, gfx::Transform()); |
| 387 AddQuad(smaller_pass, smaller_rect, SK_ColorMAGENTA); |
| 388 |
| 389 // Root pass is green. |
| 390 RenderPassId root_clear_pass_id(1, 0); |
| 391 TestRenderPass* root_clear_pass = AddRenderPass( |
| 392 &list, root_clear_pass_id, device_viewport_rect, gfx::Transform()); |
| 393 AddRenderPassQuad(root_clear_pass, smaller_pass); |
| 394 AddQuad(root_clear_pass, device_viewport_rect, SK_ColorGREEN); |
| 395 |
| 396 // Interior pass quad has smaller visible rect. |
| 397 gfx::Rect interior_visible_rect(30, 30, 40, 40); |
| 398 root_clear_pass->quad_list.front()->visible_rect = interior_visible_rect; |
| 399 |
| 400 renderer()->DecideRenderPassAllocationsForFrame(list); |
| 401 |
| 402 scoped_ptr<SkBitmap> output = |
| 403 DrawAndCopyOutput(&list, device_scale_factor, device_viewport_rect); |
| 404 EXPECT_EQ(device_viewport_rect.width(), output->info().fWidth); |
| 405 EXPECT_EQ(device_viewport_rect.height(), output->info().fHeight); |
| 406 |
| 407 EXPECT_EQ(SK_ColorGREEN, output->getColor(0, 0)); |
| 408 EXPECT_EQ(SK_ColorGREEN, |
| 409 output->getColor(device_viewport_rect.width() - 1, |
| 410 device_viewport_rect.height() - 1)); |
| 411 |
| 412 // Part outside visible rect should remain green. |
| 413 EXPECT_EQ(SK_ColorGREEN, |
| 414 output->getColor(smaller_rect.x(), smaller_rect.y())); |
| 415 EXPECT_EQ( |
| 416 SK_ColorGREEN, |
| 417 output->getColor(smaller_rect.right() - 1, smaller_rect.bottom() - 1)); |
| 418 |
| 419 EXPECT_EQ( |
| 420 SK_ColorMAGENTA, |
| 421 output->getColor(interior_visible_rect.x(), interior_visible_rect.y())); |
| 422 EXPECT_EQ(SK_ColorMAGENTA, |
| 423 output->getColor(interior_visible_rect.right() - 1, |
| 424 interior_visible_rect.bottom() - 1)); |
| 425 } |
| 426 |
| 427 } // namespace |
| 428 } // namespace cc |
OLD | NEW |