blob: 513b5bbdc96245cf9fd52a22b0d34393ef271ce3 [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
bungeman@google.com79bd8772011-07-18 15:34:08 +0000758 bool doStroke = paint.getStyle() != SkPaint::kFill_Style;
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000759 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 }
bungeman@google.com79bd8772011-07-18 15:34:08 +0000775 // until we can both stroke and fill rectangles
776 // with large enough miter limit...
777 if (paint.getStyle() == SkPaint::kStrokeAndFill_Style) {
778 usePath = true;
779 }
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000780
781 if (usePath) {
782 SkPath path;
783 path.addRect(rect);
784 this->drawPath(draw, path, paint, NULL, true);
785 return;
786 }
787
788 GrPaint grPaint;
789 SkAutoCachedTexture act;
Scroggod757df22011-05-16 13:11:16 +0000790 if (!this->skPaint2GrPaintShader(paint,
791 &act,
792 *draw.fMatrix,
793 &grPaint,
794 true)) {
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000795 return;
796 }
reed@google.com20efde72011-05-09 17:00:02 +0000797 fContext->drawRect(grPaint, rect, doStroke ? width : -1);
reed@google.comac10a2d2010-12-22 21:39:39 +0000798}
799
reed@google.com69302852011-02-16 18:08:07 +0000800#include "SkMaskFilter.h"
801#include "SkBounder.h"
802
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +0000803static GrPathFill skToGrFillType(SkPath::FillType fillType) {
804 switch (fillType) {
805 case SkPath::kWinding_FillType:
806 return kWinding_PathFill;
807 case SkPath::kEvenOdd_FillType:
808 return kEvenOdd_PathFill;
809 case SkPath::kInverseWinding_FillType:
810 return kInverseWinding_PathFill;
811 case SkPath::kInverseEvenOdd_FillType:
812 return kInverseEvenOdd_PathFill;
813 default:
814 SkDebugf("Unsupported path fill type\n");
815 return kHairLine_PathFill;
816 }
817}
818
senorblanco@chromium.orgb08ea1b2011-07-12 16:54:59 +0000819static void buildKernel(float sigma, float* kernel, int kernelWidth) {
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +0000820 int halfWidth = (kernelWidth - 1) / 2;
821 float sum = 0.0f;
senorblanco@chromium.orgb08ea1b2011-07-12 16:54:59 +0000822 float denom = 1.0f / (2.0f * sigma * sigma);
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +0000823 for (int i = 0; i < kernelWidth; ++i) {
senorblanco@chromium.orgb08ea1b2011-07-12 16:54:59 +0000824 float x = static_cast<float>(i - halfWidth);
825 // Note that the constant term (1/(sqrt(2*pi*sigma^2)) of the Gaussian
826 // is dropped here, since we renormalize the kernel below.
827 kernel[i] = sk_float_exp(- x * x * denom);
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +0000828 sum += kernel[i];
829 }
830 // Normalize the kernel
831 float scale = 1.0f / sum;
832 for (int i = 0; i < kernelWidth; ++i)
833 kernel[i] *= scale;
834}
835
senorblanco@chromium.orgb08ea1b2011-07-12 16:54:59 +0000836static void scaleRect(SkRect* rect, float scale) {
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +0000837 rect->fLeft *= scale;
838 rect->fTop *= scale;
839 rect->fRight *= scale;
840 rect->fBottom *= scale;
841}
842
843static bool drawWithGPUMaskFilter(GrContext* context, const SkPath& path,
844 SkMaskFilter* filter, const SkMatrix& matrix,
845 const SkRegion& clip, SkBounder* bounder,
846 GrPaint* grp) {
senorblanco@chromium.orgaadd9f82011-07-12 19:44:51 +0000847#if !USE_GPU_BLUR
848 return false;
senorblanco@chromium.orgb08ea1b2011-07-12 16:54:59 +0000849#endif
senorblanco@chromium.orgaadd9f82011-07-12 19:44:51 +0000850 SkMaskFilter::BlurInfo info;
851 SkMaskFilter::BlurType blurType = filter->asABlur(&info);
senorblanco@chromium.orgb08ea1b2011-07-12 16:54:59 +0000852 if (SkMaskFilter::kNone_BlurType == blurType) {
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +0000853 return false;
854 }
senorblanco@chromium.orge36ddf02011-07-15 14:28:16 +0000855 SkScalar radius = info.fIgnoreTransform ? info.fRadius
856 : matrix.mapRadius(info.fRadius);
857 radius = SkMinScalar(radius, MAX_BLUR_RADIUS);
858 float sigma = SkScalarToFloat(radius) * BLUR_SIGMA_SCALE;
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +0000859 SkRect srcRect = path.getBounds();
860
861 int scaleFactor = 1;
862
senorblanco@chromium.orge36ddf02011-07-15 14:28:16 +0000863 while (sigma > MAX_BLUR_SIGMA) {
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +0000864 scaleFactor *= 2;
865 sigma *= 0.5f;
866 }
867 scaleRect(&srcRect, 1.0f / scaleFactor);
868 int halfWidth = static_cast<int>(sigma * 3.0f);
869 int kernelWidth = halfWidth * 2 + 1;
870
871 SkIRect srcIRect;
872 srcRect.roundOut(&srcIRect);
873 srcRect.set(srcIRect);
874 srcRect.inset(-halfWidth, -halfWidth);
875
876 scaleRect(&srcRect, scaleFactor);
877 SkRect finalRect = srcRect;
878
879 SkIRect finalIRect;
880 finalRect.roundOut(&finalIRect);
881 if (clip.quickReject(finalIRect)) {
senorblanco@chromium.orgaadd9f82011-07-12 19:44:51 +0000882 return true;
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +0000883 }
884 if (bounder && !bounder->doIRect(finalIRect)) {
senorblanco@chromium.orgaadd9f82011-07-12 19:44:51 +0000885 return true;
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +0000886 }
887 GrPoint offset = GrPoint::Make(-srcRect.fLeft, -srcRect.fTop);
888 srcRect.offset(-srcRect.fLeft, -srcRect.fTop);
889 const GrTextureDesc desc = {
890 kRenderTarget_GrTextureFlagBit,
891 kNone_GrAALevel,
892 srcRect.width(),
893 srcRect.height(),
894 // We actually only need A8, but it often isn't supported as a
895 // render target
896 kRGBA_8888_GrPixelConfig
897 };
898
899 GrTextureEntry* srcEntry = context->findApproximateKeylessTexture(desc);
900 GrTextureEntry* dstEntry = context->findApproximateKeylessTexture(desc);
senorblanco@chromium.orgaadd9f82011-07-12 19:44:51 +0000901 GrAutoUnlockTextureEntry srcLock(context, srcEntry),
902 dstLock(context, dstEntry);
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +0000903 if (NULL == srcEntry || NULL == dstEntry) {
904 return false;
905 }
906 GrTexture* srcTexture = srcEntry->texture();
907 GrTexture* dstTexture = dstEntry->texture();
908 if (NULL == srcTexture || NULL == dstTexture) {
909 return false;
910 }
911 GrRenderTarget* oldRenderTarget = context->getRenderTarget();
senorblanco@chromium.org42dd0f92011-07-14 15:29:57 +0000912 // Once this code moves into GrContext, this should be changed to use
913 // an AutoClipRestore.
914 GrClip oldClip = context->getClip();
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +0000915 context->setRenderTarget(dstTexture->asRenderTarget());
senorblanco@chromium.org42dd0f92011-07-14 15:29:57 +0000916 context->setClip(srcRect);
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +0000917 // FIXME: could just clear bounds
918 context->clear(NULL, 0);
919 GrMatrix transM;
920 GrPaint tempPaint;
921 tempPaint.reset();
922
923 GrAutoMatrix avm(context, GrMatrix::I());
senorblanco@chromium.orgb08ea1b2011-07-12 16:54:59 +0000924 tempPaint.fAntiAlias = grp->fAntiAlias;
925 if (tempPaint.fAntiAlias) {
926 // AA uses the "coverage" stages on GrDrawTarget. Coverage with a dst
927 // blend coeff of zero requires dual source blending support in order
928 // to properly blend partially covered pixels. This means the AA
929 // code path may not be taken. So we use a dst blend coeff of ISA. We
930 // could special case AA draws to a dst surface with known alpha=0 to
931 // use a zero dst coeff when dual source blending isn't available.
932 tempPaint.fSrcBlendCoeff = kOne_BlendCoeff;
933 tempPaint.fDstBlendCoeff = kISC_BlendCoeff;
934 }
935 // Draw hard shadow to dstTexture with path topleft at origin 0,0.
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +0000936 context->drawPath(tempPaint, path, skToGrFillType(path.getFillType()), &offset);
senorblanco@chromium.orgb08ea1b2011-07-12 16:54:59 +0000937 SkTSwap(srcTexture, dstTexture);
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +0000938
939 GrMatrix sampleM;
940 sampleM.setScale(GR_Scalar1 / srcTexture->width(),
941 GR_Scalar1 / srcTexture->height());
942 GrPaint paint;
943 paint.reset();
944 paint.getTextureSampler(0)->setFilter(GrSamplerState::kBilinear_Filter);
945 paint.getTextureSampler(0)->setMatrix(sampleM);
senorblanco@chromium.orgb08ea1b2011-07-12 16:54:59 +0000946 GrTextureEntry* origEntry = NULL;
947 if (blurType != SkMaskFilter::kNormal_BlurType) {
948 // Stash away a copy of the unblurred image.
949 origEntry = context->findApproximateKeylessTexture(desc);
950 if (NULL == origEntry) {
951 return false;
952 }
953 context->setRenderTarget(origEntry->texture()->asRenderTarget());
954 paint.setTexture(0, srcTexture);
955 context->drawRect(paint, srcRect);
956 }
senorblanco@chromium.orgaadd9f82011-07-12 19:44:51 +0000957 GrAutoUnlockTextureEntry origLock(context, origEntry);
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +0000958 for (int i = 1; i < scaleFactor; i *= 2) {
959 context->setRenderTarget(dstTexture->asRenderTarget());
960 SkRect dstRect(srcRect);
961 scaleRect(&dstRect, 0.5f);
962 // Clear out 1 pixel border for linear filtering.
963 // FIXME: for now, clear everything
964 context->clear(NULL, 0);
965 paint.setTexture(0, srcTexture);
966 context->drawRectToRect(paint, dstRect, srcRect);
967 srcRect = dstRect;
senorblanco@chromium.orgb08ea1b2011-07-12 16:54:59 +0000968 SkTSwap(srcTexture, dstTexture);
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +0000969 }
970
971 SkAutoTMalloc<float> kernelStorage(kernelWidth);
972 float* kernel = kernelStorage.get();
973 buildKernel(sigma, kernel, kernelWidth);
974
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->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.org027de5f2011-07-08 18:03:33 +0000980 context->setRenderTarget(dstTexture->asRenderTarget());
981 context->clear(NULL, 0);
senorblanco@chromium.orgaadd9f82011-07-12 19:44:51 +0000982 context->convolveInY(srcTexture, srcRect, kernel, kernelWidth);
senorblanco@chromium.orgb08ea1b2011-07-12 16:54:59 +0000983 SkTSwap(srcTexture, dstTexture);
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +0000984
985 if (scaleFactor > 1) {
986 // FIXME: This should be mitchell, not bilinear.
987 paint.getTextureSampler(0)->setFilter(GrSamplerState::kBilinear_Filter);
988 sampleM.setScale(GR_Scalar1 / srcTexture->width(),
989 GR_Scalar1 / srcTexture->height());
990 paint.getTextureSampler(0)->setMatrix(sampleM);
991 context->setRenderTarget(dstTexture->asRenderTarget());
992 // Clear out 2 pixel border for bicubic filtering.
993 // FIXME: for now, clear everything
994 context->clear(NULL, 0);
995 paint.setTexture(0, srcTexture);
996 SkRect dstRect(srcRect);
997 scaleRect(&dstRect, scaleFactor);
998 context->drawRectToRect(paint, dstRect, srcRect);
999 srcRect = dstRect;
senorblanco@chromium.orgb08ea1b2011-07-12 16:54:59 +00001000 SkTSwap(srcTexture, dstTexture);
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +00001001 }
1002
senorblanco@chromium.orgb08ea1b2011-07-12 16:54:59 +00001003 if (blurType != SkMaskFilter::kNormal_BlurType) {
1004 GrTexture* origTexture = origEntry->texture();
1005 paint.getTextureSampler(0)->setFilter(GrSamplerState::kNearest_Filter);
1006 sampleM.setScale(GR_Scalar1 / origTexture->width(),
1007 GR_Scalar1 / origTexture->height());
1008 paint.getTextureSampler(0)->setMatrix(sampleM);
1009 // Blend origTexture over srcTexture.
1010 context->setRenderTarget(srcTexture->asRenderTarget());
1011 paint.setTexture(0, origTexture);
1012 if (SkMaskFilter::kInner_BlurType == blurType) {
1013 // inner: dst = dst * src
1014 paint.fSrcBlendCoeff = kDC_BlendCoeff;
1015 paint.fDstBlendCoeff = kZero_BlendCoeff;
1016 } else if (SkMaskFilter::kSolid_BlurType == blurType) {
1017 // solid: dst = src + dst - src * dst
1018 // = (1 - dst) * src + 1 * dst
1019 paint.fSrcBlendCoeff = kIDC_BlendCoeff;
1020 paint.fDstBlendCoeff = kOne_BlendCoeff;
1021 } else if (SkMaskFilter::kOuter_BlurType == blurType) {
1022 // outer: dst = dst * (1 - src)
1023 // = 0 * src + (1 - src) * dst
1024 paint.fSrcBlendCoeff = kZero_BlendCoeff;
1025 paint.fDstBlendCoeff = kISC_BlendCoeff;
1026 }
1027 context->drawRect(paint, srcRect);
1028 }
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +00001029 context->setRenderTarget(oldRenderTarget);
senorblanco@chromium.org42dd0f92011-07-14 15:29:57 +00001030 context->setClip(oldClip);
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +00001031
1032 if (grp->hasTextureOrMask()) {
1033 GrMatrix inverse;
1034 if (!matrix.invert(&inverse)) {
1035 return false;
1036 }
1037 grp->preConcatActiveSamplerMatrices(inverse);
1038 }
1039
1040 static const int MASK_IDX = GrPaint::kMaxMasks - 1;
1041 // we assume the last mask index is available for use
1042 GrAssert(NULL == grp->getMask(MASK_IDX));
1043 grp->setMask(MASK_IDX, srcTexture);
1044 grp->getMaskSampler(MASK_IDX)->setClampNoFilter();
1045
1046 GrMatrix m;
1047 m.setTranslate(-finalRect.fLeft, -finalRect.fTop);
1048 m.postIDiv(srcTexture->width(), srcTexture->height());
1049 grp->getMaskSampler(MASK_IDX)->setMatrix(m);
1050 context->drawRect(*grp, finalRect);
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +00001051 return true;
1052}
1053
reed@google.com69302852011-02-16 18:08:07 +00001054static bool drawWithMaskFilter(GrContext* context, const SkPath& path,
1055 SkMaskFilter* filter, const SkMatrix& matrix,
1056 const SkRegion& clip, SkBounder* bounder,
1057 GrPaint* grp) {
1058 SkMask srcM, dstM;
1059
1060 if (!SkDraw::DrawToMask(path, &clip.getBounds(), filter, &matrix, &srcM,
1061 SkMask::kComputeBoundsAndRenderImage_CreateMode)) {
1062 return false;
1063 }
1064
1065 SkAutoMaskImage autoSrc(&srcM, false);
1066
1067 if (!filter->filterMask(&dstM, srcM, matrix, NULL)) {
1068 return false;
1069 }
1070 // this will free-up dstM when we're done (allocated in filterMask())
1071 SkAutoMaskImage autoDst(&dstM, false);
1072
1073 if (clip.quickReject(dstM.fBounds)) {
1074 return false;
1075 }
1076 if (bounder && !bounder->doIRect(dstM.fBounds)) {
1077 return false;
1078 }
1079
1080 // we now have a device-aligned 8bit mask in dstM, ready to be drawn using
1081 // the current clip (and identity matrix) and grpaint settings
1082
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001083 // used to compute inverse view, if necessary
1084 GrMatrix ivm = context->getMatrix();
1085
reed@google.com0c219b62011-02-16 21:31:18 +00001086 GrAutoMatrix avm(context, GrMatrix::I());
reed@google.com69302852011-02-16 18:08:07 +00001087
bsalomon@google.comfea37b52011-04-25 15:51:06 +00001088 const GrTextureDesc desc = {
1089 kNone_GrTextureFlags,
1090 kNone_GrAALevel,
reed@google.com69302852011-02-16 18:08:07 +00001091 dstM.fBounds.width(),
1092 dstM.fBounds.height(),
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001093 kAlpha_8_GrPixelConfig
reed@google.com69302852011-02-16 18:08:07 +00001094 };
1095
bsalomon@google.comeb2aa1d2011-07-14 15:45:19 +00001096 GrAutoUnlockTextureEntry aute(context,
1097 context->findApproximateKeylessTexture(desc));
1098 GrTexture* texture = aute.texture();
1099
reed@google.com69302852011-02-16 18:08:07 +00001100 if (NULL == texture) {
1101 return false;
1102 }
bsalomon@google.comeb2aa1d2011-07-14 15:45:19 +00001103 texture->uploadTextureData(0, 0, desc.fWidth, desc.fHeight,
1104 dstM.fImage, dstM.fRowBytes);
reed@google.com69302852011-02-16 18:08:07 +00001105
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001106 if (grp->hasTextureOrMask() && ivm.invert(&ivm)) {
1107 grp->preConcatActiveSamplerMatrices(ivm);
1108 }
1109
1110 static const int MASK_IDX = GrPaint::kMaxMasks - 1;
1111 // we assume the last mask index is available for use
1112 GrAssert(NULL == grp->getMask(MASK_IDX));
1113 grp->setMask(MASK_IDX, texture);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001114 grp->getMaskSampler(MASK_IDX)->setClampNoFilter();
reed@google.com69302852011-02-16 18:08:07 +00001115
bsalomon@google.comc6cf7232011-02-17 16:43:10 +00001116 GrRect d;
1117 d.setLTRB(GrIntToScalar(dstM.fBounds.fLeft),
reed@google.com0c219b62011-02-16 21:31:18 +00001118 GrIntToScalar(dstM.fBounds.fTop),
1119 GrIntToScalar(dstM.fBounds.fRight),
1120 GrIntToScalar(dstM.fBounds.fBottom));
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001121
1122 GrMatrix m;
1123 m.setTranslate(-dstM.fBounds.fLeft, -dstM.fBounds.fTop);
bsalomon@google.comeb2aa1d2011-07-14 15:45:19 +00001124 m.postIDiv(texture->width(), texture->height());
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001125 grp->getMaskSampler(MASK_IDX)->setMatrix(m);
1126
1127 context->drawRect(*grp, d);
reed@google.com69302852011-02-16 18:08:07 +00001128 return true;
1129}
reed@google.com69302852011-02-16 18:08:07 +00001130
reed@google.com0c219b62011-02-16 21:31:18 +00001131void SkGpuDevice::drawPath(const SkDraw& draw, const SkPath& origSrcPath,
reed@google.comac10a2d2010-12-22 21:39:39 +00001132 const SkPaint& paint, const SkMatrix* prePathMatrix,
1133 bool pathIsMutable) {
1134 CHECK_SHOULD_DRAW(draw);
1135
bsalomon@google.com5782d712011-01-21 21:03:59 +00001136 GrPaint grPaint;
1137 SkAutoCachedTexture act;
Scroggod757df22011-05-16 13:11:16 +00001138 if (!this->skPaint2GrPaintShader(paint,
1139 &act,
1140 *draw.fMatrix,
1141 &grPaint,
1142 true)) {
reed@google.comac10a2d2010-12-22 21:39:39 +00001143 return;
1144 }
1145
reed@google.com0c219b62011-02-16 21:31:18 +00001146 // BEGIN lift from SkDraw::drawPath()
1147
1148 SkPath* pathPtr = const_cast<SkPath*>(&origSrcPath);
1149 bool doFill = true;
1150 SkPath tmpPath;
reed@google.comac10a2d2010-12-22 21:39:39 +00001151
1152 if (prePathMatrix) {
reed@google.come3445642011-02-16 23:20:39 +00001153 SkPath* result = pathPtr;
reed@google.com0c219b62011-02-16 21:31:18 +00001154
reed@google.come3445642011-02-16 23:20:39 +00001155 if (!pathIsMutable) {
1156 result = &tmpPath;
1157 pathIsMutable = true;
reed@google.comac10a2d2010-12-22 21:39:39 +00001158 }
reed@google.come3445642011-02-16 23:20:39 +00001159 // should I push prePathMatrix on our MV stack temporarily, instead
1160 // of applying it here? See SkDraw.cpp
1161 pathPtr->transform(*prePathMatrix, result);
1162 pathPtr = result;
reed@google.comac10a2d2010-12-22 21:39:39 +00001163 }
reed@google.com0c219b62011-02-16 21:31:18 +00001164 // at this point we're done with prePathMatrix
1165 SkDEBUGCODE(prePathMatrix = (const SkMatrix*)0x50FF8001;)
reed@google.comac10a2d2010-12-22 21:39:39 +00001166
bsalomon@google.com04de7822011-03-25 18:04:43 +00001167 // This "if" is not part of the SkDraw::drawPath() lift.
1168 // When we get a 1.0 wide stroke we hairline stroke it instead of creating
1169 // a new stroked-path. This is motivated by canvas2D sites that draw
1170 // lines as 1.0 wide stroked paths. We can consider doing an alpha-modulated-
1171 // hairline for width < 1.0 when AA is enabled.
1172 static const int gMatrixMask = ~(SkMatrix::kIdentity_Mask |
1173 SkMatrix::kTranslate_Mask);
1174 if (!paint.getPathEffect() &&
1175 SkPaint::kStroke_Style == paint.getStyle() &&
1176 !(draw.fMatrix->getType() & gMatrixMask) &&
1177 SK_Scalar1 == paint.getStrokeWidth()) {
1178 doFill = false;
1179 }
1180
1181 if (doFill && (paint.getPathEffect() ||
1182 paint.getStyle() != SkPaint::kFill_Style)) {
reed@google.com0c219b62011-02-16 21:31:18 +00001183 doFill = paint.getFillPath(*pathPtr, &tmpPath);
1184 pathPtr = &tmpPath;
1185 }
1186
1187 // END lift from SkDraw::drawPath()
1188
reed@google.com69302852011-02-16 18:08:07 +00001189 if (paint.getMaskFilter()) {
reed@google.com0c219b62011-02-16 21:31:18 +00001190 // avoid possibly allocating a new path in transform if we can
1191 SkPath* devPathPtr = pathIsMutable ? pathPtr : &tmpPath;
1192
1193 // transform the path into device space
reed@google.come3445642011-02-16 23:20:39 +00001194 pathPtr->transform(*draw.fMatrix, devPathPtr);
senorblanco@chromium.orgb08ea1b2011-07-12 16:54:59 +00001195 if (!drawWithGPUMaskFilter(fContext, *devPathPtr, paint.getMaskFilter(),
1196 *draw.fMatrix, *draw.fClip, draw.fBounder,
1197 &grPaint)) {
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +00001198 drawWithMaskFilter(fContext, *devPathPtr, paint.getMaskFilter(),
1199 *draw.fMatrix, *draw.fClip, draw.fBounder,
1200 &grPaint);
1201 }
reed@google.com69302852011-02-16 18:08:07 +00001202 return;
1203 }
reed@google.com69302852011-02-16 18:08:07 +00001204
bsalomon@google.comffca4002011-02-22 20:34:01 +00001205 GrPathFill fill = kHairLine_PathFill;
reed@google.comac10a2d2010-12-22 21:39:39 +00001206
reed@google.com0c219b62011-02-16 21:31:18 +00001207 if (doFill) {
1208 switch (pathPtr->getFillType()) {
reed@google.comac10a2d2010-12-22 21:39:39 +00001209 case SkPath::kWinding_FillType:
bsalomon@google.comffca4002011-02-22 20:34:01 +00001210 fill = kWinding_PathFill;
reed@google.comac10a2d2010-12-22 21:39:39 +00001211 break;
1212 case SkPath::kEvenOdd_FillType:
bsalomon@google.comffca4002011-02-22 20:34:01 +00001213 fill = kEvenOdd_PathFill;
reed@google.comac10a2d2010-12-22 21:39:39 +00001214 break;
1215 case SkPath::kInverseWinding_FillType:
bsalomon@google.comffca4002011-02-22 20:34:01 +00001216 fill = kInverseWinding_PathFill;
reed@google.comac10a2d2010-12-22 21:39:39 +00001217 break;
1218 case SkPath::kInverseEvenOdd_FillType:
bsalomon@google.comffca4002011-02-22 20:34:01 +00001219 fill = kInverseEvenOdd_PathFill;
reed@google.comac10a2d2010-12-22 21:39:39 +00001220 break;
1221 default:
bsalomon@google.com5782d712011-01-21 21:03:59 +00001222 SkDebugf("Unsupported path fill type\n");
reed@google.comac10a2d2010-12-22 21:39:39 +00001223 return;
1224 }
1225 }
1226
reed@google.com07f3ee12011-05-16 17:21:57 +00001227 fContext->drawPath(grPaint, *pathPtr, fill);
reed@google.comac10a2d2010-12-22 21:39:39 +00001228}
1229
reed@google.comac10a2d2010-12-22 21:39:39 +00001230void SkGpuDevice::drawBitmap(const SkDraw& draw,
1231 const SkBitmap& bitmap,
1232 const SkIRect* srcRectPtr,
1233 const SkMatrix& m,
1234 const SkPaint& paint) {
1235 CHECK_SHOULD_DRAW(draw);
1236
1237 SkIRect srcRect;
1238 if (NULL == srcRectPtr) {
1239 srcRect.set(0, 0, bitmap.width(), bitmap.height());
1240 } else {
1241 srcRect = *srcRectPtr;
1242 }
1243
junov@google.comd935cfb2011-06-27 20:48:23 +00001244 if (paint.getMaskFilter()){
epoger@google.com9ef2d832011-07-01 21:12:20 +00001245 SkBitmap tmp; // storage if we need a subset of bitmap
junov@google.comd935cfb2011-06-27 20:48:23 +00001246 const SkBitmap* bitmapPtr = &bitmap;
epoger@google.com9ef2d832011-07-01 21:12:20 +00001247 if (srcRectPtr) {
1248 if (!bitmap.extractSubset(&tmp, srcRect)) {
1249 return; // extraction failed
1250 }
1251 bitmapPtr = &tmp;
junov@google.comd935cfb2011-06-27 20:48:23 +00001252 }
1253 SkPaint paintWithTexture(paint);
1254 paintWithTexture.setShader(SkShader::CreateBitmapShader( *bitmapPtr,
1255 SkShader::kClamp_TileMode, SkShader::kClamp_TileMode))->unref();
1256 paintWithTexture.getShader()->setLocalMatrix(m);
1257
1258 SkRect ScalarRect;
epoger@google.com9ef2d832011-07-01 21:12:20 +00001259 ScalarRect.set(srcRect);
junov@google.comd935cfb2011-06-27 20:48:23 +00001260
epoger@google.com9ef2d832011-07-01 21:12:20 +00001261 if (m.rectStaysRect()) {
1262 // Preferred drawing method, optimized for rectangles
1263 m.mapRect(&ScalarRect);
1264 this->drawRect(draw, ScalarRect, paintWithTexture);
1265 } else {
1266 // Slower drawing method, for warped or rotated rectangles
1267 SkPath path;
1268 path.addRect(ScalarRect);
1269 path.transform(m);
1270 this->drawPath(draw, path, paintWithTexture, NULL, true);
1271 }
junov@google.comd935cfb2011-06-27 20:48:23 +00001272 return;
1273 }
1274
bsalomon@google.com5782d712011-01-21 21:03:59 +00001275 GrPaint grPaint;
Scroggod757df22011-05-16 13:11:16 +00001276 if (!this->skPaint2GrPaintNoShader(paint, true, &grPaint, false)) {
bsalomon@google.com5782d712011-01-21 21:03:59 +00001277 return;
1278 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001279 GrSamplerState* sampler = grPaint.getTextureSampler(kBitmapTextureIdx);
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +00001280 if (paint.isFilterBitmap()) {
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001281 sampler->setFilter(GrSamplerState::kBilinear_Filter);
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +00001282 } else {
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001283 sampler->setFilter(GrSamplerState::kNearest_Filter);
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +00001284 }
bsalomon@google.com5782d712011-01-21 21:03:59 +00001285
bsalomon@google.com91958362011-06-13 17:58:13 +00001286 const int maxTextureSize = fContext->getMaxTextureSize();
1287 if (bitmap.getTexture() || (bitmap.width() <= maxTextureSize &&
1288 bitmap.height() <= maxTextureSize)) {
reed@google.comac10a2d2010-12-22 21:39:39 +00001289 // take the fast case
bsalomon@google.com5782d712011-01-21 21:03:59 +00001290 this->internalDrawBitmap(draw, bitmap, srcRect, m, &grPaint);
reed@google.comac10a2d2010-12-22 21:39:39 +00001291 return;
1292 }
1293
1294 // undo the translate done by SkCanvas
1295 int DX = SkMax32(0, srcRect.fLeft);
1296 int DY = SkMax32(0, srcRect.fTop);
1297 // compute clip bounds in local coordinates
1298 SkIRect clipRect;
1299 {
1300 SkRect r;
1301 r.set(draw.fClip->getBounds());
1302 SkMatrix matrix, inverse;
1303 matrix.setConcat(*draw.fMatrix, m);
1304 if (!matrix.invert(&inverse)) {
1305 return;
1306 }
1307 inverse.mapRect(&r);
1308 r.roundOut(&clipRect);
1309 // apply the canvas' translate to our local clip
1310 clipRect.offset(DX, DY);
1311 }
1312
bsalomon@google.com91958362011-06-13 17:58:13 +00001313 int nx = bitmap.width() / maxTextureSize;
1314 int ny = bitmap.height() / maxTextureSize;
reed@google.comac10a2d2010-12-22 21:39:39 +00001315 for (int x = 0; x <= nx; x++) {
1316 for (int y = 0; y <= ny; y++) {
1317 SkIRect tileR;
bsalomon@google.com91958362011-06-13 17:58:13 +00001318 tileR.set(x * maxTextureSize, y * maxTextureSize,
1319 (x + 1) * maxTextureSize, (y + 1) * maxTextureSize);
reed@google.comac10a2d2010-12-22 21:39:39 +00001320 if (!SkIRect::Intersects(tileR, clipRect)) {
1321 continue;
1322 }
1323
1324 SkIRect srcR = tileR;
1325 if (!srcR.intersect(srcRect)) {
1326 continue;
1327 }
1328
1329 SkBitmap tmpB;
1330 if (bitmap.extractSubset(&tmpB, tileR)) {
1331 // now offset it to make it "local" to our tmp bitmap
1332 srcR.offset(-tileR.fLeft, -tileR.fTop);
1333
1334 SkMatrix tmpM(m);
1335 {
1336 int dx = tileR.fLeft - DX + SkMax32(0, srcR.fLeft);
1337 int dy = tileR.fTop - DY + SkMax32(0, srcR.fTop);
1338 tmpM.preTranslate(SkIntToScalar(dx), SkIntToScalar(dy));
1339 }
bsalomon@google.com5782d712011-01-21 21:03:59 +00001340 this->internalDrawBitmap(draw, tmpB, srcR, tmpM, &grPaint);
reed@google.comac10a2d2010-12-22 21:39:39 +00001341 }
1342 }
1343 }
1344}
1345
1346/*
1347 * This is called by drawBitmap(), which has to handle images that may be too
1348 * large to be represented by a single texture.
1349 *
bsalomon@google.com5782d712011-01-21 21:03:59 +00001350 * internalDrawBitmap assumes that the specified bitmap will fit in a texture
1351 * and that non-texture portion of the GrPaint has already been setup.
reed@google.comac10a2d2010-12-22 21:39:39 +00001352 */
1353void SkGpuDevice::internalDrawBitmap(const SkDraw& draw,
1354 const SkBitmap& bitmap,
1355 const SkIRect& srcRect,
1356 const SkMatrix& m,
bsalomon@google.com5782d712011-01-21 21:03:59 +00001357 GrPaint* grPaint) {
bsalomon@google.com91958362011-06-13 17:58:13 +00001358 SkASSERT(bitmap.width() <= fContext->getMaxTextureSize() &&
1359 bitmap.height() <= fContext->getMaxTextureSize());
reed@google.comac10a2d2010-12-22 21:39:39 +00001360
reed@google.com9c49bc32011-07-07 13:42:37 +00001361 SkAutoLockPixels alp(bitmap, !bitmap.getTexture());
reed@google.comac10a2d2010-12-22 21:39:39 +00001362 if (!bitmap.getTexture() && !bitmap.readyToDraw()) {
reed@google.com9c49bc32011-07-07 13:42:37 +00001363 SkDebugf("nothing to draw\n");
reed@google.comac10a2d2010-12-22 21:39:39 +00001364 return;
1365 }
1366
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001367 GrSamplerState* sampler = grPaint->getTextureSampler(kBitmapTextureIdx);
1368
1369 sampler->setWrapX(GrSamplerState::kClamp_WrapMode);
1370 sampler->setWrapY(GrSamplerState::kClamp_WrapMode);
1371 sampler->setSampleMode(GrSamplerState::kNormal_SampleMode);
1372 sampler->setMatrix(GrMatrix::I());
reed@google.comac10a2d2010-12-22 21:39:39 +00001373
1374 GrTexture* texture;
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001375 SkAutoCachedTexture act(this, bitmap, *sampler, &texture);
reed@google.comac10a2d2010-12-22 21:39:39 +00001376 if (NULL == texture) {
1377 return;
1378 }
1379
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001380 grPaint->setTexture(kShaderTextureIdx, texture);
reed@google.com46799cd2011-02-22 20:56:26 +00001381
reed@google.com20efde72011-05-09 17:00:02 +00001382 GrRect dstRect = SkRect::MakeWH(GrIntToScalar(srcRect.width()),
1383 GrIntToScalar(srcRect.height()));
bsalomon@google.comc6cf7232011-02-17 16:43:10 +00001384 GrRect paintRect;
junov@google.com6acc9b32011-05-16 18:32:07 +00001385 paintRect.setLTRB(GrFixedToScalar((srcRect.fLeft << 16) / bitmap.width()),
1386 GrFixedToScalar((srcRect.fTop << 16) / bitmap.height()),
1387 GrFixedToScalar((srcRect.fRight << 16) / bitmap.width()),
bsalomon@google.comc6cf7232011-02-17 16:43:10 +00001388 GrFixedToScalar((srcRect.fBottom << 16) / bitmap.height()));
reed@google.comac10a2d2010-12-22 21:39:39 +00001389
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001390 if (GrSamplerState::kNearest_Filter != sampler->getFilter() &&
junov@google.com6acc9b32011-05-16 18:32:07 +00001391 (srcRect.width() < bitmap.width() ||
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001392 srcRect.height() < bitmap.height())) {
junov@google.com6acc9b32011-05-16 18:32:07 +00001393 // If drawing a subrect of the bitmap and filtering is enabled,
1394 // use a constrained texture domain to avoid color bleeding
1395 GrScalar left, top, right, bottom;
1396 if (srcRect.width() > 1) {
1397 GrScalar border = GR_ScalarHalf / bitmap.width();
1398 left = paintRect.left() + border;
1399 right = paintRect.right() - border;
1400 } else {
1401 left = right = GrScalarHalf(paintRect.left() + paintRect.right());
1402 }
1403 if (srcRect.height() > 1) {
1404 GrScalar border = GR_ScalarHalf / bitmap.height();
1405 top = paintRect.top() + border;
1406 bottom = paintRect.bottom() - border;
1407 } else {
1408 top = bottom = GrScalarHalf(paintRect.top() + paintRect.bottom());
1409 }
1410 GrRect textureDomain;
1411 textureDomain.setLTRB(left, top, right, bottom);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001412 sampler->setTextureDomain(textureDomain);
junov@google.com6acc9b32011-05-16 18:32:07 +00001413 }
1414
bsalomon@google.comcc4dac32011-05-10 13:52:42 +00001415 fContext->drawRectToRect(*grPaint, dstRect, paintRect, &m);
reed@google.comac10a2d2010-12-22 21:39:39 +00001416}
1417
1418void SkGpuDevice::drawSprite(const SkDraw& draw, const SkBitmap& bitmap,
1419 int left, int top, const SkPaint& paint) {
1420 CHECK_SHOULD_DRAW(draw);
1421
1422 SkAutoLockPixels alp(bitmap);
1423 if (!bitmap.getTexture() && !bitmap.readyToDraw()) {
1424 return;
1425 }
1426
bsalomon@google.com5782d712011-01-21 21:03:59 +00001427 GrPaint grPaint;
Scroggod757df22011-05-16 13:11:16 +00001428 if(!this->skPaint2GrPaintNoShader(paint, true, &grPaint, false)) {
bsalomon@google.com5782d712011-01-21 21:03:59 +00001429 return;
1430 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001431
bsalomon@google.com5782d712011-01-21 21:03:59 +00001432 GrAutoMatrix avm(fContext, GrMatrix::I());
1433
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001434 GrSamplerState* sampler = grPaint.getTextureSampler(kBitmapTextureIdx);
bsalomon@google.com5782d712011-01-21 21:03:59 +00001435
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001436 GrTexture* texture;
1437 sampler->setClampNoFilter();
1438 SkAutoCachedTexture act(this, bitmap, *sampler, &texture);
1439
1440 grPaint.setTexture(kBitmapTextureIdx, texture);
bsalomon@google.com5782d712011-01-21 21:03:59 +00001441
bsalomon@google.com5782d712011-01-21 21:03:59 +00001442 fContext->drawRectToRect(grPaint,
reed@google.com20efde72011-05-09 17:00:02 +00001443 GrRect::MakeXYWH(GrIntToScalar(left),
1444 GrIntToScalar(top),
1445 GrIntToScalar(bitmap.width()),
1446 GrIntToScalar(bitmap.height())),
1447 GrRect::MakeWH(GR_Scalar1, GR_Scalar1));
reed@google.comac10a2d2010-12-22 21:39:39 +00001448}
1449
1450void SkGpuDevice::drawDevice(const SkDraw& draw, SkDevice* dev,
1451 int x, int y, const SkPaint& paint) {
1452 CHECK_SHOULD_DRAW(draw);
1453
bsalomon@google.com5782d712011-01-21 21:03:59 +00001454 GrPaint grPaint;
bsalomon@google.comc6cf7232011-02-17 16:43:10 +00001455 if (!((SkGpuDevice*)dev)->bindDeviceAsTexture(&grPaint) ||
Scroggod757df22011-05-16 13:11:16 +00001456 !this->skPaint2GrPaintNoShader(paint, true, &grPaint, false)) {
bsalomon@google.com5782d712011-01-21 21:03:59 +00001457 return;
reed@google.comac10a2d2010-12-22 21:39:39 +00001458 }
bsalomon@google.com5782d712011-01-21 21:03:59 +00001459
bsalomon@google.comb5b31682011-06-16 18:05:35 +00001460 GrTexture* devTex = grPaint.getTexture(0);
1461 SkASSERT(NULL != devTex);
bsalomon@google.com5782d712011-01-21 21:03:59 +00001462
1463 const SkBitmap& bm = dev->accessBitmap(false);
1464 int w = bm.width();
1465 int h = bm.height();
1466
1467 GrAutoMatrix avm(fContext, GrMatrix::I());
1468
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001469 grPaint.getTextureSampler(kBitmapTextureIdx)->setClampNoFilter();
bsalomon@google.com5782d712011-01-21 21:03:59 +00001470
bsalomon@google.comb5b31682011-06-16 18:05:35 +00001471 GrRect dstRect = GrRect::MakeXYWH(GrIntToScalar(x),
1472 GrIntToScalar(y),
1473 GrIntToScalar(w),
1474 GrIntToScalar(h));
1475 // The device being drawn may not fill up its texture (saveLayer uses
1476 // the approximate ).
1477 GrRect srcRect = GrRect::MakeWH(GR_Scalar1 * w / devTex->width(),
1478 GR_Scalar1 * h / devTex->height());
1479
1480 fContext->drawRectToRect(grPaint, dstRect, srcRect);
reed@google.comac10a2d2010-12-22 21:39:39 +00001481}
1482
1483///////////////////////////////////////////////////////////////////////////////
1484
1485// must be in SkCanvas::VertexMode order
bsalomon@google.comffca4002011-02-22 20:34:01 +00001486static const GrPrimitiveType gVertexMode2PrimitiveType[] = {
1487 kTriangles_PrimitiveType,
1488 kTriangleStrip_PrimitiveType,
1489 kTriangleFan_PrimitiveType,
reed@google.comac10a2d2010-12-22 21:39:39 +00001490};
1491
1492void SkGpuDevice::drawVertices(const SkDraw& draw, SkCanvas::VertexMode vmode,
1493 int vertexCount, const SkPoint vertices[],
1494 const SkPoint texs[], const SkColor colors[],
1495 SkXfermode* xmode,
1496 const uint16_t indices[], int indexCount,
1497 const SkPaint& paint) {
1498 CHECK_SHOULD_DRAW(draw);
1499
bsalomon@google.com5782d712011-01-21 21:03:59 +00001500 GrPaint grPaint;
1501 SkAutoCachedTexture act;
1502 // we ignore the shader if texs is null.
1503 if (NULL == texs) {
Scroggod757df22011-05-16 13:11:16 +00001504 if (!this->skPaint2GrPaintNoShader(paint,
1505 false,
1506 &grPaint,
1507 NULL == colors)) {
reed@google.comac10a2d2010-12-22 21:39:39 +00001508 return;
1509 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001510 } else {
reed@google.com1a2e8d22011-01-21 22:08:29 +00001511 if (!this->skPaint2GrPaintShader(paint, &act,
1512 *draw.fMatrix,
Scroggod757df22011-05-16 13:11:16 +00001513 &grPaint,
1514 NULL == colors)) {
bsalomon@google.com5782d712011-01-21 21:03:59 +00001515 return;
1516 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001517 }
bsalomon@google.com5782d712011-01-21 21:03:59 +00001518
1519 if (NULL != xmode && NULL != texs && NULL != colors) {
1520 SkXfermode::Mode mode;
1521 if (!SkXfermode::IsMode(xmode, &mode) ||
1522 SkXfermode::kMultiply_Mode != mode) {
1523 SkDebugf("Unsupported vertex-color/texture xfer mode.\n");
1524#if 0
1525 return
1526#endif
1527 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001528 }
bsalomon@google.com5782d712011-01-21 21:03:59 +00001529
1530#if SK_SCALAR_IS_GR_SCALAR
1531 // even if GrColor and SkColor byte offsets match we need
1532 // to perform pre-multiply.
1533 if (NULL == colors) {
1534 fContext->drawVertices(grPaint,
1535 gVertexMode2PrimitiveType[vmode],
1536 vertexCount,
1537 (GrPoint*) vertices,
1538 (GrPoint*) texs,
1539 NULL,
1540 indices,
1541 indexCount);
1542 } else
1543#endif
1544 {
1545 SkTexCoordSource texSrc(texs);
1546 SkColorSource colSrc(colors);
1547 SkIndexSource idxSrc(indices, indexCount);
1548
1549 fContext->drawCustomVertices(grPaint,
1550 gVertexMode2PrimitiveType[vmode],
1551 SkPositionSource(vertices, vertexCount),
1552 (NULL == texs) ? NULL : &texSrc,
1553 (NULL == colors) ? NULL : &colSrc,
1554 (NULL == indices) ? NULL : &idxSrc);
reed@google.comac10a2d2010-12-22 21:39:39 +00001555 }
1556}
1557
1558///////////////////////////////////////////////////////////////////////////////
1559
1560static void GlyphCacheAuxProc(void* data) {
1561 delete (GrFontScaler*)data;
1562}
1563
1564static GrFontScaler* get_gr_font_scaler(SkGlyphCache* cache) {
1565 void* auxData;
1566 GrFontScaler* scaler = NULL;
1567 if (cache->getAuxProcData(GlyphCacheAuxProc, &auxData)) {
1568 scaler = (GrFontScaler*)auxData;
1569 }
1570 if (NULL == scaler) {
1571 scaler = new SkGrFontScaler(cache);
1572 cache->setAuxProc(GlyphCacheAuxProc, scaler);
1573 }
1574 return scaler;
1575}
1576
1577static void SkGPU_Draw1Glyph(const SkDraw1Glyph& state,
1578 SkFixed fx, SkFixed fy,
1579 const SkGlyph& glyph) {
1580 SkASSERT(glyph.fWidth > 0 && glyph.fHeight > 0);
1581
1582 GrSkDrawProcs* procs = (GrSkDrawProcs*)state.fDraw->fProcs;
1583
1584 if (NULL == procs->fFontScaler) {
1585 procs->fFontScaler = get_gr_font_scaler(state.fCache);
1586 }
reed@google.com39ce0ac2011-04-08 15:42:19 +00001587
1588 /*
reed@google.com3b139f52011-06-07 17:56:25 +00001589 * What should we do with fy? (assuming horizontal/latin text)
reed@google.com39ce0ac2011-04-08 15:42:19 +00001590 *
reed@google.com3b139f52011-06-07 17:56:25 +00001591 * The raster code calls SkFixedFloorToFixed on it, as it does with fx.
1592 * It calls that rather than round, because our caller has already added
1593 * SK_FixedHalf, so that calling floor gives us the rounded integer.
1594 *
1595 * Test code between raster and gpu (they should draw the same)
1596 *
1597 * canvas->drawText("Hamburgefons", 12, 0, 16.5f, paint);
1598 *
1599 * Perhaps we should only perform this integralization if there is no
1600 * fExtMatrix...
reed@google.com39ce0ac2011-04-08 15:42:19 +00001601 */
reed@google.com3b139f52011-06-07 17:56:25 +00001602 fy = SkFixedFloorToFixed(fy);
1603
reed@google.comac10a2d2010-12-22 21:39:39 +00001604 procs->fTextContext->drawPackedGlyph(GrGlyph::Pack(glyph.getGlyphID(), fx, 0),
reed@google.com3b139f52011-06-07 17:56:25 +00001605 SkFixedFloorToFixed(fx), fy,
reed@google.comac10a2d2010-12-22 21:39:39 +00001606 procs->fFontScaler);
1607}
1608
bsalomon@google.com5782d712011-01-21 21:03:59 +00001609SkDrawProcs* SkGpuDevice::initDrawForText(GrTextContext* context) {
reed@google.comac10a2d2010-12-22 21:39:39 +00001610
1611 // deferred allocation
1612 if (NULL == fDrawProcs) {
1613 fDrawProcs = new GrSkDrawProcs;
1614 fDrawProcs->fD1GProc = SkGPU_Draw1Glyph;
1615 fDrawProcs->fContext = fContext;
1616 }
1617
1618 // init our (and GL's) state
1619 fDrawProcs->fTextContext = context;
1620 fDrawProcs->fFontScaler = NULL;
1621 return fDrawProcs;
1622}
1623
1624void SkGpuDevice::drawText(const SkDraw& draw, const void* text,
1625 size_t byteLength, SkScalar x, SkScalar y,
1626 const SkPaint& paint) {
1627 CHECK_SHOULD_DRAW(draw);
1628
1629 if (draw.fMatrix->getType() & SkMatrix::kPerspective_Mask) {
1630 // this guy will just call our drawPath()
1631 draw.drawText((const char*)text, byteLength, x, y, paint);
1632 } else {
reed@google.comac10a2d2010-12-22 21:39:39 +00001633 SkDraw myDraw(draw);
bsalomon@google.com5782d712011-01-21 21:03:59 +00001634
1635 GrPaint grPaint;
1636 SkAutoCachedTexture act;
1637
Scroggod757df22011-05-16 13:11:16 +00001638 if (!this->skPaint2GrPaintShader(paint,
1639 &act,
1640 *draw.fMatrix,
1641 &grPaint,
1642 true)) {
bsalomon@google.com5782d712011-01-21 21:03:59 +00001643 return;
1644 }
bsalomon@google.comcc4dac32011-05-10 13:52:42 +00001645 GrTextContext context(fContext, grPaint, draw.fExtMatrix);
bsalomon@google.com5782d712011-01-21 21:03:59 +00001646 myDraw.fProcs = this->initDrawForText(&context);
reed@google.comac10a2d2010-12-22 21:39:39 +00001647 this->INHERITED::drawText(myDraw, text, byteLength, x, y, paint);
1648 }
1649}
1650
1651void SkGpuDevice::drawPosText(const SkDraw& draw, const void* text,
1652 size_t byteLength, const SkScalar pos[],
1653 SkScalar constY, int scalarsPerPos,
1654 const SkPaint& paint) {
1655 CHECK_SHOULD_DRAW(draw);
1656
1657 if (draw.fMatrix->getType() & SkMatrix::kPerspective_Mask) {
1658 // this guy will just call our drawPath()
1659 draw.drawPosText((const char*)text, byteLength, pos, constY,
1660 scalarsPerPos, paint);
1661 } else {
reed@google.comac10a2d2010-12-22 21:39:39 +00001662 SkDraw myDraw(draw);
bsalomon@google.com5782d712011-01-21 21:03:59 +00001663
1664 GrPaint grPaint;
1665 SkAutoCachedTexture act;
Scroggod757df22011-05-16 13:11:16 +00001666 if (!this->skPaint2GrPaintShader(paint,
1667 &act,
1668 *draw.fMatrix,
1669 &grPaint,
1670 true)) {
bsalomon@google.com5782d712011-01-21 21:03:59 +00001671 return;
1672 }
1673
bsalomon@google.comcc4dac32011-05-10 13:52:42 +00001674 GrTextContext context(fContext, grPaint, draw.fExtMatrix);
bsalomon@google.com5782d712011-01-21 21:03:59 +00001675 myDraw.fProcs = this->initDrawForText(&context);
reed@google.comac10a2d2010-12-22 21:39:39 +00001676 this->INHERITED::drawPosText(myDraw, text, byteLength, pos, constY,
1677 scalarsPerPos, paint);
1678 }
1679}
1680
1681void SkGpuDevice::drawTextOnPath(const SkDraw& draw, const void* text,
1682 size_t len, const SkPath& path,
1683 const SkMatrix* m, const SkPaint& paint) {
1684 CHECK_SHOULD_DRAW(draw);
1685
1686 SkASSERT(draw.fDevice == this);
1687 draw.drawTextOnPath((const char*)text, len, path, m, paint);
1688}
1689
1690///////////////////////////////////////////////////////////////////////////////
1691
reed@google.comf67e4cf2011-03-15 20:56:58 +00001692bool SkGpuDevice::filterTextFlags(const SkPaint& paint, TextFlags* flags) {
1693 if (!paint.isLCDRenderText()) {
1694 // we're cool with the paint as is
1695 return false;
1696 }
1697
1698 if (paint.getShader() ||
1699 paint.getXfermode() || // unless its srcover
1700 paint.getMaskFilter() ||
1701 paint.getRasterizer() ||
1702 paint.getColorFilter() ||
1703 paint.getPathEffect() ||
1704 paint.isFakeBoldText() ||
1705 paint.getStyle() != SkPaint::kFill_Style) {
1706 // turn off lcd
1707 flags->fFlags = paint.getFlags() & ~SkPaint::kLCDRenderText_Flag;
1708 flags->fHinting = paint.getHinting();
1709 return true;
1710 }
1711 // we're cool with the paint as is
1712 return false;
1713}
1714
1715///////////////////////////////////////////////////////////////////////////////
1716
reed@google.comac10a2d2010-12-22 21:39:39 +00001717SkGpuDevice::TexCache* SkGpuDevice::lockCachedTexture(const SkBitmap& bitmap,
bsalomon@google.comfea37b52011-04-25 15:51:06 +00001718 const GrSamplerState& sampler,
1719 GrTexture** texture,
bsalomon@google.come97f0852011-06-17 13:10:25 +00001720 TexType type) {
bsalomon@google.comfea37b52011-04-25 15:51:06 +00001721 GrTexture* newTexture = NULL;
1722 GrTextureEntry* entry = NULL;
reed@google.comac10a2d2010-12-22 21:39:39 +00001723 GrContext* ctx = this->context();
bsalomon@google.comfea37b52011-04-25 15:51:06 +00001724
bsalomon@google.come97f0852011-06-17 13:10:25 +00001725 if (kBitmap_TexType != type) {
bsalomon@google.comfea37b52011-04-25 15:51:06 +00001726 const GrTextureDesc desc = {
1727 kRenderTarget_GrTextureFlagBit,
1728 kNone_GrAALevel,
1729 bitmap.width(),
1730 bitmap.height(),
1731 SkGr::Bitmap2PixelConfig(bitmap)
1732 };
bsalomon@google.come97f0852011-06-17 13:10:25 +00001733 if (kSaveLayerDeviceRenderTarget_TexType == type) {
bsalomon@google.comb5b31682011-06-16 18:05:35 +00001734 // we know layers will only be drawn through drawDevice.
1735 // drawDevice has been made to work with content embedded in a
1736 // larger texture so its okay to use the approximate version.
1737 entry = ctx->findApproximateKeylessTexture(desc);
1738 } else {
bsalomon@google.come97f0852011-06-17 13:10:25 +00001739 SkASSERT(kDeviceRenderTarget_TexType == type);
bsalomon@google.comb5b31682011-06-16 18:05:35 +00001740 entry = ctx->lockKeylessTexture(desc);
1741 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001742 } else {
junov@google.com4ee7ae52011-06-30 17:30:49 +00001743 if (!bitmap.isVolatile()) {
1744 uint32_t p0, p1;
1745 p0 = bitmap.getGenerationID();
1746 p1 = bitmap.pixelRefOffset();
1747 GrTextureKey key(p0, p1, bitmap.width(), bitmap.height());
1748
1749 entry = ctx->findAndLockTexture(&key, sampler);
1750 if (NULL == entry)
1751 entry = sk_gr_create_bitmap_texture(ctx, &key, sampler,
1752 bitmap);
1753 } else {
1754 entry = sk_gr_create_bitmap_texture(ctx, NULL, sampler, bitmap);
1755 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001756 if (NULL == entry) {
junov@google.com4ee7ae52011-06-30 17:30:49 +00001757 GrPrintf("---- failed to create texture for cache [%d %d]\n",
1758 bitmap.width(), bitmap.height());
reed@google.comac10a2d2010-12-22 21:39:39 +00001759 }
1760 }
1761
1762 if (NULL != entry) {
1763 newTexture = entry->texture();
reed@google.comac10a2d2010-12-22 21:39:39 +00001764 if (texture) {
1765 *texture = newTexture;
1766 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001767 }
1768 return (TexCache*)entry;
1769}
1770
1771void SkGpuDevice::unlockCachedTexture(TexCache* cache) {
1772 this->context()->unlockTexture((GrTextureEntry*)cache);
1773}
1774
bsalomon@google.come97f0852011-06-17 13:10:25 +00001775SkDevice* SkGpuDevice::onCreateCompatibleDevice(SkBitmap::Config config,
1776 int width, int height,
1777 bool isOpaque,
1778 Usage usage) {
1779 return SkNEW_ARGS(SkGpuDevice,(this->context(), config,
1780 width, height, usage));
1781}
1782