blob: b441f8d1dcc1075e933ca4f5754db76b653c4279 [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]1c0088f2012-10-17 00:29:307#include "CCRendererSoftware.h"
[email protected]d61675de42012-09-24 21:32:578
9#include "CCDebugBorderDrawQuad.h"
10#include "CCSolidColorDrawQuad.h"
11#include "CCTextureDrawQuad.h"
[email protected]1c0088f2012-10-17 00:29:3012#include "CCTileDrawQuad.h"
[email protected]0b056ee2012-10-15 21:31:2113#include "CCRenderPassDrawQuad.h"
14#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]d61675de42012-09-24 21:32:5719#include <public/WebImage.h>
20#include <public/WebSize.h>
21#include <public/WebTransformationMatrix.h>
22
23using WebKit::WebCompositorSoftwareOutputDevice;
24using WebKit::WebImage;
25using WebKit::WebSize;
26using WebKit::WebTransformationMatrix;
27
28namespace cc {
29
30namespace {
31
32SkRect toSkRect(const FloatRect& rect)
33{
34 return SkRect::MakeXYWH(rect.x(), rect.y(), rect.width(), rect.height());
35}
36
37SkIRect toSkIRect(const IntRect& rect)
38{
39 return SkIRect::MakeXYWH(rect.x(), rect.y(), rect.width(), rect.height());
40}
41
42void toSkMatrix(SkMatrix* flattened, const WebTransformationMatrix& m)
43{
44 // Convert from 4x4 to 3x3 by dropping the third row and column.
45 flattened->set(0, m.m11());
46 flattened->set(1, m.m21());
47 flattened->set(2, m.m41());
48 flattened->set(3, m.m12());
49 flattened->set(4, m.m22());
50 flattened->set(5, m.m42());
51 flattened->set(6, m.m14());
52 flattened->set(7, m.m24());
53 flattened->set(8, m.m44());
54}
55
[email protected]276508a2012-10-16 00:56:3456bool isScaleAndTranslate(const SkMatrix& matrix)
57{
58 return SkScalarNearlyZero(matrix[SkMatrix::kMSkewX]) &&
59 SkScalarNearlyZero(matrix[SkMatrix::kMSkewY]) &&
60 SkScalarNearlyZero(matrix[SkMatrix::kMPersp0]) &&
61 SkScalarNearlyZero(matrix[SkMatrix::kMPersp1]) &&
62 SkScalarNearlyZero(matrix[SkMatrix::kMPersp2] - 1.0f);
63}
64
[email protected]d61675de42012-09-24 21:32:5765} // anonymous namespace
66
[email protected]0704caf2012-10-16 03:39:4767scoped_ptr<CCRendererSoftware> CCRendererSoftware::create(CCRendererClient* client, CCResourceProvider* resourceProvider, WebCompositorSoftwareOutputDevice* outputDevice)
[email protected]d61675de42012-09-24 21:32:5768{
[email protected]0704caf2012-10-16 03:39:4769 return make_scoped_ptr(new CCRendererSoftware(client, resourceProvider, outputDevice));
[email protected]d61675de42012-09-24 21:32:5770}
71
72CCRendererSoftware::CCRendererSoftware(CCRendererClient* client, CCResourceProvider* resourceProvider, WebCompositorSoftwareOutputDevice* outputDevice)
73 : CCDirectRenderer(client, resourceProvider)
74 , m_visible(true)
75 , m_outputDevice(outputDevice)
[email protected]d61675de42012-09-24 21:32:5776 , m_skCurrentCanvas(0)
77{
78 m_resourceProvider->setDefaultResourceType(CCResourceProvider::Bitmap);
79
80 m_capabilities.maxTextureSize = INT_MAX;
81 m_capabilities.bestTextureFormat = GraphicsContext3D::RGBA;
82 m_capabilities.contextHasCachedFrontBuffer = true;
83 m_capabilities.usingSetVisibility = true;
84
85 viewportChanged();
86}
87
88CCRendererSoftware::~CCRendererSoftware()
89{
90}
91
92const RendererCapabilities& CCRendererSoftware::capabilities() const
93{
94 return m_capabilities;
95}
96
97void CCRendererSoftware::viewportChanged()
98{
99 m_outputDevice->didChangeViewportSize(WebSize(viewportSize().width(), viewportSize().height()));
100}
101
102void CCRendererSoftware::beginDrawingFrame(DrawingFrame& frame)
103{
[email protected]0704caf2012-10-16 03:39:47104 m_skRootCanvas = make_scoped_ptr(new SkCanvas(m_outputDevice->lock(true)->getSkBitmap()));
[email protected]d61675de42012-09-24 21:32:57105}
106
107void CCRendererSoftware::finishDrawingFrame(DrawingFrame& frame)
108{
[email protected]0704caf2012-10-16 03:39:47109 m_currentFramebufferLock.reset();
[email protected]d61675de42012-09-24 21:32:57110 m_skCurrentCanvas = 0;
[email protected]0704caf2012-10-16 03:39:47111 m_skRootCanvas.reset();
[email protected]d61675de42012-09-24 21:32:57112 m_outputDevice->unlock();
113}
114
115bool CCRendererSoftware::flippedFramebuffer() const
116{
117 return false;
118}
119
120void CCRendererSoftware::finish()
121{
122}
123
124void CCRendererSoftware::bindFramebufferToOutputSurface(DrawingFrame& frame)
125{
[email protected]0704caf2012-10-16 03:39:47126 m_currentFramebufferLock.reset();
[email protected]75fe7f822012-09-28 17:54:14127 m_skCurrentCanvas = m_skRootCanvas.get();
[email protected]d61675de42012-09-24 21:32:57128}
129
130bool CCRendererSoftware::bindFramebufferToTexture(DrawingFrame& frame, const CCScopedTexture* texture, const IntRect& framebufferRect)
131{
[email protected]0704caf2012-10-16 03:39:47132 m_currentFramebufferLock = make_scoped_ptr(new CCResourceProvider::ScopedWriteLockSoftware(m_resourceProvider, texture->id()));
[email protected]d61675de42012-09-24 21:32:57133 m_skCurrentCanvas = m_currentFramebufferLock->skCanvas();
134 initializeMatrices(frame, framebufferRect, false);
135 setDrawViewportSize(framebufferRect.size());
136
137 return true;
138}
139
140void CCRendererSoftware::enableScissorTestRect(const IntRect& scissorRect)
141{
142 m_skCurrentCanvas->clipRect(toSkRect(scissorRect), SkRegion::kReplace_Op);
143}
144
145void CCRendererSoftware::disableScissorTest()
146{
147 IntRect canvasRect(IntPoint(), viewportSize());
148 m_skCurrentCanvas->clipRect(toSkRect(canvasRect), SkRegion::kReplace_Op);
149}
150
151void CCRendererSoftware::clearFramebuffer(DrawingFrame& frame)
152{
[email protected]0b056ee2012-10-15 21:31:21153 if (frame.currentRenderPass->hasTransparentBackground()) {
154 m_skCurrentCanvas->clear(SkColorSetARGB(0, 0, 0, 0));
155 } else {
156#ifndef NDEBUG
157 // On DEBUG builds, opaque render passes are cleared to blue to easily see regions that were not drawn on the screen.
158 m_skCurrentCanvas->clear(SkColorSetARGB(255, 0, 0, 255));
159#endif
160 }
[email protected]d61675de42012-09-24 21:32:57161}
162
163void CCRendererSoftware::setDrawViewportSize(const IntSize& viewportSize)
164{
165}
166
167bool CCRendererSoftware::isSoftwareResource(CCResourceProvider::ResourceId id) const
168{
169 switch (m_resourceProvider->resourceType(id)) {
170 case CCResourceProvider::GLTexture:
171 return false;
172 case CCResourceProvider::Bitmap:
173 return true;
174 }
175
176 CRASH();
177 return false;
178}
179
180void CCRendererSoftware::drawQuad(DrawingFrame& frame, const CCDrawQuad* quad)
181{
182 WebTransformationMatrix quadRectMatrix;
183 quadRectTransform(&quadRectMatrix, quad->quadTransform(), quad->quadRect());
[email protected]0b056ee2012-10-15 21:31:21184 WebTransformationMatrix contentsDeviceTransform = (frame.windowMatrix * frame.projectionMatrix * quadRectMatrix).to2dTransform();
185 SkMatrix skDeviceMatrix;
186 toSkMatrix(&skDeviceMatrix, contentsDeviceTransform);
187 m_skCurrentCanvas->setMatrix(skDeviceMatrix);
[email protected]d61675de42012-09-24 21:32:57188
189 m_skCurrentPaint.reset();
[email protected]276508a2012-10-16 00:56:34190 if (!isScaleAndTranslate(skDeviceMatrix)) {
191 m_skCurrentPaint.setAntiAlias(true);
192 m_skCurrentPaint.setFilterBitmap(true);
193 }
[email protected]0b056ee2012-10-15 21:31:21194 if (quad->needsBlending()) {
[email protected]d61675de42012-09-24 21:32:57195 m_skCurrentPaint.setAlpha(quad->opacity() * 255);
[email protected]0b056ee2012-10-15 21:31:21196 m_skCurrentPaint.setXfermodeMode(SkXfermode::kSrcOver_Mode);
197 } else {
[email protected]d61675de42012-09-24 21:32:57198 m_skCurrentPaint.setXfermodeMode(SkXfermode::kSrc_Mode);
[email protected]0b056ee2012-10-15 21:31:21199 }
[email protected]d61675de42012-09-24 21:32:57200
201 switch (quad->material()) {
202 case CCDrawQuad::DebugBorder:
203 drawDebugBorderQuad(frame, CCDebugBorderDrawQuad::materialCast(quad));
204 break;
205 case CCDrawQuad::SolidColor:
206 drawSolidColorQuad(frame, CCSolidColorDrawQuad::materialCast(quad));
207 break;
208 case CCDrawQuad::TextureContent:
209 drawTextureQuad(frame, CCTextureDrawQuad::materialCast(quad));
210 break;
211 case CCDrawQuad::TiledContent:
212 drawTileQuad(frame, CCTileDrawQuad::materialCast(quad));
213 break;
[email protected]0b056ee2012-10-15 21:31:21214 case CCDrawQuad::RenderPass:
215 drawRenderPassQuad(frame, CCRenderPassDrawQuad::materialCast(quad));
216 break;
[email protected]d61675de42012-09-24 21:32:57217 default:
218 drawUnsupportedQuad(frame, quad);
219 break;
220 }
221
222 m_skCurrentCanvas->resetMatrix();
223}
224
225void CCRendererSoftware::drawDebugBorderQuad(const DrawingFrame& frame, const CCDebugBorderDrawQuad* quad)
226{
227 // We need to apply the matrix manually to have pixel-sized stroke width.
228 SkPoint vertices[4];
229 toSkRect(quadVertexRect()).toQuad(vertices);
230 SkPoint transformedVertices[4];
231 m_skCurrentCanvas->getTotalMatrix().mapPoints(transformedVertices, vertices, 4);
232 m_skCurrentCanvas->resetMatrix();
233
234 m_skCurrentPaint.setColor(quad->color());
235 m_skCurrentPaint.setAlpha(quad->opacity() * SkColorGetA(quad->color()));
236 m_skCurrentPaint.setStyle(SkPaint::kStroke_Style);
237 m_skCurrentPaint.setStrokeWidth(quad->width());
238 m_skCurrentCanvas->drawPoints(SkCanvas::kPolygon_PointMode, 4, transformedVertices, m_skCurrentPaint);
239}
240
241void CCRendererSoftware::drawSolidColorQuad(const DrawingFrame& frame, const CCSolidColorDrawQuad* quad)
242{
243 m_skCurrentPaint.setColor(quad->color());
244 m_skCurrentPaint.setAlpha(quad->opacity() * SkColorGetA(quad->color()));
245 m_skCurrentCanvas->drawRect(toSkRect(quadVertexRect()), m_skCurrentPaint);
246}
247
248void CCRendererSoftware::drawTextureQuad(const DrawingFrame& frame, const CCTextureDrawQuad* quad)
249{
250 if (!isSoftwareResource(quad->resourceId())) {
251 drawUnsupportedQuad(frame, quad);
252 return;
253 }
254
255 // FIXME: Add support for non-premultiplied alpha.
256 CCResourceProvider::ScopedReadLockSoftware quadResourceLock(m_resourceProvider, quad->resourceId());
257 FloatRect uvRect = quad->uvRect();
258 uvRect.scale(quad->quadRect().width(), quad->quadRect().height());
259 SkIRect skUvRect = toSkIRect(enclosingIntRect(uvRect));
260 if (quad->flipped())
261 m_skCurrentCanvas->scale(1, -1);
262 m_skCurrentCanvas->drawBitmapRect(*quadResourceLock.skBitmap(), &skUvRect, toSkRect(quadVertexRect()), &m_skCurrentPaint);
263}
264
265void CCRendererSoftware::drawTileQuad(const DrawingFrame& frame, const CCTileDrawQuad* quad)
266{
[email protected]1d993172012-10-18 18:15:04267 DCHECK(isSoftwareResource(quad->resourceId()));
[email protected]d61675de42012-09-24 21:32:57268 CCResourceProvider::ScopedReadLockSoftware quadResourceLock(m_resourceProvider, quad->resourceId());
269
270 SkIRect uvRect = toSkIRect(IntRect(quad->textureOffset(), quad->quadRect().size()));
271 m_skCurrentCanvas->drawBitmapRect(*quadResourceLock.skBitmap(), &uvRect, toSkRect(quadVertexRect()), &m_skCurrentPaint);
272}
273
[email protected]0b056ee2012-10-15 21:31:21274void CCRendererSoftware::drawRenderPassQuad(const DrawingFrame& frame, const CCRenderPassDrawQuad* quad)
275{
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]0b056ee2012-10-15 21:31:21281 CCResourceProvider::ScopedReadLockSoftware contentsTextureLock(m_resourceProvider, contentsTexture->id());
282
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()) {
300 CCResourceProvider::ScopedReadLockSoftware maskResourceLock(m_resourceProvider, quad->maskResourceId());
301 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]d61675de42012-09-24 21:32:57326void CCRendererSoftware::drawUnsupportedQuad(const DrawingFrame& frame, const CCDrawQuad* quad)
327{
328 m_skCurrentPaint.setColor(SK_ColorMAGENTA);
329 m_skCurrentPaint.setAlpha(quad->opacity() * 255);
330 m_skCurrentCanvas->drawRect(toSkRect(quadVertexRect()), m_skCurrentPaint);
331}
332
333bool CCRendererSoftware::swapBuffers()
334{
335 if (CCProxy::hasImplThread())
336 m_client->onSwapBuffersComplete();
337 return true;
338}
339
340void CCRendererSoftware::getFramebufferPixels(void *pixels, const IntRect& rect)
341{
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
350void CCRendererSoftware::setVisible(bool visible)
351{
352 if (m_visible == visible)
353 return;
354 m_visible = visible;
355}
356
357}