blob: c4e0ebecd12ec5d1c0551ebe36da09be5446c4ab [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.orgfdaf2b92011-07-21 22:16:05 +0000916 // FIXME: could just clear bounds
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +0000917 context->clear(NULL, 0);
senorblanco@chromium.orgfdaf2b92011-07-21 22:16:05 +0000918 GrMatrix transM;
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +0000919 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;
senorblanco@chromium.org422b67d2011-07-19 21:22:13 +0000939 sampleM.setIDiv(srcTexture->width(), srcTexture->height());
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +0000940 GrPaint paint;
941 paint.reset();
942 paint.getTextureSampler(0)->setFilter(GrSamplerState::kBilinear_Filter);
943 paint.getTextureSampler(0)->setMatrix(sampleM);
senorblanco@chromium.orgb08ea1b2011-07-12 16:54:59 +0000944 GrTextureEntry* origEntry = NULL;
945 if (blurType != SkMaskFilter::kNormal_BlurType) {
946 // Stash away a copy of the unblurred image.
947 origEntry = context->findApproximateKeylessTexture(desc);
948 if (NULL == origEntry) {
949 return false;
950 }
951 context->setRenderTarget(origEntry->texture()->asRenderTarget());
952 paint.setTexture(0, srcTexture);
953 context->drawRect(paint, srcRect);
954 }
senorblanco@chromium.orgaadd9f82011-07-12 19:44:51 +0000955 GrAutoUnlockTextureEntry origLock(context, origEntry);
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +0000956 for (int i = 1; i < scaleFactor; i *= 2) {
senorblanco@chromium.org422b67d2011-07-19 21:22:13 +0000957 sampleM.setIDiv(srcTexture->width(), srcTexture->height());
958 paint.getTextureSampler(0)->setMatrix(sampleM);
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +0000959 context->setRenderTarget(dstTexture->asRenderTarget());
960 SkRect dstRect(srcRect);
961 scaleRect(&dstRect, 0.5f);
senorblanco@chromium.orgfdaf2b92011-07-21 22:16:05 +0000962 // Clear out 1 pixel border for linear filtering.
963 // FIXME: for now, clear everything
964 context->clear(NULL, 0);
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +0000965 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());
senorblanco@chromium.orgfdaf2b92011-07-21 22:16:05 +0000976 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());
senorblanco@chromium.orgfdaf2b92011-07-21 22:16:05 +0000981 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);
senorblanco@chromium.org422b67d2011-07-19 21:22:13 +0000988 sampleM.setIDiv(srcTexture->width(), srcTexture->height());
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +0000989 paint.getTextureSampler(0)->setMatrix(sampleM);
990 context->setRenderTarget(dstTexture->asRenderTarget());
senorblanco@chromium.orgfdaf2b92011-07-21 22:16:05 +0000991 // Clear out 2 pixel border for bicubic filtering.
992 // FIXME: for now, clear everything
993 context->clear(NULL, 0);
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +0000994 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);
senorblanco@chromium.org422b67d2011-07-19 21:22:13 +00001005 sampleM.setIDiv(origTexture->width(), origTexture->height());
senorblanco@chromium.orgb08ea1b2011-07-12 16:54:59 +00001006 paint.getTextureSampler(0)->setMatrix(sampleM);
1007 // Blend origTexture over srcTexture.
1008 context->setRenderTarget(srcTexture->asRenderTarget());
1009 paint.setTexture(0, origTexture);
1010 if (SkMaskFilter::kInner_BlurType == blurType) {
1011 // inner: dst = dst * src
1012 paint.fSrcBlendCoeff = kDC_BlendCoeff;
1013 paint.fDstBlendCoeff = kZero_BlendCoeff;
1014 } else if (SkMaskFilter::kSolid_BlurType == blurType) {
1015 // solid: dst = src + dst - src * dst
1016 // = (1 - dst) * src + 1 * dst
1017 paint.fSrcBlendCoeff = kIDC_BlendCoeff;
1018 paint.fDstBlendCoeff = kOne_BlendCoeff;
1019 } else if (SkMaskFilter::kOuter_BlurType == blurType) {
1020 // outer: dst = dst * (1 - src)
1021 // = 0 * src + (1 - src) * dst
1022 paint.fSrcBlendCoeff = kZero_BlendCoeff;
1023 paint.fDstBlendCoeff = kISC_BlendCoeff;
1024 }
1025 context->drawRect(paint, srcRect);
1026 }
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +00001027 context->setRenderTarget(oldRenderTarget);
senorblanco@chromium.org42dd0f92011-07-14 15:29:57 +00001028 context->setClip(oldClip);
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +00001029
1030 if (grp->hasTextureOrMask()) {
1031 GrMatrix inverse;
1032 if (!matrix.invert(&inverse)) {
1033 return false;
1034 }
1035 grp->preConcatActiveSamplerMatrices(inverse);
1036 }
1037
1038 static const int MASK_IDX = GrPaint::kMaxMasks - 1;
1039 // we assume the last mask index is available for use
1040 GrAssert(NULL == grp->getMask(MASK_IDX));
1041 grp->setMask(MASK_IDX, srcTexture);
1042 grp->getMaskSampler(MASK_IDX)->setClampNoFilter();
1043
1044 GrMatrix m;
1045 m.setTranslate(-finalRect.fLeft, -finalRect.fTop);
1046 m.postIDiv(srcTexture->width(), srcTexture->height());
1047 grp->getMaskSampler(MASK_IDX)->setMatrix(m);
1048 context->drawRect(*grp, finalRect);
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +00001049 return true;
1050}
1051
reed@google.com69302852011-02-16 18:08:07 +00001052static bool drawWithMaskFilter(GrContext* context, const SkPath& path,
1053 SkMaskFilter* filter, const SkMatrix& matrix,
1054 const SkRegion& clip, SkBounder* bounder,
1055 GrPaint* grp) {
1056 SkMask srcM, dstM;
1057
1058 if (!SkDraw::DrawToMask(path, &clip.getBounds(), filter, &matrix, &srcM,
1059 SkMask::kComputeBoundsAndRenderImage_CreateMode)) {
1060 return false;
1061 }
1062
1063 SkAutoMaskImage autoSrc(&srcM, false);
1064
1065 if (!filter->filterMask(&dstM, srcM, matrix, NULL)) {
1066 return false;
1067 }
1068 // this will free-up dstM when we're done (allocated in filterMask())
1069 SkAutoMaskImage autoDst(&dstM, false);
1070
1071 if (clip.quickReject(dstM.fBounds)) {
1072 return false;
1073 }
1074 if (bounder && !bounder->doIRect(dstM.fBounds)) {
1075 return false;
1076 }
1077
1078 // we now have a device-aligned 8bit mask in dstM, ready to be drawn using
1079 // the current clip (and identity matrix) and grpaint settings
1080
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001081 // used to compute inverse view, if necessary
1082 GrMatrix ivm = context->getMatrix();
1083
reed@google.com0c219b62011-02-16 21:31:18 +00001084 GrAutoMatrix avm(context, GrMatrix::I());
reed@google.com69302852011-02-16 18:08:07 +00001085
bsalomon@google.comfea37b52011-04-25 15:51:06 +00001086 const GrTextureDesc desc = {
1087 kNone_GrTextureFlags,
1088 kNone_GrAALevel,
reed@google.com69302852011-02-16 18:08:07 +00001089 dstM.fBounds.width(),
1090 dstM.fBounds.height(),
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001091 kAlpha_8_GrPixelConfig
reed@google.com69302852011-02-16 18:08:07 +00001092 };
1093
bsalomon@google.comeb2aa1d2011-07-14 15:45:19 +00001094 GrAutoUnlockTextureEntry aute(context,
1095 context->findApproximateKeylessTexture(desc));
1096 GrTexture* texture = aute.texture();
1097
reed@google.com69302852011-02-16 18:08:07 +00001098 if (NULL == texture) {
1099 return false;
1100 }
bsalomon@google.comeb2aa1d2011-07-14 15:45:19 +00001101 texture->uploadTextureData(0, 0, desc.fWidth, desc.fHeight,
1102 dstM.fImage, dstM.fRowBytes);
reed@google.com69302852011-02-16 18:08:07 +00001103
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001104 if (grp->hasTextureOrMask() && ivm.invert(&ivm)) {
1105 grp->preConcatActiveSamplerMatrices(ivm);
1106 }
1107
1108 static const int MASK_IDX = GrPaint::kMaxMasks - 1;
1109 // we assume the last mask index is available for use
1110 GrAssert(NULL == grp->getMask(MASK_IDX));
1111 grp->setMask(MASK_IDX, texture);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001112 grp->getMaskSampler(MASK_IDX)->setClampNoFilter();
reed@google.com69302852011-02-16 18:08:07 +00001113
bsalomon@google.comc6cf7232011-02-17 16:43:10 +00001114 GrRect d;
1115 d.setLTRB(GrIntToScalar(dstM.fBounds.fLeft),
reed@google.com0c219b62011-02-16 21:31:18 +00001116 GrIntToScalar(dstM.fBounds.fTop),
1117 GrIntToScalar(dstM.fBounds.fRight),
1118 GrIntToScalar(dstM.fBounds.fBottom));
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001119
1120 GrMatrix m;
1121 m.setTranslate(-dstM.fBounds.fLeft, -dstM.fBounds.fTop);
bsalomon@google.comeb2aa1d2011-07-14 15:45:19 +00001122 m.postIDiv(texture->width(), texture->height());
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001123 grp->getMaskSampler(MASK_IDX)->setMatrix(m);
1124
1125 context->drawRect(*grp, d);
reed@google.com69302852011-02-16 18:08:07 +00001126 return true;
1127}
reed@google.com69302852011-02-16 18:08:07 +00001128
reed@google.com0c219b62011-02-16 21:31:18 +00001129void SkGpuDevice::drawPath(const SkDraw& draw, const SkPath& origSrcPath,
reed@google.comac10a2d2010-12-22 21:39:39 +00001130 const SkPaint& paint, const SkMatrix* prePathMatrix,
1131 bool pathIsMutable) {
1132 CHECK_SHOULD_DRAW(draw);
1133
bsalomon@google.com5782d712011-01-21 21:03:59 +00001134 GrPaint grPaint;
1135 SkAutoCachedTexture act;
Scroggod757df22011-05-16 13:11:16 +00001136 if (!this->skPaint2GrPaintShader(paint,
1137 &act,
1138 *draw.fMatrix,
1139 &grPaint,
1140 true)) {
reed@google.comac10a2d2010-12-22 21:39:39 +00001141 return;
1142 }
1143
reed@google.com0c219b62011-02-16 21:31:18 +00001144 // BEGIN lift from SkDraw::drawPath()
1145
1146 SkPath* pathPtr = const_cast<SkPath*>(&origSrcPath);
1147 bool doFill = true;
1148 SkPath tmpPath;
reed@google.comac10a2d2010-12-22 21:39:39 +00001149
1150 if (prePathMatrix) {
reed@google.come3445642011-02-16 23:20:39 +00001151 SkPath* result = pathPtr;
reed@google.com0c219b62011-02-16 21:31:18 +00001152
reed@google.come3445642011-02-16 23:20:39 +00001153 if (!pathIsMutable) {
1154 result = &tmpPath;
1155 pathIsMutable = true;
reed@google.comac10a2d2010-12-22 21:39:39 +00001156 }
reed@google.come3445642011-02-16 23:20:39 +00001157 // should I push prePathMatrix on our MV stack temporarily, instead
1158 // of applying it here? See SkDraw.cpp
1159 pathPtr->transform(*prePathMatrix, result);
1160 pathPtr = result;
reed@google.comac10a2d2010-12-22 21:39:39 +00001161 }
reed@google.com0c219b62011-02-16 21:31:18 +00001162 // at this point we're done with prePathMatrix
1163 SkDEBUGCODE(prePathMatrix = (const SkMatrix*)0x50FF8001;)
reed@google.comac10a2d2010-12-22 21:39:39 +00001164
bsalomon@google.com04de7822011-03-25 18:04:43 +00001165 // This "if" is not part of the SkDraw::drawPath() lift.
1166 // When we get a 1.0 wide stroke we hairline stroke it instead of creating
1167 // a new stroked-path. This is motivated by canvas2D sites that draw
1168 // lines as 1.0 wide stroked paths. We can consider doing an alpha-modulated-
1169 // hairline for width < 1.0 when AA is enabled.
1170 static const int gMatrixMask = ~(SkMatrix::kIdentity_Mask |
1171 SkMatrix::kTranslate_Mask);
1172 if (!paint.getPathEffect() &&
1173 SkPaint::kStroke_Style == paint.getStyle() &&
1174 !(draw.fMatrix->getType() & gMatrixMask) &&
1175 SK_Scalar1 == paint.getStrokeWidth()) {
1176 doFill = false;
1177 }
1178
1179 if (doFill && (paint.getPathEffect() ||
1180 paint.getStyle() != SkPaint::kFill_Style)) {
reed@google.com0c219b62011-02-16 21:31:18 +00001181 doFill = paint.getFillPath(*pathPtr, &tmpPath);
1182 pathPtr = &tmpPath;
1183 }
1184
1185 // END lift from SkDraw::drawPath()
1186
reed@google.com69302852011-02-16 18:08:07 +00001187 if (paint.getMaskFilter()) {
reed@google.com0c219b62011-02-16 21:31:18 +00001188 // avoid possibly allocating a new path in transform if we can
1189 SkPath* devPathPtr = pathIsMutable ? pathPtr : &tmpPath;
1190
1191 // transform the path into device space
reed@google.come3445642011-02-16 23:20:39 +00001192 pathPtr->transform(*draw.fMatrix, devPathPtr);
senorblanco@chromium.orgb08ea1b2011-07-12 16:54:59 +00001193 if (!drawWithGPUMaskFilter(fContext, *devPathPtr, paint.getMaskFilter(),
1194 *draw.fMatrix, *draw.fClip, draw.fBounder,
1195 &grPaint)) {
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +00001196 drawWithMaskFilter(fContext, *devPathPtr, paint.getMaskFilter(),
1197 *draw.fMatrix, *draw.fClip, draw.fBounder,
1198 &grPaint);
1199 }
reed@google.com69302852011-02-16 18:08:07 +00001200 return;
1201 }
reed@google.com69302852011-02-16 18:08:07 +00001202
bsalomon@google.comffca4002011-02-22 20:34:01 +00001203 GrPathFill fill = kHairLine_PathFill;
reed@google.comac10a2d2010-12-22 21:39:39 +00001204
reed@google.com0c219b62011-02-16 21:31:18 +00001205 if (doFill) {
1206 switch (pathPtr->getFillType()) {
reed@google.comac10a2d2010-12-22 21:39:39 +00001207 case SkPath::kWinding_FillType:
bsalomon@google.comffca4002011-02-22 20:34:01 +00001208 fill = kWinding_PathFill;
reed@google.comac10a2d2010-12-22 21:39:39 +00001209 break;
1210 case SkPath::kEvenOdd_FillType:
bsalomon@google.comffca4002011-02-22 20:34:01 +00001211 fill = kEvenOdd_PathFill;
reed@google.comac10a2d2010-12-22 21:39:39 +00001212 break;
1213 case SkPath::kInverseWinding_FillType:
bsalomon@google.comffca4002011-02-22 20:34:01 +00001214 fill = kInverseWinding_PathFill;
reed@google.comac10a2d2010-12-22 21:39:39 +00001215 break;
1216 case SkPath::kInverseEvenOdd_FillType:
bsalomon@google.comffca4002011-02-22 20:34:01 +00001217 fill = kInverseEvenOdd_PathFill;
reed@google.comac10a2d2010-12-22 21:39:39 +00001218 break;
1219 default:
bsalomon@google.com5782d712011-01-21 21:03:59 +00001220 SkDebugf("Unsupported path fill type\n");
reed@google.comac10a2d2010-12-22 21:39:39 +00001221 return;
1222 }
1223 }
1224
reed@google.com07f3ee12011-05-16 17:21:57 +00001225 fContext->drawPath(grPaint, *pathPtr, fill);
reed@google.comac10a2d2010-12-22 21:39:39 +00001226}
1227
reed@google.comac10a2d2010-12-22 21:39:39 +00001228void SkGpuDevice::drawBitmap(const SkDraw& draw,
1229 const SkBitmap& bitmap,
1230 const SkIRect* srcRectPtr,
1231 const SkMatrix& m,
1232 const SkPaint& paint) {
1233 CHECK_SHOULD_DRAW(draw);
1234
1235 SkIRect srcRect;
1236 if (NULL == srcRectPtr) {
1237 srcRect.set(0, 0, bitmap.width(), bitmap.height());
1238 } else {
1239 srcRect = *srcRectPtr;
1240 }
1241
junov@google.comd935cfb2011-06-27 20:48:23 +00001242 if (paint.getMaskFilter()){
epoger@google.com9ef2d832011-07-01 21:12:20 +00001243 SkBitmap tmp; // storage if we need a subset of bitmap
junov@google.comd935cfb2011-06-27 20:48:23 +00001244 const SkBitmap* bitmapPtr = &bitmap;
epoger@google.com9ef2d832011-07-01 21:12:20 +00001245 if (srcRectPtr) {
1246 if (!bitmap.extractSubset(&tmp, srcRect)) {
1247 return; // extraction failed
1248 }
1249 bitmapPtr = &tmp;
junov@google.comd935cfb2011-06-27 20:48:23 +00001250 }
1251 SkPaint paintWithTexture(paint);
1252 paintWithTexture.setShader(SkShader::CreateBitmapShader( *bitmapPtr,
1253 SkShader::kClamp_TileMode, SkShader::kClamp_TileMode))->unref();
1254 paintWithTexture.getShader()->setLocalMatrix(m);
1255
1256 SkRect ScalarRect;
epoger@google.com9ef2d832011-07-01 21:12:20 +00001257 ScalarRect.set(srcRect);
junov@google.comd935cfb2011-06-27 20:48:23 +00001258
epoger@google.com9ef2d832011-07-01 21:12:20 +00001259 if (m.rectStaysRect()) {
1260 // Preferred drawing method, optimized for rectangles
1261 m.mapRect(&ScalarRect);
1262 this->drawRect(draw, ScalarRect, paintWithTexture);
1263 } else {
1264 // Slower drawing method, for warped or rotated rectangles
1265 SkPath path;
1266 path.addRect(ScalarRect);
1267 path.transform(m);
1268 this->drawPath(draw, path, paintWithTexture, NULL, true);
1269 }
junov@google.comd935cfb2011-06-27 20:48:23 +00001270 return;
1271 }
1272
bsalomon@google.com5782d712011-01-21 21:03:59 +00001273 GrPaint grPaint;
Scroggod757df22011-05-16 13:11:16 +00001274 if (!this->skPaint2GrPaintNoShader(paint, true, &grPaint, false)) {
bsalomon@google.com5782d712011-01-21 21:03:59 +00001275 return;
1276 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001277 GrSamplerState* sampler = grPaint.getTextureSampler(kBitmapTextureIdx);
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +00001278 if (paint.isFilterBitmap()) {
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001279 sampler->setFilter(GrSamplerState::kBilinear_Filter);
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +00001280 } else {
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001281 sampler->setFilter(GrSamplerState::kNearest_Filter);
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +00001282 }
bsalomon@google.com5782d712011-01-21 21:03:59 +00001283
bsalomon@google.com91958362011-06-13 17:58:13 +00001284 const int maxTextureSize = fContext->getMaxTextureSize();
1285 if (bitmap.getTexture() || (bitmap.width() <= maxTextureSize &&
1286 bitmap.height() <= maxTextureSize)) {
reed@google.comac10a2d2010-12-22 21:39:39 +00001287 // take the fast case
bsalomon@google.com5782d712011-01-21 21:03:59 +00001288 this->internalDrawBitmap(draw, bitmap, srcRect, m, &grPaint);
reed@google.comac10a2d2010-12-22 21:39:39 +00001289 return;
1290 }
1291
1292 // undo the translate done by SkCanvas
1293 int DX = SkMax32(0, srcRect.fLeft);
1294 int DY = SkMax32(0, srcRect.fTop);
1295 // compute clip bounds in local coordinates
1296 SkIRect clipRect;
1297 {
1298 SkRect r;
1299 r.set(draw.fClip->getBounds());
1300 SkMatrix matrix, inverse;
1301 matrix.setConcat(*draw.fMatrix, m);
1302 if (!matrix.invert(&inverse)) {
1303 return;
1304 }
1305 inverse.mapRect(&r);
1306 r.roundOut(&clipRect);
1307 // apply the canvas' translate to our local clip
1308 clipRect.offset(DX, DY);
1309 }
1310
bsalomon@google.com91958362011-06-13 17:58:13 +00001311 int nx = bitmap.width() / maxTextureSize;
1312 int ny = bitmap.height() / maxTextureSize;
reed@google.comac10a2d2010-12-22 21:39:39 +00001313 for (int x = 0; x <= nx; x++) {
1314 for (int y = 0; y <= ny; y++) {
1315 SkIRect tileR;
bsalomon@google.com91958362011-06-13 17:58:13 +00001316 tileR.set(x * maxTextureSize, y * maxTextureSize,
1317 (x + 1) * maxTextureSize, (y + 1) * maxTextureSize);
reed@google.comac10a2d2010-12-22 21:39:39 +00001318 if (!SkIRect::Intersects(tileR, clipRect)) {
1319 continue;
1320 }
1321
1322 SkIRect srcR = tileR;
1323 if (!srcR.intersect(srcRect)) {
1324 continue;
1325 }
1326
1327 SkBitmap tmpB;
1328 if (bitmap.extractSubset(&tmpB, tileR)) {
1329 // now offset it to make it "local" to our tmp bitmap
1330 srcR.offset(-tileR.fLeft, -tileR.fTop);
1331
1332 SkMatrix tmpM(m);
1333 {
1334 int dx = tileR.fLeft - DX + SkMax32(0, srcR.fLeft);
1335 int dy = tileR.fTop - DY + SkMax32(0, srcR.fTop);
1336 tmpM.preTranslate(SkIntToScalar(dx), SkIntToScalar(dy));
1337 }
bsalomon@google.com5782d712011-01-21 21:03:59 +00001338 this->internalDrawBitmap(draw, tmpB, srcR, tmpM, &grPaint);
reed@google.comac10a2d2010-12-22 21:39:39 +00001339 }
1340 }
1341 }
1342}
1343
1344/*
1345 * This is called by drawBitmap(), which has to handle images that may be too
1346 * large to be represented by a single texture.
1347 *
bsalomon@google.com5782d712011-01-21 21:03:59 +00001348 * internalDrawBitmap assumes that the specified bitmap will fit in a texture
1349 * and that non-texture portion of the GrPaint has already been setup.
reed@google.comac10a2d2010-12-22 21:39:39 +00001350 */
1351void SkGpuDevice::internalDrawBitmap(const SkDraw& draw,
1352 const SkBitmap& bitmap,
1353 const SkIRect& srcRect,
1354 const SkMatrix& m,
bsalomon@google.com5782d712011-01-21 21:03:59 +00001355 GrPaint* grPaint) {
bsalomon@google.com91958362011-06-13 17:58:13 +00001356 SkASSERT(bitmap.width() <= fContext->getMaxTextureSize() &&
1357 bitmap.height() <= fContext->getMaxTextureSize());
reed@google.comac10a2d2010-12-22 21:39:39 +00001358
reed@google.com9c49bc32011-07-07 13:42:37 +00001359 SkAutoLockPixels alp(bitmap, !bitmap.getTexture());
reed@google.comac10a2d2010-12-22 21:39:39 +00001360 if (!bitmap.getTexture() && !bitmap.readyToDraw()) {
reed@google.com9c49bc32011-07-07 13:42:37 +00001361 SkDebugf("nothing to draw\n");
reed@google.comac10a2d2010-12-22 21:39:39 +00001362 return;
1363 }
1364
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001365 GrSamplerState* sampler = grPaint->getTextureSampler(kBitmapTextureIdx);
1366
1367 sampler->setWrapX(GrSamplerState::kClamp_WrapMode);
1368 sampler->setWrapY(GrSamplerState::kClamp_WrapMode);
1369 sampler->setSampleMode(GrSamplerState::kNormal_SampleMode);
1370 sampler->setMatrix(GrMatrix::I());
reed@google.comac10a2d2010-12-22 21:39:39 +00001371
1372 GrTexture* texture;
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001373 SkAutoCachedTexture act(this, bitmap, *sampler, &texture);
reed@google.comac10a2d2010-12-22 21:39:39 +00001374 if (NULL == texture) {
1375 return;
1376 }
1377
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001378 grPaint->setTexture(kShaderTextureIdx, texture);
reed@google.com46799cd2011-02-22 20:56:26 +00001379
reed@google.com20efde72011-05-09 17:00:02 +00001380 GrRect dstRect = SkRect::MakeWH(GrIntToScalar(srcRect.width()),
1381 GrIntToScalar(srcRect.height()));
bsalomon@google.comc6cf7232011-02-17 16:43:10 +00001382 GrRect paintRect;
junov@google.com6acc9b32011-05-16 18:32:07 +00001383 paintRect.setLTRB(GrFixedToScalar((srcRect.fLeft << 16) / bitmap.width()),
1384 GrFixedToScalar((srcRect.fTop << 16) / bitmap.height()),
1385 GrFixedToScalar((srcRect.fRight << 16) / bitmap.width()),
bsalomon@google.comc6cf7232011-02-17 16:43:10 +00001386 GrFixedToScalar((srcRect.fBottom << 16) / bitmap.height()));
reed@google.comac10a2d2010-12-22 21:39:39 +00001387
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001388 if (GrSamplerState::kNearest_Filter != sampler->getFilter() &&
junov@google.com6acc9b32011-05-16 18:32:07 +00001389 (srcRect.width() < bitmap.width() ||
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001390 srcRect.height() < bitmap.height())) {
junov@google.com6acc9b32011-05-16 18:32:07 +00001391 // If drawing a subrect of the bitmap and filtering is enabled,
1392 // use a constrained texture domain to avoid color bleeding
1393 GrScalar left, top, right, bottom;
1394 if (srcRect.width() > 1) {
1395 GrScalar border = GR_ScalarHalf / bitmap.width();
1396 left = paintRect.left() + border;
1397 right = paintRect.right() - border;
1398 } else {
1399 left = right = GrScalarHalf(paintRect.left() + paintRect.right());
1400 }
1401 if (srcRect.height() > 1) {
1402 GrScalar border = GR_ScalarHalf / bitmap.height();
1403 top = paintRect.top() + border;
1404 bottom = paintRect.bottom() - border;
1405 } else {
1406 top = bottom = GrScalarHalf(paintRect.top() + paintRect.bottom());
1407 }
1408 GrRect textureDomain;
1409 textureDomain.setLTRB(left, top, right, bottom);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001410 sampler->setTextureDomain(textureDomain);
junov@google.com6acc9b32011-05-16 18:32:07 +00001411 }
1412
bsalomon@google.comcc4dac32011-05-10 13:52:42 +00001413 fContext->drawRectToRect(*grPaint, dstRect, paintRect, &m);
reed@google.comac10a2d2010-12-22 21:39:39 +00001414}
1415
1416void SkGpuDevice::drawSprite(const SkDraw& draw, const SkBitmap& bitmap,
1417 int left, int top, const SkPaint& paint) {
1418 CHECK_SHOULD_DRAW(draw);
1419
1420 SkAutoLockPixels alp(bitmap);
1421 if (!bitmap.getTexture() && !bitmap.readyToDraw()) {
1422 return;
1423 }
1424
bsalomon@google.com5782d712011-01-21 21:03:59 +00001425 GrPaint grPaint;
Scroggod757df22011-05-16 13:11:16 +00001426 if(!this->skPaint2GrPaintNoShader(paint, true, &grPaint, false)) {
bsalomon@google.com5782d712011-01-21 21:03:59 +00001427 return;
1428 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001429
bsalomon@google.com5782d712011-01-21 21:03:59 +00001430 GrAutoMatrix avm(fContext, GrMatrix::I());
1431
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001432 GrSamplerState* sampler = grPaint.getTextureSampler(kBitmapTextureIdx);
bsalomon@google.com5782d712011-01-21 21:03:59 +00001433
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001434 GrTexture* texture;
1435 sampler->setClampNoFilter();
1436 SkAutoCachedTexture act(this, bitmap, *sampler, &texture);
1437
1438 grPaint.setTexture(kBitmapTextureIdx, texture);
bsalomon@google.com5782d712011-01-21 21:03:59 +00001439
bsalomon@google.com5782d712011-01-21 21:03:59 +00001440 fContext->drawRectToRect(grPaint,
reed@google.com20efde72011-05-09 17:00:02 +00001441 GrRect::MakeXYWH(GrIntToScalar(left),
1442 GrIntToScalar(top),
1443 GrIntToScalar(bitmap.width()),
1444 GrIntToScalar(bitmap.height())),
1445 GrRect::MakeWH(GR_Scalar1, GR_Scalar1));
reed@google.comac10a2d2010-12-22 21:39:39 +00001446}
1447
1448void SkGpuDevice::drawDevice(const SkDraw& draw, SkDevice* dev,
1449 int x, int y, const SkPaint& paint) {
1450 CHECK_SHOULD_DRAW(draw);
1451
bsalomon@google.com5782d712011-01-21 21:03:59 +00001452 GrPaint grPaint;
bsalomon@google.comc6cf7232011-02-17 16:43:10 +00001453 if (!((SkGpuDevice*)dev)->bindDeviceAsTexture(&grPaint) ||
Scroggod757df22011-05-16 13:11:16 +00001454 !this->skPaint2GrPaintNoShader(paint, true, &grPaint, false)) {
bsalomon@google.com5782d712011-01-21 21:03:59 +00001455 return;
reed@google.comac10a2d2010-12-22 21:39:39 +00001456 }
bsalomon@google.com5782d712011-01-21 21:03:59 +00001457
bsalomon@google.comb5b31682011-06-16 18:05:35 +00001458 GrTexture* devTex = grPaint.getTexture(0);
1459 SkASSERT(NULL != devTex);
bsalomon@google.com5782d712011-01-21 21:03:59 +00001460
1461 const SkBitmap& bm = dev->accessBitmap(false);
1462 int w = bm.width();
1463 int h = bm.height();
1464
1465 GrAutoMatrix avm(fContext, GrMatrix::I());
1466
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001467 grPaint.getTextureSampler(kBitmapTextureIdx)->setClampNoFilter();
bsalomon@google.com5782d712011-01-21 21:03:59 +00001468
bsalomon@google.comb5b31682011-06-16 18:05:35 +00001469 GrRect dstRect = GrRect::MakeXYWH(GrIntToScalar(x),
1470 GrIntToScalar(y),
1471 GrIntToScalar(w),
1472 GrIntToScalar(h));
1473 // The device being drawn may not fill up its texture (saveLayer uses
1474 // the approximate ).
1475 GrRect srcRect = GrRect::MakeWH(GR_Scalar1 * w / devTex->width(),
1476 GR_Scalar1 * h / devTex->height());
1477
1478 fContext->drawRectToRect(grPaint, dstRect, srcRect);
reed@google.comac10a2d2010-12-22 21:39:39 +00001479}
1480
1481///////////////////////////////////////////////////////////////////////////////
1482
1483// must be in SkCanvas::VertexMode order
bsalomon@google.comffca4002011-02-22 20:34:01 +00001484static const GrPrimitiveType gVertexMode2PrimitiveType[] = {
1485 kTriangles_PrimitiveType,
1486 kTriangleStrip_PrimitiveType,
1487 kTriangleFan_PrimitiveType,
reed@google.comac10a2d2010-12-22 21:39:39 +00001488};
1489
1490void SkGpuDevice::drawVertices(const SkDraw& draw, SkCanvas::VertexMode vmode,
1491 int vertexCount, const SkPoint vertices[],
1492 const SkPoint texs[], const SkColor colors[],
1493 SkXfermode* xmode,
1494 const uint16_t indices[], int indexCount,
1495 const SkPaint& paint) {
1496 CHECK_SHOULD_DRAW(draw);
1497
bsalomon@google.com5782d712011-01-21 21:03:59 +00001498 GrPaint grPaint;
1499 SkAutoCachedTexture act;
1500 // we ignore the shader if texs is null.
1501 if (NULL == texs) {
Scroggod757df22011-05-16 13:11:16 +00001502 if (!this->skPaint2GrPaintNoShader(paint,
1503 false,
1504 &grPaint,
1505 NULL == colors)) {
reed@google.comac10a2d2010-12-22 21:39:39 +00001506 return;
1507 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001508 } else {
reed@google.com1a2e8d22011-01-21 22:08:29 +00001509 if (!this->skPaint2GrPaintShader(paint, &act,
1510 *draw.fMatrix,
Scroggod757df22011-05-16 13:11:16 +00001511 &grPaint,
1512 NULL == colors)) {
bsalomon@google.com5782d712011-01-21 21:03:59 +00001513 return;
1514 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001515 }
bsalomon@google.com5782d712011-01-21 21:03:59 +00001516
1517 if (NULL != xmode && NULL != texs && NULL != colors) {
1518 SkXfermode::Mode mode;
1519 if (!SkXfermode::IsMode(xmode, &mode) ||
1520 SkXfermode::kMultiply_Mode != mode) {
1521 SkDebugf("Unsupported vertex-color/texture xfer mode.\n");
1522#if 0
1523 return
1524#endif
1525 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001526 }
bsalomon@google.com5782d712011-01-21 21:03:59 +00001527
1528#if SK_SCALAR_IS_GR_SCALAR
1529 // even if GrColor and SkColor byte offsets match we need
1530 // to perform pre-multiply.
1531 if (NULL == colors) {
1532 fContext->drawVertices(grPaint,
1533 gVertexMode2PrimitiveType[vmode],
1534 vertexCount,
1535 (GrPoint*) vertices,
1536 (GrPoint*) texs,
1537 NULL,
1538 indices,
1539 indexCount);
1540 } else
1541#endif
1542 {
1543 SkTexCoordSource texSrc(texs);
1544 SkColorSource colSrc(colors);
1545 SkIndexSource idxSrc(indices, indexCount);
1546
1547 fContext->drawCustomVertices(grPaint,
1548 gVertexMode2PrimitiveType[vmode],
1549 SkPositionSource(vertices, vertexCount),
1550 (NULL == texs) ? NULL : &texSrc,
1551 (NULL == colors) ? NULL : &colSrc,
1552 (NULL == indices) ? NULL : &idxSrc);
reed@google.comac10a2d2010-12-22 21:39:39 +00001553 }
1554}
1555
1556///////////////////////////////////////////////////////////////////////////////
1557
1558static void GlyphCacheAuxProc(void* data) {
1559 delete (GrFontScaler*)data;
1560}
1561
1562static GrFontScaler* get_gr_font_scaler(SkGlyphCache* cache) {
1563 void* auxData;
1564 GrFontScaler* scaler = NULL;
1565 if (cache->getAuxProcData(GlyphCacheAuxProc, &auxData)) {
1566 scaler = (GrFontScaler*)auxData;
1567 }
1568 if (NULL == scaler) {
1569 scaler = new SkGrFontScaler(cache);
1570 cache->setAuxProc(GlyphCacheAuxProc, scaler);
1571 }
1572 return scaler;
1573}
1574
1575static void SkGPU_Draw1Glyph(const SkDraw1Glyph& state,
1576 SkFixed fx, SkFixed fy,
1577 const SkGlyph& glyph) {
1578 SkASSERT(glyph.fWidth > 0 && glyph.fHeight > 0);
1579
1580 GrSkDrawProcs* procs = (GrSkDrawProcs*)state.fDraw->fProcs;
1581
1582 if (NULL == procs->fFontScaler) {
1583 procs->fFontScaler = get_gr_font_scaler(state.fCache);
1584 }
reed@google.com39ce0ac2011-04-08 15:42:19 +00001585
1586 /*
reed@google.com3b139f52011-06-07 17:56:25 +00001587 * What should we do with fy? (assuming horizontal/latin text)
reed@google.com39ce0ac2011-04-08 15:42:19 +00001588 *
reed@google.com3b139f52011-06-07 17:56:25 +00001589 * The raster code calls SkFixedFloorToFixed on it, as it does with fx.
1590 * It calls that rather than round, because our caller has already added
1591 * SK_FixedHalf, so that calling floor gives us the rounded integer.
1592 *
1593 * Test code between raster and gpu (they should draw the same)
1594 *
1595 * canvas->drawText("Hamburgefons", 12, 0, 16.5f, paint);
1596 *
1597 * Perhaps we should only perform this integralization if there is no
1598 * fExtMatrix...
reed@google.com39ce0ac2011-04-08 15:42:19 +00001599 */
reed@google.com3b139f52011-06-07 17:56:25 +00001600 fy = SkFixedFloorToFixed(fy);
1601
reed@google.comac10a2d2010-12-22 21:39:39 +00001602 procs->fTextContext->drawPackedGlyph(GrGlyph::Pack(glyph.getGlyphID(), fx, 0),
reed@google.com3b139f52011-06-07 17:56:25 +00001603 SkFixedFloorToFixed(fx), fy,
reed@google.comac10a2d2010-12-22 21:39:39 +00001604 procs->fFontScaler);
1605}
1606
bsalomon@google.com5782d712011-01-21 21:03:59 +00001607SkDrawProcs* SkGpuDevice::initDrawForText(GrTextContext* context) {
reed@google.comac10a2d2010-12-22 21:39:39 +00001608
1609 // deferred allocation
1610 if (NULL == fDrawProcs) {
1611 fDrawProcs = new GrSkDrawProcs;
1612 fDrawProcs->fD1GProc = SkGPU_Draw1Glyph;
1613 fDrawProcs->fContext = fContext;
1614 }
1615
1616 // init our (and GL's) state
1617 fDrawProcs->fTextContext = context;
1618 fDrawProcs->fFontScaler = NULL;
1619 return fDrawProcs;
1620}
1621
1622void SkGpuDevice::drawText(const SkDraw& draw, const void* text,
1623 size_t byteLength, SkScalar x, SkScalar y,
1624 const SkPaint& paint) {
1625 CHECK_SHOULD_DRAW(draw);
1626
1627 if (draw.fMatrix->getType() & SkMatrix::kPerspective_Mask) {
1628 // this guy will just call our drawPath()
1629 draw.drawText((const char*)text, byteLength, x, y, paint);
1630 } else {
reed@google.comac10a2d2010-12-22 21:39:39 +00001631 SkDraw myDraw(draw);
bsalomon@google.com5782d712011-01-21 21:03:59 +00001632
1633 GrPaint grPaint;
1634 SkAutoCachedTexture act;
1635
Scroggod757df22011-05-16 13:11:16 +00001636 if (!this->skPaint2GrPaintShader(paint,
1637 &act,
1638 *draw.fMatrix,
1639 &grPaint,
1640 true)) {
bsalomon@google.com5782d712011-01-21 21:03:59 +00001641 return;
1642 }
bsalomon@google.comcc4dac32011-05-10 13:52:42 +00001643 GrTextContext context(fContext, grPaint, draw.fExtMatrix);
bsalomon@google.com5782d712011-01-21 21:03:59 +00001644 myDraw.fProcs = this->initDrawForText(&context);
reed@google.comac10a2d2010-12-22 21:39:39 +00001645 this->INHERITED::drawText(myDraw, text, byteLength, x, y, paint);
1646 }
1647}
1648
1649void SkGpuDevice::drawPosText(const SkDraw& draw, const void* text,
1650 size_t byteLength, const SkScalar pos[],
1651 SkScalar constY, int scalarsPerPos,
1652 const SkPaint& paint) {
1653 CHECK_SHOULD_DRAW(draw);
1654
1655 if (draw.fMatrix->getType() & SkMatrix::kPerspective_Mask) {
1656 // this guy will just call our drawPath()
1657 draw.drawPosText((const char*)text, byteLength, pos, constY,
1658 scalarsPerPos, paint);
1659 } else {
reed@google.comac10a2d2010-12-22 21:39:39 +00001660 SkDraw myDraw(draw);
bsalomon@google.com5782d712011-01-21 21:03:59 +00001661
1662 GrPaint grPaint;
1663 SkAutoCachedTexture act;
Scroggod757df22011-05-16 13:11:16 +00001664 if (!this->skPaint2GrPaintShader(paint,
1665 &act,
1666 *draw.fMatrix,
1667 &grPaint,
1668 true)) {
bsalomon@google.com5782d712011-01-21 21:03:59 +00001669 return;
1670 }
1671
bsalomon@google.comcc4dac32011-05-10 13:52:42 +00001672 GrTextContext context(fContext, grPaint, draw.fExtMatrix);
bsalomon@google.com5782d712011-01-21 21:03:59 +00001673 myDraw.fProcs = this->initDrawForText(&context);
reed@google.comac10a2d2010-12-22 21:39:39 +00001674 this->INHERITED::drawPosText(myDraw, text, byteLength, pos, constY,
1675 scalarsPerPos, paint);
1676 }
1677}
1678
1679void SkGpuDevice::drawTextOnPath(const SkDraw& draw, const void* text,
1680 size_t len, const SkPath& path,
1681 const SkMatrix* m, const SkPaint& paint) {
1682 CHECK_SHOULD_DRAW(draw);
1683
1684 SkASSERT(draw.fDevice == this);
1685 draw.drawTextOnPath((const char*)text, len, path, m, paint);
1686}
1687
1688///////////////////////////////////////////////////////////////////////////////
1689
reed@google.comf67e4cf2011-03-15 20:56:58 +00001690bool SkGpuDevice::filterTextFlags(const SkPaint& paint, TextFlags* flags) {
1691 if (!paint.isLCDRenderText()) {
1692 // we're cool with the paint as is
1693 return false;
1694 }
1695
1696 if (paint.getShader() ||
1697 paint.getXfermode() || // unless its srcover
1698 paint.getMaskFilter() ||
1699 paint.getRasterizer() ||
1700 paint.getColorFilter() ||
1701 paint.getPathEffect() ||
1702 paint.isFakeBoldText() ||
1703 paint.getStyle() != SkPaint::kFill_Style) {
1704 // turn off lcd
1705 flags->fFlags = paint.getFlags() & ~SkPaint::kLCDRenderText_Flag;
1706 flags->fHinting = paint.getHinting();
1707 return true;
1708 }
1709 // we're cool with the paint as is
1710 return false;
1711}
1712
1713///////////////////////////////////////////////////////////////////////////////
1714
reed@google.comac10a2d2010-12-22 21:39:39 +00001715SkGpuDevice::TexCache* SkGpuDevice::lockCachedTexture(const SkBitmap& bitmap,
bsalomon@google.comfea37b52011-04-25 15:51:06 +00001716 const GrSamplerState& sampler,
1717 GrTexture** texture,
bsalomon@google.come97f0852011-06-17 13:10:25 +00001718 TexType type) {
bsalomon@google.comfea37b52011-04-25 15:51:06 +00001719 GrTexture* newTexture = NULL;
1720 GrTextureEntry* entry = NULL;
reed@google.comac10a2d2010-12-22 21:39:39 +00001721 GrContext* ctx = this->context();
bsalomon@google.comfea37b52011-04-25 15:51:06 +00001722
bsalomon@google.come97f0852011-06-17 13:10:25 +00001723 if (kBitmap_TexType != type) {
bsalomon@google.comfea37b52011-04-25 15:51:06 +00001724 const GrTextureDesc desc = {
1725 kRenderTarget_GrTextureFlagBit,
1726 kNone_GrAALevel,
1727 bitmap.width(),
1728 bitmap.height(),
1729 SkGr::Bitmap2PixelConfig(bitmap)
1730 };
bsalomon@google.come97f0852011-06-17 13:10:25 +00001731 if (kSaveLayerDeviceRenderTarget_TexType == type) {
bsalomon@google.comb5b31682011-06-16 18:05:35 +00001732 // we know layers will only be drawn through drawDevice.
1733 // drawDevice has been made to work with content embedded in a
1734 // larger texture so its okay to use the approximate version.
1735 entry = ctx->findApproximateKeylessTexture(desc);
1736 } else {
bsalomon@google.come97f0852011-06-17 13:10:25 +00001737 SkASSERT(kDeviceRenderTarget_TexType == type);
bsalomon@google.comb5b31682011-06-16 18:05:35 +00001738 entry = ctx->lockKeylessTexture(desc);
1739 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001740 } else {
junov@google.com4ee7ae52011-06-30 17:30:49 +00001741 if (!bitmap.isVolatile()) {
1742 uint32_t p0, p1;
1743 p0 = bitmap.getGenerationID();
1744 p1 = bitmap.pixelRefOffset();
1745 GrTextureKey key(p0, p1, bitmap.width(), bitmap.height());
1746
1747 entry = ctx->findAndLockTexture(&key, sampler);
1748 if (NULL == entry)
1749 entry = sk_gr_create_bitmap_texture(ctx, &key, sampler,
1750 bitmap);
1751 } else {
1752 entry = sk_gr_create_bitmap_texture(ctx, NULL, sampler, bitmap);
1753 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001754 if (NULL == entry) {
junov@google.com4ee7ae52011-06-30 17:30:49 +00001755 GrPrintf("---- failed to create texture for cache [%d %d]\n",
1756 bitmap.width(), bitmap.height());
reed@google.comac10a2d2010-12-22 21:39:39 +00001757 }
1758 }
1759
1760 if (NULL != entry) {
1761 newTexture = entry->texture();
reed@google.comac10a2d2010-12-22 21:39:39 +00001762 if (texture) {
1763 *texture = newTexture;
1764 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001765 }
1766 return (TexCache*)entry;
1767}
1768
1769void SkGpuDevice::unlockCachedTexture(TexCache* cache) {
1770 this->context()->unlockTexture((GrTextureEntry*)cache);
1771}
1772
bsalomon@google.come97f0852011-06-17 13:10:25 +00001773SkDevice* SkGpuDevice::onCreateCompatibleDevice(SkBitmap::Config config,
1774 int width, int height,
1775 bool isOpaque,
1776 Usage usage) {
1777 return SkNEW_ARGS(SkGpuDevice,(this->context(), config,
1778 width, height, usage));
1779}
1780