blob: 45dac336eaddaa82aec19ed7a7a97a5739b36de1 [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.orge36ddf02011-07-15 14:28:16 +000050#define MAX_BLUR_SIGMA 4.0f
51// FIXME: This value comes from from SkBlurMaskFilter.cpp.
52// Should probably be put in a common header someplace.
53#define MAX_BLUR_RADIUS SkIntToScalar(128)
54// This constant approximates the scaling done in the software path's
55// "high quality" mode, in SkBlurMask::Blur() (1 / sqrt(3)).
56// IMHO, it actually should be 1: we blur "less" than we should do
57// according to the CSS and canvas specs, simply because Safari does the same.
58// Firefox used to do the same too, until 4.0 where they fixed it. So at some
59// point we should probably get rid of these scaling constants and rebaseline
60// all the blur tests.
61#define BLUR_SIGMA_SCALE 0.6f
reed@google.comac10a2d2010-12-22 21:39:39 +000062///////////////////////////////////////////////////////////////////////////////
63
64SkGpuDevice::SkAutoCachedTexture::
65 SkAutoCachedTexture(SkGpuDevice* device,
66 const SkBitmap& bitmap,
67 const GrSamplerState& sampler,
68 GrTexture** texture) {
69 GrAssert(texture);
70 fTex = NULL;
71 *texture = this->set(device, bitmap, sampler);
72}
73
74SkGpuDevice::SkAutoCachedTexture::SkAutoCachedTexture() {
75 fTex = NULL;
76}
77
78GrTexture* SkGpuDevice::SkAutoCachedTexture::set(SkGpuDevice* device,
79 const SkBitmap& bitmap,
80 const GrSamplerState& sampler) {
81 if (fTex) {
82 fDevice->unlockCachedTexture(fTex);
83 }
84 fDevice = device;
85 GrTexture* texture = (GrTexture*)bitmap.getTexture();
86 if (texture) {
87 // return the native texture
88 fTex = NULL;
reed@google.comac10a2d2010-12-22 21:39:39 +000089 } else {
90 // look it up in our cache
bsalomon@google.come97f0852011-06-17 13:10:25 +000091 fTex = device->lockCachedTexture(bitmap, sampler, &texture);
reed@google.comac10a2d2010-12-22 21:39:39 +000092 }
93 return texture;
94}
95
96SkGpuDevice::SkAutoCachedTexture::~SkAutoCachedTexture() {
97 if (fTex) {
98 fDevice->unlockCachedTexture(fTex);
99 }
100}
101
102///////////////////////////////////////////////////////////////////////////////
103
104bool gDoTraceDraw;
105
106struct GrSkDrawProcs : public SkDrawProcs {
107public:
108 GrContext* fContext;
109 GrTextContext* fTextContext;
110 GrFontScaler* fFontScaler; // cached in the skia glyphcache
111};
112
113///////////////////////////////////////////////////////////////////////////////
114
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000115GrRenderTarget* SkGpuDevice::Current3DApiRenderTarget() {
116 return (GrRenderTarget*) -1;
117}
118
reed@google.comaf951c92011-06-16 19:10:39 +0000119static SkBitmap::Config grConfig2skConfig(GrPixelConfig config, bool* isOpaque) {
120 switch (config) {
121 case kAlpha_8_GrPixelConfig:
122 *isOpaque = false;
123 return SkBitmap::kA8_Config;
124 case kRGB_565_GrPixelConfig:
125 *isOpaque = true;
126 return SkBitmap::kRGB_565_Config;
127 case kRGBA_4444_GrPixelConfig:
128 *isOpaque = false;
129 return SkBitmap::kARGB_4444_Config;
130 case kRGBA_8888_GrPixelConfig:
131 case kRGBX_8888_GrPixelConfig:
132 *isOpaque = (kRGBX_8888_GrPixelConfig == config);
133 return SkBitmap::kARGB_8888_Config;
134 default:
135 *isOpaque = false;
136 return SkBitmap::kNo_Config;
137 }
138}
reed@google.comac10a2d2010-12-22 21:39:39 +0000139
reed@google.comaf951c92011-06-16 19:10:39 +0000140static SkBitmap make_bitmap(GrContext* context, GrRenderTarget* renderTarget) {
141 if (SkGpuDevice::Current3DApiRenderTarget() == renderTarget) {
142 renderTarget = context->createRenderTargetFrom3DApiState();
143 }
144 GrTexture* texture = renderTarget->asTexture();
145 GrPixelConfig config = texture ? texture->config() : kRGBA_8888_GrPixelConfig;
146
147 bool isOpaque;
148 SkBitmap bitmap;
149 bitmap.setConfig(grConfig2skConfig(config, &isOpaque),
150 renderTarget->width(), renderTarget->height());
151 bitmap.setIsOpaque(isOpaque);
152 return bitmap;
153}
154
bsalomon@google.comf9046fe2011-06-17 15:10:21 +0000155SkGpuDevice::SkGpuDevice(GrContext* context, GrTexture* texture)
156: SkDevice(make_bitmap(context, texture->asRenderTarget())) {
157 this->initFromRenderTarget(context, texture->asRenderTarget());
158}
159
reed@google.comaf951c92011-06-16 19:10:39 +0000160SkGpuDevice::SkGpuDevice(GrContext* context, GrRenderTarget* renderTarget)
161: SkDevice(make_bitmap(context, renderTarget)) {
bsalomon@google.comf9046fe2011-06-17 15:10:21 +0000162 this->initFromRenderTarget(context, renderTarget);
163}
164
165void SkGpuDevice::initFromRenderTarget(GrContext* context,
166 GrRenderTarget* renderTarget) {
reed@google.comaf951c92011-06-16 19:10:39 +0000167 fNeedPrepareRenderTarget = false;
168 fDrawProcs = NULL;
169
170 fContext = context;
171 fContext->ref();
172
173 fCache = NULL;
174 fTexture = NULL;
175 fRenderTarget = NULL;
176 fNeedClear = false;
177
178 if (Current3DApiRenderTarget() == renderTarget) {
179 fRenderTarget = fContext->createRenderTargetFrom3DApiState();
180 } else {
bsalomon@google.comf9046fe2011-06-17 15:10:21 +0000181 GrAssert(NULL != renderTarget);
reed@google.comaf951c92011-06-16 19:10:39 +0000182 fRenderTarget = renderTarget;
183 fRenderTarget->ref();
bsalomon@google.comf9046fe2011-06-17 15:10:21 +0000184 // if this RT is also a texture, hold a ref on it
185 fTexture = fRenderTarget->asTexture();
186 SkSafeRef(fTexture);
reed@google.comaf951c92011-06-16 19:10:39 +0000187 }
188
189 SkGrRenderTargetPixelRef* pr = new SkGrRenderTargetPixelRef(fRenderTarget);
190 this->setPixelRef(pr, 0)->unref();
191}
192
193SkGpuDevice::SkGpuDevice(GrContext* context, SkBitmap::Config config, int width,
bsalomon@google.come97f0852011-06-17 13:10:25 +0000194 int height, Usage usage)
reed@google.comaf951c92011-06-16 19:10:39 +0000195: SkDevice(config, width, height, false /*isOpaque*/) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000196 fNeedPrepareRenderTarget = false;
197 fDrawProcs = NULL;
198
reed@google.com7b201d22011-01-11 18:59:23 +0000199 fContext = context;
bsalomon@google.com5782d712011-01-21 21:03:59 +0000200 fContext->ref();
reed@google.comac10a2d2010-12-22 21:39:39 +0000201
202 fCache = NULL;
203 fTexture = NULL;
204 fRenderTarget = NULL;
205 fNeedClear = false;
206
reed@google.comaf951c92011-06-16 19:10:39 +0000207 if (config != SkBitmap::kRGB_565_Config) {
208 config = SkBitmap::kARGB_8888_Config;
209 }
210 SkBitmap bm;
211 bm.setConfig(config, width, height);
reed@google.comac10a2d2010-12-22 21:39:39 +0000212
213#if CACHE_LAYER_TEXTURES
bsalomon@google.come97f0852011-06-17 13:10:25 +0000214 TexType type = (kSaveLayer_Usage == usage) ?
215 kSaveLayerDeviceRenderTarget_TexType :
216 kDeviceRenderTarget_TexType;
reed@google.comaf951c92011-06-16 19:10:39 +0000217 fCache = this->lockCachedTexture(bm, GrSamplerState::ClampNoFilter(),
bsalomon@google.come97f0852011-06-17 13:10:25 +0000218 &fTexture, type);
reed@google.comaf951c92011-06-16 19:10:39 +0000219 if (fCache) {
220 SkASSERT(NULL != fTexture);
221 SkASSERT(NULL != fTexture->asRenderTarget());
bsalomon@google.comf9046fe2011-06-17 15:10:21 +0000222 // hold a ref directly on fTexture (even though fCache has one) to match
223 // other constructor paths. Simplifies cleanup.
224 fTexture->ref();
reed@google.comaf951c92011-06-16 19:10:39 +0000225 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000226#else
reed@google.comaf951c92011-06-16 19:10:39 +0000227 const GrTextureDesc desc = {
228 kRenderTarget_GrTextureFlagBit,
229 kNone_GrAALevel,
230 width,
231 height,
232 SkGr::Bitmap2PixelConfig(bm)
233 };
reed@google.comac10a2d2010-12-22 21:39:39 +0000234
reed@google.comaf951c92011-06-16 19:10:39 +0000235 fTexture = fContext->createUncachedTexture(desc, NULL, 0);
reed@google.comac10a2d2010-12-22 21:39:39 +0000236#endif
reed@google.comaf951c92011-06-16 19:10:39 +0000237 if (NULL != fTexture) {
238 fRenderTarget = fTexture->asRenderTarget();
bsalomon@google.comf9046fe2011-06-17 15:10:21 +0000239 fRenderTarget->ref();
reed@google.comac10a2d2010-12-22 21:39:39 +0000240
reed@google.comaf951c92011-06-16 19:10:39 +0000241 GrAssert(NULL != fRenderTarget);
reed@google.comac10a2d2010-12-22 21:39:39 +0000242
reed@google.comaf951c92011-06-16 19:10:39 +0000243 // we defer the actual clear until our gainFocus()
244 fNeedClear = true;
reed@google.comac10a2d2010-12-22 21:39:39 +0000245
reed@google.comaf951c92011-06-16 19:10:39 +0000246 // wrap the bitmap with a pixelref to expose our texture
247 SkGrTexturePixelRef* pr = new SkGrTexturePixelRef(fTexture);
bsalomon@google.com669fdc42011-04-05 17:08:27 +0000248 this->setPixelRef(pr, 0)->unref();
reed@google.comaf951c92011-06-16 19:10:39 +0000249 } else {
250 GrPrintf("--- failed to create gpu-offscreen [%d %d]\n",
251 width, height);
252 GrAssert(false);
reed@google.comac10a2d2010-12-22 21:39:39 +0000253 }
254}
255
256SkGpuDevice::~SkGpuDevice() {
257 if (fDrawProcs) {
258 delete fDrawProcs;
259 }
260
bsalomon@google.comf9046fe2011-06-17 15:10:21 +0000261 SkSafeUnref(fTexture);
262 SkSafeUnref(fRenderTarget);
reed@google.comac10a2d2010-12-22 21:39:39 +0000263 if (fCache) {
264 GrAssert(NULL != fTexture);
265 GrAssert(fRenderTarget == fTexture->asRenderTarget());
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000266 fContext->unlockTexture((GrTextureEntry*)fCache);
bsalomon@google.comf9046fe2011-06-17 15:10:21 +0000267 }
bsalomon@google.com5782d712011-01-21 21:03:59 +0000268 fContext->unref();
reed@google.comac10a2d2010-12-22 21:39:39 +0000269}
270
reed@google.comac10a2d2010-12-22 21:39:39 +0000271///////////////////////////////////////////////////////////////////////////////
272
273void SkGpuDevice::makeRenderTargetCurrent() {
274 fContext->setRenderTarget(fRenderTarget);
275 fContext->flush(true);
276 fNeedPrepareRenderTarget = true;
277}
278
279///////////////////////////////////////////////////////////////////////////////
280
281bool SkGpuDevice::readPixels(const SkIRect& srcRect, SkBitmap* bitmap) {
282 SkIRect bounds;
283 bounds.set(0, 0, this->width(), this->height());
284 if (!bounds.intersect(srcRect)) {
285 return false;
286 }
287
288 const int w = bounds.width();
289 const int h = bounds.height();
290 SkBitmap tmp;
291 // note we explicitly specify our rowBytes to be snug (no gap between rows)
292 tmp.setConfig(SkBitmap::kARGB_8888_Config, w, h, w * 4);
293 if (!tmp.allocPixels()) {
294 return false;
295 }
296
Scroggo813c33c2011-04-07 20:56:21 +0000297 tmp.lockPixels();
reed@google.comac10a2d2010-12-22 21:39:39 +0000298
Scroggoeb176032011-04-07 21:11:49 +0000299 bool read = fContext->readRenderTargetPixels(fRenderTarget,
300 bounds.fLeft, bounds.fTop,
301 bounds.width(), bounds.height(),
302 kRGBA_8888_GrPixelConfig,
303 tmp.getPixels());
Scroggo813c33c2011-04-07 20:56:21 +0000304 tmp.unlockPixels();
305 if (!read) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000306 return false;
307 }
308
309 tmp.swap(*bitmap);
310 return true;
311}
312
313void SkGpuDevice::writePixels(const SkBitmap& bitmap, int x, int y) {
314 SkAutoLockPixels alp(bitmap);
315 if (!bitmap.readyToDraw()) {
316 return;
317 }
bsalomon@google.com669fdc42011-04-05 17:08:27 +0000318 GrPixelConfig config = SkGr::BitmapConfig2PixelConfig(bitmap.config(),
319 bitmap.isOpaque());
reed@google.comac10a2d2010-12-22 21:39:39 +0000320 fContext->setRenderTarget(fRenderTarget);
321 // we aren't setting the clip or matrix, so mark as dirty
322 // we don't need to set them for this call and don't have them anyway
323 fNeedPrepareRenderTarget = true;
324
325 fContext->writePixels(x, y, bitmap.width(), bitmap.height(),
326 config, bitmap.getPixels(), bitmap.rowBytes());
327}
328
329///////////////////////////////////////////////////////////////////////////////
330
331static void convert_matrixclip(GrContext* context, const SkMatrix& matrix,
bsalomon@google.comd302f142011-03-03 13:54:13 +0000332 const SkClipStack& clipStack,
reed@google.com6f8f2922011-03-04 22:27:10 +0000333 const SkRegion& clipRegion,
334 const SkIPoint& origin) {
bsalomon@google.comcc4dac32011-05-10 13:52:42 +0000335 context->setMatrix(matrix);
reed@google.comac10a2d2010-12-22 21:39:39 +0000336
337 SkGrClipIterator iter;
bsalomon@google.comd302f142011-03-03 13:54:13 +0000338 iter.reset(clipStack);
bsalomon@google.comd302f142011-03-03 13:54:13 +0000339 const SkIRect& skBounds = clipRegion.getBounds();
340 GrRect bounds;
341 bounds.setLTRB(GrIntToScalar(skBounds.fLeft),
342 GrIntToScalar(skBounds.fTop),
343 GrIntToScalar(skBounds.fRight),
344 GrIntToScalar(skBounds.fBottom));
reed@google.com6f8f2922011-03-04 22:27:10 +0000345 GrClip grc(&iter, GrIntToScalar(-origin.x()), GrIntToScalar(-origin.y()),
346 &bounds);
bsalomon@google.comd302f142011-03-03 13:54:13 +0000347 context->setClip(grc);
reed@google.comac10a2d2010-12-22 21:39:39 +0000348}
349
350// call this ever each draw call, to ensure that the context reflects our state,
351// and not the state from some other canvas/device
352void SkGpuDevice::prepareRenderTarget(const SkDraw& draw) {
353 if (fNeedPrepareRenderTarget ||
bsalomon@google.com5782d712011-01-21 21:03:59 +0000354 fContext->getRenderTarget() != fRenderTarget) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000355
356 fContext->setRenderTarget(fRenderTarget);
bsalomon@google.comd302f142011-03-03 13:54:13 +0000357 SkASSERT(draw.fClipStack);
358 convert_matrixclip(fContext, *draw.fMatrix,
reed@google.com6f8f2922011-03-04 22:27:10 +0000359 *draw.fClipStack, *draw.fClip, this->getOrigin());
reed@google.comac10a2d2010-12-22 21:39:39 +0000360 fNeedPrepareRenderTarget = false;
361 }
362}
363
reed@google.com46799cd2011-02-22 20:56:26 +0000364void SkGpuDevice::setMatrixClip(const SkMatrix& matrix, const SkRegion& clip,
365 const SkClipStack& clipStack) {
366 this->INHERITED::setMatrixClip(matrix, clip, clipStack);
bsalomon@google.coma7bf6e22011-04-11 19:20:46 +0000367 // We don't need to set them now because the context may not reflect this device.
368 fNeedPrepareRenderTarget = true;
reed@google.comac10a2d2010-12-22 21:39:39 +0000369}
370
371void SkGpuDevice::gainFocus(SkCanvas* canvas, const SkMatrix& matrix,
bsalomon@google.comd302f142011-03-03 13:54:13 +0000372 const SkRegion& clip, const SkClipStack& clipStack) {
373
reed@google.comac10a2d2010-12-22 21:39:39 +0000374 fContext->setRenderTarget(fRenderTarget);
375
bsalomon@google.comd302f142011-03-03 13:54:13 +0000376 this->INHERITED::gainFocus(canvas, matrix, clip, clipStack);
reed@google.comac10a2d2010-12-22 21:39:39 +0000377
reed@google.com6f8f2922011-03-04 22:27:10 +0000378 convert_matrixclip(fContext, matrix, clipStack, clip, this->getOrigin());
reed@google.comac10a2d2010-12-22 21:39:39 +0000379
380 if (fNeedClear) {
bsalomon@google.com31a58402011-04-27 21:00:02 +0000381 fContext->clear(NULL, 0x0);
reed@google.comac10a2d2010-12-22 21:39:39 +0000382 fNeedClear = false;
383 }
384}
385
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000386bool SkGpuDevice::bindDeviceAsTexture(GrPaint* paint) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000387 if (NULL != fTexture) {
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000388 paint->setTexture(kBitmapTextureIdx, fTexture);
reed@google.comac10a2d2010-12-22 21:39:39 +0000389 return true;
390 }
391 return false;
392}
393
394///////////////////////////////////////////////////////////////////////////////
395
vandebo@chromium.orgd3ae7792011-02-24 00:21:06 +0000396SK_COMPILE_ASSERT(SkShader::kNone_BitmapType == 0, shader_type_mismatch);
397SK_COMPILE_ASSERT(SkShader::kDefault_BitmapType == 1, shader_type_mismatch);
398SK_COMPILE_ASSERT(SkShader::kRadial_BitmapType == 2, shader_type_mismatch);
399SK_COMPILE_ASSERT(SkShader::kSweep_BitmapType == 3, shader_type_mismatch);
400SK_COMPILE_ASSERT(SkShader::kTwoPointRadial_BitmapType == 4,
401 shader_type_mismatch);
402SK_COMPILE_ASSERT(SkShader::kLast_BitmapType == 4, shader_type_mismatch);
reed@google.comac10a2d2010-12-22 21:39:39 +0000403
bsalomon@google.com5782d712011-01-21 21:03:59 +0000404static const GrSamplerState::SampleMode sk_bmp_type_to_sample_mode[] = {
405 (GrSamplerState::SampleMode) -1, // kNone_BitmapType
406 GrSamplerState::kNormal_SampleMode, // kDefault_BitmapType
407 GrSamplerState::kRadial_SampleMode, // kRadial_BitmapType
408 GrSamplerState::kSweep_SampleMode, // kSweep_BitmapType
409 GrSamplerState::kRadial2_SampleMode, // kTwoPointRadial_BitmapType
410};
411
412bool SkGpuDevice::skPaint2GrPaintNoShader(const SkPaint& skPaint,
413 bool justAlpha,
Scroggod757df22011-05-16 13:11:16 +0000414 GrPaint* grPaint,
415 bool constantColor) {
bsalomon@google.com5782d712011-01-21 21:03:59 +0000416
417 grPaint->fDither = skPaint.isDither();
418 grPaint->fAntiAlias = skPaint.isAntiAlias();
419
420 SkXfermode::Coeff sm = SkXfermode::kOne_Coeff;
421 SkXfermode::Coeff dm = SkXfermode::kISA_Coeff;
422
423 SkXfermode* mode = skPaint.getXfermode();
424 if (mode) {
425 if (!mode->asCoeff(&sm, &dm)) {
reed@google.com1a2e8d22011-01-21 22:08:29 +0000426 SkDEBUGCODE(SkDebugf("Unsupported xfer mode.\n");)
bsalomon@google.com5782d712011-01-21 21:03:59 +0000427#if 0
428 return false;
429#endif
430 }
431 }
432 grPaint->fSrcBlendCoeff = sk_blend_to_grblend(sm);
433 grPaint->fDstBlendCoeff = sk_blend_to_grblend(dm);
434
435 if (justAlpha) {
436 uint8_t alpha = skPaint.getAlpha();
437 grPaint->fColor = GrColorPackRGBA(alpha, alpha, alpha, alpha);
Scroggod757df22011-05-16 13:11:16 +0000438 // justAlpha is currently set to true only if there is a texture,
439 // so constantColor should not also be true.
440 GrAssert(!constantColor);
bsalomon@google.com5782d712011-01-21 21:03:59 +0000441 } else {
442 grPaint->fColor = SkGr::SkColor2GrColor(skPaint.getColor());
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000443 grPaint->setTexture(kShaderTextureIdx, NULL);
bsalomon@google.com5782d712011-01-21 21:03:59 +0000444 }
Scroggo97c88c22011-05-11 14:05:25 +0000445 SkColorFilter* colorFilter = skPaint.getColorFilter();
446 SkColor color;
447 SkXfermode::Mode filterMode;
448 if (colorFilter != NULL && colorFilter->asColorMode(&color, &filterMode)) {
Scroggod757df22011-05-16 13:11:16 +0000449 if (!constantColor) {
450 grPaint->fColorFilterColor = SkGr::SkColor2GrColor(color);
451 grPaint->fColorFilterXfermode = filterMode;
452 return true;
453 }
454 SkColor filtered = colorFilter->filterColor(skPaint.getColor());
455 grPaint->fColor = SkGr::SkColor2GrColor(filtered);
Scroggo97c88c22011-05-11 14:05:25 +0000456 }
Scroggod757df22011-05-16 13:11:16 +0000457 grPaint->resetColorFilter();
bsalomon@google.com5782d712011-01-21 21:03:59 +0000458 return true;
reed@google.comac10a2d2010-12-22 21:39:39 +0000459}
460
bsalomon@google.com5782d712011-01-21 21:03:59 +0000461bool SkGpuDevice::skPaint2GrPaintShader(const SkPaint& skPaint,
462 SkAutoCachedTexture* act,
463 const SkMatrix& ctm,
Scroggod757df22011-05-16 13:11:16 +0000464 GrPaint* grPaint,
465 bool constantColor) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000466
bsalomon@google.com5782d712011-01-21 21:03:59 +0000467 SkASSERT(NULL != act);
reed@google.comac10a2d2010-12-22 21:39:39 +0000468
bsalomon@google.com5782d712011-01-21 21:03:59 +0000469 SkShader* shader = skPaint.getShader();
reed@google.comac10a2d2010-12-22 21:39:39 +0000470 if (NULL == shader) {
Scroggod757df22011-05-16 13:11:16 +0000471 return this->skPaint2GrPaintNoShader(skPaint,
472 false,
473 grPaint,
474 constantColor);
475 } else if (!this->skPaint2GrPaintNoShader(skPaint, true, grPaint, false)) {
bsalomon@google.com5782d712011-01-21 21:03:59 +0000476 return false;
reed@google.comac10a2d2010-12-22 21:39:39 +0000477 }
478
reed@google.comac10a2d2010-12-22 21:39:39 +0000479 SkBitmap bitmap;
480 SkMatrix matrix;
481 SkShader::TileMode tileModes[2];
482 SkScalar twoPointParams[3];
483 SkShader::BitmapType bmptype = shader->asABitmap(&bitmap, &matrix,
484 tileModes, twoPointParams);
485
bsalomon@google.com5782d712011-01-21 21:03:59 +0000486 GrSamplerState::SampleMode sampleMode = sk_bmp_type_to_sample_mode[bmptype];
487 if (-1 == sampleMode) {
reed@google.com2be9e8b2011-07-06 21:18:09 +0000488 SkShader::GradientInfo info;
489 SkColor color;
490
491 info.fColors = &color;
492 info.fColorOffsets = NULL;
493 info.fColorCount = 1;
494 if (SkShader::kColor_GradientType == shader->asAGradient(&info)) {
495 SkPaint copy(skPaint);
496 copy.setShader(NULL);
bsalomon@google.comcd9cfd72011-07-08 16:55:04 +0000497 // modulate the paint alpha by the shader's solid color alpha
498 U8CPU newA = SkMulDiv255Round(SkColorGetA(color), copy.getAlpha());
499 copy.setColor(SkColorSetA(color, newA));
reed@google.com2be9e8b2011-07-06 21:18:09 +0000500 return this->skPaint2GrPaintNoShader(copy,
501 false,
502 grPaint,
503 constantColor);
504 }
bsalomon@google.com5782d712011-01-21 21:03:59 +0000505 return false;
reed@google.comac10a2d2010-12-22 21:39:39 +0000506 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000507 GrSamplerState* sampler = grPaint->getTextureSampler(kShaderTextureIdx);
508 sampler->setSampleMode(sampleMode);
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000509 if (skPaint.isFilterBitmap()) {
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000510 sampler->setFilter(GrSamplerState::kBilinear_Filter);
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000511 } else {
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000512 sampler->setFilter(GrSamplerState::kNearest_Filter);
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000513 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000514 sampler->setWrapX(sk_tile_mode_to_grwrap(tileModes[0]));
515 sampler->setWrapY(sk_tile_mode_to_grwrap(tileModes[1]));
reed@google.comac10a2d2010-12-22 21:39:39 +0000516 if (GrSamplerState::kRadial2_SampleMode == sampleMode) {
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000517 sampler->setRadial2Params(twoPointParams[0],
518 twoPointParams[1],
519 twoPointParams[2] < 0);
reed@google.comac10a2d2010-12-22 21:39:39 +0000520 }
521
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000522 GrTexture* texture = act->set(this, bitmap, *sampler);
reed@google.comac10a2d2010-12-22 21:39:39 +0000523 if (NULL == texture) {
bsalomon@google.com5782d712011-01-21 21:03:59 +0000524 SkDebugf("Couldn't convert bitmap to texture.\n");
525 return false;
reed@google.comac10a2d2010-12-22 21:39:39 +0000526 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000527 grPaint->setTexture(kShaderTextureIdx, texture);
reed@google.comac10a2d2010-12-22 21:39:39 +0000528
529 // since our texture coords will be in local space, we wack the texture
530 // matrix to map them back into 0...1 before we load it
531 SkMatrix localM;
532 if (shader->getLocalMatrix(&localM)) {
533 SkMatrix inverse;
534 if (localM.invert(&inverse)) {
535 matrix.preConcat(inverse);
536 }
537 }
538 if (SkShader::kDefault_BitmapType == bmptype) {
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000539 GrScalar sx = GrFixedToScalar(GR_Fixed1 / bitmap.width());
540 GrScalar sy = GrFixedToScalar(GR_Fixed1 / bitmap.height());
reed@google.comac10a2d2010-12-22 21:39:39 +0000541 matrix.postScale(sx, sy);
reed@google.comac10a2d2010-12-22 21:39:39 +0000542 } else if (SkShader::kRadial_BitmapType == bmptype) {
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000543 GrScalar s = GrFixedToScalar(GR_Fixed1 / bitmap.width());
reed@google.comac10a2d2010-12-22 21:39:39 +0000544 matrix.postScale(s, s);
545 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000546 sampler->setMatrix(matrix);
bsalomon@google.com5782d712011-01-21 21:03:59 +0000547
548 return true;
reed@google.comac10a2d2010-12-22 21:39:39 +0000549}
550
551///////////////////////////////////////////////////////////////////////////////
bsalomon@google.com5782d712011-01-21 21:03:59 +0000552
553class SkPositionSource {
554public:
555 SkPositionSource(const SkPoint* points, int count)
556 : fPoints(points), fCount(count) {}
557
558 int count() const { return fCount; }
559
560 void writeValue(int i, GrPoint* dstPosition) const {
561 SkASSERT(i < fCount);
562 dstPosition->fX = SkScalarToGrScalar(fPoints[i].fX);
563 dstPosition->fY = SkScalarToGrScalar(fPoints[i].fY);
564 }
565private:
bsalomon@google.com5782d712011-01-21 21:03:59 +0000566 const SkPoint* fPoints;
bsalomon@google.com19628322011-02-03 21:30:17 +0000567 int fCount;
bsalomon@google.com5782d712011-01-21 21:03:59 +0000568};
569
570class SkTexCoordSource {
571public:
572 SkTexCoordSource(const SkPoint* coords)
573 : fCoords(coords) {}
574
575 void writeValue(int i, GrPoint* dstCoord) const {
576 dstCoord->fX = SkScalarToGrScalar(fCoords[i].fX);
577 dstCoord->fY = SkScalarToGrScalar(fCoords[i].fY);
578 }
579private:
580 const SkPoint* fCoords;
581};
582
583class SkColorSource {
584public:
585 SkColorSource(const SkColor* colors) : fColors(colors) {}
586
587 void writeValue(int i, GrColor* dstColor) const {
588 *dstColor = SkGr::SkColor2GrColor(fColors[i]);
589 }
590private:
591 const SkColor* fColors;
592};
593
594class SkIndexSource {
595public:
596 SkIndexSource(const uint16_t* indices, int count)
597 : fIndices(indices), fCount(count) {
598 }
599
600 int count() const { return fCount; }
601
602 void writeValue(int i, uint16_t* dstIndex) const {
603 *dstIndex = fIndices[i];
604 }
605
606private:
bsalomon@google.com5782d712011-01-21 21:03:59 +0000607 const uint16_t* fIndices;
bsalomon@google.com19628322011-02-03 21:30:17 +0000608 int fCount;
bsalomon@google.com5782d712011-01-21 21:03:59 +0000609};
610
611///////////////////////////////////////////////////////////////////////////////
612
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000613#if 0 // not currently being used so don't compile,
614
bsalomon@google.com5782d712011-01-21 21:03:59 +0000615// can be used for positions or texture coordinates
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000616
bsalomon@google.com5782d712011-01-21 21:03:59 +0000617class SkRectFanSource {
618public:
619 SkRectFanSource(const SkRect& rect) : fRect(rect) {}
620
621 int count() const { return 4; }
622
623 void writeValue(int i, GrPoint* dstPoint) const {
624 SkASSERT(i < 4);
625 dstPoint->fX = SkScalarToGrScalar((i % 3) ? fRect.fRight :
626 fRect.fLeft);
627 dstPoint->fY = SkScalarToGrScalar((i < 2) ? fRect.fTop :
628 fRect.fBottom);
629 }
630private:
631 const SkRect& fRect;
632};
633
634class SkIRectFanSource {
635public:
636 SkIRectFanSource(const SkIRect& rect) : fRect(rect) {}
637
638 int count() const { return 4; }
639
640 void writeValue(int i, GrPoint* dstPoint) const {
641 SkASSERT(i < 4);
642 dstPoint->fX = (i % 3) ? GrIntToScalar(fRect.fRight) :
643 GrIntToScalar(fRect.fLeft);
644 dstPoint->fY = (i < 2) ? GrIntToScalar(fRect.fTop) :
645 GrIntToScalar(fRect.fBottom);
646 }
647private:
648 const SkIRect& fRect;
649};
650
651class SkMatRectFanSource {
652public:
653 SkMatRectFanSource(const SkRect& rect, const SkMatrix& matrix)
654 : fRect(rect), fMatrix(matrix) {}
655
656 int count() const { return 4; }
657
658 void writeValue(int i, GrPoint* dstPoint) const {
659 SkASSERT(i < 4);
660
661#if SK_SCALAR_IS_GR_SCALAR
662 fMatrix.mapXY((i % 3) ? fRect.fRight : fRect.fLeft,
663 (i < 2) ? fRect.fTop : fRect.fBottom,
664 (SkPoint*)dstPoint);
665#else
666 SkPoint dst;
667 fMatrix.mapXY((i % 3) ? fRect.fRight : fRect.fLeft,
668 (i < 2) ? fRect.fTop : fRect.fBottom,
669 &dst);
670 dstPoint->fX = SkScalarToGrScalar(dst.fX);
671 dstPoint->fY = SkScalarToGrScalar(dst.fY);
672#endif
673 }
674private:
675 const SkRect& fRect;
676 const SkMatrix& fMatrix;
677};
678
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000679#endif
680
reed@google.comac10a2d2010-12-22 21:39:39 +0000681///////////////////////////////////////////////////////////////////////////////
682
bsalomon@google.com398109c2011-04-14 18:40:27 +0000683void SkGpuDevice::clear(SkColor color) {
bsalomon@google.com31a58402011-04-27 21:00:02 +0000684 fContext->clear(NULL, color);
bsalomon@google.com398109c2011-04-14 18:40:27 +0000685}
686
reed@google.comac10a2d2010-12-22 21:39:39 +0000687void SkGpuDevice::drawPaint(const SkDraw& draw, const SkPaint& paint) {
688 CHECK_SHOULD_DRAW(draw);
689
bsalomon@google.com5782d712011-01-21 21:03:59 +0000690 GrPaint grPaint;
691 SkAutoCachedTexture act;
Scroggod757df22011-05-16 13:11:16 +0000692 if (!this->skPaint2GrPaintShader(paint,
693 &act,
694 *draw.fMatrix,
695 &grPaint,
696 true)) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000697 return;
698 }
bsalomon@google.com5782d712011-01-21 21:03:59 +0000699
700 fContext->drawPaint(grPaint);
reed@google.comac10a2d2010-12-22 21:39:39 +0000701}
702
703// must be in SkCanvas::PointMode order
bsalomon@google.comffca4002011-02-22 20:34:01 +0000704static const GrPrimitiveType gPointMode2PrimtiveType[] = {
705 kPoints_PrimitiveType,
706 kLines_PrimitiveType,
707 kLineStrip_PrimitiveType
reed@google.comac10a2d2010-12-22 21:39:39 +0000708};
709
710void SkGpuDevice::drawPoints(const SkDraw& draw, SkCanvas::PointMode mode,
bsalomon@google.com5782d712011-01-21 21:03:59 +0000711 size_t count, const SkPoint pts[], const SkPaint& paint) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000712 CHECK_SHOULD_DRAW(draw);
713
714 SkScalar width = paint.getStrokeWidth();
715 if (width < 0) {
716 return;
717 }
718
719 // we only handle hairlines here, else we let the SkDraw call our drawPath()
720 if (width > 0) {
721 draw.drawPoints(mode, count, pts, paint, true);
722 return;
723 }
724
bsalomon@google.com5782d712011-01-21 21:03:59 +0000725 GrPaint grPaint;
726 SkAutoCachedTexture act;
Scroggod757df22011-05-16 13:11:16 +0000727 if (!this->skPaint2GrPaintShader(paint,
728 &act,
729 *draw.fMatrix,
730 &grPaint,
731 true)) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000732 return;
733 }
734
reed@google.comac10a2d2010-12-22 21:39:39 +0000735#if SK_SCALAR_IS_GR_SCALAR
bsalomon@google.com5782d712011-01-21 21:03:59 +0000736 fContext->drawVertices(grPaint,
737 gPointMode2PrimtiveType[mode],
738 count,
739 (GrPoint*)pts,
740 NULL,
741 NULL,
742 NULL,
743 0);
reed@google.comac10a2d2010-12-22 21:39:39 +0000744#else
bsalomon@google.com5782d712011-01-21 21:03:59 +0000745 fContext->drawCustomVertices(grPaint,
746 gPointMode2PrimtiveType[mode],
747 SkPositionSource(pts, count));
reed@google.comac10a2d2010-12-22 21:39:39 +0000748#endif
reed@google.comac10a2d2010-12-22 21:39:39 +0000749}
750
reed@google.comc9aa5872011-04-05 21:05:37 +0000751///////////////////////////////////////////////////////////////////////////////
752
reed@google.comac10a2d2010-12-22 21:39:39 +0000753void SkGpuDevice::drawRect(const SkDraw& draw, const SkRect& rect,
754 const SkPaint& paint) {
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000755 CHECK_SHOULD_DRAW(draw);
756
bungeman@google.com79bd8772011-07-18 15:34:08 +0000757 bool doStroke = paint.getStyle() != SkPaint::kFill_Style;
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000758 SkScalar width = paint.getStrokeWidth();
759
760 /*
761 We have special code for hairline strokes, miter-strokes, and fills.
762 Anything else we just call our path code.
763 */
764 bool usePath = doStroke && width > 0 &&
765 paint.getStrokeJoin() != SkPaint::kMiter_Join;
766 // another reason we might need to call drawPath...
767 if (paint.getMaskFilter()) {
768 usePath = true;
769 }
reed@google.com67db6642011-05-26 11:46:35 +0000770 // until we aa rotated rects...
771 if (!usePath && paint.isAntiAlias() && !draw.fMatrix->rectStaysRect()) {
772 usePath = true;
773 }
bungeman@google.com79bd8772011-07-18 15:34:08 +0000774 // until we can both stroke and fill rectangles
775 // with large enough miter limit...
776 if (paint.getStyle() == SkPaint::kStrokeAndFill_Style) {
777 usePath = true;
778 }
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000779
780 if (usePath) {
781 SkPath path;
782 path.addRect(rect);
783 this->drawPath(draw, path, paint, NULL, true);
784 return;
785 }
786
787 GrPaint grPaint;
788 SkAutoCachedTexture act;
Scroggod757df22011-05-16 13:11:16 +0000789 if (!this->skPaint2GrPaintShader(paint,
790 &act,
791 *draw.fMatrix,
792 &grPaint,
793 true)) {
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000794 return;
795 }
reed@google.com20efde72011-05-09 17:00:02 +0000796 fContext->drawRect(grPaint, rect, doStroke ? width : -1);
reed@google.comac10a2d2010-12-22 21:39:39 +0000797}
798
reed@google.com69302852011-02-16 18:08:07 +0000799#include "SkMaskFilter.h"
800#include "SkBounder.h"
801
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +0000802static GrPathFill skToGrFillType(SkPath::FillType fillType) {
803 switch (fillType) {
804 case SkPath::kWinding_FillType:
805 return kWinding_PathFill;
806 case SkPath::kEvenOdd_FillType:
807 return kEvenOdd_PathFill;
808 case SkPath::kInverseWinding_FillType:
809 return kInverseWinding_PathFill;
810 case SkPath::kInverseEvenOdd_FillType:
811 return kInverseEvenOdd_PathFill;
812 default:
813 SkDebugf("Unsupported path fill type\n");
814 return kHairLine_PathFill;
815 }
816}
817
senorblanco@chromium.orgb08ea1b2011-07-12 16:54:59 +0000818static void buildKernel(float sigma, float* kernel, int kernelWidth) {
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +0000819 int halfWidth = (kernelWidth - 1) / 2;
820 float sum = 0.0f;
senorblanco@chromium.orgb08ea1b2011-07-12 16:54:59 +0000821 float denom = 1.0f / (2.0f * sigma * sigma);
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +0000822 for (int i = 0; i < kernelWidth; ++i) {
senorblanco@chromium.orgb08ea1b2011-07-12 16:54:59 +0000823 float x = static_cast<float>(i - halfWidth);
824 // Note that the constant term (1/(sqrt(2*pi*sigma^2)) of the Gaussian
825 // is dropped here, since we renormalize the kernel below.
826 kernel[i] = sk_float_exp(- x * x * denom);
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +0000827 sum += kernel[i];
828 }
829 // Normalize the kernel
830 float scale = 1.0f / sum;
831 for (int i = 0; i < kernelWidth; ++i)
832 kernel[i] *= scale;
833}
834
senorblanco@chromium.orgb08ea1b2011-07-12 16:54:59 +0000835static void scaleRect(SkRect* rect, float scale) {
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +0000836 rect->fLeft *= scale;
837 rect->fTop *= scale;
838 rect->fRight *= scale;
839 rect->fBottom *= scale;
840}
841
842static bool drawWithGPUMaskFilter(GrContext* context, const SkPath& path,
843 SkMaskFilter* filter, const SkMatrix& matrix,
844 const SkRegion& clip, SkBounder* bounder,
845 GrPaint* grp) {
senorblanco@chromium.orga479fc72011-07-19 16:40:58 +0000846#ifdef SK_DISABLE_GPU_BLUR
senorblanco@chromium.orgaadd9f82011-07-12 19:44:51 +0000847 return false;
senorblanco@chromium.orgb08ea1b2011-07-12 16:54:59 +0000848#endif
senorblanco@chromium.orgaadd9f82011-07-12 19:44:51 +0000849 SkMaskFilter::BlurInfo info;
850 SkMaskFilter::BlurType blurType = filter->asABlur(&info);
senorblanco@chromium.orgb08ea1b2011-07-12 16:54:59 +0000851 if (SkMaskFilter::kNone_BlurType == blurType) {
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +0000852 return false;
853 }
senorblanco@chromium.orge36ddf02011-07-15 14:28:16 +0000854 SkScalar radius = info.fIgnoreTransform ? info.fRadius
855 : matrix.mapRadius(info.fRadius);
856 radius = SkMinScalar(radius, MAX_BLUR_RADIUS);
857 float sigma = SkScalarToFloat(radius) * BLUR_SIGMA_SCALE;
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +0000858 SkRect srcRect = path.getBounds();
859
860 int scaleFactor = 1;
861
senorblanco@chromium.orge36ddf02011-07-15 14:28:16 +0000862 while (sigma > MAX_BLUR_SIGMA) {
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +0000863 scaleFactor *= 2;
864 sigma *= 0.5f;
865 }
866 scaleRect(&srcRect, 1.0f / scaleFactor);
senorblanco@chromium.org4a947d22011-07-18 21:48:35 +0000867 int halfWidth = static_cast<int>(ceilf(sigma * 3.0f));
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +0000868 int kernelWidth = halfWidth * 2 + 1;
869
870 SkIRect srcIRect;
871 srcRect.roundOut(&srcIRect);
872 srcRect.set(srcIRect);
873 srcRect.inset(-halfWidth, -halfWidth);
874
875 scaleRect(&srcRect, scaleFactor);
876 SkRect finalRect = srcRect;
877
878 SkIRect finalIRect;
879 finalRect.roundOut(&finalIRect);
880 if (clip.quickReject(finalIRect)) {
senorblanco@chromium.orgaadd9f82011-07-12 19:44:51 +0000881 return true;
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +0000882 }
883 if (bounder && !bounder->doIRect(finalIRect)) {
senorblanco@chromium.orgaadd9f82011-07-12 19:44:51 +0000884 return true;
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +0000885 }
886 GrPoint offset = GrPoint::Make(-srcRect.fLeft, -srcRect.fTop);
887 srcRect.offset(-srcRect.fLeft, -srcRect.fTop);
888 const GrTextureDesc desc = {
889 kRenderTarget_GrTextureFlagBit,
890 kNone_GrAALevel,
891 srcRect.width(),
892 srcRect.height(),
893 // We actually only need A8, but it often isn't supported as a
894 // render target
895 kRGBA_8888_GrPixelConfig
896 };
897
898 GrTextureEntry* srcEntry = context->findApproximateKeylessTexture(desc);
899 GrTextureEntry* dstEntry = context->findApproximateKeylessTexture(desc);
senorblanco@chromium.orgaadd9f82011-07-12 19:44:51 +0000900 GrAutoUnlockTextureEntry srcLock(context, srcEntry),
901 dstLock(context, dstEntry);
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +0000902 if (NULL == srcEntry || NULL == dstEntry) {
903 return false;
904 }
905 GrTexture* srcTexture = srcEntry->texture();
906 GrTexture* dstTexture = dstEntry->texture();
907 if (NULL == srcTexture || NULL == dstTexture) {
908 return false;
909 }
910 GrRenderTarget* oldRenderTarget = context->getRenderTarget();
senorblanco@chromium.org42dd0f92011-07-14 15:29:57 +0000911 // Once this code moves into GrContext, this should be changed to use
912 // an AutoClipRestore.
913 GrClip oldClip = context->getClip();
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +0000914 context->setRenderTarget(dstTexture->asRenderTarget());
senorblanco@chromium.org42dd0f92011-07-14 15:29:57 +0000915 context->setClip(srcRect);
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +0000916 context->clear(NULL, 0);
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +0000917 GrPaint tempPaint;
918 tempPaint.reset();
919
920 GrAutoMatrix avm(context, GrMatrix::I());
senorblanco@chromium.orgb08ea1b2011-07-12 16:54:59 +0000921 tempPaint.fAntiAlias = grp->fAntiAlias;
922 if (tempPaint.fAntiAlias) {
923 // AA uses the "coverage" stages on GrDrawTarget. Coverage with a dst
924 // blend coeff of zero requires dual source blending support in order
925 // to properly blend partially covered pixels. This means the AA
926 // code path may not be taken. So we use a dst blend coeff of ISA. We
927 // could special case AA draws to a dst surface with known alpha=0 to
928 // use a zero dst coeff when dual source blending isn't available.
929 tempPaint.fSrcBlendCoeff = kOne_BlendCoeff;
930 tempPaint.fDstBlendCoeff = kISC_BlendCoeff;
931 }
932 // Draw hard shadow to dstTexture with path topleft at origin 0,0.
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +0000933 context->drawPath(tempPaint, path, skToGrFillType(path.getFillType()), &offset);
senorblanco@chromium.orgb08ea1b2011-07-12 16:54:59 +0000934 SkTSwap(srcTexture, dstTexture);
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +0000935
936 GrMatrix sampleM;
senorblanco@chromium.org422b67d2011-07-19 21:22:13 +0000937 sampleM.setIDiv(srcTexture->width(), srcTexture->height());
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +0000938 GrPaint paint;
939 paint.reset();
940 paint.getTextureSampler(0)->setFilter(GrSamplerState::kBilinear_Filter);
941 paint.getTextureSampler(0)->setMatrix(sampleM);
senorblanco@chromium.orgb08ea1b2011-07-12 16:54:59 +0000942 GrTextureEntry* origEntry = NULL;
943 if (blurType != SkMaskFilter::kNormal_BlurType) {
944 // Stash away a copy of the unblurred image.
945 origEntry = context->findApproximateKeylessTexture(desc);
946 if (NULL == origEntry) {
947 return false;
948 }
949 context->setRenderTarget(origEntry->texture()->asRenderTarget());
950 paint.setTexture(0, srcTexture);
951 context->drawRect(paint, srcRect);
952 }
senorblanco@chromium.orgaadd9f82011-07-12 19:44:51 +0000953 GrAutoUnlockTextureEntry origLock(context, origEntry);
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +0000954 for (int i = 1; i < scaleFactor; i *= 2) {
senorblanco@chromium.org422b67d2011-07-19 21:22:13 +0000955 sampleM.setIDiv(srcTexture->width(), srcTexture->height());
956 paint.getTextureSampler(0)->setMatrix(sampleM);
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +0000957 context->setRenderTarget(dstTexture->asRenderTarget());
958 SkRect dstRect(srcRect);
959 scaleRect(&dstRect, 0.5f);
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +0000960 paint.setTexture(0, srcTexture);
961 context->drawRectToRect(paint, dstRect, srcRect);
962 srcRect = dstRect;
senorblanco@chromium.orgb08ea1b2011-07-12 16:54:59 +0000963 SkTSwap(srcTexture, dstTexture);
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +0000964 }
965
966 SkAutoTMalloc<float> kernelStorage(kernelWidth);
967 float* kernel = kernelStorage.get();
968 buildKernel(sigma, kernel, kernelWidth);
969
senorblanco@chromium.org2ce9a042011-07-22 15:31:14 +0000970 // Clear out a halfWidth to the right of the srcRect to prevent the
971 // X convolution from reading garbage.
972 SkIRect clearRect = SkIRect::MakeXYWH(
973 srcRect.fRight, srcRect.fTop, halfWidth, srcRect.height());
974 context->clear(&clearRect, 0x0);
975
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +0000976 context->setRenderTarget(dstTexture->asRenderTarget());
senorblanco@chromium.orgaadd9f82011-07-12 19:44:51 +0000977 context->convolveInX(srcTexture, srcRect, kernel, kernelWidth);
senorblanco@chromium.orgb08ea1b2011-07-12 16:54:59 +0000978 SkTSwap(srcTexture, dstTexture);
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +0000979
senorblanco@chromium.org2ce9a042011-07-22 15:31:14 +0000980 // Clear out a halfWidth below the srcRect to prevent the Y
981 // convolution from reading garbage.
982 clearRect = SkIRect::MakeXYWH(
983 srcRect.fLeft, srcRect.fBottom, srcRect.width(), halfWidth);
984 context->clear(&clearRect, 0x0);
985
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +0000986 context->setRenderTarget(dstTexture->asRenderTarget());
senorblanco@chromium.orgaadd9f82011-07-12 19:44:51 +0000987 context->convolveInY(srcTexture, srcRect, kernel, kernelWidth);
senorblanco@chromium.orgb08ea1b2011-07-12 16:54:59 +0000988 SkTSwap(srcTexture, dstTexture);
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +0000989
senorblanco@chromium.org2ce9a042011-07-22 15:31:14 +0000990 // Clear one pixel to the right and below, to accommodate bilinear
991 // upsampling.
992 clearRect = SkIRect::MakeXYWH(
993 srcRect.fLeft, srcRect.fBottom, srcRect.width() + 1, 1);
994 context->clear(&clearRect, 0x0);
995 clearRect = SkIRect::MakeXYWH(
996 srcRect.fRight, srcRect.fTop, 1, srcRect.height());
997 context->clear(&clearRect, 0x0);
998
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +0000999 if (scaleFactor > 1) {
1000 // FIXME: This should be mitchell, not bilinear.
1001 paint.getTextureSampler(0)->setFilter(GrSamplerState::kBilinear_Filter);
senorblanco@chromium.org422b67d2011-07-19 21:22:13 +00001002 sampleM.setIDiv(srcTexture->width(), srcTexture->height());
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +00001003 paint.getTextureSampler(0)->setMatrix(sampleM);
1004 context->setRenderTarget(dstTexture->asRenderTarget());
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +00001005 paint.setTexture(0, srcTexture);
1006 SkRect dstRect(srcRect);
1007 scaleRect(&dstRect, scaleFactor);
1008 context->drawRectToRect(paint, dstRect, srcRect);
1009 srcRect = dstRect;
senorblanco@chromium.orgb08ea1b2011-07-12 16:54:59 +00001010 SkTSwap(srcTexture, dstTexture);
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +00001011 }
1012
senorblanco@chromium.orgb08ea1b2011-07-12 16:54:59 +00001013 if (blurType != SkMaskFilter::kNormal_BlurType) {
1014 GrTexture* origTexture = origEntry->texture();
1015 paint.getTextureSampler(0)->setFilter(GrSamplerState::kNearest_Filter);
senorblanco@chromium.org422b67d2011-07-19 21:22:13 +00001016 sampleM.setIDiv(origTexture->width(), origTexture->height());
senorblanco@chromium.orgb08ea1b2011-07-12 16:54:59 +00001017 paint.getTextureSampler(0)->setMatrix(sampleM);
1018 // Blend origTexture over srcTexture.
1019 context->setRenderTarget(srcTexture->asRenderTarget());
1020 paint.setTexture(0, origTexture);
1021 if (SkMaskFilter::kInner_BlurType == blurType) {
1022 // inner: dst = dst * src
1023 paint.fSrcBlendCoeff = kDC_BlendCoeff;
1024 paint.fDstBlendCoeff = kZero_BlendCoeff;
1025 } else if (SkMaskFilter::kSolid_BlurType == blurType) {
1026 // solid: dst = src + dst - src * dst
1027 // = (1 - dst) * src + 1 * dst
1028 paint.fSrcBlendCoeff = kIDC_BlendCoeff;
1029 paint.fDstBlendCoeff = kOne_BlendCoeff;
1030 } else if (SkMaskFilter::kOuter_BlurType == blurType) {
1031 // outer: dst = dst * (1 - src)
1032 // = 0 * src + (1 - src) * dst
1033 paint.fSrcBlendCoeff = kZero_BlendCoeff;
1034 paint.fDstBlendCoeff = kISC_BlendCoeff;
1035 }
1036 context->drawRect(paint, srcRect);
1037 }
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +00001038 context->setRenderTarget(oldRenderTarget);
senorblanco@chromium.org42dd0f92011-07-14 15:29:57 +00001039 context->setClip(oldClip);
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +00001040
1041 if (grp->hasTextureOrMask()) {
1042 GrMatrix inverse;
1043 if (!matrix.invert(&inverse)) {
1044 return false;
1045 }
1046 grp->preConcatActiveSamplerMatrices(inverse);
1047 }
1048
1049 static const int MASK_IDX = GrPaint::kMaxMasks - 1;
1050 // we assume the last mask index is available for use
1051 GrAssert(NULL == grp->getMask(MASK_IDX));
1052 grp->setMask(MASK_IDX, srcTexture);
1053 grp->getMaskSampler(MASK_IDX)->setClampNoFilter();
1054
1055 GrMatrix m;
1056 m.setTranslate(-finalRect.fLeft, -finalRect.fTop);
1057 m.postIDiv(srcTexture->width(), srcTexture->height());
1058 grp->getMaskSampler(MASK_IDX)->setMatrix(m);
1059 context->drawRect(*grp, finalRect);
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +00001060 return true;
1061}
1062
reed@google.com69302852011-02-16 18:08:07 +00001063static bool drawWithMaskFilter(GrContext* context, const SkPath& path,
1064 SkMaskFilter* filter, const SkMatrix& matrix,
1065 const SkRegion& clip, SkBounder* bounder,
1066 GrPaint* grp) {
1067 SkMask srcM, dstM;
1068
1069 if (!SkDraw::DrawToMask(path, &clip.getBounds(), filter, &matrix, &srcM,
1070 SkMask::kComputeBoundsAndRenderImage_CreateMode)) {
1071 return false;
1072 }
1073
1074 SkAutoMaskImage autoSrc(&srcM, false);
1075
1076 if (!filter->filterMask(&dstM, srcM, matrix, NULL)) {
1077 return false;
1078 }
1079 // this will free-up dstM when we're done (allocated in filterMask())
1080 SkAutoMaskImage autoDst(&dstM, false);
1081
1082 if (clip.quickReject(dstM.fBounds)) {
1083 return false;
1084 }
1085 if (bounder && !bounder->doIRect(dstM.fBounds)) {
1086 return false;
1087 }
1088
1089 // we now have a device-aligned 8bit mask in dstM, ready to be drawn using
1090 // the current clip (and identity matrix) and grpaint settings
1091
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001092 // used to compute inverse view, if necessary
1093 GrMatrix ivm = context->getMatrix();
1094
reed@google.com0c219b62011-02-16 21:31:18 +00001095 GrAutoMatrix avm(context, GrMatrix::I());
reed@google.com69302852011-02-16 18:08:07 +00001096
bsalomon@google.comfea37b52011-04-25 15:51:06 +00001097 const GrTextureDesc desc = {
1098 kNone_GrTextureFlags,
1099 kNone_GrAALevel,
reed@google.com69302852011-02-16 18:08:07 +00001100 dstM.fBounds.width(),
1101 dstM.fBounds.height(),
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001102 kAlpha_8_GrPixelConfig
reed@google.com69302852011-02-16 18:08:07 +00001103 };
1104
bsalomon@google.comeb2aa1d2011-07-14 15:45:19 +00001105 GrAutoUnlockTextureEntry aute(context,
1106 context->findApproximateKeylessTexture(desc));
1107 GrTexture* texture = aute.texture();
1108
reed@google.com69302852011-02-16 18:08:07 +00001109 if (NULL == texture) {
1110 return false;
1111 }
bsalomon@google.comeb2aa1d2011-07-14 15:45:19 +00001112 texture->uploadTextureData(0, 0, desc.fWidth, desc.fHeight,
1113 dstM.fImage, dstM.fRowBytes);
reed@google.com69302852011-02-16 18:08:07 +00001114
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001115 if (grp->hasTextureOrMask() && ivm.invert(&ivm)) {
1116 grp->preConcatActiveSamplerMatrices(ivm);
1117 }
1118
1119 static const int MASK_IDX = GrPaint::kMaxMasks - 1;
1120 // we assume the last mask index is available for use
1121 GrAssert(NULL == grp->getMask(MASK_IDX));
1122 grp->setMask(MASK_IDX, texture);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001123 grp->getMaskSampler(MASK_IDX)->setClampNoFilter();
reed@google.com69302852011-02-16 18:08:07 +00001124
bsalomon@google.comc6cf7232011-02-17 16:43:10 +00001125 GrRect d;
1126 d.setLTRB(GrIntToScalar(dstM.fBounds.fLeft),
reed@google.com0c219b62011-02-16 21:31:18 +00001127 GrIntToScalar(dstM.fBounds.fTop),
1128 GrIntToScalar(dstM.fBounds.fRight),
1129 GrIntToScalar(dstM.fBounds.fBottom));
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001130
1131 GrMatrix m;
1132 m.setTranslate(-dstM.fBounds.fLeft, -dstM.fBounds.fTop);
bsalomon@google.comeb2aa1d2011-07-14 15:45:19 +00001133 m.postIDiv(texture->width(), texture->height());
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001134 grp->getMaskSampler(MASK_IDX)->setMatrix(m);
1135
1136 context->drawRect(*grp, d);
reed@google.com69302852011-02-16 18:08:07 +00001137 return true;
1138}
reed@google.com69302852011-02-16 18:08:07 +00001139
reed@google.com0c219b62011-02-16 21:31:18 +00001140void SkGpuDevice::drawPath(const SkDraw& draw, const SkPath& origSrcPath,
reed@google.comac10a2d2010-12-22 21:39:39 +00001141 const SkPaint& paint, const SkMatrix* prePathMatrix,
1142 bool pathIsMutable) {
1143 CHECK_SHOULD_DRAW(draw);
1144
bsalomon@google.com5782d712011-01-21 21:03:59 +00001145 GrPaint grPaint;
1146 SkAutoCachedTexture act;
Scroggod757df22011-05-16 13:11:16 +00001147 if (!this->skPaint2GrPaintShader(paint,
1148 &act,
1149 *draw.fMatrix,
1150 &grPaint,
1151 true)) {
reed@google.comac10a2d2010-12-22 21:39:39 +00001152 return;
1153 }
1154
reed@google.com0c219b62011-02-16 21:31:18 +00001155 // BEGIN lift from SkDraw::drawPath()
1156
1157 SkPath* pathPtr = const_cast<SkPath*>(&origSrcPath);
1158 bool doFill = true;
1159 SkPath tmpPath;
reed@google.comac10a2d2010-12-22 21:39:39 +00001160
1161 if (prePathMatrix) {
reed@google.come3445642011-02-16 23:20:39 +00001162 SkPath* result = pathPtr;
reed@google.com0c219b62011-02-16 21:31:18 +00001163
reed@google.come3445642011-02-16 23:20:39 +00001164 if (!pathIsMutable) {
1165 result = &tmpPath;
1166 pathIsMutable = true;
reed@google.comac10a2d2010-12-22 21:39:39 +00001167 }
reed@google.come3445642011-02-16 23:20:39 +00001168 // should I push prePathMatrix on our MV stack temporarily, instead
1169 // of applying it here? See SkDraw.cpp
1170 pathPtr->transform(*prePathMatrix, result);
1171 pathPtr = result;
reed@google.comac10a2d2010-12-22 21:39:39 +00001172 }
reed@google.com0c219b62011-02-16 21:31:18 +00001173 // at this point we're done with prePathMatrix
1174 SkDEBUGCODE(prePathMatrix = (const SkMatrix*)0x50FF8001;)
reed@google.comac10a2d2010-12-22 21:39:39 +00001175
bsalomon@google.com04de7822011-03-25 18:04:43 +00001176 // This "if" is not part of the SkDraw::drawPath() lift.
1177 // When we get a 1.0 wide stroke we hairline stroke it instead of creating
1178 // a new stroked-path. This is motivated by canvas2D sites that draw
1179 // lines as 1.0 wide stroked paths. We can consider doing an alpha-modulated-
1180 // hairline for width < 1.0 when AA is enabled.
1181 static const int gMatrixMask = ~(SkMatrix::kIdentity_Mask |
1182 SkMatrix::kTranslate_Mask);
1183 if (!paint.getPathEffect() &&
1184 SkPaint::kStroke_Style == paint.getStyle() &&
1185 !(draw.fMatrix->getType() & gMatrixMask) &&
1186 SK_Scalar1 == paint.getStrokeWidth()) {
1187 doFill = false;
1188 }
1189
1190 if (doFill && (paint.getPathEffect() ||
1191 paint.getStyle() != SkPaint::kFill_Style)) {
reed@google.com0c219b62011-02-16 21:31:18 +00001192 doFill = paint.getFillPath(*pathPtr, &tmpPath);
1193 pathPtr = &tmpPath;
1194 }
1195
1196 // END lift from SkDraw::drawPath()
1197
reed@google.com69302852011-02-16 18:08:07 +00001198 if (paint.getMaskFilter()) {
reed@google.com0c219b62011-02-16 21:31:18 +00001199 // avoid possibly allocating a new path in transform if we can
1200 SkPath* devPathPtr = pathIsMutable ? pathPtr : &tmpPath;
1201
1202 // transform the path into device space
reed@google.come3445642011-02-16 23:20:39 +00001203 pathPtr->transform(*draw.fMatrix, devPathPtr);
senorblanco@chromium.orgb08ea1b2011-07-12 16:54:59 +00001204 if (!drawWithGPUMaskFilter(fContext, *devPathPtr, paint.getMaskFilter(),
1205 *draw.fMatrix, *draw.fClip, draw.fBounder,
1206 &grPaint)) {
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +00001207 drawWithMaskFilter(fContext, *devPathPtr, paint.getMaskFilter(),
1208 *draw.fMatrix, *draw.fClip, draw.fBounder,
1209 &grPaint);
1210 }
reed@google.com69302852011-02-16 18:08:07 +00001211 return;
1212 }
reed@google.com69302852011-02-16 18:08:07 +00001213
bsalomon@google.comffca4002011-02-22 20:34:01 +00001214 GrPathFill fill = kHairLine_PathFill;
reed@google.comac10a2d2010-12-22 21:39:39 +00001215
reed@google.com0c219b62011-02-16 21:31:18 +00001216 if (doFill) {
1217 switch (pathPtr->getFillType()) {
reed@google.comac10a2d2010-12-22 21:39:39 +00001218 case SkPath::kWinding_FillType:
bsalomon@google.comffca4002011-02-22 20:34:01 +00001219 fill = kWinding_PathFill;
reed@google.comac10a2d2010-12-22 21:39:39 +00001220 break;
1221 case SkPath::kEvenOdd_FillType:
bsalomon@google.comffca4002011-02-22 20:34:01 +00001222 fill = kEvenOdd_PathFill;
reed@google.comac10a2d2010-12-22 21:39:39 +00001223 break;
1224 case SkPath::kInverseWinding_FillType:
bsalomon@google.comffca4002011-02-22 20:34:01 +00001225 fill = kInverseWinding_PathFill;
reed@google.comac10a2d2010-12-22 21:39:39 +00001226 break;
1227 case SkPath::kInverseEvenOdd_FillType:
bsalomon@google.comffca4002011-02-22 20:34:01 +00001228 fill = kInverseEvenOdd_PathFill;
reed@google.comac10a2d2010-12-22 21:39:39 +00001229 break;
1230 default:
bsalomon@google.com5782d712011-01-21 21:03:59 +00001231 SkDebugf("Unsupported path fill type\n");
reed@google.comac10a2d2010-12-22 21:39:39 +00001232 return;
1233 }
1234 }
1235
reed@google.com07f3ee12011-05-16 17:21:57 +00001236 fContext->drawPath(grPaint, *pathPtr, fill);
reed@google.comac10a2d2010-12-22 21:39:39 +00001237}
1238
reed@google.comac10a2d2010-12-22 21:39:39 +00001239void SkGpuDevice::drawBitmap(const SkDraw& draw,
1240 const SkBitmap& bitmap,
1241 const SkIRect* srcRectPtr,
1242 const SkMatrix& m,
1243 const SkPaint& paint) {
1244 CHECK_SHOULD_DRAW(draw);
1245
1246 SkIRect srcRect;
1247 if (NULL == srcRectPtr) {
1248 srcRect.set(0, 0, bitmap.width(), bitmap.height());
1249 } else {
1250 srcRect = *srcRectPtr;
1251 }
1252
junov@google.comd935cfb2011-06-27 20:48:23 +00001253 if (paint.getMaskFilter()){
epoger@google.com9ef2d832011-07-01 21:12:20 +00001254 SkBitmap tmp; // storage if we need a subset of bitmap
junov@google.comd935cfb2011-06-27 20:48:23 +00001255 const SkBitmap* bitmapPtr = &bitmap;
epoger@google.com9ef2d832011-07-01 21:12:20 +00001256 if (srcRectPtr) {
1257 if (!bitmap.extractSubset(&tmp, srcRect)) {
1258 return; // extraction failed
1259 }
1260 bitmapPtr = &tmp;
junov@google.comd935cfb2011-06-27 20:48:23 +00001261 }
1262 SkPaint paintWithTexture(paint);
1263 paintWithTexture.setShader(SkShader::CreateBitmapShader( *bitmapPtr,
1264 SkShader::kClamp_TileMode, SkShader::kClamp_TileMode))->unref();
1265 paintWithTexture.getShader()->setLocalMatrix(m);
1266
1267 SkRect ScalarRect;
epoger@google.com9ef2d832011-07-01 21:12:20 +00001268 ScalarRect.set(srcRect);
junov@google.comd935cfb2011-06-27 20:48:23 +00001269
epoger@google.com9ef2d832011-07-01 21:12:20 +00001270 if (m.rectStaysRect()) {
1271 // Preferred drawing method, optimized for rectangles
1272 m.mapRect(&ScalarRect);
1273 this->drawRect(draw, ScalarRect, paintWithTexture);
1274 } else {
1275 // Slower drawing method, for warped or rotated rectangles
1276 SkPath path;
1277 path.addRect(ScalarRect);
1278 path.transform(m);
1279 this->drawPath(draw, path, paintWithTexture, NULL, true);
1280 }
junov@google.comd935cfb2011-06-27 20:48:23 +00001281 return;
1282 }
1283
bsalomon@google.com5782d712011-01-21 21:03:59 +00001284 GrPaint grPaint;
Scroggod757df22011-05-16 13:11:16 +00001285 if (!this->skPaint2GrPaintNoShader(paint, true, &grPaint, false)) {
bsalomon@google.com5782d712011-01-21 21:03:59 +00001286 return;
1287 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001288 GrSamplerState* sampler = grPaint.getTextureSampler(kBitmapTextureIdx);
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +00001289 if (paint.isFilterBitmap()) {
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001290 sampler->setFilter(GrSamplerState::kBilinear_Filter);
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +00001291 } else {
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001292 sampler->setFilter(GrSamplerState::kNearest_Filter);
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +00001293 }
bsalomon@google.com5782d712011-01-21 21:03:59 +00001294
bsalomon@google.com91958362011-06-13 17:58:13 +00001295 const int maxTextureSize = fContext->getMaxTextureSize();
1296 if (bitmap.getTexture() || (bitmap.width() <= maxTextureSize &&
1297 bitmap.height() <= maxTextureSize)) {
reed@google.comac10a2d2010-12-22 21:39:39 +00001298 // take the fast case
bsalomon@google.com5782d712011-01-21 21:03:59 +00001299 this->internalDrawBitmap(draw, bitmap, srcRect, m, &grPaint);
reed@google.comac10a2d2010-12-22 21:39:39 +00001300 return;
1301 }
1302
1303 // undo the translate done by SkCanvas
1304 int DX = SkMax32(0, srcRect.fLeft);
1305 int DY = SkMax32(0, srcRect.fTop);
1306 // compute clip bounds in local coordinates
1307 SkIRect clipRect;
1308 {
1309 SkRect r;
1310 r.set(draw.fClip->getBounds());
1311 SkMatrix matrix, inverse;
1312 matrix.setConcat(*draw.fMatrix, m);
1313 if (!matrix.invert(&inverse)) {
1314 return;
1315 }
1316 inverse.mapRect(&r);
1317 r.roundOut(&clipRect);
1318 // apply the canvas' translate to our local clip
1319 clipRect.offset(DX, DY);
1320 }
1321
bsalomon@google.com91958362011-06-13 17:58:13 +00001322 int nx = bitmap.width() / maxTextureSize;
1323 int ny = bitmap.height() / maxTextureSize;
reed@google.comac10a2d2010-12-22 21:39:39 +00001324 for (int x = 0; x <= nx; x++) {
1325 for (int y = 0; y <= ny; y++) {
1326 SkIRect tileR;
bsalomon@google.com91958362011-06-13 17:58:13 +00001327 tileR.set(x * maxTextureSize, y * maxTextureSize,
1328 (x + 1) * maxTextureSize, (y + 1) * maxTextureSize);
reed@google.comac10a2d2010-12-22 21:39:39 +00001329 if (!SkIRect::Intersects(tileR, clipRect)) {
1330 continue;
1331 }
1332
1333 SkIRect srcR = tileR;
1334 if (!srcR.intersect(srcRect)) {
1335 continue;
1336 }
1337
1338 SkBitmap tmpB;
1339 if (bitmap.extractSubset(&tmpB, tileR)) {
1340 // now offset it to make it "local" to our tmp bitmap
1341 srcR.offset(-tileR.fLeft, -tileR.fTop);
1342
1343 SkMatrix tmpM(m);
1344 {
1345 int dx = tileR.fLeft - DX + SkMax32(0, srcR.fLeft);
1346 int dy = tileR.fTop - DY + SkMax32(0, srcR.fTop);
1347 tmpM.preTranslate(SkIntToScalar(dx), SkIntToScalar(dy));
1348 }
bsalomon@google.com5782d712011-01-21 21:03:59 +00001349 this->internalDrawBitmap(draw, tmpB, srcR, tmpM, &grPaint);
reed@google.comac10a2d2010-12-22 21:39:39 +00001350 }
1351 }
1352 }
1353}
1354
1355/*
1356 * This is called by drawBitmap(), which has to handle images that may be too
1357 * large to be represented by a single texture.
1358 *
bsalomon@google.com5782d712011-01-21 21:03:59 +00001359 * internalDrawBitmap assumes that the specified bitmap will fit in a texture
1360 * and that non-texture portion of the GrPaint has already been setup.
reed@google.comac10a2d2010-12-22 21:39:39 +00001361 */
1362void SkGpuDevice::internalDrawBitmap(const SkDraw& draw,
1363 const SkBitmap& bitmap,
1364 const SkIRect& srcRect,
1365 const SkMatrix& m,
bsalomon@google.com5782d712011-01-21 21:03:59 +00001366 GrPaint* grPaint) {
bsalomon@google.com91958362011-06-13 17:58:13 +00001367 SkASSERT(bitmap.width() <= fContext->getMaxTextureSize() &&
1368 bitmap.height() <= fContext->getMaxTextureSize());
reed@google.comac10a2d2010-12-22 21:39:39 +00001369
reed@google.com9c49bc32011-07-07 13:42:37 +00001370 SkAutoLockPixels alp(bitmap, !bitmap.getTexture());
reed@google.comac10a2d2010-12-22 21:39:39 +00001371 if (!bitmap.getTexture() && !bitmap.readyToDraw()) {
reed@google.com9c49bc32011-07-07 13:42:37 +00001372 SkDebugf("nothing to draw\n");
reed@google.comac10a2d2010-12-22 21:39:39 +00001373 return;
1374 }
1375
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001376 GrSamplerState* sampler = grPaint->getTextureSampler(kBitmapTextureIdx);
1377
1378 sampler->setWrapX(GrSamplerState::kClamp_WrapMode);
1379 sampler->setWrapY(GrSamplerState::kClamp_WrapMode);
1380 sampler->setSampleMode(GrSamplerState::kNormal_SampleMode);
1381 sampler->setMatrix(GrMatrix::I());
reed@google.comac10a2d2010-12-22 21:39:39 +00001382
1383 GrTexture* texture;
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001384 SkAutoCachedTexture act(this, bitmap, *sampler, &texture);
reed@google.comac10a2d2010-12-22 21:39:39 +00001385 if (NULL == texture) {
1386 return;
1387 }
1388
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001389 grPaint->setTexture(kShaderTextureIdx, texture);
reed@google.com46799cd2011-02-22 20:56:26 +00001390
reed@google.com20efde72011-05-09 17:00:02 +00001391 GrRect dstRect = SkRect::MakeWH(GrIntToScalar(srcRect.width()),
1392 GrIntToScalar(srcRect.height()));
bsalomon@google.comc6cf7232011-02-17 16:43:10 +00001393 GrRect paintRect;
junov@google.com6acc9b32011-05-16 18:32:07 +00001394 paintRect.setLTRB(GrFixedToScalar((srcRect.fLeft << 16) / bitmap.width()),
1395 GrFixedToScalar((srcRect.fTop << 16) / bitmap.height()),
1396 GrFixedToScalar((srcRect.fRight << 16) / bitmap.width()),
bsalomon@google.comc6cf7232011-02-17 16:43:10 +00001397 GrFixedToScalar((srcRect.fBottom << 16) / bitmap.height()));
reed@google.comac10a2d2010-12-22 21:39:39 +00001398
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001399 if (GrSamplerState::kNearest_Filter != sampler->getFilter() &&
junov@google.com6acc9b32011-05-16 18:32:07 +00001400 (srcRect.width() < bitmap.width() ||
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001401 srcRect.height() < bitmap.height())) {
junov@google.com6acc9b32011-05-16 18:32:07 +00001402 // If drawing a subrect of the bitmap and filtering is enabled,
1403 // use a constrained texture domain to avoid color bleeding
1404 GrScalar left, top, right, bottom;
1405 if (srcRect.width() > 1) {
1406 GrScalar border = GR_ScalarHalf / bitmap.width();
1407 left = paintRect.left() + border;
1408 right = paintRect.right() - border;
1409 } else {
1410 left = right = GrScalarHalf(paintRect.left() + paintRect.right());
1411 }
1412 if (srcRect.height() > 1) {
1413 GrScalar border = GR_ScalarHalf / bitmap.height();
1414 top = paintRect.top() + border;
1415 bottom = paintRect.bottom() - border;
1416 } else {
1417 top = bottom = GrScalarHalf(paintRect.top() + paintRect.bottom());
1418 }
1419 GrRect textureDomain;
1420 textureDomain.setLTRB(left, top, right, bottom);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001421 sampler->setTextureDomain(textureDomain);
junov@google.com6acc9b32011-05-16 18:32:07 +00001422 }
1423
bsalomon@google.comcc4dac32011-05-10 13:52:42 +00001424 fContext->drawRectToRect(*grPaint, dstRect, paintRect, &m);
reed@google.comac10a2d2010-12-22 21:39:39 +00001425}
1426
1427void SkGpuDevice::drawSprite(const SkDraw& draw, const SkBitmap& bitmap,
1428 int left, int top, const SkPaint& paint) {
1429 CHECK_SHOULD_DRAW(draw);
1430
1431 SkAutoLockPixels alp(bitmap);
1432 if (!bitmap.getTexture() && !bitmap.readyToDraw()) {
1433 return;
1434 }
1435
bsalomon@google.com5782d712011-01-21 21:03:59 +00001436 GrPaint grPaint;
Scroggod757df22011-05-16 13:11:16 +00001437 if(!this->skPaint2GrPaintNoShader(paint, true, &grPaint, false)) {
bsalomon@google.com5782d712011-01-21 21:03:59 +00001438 return;
1439 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001440
bsalomon@google.com5782d712011-01-21 21:03:59 +00001441 GrAutoMatrix avm(fContext, GrMatrix::I());
1442
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001443 GrSamplerState* sampler = grPaint.getTextureSampler(kBitmapTextureIdx);
bsalomon@google.com5782d712011-01-21 21:03:59 +00001444
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001445 GrTexture* texture;
1446 sampler->setClampNoFilter();
1447 SkAutoCachedTexture act(this, bitmap, *sampler, &texture);
1448
1449 grPaint.setTexture(kBitmapTextureIdx, texture);
bsalomon@google.com5782d712011-01-21 21:03:59 +00001450
bsalomon@google.com5782d712011-01-21 21:03:59 +00001451 fContext->drawRectToRect(grPaint,
reed@google.com20efde72011-05-09 17:00:02 +00001452 GrRect::MakeXYWH(GrIntToScalar(left),
1453 GrIntToScalar(top),
1454 GrIntToScalar(bitmap.width()),
1455 GrIntToScalar(bitmap.height())),
1456 GrRect::MakeWH(GR_Scalar1, GR_Scalar1));
reed@google.comac10a2d2010-12-22 21:39:39 +00001457}
1458
1459void SkGpuDevice::drawDevice(const SkDraw& draw, SkDevice* dev,
1460 int x, int y, const SkPaint& paint) {
1461 CHECK_SHOULD_DRAW(draw);
1462
bsalomon@google.com5782d712011-01-21 21:03:59 +00001463 GrPaint grPaint;
bsalomon@google.comc6cf7232011-02-17 16:43:10 +00001464 if (!((SkGpuDevice*)dev)->bindDeviceAsTexture(&grPaint) ||
Scroggod757df22011-05-16 13:11:16 +00001465 !this->skPaint2GrPaintNoShader(paint, true, &grPaint, false)) {
bsalomon@google.com5782d712011-01-21 21:03:59 +00001466 return;
reed@google.comac10a2d2010-12-22 21:39:39 +00001467 }
bsalomon@google.com5782d712011-01-21 21:03:59 +00001468
bsalomon@google.comb5b31682011-06-16 18:05:35 +00001469 GrTexture* devTex = grPaint.getTexture(0);
1470 SkASSERT(NULL != devTex);
bsalomon@google.com5782d712011-01-21 21:03:59 +00001471
1472 const SkBitmap& bm = dev->accessBitmap(false);
1473 int w = bm.width();
1474 int h = bm.height();
1475
1476 GrAutoMatrix avm(fContext, GrMatrix::I());
1477
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001478 grPaint.getTextureSampler(kBitmapTextureIdx)->setClampNoFilter();
bsalomon@google.com5782d712011-01-21 21:03:59 +00001479
bsalomon@google.comb5b31682011-06-16 18:05:35 +00001480 GrRect dstRect = GrRect::MakeXYWH(GrIntToScalar(x),
1481 GrIntToScalar(y),
1482 GrIntToScalar(w),
1483 GrIntToScalar(h));
1484 // The device being drawn may not fill up its texture (saveLayer uses
1485 // the approximate ).
1486 GrRect srcRect = GrRect::MakeWH(GR_Scalar1 * w / devTex->width(),
1487 GR_Scalar1 * h / devTex->height());
1488
1489 fContext->drawRectToRect(grPaint, dstRect, srcRect);
reed@google.comac10a2d2010-12-22 21:39:39 +00001490}
1491
1492///////////////////////////////////////////////////////////////////////////////
1493
1494// must be in SkCanvas::VertexMode order
bsalomon@google.comffca4002011-02-22 20:34:01 +00001495static const GrPrimitiveType gVertexMode2PrimitiveType[] = {
1496 kTriangles_PrimitiveType,
1497 kTriangleStrip_PrimitiveType,
1498 kTriangleFan_PrimitiveType,
reed@google.comac10a2d2010-12-22 21:39:39 +00001499};
1500
1501void SkGpuDevice::drawVertices(const SkDraw& draw, SkCanvas::VertexMode vmode,
1502 int vertexCount, const SkPoint vertices[],
1503 const SkPoint texs[], const SkColor colors[],
1504 SkXfermode* xmode,
1505 const uint16_t indices[], int indexCount,
1506 const SkPaint& paint) {
1507 CHECK_SHOULD_DRAW(draw);
1508
bsalomon@google.com5782d712011-01-21 21:03:59 +00001509 GrPaint grPaint;
1510 SkAutoCachedTexture act;
1511 // we ignore the shader if texs is null.
1512 if (NULL == texs) {
Scroggod757df22011-05-16 13:11:16 +00001513 if (!this->skPaint2GrPaintNoShader(paint,
1514 false,
1515 &grPaint,
1516 NULL == colors)) {
reed@google.comac10a2d2010-12-22 21:39:39 +00001517 return;
1518 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001519 } else {
reed@google.com1a2e8d22011-01-21 22:08:29 +00001520 if (!this->skPaint2GrPaintShader(paint, &act,
1521 *draw.fMatrix,
Scroggod757df22011-05-16 13:11:16 +00001522 &grPaint,
1523 NULL == colors)) {
bsalomon@google.com5782d712011-01-21 21:03:59 +00001524 return;
1525 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001526 }
bsalomon@google.com5782d712011-01-21 21:03:59 +00001527
1528 if (NULL != xmode && NULL != texs && NULL != colors) {
1529 SkXfermode::Mode mode;
1530 if (!SkXfermode::IsMode(xmode, &mode) ||
1531 SkXfermode::kMultiply_Mode != mode) {
1532 SkDebugf("Unsupported vertex-color/texture xfer mode.\n");
1533#if 0
1534 return
1535#endif
1536 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001537 }
bsalomon@google.com5782d712011-01-21 21:03:59 +00001538
1539#if SK_SCALAR_IS_GR_SCALAR
1540 // even if GrColor and SkColor byte offsets match we need
1541 // to perform pre-multiply.
1542 if (NULL == colors) {
1543 fContext->drawVertices(grPaint,
1544 gVertexMode2PrimitiveType[vmode],
1545 vertexCount,
1546 (GrPoint*) vertices,
1547 (GrPoint*) texs,
1548 NULL,
1549 indices,
1550 indexCount);
1551 } else
1552#endif
1553 {
1554 SkTexCoordSource texSrc(texs);
1555 SkColorSource colSrc(colors);
1556 SkIndexSource idxSrc(indices, indexCount);
1557
1558 fContext->drawCustomVertices(grPaint,
1559 gVertexMode2PrimitiveType[vmode],
1560 SkPositionSource(vertices, vertexCount),
1561 (NULL == texs) ? NULL : &texSrc,
1562 (NULL == colors) ? NULL : &colSrc,
1563 (NULL == indices) ? NULL : &idxSrc);
reed@google.comac10a2d2010-12-22 21:39:39 +00001564 }
1565}
1566
1567///////////////////////////////////////////////////////////////////////////////
1568
1569static void GlyphCacheAuxProc(void* data) {
1570 delete (GrFontScaler*)data;
1571}
1572
1573static GrFontScaler* get_gr_font_scaler(SkGlyphCache* cache) {
1574 void* auxData;
1575 GrFontScaler* scaler = NULL;
1576 if (cache->getAuxProcData(GlyphCacheAuxProc, &auxData)) {
1577 scaler = (GrFontScaler*)auxData;
1578 }
1579 if (NULL == scaler) {
1580 scaler = new SkGrFontScaler(cache);
1581 cache->setAuxProc(GlyphCacheAuxProc, scaler);
1582 }
1583 return scaler;
1584}
1585
1586static void SkGPU_Draw1Glyph(const SkDraw1Glyph& state,
1587 SkFixed fx, SkFixed fy,
1588 const SkGlyph& glyph) {
1589 SkASSERT(glyph.fWidth > 0 && glyph.fHeight > 0);
1590
1591 GrSkDrawProcs* procs = (GrSkDrawProcs*)state.fDraw->fProcs;
1592
1593 if (NULL == procs->fFontScaler) {
1594 procs->fFontScaler = get_gr_font_scaler(state.fCache);
1595 }
reed@google.com39ce0ac2011-04-08 15:42:19 +00001596
1597 /*
reed@google.com3b139f52011-06-07 17:56:25 +00001598 * What should we do with fy? (assuming horizontal/latin text)
reed@google.com39ce0ac2011-04-08 15:42:19 +00001599 *
reed@google.com3b139f52011-06-07 17:56:25 +00001600 * The raster code calls SkFixedFloorToFixed on it, as it does with fx.
1601 * It calls that rather than round, because our caller has already added
1602 * SK_FixedHalf, so that calling floor gives us the rounded integer.
1603 *
1604 * Test code between raster and gpu (they should draw the same)
1605 *
1606 * canvas->drawText("Hamburgefons", 12, 0, 16.5f, paint);
1607 *
1608 * Perhaps we should only perform this integralization if there is no
1609 * fExtMatrix...
reed@google.com39ce0ac2011-04-08 15:42:19 +00001610 */
reed@google.com3b139f52011-06-07 17:56:25 +00001611 fy = SkFixedFloorToFixed(fy);
1612
reed@google.comac10a2d2010-12-22 21:39:39 +00001613 procs->fTextContext->drawPackedGlyph(GrGlyph::Pack(glyph.getGlyphID(), fx, 0),
reed@google.com3b139f52011-06-07 17:56:25 +00001614 SkFixedFloorToFixed(fx), fy,
reed@google.comac10a2d2010-12-22 21:39:39 +00001615 procs->fFontScaler);
1616}
1617
bsalomon@google.com5782d712011-01-21 21:03:59 +00001618SkDrawProcs* SkGpuDevice::initDrawForText(GrTextContext* context) {
reed@google.comac10a2d2010-12-22 21:39:39 +00001619
1620 // deferred allocation
1621 if (NULL == fDrawProcs) {
1622 fDrawProcs = new GrSkDrawProcs;
1623 fDrawProcs->fD1GProc = SkGPU_Draw1Glyph;
1624 fDrawProcs->fContext = fContext;
1625 }
1626
1627 // init our (and GL's) state
1628 fDrawProcs->fTextContext = context;
1629 fDrawProcs->fFontScaler = NULL;
1630 return fDrawProcs;
1631}
1632
1633void SkGpuDevice::drawText(const SkDraw& draw, const void* text,
1634 size_t byteLength, SkScalar x, SkScalar y,
1635 const SkPaint& paint) {
1636 CHECK_SHOULD_DRAW(draw);
1637
1638 if (draw.fMatrix->getType() & SkMatrix::kPerspective_Mask) {
1639 // this guy will just call our drawPath()
1640 draw.drawText((const char*)text, byteLength, x, y, paint);
1641 } else {
reed@google.comac10a2d2010-12-22 21:39:39 +00001642 SkDraw myDraw(draw);
bsalomon@google.com5782d712011-01-21 21:03:59 +00001643
1644 GrPaint grPaint;
1645 SkAutoCachedTexture act;
1646
Scroggod757df22011-05-16 13:11:16 +00001647 if (!this->skPaint2GrPaintShader(paint,
1648 &act,
1649 *draw.fMatrix,
1650 &grPaint,
1651 true)) {
bsalomon@google.com5782d712011-01-21 21:03:59 +00001652 return;
1653 }
bsalomon@google.comcc4dac32011-05-10 13:52:42 +00001654 GrTextContext context(fContext, grPaint, draw.fExtMatrix);
bsalomon@google.com5782d712011-01-21 21:03:59 +00001655 myDraw.fProcs = this->initDrawForText(&context);
reed@google.comac10a2d2010-12-22 21:39:39 +00001656 this->INHERITED::drawText(myDraw, text, byteLength, x, y, paint);
1657 }
1658}
1659
1660void SkGpuDevice::drawPosText(const SkDraw& draw, const void* text,
1661 size_t byteLength, const SkScalar pos[],
1662 SkScalar constY, int scalarsPerPos,
1663 const SkPaint& paint) {
1664 CHECK_SHOULD_DRAW(draw);
1665
1666 if (draw.fMatrix->getType() & SkMatrix::kPerspective_Mask) {
1667 // this guy will just call our drawPath()
1668 draw.drawPosText((const char*)text, byteLength, pos, constY,
1669 scalarsPerPos, paint);
1670 } else {
reed@google.comac10a2d2010-12-22 21:39:39 +00001671 SkDraw myDraw(draw);
bsalomon@google.com5782d712011-01-21 21:03:59 +00001672
1673 GrPaint grPaint;
1674 SkAutoCachedTexture act;
Scroggod757df22011-05-16 13:11:16 +00001675 if (!this->skPaint2GrPaintShader(paint,
1676 &act,
1677 *draw.fMatrix,
1678 &grPaint,
1679 true)) {
bsalomon@google.com5782d712011-01-21 21:03:59 +00001680 return;
1681 }
1682
bsalomon@google.comcc4dac32011-05-10 13:52:42 +00001683 GrTextContext context(fContext, grPaint, draw.fExtMatrix);
bsalomon@google.com5782d712011-01-21 21:03:59 +00001684 myDraw.fProcs = this->initDrawForText(&context);
reed@google.comac10a2d2010-12-22 21:39:39 +00001685 this->INHERITED::drawPosText(myDraw, text, byteLength, pos, constY,
1686 scalarsPerPos, paint);
1687 }
1688}
1689
1690void SkGpuDevice::drawTextOnPath(const SkDraw& draw, const void* text,
1691 size_t len, const SkPath& path,
1692 const SkMatrix* m, const SkPaint& paint) {
1693 CHECK_SHOULD_DRAW(draw);
1694
1695 SkASSERT(draw.fDevice == this);
1696 draw.drawTextOnPath((const char*)text, len, path, m, paint);
1697}
1698
1699///////////////////////////////////////////////////////////////////////////////
1700
reed@google.comf67e4cf2011-03-15 20:56:58 +00001701bool SkGpuDevice::filterTextFlags(const SkPaint& paint, TextFlags* flags) {
1702 if (!paint.isLCDRenderText()) {
1703 // we're cool with the paint as is
1704 return false;
1705 }
1706
1707 if (paint.getShader() ||
1708 paint.getXfermode() || // unless its srcover
1709 paint.getMaskFilter() ||
1710 paint.getRasterizer() ||
1711 paint.getColorFilter() ||
1712 paint.getPathEffect() ||
1713 paint.isFakeBoldText() ||
1714 paint.getStyle() != SkPaint::kFill_Style) {
1715 // turn off lcd
1716 flags->fFlags = paint.getFlags() & ~SkPaint::kLCDRenderText_Flag;
1717 flags->fHinting = paint.getHinting();
1718 return true;
1719 }
1720 // we're cool with the paint as is
1721 return false;
1722}
1723
1724///////////////////////////////////////////////////////////////////////////////
1725
reed@google.comac10a2d2010-12-22 21:39:39 +00001726SkGpuDevice::TexCache* SkGpuDevice::lockCachedTexture(const SkBitmap& bitmap,
bsalomon@google.comfea37b52011-04-25 15:51:06 +00001727 const GrSamplerState& sampler,
1728 GrTexture** texture,
bsalomon@google.come97f0852011-06-17 13:10:25 +00001729 TexType type) {
bsalomon@google.comfea37b52011-04-25 15:51:06 +00001730 GrTexture* newTexture = NULL;
1731 GrTextureEntry* entry = NULL;
reed@google.comac10a2d2010-12-22 21:39:39 +00001732 GrContext* ctx = this->context();
bsalomon@google.comfea37b52011-04-25 15:51:06 +00001733
bsalomon@google.come97f0852011-06-17 13:10:25 +00001734 if (kBitmap_TexType != type) {
bsalomon@google.comfea37b52011-04-25 15:51:06 +00001735 const GrTextureDesc desc = {
1736 kRenderTarget_GrTextureFlagBit,
1737 kNone_GrAALevel,
1738 bitmap.width(),
1739 bitmap.height(),
1740 SkGr::Bitmap2PixelConfig(bitmap)
1741 };
bsalomon@google.come97f0852011-06-17 13:10:25 +00001742 if (kSaveLayerDeviceRenderTarget_TexType == type) {
bsalomon@google.comb5b31682011-06-16 18:05:35 +00001743 // we know layers will only be drawn through drawDevice.
1744 // drawDevice has been made to work with content embedded in a
1745 // larger texture so its okay to use the approximate version.
1746 entry = ctx->findApproximateKeylessTexture(desc);
1747 } else {
bsalomon@google.come97f0852011-06-17 13:10:25 +00001748 SkASSERT(kDeviceRenderTarget_TexType == type);
bsalomon@google.comb5b31682011-06-16 18:05:35 +00001749 entry = ctx->lockKeylessTexture(desc);
1750 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001751 } else {
junov@google.com4ee7ae52011-06-30 17:30:49 +00001752 if (!bitmap.isVolatile()) {
1753 uint32_t p0, p1;
1754 p0 = bitmap.getGenerationID();
1755 p1 = bitmap.pixelRefOffset();
1756 GrTextureKey key(p0, p1, bitmap.width(), bitmap.height());
1757
1758 entry = ctx->findAndLockTexture(&key, sampler);
1759 if (NULL == entry)
1760 entry = sk_gr_create_bitmap_texture(ctx, &key, sampler,
1761 bitmap);
1762 } else {
1763 entry = sk_gr_create_bitmap_texture(ctx, NULL, sampler, bitmap);
1764 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001765 if (NULL == entry) {
junov@google.com4ee7ae52011-06-30 17:30:49 +00001766 GrPrintf("---- failed to create texture for cache [%d %d]\n",
1767 bitmap.width(), bitmap.height());
reed@google.comac10a2d2010-12-22 21:39:39 +00001768 }
1769 }
1770
1771 if (NULL != entry) {
1772 newTexture = entry->texture();
reed@google.comac10a2d2010-12-22 21:39:39 +00001773 if (texture) {
1774 *texture = newTexture;
1775 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001776 }
1777 return (TexCache*)entry;
1778}
1779
1780void SkGpuDevice::unlockCachedTexture(TexCache* cache) {
1781 this->context()->unlockTexture((GrTextureEntry*)cache);
1782}
1783
bsalomon@google.come97f0852011-06-17 13:10:25 +00001784SkDevice* SkGpuDevice::onCreateCompatibleDevice(SkBitmap::Config config,
1785 int width, int height,
1786 bool isOpaque,
1787 Usage usage) {
1788 return SkNEW_ARGS(SkGpuDevice,(this->context(), config,
1789 width, height, usage));
1790}
1791