blob: b39f90eb32309439020d8986074d23aa91b2ebb8 [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.orge36ddf02011-07-15 14:28:16 +000051#define MAX_BLUR_SIGMA 4.0f
52// FIXME: This value comes from from SkBlurMaskFilter.cpp.
53// Should probably be put in a common header someplace.
54#define MAX_BLUR_RADIUS SkIntToScalar(128)
55// This constant approximates the scaling done in the software path's
56// "high quality" mode, in SkBlurMask::Blur() (1 / sqrt(3)).
57// IMHO, it actually should be 1: we blur "less" than we should do
58// according to the CSS and canvas specs, simply because Safari does the same.
59// Firefox used to do the same too, until 4.0 where they fixed it. So at some
60// point we should probably get rid of these scaling constants and rebaseline
61// all the blur tests.
62#define BLUR_SIGMA_SCALE 0.6f
reed@google.comac10a2d2010-12-22 21:39:39 +000063///////////////////////////////////////////////////////////////////////////////
64
65SkGpuDevice::SkAutoCachedTexture::
66 SkAutoCachedTexture(SkGpuDevice* device,
67 const SkBitmap& bitmap,
68 const GrSamplerState& sampler,
69 GrTexture** texture) {
70 GrAssert(texture);
71 fTex = NULL;
72 *texture = this->set(device, bitmap, sampler);
73}
74
75SkGpuDevice::SkAutoCachedTexture::SkAutoCachedTexture() {
76 fTex = NULL;
77}
78
79GrTexture* SkGpuDevice::SkAutoCachedTexture::set(SkGpuDevice* device,
80 const SkBitmap& bitmap,
81 const GrSamplerState& sampler) {
82 if (fTex) {
83 fDevice->unlockCachedTexture(fTex);
84 }
85 fDevice = device;
86 GrTexture* texture = (GrTexture*)bitmap.getTexture();
87 if (texture) {
88 // return the native texture
89 fTex = NULL;
reed@google.comac10a2d2010-12-22 21:39:39 +000090 } else {
91 // look it up in our cache
bsalomon@google.come97f0852011-06-17 13:10:25 +000092 fTex = device->lockCachedTexture(bitmap, sampler, &texture);
reed@google.comac10a2d2010-12-22 21:39:39 +000093 }
94 return texture;
95}
96
97SkGpuDevice::SkAutoCachedTexture::~SkAutoCachedTexture() {
98 if (fTex) {
99 fDevice->unlockCachedTexture(fTex);
100 }
101}
102
103///////////////////////////////////////////////////////////////////////////////
104
105bool gDoTraceDraw;
106
107struct GrSkDrawProcs : public SkDrawProcs {
108public:
109 GrContext* fContext;
110 GrTextContext* fTextContext;
111 GrFontScaler* fFontScaler; // cached in the skia glyphcache
112};
113
114///////////////////////////////////////////////////////////////////////////////
115
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000116GrRenderTarget* SkGpuDevice::Current3DApiRenderTarget() {
117 return (GrRenderTarget*) -1;
118}
119
reed@google.comaf951c92011-06-16 19:10:39 +0000120static SkBitmap::Config grConfig2skConfig(GrPixelConfig config, bool* isOpaque) {
121 switch (config) {
122 case kAlpha_8_GrPixelConfig:
123 *isOpaque = false;
124 return SkBitmap::kA8_Config;
125 case kRGB_565_GrPixelConfig:
126 *isOpaque = true;
127 return SkBitmap::kRGB_565_Config;
128 case kRGBA_4444_GrPixelConfig:
129 *isOpaque = false;
130 return SkBitmap::kARGB_4444_Config;
131 case kRGBA_8888_GrPixelConfig:
132 case kRGBX_8888_GrPixelConfig:
133 *isOpaque = (kRGBX_8888_GrPixelConfig == config);
134 return SkBitmap::kARGB_8888_Config;
135 default:
136 *isOpaque = false;
137 return SkBitmap::kNo_Config;
138 }
139}
reed@google.comac10a2d2010-12-22 21:39:39 +0000140
reed@google.comaf951c92011-06-16 19:10:39 +0000141static SkBitmap make_bitmap(GrContext* context, GrRenderTarget* renderTarget) {
142 if (SkGpuDevice::Current3DApiRenderTarget() == renderTarget) {
143 renderTarget = context->createRenderTargetFrom3DApiState();
144 }
145 GrTexture* texture = renderTarget->asTexture();
146 GrPixelConfig config = texture ? texture->config() : kRGBA_8888_GrPixelConfig;
147
148 bool isOpaque;
149 SkBitmap bitmap;
150 bitmap.setConfig(grConfig2skConfig(config, &isOpaque),
151 renderTarget->width(), renderTarget->height());
152 bitmap.setIsOpaque(isOpaque);
153 return bitmap;
154}
155
bsalomon@google.comf9046fe2011-06-17 15:10:21 +0000156SkGpuDevice::SkGpuDevice(GrContext* context, GrTexture* texture)
157: SkDevice(make_bitmap(context, texture->asRenderTarget())) {
158 this->initFromRenderTarget(context, texture->asRenderTarget());
159}
160
reed@google.comaf951c92011-06-16 19:10:39 +0000161SkGpuDevice::SkGpuDevice(GrContext* context, GrRenderTarget* renderTarget)
162: SkDevice(make_bitmap(context, renderTarget)) {
bsalomon@google.comf9046fe2011-06-17 15:10:21 +0000163 this->initFromRenderTarget(context, renderTarget);
164}
165
166void SkGpuDevice::initFromRenderTarget(GrContext* context,
167 GrRenderTarget* renderTarget) {
reed@google.comaf951c92011-06-16 19:10:39 +0000168 fNeedPrepareRenderTarget = false;
169 fDrawProcs = NULL;
170
171 fContext = context;
172 fContext->ref();
173
174 fCache = NULL;
175 fTexture = NULL;
176 fRenderTarget = NULL;
177 fNeedClear = false;
178
179 if (Current3DApiRenderTarget() == renderTarget) {
180 fRenderTarget = fContext->createRenderTargetFrom3DApiState();
181 } else {
bsalomon@google.comf9046fe2011-06-17 15:10:21 +0000182 GrAssert(NULL != renderTarget);
reed@google.comaf951c92011-06-16 19:10:39 +0000183 fRenderTarget = renderTarget;
184 fRenderTarget->ref();
bsalomon@google.comf9046fe2011-06-17 15:10:21 +0000185 // if this RT is also a texture, hold a ref on it
186 fTexture = fRenderTarget->asTexture();
187 SkSafeRef(fTexture);
reed@google.comaf951c92011-06-16 19:10:39 +0000188 }
189
190 SkGrRenderTargetPixelRef* pr = new SkGrRenderTargetPixelRef(fRenderTarget);
191 this->setPixelRef(pr, 0)->unref();
192}
193
194SkGpuDevice::SkGpuDevice(GrContext* context, SkBitmap::Config config, int width,
bsalomon@google.come97f0852011-06-17 13:10:25 +0000195 int height, Usage usage)
reed@google.comaf951c92011-06-16 19:10:39 +0000196: SkDevice(config, width, height, false /*isOpaque*/) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000197 fNeedPrepareRenderTarget = false;
198 fDrawProcs = NULL;
199
reed@google.com7b201d22011-01-11 18:59:23 +0000200 fContext = context;
bsalomon@google.com5782d712011-01-21 21:03:59 +0000201 fContext->ref();
reed@google.comac10a2d2010-12-22 21:39:39 +0000202
203 fCache = NULL;
204 fTexture = NULL;
205 fRenderTarget = NULL;
206 fNeedClear = false;
207
reed@google.comaf951c92011-06-16 19:10:39 +0000208 if (config != SkBitmap::kRGB_565_Config) {
209 config = SkBitmap::kARGB_8888_Config;
210 }
211 SkBitmap bm;
212 bm.setConfig(config, width, height);
reed@google.comac10a2d2010-12-22 21:39:39 +0000213
214#if CACHE_LAYER_TEXTURES
bsalomon@google.come97f0852011-06-17 13:10:25 +0000215 TexType type = (kSaveLayer_Usage == usage) ?
216 kSaveLayerDeviceRenderTarget_TexType :
217 kDeviceRenderTarget_TexType;
reed@google.comaf951c92011-06-16 19:10:39 +0000218 fCache = this->lockCachedTexture(bm, GrSamplerState::ClampNoFilter(),
bsalomon@google.come97f0852011-06-17 13:10:25 +0000219 &fTexture, type);
reed@google.comaf951c92011-06-16 19:10:39 +0000220 if (fCache) {
221 SkASSERT(NULL != fTexture);
222 SkASSERT(NULL != fTexture->asRenderTarget());
bsalomon@google.comf9046fe2011-06-17 15:10:21 +0000223 // hold a ref directly on fTexture (even though fCache has one) to match
224 // other constructor paths. Simplifies cleanup.
225 fTexture->ref();
reed@google.comaf951c92011-06-16 19:10:39 +0000226 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000227#else
reed@google.comaf951c92011-06-16 19:10:39 +0000228 const GrTextureDesc desc = {
229 kRenderTarget_GrTextureFlagBit,
230 kNone_GrAALevel,
231 width,
232 height,
233 SkGr::Bitmap2PixelConfig(bm)
234 };
reed@google.comac10a2d2010-12-22 21:39:39 +0000235
reed@google.comaf951c92011-06-16 19:10:39 +0000236 fTexture = fContext->createUncachedTexture(desc, NULL, 0);
reed@google.comac10a2d2010-12-22 21:39:39 +0000237#endif
reed@google.comaf951c92011-06-16 19:10:39 +0000238 if (NULL != fTexture) {
239 fRenderTarget = fTexture->asRenderTarget();
bsalomon@google.comf9046fe2011-06-17 15:10:21 +0000240 fRenderTarget->ref();
reed@google.comac10a2d2010-12-22 21:39:39 +0000241
reed@google.comaf951c92011-06-16 19:10:39 +0000242 GrAssert(NULL != fRenderTarget);
reed@google.comac10a2d2010-12-22 21:39:39 +0000243
reed@google.comaf951c92011-06-16 19:10:39 +0000244 // we defer the actual clear until our gainFocus()
245 fNeedClear = true;
reed@google.comac10a2d2010-12-22 21:39:39 +0000246
reed@google.comaf951c92011-06-16 19:10:39 +0000247 // wrap the bitmap with a pixelref to expose our texture
248 SkGrTexturePixelRef* pr = new SkGrTexturePixelRef(fTexture);
bsalomon@google.com669fdc42011-04-05 17:08:27 +0000249 this->setPixelRef(pr, 0)->unref();
reed@google.comaf951c92011-06-16 19:10:39 +0000250 } else {
251 GrPrintf("--- failed to create gpu-offscreen [%d %d]\n",
252 width, height);
253 GrAssert(false);
reed@google.comac10a2d2010-12-22 21:39:39 +0000254 }
255}
256
257SkGpuDevice::~SkGpuDevice() {
258 if (fDrawProcs) {
259 delete fDrawProcs;
260 }
261
bsalomon@google.comf9046fe2011-06-17 15:10:21 +0000262 SkSafeUnref(fTexture);
263 SkSafeUnref(fRenderTarget);
reed@google.comac10a2d2010-12-22 21:39:39 +0000264 if (fCache) {
265 GrAssert(NULL != fTexture);
266 GrAssert(fRenderTarget == fTexture->asRenderTarget());
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000267 fContext->unlockTexture((GrTextureEntry*)fCache);
bsalomon@google.comf9046fe2011-06-17 15:10:21 +0000268 }
bsalomon@google.com5782d712011-01-21 21:03:59 +0000269 fContext->unref();
reed@google.comac10a2d2010-12-22 21:39:39 +0000270}
271
reed@google.comac10a2d2010-12-22 21:39:39 +0000272///////////////////////////////////////////////////////////////////////////////
273
274void SkGpuDevice::makeRenderTargetCurrent() {
275 fContext->setRenderTarget(fRenderTarget);
276 fContext->flush(true);
277 fNeedPrepareRenderTarget = true;
278}
279
280///////////////////////////////////////////////////////////////////////////////
281
282bool SkGpuDevice::readPixels(const SkIRect& srcRect, SkBitmap* bitmap) {
283 SkIRect bounds;
284 bounds.set(0, 0, this->width(), this->height());
285 if (!bounds.intersect(srcRect)) {
286 return false;
287 }
288
289 const int w = bounds.width();
290 const int h = bounds.height();
291 SkBitmap tmp;
292 // note we explicitly specify our rowBytes to be snug (no gap between rows)
293 tmp.setConfig(SkBitmap::kARGB_8888_Config, w, h, w * 4);
294 if (!tmp.allocPixels()) {
295 return false;
296 }
297
Scroggo813c33c2011-04-07 20:56:21 +0000298 tmp.lockPixels();
reed@google.comac10a2d2010-12-22 21:39:39 +0000299
Scroggoeb176032011-04-07 21:11:49 +0000300 bool read = fContext->readRenderTargetPixels(fRenderTarget,
301 bounds.fLeft, bounds.fTop,
302 bounds.width(), bounds.height(),
303 kRGBA_8888_GrPixelConfig,
304 tmp.getPixels());
Scroggo813c33c2011-04-07 20:56:21 +0000305 tmp.unlockPixels();
306 if (!read) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000307 return false;
308 }
309
310 tmp.swap(*bitmap);
311 return true;
312}
313
314void SkGpuDevice::writePixels(const SkBitmap& bitmap, int x, int y) {
315 SkAutoLockPixels alp(bitmap);
316 if (!bitmap.readyToDraw()) {
317 return;
318 }
bsalomon@google.com669fdc42011-04-05 17:08:27 +0000319 GrPixelConfig config = SkGr::BitmapConfig2PixelConfig(bitmap.config(),
320 bitmap.isOpaque());
reed@google.comac10a2d2010-12-22 21:39:39 +0000321 fContext->setRenderTarget(fRenderTarget);
322 // we aren't setting the clip or matrix, so mark as dirty
323 // we don't need to set them for this call and don't have them anyway
324 fNeedPrepareRenderTarget = true;
325
326 fContext->writePixels(x, y, bitmap.width(), bitmap.height(),
327 config, bitmap.getPixels(), bitmap.rowBytes());
328}
329
330///////////////////////////////////////////////////////////////////////////////
331
332static void convert_matrixclip(GrContext* context, const SkMatrix& matrix,
bsalomon@google.comd302f142011-03-03 13:54:13 +0000333 const SkClipStack& clipStack,
reed@google.com6f8f2922011-03-04 22:27:10 +0000334 const SkRegion& clipRegion,
335 const SkIPoint& origin) {
bsalomon@google.comcc4dac32011-05-10 13:52:42 +0000336 context->setMatrix(matrix);
reed@google.comac10a2d2010-12-22 21:39:39 +0000337
338 SkGrClipIterator iter;
bsalomon@google.comd302f142011-03-03 13:54:13 +0000339 iter.reset(clipStack);
bsalomon@google.comd302f142011-03-03 13:54:13 +0000340 const SkIRect& skBounds = clipRegion.getBounds();
341 GrRect bounds;
342 bounds.setLTRB(GrIntToScalar(skBounds.fLeft),
343 GrIntToScalar(skBounds.fTop),
344 GrIntToScalar(skBounds.fRight),
345 GrIntToScalar(skBounds.fBottom));
reed@google.com6f8f2922011-03-04 22:27:10 +0000346 GrClip grc(&iter, GrIntToScalar(-origin.x()), GrIntToScalar(-origin.y()),
347 &bounds);
bsalomon@google.comd302f142011-03-03 13:54:13 +0000348 context->setClip(grc);
reed@google.comac10a2d2010-12-22 21:39:39 +0000349}
350
351// call this ever each draw call, to ensure that the context reflects our state,
352// and not the state from some other canvas/device
353void SkGpuDevice::prepareRenderTarget(const SkDraw& draw) {
354 if (fNeedPrepareRenderTarget ||
bsalomon@google.com5782d712011-01-21 21:03:59 +0000355 fContext->getRenderTarget() != fRenderTarget) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000356
357 fContext->setRenderTarget(fRenderTarget);
bsalomon@google.comd302f142011-03-03 13:54:13 +0000358 SkASSERT(draw.fClipStack);
359 convert_matrixclip(fContext, *draw.fMatrix,
reed@google.com6f8f2922011-03-04 22:27:10 +0000360 *draw.fClipStack, *draw.fClip, this->getOrigin());
reed@google.comac10a2d2010-12-22 21:39:39 +0000361 fNeedPrepareRenderTarget = false;
362 }
363}
364
reed@google.com46799cd2011-02-22 20:56:26 +0000365void SkGpuDevice::setMatrixClip(const SkMatrix& matrix, const SkRegion& clip,
366 const SkClipStack& clipStack) {
367 this->INHERITED::setMatrixClip(matrix, clip, clipStack);
bsalomon@google.coma7bf6e22011-04-11 19:20:46 +0000368 // We don't need to set them now because the context may not reflect this device.
369 fNeedPrepareRenderTarget = true;
reed@google.comac10a2d2010-12-22 21:39:39 +0000370}
371
372void SkGpuDevice::gainFocus(SkCanvas* canvas, const SkMatrix& matrix,
bsalomon@google.comd302f142011-03-03 13:54:13 +0000373 const SkRegion& clip, const SkClipStack& clipStack) {
374
reed@google.comac10a2d2010-12-22 21:39:39 +0000375 fContext->setRenderTarget(fRenderTarget);
376
bsalomon@google.comd302f142011-03-03 13:54:13 +0000377 this->INHERITED::gainFocus(canvas, matrix, clip, clipStack);
reed@google.comac10a2d2010-12-22 21:39:39 +0000378
reed@google.com6f8f2922011-03-04 22:27:10 +0000379 convert_matrixclip(fContext, matrix, clipStack, clip, this->getOrigin());
reed@google.comac10a2d2010-12-22 21:39:39 +0000380
381 if (fNeedClear) {
bsalomon@google.com31a58402011-04-27 21:00:02 +0000382 fContext->clear(NULL, 0x0);
reed@google.comac10a2d2010-12-22 21:39:39 +0000383 fNeedClear = false;
384 }
385}
386
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000387bool SkGpuDevice::bindDeviceAsTexture(GrPaint* paint) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000388 if (NULL != fTexture) {
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000389 paint->setTexture(kBitmapTextureIdx, fTexture);
reed@google.comac10a2d2010-12-22 21:39:39 +0000390 return true;
391 }
392 return false;
393}
394
395///////////////////////////////////////////////////////////////////////////////
396
vandebo@chromium.orgd3ae7792011-02-24 00:21:06 +0000397SK_COMPILE_ASSERT(SkShader::kNone_BitmapType == 0, shader_type_mismatch);
398SK_COMPILE_ASSERT(SkShader::kDefault_BitmapType == 1, shader_type_mismatch);
399SK_COMPILE_ASSERT(SkShader::kRadial_BitmapType == 2, shader_type_mismatch);
400SK_COMPILE_ASSERT(SkShader::kSweep_BitmapType == 3, shader_type_mismatch);
401SK_COMPILE_ASSERT(SkShader::kTwoPointRadial_BitmapType == 4,
402 shader_type_mismatch);
403SK_COMPILE_ASSERT(SkShader::kLast_BitmapType == 4, shader_type_mismatch);
reed@google.comac10a2d2010-12-22 21:39:39 +0000404
bsalomon@google.com5782d712011-01-21 21:03:59 +0000405static const GrSamplerState::SampleMode sk_bmp_type_to_sample_mode[] = {
406 (GrSamplerState::SampleMode) -1, // kNone_BitmapType
407 GrSamplerState::kNormal_SampleMode, // kDefault_BitmapType
408 GrSamplerState::kRadial_SampleMode, // kRadial_BitmapType
409 GrSamplerState::kSweep_SampleMode, // kSweep_BitmapType
410 GrSamplerState::kRadial2_SampleMode, // kTwoPointRadial_BitmapType
411};
412
413bool SkGpuDevice::skPaint2GrPaintNoShader(const SkPaint& skPaint,
414 bool justAlpha,
Scroggod757df22011-05-16 13:11:16 +0000415 GrPaint* grPaint,
416 bool constantColor) {
bsalomon@google.com5782d712011-01-21 21:03:59 +0000417
418 grPaint->fDither = skPaint.isDither();
419 grPaint->fAntiAlias = skPaint.isAntiAlias();
420
421 SkXfermode::Coeff sm = SkXfermode::kOne_Coeff;
422 SkXfermode::Coeff dm = SkXfermode::kISA_Coeff;
423
424 SkXfermode* mode = skPaint.getXfermode();
425 if (mode) {
426 if (!mode->asCoeff(&sm, &dm)) {
reed@google.com1a2e8d22011-01-21 22:08:29 +0000427 SkDEBUGCODE(SkDebugf("Unsupported xfer mode.\n");)
bsalomon@google.com5782d712011-01-21 21:03:59 +0000428#if 0
429 return false;
430#endif
431 }
432 }
433 grPaint->fSrcBlendCoeff = sk_blend_to_grblend(sm);
434 grPaint->fDstBlendCoeff = sk_blend_to_grblend(dm);
435
436 if (justAlpha) {
437 uint8_t alpha = skPaint.getAlpha();
438 grPaint->fColor = GrColorPackRGBA(alpha, alpha, alpha, alpha);
Scroggod757df22011-05-16 13:11:16 +0000439 // justAlpha is currently set to true only if there is a texture,
440 // so constantColor should not also be true.
441 GrAssert(!constantColor);
bsalomon@google.com5782d712011-01-21 21:03:59 +0000442 } else {
443 grPaint->fColor = SkGr::SkColor2GrColor(skPaint.getColor());
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000444 grPaint->setTexture(kShaderTextureIdx, NULL);
bsalomon@google.com5782d712011-01-21 21:03:59 +0000445 }
Scroggo97c88c22011-05-11 14:05:25 +0000446 SkColorFilter* colorFilter = skPaint.getColorFilter();
447 SkColor color;
448 SkXfermode::Mode filterMode;
449 if (colorFilter != NULL && colorFilter->asColorMode(&color, &filterMode)) {
Scroggod757df22011-05-16 13:11:16 +0000450 if (!constantColor) {
451 grPaint->fColorFilterColor = SkGr::SkColor2GrColor(color);
452 grPaint->fColorFilterXfermode = filterMode;
453 return true;
454 }
455 SkColor filtered = colorFilter->filterColor(skPaint.getColor());
456 grPaint->fColor = SkGr::SkColor2GrColor(filtered);
Scroggo97c88c22011-05-11 14:05:25 +0000457 }
Scroggod757df22011-05-16 13:11:16 +0000458 grPaint->resetColorFilter();
bsalomon@google.com5782d712011-01-21 21:03:59 +0000459 return true;
reed@google.comac10a2d2010-12-22 21:39:39 +0000460}
461
bsalomon@google.com5782d712011-01-21 21:03:59 +0000462bool SkGpuDevice::skPaint2GrPaintShader(const SkPaint& skPaint,
463 SkAutoCachedTexture* act,
464 const SkMatrix& ctm,
Scroggod757df22011-05-16 13:11:16 +0000465 GrPaint* grPaint,
466 bool constantColor) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000467
bsalomon@google.com5782d712011-01-21 21:03:59 +0000468 SkASSERT(NULL != act);
reed@google.comac10a2d2010-12-22 21:39:39 +0000469
bsalomon@google.com5782d712011-01-21 21:03:59 +0000470 SkShader* shader = skPaint.getShader();
reed@google.comac10a2d2010-12-22 21:39:39 +0000471 if (NULL == shader) {
Scroggod757df22011-05-16 13:11:16 +0000472 return this->skPaint2GrPaintNoShader(skPaint,
473 false,
474 grPaint,
475 constantColor);
476 } else if (!this->skPaint2GrPaintNoShader(skPaint, true, grPaint, false)) {
bsalomon@google.com5782d712011-01-21 21:03:59 +0000477 return false;
reed@google.comac10a2d2010-12-22 21:39:39 +0000478 }
479
reed@google.comac10a2d2010-12-22 21:39:39 +0000480 SkBitmap bitmap;
481 SkMatrix matrix;
482 SkShader::TileMode tileModes[2];
483 SkScalar twoPointParams[3];
484 SkShader::BitmapType bmptype = shader->asABitmap(&bitmap, &matrix,
485 tileModes, twoPointParams);
486
bsalomon@google.com5782d712011-01-21 21:03:59 +0000487 GrSamplerState::SampleMode sampleMode = sk_bmp_type_to_sample_mode[bmptype];
488 if (-1 == sampleMode) {
reed@google.com2be9e8b2011-07-06 21:18:09 +0000489 SkShader::GradientInfo info;
490 SkColor color;
491
492 info.fColors = &color;
493 info.fColorOffsets = NULL;
494 info.fColorCount = 1;
495 if (SkShader::kColor_GradientType == shader->asAGradient(&info)) {
496 SkPaint copy(skPaint);
497 copy.setShader(NULL);
bsalomon@google.comcd9cfd72011-07-08 16:55:04 +0000498 // modulate the paint alpha by the shader's solid color alpha
499 U8CPU newA = SkMulDiv255Round(SkColorGetA(color), copy.getAlpha());
500 copy.setColor(SkColorSetA(color, newA));
reed@google.com2be9e8b2011-07-06 21:18:09 +0000501 return this->skPaint2GrPaintNoShader(copy,
502 false,
503 grPaint,
504 constantColor);
505 }
bsalomon@google.com5782d712011-01-21 21:03:59 +0000506 return false;
reed@google.comac10a2d2010-12-22 21:39:39 +0000507 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000508 GrSamplerState* sampler = grPaint->getTextureSampler(kShaderTextureIdx);
509 sampler->setSampleMode(sampleMode);
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000510 if (skPaint.isFilterBitmap()) {
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000511 sampler->setFilter(GrSamplerState::kBilinear_Filter);
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000512 } else {
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000513 sampler->setFilter(GrSamplerState::kNearest_Filter);
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000514 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000515 sampler->setWrapX(sk_tile_mode_to_grwrap(tileModes[0]));
516 sampler->setWrapY(sk_tile_mode_to_grwrap(tileModes[1]));
reed@google.comac10a2d2010-12-22 21:39:39 +0000517 if (GrSamplerState::kRadial2_SampleMode == sampleMode) {
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000518 sampler->setRadial2Params(twoPointParams[0],
519 twoPointParams[1],
520 twoPointParams[2] < 0);
reed@google.comac10a2d2010-12-22 21:39:39 +0000521 }
522
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000523 GrTexture* texture = act->set(this, bitmap, *sampler);
reed@google.comac10a2d2010-12-22 21:39:39 +0000524 if (NULL == texture) {
bsalomon@google.com5782d712011-01-21 21:03:59 +0000525 SkDebugf("Couldn't convert bitmap to texture.\n");
526 return false;
reed@google.comac10a2d2010-12-22 21:39:39 +0000527 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000528 grPaint->setTexture(kShaderTextureIdx, texture);
reed@google.comac10a2d2010-12-22 21:39:39 +0000529
530 // since our texture coords will be in local space, we wack the texture
531 // matrix to map them back into 0...1 before we load it
532 SkMatrix localM;
533 if (shader->getLocalMatrix(&localM)) {
534 SkMatrix inverse;
535 if (localM.invert(&inverse)) {
536 matrix.preConcat(inverse);
537 }
538 }
539 if (SkShader::kDefault_BitmapType == bmptype) {
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000540 GrScalar sx = GrFixedToScalar(GR_Fixed1 / bitmap.width());
541 GrScalar sy = GrFixedToScalar(GR_Fixed1 / bitmap.height());
reed@google.comac10a2d2010-12-22 21:39:39 +0000542 matrix.postScale(sx, sy);
reed@google.comac10a2d2010-12-22 21:39:39 +0000543 } else if (SkShader::kRadial_BitmapType == bmptype) {
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000544 GrScalar s = GrFixedToScalar(GR_Fixed1 / bitmap.width());
reed@google.comac10a2d2010-12-22 21:39:39 +0000545 matrix.postScale(s, s);
546 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000547 sampler->setMatrix(matrix);
bsalomon@google.com5782d712011-01-21 21:03:59 +0000548
549 return true;
reed@google.comac10a2d2010-12-22 21:39:39 +0000550}
551
552///////////////////////////////////////////////////////////////////////////////
bsalomon@google.com5782d712011-01-21 21:03:59 +0000553
554class SkPositionSource {
555public:
556 SkPositionSource(const SkPoint* points, int count)
557 : fPoints(points), fCount(count) {}
558
559 int count() const { return fCount; }
560
561 void writeValue(int i, GrPoint* dstPosition) const {
562 SkASSERT(i < fCount);
563 dstPosition->fX = SkScalarToGrScalar(fPoints[i].fX);
564 dstPosition->fY = SkScalarToGrScalar(fPoints[i].fY);
565 }
566private:
bsalomon@google.com5782d712011-01-21 21:03:59 +0000567 const SkPoint* fPoints;
bsalomon@google.com19628322011-02-03 21:30:17 +0000568 int fCount;
bsalomon@google.com5782d712011-01-21 21:03:59 +0000569};
570
571class SkTexCoordSource {
572public:
573 SkTexCoordSource(const SkPoint* coords)
574 : fCoords(coords) {}
575
576 void writeValue(int i, GrPoint* dstCoord) const {
577 dstCoord->fX = SkScalarToGrScalar(fCoords[i].fX);
578 dstCoord->fY = SkScalarToGrScalar(fCoords[i].fY);
579 }
580private:
581 const SkPoint* fCoords;
582};
583
584class SkColorSource {
585public:
586 SkColorSource(const SkColor* colors) : fColors(colors) {}
587
588 void writeValue(int i, GrColor* dstColor) const {
589 *dstColor = SkGr::SkColor2GrColor(fColors[i]);
590 }
591private:
592 const SkColor* fColors;
593};
594
595class SkIndexSource {
596public:
597 SkIndexSource(const uint16_t* indices, int count)
598 : fIndices(indices), fCount(count) {
599 }
600
601 int count() const { return fCount; }
602
603 void writeValue(int i, uint16_t* dstIndex) const {
604 *dstIndex = fIndices[i];
605 }
606
607private:
bsalomon@google.com5782d712011-01-21 21:03:59 +0000608 const uint16_t* fIndices;
bsalomon@google.com19628322011-02-03 21:30:17 +0000609 int fCount;
bsalomon@google.com5782d712011-01-21 21:03:59 +0000610};
611
612///////////////////////////////////////////////////////////////////////////////
613
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000614#if 0 // not currently being used so don't compile,
615
bsalomon@google.com5782d712011-01-21 21:03:59 +0000616// can be used for positions or texture coordinates
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000617
bsalomon@google.com5782d712011-01-21 21:03:59 +0000618class SkRectFanSource {
619public:
620 SkRectFanSource(const SkRect& rect) : fRect(rect) {}
621
622 int count() const { return 4; }
623
624 void writeValue(int i, GrPoint* dstPoint) const {
625 SkASSERT(i < 4);
626 dstPoint->fX = SkScalarToGrScalar((i % 3) ? fRect.fRight :
627 fRect.fLeft);
628 dstPoint->fY = SkScalarToGrScalar((i < 2) ? fRect.fTop :
629 fRect.fBottom);
630 }
631private:
632 const SkRect& fRect;
633};
634
635class SkIRectFanSource {
636public:
637 SkIRectFanSource(const SkIRect& rect) : fRect(rect) {}
638
639 int count() const { return 4; }
640
641 void writeValue(int i, GrPoint* dstPoint) const {
642 SkASSERT(i < 4);
643 dstPoint->fX = (i % 3) ? GrIntToScalar(fRect.fRight) :
644 GrIntToScalar(fRect.fLeft);
645 dstPoint->fY = (i < 2) ? GrIntToScalar(fRect.fTop) :
646 GrIntToScalar(fRect.fBottom);
647 }
648private:
649 const SkIRect& fRect;
650};
651
652class SkMatRectFanSource {
653public:
654 SkMatRectFanSource(const SkRect& rect, const SkMatrix& matrix)
655 : fRect(rect), fMatrix(matrix) {}
656
657 int count() const { return 4; }
658
659 void writeValue(int i, GrPoint* dstPoint) const {
660 SkASSERT(i < 4);
661
662#if SK_SCALAR_IS_GR_SCALAR
663 fMatrix.mapXY((i % 3) ? fRect.fRight : fRect.fLeft,
664 (i < 2) ? fRect.fTop : fRect.fBottom,
665 (SkPoint*)dstPoint);
666#else
667 SkPoint dst;
668 fMatrix.mapXY((i % 3) ? fRect.fRight : fRect.fLeft,
669 (i < 2) ? fRect.fTop : fRect.fBottom,
670 &dst);
671 dstPoint->fX = SkScalarToGrScalar(dst.fX);
672 dstPoint->fY = SkScalarToGrScalar(dst.fY);
673#endif
674 }
675private:
676 const SkRect& fRect;
677 const SkMatrix& fMatrix;
678};
679
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000680#endif
681
reed@google.comac10a2d2010-12-22 21:39:39 +0000682///////////////////////////////////////////////////////////////////////////////
683
bsalomon@google.com398109c2011-04-14 18:40:27 +0000684void SkGpuDevice::clear(SkColor color) {
bsalomon@google.com31a58402011-04-27 21:00:02 +0000685 fContext->clear(NULL, color);
bsalomon@google.com398109c2011-04-14 18:40:27 +0000686}
687
reed@google.comac10a2d2010-12-22 21:39:39 +0000688void SkGpuDevice::drawPaint(const SkDraw& draw, const SkPaint& paint) {
689 CHECK_SHOULD_DRAW(draw);
690
bsalomon@google.com5782d712011-01-21 21:03:59 +0000691 GrPaint grPaint;
692 SkAutoCachedTexture act;
Scroggod757df22011-05-16 13:11:16 +0000693 if (!this->skPaint2GrPaintShader(paint,
694 &act,
695 *draw.fMatrix,
696 &grPaint,
697 true)) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000698 return;
699 }
bsalomon@google.com5782d712011-01-21 21:03:59 +0000700
701 fContext->drawPaint(grPaint);
reed@google.comac10a2d2010-12-22 21:39:39 +0000702}
703
704// must be in SkCanvas::PointMode order
bsalomon@google.comffca4002011-02-22 20:34:01 +0000705static const GrPrimitiveType gPointMode2PrimtiveType[] = {
706 kPoints_PrimitiveType,
707 kLines_PrimitiveType,
708 kLineStrip_PrimitiveType
reed@google.comac10a2d2010-12-22 21:39:39 +0000709};
710
711void SkGpuDevice::drawPoints(const SkDraw& draw, SkCanvas::PointMode mode,
bsalomon@google.com5782d712011-01-21 21:03:59 +0000712 size_t count, const SkPoint pts[], const SkPaint& paint) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000713 CHECK_SHOULD_DRAW(draw);
714
715 SkScalar width = paint.getStrokeWidth();
716 if (width < 0) {
717 return;
718 }
719
720 // we only handle hairlines here, else we let the SkDraw call our drawPath()
721 if (width > 0) {
722 draw.drawPoints(mode, count, pts, paint, true);
723 return;
724 }
725
bsalomon@google.com5782d712011-01-21 21:03:59 +0000726 GrPaint grPaint;
727 SkAutoCachedTexture act;
Scroggod757df22011-05-16 13:11:16 +0000728 if (!this->skPaint2GrPaintShader(paint,
729 &act,
730 *draw.fMatrix,
731 &grPaint,
732 true)) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000733 return;
734 }
735
reed@google.comac10a2d2010-12-22 21:39:39 +0000736#if SK_SCALAR_IS_GR_SCALAR
bsalomon@google.com5782d712011-01-21 21:03:59 +0000737 fContext->drawVertices(grPaint,
738 gPointMode2PrimtiveType[mode],
739 count,
740 (GrPoint*)pts,
741 NULL,
742 NULL,
743 NULL,
744 0);
reed@google.comac10a2d2010-12-22 21:39:39 +0000745#else
bsalomon@google.com5782d712011-01-21 21:03:59 +0000746 fContext->drawCustomVertices(grPaint,
747 gPointMode2PrimtiveType[mode],
748 SkPositionSource(pts, count));
reed@google.comac10a2d2010-12-22 21:39:39 +0000749#endif
reed@google.comac10a2d2010-12-22 21:39:39 +0000750}
751
reed@google.comc9aa5872011-04-05 21:05:37 +0000752///////////////////////////////////////////////////////////////////////////////
753
reed@google.comac10a2d2010-12-22 21:39:39 +0000754void SkGpuDevice::drawRect(const SkDraw& draw, const SkRect& rect,
755 const SkPaint& paint) {
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000756 CHECK_SHOULD_DRAW(draw);
757
758 bool doStroke = paint.getStyle() == SkPaint::kStroke_Style;
759 SkScalar width = paint.getStrokeWidth();
760
761 /*
762 We have special code for hairline strokes, miter-strokes, and fills.
763 Anything else we just call our path code.
764 */
765 bool usePath = doStroke && width > 0 &&
766 paint.getStrokeJoin() != SkPaint::kMiter_Join;
767 // another reason we might need to call drawPath...
768 if (paint.getMaskFilter()) {
769 usePath = true;
770 }
reed@google.com67db6642011-05-26 11:46:35 +0000771 // until we aa rotated rects...
772 if (!usePath && paint.isAntiAlias() && !draw.fMatrix->rectStaysRect()) {
773 usePath = true;
774 }
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000775
776 if (usePath) {
777 SkPath path;
778 path.addRect(rect);
779 this->drawPath(draw, path, paint, NULL, true);
780 return;
781 }
782
783 GrPaint grPaint;
784 SkAutoCachedTexture act;
Scroggod757df22011-05-16 13:11:16 +0000785 if (!this->skPaint2GrPaintShader(paint,
786 &act,
787 *draw.fMatrix,
788 &grPaint,
789 true)) {
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000790 return;
791 }
reed@google.com20efde72011-05-09 17:00:02 +0000792 fContext->drawRect(grPaint, rect, doStroke ? width : -1);
reed@google.comac10a2d2010-12-22 21:39:39 +0000793}
794
reed@google.com69302852011-02-16 18:08:07 +0000795#include "SkMaskFilter.h"
796#include "SkBounder.h"
797
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +0000798static GrPathFill skToGrFillType(SkPath::FillType fillType) {
799 switch (fillType) {
800 case SkPath::kWinding_FillType:
801 return kWinding_PathFill;
802 case SkPath::kEvenOdd_FillType:
803 return kEvenOdd_PathFill;
804 case SkPath::kInverseWinding_FillType:
805 return kInverseWinding_PathFill;
806 case SkPath::kInverseEvenOdd_FillType:
807 return kInverseEvenOdd_PathFill;
808 default:
809 SkDebugf("Unsupported path fill type\n");
810 return kHairLine_PathFill;
811 }
812}
813
senorblanco@chromium.orgb08ea1b2011-07-12 16:54:59 +0000814static void buildKernel(float sigma, float* kernel, int kernelWidth) {
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +0000815 int halfWidth = (kernelWidth - 1) / 2;
816 float sum = 0.0f;
senorblanco@chromium.orgb08ea1b2011-07-12 16:54:59 +0000817 float denom = 1.0f / (2.0f * sigma * sigma);
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +0000818 for (int i = 0; i < kernelWidth; ++i) {
senorblanco@chromium.orgb08ea1b2011-07-12 16:54:59 +0000819 float x = static_cast<float>(i - halfWidth);
820 // Note that the constant term (1/(sqrt(2*pi*sigma^2)) of the Gaussian
821 // is dropped here, since we renormalize the kernel below.
822 kernel[i] = sk_float_exp(- x * x * denom);
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +0000823 sum += kernel[i];
824 }
825 // Normalize the kernel
826 float scale = 1.0f / sum;
827 for (int i = 0; i < kernelWidth; ++i)
828 kernel[i] *= scale;
829}
830
senorblanco@chromium.orgb08ea1b2011-07-12 16:54:59 +0000831static void scaleRect(SkRect* rect, float scale) {
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +0000832 rect->fLeft *= scale;
833 rect->fTop *= scale;
834 rect->fRight *= scale;
835 rect->fBottom *= scale;
836}
837
838static bool drawWithGPUMaskFilter(GrContext* context, const SkPath& path,
839 SkMaskFilter* filter, const SkMatrix& matrix,
840 const SkRegion& clip, SkBounder* bounder,
841 GrPaint* grp) {
senorblanco@chromium.orgaadd9f82011-07-12 19:44:51 +0000842#if !USE_GPU_BLUR
843 return false;
senorblanco@chromium.orgb08ea1b2011-07-12 16:54:59 +0000844#endif
senorblanco@chromium.orgaadd9f82011-07-12 19:44:51 +0000845 SkMaskFilter::BlurInfo info;
846 SkMaskFilter::BlurType blurType = filter->asABlur(&info);
senorblanco@chromium.orgb08ea1b2011-07-12 16:54:59 +0000847 if (SkMaskFilter::kNone_BlurType == blurType) {
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +0000848 return false;
849 }
senorblanco@chromium.orge36ddf02011-07-15 14:28:16 +0000850 SkScalar radius = info.fIgnoreTransform ? info.fRadius
851 : matrix.mapRadius(info.fRadius);
852 radius = SkMinScalar(radius, MAX_BLUR_RADIUS);
853 float sigma = SkScalarToFloat(radius) * BLUR_SIGMA_SCALE;
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +0000854 SkRect srcRect = path.getBounds();
855
856 int scaleFactor = 1;
857
senorblanco@chromium.orge36ddf02011-07-15 14:28:16 +0000858 while (sigma > MAX_BLUR_SIGMA) {
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +0000859 scaleFactor *= 2;
860 sigma *= 0.5f;
861 }
862 scaleRect(&srcRect, 1.0f / scaleFactor);
863 int halfWidth = static_cast<int>(sigma * 3.0f);
864 int kernelWidth = halfWidth * 2 + 1;
865
866 SkIRect srcIRect;
867 srcRect.roundOut(&srcIRect);
868 srcRect.set(srcIRect);
869 srcRect.inset(-halfWidth, -halfWidth);
870
871 scaleRect(&srcRect, scaleFactor);
872 SkRect finalRect = srcRect;
873
874 SkIRect finalIRect;
875 finalRect.roundOut(&finalIRect);
876 if (clip.quickReject(finalIRect)) {
senorblanco@chromium.orgaadd9f82011-07-12 19:44:51 +0000877 return true;
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +0000878 }
879 if (bounder && !bounder->doIRect(finalIRect)) {
senorblanco@chromium.orgaadd9f82011-07-12 19:44:51 +0000880 return true;
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +0000881 }
882 GrPoint offset = GrPoint::Make(-srcRect.fLeft, -srcRect.fTop);
883 srcRect.offset(-srcRect.fLeft, -srcRect.fTop);
884 const GrTextureDesc desc = {
885 kRenderTarget_GrTextureFlagBit,
886 kNone_GrAALevel,
887 srcRect.width(),
888 srcRect.height(),
889 // We actually only need A8, but it often isn't supported as a
890 // render target
891 kRGBA_8888_GrPixelConfig
892 };
893
894 GrTextureEntry* srcEntry = context->findApproximateKeylessTexture(desc);
895 GrTextureEntry* dstEntry = context->findApproximateKeylessTexture(desc);
senorblanco@chromium.orgaadd9f82011-07-12 19:44:51 +0000896 GrAutoUnlockTextureEntry srcLock(context, srcEntry),
897 dstLock(context, dstEntry);
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +0000898 if (NULL == srcEntry || NULL == dstEntry) {
899 return false;
900 }
901 GrTexture* srcTexture = srcEntry->texture();
902 GrTexture* dstTexture = dstEntry->texture();
903 if (NULL == srcTexture || NULL == dstTexture) {
904 return false;
905 }
906 GrRenderTarget* oldRenderTarget = context->getRenderTarget();
senorblanco@chromium.org42dd0f92011-07-14 15:29:57 +0000907 // Once this code moves into GrContext, this should be changed to use
908 // an AutoClipRestore.
909 GrClip oldClip = context->getClip();
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +0000910 context->setRenderTarget(dstTexture->asRenderTarget());
senorblanco@chromium.org42dd0f92011-07-14 15:29:57 +0000911 context->setClip(srcRect);
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +0000912 // FIXME: could just clear bounds
913 context->clear(NULL, 0);
914 GrMatrix transM;
915 GrPaint tempPaint;
916 tempPaint.reset();
917
918 GrAutoMatrix avm(context, GrMatrix::I());
senorblanco@chromium.orgb08ea1b2011-07-12 16:54:59 +0000919 tempPaint.fAntiAlias = grp->fAntiAlias;
920 if (tempPaint.fAntiAlias) {
921 // AA uses the "coverage" stages on GrDrawTarget. Coverage with a dst
922 // blend coeff of zero requires dual source blending support in order
923 // to properly blend partially covered pixels. This means the AA
924 // code path may not be taken. So we use a dst blend coeff of ISA. We
925 // could special case AA draws to a dst surface with known alpha=0 to
926 // use a zero dst coeff when dual source blending isn't available.
927 tempPaint.fSrcBlendCoeff = kOne_BlendCoeff;
928 tempPaint.fDstBlendCoeff = kISC_BlendCoeff;
929 }
930 // Draw hard shadow to dstTexture with path topleft at origin 0,0.
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +0000931 context->drawPath(tempPaint, path, skToGrFillType(path.getFillType()), &offset);
senorblanco@chromium.orgb08ea1b2011-07-12 16:54:59 +0000932 SkTSwap(srcTexture, dstTexture);
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +0000933
934 GrMatrix sampleM;
935 sampleM.setScale(GR_Scalar1 / srcTexture->width(),
936 GR_Scalar1 / srcTexture->height());
937 GrPaint paint;
938 paint.reset();
939 paint.getTextureSampler(0)->setFilter(GrSamplerState::kBilinear_Filter);
940 paint.getTextureSampler(0)->setMatrix(sampleM);
senorblanco@chromium.orgb08ea1b2011-07-12 16:54:59 +0000941 GrTextureEntry* origEntry = NULL;
942 if (blurType != SkMaskFilter::kNormal_BlurType) {
943 // Stash away a copy of the unblurred image.
944 origEntry = context->findApproximateKeylessTexture(desc);
945 if (NULL == origEntry) {
946 return false;
947 }
948 context->setRenderTarget(origEntry->texture()->asRenderTarget());
949 paint.setTexture(0, srcTexture);
950 context->drawRect(paint, srcRect);
951 }
senorblanco@chromium.orgaadd9f82011-07-12 19:44:51 +0000952 GrAutoUnlockTextureEntry origLock(context, origEntry);
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +0000953 for (int i = 1; i < scaleFactor; i *= 2) {
954 context->setRenderTarget(dstTexture->asRenderTarget());
955 SkRect dstRect(srcRect);
956 scaleRect(&dstRect, 0.5f);
957 // Clear out 1 pixel border for linear filtering.
958 // FIXME: for now, clear everything
959 context->clear(NULL, 0);
960 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.org027de5f2011-07-08 18:03:33 +0000970 context->setRenderTarget(dstTexture->asRenderTarget());
971 context->clear(NULL, 0);
senorblanco@chromium.orgaadd9f82011-07-12 19:44:51 +0000972 context->convolveInX(srcTexture, srcRect, kernel, kernelWidth);
senorblanco@chromium.orgb08ea1b2011-07-12 16:54:59 +0000973 SkTSwap(srcTexture, dstTexture);
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +0000974
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +0000975 context->setRenderTarget(dstTexture->asRenderTarget());
976 context->clear(NULL, 0);
senorblanco@chromium.orgaadd9f82011-07-12 19:44:51 +0000977 context->convolveInY(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
980 if (scaleFactor > 1) {
981 // FIXME: This should be mitchell, not bilinear.
982 paint.getTextureSampler(0)->setFilter(GrSamplerState::kBilinear_Filter);
983 sampleM.setScale(GR_Scalar1 / srcTexture->width(),
984 GR_Scalar1 / srcTexture->height());
985 paint.getTextureSampler(0)->setMatrix(sampleM);
986 context->setRenderTarget(dstTexture->asRenderTarget());
987 // Clear out 2 pixel border for bicubic filtering.
988 // FIXME: for now, clear everything
989 context->clear(NULL, 0);
990 paint.setTexture(0, srcTexture);
991 SkRect dstRect(srcRect);
992 scaleRect(&dstRect, scaleFactor);
993 context->drawRectToRect(paint, dstRect, srcRect);
994 srcRect = dstRect;
senorblanco@chromium.orgb08ea1b2011-07-12 16:54:59 +0000995 SkTSwap(srcTexture, dstTexture);
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +0000996 }
997
senorblanco@chromium.orgb08ea1b2011-07-12 16:54:59 +0000998 if (blurType != SkMaskFilter::kNormal_BlurType) {
999 GrTexture* origTexture = origEntry->texture();
1000 paint.getTextureSampler(0)->setFilter(GrSamplerState::kNearest_Filter);
1001 sampleM.setScale(GR_Scalar1 / origTexture->width(),
1002 GR_Scalar1 / origTexture->height());
1003 paint.getTextureSampler(0)->setMatrix(sampleM);
1004 // Blend origTexture over srcTexture.
1005 context->setRenderTarget(srcTexture->asRenderTarget());
1006 paint.setTexture(0, origTexture);
1007 if (SkMaskFilter::kInner_BlurType == blurType) {
1008 // inner: dst = dst * src
1009 paint.fSrcBlendCoeff = kDC_BlendCoeff;
1010 paint.fDstBlendCoeff = kZero_BlendCoeff;
1011 } else if (SkMaskFilter::kSolid_BlurType == blurType) {
1012 // solid: dst = src + dst - src * dst
1013 // = (1 - dst) * src + 1 * dst
1014 paint.fSrcBlendCoeff = kIDC_BlendCoeff;
1015 paint.fDstBlendCoeff = kOne_BlendCoeff;
1016 } else if (SkMaskFilter::kOuter_BlurType == blurType) {
1017 // outer: dst = dst * (1 - src)
1018 // = 0 * src + (1 - src) * dst
1019 paint.fSrcBlendCoeff = kZero_BlendCoeff;
1020 paint.fDstBlendCoeff = kISC_BlendCoeff;
1021 }
1022 context->drawRect(paint, srcRect);
1023 }
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +00001024 context->setRenderTarget(oldRenderTarget);
senorblanco@chromium.org42dd0f92011-07-14 15:29:57 +00001025 context->setClip(oldClip);
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +00001026
1027 if (grp->hasTextureOrMask()) {
1028 GrMatrix inverse;
1029 if (!matrix.invert(&inverse)) {
1030 return false;
1031 }
1032 grp->preConcatActiveSamplerMatrices(inverse);
1033 }
1034
1035 static const int MASK_IDX = GrPaint::kMaxMasks - 1;
1036 // we assume the last mask index is available for use
1037 GrAssert(NULL == grp->getMask(MASK_IDX));
1038 grp->setMask(MASK_IDX, srcTexture);
1039 grp->getMaskSampler(MASK_IDX)->setClampNoFilter();
1040
1041 GrMatrix m;
1042 m.setTranslate(-finalRect.fLeft, -finalRect.fTop);
1043 m.postIDiv(srcTexture->width(), srcTexture->height());
1044 grp->getMaskSampler(MASK_IDX)->setMatrix(m);
1045 context->drawRect(*grp, finalRect);
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +00001046 return true;
1047}
1048
reed@google.com69302852011-02-16 18:08:07 +00001049static bool drawWithMaskFilter(GrContext* context, const SkPath& path,
1050 SkMaskFilter* filter, const SkMatrix& matrix,
1051 const SkRegion& clip, SkBounder* bounder,
1052 GrPaint* grp) {
1053 SkMask srcM, dstM;
1054
1055 if (!SkDraw::DrawToMask(path, &clip.getBounds(), filter, &matrix, &srcM,
1056 SkMask::kComputeBoundsAndRenderImage_CreateMode)) {
1057 return false;
1058 }
1059
1060 SkAutoMaskImage autoSrc(&srcM, false);
1061
1062 if (!filter->filterMask(&dstM, srcM, matrix, NULL)) {
1063 return false;
1064 }
1065 // this will free-up dstM when we're done (allocated in filterMask())
1066 SkAutoMaskImage autoDst(&dstM, false);
1067
1068 if (clip.quickReject(dstM.fBounds)) {
1069 return false;
1070 }
1071 if (bounder && !bounder->doIRect(dstM.fBounds)) {
1072 return false;
1073 }
1074
1075 // we now have a device-aligned 8bit mask in dstM, ready to be drawn using
1076 // the current clip (and identity matrix) and grpaint settings
1077
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001078 // used to compute inverse view, if necessary
1079 GrMatrix ivm = context->getMatrix();
1080
reed@google.com0c219b62011-02-16 21:31:18 +00001081 GrAutoMatrix avm(context, GrMatrix::I());
reed@google.com69302852011-02-16 18:08:07 +00001082
bsalomon@google.comfea37b52011-04-25 15:51:06 +00001083 const GrTextureDesc desc = {
1084 kNone_GrTextureFlags,
1085 kNone_GrAALevel,
reed@google.com69302852011-02-16 18:08:07 +00001086 dstM.fBounds.width(),
1087 dstM.fBounds.height(),
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001088 kAlpha_8_GrPixelConfig
reed@google.com69302852011-02-16 18:08:07 +00001089 };
1090
bsalomon@google.comeb2aa1d2011-07-14 15:45:19 +00001091 GrAutoUnlockTextureEntry aute(context,
1092 context->findApproximateKeylessTexture(desc));
1093 GrTexture* texture = aute.texture();
1094
reed@google.com69302852011-02-16 18:08:07 +00001095 if (NULL == texture) {
1096 return false;
1097 }
bsalomon@google.comeb2aa1d2011-07-14 15:45:19 +00001098 texture->uploadTextureData(0, 0, desc.fWidth, desc.fHeight,
1099 dstM.fImage, dstM.fRowBytes);
reed@google.com69302852011-02-16 18:08:07 +00001100
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001101 if (grp->hasTextureOrMask() && ivm.invert(&ivm)) {
1102 grp->preConcatActiveSamplerMatrices(ivm);
1103 }
1104
1105 static const int MASK_IDX = GrPaint::kMaxMasks - 1;
1106 // we assume the last mask index is available for use
1107 GrAssert(NULL == grp->getMask(MASK_IDX));
1108 grp->setMask(MASK_IDX, texture);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001109 grp->getMaskSampler(MASK_IDX)->setClampNoFilter();
reed@google.com69302852011-02-16 18:08:07 +00001110
bsalomon@google.comc6cf7232011-02-17 16:43:10 +00001111 GrRect d;
1112 d.setLTRB(GrIntToScalar(dstM.fBounds.fLeft),
reed@google.com0c219b62011-02-16 21:31:18 +00001113 GrIntToScalar(dstM.fBounds.fTop),
1114 GrIntToScalar(dstM.fBounds.fRight),
1115 GrIntToScalar(dstM.fBounds.fBottom));
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001116
1117 GrMatrix m;
1118 m.setTranslate(-dstM.fBounds.fLeft, -dstM.fBounds.fTop);
bsalomon@google.comeb2aa1d2011-07-14 15:45:19 +00001119 m.postIDiv(texture->width(), texture->height());
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001120 grp->getMaskSampler(MASK_IDX)->setMatrix(m);
1121
1122 context->drawRect(*grp, d);
reed@google.com69302852011-02-16 18:08:07 +00001123 return true;
1124}
reed@google.com69302852011-02-16 18:08:07 +00001125
reed@google.com0c219b62011-02-16 21:31:18 +00001126void SkGpuDevice::drawPath(const SkDraw& draw, const SkPath& origSrcPath,
reed@google.comac10a2d2010-12-22 21:39:39 +00001127 const SkPaint& paint, const SkMatrix* prePathMatrix,
1128 bool pathIsMutable) {
1129 CHECK_SHOULD_DRAW(draw);
1130
bsalomon@google.com5782d712011-01-21 21:03:59 +00001131 GrPaint grPaint;
1132 SkAutoCachedTexture act;
Scroggod757df22011-05-16 13:11:16 +00001133 if (!this->skPaint2GrPaintShader(paint,
1134 &act,
1135 *draw.fMatrix,
1136 &grPaint,
1137 true)) {
reed@google.comac10a2d2010-12-22 21:39:39 +00001138 return;
1139 }
1140
reed@google.com0c219b62011-02-16 21:31:18 +00001141 // BEGIN lift from SkDraw::drawPath()
1142
1143 SkPath* pathPtr = const_cast<SkPath*>(&origSrcPath);
1144 bool doFill = true;
1145 SkPath tmpPath;
reed@google.comac10a2d2010-12-22 21:39:39 +00001146
1147 if (prePathMatrix) {
reed@google.come3445642011-02-16 23:20:39 +00001148 SkPath* result = pathPtr;
reed@google.com0c219b62011-02-16 21:31:18 +00001149
reed@google.come3445642011-02-16 23:20:39 +00001150 if (!pathIsMutable) {
1151 result = &tmpPath;
1152 pathIsMutable = true;
reed@google.comac10a2d2010-12-22 21:39:39 +00001153 }
reed@google.come3445642011-02-16 23:20:39 +00001154 // should I push prePathMatrix on our MV stack temporarily, instead
1155 // of applying it here? See SkDraw.cpp
1156 pathPtr->transform(*prePathMatrix, result);
1157 pathPtr = result;
reed@google.comac10a2d2010-12-22 21:39:39 +00001158 }
reed@google.com0c219b62011-02-16 21:31:18 +00001159 // at this point we're done with prePathMatrix
1160 SkDEBUGCODE(prePathMatrix = (const SkMatrix*)0x50FF8001;)
reed@google.comac10a2d2010-12-22 21:39:39 +00001161
bsalomon@google.com04de7822011-03-25 18:04:43 +00001162 // This "if" is not part of the SkDraw::drawPath() lift.
1163 // When we get a 1.0 wide stroke we hairline stroke it instead of creating
1164 // a new stroked-path. This is motivated by canvas2D sites that draw
1165 // lines as 1.0 wide stroked paths. We can consider doing an alpha-modulated-
1166 // hairline for width < 1.0 when AA is enabled.
1167 static const int gMatrixMask = ~(SkMatrix::kIdentity_Mask |
1168 SkMatrix::kTranslate_Mask);
1169 if (!paint.getPathEffect() &&
1170 SkPaint::kStroke_Style == paint.getStyle() &&
1171 !(draw.fMatrix->getType() & gMatrixMask) &&
1172 SK_Scalar1 == paint.getStrokeWidth()) {
1173 doFill = false;
1174 }
1175
1176 if (doFill && (paint.getPathEffect() ||
1177 paint.getStyle() != SkPaint::kFill_Style)) {
reed@google.com0c219b62011-02-16 21:31:18 +00001178 doFill = paint.getFillPath(*pathPtr, &tmpPath);
1179 pathPtr = &tmpPath;
1180 }
1181
1182 // END lift from SkDraw::drawPath()
1183
reed@google.com69302852011-02-16 18:08:07 +00001184 if (paint.getMaskFilter()) {
reed@google.com0c219b62011-02-16 21:31:18 +00001185 // avoid possibly allocating a new path in transform if we can
1186 SkPath* devPathPtr = pathIsMutable ? pathPtr : &tmpPath;
1187
1188 // transform the path into device space
reed@google.come3445642011-02-16 23:20:39 +00001189 pathPtr->transform(*draw.fMatrix, devPathPtr);
senorblanco@chromium.orgb08ea1b2011-07-12 16:54:59 +00001190 if (!drawWithGPUMaskFilter(fContext, *devPathPtr, paint.getMaskFilter(),
1191 *draw.fMatrix, *draw.fClip, draw.fBounder,
1192 &grPaint)) {
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +00001193 drawWithMaskFilter(fContext, *devPathPtr, paint.getMaskFilter(),
1194 *draw.fMatrix, *draw.fClip, draw.fBounder,
1195 &grPaint);
1196 }
reed@google.com69302852011-02-16 18:08:07 +00001197 return;
1198 }
reed@google.com69302852011-02-16 18:08:07 +00001199
bsalomon@google.comffca4002011-02-22 20:34:01 +00001200 GrPathFill fill = kHairLine_PathFill;
reed@google.comac10a2d2010-12-22 21:39:39 +00001201
reed@google.com0c219b62011-02-16 21:31:18 +00001202 if (doFill) {
1203 switch (pathPtr->getFillType()) {
reed@google.comac10a2d2010-12-22 21:39:39 +00001204 case SkPath::kWinding_FillType:
bsalomon@google.comffca4002011-02-22 20:34:01 +00001205 fill = kWinding_PathFill;
reed@google.comac10a2d2010-12-22 21:39:39 +00001206 break;
1207 case SkPath::kEvenOdd_FillType:
bsalomon@google.comffca4002011-02-22 20:34:01 +00001208 fill = kEvenOdd_PathFill;
reed@google.comac10a2d2010-12-22 21:39:39 +00001209 break;
1210 case SkPath::kInverseWinding_FillType:
bsalomon@google.comffca4002011-02-22 20:34:01 +00001211 fill = kInverseWinding_PathFill;
reed@google.comac10a2d2010-12-22 21:39:39 +00001212 break;
1213 case SkPath::kInverseEvenOdd_FillType:
bsalomon@google.comffca4002011-02-22 20:34:01 +00001214 fill = kInverseEvenOdd_PathFill;
reed@google.comac10a2d2010-12-22 21:39:39 +00001215 break;
1216 default:
bsalomon@google.com5782d712011-01-21 21:03:59 +00001217 SkDebugf("Unsupported path fill type\n");
reed@google.comac10a2d2010-12-22 21:39:39 +00001218 return;
1219 }
1220 }
1221
reed@google.com07f3ee12011-05-16 17:21:57 +00001222 fContext->drawPath(grPaint, *pathPtr, fill);
reed@google.comac10a2d2010-12-22 21:39:39 +00001223}
1224
reed@google.comac10a2d2010-12-22 21:39:39 +00001225void SkGpuDevice::drawBitmap(const SkDraw& draw,
1226 const SkBitmap& bitmap,
1227 const SkIRect* srcRectPtr,
1228 const SkMatrix& m,
1229 const SkPaint& paint) {
1230 CHECK_SHOULD_DRAW(draw);
1231
1232 SkIRect srcRect;
1233 if (NULL == srcRectPtr) {
1234 srcRect.set(0, 0, bitmap.width(), bitmap.height());
1235 } else {
1236 srcRect = *srcRectPtr;
1237 }
1238
junov@google.comd935cfb2011-06-27 20:48:23 +00001239 if (paint.getMaskFilter()){
epoger@google.com9ef2d832011-07-01 21:12:20 +00001240 SkBitmap tmp; // storage if we need a subset of bitmap
junov@google.comd935cfb2011-06-27 20:48:23 +00001241 const SkBitmap* bitmapPtr = &bitmap;
epoger@google.com9ef2d832011-07-01 21:12:20 +00001242 if (srcRectPtr) {
1243 if (!bitmap.extractSubset(&tmp, srcRect)) {
1244 return; // extraction failed
1245 }
1246 bitmapPtr = &tmp;
junov@google.comd935cfb2011-06-27 20:48:23 +00001247 }
1248 SkPaint paintWithTexture(paint);
1249 paintWithTexture.setShader(SkShader::CreateBitmapShader( *bitmapPtr,
1250 SkShader::kClamp_TileMode, SkShader::kClamp_TileMode))->unref();
1251 paintWithTexture.getShader()->setLocalMatrix(m);
1252
1253 SkRect ScalarRect;
epoger@google.com9ef2d832011-07-01 21:12:20 +00001254 ScalarRect.set(srcRect);
junov@google.comd935cfb2011-06-27 20:48:23 +00001255
epoger@google.com9ef2d832011-07-01 21:12:20 +00001256 if (m.rectStaysRect()) {
1257 // Preferred drawing method, optimized for rectangles
1258 m.mapRect(&ScalarRect);
1259 this->drawRect(draw, ScalarRect, paintWithTexture);
1260 } else {
1261 // Slower drawing method, for warped or rotated rectangles
1262 SkPath path;
1263 path.addRect(ScalarRect);
1264 path.transform(m);
1265 this->drawPath(draw, path, paintWithTexture, NULL, true);
1266 }
junov@google.comd935cfb2011-06-27 20:48:23 +00001267 return;
1268 }
1269
bsalomon@google.com5782d712011-01-21 21:03:59 +00001270 GrPaint grPaint;
Scroggod757df22011-05-16 13:11:16 +00001271 if (!this->skPaint2GrPaintNoShader(paint, true, &grPaint, false)) {
bsalomon@google.com5782d712011-01-21 21:03:59 +00001272 return;
1273 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001274 GrSamplerState* sampler = grPaint.getTextureSampler(kBitmapTextureIdx);
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +00001275 if (paint.isFilterBitmap()) {
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001276 sampler->setFilter(GrSamplerState::kBilinear_Filter);
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +00001277 } else {
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001278 sampler->setFilter(GrSamplerState::kNearest_Filter);
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +00001279 }
bsalomon@google.com5782d712011-01-21 21:03:59 +00001280
bsalomon@google.com91958362011-06-13 17:58:13 +00001281 const int maxTextureSize = fContext->getMaxTextureSize();
1282 if (bitmap.getTexture() || (bitmap.width() <= maxTextureSize &&
1283 bitmap.height() <= maxTextureSize)) {
reed@google.comac10a2d2010-12-22 21:39:39 +00001284 // take the fast case
bsalomon@google.com5782d712011-01-21 21:03:59 +00001285 this->internalDrawBitmap(draw, bitmap, srcRect, m, &grPaint);
reed@google.comac10a2d2010-12-22 21:39:39 +00001286 return;
1287 }
1288
1289 // undo the translate done by SkCanvas
1290 int DX = SkMax32(0, srcRect.fLeft);
1291 int DY = SkMax32(0, srcRect.fTop);
1292 // compute clip bounds in local coordinates
1293 SkIRect clipRect;
1294 {
1295 SkRect r;
1296 r.set(draw.fClip->getBounds());
1297 SkMatrix matrix, inverse;
1298 matrix.setConcat(*draw.fMatrix, m);
1299 if (!matrix.invert(&inverse)) {
1300 return;
1301 }
1302 inverse.mapRect(&r);
1303 r.roundOut(&clipRect);
1304 // apply the canvas' translate to our local clip
1305 clipRect.offset(DX, DY);
1306 }
1307
bsalomon@google.com91958362011-06-13 17:58:13 +00001308 int nx = bitmap.width() / maxTextureSize;
1309 int ny = bitmap.height() / maxTextureSize;
reed@google.comac10a2d2010-12-22 21:39:39 +00001310 for (int x = 0; x <= nx; x++) {
1311 for (int y = 0; y <= ny; y++) {
1312 SkIRect tileR;
bsalomon@google.com91958362011-06-13 17:58:13 +00001313 tileR.set(x * maxTextureSize, y * maxTextureSize,
1314 (x + 1) * maxTextureSize, (y + 1) * maxTextureSize);
reed@google.comac10a2d2010-12-22 21:39:39 +00001315 if (!SkIRect::Intersects(tileR, clipRect)) {
1316 continue;
1317 }
1318
1319 SkIRect srcR = tileR;
1320 if (!srcR.intersect(srcRect)) {
1321 continue;
1322 }
1323
1324 SkBitmap tmpB;
1325 if (bitmap.extractSubset(&tmpB, tileR)) {
1326 // now offset it to make it "local" to our tmp bitmap
1327 srcR.offset(-tileR.fLeft, -tileR.fTop);
1328
1329 SkMatrix tmpM(m);
1330 {
1331 int dx = tileR.fLeft - DX + SkMax32(0, srcR.fLeft);
1332 int dy = tileR.fTop - DY + SkMax32(0, srcR.fTop);
1333 tmpM.preTranslate(SkIntToScalar(dx), SkIntToScalar(dy));
1334 }
bsalomon@google.com5782d712011-01-21 21:03:59 +00001335 this->internalDrawBitmap(draw, tmpB, srcR, tmpM, &grPaint);
reed@google.comac10a2d2010-12-22 21:39:39 +00001336 }
1337 }
1338 }
1339}
1340
1341/*
1342 * This is called by drawBitmap(), which has to handle images that may be too
1343 * large to be represented by a single texture.
1344 *
bsalomon@google.com5782d712011-01-21 21:03:59 +00001345 * internalDrawBitmap assumes that the specified bitmap will fit in a texture
1346 * and that non-texture portion of the GrPaint has already been setup.
reed@google.comac10a2d2010-12-22 21:39:39 +00001347 */
1348void SkGpuDevice::internalDrawBitmap(const SkDraw& draw,
1349 const SkBitmap& bitmap,
1350 const SkIRect& srcRect,
1351 const SkMatrix& m,
bsalomon@google.com5782d712011-01-21 21:03:59 +00001352 GrPaint* grPaint) {
bsalomon@google.com91958362011-06-13 17:58:13 +00001353 SkASSERT(bitmap.width() <= fContext->getMaxTextureSize() &&
1354 bitmap.height() <= fContext->getMaxTextureSize());
reed@google.comac10a2d2010-12-22 21:39:39 +00001355
reed@google.com9c49bc32011-07-07 13:42:37 +00001356 SkAutoLockPixels alp(bitmap, !bitmap.getTexture());
reed@google.comac10a2d2010-12-22 21:39:39 +00001357 if (!bitmap.getTexture() && !bitmap.readyToDraw()) {
reed@google.com9c49bc32011-07-07 13:42:37 +00001358 SkDebugf("nothing to draw\n");
reed@google.comac10a2d2010-12-22 21:39:39 +00001359 return;
1360 }
1361
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001362 GrSamplerState* sampler = grPaint->getTextureSampler(kBitmapTextureIdx);
1363
1364 sampler->setWrapX(GrSamplerState::kClamp_WrapMode);
1365 sampler->setWrapY(GrSamplerState::kClamp_WrapMode);
1366 sampler->setSampleMode(GrSamplerState::kNormal_SampleMode);
1367 sampler->setMatrix(GrMatrix::I());
reed@google.comac10a2d2010-12-22 21:39:39 +00001368
1369 GrTexture* texture;
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001370 SkAutoCachedTexture act(this, bitmap, *sampler, &texture);
reed@google.comac10a2d2010-12-22 21:39:39 +00001371 if (NULL == texture) {
1372 return;
1373 }
1374
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001375 grPaint->setTexture(kShaderTextureIdx, texture);
reed@google.com46799cd2011-02-22 20:56:26 +00001376
reed@google.com20efde72011-05-09 17:00:02 +00001377 GrRect dstRect = SkRect::MakeWH(GrIntToScalar(srcRect.width()),
1378 GrIntToScalar(srcRect.height()));
bsalomon@google.comc6cf7232011-02-17 16:43:10 +00001379 GrRect paintRect;
junov@google.com6acc9b32011-05-16 18:32:07 +00001380 paintRect.setLTRB(GrFixedToScalar((srcRect.fLeft << 16) / bitmap.width()),
1381 GrFixedToScalar((srcRect.fTop << 16) / bitmap.height()),
1382 GrFixedToScalar((srcRect.fRight << 16) / bitmap.width()),
bsalomon@google.comc6cf7232011-02-17 16:43:10 +00001383 GrFixedToScalar((srcRect.fBottom << 16) / bitmap.height()));
reed@google.comac10a2d2010-12-22 21:39:39 +00001384
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001385 if (GrSamplerState::kNearest_Filter != sampler->getFilter() &&
junov@google.com6acc9b32011-05-16 18:32:07 +00001386 (srcRect.width() < bitmap.width() ||
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001387 srcRect.height() < bitmap.height())) {
junov@google.com6acc9b32011-05-16 18:32:07 +00001388 // If drawing a subrect of the bitmap and filtering is enabled,
1389 // use a constrained texture domain to avoid color bleeding
1390 GrScalar left, top, right, bottom;
1391 if (srcRect.width() > 1) {
1392 GrScalar border = GR_ScalarHalf / bitmap.width();
1393 left = paintRect.left() + border;
1394 right = paintRect.right() - border;
1395 } else {
1396 left = right = GrScalarHalf(paintRect.left() + paintRect.right());
1397 }
1398 if (srcRect.height() > 1) {
1399 GrScalar border = GR_ScalarHalf / bitmap.height();
1400 top = paintRect.top() + border;
1401 bottom = paintRect.bottom() - border;
1402 } else {
1403 top = bottom = GrScalarHalf(paintRect.top() + paintRect.bottom());
1404 }
1405 GrRect textureDomain;
1406 textureDomain.setLTRB(left, top, right, bottom);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001407 sampler->setTextureDomain(textureDomain);
junov@google.com6acc9b32011-05-16 18:32:07 +00001408 }
1409
bsalomon@google.comcc4dac32011-05-10 13:52:42 +00001410 fContext->drawRectToRect(*grPaint, dstRect, paintRect, &m);
reed@google.comac10a2d2010-12-22 21:39:39 +00001411}
1412
1413void SkGpuDevice::drawSprite(const SkDraw& draw, const SkBitmap& bitmap,
1414 int left, int top, const SkPaint& paint) {
1415 CHECK_SHOULD_DRAW(draw);
1416
1417 SkAutoLockPixels alp(bitmap);
1418 if (!bitmap.getTexture() && !bitmap.readyToDraw()) {
1419 return;
1420 }
1421
bsalomon@google.com5782d712011-01-21 21:03:59 +00001422 GrPaint grPaint;
Scroggod757df22011-05-16 13:11:16 +00001423 if(!this->skPaint2GrPaintNoShader(paint, true, &grPaint, false)) {
bsalomon@google.com5782d712011-01-21 21:03:59 +00001424 return;
1425 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001426
bsalomon@google.com5782d712011-01-21 21:03:59 +00001427 GrAutoMatrix avm(fContext, GrMatrix::I());
1428
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001429 GrSamplerState* sampler = grPaint.getTextureSampler(kBitmapTextureIdx);
bsalomon@google.com5782d712011-01-21 21:03:59 +00001430
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001431 GrTexture* texture;
1432 sampler->setClampNoFilter();
1433 SkAutoCachedTexture act(this, bitmap, *sampler, &texture);
1434
1435 grPaint.setTexture(kBitmapTextureIdx, texture);
bsalomon@google.com5782d712011-01-21 21:03:59 +00001436
bsalomon@google.com5782d712011-01-21 21:03:59 +00001437 fContext->drawRectToRect(grPaint,
reed@google.com20efde72011-05-09 17:00:02 +00001438 GrRect::MakeXYWH(GrIntToScalar(left),
1439 GrIntToScalar(top),
1440 GrIntToScalar(bitmap.width()),
1441 GrIntToScalar(bitmap.height())),
1442 GrRect::MakeWH(GR_Scalar1, GR_Scalar1));
reed@google.comac10a2d2010-12-22 21:39:39 +00001443}
1444
1445void SkGpuDevice::drawDevice(const SkDraw& draw, SkDevice* dev,
1446 int x, int y, const SkPaint& paint) {
1447 CHECK_SHOULD_DRAW(draw);
1448
bsalomon@google.com5782d712011-01-21 21:03:59 +00001449 GrPaint grPaint;
bsalomon@google.comc6cf7232011-02-17 16:43:10 +00001450 if (!((SkGpuDevice*)dev)->bindDeviceAsTexture(&grPaint) ||
Scroggod757df22011-05-16 13:11:16 +00001451 !this->skPaint2GrPaintNoShader(paint, true, &grPaint, false)) {
bsalomon@google.com5782d712011-01-21 21:03:59 +00001452 return;
reed@google.comac10a2d2010-12-22 21:39:39 +00001453 }
bsalomon@google.com5782d712011-01-21 21:03:59 +00001454
bsalomon@google.comb5b31682011-06-16 18:05:35 +00001455 GrTexture* devTex = grPaint.getTexture(0);
1456 SkASSERT(NULL != devTex);
bsalomon@google.com5782d712011-01-21 21:03:59 +00001457
1458 const SkBitmap& bm = dev->accessBitmap(false);
1459 int w = bm.width();
1460 int h = bm.height();
1461
1462 GrAutoMatrix avm(fContext, GrMatrix::I());
1463
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001464 grPaint.getTextureSampler(kBitmapTextureIdx)->setClampNoFilter();
bsalomon@google.com5782d712011-01-21 21:03:59 +00001465
bsalomon@google.comb5b31682011-06-16 18:05:35 +00001466 GrRect dstRect = GrRect::MakeXYWH(GrIntToScalar(x),
1467 GrIntToScalar(y),
1468 GrIntToScalar(w),
1469 GrIntToScalar(h));
1470 // The device being drawn may not fill up its texture (saveLayer uses
1471 // the approximate ).
1472 GrRect srcRect = GrRect::MakeWH(GR_Scalar1 * w / devTex->width(),
1473 GR_Scalar1 * h / devTex->height());
1474
1475 fContext->drawRectToRect(grPaint, dstRect, srcRect);
reed@google.comac10a2d2010-12-22 21:39:39 +00001476}
1477
1478///////////////////////////////////////////////////////////////////////////////
1479
1480// must be in SkCanvas::VertexMode order
bsalomon@google.comffca4002011-02-22 20:34:01 +00001481static const GrPrimitiveType gVertexMode2PrimitiveType[] = {
1482 kTriangles_PrimitiveType,
1483 kTriangleStrip_PrimitiveType,
1484 kTriangleFan_PrimitiveType,
reed@google.comac10a2d2010-12-22 21:39:39 +00001485};
1486
1487void SkGpuDevice::drawVertices(const SkDraw& draw, SkCanvas::VertexMode vmode,
1488 int vertexCount, const SkPoint vertices[],
1489 const SkPoint texs[], const SkColor colors[],
1490 SkXfermode* xmode,
1491 const uint16_t indices[], int indexCount,
1492 const SkPaint& paint) {
1493 CHECK_SHOULD_DRAW(draw);
1494
bsalomon@google.com5782d712011-01-21 21:03:59 +00001495 GrPaint grPaint;
1496 SkAutoCachedTexture act;
1497 // we ignore the shader if texs is null.
1498 if (NULL == texs) {
Scroggod757df22011-05-16 13:11:16 +00001499 if (!this->skPaint2GrPaintNoShader(paint,
1500 false,
1501 &grPaint,
1502 NULL == colors)) {
reed@google.comac10a2d2010-12-22 21:39:39 +00001503 return;
1504 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001505 } else {
reed@google.com1a2e8d22011-01-21 22:08:29 +00001506 if (!this->skPaint2GrPaintShader(paint, &act,
1507 *draw.fMatrix,
Scroggod757df22011-05-16 13:11:16 +00001508 &grPaint,
1509 NULL == colors)) {
bsalomon@google.com5782d712011-01-21 21:03:59 +00001510 return;
1511 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001512 }
bsalomon@google.com5782d712011-01-21 21:03:59 +00001513
1514 if (NULL != xmode && NULL != texs && NULL != colors) {
1515 SkXfermode::Mode mode;
1516 if (!SkXfermode::IsMode(xmode, &mode) ||
1517 SkXfermode::kMultiply_Mode != mode) {
1518 SkDebugf("Unsupported vertex-color/texture xfer mode.\n");
1519#if 0
1520 return
1521#endif
1522 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001523 }
bsalomon@google.com5782d712011-01-21 21:03:59 +00001524
1525#if SK_SCALAR_IS_GR_SCALAR
1526 // even if GrColor and SkColor byte offsets match we need
1527 // to perform pre-multiply.
1528 if (NULL == colors) {
1529 fContext->drawVertices(grPaint,
1530 gVertexMode2PrimitiveType[vmode],
1531 vertexCount,
1532 (GrPoint*) vertices,
1533 (GrPoint*) texs,
1534 NULL,
1535 indices,
1536 indexCount);
1537 } else
1538#endif
1539 {
1540 SkTexCoordSource texSrc(texs);
1541 SkColorSource colSrc(colors);
1542 SkIndexSource idxSrc(indices, indexCount);
1543
1544 fContext->drawCustomVertices(grPaint,
1545 gVertexMode2PrimitiveType[vmode],
1546 SkPositionSource(vertices, vertexCount),
1547 (NULL == texs) ? NULL : &texSrc,
1548 (NULL == colors) ? NULL : &colSrc,
1549 (NULL == indices) ? NULL : &idxSrc);
reed@google.comac10a2d2010-12-22 21:39:39 +00001550 }
1551}
1552
1553///////////////////////////////////////////////////////////////////////////////
1554
1555static void GlyphCacheAuxProc(void* data) {
1556 delete (GrFontScaler*)data;
1557}
1558
1559static GrFontScaler* get_gr_font_scaler(SkGlyphCache* cache) {
1560 void* auxData;
1561 GrFontScaler* scaler = NULL;
1562 if (cache->getAuxProcData(GlyphCacheAuxProc, &auxData)) {
1563 scaler = (GrFontScaler*)auxData;
1564 }
1565 if (NULL == scaler) {
1566 scaler = new SkGrFontScaler(cache);
1567 cache->setAuxProc(GlyphCacheAuxProc, scaler);
1568 }
1569 return scaler;
1570}
1571
1572static void SkGPU_Draw1Glyph(const SkDraw1Glyph& state,
1573 SkFixed fx, SkFixed fy,
1574 const SkGlyph& glyph) {
1575 SkASSERT(glyph.fWidth > 0 && glyph.fHeight > 0);
1576
1577 GrSkDrawProcs* procs = (GrSkDrawProcs*)state.fDraw->fProcs;
1578
1579 if (NULL == procs->fFontScaler) {
1580 procs->fFontScaler = get_gr_font_scaler(state.fCache);
1581 }
reed@google.com39ce0ac2011-04-08 15:42:19 +00001582
1583 /*
reed@google.com3b139f52011-06-07 17:56:25 +00001584 * What should we do with fy? (assuming horizontal/latin text)
reed@google.com39ce0ac2011-04-08 15:42:19 +00001585 *
reed@google.com3b139f52011-06-07 17:56:25 +00001586 * The raster code calls SkFixedFloorToFixed on it, as it does with fx.
1587 * It calls that rather than round, because our caller has already added
1588 * SK_FixedHalf, so that calling floor gives us the rounded integer.
1589 *
1590 * Test code between raster and gpu (they should draw the same)
1591 *
1592 * canvas->drawText("Hamburgefons", 12, 0, 16.5f, paint);
1593 *
1594 * Perhaps we should only perform this integralization if there is no
1595 * fExtMatrix...
reed@google.com39ce0ac2011-04-08 15:42:19 +00001596 */
reed@google.com3b139f52011-06-07 17:56:25 +00001597 fy = SkFixedFloorToFixed(fy);
1598
reed@google.comac10a2d2010-12-22 21:39:39 +00001599 procs->fTextContext->drawPackedGlyph(GrGlyph::Pack(glyph.getGlyphID(), fx, 0),
reed@google.com3b139f52011-06-07 17:56:25 +00001600 SkFixedFloorToFixed(fx), fy,
reed@google.comac10a2d2010-12-22 21:39:39 +00001601 procs->fFontScaler);
1602}
1603
bsalomon@google.com5782d712011-01-21 21:03:59 +00001604SkDrawProcs* SkGpuDevice::initDrawForText(GrTextContext* context) {
reed@google.comac10a2d2010-12-22 21:39:39 +00001605
1606 // deferred allocation
1607 if (NULL == fDrawProcs) {
1608 fDrawProcs = new GrSkDrawProcs;
1609 fDrawProcs->fD1GProc = SkGPU_Draw1Glyph;
1610 fDrawProcs->fContext = fContext;
1611 }
1612
1613 // init our (and GL's) state
1614 fDrawProcs->fTextContext = context;
1615 fDrawProcs->fFontScaler = NULL;
1616 return fDrawProcs;
1617}
1618
1619void SkGpuDevice::drawText(const SkDraw& draw, const void* text,
1620 size_t byteLength, SkScalar x, SkScalar y,
1621 const SkPaint& paint) {
1622 CHECK_SHOULD_DRAW(draw);
1623
1624 if (draw.fMatrix->getType() & SkMatrix::kPerspective_Mask) {
1625 // this guy will just call our drawPath()
1626 draw.drawText((const char*)text, byteLength, x, y, paint);
1627 } else {
reed@google.comac10a2d2010-12-22 21:39:39 +00001628 SkDraw myDraw(draw);
bsalomon@google.com5782d712011-01-21 21:03:59 +00001629
1630 GrPaint grPaint;
1631 SkAutoCachedTexture act;
1632
Scroggod757df22011-05-16 13:11:16 +00001633 if (!this->skPaint2GrPaintShader(paint,
1634 &act,
1635 *draw.fMatrix,
1636 &grPaint,
1637 true)) {
bsalomon@google.com5782d712011-01-21 21:03:59 +00001638 return;
1639 }
bsalomon@google.comcc4dac32011-05-10 13:52:42 +00001640 GrTextContext context(fContext, grPaint, draw.fExtMatrix);
bsalomon@google.com5782d712011-01-21 21:03:59 +00001641 myDraw.fProcs = this->initDrawForText(&context);
reed@google.comac10a2d2010-12-22 21:39:39 +00001642 this->INHERITED::drawText(myDraw, text, byteLength, x, y, paint);
1643 }
1644}
1645
1646void SkGpuDevice::drawPosText(const SkDraw& draw, const void* text,
1647 size_t byteLength, const SkScalar pos[],
1648 SkScalar constY, int scalarsPerPos,
1649 const SkPaint& paint) {
1650 CHECK_SHOULD_DRAW(draw);
1651
1652 if (draw.fMatrix->getType() & SkMatrix::kPerspective_Mask) {
1653 // this guy will just call our drawPath()
1654 draw.drawPosText((const char*)text, byteLength, pos, constY,
1655 scalarsPerPos, paint);
1656 } else {
reed@google.comac10a2d2010-12-22 21:39:39 +00001657 SkDraw myDraw(draw);
bsalomon@google.com5782d712011-01-21 21:03:59 +00001658
1659 GrPaint grPaint;
1660 SkAutoCachedTexture act;
Scroggod757df22011-05-16 13:11:16 +00001661 if (!this->skPaint2GrPaintShader(paint,
1662 &act,
1663 *draw.fMatrix,
1664 &grPaint,
1665 true)) {
bsalomon@google.com5782d712011-01-21 21:03:59 +00001666 return;
1667 }
1668
bsalomon@google.comcc4dac32011-05-10 13:52:42 +00001669 GrTextContext context(fContext, grPaint, draw.fExtMatrix);
bsalomon@google.com5782d712011-01-21 21:03:59 +00001670 myDraw.fProcs = this->initDrawForText(&context);
reed@google.comac10a2d2010-12-22 21:39:39 +00001671 this->INHERITED::drawPosText(myDraw, text, byteLength, pos, constY,
1672 scalarsPerPos, paint);
1673 }
1674}
1675
1676void SkGpuDevice::drawTextOnPath(const SkDraw& draw, const void* text,
1677 size_t len, const SkPath& path,
1678 const SkMatrix* m, const SkPaint& paint) {
1679 CHECK_SHOULD_DRAW(draw);
1680
1681 SkASSERT(draw.fDevice == this);
1682 draw.drawTextOnPath((const char*)text, len, path, m, paint);
1683}
1684
1685///////////////////////////////////////////////////////////////////////////////
1686
reed@google.comf67e4cf2011-03-15 20:56:58 +00001687bool SkGpuDevice::filterTextFlags(const SkPaint& paint, TextFlags* flags) {
1688 if (!paint.isLCDRenderText()) {
1689 // we're cool with the paint as is
1690 return false;
1691 }
1692
1693 if (paint.getShader() ||
1694 paint.getXfermode() || // unless its srcover
1695 paint.getMaskFilter() ||
1696 paint.getRasterizer() ||
1697 paint.getColorFilter() ||
1698 paint.getPathEffect() ||
1699 paint.isFakeBoldText() ||
1700 paint.getStyle() != SkPaint::kFill_Style) {
1701 // turn off lcd
1702 flags->fFlags = paint.getFlags() & ~SkPaint::kLCDRenderText_Flag;
1703 flags->fHinting = paint.getHinting();
1704 return true;
1705 }
1706 // we're cool with the paint as is
1707 return false;
1708}
1709
1710///////////////////////////////////////////////////////////////////////////////
1711
reed@google.comac10a2d2010-12-22 21:39:39 +00001712SkGpuDevice::TexCache* SkGpuDevice::lockCachedTexture(const SkBitmap& bitmap,
bsalomon@google.comfea37b52011-04-25 15:51:06 +00001713 const GrSamplerState& sampler,
1714 GrTexture** texture,
bsalomon@google.come97f0852011-06-17 13:10:25 +00001715 TexType type) {
bsalomon@google.comfea37b52011-04-25 15:51:06 +00001716 GrTexture* newTexture = NULL;
1717 GrTextureEntry* entry = NULL;
reed@google.comac10a2d2010-12-22 21:39:39 +00001718 GrContext* ctx = this->context();
bsalomon@google.comfea37b52011-04-25 15:51:06 +00001719
bsalomon@google.come97f0852011-06-17 13:10:25 +00001720 if (kBitmap_TexType != type) {
bsalomon@google.comfea37b52011-04-25 15:51:06 +00001721 const GrTextureDesc desc = {
1722 kRenderTarget_GrTextureFlagBit,
1723 kNone_GrAALevel,
1724 bitmap.width(),
1725 bitmap.height(),
1726 SkGr::Bitmap2PixelConfig(bitmap)
1727 };
bsalomon@google.come97f0852011-06-17 13:10:25 +00001728 if (kSaveLayerDeviceRenderTarget_TexType == type) {
bsalomon@google.comb5b31682011-06-16 18:05:35 +00001729 // we know layers will only be drawn through drawDevice.
1730 // drawDevice has been made to work with content embedded in a
1731 // larger texture so its okay to use the approximate version.
1732 entry = ctx->findApproximateKeylessTexture(desc);
1733 } else {
bsalomon@google.come97f0852011-06-17 13:10:25 +00001734 SkASSERT(kDeviceRenderTarget_TexType == type);
bsalomon@google.comb5b31682011-06-16 18:05:35 +00001735 entry = ctx->lockKeylessTexture(desc);
1736 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001737 } else {
junov@google.com4ee7ae52011-06-30 17:30:49 +00001738 if (!bitmap.isVolatile()) {
1739 uint32_t p0, p1;
1740 p0 = bitmap.getGenerationID();
1741 p1 = bitmap.pixelRefOffset();
1742 GrTextureKey key(p0, p1, bitmap.width(), bitmap.height());
1743
1744 entry = ctx->findAndLockTexture(&key, sampler);
1745 if (NULL == entry)
1746 entry = sk_gr_create_bitmap_texture(ctx, &key, sampler,
1747 bitmap);
1748 } else {
1749 entry = sk_gr_create_bitmap_texture(ctx, NULL, sampler, bitmap);
1750 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001751 if (NULL == entry) {
junov@google.com4ee7ae52011-06-30 17:30:49 +00001752 GrPrintf("---- failed to create texture for cache [%d %d]\n",
1753 bitmap.width(), bitmap.height());
reed@google.comac10a2d2010-12-22 21:39:39 +00001754 }
1755 }
1756
1757 if (NULL != entry) {
1758 newTexture = entry->texture();
reed@google.comac10a2d2010-12-22 21:39:39 +00001759 if (texture) {
1760 *texture = newTexture;
1761 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001762 }
1763 return (TexCache*)entry;
1764}
1765
1766void SkGpuDevice::unlockCachedTexture(TexCache* cache) {
1767 this->context()->unlockTexture((GrTextureEntry*)cache);
1768}
1769
bsalomon@google.come97f0852011-06-17 13:10:25 +00001770SkDevice* SkGpuDevice::onCreateCompatibleDevice(SkBitmap::Config config,
1771 int width, int height,
1772 bool isOpaque,
1773 Usage usage) {
1774 return SkNEW_ARGS(SkGpuDevice,(this->context(), config,
1775 width, height, usage));
1776}
1777