blob: f0e7d612f81645af2fbfaa60fb71a8deffdb3dd4 [file] [log] [blame]
reed@google.comac10a2d2010-12-22 21:39:39 +00001/*
bsalomon@google.com1da07462011-03-10 14:51:57 +00002 Copyright 2011 Google Inc.
reed@google.comac10a2d2010-12-22 21:39:39 +00003
4 Licensed under the Apache License, Version 2.0 (the "License");
5 you may not use this file except in compliance with the License.
6 You may obtain a copy of the License at
7
8 http://www.apache.org/licenses/LICENSE-2.0
9
10 Unless required by applicable law or agreed to in writing, software
11 distributed under the License is distributed on an "AS IS" BASIS,
12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 See the License for the specific language governing permissions and
14 limitations under the License.
15 */
16
17
18#include "GrContext.h"
19#include "GrTextContext.h"
20
reed@google.comac10a2d2010-12-22 21:39:39 +000021#include "SkGpuDevice.h"
22#include "SkGrTexturePixelRef.h"
23
Scroggo97c88c22011-05-11 14:05:25 +000024#include "SkColorFilter.h"
reed@google.comac10a2d2010-12-22 21:39:39 +000025#include "SkDrawProcs.h"
26#include "SkGlyphCache.h"
reed@google.comc9aa5872011-04-05 21:05:37 +000027#include "SkUtils.h"
reed@google.comac10a2d2010-12-22 21:39:39 +000028
29#define CACHE_LAYER_TEXTURES 1
30
31#if 0
32 extern bool (*gShouldDrawProc)();
33 #define CHECK_SHOULD_DRAW(draw) \
34 do { \
35 if (gShouldDrawProc && !gShouldDrawProc()) return; \
36 this->prepareRenderTarget(draw); \
37 } while (0)
38#else
39 #define CHECK_SHOULD_DRAW(draw) this->prepareRenderTarget(draw)
40#endif
41
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +000042// we use the same texture slot on GrPaint for bitmaps and shaders
43// (since drawBitmap, drawSprite, and drawDevice ignore skia's shader)
44enum {
45 kBitmapTextureIdx = 0,
46 kShaderTextureIdx = 0
47};
48
reed@google.comcde92112011-07-06 20:00:52 +000049
senorblanco@chromium.orgadec4462011-07-12 17:02:06 +000050#define USE_GPU_BLUR 0
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +000051#define MAX_SIGMA 4.0f
reed@google.comac10a2d2010-12-22 21:39:39 +000052///////////////////////////////////////////////////////////////////////////////
53
54SkGpuDevice::SkAutoCachedTexture::
55 SkAutoCachedTexture(SkGpuDevice* device,
56 const SkBitmap& bitmap,
57 const GrSamplerState& sampler,
58 GrTexture** texture) {
59 GrAssert(texture);
60 fTex = NULL;
61 *texture = this->set(device, bitmap, sampler);
62}
63
64SkGpuDevice::SkAutoCachedTexture::SkAutoCachedTexture() {
65 fTex = NULL;
66}
67
68GrTexture* SkGpuDevice::SkAutoCachedTexture::set(SkGpuDevice* device,
69 const SkBitmap& bitmap,
70 const GrSamplerState& sampler) {
71 if (fTex) {
72 fDevice->unlockCachedTexture(fTex);
73 }
74 fDevice = device;
75 GrTexture* texture = (GrTexture*)bitmap.getTexture();
76 if (texture) {
77 // return the native texture
78 fTex = NULL;
reed@google.comac10a2d2010-12-22 21:39:39 +000079 } else {
80 // look it up in our cache
bsalomon@google.come97f0852011-06-17 13:10:25 +000081 fTex = device->lockCachedTexture(bitmap, sampler, &texture);
reed@google.comac10a2d2010-12-22 21:39:39 +000082 }
83 return texture;
84}
85
86SkGpuDevice::SkAutoCachedTexture::~SkAutoCachedTexture() {
87 if (fTex) {
88 fDevice->unlockCachedTexture(fTex);
89 }
90}
91
92///////////////////////////////////////////////////////////////////////////////
93
94bool gDoTraceDraw;
95
96struct GrSkDrawProcs : public SkDrawProcs {
97public:
98 GrContext* fContext;
99 GrTextContext* fTextContext;
100 GrFontScaler* fFontScaler; // cached in the skia glyphcache
101};
102
103///////////////////////////////////////////////////////////////////////////////
104
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000105GrRenderTarget* SkGpuDevice::Current3DApiRenderTarget() {
106 return (GrRenderTarget*) -1;
107}
108
reed@google.comaf951c92011-06-16 19:10:39 +0000109static SkBitmap::Config grConfig2skConfig(GrPixelConfig config, bool* isOpaque) {
110 switch (config) {
111 case kAlpha_8_GrPixelConfig:
112 *isOpaque = false;
113 return SkBitmap::kA8_Config;
114 case kRGB_565_GrPixelConfig:
115 *isOpaque = true;
116 return SkBitmap::kRGB_565_Config;
117 case kRGBA_4444_GrPixelConfig:
118 *isOpaque = false;
119 return SkBitmap::kARGB_4444_Config;
120 case kRGBA_8888_GrPixelConfig:
121 case kRGBX_8888_GrPixelConfig:
122 *isOpaque = (kRGBX_8888_GrPixelConfig == config);
123 return SkBitmap::kARGB_8888_Config;
124 default:
125 *isOpaque = false;
126 return SkBitmap::kNo_Config;
127 }
128}
reed@google.comac10a2d2010-12-22 21:39:39 +0000129
reed@google.comaf951c92011-06-16 19:10:39 +0000130static SkBitmap make_bitmap(GrContext* context, GrRenderTarget* renderTarget) {
131 if (SkGpuDevice::Current3DApiRenderTarget() == renderTarget) {
132 renderTarget = context->createRenderTargetFrom3DApiState();
133 }
134 GrTexture* texture = renderTarget->asTexture();
135 GrPixelConfig config = texture ? texture->config() : kRGBA_8888_GrPixelConfig;
136
137 bool isOpaque;
138 SkBitmap bitmap;
139 bitmap.setConfig(grConfig2skConfig(config, &isOpaque),
140 renderTarget->width(), renderTarget->height());
141 bitmap.setIsOpaque(isOpaque);
142 return bitmap;
143}
144
bsalomon@google.comf9046fe2011-06-17 15:10:21 +0000145SkGpuDevice::SkGpuDevice(GrContext* context, GrTexture* texture)
146: SkDevice(make_bitmap(context, texture->asRenderTarget())) {
147 this->initFromRenderTarget(context, texture->asRenderTarget());
148}
149
reed@google.comaf951c92011-06-16 19:10:39 +0000150SkGpuDevice::SkGpuDevice(GrContext* context, GrRenderTarget* renderTarget)
151: SkDevice(make_bitmap(context, renderTarget)) {
bsalomon@google.comf9046fe2011-06-17 15:10:21 +0000152 this->initFromRenderTarget(context, renderTarget);
153}
154
155void SkGpuDevice::initFromRenderTarget(GrContext* context,
156 GrRenderTarget* renderTarget) {
reed@google.comaf951c92011-06-16 19:10:39 +0000157 fNeedPrepareRenderTarget = false;
158 fDrawProcs = NULL;
159
160 fContext = context;
161 fContext->ref();
162
163 fCache = NULL;
164 fTexture = NULL;
165 fRenderTarget = NULL;
166 fNeedClear = false;
167
168 if (Current3DApiRenderTarget() == renderTarget) {
169 fRenderTarget = fContext->createRenderTargetFrom3DApiState();
170 } else {
bsalomon@google.comf9046fe2011-06-17 15:10:21 +0000171 GrAssert(NULL != renderTarget);
reed@google.comaf951c92011-06-16 19:10:39 +0000172 fRenderTarget = renderTarget;
173 fRenderTarget->ref();
bsalomon@google.comf9046fe2011-06-17 15:10:21 +0000174 // if this RT is also a texture, hold a ref on it
175 fTexture = fRenderTarget->asTexture();
176 SkSafeRef(fTexture);
reed@google.comaf951c92011-06-16 19:10:39 +0000177 }
178
179 SkGrRenderTargetPixelRef* pr = new SkGrRenderTargetPixelRef(fRenderTarget);
180 this->setPixelRef(pr, 0)->unref();
181}
182
183SkGpuDevice::SkGpuDevice(GrContext* context, SkBitmap::Config config, int width,
bsalomon@google.come97f0852011-06-17 13:10:25 +0000184 int height, Usage usage)
reed@google.comaf951c92011-06-16 19:10:39 +0000185: SkDevice(config, width, height, false /*isOpaque*/) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000186 fNeedPrepareRenderTarget = false;
187 fDrawProcs = NULL;
188
reed@google.com7b201d22011-01-11 18:59:23 +0000189 fContext = context;
bsalomon@google.com5782d712011-01-21 21:03:59 +0000190 fContext->ref();
reed@google.comac10a2d2010-12-22 21:39:39 +0000191
192 fCache = NULL;
193 fTexture = NULL;
194 fRenderTarget = NULL;
195 fNeedClear = false;
196
reed@google.comaf951c92011-06-16 19:10:39 +0000197 if (config != SkBitmap::kRGB_565_Config) {
198 config = SkBitmap::kARGB_8888_Config;
199 }
200 SkBitmap bm;
201 bm.setConfig(config, width, height);
reed@google.comac10a2d2010-12-22 21:39:39 +0000202
203#if CACHE_LAYER_TEXTURES
bsalomon@google.come97f0852011-06-17 13:10:25 +0000204 TexType type = (kSaveLayer_Usage == usage) ?
205 kSaveLayerDeviceRenderTarget_TexType :
206 kDeviceRenderTarget_TexType;
reed@google.comaf951c92011-06-16 19:10:39 +0000207 fCache = this->lockCachedTexture(bm, GrSamplerState::ClampNoFilter(),
bsalomon@google.come97f0852011-06-17 13:10:25 +0000208 &fTexture, type);
reed@google.comaf951c92011-06-16 19:10:39 +0000209 if (fCache) {
210 SkASSERT(NULL != fTexture);
211 SkASSERT(NULL != fTexture->asRenderTarget());
bsalomon@google.comf9046fe2011-06-17 15:10:21 +0000212 // hold a ref directly on fTexture (even though fCache has one) to match
213 // other constructor paths. Simplifies cleanup.
214 fTexture->ref();
reed@google.comaf951c92011-06-16 19:10:39 +0000215 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000216#else
reed@google.comaf951c92011-06-16 19:10:39 +0000217 const GrTextureDesc desc = {
218 kRenderTarget_GrTextureFlagBit,
219 kNone_GrAALevel,
220 width,
221 height,
222 SkGr::Bitmap2PixelConfig(bm)
223 };
reed@google.comac10a2d2010-12-22 21:39:39 +0000224
reed@google.comaf951c92011-06-16 19:10:39 +0000225 fTexture = fContext->createUncachedTexture(desc, NULL, 0);
reed@google.comac10a2d2010-12-22 21:39:39 +0000226#endif
reed@google.comaf951c92011-06-16 19:10:39 +0000227 if (NULL != fTexture) {
228 fRenderTarget = fTexture->asRenderTarget();
bsalomon@google.comf9046fe2011-06-17 15:10:21 +0000229 fRenderTarget->ref();
reed@google.comac10a2d2010-12-22 21:39:39 +0000230
reed@google.comaf951c92011-06-16 19:10:39 +0000231 GrAssert(NULL != fRenderTarget);
reed@google.comac10a2d2010-12-22 21:39:39 +0000232
reed@google.comaf951c92011-06-16 19:10:39 +0000233 // we defer the actual clear until our gainFocus()
234 fNeedClear = true;
reed@google.comac10a2d2010-12-22 21:39:39 +0000235
reed@google.comaf951c92011-06-16 19:10:39 +0000236 // wrap the bitmap with a pixelref to expose our texture
237 SkGrTexturePixelRef* pr = new SkGrTexturePixelRef(fTexture);
bsalomon@google.com669fdc42011-04-05 17:08:27 +0000238 this->setPixelRef(pr, 0)->unref();
reed@google.comaf951c92011-06-16 19:10:39 +0000239 } else {
240 GrPrintf("--- failed to create gpu-offscreen [%d %d]\n",
241 width, height);
242 GrAssert(false);
reed@google.comac10a2d2010-12-22 21:39:39 +0000243 }
244}
245
246SkGpuDevice::~SkGpuDevice() {
247 if (fDrawProcs) {
248 delete fDrawProcs;
249 }
250
bsalomon@google.comf9046fe2011-06-17 15:10:21 +0000251 SkSafeUnref(fTexture);
252 SkSafeUnref(fRenderTarget);
reed@google.comac10a2d2010-12-22 21:39:39 +0000253 if (fCache) {
254 GrAssert(NULL != fTexture);
255 GrAssert(fRenderTarget == fTexture->asRenderTarget());
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000256 fContext->unlockTexture((GrTextureEntry*)fCache);
bsalomon@google.comf9046fe2011-06-17 15:10:21 +0000257 }
bsalomon@google.com5782d712011-01-21 21:03:59 +0000258 fContext->unref();
reed@google.comac10a2d2010-12-22 21:39:39 +0000259}
260
reed@google.comac10a2d2010-12-22 21:39:39 +0000261intptr_t SkGpuDevice::getLayerTextureHandle() const {
262 if (fTexture) {
263 return fTexture->getTextureHandle();
264 } else {
265 return 0;
266 }
267}
mike@reedtribe.orgea4ac972011-04-26 11:48:33 +0000268
reed@google.comac10a2d2010-12-22 21:39:39 +0000269///////////////////////////////////////////////////////////////////////////////
270
271void SkGpuDevice::makeRenderTargetCurrent() {
272 fContext->setRenderTarget(fRenderTarget);
273 fContext->flush(true);
274 fNeedPrepareRenderTarget = true;
275}
276
277///////////////////////////////////////////////////////////////////////////////
278
279bool SkGpuDevice::readPixels(const SkIRect& srcRect, SkBitmap* bitmap) {
280 SkIRect bounds;
281 bounds.set(0, 0, this->width(), this->height());
282 if (!bounds.intersect(srcRect)) {
283 return false;
284 }
285
286 const int w = bounds.width();
287 const int h = bounds.height();
288 SkBitmap tmp;
289 // note we explicitly specify our rowBytes to be snug (no gap between rows)
290 tmp.setConfig(SkBitmap::kARGB_8888_Config, w, h, w * 4);
291 if (!tmp.allocPixels()) {
292 return false;
293 }
294
Scroggo813c33c2011-04-07 20:56:21 +0000295 tmp.lockPixels();
reed@google.comac10a2d2010-12-22 21:39:39 +0000296
Scroggoeb176032011-04-07 21:11:49 +0000297 bool read = fContext->readRenderTargetPixels(fRenderTarget,
298 bounds.fLeft, bounds.fTop,
299 bounds.width(), bounds.height(),
300 kRGBA_8888_GrPixelConfig,
301 tmp.getPixels());
Scroggo813c33c2011-04-07 20:56:21 +0000302 tmp.unlockPixels();
303 if (!read) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000304 return false;
305 }
306
307 tmp.swap(*bitmap);
308 return true;
309}
310
311void SkGpuDevice::writePixels(const SkBitmap& bitmap, int x, int y) {
312 SkAutoLockPixels alp(bitmap);
313 if (!bitmap.readyToDraw()) {
314 return;
315 }
bsalomon@google.com669fdc42011-04-05 17:08:27 +0000316 GrPixelConfig config = SkGr::BitmapConfig2PixelConfig(bitmap.config(),
317 bitmap.isOpaque());
reed@google.comac10a2d2010-12-22 21:39:39 +0000318 fContext->setRenderTarget(fRenderTarget);
319 // we aren't setting the clip or matrix, so mark as dirty
320 // we don't need to set them for this call and don't have them anyway
321 fNeedPrepareRenderTarget = true;
322
323 fContext->writePixels(x, y, bitmap.width(), bitmap.height(),
324 config, bitmap.getPixels(), bitmap.rowBytes());
325}
326
327///////////////////////////////////////////////////////////////////////////////
328
329static void convert_matrixclip(GrContext* context, const SkMatrix& matrix,
bsalomon@google.comd302f142011-03-03 13:54:13 +0000330 const SkClipStack& clipStack,
reed@google.com6f8f2922011-03-04 22:27:10 +0000331 const SkRegion& clipRegion,
332 const SkIPoint& origin) {
bsalomon@google.comcc4dac32011-05-10 13:52:42 +0000333 context->setMatrix(matrix);
reed@google.comac10a2d2010-12-22 21:39:39 +0000334
335 SkGrClipIterator iter;
bsalomon@google.comd302f142011-03-03 13:54:13 +0000336 iter.reset(clipStack);
bsalomon@google.comd302f142011-03-03 13:54:13 +0000337 const SkIRect& skBounds = clipRegion.getBounds();
338 GrRect bounds;
339 bounds.setLTRB(GrIntToScalar(skBounds.fLeft),
340 GrIntToScalar(skBounds.fTop),
341 GrIntToScalar(skBounds.fRight),
342 GrIntToScalar(skBounds.fBottom));
reed@google.com6f8f2922011-03-04 22:27:10 +0000343 GrClip grc(&iter, GrIntToScalar(-origin.x()), GrIntToScalar(-origin.y()),
344 &bounds);
bsalomon@google.comd302f142011-03-03 13:54:13 +0000345 context->setClip(grc);
reed@google.comac10a2d2010-12-22 21:39:39 +0000346}
347
348// call this ever each draw call, to ensure that the context reflects our state,
349// and not the state from some other canvas/device
350void SkGpuDevice::prepareRenderTarget(const SkDraw& draw) {
351 if (fNeedPrepareRenderTarget ||
bsalomon@google.com5782d712011-01-21 21:03:59 +0000352 fContext->getRenderTarget() != fRenderTarget) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000353
354 fContext->setRenderTarget(fRenderTarget);
bsalomon@google.comd302f142011-03-03 13:54:13 +0000355 SkASSERT(draw.fClipStack);
356 convert_matrixclip(fContext, *draw.fMatrix,
reed@google.com6f8f2922011-03-04 22:27:10 +0000357 *draw.fClipStack, *draw.fClip, this->getOrigin());
reed@google.comac10a2d2010-12-22 21:39:39 +0000358 fNeedPrepareRenderTarget = false;
359 }
360}
361
reed@google.com46799cd2011-02-22 20:56:26 +0000362void SkGpuDevice::setMatrixClip(const SkMatrix& matrix, const SkRegion& clip,
363 const SkClipStack& clipStack) {
364 this->INHERITED::setMatrixClip(matrix, clip, clipStack);
bsalomon@google.coma7bf6e22011-04-11 19:20:46 +0000365 // We don't need to set them now because the context may not reflect this device.
366 fNeedPrepareRenderTarget = true;
reed@google.comac10a2d2010-12-22 21:39:39 +0000367}
368
369void SkGpuDevice::gainFocus(SkCanvas* canvas, const SkMatrix& matrix,
bsalomon@google.comd302f142011-03-03 13:54:13 +0000370 const SkRegion& clip, const SkClipStack& clipStack) {
371
reed@google.comac10a2d2010-12-22 21:39:39 +0000372 fContext->setRenderTarget(fRenderTarget);
373
bsalomon@google.comd302f142011-03-03 13:54:13 +0000374 this->INHERITED::gainFocus(canvas, matrix, clip, clipStack);
reed@google.comac10a2d2010-12-22 21:39:39 +0000375
reed@google.com6f8f2922011-03-04 22:27:10 +0000376 convert_matrixclip(fContext, matrix, clipStack, clip, this->getOrigin());
reed@google.comac10a2d2010-12-22 21:39:39 +0000377
378 if (fNeedClear) {
bsalomon@google.com31a58402011-04-27 21:00:02 +0000379 fContext->clear(NULL, 0x0);
reed@google.comac10a2d2010-12-22 21:39:39 +0000380 fNeedClear = false;
381 }
382}
383
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000384bool SkGpuDevice::bindDeviceAsTexture(GrPaint* paint) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000385 if (NULL != fTexture) {
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000386 paint->setTexture(kBitmapTextureIdx, fTexture);
reed@google.comac10a2d2010-12-22 21:39:39 +0000387 return true;
388 }
389 return false;
390}
391
392///////////////////////////////////////////////////////////////////////////////
393
vandebo@chromium.orgd3ae7792011-02-24 00:21:06 +0000394SK_COMPILE_ASSERT(SkShader::kNone_BitmapType == 0, shader_type_mismatch);
395SK_COMPILE_ASSERT(SkShader::kDefault_BitmapType == 1, shader_type_mismatch);
396SK_COMPILE_ASSERT(SkShader::kRadial_BitmapType == 2, shader_type_mismatch);
397SK_COMPILE_ASSERT(SkShader::kSweep_BitmapType == 3, shader_type_mismatch);
398SK_COMPILE_ASSERT(SkShader::kTwoPointRadial_BitmapType == 4,
399 shader_type_mismatch);
400SK_COMPILE_ASSERT(SkShader::kLast_BitmapType == 4, shader_type_mismatch);
reed@google.comac10a2d2010-12-22 21:39:39 +0000401
bsalomon@google.com5782d712011-01-21 21:03:59 +0000402static const GrSamplerState::SampleMode sk_bmp_type_to_sample_mode[] = {
403 (GrSamplerState::SampleMode) -1, // kNone_BitmapType
404 GrSamplerState::kNormal_SampleMode, // kDefault_BitmapType
405 GrSamplerState::kRadial_SampleMode, // kRadial_BitmapType
406 GrSamplerState::kSweep_SampleMode, // kSweep_BitmapType
407 GrSamplerState::kRadial2_SampleMode, // kTwoPointRadial_BitmapType
408};
409
410bool SkGpuDevice::skPaint2GrPaintNoShader(const SkPaint& skPaint,
411 bool justAlpha,
Scroggod757df22011-05-16 13:11:16 +0000412 GrPaint* grPaint,
413 bool constantColor) {
bsalomon@google.com5782d712011-01-21 21:03:59 +0000414
415 grPaint->fDither = skPaint.isDither();
416 grPaint->fAntiAlias = skPaint.isAntiAlias();
417
418 SkXfermode::Coeff sm = SkXfermode::kOne_Coeff;
419 SkXfermode::Coeff dm = SkXfermode::kISA_Coeff;
420
421 SkXfermode* mode = skPaint.getXfermode();
422 if (mode) {
423 if (!mode->asCoeff(&sm, &dm)) {
reed@google.com1a2e8d22011-01-21 22:08:29 +0000424 SkDEBUGCODE(SkDebugf("Unsupported xfer mode.\n");)
bsalomon@google.com5782d712011-01-21 21:03:59 +0000425#if 0
426 return false;
427#endif
428 }
429 }
430 grPaint->fSrcBlendCoeff = sk_blend_to_grblend(sm);
431 grPaint->fDstBlendCoeff = sk_blend_to_grblend(dm);
432
433 if (justAlpha) {
434 uint8_t alpha = skPaint.getAlpha();
435 grPaint->fColor = GrColorPackRGBA(alpha, alpha, alpha, alpha);
Scroggod757df22011-05-16 13:11:16 +0000436 // justAlpha is currently set to true only if there is a texture,
437 // so constantColor should not also be true.
438 GrAssert(!constantColor);
bsalomon@google.com5782d712011-01-21 21:03:59 +0000439 } else {
440 grPaint->fColor = SkGr::SkColor2GrColor(skPaint.getColor());
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000441 grPaint->setTexture(kShaderTextureIdx, NULL);
bsalomon@google.com5782d712011-01-21 21:03:59 +0000442 }
Scroggo97c88c22011-05-11 14:05:25 +0000443 SkColorFilter* colorFilter = skPaint.getColorFilter();
444 SkColor color;
445 SkXfermode::Mode filterMode;
446 if (colorFilter != NULL && colorFilter->asColorMode(&color, &filterMode)) {
Scroggod757df22011-05-16 13:11:16 +0000447 if (!constantColor) {
448 grPaint->fColorFilterColor = SkGr::SkColor2GrColor(color);
449 grPaint->fColorFilterXfermode = filterMode;
450 return true;
451 }
452 SkColor filtered = colorFilter->filterColor(skPaint.getColor());
453 grPaint->fColor = SkGr::SkColor2GrColor(filtered);
Scroggo97c88c22011-05-11 14:05:25 +0000454 }
Scroggod757df22011-05-16 13:11:16 +0000455 grPaint->resetColorFilter();
bsalomon@google.com5782d712011-01-21 21:03:59 +0000456 return true;
reed@google.comac10a2d2010-12-22 21:39:39 +0000457}
458
bsalomon@google.com5782d712011-01-21 21:03:59 +0000459bool SkGpuDevice::skPaint2GrPaintShader(const SkPaint& skPaint,
460 SkAutoCachedTexture* act,
461 const SkMatrix& ctm,
Scroggod757df22011-05-16 13:11:16 +0000462 GrPaint* grPaint,
463 bool constantColor) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000464
bsalomon@google.com5782d712011-01-21 21:03:59 +0000465 SkASSERT(NULL != act);
reed@google.comac10a2d2010-12-22 21:39:39 +0000466
bsalomon@google.com5782d712011-01-21 21:03:59 +0000467 SkShader* shader = skPaint.getShader();
reed@google.comac10a2d2010-12-22 21:39:39 +0000468 if (NULL == shader) {
Scroggod757df22011-05-16 13:11:16 +0000469 return this->skPaint2GrPaintNoShader(skPaint,
470 false,
471 grPaint,
472 constantColor);
473 } else if (!this->skPaint2GrPaintNoShader(skPaint, true, grPaint, false)) {
bsalomon@google.com5782d712011-01-21 21:03:59 +0000474 return false;
reed@google.comac10a2d2010-12-22 21:39:39 +0000475 }
476
reed@google.comac10a2d2010-12-22 21:39:39 +0000477 SkBitmap bitmap;
478 SkMatrix matrix;
479 SkShader::TileMode tileModes[2];
480 SkScalar twoPointParams[3];
481 SkShader::BitmapType bmptype = shader->asABitmap(&bitmap, &matrix,
482 tileModes, twoPointParams);
483
bsalomon@google.com5782d712011-01-21 21:03:59 +0000484 GrSamplerState::SampleMode sampleMode = sk_bmp_type_to_sample_mode[bmptype];
485 if (-1 == sampleMode) {
reed@google.com2be9e8b2011-07-06 21:18:09 +0000486 SkShader::GradientInfo info;
487 SkColor color;
488
489 info.fColors = &color;
490 info.fColorOffsets = NULL;
491 info.fColorCount = 1;
492 if (SkShader::kColor_GradientType == shader->asAGradient(&info)) {
493 SkPaint copy(skPaint);
494 copy.setShader(NULL);
bsalomon@google.comcd9cfd72011-07-08 16:55:04 +0000495 // modulate the paint alpha by the shader's solid color alpha
496 U8CPU newA = SkMulDiv255Round(SkColorGetA(color), copy.getAlpha());
497 copy.setColor(SkColorSetA(color, newA));
reed@google.com2be9e8b2011-07-06 21:18:09 +0000498 return this->skPaint2GrPaintNoShader(copy,
499 false,
500 grPaint,
501 constantColor);
502 }
bsalomon@google.com5782d712011-01-21 21:03:59 +0000503 return false;
reed@google.comac10a2d2010-12-22 21:39:39 +0000504 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000505 GrSamplerState* sampler = grPaint->getTextureSampler(kShaderTextureIdx);
506 sampler->setSampleMode(sampleMode);
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000507 if (skPaint.isFilterBitmap()) {
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000508 sampler->setFilter(GrSamplerState::kBilinear_Filter);
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000509 } else {
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000510 sampler->setFilter(GrSamplerState::kNearest_Filter);
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000511 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000512 sampler->setWrapX(sk_tile_mode_to_grwrap(tileModes[0]));
513 sampler->setWrapY(sk_tile_mode_to_grwrap(tileModes[1]));
reed@google.comac10a2d2010-12-22 21:39:39 +0000514 if (GrSamplerState::kRadial2_SampleMode == sampleMode) {
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000515 sampler->setRadial2Params(twoPointParams[0],
516 twoPointParams[1],
517 twoPointParams[2] < 0);
reed@google.comac10a2d2010-12-22 21:39:39 +0000518 }
519
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000520 GrTexture* texture = act->set(this, bitmap, *sampler);
reed@google.comac10a2d2010-12-22 21:39:39 +0000521 if (NULL == texture) {
bsalomon@google.com5782d712011-01-21 21:03:59 +0000522 SkDebugf("Couldn't convert bitmap to texture.\n");
523 return false;
reed@google.comac10a2d2010-12-22 21:39:39 +0000524 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000525 grPaint->setTexture(kShaderTextureIdx, texture);
reed@google.comac10a2d2010-12-22 21:39:39 +0000526
527 // since our texture coords will be in local space, we wack the texture
528 // matrix to map them back into 0...1 before we load it
529 SkMatrix localM;
530 if (shader->getLocalMatrix(&localM)) {
531 SkMatrix inverse;
532 if (localM.invert(&inverse)) {
533 matrix.preConcat(inverse);
534 }
535 }
536 if (SkShader::kDefault_BitmapType == bmptype) {
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000537 GrScalar sx = GrFixedToScalar(GR_Fixed1 / bitmap.width());
538 GrScalar sy = GrFixedToScalar(GR_Fixed1 / bitmap.height());
reed@google.comac10a2d2010-12-22 21:39:39 +0000539 matrix.postScale(sx, sy);
reed@google.comac10a2d2010-12-22 21:39:39 +0000540 } else if (SkShader::kRadial_BitmapType == bmptype) {
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000541 GrScalar s = GrFixedToScalar(GR_Fixed1 / bitmap.width());
reed@google.comac10a2d2010-12-22 21:39:39 +0000542 matrix.postScale(s, s);
543 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000544 sampler->setMatrix(matrix);
bsalomon@google.com5782d712011-01-21 21:03:59 +0000545
546 return true;
reed@google.comac10a2d2010-12-22 21:39:39 +0000547}
548
549///////////////////////////////////////////////////////////////////////////////
bsalomon@google.com5782d712011-01-21 21:03:59 +0000550
551class SkPositionSource {
552public:
553 SkPositionSource(const SkPoint* points, int count)
554 : fPoints(points), fCount(count) {}
555
556 int count() const { return fCount; }
557
558 void writeValue(int i, GrPoint* dstPosition) const {
559 SkASSERT(i < fCount);
560 dstPosition->fX = SkScalarToGrScalar(fPoints[i].fX);
561 dstPosition->fY = SkScalarToGrScalar(fPoints[i].fY);
562 }
563private:
bsalomon@google.com5782d712011-01-21 21:03:59 +0000564 const SkPoint* fPoints;
bsalomon@google.com19628322011-02-03 21:30:17 +0000565 int fCount;
bsalomon@google.com5782d712011-01-21 21:03:59 +0000566};
567
568class SkTexCoordSource {
569public:
570 SkTexCoordSource(const SkPoint* coords)
571 : fCoords(coords) {}
572
573 void writeValue(int i, GrPoint* dstCoord) const {
574 dstCoord->fX = SkScalarToGrScalar(fCoords[i].fX);
575 dstCoord->fY = SkScalarToGrScalar(fCoords[i].fY);
576 }
577private:
578 const SkPoint* fCoords;
579};
580
581class SkColorSource {
582public:
583 SkColorSource(const SkColor* colors) : fColors(colors) {}
584
585 void writeValue(int i, GrColor* dstColor) const {
586 *dstColor = SkGr::SkColor2GrColor(fColors[i]);
587 }
588private:
589 const SkColor* fColors;
590};
591
592class SkIndexSource {
593public:
594 SkIndexSource(const uint16_t* indices, int count)
595 : fIndices(indices), fCount(count) {
596 }
597
598 int count() const { return fCount; }
599
600 void writeValue(int i, uint16_t* dstIndex) const {
601 *dstIndex = fIndices[i];
602 }
603
604private:
bsalomon@google.com5782d712011-01-21 21:03:59 +0000605 const uint16_t* fIndices;
bsalomon@google.com19628322011-02-03 21:30:17 +0000606 int fCount;
bsalomon@google.com5782d712011-01-21 21:03:59 +0000607};
608
609///////////////////////////////////////////////////////////////////////////////
610
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000611#if 0 // not currently being used so don't compile,
612
bsalomon@google.com5782d712011-01-21 21:03:59 +0000613// can be used for positions or texture coordinates
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000614
bsalomon@google.com5782d712011-01-21 21:03:59 +0000615class SkRectFanSource {
616public:
617 SkRectFanSource(const SkRect& rect) : fRect(rect) {}
618
619 int count() const { return 4; }
620
621 void writeValue(int i, GrPoint* dstPoint) const {
622 SkASSERT(i < 4);
623 dstPoint->fX = SkScalarToGrScalar((i % 3) ? fRect.fRight :
624 fRect.fLeft);
625 dstPoint->fY = SkScalarToGrScalar((i < 2) ? fRect.fTop :
626 fRect.fBottom);
627 }
628private:
629 const SkRect& fRect;
630};
631
632class SkIRectFanSource {
633public:
634 SkIRectFanSource(const SkIRect& rect) : fRect(rect) {}
635
636 int count() const { return 4; }
637
638 void writeValue(int i, GrPoint* dstPoint) const {
639 SkASSERT(i < 4);
640 dstPoint->fX = (i % 3) ? GrIntToScalar(fRect.fRight) :
641 GrIntToScalar(fRect.fLeft);
642 dstPoint->fY = (i < 2) ? GrIntToScalar(fRect.fTop) :
643 GrIntToScalar(fRect.fBottom);
644 }
645private:
646 const SkIRect& fRect;
647};
648
649class SkMatRectFanSource {
650public:
651 SkMatRectFanSource(const SkRect& rect, const SkMatrix& matrix)
652 : fRect(rect), fMatrix(matrix) {}
653
654 int count() const { return 4; }
655
656 void writeValue(int i, GrPoint* dstPoint) const {
657 SkASSERT(i < 4);
658
659#if SK_SCALAR_IS_GR_SCALAR
660 fMatrix.mapXY((i % 3) ? fRect.fRight : fRect.fLeft,
661 (i < 2) ? fRect.fTop : fRect.fBottom,
662 (SkPoint*)dstPoint);
663#else
664 SkPoint dst;
665 fMatrix.mapXY((i % 3) ? fRect.fRight : fRect.fLeft,
666 (i < 2) ? fRect.fTop : fRect.fBottom,
667 &dst);
668 dstPoint->fX = SkScalarToGrScalar(dst.fX);
669 dstPoint->fY = SkScalarToGrScalar(dst.fY);
670#endif
671 }
672private:
673 const SkRect& fRect;
674 const SkMatrix& fMatrix;
675};
676
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000677#endif
678
reed@google.comac10a2d2010-12-22 21:39:39 +0000679///////////////////////////////////////////////////////////////////////////////
680
bsalomon@google.com398109c2011-04-14 18:40:27 +0000681void SkGpuDevice::clear(SkColor color) {
bsalomon@google.com31a58402011-04-27 21:00:02 +0000682 fContext->clear(NULL, color);
bsalomon@google.com398109c2011-04-14 18:40:27 +0000683}
684
reed@google.comac10a2d2010-12-22 21:39:39 +0000685void SkGpuDevice::drawPaint(const SkDraw& draw, const SkPaint& paint) {
686 CHECK_SHOULD_DRAW(draw);
687
bsalomon@google.com5782d712011-01-21 21:03:59 +0000688 GrPaint grPaint;
689 SkAutoCachedTexture act;
Scroggod757df22011-05-16 13:11:16 +0000690 if (!this->skPaint2GrPaintShader(paint,
691 &act,
692 *draw.fMatrix,
693 &grPaint,
694 true)) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000695 return;
696 }
bsalomon@google.com5782d712011-01-21 21:03:59 +0000697
698 fContext->drawPaint(grPaint);
reed@google.comac10a2d2010-12-22 21:39:39 +0000699}
700
701// must be in SkCanvas::PointMode order
bsalomon@google.comffca4002011-02-22 20:34:01 +0000702static const GrPrimitiveType gPointMode2PrimtiveType[] = {
703 kPoints_PrimitiveType,
704 kLines_PrimitiveType,
705 kLineStrip_PrimitiveType
reed@google.comac10a2d2010-12-22 21:39:39 +0000706};
707
708void SkGpuDevice::drawPoints(const SkDraw& draw, SkCanvas::PointMode mode,
bsalomon@google.com5782d712011-01-21 21:03:59 +0000709 size_t count, const SkPoint pts[], const SkPaint& paint) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000710 CHECK_SHOULD_DRAW(draw);
711
712 SkScalar width = paint.getStrokeWidth();
713 if (width < 0) {
714 return;
715 }
716
717 // we only handle hairlines here, else we let the SkDraw call our drawPath()
718 if (width > 0) {
719 draw.drawPoints(mode, count, pts, paint, true);
720 return;
721 }
722
bsalomon@google.com5782d712011-01-21 21:03:59 +0000723 GrPaint grPaint;
724 SkAutoCachedTexture act;
Scroggod757df22011-05-16 13:11:16 +0000725 if (!this->skPaint2GrPaintShader(paint,
726 &act,
727 *draw.fMatrix,
728 &grPaint,
729 true)) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000730 return;
731 }
732
reed@google.comac10a2d2010-12-22 21:39:39 +0000733#if SK_SCALAR_IS_GR_SCALAR
bsalomon@google.com5782d712011-01-21 21:03:59 +0000734 fContext->drawVertices(grPaint,
735 gPointMode2PrimtiveType[mode],
736 count,
737 (GrPoint*)pts,
738 NULL,
739 NULL,
740 NULL,
741 0);
reed@google.comac10a2d2010-12-22 21:39:39 +0000742#else
bsalomon@google.com5782d712011-01-21 21:03:59 +0000743 fContext->drawCustomVertices(grPaint,
744 gPointMode2PrimtiveType[mode],
745 SkPositionSource(pts, count));
reed@google.comac10a2d2010-12-22 21:39:39 +0000746#endif
reed@google.comac10a2d2010-12-22 21:39:39 +0000747}
748
reed@google.comc9aa5872011-04-05 21:05:37 +0000749///////////////////////////////////////////////////////////////////////////////
750
reed@google.comac10a2d2010-12-22 21:39:39 +0000751void SkGpuDevice::drawRect(const SkDraw& draw, const SkRect& rect,
752 const SkPaint& paint) {
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000753 CHECK_SHOULD_DRAW(draw);
754
755 bool doStroke = paint.getStyle() == SkPaint::kStroke_Style;
756 SkScalar width = paint.getStrokeWidth();
757
758 /*
759 We have special code for hairline strokes, miter-strokes, and fills.
760 Anything else we just call our path code.
761 */
762 bool usePath = doStroke && width > 0 &&
763 paint.getStrokeJoin() != SkPaint::kMiter_Join;
764 // another reason we might need to call drawPath...
765 if (paint.getMaskFilter()) {
766 usePath = true;
767 }
reed@google.com67db6642011-05-26 11:46:35 +0000768 // until we aa rotated rects...
769 if (!usePath && paint.isAntiAlias() && !draw.fMatrix->rectStaysRect()) {
770 usePath = true;
771 }
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000772
773 if (usePath) {
774 SkPath path;
775 path.addRect(rect);
776 this->drawPath(draw, path, paint, NULL, true);
777 return;
778 }
779
780 GrPaint grPaint;
781 SkAutoCachedTexture act;
Scroggod757df22011-05-16 13:11:16 +0000782 if (!this->skPaint2GrPaintShader(paint,
783 &act,
784 *draw.fMatrix,
785 &grPaint,
786 true)) {
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000787 return;
788 }
reed@google.com20efde72011-05-09 17:00:02 +0000789 fContext->drawRect(grPaint, rect, doStroke ? width : -1);
reed@google.comac10a2d2010-12-22 21:39:39 +0000790}
791
reed@google.com69302852011-02-16 18:08:07 +0000792#include "SkMaskFilter.h"
793#include "SkBounder.h"
794
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +0000795static GrPathFill skToGrFillType(SkPath::FillType fillType) {
796 switch (fillType) {
797 case SkPath::kWinding_FillType:
798 return kWinding_PathFill;
799 case SkPath::kEvenOdd_FillType:
800 return kEvenOdd_PathFill;
801 case SkPath::kInverseWinding_FillType:
802 return kInverseWinding_PathFill;
803 case SkPath::kInverseEvenOdd_FillType:
804 return kInverseEvenOdd_PathFill;
805 default:
806 SkDebugf("Unsupported path fill type\n");
807 return kHairLine_PathFill;
808 }
809}
810
senorblanco@chromium.orgb08ea1b2011-07-12 16:54:59 +0000811static void buildKernel(float sigma, float* kernel, int kernelWidth) {
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +0000812 int halfWidth = (kernelWidth - 1) / 2;
813 float sum = 0.0f;
senorblanco@chromium.orgb08ea1b2011-07-12 16:54:59 +0000814 float denom = 1.0f / (2.0f * sigma * sigma);
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +0000815 for (int i = 0; i < kernelWidth; ++i) {
senorblanco@chromium.orgb08ea1b2011-07-12 16:54:59 +0000816 float x = static_cast<float>(i - halfWidth);
817 // Note that the constant term (1/(sqrt(2*pi*sigma^2)) of the Gaussian
818 // is dropped here, since we renormalize the kernel below.
819 kernel[i] = sk_float_exp(- x * x * denom);
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +0000820 sum += kernel[i];
821 }
822 // Normalize the kernel
823 float scale = 1.0f / sum;
824 for (int i = 0; i < kernelWidth; ++i)
825 kernel[i] *= scale;
826}
827
senorblanco@chromium.orgb08ea1b2011-07-12 16:54:59 +0000828static void scaleRect(SkRect* rect, float scale) {
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +0000829 rect->fLeft *= scale;
830 rect->fTop *= scale;
831 rect->fRight *= scale;
832 rect->fBottom *= scale;
833}
834
835static bool drawWithGPUMaskFilter(GrContext* context, const SkPath& path,
836 SkMaskFilter* filter, const SkMatrix& matrix,
837 const SkRegion& clip, SkBounder* bounder,
838 GrPaint* grp) {
senorblanco@chromium.orgaadd9f82011-07-12 19:44:51 +0000839#if !USE_GPU_BLUR
840 return false;
senorblanco@chromium.orgb08ea1b2011-07-12 16:54:59 +0000841#endif
senorblanco@chromium.orgaadd9f82011-07-12 19:44:51 +0000842 SkMaskFilter::BlurInfo info;
843 SkMaskFilter::BlurType blurType = filter->asABlur(&info);
senorblanco@chromium.orgb08ea1b2011-07-12 16:54:59 +0000844 if (SkMaskFilter::kNone_BlurType == blurType) {
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +0000845 return false;
846 }
847 float radius = info.fIgnoreTransform ? info.fRadius
848 : matrix.mapRadius(info.fRadius);
849 float sigma = radius * 0.6666f;
850 SkRect srcRect = path.getBounds();
851
852 int scaleFactor = 1;
853
854 while (sigma > MAX_SIGMA) {
855 scaleFactor *= 2;
856 sigma *= 0.5f;
857 }
858 scaleRect(&srcRect, 1.0f / scaleFactor);
859 int halfWidth = static_cast<int>(sigma * 3.0f);
860 int kernelWidth = halfWidth * 2 + 1;
861
862 SkIRect srcIRect;
863 srcRect.roundOut(&srcIRect);
864 srcRect.set(srcIRect);
865 srcRect.inset(-halfWidth, -halfWidth);
866
867 scaleRect(&srcRect, scaleFactor);
868 SkRect finalRect = srcRect;
869
870 SkIRect finalIRect;
871 finalRect.roundOut(&finalIRect);
872 if (clip.quickReject(finalIRect)) {
senorblanco@chromium.orgaadd9f82011-07-12 19:44:51 +0000873 return true;
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +0000874 }
875 if (bounder && !bounder->doIRect(finalIRect)) {
senorblanco@chromium.orgaadd9f82011-07-12 19:44:51 +0000876 return true;
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +0000877 }
878 GrPoint offset = GrPoint::Make(-srcRect.fLeft, -srcRect.fTop);
879 srcRect.offset(-srcRect.fLeft, -srcRect.fTop);
880 const GrTextureDesc desc = {
881 kRenderTarget_GrTextureFlagBit,
882 kNone_GrAALevel,
883 srcRect.width(),
884 srcRect.height(),
885 // We actually only need A8, but it often isn't supported as a
886 // render target
887 kRGBA_8888_GrPixelConfig
888 };
889
890 GrTextureEntry* srcEntry = context->findApproximateKeylessTexture(desc);
891 GrTextureEntry* dstEntry = context->findApproximateKeylessTexture(desc);
senorblanco@chromium.orgaadd9f82011-07-12 19:44:51 +0000892 GrAutoUnlockTextureEntry srcLock(context, srcEntry),
893 dstLock(context, dstEntry);
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +0000894 if (NULL == srcEntry || NULL == dstEntry) {
895 return false;
896 }
897 GrTexture* srcTexture = srcEntry->texture();
898 GrTexture* dstTexture = dstEntry->texture();
899 if (NULL == srcTexture || NULL == dstTexture) {
900 return false;
901 }
902 GrRenderTarget* oldRenderTarget = context->getRenderTarget();
903 context->setRenderTarget(dstTexture->asRenderTarget());
904 // FIXME: could just clear bounds
905 context->clear(NULL, 0);
906 GrMatrix transM;
907 GrPaint tempPaint;
908 tempPaint.reset();
909
910 GrAutoMatrix avm(context, GrMatrix::I());
senorblanco@chromium.orgb08ea1b2011-07-12 16:54:59 +0000911 tempPaint.fAntiAlias = grp->fAntiAlias;
912 if (tempPaint.fAntiAlias) {
913 // AA uses the "coverage" stages on GrDrawTarget. Coverage with a dst
914 // blend coeff of zero requires dual source blending support in order
915 // to properly blend partially covered pixels. This means the AA
916 // code path may not be taken. So we use a dst blend coeff of ISA. We
917 // could special case AA draws to a dst surface with known alpha=0 to
918 // use a zero dst coeff when dual source blending isn't available.
919 tempPaint.fSrcBlendCoeff = kOne_BlendCoeff;
920 tempPaint.fDstBlendCoeff = kISC_BlendCoeff;
921 }
922 // Draw hard shadow to dstTexture with path topleft at origin 0,0.
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +0000923 context->drawPath(tempPaint, path, skToGrFillType(path.getFillType()), &offset);
senorblanco@chromium.orgb08ea1b2011-07-12 16:54:59 +0000924 SkTSwap(srcTexture, dstTexture);
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +0000925
926 GrMatrix sampleM;
927 sampleM.setScale(GR_Scalar1 / srcTexture->width(),
928 GR_Scalar1 / srcTexture->height());
929 GrPaint paint;
930 paint.reset();
931 paint.getTextureSampler(0)->setFilter(GrSamplerState::kBilinear_Filter);
932 paint.getTextureSampler(0)->setMatrix(sampleM);
senorblanco@chromium.orgb08ea1b2011-07-12 16:54:59 +0000933 GrTextureEntry* origEntry = NULL;
934 if (blurType != SkMaskFilter::kNormal_BlurType) {
935 // Stash away a copy of the unblurred image.
936 origEntry = context->findApproximateKeylessTexture(desc);
937 if (NULL == origEntry) {
938 return false;
939 }
940 context->setRenderTarget(origEntry->texture()->asRenderTarget());
941 paint.setTexture(0, srcTexture);
942 context->drawRect(paint, srcRect);
943 }
senorblanco@chromium.orgaadd9f82011-07-12 19:44:51 +0000944 GrAutoUnlockTextureEntry origLock(context, origEntry);
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +0000945 for (int i = 1; i < scaleFactor; i *= 2) {
946 context->setRenderTarget(dstTexture->asRenderTarget());
947 SkRect dstRect(srcRect);
948 scaleRect(&dstRect, 0.5f);
949 // Clear out 1 pixel border for linear filtering.
950 // FIXME: for now, clear everything
951 context->clear(NULL, 0);
952 paint.setTexture(0, srcTexture);
953 context->drawRectToRect(paint, dstRect, srcRect);
954 srcRect = dstRect;
senorblanco@chromium.orgb08ea1b2011-07-12 16:54:59 +0000955 SkTSwap(srcTexture, dstTexture);
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +0000956 }
957
958 SkAutoTMalloc<float> kernelStorage(kernelWidth);
959 float* kernel = kernelStorage.get();
960 buildKernel(sigma, kernel, kernelWidth);
961
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +0000962 context->setRenderTarget(dstTexture->asRenderTarget());
963 context->clear(NULL, 0);
senorblanco@chromium.orgaadd9f82011-07-12 19:44:51 +0000964 context->convolveInX(srcTexture, srcRect, kernel, kernelWidth);
senorblanco@chromium.orgb08ea1b2011-07-12 16:54:59 +0000965 SkTSwap(srcTexture, dstTexture);
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +0000966
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +0000967 context->setRenderTarget(dstTexture->asRenderTarget());
968 context->clear(NULL, 0);
senorblanco@chromium.orgaadd9f82011-07-12 19:44:51 +0000969 context->convolveInY(srcTexture, srcRect, kernel, kernelWidth);
senorblanco@chromium.orgb08ea1b2011-07-12 16:54:59 +0000970 SkTSwap(srcTexture, dstTexture);
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +0000971
972 if (scaleFactor > 1) {
973 // FIXME: This should be mitchell, not bilinear.
974 paint.getTextureSampler(0)->setFilter(GrSamplerState::kBilinear_Filter);
975 sampleM.setScale(GR_Scalar1 / srcTexture->width(),
976 GR_Scalar1 / srcTexture->height());
977 paint.getTextureSampler(0)->setMatrix(sampleM);
978 context->setRenderTarget(dstTexture->asRenderTarget());
979 // Clear out 2 pixel border for bicubic filtering.
980 // FIXME: for now, clear everything
981 context->clear(NULL, 0);
982 paint.setTexture(0, srcTexture);
983 SkRect dstRect(srcRect);
984 scaleRect(&dstRect, scaleFactor);
985 context->drawRectToRect(paint, dstRect, srcRect);
986 srcRect = dstRect;
senorblanco@chromium.orgb08ea1b2011-07-12 16:54:59 +0000987 SkTSwap(srcTexture, dstTexture);
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +0000988 }
989
senorblanco@chromium.orgb08ea1b2011-07-12 16:54:59 +0000990 if (blurType != SkMaskFilter::kNormal_BlurType) {
991 GrTexture* origTexture = origEntry->texture();
992 paint.getTextureSampler(0)->setFilter(GrSamplerState::kNearest_Filter);
993 sampleM.setScale(GR_Scalar1 / origTexture->width(),
994 GR_Scalar1 / origTexture->height());
995 paint.getTextureSampler(0)->setMatrix(sampleM);
996 // Blend origTexture over srcTexture.
997 context->setRenderTarget(srcTexture->asRenderTarget());
998 paint.setTexture(0, origTexture);
999 if (SkMaskFilter::kInner_BlurType == blurType) {
1000 // inner: dst = dst * src
1001 paint.fSrcBlendCoeff = kDC_BlendCoeff;
1002 paint.fDstBlendCoeff = kZero_BlendCoeff;
1003 } else if (SkMaskFilter::kSolid_BlurType == blurType) {
1004 // solid: dst = src + dst - src * dst
1005 // = (1 - dst) * src + 1 * dst
1006 paint.fSrcBlendCoeff = kIDC_BlendCoeff;
1007 paint.fDstBlendCoeff = kOne_BlendCoeff;
1008 } else if (SkMaskFilter::kOuter_BlurType == blurType) {
1009 // outer: dst = dst * (1 - src)
1010 // = 0 * src + (1 - src) * dst
1011 paint.fSrcBlendCoeff = kZero_BlendCoeff;
1012 paint.fDstBlendCoeff = kISC_BlendCoeff;
1013 }
1014 context->drawRect(paint, srcRect);
1015 }
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +00001016 context->setRenderTarget(oldRenderTarget);
1017
1018 if (grp->hasTextureOrMask()) {
1019 GrMatrix inverse;
1020 if (!matrix.invert(&inverse)) {
1021 return false;
1022 }
1023 grp->preConcatActiveSamplerMatrices(inverse);
1024 }
1025
1026 static const int MASK_IDX = GrPaint::kMaxMasks - 1;
1027 // we assume the last mask index is available for use
1028 GrAssert(NULL == grp->getMask(MASK_IDX));
1029 grp->setMask(MASK_IDX, srcTexture);
1030 grp->getMaskSampler(MASK_IDX)->setClampNoFilter();
1031
1032 GrMatrix m;
1033 m.setTranslate(-finalRect.fLeft, -finalRect.fTop);
1034 m.postIDiv(srcTexture->width(), srcTexture->height());
1035 grp->getMaskSampler(MASK_IDX)->setMatrix(m);
1036 context->drawRect(*grp, finalRect);
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +00001037 return true;
1038}
1039
reed@google.com69302852011-02-16 18:08:07 +00001040static bool drawWithMaskFilter(GrContext* context, const SkPath& path,
1041 SkMaskFilter* filter, const SkMatrix& matrix,
1042 const SkRegion& clip, SkBounder* bounder,
1043 GrPaint* grp) {
1044 SkMask srcM, dstM;
1045
1046 if (!SkDraw::DrawToMask(path, &clip.getBounds(), filter, &matrix, &srcM,
1047 SkMask::kComputeBoundsAndRenderImage_CreateMode)) {
1048 return false;
1049 }
1050
1051 SkAutoMaskImage autoSrc(&srcM, false);
1052
1053 if (!filter->filterMask(&dstM, srcM, matrix, NULL)) {
1054 return false;
1055 }
1056 // this will free-up dstM when we're done (allocated in filterMask())
1057 SkAutoMaskImage autoDst(&dstM, false);
1058
1059 if (clip.quickReject(dstM.fBounds)) {
1060 return false;
1061 }
1062 if (bounder && !bounder->doIRect(dstM.fBounds)) {
1063 return false;
1064 }
1065
1066 // we now have a device-aligned 8bit mask in dstM, ready to be drawn using
1067 // the current clip (and identity matrix) and grpaint settings
1068
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001069 // used to compute inverse view, if necessary
1070 GrMatrix ivm = context->getMatrix();
1071
reed@google.com0c219b62011-02-16 21:31:18 +00001072 GrAutoMatrix avm(context, GrMatrix::I());
reed@google.com69302852011-02-16 18:08:07 +00001073
bsalomon@google.comfea37b52011-04-25 15:51:06 +00001074 const GrTextureDesc desc = {
1075 kNone_GrTextureFlags,
1076 kNone_GrAALevel,
reed@google.com69302852011-02-16 18:08:07 +00001077 dstM.fBounds.width(),
1078 dstM.fBounds.height(),
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001079 kAlpha_8_GrPixelConfig
reed@google.com69302852011-02-16 18:08:07 +00001080 };
1081
1082 GrTexture* texture = context->createUncachedTexture(desc, dstM.fImage,
1083 dstM.fRowBytes);
1084 if (NULL == texture) {
1085 return false;
1086 }
1087
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001088 if (grp->hasTextureOrMask() && ivm.invert(&ivm)) {
1089 grp->preConcatActiveSamplerMatrices(ivm);
1090 }
1091
1092 static const int MASK_IDX = GrPaint::kMaxMasks - 1;
1093 // we assume the last mask index is available for use
1094 GrAssert(NULL == grp->getMask(MASK_IDX));
1095 grp->setMask(MASK_IDX, texture);
reed@google.com0c219b62011-02-16 21:31:18 +00001096 texture->unref();
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001097 grp->getMaskSampler(MASK_IDX)->setClampNoFilter();
reed@google.com69302852011-02-16 18:08:07 +00001098
bsalomon@google.comc6cf7232011-02-17 16:43:10 +00001099 GrRect d;
1100 d.setLTRB(GrIntToScalar(dstM.fBounds.fLeft),
reed@google.com0c219b62011-02-16 21:31:18 +00001101 GrIntToScalar(dstM.fBounds.fTop),
1102 GrIntToScalar(dstM.fBounds.fRight),
1103 GrIntToScalar(dstM.fBounds.fBottom));
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001104
1105 GrMatrix m;
1106 m.setTranslate(-dstM.fBounds.fLeft, -dstM.fBounds.fTop);
1107 m.postIDiv(dstM.fBounds.width(), dstM.fBounds.height());
1108 grp->getMaskSampler(MASK_IDX)->setMatrix(m);
1109
1110 context->drawRect(*grp, d);
reed@google.com69302852011-02-16 18:08:07 +00001111 return true;
1112}
reed@google.com69302852011-02-16 18:08:07 +00001113
reed@google.com0c219b62011-02-16 21:31:18 +00001114void SkGpuDevice::drawPath(const SkDraw& draw, const SkPath& origSrcPath,
reed@google.comac10a2d2010-12-22 21:39:39 +00001115 const SkPaint& paint, const SkMatrix* prePathMatrix,
1116 bool pathIsMutable) {
1117 CHECK_SHOULD_DRAW(draw);
1118
bsalomon@google.com5782d712011-01-21 21:03:59 +00001119 GrPaint grPaint;
1120 SkAutoCachedTexture act;
Scroggod757df22011-05-16 13:11:16 +00001121 if (!this->skPaint2GrPaintShader(paint,
1122 &act,
1123 *draw.fMatrix,
1124 &grPaint,
1125 true)) {
reed@google.comac10a2d2010-12-22 21:39:39 +00001126 return;
1127 }
1128
reed@google.com0c219b62011-02-16 21:31:18 +00001129 // BEGIN lift from SkDraw::drawPath()
1130
1131 SkPath* pathPtr = const_cast<SkPath*>(&origSrcPath);
1132 bool doFill = true;
1133 SkPath tmpPath;
reed@google.comac10a2d2010-12-22 21:39:39 +00001134
1135 if (prePathMatrix) {
reed@google.come3445642011-02-16 23:20:39 +00001136 SkPath* result = pathPtr;
reed@google.com0c219b62011-02-16 21:31:18 +00001137
reed@google.come3445642011-02-16 23:20:39 +00001138 if (!pathIsMutable) {
1139 result = &tmpPath;
1140 pathIsMutable = true;
reed@google.comac10a2d2010-12-22 21:39:39 +00001141 }
reed@google.come3445642011-02-16 23:20:39 +00001142 // should I push prePathMatrix on our MV stack temporarily, instead
1143 // of applying it here? See SkDraw.cpp
1144 pathPtr->transform(*prePathMatrix, result);
1145 pathPtr = result;
reed@google.comac10a2d2010-12-22 21:39:39 +00001146 }
reed@google.com0c219b62011-02-16 21:31:18 +00001147 // at this point we're done with prePathMatrix
1148 SkDEBUGCODE(prePathMatrix = (const SkMatrix*)0x50FF8001;)
reed@google.comac10a2d2010-12-22 21:39:39 +00001149
bsalomon@google.com04de7822011-03-25 18:04:43 +00001150 // This "if" is not part of the SkDraw::drawPath() lift.
1151 // When we get a 1.0 wide stroke we hairline stroke it instead of creating
1152 // a new stroked-path. This is motivated by canvas2D sites that draw
1153 // lines as 1.0 wide stroked paths. We can consider doing an alpha-modulated-
1154 // hairline for width < 1.0 when AA is enabled.
1155 static const int gMatrixMask = ~(SkMatrix::kIdentity_Mask |
1156 SkMatrix::kTranslate_Mask);
1157 if (!paint.getPathEffect() &&
1158 SkPaint::kStroke_Style == paint.getStyle() &&
1159 !(draw.fMatrix->getType() & gMatrixMask) &&
1160 SK_Scalar1 == paint.getStrokeWidth()) {
1161 doFill = false;
1162 }
1163
1164 if (doFill && (paint.getPathEffect() ||
1165 paint.getStyle() != SkPaint::kFill_Style)) {
reed@google.com0c219b62011-02-16 21:31:18 +00001166 doFill = paint.getFillPath(*pathPtr, &tmpPath);
1167 pathPtr = &tmpPath;
1168 }
1169
1170 // END lift from SkDraw::drawPath()
1171
reed@google.com69302852011-02-16 18:08:07 +00001172 if (paint.getMaskFilter()) {
reed@google.com0c219b62011-02-16 21:31:18 +00001173 // avoid possibly allocating a new path in transform if we can
1174 SkPath* devPathPtr = pathIsMutable ? pathPtr : &tmpPath;
1175
1176 // transform the path into device space
reed@google.come3445642011-02-16 23:20:39 +00001177 pathPtr->transform(*draw.fMatrix, devPathPtr);
senorblanco@chromium.orgb08ea1b2011-07-12 16:54:59 +00001178 if (!drawWithGPUMaskFilter(fContext, *devPathPtr, paint.getMaskFilter(),
1179 *draw.fMatrix, *draw.fClip, draw.fBounder,
1180 &grPaint)) {
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +00001181 drawWithMaskFilter(fContext, *devPathPtr, paint.getMaskFilter(),
1182 *draw.fMatrix, *draw.fClip, draw.fBounder,
1183 &grPaint);
1184 }
reed@google.com69302852011-02-16 18:08:07 +00001185 return;
1186 }
reed@google.com69302852011-02-16 18:08:07 +00001187
bsalomon@google.comffca4002011-02-22 20:34:01 +00001188 GrPathFill fill = kHairLine_PathFill;
reed@google.comac10a2d2010-12-22 21:39:39 +00001189
reed@google.com0c219b62011-02-16 21:31:18 +00001190 if (doFill) {
1191 switch (pathPtr->getFillType()) {
reed@google.comac10a2d2010-12-22 21:39:39 +00001192 case SkPath::kWinding_FillType:
bsalomon@google.comffca4002011-02-22 20:34:01 +00001193 fill = kWinding_PathFill;
reed@google.comac10a2d2010-12-22 21:39:39 +00001194 break;
1195 case SkPath::kEvenOdd_FillType:
bsalomon@google.comffca4002011-02-22 20:34:01 +00001196 fill = kEvenOdd_PathFill;
reed@google.comac10a2d2010-12-22 21:39:39 +00001197 break;
1198 case SkPath::kInverseWinding_FillType:
bsalomon@google.comffca4002011-02-22 20:34:01 +00001199 fill = kInverseWinding_PathFill;
reed@google.comac10a2d2010-12-22 21:39:39 +00001200 break;
1201 case SkPath::kInverseEvenOdd_FillType:
bsalomon@google.comffca4002011-02-22 20:34:01 +00001202 fill = kInverseEvenOdd_PathFill;
reed@google.comac10a2d2010-12-22 21:39:39 +00001203 break;
1204 default:
bsalomon@google.com5782d712011-01-21 21:03:59 +00001205 SkDebugf("Unsupported path fill type\n");
reed@google.comac10a2d2010-12-22 21:39:39 +00001206 return;
1207 }
1208 }
1209
reed@google.com07f3ee12011-05-16 17:21:57 +00001210 fContext->drawPath(grPaint, *pathPtr, fill);
reed@google.comac10a2d2010-12-22 21:39:39 +00001211}
1212
reed@google.comac10a2d2010-12-22 21:39:39 +00001213void SkGpuDevice::drawBitmap(const SkDraw& draw,
1214 const SkBitmap& bitmap,
1215 const SkIRect* srcRectPtr,
1216 const SkMatrix& m,
1217 const SkPaint& paint) {
1218 CHECK_SHOULD_DRAW(draw);
1219
1220 SkIRect srcRect;
1221 if (NULL == srcRectPtr) {
1222 srcRect.set(0, 0, bitmap.width(), bitmap.height());
1223 } else {
1224 srcRect = *srcRectPtr;
1225 }
1226
junov@google.comd935cfb2011-06-27 20:48:23 +00001227 if (paint.getMaskFilter()){
epoger@google.com9ef2d832011-07-01 21:12:20 +00001228 SkBitmap tmp; // storage if we need a subset of bitmap
junov@google.comd935cfb2011-06-27 20:48:23 +00001229 const SkBitmap* bitmapPtr = &bitmap;
epoger@google.com9ef2d832011-07-01 21:12:20 +00001230 if (srcRectPtr) {
1231 if (!bitmap.extractSubset(&tmp, srcRect)) {
1232 return; // extraction failed
1233 }
1234 bitmapPtr = &tmp;
junov@google.comd935cfb2011-06-27 20:48:23 +00001235 }
1236 SkPaint paintWithTexture(paint);
1237 paintWithTexture.setShader(SkShader::CreateBitmapShader( *bitmapPtr,
1238 SkShader::kClamp_TileMode, SkShader::kClamp_TileMode))->unref();
1239 paintWithTexture.getShader()->setLocalMatrix(m);
1240
1241 SkRect ScalarRect;
epoger@google.com9ef2d832011-07-01 21:12:20 +00001242 ScalarRect.set(srcRect);
junov@google.comd935cfb2011-06-27 20:48:23 +00001243
epoger@google.com9ef2d832011-07-01 21:12:20 +00001244 if (m.rectStaysRect()) {
1245 // Preferred drawing method, optimized for rectangles
1246 m.mapRect(&ScalarRect);
1247 this->drawRect(draw, ScalarRect, paintWithTexture);
1248 } else {
1249 // Slower drawing method, for warped or rotated rectangles
1250 SkPath path;
1251 path.addRect(ScalarRect);
1252 path.transform(m);
1253 this->drawPath(draw, path, paintWithTexture, NULL, true);
1254 }
junov@google.comd935cfb2011-06-27 20:48:23 +00001255 return;
1256 }
1257
bsalomon@google.com5782d712011-01-21 21:03:59 +00001258 GrPaint grPaint;
Scroggod757df22011-05-16 13:11:16 +00001259 if (!this->skPaint2GrPaintNoShader(paint, true, &grPaint, false)) {
bsalomon@google.com5782d712011-01-21 21:03:59 +00001260 return;
1261 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001262 GrSamplerState* sampler = grPaint.getTextureSampler(kBitmapTextureIdx);
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +00001263 if (paint.isFilterBitmap()) {
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001264 sampler->setFilter(GrSamplerState::kBilinear_Filter);
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +00001265 } else {
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001266 sampler->setFilter(GrSamplerState::kNearest_Filter);
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +00001267 }
bsalomon@google.com5782d712011-01-21 21:03:59 +00001268
bsalomon@google.com91958362011-06-13 17:58:13 +00001269 const int maxTextureSize = fContext->getMaxTextureSize();
1270 if (bitmap.getTexture() || (bitmap.width() <= maxTextureSize &&
1271 bitmap.height() <= maxTextureSize)) {
reed@google.comac10a2d2010-12-22 21:39:39 +00001272 // take the fast case
bsalomon@google.com5782d712011-01-21 21:03:59 +00001273 this->internalDrawBitmap(draw, bitmap, srcRect, m, &grPaint);
reed@google.comac10a2d2010-12-22 21:39:39 +00001274 return;
1275 }
1276
1277 // undo the translate done by SkCanvas
1278 int DX = SkMax32(0, srcRect.fLeft);
1279 int DY = SkMax32(0, srcRect.fTop);
1280 // compute clip bounds in local coordinates
1281 SkIRect clipRect;
1282 {
1283 SkRect r;
1284 r.set(draw.fClip->getBounds());
1285 SkMatrix matrix, inverse;
1286 matrix.setConcat(*draw.fMatrix, m);
1287 if (!matrix.invert(&inverse)) {
1288 return;
1289 }
1290 inverse.mapRect(&r);
1291 r.roundOut(&clipRect);
1292 // apply the canvas' translate to our local clip
1293 clipRect.offset(DX, DY);
1294 }
1295
bsalomon@google.com91958362011-06-13 17:58:13 +00001296 int nx = bitmap.width() / maxTextureSize;
1297 int ny = bitmap.height() / maxTextureSize;
reed@google.comac10a2d2010-12-22 21:39:39 +00001298 for (int x = 0; x <= nx; x++) {
1299 for (int y = 0; y <= ny; y++) {
1300 SkIRect tileR;
bsalomon@google.com91958362011-06-13 17:58:13 +00001301 tileR.set(x * maxTextureSize, y * maxTextureSize,
1302 (x + 1) * maxTextureSize, (y + 1) * maxTextureSize);
reed@google.comac10a2d2010-12-22 21:39:39 +00001303 if (!SkIRect::Intersects(tileR, clipRect)) {
1304 continue;
1305 }
1306
1307 SkIRect srcR = tileR;
1308 if (!srcR.intersect(srcRect)) {
1309 continue;
1310 }
1311
1312 SkBitmap tmpB;
1313 if (bitmap.extractSubset(&tmpB, tileR)) {
1314 // now offset it to make it "local" to our tmp bitmap
1315 srcR.offset(-tileR.fLeft, -tileR.fTop);
1316
1317 SkMatrix tmpM(m);
1318 {
1319 int dx = tileR.fLeft - DX + SkMax32(0, srcR.fLeft);
1320 int dy = tileR.fTop - DY + SkMax32(0, srcR.fTop);
1321 tmpM.preTranslate(SkIntToScalar(dx), SkIntToScalar(dy));
1322 }
bsalomon@google.com5782d712011-01-21 21:03:59 +00001323 this->internalDrawBitmap(draw, tmpB, srcR, tmpM, &grPaint);
reed@google.comac10a2d2010-12-22 21:39:39 +00001324 }
1325 }
1326 }
1327}
1328
1329/*
1330 * This is called by drawBitmap(), which has to handle images that may be too
1331 * large to be represented by a single texture.
1332 *
bsalomon@google.com5782d712011-01-21 21:03:59 +00001333 * internalDrawBitmap assumes that the specified bitmap will fit in a texture
1334 * and that non-texture portion of the GrPaint has already been setup.
reed@google.comac10a2d2010-12-22 21:39:39 +00001335 */
1336void SkGpuDevice::internalDrawBitmap(const SkDraw& draw,
1337 const SkBitmap& bitmap,
1338 const SkIRect& srcRect,
1339 const SkMatrix& m,
bsalomon@google.com5782d712011-01-21 21:03:59 +00001340 GrPaint* grPaint) {
bsalomon@google.com91958362011-06-13 17:58:13 +00001341 SkASSERT(bitmap.width() <= fContext->getMaxTextureSize() &&
1342 bitmap.height() <= fContext->getMaxTextureSize());
reed@google.comac10a2d2010-12-22 21:39:39 +00001343
reed@google.com9c49bc32011-07-07 13:42:37 +00001344 SkAutoLockPixels alp(bitmap, !bitmap.getTexture());
reed@google.comac10a2d2010-12-22 21:39:39 +00001345 if (!bitmap.getTexture() && !bitmap.readyToDraw()) {
reed@google.com9c49bc32011-07-07 13:42:37 +00001346 SkDebugf("nothing to draw\n");
reed@google.comac10a2d2010-12-22 21:39:39 +00001347 return;
1348 }
1349
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001350 GrSamplerState* sampler = grPaint->getTextureSampler(kBitmapTextureIdx);
1351
1352 sampler->setWrapX(GrSamplerState::kClamp_WrapMode);
1353 sampler->setWrapY(GrSamplerState::kClamp_WrapMode);
1354 sampler->setSampleMode(GrSamplerState::kNormal_SampleMode);
1355 sampler->setMatrix(GrMatrix::I());
reed@google.comac10a2d2010-12-22 21:39:39 +00001356
1357 GrTexture* texture;
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001358 SkAutoCachedTexture act(this, bitmap, *sampler, &texture);
reed@google.comac10a2d2010-12-22 21:39:39 +00001359 if (NULL == texture) {
1360 return;
1361 }
1362
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001363 grPaint->setTexture(kShaderTextureIdx, texture);
reed@google.com46799cd2011-02-22 20:56:26 +00001364
reed@google.com20efde72011-05-09 17:00:02 +00001365 GrRect dstRect = SkRect::MakeWH(GrIntToScalar(srcRect.width()),
1366 GrIntToScalar(srcRect.height()));
bsalomon@google.comc6cf7232011-02-17 16:43:10 +00001367 GrRect paintRect;
junov@google.com6acc9b32011-05-16 18:32:07 +00001368 paintRect.setLTRB(GrFixedToScalar((srcRect.fLeft << 16) / bitmap.width()),
1369 GrFixedToScalar((srcRect.fTop << 16) / bitmap.height()),
1370 GrFixedToScalar((srcRect.fRight << 16) / bitmap.width()),
bsalomon@google.comc6cf7232011-02-17 16:43:10 +00001371 GrFixedToScalar((srcRect.fBottom << 16) / bitmap.height()));
reed@google.comac10a2d2010-12-22 21:39:39 +00001372
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001373 if (GrSamplerState::kNearest_Filter != sampler->getFilter() &&
junov@google.com6acc9b32011-05-16 18:32:07 +00001374 (srcRect.width() < bitmap.width() ||
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001375 srcRect.height() < bitmap.height())) {
junov@google.com6acc9b32011-05-16 18:32:07 +00001376 // If drawing a subrect of the bitmap and filtering is enabled,
1377 // use a constrained texture domain to avoid color bleeding
1378 GrScalar left, top, right, bottom;
1379 if (srcRect.width() > 1) {
1380 GrScalar border = GR_ScalarHalf / bitmap.width();
1381 left = paintRect.left() + border;
1382 right = paintRect.right() - border;
1383 } else {
1384 left = right = GrScalarHalf(paintRect.left() + paintRect.right());
1385 }
1386 if (srcRect.height() > 1) {
1387 GrScalar border = GR_ScalarHalf / bitmap.height();
1388 top = paintRect.top() + border;
1389 bottom = paintRect.bottom() - border;
1390 } else {
1391 top = bottom = GrScalarHalf(paintRect.top() + paintRect.bottom());
1392 }
1393 GrRect textureDomain;
1394 textureDomain.setLTRB(left, top, right, bottom);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001395 sampler->setTextureDomain(textureDomain);
junov@google.com6acc9b32011-05-16 18:32:07 +00001396 }
1397
bsalomon@google.comcc4dac32011-05-10 13:52:42 +00001398 fContext->drawRectToRect(*grPaint, dstRect, paintRect, &m);
reed@google.comac10a2d2010-12-22 21:39:39 +00001399}
1400
1401void SkGpuDevice::drawSprite(const SkDraw& draw, const SkBitmap& bitmap,
1402 int left, int top, const SkPaint& paint) {
1403 CHECK_SHOULD_DRAW(draw);
1404
1405 SkAutoLockPixels alp(bitmap);
1406 if (!bitmap.getTexture() && !bitmap.readyToDraw()) {
1407 return;
1408 }
1409
bsalomon@google.com5782d712011-01-21 21:03:59 +00001410 GrPaint grPaint;
Scroggod757df22011-05-16 13:11:16 +00001411 if(!this->skPaint2GrPaintNoShader(paint, true, &grPaint, false)) {
bsalomon@google.com5782d712011-01-21 21:03:59 +00001412 return;
1413 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001414
bsalomon@google.com5782d712011-01-21 21:03:59 +00001415 GrAutoMatrix avm(fContext, GrMatrix::I());
1416
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001417 GrSamplerState* sampler = grPaint.getTextureSampler(kBitmapTextureIdx);
bsalomon@google.com5782d712011-01-21 21:03:59 +00001418
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001419 GrTexture* texture;
1420 sampler->setClampNoFilter();
1421 SkAutoCachedTexture act(this, bitmap, *sampler, &texture);
1422
1423 grPaint.setTexture(kBitmapTextureIdx, texture);
bsalomon@google.com5782d712011-01-21 21:03:59 +00001424
bsalomon@google.com5782d712011-01-21 21:03:59 +00001425 fContext->drawRectToRect(grPaint,
reed@google.com20efde72011-05-09 17:00:02 +00001426 GrRect::MakeXYWH(GrIntToScalar(left),
1427 GrIntToScalar(top),
1428 GrIntToScalar(bitmap.width()),
1429 GrIntToScalar(bitmap.height())),
1430 GrRect::MakeWH(GR_Scalar1, GR_Scalar1));
reed@google.comac10a2d2010-12-22 21:39:39 +00001431}
1432
1433void SkGpuDevice::drawDevice(const SkDraw& draw, SkDevice* dev,
1434 int x, int y, const SkPaint& paint) {
1435 CHECK_SHOULD_DRAW(draw);
1436
bsalomon@google.com5782d712011-01-21 21:03:59 +00001437 GrPaint grPaint;
bsalomon@google.comc6cf7232011-02-17 16:43:10 +00001438 if (!((SkGpuDevice*)dev)->bindDeviceAsTexture(&grPaint) ||
Scroggod757df22011-05-16 13:11:16 +00001439 !this->skPaint2GrPaintNoShader(paint, true, &grPaint, false)) {
bsalomon@google.com5782d712011-01-21 21:03:59 +00001440 return;
reed@google.comac10a2d2010-12-22 21:39:39 +00001441 }
bsalomon@google.com5782d712011-01-21 21:03:59 +00001442
bsalomon@google.comb5b31682011-06-16 18:05:35 +00001443 GrTexture* devTex = grPaint.getTexture(0);
1444 SkASSERT(NULL != devTex);
bsalomon@google.com5782d712011-01-21 21:03:59 +00001445
1446 const SkBitmap& bm = dev->accessBitmap(false);
1447 int w = bm.width();
1448 int h = bm.height();
1449
1450 GrAutoMatrix avm(fContext, GrMatrix::I());
1451
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001452 grPaint.getTextureSampler(kBitmapTextureIdx)->setClampNoFilter();
bsalomon@google.com5782d712011-01-21 21:03:59 +00001453
bsalomon@google.comb5b31682011-06-16 18:05:35 +00001454 GrRect dstRect = GrRect::MakeXYWH(GrIntToScalar(x),
1455 GrIntToScalar(y),
1456 GrIntToScalar(w),
1457 GrIntToScalar(h));
1458 // The device being drawn may not fill up its texture (saveLayer uses
1459 // the approximate ).
1460 GrRect srcRect = GrRect::MakeWH(GR_Scalar1 * w / devTex->width(),
1461 GR_Scalar1 * h / devTex->height());
1462
1463 fContext->drawRectToRect(grPaint, dstRect, srcRect);
reed@google.comac10a2d2010-12-22 21:39:39 +00001464}
1465
1466///////////////////////////////////////////////////////////////////////////////
1467
1468// must be in SkCanvas::VertexMode order
bsalomon@google.comffca4002011-02-22 20:34:01 +00001469static const GrPrimitiveType gVertexMode2PrimitiveType[] = {
1470 kTriangles_PrimitiveType,
1471 kTriangleStrip_PrimitiveType,
1472 kTriangleFan_PrimitiveType,
reed@google.comac10a2d2010-12-22 21:39:39 +00001473};
1474
1475void SkGpuDevice::drawVertices(const SkDraw& draw, SkCanvas::VertexMode vmode,
1476 int vertexCount, const SkPoint vertices[],
1477 const SkPoint texs[], const SkColor colors[],
1478 SkXfermode* xmode,
1479 const uint16_t indices[], int indexCount,
1480 const SkPaint& paint) {
1481 CHECK_SHOULD_DRAW(draw);
1482
bsalomon@google.com5782d712011-01-21 21:03:59 +00001483 GrPaint grPaint;
1484 SkAutoCachedTexture act;
1485 // we ignore the shader if texs is null.
1486 if (NULL == texs) {
Scroggod757df22011-05-16 13:11:16 +00001487 if (!this->skPaint2GrPaintNoShader(paint,
1488 false,
1489 &grPaint,
1490 NULL == colors)) {
reed@google.comac10a2d2010-12-22 21:39:39 +00001491 return;
1492 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001493 } else {
reed@google.com1a2e8d22011-01-21 22:08:29 +00001494 if (!this->skPaint2GrPaintShader(paint, &act,
1495 *draw.fMatrix,
Scroggod757df22011-05-16 13:11:16 +00001496 &grPaint,
1497 NULL == colors)) {
bsalomon@google.com5782d712011-01-21 21:03:59 +00001498 return;
1499 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001500 }
bsalomon@google.com5782d712011-01-21 21:03:59 +00001501
1502 if (NULL != xmode && NULL != texs && NULL != colors) {
1503 SkXfermode::Mode mode;
1504 if (!SkXfermode::IsMode(xmode, &mode) ||
1505 SkXfermode::kMultiply_Mode != mode) {
1506 SkDebugf("Unsupported vertex-color/texture xfer mode.\n");
1507#if 0
1508 return
1509#endif
1510 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001511 }
bsalomon@google.com5782d712011-01-21 21:03:59 +00001512
1513#if SK_SCALAR_IS_GR_SCALAR
1514 // even if GrColor and SkColor byte offsets match we need
1515 // to perform pre-multiply.
1516 if (NULL == colors) {
1517 fContext->drawVertices(grPaint,
1518 gVertexMode2PrimitiveType[vmode],
1519 vertexCount,
1520 (GrPoint*) vertices,
1521 (GrPoint*) texs,
1522 NULL,
1523 indices,
1524 indexCount);
1525 } else
1526#endif
1527 {
1528 SkTexCoordSource texSrc(texs);
1529 SkColorSource colSrc(colors);
1530 SkIndexSource idxSrc(indices, indexCount);
1531
1532 fContext->drawCustomVertices(grPaint,
1533 gVertexMode2PrimitiveType[vmode],
1534 SkPositionSource(vertices, vertexCount),
1535 (NULL == texs) ? NULL : &texSrc,
1536 (NULL == colors) ? NULL : &colSrc,
1537 (NULL == indices) ? NULL : &idxSrc);
reed@google.comac10a2d2010-12-22 21:39:39 +00001538 }
1539}
1540
1541///////////////////////////////////////////////////////////////////////////////
1542
1543static void GlyphCacheAuxProc(void* data) {
1544 delete (GrFontScaler*)data;
1545}
1546
1547static GrFontScaler* get_gr_font_scaler(SkGlyphCache* cache) {
1548 void* auxData;
1549 GrFontScaler* scaler = NULL;
1550 if (cache->getAuxProcData(GlyphCacheAuxProc, &auxData)) {
1551 scaler = (GrFontScaler*)auxData;
1552 }
1553 if (NULL == scaler) {
1554 scaler = new SkGrFontScaler(cache);
1555 cache->setAuxProc(GlyphCacheAuxProc, scaler);
1556 }
1557 return scaler;
1558}
1559
1560static void SkGPU_Draw1Glyph(const SkDraw1Glyph& state,
1561 SkFixed fx, SkFixed fy,
1562 const SkGlyph& glyph) {
1563 SkASSERT(glyph.fWidth > 0 && glyph.fHeight > 0);
1564
1565 GrSkDrawProcs* procs = (GrSkDrawProcs*)state.fDraw->fProcs;
1566
1567 if (NULL == procs->fFontScaler) {
1568 procs->fFontScaler = get_gr_font_scaler(state.fCache);
1569 }
reed@google.com39ce0ac2011-04-08 15:42:19 +00001570
1571 /*
reed@google.com3b139f52011-06-07 17:56:25 +00001572 * What should we do with fy? (assuming horizontal/latin text)
reed@google.com39ce0ac2011-04-08 15:42:19 +00001573 *
reed@google.com3b139f52011-06-07 17:56:25 +00001574 * The raster code calls SkFixedFloorToFixed on it, as it does with fx.
1575 * It calls that rather than round, because our caller has already added
1576 * SK_FixedHalf, so that calling floor gives us the rounded integer.
1577 *
1578 * Test code between raster and gpu (they should draw the same)
1579 *
1580 * canvas->drawText("Hamburgefons", 12, 0, 16.5f, paint);
1581 *
1582 * Perhaps we should only perform this integralization if there is no
1583 * fExtMatrix...
reed@google.com39ce0ac2011-04-08 15:42:19 +00001584 */
reed@google.com3b139f52011-06-07 17:56:25 +00001585 fy = SkFixedFloorToFixed(fy);
1586
reed@google.comac10a2d2010-12-22 21:39:39 +00001587 procs->fTextContext->drawPackedGlyph(GrGlyph::Pack(glyph.getGlyphID(), fx, 0),
reed@google.com3b139f52011-06-07 17:56:25 +00001588 SkFixedFloorToFixed(fx), fy,
reed@google.comac10a2d2010-12-22 21:39:39 +00001589 procs->fFontScaler);
1590}
1591
bsalomon@google.com5782d712011-01-21 21:03:59 +00001592SkDrawProcs* SkGpuDevice::initDrawForText(GrTextContext* context) {
reed@google.comac10a2d2010-12-22 21:39:39 +00001593
1594 // deferred allocation
1595 if (NULL == fDrawProcs) {
1596 fDrawProcs = new GrSkDrawProcs;
1597 fDrawProcs->fD1GProc = SkGPU_Draw1Glyph;
1598 fDrawProcs->fContext = fContext;
1599 }
1600
1601 // init our (and GL's) state
1602 fDrawProcs->fTextContext = context;
1603 fDrawProcs->fFontScaler = NULL;
1604 return fDrawProcs;
1605}
1606
1607void SkGpuDevice::drawText(const SkDraw& draw, const void* text,
1608 size_t byteLength, SkScalar x, SkScalar y,
1609 const SkPaint& paint) {
1610 CHECK_SHOULD_DRAW(draw);
1611
1612 if (draw.fMatrix->getType() & SkMatrix::kPerspective_Mask) {
1613 // this guy will just call our drawPath()
1614 draw.drawText((const char*)text, byteLength, x, y, paint);
1615 } else {
reed@google.comac10a2d2010-12-22 21:39:39 +00001616 SkDraw myDraw(draw);
bsalomon@google.com5782d712011-01-21 21:03:59 +00001617
1618 GrPaint grPaint;
1619 SkAutoCachedTexture act;
1620
Scroggod757df22011-05-16 13:11:16 +00001621 if (!this->skPaint2GrPaintShader(paint,
1622 &act,
1623 *draw.fMatrix,
1624 &grPaint,
1625 true)) {
bsalomon@google.com5782d712011-01-21 21:03:59 +00001626 return;
1627 }
bsalomon@google.comcc4dac32011-05-10 13:52:42 +00001628 GrTextContext context(fContext, grPaint, draw.fExtMatrix);
bsalomon@google.com5782d712011-01-21 21:03:59 +00001629 myDraw.fProcs = this->initDrawForText(&context);
reed@google.comac10a2d2010-12-22 21:39:39 +00001630 this->INHERITED::drawText(myDraw, text, byteLength, x, y, paint);
1631 }
1632}
1633
1634void SkGpuDevice::drawPosText(const SkDraw& draw, const void* text,
1635 size_t byteLength, const SkScalar pos[],
1636 SkScalar constY, int scalarsPerPos,
1637 const SkPaint& paint) {
1638 CHECK_SHOULD_DRAW(draw);
1639
1640 if (draw.fMatrix->getType() & SkMatrix::kPerspective_Mask) {
1641 // this guy will just call our drawPath()
1642 draw.drawPosText((const char*)text, byteLength, pos, constY,
1643 scalarsPerPos, paint);
1644 } else {
reed@google.comac10a2d2010-12-22 21:39:39 +00001645 SkDraw myDraw(draw);
bsalomon@google.com5782d712011-01-21 21:03:59 +00001646
1647 GrPaint grPaint;
1648 SkAutoCachedTexture act;
Scroggod757df22011-05-16 13:11:16 +00001649 if (!this->skPaint2GrPaintShader(paint,
1650 &act,
1651 *draw.fMatrix,
1652 &grPaint,
1653 true)) {
bsalomon@google.com5782d712011-01-21 21:03:59 +00001654 return;
1655 }
1656
bsalomon@google.comcc4dac32011-05-10 13:52:42 +00001657 GrTextContext context(fContext, grPaint, draw.fExtMatrix);
bsalomon@google.com5782d712011-01-21 21:03:59 +00001658 myDraw.fProcs = this->initDrawForText(&context);
reed@google.comac10a2d2010-12-22 21:39:39 +00001659 this->INHERITED::drawPosText(myDraw, text, byteLength, pos, constY,
1660 scalarsPerPos, paint);
1661 }
1662}
1663
1664void SkGpuDevice::drawTextOnPath(const SkDraw& draw, const void* text,
1665 size_t len, const SkPath& path,
1666 const SkMatrix* m, const SkPaint& paint) {
1667 CHECK_SHOULD_DRAW(draw);
1668
1669 SkASSERT(draw.fDevice == this);
1670 draw.drawTextOnPath((const char*)text, len, path, m, paint);
1671}
1672
1673///////////////////////////////////////////////////////////////////////////////
1674
reed@google.comf67e4cf2011-03-15 20:56:58 +00001675bool SkGpuDevice::filterTextFlags(const SkPaint& paint, TextFlags* flags) {
1676 if (!paint.isLCDRenderText()) {
1677 // we're cool with the paint as is
1678 return false;
1679 }
1680
1681 if (paint.getShader() ||
1682 paint.getXfermode() || // unless its srcover
1683 paint.getMaskFilter() ||
1684 paint.getRasterizer() ||
1685 paint.getColorFilter() ||
1686 paint.getPathEffect() ||
1687 paint.isFakeBoldText() ||
1688 paint.getStyle() != SkPaint::kFill_Style) {
1689 // turn off lcd
1690 flags->fFlags = paint.getFlags() & ~SkPaint::kLCDRenderText_Flag;
1691 flags->fHinting = paint.getHinting();
1692 return true;
1693 }
1694 // we're cool with the paint as is
1695 return false;
1696}
1697
1698///////////////////////////////////////////////////////////////////////////////
1699
reed@google.comac10a2d2010-12-22 21:39:39 +00001700SkGpuDevice::TexCache* SkGpuDevice::lockCachedTexture(const SkBitmap& bitmap,
bsalomon@google.comfea37b52011-04-25 15:51:06 +00001701 const GrSamplerState& sampler,
1702 GrTexture** texture,
bsalomon@google.come97f0852011-06-17 13:10:25 +00001703 TexType type) {
bsalomon@google.comfea37b52011-04-25 15:51:06 +00001704 GrTexture* newTexture = NULL;
1705 GrTextureEntry* entry = NULL;
reed@google.comac10a2d2010-12-22 21:39:39 +00001706 GrContext* ctx = this->context();
bsalomon@google.comfea37b52011-04-25 15:51:06 +00001707
bsalomon@google.come97f0852011-06-17 13:10:25 +00001708 if (kBitmap_TexType != type) {
bsalomon@google.comfea37b52011-04-25 15:51:06 +00001709 const GrTextureDesc desc = {
1710 kRenderTarget_GrTextureFlagBit,
1711 kNone_GrAALevel,
1712 bitmap.width(),
1713 bitmap.height(),
1714 SkGr::Bitmap2PixelConfig(bitmap)
1715 };
bsalomon@google.come97f0852011-06-17 13:10:25 +00001716 if (kSaveLayerDeviceRenderTarget_TexType == type) {
bsalomon@google.comb5b31682011-06-16 18:05:35 +00001717 // we know layers will only be drawn through drawDevice.
1718 // drawDevice has been made to work with content embedded in a
1719 // larger texture so its okay to use the approximate version.
1720 entry = ctx->findApproximateKeylessTexture(desc);
1721 } else {
bsalomon@google.come97f0852011-06-17 13:10:25 +00001722 SkASSERT(kDeviceRenderTarget_TexType == type);
bsalomon@google.comb5b31682011-06-16 18:05:35 +00001723 entry = ctx->lockKeylessTexture(desc);
1724 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001725 } else {
junov@google.com4ee7ae52011-06-30 17:30:49 +00001726 if (!bitmap.isVolatile()) {
1727 uint32_t p0, p1;
1728 p0 = bitmap.getGenerationID();
1729 p1 = bitmap.pixelRefOffset();
1730 GrTextureKey key(p0, p1, bitmap.width(), bitmap.height());
1731
1732 entry = ctx->findAndLockTexture(&key, sampler);
1733 if (NULL == entry)
1734 entry = sk_gr_create_bitmap_texture(ctx, &key, sampler,
1735 bitmap);
1736 } else {
1737 entry = sk_gr_create_bitmap_texture(ctx, NULL, sampler, bitmap);
1738 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001739 if (NULL == entry) {
junov@google.com4ee7ae52011-06-30 17:30:49 +00001740 GrPrintf("---- failed to create texture for cache [%d %d]\n",
1741 bitmap.width(), bitmap.height());
reed@google.comac10a2d2010-12-22 21:39:39 +00001742 }
1743 }
1744
1745 if (NULL != entry) {
1746 newTexture = entry->texture();
reed@google.comac10a2d2010-12-22 21:39:39 +00001747 if (texture) {
1748 *texture = newTexture;
1749 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001750 }
1751 return (TexCache*)entry;
1752}
1753
1754void SkGpuDevice::unlockCachedTexture(TexCache* cache) {
1755 this->context()->unlockTexture((GrTextureEntry*)cache);
1756}
1757
bsalomon@google.come97f0852011-06-17 13:10:25 +00001758SkDevice* SkGpuDevice::onCreateCompatibleDevice(SkBitmap::Config config,
1759 int width, int height,
1760 bool isOpaque,
1761 Usage usage) {
1762 return SkNEW_ARGS(SkGpuDevice,(this->context(), config,
1763 width, height, usage));
1764}
1765