blob: 028a2766f6af24a56e5d01df5e6658eee6d325d3 [file] [log] [blame]
[email protected]d61675de42012-09-24 21:32:571// 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 "config.h"
6
[email protected]c4040a522012-10-21 15:01:407#include "cc/software_renderer.h"
[email protected]d61675de42012-09-24 21:32:578
9#include "CCDebugBorderDrawQuad.h"
[email protected]ad5d1422012-10-19 13:40:2910#include "CCRenderPassDrawQuad.h"
[email protected]4456eee22012-10-19 18:16:3811#include "cc/solid_color_draw_quad.h"
12#include "cc/texture_draw_quad.h"
[email protected]da2c9122012-10-20 23:13:0613#include "cc/tile_draw_quad.h"
[email protected]0b056ee2012-10-15 21:31:2114#include "third_party/skia/include/core/SkCanvas.h"
15#include "third_party/skia/include/core/SkColor.h"
16#include "third_party/skia/include/core/SkMatrix.h"
17#include "third_party/skia/include/core/SkShader.h"
18#include "third_party/skia/include/effects/SkLayerRasterizer.h"
[email protected]1fea8142012-10-20 04:12:4119#include "ui/gfx/rect_conversions.h"
[email protected]d61675de42012-09-24 21:32:5720#include <public/WebImage.h>
21#include <public/WebSize.h>
22#include <public/WebTransformationMatrix.h>
23
24using WebKit::WebCompositorSoftwareOutputDevice;
25using WebKit::WebImage;
26using WebKit::WebSize;
27using WebKit::WebTransformationMatrix;
28
29namespace cc {
30
31namespace {
32
[email protected]1fea8142012-10-20 04:12:4133SkRect toSkRect(const gfx::RectF& rect)
[email protected]d61675de42012-09-24 21:32:5734{
35 return SkRect::MakeXYWH(rect.x(), rect.y(), rect.width(), rect.height());
36}
37
[email protected]1fea8142012-10-20 04:12:4138SkIRect toSkIRect(const gfx::Rect& rect)
[email protected]d61675de42012-09-24 21:32:5739{
40 return SkIRect::MakeXYWH(rect.x(), rect.y(), rect.width(), rect.height());
41}
42
43void toSkMatrix(SkMatrix* flattened, const WebTransformationMatrix& m)
44{
45 // Convert from 4x4 to 3x3 by dropping the third row and column.
46 flattened->set(0, m.m11());
47 flattened->set(1, m.m21());
48 flattened->set(2, m.m41());
49 flattened->set(3, m.m12());
50 flattened->set(4, m.m22());
51 flattened->set(5, m.m42());
52 flattened->set(6, m.m14());
53 flattened->set(7, m.m24());
54 flattened->set(8, m.m44());
55}
56
[email protected]276508a2012-10-16 00:56:3457bool isScaleAndTranslate(const SkMatrix& matrix)
58{
59 return SkScalarNearlyZero(matrix[SkMatrix::kMSkewX]) &&
60 SkScalarNearlyZero(matrix[SkMatrix::kMSkewY]) &&
61 SkScalarNearlyZero(matrix[SkMatrix::kMPersp0]) &&
62 SkScalarNearlyZero(matrix[SkMatrix::kMPersp1]) &&
63 SkScalarNearlyZero(matrix[SkMatrix::kMPersp2] - 1.0f);
64}
65
[email protected]d61675de42012-09-24 21:32:5766} // anonymous namespace
67
[email protected]c753e25a2012-10-19 21:22:4268scoped_ptr<CCRendererSoftware> CCRendererSoftware::create(CCRendererClient* client, CCResourceProvider* resourceProvider, WebCompositorSoftwareOutputDevice* outputDevice)
[email protected]d61675de42012-09-24 21:32:5769{
[email protected]c753e25a2012-10-19 21:22:4270 return make_scoped_ptr(new CCRendererSoftware(client, resourceProvider, outputDevice));
[email protected]d61675de42012-09-24 21:32:5771}
72
[email protected]c753e25a2012-10-19 21:22:4273CCRendererSoftware::CCRendererSoftware(CCRendererClient* client, CCResourceProvider* resourceProvider, WebCompositorSoftwareOutputDevice* outputDevice)
74 : CCDirectRenderer(client, resourceProvider)
[email protected]d61675de42012-09-24 21:32:5775 , m_visible(true)
76 , m_outputDevice(outputDevice)
[email protected]d61675de42012-09-24 21:32:5777 , m_skCurrentCanvas(0)
78{
[email protected]c753e25a2012-10-19 21:22:4279 m_resourceProvider->setDefaultResourceType(CCResourceProvider::Bitmap);
[email protected]d61675de42012-09-24 21:32:5780
81 m_capabilities.maxTextureSize = INT_MAX;
[email protected]d9c28522012-10-18 23:35:4382 m_capabilities.bestTextureFormat = GL_RGBA;
[email protected]d61675de42012-09-24 21:32:5783 m_capabilities.contextHasCachedFrontBuffer = true;
84 m_capabilities.usingSetVisibility = true;
85
86 viewportChanged();
87}
88
[email protected]c753e25a2012-10-19 21:22:4289CCRendererSoftware::~CCRendererSoftware()
[email protected]d61675de42012-09-24 21:32:5790{
91}
92
[email protected]c753e25a2012-10-19 21:22:4293const RendererCapabilities& CCRendererSoftware::capabilities() const
[email protected]d61675de42012-09-24 21:32:5794{
95 return m_capabilities;
96}
97
[email protected]c753e25a2012-10-19 21:22:4298void CCRendererSoftware::viewportChanged()
[email protected]d61675de42012-09-24 21:32:5799{
100 m_outputDevice->didChangeViewportSize(WebSize(viewportSize().width(), viewportSize().height()));
101}
102
[email protected]c753e25a2012-10-19 21:22:42103void CCRendererSoftware::beginDrawingFrame(DrawingFrame& frame)
[email protected]d61675de42012-09-24 21:32:57104{
[email protected]0704caf2012-10-16 03:39:47105 m_skRootCanvas = make_scoped_ptr(new SkCanvas(m_outputDevice->lock(true)->getSkBitmap()));
[email protected]d61675de42012-09-24 21:32:57106}
107
[email protected]c753e25a2012-10-19 21:22:42108void CCRendererSoftware::finishDrawingFrame(DrawingFrame& frame)
[email protected]d61675de42012-09-24 21:32:57109{
[email protected]0704caf2012-10-16 03:39:47110 m_currentFramebufferLock.reset();
[email protected]d61675de42012-09-24 21:32:57111 m_skCurrentCanvas = 0;
[email protected]0704caf2012-10-16 03:39:47112 m_skRootCanvas.reset();
[email protected]d61675de42012-09-24 21:32:57113 m_outputDevice->unlock();
114}
115
[email protected]c753e25a2012-10-19 21:22:42116bool CCRendererSoftware::flippedFramebuffer() const
[email protected]d61675de42012-09-24 21:32:57117{
118 return false;
119}
120
[email protected]c753e25a2012-10-19 21:22:42121void CCRendererSoftware::finish()
[email protected]d61675de42012-09-24 21:32:57122{
123}
124
[email protected]c753e25a2012-10-19 21:22:42125void CCRendererSoftware::bindFramebufferToOutputSurface(DrawingFrame& frame)
[email protected]d61675de42012-09-24 21:32:57126{
[email protected]0704caf2012-10-16 03:39:47127 m_currentFramebufferLock.reset();
[email protected]75fe7f822012-09-28 17:54:14128 m_skCurrentCanvas = m_skRootCanvas.get();
[email protected]d61675de42012-09-24 21:32:57129}
130
[email protected]1fea8142012-10-20 04:12:41131bool CCRendererSoftware::bindFramebufferToTexture(DrawingFrame& frame, const CCScopedTexture* texture, const gfx::Rect& framebufferRect)
[email protected]d61675de42012-09-24 21:32:57132{
[email protected]c753e25a2012-10-19 21:22:42133 m_currentFramebufferLock = make_scoped_ptr(new CCResourceProvider::ScopedWriteLockSoftware(m_resourceProvider, texture->id()));
[email protected]d61675de42012-09-24 21:32:57134 m_skCurrentCanvas = m_currentFramebufferLock->skCanvas();
135 initializeMatrices(frame, framebufferRect, false);
136 setDrawViewportSize(framebufferRect.size());
137
138 return true;
139}
140
[email protected]1fea8142012-10-20 04:12:41141void CCRendererSoftware::enableScissorTestRect(const gfx::Rect& scissorRect)
[email protected]d61675de42012-09-24 21:32:57142{
143 m_skCurrentCanvas->clipRect(toSkRect(scissorRect), SkRegion::kReplace_Op);
144}
145
[email protected]c753e25a2012-10-19 21:22:42146void CCRendererSoftware::disableScissorTest()
[email protected]d61675de42012-09-24 21:32:57147{
[email protected]1fea8142012-10-20 04:12:41148 gfx::Rect canvasRect(gfx::Point(), viewportSize());
[email protected]d61675de42012-09-24 21:32:57149 m_skCurrentCanvas->clipRect(toSkRect(canvasRect), SkRegion::kReplace_Op);
150}
151
[email protected]c753e25a2012-10-19 21:22:42152void CCRendererSoftware::clearFramebuffer(DrawingFrame& frame)
[email protected]d61675de42012-09-24 21:32:57153{
[email protected]0b056ee2012-10-15 21:31:21154 if (frame.currentRenderPass->hasTransparentBackground()) {
155 m_skCurrentCanvas->clear(SkColorSetARGB(0, 0, 0, 0));
156 } else {
157#ifndef NDEBUG
158 // On DEBUG builds, opaque render passes are cleared to blue to easily see regions that were not drawn on the screen.
159 m_skCurrentCanvas->clear(SkColorSetARGB(255, 0, 0, 255));
160#endif
161 }
[email protected]d61675de42012-09-24 21:32:57162}
163
[email protected]1fea8142012-10-20 04:12:41164void CCRendererSoftware::setDrawViewportSize(const gfx::Size& viewportSize)
[email protected]d61675de42012-09-24 21:32:57165{
166}
167
[email protected]c753e25a2012-10-19 21:22:42168bool CCRendererSoftware::isSoftwareResource(CCResourceProvider::ResourceId id) const
[email protected]d61675de42012-09-24 21:32:57169{
170 switch (m_resourceProvider->resourceType(id)) {
[email protected]c753e25a2012-10-19 21:22:42171 case CCResourceProvider::GLTexture:
[email protected]d61675de42012-09-24 21:32:57172 return false;
[email protected]c753e25a2012-10-19 21:22:42173 case CCResourceProvider::Bitmap:
[email protected]d61675de42012-09-24 21:32:57174 return true;
175 }
176
177 CRASH();
178 return false;
179}
180
[email protected]c753e25a2012-10-19 21:22:42181void CCRendererSoftware::drawQuad(DrawingFrame& frame, const CCDrawQuad* quad)
[email protected]d61675de42012-09-24 21:32:57182{
183 WebTransformationMatrix quadRectMatrix;
184 quadRectTransform(&quadRectMatrix, quad->quadTransform(), quad->quadRect());
[email protected]0b056ee2012-10-15 21:31:21185 WebTransformationMatrix contentsDeviceTransform = (frame.windowMatrix * frame.projectionMatrix * quadRectMatrix).to2dTransform();
186 SkMatrix skDeviceMatrix;
187 toSkMatrix(&skDeviceMatrix, contentsDeviceTransform);
188 m_skCurrentCanvas->setMatrix(skDeviceMatrix);
[email protected]d61675de42012-09-24 21:32:57189
190 m_skCurrentPaint.reset();
[email protected]276508a2012-10-16 00:56:34191 if (!isScaleAndTranslate(skDeviceMatrix)) {
192 m_skCurrentPaint.setAntiAlias(true);
193 m_skCurrentPaint.setFilterBitmap(true);
194 }
[email protected]0b056ee2012-10-15 21:31:21195 if (quad->needsBlending()) {
[email protected]d61675de42012-09-24 21:32:57196 m_skCurrentPaint.setAlpha(quad->opacity() * 255);
[email protected]0b056ee2012-10-15 21:31:21197 m_skCurrentPaint.setXfermodeMode(SkXfermode::kSrcOver_Mode);
198 } else {
[email protected]d61675de42012-09-24 21:32:57199 m_skCurrentPaint.setXfermodeMode(SkXfermode::kSrc_Mode);
[email protected]0b056ee2012-10-15 21:31:21200 }
[email protected]d61675de42012-09-24 21:32:57201
202 switch (quad->material()) {
[email protected]c753e25a2012-10-19 21:22:42203 case CCDrawQuad::DebugBorder:
204 drawDebugBorderQuad(frame, CCDebugBorderDrawQuad::materialCast(quad));
[email protected]d61675de42012-09-24 21:32:57205 break;
[email protected]c753e25a2012-10-19 21:22:42206 case CCDrawQuad::SolidColor:
207 drawSolidColorQuad(frame, CCSolidColorDrawQuad::materialCast(quad));
[email protected]d61675de42012-09-24 21:32:57208 break;
[email protected]c753e25a2012-10-19 21:22:42209 case CCDrawQuad::TextureContent:
210 drawTextureQuad(frame, CCTextureDrawQuad::materialCast(quad));
[email protected]d61675de42012-09-24 21:32:57211 break;
[email protected]c753e25a2012-10-19 21:22:42212 case CCDrawQuad::TiledContent:
213 drawTileQuad(frame, CCTileDrawQuad::materialCast(quad));
[email protected]d61675de42012-09-24 21:32:57214 break;
[email protected]c753e25a2012-10-19 21:22:42215 case CCDrawQuad::RenderPass:
216 drawRenderPassQuad(frame, CCRenderPassDrawQuad::materialCast(quad));
[email protected]0b056ee2012-10-15 21:31:21217 break;
[email protected]d61675de42012-09-24 21:32:57218 default:
219 drawUnsupportedQuad(frame, quad);
220 break;
221 }
222
223 m_skCurrentCanvas->resetMatrix();
224}
225
[email protected]c753e25a2012-10-19 21:22:42226void CCRendererSoftware::drawDebugBorderQuad(const DrawingFrame& frame, const CCDebugBorderDrawQuad* quad)
[email protected]d61675de42012-09-24 21:32:57227{
228 // We need to apply the matrix manually to have pixel-sized stroke width.
229 SkPoint vertices[4];
230 toSkRect(quadVertexRect()).toQuad(vertices);
231 SkPoint transformedVertices[4];
232 m_skCurrentCanvas->getTotalMatrix().mapPoints(transformedVertices, vertices, 4);
233 m_skCurrentCanvas->resetMatrix();
234
235 m_skCurrentPaint.setColor(quad->color());
236 m_skCurrentPaint.setAlpha(quad->opacity() * SkColorGetA(quad->color()));
237 m_skCurrentPaint.setStyle(SkPaint::kStroke_Style);
238 m_skCurrentPaint.setStrokeWidth(quad->width());
239 m_skCurrentCanvas->drawPoints(SkCanvas::kPolygon_PointMode, 4, transformedVertices, m_skCurrentPaint);
240}
241
[email protected]c753e25a2012-10-19 21:22:42242void CCRendererSoftware::drawSolidColorQuad(const DrawingFrame& frame, const CCSolidColorDrawQuad* quad)
[email protected]d61675de42012-09-24 21:32:57243{
244 m_skCurrentPaint.setColor(quad->color());
245 m_skCurrentPaint.setAlpha(quad->opacity() * SkColorGetA(quad->color()));
246 m_skCurrentCanvas->drawRect(toSkRect(quadVertexRect()), m_skCurrentPaint);
247}
248
[email protected]c753e25a2012-10-19 21:22:42249void CCRendererSoftware::drawTextureQuad(const DrawingFrame& frame, const CCTextureDrawQuad* quad)
[email protected]d61675de42012-09-24 21:32:57250{
251 if (!isSoftwareResource(quad->resourceId())) {
252 drawUnsupportedQuad(frame, quad);
253 return;
254 }
255
256 // FIXME: Add support for non-premultiplied alpha.
[email protected]c753e25a2012-10-19 21:22:42257 CCResourceProvider::ScopedReadLockSoftware quadResourceLock(m_resourceProvider, quad->resourceId());
[email protected]1fea8142012-10-20 04:12:41258 gfx::RectF uvRect = quad->uvRect().Scale(quad->quadRect().width(), quad->quadRect().height());
259 SkIRect skUvRect = toSkIRect(gfx::ToEnclosingRect(uvRect));
[email protected]d61675de42012-09-24 21:32:57260 if (quad->flipped())
261 m_skCurrentCanvas->scale(1, -1);
262 m_skCurrentCanvas->drawBitmapRect(*quadResourceLock.skBitmap(), &skUvRect, toSkRect(quadVertexRect()), &m_skCurrentPaint);
263}
264
[email protected]c753e25a2012-10-19 21:22:42265void CCRendererSoftware::drawTileQuad(const DrawingFrame& frame, const CCTileDrawQuad* quad)
[email protected]d61675de42012-09-24 21:32:57266{
[email protected]1d993172012-10-18 18:15:04267 DCHECK(isSoftwareResource(quad->resourceId()));
[email protected]c753e25a2012-10-19 21:22:42268 CCResourceProvider::ScopedReadLockSoftware quadResourceLock(m_resourceProvider, quad->resourceId());
[email protected]d61675de42012-09-24 21:32:57269
[email protected]1fea8142012-10-20 04:12:41270 SkIRect uvRect = toSkIRect(gfx::Rect(quad->textureOffset(), quad->quadRect().size()));
[email protected]d61675de42012-09-24 21:32:57271 m_skCurrentCanvas->drawBitmapRect(*quadResourceLock.skBitmap(), &uvRect, toSkRect(quadVertexRect()), &m_skCurrentPaint);
272}
273
[email protected]c753e25a2012-10-19 21:22:42274void CCRendererSoftware::drawRenderPassQuad(const DrawingFrame& frame, const CCRenderPassDrawQuad* quad)
[email protected]0b056ee2012-10-15 21:31:21275{
276 CachedTexture* contentsTexture = m_renderPassTextures.get(quad->renderPassId());
277 if (!contentsTexture || !contentsTexture->id())
278 return;
279
[email protected]1d993172012-10-18 18:15:04280 DCHECK(isSoftwareResource(contentsTexture->id()));
[email protected]c753e25a2012-10-19 21:22:42281 CCResourceProvider::ScopedReadLockSoftware contentsTextureLock(m_resourceProvider, contentsTexture->id());
[email protected]0b056ee2012-10-15 21:31:21282
283 const SkBitmap* bitmap = contentsTextureLock.skBitmap();
284
285 SkRect sourceRect;
286 bitmap->getBounds(&sourceRect);
287
288 SkRect destRect = toSkRect(quadVertexRect());
289
290 SkMatrix matrix;
291 matrix.setRectToRect(sourceRect, destRect, SkMatrix::kFill_ScaleToFit);
292
293 SkAutoTUnref<SkShader> shader(SkShader::CreateBitmapShader(*bitmap,
294 SkShader::kClamp_TileMode,
295 SkShader::kClamp_TileMode));
296 shader->setLocalMatrix(matrix);
297 m_skCurrentPaint.setShader(shader);
298
299 if (quad->maskResourceId()) {
[email protected]c753e25a2012-10-19 21:22:42300 CCResourceProvider::ScopedReadLockSoftware maskResourceLock(m_resourceProvider, quad->maskResourceId());
[email protected]0b056ee2012-10-15 21:31:21301 const SkBitmap* maskBitmap = maskResourceLock.skBitmap();
302
303 SkMatrix maskMat;
304 maskMat.setRectToRect(toSkRect(quad->quadRect()), destRect, SkMatrix::kFill_ScaleToFit);
305 maskMat.postTranslate(quad->maskTexCoordOffsetX(), quad->maskTexCoordOffsetY());
306
307 SkAutoTUnref<SkShader> maskShader(SkShader::CreateBitmapShader(*maskBitmap,
308 SkShader::kClamp_TileMode,
309 SkShader::kClamp_TileMode));
310 maskShader->setLocalMatrix(maskMat);
311
312 SkPaint maskPaint;
313 maskPaint.setShader(maskShader);
314
315 SkAutoTUnref<SkLayerRasterizer> maskRasterizer(new SkLayerRasterizer);
316 maskRasterizer->addLayer(maskPaint);
317
318 m_skCurrentPaint.setRasterizer(maskRasterizer);
319 m_skCurrentCanvas->drawRect(destRect, m_skCurrentPaint);
320 } else {
321 // FIXME: Apply background filters and blend with contents
322 m_skCurrentCanvas->drawRect(destRect, m_skCurrentPaint);
323 }
324}
325
[email protected]c753e25a2012-10-19 21:22:42326void CCRendererSoftware::drawUnsupportedQuad(const DrawingFrame& frame, const CCDrawQuad* quad)
[email protected]d61675de42012-09-24 21:32:57327{
328 m_skCurrentPaint.setColor(SK_ColorMAGENTA);
329 m_skCurrentPaint.setAlpha(quad->opacity() * 255);
330 m_skCurrentCanvas->drawRect(toSkRect(quadVertexRect()), m_skCurrentPaint);
331}
332
[email protected]c753e25a2012-10-19 21:22:42333bool CCRendererSoftware::swapBuffers()
[email protected]d61675de42012-09-24 21:32:57334{
[email protected]c753e25a2012-10-19 21:22:42335 if (CCProxy::hasImplThread())
[email protected]d61675de42012-09-24 21:32:57336 m_client->onSwapBuffersComplete();
337 return true;
338}
339
[email protected]c753e25a2012-10-19 21:22:42340void CCRendererSoftware::getFramebufferPixels(void *pixels, const IntRect& rect)
[email protected]d61675de42012-09-24 21:32:57341{
342 SkBitmap fullBitmap = m_outputDevice->lock(false)->getSkBitmap();
343 SkBitmap subsetBitmap;
344 SkIRect invertRect = SkIRect::MakeXYWH(rect.x(), viewportSize().height() - rect.maxY(), rect.width(), rect.height());
345 fullBitmap.extractSubset(&subsetBitmap, invertRect);
346 subsetBitmap.copyPixelsTo(pixels, rect.width() * rect.height() * 4, rect.width() * 4);
347 m_outputDevice->unlock();
348}
349
[email protected]c753e25a2012-10-19 21:22:42350void CCRendererSoftware::setVisible(bool visible)
[email protected]d61675de42012-09-24 21:32:57351{
352 if (m_visible == visible)
353 return;
354 m_visible = visible;
355}
356
357}