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/debug/trace_event.h" 8 #include "cc/base/math_util.h" 9 #include "cc/output/compositor_frame.h" 10 #include "cc/output/compositor_frame_ack.h" 11 #include "cc/output/compositor_frame_metadata.h" 12 #include "cc/output/copy_output_request.h" 13 #include "cc/output/output_surface.h" 14 #include "cc/output/render_surface_filters.h" 15 #include "cc/output/software_output_device.h" 16 #include "cc/quads/checkerboard_draw_quad.h" 17 #include "cc/quads/debug_border_draw_quad.h" 18 #include "cc/quads/picture_draw_quad.h" 19 #include "cc/quads/render_pass_draw_quad.h" 20 #include "cc/quads/solid_color_draw_quad.h" 21 #include "cc/quads/texture_draw_quad.h" 22 #include "cc/quads/tile_draw_quad.h" 23 #include "cc/resources/raster_worker_pool.h" 24 #include "skia/ext/opacity_draw_filter.h" 25 #include "third_party/skia/include/core/SkBitmapDevice.h" 26 #include "third_party/skia/include/core/SkCanvas.h" 27 #include "third_party/skia/include/core/SkColor.h" 28 #include "third_party/skia/include/core/SkImageFilter.h" 29 #include "third_party/skia/include/core/SkMatrix.h" 30 #include "third_party/skia/include/core/SkShader.h" 31 #include "third_party/skia/include/effects/SkLayerRasterizer.h" 32 #include "ui/gfx/rect_conversions.h" 33 #include "ui/gfx/skia_util.h" 34 #include "ui/gfx/transform.h" 35 36 namespace cc { 37 38 namespace { 39 40 class OnDemandRasterTaskImpl : public Task { 41 public: 42 OnDemandRasterTaskImpl(PicturePileImpl* picture_pile, 43 SkCanvas* canvas, 44 gfx::Rect content_rect, 45 float contents_scale) 46 : picture_pile_(picture_pile), 47 canvas_(canvas), 48 content_rect_(content_rect), 49 contents_scale_(contents_scale) { 50 DCHECK(picture_pile_); 51 DCHECK(canvas_); 52 } 53 54 // Overridden from Task: 55 virtual void RunOnWorkerThread() OVERRIDE { 56 TRACE_EVENT0("cc", "OnDemandRasterTaskImpl::RunOnWorkerThread"); 57 58 PicturePileImpl* picture_pile = picture_pile_->GetCloneForDrawingOnThread( 59 RasterWorkerPool::GetPictureCloneIndexForCurrentThread()); 60 DCHECK(picture_pile); 61 62 picture_pile->RasterDirect(canvas_, content_rect_, contents_scale_, NULL); 63 } 64 65 protected: 66 virtual ~OnDemandRasterTaskImpl() {} 67 68 private: 69 PicturePileImpl* picture_pile_; 70 SkCanvas* canvas_; 71 const gfx::Rect content_rect_; 72 const float contents_scale_; 73 74 DISALLOW_COPY_AND_ASSIGN(OnDemandRasterTaskImpl); 75 }; 76 77 static inline bool IsScalarNearlyInteger(SkScalar scalar) { 78 return SkScalarNearlyZero(scalar - SkScalarRoundToScalar(scalar)); 79 } 80 81 bool IsScaleAndIntegerTranslate(const SkMatrix& matrix) { 82 return IsScalarNearlyInteger(matrix[SkMatrix::kMTransX]) && 83 IsScalarNearlyInteger(matrix[SkMatrix::kMTransY]) && 84 SkScalarNearlyZero(matrix[SkMatrix::kMSkewX]) && 85 SkScalarNearlyZero(matrix[SkMatrix::kMSkewY]) && 86 SkScalarNearlyZero(matrix[SkMatrix::kMPersp0]) && 87 SkScalarNearlyZero(matrix[SkMatrix::kMPersp1]) && 88 SkScalarNearlyZero(matrix[SkMatrix::kMPersp2] - 1.0f); 89 } 90 91 static SkShader::TileMode WrapModeToTileMode(GLint wrap_mode) { 92 switch (wrap_mode) { 93 case GL_REPEAT: 94 return SkShader::kRepeat_TileMode; 95 case GL_CLAMP_TO_EDGE: 96 return SkShader::kClamp_TileMode; 97 } 98 NOTREACHED(); 99 return SkShader::kClamp_TileMode; 100 } 101 102 } // anonymous namespace 103 104 scoped_ptr<SoftwareRenderer> SoftwareRenderer::Create( 105 RendererClient* client, 106 const LayerTreeSettings* settings, 107 OutputSurface* output_surface, 108 ResourceProvider* resource_provider) { 109 return make_scoped_ptr(new SoftwareRenderer( 110 client, settings, output_surface, resource_provider)); 111 } 112 113 SoftwareRenderer::SoftwareRenderer(RendererClient* client, 114 const LayerTreeSettings* settings, 115 OutputSurface* output_surface, 116 ResourceProvider* resource_provider) 117 : DirectRenderer(client, settings, output_surface, resource_provider), 118 is_scissor_enabled_(false), 119 is_backbuffer_discarded_(false), 120 output_device_(output_surface->software_device()), 121 current_canvas_(NULL) { 122 if (resource_provider_) { 123 capabilities_.max_texture_size = resource_provider_->max_texture_size(); 124 capabilities_.best_texture_format = 125 resource_provider_->best_texture_format(); 126 } 127 // The updater can access bitmaps while the SoftwareRenderer is using them. 128 capabilities_.allow_partial_texture_updates = true; 129 capabilities_.using_partial_swap = true; 130 131 capabilities_.using_map_image = true; 132 capabilities_.using_shared_memory_resources = true; 133 134 capabilities_.allow_rasterize_on_demand = true; 135 } 136 137 SoftwareRenderer::~SoftwareRenderer() {} 138 139 const RendererCapabilitiesImpl& SoftwareRenderer::Capabilities() const { 140 return capabilities_; 141 } 142 143 void SoftwareRenderer::BeginDrawingFrame(DrawingFrame* frame) { 144 TRACE_EVENT0("cc", "SoftwareRenderer::BeginDrawingFrame"); 145 root_canvas_ = output_device_->BeginPaint( 146 gfx::ToEnclosingRect(frame->root_damage_rect)); 147 } 148 149 void SoftwareRenderer::FinishDrawingFrame(DrawingFrame* frame) { 150 TRACE_EVENT0("cc", "SoftwareRenderer::FinishDrawingFrame"); 151 current_framebuffer_lock_.reset(); 152 current_canvas_ = NULL; 153 root_canvas_ = NULL; 154 155 current_frame_data_.reset(new SoftwareFrameData); 156 output_device_->EndPaint(current_frame_data_.get()); 157 } 158 159 void SoftwareRenderer::SwapBuffers(const CompositorFrameMetadata& metadata) { 160 TRACE_EVENT0("cc,benchmark", "SoftwareRenderer::SwapBuffers"); 161 CompositorFrame compositor_frame; 162 compositor_frame.metadata = metadata; 163 compositor_frame.software_frame_data = current_frame_data_.Pass(); 164 output_surface_->SwapBuffers(&compositor_frame); 165 } 166 167 void SoftwareRenderer::ReceiveSwapBuffersAck(const CompositorFrameAck& ack) { 168 output_device_->ReclaimSoftwareFrame(ack.last_software_frame_id); 169 } 170 171 bool SoftwareRenderer::FlippedFramebuffer() const { 172 return false; 173 } 174 175 void SoftwareRenderer::EnsureScissorTestEnabled() { 176 is_scissor_enabled_ = true; 177 SetClipRect(scissor_rect_); 178 } 179 180 void SoftwareRenderer::EnsureScissorTestDisabled() { 181 // There is no explicit notion of enabling/disabling scissoring in software 182 // rendering, but the underlying effect we want is to clear any existing 183 // clipRect on the current SkCanvas. This is done by setting clipRect to 184 // the viewport's dimensions. 185 is_scissor_enabled_ = false; 186 SkISize size = current_canvas_->getDeviceSize(); 187 SetClipRect(gfx::Rect(size.width(), size.height())); 188 } 189 190 void SoftwareRenderer::Finish() {} 191 192 void SoftwareRenderer::BindFramebufferToOutputSurface(DrawingFrame* frame) { 193 DCHECK(!output_surface_->HasExternalStencilTest()); 194 current_framebuffer_lock_.reset(); 195 current_canvas_ = root_canvas_; 196 } 197 198 bool SoftwareRenderer::BindFramebufferToTexture( 199 DrawingFrame* frame, 200 const ScopedResource* texture, 201 const gfx::Rect& target_rect) { 202 current_framebuffer_lock_.reset(); 203 current_framebuffer_lock_ = make_scoped_ptr( 204 new ResourceProvider::ScopedWriteLockSoftware( 205 resource_provider_, texture->id())); 206 current_canvas_ = current_framebuffer_lock_->sk_canvas(); 207 InitializeViewport(frame, 208 target_rect, 209 gfx::Rect(target_rect.size()), 210 target_rect.size()); 211 return true; 212 } 213 214 void SoftwareRenderer::SetScissorTestRect(const gfx::Rect& scissor_rect) { 215 is_scissor_enabled_ = true; 216 scissor_rect_ = scissor_rect; 217 SetClipRect(scissor_rect); 218 } 219 220 void SoftwareRenderer::SetClipRect(const gfx::Rect& rect) { 221 // Skia applies the current matrix to clip rects so we reset it temporary. 222 SkMatrix current_matrix = current_canvas_->getTotalMatrix(); 223 current_canvas_->resetMatrix(); 224 current_canvas_->clipRect(gfx::RectToSkRect(rect), SkRegion::kReplace_Op); 225 current_canvas_->setMatrix(current_matrix); 226 } 227 228 void SoftwareRenderer::ClearCanvas(SkColor color) { 229 // SkCanvas::clear doesn't respect the current clipping region 230 // so we SkCanvas::drawColor instead if scissoring is active. 231 if (is_scissor_enabled_) 232 current_canvas_->drawColor(color, SkXfermode::kSrc_Mode); 233 else 234 current_canvas_->clear(color); 235 } 236 237 void SoftwareRenderer::DiscardPixels(bool has_external_stencil_test, 238 bool draw_rect_covers_full_surface) {} 239 240 void SoftwareRenderer::ClearFramebuffer(DrawingFrame* frame, 241 bool has_external_stencil_test) { 242 if (frame->current_render_pass->has_transparent_background) { 243 ClearCanvas(SkColorSetARGB(0, 0, 0, 0)); 244 } else { 245 #ifndef NDEBUG 246 // On DEBUG builds, opaque render passes are cleared to blue 247 // to easily see regions that were not drawn on the screen. 248 ClearCanvas(SkColorSetARGB(255, 0, 0, 255)); 249 #endif 250 } 251 } 252 253 void SoftwareRenderer::SetDrawViewport( 254 const gfx::Rect& window_space_viewport) {} 255 256 bool SoftwareRenderer::IsSoftwareResource( 257 ResourceProvider::ResourceId resource_id) const { 258 switch (resource_provider_->GetResourceType(resource_id)) { 259 case ResourceProvider::GLTexture: 260 return false; 261 case ResourceProvider::Bitmap: 262 return true; 263 case ResourceProvider::InvalidType: 264 break; 265 } 266 267 LOG(FATAL) << "Invalid resource type."; 268 return false; 269 } 270 271 void SoftwareRenderer::DoDrawQuad(DrawingFrame* frame, const DrawQuad* quad) { 272 TRACE_EVENT0("cc", "SoftwareRenderer::DoDrawQuad"); 273 gfx::Transform quad_rect_matrix; 274 QuadRectTransform(&quad_rect_matrix, quad->quadTransform(), quad->rect); 275 gfx::Transform contents_device_transform = 276 frame->window_matrix * frame->projection_matrix * quad_rect_matrix; 277 contents_device_transform.FlattenTo2d(); 278 SkMatrix sk_device_matrix; 279 gfx::TransformToFlattenedSkMatrix(contents_device_transform, 280 &sk_device_matrix); 281 current_canvas_->setMatrix(sk_device_matrix); 282 283 current_paint_.reset(); 284 if (!IsScaleAndIntegerTranslate(sk_device_matrix)) { 285 // TODO(danakj): Until we can enable AA only on exterior edges of the 286 // layer, disable AA if any interior edges are present. crbug.com/248175 287 bool all_four_edges_are_exterior = quad->IsTopEdge() && 288 quad->IsLeftEdge() && 289 quad->IsBottomEdge() && 290 quad->IsRightEdge(); 291 if (settings_->allow_antialiasing && all_four_edges_are_exterior) 292 current_paint_.setAntiAlias(true); 293 current_paint_.setFilterLevel(SkPaint::kLow_FilterLevel); 294 } 295 296 if (quad->ShouldDrawWithBlending()) { 297 current_paint_.setAlpha(quad->opacity() * 255); 298 current_paint_.setXfermodeMode(SkXfermode::kSrcOver_Mode); 299 } else { 300 current_paint_.setXfermodeMode(SkXfermode::kSrc_Mode); 301 } 302 303 switch (quad->material) { 304 case DrawQuad::CHECKERBOARD: 305 DrawCheckerboardQuad(frame, CheckerboardDrawQuad::MaterialCast(quad)); 306 break; 307 case DrawQuad::DEBUG_BORDER: 308 DrawDebugBorderQuad(frame, DebugBorderDrawQuad::MaterialCast(quad)); 309 break; 310 case DrawQuad::PICTURE_CONTENT: 311 DrawPictureQuad(frame, PictureDrawQuad::MaterialCast(quad)); 312 break; 313 case DrawQuad::RENDER_PASS: 314 DrawRenderPassQuad(frame, RenderPassDrawQuad::MaterialCast(quad)); 315 break; 316 case DrawQuad::SOLID_COLOR: 317 DrawSolidColorQuad(frame, SolidColorDrawQuad::MaterialCast(quad)); 318 break; 319 case DrawQuad::TEXTURE_CONTENT: 320 DrawTextureQuad(frame, TextureDrawQuad::MaterialCast(quad)); 321 break; 322 case DrawQuad::TILED_CONTENT: 323 DrawTileQuad(frame, TileDrawQuad::MaterialCast(quad)); 324 break; 325 case DrawQuad::SURFACE_CONTENT: 326 // Surface content should be fully resolved to other quad types before 327 // reaching a direct renderer. 328 NOTREACHED(); 329 break; 330 case DrawQuad::INVALID: 331 case DrawQuad::IO_SURFACE_CONTENT: 332 case DrawQuad::YUV_VIDEO_CONTENT: 333 case DrawQuad::STREAM_VIDEO_CONTENT: 334 DrawUnsupportedQuad(frame, quad); 335 NOTREACHED(); 336 break; 337 } 338 339 current_canvas_->resetMatrix(); 340 } 341 342 void SoftwareRenderer::DrawCheckerboardQuad(const DrawingFrame* frame, 343 const CheckerboardDrawQuad* quad) { 344 gfx::RectF visible_quad_vertex_rect = MathUtil::ScaleRectProportional( 345 QuadVertexRect(), quad->rect, quad->visible_rect); 346 current_paint_.setColor(quad->color); 347 current_paint_.setAlpha(quad->opacity() * SkColorGetA(quad->color)); 348 current_canvas_->drawRect(gfx::RectFToSkRect(visible_quad_vertex_rect), 349 current_paint_); 350 } 351 352 void SoftwareRenderer::DrawDebugBorderQuad(const DrawingFrame* frame, 353 const DebugBorderDrawQuad* quad) { 354 // We need to apply the matrix manually to have pixel-sized stroke width. 355 SkPoint vertices[4]; 356 gfx::RectFToSkRect(QuadVertexRect()).toQuad(vertices); 357 SkPoint transformed_vertices[4]; 358 current_canvas_->getTotalMatrix().mapPoints(transformed_vertices, 359 vertices, 360 4); 361 current_canvas_->resetMatrix(); 362 363 current_paint_.setColor(quad->color); 364 current_paint_.setAlpha(quad->opacity() * SkColorGetA(quad->color)); 365 current_paint_.setStyle(SkPaint::kStroke_Style); 366 current_paint_.setStrokeWidth(quad->width); 367 current_canvas_->drawPoints(SkCanvas::kPolygon_PointMode, 368 4, transformed_vertices, current_paint_); 369 } 370 371 void SoftwareRenderer::DrawPictureQuad(const DrawingFrame* frame, 372 const PictureDrawQuad* quad) { 373 SkMatrix content_matrix; 374 content_matrix.setRectToRect( 375 gfx::RectFToSkRect(quad->tex_coord_rect), 376 gfx::RectFToSkRect(QuadVertexRect()), 377 SkMatrix::kFill_ScaleToFit); 378 current_canvas_->concat(content_matrix); 379 380 // TODO(aelias): This isn't correct in all cases. We should detect these 381 // cases and fall back to a persistent bitmap backing 382 // (http://crbug.com/280374). 383 skia::RefPtr<SkDrawFilter> opacity_filter = 384 skia::AdoptRef(new skia::OpacityDrawFilter( 385 quad->opacity(), frame->disable_picture_quad_image_filtering)); 386 DCHECK(!current_canvas_->getDrawFilter()); 387 current_canvas_->setDrawFilter(opacity_filter.get()); 388 389 TRACE_EVENT0("cc", 390 "SoftwareRenderer::DrawPictureQuad"); 391 392 // Create and run on-demand raster task for tile. 393 scoped_refptr<Task> on_demand_raster_task( 394 new OnDemandRasterTaskImpl(quad->picture_pile, 395 current_canvas_, 396 quad->content_rect, 397 quad->contents_scale)); 398 client_->RunOnDemandRasterTask(on_demand_raster_task.get()); 399 400 current_canvas_->setDrawFilter(NULL); 401 } 402 403 void SoftwareRenderer::DrawSolidColorQuad(const DrawingFrame* frame, 404 const SolidColorDrawQuad* quad) { 405 gfx::RectF visible_quad_vertex_rect = MathUtil::ScaleRectProportional( 406 QuadVertexRect(), quad->rect, quad->visible_rect); 407 current_paint_.setColor(quad->color); 408 current_paint_.setAlpha(quad->opacity() * SkColorGetA(quad->color)); 409 current_canvas_->drawRect(gfx::RectFToSkRect(visible_quad_vertex_rect), 410 current_paint_); 411 } 412 413 void SoftwareRenderer::DrawTextureQuad(const DrawingFrame* frame, 414 const TextureDrawQuad* quad) { 415 if (!IsSoftwareResource(quad->resource_id)) { 416 DrawUnsupportedQuad(frame, quad); 417 return; 418 } 419 420 // TODO(skaslev): Add support for non-premultiplied alpha. 421 ResourceProvider::ScopedReadLockSoftware lock(resource_provider_, 422 quad->resource_id); 423 if (!lock.valid()) 424 return; 425 const SkBitmap* bitmap = lock.sk_bitmap(); 426 gfx::RectF uv_rect = gfx::ScaleRect(gfx::BoundingRect(quad->uv_top_left, 427 quad->uv_bottom_right), 428 bitmap->width(), 429 bitmap->height()); 430 gfx::RectF visible_uv_rect = 431 MathUtil::ScaleRectProportional(uv_rect, quad->rect, quad->visible_rect); 432 SkRect sk_uv_rect = gfx::RectFToSkRect(visible_uv_rect); 433 gfx::RectF visible_quad_vertex_rect = MathUtil::ScaleRectProportional( 434 QuadVertexRect(), quad->rect, quad->visible_rect); 435 SkRect quad_rect = gfx::RectFToSkRect(visible_quad_vertex_rect); 436 437 if (quad->flipped) 438 current_canvas_->scale(1, -1); 439 440 bool blend_background = quad->background_color != SK_ColorTRANSPARENT && 441 !bitmap->isOpaque(); 442 bool needs_layer = blend_background && (current_paint_.getAlpha() != 0xFF); 443 if (needs_layer) { 444 current_canvas_->saveLayerAlpha(&quad_rect, current_paint_.getAlpha()); 445 current_paint_.setAlpha(0xFF); 446 } 447 if (blend_background) { 448 SkPaint background_paint; 449 background_paint.setColor(quad->background_color); 450 current_canvas_->drawRect(quad_rect, background_paint); 451 } 452 SkShader::TileMode tile_mode = WrapModeToTileMode(lock.wrap_mode()); 453 if (tile_mode != SkShader::kClamp_TileMode) { 454 SkMatrix matrix; 455 matrix.setRectToRect(sk_uv_rect, quad_rect, SkMatrix::kFill_ScaleToFit); 456 skia::RefPtr<SkShader> shader = skia::AdoptRef( 457 SkShader::CreateBitmapShader(*bitmap, tile_mode, tile_mode, &matrix)); 458 SkPaint paint; 459 paint.setStyle(SkPaint::kFill_Style); 460 paint.setShader(shader.get()); 461 current_canvas_->drawRect(quad_rect, paint); 462 } else { 463 current_canvas_->drawBitmapRectToRect(*bitmap, 464 &sk_uv_rect, 465 quad_rect, 466 ¤t_paint_); 467 } 468 469 if (needs_layer) 470 current_canvas_->restore(); 471 } 472 473 void SoftwareRenderer::DrawTileQuad(const DrawingFrame* frame, 474 const TileDrawQuad* quad) { 475 // |resource_provider_| can be NULL in resourceless software draws, which 476 // should never produce tile quads in the first place. 477 DCHECK(resource_provider_); 478 DCHECK(IsSoftwareResource(quad->resource_id)); 479 480 ResourceProvider::ScopedReadLockSoftware lock(resource_provider_, 481 quad->resource_id); 482 if (!lock.valid()) 483 return; 484 DCHECK_EQ(GL_CLAMP_TO_EDGE, lock.wrap_mode()); 485 486 gfx::RectF visible_tex_coord_rect = MathUtil::ScaleRectProportional( 487 quad->tex_coord_rect, quad->rect, quad->visible_rect); 488 gfx::RectF visible_quad_vertex_rect = MathUtil::ScaleRectProportional( 489 QuadVertexRect(), quad->rect, quad->visible_rect); 490 491 SkRect uv_rect = gfx::RectFToSkRect(visible_tex_coord_rect); 492 current_paint_.setFilterLevel(SkPaint::kLow_FilterLevel); 493 current_canvas_->drawBitmapRectToRect( 494 *lock.sk_bitmap(), 495 &uv_rect, 496 gfx::RectFToSkRect(visible_quad_vertex_rect), 497 ¤t_paint_); 498 } 499 500 void SoftwareRenderer::DrawRenderPassQuad(const DrawingFrame* frame, 501 const RenderPassDrawQuad* quad) { 502 ScopedResource* content_texture = 503 render_pass_textures_.get(quad->render_pass_id); 504 if (!content_texture || !content_texture->id()) 505 return; 506 507 DCHECK(IsSoftwareResource(content_texture->id())); 508 ResourceProvider::ScopedReadLockSoftware lock(resource_provider_, 509 content_texture->id()); 510 if (!lock.valid()) 511 return; 512 SkShader::TileMode content_tile_mode = WrapModeToTileMode(lock.wrap_mode()); 513 514 SkRect dest_rect = gfx::RectFToSkRect(QuadVertexRect()); 515 SkRect dest_visible_rect = gfx::RectFToSkRect(MathUtil::ScaleRectProportional( 516 QuadVertexRect(), quad->rect, quad->visible_rect)); 517 SkRect content_rect = SkRect::MakeWH(quad->rect.width(), quad->rect.height()); 518 519 SkMatrix content_mat; 520 content_mat.setRectToRect(content_rect, dest_rect, 521 SkMatrix::kFill_ScaleToFit); 522 523 const SkBitmap* content = lock.sk_bitmap(); 524 525 SkBitmap filter_bitmap; 526 if (!quad->filters.IsEmpty()) { 527 skia::RefPtr<SkImageFilter> filter = RenderSurfaceFilters::BuildImageFilter( 528 quad->filters, content_texture->size()); 529 // TODO(ajuma): In addition origin translation, the canvas should also be 530 // scaled to accomodate device pixel ratio and pinch zoom. See 531 // crbug.com/281516 and crbug.com/281518. 532 // TODO(ajuma): Apply the filter in the same pass as the content where 533 // possible (e.g. when there's no origin offset). See crbug.com/308201. 534 if (filter) { 535 SkImageInfo info = SkImageInfo::MakeN32Premul( 536 content_texture->size().width(), content_texture->size().height()); 537 if (filter_bitmap.allocPixels(info)) { 538 SkCanvas canvas(filter_bitmap); 539 SkPaint paint; 540 paint.setImageFilter(filter.get()); 541 canvas.clear(SK_ColorTRANSPARENT); 542 canvas.translate(SkIntToScalar(-quad->rect.origin().x()), 543 SkIntToScalar(-quad->rect.origin().y())); 544 canvas.drawSprite(*content, 0, 0, &paint); 545 } 546 } 547 } 548 549 skia::RefPtr<SkShader> shader; 550 if (filter_bitmap.isNull()) { 551 shader = skia::AdoptRef(SkShader::CreateBitmapShader( 552 *content, content_tile_mode, content_tile_mode, &content_mat)); 553 } else { 554 shader = skia::AdoptRef(SkShader::CreateBitmapShader( 555 filter_bitmap, content_tile_mode, content_tile_mode, &content_mat)); 556 } 557 current_paint_.setShader(shader.get()); 558 559 if (quad->mask_resource_id) { 560 ResourceProvider::ScopedReadLockSoftware mask_lock(resource_provider_, 561 quad->mask_resource_id); 562 if (!lock.valid()) 563 return; 564 SkShader::TileMode mask_tile_mode = WrapModeToTileMode( 565 mask_lock.wrap_mode()); 566 567 const SkBitmap* mask = mask_lock.sk_bitmap(); 568 569 SkRect mask_rect = SkRect::MakeXYWH( 570 quad->mask_uv_rect.x() * mask->width(), 571 quad->mask_uv_rect.y() * mask->height(), 572 quad->mask_uv_rect.width() * mask->width(), 573 quad->mask_uv_rect.height() * mask->height()); 574 575 SkMatrix mask_mat; 576 mask_mat.setRectToRect(mask_rect, dest_rect, SkMatrix::kFill_ScaleToFit); 577 578 skia::RefPtr<SkShader> mask_shader = 579 skia::AdoptRef(SkShader::CreateBitmapShader( 580 *mask, mask_tile_mode, mask_tile_mode, &mask_mat)); 581 582 SkPaint mask_paint; 583 mask_paint.setShader(mask_shader.get()); 584 585 SkLayerRasterizer::Builder builder; 586 builder.addLayer(mask_paint); 587 588 skia::RefPtr<SkLayerRasterizer> mask_rasterizer = 589 skia::AdoptRef(builder.detachRasterizer()); 590 591 current_paint_.setRasterizer(mask_rasterizer.get()); 592 current_canvas_->drawRect(dest_visible_rect, current_paint_); 593 } else { 594 // TODO(skaslev): Apply background filters and blend with content 595 current_canvas_->drawRect(dest_visible_rect, current_paint_); 596 } 597 } 598 599 void SoftwareRenderer::DrawUnsupportedQuad(const DrawingFrame* frame, 600 const DrawQuad* quad) { 601 #ifdef NDEBUG 602 current_paint_.setColor(SK_ColorWHITE); 603 #else 604 current_paint_.setColor(SK_ColorMAGENTA); 605 #endif 606 current_paint_.setAlpha(quad->opacity() * 255); 607 current_canvas_->drawRect(gfx::RectFToSkRect(QuadVertexRect()), 608 current_paint_); 609 } 610 611 void SoftwareRenderer::CopyCurrentRenderPassToBitmap( 612 DrawingFrame* frame, 613 scoped_ptr<CopyOutputRequest> request) { 614 gfx::Rect copy_rect = frame->current_render_pass->output_rect; 615 if (request->has_area()) 616 copy_rect.Intersect(request->area()); 617 gfx::Rect window_copy_rect = MoveFromDrawToWindowSpace(copy_rect); 618 619 scoped_ptr<SkBitmap> bitmap(new SkBitmap); 620 bitmap->setConfig(SkBitmap::kARGB_8888_Config, 621 window_copy_rect.width(), 622 window_copy_rect.height()); 623 current_canvas_->readPixels( 624 bitmap.get(), window_copy_rect.x(), window_copy_rect.y()); 625 626 request->SendBitmapResult(bitmap.Pass()); 627 } 628 629 void SoftwareRenderer::DiscardBackbuffer() { 630 if (is_backbuffer_discarded_) 631 return; 632 633 output_surface_->DiscardBackbuffer(); 634 635 is_backbuffer_discarded_ = true; 636 637 // Damage tracker needs a full reset every time framebuffer is discarded. 638 client_->SetFullRootLayerDamage(); 639 } 640 641 void SoftwareRenderer::EnsureBackbuffer() { 642 if (!is_backbuffer_discarded_) 643 return; 644 645 output_surface_->EnsureBackbuffer(); 646 is_backbuffer_discarded_ = false; 647 } 648 649 void SoftwareRenderer::DidChangeVisibility() { 650 if (visible()) 651 EnsureBackbuffer(); 652 else 653 DiscardBackbuffer(); 654 } 655 656 } // namespace cc 657