blob: cc669fe3114296722b16b1e54772b3c5974a28ba [file] [log] [blame]
reed@google.comac10a2d2010-12-22 21:39:39 +00001/*
bsalomon@google.com1da07462011-03-10 14:51:57 +00002 Copyright 2011 Google Inc.
reed@google.comac10a2d2010-12-22 21:39:39 +00003
4 Licensed under the Apache License, Version 2.0 (the "License");
5 you may not use this file except in compliance with the License.
6 You may obtain a copy of the License at
7
8 http://www.apache.org/licenses/LICENSE-2.0
9
10 Unless required by applicable law or agreed to in writing, software
11 distributed under the License is distributed on an "AS IS" BASIS,
12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 See the License for the specific language governing permissions and
14 limitations under the License.
15 */
16
17
18#include "GrContext.h"
19#include "GrTextContext.h"
20
reed@google.comac10a2d2010-12-22 21:39:39 +000021#include "SkGpuDevice.h"
22#include "SkGrTexturePixelRef.h"
23
Scroggo97c88c22011-05-11 14:05:25 +000024#include "SkColorFilter.h"
reed@google.comac10a2d2010-12-22 21:39:39 +000025#include "SkDrawProcs.h"
26#include "SkGlyphCache.h"
reed@google.comc9aa5872011-04-05 21:05:37 +000027#include "SkUtils.h"
reed@google.comac10a2d2010-12-22 21:39:39 +000028
29#define CACHE_LAYER_TEXTURES 1
30
31#if 0
32 extern bool (*gShouldDrawProc)();
33 #define CHECK_SHOULD_DRAW(draw) \
34 do { \
35 if (gShouldDrawProc && !gShouldDrawProc()) return; \
36 this->prepareRenderTarget(draw); \
37 } while (0)
38#else
39 #define CHECK_SHOULD_DRAW(draw) this->prepareRenderTarget(draw)
40#endif
41
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +000042// we use the same texture slot on GrPaint for bitmaps and shaders
43// (since drawBitmap, drawSprite, and drawDevice ignore skia's shader)
44enum {
45 kBitmapTextureIdx = 0,
46 kShaderTextureIdx = 0
47};
48
reed@google.comcde92112011-07-06 20:00:52 +000049
senorblanco@chromium.orge36ddf02011-07-15 14:28:16 +000050#define MAX_BLUR_SIGMA 4.0f
51// FIXME: This value comes from from SkBlurMaskFilter.cpp.
52// Should probably be put in a common header someplace.
53#define MAX_BLUR_RADIUS SkIntToScalar(128)
54// This constant approximates the scaling done in the software path's
55// "high quality" mode, in SkBlurMask::Blur() (1 / sqrt(3)).
56// IMHO, it actually should be 1: we blur "less" than we should do
57// according to the CSS and canvas specs, simply because Safari does the same.
58// Firefox used to do the same too, until 4.0 where they fixed it. So at some
59// point we should probably get rid of these scaling constants and rebaseline
60// all the blur tests.
61#define BLUR_SIGMA_SCALE 0.6f
reed@google.comac10a2d2010-12-22 21:39:39 +000062///////////////////////////////////////////////////////////////////////////////
63
64SkGpuDevice::SkAutoCachedTexture::
65 SkAutoCachedTexture(SkGpuDevice* device,
66 const SkBitmap& bitmap,
67 const GrSamplerState& sampler,
68 GrTexture** texture) {
69 GrAssert(texture);
70 fTex = NULL;
71 *texture = this->set(device, bitmap, sampler);
72}
73
74SkGpuDevice::SkAutoCachedTexture::SkAutoCachedTexture() {
75 fTex = NULL;
76}
77
78GrTexture* SkGpuDevice::SkAutoCachedTexture::set(SkGpuDevice* device,
79 const SkBitmap& bitmap,
80 const GrSamplerState& sampler) {
81 if (fTex) {
82 fDevice->unlockCachedTexture(fTex);
83 }
84 fDevice = device;
85 GrTexture* texture = (GrTexture*)bitmap.getTexture();
86 if (texture) {
87 // return the native texture
88 fTex = NULL;
reed@google.comac10a2d2010-12-22 21:39:39 +000089 } else {
90 // look it up in our cache
bsalomon@google.come97f0852011-06-17 13:10:25 +000091 fTex = device->lockCachedTexture(bitmap, sampler, &texture);
reed@google.comac10a2d2010-12-22 21:39:39 +000092 }
93 return texture;
94}
95
96SkGpuDevice::SkAutoCachedTexture::~SkAutoCachedTexture() {
97 if (fTex) {
98 fDevice->unlockCachedTexture(fTex);
99 }
100}
101
102///////////////////////////////////////////////////////////////////////////////
103
104bool gDoTraceDraw;
105
106struct GrSkDrawProcs : public SkDrawProcs {
107public:
108 GrContext* fContext;
109 GrTextContext* fTextContext;
110 GrFontScaler* fFontScaler; // cached in the skia glyphcache
111};
112
113///////////////////////////////////////////////////////////////////////////////
114
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000115GrRenderTarget* SkGpuDevice::Current3DApiRenderTarget() {
116 return (GrRenderTarget*) -1;
117}
118
reed@google.comaf951c92011-06-16 19:10:39 +0000119static SkBitmap::Config grConfig2skConfig(GrPixelConfig config, bool* isOpaque) {
120 switch (config) {
121 case kAlpha_8_GrPixelConfig:
122 *isOpaque = false;
123 return SkBitmap::kA8_Config;
124 case kRGB_565_GrPixelConfig:
125 *isOpaque = true;
126 return SkBitmap::kRGB_565_Config;
127 case kRGBA_4444_GrPixelConfig:
128 *isOpaque = false;
129 return SkBitmap::kARGB_4444_Config;
130 case kRGBA_8888_GrPixelConfig:
131 case kRGBX_8888_GrPixelConfig:
132 *isOpaque = (kRGBX_8888_GrPixelConfig == config);
133 return SkBitmap::kARGB_8888_Config;
134 default:
135 *isOpaque = false;
136 return SkBitmap::kNo_Config;
137 }
138}
reed@google.comac10a2d2010-12-22 21:39:39 +0000139
reed@google.comaf951c92011-06-16 19:10:39 +0000140static SkBitmap make_bitmap(GrContext* context, GrRenderTarget* renderTarget) {
141 if (SkGpuDevice::Current3DApiRenderTarget() == renderTarget) {
142 renderTarget = context->createRenderTargetFrom3DApiState();
143 }
144 GrTexture* texture = renderTarget->asTexture();
145 GrPixelConfig config = texture ? texture->config() : kRGBA_8888_GrPixelConfig;
146
147 bool isOpaque;
148 SkBitmap bitmap;
149 bitmap.setConfig(grConfig2skConfig(config, &isOpaque),
150 renderTarget->width(), renderTarget->height());
151 bitmap.setIsOpaque(isOpaque);
152 return bitmap;
153}
154
bsalomon@google.comf9046fe2011-06-17 15:10:21 +0000155SkGpuDevice::SkGpuDevice(GrContext* context, GrTexture* texture)
156: SkDevice(make_bitmap(context, texture->asRenderTarget())) {
157 this->initFromRenderTarget(context, texture->asRenderTarget());
158}
159
reed@google.comaf951c92011-06-16 19:10:39 +0000160SkGpuDevice::SkGpuDevice(GrContext* context, GrRenderTarget* renderTarget)
161: SkDevice(make_bitmap(context, renderTarget)) {
bsalomon@google.comf9046fe2011-06-17 15:10:21 +0000162 this->initFromRenderTarget(context, renderTarget);
163}
164
165void SkGpuDevice::initFromRenderTarget(GrContext* context,
166 GrRenderTarget* renderTarget) {
reed@google.comaf951c92011-06-16 19:10:39 +0000167 fNeedPrepareRenderTarget = false;
168 fDrawProcs = NULL;
169
170 fContext = context;
171 fContext->ref();
172
173 fCache = NULL;
174 fTexture = NULL;
175 fRenderTarget = NULL;
176 fNeedClear = false;
177
178 if (Current3DApiRenderTarget() == renderTarget) {
179 fRenderTarget = fContext->createRenderTargetFrom3DApiState();
180 } else {
bsalomon@google.comf9046fe2011-06-17 15:10:21 +0000181 GrAssert(NULL != renderTarget);
reed@google.comaf951c92011-06-16 19:10:39 +0000182 fRenderTarget = renderTarget;
183 fRenderTarget->ref();
bsalomon@google.comf9046fe2011-06-17 15:10:21 +0000184 // if this RT is also a texture, hold a ref on it
185 fTexture = fRenderTarget->asTexture();
186 SkSafeRef(fTexture);
reed@google.comaf951c92011-06-16 19:10:39 +0000187 }
188
189 SkGrRenderTargetPixelRef* pr = new SkGrRenderTargetPixelRef(fRenderTarget);
190 this->setPixelRef(pr, 0)->unref();
191}
192
193SkGpuDevice::SkGpuDevice(GrContext* context, SkBitmap::Config config, int width,
bsalomon@google.come97f0852011-06-17 13:10:25 +0000194 int height, Usage usage)
reed@google.comaf951c92011-06-16 19:10:39 +0000195: SkDevice(config, width, height, false /*isOpaque*/) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000196 fNeedPrepareRenderTarget = false;
197 fDrawProcs = NULL;
198
reed@google.com7b201d22011-01-11 18:59:23 +0000199 fContext = context;
bsalomon@google.com5782d712011-01-21 21:03:59 +0000200 fContext->ref();
reed@google.comac10a2d2010-12-22 21:39:39 +0000201
202 fCache = NULL;
203 fTexture = NULL;
204 fRenderTarget = NULL;
205 fNeedClear = false;
206
reed@google.comaf951c92011-06-16 19:10:39 +0000207 if (config != SkBitmap::kRGB_565_Config) {
208 config = SkBitmap::kARGB_8888_Config;
209 }
210 SkBitmap bm;
211 bm.setConfig(config, width, height);
reed@google.comac10a2d2010-12-22 21:39:39 +0000212
213#if CACHE_LAYER_TEXTURES
bsalomon@google.come97f0852011-06-17 13:10:25 +0000214 TexType type = (kSaveLayer_Usage == usage) ?
215 kSaveLayerDeviceRenderTarget_TexType :
216 kDeviceRenderTarget_TexType;
reed@google.comaf951c92011-06-16 19:10:39 +0000217 fCache = this->lockCachedTexture(bm, GrSamplerState::ClampNoFilter(),
bsalomon@google.come97f0852011-06-17 13:10:25 +0000218 &fTexture, type);
reed@google.comaf951c92011-06-16 19:10:39 +0000219 if (fCache) {
220 SkASSERT(NULL != fTexture);
221 SkASSERT(NULL != fTexture->asRenderTarget());
bsalomon@google.comf9046fe2011-06-17 15:10:21 +0000222 // hold a ref directly on fTexture (even though fCache has one) to match
223 // other constructor paths. Simplifies cleanup.
224 fTexture->ref();
reed@google.comaf951c92011-06-16 19:10:39 +0000225 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000226#else
reed@google.comaf951c92011-06-16 19:10:39 +0000227 const GrTextureDesc desc = {
228 kRenderTarget_GrTextureFlagBit,
229 kNone_GrAALevel,
230 width,
231 height,
232 SkGr::Bitmap2PixelConfig(bm)
233 };
reed@google.comac10a2d2010-12-22 21:39:39 +0000234
reed@google.comaf951c92011-06-16 19:10:39 +0000235 fTexture = fContext->createUncachedTexture(desc, NULL, 0);
reed@google.comac10a2d2010-12-22 21:39:39 +0000236#endif
reed@google.comaf951c92011-06-16 19:10:39 +0000237 if (NULL != fTexture) {
238 fRenderTarget = fTexture->asRenderTarget();
bsalomon@google.comf9046fe2011-06-17 15:10:21 +0000239 fRenderTarget->ref();
reed@google.comac10a2d2010-12-22 21:39:39 +0000240
reed@google.comaf951c92011-06-16 19:10:39 +0000241 GrAssert(NULL != fRenderTarget);
reed@google.comac10a2d2010-12-22 21:39:39 +0000242
reed@google.comaf951c92011-06-16 19:10:39 +0000243 // we defer the actual clear until our gainFocus()
244 fNeedClear = true;
reed@google.comac10a2d2010-12-22 21:39:39 +0000245
reed@google.comaf951c92011-06-16 19:10:39 +0000246 // wrap the bitmap with a pixelref to expose our texture
247 SkGrTexturePixelRef* pr = new SkGrTexturePixelRef(fTexture);
bsalomon@google.com669fdc42011-04-05 17:08:27 +0000248 this->setPixelRef(pr, 0)->unref();
reed@google.comaf951c92011-06-16 19:10:39 +0000249 } else {
250 GrPrintf("--- failed to create gpu-offscreen [%d %d]\n",
251 width, height);
252 GrAssert(false);
reed@google.comac10a2d2010-12-22 21:39:39 +0000253 }
254}
255
256SkGpuDevice::~SkGpuDevice() {
257 if (fDrawProcs) {
258 delete fDrawProcs;
259 }
260
bsalomon@google.comf9046fe2011-06-17 15:10:21 +0000261 SkSafeUnref(fTexture);
262 SkSafeUnref(fRenderTarget);
reed@google.comac10a2d2010-12-22 21:39:39 +0000263 if (fCache) {
264 GrAssert(NULL != fTexture);
265 GrAssert(fRenderTarget == fTexture->asRenderTarget());
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000266 fContext->unlockTexture((GrTextureEntry*)fCache);
bsalomon@google.comf9046fe2011-06-17 15:10:21 +0000267 }
bsalomon@google.com5782d712011-01-21 21:03:59 +0000268 fContext->unref();
reed@google.comac10a2d2010-12-22 21:39:39 +0000269}
270
reed@google.comac10a2d2010-12-22 21:39:39 +0000271///////////////////////////////////////////////////////////////////////////////
272
273void SkGpuDevice::makeRenderTargetCurrent() {
274 fContext->setRenderTarget(fRenderTarget);
275 fContext->flush(true);
276 fNeedPrepareRenderTarget = true;
277}
278
279///////////////////////////////////////////////////////////////////////////////
280
281bool SkGpuDevice::readPixels(const SkIRect& srcRect, SkBitmap* bitmap) {
282 SkIRect bounds;
283 bounds.set(0, 0, this->width(), this->height());
284 if (!bounds.intersect(srcRect)) {
285 return false;
286 }
287
288 const int w = bounds.width();
289 const int h = bounds.height();
290 SkBitmap tmp;
291 // note we explicitly specify our rowBytes to be snug (no gap between rows)
292 tmp.setConfig(SkBitmap::kARGB_8888_Config, w, h, w * 4);
293 if (!tmp.allocPixels()) {
294 return false;
295 }
296
Scroggo813c33c2011-04-07 20:56:21 +0000297 tmp.lockPixels();
reed@google.comac10a2d2010-12-22 21:39:39 +0000298
Scroggoeb176032011-04-07 21:11:49 +0000299 bool read = fContext->readRenderTargetPixels(fRenderTarget,
300 bounds.fLeft, bounds.fTop,
301 bounds.width(), bounds.height(),
302 kRGBA_8888_GrPixelConfig,
303 tmp.getPixels());
Scroggo813c33c2011-04-07 20:56:21 +0000304 tmp.unlockPixels();
305 if (!read) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000306 return false;
307 }
308
309 tmp.swap(*bitmap);
310 return true;
311}
312
313void SkGpuDevice::writePixels(const SkBitmap& bitmap, int x, int y) {
314 SkAutoLockPixels alp(bitmap);
315 if (!bitmap.readyToDraw()) {
316 return;
317 }
bsalomon@google.com669fdc42011-04-05 17:08:27 +0000318 GrPixelConfig config = SkGr::BitmapConfig2PixelConfig(bitmap.config(),
319 bitmap.isOpaque());
reed@google.comac10a2d2010-12-22 21:39:39 +0000320 fContext->setRenderTarget(fRenderTarget);
321 // we aren't setting the clip or matrix, so mark as dirty
322 // we don't need to set them for this call and don't have them anyway
323 fNeedPrepareRenderTarget = true;
324
325 fContext->writePixels(x, y, bitmap.width(), bitmap.height(),
326 config, bitmap.getPixels(), bitmap.rowBytes());
327}
328
329///////////////////////////////////////////////////////////////////////////////
330
331static void convert_matrixclip(GrContext* context, const SkMatrix& matrix,
bsalomon@google.comd302f142011-03-03 13:54:13 +0000332 const SkClipStack& clipStack,
reed@google.com6f8f2922011-03-04 22:27:10 +0000333 const SkRegion& clipRegion,
334 const SkIPoint& origin) {
bsalomon@google.comcc4dac32011-05-10 13:52:42 +0000335 context->setMatrix(matrix);
reed@google.comac10a2d2010-12-22 21:39:39 +0000336
337 SkGrClipIterator iter;
bsalomon@google.comd302f142011-03-03 13:54:13 +0000338 iter.reset(clipStack);
bsalomon@google.comd302f142011-03-03 13:54:13 +0000339 const SkIRect& skBounds = clipRegion.getBounds();
340 GrRect bounds;
341 bounds.setLTRB(GrIntToScalar(skBounds.fLeft),
342 GrIntToScalar(skBounds.fTop),
343 GrIntToScalar(skBounds.fRight),
344 GrIntToScalar(skBounds.fBottom));
reed@google.com6f8f2922011-03-04 22:27:10 +0000345 GrClip grc(&iter, GrIntToScalar(-origin.x()), GrIntToScalar(-origin.y()),
346 &bounds);
bsalomon@google.comd302f142011-03-03 13:54:13 +0000347 context->setClip(grc);
reed@google.comac10a2d2010-12-22 21:39:39 +0000348}
349
350// call this ever each draw call, to ensure that the context reflects our state,
351// and not the state from some other canvas/device
352void SkGpuDevice::prepareRenderTarget(const SkDraw& draw) {
353 if (fNeedPrepareRenderTarget ||
bsalomon@google.com5782d712011-01-21 21:03:59 +0000354 fContext->getRenderTarget() != fRenderTarget) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000355
356 fContext->setRenderTarget(fRenderTarget);
bsalomon@google.comd302f142011-03-03 13:54:13 +0000357 SkASSERT(draw.fClipStack);
358 convert_matrixclip(fContext, *draw.fMatrix,
reed@google.com6f8f2922011-03-04 22:27:10 +0000359 *draw.fClipStack, *draw.fClip, this->getOrigin());
reed@google.comac10a2d2010-12-22 21:39:39 +0000360 fNeedPrepareRenderTarget = false;
361 }
362}
363
reed@google.com46799cd2011-02-22 20:56:26 +0000364void SkGpuDevice::setMatrixClip(const SkMatrix& matrix, const SkRegion& clip,
365 const SkClipStack& clipStack) {
366 this->INHERITED::setMatrixClip(matrix, clip, clipStack);
bsalomon@google.coma7bf6e22011-04-11 19:20:46 +0000367 // We don't need to set them now because the context may not reflect this device.
368 fNeedPrepareRenderTarget = true;
reed@google.comac10a2d2010-12-22 21:39:39 +0000369}
370
371void SkGpuDevice::gainFocus(SkCanvas* canvas, const SkMatrix& matrix,
bsalomon@google.comd302f142011-03-03 13:54:13 +0000372 const SkRegion& clip, const SkClipStack& clipStack) {
373
reed@google.comac10a2d2010-12-22 21:39:39 +0000374 fContext->setRenderTarget(fRenderTarget);
375
bsalomon@google.comd302f142011-03-03 13:54:13 +0000376 this->INHERITED::gainFocus(canvas, matrix, clip, clipStack);
reed@google.comac10a2d2010-12-22 21:39:39 +0000377
reed@google.com6f8f2922011-03-04 22:27:10 +0000378 convert_matrixclip(fContext, matrix, clipStack, clip, this->getOrigin());
reed@google.comac10a2d2010-12-22 21:39:39 +0000379
380 if (fNeedClear) {
bsalomon@google.com31a58402011-04-27 21:00:02 +0000381 fContext->clear(NULL, 0x0);
reed@google.comac10a2d2010-12-22 21:39:39 +0000382 fNeedClear = false;
383 }
384}
385
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000386bool SkGpuDevice::bindDeviceAsTexture(GrPaint* paint) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000387 if (NULL != fTexture) {
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000388 paint->setTexture(kBitmapTextureIdx, fTexture);
reed@google.comac10a2d2010-12-22 21:39:39 +0000389 return true;
390 }
391 return false;
392}
393
394///////////////////////////////////////////////////////////////////////////////
395
vandebo@chromium.orgd3ae7792011-02-24 00:21:06 +0000396SK_COMPILE_ASSERT(SkShader::kNone_BitmapType == 0, shader_type_mismatch);
397SK_COMPILE_ASSERT(SkShader::kDefault_BitmapType == 1, shader_type_mismatch);
398SK_COMPILE_ASSERT(SkShader::kRadial_BitmapType == 2, shader_type_mismatch);
399SK_COMPILE_ASSERT(SkShader::kSweep_BitmapType == 3, shader_type_mismatch);
400SK_COMPILE_ASSERT(SkShader::kTwoPointRadial_BitmapType == 4,
401 shader_type_mismatch);
402SK_COMPILE_ASSERT(SkShader::kLast_BitmapType == 4, shader_type_mismatch);
reed@google.comac10a2d2010-12-22 21:39:39 +0000403
bsalomon@google.com5782d712011-01-21 21:03:59 +0000404static const GrSamplerState::SampleMode sk_bmp_type_to_sample_mode[] = {
405 (GrSamplerState::SampleMode) -1, // kNone_BitmapType
406 GrSamplerState::kNormal_SampleMode, // kDefault_BitmapType
407 GrSamplerState::kRadial_SampleMode, // kRadial_BitmapType
408 GrSamplerState::kSweep_SampleMode, // kSweep_BitmapType
409 GrSamplerState::kRadial2_SampleMode, // kTwoPointRadial_BitmapType
410};
411
412bool SkGpuDevice::skPaint2GrPaintNoShader(const SkPaint& skPaint,
413 bool justAlpha,
Scroggod757df22011-05-16 13:11:16 +0000414 GrPaint* grPaint,
415 bool constantColor) {
bsalomon@google.com5782d712011-01-21 21:03:59 +0000416
417 grPaint->fDither = skPaint.isDither();
418 grPaint->fAntiAlias = skPaint.isAntiAlias();
419
420 SkXfermode::Coeff sm = SkXfermode::kOne_Coeff;
421 SkXfermode::Coeff dm = SkXfermode::kISA_Coeff;
422
423 SkXfermode* mode = skPaint.getXfermode();
424 if (mode) {
425 if (!mode->asCoeff(&sm, &dm)) {
reed@google.com1a2e8d22011-01-21 22:08:29 +0000426 SkDEBUGCODE(SkDebugf("Unsupported xfer mode.\n");)
bsalomon@google.com5782d712011-01-21 21:03:59 +0000427#if 0
428 return false;
429#endif
430 }
431 }
432 grPaint->fSrcBlendCoeff = sk_blend_to_grblend(sm);
433 grPaint->fDstBlendCoeff = sk_blend_to_grblend(dm);
434
435 if (justAlpha) {
436 uint8_t alpha = skPaint.getAlpha();
437 grPaint->fColor = GrColorPackRGBA(alpha, alpha, alpha, alpha);
Scroggod757df22011-05-16 13:11:16 +0000438 // justAlpha is currently set to true only if there is a texture,
439 // so constantColor should not also be true.
440 GrAssert(!constantColor);
bsalomon@google.com5782d712011-01-21 21:03:59 +0000441 } else {
442 grPaint->fColor = SkGr::SkColor2GrColor(skPaint.getColor());
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000443 grPaint->setTexture(kShaderTextureIdx, NULL);
bsalomon@google.com5782d712011-01-21 21:03:59 +0000444 }
Scroggo97c88c22011-05-11 14:05:25 +0000445 SkColorFilter* colorFilter = skPaint.getColorFilter();
446 SkColor color;
447 SkXfermode::Mode filterMode;
448 if (colorFilter != NULL && colorFilter->asColorMode(&color, &filterMode)) {
Scroggod757df22011-05-16 13:11:16 +0000449 if (!constantColor) {
450 grPaint->fColorFilterColor = SkGr::SkColor2GrColor(color);
451 grPaint->fColorFilterXfermode = filterMode;
452 return true;
453 }
454 SkColor filtered = colorFilter->filterColor(skPaint.getColor());
455 grPaint->fColor = SkGr::SkColor2GrColor(filtered);
Scroggo97c88c22011-05-11 14:05:25 +0000456 }
Scroggod757df22011-05-16 13:11:16 +0000457 grPaint->resetColorFilter();
bsalomon@google.com5782d712011-01-21 21:03:59 +0000458 return true;
reed@google.comac10a2d2010-12-22 21:39:39 +0000459}
460
bsalomon@google.com5782d712011-01-21 21:03:59 +0000461bool SkGpuDevice::skPaint2GrPaintShader(const SkPaint& skPaint,
462 SkAutoCachedTexture* act,
463 const SkMatrix& ctm,
Scroggod757df22011-05-16 13:11:16 +0000464 GrPaint* grPaint,
465 bool constantColor) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000466
bsalomon@google.com5782d712011-01-21 21:03:59 +0000467 SkASSERT(NULL != act);
reed@google.comac10a2d2010-12-22 21:39:39 +0000468
bsalomon@google.com5782d712011-01-21 21:03:59 +0000469 SkShader* shader = skPaint.getShader();
reed@google.comac10a2d2010-12-22 21:39:39 +0000470 if (NULL == shader) {
Scroggod757df22011-05-16 13:11:16 +0000471 return this->skPaint2GrPaintNoShader(skPaint,
472 false,
473 grPaint,
474 constantColor);
475 } else if (!this->skPaint2GrPaintNoShader(skPaint, true, grPaint, false)) {
bsalomon@google.com5782d712011-01-21 21:03:59 +0000476 return false;
reed@google.comac10a2d2010-12-22 21:39:39 +0000477 }
478
reed@google.comac10a2d2010-12-22 21:39:39 +0000479 SkBitmap bitmap;
480 SkMatrix matrix;
481 SkShader::TileMode tileModes[2];
482 SkScalar twoPointParams[3];
483 SkShader::BitmapType bmptype = shader->asABitmap(&bitmap, &matrix,
484 tileModes, twoPointParams);
485
bsalomon@google.com5782d712011-01-21 21:03:59 +0000486 GrSamplerState::SampleMode sampleMode = sk_bmp_type_to_sample_mode[bmptype];
487 if (-1 == sampleMode) {
reed@google.com2be9e8b2011-07-06 21:18:09 +0000488 SkShader::GradientInfo info;
489 SkColor color;
490
491 info.fColors = &color;
492 info.fColorOffsets = NULL;
493 info.fColorCount = 1;
494 if (SkShader::kColor_GradientType == shader->asAGradient(&info)) {
495 SkPaint copy(skPaint);
496 copy.setShader(NULL);
bsalomon@google.comcd9cfd72011-07-08 16:55:04 +0000497 // modulate the paint alpha by the shader's solid color alpha
498 U8CPU newA = SkMulDiv255Round(SkColorGetA(color), copy.getAlpha());
499 copy.setColor(SkColorSetA(color, newA));
reed@google.com2be9e8b2011-07-06 21:18:09 +0000500 return this->skPaint2GrPaintNoShader(copy,
501 false,
502 grPaint,
503 constantColor);
504 }
bsalomon@google.com5782d712011-01-21 21:03:59 +0000505 return false;
reed@google.comac10a2d2010-12-22 21:39:39 +0000506 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000507 GrSamplerState* sampler = grPaint->getTextureSampler(kShaderTextureIdx);
508 sampler->setSampleMode(sampleMode);
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000509 if (skPaint.isFilterBitmap()) {
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000510 sampler->setFilter(GrSamplerState::kBilinear_Filter);
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000511 } else {
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000512 sampler->setFilter(GrSamplerState::kNearest_Filter);
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000513 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000514 sampler->setWrapX(sk_tile_mode_to_grwrap(tileModes[0]));
515 sampler->setWrapY(sk_tile_mode_to_grwrap(tileModes[1]));
reed@google.comac10a2d2010-12-22 21:39:39 +0000516 if (GrSamplerState::kRadial2_SampleMode == sampleMode) {
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000517 sampler->setRadial2Params(twoPointParams[0],
518 twoPointParams[1],
519 twoPointParams[2] < 0);
reed@google.comac10a2d2010-12-22 21:39:39 +0000520 }
521
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000522 GrTexture* texture = act->set(this, bitmap, *sampler);
reed@google.comac10a2d2010-12-22 21:39:39 +0000523 if (NULL == texture) {
bsalomon@google.com5782d712011-01-21 21:03:59 +0000524 SkDebugf("Couldn't convert bitmap to texture.\n");
525 return false;
reed@google.comac10a2d2010-12-22 21:39:39 +0000526 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000527 grPaint->setTexture(kShaderTextureIdx, texture);
reed@google.comac10a2d2010-12-22 21:39:39 +0000528
529 // since our texture coords will be in local space, we wack the texture
530 // matrix to map them back into 0...1 before we load it
531 SkMatrix localM;
532 if (shader->getLocalMatrix(&localM)) {
533 SkMatrix inverse;
534 if (localM.invert(&inverse)) {
535 matrix.preConcat(inverse);
536 }
537 }
538 if (SkShader::kDefault_BitmapType == bmptype) {
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000539 GrScalar sx = GrFixedToScalar(GR_Fixed1 / bitmap.width());
540 GrScalar sy = GrFixedToScalar(GR_Fixed1 / bitmap.height());
reed@google.comac10a2d2010-12-22 21:39:39 +0000541 matrix.postScale(sx, sy);
reed@google.comac10a2d2010-12-22 21:39:39 +0000542 } else if (SkShader::kRadial_BitmapType == bmptype) {
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000543 GrScalar s = GrFixedToScalar(GR_Fixed1 / bitmap.width());
reed@google.comac10a2d2010-12-22 21:39:39 +0000544 matrix.postScale(s, s);
545 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000546 sampler->setMatrix(matrix);
bsalomon@google.com5782d712011-01-21 21:03:59 +0000547
548 return true;
reed@google.comac10a2d2010-12-22 21:39:39 +0000549}
550
551///////////////////////////////////////////////////////////////////////////////
bsalomon@google.com5782d712011-01-21 21:03:59 +0000552
553class SkPositionSource {
554public:
555 SkPositionSource(const SkPoint* points, int count)
556 : fPoints(points), fCount(count) {}
557
558 int count() const { return fCount; }
559
560 void writeValue(int i, GrPoint* dstPosition) const {
561 SkASSERT(i < fCount);
562 dstPosition->fX = SkScalarToGrScalar(fPoints[i].fX);
563 dstPosition->fY = SkScalarToGrScalar(fPoints[i].fY);
564 }
565private:
bsalomon@google.com5782d712011-01-21 21:03:59 +0000566 const SkPoint* fPoints;
bsalomon@google.com19628322011-02-03 21:30:17 +0000567 int fCount;
bsalomon@google.com5782d712011-01-21 21:03:59 +0000568};
569
570class SkTexCoordSource {
571public:
572 SkTexCoordSource(const SkPoint* coords)
573 : fCoords(coords) {}
574
575 void writeValue(int i, GrPoint* dstCoord) const {
576 dstCoord->fX = SkScalarToGrScalar(fCoords[i].fX);
577 dstCoord->fY = SkScalarToGrScalar(fCoords[i].fY);
578 }
579private:
580 const SkPoint* fCoords;
581};
582
583class SkColorSource {
584public:
585 SkColorSource(const SkColor* colors) : fColors(colors) {}
586
587 void writeValue(int i, GrColor* dstColor) const {
588 *dstColor = SkGr::SkColor2GrColor(fColors[i]);
589 }
590private:
591 const SkColor* fColors;
592};
593
594class SkIndexSource {
595public:
596 SkIndexSource(const uint16_t* indices, int count)
597 : fIndices(indices), fCount(count) {
598 }
599
600 int count() const { return fCount; }
601
602 void writeValue(int i, uint16_t* dstIndex) const {
603 *dstIndex = fIndices[i];
604 }
605
606private:
bsalomon@google.com5782d712011-01-21 21:03:59 +0000607 const uint16_t* fIndices;
bsalomon@google.com19628322011-02-03 21:30:17 +0000608 int fCount;
bsalomon@google.com5782d712011-01-21 21:03:59 +0000609};
610
611///////////////////////////////////////////////////////////////////////////////
612
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000613#if 0 // not currently being used so don't compile,
614
bsalomon@google.com5782d712011-01-21 21:03:59 +0000615// can be used for positions or texture coordinates
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000616
bsalomon@google.com5782d712011-01-21 21:03:59 +0000617class SkRectFanSource {
618public:
619 SkRectFanSource(const SkRect& rect) : fRect(rect) {}
620
621 int count() const { return 4; }
622
623 void writeValue(int i, GrPoint* dstPoint) const {
624 SkASSERT(i < 4);
625 dstPoint->fX = SkScalarToGrScalar((i % 3) ? fRect.fRight :
626 fRect.fLeft);
627 dstPoint->fY = SkScalarToGrScalar((i < 2) ? fRect.fTop :
628 fRect.fBottom);
629 }
630private:
631 const SkRect& fRect;
632};
633
634class SkIRectFanSource {
635public:
636 SkIRectFanSource(const SkIRect& rect) : fRect(rect) {}
637
638 int count() const { return 4; }
639
640 void writeValue(int i, GrPoint* dstPoint) const {
641 SkASSERT(i < 4);
642 dstPoint->fX = (i % 3) ? GrIntToScalar(fRect.fRight) :
643 GrIntToScalar(fRect.fLeft);
644 dstPoint->fY = (i < 2) ? GrIntToScalar(fRect.fTop) :
645 GrIntToScalar(fRect.fBottom);
646 }
647private:
648 const SkIRect& fRect;
649};
650
651class SkMatRectFanSource {
652public:
653 SkMatRectFanSource(const SkRect& rect, const SkMatrix& matrix)
654 : fRect(rect), fMatrix(matrix) {}
655
656 int count() const { return 4; }
657
658 void writeValue(int i, GrPoint* dstPoint) const {
659 SkASSERT(i < 4);
660
661#if SK_SCALAR_IS_GR_SCALAR
662 fMatrix.mapXY((i % 3) ? fRect.fRight : fRect.fLeft,
663 (i < 2) ? fRect.fTop : fRect.fBottom,
664 (SkPoint*)dstPoint);
665#else
666 SkPoint dst;
667 fMatrix.mapXY((i % 3) ? fRect.fRight : fRect.fLeft,
668 (i < 2) ? fRect.fTop : fRect.fBottom,
669 &dst);
670 dstPoint->fX = SkScalarToGrScalar(dst.fX);
671 dstPoint->fY = SkScalarToGrScalar(dst.fY);
672#endif
673 }
674private:
675 const SkRect& fRect;
676 const SkMatrix& fMatrix;
677};
678
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000679#endif
680
reed@google.comac10a2d2010-12-22 21:39:39 +0000681///////////////////////////////////////////////////////////////////////////////
682
bsalomon@google.com398109c2011-04-14 18:40:27 +0000683void SkGpuDevice::clear(SkColor color) {
bsalomon@google.com31a58402011-04-27 21:00:02 +0000684 fContext->clear(NULL, color);
bsalomon@google.com398109c2011-04-14 18:40:27 +0000685}
686
reed@google.comac10a2d2010-12-22 21:39:39 +0000687void SkGpuDevice::drawPaint(const SkDraw& draw, const SkPaint& paint) {
688 CHECK_SHOULD_DRAW(draw);
689
bsalomon@google.com5782d712011-01-21 21:03:59 +0000690 GrPaint grPaint;
691 SkAutoCachedTexture act;
Scroggod757df22011-05-16 13:11:16 +0000692 if (!this->skPaint2GrPaintShader(paint,
693 &act,
694 *draw.fMatrix,
695 &grPaint,
696 true)) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000697 return;
698 }
bsalomon@google.com5782d712011-01-21 21:03:59 +0000699
700 fContext->drawPaint(grPaint);
reed@google.comac10a2d2010-12-22 21:39:39 +0000701}
702
703// must be in SkCanvas::PointMode order
bsalomon@google.comffca4002011-02-22 20:34:01 +0000704static const GrPrimitiveType gPointMode2PrimtiveType[] = {
705 kPoints_PrimitiveType,
706 kLines_PrimitiveType,
707 kLineStrip_PrimitiveType
reed@google.comac10a2d2010-12-22 21:39:39 +0000708};
709
710void SkGpuDevice::drawPoints(const SkDraw& draw, SkCanvas::PointMode mode,
bsalomon@google.com5782d712011-01-21 21:03:59 +0000711 size_t count, const SkPoint pts[], const SkPaint& paint) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000712 CHECK_SHOULD_DRAW(draw);
713
714 SkScalar width = paint.getStrokeWidth();
715 if (width < 0) {
716 return;
717 }
718
719 // we only handle hairlines here, else we let the SkDraw call our drawPath()
720 if (width > 0) {
721 draw.drawPoints(mode, count, pts, paint, true);
722 return;
723 }
724
bsalomon@google.com5782d712011-01-21 21:03:59 +0000725 GrPaint grPaint;
726 SkAutoCachedTexture act;
Scroggod757df22011-05-16 13:11:16 +0000727 if (!this->skPaint2GrPaintShader(paint,
728 &act,
729 *draw.fMatrix,
730 &grPaint,
731 true)) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000732 return;
733 }
734
reed@google.comac10a2d2010-12-22 21:39:39 +0000735#if SK_SCALAR_IS_GR_SCALAR
bsalomon@google.com5782d712011-01-21 21:03:59 +0000736 fContext->drawVertices(grPaint,
737 gPointMode2PrimtiveType[mode],
738 count,
739 (GrPoint*)pts,
740 NULL,
741 NULL,
742 NULL,
743 0);
reed@google.comac10a2d2010-12-22 21:39:39 +0000744#else
bsalomon@google.com5782d712011-01-21 21:03:59 +0000745 fContext->drawCustomVertices(grPaint,
746 gPointMode2PrimtiveType[mode],
747 SkPositionSource(pts, count));
reed@google.comac10a2d2010-12-22 21:39:39 +0000748#endif
reed@google.comac10a2d2010-12-22 21:39:39 +0000749}
750
reed@google.comc9aa5872011-04-05 21:05:37 +0000751///////////////////////////////////////////////////////////////////////////////
752
reed@google.comac10a2d2010-12-22 21:39:39 +0000753void SkGpuDevice::drawRect(const SkDraw& draw, const SkRect& rect,
754 const SkPaint& paint) {
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000755 CHECK_SHOULD_DRAW(draw);
756
bungeman@google.com79bd8772011-07-18 15:34:08 +0000757 bool doStroke = paint.getStyle() != SkPaint::kFill_Style;
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000758 SkScalar width = paint.getStrokeWidth();
759
760 /*
761 We have special code for hairline strokes, miter-strokes, and fills.
762 Anything else we just call our path code.
763 */
764 bool usePath = doStroke && width > 0 &&
765 paint.getStrokeJoin() != SkPaint::kMiter_Join;
766 // another reason we might need to call drawPath...
767 if (paint.getMaskFilter()) {
768 usePath = true;
769 }
reed@google.com67db6642011-05-26 11:46:35 +0000770 // until we aa rotated rects...
771 if (!usePath && paint.isAntiAlias() && !draw.fMatrix->rectStaysRect()) {
772 usePath = true;
773 }
bungeman@google.com79bd8772011-07-18 15:34:08 +0000774 // until we can both stroke and fill rectangles
775 // with large enough miter limit...
776 if (paint.getStyle() == SkPaint::kStrokeAndFill_Style) {
777 usePath = true;
778 }
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000779
780 if (usePath) {
781 SkPath path;
782 path.addRect(rect);
783 this->drawPath(draw, path, paint, NULL, true);
784 return;
785 }
786
787 GrPaint grPaint;
788 SkAutoCachedTexture act;
Scroggod757df22011-05-16 13:11:16 +0000789 if (!this->skPaint2GrPaintShader(paint,
790 &act,
791 *draw.fMatrix,
792 &grPaint,
793 true)) {
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000794 return;
795 }
reed@google.com20efde72011-05-09 17:00:02 +0000796 fContext->drawRect(grPaint, rect, doStroke ? width : -1);
reed@google.comac10a2d2010-12-22 21:39:39 +0000797}
798
reed@google.com69302852011-02-16 18:08:07 +0000799#include "SkMaskFilter.h"
800#include "SkBounder.h"
801
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +0000802static GrPathFill skToGrFillType(SkPath::FillType fillType) {
803 switch (fillType) {
804 case SkPath::kWinding_FillType:
805 return kWinding_PathFill;
806 case SkPath::kEvenOdd_FillType:
807 return kEvenOdd_PathFill;
808 case SkPath::kInverseWinding_FillType:
809 return kInverseWinding_PathFill;
810 case SkPath::kInverseEvenOdd_FillType:
811 return kInverseEvenOdd_PathFill;
812 default:
813 SkDebugf("Unsupported path fill type\n");
814 return kHairLine_PathFill;
815 }
816}
817
senorblanco@chromium.orgb08ea1b2011-07-12 16:54:59 +0000818static void buildKernel(float sigma, float* kernel, int kernelWidth) {
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +0000819 int halfWidth = (kernelWidth - 1) / 2;
820 float sum = 0.0f;
senorblanco@chromium.orgb08ea1b2011-07-12 16:54:59 +0000821 float denom = 1.0f / (2.0f * sigma * sigma);
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +0000822 for (int i = 0; i < kernelWidth; ++i) {
senorblanco@chromium.orgb08ea1b2011-07-12 16:54:59 +0000823 float x = static_cast<float>(i - halfWidth);
824 // Note that the constant term (1/(sqrt(2*pi*sigma^2)) of the Gaussian
825 // is dropped here, since we renormalize the kernel below.
826 kernel[i] = sk_float_exp(- x * x * denom);
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +0000827 sum += kernel[i];
828 }
829 // Normalize the kernel
830 float scale = 1.0f / sum;
831 for (int i = 0; i < kernelWidth; ++i)
832 kernel[i] *= scale;
833}
834
senorblanco@chromium.orgb08ea1b2011-07-12 16:54:59 +0000835static void scaleRect(SkRect* rect, float scale) {
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +0000836 rect->fLeft *= scale;
837 rect->fTop *= scale;
838 rect->fRight *= scale;
839 rect->fBottom *= scale;
840}
841
842static bool drawWithGPUMaskFilter(GrContext* context, const SkPath& path,
843 SkMaskFilter* filter, const SkMatrix& matrix,
844 const SkRegion& clip, SkBounder* bounder,
845 GrPaint* grp) {
senorblanco@chromium.orga479fc72011-07-19 16:40:58 +0000846#ifdef SK_DISABLE_GPU_BLUR
senorblanco@chromium.orgaadd9f82011-07-12 19:44:51 +0000847 return false;
senorblanco@chromium.orgb08ea1b2011-07-12 16:54:59 +0000848#endif
senorblanco@chromium.orgaadd9f82011-07-12 19:44:51 +0000849 SkMaskFilter::BlurInfo info;
850 SkMaskFilter::BlurType blurType = filter->asABlur(&info);
senorblanco@chromium.orgb08ea1b2011-07-12 16:54:59 +0000851 if (SkMaskFilter::kNone_BlurType == blurType) {
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +0000852 return false;
853 }
senorblanco@chromium.orge36ddf02011-07-15 14:28:16 +0000854 SkScalar radius = info.fIgnoreTransform ? info.fRadius
855 : matrix.mapRadius(info.fRadius);
856 radius = SkMinScalar(radius, MAX_BLUR_RADIUS);
857 float sigma = SkScalarToFloat(radius) * BLUR_SIGMA_SCALE;
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +0000858 SkRect srcRect = path.getBounds();
859
860 int scaleFactor = 1;
861
senorblanco@chromium.orge36ddf02011-07-15 14:28:16 +0000862 while (sigma > MAX_BLUR_SIGMA) {
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +0000863 scaleFactor *= 2;
864 sigma *= 0.5f;
865 }
866 scaleRect(&srcRect, 1.0f / scaleFactor);
senorblanco@chromium.org4a947d22011-07-18 21:48:35 +0000867 int halfWidth = static_cast<int>(ceilf(sigma * 3.0f));
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +0000868 int kernelWidth = halfWidth * 2 + 1;
869
870 SkIRect srcIRect;
871 srcRect.roundOut(&srcIRect);
872 srcRect.set(srcIRect);
873 srcRect.inset(-halfWidth, -halfWidth);
874
875 scaleRect(&srcRect, scaleFactor);
876 SkRect finalRect = srcRect;
877
878 SkIRect finalIRect;
879 finalRect.roundOut(&finalIRect);
880 if (clip.quickReject(finalIRect)) {
senorblanco@chromium.orgaadd9f82011-07-12 19:44:51 +0000881 return true;
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +0000882 }
883 if (bounder && !bounder->doIRect(finalIRect)) {
senorblanco@chromium.orgaadd9f82011-07-12 19:44:51 +0000884 return true;
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +0000885 }
886 GrPoint offset = GrPoint::Make(-srcRect.fLeft, -srcRect.fTop);
887 srcRect.offset(-srcRect.fLeft, -srcRect.fTop);
888 const GrTextureDesc desc = {
889 kRenderTarget_GrTextureFlagBit,
890 kNone_GrAALevel,
891 srcRect.width(),
892 srcRect.height(),
893 // We actually only need A8, but it often isn't supported as a
894 // render target
895 kRGBA_8888_GrPixelConfig
896 };
897
898 GrTextureEntry* srcEntry = context->findApproximateKeylessTexture(desc);
899 GrTextureEntry* dstEntry = context->findApproximateKeylessTexture(desc);
senorblanco@chromium.orgaadd9f82011-07-12 19:44:51 +0000900 GrAutoUnlockTextureEntry srcLock(context, srcEntry),
901 dstLock(context, dstEntry);
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +0000902 if (NULL == srcEntry || NULL == dstEntry) {
903 return false;
904 }
905 GrTexture* srcTexture = srcEntry->texture();
906 GrTexture* dstTexture = dstEntry->texture();
907 if (NULL == srcTexture || NULL == dstTexture) {
908 return false;
909 }
910 GrRenderTarget* oldRenderTarget = context->getRenderTarget();
senorblanco@chromium.org42dd0f92011-07-14 15:29:57 +0000911 // Once this code moves into GrContext, this should be changed to use
912 // an AutoClipRestore.
913 GrClip oldClip = context->getClip();
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +0000914 context->setRenderTarget(dstTexture->asRenderTarget());
senorblanco@chromium.org42dd0f92011-07-14 15:29:57 +0000915 context->setClip(srcRect);
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +0000916 // FIXME: could just clear bounds
917 context->clear(NULL, 0);
918 GrMatrix transM;
919 GrPaint tempPaint;
920 tempPaint.reset();
921
922 GrAutoMatrix avm(context, GrMatrix::I());
senorblanco@chromium.orgb08ea1b2011-07-12 16:54:59 +0000923 tempPaint.fAntiAlias = grp->fAntiAlias;
924 if (tempPaint.fAntiAlias) {
925 // AA uses the "coverage" stages on GrDrawTarget. Coverage with a dst
926 // blend coeff of zero requires dual source blending support in order
927 // to properly blend partially covered pixels. This means the AA
928 // code path may not be taken. So we use a dst blend coeff of ISA. We
929 // could special case AA draws to a dst surface with known alpha=0 to
930 // use a zero dst coeff when dual source blending isn't available.
931 tempPaint.fSrcBlendCoeff = kOne_BlendCoeff;
932 tempPaint.fDstBlendCoeff = kISC_BlendCoeff;
933 }
934 // Draw hard shadow to dstTexture with path topleft at origin 0,0.
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +0000935 context->drawPath(tempPaint, path, skToGrFillType(path.getFillType()), &offset);
senorblanco@chromium.orgb08ea1b2011-07-12 16:54:59 +0000936 SkTSwap(srcTexture, dstTexture);
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +0000937
938 GrMatrix sampleM;
939 sampleM.setScale(GR_Scalar1 / srcTexture->width(),
940 GR_Scalar1 / srcTexture->height());
941 GrPaint paint;
942 paint.reset();
943 paint.getTextureSampler(0)->setFilter(GrSamplerState::kBilinear_Filter);
944 paint.getTextureSampler(0)->setMatrix(sampleM);
senorblanco@chromium.orgb08ea1b2011-07-12 16:54:59 +0000945 GrTextureEntry* origEntry = NULL;
946 if (blurType != SkMaskFilter::kNormal_BlurType) {
947 // Stash away a copy of the unblurred image.
948 origEntry = context->findApproximateKeylessTexture(desc);
949 if (NULL == origEntry) {
950 return false;
951 }
952 context->setRenderTarget(origEntry->texture()->asRenderTarget());
953 paint.setTexture(0, srcTexture);
954 context->drawRect(paint, srcRect);
955 }
senorblanco@chromium.orgaadd9f82011-07-12 19:44:51 +0000956 GrAutoUnlockTextureEntry origLock(context, origEntry);
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +0000957 for (int i = 1; i < scaleFactor; i *= 2) {
958 context->setRenderTarget(dstTexture->asRenderTarget());
959 SkRect dstRect(srcRect);
960 scaleRect(&dstRect, 0.5f);
961 // Clear out 1 pixel border for linear filtering.
962 // FIXME: for now, clear everything
963 context->clear(NULL, 0);
964 paint.setTexture(0, srcTexture);
965 context->drawRectToRect(paint, dstRect, srcRect);
966 srcRect = dstRect;
senorblanco@chromium.orgb08ea1b2011-07-12 16:54:59 +0000967 SkTSwap(srcTexture, dstTexture);
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +0000968 }
969
970 SkAutoTMalloc<float> kernelStorage(kernelWidth);
971 float* kernel = kernelStorage.get();
972 buildKernel(sigma, kernel, kernelWidth);
973
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +0000974 context->setRenderTarget(dstTexture->asRenderTarget());
975 context->clear(NULL, 0);
senorblanco@chromium.orgaadd9f82011-07-12 19:44:51 +0000976 context->convolveInX(srcTexture, srcRect, kernel, kernelWidth);
senorblanco@chromium.orgb08ea1b2011-07-12 16:54:59 +0000977 SkTSwap(srcTexture, dstTexture);
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +0000978
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +0000979 context->setRenderTarget(dstTexture->asRenderTarget());
980 context->clear(NULL, 0);
senorblanco@chromium.orgaadd9f82011-07-12 19:44:51 +0000981 context->convolveInY(srcTexture, srcRect, kernel, kernelWidth);
senorblanco@chromium.orgb08ea1b2011-07-12 16:54:59 +0000982 SkTSwap(srcTexture, dstTexture);
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +0000983
984 if (scaleFactor > 1) {
985 // FIXME: This should be mitchell, not bilinear.
986 paint.getTextureSampler(0)->setFilter(GrSamplerState::kBilinear_Filter);
987 sampleM.setScale(GR_Scalar1 / srcTexture->width(),
988 GR_Scalar1 / srcTexture->height());
989 paint.getTextureSampler(0)->setMatrix(sampleM);
990 context->setRenderTarget(dstTexture->asRenderTarget());
991 // Clear out 2 pixel border for bicubic filtering.
992 // FIXME: for now, clear everything
993 context->clear(NULL, 0);
994 paint.setTexture(0, srcTexture);
995 SkRect dstRect(srcRect);
996 scaleRect(&dstRect, scaleFactor);
997 context->drawRectToRect(paint, dstRect, srcRect);
998 srcRect = dstRect;
senorblanco@chromium.orgb08ea1b2011-07-12 16:54:59 +0000999 SkTSwap(srcTexture, dstTexture);
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +00001000 }
1001
senorblanco@chromium.orgb08ea1b2011-07-12 16:54:59 +00001002 if (blurType != SkMaskFilter::kNormal_BlurType) {
1003 GrTexture* origTexture = origEntry->texture();
1004 paint.getTextureSampler(0)->setFilter(GrSamplerState::kNearest_Filter);
1005 sampleM.setScale(GR_Scalar1 / origTexture->width(),
1006 GR_Scalar1 / origTexture->height());
1007 paint.getTextureSampler(0)->setMatrix(sampleM);
1008 // Blend origTexture over srcTexture.
1009 context->setRenderTarget(srcTexture->asRenderTarget());
1010 paint.setTexture(0, origTexture);
1011 if (SkMaskFilter::kInner_BlurType == blurType) {
1012 // inner: dst = dst * src
1013 paint.fSrcBlendCoeff = kDC_BlendCoeff;
1014 paint.fDstBlendCoeff = kZero_BlendCoeff;
1015 } else if (SkMaskFilter::kSolid_BlurType == blurType) {
1016 // solid: dst = src + dst - src * dst
1017 // = (1 - dst) * src + 1 * dst
1018 paint.fSrcBlendCoeff = kIDC_BlendCoeff;
1019 paint.fDstBlendCoeff = kOne_BlendCoeff;
1020 } else if (SkMaskFilter::kOuter_BlurType == blurType) {
1021 // outer: dst = dst * (1 - src)
1022 // = 0 * src + (1 - src) * dst
1023 paint.fSrcBlendCoeff = kZero_BlendCoeff;
1024 paint.fDstBlendCoeff = kISC_BlendCoeff;
1025 }
1026 context->drawRect(paint, srcRect);
1027 }
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +00001028 context->setRenderTarget(oldRenderTarget);
senorblanco@chromium.org42dd0f92011-07-14 15:29:57 +00001029 context->setClip(oldClip);
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +00001030
1031 if (grp->hasTextureOrMask()) {
1032 GrMatrix inverse;
1033 if (!matrix.invert(&inverse)) {
1034 return false;
1035 }
1036 grp->preConcatActiveSamplerMatrices(inverse);
1037 }
1038
1039 static const int MASK_IDX = GrPaint::kMaxMasks - 1;
1040 // we assume the last mask index is available for use
1041 GrAssert(NULL == grp->getMask(MASK_IDX));
1042 grp->setMask(MASK_IDX, srcTexture);
1043 grp->getMaskSampler(MASK_IDX)->setClampNoFilter();
1044
1045 GrMatrix m;
1046 m.setTranslate(-finalRect.fLeft, -finalRect.fTop);
1047 m.postIDiv(srcTexture->width(), srcTexture->height());
1048 grp->getMaskSampler(MASK_IDX)->setMatrix(m);
1049 context->drawRect(*grp, finalRect);
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +00001050 return true;
1051}
1052
reed@google.com69302852011-02-16 18:08:07 +00001053static bool drawWithMaskFilter(GrContext* context, const SkPath& path,
1054 SkMaskFilter* filter, const SkMatrix& matrix,
1055 const SkRegion& clip, SkBounder* bounder,
1056 GrPaint* grp) {
1057 SkMask srcM, dstM;
1058
1059 if (!SkDraw::DrawToMask(path, &clip.getBounds(), filter, &matrix, &srcM,
1060 SkMask::kComputeBoundsAndRenderImage_CreateMode)) {
1061 return false;
1062 }
1063
1064 SkAutoMaskImage autoSrc(&srcM, false);
1065
1066 if (!filter->filterMask(&dstM, srcM, matrix, NULL)) {
1067 return false;
1068 }
1069 // this will free-up dstM when we're done (allocated in filterMask())
1070 SkAutoMaskImage autoDst(&dstM, false);
1071
1072 if (clip.quickReject(dstM.fBounds)) {
1073 return false;
1074 }
1075 if (bounder && !bounder->doIRect(dstM.fBounds)) {
1076 return false;
1077 }
1078
1079 // we now have a device-aligned 8bit mask in dstM, ready to be drawn using
1080 // the current clip (and identity matrix) and grpaint settings
1081
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001082 // used to compute inverse view, if necessary
1083 GrMatrix ivm = context->getMatrix();
1084
reed@google.com0c219b62011-02-16 21:31:18 +00001085 GrAutoMatrix avm(context, GrMatrix::I());
reed@google.com69302852011-02-16 18:08:07 +00001086
bsalomon@google.comfea37b52011-04-25 15:51:06 +00001087 const GrTextureDesc desc = {
1088 kNone_GrTextureFlags,
1089 kNone_GrAALevel,
reed@google.com69302852011-02-16 18:08:07 +00001090 dstM.fBounds.width(),
1091 dstM.fBounds.height(),
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001092 kAlpha_8_GrPixelConfig
reed@google.com69302852011-02-16 18:08:07 +00001093 };
1094
bsalomon@google.comeb2aa1d2011-07-14 15:45:19 +00001095 GrAutoUnlockTextureEntry aute(context,
1096 context->findApproximateKeylessTexture(desc));
1097 GrTexture* texture = aute.texture();
1098
reed@google.com69302852011-02-16 18:08:07 +00001099 if (NULL == texture) {
1100 return false;
1101 }
bsalomon@google.comeb2aa1d2011-07-14 15:45:19 +00001102 texture->uploadTextureData(0, 0, desc.fWidth, desc.fHeight,
1103 dstM.fImage, dstM.fRowBytes);
reed@google.com69302852011-02-16 18:08:07 +00001104
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001105 if (grp->hasTextureOrMask() && ivm.invert(&ivm)) {
1106 grp->preConcatActiveSamplerMatrices(ivm);
1107 }
1108
1109 static const int MASK_IDX = GrPaint::kMaxMasks - 1;
1110 // we assume the last mask index is available for use
1111 GrAssert(NULL == grp->getMask(MASK_IDX));
1112 grp->setMask(MASK_IDX, texture);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001113 grp->getMaskSampler(MASK_IDX)->setClampNoFilter();
reed@google.com69302852011-02-16 18:08:07 +00001114
bsalomon@google.comc6cf7232011-02-17 16:43:10 +00001115 GrRect d;
1116 d.setLTRB(GrIntToScalar(dstM.fBounds.fLeft),
reed@google.com0c219b62011-02-16 21:31:18 +00001117 GrIntToScalar(dstM.fBounds.fTop),
1118 GrIntToScalar(dstM.fBounds.fRight),
1119 GrIntToScalar(dstM.fBounds.fBottom));
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001120
1121 GrMatrix m;
1122 m.setTranslate(-dstM.fBounds.fLeft, -dstM.fBounds.fTop);
bsalomon@google.comeb2aa1d2011-07-14 15:45:19 +00001123 m.postIDiv(texture->width(), texture->height());
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001124 grp->getMaskSampler(MASK_IDX)->setMatrix(m);
1125
1126 context->drawRect(*grp, d);
reed@google.com69302852011-02-16 18:08:07 +00001127 return true;
1128}
reed@google.com69302852011-02-16 18:08:07 +00001129
reed@google.com0c219b62011-02-16 21:31:18 +00001130void SkGpuDevice::drawPath(const SkDraw& draw, const SkPath& origSrcPath,
reed@google.comac10a2d2010-12-22 21:39:39 +00001131 const SkPaint& paint, const SkMatrix* prePathMatrix,
1132 bool pathIsMutable) {
1133 CHECK_SHOULD_DRAW(draw);
1134
bsalomon@google.com5782d712011-01-21 21:03:59 +00001135 GrPaint grPaint;
1136 SkAutoCachedTexture act;
Scroggod757df22011-05-16 13:11:16 +00001137 if (!this->skPaint2GrPaintShader(paint,
1138 &act,
1139 *draw.fMatrix,
1140 &grPaint,
1141 true)) {
reed@google.comac10a2d2010-12-22 21:39:39 +00001142 return;
1143 }
1144
reed@google.com0c219b62011-02-16 21:31:18 +00001145 // BEGIN lift from SkDraw::drawPath()
1146
1147 SkPath* pathPtr = const_cast<SkPath*>(&origSrcPath);
1148 bool doFill = true;
1149 SkPath tmpPath;
reed@google.comac10a2d2010-12-22 21:39:39 +00001150
1151 if (prePathMatrix) {
reed@google.come3445642011-02-16 23:20:39 +00001152 SkPath* result = pathPtr;
reed@google.com0c219b62011-02-16 21:31:18 +00001153
reed@google.come3445642011-02-16 23:20:39 +00001154 if (!pathIsMutable) {
1155 result = &tmpPath;
1156 pathIsMutable = true;
reed@google.comac10a2d2010-12-22 21:39:39 +00001157 }
reed@google.come3445642011-02-16 23:20:39 +00001158 // should I push prePathMatrix on our MV stack temporarily, instead
1159 // of applying it here? See SkDraw.cpp
1160 pathPtr->transform(*prePathMatrix, result);
1161 pathPtr = result;
reed@google.comac10a2d2010-12-22 21:39:39 +00001162 }
reed@google.com0c219b62011-02-16 21:31:18 +00001163 // at this point we're done with prePathMatrix
1164 SkDEBUGCODE(prePathMatrix = (const SkMatrix*)0x50FF8001;)
reed@google.comac10a2d2010-12-22 21:39:39 +00001165
bsalomon@google.com04de7822011-03-25 18:04:43 +00001166 // This "if" is not part of the SkDraw::drawPath() lift.
1167 // When we get a 1.0 wide stroke we hairline stroke it instead of creating
1168 // a new stroked-path. This is motivated by canvas2D sites that draw
1169 // lines as 1.0 wide stroked paths. We can consider doing an alpha-modulated-
1170 // hairline for width < 1.0 when AA is enabled.
1171 static const int gMatrixMask = ~(SkMatrix::kIdentity_Mask |
1172 SkMatrix::kTranslate_Mask);
1173 if (!paint.getPathEffect() &&
1174 SkPaint::kStroke_Style == paint.getStyle() &&
1175 !(draw.fMatrix->getType() & gMatrixMask) &&
1176 SK_Scalar1 == paint.getStrokeWidth()) {
1177 doFill = false;
1178 }
1179
1180 if (doFill && (paint.getPathEffect() ||
1181 paint.getStyle() != SkPaint::kFill_Style)) {
reed@google.com0c219b62011-02-16 21:31:18 +00001182 doFill = paint.getFillPath(*pathPtr, &tmpPath);
1183 pathPtr = &tmpPath;
1184 }
1185
1186 // END lift from SkDraw::drawPath()
1187
reed@google.com69302852011-02-16 18:08:07 +00001188 if (paint.getMaskFilter()) {
reed@google.com0c219b62011-02-16 21:31:18 +00001189 // avoid possibly allocating a new path in transform if we can
1190 SkPath* devPathPtr = pathIsMutable ? pathPtr : &tmpPath;
1191
1192 // transform the path into device space
reed@google.come3445642011-02-16 23:20:39 +00001193 pathPtr->transform(*draw.fMatrix, devPathPtr);
senorblanco@chromium.orgb08ea1b2011-07-12 16:54:59 +00001194 if (!drawWithGPUMaskFilter(fContext, *devPathPtr, paint.getMaskFilter(),
1195 *draw.fMatrix, *draw.fClip, draw.fBounder,
1196 &grPaint)) {
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +00001197 drawWithMaskFilter(fContext, *devPathPtr, paint.getMaskFilter(),
1198 *draw.fMatrix, *draw.fClip, draw.fBounder,
1199 &grPaint);
1200 }
reed@google.com69302852011-02-16 18:08:07 +00001201 return;
1202 }
reed@google.com69302852011-02-16 18:08:07 +00001203
bsalomon@google.comffca4002011-02-22 20:34:01 +00001204 GrPathFill fill = kHairLine_PathFill;
reed@google.comac10a2d2010-12-22 21:39:39 +00001205
reed@google.com0c219b62011-02-16 21:31:18 +00001206 if (doFill) {
1207 switch (pathPtr->getFillType()) {
reed@google.comac10a2d2010-12-22 21:39:39 +00001208 case SkPath::kWinding_FillType:
bsalomon@google.comffca4002011-02-22 20:34:01 +00001209 fill = kWinding_PathFill;
reed@google.comac10a2d2010-12-22 21:39:39 +00001210 break;
1211 case SkPath::kEvenOdd_FillType:
bsalomon@google.comffca4002011-02-22 20:34:01 +00001212 fill = kEvenOdd_PathFill;
reed@google.comac10a2d2010-12-22 21:39:39 +00001213 break;
1214 case SkPath::kInverseWinding_FillType:
bsalomon@google.comffca4002011-02-22 20:34:01 +00001215 fill = kInverseWinding_PathFill;
reed@google.comac10a2d2010-12-22 21:39:39 +00001216 break;
1217 case SkPath::kInverseEvenOdd_FillType:
bsalomon@google.comffca4002011-02-22 20:34:01 +00001218 fill = kInverseEvenOdd_PathFill;
reed@google.comac10a2d2010-12-22 21:39:39 +00001219 break;
1220 default:
bsalomon@google.com5782d712011-01-21 21:03:59 +00001221 SkDebugf("Unsupported path fill type\n");
reed@google.comac10a2d2010-12-22 21:39:39 +00001222 return;
1223 }
1224 }
1225
reed@google.com07f3ee12011-05-16 17:21:57 +00001226 fContext->drawPath(grPaint, *pathPtr, fill);
reed@google.comac10a2d2010-12-22 21:39:39 +00001227}
1228
reed@google.comac10a2d2010-12-22 21:39:39 +00001229void SkGpuDevice::drawBitmap(const SkDraw& draw,
1230 const SkBitmap& bitmap,
1231 const SkIRect* srcRectPtr,
1232 const SkMatrix& m,
1233 const SkPaint& paint) {
1234 CHECK_SHOULD_DRAW(draw);
1235
1236 SkIRect srcRect;
1237 if (NULL == srcRectPtr) {
1238 srcRect.set(0, 0, bitmap.width(), bitmap.height());
1239 } else {
1240 srcRect = *srcRectPtr;
1241 }
1242
junov@google.comd935cfb2011-06-27 20:48:23 +00001243 if (paint.getMaskFilter()){
epoger@google.com9ef2d832011-07-01 21:12:20 +00001244 SkBitmap tmp; // storage if we need a subset of bitmap
junov@google.comd935cfb2011-06-27 20:48:23 +00001245 const SkBitmap* bitmapPtr = &bitmap;
epoger@google.com9ef2d832011-07-01 21:12:20 +00001246 if (srcRectPtr) {
1247 if (!bitmap.extractSubset(&tmp, srcRect)) {
1248 return; // extraction failed
1249 }
1250 bitmapPtr = &tmp;
junov@google.comd935cfb2011-06-27 20:48:23 +00001251 }
1252 SkPaint paintWithTexture(paint);
1253 paintWithTexture.setShader(SkShader::CreateBitmapShader( *bitmapPtr,
1254 SkShader::kClamp_TileMode, SkShader::kClamp_TileMode))->unref();
1255 paintWithTexture.getShader()->setLocalMatrix(m);
1256
1257 SkRect ScalarRect;
epoger@google.com9ef2d832011-07-01 21:12:20 +00001258 ScalarRect.set(srcRect);
junov@google.comd935cfb2011-06-27 20:48:23 +00001259
epoger@google.com9ef2d832011-07-01 21:12:20 +00001260 if (m.rectStaysRect()) {
1261 // Preferred drawing method, optimized for rectangles
1262 m.mapRect(&ScalarRect);
1263 this->drawRect(draw, ScalarRect, paintWithTexture);
1264 } else {
1265 // Slower drawing method, for warped or rotated rectangles
1266 SkPath path;
1267 path.addRect(ScalarRect);
1268 path.transform(m);
1269 this->drawPath(draw, path, paintWithTexture, NULL, true);
1270 }
junov@google.comd935cfb2011-06-27 20:48:23 +00001271 return;
1272 }
1273
bsalomon@google.com5782d712011-01-21 21:03:59 +00001274 GrPaint grPaint;
Scroggod757df22011-05-16 13:11:16 +00001275 if (!this->skPaint2GrPaintNoShader(paint, true, &grPaint, false)) {
bsalomon@google.com5782d712011-01-21 21:03:59 +00001276 return;
1277 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001278 GrSamplerState* sampler = grPaint.getTextureSampler(kBitmapTextureIdx);
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +00001279 if (paint.isFilterBitmap()) {
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001280 sampler->setFilter(GrSamplerState::kBilinear_Filter);
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +00001281 } else {
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001282 sampler->setFilter(GrSamplerState::kNearest_Filter);
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +00001283 }
bsalomon@google.com5782d712011-01-21 21:03:59 +00001284
bsalomon@google.com91958362011-06-13 17:58:13 +00001285 const int maxTextureSize = fContext->getMaxTextureSize();
1286 if (bitmap.getTexture() || (bitmap.width() <= maxTextureSize &&
1287 bitmap.height() <= maxTextureSize)) {
reed@google.comac10a2d2010-12-22 21:39:39 +00001288 // take the fast case
bsalomon@google.com5782d712011-01-21 21:03:59 +00001289 this->internalDrawBitmap(draw, bitmap, srcRect, m, &grPaint);
reed@google.comac10a2d2010-12-22 21:39:39 +00001290 return;
1291 }
1292
1293 // undo the translate done by SkCanvas
1294 int DX = SkMax32(0, srcRect.fLeft);
1295 int DY = SkMax32(0, srcRect.fTop);
1296 // compute clip bounds in local coordinates
1297 SkIRect clipRect;
1298 {
1299 SkRect r;
1300 r.set(draw.fClip->getBounds());
1301 SkMatrix matrix, inverse;
1302 matrix.setConcat(*draw.fMatrix, m);
1303 if (!matrix.invert(&inverse)) {
1304 return;
1305 }
1306 inverse.mapRect(&r);
1307 r.roundOut(&clipRect);
1308 // apply the canvas' translate to our local clip
1309 clipRect.offset(DX, DY);
1310 }
1311
bsalomon@google.com91958362011-06-13 17:58:13 +00001312 int nx = bitmap.width() / maxTextureSize;
1313 int ny = bitmap.height() / maxTextureSize;
reed@google.comac10a2d2010-12-22 21:39:39 +00001314 for (int x = 0; x <= nx; x++) {
1315 for (int y = 0; y <= ny; y++) {
1316 SkIRect tileR;
bsalomon@google.com91958362011-06-13 17:58:13 +00001317 tileR.set(x * maxTextureSize, y * maxTextureSize,
1318 (x + 1) * maxTextureSize, (y + 1) * maxTextureSize);
reed@google.comac10a2d2010-12-22 21:39:39 +00001319 if (!SkIRect::Intersects(tileR, clipRect)) {
1320 continue;
1321 }
1322
1323 SkIRect srcR = tileR;
1324 if (!srcR.intersect(srcRect)) {
1325 continue;
1326 }
1327
1328 SkBitmap tmpB;
1329 if (bitmap.extractSubset(&tmpB, tileR)) {
1330 // now offset it to make it "local" to our tmp bitmap
1331 srcR.offset(-tileR.fLeft, -tileR.fTop);
1332
1333 SkMatrix tmpM(m);
1334 {
1335 int dx = tileR.fLeft - DX + SkMax32(0, srcR.fLeft);
1336 int dy = tileR.fTop - DY + SkMax32(0, srcR.fTop);
1337 tmpM.preTranslate(SkIntToScalar(dx), SkIntToScalar(dy));
1338 }
bsalomon@google.com5782d712011-01-21 21:03:59 +00001339 this->internalDrawBitmap(draw, tmpB, srcR, tmpM, &grPaint);
reed@google.comac10a2d2010-12-22 21:39:39 +00001340 }
1341 }
1342 }
1343}
1344
1345/*
1346 * This is called by drawBitmap(), which has to handle images that may be too
1347 * large to be represented by a single texture.
1348 *
bsalomon@google.com5782d712011-01-21 21:03:59 +00001349 * internalDrawBitmap assumes that the specified bitmap will fit in a texture
1350 * and that non-texture portion of the GrPaint has already been setup.
reed@google.comac10a2d2010-12-22 21:39:39 +00001351 */
1352void SkGpuDevice::internalDrawBitmap(const SkDraw& draw,
1353 const SkBitmap& bitmap,
1354 const SkIRect& srcRect,
1355 const SkMatrix& m,
bsalomon@google.com5782d712011-01-21 21:03:59 +00001356 GrPaint* grPaint) {
bsalomon@google.com91958362011-06-13 17:58:13 +00001357 SkASSERT(bitmap.width() <= fContext->getMaxTextureSize() &&
1358 bitmap.height() <= fContext->getMaxTextureSize());
reed@google.comac10a2d2010-12-22 21:39:39 +00001359
reed@google.com9c49bc32011-07-07 13:42:37 +00001360 SkAutoLockPixels alp(bitmap, !bitmap.getTexture());
reed@google.comac10a2d2010-12-22 21:39:39 +00001361 if (!bitmap.getTexture() && !bitmap.readyToDraw()) {
reed@google.com9c49bc32011-07-07 13:42:37 +00001362 SkDebugf("nothing to draw\n");
reed@google.comac10a2d2010-12-22 21:39:39 +00001363 return;
1364 }
1365
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001366 GrSamplerState* sampler = grPaint->getTextureSampler(kBitmapTextureIdx);
1367
1368 sampler->setWrapX(GrSamplerState::kClamp_WrapMode);
1369 sampler->setWrapY(GrSamplerState::kClamp_WrapMode);
1370 sampler->setSampleMode(GrSamplerState::kNormal_SampleMode);
1371 sampler->setMatrix(GrMatrix::I());
reed@google.comac10a2d2010-12-22 21:39:39 +00001372
1373 GrTexture* texture;
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001374 SkAutoCachedTexture act(this, bitmap, *sampler, &texture);
reed@google.comac10a2d2010-12-22 21:39:39 +00001375 if (NULL == texture) {
1376 return;
1377 }
1378
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001379 grPaint->setTexture(kShaderTextureIdx, texture);
reed@google.com46799cd2011-02-22 20:56:26 +00001380
reed@google.com20efde72011-05-09 17:00:02 +00001381 GrRect dstRect = SkRect::MakeWH(GrIntToScalar(srcRect.width()),
1382 GrIntToScalar(srcRect.height()));
bsalomon@google.comc6cf7232011-02-17 16:43:10 +00001383 GrRect paintRect;
junov@google.com6acc9b32011-05-16 18:32:07 +00001384 paintRect.setLTRB(GrFixedToScalar((srcRect.fLeft << 16) / bitmap.width()),
1385 GrFixedToScalar((srcRect.fTop << 16) / bitmap.height()),
1386 GrFixedToScalar((srcRect.fRight << 16) / bitmap.width()),
bsalomon@google.comc6cf7232011-02-17 16:43:10 +00001387 GrFixedToScalar((srcRect.fBottom << 16) / bitmap.height()));
reed@google.comac10a2d2010-12-22 21:39:39 +00001388
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001389 if (GrSamplerState::kNearest_Filter != sampler->getFilter() &&
junov@google.com6acc9b32011-05-16 18:32:07 +00001390 (srcRect.width() < bitmap.width() ||
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001391 srcRect.height() < bitmap.height())) {
junov@google.com6acc9b32011-05-16 18:32:07 +00001392 // If drawing a subrect of the bitmap and filtering is enabled,
1393 // use a constrained texture domain to avoid color bleeding
1394 GrScalar left, top, right, bottom;
1395 if (srcRect.width() > 1) {
1396 GrScalar border = GR_ScalarHalf / bitmap.width();
1397 left = paintRect.left() + border;
1398 right = paintRect.right() - border;
1399 } else {
1400 left = right = GrScalarHalf(paintRect.left() + paintRect.right());
1401 }
1402 if (srcRect.height() > 1) {
1403 GrScalar border = GR_ScalarHalf / bitmap.height();
1404 top = paintRect.top() + border;
1405 bottom = paintRect.bottom() - border;
1406 } else {
1407 top = bottom = GrScalarHalf(paintRect.top() + paintRect.bottom());
1408 }
1409 GrRect textureDomain;
1410 textureDomain.setLTRB(left, top, right, bottom);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001411 sampler->setTextureDomain(textureDomain);
junov@google.com6acc9b32011-05-16 18:32:07 +00001412 }
1413
bsalomon@google.comcc4dac32011-05-10 13:52:42 +00001414 fContext->drawRectToRect(*grPaint, dstRect, paintRect, &m);
reed@google.comac10a2d2010-12-22 21:39:39 +00001415}
1416
1417void SkGpuDevice::drawSprite(const SkDraw& draw, const SkBitmap& bitmap,
1418 int left, int top, const SkPaint& paint) {
1419 CHECK_SHOULD_DRAW(draw);
1420
1421 SkAutoLockPixels alp(bitmap);
1422 if (!bitmap.getTexture() && !bitmap.readyToDraw()) {
1423 return;
1424 }
1425
bsalomon@google.com5782d712011-01-21 21:03:59 +00001426 GrPaint grPaint;
Scroggod757df22011-05-16 13:11:16 +00001427 if(!this->skPaint2GrPaintNoShader(paint, true, &grPaint, false)) {
bsalomon@google.com5782d712011-01-21 21:03:59 +00001428 return;
1429 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001430
bsalomon@google.com5782d712011-01-21 21:03:59 +00001431 GrAutoMatrix avm(fContext, GrMatrix::I());
1432
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001433 GrSamplerState* sampler = grPaint.getTextureSampler(kBitmapTextureIdx);
bsalomon@google.com5782d712011-01-21 21:03:59 +00001434
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001435 GrTexture* texture;
1436 sampler->setClampNoFilter();
1437 SkAutoCachedTexture act(this, bitmap, *sampler, &texture);
1438
1439 grPaint.setTexture(kBitmapTextureIdx, texture);
bsalomon@google.com5782d712011-01-21 21:03:59 +00001440
bsalomon@google.com5782d712011-01-21 21:03:59 +00001441 fContext->drawRectToRect(grPaint,
reed@google.com20efde72011-05-09 17:00:02 +00001442 GrRect::MakeXYWH(GrIntToScalar(left),
1443 GrIntToScalar(top),
1444 GrIntToScalar(bitmap.width()),
1445 GrIntToScalar(bitmap.height())),
1446 GrRect::MakeWH(GR_Scalar1, GR_Scalar1));
reed@google.comac10a2d2010-12-22 21:39:39 +00001447}
1448
1449void SkGpuDevice::drawDevice(const SkDraw& draw, SkDevice* dev,
1450 int x, int y, const SkPaint& paint) {
1451 CHECK_SHOULD_DRAW(draw);
1452
bsalomon@google.com5782d712011-01-21 21:03:59 +00001453 GrPaint grPaint;
bsalomon@google.comc6cf7232011-02-17 16:43:10 +00001454 if (!((SkGpuDevice*)dev)->bindDeviceAsTexture(&grPaint) ||
Scroggod757df22011-05-16 13:11:16 +00001455 !this->skPaint2GrPaintNoShader(paint, true, &grPaint, false)) {
bsalomon@google.com5782d712011-01-21 21:03:59 +00001456 return;
reed@google.comac10a2d2010-12-22 21:39:39 +00001457 }
bsalomon@google.com5782d712011-01-21 21:03:59 +00001458
bsalomon@google.comb5b31682011-06-16 18:05:35 +00001459 GrTexture* devTex = grPaint.getTexture(0);
1460 SkASSERT(NULL != devTex);
bsalomon@google.com5782d712011-01-21 21:03:59 +00001461
1462 const SkBitmap& bm = dev->accessBitmap(false);
1463 int w = bm.width();
1464 int h = bm.height();
1465
1466 GrAutoMatrix avm(fContext, GrMatrix::I());
1467
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001468 grPaint.getTextureSampler(kBitmapTextureIdx)->setClampNoFilter();
bsalomon@google.com5782d712011-01-21 21:03:59 +00001469
bsalomon@google.comb5b31682011-06-16 18:05:35 +00001470 GrRect dstRect = GrRect::MakeXYWH(GrIntToScalar(x),
1471 GrIntToScalar(y),
1472 GrIntToScalar(w),
1473 GrIntToScalar(h));
1474 // The device being drawn may not fill up its texture (saveLayer uses
1475 // the approximate ).
1476 GrRect srcRect = GrRect::MakeWH(GR_Scalar1 * w / devTex->width(),
1477 GR_Scalar1 * h / devTex->height());
1478
1479 fContext->drawRectToRect(grPaint, dstRect, srcRect);
reed@google.comac10a2d2010-12-22 21:39:39 +00001480}
1481
1482///////////////////////////////////////////////////////////////////////////////
1483
1484// must be in SkCanvas::VertexMode order
bsalomon@google.comffca4002011-02-22 20:34:01 +00001485static const GrPrimitiveType gVertexMode2PrimitiveType[] = {
1486 kTriangles_PrimitiveType,
1487 kTriangleStrip_PrimitiveType,
1488 kTriangleFan_PrimitiveType,
reed@google.comac10a2d2010-12-22 21:39:39 +00001489};
1490
1491void SkGpuDevice::drawVertices(const SkDraw& draw, SkCanvas::VertexMode vmode,
1492 int vertexCount, const SkPoint vertices[],
1493 const SkPoint texs[], const SkColor colors[],
1494 SkXfermode* xmode,
1495 const uint16_t indices[], int indexCount,
1496 const SkPaint& paint) {
1497 CHECK_SHOULD_DRAW(draw);
1498
bsalomon@google.com5782d712011-01-21 21:03:59 +00001499 GrPaint grPaint;
1500 SkAutoCachedTexture act;
1501 // we ignore the shader if texs is null.
1502 if (NULL == texs) {
Scroggod757df22011-05-16 13:11:16 +00001503 if (!this->skPaint2GrPaintNoShader(paint,
1504 false,
1505 &grPaint,
1506 NULL == colors)) {
reed@google.comac10a2d2010-12-22 21:39:39 +00001507 return;
1508 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001509 } else {
reed@google.com1a2e8d22011-01-21 22:08:29 +00001510 if (!this->skPaint2GrPaintShader(paint, &act,
1511 *draw.fMatrix,
Scroggod757df22011-05-16 13:11:16 +00001512 &grPaint,
1513 NULL == colors)) {
bsalomon@google.com5782d712011-01-21 21:03:59 +00001514 return;
1515 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001516 }
bsalomon@google.com5782d712011-01-21 21:03:59 +00001517
1518 if (NULL != xmode && NULL != texs && NULL != colors) {
1519 SkXfermode::Mode mode;
1520 if (!SkXfermode::IsMode(xmode, &mode) ||
1521 SkXfermode::kMultiply_Mode != mode) {
1522 SkDebugf("Unsupported vertex-color/texture xfer mode.\n");
1523#if 0
1524 return
1525#endif
1526 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001527 }
bsalomon@google.com5782d712011-01-21 21:03:59 +00001528
1529#if SK_SCALAR_IS_GR_SCALAR
1530 // even if GrColor and SkColor byte offsets match we need
1531 // to perform pre-multiply.
1532 if (NULL == colors) {
1533 fContext->drawVertices(grPaint,
1534 gVertexMode2PrimitiveType[vmode],
1535 vertexCount,
1536 (GrPoint*) vertices,
1537 (GrPoint*) texs,
1538 NULL,
1539 indices,
1540 indexCount);
1541 } else
1542#endif
1543 {
1544 SkTexCoordSource texSrc(texs);
1545 SkColorSource colSrc(colors);
1546 SkIndexSource idxSrc(indices, indexCount);
1547
1548 fContext->drawCustomVertices(grPaint,
1549 gVertexMode2PrimitiveType[vmode],
1550 SkPositionSource(vertices, vertexCount),
1551 (NULL == texs) ? NULL : &texSrc,
1552 (NULL == colors) ? NULL : &colSrc,
1553 (NULL == indices) ? NULL : &idxSrc);
reed@google.comac10a2d2010-12-22 21:39:39 +00001554 }
1555}
1556
1557///////////////////////////////////////////////////////////////////////////////
1558
1559static void GlyphCacheAuxProc(void* data) {
1560 delete (GrFontScaler*)data;
1561}
1562
1563static GrFontScaler* get_gr_font_scaler(SkGlyphCache* cache) {
1564 void* auxData;
1565 GrFontScaler* scaler = NULL;
1566 if (cache->getAuxProcData(GlyphCacheAuxProc, &auxData)) {
1567 scaler = (GrFontScaler*)auxData;
1568 }
1569 if (NULL == scaler) {
1570 scaler = new SkGrFontScaler(cache);
1571 cache->setAuxProc(GlyphCacheAuxProc, scaler);
1572 }
1573 return scaler;
1574}
1575
1576static void SkGPU_Draw1Glyph(const SkDraw1Glyph& state,
1577 SkFixed fx, SkFixed fy,
1578 const SkGlyph& glyph) {
1579 SkASSERT(glyph.fWidth > 0 && glyph.fHeight > 0);
1580
1581 GrSkDrawProcs* procs = (GrSkDrawProcs*)state.fDraw->fProcs;
1582
1583 if (NULL == procs->fFontScaler) {
1584 procs->fFontScaler = get_gr_font_scaler(state.fCache);
1585 }
reed@google.com39ce0ac2011-04-08 15:42:19 +00001586
1587 /*
reed@google.com3b139f52011-06-07 17:56:25 +00001588 * What should we do with fy? (assuming horizontal/latin text)
reed@google.com39ce0ac2011-04-08 15:42:19 +00001589 *
reed@google.com3b139f52011-06-07 17:56:25 +00001590 * The raster code calls SkFixedFloorToFixed on it, as it does with fx.
1591 * It calls that rather than round, because our caller has already added
1592 * SK_FixedHalf, so that calling floor gives us the rounded integer.
1593 *
1594 * Test code between raster and gpu (they should draw the same)
1595 *
1596 * canvas->drawText("Hamburgefons", 12, 0, 16.5f, paint);
1597 *
1598 * Perhaps we should only perform this integralization if there is no
1599 * fExtMatrix...
reed@google.com39ce0ac2011-04-08 15:42:19 +00001600 */
reed@google.com3b139f52011-06-07 17:56:25 +00001601 fy = SkFixedFloorToFixed(fy);
1602
reed@google.comac10a2d2010-12-22 21:39:39 +00001603 procs->fTextContext->drawPackedGlyph(GrGlyph::Pack(glyph.getGlyphID(), fx, 0),
reed@google.com3b139f52011-06-07 17:56:25 +00001604 SkFixedFloorToFixed(fx), fy,
reed@google.comac10a2d2010-12-22 21:39:39 +00001605 procs->fFontScaler);
1606}
1607
bsalomon@google.com5782d712011-01-21 21:03:59 +00001608SkDrawProcs* SkGpuDevice::initDrawForText(GrTextContext* context) {
reed@google.comac10a2d2010-12-22 21:39:39 +00001609
1610 // deferred allocation
1611 if (NULL == fDrawProcs) {
1612 fDrawProcs = new GrSkDrawProcs;
1613 fDrawProcs->fD1GProc = SkGPU_Draw1Glyph;
1614 fDrawProcs->fContext = fContext;
1615 }
1616
1617 // init our (and GL's) state
1618 fDrawProcs->fTextContext = context;
1619 fDrawProcs->fFontScaler = NULL;
1620 return fDrawProcs;
1621}
1622
1623void SkGpuDevice::drawText(const SkDraw& draw, const void* text,
1624 size_t byteLength, SkScalar x, SkScalar y,
1625 const SkPaint& paint) {
1626 CHECK_SHOULD_DRAW(draw);
1627
1628 if (draw.fMatrix->getType() & SkMatrix::kPerspective_Mask) {
1629 // this guy will just call our drawPath()
1630 draw.drawText((const char*)text, byteLength, x, y, paint);
1631 } else {
reed@google.comac10a2d2010-12-22 21:39:39 +00001632 SkDraw myDraw(draw);
bsalomon@google.com5782d712011-01-21 21:03:59 +00001633
1634 GrPaint grPaint;
1635 SkAutoCachedTexture act;
1636
Scroggod757df22011-05-16 13:11:16 +00001637 if (!this->skPaint2GrPaintShader(paint,
1638 &act,
1639 *draw.fMatrix,
1640 &grPaint,
1641 true)) {
bsalomon@google.com5782d712011-01-21 21:03:59 +00001642 return;
1643 }
bsalomon@google.comcc4dac32011-05-10 13:52:42 +00001644 GrTextContext context(fContext, grPaint, draw.fExtMatrix);
bsalomon@google.com5782d712011-01-21 21:03:59 +00001645 myDraw.fProcs = this->initDrawForText(&context);
reed@google.comac10a2d2010-12-22 21:39:39 +00001646 this->INHERITED::drawText(myDraw, text, byteLength, x, y, paint);
1647 }
1648}
1649
1650void SkGpuDevice::drawPosText(const SkDraw& draw, const void* text,
1651 size_t byteLength, const SkScalar pos[],
1652 SkScalar constY, int scalarsPerPos,
1653 const SkPaint& paint) {
1654 CHECK_SHOULD_DRAW(draw);
1655
1656 if (draw.fMatrix->getType() & SkMatrix::kPerspective_Mask) {
1657 // this guy will just call our drawPath()
1658 draw.drawPosText((const char*)text, byteLength, pos, constY,
1659 scalarsPerPos, paint);
1660 } else {
reed@google.comac10a2d2010-12-22 21:39:39 +00001661 SkDraw myDraw(draw);
bsalomon@google.com5782d712011-01-21 21:03:59 +00001662
1663 GrPaint grPaint;
1664 SkAutoCachedTexture act;
Scroggod757df22011-05-16 13:11:16 +00001665 if (!this->skPaint2GrPaintShader(paint,
1666 &act,
1667 *draw.fMatrix,
1668 &grPaint,
1669 true)) {
bsalomon@google.com5782d712011-01-21 21:03:59 +00001670 return;
1671 }
1672
bsalomon@google.comcc4dac32011-05-10 13:52:42 +00001673 GrTextContext context(fContext, grPaint, draw.fExtMatrix);
bsalomon@google.com5782d712011-01-21 21:03:59 +00001674 myDraw.fProcs = this->initDrawForText(&context);
reed@google.comac10a2d2010-12-22 21:39:39 +00001675 this->INHERITED::drawPosText(myDraw, text, byteLength, pos, constY,
1676 scalarsPerPos, paint);
1677 }
1678}
1679
1680void SkGpuDevice::drawTextOnPath(const SkDraw& draw, const void* text,
1681 size_t len, const SkPath& path,
1682 const SkMatrix* m, const SkPaint& paint) {
1683 CHECK_SHOULD_DRAW(draw);
1684
1685 SkASSERT(draw.fDevice == this);
1686 draw.drawTextOnPath((const char*)text, len, path, m, paint);
1687}
1688
1689///////////////////////////////////////////////////////////////////////////////
1690
reed@google.comf67e4cf2011-03-15 20:56:58 +00001691bool SkGpuDevice::filterTextFlags(const SkPaint& paint, TextFlags* flags) {
1692 if (!paint.isLCDRenderText()) {
1693 // we're cool with the paint as is
1694 return false;
1695 }
1696
1697 if (paint.getShader() ||
1698 paint.getXfermode() || // unless its srcover
1699 paint.getMaskFilter() ||
1700 paint.getRasterizer() ||
1701 paint.getColorFilter() ||
1702 paint.getPathEffect() ||
1703 paint.isFakeBoldText() ||
1704 paint.getStyle() != SkPaint::kFill_Style) {
1705 // turn off lcd
1706 flags->fFlags = paint.getFlags() & ~SkPaint::kLCDRenderText_Flag;
1707 flags->fHinting = paint.getHinting();
1708 return true;
1709 }
1710 // we're cool with the paint as is
1711 return false;
1712}
1713
1714///////////////////////////////////////////////////////////////////////////////
1715
reed@google.comac10a2d2010-12-22 21:39:39 +00001716SkGpuDevice::TexCache* SkGpuDevice::lockCachedTexture(const SkBitmap& bitmap,
bsalomon@google.comfea37b52011-04-25 15:51:06 +00001717 const GrSamplerState& sampler,
1718 GrTexture** texture,
bsalomon@google.come97f0852011-06-17 13:10:25 +00001719 TexType type) {
bsalomon@google.comfea37b52011-04-25 15:51:06 +00001720 GrTexture* newTexture = NULL;
1721 GrTextureEntry* entry = NULL;
reed@google.comac10a2d2010-12-22 21:39:39 +00001722 GrContext* ctx = this->context();
bsalomon@google.comfea37b52011-04-25 15:51:06 +00001723
bsalomon@google.come97f0852011-06-17 13:10:25 +00001724 if (kBitmap_TexType != type) {
bsalomon@google.comfea37b52011-04-25 15:51:06 +00001725 const GrTextureDesc desc = {
1726 kRenderTarget_GrTextureFlagBit,
1727 kNone_GrAALevel,
1728 bitmap.width(),
1729 bitmap.height(),
1730 SkGr::Bitmap2PixelConfig(bitmap)
1731 };
bsalomon@google.come97f0852011-06-17 13:10:25 +00001732 if (kSaveLayerDeviceRenderTarget_TexType == type) {
bsalomon@google.comb5b31682011-06-16 18:05:35 +00001733 // we know layers will only be drawn through drawDevice.
1734 // drawDevice has been made to work with content embedded in a
1735 // larger texture so its okay to use the approximate version.
1736 entry = ctx->findApproximateKeylessTexture(desc);
1737 } else {
bsalomon@google.come97f0852011-06-17 13:10:25 +00001738 SkASSERT(kDeviceRenderTarget_TexType == type);
bsalomon@google.comb5b31682011-06-16 18:05:35 +00001739 entry = ctx->lockKeylessTexture(desc);
1740 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001741 } else {
junov@google.com4ee7ae52011-06-30 17:30:49 +00001742 if (!bitmap.isVolatile()) {
1743 uint32_t p0, p1;
1744 p0 = bitmap.getGenerationID();
1745 p1 = bitmap.pixelRefOffset();
1746 GrTextureKey key(p0, p1, bitmap.width(), bitmap.height());
1747
1748 entry = ctx->findAndLockTexture(&key, sampler);
1749 if (NULL == entry)
1750 entry = sk_gr_create_bitmap_texture(ctx, &key, sampler,
1751 bitmap);
1752 } else {
1753 entry = sk_gr_create_bitmap_texture(ctx, NULL, sampler, bitmap);
1754 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001755 if (NULL == entry) {
junov@google.com4ee7ae52011-06-30 17:30:49 +00001756 GrPrintf("---- failed to create texture for cache [%d %d]\n",
1757 bitmap.width(), bitmap.height());
reed@google.comac10a2d2010-12-22 21:39:39 +00001758 }
1759 }
1760
1761 if (NULL != entry) {
1762 newTexture = entry->texture();
reed@google.comac10a2d2010-12-22 21:39:39 +00001763 if (texture) {
1764 *texture = newTexture;
1765 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001766 }
1767 return (TexCache*)entry;
1768}
1769
1770void SkGpuDevice::unlockCachedTexture(TexCache* cache) {
1771 this->context()->unlockTexture((GrTextureEntry*)cache);
1772}
1773
bsalomon@google.come97f0852011-06-17 13:10:25 +00001774SkDevice* SkGpuDevice::onCreateCompatibleDevice(SkBitmap::Config config,
1775 int width, int height,
1776 bool isOpaque,
1777 Usage usage) {
1778 return SkNEW_ARGS(SkGpuDevice,(this->context(), config,
1779 width, height, usage));
1780}
1781