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