software_renderer.cc revision 868fa2fe829687343ffae624259930155e16dbd8
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/software_output_device.h" 15#include "cc/quads/debug_border_draw_quad.h" 16#include "cc/quads/picture_draw_quad.h" 17#include "cc/quads/render_pass_draw_quad.h" 18#include "cc/quads/solid_color_draw_quad.h" 19#include "cc/quads/texture_draw_quad.h" 20#include "cc/quads/tile_draw_quad.h" 21#include "third_party/skia/include/core/SkCanvas.h" 22#include "third_party/skia/include/core/SkColor.h" 23#include "third_party/skia/include/core/SkDevice.h" 24#include "third_party/skia/include/core/SkMatrix.h" 25#include "third_party/skia/include/core/SkShader.h" 26#include "third_party/skia/include/effects/SkLayerRasterizer.h" 27#include "ui/gfx/rect_conversions.h" 28#include "ui/gfx/skia_util.h" 29#include "ui/gfx/transform.h" 30 31namespace cc { 32 33namespace { 34 35bool IsScaleAndTranslate(const SkMatrix& matrix) { 36 return SkScalarNearlyZero(matrix[SkMatrix::kMSkewX]) && 37 SkScalarNearlyZero(matrix[SkMatrix::kMSkewY]) && 38 SkScalarNearlyZero(matrix[SkMatrix::kMPersp0]) && 39 SkScalarNearlyZero(matrix[SkMatrix::kMPersp1]) && 40 SkScalarNearlyZero(matrix[SkMatrix::kMPersp2] - 1.0f); 41} 42 43} // anonymous namespace 44 45scoped_ptr<SoftwareRenderer> SoftwareRenderer::Create( 46 RendererClient* client, 47 OutputSurface* output_surface, 48 ResourceProvider* resource_provider) { 49 return make_scoped_ptr( 50 new SoftwareRenderer(client, output_surface, resource_provider)); 51} 52 53SoftwareRenderer::SoftwareRenderer(RendererClient* client, 54 OutputSurface* output_surface, 55 ResourceProvider* resource_provider) 56 : DirectRenderer(client, output_surface, resource_provider), 57 visible_(true), 58 is_scissor_enabled_(false), 59 is_viewport_changed_(true), 60 output_device_(output_surface->software_device()), 61 current_canvas_(NULL) { 62 if (resource_provider_) { 63 capabilities_.max_texture_size = resource_provider_->max_texture_size(); 64 capabilities_.best_texture_format = 65 resource_provider_->best_texture_format(); 66 } 67 capabilities_.using_set_visibility = true; 68 // The updater can access bitmaps while the SoftwareRenderer is using them. 69 capabilities_.allow_partial_texture_updates = true; 70 capabilities_.using_partial_swap = true; 71 if (Settings().compositor_frame_message && client_->HasImplThread()) 72 capabilities_.using_swap_complete_callback = true; 73 compositor_frame_.software_frame_data.reset(new SoftwareFrameData()); 74} 75 76SoftwareRenderer::~SoftwareRenderer() {} 77 78const RendererCapabilities& SoftwareRenderer::Capabilities() const { 79 return capabilities_; 80} 81 82void SoftwareRenderer::ViewportChanged() { 83 is_viewport_changed_ = true; 84} 85 86void SoftwareRenderer::BeginDrawingFrame(DrawingFrame* frame) { 87 TRACE_EVENT0("cc", "SoftwareRenderer::BeginDrawingFrame"); 88 if (is_viewport_changed_) { 89 is_viewport_changed_ = false; 90 output_device_->Resize(client_->DeviceViewport().size()); 91 } 92 root_canvas_ = output_device_->BeginPaint( 93 gfx::ToEnclosingRect(frame->root_damage_rect)); 94} 95 96void SoftwareRenderer::FinishDrawingFrame(DrawingFrame* frame) { 97 TRACE_EVENT0("cc", "SoftwareRenderer::FinishDrawingFrame"); 98 current_framebuffer_lock_.reset(); 99 current_canvas_ = NULL; 100 root_canvas_ = NULL; 101 if (Settings().compositor_frame_message) { 102 compositor_frame_.metadata = client_->MakeCompositorFrameMetadata(); 103 output_device_->EndPaint(compositor_frame_.software_frame_data.get()); 104 } else { 105 output_device_->EndPaint(NULL); 106 } 107} 108 109void SoftwareRenderer::SwapBuffers(const ui::LatencyInfo& latency_info) { 110 if (Settings().compositor_frame_message) 111 output_surface_->SendFrameToParentCompositor(&compositor_frame_); 112} 113 114void SoftwareRenderer::ReceiveCompositorFrameAck( 115 const CompositorFrameAck& ack) { 116 output_device_->ReclaimSoftwareFrame(ack.last_software_frame_id); 117} 118 119bool SoftwareRenderer::FlippedFramebuffer() const { 120 return false; 121} 122 123void SoftwareRenderer::EnsureScissorTestEnabled() { 124 is_scissor_enabled_ = true; 125 SetClipRect(scissor_rect_); 126} 127 128void SoftwareRenderer::EnsureScissorTestDisabled() { 129 // There is no explicit notion of enabling/disabling scissoring in software 130 // rendering, but the underlying effect we want is to clear any existing 131 // clipRect on the current SkCanvas. This is done by setting clipRect to 132 // the viewport's dimensions. 133 is_scissor_enabled_ = false; 134 SkDevice* device = current_canvas_->getDevice(); 135 SetClipRect(gfx::Rect(device->width(), device->height())); 136} 137 138void SoftwareRenderer::Finish() {} 139 140void SoftwareRenderer::BindFramebufferToOutputSurface(DrawingFrame* frame) { 141 current_framebuffer_lock_.reset(); 142 current_canvas_ = root_canvas_; 143} 144 145bool SoftwareRenderer::BindFramebufferToTexture( 146 DrawingFrame* frame, 147 const ScopedResource* texture, 148 gfx::Rect target_rect) { 149 current_framebuffer_lock_.reset(); 150 current_framebuffer_lock_ = make_scoped_ptr( 151 new ResourceProvider::ScopedWriteLockSoftware( 152 resource_provider_, texture->id())); 153 current_canvas_ = current_framebuffer_lock_->sk_canvas(); 154 InitializeViewport(frame, 155 target_rect, 156 gfx::Rect(target_rect.size()), 157 target_rect.size(), 158 false); 159 return true; 160} 161 162void SoftwareRenderer::SetScissorTestRect(gfx::Rect scissor_rect) { 163 is_scissor_enabled_ = true; 164 scissor_rect_ = scissor_rect; 165 SetClipRect(scissor_rect); 166} 167 168void SoftwareRenderer::SetClipRect(gfx::Rect rect) { 169 // Skia applies the current matrix to clip rects so we reset it temporary. 170 SkMatrix current_matrix = current_canvas_->getTotalMatrix(); 171 current_canvas_->resetMatrix(); 172 current_canvas_->clipRect(gfx::RectToSkRect(rect), SkRegion::kReplace_Op); 173 current_canvas_->setMatrix(current_matrix); 174} 175 176void SoftwareRenderer::ClearCanvas(SkColor color) { 177 // SkCanvas::clear doesn't respect the current clipping region 178 // so we SkCanvas::drawColor instead if scissoring is active. 179 if (is_scissor_enabled_) 180 current_canvas_->drawColor(color, SkXfermode::kSrc_Mode); 181 else 182 current_canvas_->clear(color); 183} 184 185void SoftwareRenderer::ClearFramebuffer(DrawingFrame* frame) { 186 if (frame->current_render_pass->has_transparent_background) { 187 ClearCanvas(SkColorSetARGB(0, 0, 0, 0)); 188 } else { 189#ifndef NDEBUG 190 // On DEBUG builds, opaque render passes are cleared to blue 191 // to easily see regions that were not drawn on the screen. 192 ClearCanvas(SkColorSetARGB(255, 0, 0, 255)); 193#endif 194 } 195} 196 197void SoftwareRenderer::SetDrawViewport(gfx::Rect window_space_viewport) {} 198 199bool SoftwareRenderer::IsSoftwareResource( 200 ResourceProvider::ResourceId resource_id) const { 201 switch (resource_provider_->GetResourceType(resource_id)) { 202 case ResourceProvider::GLTexture: 203 return false; 204 case ResourceProvider::Bitmap: 205 return true; 206 } 207 208 LOG(FATAL) << "Invalid resource type."; 209 return false; 210} 211 212void SoftwareRenderer::DoDrawQuad(DrawingFrame* frame, const DrawQuad* quad) { 213 TRACE_EVENT0("cc", "SoftwareRenderer::DoDrawQuad"); 214 gfx::Transform quad_rect_matrix; 215 QuadRectTransform(&quad_rect_matrix, quad->quadTransform(), quad->rect); 216 gfx::Transform contents_device_transform = 217 frame->window_matrix * frame->projection_matrix * quad_rect_matrix; 218 contents_device_transform.FlattenTo2d(); 219 SkMatrix sk_device_matrix; 220 gfx::TransformToFlattenedSkMatrix(contents_device_transform, 221 &sk_device_matrix); 222 current_canvas_->setMatrix(sk_device_matrix); 223 224 current_paint_.reset(); 225 if (!IsScaleAndTranslate(sk_device_matrix)) { 226 // TODO(danakj): Until we can enable AA only on exterior edges of the 227 // layer, disable AA if any interior edges are present. crbug.com/248175 228 bool all_four_edges_are_exterior = quad->IsTopEdge() && 229 quad->IsLeftEdge() && 230 quad->IsBottomEdge() && 231 quad->IsRightEdge(); 232 if (all_four_edges_are_exterior) 233 current_paint_.setAntiAlias(true); 234 current_paint_.setFilterBitmap(true); 235 } 236 237 if (quad->ShouldDrawWithBlending()) { 238 current_paint_.setAlpha(quad->opacity() * 255); 239 current_paint_.setXfermodeMode(SkXfermode::kSrcOver_Mode); 240 } else { 241 current_paint_.setXfermodeMode(SkXfermode::kSrc_Mode); 242 } 243 244 switch (quad->material) { 245 case DrawQuad::DEBUG_BORDER: 246 DrawDebugBorderQuad(frame, DebugBorderDrawQuad::MaterialCast(quad)); 247 break; 248 case DrawQuad::PICTURE_CONTENT: 249 DrawPictureQuad(frame, PictureDrawQuad::MaterialCast(quad)); 250 break; 251 case DrawQuad::SOLID_COLOR: 252 DrawSolidColorQuad(frame, SolidColorDrawQuad::MaterialCast(quad)); 253 break; 254 case DrawQuad::TEXTURE_CONTENT: 255 DrawTextureQuad(frame, TextureDrawQuad::MaterialCast(quad)); 256 break; 257 case DrawQuad::TILED_CONTENT: 258 DrawTileQuad(frame, TileDrawQuad::MaterialCast(quad)); 259 break; 260 case DrawQuad::RENDER_PASS: 261 DrawRenderPassQuad(frame, RenderPassDrawQuad::MaterialCast(quad)); 262 break; 263 default: 264 DrawUnsupportedQuad(frame, quad); 265 break; 266 } 267 268 current_canvas_->resetMatrix(); 269} 270 271void SoftwareRenderer::DrawDebugBorderQuad(const DrawingFrame* frame, 272 const DebugBorderDrawQuad* quad) { 273 // We need to apply the matrix manually to have pixel-sized stroke width. 274 SkPoint vertices[4]; 275 gfx::RectFToSkRect(QuadVertexRect()).toQuad(vertices); 276 SkPoint transformed_vertices[4]; 277 current_canvas_->getTotalMatrix().mapPoints(transformed_vertices, 278 vertices, 279 4); 280 current_canvas_->resetMatrix(); 281 282 current_paint_.setColor(quad->color); 283 current_paint_.setAlpha(quad->opacity() * SkColorGetA(quad->color)); 284 current_paint_.setStyle(SkPaint::kStroke_Style); 285 current_paint_.setStrokeWidth(quad->width); 286 current_canvas_->drawPoints(SkCanvas::kPolygon_PointMode, 287 4, transformed_vertices, current_paint_); 288} 289 290void SoftwareRenderer::DrawPictureQuad(const DrawingFrame* frame, 291 const PictureDrawQuad* quad) { 292 SkMatrix content_matrix; 293 content_matrix.setRectToRect( 294 gfx::RectFToSkRect(quad->tex_coord_rect), 295 gfx::RectFToSkRect(QuadVertexRect()), 296 SkMatrix::kFill_ScaleToFit); 297 current_canvas_->concat(content_matrix); 298 299 if (quad->ShouldDrawWithBlending()) { 300 TRACE_EVENT0("cc", "SoftwareRenderer::DrawPictureQuad with blending"); 301 SkBitmap temp_bitmap; 302 temp_bitmap.setConfig(SkBitmap::kARGB_8888_Config, 303 quad->texture_size.width(), 304 quad->texture_size.height()); 305 temp_bitmap.allocPixels(); 306 SkDevice temp_device(temp_bitmap); 307 SkCanvas temp_canvas(&temp_device); 308 309 quad->picture_pile->RasterToBitmap( 310 &temp_canvas, quad->content_rect, quad->contents_scale, NULL); 311 312 current_paint_.setFilterBitmap(true); 313 current_canvas_->drawBitmap(temp_bitmap, 0, 0, ¤t_paint_); 314 } else { 315 TRACE_EVENT0("cc", 316 "SoftwareRenderer::DrawPictureQuad direct from PicturePile"); 317 quad->picture_pile->RasterDirect( 318 current_canvas_, quad->content_rect, quad->contents_scale, NULL); 319 } 320} 321 322void SoftwareRenderer::DrawSolidColorQuad(const DrawingFrame* frame, 323 const SolidColorDrawQuad* quad) { 324 current_paint_.setColor(quad->color); 325 current_paint_.setAlpha(quad->opacity() * SkColorGetA(quad->color)); 326 current_canvas_->drawRect(gfx::RectFToSkRect(QuadVertexRect()), 327 current_paint_); 328} 329 330void SoftwareRenderer::DrawTextureQuad(const DrawingFrame* frame, 331 const TextureDrawQuad* quad) { 332 if (!IsSoftwareResource(quad->resource_id)) { 333 DrawUnsupportedQuad(frame, quad); 334 return; 335 } 336 337 // FIXME: Add support for non-premultiplied alpha. 338 ResourceProvider::ScopedReadLockSoftware lock(resource_provider_, 339 quad->resource_id); 340 const SkBitmap* bitmap = lock.sk_bitmap(); 341 gfx::RectF uv_rect = gfx::ScaleRect(gfx::BoundingRect(quad->uv_top_left, 342 quad->uv_bottom_right), 343 bitmap->width(), 344 bitmap->height()); 345 SkRect sk_uv_rect = gfx::RectFToSkRect(uv_rect); 346 if (quad->flipped) 347 current_canvas_->scale(1, -1); 348 current_canvas_->drawBitmapRectToRect(*bitmap, &sk_uv_rect, 349 gfx::RectFToSkRect(QuadVertexRect()), 350 ¤t_paint_); 351} 352 353void SoftwareRenderer::DrawTileQuad(const DrawingFrame* frame, 354 const TileDrawQuad* quad) { 355 DCHECK(!output_surface_->ForcedDrawToSoftwareDevice()); 356 DCHECK(IsSoftwareResource(quad->resource_id)); 357 ResourceProvider::ScopedReadLockSoftware lock(resource_provider_, 358 quad->resource_id); 359 360 SkRect uv_rect = gfx::RectFToSkRect(quad->tex_coord_rect); 361 current_paint_.setFilterBitmap(true); 362 current_canvas_->drawBitmapRectToRect(*lock.sk_bitmap(), &uv_rect, 363 gfx::RectFToSkRect(QuadVertexRect()), 364 ¤t_paint_); 365} 366 367void SoftwareRenderer::DrawRenderPassQuad(const DrawingFrame* frame, 368 const RenderPassDrawQuad* quad) { 369 CachedResource* content_texture = 370 render_pass_textures_.get(quad->render_pass_id); 371 if (!content_texture || !content_texture->id()) 372 return; 373 374 DCHECK(IsSoftwareResource(content_texture->id())); 375 ResourceProvider::ScopedReadLockSoftware lock(resource_provider_, 376 content_texture->id()); 377 378 SkRect dest_rect = gfx::RectFToSkRect(QuadVertexRect()); 379 SkRect content_rect = SkRect::MakeWH(quad->rect.width(), quad->rect.height()); 380 381 SkMatrix content_mat; 382 content_mat.setRectToRect(content_rect, dest_rect, 383 SkMatrix::kFill_ScaleToFit); 384 385 const SkBitmap* content = lock.sk_bitmap(); 386 skia::RefPtr<SkShader> shader = skia::AdoptRef( 387 SkShader::CreateBitmapShader(*content, 388 SkShader::kClamp_TileMode, 389 SkShader::kClamp_TileMode)); 390 shader->setLocalMatrix(content_mat); 391 current_paint_.setShader(shader.get()); 392 393 SkImageFilter* filter = quad->filter.get(); 394 if (filter) 395 current_paint_.setImageFilter(filter); 396 397 if (quad->mask_resource_id) { 398 ResourceProvider::ScopedReadLockSoftware mask_lock(resource_provider_, 399 quad->mask_resource_id); 400 401 const SkBitmap* mask = mask_lock.sk_bitmap(); 402 403 SkRect mask_rect = SkRect::MakeXYWH( 404 quad->mask_uv_rect.x() * mask->width(), 405 quad->mask_uv_rect.y() * mask->height(), 406 quad->mask_uv_rect.width() * mask->width(), 407 quad->mask_uv_rect.height() * mask->height()); 408 409 SkMatrix mask_mat; 410 mask_mat.setRectToRect(mask_rect, dest_rect, SkMatrix::kFill_ScaleToFit); 411 412 skia::RefPtr<SkShader> mask_shader = skia::AdoptRef( 413 SkShader::CreateBitmapShader(*mask, 414 SkShader::kClamp_TileMode, 415 SkShader::kClamp_TileMode)); 416 mask_shader->setLocalMatrix(mask_mat); 417 418 SkPaint mask_paint; 419 mask_paint.setShader(mask_shader.get()); 420 421 skia::RefPtr<SkLayerRasterizer> mask_rasterizer = 422 skia::AdoptRef(new SkLayerRasterizer); 423 mask_rasterizer->addLayer(mask_paint); 424 425 current_paint_.setRasterizer(mask_rasterizer.get()); 426 current_canvas_->drawRect(dest_rect, current_paint_); 427 } else { 428 // FIXME: Apply background filters and blend with content 429 current_canvas_->drawRect(dest_rect, current_paint_); 430 } 431} 432 433void SoftwareRenderer::DrawUnsupportedQuad(const DrawingFrame* frame, 434 const DrawQuad* quad) { 435#ifdef NDEBUG 436 current_paint_.setColor(SK_ColorWHITE); 437#else 438 current_paint_.setColor(SK_ColorMAGENTA); 439#endif 440 current_paint_.setAlpha(quad->opacity() * 255); 441 current_canvas_->drawRect(gfx::RectFToSkRect(QuadVertexRect()), 442 current_paint_); 443} 444 445void SoftwareRenderer::CopyCurrentRenderPassToBitmap( 446 DrawingFrame* frame, 447 scoped_ptr<CopyOutputRequest> request) { 448 scoped_ptr<SkBitmap> bitmap(new SkBitmap); 449 bitmap->setConfig(SkBitmap::kARGB_8888_Config, 450 current_viewport_rect_.width(), 451 current_viewport_rect_.height()); 452 current_canvas_->readPixels( 453 bitmap.get(), current_viewport_rect_.x(), current_viewport_rect_.y()); 454 455 request->SendBitmapResult(bitmap.Pass()); 456} 457 458void SoftwareRenderer::GetFramebufferPixels(void* pixels, gfx::Rect rect) { 459 TRACE_EVENT0("cc", "SoftwareRenderer::GetFramebufferPixels"); 460 SkBitmap subset_bitmap; 461 rect += current_viewport_rect_.OffsetFromOrigin(); 462 output_device_->CopyToBitmap(rect, &subset_bitmap); 463 subset_bitmap.copyPixelsTo(pixels, 464 4 * rect.width() * rect.height(), 465 4 * rect.width()); 466} 467 468void SoftwareRenderer::SetVisible(bool visible) { 469 if (visible_ == visible) 470 return; 471 visible_ = visible; 472} 473 474} // namespace cc 475