add a use_alsa gyp setting
[chromium-blink-merge.git] / cc / software_renderer.cc
blobe1764c79a4c24b69c6ebb5bfcefb94f202b21054
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.
5 #include "cc/software_renderer.h"
7 #include "base/debug/trace_event.h"
8 #include "cc/debug_border_draw_quad.h"
9 #include "cc/math_util.h"
10 #include "cc/render_pass_draw_quad.h"
11 #include "cc/software_output_device.h"
12 #include "cc/solid_color_draw_quad.h"
13 #include "cc/texture_draw_quad.h"
14 #include "cc/tile_draw_quad.h"
15 #include "third_party/WebKit/Source/Platform/chromium/public/WebImage.h"
16 #include "third_party/skia/include/core/SkCanvas.h"
17 #include "third_party/skia/include/core/SkColor.h"
18 #include "third_party/skia/include/core/SkDevice.h"
19 #include "third_party/skia/include/core/SkMatrix.h"
20 #include "third_party/skia/include/core/SkShader.h"
21 #include "third_party/skia/include/effects/SkLayerRasterizer.h"
22 #include "ui/gfx/rect_conversions.h"
23 #include "ui/gfx/skia_util.h"
24 #include "ui/gfx/transform.h"
26 namespace cc {
28 namespace {
30 void toSkMatrix(SkMatrix* flattened, const gfx::Transform& m)
32 // Convert from 4x4 to 3x3 by dropping the third row and column.
33 flattened->set(0, SkDoubleToScalar(m.matrix().getDouble(0, 0)));
34 flattened->set(1, SkDoubleToScalar(m.matrix().getDouble(0, 1)));
35 flattened->set(2, SkDoubleToScalar(m.matrix().getDouble(0, 3)));
36 flattened->set(3, SkDoubleToScalar(m.matrix().getDouble(1, 0)));
37 flattened->set(4, SkDoubleToScalar(m.matrix().getDouble(1, 1)));
38 flattened->set(5, SkDoubleToScalar(m.matrix().getDouble(1, 3)));
39 flattened->set(6, SkDoubleToScalar(m.matrix().getDouble(3, 0)));
40 flattened->set(7, SkDoubleToScalar(m.matrix().getDouble(3, 1)));
41 flattened->set(8, SkDoubleToScalar(m.matrix().getDouble(3, 3)));
44 bool isScaleAndTranslate(const SkMatrix& matrix)
46 return SkScalarNearlyZero(matrix[SkMatrix::kMSkewX]) &&
47 SkScalarNearlyZero(matrix[SkMatrix::kMSkewY]) &&
48 SkScalarNearlyZero(matrix[SkMatrix::kMPersp0]) &&
49 SkScalarNearlyZero(matrix[SkMatrix::kMPersp1]) &&
50 SkScalarNearlyZero(matrix[SkMatrix::kMPersp2] - 1.0f);
53 } // anonymous namespace
55 scoped_ptr<SoftwareRenderer> SoftwareRenderer::create(RendererClient* client, ResourceProvider* resourceProvider, SoftwareOutputDevice* outputDevice)
57 return make_scoped_ptr(new SoftwareRenderer(client, resourceProvider, outputDevice));
60 SoftwareRenderer::SoftwareRenderer(RendererClient* client, ResourceProvider* resourceProvider, SoftwareOutputDevice* outputDevice)
61 : DirectRenderer(client, resourceProvider)
62 , m_visible(true)
63 , m_isScissorEnabled(false)
64 , m_outputDevice(outputDevice)
65 , m_skCurrentCanvas(0)
67 m_resourceProvider->setDefaultResourceType(ResourceProvider::Bitmap);
69 m_capabilities.maxTextureSize = m_resourceProvider->maxTextureSize();
70 m_capabilities.bestTextureFormat = m_resourceProvider->bestTextureFormat();
71 m_capabilities.usingSetVisibility = true;
72 // The updater can access bitmaps while the SoftwareRenderer is using them.
73 m_capabilities.allowPartialTextureUpdates = true;
74 m_capabilities.usingPartialSwap = true;
76 viewportChanged();
79 SoftwareRenderer::~SoftwareRenderer()
83 const RendererCapabilities& SoftwareRenderer::capabilities() const
85 return m_capabilities;
88 void SoftwareRenderer::viewportChanged()
90 m_outputDevice->DidChangeViewportSize(viewportSize());
93 void SoftwareRenderer::beginDrawingFrame(DrawingFrame& frame)
95 TRACE_EVENT0("cc", "SoftwareRenderer::beginDrawingFrame");
96 m_skRootCanvas = make_scoped_ptr(new SkCanvas(m_outputDevice->Lock(true)->getSkBitmap()));
99 void SoftwareRenderer::finishDrawingFrame(DrawingFrame& frame)
101 TRACE_EVENT0("cc", "SoftwareRenderer::finishDrawingFrame");
102 m_currentFramebufferLock.reset();
103 m_skCurrentCanvas = 0;
104 m_skRootCanvas.reset();
105 m_outputDevice->Unlock();
108 bool SoftwareRenderer::flippedFramebuffer() const
110 return false;
113 void SoftwareRenderer::ensureScissorTestEnabled()
115 m_isScissorEnabled = true;
116 setClipRect(m_scissorRect);
119 void SoftwareRenderer::ensureScissorTestDisabled()
121 // There is no explicit notion of enabling/disabling scissoring in software
122 // rendering, but the underlying effect we want is to clear any existing
123 // clipRect on the current SkCanvas. This is done by setting clipRect to
124 // the viewport's dimensions.
125 m_isScissorEnabled = false;
126 SkDevice* device = m_skCurrentCanvas->getDevice();
127 setClipRect(gfx::Rect(device->width(), device->height()));
130 void SoftwareRenderer::finish()
134 void SoftwareRenderer::bindFramebufferToOutputSurface(DrawingFrame& frame)
136 m_currentFramebufferLock.reset();
137 m_skCurrentCanvas = m_skRootCanvas.get();
140 bool SoftwareRenderer::bindFramebufferToTexture(DrawingFrame& frame, const ScopedResource* texture, const gfx::Rect& framebufferRect)
142 m_currentFramebufferLock = make_scoped_ptr(new ResourceProvider::ScopedWriteLockSoftware(m_resourceProvider, texture->id()));
143 m_skCurrentCanvas = m_currentFramebufferLock->skCanvas();
144 initializeMatrices(frame, framebufferRect, false);
145 setDrawViewportSize(framebufferRect.size());
147 return true;
150 void SoftwareRenderer::setScissorTestRect(const gfx::Rect& scissorRect)
152 m_isScissorEnabled = true;
153 m_scissorRect = scissorRect;
154 setClipRect(scissorRect);
157 void SoftwareRenderer::setClipRect(const gfx::Rect& rect)
159 // Skia applies the current matrix to clip rects so we reset it temporary.
160 SkMatrix currentMatrix = m_skCurrentCanvas->getTotalMatrix();
161 m_skCurrentCanvas->resetMatrix();
162 m_skCurrentCanvas->clipRect(gfx::RectToSkRect(rect), SkRegion::kReplace_Op);
163 m_skCurrentCanvas->setMatrix(currentMatrix);
166 void SoftwareRenderer::clearCanvas(SkColor color)
168 // SkCanvas::clear doesn't respect the current clipping region
169 // so we SkCanvas::drawColor instead if scissoring is active.
170 if (m_isScissorEnabled)
171 m_skCurrentCanvas->drawColor(color, SkXfermode::kSrc_Mode);
172 else
173 m_skCurrentCanvas->clear(color);
176 void SoftwareRenderer::clearFramebuffer(DrawingFrame& frame)
178 if (frame.currentRenderPass->has_transparent_background) {
179 clearCanvas(SkColorSetARGB(0, 0, 0, 0));
180 } else {
181 #ifndef NDEBUG
182 // On DEBUG builds, opaque render passes are cleared to blue to easily see regions that were not drawn on the screen.
183 clearCanvas(SkColorSetARGB(255, 0, 0, 255));
184 #endif
188 void SoftwareRenderer::setDrawViewportSize(const gfx::Size& viewportSize)
192 bool SoftwareRenderer::isSoftwareResource(ResourceProvider::ResourceId id) const
194 switch (m_resourceProvider->resourceType(id)) {
195 case ResourceProvider::GLTexture:
196 return false;
197 case ResourceProvider::Bitmap:
198 return true;
201 LOG(FATAL) << "Invalid resource type.";
202 return false;
205 void SoftwareRenderer::drawQuad(DrawingFrame& frame, const DrawQuad* quad)
207 TRACE_EVENT0("cc", "SoftwareRenderer::drawQuad");
208 gfx::Transform quadRectMatrix;
209 quadRectTransform(&quadRectMatrix, quad->quadTransform(), quad->rect);
210 gfx::Transform contentsDeviceTransform = frame.windowMatrix * frame.projectionMatrix * quadRectMatrix;
211 contentsDeviceTransform.FlattenTo2d();
212 SkMatrix skDeviceMatrix;
213 toSkMatrix(&skDeviceMatrix, contentsDeviceTransform);
214 m_skCurrentCanvas->setMatrix(skDeviceMatrix);
216 m_skCurrentPaint.reset();
217 if (!isScaleAndTranslate(skDeviceMatrix)) {
218 m_skCurrentPaint.setAntiAlias(true);
219 m_skCurrentPaint.setFilterBitmap(true);
222 if (quad->ShouldDrawWithBlending()) {
223 m_skCurrentPaint.setAlpha(quad->opacity() * 255);
224 m_skCurrentPaint.setXfermodeMode(SkXfermode::kSrcOver_Mode);
225 } else {
226 m_skCurrentPaint.setXfermodeMode(SkXfermode::kSrc_Mode);
229 switch (quad->material) {
230 case DrawQuad::DEBUG_BORDER:
231 drawDebugBorderQuad(frame, DebugBorderDrawQuad::MaterialCast(quad));
232 break;
233 case DrawQuad::SOLID_COLOR:
234 drawSolidColorQuad(frame, SolidColorDrawQuad::MaterialCast(quad));
235 break;
236 case DrawQuad::TEXTURE_CONTENT:
237 drawTextureQuad(frame, TextureDrawQuad::MaterialCast(quad));
238 break;
239 case DrawQuad::TILED_CONTENT:
240 drawTileQuad(frame, TileDrawQuad::MaterialCast(quad));
241 break;
242 case DrawQuad::RENDER_PASS:
243 drawRenderPassQuad(frame, RenderPassDrawQuad::MaterialCast(quad));
244 break;
245 default:
246 drawUnsupportedQuad(frame, quad);
247 break;
250 m_skCurrentCanvas->resetMatrix();
253 void SoftwareRenderer::drawDebugBorderQuad(const DrawingFrame& frame, const DebugBorderDrawQuad* quad)
255 // We need to apply the matrix manually to have pixel-sized stroke width.
256 SkPoint vertices[4];
257 gfx::RectFToSkRect(quadVertexRect()).toQuad(vertices);
258 SkPoint transformedVertices[4];
259 m_skCurrentCanvas->getTotalMatrix().mapPoints(transformedVertices, vertices, 4);
260 m_skCurrentCanvas->resetMatrix();
262 m_skCurrentPaint.setColor(quad->color);
263 m_skCurrentPaint.setAlpha(quad->opacity() * SkColorGetA(quad->color));
264 m_skCurrentPaint.setStyle(SkPaint::kStroke_Style);
265 m_skCurrentPaint.setStrokeWidth(quad->width);
266 m_skCurrentCanvas->drawPoints(SkCanvas::kPolygon_PointMode, 4, transformedVertices, m_skCurrentPaint);
269 void SoftwareRenderer::drawSolidColorQuad(const DrawingFrame& frame, const SolidColorDrawQuad* quad)
271 m_skCurrentPaint.setColor(quad->color);
272 m_skCurrentPaint.setAlpha(quad->opacity() * SkColorGetA(quad->color));
273 m_skCurrentCanvas->drawRect(gfx::RectFToSkRect(quadVertexRect()), m_skCurrentPaint);
276 void SoftwareRenderer::drawTextureQuad(const DrawingFrame& frame, const TextureDrawQuad* quad)
278 if (!isSoftwareResource(quad->resource_id)) {
279 drawUnsupportedQuad(frame, quad);
280 return;
283 // FIXME: Add support for non-premultiplied alpha.
284 ResourceProvider::ScopedReadLockSoftware lock(m_resourceProvider, quad->resource_id);
285 const SkBitmap* bitmap = lock.skBitmap();
286 gfx::RectF uvRect = gfx::ScaleRect(gfx::BoundingRect(quad->uv_top_left, quad->uv_bottom_right),
287 bitmap->width(),
288 bitmap->height());
289 SkRect skUvRect = gfx::RectFToSkRect(uvRect);
290 if (quad->flipped)
291 m_skCurrentCanvas->scale(1, -1);
292 m_skCurrentCanvas->drawBitmapRectToRect(*bitmap, &skUvRect,
293 gfx::RectFToSkRect(quadVertexRect()),
294 &m_skCurrentPaint);
297 void SoftwareRenderer::drawTileQuad(const DrawingFrame& frame, const TileDrawQuad* quad)
299 DCHECK(isSoftwareResource(quad->resource_id));
300 ResourceProvider::ScopedReadLockSoftware lock(m_resourceProvider, quad->resource_id);
302 SkRect uvRect = gfx::RectFToSkRect(quad->tex_coord_rect);
303 m_skCurrentPaint.setFilterBitmap(true);
304 m_skCurrentCanvas->drawBitmapRectToRect(*lock.skBitmap(), &uvRect,
305 gfx::RectFToSkRect(quadVertexRect()),
306 &m_skCurrentPaint);
309 void SoftwareRenderer::drawRenderPassQuad(const DrawingFrame& frame, const RenderPassDrawQuad* quad)
311 CachedResource* contentTexture = m_renderPassTextures.get(quad->render_pass_id);
312 if (!contentTexture || !contentTexture->id())
313 return;
315 DCHECK(isSoftwareResource(contentTexture->id()));
316 ResourceProvider::ScopedReadLockSoftware lock(m_resourceProvider, contentTexture->id());
318 SkRect destRect = gfx::RectFToSkRect(quadVertexRect());
319 SkRect contentRect = SkRect::MakeWH(quad->rect.width(), quad->rect.height());
321 SkMatrix contentMat;
322 contentMat.setRectToRect(contentRect, destRect, SkMatrix::kFill_ScaleToFit);
324 const SkBitmap* content = lock.skBitmap();
325 skia::RefPtr<SkShader> shader = skia::AdoptRef(
326 SkShader::CreateBitmapShader(*content,
327 SkShader::kClamp_TileMode,
328 SkShader::kClamp_TileMode));
329 shader->setLocalMatrix(contentMat);
330 m_skCurrentPaint.setShader(shader.get());
332 SkImageFilter* filter = quad->filter.get();
333 if (filter)
334 m_skCurrentPaint.setImageFilter(filter);
336 if (quad->mask_resource_id) {
337 ResourceProvider::ScopedReadLockSoftware maskLock(m_resourceProvider, quad->mask_resource_id);
339 const SkBitmap* mask = maskLock.skBitmap();
341 SkRect maskRect = SkRect::MakeXYWH(
342 quad->mask_uv_rect.x() * mask->width(),
343 quad->mask_uv_rect.y() * mask->height(),
344 quad->mask_uv_rect.width() * mask->width(),
345 quad->mask_uv_rect.height() * mask->height());
347 SkMatrix maskMat;
348 maskMat.setRectToRect(maskRect, destRect, SkMatrix::kFill_ScaleToFit);
350 skia::RefPtr<SkShader> maskShader = skia::AdoptRef(
351 SkShader::CreateBitmapShader(*mask,
352 SkShader::kClamp_TileMode,
353 SkShader::kClamp_TileMode));
354 maskShader->setLocalMatrix(maskMat);
356 SkPaint maskPaint;
357 maskPaint.setShader(maskShader.get());
359 skia::RefPtr<SkLayerRasterizer> maskRasterizer = skia::AdoptRef(new SkLayerRasterizer);
360 maskRasterizer->addLayer(maskPaint);
362 m_skCurrentPaint.setRasterizer(maskRasterizer.get());
363 m_skCurrentCanvas->drawRect(destRect, m_skCurrentPaint);
364 } else {
365 // FIXME: Apply background filters and blend with content
366 m_skCurrentCanvas->drawRect(destRect, m_skCurrentPaint);
370 void SoftwareRenderer::drawUnsupportedQuad(const DrawingFrame& frame, const DrawQuad* quad)
372 m_skCurrentPaint.setColor(SK_ColorMAGENTA);
373 m_skCurrentPaint.setAlpha(quad->opacity() * 255);
374 m_skCurrentCanvas->drawRect(gfx::RectFToSkRect(quadVertexRect()), m_skCurrentPaint);
377 bool SoftwareRenderer::swapBuffers()
379 if (m_client->hasImplThread())
380 m_client->onSwapBuffersComplete();
381 return true;
384 void SoftwareRenderer::getFramebufferPixels(void *pixels, const gfx::Rect& rect)
386 TRACE_EVENT0("cc", "SoftwareRenderer::getFramebufferPixels");
387 SkBitmap fullBitmap = m_outputDevice->Lock(false)->getSkBitmap();
388 SkBitmap subsetBitmap;
389 SkIRect invertRect = SkIRect::MakeXYWH(rect.x(), viewportSize().height() - rect.bottom(), rect.width(), rect.height());
390 fullBitmap.extractSubset(&subsetBitmap, invertRect);
391 subsetBitmap.copyPixelsTo(pixels, rect.width() * rect.height() * 4, rect.width() * 4);
392 m_outputDevice->Unlock();
395 void SoftwareRenderer::setVisible(bool visible)
397 if (m_visible == visible)
398 return;
399 m_visible = visible;
402 } // namespace cc