blob: 790767e6fbee82459e5ec78778337878a1b47463 [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);
reed@google.comac10a2d2010-12-22 21:39:39 +000070 *texture = this->set(device, bitmap, sampler);
71}
72
73SkGpuDevice::SkAutoCachedTexture::SkAutoCachedTexture() {
reed@google.comac10a2d2010-12-22 21:39:39 +000074}
75
76GrTexture* SkGpuDevice::SkAutoCachedTexture::set(SkGpuDevice* device,
77 const SkBitmap& bitmap,
78 const GrSamplerState& sampler) {
bsalomon@google.com50398bf2011-07-26 20:45:30 +000079 if (fTex.texture()) {
reed@google.comac10a2d2010-12-22 21:39:39 +000080 fDevice->unlockCachedTexture(fTex);
81 }
82 fDevice = device;
83 GrTexture* texture = (GrTexture*)bitmap.getTexture();
84 if (texture) {
85 // return the native texture
bsalomon@google.com50398bf2011-07-26 20:45:30 +000086 fTex.reset();
reed@google.comac10a2d2010-12-22 21:39:39 +000087 } else {
88 // look it up in our cache
bsalomon@google.com50398bf2011-07-26 20:45:30 +000089 fTex = device->lockCachedTexture(bitmap, sampler);
90 texture = fTex.texture();
reed@google.comac10a2d2010-12-22 21:39:39 +000091 }
92 return texture;
93}
94
95SkGpuDevice::SkAutoCachedTexture::~SkAutoCachedTexture() {
bsalomon@google.com50398bf2011-07-26 20:45:30 +000096 if (fTex.texture()) {
reed@google.comac10a2d2010-12-22 21:39:39 +000097 fDevice->unlockCachedTexture(fTex);
98 }
99}
100
101///////////////////////////////////////////////////////////////////////////////
102
103bool gDoTraceDraw;
104
105struct GrSkDrawProcs : public SkDrawProcs {
106public:
107 GrContext* fContext;
108 GrTextContext* fTextContext;
109 GrFontScaler* fFontScaler; // cached in the skia glyphcache
110};
111
112///////////////////////////////////////////////////////////////////////////////
113
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000114GrRenderTarget* SkGpuDevice::Current3DApiRenderTarget() {
115 return (GrRenderTarget*) -1;
116}
117
reed@google.comaf951c92011-06-16 19:10:39 +0000118static SkBitmap::Config grConfig2skConfig(GrPixelConfig config, bool* isOpaque) {
119 switch (config) {
120 case kAlpha_8_GrPixelConfig:
121 *isOpaque = false;
122 return SkBitmap::kA8_Config;
123 case kRGB_565_GrPixelConfig:
124 *isOpaque = true;
125 return SkBitmap::kRGB_565_Config;
126 case kRGBA_4444_GrPixelConfig:
127 *isOpaque = false;
128 return SkBitmap::kARGB_4444_Config;
129 case kRGBA_8888_GrPixelConfig:
130 case kRGBX_8888_GrPixelConfig:
131 *isOpaque = (kRGBX_8888_GrPixelConfig == config);
132 return SkBitmap::kARGB_8888_Config;
133 default:
134 *isOpaque = false;
135 return SkBitmap::kNo_Config;
136 }
137}
reed@google.comac10a2d2010-12-22 21:39:39 +0000138
reed@google.comaf951c92011-06-16 19:10:39 +0000139static SkBitmap make_bitmap(GrContext* context, GrRenderTarget* renderTarget) {
140 if (SkGpuDevice::Current3DApiRenderTarget() == renderTarget) {
141 renderTarget = context->createRenderTargetFrom3DApiState();
142 }
143 GrTexture* texture = renderTarget->asTexture();
144 GrPixelConfig config = texture ? texture->config() : kRGBA_8888_GrPixelConfig;
145
146 bool isOpaque;
147 SkBitmap bitmap;
148 bitmap.setConfig(grConfig2skConfig(config, &isOpaque),
149 renderTarget->width(), renderTarget->height());
150 bitmap.setIsOpaque(isOpaque);
151 return bitmap;
152}
153
bsalomon@google.comf9046fe2011-06-17 15:10:21 +0000154SkGpuDevice::SkGpuDevice(GrContext* context, GrTexture* texture)
155: SkDevice(make_bitmap(context, texture->asRenderTarget())) {
156 this->initFromRenderTarget(context, texture->asRenderTarget());
157}
158
reed@google.comaf951c92011-06-16 19:10:39 +0000159SkGpuDevice::SkGpuDevice(GrContext* context, GrRenderTarget* renderTarget)
160: SkDevice(make_bitmap(context, renderTarget)) {
bsalomon@google.comf9046fe2011-06-17 15:10:21 +0000161 this->initFromRenderTarget(context, renderTarget);
162}
163
164void SkGpuDevice::initFromRenderTarget(GrContext* context,
165 GrRenderTarget* renderTarget) {
reed@google.comaf951c92011-06-16 19:10:39 +0000166 fNeedPrepareRenderTarget = false;
167 fDrawProcs = NULL;
168
169 fContext = context;
170 fContext->ref();
171
reed@google.comaf951c92011-06-16 19:10:39 +0000172 fTexture = NULL;
173 fRenderTarget = NULL;
174 fNeedClear = false;
175
176 if (Current3DApiRenderTarget() == renderTarget) {
177 fRenderTarget = fContext->createRenderTargetFrom3DApiState();
178 } else {
bsalomon@google.comf9046fe2011-06-17 15:10:21 +0000179 GrAssert(NULL != renderTarget);
reed@google.comaf951c92011-06-16 19:10:39 +0000180 fRenderTarget = renderTarget;
181 fRenderTarget->ref();
bsalomon@google.comf9046fe2011-06-17 15:10:21 +0000182 // if this RT is also a texture, hold a ref on it
183 fTexture = fRenderTarget->asTexture();
184 SkSafeRef(fTexture);
reed@google.comaf951c92011-06-16 19:10:39 +0000185 }
186
187 SkGrRenderTargetPixelRef* pr = new SkGrRenderTargetPixelRef(fRenderTarget);
188 this->setPixelRef(pr, 0)->unref();
189}
190
191SkGpuDevice::SkGpuDevice(GrContext* context, SkBitmap::Config config, int width,
bsalomon@google.come97f0852011-06-17 13:10:25 +0000192 int height, Usage usage)
reed@google.comaf951c92011-06-16 19:10:39 +0000193: SkDevice(config, width, height, false /*isOpaque*/) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000194 fNeedPrepareRenderTarget = false;
195 fDrawProcs = NULL;
196
reed@google.com7b201d22011-01-11 18:59:23 +0000197 fContext = context;
bsalomon@google.com5782d712011-01-21 21:03:59 +0000198 fContext->ref();
reed@google.comac10a2d2010-12-22 21:39:39 +0000199
reed@google.comac10a2d2010-12-22 21:39:39 +0000200 fTexture = NULL;
201 fRenderTarget = NULL;
202 fNeedClear = false;
203
reed@google.comaf951c92011-06-16 19:10:39 +0000204 if (config != SkBitmap::kRGB_565_Config) {
205 config = SkBitmap::kARGB_8888_Config;
206 }
207 SkBitmap bm;
208 bm.setConfig(config, width, height);
reed@google.comac10a2d2010-12-22 21:39:39 +0000209
210#if CACHE_LAYER_TEXTURES
bsalomon@google.come97f0852011-06-17 13:10:25 +0000211 TexType type = (kSaveLayer_Usage == usage) ?
212 kSaveLayerDeviceRenderTarget_TexType :
213 kDeviceRenderTarget_TexType;
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000214 fCache = this->lockCachedTexture(bm, GrSamplerState::ClampNoFilter(), type);
215 fTexture = fCache.texture();
216 if (fTexture) {
reed@google.comaf951c92011-06-16 19:10:39 +0000217 SkASSERT(NULL != fTexture->asRenderTarget());
bsalomon@google.comf9046fe2011-06-17 15:10:21 +0000218 // hold a ref directly on fTexture (even though fCache has one) to match
219 // other constructor paths. Simplifies cleanup.
220 fTexture->ref();
reed@google.comaf951c92011-06-16 19:10:39 +0000221 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000222#else
reed@google.comaf951c92011-06-16 19:10:39 +0000223 const GrTextureDesc desc = {
224 kRenderTarget_GrTextureFlagBit,
225 kNone_GrAALevel,
226 width,
227 height,
228 SkGr::Bitmap2PixelConfig(bm)
229 };
reed@google.comac10a2d2010-12-22 21:39:39 +0000230
reed@google.comaf951c92011-06-16 19:10:39 +0000231 fTexture = fContext->createUncachedTexture(desc, NULL, 0);
reed@google.comac10a2d2010-12-22 21:39:39 +0000232#endif
reed@google.comaf951c92011-06-16 19:10:39 +0000233 if (NULL != fTexture) {
234 fRenderTarget = fTexture->asRenderTarget();
bsalomon@google.comf9046fe2011-06-17 15:10:21 +0000235 fRenderTarget->ref();
reed@google.comac10a2d2010-12-22 21:39:39 +0000236
reed@google.comaf951c92011-06-16 19:10:39 +0000237 GrAssert(NULL != fRenderTarget);
reed@google.comac10a2d2010-12-22 21:39:39 +0000238
reed@google.comaf951c92011-06-16 19:10:39 +0000239 // we defer the actual clear until our gainFocus()
240 fNeedClear = true;
reed@google.comac10a2d2010-12-22 21:39:39 +0000241
reed@google.comaf951c92011-06-16 19:10:39 +0000242 // wrap the bitmap with a pixelref to expose our texture
243 SkGrTexturePixelRef* pr = new SkGrTexturePixelRef(fTexture);
bsalomon@google.com669fdc42011-04-05 17:08:27 +0000244 this->setPixelRef(pr, 0)->unref();
reed@google.comaf951c92011-06-16 19:10:39 +0000245 } else {
246 GrPrintf("--- failed to create gpu-offscreen [%d %d]\n",
247 width, height);
248 GrAssert(false);
reed@google.comac10a2d2010-12-22 21:39:39 +0000249 }
250}
251
252SkGpuDevice::~SkGpuDevice() {
253 if (fDrawProcs) {
254 delete fDrawProcs;
255 }
256
bsalomon@google.comf9046fe2011-06-17 15:10:21 +0000257 SkSafeUnref(fTexture);
258 SkSafeUnref(fRenderTarget);
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000259 if (fCache.texture()) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000260 GrAssert(NULL != fTexture);
261 GrAssert(fRenderTarget == fTexture->asRenderTarget());
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000262 fContext->unlockTexture(fCache);
bsalomon@google.comf9046fe2011-06-17 15:10:21 +0000263 }
bsalomon@google.com5782d712011-01-21 21:03:59 +0000264 fContext->unref();
reed@google.comac10a2d2010-12-22 21:39:39 +0000265}
266
reed@google.comac10a2d2010-12-22 21:39:39 +0000267///////////////////////////////////////////////////////////////////////////////
268
269void SkGpuDevice::makeRenderTargetCurrent() {
270 fContext->setRenderTarget(fRenderTarget);
271 fContext->flush(true);
272 fNeedPrepareRenderTarget = true;
273}
274
275///////////////////////////////////////////////////////////////////////////////
276
277bool SkGpuDevice::readPixels(const SkIRect& srcRect, SkBitmap* bitmap) {
278 SkIRect bounds;
279 bounds.set(0, 0, this->width(), this->height());
280 if (!bounds.intersect(srcRect)) {
281 return false;
282 }
283
284 const int w = bounds.width();
285 const int h = bounds.height();
286 SkBitmap tmp;
287 // note we explicitly specify our rowBytes to be snug (no gap between rows)
288 tmp.setConfig(SkBitmap::kARGB_8888_Config, w, h, w * 4);
289 if (!tmp.allocPixels()) {
290 return false;
291 }
292
Scroggo813c33c2011-04-07 20:56:21 +0000293 tmp.lockPixels();
reed@google.comac10a2d2010-12-22 21:39:39 +0000294
Scroggoeb176032011-04-07 21:11:49 +0000295 bool read = fContext->readRenderTargetPixels(fRenderTarget,
296 bounds.fLeft, bounds.fTop,
297 bounds.width(), bounds.height(),
298 kRGBA_8888_GrPixelConfig,
299 tmp.getPixels());
Scroggo813c33c2011-04-07 20:56:21 +0000300 tmp.unlockPixels();
301 if (!read) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000302 return false;
303 }
304
305 tmp.swap(*bitmap);
306 return true;
307}
308
309void SkGpuDevice::writePixels(const SkBitmap& bitmap, int x, int y) {
310 SkAutoLockPixels alp(bitmap);
311 if (!bitmap.readyToDraw()) {
312 return;
313 }
bsalomon@google.com669fdc42011-04-05 17:08:27 +0000314 GrPixelConfig config = SkGr::BitmapConfig2PixelConfig(bitmap.config(),
315 bitmap.isOpaque());
reed@google.comac10a2d2010-12-22 21:39:39 +0000316 fContext->setRenderTarget(fRenderTarget);
317 // we aren't setting the clip or matrix, so mark as dirty
318 // we don't need to set them for this call and don't have them anyway
319 fNeedPrepareRenderTarget = true;
320
321 fContext->writePixels(x, y, bitmap.width(), bitmap.height(),
322 config, bitmap.getPixels(), bitmap.rowBytes());
323}
324
325///////////////////////////////////////////////////////////////////////////////
326
327static void convert_matrixclip(GrContext* context, const SkMatrix& matrix,
bsalomon@google.comd302f142011-03-03 13:54:13 +0000328 const SkClipStack& clipStack,
reed@google.com6f8f2922011-03-04 22:27:10 +0000329 const SkRegion& clipRegion,
330 const SkIPoint& origin) {
bsalomon@google.comcc4dac32011-05-10 13:52:42 +0000331 context->setMatrix(matrix);
reed@google.comac10a2d2010-12-22 21:39:39 +0000332
333 SkGrClipIterator iter;
bsalomon@google.comd302f142011-03-03 13:54:13 +0000334 iter.reset(clipStack);
bsalomon@google.comd302f142011-03-03 13:54:13 +0000335 const SkIRect& skBounds = clipRegion.getBounds();
336 GrRect bounds;
337 bounds.setLTRB(GrIntToScalar(skBounds.fLeft),
338 GrIntToScalar(skBounds.fTop),
339 GrIntToScalar(skBounds.fRight),
340 GrIntToScalar(skBounds.fBottom));
reed@google.com6f8f2922011-03-04 22:27:10 +0000341 GrClip grc(&iter, GrIntToScalar(-origin.x()), GrIntToScalar(-origin.y()),
342 &bounds);
bsalomon@google.comd302f142011-03-03 13:54:13 +0000343 context->setClip(grc);
reed@google.comac10a2d2010-12-22 21:39:39 +0000344}
345
346// call this ever each draw call, to ensure that the context reflects our state,
347// and not the state from some other canvas/device
348void SkGpuDevice::prepareRenderTarget(const SkDraw& draw) {
349 if (fNeedPrepareRenderTarget ||
bsalomon@google.com5782d712011-01-21 21:03:59 +0000350 fContext->getRenderTarget() != fRenderTarget) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000351
352 fContext->setRenderTarget(fRenderTarget);
bsalomon@google.comd302f142011-03-03 13:54:13 +0000353 SkASSERT(draw.fClipStack);
354 convert_matrixclip(fContext, *draw.fMatrix,
reed@google.com6f8f2922011-03-04 22:27:10 +0000355 *draw.fClipStack, *draw.fClip, this->getOrigin());
reed@google.comac10a2d2010-12-22 21:39:39 +0000356 fNeedPrepareRenderTarget = false;
357 }
358}
359
reed@google.com46799cd2011-02-22 20:56:26 +0000360void SkGpuDevice::setMatrixClip(const SkMatrix& matrix, const SkRegion& clip,
361 const SkClipStack& clipStack) {
362 this->INHERITED::setMatrixClip(matrix, clip, clipStack);
bsalomon@google.coma7bf6e22011-04-11 19:20:46 +0000363 // We don't need to set them now because the context may not reflect this device.
364 fNeedPrepareRenderTarget = true;
reed@google.comac10a2d2010-12-22 21:39:39 +0000365}
366
367void SkGpuDevice::gainFocus(SkCanvas* canvas, const SkMatrix& matrix,
bsalomon@google.comd302f142011-03-03 13:54:13 +0000368 const SkRegion& clip, const SkClipStack& clipStack) {
369
reed@google.comac10a2d2010-12-22 21:39:39 +0000370 fContext->setRenderTarget(fRenderTarget);
371
bsalomon@google.comd302f142011-03-03 13:54:13 +0000372 this->INHERITED::gainFocus(canvas, matrix, clip, clipStack);
reed@google.comac10a2d2010-12-22 21:39:39 +0000373
reed@google.com6f8f2922011-03-04 22:27:10 +0000374 convert_matrixclip(fContext, matrix, clipStack, clip, this->getOrigin());
reed@google.comac10a2d2010-12-22 21:39:39 +0000375
376 if (fNeedClear) {
bsalomon@google.com31a58402011-04-27 21:00:02 +0000377 fContext->clear(NULL, 0x0);
reed@google.comac10a2d2010-12-22 21:39:39 +0000378 fNeedClear = false;
379 }
380}
381
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000382bool SkGpuDevice::bindDeviceAsTexture(GrPaint* paint) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000383 if (NULL != fTexture) {
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000384 paint->setTexture(kBitmapTextureIdx, fTexture);
reed@google.comac10a2d2010-12-22 21:39:39 +0000385 return true;
386 }
387 return false;
388}
389
390///////////////////////////////////////////////////////////////////////////////
391
vandebo@chromium.orgd3ae7792011-02-24 00:21:06 +0000392SK_COMPILE_ASSERT(SkShader::kNone_BitmapType == 0, shader_type_mismatch);
393SK_COMPILE_ASSERT(SkShader::kDefault_BitmapType == 1, shader_type_mismatch);
394SK_COMPILE_ASSERT(SkShader::kRadial_BitmapType == 2, shader_type_mismatch);
395SK_COMPILE_ASSERT(SkShader::kSweep_BitmapType == 3, shader_type_mismatch);
396SK_COMPILE_ASSERT(SkShader::kTwoPointRadial_BitmapType == 4,
397 shader_type_mismatch);
398SK_COMPILE_ASSERT(SkShader::kLast_BitmapType == 4, shader_type_mismatch);
reed@google.comac10a2d2010-12-22 21:39:39 +0000399
bsalomon@google.com5782d712011-01-21 21:03:59 +0000400static const GrSamplerState::SampleMode sk_bmp_type_to_sample_mode[] = {
401 (GrSamplerState::SampleMode) -1, // kNone_BitmapType
402 GrSamplerState::kNormal_SampleMode, // kDefault_BitmapType
403 GrSamplerState::kRadial_SampleMode, // kRadial_BitmapType
404 GrSamplerState::kSweep_SampleMode, // kSweep_BitmapType
405 GrSamplerState::kRadial2_SampleMode, // kTwoPointRadial_BitmapType
406};
407
408bool SkGpuDevice::skPaint2GrPaintNoShader(const SkPaint& skPaint,
409 bool justAlpha,
Scroggod757df22011-05-16 13:11:16 +0000410 GrPaint* grPaint,
411 bool constantColor) {
bsalomon@google.com5782d712011-01-21 21:03:59 +0000412
413 grPaint->fDither = skPaint.isDither();
414 grPaint->fAntiAlias = skPaint.isAntiAlias();
415
416 SkXfermode::Coeff sm = SkXfermode::kOne_Coeff;
417 SkXfermode::Coeff dm = SkXfermode::kISA_Coeff;
418
419 SkXfermode* mode = skPaint.getXfermode();
420 if (mode) {
421 if (!mode->asCoeff(&sm, &dm)) {
reed@google.com1a2e8d22011-01-21 22:08:29 +0000422 SkDEBUGCODE(SkDebugf("Unsupported xfer mode.\n");)
bsalomon@google.com5782d712011-01-21 21:03:59 +0000423#if 0
424 return false;
425#endif
426 }
427 }
428 grPaint->fSrcBlendCoeff = sk_blend_to_grblend(sm);
429 grPaint->fDstBlendCoeff = sk_blend_to_grblend(dm);
430
431 if (justAlpha) {
432 uint8_t alpha = skPaint.getAlpha();
433 grPaint->fColor = GrColorPackRGBA(alpha, alpha, alpha, alpha);
Scroggod757df22011-05-16 13:11:16 +0000434 // justAlpha is currently set to true only if there is a texture,
435 // so constantColor should not also be true.
436 GrAssert(!constantColor);
bsalomon@google.com5782d712011-01-21 21:03:59 +0000437 } else {
438 grPaint->fColor = SkGr::SkColor2GrColor(skPaint.getColor());
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000439 grPaint->setTexture(kShaderTextureIdx, NULL);
bsalomon@google.com5782d712011-01-21 21:03:59 +0000440 }
Scroggo97c88c22011-05-11 14:05:25 +0000441 SkColorFilter* colorFilter = skPaint.getColorFilter();
442 SkColor color;
443 SkXfermode::Mode filterMode;
444 if (colorFilter != NULL && colorFilter->asColorMode(&color, &filterMode)) {
Scroggod757df22011-05-16 13:11:16 +0000445 if (!constantColor) {
446 grPaint->fColorFilterColor = SkGr::SkColor2GrColor(color);
447 grPaint->fColorFilterXfermode = filterMode;
448 return true;
449 }
450 SkColor filtered = colorFilter->filterColor(skPaint.getColor());
451 grPaint->fColor = SkGr::SkColor2GrColor(filtered);
Scroggo97c88c22011-05-11 14:05:25 +0000452 }
Scroggod757df22011-05-16 13:11:16 +0000453 grPaint->resetColorFilter();
bsalomon@google.com5782d712011-01-21 21:03:59 +0000454 return true;
reed@google.comac10a2d2010-12-22 21:39:39 +0000455}
456
bsalomon@google.com5782d712011-01-21 21:03:59 +0000457bool SkGpuDevice::skPaint2GrPaintShader(const SkPaint& skPaint,
458 SkAutoCachedTexture* act,
459 const SkMatrix& ctm,
Scroggod757df22011-05-16 13:11:16 +0000460 GrPaint* grPaint,
461 bool constantColor) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000462
bsalomon@google.com5782d712011-01-21 21:03:59 +0000463 SkASSERT(NULL != act);
reed@google.comac10a2d2010-12-22 21:39:39 +0000464
bsalomon@google.com5782d712011-01-21 21:03:59 +0000465 SkShader* shader = skPaint.getShader();
reed@google.comac10a2d2010-12-22 21:39:39 +0000466 if (NULL == shader) {
Scroggod757df22011-05-16 13:11:16 +0000467 return this->skPaint2GrPaintNoShader(skPaint,
468 false,
469 grPaint,
470 constantColor);
471 } else if (!this->skPaint2GrPaintNoShader(skPaint, true, grPaint, false)) {
bsalomon@google.com5782d712011-01-21 21:03:59 +0000472 return false;
reed@google.comac10a2d2010-12-22 21:39:39 +0000473 }
474
reed@google.comac10a2d2010-12-22 21:39:39 +0000475 SkBitmap bitmap;
476 SkMatrix matrix;
477 SkShader::TileMode tileModes[2];
478 SkScalar twoPointParams[3];
479 SkShader::BitmapType bmptype = shader->asABitmap(&bitmap, &matrix,
480 tileModes, twoPointParams);
481
bsalomon@google.com5782d712011-01-21 21:03:59 +0000482 GrSamplerState::SampleMode sampleMode = sk_bmp_type_to_sample_mode[bmptype];
483 if (-1 == sampleMode) {
reed@google.com2be9e8b2011-07-06 21:18:09 +0000484 SkShader::GradientInfo info;
485 SkColor color;
486
487 info.fColors = &color;
488 info.fColorOffsets = NULL;
489 info.fColorCount = 1;
490 if (SkShader::kColor_GradientType == shader->asAGradient(&info)) {
491 SkPaint copy(skPaint);
492 copy.setShader(NULL);
bsalomon@google.comcd9cfd72011-07-08 16:55:04 +0000493 // modulate the paint alpha by the shader's solid color alpha
494 U8CPU newA = SkMulDiv255Round(SkColorGetA(color), copy.getAlpha());
495 copy.setColor(SkColorSetA(color, newA));
reed@google.com2be9e8b2011-07-06 21:18:09 +0000496 return this->skPaint2GrPaintNoShader(copy,
497 false,
498 grPaint,
499 constantColor);
500 }
bsalomon@google.com5782d712011-01-21 21:03:59 +0000501 return false;
reed@google.comac10a2d2010-12-22 21:39:39 +0000502 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000503 GrSamplerState* sampler = grPaint->getTextureSampler(kShaderTextureIdx);
504 sampler->setSampleMode(sampleMode);
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000505 if (skPaint.isFilterBitmap()) {
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000506 sampler->setFilter(GrSamplerState::kBilinear_Filter);
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000507 } else {
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000508 sampler->setFilter(GrSamplerState::kNearest_Filter);
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000509 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000510 sampler->setWrapX(sk_tile_mode_to_grwrap(tileModes[0]));
511 sampler->setWrapY(sk_tile_mode_to_grwrap(tileModes[1]));
reed@google.comac10a2d2010-12-22 21:39:39 +0000512 if (GrSamplerState::kRadial2_SampleMode == sampleMode) {
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000513 sampler->setRadial2Params(twoPointParams[0],
514 twoPointParams[1],
515 twoPointParams[2] < 0);
reed@google.comac10a2d2010-12-22 21:39:39 +0000516 }
517
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000518 GrTexture* texture = act->set(this, bitmap, *sampler);
reed@google.comac10a2d2010-12-22 21:39:39 +0000519 if (NULL == texture) {
bsalomon@google.com5782d712011-01-21 21:03:59 +0000520 SkDebugf("Couldn't convert bitmap to texture.\n");
521 return false;
reed@google.comac10a2d2010-12-22 21:39:39 +0000522 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000523 grPaint->setTexture(kShaderTextureIdx, texture);
reed@google.comac10a2d2010-12-22 21:39:39 +0000524
525 // since our texture coords will be in local space, we wack the texture
526 // matrix to map them back into 0...1 before we load it
527 SkMatrix localM;
528 if (shader->getLocalMatrix(&localM)) {
529 SkMatrix inverse;
530 if (localM.invert(&inverse)) {
531 matrix.preConcat(inverse);
532 }
533 }
534 if (SkShader::kDefault_BitmapType == bmptype) {
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000535 GrScalar sx = GrFixedToScalar(GR_Fixed1 / bitmap.width());
536 GrScalar sy = GrFixedToScalar(GR_Fixed1 / bitmap.height());
reed@google.comac10a2d2010-12-22 21:39:39 +0000537 matrix.postScale(sx, sy);
reed@google.comac10a2d2010-12-22 21:39:39 +0000538 } else if (SkShader::kRadial_BitmapType == bmptype) {
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000539 GrScalar s = GrFixedToScalar(GR_Fixed1 / bitmap.width());
reed@google.comac10a2d2010-12-22 21:39:39 +0000540 matrix.postScale(s, s);
541 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000542 sampler->setMatrix(matrix);
bsalomon@google.com5782d712011-01-21 21:03:59 +0000543
544 return true;
reed@google.comac10a2d2010-12-22 21:39:39 +0000545}
546
547///////////////////////////////////////////////////////////////////////////////
bsalomon@google.com5782d712011-01-21 21:03:59 +0000548
549class SkPositionSource {
550public:
551 SkPositionSource(const SkPoint* points, int count)
552 : fPoints(points), fCount(count) {}
553
554 int count() const { return fCount; }
555
556 void writeValue(int i, GrPoint* dstPosition) const {
557 SkASSERT(i < fCount);
558 dstPosition->fX = SkScalarToGrScalar(fPoints[i].fX);
559 dstPosition->fY = SkScalarToGrScalar(fPoints[i].fY);
560 }
561private:
bsalomon@google.com5782d712011-01-21 21:03:59 +0000562 const SkPoint* fPoints;
bsalomon@google.com19628322011-02-03 21:30:17 +0000563 int fCount;
bsalomon@google.com5782d712011-01-21 21:03:59 +0000564};
565
566class SkTexCoordSource {
567public:
568 SkTexCoordSource(const SkPoint* coords)
569 : fCoords(coords) {}
570
571 void writeValue(int i, GrPoint* dstCoord) const {
572 dstCoord->fX = SkScalarToGrScalar(fCoords[i].fX);
573 dstCoord->fY = SkScalarToGrScalar(fCoords[i].fY);
574 }
575private:
576 const SkPoint* fCoords;
577};
578
579class SkColorSource {
580public:
581 SkColorSource(const SkColor* colors) : fColors(colors) {}
582
583 void writeValue(int i, GrColor* dstColor) const {
584 *dstColor = SkGr::SkColor2GrColor(fColors[i]);
585 }
586private:
587 const SkColor* fColors;
588};
589
590class SkIndexSource {
591public:
592 SkIndexSource(const uint16_t* indices, int count)
593 : fIndices(indices), fCount(count) {
594 }
595
596 int count() const { return fCount; }
597
598 void writeValue(int i, uint16_t* dstIndex) const {
599 *dstIndex = fIndices[i];
600 }
601
602private:
bsalomon@google.com5782d712011-01-21 21:03:59 +0000603 const uint16_t* fIndices;
bsalomon@google.com19628322011-02-03 21:30:17 +0000604 int fCount;
bsalomon@google.com5782d712011-01-21 21:03:59 +0000605};
606
607///////////////////////////////////////////////////////////////////////////////
608
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000609#if 0 // not currently being used so don't compile,
610
bsalomon@google.com5782d712011-01-21 21:03:59 +0000611// can be used for positions or texture coordinates
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000612
bsalomon@google.com5782d712011-01-21 21:03:59 +0000613class SkRectFanSource {
614public:
615 SkRectFanSource(const SkRect& rect) : fRect(rect) {}
616
617 int count() const { return 4; }
618
619 void writeValue(int i, GrPoint* dstPoint) const {
620 SkASSERT(i < 4);
621 dstPoint->fX = SkScalarToGrScalar((i % 3) ? fRect.fRight :
622 fRect.fLeft);
623 dstPoint->fY = SkScalarToGrScalar((i < 2) ? fRect.fTop :
624 fRect.fBottom);
625 }
626private:
627 const SkRect& fRect;
628};
629
630class SkIRectFanSource {
631public:
632 SkIRectFanSource(const SkIRect& rect) : fRect(rect) {}
633
634 int count() const { return 4; }
635
636 void writeValue(int i, GrPoint* dstPoint) const {
637 SkASSERT(i < 4);
638 dstPoint->fX = (i % 3) ? GrIntToScalar(fRect.fRight) :
639 GrIntToScalar(fRect.fLeft);
640 dstPoint->fY = (i < 2) ? GrIntToScalar(fRect.fTop) :
641 GrIntToScalar(fRect.fBottom);
642 }
643private:
644 const SkIRect& fRect;
645};
646
647class SkMatRectFanSource {
648public:
649 SkMatRectFanSource(const SkRect& rect, const SkMatrix& matrix)
650 : fRect(rect), fMatrix(matrix) {}
651
652 int count() const { return 4; }
653
654 void writeValue(int i, GrPoint* dstPoint) const {
655 SkASSERT(i < 4);
656
657#if SK_SCALAR_IS_GR_SCALAR
658 fMatrix.mapXY((i % 3) ? fRect.fRight : fRect.fLeft,
659 (i < 2) ? fRect.fTop : fRect.fBottom,
660 (SkPoint*)dstPoint);
661#else
662 SkPoint dst;
663 fMatrix.mapXY((i % 3) ? fRect.fRight : fRect.fLeft,
664 (i < 2) ? fRect.fTop : fRect.fBottom,
665 &dst);
666 dstPoint->fX = SkScalarToGrScalar(dst.fX);
667 dstPoint->fY = SkScalarToGrScalar(dst.fY);
668#endif
669 }
670private:
671 const SkRect& fRect;
672 const SkMatrix& fMatrix;
673};
674
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000675#endif
676
reed@google.comac10a2d2010-12-22 21:39:39 +0000677///////////////////////////////////////////////////////////////////////////////
678
bsalomon@google.com398109c2011-04-14 18:40:27 +0000679void SkGpuDevice::clear(SkColor color) {
bsalomon@google.com31a58402011-04-27 21:00:02 +0000680 fContext->clear(NULL, color);
bsalomon@google.com398109c2011-04-14 18:40:27 +0000681}
682
reed@google.comac10a2d2010-12-22 21:39:39 +0000683void SkGpuDevice::drawPaint(const SkDraw& draw, const SkPaint& paint) {
684 CHECK_SHOULD_DRAW(draw);
685
bsalomon@google.com5782d712011-01-21 21:03:59 +0000686 GrPaint grPaint;
687 SkAutoCachedTexture act;
Scroggod757df22011-05-16 13:11:16 +0000688 if (!this->skPaint2GrPaintShader(paint,
689 &act,
690 *draw.fMatrix,
691 &grPaint,
692 true)) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000693 return;
694 }
bsalomon@google.com5782d712011-01-21 21:03:59 +0000695
696 fContext->drawPaint(grPaint);
reed@google.comac10a2d2010-12-22 21:39:39 +0000697}
698
699// must be in SkCanvas::PointMode order
bsalomon@google.comffca4002011-02-22 20:34:01 +0000700static const GrPrimitiveType gPointMode2PrimtiveType[] = {
701 kPoints_PrimitiveType,
702 kLines_PrimitiveType,
703 kLineStrip_PrimitiveType
reed@google.comac10a2d2010-12-22 21:39:39 +0000704};
705
706void SkGpuDevice::drawPoints(const SkDraw& draw, SkCanvas::PointMode mode,
bsalomon@google.com5782d712011-01-21 21:03:59 +0000707 size_t count, const SkPoint pts[], const SkPaint& paint) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000708 CHECK_SHOULD_DRAW(draw);
709
710 SkScalar width = paint.getStrokeWidth();
711 if (width < 0) {
712 return;
713 }
714
715 // we only handle hairlines here, else we let the SkDraw call our drawPath()
716 if (width > 0) {
717 draw.drawPoints(mode, count, pts, paint, true);
718 return;
719 }
720
bsalomon@google.com5782d712011-01-21 21:03:59 +0000721 GrPaint grPaint;
722 SkAutoCachedTexture act;
Scroggod757df22011-05-16 13:11:16 +0000723 if (!this->skPaint2GrPaintShader(paint,
724 &act,
725 *draw.fMatrix,
726 &grPaint,
727 true)) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000728 return;
729 }
730
reed@google.comac10a2d2010-12-22 21:39:39 +0000731#if SK_SCALAR_IS_GR_SCALAR
bsalomon@google.com5782d712011-01-21 21:03:59 +0000732 fContext->drawVertices(grPaint,
733 gPointMode2PrimtiveType[mode],
734 count,
735 (GrPoint*)pts,
736 NULL,
737 NULL,
738 NULL,
739 0);
reed@google.comac10a2d2010-12-22 21:39:39 +0000740#else
bsalomon@google.com5782d712011-01-21 21:03:59 +0000741 fContext->drawCustomVertices(grPaint,
742 gPointMode2PrimtiveType[mode],
743 SkPositionSource(pts, count));
reed@google.comac10a2d2010-12-22 21:39:39 +0000744#endif
reed@google.comac10a2d2010-12-22 21:39:39 +0000745}
746
reed@google.comc9aa5872011-04-05 21:05:37 +0000747///////////////////////////////////////////////////////////////////////////////
748
reed@google.comac10a2d2010-12-22 21:39:39 +0000749void SkGpuDevice::drawRect(const SkDraw& draw, const SkRect& rect,
750 const SkPaint& paint) {
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000751 CHECK_SHOULD_DRAW(draw);
752
bungeman@google.com79bd8772011-07-18 15:34:08 +0000753 bool doStroke = paint.getStyle() != SkPaint::kFill_Style;
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000754 SkScalar width = paint.getStrokeWidth();
755
756 /*
757 We have special code for hairline strokes, miter-strokes, and fills.
758 Anything else we just call our path code.
759 */
760 bool usePath = doStroke && width > 0 &&
761 paint.getStrokeJoin() != SkPaint::kMiter_Join;
762 // another reason we might need to call drawPath...
763 if (paint.getMaskFilter()) {
764 usePath = true;
765 }
reed@google.com67db6642011-05-26 11:46:35 +0000766 // until we aa rotated rects...
767 if (!usePath && paint.isAntiAlias() && !draw.fMatrix->rectStaysRect()) {
768 usePath = true;
769 }
bungeman@google.com79bd8772011-07-18 15:34:08 +0000770 // until we can both stroke and fill rectangles
771 // with large enough miter limit...
772 if (paint.getStyle() == SkPaint::kStrokeAndFill_Style) {
773 usePath = true;
774 }
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000775
776 if (usePath) {
777 SkPath path;
778 path.addRect(rect);
779 this->drawPath(draw, path, paint, NULL, true);
780 return;
781 }
782
783 GrPaint grPaint;
784 SkAutoCachedTexture act;
Scroggod757df22011-05-16 13:11:16 +0000785 if (!this->skPaint2GrPaintShader(paint,
786 &act,
787 *draw.fMatrix,
788 &grPaint,
789 true)) {
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000790 return;
791 }
reed@google.com20efde72011-05-09 17:00:02 +0000792 fContext->drawRect(grPaint, rect, doStroke ? width : -1);
reed@google.comac10a2d2010-12-22 21:39:39 +0000793}
794
reed@google.com69302852011-02-16 18:08:07 +0000795#include "SkMaskFilter.h"
796#include "SkBounder.h"
797
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +0000798static GrPathFill skToGrFillType(SkPath::FillType fillType) {
799 switch (fillType) {
800 case SkPath::kWinding_FillType:
801 return kWinding_PathFill;
802 case SkPath::kEvenOdd_FillType:
803 return kEvenOdd_PathFill;
804 case SkPath::kInverseWinding_FillType:
805 return kInverseWinding_PathFill;
806 case SkPath::kInverseEvenOdd_FillType:
807 return kInverseEvenOdd_PathFill;
808 default:
809 SkDebugf("Unsupported path fill type\n");
810 return kHairLine_PathFill;
811 }
812}
813
senorblanco@chromium.orgb08ea1b2011-07-12 16:54:59 +0000814static void buildKernel(float sigma, float* kernel, int kernelWidth) {
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +0000815 int halfWidth = (kernelWidth - 1) / 2;
816 float sum = 0.0f;
senorblanco@chromium.orgb08ea1b2011-07-12 16:54:59 +0000817 float denom = 1.0f / (2.0f * sigma * sigma);
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +0000818 for (int i = 0; i < kernelWidth; ++i) {
senorblanco@chromium.orgb08ea1b2011-07-12 16:54:59 +0000819 float x = static_cast<float>(i - halfWidth);
820 // Note that the constant term (1/(sqrt(2*pi*sigma^2)) of the Gaussian
821 // is dropped here, since we renormalize the kernel below.
822 kernel[i] = sk_float_exp(- x * x * denom);
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +0000823 sum += kernel[i];
824 }
825 // Normalize the kernel
826 float scale = 1.0f / sum;
827 for (int i = 0; i < kernelWidth; ++i)
828 kernel[i] *= scale;
829}
830
senorblanco@chromium.orgb08ea1b2011-07-12 16:54:59 +0000831static void scaleRect(SkRect* rect, float scale) {
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +0000832 rect->fLeft *= scale;
833 rect->fTop *= scale;
834 rect->fRight *= scale;
835 rect->fBottom *= scale;
836}
837
838static bool drawWithGPUMaskFilter(GrContext* context, const SkPath& path,
839 SkMaskFilter* filter, const SkMatrix& matrix,
840 const SkRegion& clip, SkBounder* bounder,
841 GrPaint* grp) {
senorblanco@chromium.orga479fc72011-07-19 16:40:58 +0000842#ifdef SK_DISABLE_GPU_BLUR
senorblanco@chromium.orgaadd9f82011-07-12 19:44:51 +0000843 return false;
senorblanco@chromium.orgb08ea1b2011-07-12 16:54:59 +0000844#endif
senorblanco@chromium.orgaadd9f82011-07-12 19:44:51 +0000845 SkMaskFilter::BlurInfo info;
846 SkMaskFilter::BlurType blurType = filter->asABlur(&info);
senorblanco@chromium.orgb08ea1b2011-07-12 16:54:59 +0000847 if (SkMaskFilter::kNone_BlurType == blurType) {
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +0000848 return false;
849 }
senorblanco@chromium.orge36ddf02011-07-15 14:28:16 +0000850 SkScalar radius = info.fIgnoreTransform ? info.fRadius
851 : matrix.mapRadius(info.fRadius);
852 radius = SkMinScalar(radius, MAX_BLUR_RADIUS);
853 float sigma = SkScalarToFloat(radius) * BLUR_SIGMA_SCALE;
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +0000854 SkRect srcRect = path.getBounds();
855
856 int scaleFactor = 1;
857
senorblanco@chromium.orge36ddf02011-07-15 14:28:16 +0000858 while (sigma > MAX_BLUR_SIGMA) {
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +0000859 scaleFactor *= 2;
860 sigma *= 0.5f;
861 }
862 scaleRect(&srcRect, 1.0f / scaleFactor);
senorblanco@chromium.org4a947d22011-07-18 21:48:35 +0000863 int halfWidth = static_cast<int>(ceilf(sigma * 3.0f));
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +0000864 int kernelWidth = halfWidth * 2 + 1;
865
866 SkIRect srcIRect;
867 srcRect.roundOut(&srcIRect);
868 srcRect.set(srcIRect);
869 srcRect.inset(-halfWidth, -halfWidth);
870
871 scaleRect(&srcRect, scaleFactor);
872 SkRect finalRect = srcRect;
873
874 SkIRect finalIRect;
875 finalRect.roundOut(&finalIRect);
876 if (clip.quickReject(finalIRect)) {
senorblanco@chromium.orgaadd9f82011-07-12 19:44:51 +0000877 return true;
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +0000878 }
879 if (bounder && !bounder->doIRect(finalIRect)) {
senorblanco@chromium.orgaadd9f82011-07-12 19:44:51 +0000880 return true;
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +0000881 }
882 GrPoint offset = GrPoint::Make(-srcRect.fLeft, -srcRect.fTop);
883 srcRect.offset(-srcRect.fLeft, -srcRect.fTop);
884 const GrTextureDesc desc = {
885 kRenderTarget_GrTextureFlagBit,
886 kNone_GrAALevel,
887 srcRect.width(),
888 srcRect.height(),
889 // We actually only need A8, but it often isn't supported as a
890 // render target
891 kRGBA_8888_GrPixelConfig
892 };
893
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000894 GrAutoScratchTexture srcEntry(context, desc);
895 GrAutoScratchTexture dstEntry(context, desc);
896 if (NULL == srcEntry.texture() || NULL == dstEntry.texture()) {
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +0000897 return false;
898 }
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000899 GrTexture* srcTexture = srcEntry.texture();
900 GrTexture* dstTexture = dstEntry.texture();
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +0000901 if (NULL == srcTexture || NULL == dstTexture) {
902 return false;
903 }
904 GrRenderTarget* oldRenderTarget = context->getRenderTarget();
senorblanco@chromium.org42dd0f92011-07-14 15:29:57 +0000905 // Once this code moves into GrContext, this should be changed to use
906 // an AutoClipRestore.
907 GrClip oldClip = context->getClip();
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +0000908 context->setRenderTarget(dstTexture->asRenderTarget());
senorblanco@chromium.org42dd0f92011-07-14 15:29:57 +0000909 context->setClip(srcRect);
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +0000910 context->clear(NULL, 0);
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +0000911 GrPaint tempPaint;
912 tempPaint.reset();
913
914 GrAutoMatrix avm(context, GrMatrix::I());
senorblanco@chromium.orgb08ea1b2011-07-12 16:54:59 +0000915 tempPaint.fAntiAlias = grp->fAntiAlias;
916 if (tempPaint.fAntiAlias) {
917 // AA uses the "coverage" stages on GrDrawTarget. Coverage with a dst
918 // blend coeff of zero requires dual source blending support in order
919 // to properly blend partially covered pixels. This means the AA
920 // code path may not be taken. So we use a dst blend coeff of ISA. We
921 // could special case AA draws to a dst surface with known alpha=0 to
922 // use a zero dst coeff when dual source blending isn't available.
923 tempPaint.fSrcBlendCoeff = kOne_BlendCoeff;
924 tempPaint.fDstBlendCoeff = kISC_BlendCoeff;
925 }
926 // Draw hard shadow to dstTexture with path topleft at origin 0,0.
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +0000927 context->drawPath(tempPaint, path, skToGrFillType(path.getFillType()), &offset);
senorblanco@chromium.orgb08ea1b2011-07-12 16:54:59 +0000928 SkTSwap(srcTexture, dstTexture);
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +0000929
930 GrMatrix sampleM;
senorblanco@chromium.org422b67d2011-07-19 21:22:13 +0000931 sampleM.setIDiv(srcTexture->width(), srcTexture->height());
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +0000932 GrPaint paint;
933 paint.reset();
934 paint.getTextureSampler(0)->setFilter(GrSamplerState::kBilinear_Filter);
935 paint.getTextureSampler(0)->setMatrix(sampleM);
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000936 GrAutoScratchTexture origEntry;
937
senorblanco@chromium.orgb08ea1b2011-07-12 16:54:59 +0000938 if (blurType != SkMaskFilter::kNormal_BlurType) {
939 // Stash away a copy of the unblurred image.
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000940 origEntry.set(context, desc);
941 if (NULL == origEntry.texture()) {
senorblanco@chromium.orgb08ea1b2011-07-12 16:54:59 +0000942 return false;
943 }
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000944 context->setRenderTarget(origEntry.texture()->asRenderTarget());
senorblanco@chromium.orgb08ea1b2011-07-12 16:54:59 +0000945 paint.setTexture(0, srcTexture);
946 context->drawRect(paint, srcRect);
947 }
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +0000948 for (int i = 1; i < scaleFactor; i *= 2) {
senorblanco@chromium.org422b67d2011-07-19 21:22:13 +0000949 sampleM.setIDiv(srcTexture->width(), srcTexture->height());
950 paint.getTextureSampler(0)->setMatrix(sampleM);
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +0000951 context->setRenderTarget(dstTexture->asRenderTarget());
952 SkRect dstRect(srcRect);
953 scaleRect(&dstRect, 0.5f);
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +0000954 paint.setTexture(0, srcTexture);
955 context->drawRectToRect(paint, dstRect, srcRect);
956 srcRect = dstRect;
senorblanco@chromium.orgb08ea1b2011-07-12 16:54:59 +0000957 SkTSwap(srcTexture, dstTexture);
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +0000958 }
959
960 SkAutoTMalloc<float> kernelStorage(kernelWidth);
961 float* kernel = kernelStorage.get();
962 buildKernel(sigma, kernel, kernelWidth);
963
senorblanco@chromium.org2ce9a042011-07-22 15:31:14 +0000964 // Clear out a halfWidth to the right of the srcRect to prevent the
965 // X convolution from reading garbage.
966 SkIRect clearRect = SkIRect::MakeXYWH(
967 srcRect.fRight, srcRect.fTop, halfWidth, srcRect.height());
968 context->clear(&clearRect, 0x0);
969
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +0000970 context->setRenderTarget(dstTexture->asRenderTarget());
senorblanco@chromium.orgaadd9f82011-07-12 19:44:51 +0000971 context->convolveInX(srcTexture, srcRect, kernel, kernelWidth);
senorblanco@chromium.orgb08ea1b2011-07-12 16:54:59 +0000972 SkTSwap(srcTexture, dstTexture);
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +0000973
senorblanco@chromium.org2ce9a042011-07-22 15:31:14 +0000974 // Clear out a halfWidth below the srcRect to prevent the Y
975 // convolution from reading garbage.
976 clearRect = SkIRect::MakeXYWH(
977 srcRect.fLeft, srcRect.fBottom, srcRect.width(), halfWidth);
978 context->clear(&clearRect, 0x0);
979
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +0000980 context->setRenderTarget(dstTexture->asRenderTarget());
senorblanco@chromium.orgaadd9f82011-07-12 19:44:51 +0000981 context->convolveInY(srcTexture, srcRect, kernel, kernelWidth);
senorblanco@chromium.orgb08ea1b2011-07-12 16:54:59 +0000982 SkTSwap(srcTexture, dstTexture);
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +0000983
senorblanco@chromium.org2ce9a042011-07-22 15:31:14 +0000984 // Clear one pixel to the right and below, to accommodate bilinear
985 // upsampling.
986 clearRect = SkIRect::MakeXYWH(
987 srcRect.fLeft, srcRect.fBottom, srcRect.width() + 1, 1);
988 context->clear(&clearRect, 0x0);
989 clearRect = SkIRect::MakeXYWH(
990 srcRect.fRight, srcRect.fTop, 1, srcRect.height());
991 context->clear(&clearRect, 0x0);
992
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +0000993 if (scaleFactor > 1) {
994 // FIXME: This should be mitchell, not bilinear.
995 paint.getTextureSampler(0)->setFilter(GrSamplerState::kBilinear_Filter);
senorblanco@chromium.org422b67d2011-07-19 21:22:13 +0000996 sampleM.setIDiv(srcTexture->width(), srcTexture->height());
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +0000997 paint.getTextureSampler(0)->setMatrix(sampleM);
998 context->setRenderTarget(dstTexture->asRenderTarget());
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +0000999 paint.setTexture(0, srcTexture);
1000 SkRect dstRect(srcRect);
1001 scaleRect(&dstRect, scaleFactor);
1002 context->drawRectToRect(paint, dstRect, srcRect);
1003 srcRect = dstRect;
senorblanco@chromium.orgb08ea1b2011-07-12 16:54:59 +00001004 SkTSwap(srcTexture, dstTexture);
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +00001005 }
1006
senorblanco@chromium.orgb08ea1b2011-07-12 16:54:59 +00001007 if (blurType != SkMaskFilter::kNormal_BlurType) {
bsalomon@google.com50398bf2011-07-26 20:45:30 +00001008 GrTexture* origTexture = origEntry.texture();
senorblanco@chromium.orgb08ea1b2011-07-12 16:54:59 +00001009 paint.getTextureSampler(0)->setFilter(GrSamplerState::kNearest_Filter);
senorblanco@chromium.org422b67d2011-07-19 21:22:13 +00001010 sampleM.setIDiv(origTexture->width(), origTexture->height());
senorblanco@chromium.orgb08ea1b2011-07-12 16:54:59 +00001011 paint.getTextureSampler(0)->setMatrix(sampleM);
1012 // Blend origTexture over srcTexture.
1013 context->setRenderTarget(srcTexture->asRenderTarget());
1014 paint.setTexture(0, origTexture);
1015 if (SkMaskFilter::kInner_BlurType == blurType) {
1016 // inner: dst = dst * src
1017 paint.fSrcBlendCoeff = kDC_BlendCoeff;
1018 paint.fDstBlendCoeff = kZero_BlendCoeff;
1019 } else if (SkMaskFilter::kSolid_BlurType == blurType) {
1020 // solid: dst = src + dst - src * dst
1021 // = (1 - dst) * src + 1 * dst
1022 paint.fSrcBlendCoeff = kIDC_BlendCoeff;
1023 paint.fDstBlendCoeff = kOne_BlendCoeff;
1024 } else if (SkMaskFilter::kOuter_BlurType == blurType) {
1025 // outer: dst = dst * (1 - src)
1026 // = 0 * src + (1 - src) * dst
1027 paint.fSrcBlendCoeff = kZero_BlendCoeff;
1028 paint.fDstBlendCoeff = kISC_BlendCoeff;
1029 }
1030 context->drawRect(paint, srcRect);
1031 }
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +00001032 context->setRenderTarget(oldRenderTarget);
senorblanco@chromium.org42dd0f92011-07-14 15:29:57 +00001033 context->setClip(oldClip);
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +00001034
1035 if (grp->hasTextureOrMask()) {
1036 GrMatrix inverse;
1037 if (!matrix.invert(&inverse)) {
1038 return false;
1039 }
1040 grp->preConcatActiveSamplerMatrices(inverse);
1041 }
1042
1043 static const int MASK_IDX = GrPaint::kMaxMasks - 1;
1044 // we assume the last mask index is available for use
1045 GrAssert(NULL == grp->getMask(MASK_IDX));
1046 grp->setMask(MASK_IDX, srcTexture);
1047 grp->getMaskSampler(MASK_IDX)->setClampNoFilter();
1048
1049 GrMatrix m;
1050 m.setTranslate(-finalRect.fLeft, -finalRect.fTop);
1051 m.postIDiv(srcTexture->width(), srcTexture->height());
1052 grp->getMaskSampler(MASK_IDX)->setMatrix(m);
1053 context->drawRect(*grp, finalRect);
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +00001054 return true;
1055}
1056
reed@google.com69302852011-02-16 18:08:07 +00001057static bool drawWithMaskFilter(GrContext* context, const SkPath& path,
1058 SkMaskFilter* filter, const SkMatrix& matrix,
1059 const SkRegion& clip, SkBounder* bounder,
1060 GrPaint* grp) {
1061 SkMask srcM, dstM;
1062
1063 if (!SkDraw::DrawToMask(path, &clip.getBounds(), filter, &matrix, &srcM,
1064 SkMask::kComputeBoundsAndRenderImage_CreateMode)) {
1065 return false;
1066 }
1067
1068 SkAutoMaskImage autoSrc(&srcM, false);
1069
1070 if (!filter->filterMask(&dstM, srcM, matrix, NULL)) {
1071 return false;
1072 }
1073 // this will free-up dstM when we're done (allocated in filterMask())
1074 SkAutoMaskImage autoDst(&dstM, false);
1075
1076 if (clip.quickReject(dstM.fBounds)) {
1077 return false;
1078 }
1079 if (bounder && !bounder->doIRect(dstM.fBounds)) {
1080 return false;
1081 }
1082
1083 // we now have a device-aligned 8bit mask in dstM, ready to be drawn using
1084 // the current clip (and identity matrix) and grpaint settings
1085
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001086 // used to compute inverse view, if necessary
1087 GrMatrix ivm = context->getMatrix();
1088
reed@google.com0c219b62011-02-16 21:31:18 +00001089 GrAutoMatrix avm(context, GrMatrix::I());
reed@google.com69302852011-02-16 18:08:07 +00001090
bsalomon@google.comfea37b52011-04-25 15:51:06 +00001091 const GrTextureDesc desc = {
1092 kNone_GrTextureFlags,
1093 kNone_GrAALevel,
reed@google.com69302852011-02-16 18:08:07 +00001094 dstM.fBounds.width(),
1095 dstM.fBounds.height(),
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001096 kAlpha_8_GrPixelConfig
reed@google.com69302852011-02-16 18:08:07 +00001097 };
1098
bsalomon@google.com50398bf2011-07-26 20:45:30 +00001099 GrAutoScratchTexture ast(context, desc);
1100 GrTexture* texture = ast.texture();
bsalomon@google.comeb2aa1d2011-07-14 15:45:19 +00001101
reed@google.com69302852011-02-16 18:08:07 +00001102 if (NULL == texture) {
1103 return false;
1104 }
bsalomon@google.comeb2aa1d2011-07-14 15:45:19 +00001105 texture->uploadTextureData(0, 0, desc.fWidth, desc.fHeight,
1106 dstM.fImage, dstM.fRowBytes);
reed@google.com69302852011-02-16 18:08:07 +00001107
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001108 if (grp->hasTextureOrMask() && ivm.invert(&ivm)) {
1109 grp->preConcatActiveSamplerMatrices(ivm);
1110 }
1111
1112 static const int MASK_IDX = GrPaint::kMaxMasks - 1;
1113 // we assume the last mask index is available for use
1114 GrAssert(NULL == grp->getMask(MASK_IDX));
1115 grp->setMask(MASK_IDX, texture);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001116 grp->getMaskSampler(MASK_IDX)->setClampNoFilter();
reed@google.com69302852011-02-16 18:08:07 +00001117
bsalomon@google.comc6cf7232011-02-17 16:43:10 +00001118 GrRect d;
1119 d.setLTRB(GrIntToScalar(dstM.fBounds.fLeft),
reed@google.com0c219b62011-02-16 21:31:18 +00001120 GrIntToScalar(dstM.fBounds.fTop),
1121 GrIntToScalar(dstM.fBounds.fRight),
1122 GrIntToScalar(dstM.fBounds.fBottom));
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001123
1124 GrMatrix m;
1125 m.setTranslate(-dstM.fBounds.fLeft, -dstM.fBounds.fTop);
bsalomon@google.comeb2aa1d2011-07-14 15:45:19 +00001126 m.postIDiv(texture->width(), texture->height());
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001127 grp->getMaskSampler(MASK_IDX)->setMatrix(m);
1128
1129 context->drawRect(*grp, d);
reed@google.com69302852011-02-16 18:08:07 +00001130 return true;
1131}
reed@google.com69302852011-02-16 18:08:07 +00001132
reed@google.com0c219b62011-02-16 21:31:18 +00001133void SkGpuDevice::drawPath(const SkDraw& draw, const SkPath& origSrcPath,
reed@google.comac10a2d2010-12-22 21:39:39 +00001134 const SkPaint& paint, const SkMatrix* prePathMatrix,
1135 bool pathIsMutable) {
1136 CHECK_SHOULD_DRAW(draw);
1137
bsalomon@google.com5782d712011-01-21 21:03:59 +00001138 GrPaint grPaint;
1139 SkAutoCachedTexture act;
Scroggod757df22011-05-16 13:11:16 +00001140 if (!this->skPaint2GrPaintShader(paint,
1141 &act,
1142 *draw.fMatrix,
1143 &grPaint,
1144 true)) {
reed@google.comac10a2d2010-12-22 21:39:39 +00001145 return;
1146 }
1147
reed@google.com0c219b62011-02-16 21:31:18 +00001148 // BEGIN lift from SkDraw::drawPath()
1149
1150 SkPath* pathPtr = const_cast<SkPath*>(&origSrcPath);
1151 bool doFill = true;
1152 SkPath tmpPath;
reed@google.comac10a2d2010-12-22 21:39:39 +00001153
1154 if (prePathMatrix) {
reed@google.come3445642011-02-16 23:20:39 +00001155 SkPath* result = pathPtr;
reed@google.com0c219b62011-02-16 21:31:18 +00001156
reed@google.come3445642011-02-16 23:20:39 +00001157 if (!pathIsMutable) {
1158 result = &tmpPath;
1159 pathIsMutable = true;
reed@google.comac10a2d2010-12-22 21:39:39 +00001160 }
reed@google.come3445642011-02-16 23:20:39 +00001161 // should I push prePathMatrix on our MV stack temporarily, instead
1162 // of applying it here? See SkDraw.cpp
1163 pathPtr->transform(*prePathMatrix, result);
1164 pathPtr = result;
reed@google.comac10a2d2010-12-22 21:39:39 +00001165 }
reed@google.com0c219b62011-02-16 21:31:18 +00001166 // at this point we're done with prePathMatrix
1167 SkDEBUGCODE(prePathMatrix = (const SkMatrix*)0x50FF8001;)
reed@google.comac10a2d2010-12-22 21:39:39 +00001168
bsalomon@google.com04de7822011-03-25 18:04:43 +00001169 // This "if" is not part of the SkDraw::drawPath() lift.
1170 // When we get a 1.0 wide stroke we hairline stroke it instead of creating
1171 // a new stroked-path. This is motivated by canvas2D sites that draw
1172 // lines as 1.0 wide stroked paths. We can consider doing an alpha-modulated-
1173 // hairline for width < 1.0 when AA is enabled.
1174 static const int gMatrixMask = ~(SkMatrix::kIdentity_Mask |
1175 SkMatrix::kTranslate_Mask);
1176 if (!paint.getPathEffect() &&
1177 SkPaint::kStroke_Style == paint.getStyle() &&
1178 !(draw.fMatrix->getType() & gMatrixMask) &&
1179 SK_Scalar1 == paint.getStrokeWidth()) {
1180 doFill = false;
1181 }
1182
1183 if (doFill && (paint.getPathEffect() ||
1184 paint.getStyle() != SkPaint::kFill_Style)) {
reed@google.com0c219b62011-02-16 21:31:18 +00001185 doFill = paint.getFillPath(*pathPtr, &tmpPath);
1186 pathPtr = &tmpPath;
1187 }
1188
1189 // END lift from SkDraw::drawPath()
1190
reed@google.com69302852011-02-16 18:08:07 +00001191 if (paint.getMaskFilter()) {
reed@google.com0c219b62011-02-16 21:31:18 +00001192 // avoid possibly allocating a new path in transform if we can
1193 SkPath* devPathPtr = pathIsMutable ? pathPtr : &tmpPath;
1194
1195 // transform the path into device space
reed@google.come3445642011-02-16 23:20:39 +00001196 pathPtr->transform(*draw.fMatrix, devPathPtr);
senorblanco@chromium.orgb08ea1b2011-07-12 16:54:59 +00001197 if (!drawWithGPUMaskFilter(fContext, *devPathPtr, paint.getMaskFilter(),
1198 *draw.fMatrix, *draw.fClip, draw.fBounder,
1199 &grPaint)) {
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +00001200 drawWithMaskFilter(fContext, *devPathPtr, paint.getMaskFilter(),
1201 *draw.fMatrix, *draw.fClip, draw.fBounder,
1202 &grPaint);
1203 }
reed@google.com69302852011-02-16 18:08:07 +00001204 return;
1205 }
reed@google.com69302852011-02-16 18:08:07 +00001206
bsalomon@google.comffca4002011-02-22 20:34:01 +00001207 GrPathFill fill = kHairLine_PathFill;
reed@google.comac10a2d2010-12-22 21:39:39 +00001208
reed@google.com0c219b62011-02-16 21:31:18 +00001209 if (doFill) {
1210 switch (pathPtr->getFillType()) {
reed@google.comac10a2d2010-12-22 21:39:39 +00001211 case SkPath::kWinding_FillType:
bsalomon@google.comffca4002011-02-22 20:34:01 +00001212 fill = kWinding_PathFill;
reed@google.comac10a2d2010-12-22 21:39:39 +00001213 break;
1214 case SkPath::kEvenOdd_FillType:
bsalomon@google.comffca4002011-02-22 20:34:01 +00001215 fill = kEvenOdd_PathFill;
reed@google.comac10a2d2010-12-22 21:39:39 +00001216 break;
1217 case SkPath::kInverseWinding_FillType:
bsalomon@google.comffca4002011-02-22 20:34:01 +00001218 fill = kInverseWinding_PathFill;
reed@google.comac10a2d2010-12-22 21:39:39 +00001219 break;
1220 case SkPath::kInverseEvenOdd_FillType:
bsalomon@google.comffca4002011-02-22 20:34:01 +00001221 fill = kInverseEvenOdd_PathFill;
reed@google.comac10a2d2010-12-22 21:39:39 +00001222 break;
1223 default:
bsalomon@google.com5782d712011-01-21 21:03:59 +00001224 SkDebugf("Unsupported path fill type\n");
reed@google.comac10a2d2010-12-22 21:39:39 +00001225 return;
1226 }
1227 }
1228
reed@google.com07f3ee12011-05-16 17:21:57 +00001229 fContext->drawPath(grPaint, *pathPtr, fill);
reed@google.comac10a2d2010-12-22 21:39:39 +00001230}
1231
reed@google.comac10a2d2010-12-22 21:39:39 +00001232void SkGpuDevice::drawBitmap(const SkDraw& draw,
1233 const SkBitmap& bitmap,
1234 const SkIRect* srcRectPtr,
1235 const SkMatrix& m,
1236 const SkPaint& paint) {
1237 CHECK_SHOULD_DRAW(draw);
1238
1239 SkIRect srcRect;
1240 if (NULL == srcRectPtr) {
1241 srcRect.set(0, 0, bitmap.width(), bitmap.height());
1242 } else {
1243 srcRect = *srcRectPtr;
1244 }
1245
junov@google.comd935cfb2011-06-27 20:48:23 +00001246 if (paint.getMaskFilter()){
epoger@google.com9ef2d832011-07-01 21:12:20 +00001247 SkBitmap tmp; // storage if we need a subset of bitmap
junov@google.comd935cfb2011-06-27 20:48:23 +00001248 const SkBitmap* bitmapPtr = &bitmap;
epoger@google.com9ef2d832011-07-01 21:12:20 +00001249 if (srcRectPtr) {
1250 if (!bitmap.extractSubset(&tmp, srcRect)) {
1251 return; // extraction failed
1252 }
1253 bitmapPtr = &tmp;
junov@google.comd935cfb2011-06-27 20:48:23 +00001254 }
1255 SkPaint paintWithTexture(paint);
1256 paintWithTexture.setShader(SkShader::CreateBitmapShader( *bitmapPtr,
1257 SkShader::kClamp_TileMode, SkShader::kClamp_TileMode))->unref();
1258 paintWithTexture.getShader()->setLocalMatrix(m);
1259
1260 SkRect ScalarRect;
epoger@google.com9ef2d832011-07-01 21:12:20 +00001261 ScalarRect.set(srcRect);
junov@google.comd935cfb2011-06-27 20:48:23 +00001262
epoger@google.com9ef2d832011-07-01 21:12:20 +00001263 if (m.rectStaysRect()) {
1264 // Preferred drawing method, optimized for rectangles
1265 m.mapRect(&ScalarRect);
1266 this->drawRect(draw, ScalarRect, paintWithTexture);
1267 } else {
1268 // Slower drawing method, for warped or rotated rectangles
1269 SkPath path;
1270 path.addRect(ScalarRect);
1271 path.transform(m);
1272 this->drawPath(draw, path, paintWithTexture, NULL, true);
1273 }
junov@google.comd935cfb2011-06-27 20:48:23 +00001274 return;
1275 }
1276
bsalomon@google.com5782d712011-01-21 21:03:59 +00001277 GrPaint grPaint;
Scroggod757df22011-05-16 13:11:16 +00001278 if (!this->skPaint2GrPaintNoShader(paint, true, &grPaint, false)) {
bsalomon@google.com5782d712011-01-21 21:03:59 +00001279 return;
1280 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001281 GrSamplerState* sampler = grPaint.getTextureSampler(kBitmapTextureIdx);
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +00001282 if (paint.isFilterBitmap()) {
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001283 sampler->setFilter(GrSamplerState::kBilinear_Filter);
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +00001284 } else {
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001285 sampler->setFilter(GrSamplerState::kNearest_Filter);
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +00001286 }
bsalomon@google.com5782d712011-01-21 21:03:59 +00001287
bsalomon@google.com91958362011-06-13 17:58:13 +00001288 const int maxTextureSize = fContext->getMaxTextureSize();
1289 if (bitmap.getTexture() || (bitmap.width() <= maxTextureSize &&
1290 bitmap.height() <= maxTextureSize)) {
reed@google.comac10a2d2010-12-22 21:39:39 +00001291 // take the fast case
bsalomon@google.com5782d712011-01-21 21:03:59 +00001292 this->internalDrawBitmap(draw, bitmap, srcRect, m, &grPaint);
reed@google.comac10a2d2010-12-22 21:39:39 +00001293 return;
1294 }
1295
1296 // undo the translate done by SkCanvas
1297 int DX = SkMax32(0, srcRect.fLeft);
1298 int DY = SkMax32(0, srcRect.fTop);
1299 // compute clip bounds in local coordinates
1300 SkIRect clipRect;
1301 {
1302 SkRect r;
1303 r.set(draw.fClip->getBounds());
1304 SkMatrix matrix, inverse;
1305 matrix.setConcat(*draw.fMatrix, m);
1306 if (!matrix.invert(&inverse)) {
1307 return;
1308 }
1309 inverse.mapRect(&r);
1310 r.roundOut(&clipRect);
1311 // apply the canvas' translate to our local clip
1312 clipRect.offset(DX, DY);
1313 }
1314
bsalomon@google.com91958362011-06-13 17:58:13 +00001315 int nx = bitmap.width() / maxTextureSize;
1316 int ny = bitmap.height() / maxTextureSize;
reed@google.comac10a2d2010-12-22 21:39:39 +00001317 for (int x = 0; x <= nx; x++) {
1318 for (int y = 0; y <= ny; y++) {
1319 SkIRect tileR;
bsalomon@google.com91958362011-06-13 17:58:13 +00001320 tileR.set(x * maxTextureSize, y * maxTextureSize,
1321 (x + 1) * maxTextureSize, (y + 1) * maxTextureSize);
reed@google.comac10a2d2010-12-22 21:39:39 +00001322 if (!SkIRect::Intersects(tileR, clipRect)) {
1323 continue;
1324 }
1325
1326 SkIRect srcR = tileR;
1327 if (!srcR.intersect(srcRect)) {
1328 continue;
1329 }
1330
1331 SkBitmap tmpB;
1332 if (bitmap.extractSubset(&tmpB, tileR)) {
1333 // now offset it to make it "local" to our tmp bitmap
1334 srcR.offset(-tileR.fLeft, -tileR.fTop);
1335
1336 SkMatrix tmpM(m);
1337 {
1338 int dx = tileR.fLeft - DX + SkMax32(0, srcR.fLeft);
1339 int dy = tileR.fTop - DY + SkMax32(0, srcR.fTop);
1340 tmpM.preTranslate(SkIntToScalar(dx), SkIntToScalar(dy));
1341 }
bsalomon@google.com5782d712011-01-21 21:03:59 +00001342 this->internalDrawBitmap(draw, tmpB, srcR, tmpM, &grPaint);
reed@google.comac10a2d2010-12-22 21:39:39 +00001343 }
1344 }
1345 }
1346}
1347
1348/*
1349 * This is called by drawBitmap(), which has to handle images that may be too
1350 * large to be represented by a single texture.
1351 *
bsalomon@google.com5782d712011-01-21 21:03:59 +00001352 * internalDrawBitmap assumes that the specified bitmap will fit in a texture
1353 * and that non-texture portion of the GrPaint has already been setup.
reed@google.comac10a2d2010-12-22 21:39:39 +00001354 */
1355void SkGpuDevice::internalDrawBitmap(const SkDraw& draw,
1356 const SkBitmap& bitmap,
1357 const SkIRect& srcRect,
1358 const SkMatrix& m,
bsalomon@google.com5782d712011-01-21 21:03:59 +00001359 GrPaint* grPaint) {
bsalomon@google.com91958362011-06-13 17:58:13 +00001360 SkASSERT(bitmap.width() <= fContext->getMaxTextureSize() &&
1361 bitmap.height() <= fContext->getMaxTextureSize());
reed@google.comac10a2d2010-12-22 21:39:39 +00001362
reed@google.com9c49bc32011-07-07 13:42:37 +00001363 SkAutoLockPixels alp(bitmap, !bitmap.getTexture());
reed@google.comac10a2d2010-12-22 21:39:39 +00001364 if (!bitmap.getTexture() && !bitmap.readyToDraw()) {
reed@google.com9c49bc32011-07-07 13:42:37 +00001365 SkDebugf("nothing to draw\n");
reed@google.comac10a2d2010-12-22 21:39:39 +00001366 return;
1367 }
1368
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001369 GrSamplerState* sampler = grPaint->getTextureSampler(kBitmapTextureIdx);
1370
1371 sampler->setWrapX(GrSamplerState::kClamp_WrapMode);
1372 sampler->setWrapY(GrSamplerState::kClamp_WrapMode);
1373 sampler->setSampleMode(GrSamplerState::kNormal_SampleMode);
1374 sampler->setMatrix(GrMatrix::I());
reed@google.comac10a2d2010-12-22 21:39:39 +00001375
1376 GrTexture* texture;
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001377 SkAutoCachedTexture act(this, bitmap, *sampler, &texture);
reed@google.comac10a2d2010-12-22 21:39:39 +00001378 if (NULL == texture) {
1379 return;
1380 }
1381
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001382 grPaint->setTexture(kShaderTextureIdx, texture);
reed@google.com46799cd2011-02-22 20:56:26 +00001383
reed@google.com20efde72011-05-09 17:00:02 +00001384 GrRect dstRect = SkRect::MakeWH(GrIntToScalar(srcRect.width()),
1385 GrIntToScalar(srcRect.height()));
bsalomon@google.comc6cf7232011-02-17 16:43:10 +00001386 GrRect paintRect;
junov@google.com6acc9b32011-05-16 18:32:07 +00001387 paintRect.setLTRB(GrFixedToScalar((srcRect.fLeft << 16) / bitmap.width()),
1388 GrFixedToScalar((srcRect.fTop << 16) / bitmap.height()),
1389 GrFixedToScalar((srcRect.fRight << 16) / bitmap.width()),
bsalomon@google.comc6cf7232011-02-17 16:43:10 +00001390 GrFixedToScalar((srcRect.fBottom << 16) / bitmap.height()));
reed@google.comac10a2d2010-12-22 21:39:39 +00001391
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001392 if (GrSamplerState::kNearest_Filter != sampler->getFilter() &&
junov@google.com6acc9b32011-05-16 18:32:07 +00001393 (srcRect.width() < bitmap.width() ||
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001394 srcRect.height() < bitmap.height())) {
junov@google.com6acc9b32011-05-16 18:32:07 +00001395 // If drawing a subrect of the bitmap and filtering is enabled,
1396 // use a constrained texture domain to avoid color bleeding
1397 GrScalar left, top, right, bottom;
1398 if (srcRect.width() > 1) {
1399 GrScalar border = GR_ScalarHalf / bitmap.width();
1400 left = paintRect.left() + border;
1401 right = paintRect.right() - border;
1402 } else {
1403 left = right = GrScalarHalf(paintRect.left() + paintRect.right());
1404 }
1405 if (srcRect.height() > 1) {
1406 GrScalar border = GR_ScalarHalf / bitmap.height();
1407 top = paintRect.top() + border;
1408 bottom = paintRect.bottom() - border;
1409 } else {
1410 top = bottom = GrScalarHalf(paintRect.top() + paintRect.bottom());
1411 }
1412 GrRect textureDomain;
1413 textureDomain.setLTRB(left, top, right, bottom);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001414 sampler->setTextureDomain(textureDomain);
junov@google.com6acc9b32011-05-16 18:32:07 +00001415 }
1416
bsalomon@google.comcc4dac32011-05-10 13:52:42 +00001417 fContext->drawRectToRect(*grPaint, dstRect, paintRect, &m);
reed@google.comac10a2d2010-12-22 21:39:39 +00001418}
1419
1420void SkGpuDevice::drawSprite(const SkDraw& draw, const SkBitmap& bitmap,
1421 int left, int top, const SkPaint& paint) {
1422 CHECK_SHOULD_DRAW(draw);
1423
1424 SkAutoLockPixels alp(bitmap);
1425 if (!bitmap.getTexture() && !bitmap.readyToDraw()) {
1426 return;
1427 }
1428
bsalomon@google.com5782d712011-01-21 21:03:59 +00001429 GrPaint grPaint;
Scroggod757df22011-05-16 13:11:16 +00001430 if(!this->skPaint2GrPaintNoShader(paint, true, &grPaint, false)) {
bsalomon@google.com5782d712011-01-21 21:03:59 +00001431 return;
1432 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001433
bsalomon@google.com5782d712011-01-21 21:03:59 +00001434 GrAutoMatrix avm(fContext, GrMatrix::I());
1435
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001436 GrSamplerState* sampler = grPaint.getTextureSampler(kBitmapTextureIdx);
bsalomon@google.com5782d712011-01-21 21:03:59 +00001437
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001438 GrTexture* texture;
1439 sampler->setClampNoFilter();
1440 SkAutoCachedTexture act(this, bitmap, *sampler, &texture);
1441
1442 grPaint.setTexture(kBitmapTextureIdx, texture);
bsalomon@google.com5782d712011-01-21 21:03:59 +00001443
bsalomon@google.com5782d712011-01-21 21:03:59 +00001444 fContext->drawRectToRect(grPaint,
reed@google.com20efde72011-05-09 17:00:02 +00001445 GrRect::MakeXYWH(GrIntToScalar(left),
1446 GrIntToScalar(top),
1447 GrIntToScalar(bitmap.width()),
1448 GrIntToScalar(bitmap.height())),
1449 GrRect::MakeWH(GR_Scalar1, GR_Scalar1));
reed@google.comac10a2d2010-12-22 21:39:39 +00001450}
1451
1452void SkGpuDevice::drawDevice(const SkDraw& draw, SkDevice* dev,
1453 int x, int y, const SkPaint& paint) {
1454 CHECK_SHOULD_DRAW(draw);
1455
bsalomon@google.com5782d712011-01-21 21:03:59 +00001456 GrPaint grPaint;
bsalomon@google.comc6cf7232011-02-17 16:43:10 +00001457 if (!((SkGpuDevice*)dev)->bindDeviceAsTexture(&grPaint) ||
Scroggod757df22011-05-16 13:11:16 +00001458 !this->skPaint2GrPaintNoShader(paint, true, &grPaint, false)) {
bsalomon@google.com5782d712011-01-21 21:03:59 +00001459 return;
reed@google.comac10a2d2010-12-22 21:39:39 +00001460 }
bsalomon@google.com5782d712011-01-21 21:03:59 +00001461
bsalomon@google.comb5b31682011-06-16 18:05:35 +00001462 GrTexture* devTex = grPaint.getTexture(0);
1463 SkASSERT(NULL != devTex);
bsalomon@google.com5782d712011-01-21 21:03:59 +00001464
1465 const SkBitmap& bm = dev->accessBitmap(false);
1466 int w = bm.width();
1467 int h = bm.height();
1468
1469 GrAutoMatrix avm(fContext, GrMatrix::I());
1470
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001471 grPaint.getTextureSampler(kBitmapTextureIdx)->setClampNoFilter();
bsalomon@google.com5782d712011-01-21 21:03:59 +00001472
bsalomon@google.comb5b31682011-06-16 18:05:35 +00001473 GrRect dstRect = GrRect::MakeXYWH(GrIntToScalar(x),
1474 GrIntToScalar(y),
1475 GrIntToScalar(w),
1476 GrIntToScalar(h));
1477 // The device being drawn may not fill up its texture (saveLayer uses
1478 // the approximate ).
1479 GrRect srcRect = GrRect::MakeWH(GR_Scalar1 * w / devTex->width(),
1480 GR_Scalar1 * h / devTex->height());
1481
1482 fContext->drawRectToRect(grPaint, dstRect, srcRect);
reed@google.comac10a2d2010-12-22 21:39:39 +00001483}
1484
1485///////////////////////////////////////////////////////////////////////////////
1486
1487// must be in SkCanvas::VertexMode order
bsalomon@google.comffca4002011-02-22 20:34:01 +00001488static const GrPrimitiveType gVertexMode2PrimitiveType[] = {
1489 kTriangles_PrimitiveType,
1490 kTriangleStrip_PrimitiveType,
1491 kTriangleFan_PrimitiveType,
reed@google.comac10a2d2010-12-22 21:39:39 +00001492};
1493
1494void SkGpuDevice::drawVertices(const SkDraw& draw, SkCanvas::VertexMode vmode,
1495 int vertexCount, const SkPoint vertices[],
1496 const SkPoint texs[], const SkColor colors[],
1497 SkXfermode* xmode,
1498 const uint16_t indices[], int indexCount,
1499 const SkPaint& paint) {
1500 CHECK_SHOULD_DRAW(draw);
1501
bsalomon@google.com5782d712011-01-21 21:03:59 +00001502 GrPaint grPaint;
1503 SkAutoCachedTexture act;
1504 // we ignore the shader if texs is null.
1505 if (NULL == texs) {
Scroggod757df22011-05-16 13:11:16 +00001506 if (!this->skPaint2GrPaintNoShader(paint,
1507 false,
1508 &grPaint,
1509 NULL == colors)) {
reed@google.comac10a2d2010-12-22 21:39:39 +00001510 return;
1511 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001512 } else {
reed@google.com1a2e8d22011-01-21 22:08:29 +00001513 if (!this->skPaint2GrPaintShader(paint, &act,
1514 *draw.fMatrix,
Scroggod757df22011-05-16 13:11:16 +00001515 &grPaint,
1516 NULL == colors)) {
bsalomon@google.com5782d712011-01-21 21:03:59 +00001517 return;
1518 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001519 }
bsalomon@google.com5782d712011-01-21 21:03:59 +00001520
1521 if (NULL != xmode && NULL != texs && NULL != colors) {
1522 SkXfermode::Mode mode;
1523 if (!SkXfermode::IsMode(xmode, &mode) ||
1524 SkXfermode::kMultiply_Mode != mode) {
1525 SkDebugf("Unsupported vertex-color/texture xfer mode.\n");
1526#if 0
1527 return
1528#endif
1529 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001530 }
bsalomon@google.com5782d712011-01-21 21:03:59 +00001531
1532#if SK_SCALAR_IS_GR_SCALAR
1533 // even if GrColor and SkColor byte offsets match we need
1534 // to perform pre-multiply.
1535 if (NULL == colors) {
1536 fContext->drawVertices(grPaint,
1537 gVertexMode2PrimitiveType[vmode],
1538 vertexCount,
1539 (GrPoint*) vertices,
1540 (GrPoint*) texs,
1541 NULL,
1542 indices,
1543 indexCount);
1544 } else
1545#endif
1546 {
1547 SkTexCoordSource texSrc(texs);
1548 SkColorSource colSrc(colors);
1549 SkIndexSource idxSrc(indices, indexCount);
1550
1551 fContext->drawCustomVertices(grPaint,
1552 gVertexMode2PrimitiveType[vmode],
1553 SkPositionSource(vertices, vertexCount),
1554 (NULL == texs) ? NULL : &texSrc,
1555 (NULL == colors) ? NULL : &colSrc,
1556 (NULL == indices) ? NULL : &idxSrc);
reed@google.comac10a2d2010-12-22 21:39:39 +00001557 }
1558}
1559
1560///////////////////////////////////////////////////////////////////////////////
1561
1562static void GlyphCacheAuxProc(void* data) {
1563 delete (GrFontScaler*)data;
1564}
1565
1566static GrFontScaler* get_gr_font_scaler(SkGlyphCache* cache) {
1567 void* auxData;
1568 GrFontScaler* scaler = NULL;
1569 if (cache->getAuxProcData(GlyphCacheAuxProc, &auxData)) {
1570 scaler = (GrFontScaler*)auxData;
1571 }
1572 if (NULL == scaler) {
1573 scaler = new SkGrFontScaler(cache);
1574 cache->setAuxProc(GlyphCacheAuxProc, scaler);
1575 }
1576 return scaler;
1577}
1578
1579static void SkGPU_Draw1Glyph(const SkDraw1Glyph& state,
1580 SkFixed fx, SkFixed fy,
1581 const SkGlyph& glyph) {
1582 SkASSERT(glyph.fWidth > 0 && glyph.fHeight > 0);
1583
1584 GrSkDrawProcs* procs = (GrSkDrawProcs*)state.fDraw->fProcs;
1585
1586 if (NULL == procs->fFontScaler) {
1587 procs->fFontScaler = get_gr_font_scaler(state.fCache);
1588 }
reed@google.com39ce0ac2011-04-08 15:42:19 +00001589
1590 /*
reed@google.com3b139f52011-06-07 17:56:25 +00001591 * What should we do with fy? (assuming horizontal/latin text)
reed@google.com39ce0ac2011-04-08 15:42:19 +00001592 *
reed@google.com3b139f52011-06-07 17:56:25 +00001593 * The raster code calls SkFixedFloorToFixed on it, as it does with fx.
1594 * It calls that rather than round, because our caller has already added
1595 * SK_FixedHalf, so that calling floor gives us the rounded integer.
1596 *
1597 * Test code between raster and gpu (they should draw the same)
1598 *
1599 * canvas->drawText("Hamburgefons", 12, 0, 16.5f, paint);
1600 *
1601 * Perhaps we should only perform this integralization if there is no
1602 * fExtMatrix...
reed@google.com39ce0ac2011-04-08 15:42:19 +00001603 */
reed@google.com3b139f52011-06-07 17:56:25 +00001604 fy = SkFixedFloorToFixed(fy);
1605
reed@google.comac10a2d2010-12-22 21:39:39 +00001606 procs->fTextContext->drawPackedGlyph(GrGlyph::Pack(glyph.getGlyphID(), fx, 0),
reed@google.com3b139f52011-06-07 17:56:25 +00001607 SkFixedFloorToFixed(fx), fy,
reed@google.comac10a2d2010-12-22 21:39:39 +00001608 procs->fFontScaler);
1609}
1610
bsalomon@google.com5782d712011-01-21 21:03:59 +00001611SkDrawProcs* SkGpuDevice::initDrawForText(GrTextContext* context) {
reed@google.comac10a2d2010-12-22 21:39:39 +00001612
1613 // deferred allocation
1614 if (NULL == fDrawProcs) {
1615 fDrawProcs = new GrSkDrawProcs;
1616 fDrawProcs->fD1GProc = SkGPU_Draw1Glyph;
1617 fDrawProcs->fContext = fContext;
1618 }
1619
1620 // init our (and GL's) state
1621 fDrawProcs->fTextContext = context;
1622 fDrawProcs->fFontScaler = NULL;
1623 return fDrawProcs;
1624}
1625
1626void SkGpuDevice::drawText(const SkDraw& draw, const void* text,
1627 size_t byteLength, SkScalar x, SkScalar y,
1628 const SkPaint& paint) {
1629 CHECK_SHOULD_DRAW(draw);
1630
1631 if (draw.fMatrix->getType() & SkMatrix::kPerspective_Mask) {
1632 // this guy will just call our drawPath()
1633 draw.drawText((const char*)text, byteLength, x, y, paint);
1634 } else {
reed@google.comac10a2d2010-12-22 21:39:39 +00001635 SkDraw myDraw(draw);
bsalomon@google.com5782d712011-01-21 21:03:59 +00001636
1637 GrPaint grPaint;
1638 SkAutoCachedTexture act;
1639
Scroggod757df22011-05-16 13:11:16 +00001640 if (!this->skPaint2GrPaintShader(paint,
1641 &act,
1642 *draw.fMatrix,
1643 &grPaint,
1644 true)) {
bsalomon@google.com5782d712011-01-21 21:03:59 +00001645 return;
1646 }
bsalomon@google.comcc4dac32011-05-10 13:52:42 +00001647 GrTextContext context(fContext, grPaint, draw.fExtMatrix);
bsalomon@google.com5782d712011-01-21 21:03:59 +00001648 myDraw.fProcs = this->initDrawForText(&context);
reed@google.comac10a2d2010-12-22 21:39:39 +00001649 this->INHERITED::drawText(myDraw, text, byteLength, x, y, paint);
1650 }
1651}
1652
1653void SkGpuDevice::drawPosText(const SkDraw& draw, const void* text,
1654 size_t byteLength, const SkScalar pos[],
1655 SkScalar constY, int scalarsPerPos,
1656 const SkPaint& paint) {
1657 CHECK_SHOULD_DRAW(draw);
1658
1659 if (draw.fMatrix->getType() & SkMatrix::kPerspective_Mask) {
1660 // this guy will just call our drawPath()
1661 draw.drawPosText((const char*)text, byteLength, pos, constY,
1662 scalarsPerPos, paint);
1663 } else {
reed@google.comac10a2d2010-12-22 21:39:39 +00001664 SkDraw myDraw(draw);
bsalomon@google.com5782d712011-01-21 21:03:59 +00001665
1666 GrPaint grPaint;
1667 SkAutoCachedTexture act;
Scroggod757df22011-05-16 13:11:16 +00001668 if (!this->skPaint2GrPaintShader(paint,
1669 &act,
1670 *draw.fMatrix,
1671 &grPaint,
1672 true)) {
bsalomon@google.com5782d712011-01-21 21:03:59 +00001673 return;
1674 }
1675
bsalomon@google.comcc4dac32011-05-10 13:52:42 +00001676 GrTextContext context(fContext, grPaint, draw.fExtMatrix);
bsalomon@google.com5782d712011-01-21 21:03:59 +00001677 myDraw.fProcs = this->initDrawForText(&context);
reed@google.comac10a2d2010-12-22 21:39:39 +00001678 this->INHERITED::drawPosText(myDraw, text, byteLength, pos, constY,
1679 scalarsPerPos, paint);
1680 }
1681}
1682
1683void SkGpuDevice::drawTextOnPath(const SkDraw& draw, const void* text,
1684 size_t len, const SkPath& path,
1685 const SkMatrix* m, const SkPaint& paint) {
1686 CHECK_SHOULD_DRAW(draw);
1687
1688 SkASSERT(draw.fDevice == this);
1689 draw.drawTextOnPath((const char*)text, len, path, m, paint);
1690}
1691
1692///////////////////////////////////////////////////////////////////////////////
1693
reed@google.comf67e4cf2011-03-15 20:56:58 +00001694bool SkGpuDevice::filterTextFlags(const SkPaint& paint, TextFlags* flags) {
1695 if (!paint.isLCDRenderText()) {
1696 // we're cool with the paint as is
1697 return false;
1698 }
1699
1700 if (paint.getShader() ||
1701 paint.getXfermode() || // unless its srcover
1702 paint.getMaskFilter() ||
1703 paint.getRasterizer() ||
1704 paint.getColorFilter() ||
1705 paint.getPathEffect() ||
1706 paint.isFakeBoldText() ||
1707 paint.getStyle() != SkPaint::kFill_Style) {
1708 // turn off lcd
1709 flags->fFlags = paint.getFlags() & ~SkPaint::kLCDRenderText_Flag;
1710 flags->fHinting = paint.getHinting();
1711 return true;
1712 }
1713 // we're cool with the paint as is
1714 return false;
1715}
1716
1717///////////////////////////////////////////////////////////////////////////////
1718
bsalomon@google.com50398bf2011-07-26 20:45:30 +00001719SkGpuDevice::TexCache SkGpuDevice::lockCachedTexture(const SkBitmap& bitmap,
1720 const GrSamplerState& sampler,
1721 TexType type) {
1722 GrContext::TextureCacheEntry entry;
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.com50398bf2011-07-26 20:45:30 +00001733 GrContext::ScratchTexMatch match;
bsalomon@google.come97f0852011-06-17 13:10:25 +00001734 if (kSaveLayerDeviceRenderTarget_TexType == type) {
bsalomon@google.comb5b31682011-06-16 18:05:35 +00001735 // we know layers will only be drawn through drawDevice.
1736 // drawDevice has been made to work with content embedded in a
1737 // larger texture so its okay to use the approximate version.
bsalomon@google.com50398bf2011-07-26 20:45:30 +00001738 match = GrContext::kApprox_ScratchTexMatch;
bsalomon@google.comb5b31682011-06-16 18:05:35 +00001739 } else {
bsalomon@google.come97f0852011-06-17 13:10:25 +00001740 SkASSERT(kDeviceRenderTarget_TexType == type);
bsalomon@google.com50398bf2011-07-26 20:45:30 +00001741 match = GrContext::kExact_ScratchTexMatch;
bsalomon@google.comb5b31682011-06-16 18:05:35 +00001742 }
bsalomon@google.com50398bf2011-07-26 20:45:30 +00001743 entry = ctx->lockScratchTexture(desc, match);
reed@google.comac10a2d2010-12-22 21:39:39 +00001744 } else {
junov@google.com4ee7ae52011-06-30 17:30:49 +00001745 if (!bitmap.isVolatile()) {
bsalomon@google.com50398bf2011-07-26 20:45:30 +00001746 GrContext::TextureKey key = bitmap.getGenerationID();
1747 key |= ((uint64_t) bitmap.pixelRefOffset()) << 32;
junov@google.com4ee7ae52011-06-30 17:30:49 +00001748
bsalomon@google.com50398bf2011-07-26 20:45:30 +00001749 entry = ctx->findAndLockTexture(key, bitmap.width(),
1750 bitmap.height(), sampler);
1751 if (NULL == entry.texture()) {
1752 entry = sk_gr_create_bitmap_texture(ctx, key, sampler,
junov@google.com4ee7ae52011-06-30 17:30:49 +00001753 bitmap);
bsalomon@google.com50398bf2011-07-26 20:45:30 +00001754 }
junov@google.com4ee7ae52011-06-30 17:30:49 +00001755 } else {
bsalomon@google.com50398bf2011-07-26 20:45:30 +00001756 entry = sk_gr_create_bitmap_texture(ctx, gUNCACHED_KEY, sampler, bitmap);
junov@google.com4ee7ae52011-06-30 17:30:49 +00001757 }
bsalomon@google.com50398bf2011-07-26 20:45:30 +00001758 if (NULL == entry.texture()) {
junov@google.com4ee7ae52011-06-30 17:30:49 +00001759 GrPrintf("---- failed to create texture for cache [%d %d]\n",
1760 bitmap.width(), bitmap.height());
reed@google.comac10a2d2010-12-22 21:39:39 +00001761 }
1762 }
bsalomon@google.com50398bf2011-07-26 20:45:30 +00001763 return entry;
reed@google.comac10a2d2010-12-22 21:39:39 +00001764}
1765
bsalomon@google.com50398bf2011-07-26 20:45:30 +00001766void SkGpuDevice::unlockCachedTexture(TexCache cache) {
1767 this->context()->unlockTexture(cache);
reed@google.comac10a2d2010-12-22 21:39:39 +00001768}
1769
bsalomon@google.come97f0852011-06-17 13:10:25 +00001770SkDevice* SkGpuDevice::onCreateCompatibleDevice(SkBitmap::Config config,
1771 int width, int height,
1772 bool isOpaque,
1773 Usage usage) {
1774 return SkNEW_ARGS(SkGpuDevice,(this->context(), config,
1775 width, height, usage));
1776}
1777