blob: 54f0e790d9fd7261da7ab359c5a58c21cb08fd5d [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.org027de5f2011-07-08 18:03:33 +000050#define USE_GPU_BLUR false
51#define MAX_SIGMA 4.0f
reed@google.comac10a2d2010-12-22 21:39:39 +000052///////////////////////////////////////////////////////////////////////////////
53
54SkGpuDevice::SkAutoCachedTexture::
55 SkAutoCachedTexture(SkGpuDevice* device,
56 const SkBitmap& bitmap,
57 const GrSamplerState& sampler,
58 GrTexture** texture) {
59 GrAssert(texture);
60 fTex = NULL;
61 *texture = this->set(device, bitmap, sampler);
62}
63
64SkGpuDevice::SkAutoCachedTexture::SkAutoCachedTexture() {
65 fTex = NULL;
66}
67
68GrTexture* SkGpuDevice::SkAutoCachedTexture::set(SkGpuDevice* device,
69 const SkBitmap& bitmap,
70 const GrSamplerState& sampler) {
71 if (fTex) {
72 fDevice->unlockCachedTexture(fTex);
73 }
74 fDevice = device;
75 GrTexture* texture = (GrTexture*)bitmap.getTexture();
76 if (texture) {
77 // return the native texture
78 fTex = NULL;
reed@google.comac10a2d2010-12-22 21:39:39 +000079 } else {
80 // look it up in our cache
bsalomon@google.come97f0852011-06-17 13:10:25 +000081 fTex = device->lockCachedTexture(bitmap, sampler, &texture);
reed@google.comac10a2d2010-12-22 21:39:39 +000082 }
83 return texture;
84}
85
86SkGpuDevice::SkAutoCachedTexture::~SkAutoCachedTexture() {
87 if (fTex) {
88 fDevice->unlockCachedTexture(fTex);
89 }
90}
91
92///////////////////////////////////////////////////////////////////////////////
93
94bool gDoTraceDraw;
95
96struct GrSkDrawProcs : public SkDrawProcs {
97public:
98 GrContext* fContext;
99 GrTextContext* fTextContext;
100 GrFontScaler* fFontScaler; // cached in the skia glyphcache
101};
102
103///////////////////////////////////////////////////////////////////////////////
104
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000105GrRenderTarget* SkGpuDevice::Current3DApiRenderTarget() {
106 return (GrRenderTarget*) -1;
107}
108
reed@google.comaf951c92011-06-16 19:10:39 +0000109static SkBitmap::Config grConfig2skConfig(GrPixelConfig config, bool* isOpaque) {
110 switch (config) {
111 case kAlpha_8_GrPixelConfig:
112 *isOpaque = false;
113 return SkBitmap::kA8_Config;
114 case kRGB_565_GrPixelConfig:
115 *isOpaque = true;
116 return SkBitmap::kRGB_565_Config;
117 case kRGBA_4444_GrPixelConfig:
118 *isOpaque = false;
119 return SkBitmap::kARGB_4444_Config;
120 case kRGBA_8888_GrPixelConfig:
121 case kRGBX_8888_GrPixelConfig:
122 *isOpaque = (kRGBX_8888_GrPixelConfig == config);
123 return SkBitmap::kARGB_8888_Config;
124 default:
125 *isOpaque = false;
126 return SkBitmap::kNo_Config;
127 }
128}
reed@google.comac10a2d2010-12-22 21:39:39 +0000129
reed@google.comaf951c92011-06-16 19:10:39 +0000130static SkBitmap make_bitmap(GrContext* context, GrRenderTarget* renderTarget) {
131 if (SkGpuDevice::Current3DApiRenderTarget() == renderTarget) {
132 renderTarget = context->createRenderTargetFrom3DApiState();
133 }
134 GrTexture* texture = renderTarget->asTexture();
135 GrPixelConfig config = texture ? texture->config() : kRGBA_8888_GrPixelConfig;
136
137 bool isOpaque;
138 SkBitmap bitmap;
139 bitmap.setConfig(grConfig2skConfig(config, &isOpaque),
140 renderTarget->width(), renderTarget->height());
141 bitmap.setIsOpaque(isOpaque);
142 return bitmap;
143}
144
bsalomon@google.comf9046fe2011-06-17 15:10:21 +0000145SkGpuDevice::SkGpuDevice(GrContext* context, GrTexture* texture)
146: SkDevice(make_bitmap(context, texture->asRenderTarget())) {
147 this->initFromRenderTarget(context, texture->asRenderTarget());
148}
149
reed@google.comaf951c92011-06-16 19:10:39 +0000150SkGpuDevice::SkGpuDevice(GrContext* context, GrRenderTarget* renderTarget)
151: SkDevice(make_bitmap(context, renderTarget)) {
bsalomon@google.comf9046fe2011-06-17 15:10:21 +0000152 this->initFromRenderTarget(context, renderTarget);
153}
154
155void SkGpuDevice::initFromRenderTarget(GrContext* context,
156 GrRenderTarget* renderTarget) {
reed@google.comaf951c92011-06-16 19:10:39 +0000157 fNeedPrepareRenderTarget = false;
158 fDrawProcs = NULL;
159
160 fContext = context;
161 fContext->ref();
162
163 fCache = NULL;
164 fTexture = NULL;
165 fRenderTarget = NULL;
166 fNeedClear = false;
167
168 if (Current3DApiRenderTarget() == renderTarget) {
169 fRenderTarget = fContext->createRenderTargetFrom3DApiState();
170 } else {
bsalomon@google.comf9046fe2011-06-17 15:10:21 +0000171 GrAssert(NULL != renderTarget);
reed@google.comaf951c92011-06-16 19:10:39 +0000172 fRenderTarget = renderTarget;
173 fRenderTarget->ref();
bsalomon@google.comf9046fe2011-06-17 15:10:21 +0000174 // if this RT is also a texture, hold a ref on it
175 fTexture = fRenderTarget->asTexture();
176 SkSafeRef(fTexture);
reed@google.comaf951c92011-06-16 19:10:39 +0000177 }
178
179 SkGrRenderTargetPixelRef* pr = new SkGrRenderTargetPixelRef(fRenderTarget);
180 this->setPixelRef(pr, 0)->unref();
181}
182
183SkGpuDevice::SkGpuDevice(GrContext* context, SkBitmap::Config config, int width,
bsalomon@google.come97f0852011-06-17 13:10:25 +0000184 int height, Usage usage)
reed@google.comaf951c92011-06-16 19:10:39 +0000185: SkDevice(config, width, height, false /*isOpaque*/) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000186 fNeedPrepareRenderTarget = false;
187 fDrawProcs = NULL;
188
reed@google.com7b201d22011-01-11 18:59:23 +0000189 fContext = context;
bsalomon@google.com5782d712011-01-21 21:03:59 +0000190 fContext->ref();
reed@google.comac10a2d2010-12-22 21:39:39 +0000191
192 fCache = NULL;
193 fTexture = NULL;
194 fRenderTarget = NULL;
195 fNeedClear = false;
196
reed@google.comaf951c92011-06-16 19:10:39 +0000197 if (config != SkBitmap::kRGB_565_Config) {
198 config = SkBitmap::kARGB_8888_Config;
199 }
200 SkBitmap bm;
201 bm.setConfig(config, width, height);
reed@google.comac10a2d2010-12-22 21:39:39 +0000202
203#if CACHE_LAYER_TEXTURES
bsalomon@google.come97f0852011-06-17 13:10:25 +0000204 TexType type = (kSaveLayer_Usage == usage) ?
205 kSaveLayerDeviceRenderTarget_TexType :
206 kDeviceRenderTarget_TexType;
reed@google.comaf951c92011-06-16 19:10:39 +0000207 fCache = this->lockCachedTexture(bm, GrSamplerState::ClampNoFilter(),
bsalomon@google.come97f0852011-06-17 13:10:25 +0000208 &fTexture, type);
reed@google.comaf951c92011-06-16 19:10:39 +0000209 if (fCache) {
210 SkASSERT(NULL != fTexture);
211 SkASSERT(NULL != fTexture->asRenderTarget());
bsalomon@google.comf9046fe2011-06-17 15:10:21 +0000212 // hold a ref directly on fTexture (even though fCache has one) to match
213 // other constructor paths. Simplifies cleanup.
214 fTexture->ref();
reed@google.comaf951c92011-06-16 19:10:39 +0000215 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000216#else
reed@google.comaf951c92011-06-16 19:10:39 +0000217 const GrTextureDesc desc = {
218 kRenderTarget_GrTextureFlagBit,
219 kNone_GrAALevel,
220 width,
221 height,
222 SkGr::Bitmap2PixelConfig(bm)
223 };
reed@google.comac10a2d2010-12-22 21:39:39 +0000224
reed@google.comaf951c92011-06-16 19:10:39 +0000225 fTexture = fContext->createUncachedTexture(desc, NULL, 0);
reed@google.comac10a2d2010-12-22 21:39:39 +0000226#endif
reed@google.comaf951c92011-06-16 19:10:39 +0000227 if (NULL != fTexture) {
228 fRenderTarget = fTexture->asRenderTarget();
bsalomon@google.comf9046fe2011-06-17 15:10:21 +0000229 fRenderTarget->ref();
reed@google.comac10a2d2010-12-22 21:39:39 +0000230
reed@google.comaf951c92011-06-16 19:10:39 +0000231 GrAssert(NULL != fRenderTarget);
reed@google.comac10a2d2010-12-22 21:39:39 +0000232
reed@google.comaf951c92011-06-16 19:10:39 +0000233 // we defer the actual clear until our gainFocus()
234 fNeedClear = true;
reed@google.comac10a2d2010-12-22 21:39:39 +0000235
reed@google.comaf951c92011-06-16 19:10:39 +0000236 // wrap the bitmap with a pixelref to expose our texture
237 SkGrTexturePixelRef* pr = new SkGrTexturePixelRef(fTexture);
bsalomon@google.com669fdc42011-04-05 17:08:27 +0000238 this->setPixelRef(pr, 0)->unref();
reed@google.comaf951c92011-06-16 19:10:39 +0000239 } else {
240 GrPrintf("--- failed to create gpu-offscreen [%d %d]\n",
241 width, height);
242 GrAssert(false);
reed@google.comac10a2d2010-12-22 21:39:39 +0000243 }
244}
245
246SkGpuDevice::~SkGpuDevice() {
247 if (fDrawProcs) {
248 delete fDrawProcs;
249 }
250
bsalomon@google.comf9046fe2011-06-17 15:10:21 +0000251 SkSafeUnref(fTexture);
252 SkSafeUnref(fRenderTarget);
reed@google.comac10a2d2010-12-22 21:39:39 +0000253 if (fCache) {
254 GrAssert(NULL != fTexture);
255 GrAssert(fRenderTarget == fTexture->asRenderTarget());
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000256 fContext->unlockTexture((GrTextureEntry*)fCache);
bsalomon@google.comf9046fe2011-06-17 15:10:21 +0000257 }
bsalomon@google.com5782d712011-01-21 21:03:59 +0000258 fContext->unref();
reed@google.comac10a2d2010-12-22 21:39:39 +0000259}
260
reed@google.comac10a2d2010-12-22 21:39:39 +0000261intptr_t SkGpuDevice::getLayerTextureHandle() const {
262 if (fTexture) {
263 return fTexture->getTextureHandle();
264 } else {
265 return 0;
266 }
267}
mike@reedtribe.orgea4ac972011-04-26 11:48:33 +0000268
reed@google.comac10a2d2010-12-22 21:39:39 +0000269///////////////////////////////////////////////////////////////////////////////
270
271void SkGpuDevice::makeRenderTargetCurrent() {
272 fContext->setRenderTarget(fRenderTarget);
273 fContext->flush(true);
274 fNeedPrepareRenderTarget = true;
275}
276
277///////////////////////////////////////////////////////////////////////////////
278
279bool SkGpuDevice::readPixels(const SkIRect& srcRect, SkBitmap* bitmap) {
280 SkIRect bounds;
281 bounds.set(0, 0, this->width(), this->height());
282 if (!bounds.intersect(srcRect)) {
283 return false;
284 }
285
286 const int w = bounds.width();
287 const int h = bounds.height();
288 SkBitmap tmp;
289 // note we explicitly specify our rowBytes to be snug (no gap between rows)
290 tmp.setConfig(SkBitmap::kARGB_8888_Config, w, h, w * 4);
291 if (!tmp.allocPixels()) {
292 return false;
293 }
294
Scroggo813c33c2011-04-07 20:56:21 +0000295 tmp.lockPixels();
reed@google.comac10a2d2010-12-22 21:39:39 +0000296
Scroggoeb176032011-04-07 21:11:49 +0000297 bool read = fContext->readRenderTargetPixels(fRenderTarget,
298 bounds.fLeft, bounds.fTop,
299 bounds.width(), bounds.height(),
300 kRGBA_8888_GrPixelConfig,
301 tmp.getPixels());
Scroggo813c33c2011-04-07 20:56:21 +0000302 tmp.unlockPixels();
303 if (!read) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000304 return false;
305 }
306
307 tmp.swap(*bitmap);
308 return true;
309}
310
311void SkGpuDevice::writePixels(const SkBitmap& bitmap, int x, int y) {
312 SkAutoLockPixels alp(bitmap);
313 if (!bitmap.readyToDraw()) {
314 return;
315 }
bsalomon@google.com669fdc42011-04-05 17:08:27 +0000316 GrPixelConfig config = SkGr::BitmapConfig2PixelConfig(bitmap.config(),
317 bitmap.isOpaque());
reed@google.comac10a2d2010-12-22 21:39:39 +0000318 fContext->setRenderTarget(fRenderTarget);
319 // we aren't setting the clip or matrix, so mark as dirty
320 // we don't need to set them for this call and don't have them anyway
321 fNeedPrepareRenderTarget = true;
322
323 fContext->writePixels(x, y, bitmap.width(), bitmap.height(),
324 config, bitmap.getPixels(), bitmap.rowBytes());
325}
326
327///////////////////////////////////////////////////////////////////////////////
328
329static void convert_matrixclip(GrContext* context, const SkMatrix& matrix,
bsalomon@google.comd302f142011-03-03 13:54:13 +0000330 const SkClipStack& clipStack,
reed@google.com6f8f2922011-03-04 22:27:10 +0000331 const SkRegion& clipRegion,
332 const SkIPoint& origin) {
bsalomon@google.comcc4dac32011-05-10 13:52:42 +0000333 context->setMatrix(matrix);
reed@google.comac10a2d2010-12-22 21:39:39 +0000334
335 SkGrClipIterator iter;
bsalomon@google.comd302f142011-03-03 13:54:13 +0000336 iter.reset(clipStack);
bsalomon@google.comd302f142011-03-03 13:54:13 +0000337 const SkIRect& skBounds = clipRegion.getBounds();
338 GrRect bounds;
339 bounds.setLTRB(GrIntToScalar(skBounds.fLeft),
340 GrIntToScalar(skBounds.fTop),
341 GrIntToScalar(skBounds.fRight),
342 GrIntToScalar(skBounds.fBottom));
reed@google.com6f8f2922011-03-04 22:27:10 +0000343 GrClip grc(&iter, GrIntToScalar(-origin.x()), GrIntToScalar(-origin.y()),
344 &bounds);
bsalomon@google.comd302f142011-03-03 13:54:13 +0000345 context->setClip(grc);
reed@google.comac10a2d2010-12-22 21:39:39 +0000346}
347
348// call this ever each draw call, to ensure that the context reflects our state,
349// and not the state from some other canvas/device
350void SkGpuDevice::prepareRenderTarget(const SkDraw& draw) {
351 if (fNeedPrepareRenderTarget ||
bsalomon@google.com5782d712011-01-21 21:03:59 +0000352 fContext->getRenderTarget() != fRenderTarget) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000353
354 fContext->setRenderTarget(fRenderTarget);
bsalomon@google.comd302f142011-03-03 13:54:13 +0000355 SkASSERT(draw.fClipStack);
356 convert_matrixclip(fContext, *draw.fMatrix,
reed@google.com6f8f2922011-03-04 22:27:10 +0000357 *draw.fClipStack, *draw.fClip, this->getOrigin());
reed@google.comac10a2d2010-12-22 21:39:39 +0000358 fNeedPrepareRenderTarget = false;
359 }
360}
361
reed@google.com46799cd2011-02-22 20:56:26 +0000362void SkGpuDevice::setMatrixClip(const SkMatrix& matrix, const SkRegion& clip,
363 const SkClipStack& clipStack) {
364 this->INHERITED::setMatrixClip(matrix, clip, clipStack);
bsalomon@google.coma7bf6e22011-04-11 19:20:46 +0000365 // We don't need to set them now because the context may not reflect this device.
366 fNeedPrepareRenderTarget = true;
reed@google.comac10a2d2010-12-22 21:39:39 +0000367}
368
369void SkGpuDevice::gainFocus(SkCanvas* canvas, const SkMatrix& matrix,
bsalomon@google.comd302f142011-03-03 13:54:13 +0000370 const SkRegion& clip, const SkClipStack& clipStack) {
371
reed@google.comac10a2d2010-12-22 21:39:39 +0000372 fContext->setRenderTarget(fRenderTarget);
373
bsalomon@google.comd302f142011-03-03 13:54:13 +0000374 this->INHERITED::gainFocus(canvas, matrix, clip, clipStack);
reed@google.comac10a2d2010-12-22 21:39:39 +0000375
reed@google.com6f8f2922011-03-04 22:27:10 +0000376 convert_matrixclip(fContext, matrix, clipStack, clip, this->getOrigin());
reed@google.comac10a2d2010-12-22 21:39:39 +0000377
378 if (fNeedClear) {
bsalomon@google.com31a58402011-04-27 21:00:02 +0000379 fContext->clear(NULL, 0x0);
reed@google.comac10a2d2010-12-22 21:39:39 +0000380 fNeedClear = false;
381 }
382}
383
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000384bool SkGpuDevice::bindDeviceAsTexture(GrPaint* paint) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000385 if (NULL != fTexture) {
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000386 paint->setTexture(kBitmapTextureIdx, fTexture);
reed@google.comac10a2d2010-12-22 21:39:39 +0000387 return true;
388 }
389 return false;
390}
391
392///////////////////////////////////////////////////////////////////////////////
393
vandebo@chromium.orgd3ae7792011-02-24 00:21:06 +0000394SK_COMPILE_ASSERT(SkShader::kNone_BitmapType == 0, shader_type_mismatch);
395SK_COMPILE_ASSERT(SkShader::kDefault_BitmapType == 1, shader_type_mismatch);
396SK_COMPILE_ASSERT(SkShader::kRadial_BitmapType == 2, shader_type_mismatch);
397SK_COMPILE_ASSERT(SkShader::kSweep_BitmapType == 3, shader_type_mismatch);
398SK_COMPILE_ASSERT(SkShader::kTwoPointRadial_BitmapType == 4,
399 shader_type_mismatch);
400SK_COMPILE_ASSERT(SkShader::kLast_BitmapType == 4, shader_type_mismatch);
reed@google.comac10a2d2010-12-22 21:39:39 +0000401
bsalomon@google.com5782d712011-01-21 21:03:59 +0000402static const GrSamplerState::SampleMode sk_bmp_type_to_sample_mode[] = {
403 (GrSamplerState::SampleMode) -1, // kNone_BitmapType
404 GrSamplerState::kNormal_SampleMode, // kDefault_BitmapType
405 GrSamplerState::kRadial_SampleMode, // kRadial_BitmapType
406 GrSamplerState::kSweep_SampleMode, // kSweep_BitmapType
407 GrSamplerState::kRadial2_SampleMode, // kTwoPointRadial_BitmapType
408};
409
410bool SkGpuDevice::skPaint2GrPaintNoShader(const SkPaint& skPaint,
411 bool justAlpha,
Scroggod757df22011-05-16 13:11:16 +0000412 GrPaint* grPaint,
413 bool constantColor) {
bsalomon@google.com5782d712011-01-21 21:03:59 +0000414
415 grPaint->fDither = skPaint.isDither();
416 grPaint->fAntiAlias = skPaint.isAntiAlias();
417
418 SkXfermode::Coeff sm = SkXfermode::kOne_Coeff;
419 SkXfermode::Coeff dm = SkXfermode::kISA_Coeff;
420
421 SkXfermode* mode = skPaint.getXfermode();
422 if (mode) {
423 if (!mode->asCoeff(&sm, &dm)) {
reed@google.com1a2e8d22011-01-21 22:08:29 +0000424 SkDEBUGCODE(SkDebugf("Unsupported xfer mode.\n");)
bsalomon@google.com5782d712011-01-21 21:03:59 +0000425#if 0
426 return false;
427#endif
428 }
429 }
430 grPaint->fSrcBlendCoeff = sk_blend_to_grblend(sm);
431 grPaint->fDstBlendCoeff = sk_blend_to_grblend(dm);
432
433 if (justAlpha) {
434 uint8_t alpha = skPaint.getAlpha();
435 grPaint->fColor = GrColorPackRGBA(alpha, alpha, alpha, alpha);
Scroggod757df22011-05-16 13:11:16 +0000436 // justAlpha is currently set to true only if there is a texture,
437 // so constantColor should not also be true.
438 GrAssert(!constantColor);
bsalomon@google.com5782d712011-01-21 21:03:59 +0000439 } else {
440 grPaint->fColor = SkGr::SkColor2GrColor(skPaint.getColor());
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000441 grPaint->setTexture(kShaderTextureIdx, NULL);
bsalomon@google.com5782d712011-01-21 21:03:59 +0000442 }
Scroggo97c88c22011-05-11 14:05:25 +0000443 SkColorFilter* colorFilter = skPaint.getColorFilter();
444 SkColor color;
445 SkXfermode::Mode filterMode;
446 if (colorFilter != NULL && colorFilter->asColorMode(&color, &filterMode)) {
Scroggod757df22011-05-16 13:11:16 +0000447 if (!constantColor) {
448 grPaint->fColorFilterColor = SkGr::SkColor2GrColor(color);
449 grPaint->fColorFilterXfermode = filterMode;
450 return true;
451 }
452 SkColor filtered = colorFilter->filterColor(skPaint.getColor());
453 grPaint->fColor = SkGr::SkColor2GrColor(filtered);
Scroggo97c88c22011-05-11 14:05:25 +0000454 }
Scroggod757df22011-05-16 13:11:16 +0000455 grPaint->resetColorFilter();
bsalomon@google.com5782d712011-01-21 21:03:59 +0000456 return true;
reed@google.comac10a2d2010-12-22 21:39:39 +0000457}
458
bsalomon@google.com5782d712011-01-21 21:03:59 +0000459bool SkGpuDevice::skPaint2GrPaintShader(const SkPaint& skPaint,
460 SkAutoCachedTexture* act,
461 const SkMatrix& ctm,
Scroggod757df22011-05-16 13:11:16 +0000462 GrPaint* grPaint,
463 bool constantColor) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000464
bsalomon@google.com5782d712011-01-21 21:03:59 +0000465 SkASSERT(NULL != act);
reed@google.comac10a2d2010-12-22 21:39:39 +0000466
bsalomon@google.com5782d712011-01-21 21:03:59 +0000467 SkShader* shader = skPaint.getShader();
reed@google.comac10a2d2010-12-22 21:39:39 +0000468 if (NULL == shader) {
Scroggod757df22011-05-16 13:11:16 +0000469 return this->skPaint2GrPaintNoShader(skPaint,
470 false,
471 grPaint,
472 constantColor);
473 } else if (!this->skPaint2GrPaintNoShader(skPaint, true, grPaint, false)) {
bsalomon@google.com5782d712011-01-21 21:03:59 +0000474 return false;
reed@google.comac10a2d2010-12-22 21:39:39 +0000475 }
476
reed@google.comac10a2d2010-12-22 21:39:39 +0000477 SkBitmap bitmap;
478 SkMatrix matrix;
479 SkShader::TileMode tileModes[2];
480 SkScalar twoPointParams[3];
481 SkShader::BitmapType bmptype = shader->asABitmap(&bitmap, &matrix,
482 tileModes, twoPointParams);
483
bsalomon@google.com5782d712011-01-21 21:03:59 +0000484 GrSamplerState::SampleMode sampleMode = sk_bmp_type_to_sample_mode[bmptype];
485 if (-1 == sampleMode) {
reed@google.com2be9e8b2011-07-06 21:18:09 +0000486 SkShader::GradientInfo info;
487 SkColor color;
488
489 info.fColors = &color;
490 info.fColorOffsets = NULL;
491 info.fColorCount = 1;
492 if (SkShader::kColor_GradientType == shader->asAGradient(&info)) {
493 SkPaint copy(skPaint);
494 copy.setShader(NULL);
bsalomon@google.comcd9cfd72011-07-08 16:55:04 +0000495 // modulate the paint alpha by the shader's solid color alpha
496 U8CPU newA = SkMulDiv255Round(SkColorGetA(color), copy.getAlpha());
497 copy.setColor(SkColorSetA(color, newA));
reed@google.com2be9e8b2011-07-06 21:18:09 +0000498 return this->skPaint2GrPaintNoShader(copy,
499 false,
500 grPaint,
501 constantColor);
502 }
bsalomon@google.com5782d712011-01-21 21:03:59 +0000503 return false;
reed@google.comac10a2d2010-12-22 21:39:39 +0000504 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000505 GrSamplerState* sampler = grPaint->getTextureSampler(kShaderTextureIdx);
506 sampler->setSampleMode(sampleMode);
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000507 if (skPaint.isFilterBitmap()) {
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000508 sampler->setFilter(GrSamplerState::kBilinear_Filter);
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000509 } else {
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000510 sampler->setFilter(GrSamplerState::kNearest_Filter);
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000511 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000512 sampler->setWrapX(sk_tile_mode_to_grwrap(tileModes[0]));
513 sampler->setWrapY(sk_tile_mode_to_grwrap(tileModes[1]));
reed@google.comac10a2d2010-12-22 21:39:39 +0000514 if (GrSamplerState::kRadial2_SampleMode == sampleMode) {
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000515 sampler->setRadial2Params(twoPointParams[0],
516 twoPointParams[1],
517 twoPointParams[2] < 0);
reed@google.comac10a2d2010-12-22 21:39:39 +0000518 }
519
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000520 GrTexture* texture = act->set(this, bitmap, *sampler);
reed@google.comac10a2d2010-12-22 21:39:39 +0000521 if (NULL == texture) {
bsalomon@google.com5782d712011-01-21 21:03:59 +0000522 SkDebugf("Couldn't convert bitmap to texture.\n");
523 return false;
reed@google.comac10a2d2010-12-22 21:39:39 +0000524 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000525 grPaint->setTexture(kShaderTextureIdx, texture);
reed@google.comac10a2d2010-12-22 21:39:39 +0000526
527 // since our texture coords will be in local space, we wack the texture
528 // matrix to map them back into 0...1 before we load it
529 SkMatrix localM;
530 if (shader->getLocalMatrix(&localM)) {
531 SkMatrix inverse;
532 if (localM.invert(&inverse)) {
533 matrix.preConcat(inverse);
534 }
535 }
536 if (SkShader::kDefault_BitmapType == bmptype) {
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000537 GrScalar sx = GrFixedToScalar(GR_Fixed1 / bitmap.width());
538 GrScalar sy = GrFixedToScalar(GR_Fixed1 / bitmap.height());
reed@google.comac10a2d2010-12-22 21:39:39 +0000539 matrix.postScale(sx, sy);
reed@google.comac10a2d2010-12-22 21:39:39 +0000540 } else if (SkShader::kRadial_BitmapType == bmptype) {
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000541 GrScalar s = GrFixedToScalar(GR_Fixed1 / bitmap.width());
reed@google.comac10a2d2010-12-22 21:39:39 +0000542 matrix.postScale(s, s);
543 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000544 sampler->setMatrix(matrix);
bsalomon@google.com5782d712011-01-21 21:03:59 +0000545
546 return true;
reed@google.comac10a2d2010-12-22 21:39:39 +0000547}
548
549///////////////////////////////////////////////////////////////////////////////
bsalomon@google.com5782d712011-01-21 21:03:59 +0000550
551class SkPositionSource {
552public:
553 SkPositionSource(const SkPoint* points, int count)
554 : fPoints(points), fCount(count) {}
555
556 int count() const { return fCount; }
557
558 void writeValue(int i, GrPoint* dstPosition) const {
559 SkASSERT(i < fCount);
560 dstPosition->fX = SkScalarToGrScalar(fPoints[i].fX);
561 dstPosition->fY = SkScalarToGrScalar(fPoints[i].fY);
562 }
563private:
bsalomon@google.com5782d712011-01-21 21:03:59 +0000564 const SkPoint* fPoints;
bsalomon@google.com19628322011-02-03 21:30:17 +0000565 int fCount;
bsalomon@google.com5782d712011-01-21 21:03:59 +0000566};
567
568class SkTexCoordSource {
569public:
570 SkTexCoordSource(const SkPoint* coords)
571 : fCoords(coords) {}
572
573 void writeValue(int i, GrPoint* dstCoord) const {
574 dstCoord->fX = SkScalarToGrScalar(fCoords[i].fX);
575 dstCoord->fY = SkScalarToGrScalar(fCoords[i].fY);
576 }
577private:
578 const SkPoint* fCoords;
579};
580
581class SkColorSource {
582public:
583 SkColorSource(const SkColor* colors) : fColors(colors) {}
584
585 void writeValue(int i, GrColor* dstColor) const {
586 *dstColor = SkGr::SkColor2GrColor(fColors[i]);
587 }
588private:
589 const SkColor* fColors;
590};
591
592class SkIndexSource {
593public:
594 SkIndexSource(const uint16_t* indices, int count)
595 : fIndices(indices), fCount(count) {
596 }
597
598 int count() const { return fCount; }
599
600 void writeValue(int i, uint16_t* dstIndex) const {
601 *dstIndex = fIndices[i];
602 }
603
604private:
bsalomon@google.com5782d712011-01-21 21:03:59 +0000605 const uint16_t* fIndices;
bsalomon@google.com19628322011-02-03 21:30:17 +0000606 int fCount;
bsalomon@google.com5782d712011-01-21 21:03:59 +0000607};
608
609///////////////////////////////////////////////////////////////////////////////
610
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000611#if 0 // not currently being used so don't compile,
612
bsalomon@google.com5782d712011-01-21 21:03:59 +0000613// can be used for positions or texture coordinates
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000614
bsalomon@google.com5782d712011-01-21 21:03:59 +0000615class SkRectFanSource {
616public:
617 SkRectFanSource(const SkRect& rect) : fRect(rect) {}
618
619 int count() const { return 4; }
620
621 void writeValue(int i, GrPoint* dstPoint) const {
622 SkASSERT(i < 4);
623 dstPoint->fX = SkScalarToGrScalar((i % 3) ? fRect.fRight :
624 fRect.fLeft);
625 dstPoint->fY = SkScalarToGrScalar((i < 2) ? fRect.fTop :
626 fRect.fBottom);
627 }
628private:
629 const SkRect& fRect;
630};
631
632class SkIRectFanSource {
633public:
634 SkIRectFanSource(const SkIRect& rect) : fRect(rect) {}
635
636 int count() const { return 4; }
637
638 void writeValue(int i, GrPoint* dstPoint) const {
639 SkASSERT(i < 4);
640 dstPoint->fX = (i % 3) ? GrIntToScalar(fRect.fRight) :
641 GrIntToScalar(fRect.fLeft);
642 dstPoint->fY = (i < 2) ? GrIntToScalar(fRect.fTop) :
643 GrIntToScalar(fRect.fBottom);
644 }
645private:
646 const SkIRect& fRect;
647};
648
649class SkMatRectFanSource {
650public:
651 SkMatRectFanSource(const SkRect& rect, const SkMatrix& matrix)
652 : fRect(rect), fMatrix(matrix) {}
653
654 int count() const { return 4; }
655
656 void writeValue(int i, GrPoint* dstPoint) const {
657 SkASSERT(i < 4);
658
659#if SK_SCALAR_IS_GR_SCALAR
660 fMatrix.mapXY((i % 3) ? fRect.fRight : fRect.fLeft,
661 (i < 2) ? fRect.fTop : fRect.fBottom,
662 (SkPoint*)dstPoint);
663#else
664 SkPoint dst;
665 fMatrix.mapXY((i % 3) ? fRect.fRight : fRect.fLeft,
666 (i < 2) ? fRect.fTop : fRect.fBottom,
667 &dst);
668 dstPoint->fX = SkScalarToGrScalar(dst.fX);
669 dstPoint->fY = SkScalarToGrScalar(dst.fY);
670#endif
671 }
672private:
673 const SkRect& fRect;
674 const SkMatrix& fMatrix;
675};
676
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000677#endif
678
reed@google.comac10a2d2010-12-22 21:39:39 +0000679///////////////////////////////////////////////////////////////////////////////
680
bsalomon@google.com398109c2011-04-14 18:40:27 +0000681void SkGpuDevice::clear(SkColor color) {
bsalomon@google.com31a58402011-04-27 21:00:02 +0000682 fContext->clear(NULL, color);
bsalomon@google.com398109c2011-04-14 18:40:27 +0000683}
684
reed@google.comac10a2d2010-12-22 21:39:39 +0000685void SkGpuDevice::drawPaint(const SkDraw& draw, const SkPaint& paint) {
686 CHECK_SHOULD_DRAW(draw);
687
bsalomon@google.com5782d712011-01-21 21:03:59 +0000688 GrPaint grPaint;
689 SkAutoCachedTexture act;
Scroggod757df22011-05-16 13:11:16 +0000690 if (!this->skPaint2GrPaintShader(paint,
691 &act,
692 *draw.fMatrix,
693 &grPaint,
694 true)) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000695 return;
696 }
bsalomon@google.com5782d712011-01-21 21:03:59 +0000697
698 fContext->drawPaint(grPaint);
reed@google.comac10a2d2010-12-22 21:39:39 +0000699}
700
701// must be in SkCanvas::PointMode order
bsalomon@google.comffca4002011-02-22 20:34:01 +0000702static const GrPrimitiveType gPointMode2PrimtiveType[] = {
703 kPoints_PrimitiveType,
704 kLines_PrimitiveType,
705 kLineStrip_PrimitiveType
reed@google.comac10a2d2010-12-22 21:39:39 +0000706};
707
708void SkGpuDevice::drawPoints(const SkDraw& draw, SkCanvas::PointMode mode,
bsalomon@google.com5782d712011-01-21 21:03:59 +0000709 size_t count, const SkPoint pts[], const SkPaint& paint) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000710 CHECK_SHOULD_DRAW(draw);
711
712 SkScalar width = paint.getStrokeWidth();
713 if (width < 0) {
714 return;
715 }
716
717 // we only handle hairlines here, else we let the SkDraw call our drawPath()
718 if (width > 0) {
719 draw.drawPoints(mode, count, pts, paint, true);
720 return;
721 }
722
bsalomon@google.com5782d712011-01-21 21:03:59 +0000723 GrPaint grPaint;
724 SkAutoCachedTexture act;
Scroggod757df22011-05-16 13:11:16 +0000725 if (!this->skPaint2GrPaintShader(paint,
726 &act,
727 *draw.fMatrix,
728 &grPaint,
729 true)) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000730 return;
731 }
732
reed@google.comac10a2d2010-12-22 21:39:39 +0000733#if SK_SCALAR_IS_GR_SCALAR
bsalomon@google.com5782d712011-01-21 21:03:59 +0000734 fContext->drawVertices(grPaint,
735 gPointMode2PrimtiveType[mode],
736 count,
737 (GrPoint*)pts,
738 NULL,
739 NULL,
740 NULL,
741 0);
reed@google.comac10a2d2010-12-22 21:39:39 +0000742#else
bsalomon@google.com5782d712011-01-21 21:03:59 +0000743 fContext->drawCustomVertices(grPaint,
744 gPointMode2PrimtiveType[mode],
745 SkPositionSource(pts, count));
reed@google.comac10a2d2010-12-22 21:39:39 +0000746#endif
reed@google.comac10a2d2010-12-22 21:39:39 +0000747}
748
reed@google.comc9aa5872011-04-05 21:05:37 +0000749///////////////////////////////////////////////////////////////////////////////
750
reed@google.comac10a2d2010-12-22 21:39:39 +0000751void SkGpuDevice::drawRect(const SkDraw& draw, const SkRect& rect,
752 const SkPaint& paint) {
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000753 CHECK_SHOULD_DRAW(draw);
754
755 bool doStroke = paint.getStyle() == SkPaint::kStroke_Style;
756 SkScalar width = paint.getStrokeWidth();
757
758 /*
759 We have special code for hairline strokes, miter-strokes, and fills.
760 Anything else we just call our path code.
761 */
762 bool usePath = doStroke && width > 0 &&
763 paint.getStrokeJoin() != SkPaint::kMiter_Join;
764 // another reason we might need to call drawPath...
765 if (paint.getMaskFilter()) {
766 usePath = true;
767 }
reed@google.com67db6642011-05-26 11:46:35 +0000768 // until we aa rotated rects...
769 if (!usePath && paint.isAntiAlias() && !draw.fMatrix->rectStaysRect()) {
770 usePath = true;
771 }
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000772
773 if (usePath) {
774 SkPath path;
775 path.addRect(rect);
776 this->drawPath(draw, path, paint, NULL, true);
777 return;
778 }
779
780 GrPaint grPaint;
781 SkAutoCachedTexture act;
Scroggod757df22011-05-16 13:11:16 +0000782 if (!this->skPaint2GrPaintShader(paint,
783 &act,
784 *draw.fMatrix,
785 &grPaint,
786 true)) {
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000787 return;
788 }
reed@google.com20efde72011-05-09 17:00:02 +0000789 fContext->drawRect(grPaint, rect, doStroke ? width : -1);
reed@google.comac10a2d2010-12-22 21:39:39 +0000790}
791
reed@google.com69302852011-02-16 18:08:07 +0000792#include "SkMaskFilter.h"
793#include "SkBounder.h"
794
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +0000795static GrPathFill skToGrFillType(SkPath::FillType fillType) {
796 switch (fillType) {
797 case SkPath::kWinding_FillType:
798 return kWinding_PathFill;
799 case SkPath::kEvenOdd_FillType:
800 return kEvenOdd_PathFill;
801 case SkPath::kInverseWinding_FillType:
802 return kInverseWinding_PathFill;
803 case SkPath::kInverseEvenOdd_FillType:
804 return kInverseEvenOdd_PathFill;
805 default:
806 SkDebugf("Unsupported path fill type\n");
807 return kHairLine_PathFill;
808 }
809}
810
811static float gauss(float x, float sigma)
812{
813 // Note that the constant term (1/(sqrt(2*pi*sigma^2)) is dropped here,
814 // since we renormalize the kernel after generation anyway.
815 return exp(- (x * x) / (2.0f * sigma * sigma));
816}
817
818static void buildKernel(float sigma, float* kernel, int kernelWidth)
819{
820 int halfWidth = (kernelWidth - 1) / 2;
821 float sum = 0.0f;
822 for (int i = 0; i < kernelWidth; ++i) {
823 kernel[i] = gauss(i - halfWidth, sigma);
824 sum += kernel[i];
825 }
826 // Normalize the kernel
827 float scale = 1.0f / sum;
828 for (int i = 0; i < kernelWidth; ++i)
829 kernel[i] *= scale;
830}
831
832static void swap(GrTexture*& a, GrTexture*& b)
833{
834 GrTexture* tmp = a;
835 a = b;
836 b = tmp;
837}
838
839static void scaleRect(SkRect* rect, float scale)
840{
841 rect->fLeft *= scale;
842 rect->fTop *= scale;
843 rect->fRight *= scale;
844 rect->fBottom *= scale;
845}
846
847static bool drawWithGPUMaskFilter(GrContext* context, const SkPath& path,
848 SkMaskFilter* filter, const SkMatrix& matrix,
849 const SkRegion& clip, SkBounder* bounder,
850 GrPaint* grp) {
851 SkMaskFilter::BlurInfo info;
852 if (!filter->asABlur(&info)) {
853 return false;
854 }
855 float radius = info.fIgnoreTransform ? info.fRadius
856 : matrix.mapRadius(info.fRadius);
857 float sigma = radius * 0.6666f;
858 SkRect srcRect = path.getBounds();
859
860 int scaleFactor = 1;
861
862 while (sigma > MAX_SIGMA) {
863 scaleFactor *= 2;
864 sigma *= 0.5f;
865 }
866 scaleRect(&srcRect, 1.0f / scaleFactor);
867 int halfWidth = static_cast<int>(sigma * 3.0f);
868 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)) {
881 return false;
882 }
883 if (bounder && !bounder->doIRect(finalIRect)) {
884 return false;
885 }
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);
900 if (NULL == srcEntry || NULL == dstEntry) {
901 return false;
902 }
903 GrTexture* srcTexture = srcEntry->texture();
904 GrTexture* dstTexture = dstEntry->texture();
905 if (NULL == srcTexture || NULL == dstTexture) {
906 return false;
907 }
908 GrRenderTarget* oldRenderTarget = context->getRenderTarget();
909 context->setRenderTarget(dstTexture->asRenderTarget());
910 // FIXME: could just clear bounds
911 context->clear(NULL, 0);
912 GrMatrix transM;
913 GrPaint tempPaint;
914 tempPaint.reset();
915
916 GrAutoMatrix avm(context, GrMatrix::I());
917 // Draw hard shadow to offscreen context, with path topleft at origin 0,0.
918 context->drawPath(tempPaint, path, skToGrFillType(path.getFillType()), &offset);
919 swap(srcTexture, dstTexture);
920
921 GrMatrix sampleM;
922 sampleM.setScale(GR_Scalar1 / srcTexture->width(),
923 GR_Scalar1 / srcTexture->height());
924 GrPaint paint;
925 paint.reset();
926 paint.getTextureSampler(0)->setFilter(GrSamplerState::kBilinear_Filter);
927 paint.getTextureSampler(0)->setMatrix(sampleM);
928 for (int i = 1; i < scaleFactor; i *= 2) {
929 context->setRenderTarget(dstTexture->asRenderTarget());
930 SkRect dstRect(srcRect);
931 scaleRect(&dstRect, 0.5f);
932 // Clear out 1 pixel border for linear filtering.
933 // FIXME: for now, clear everything
934 context->clear(NULL, 0);
935 paint.setTexture(0, srcTexture);
936 context->drawRectToRect(paint, dstRect, srcRect);
937 srcRect = dstRect;
938 swap(srcTexture, dstTexture);
939 }
940
941 SkAutoTMalloc<float> kernelStorage(kernelWidth);
942 float* kernel = kernelStorage.get();
943 buildKernel(sigma, kernel, kernelWidth);
944
945 float imageIncrementX[2] = {1.0f / srcTexture->width(), 0.0f};
946 context->setRenderTarget(dstTexture->asRenderTarget());
947 context->clear(NULL, 0);
948 context->convolveRect(srcTexture, srcRect, imageIncrementX, kernel,
949 kernelWidth);
950 swap(srcTexture, dstTexture);
951
952 float imageIncrementY[2] = {0.0f, 1.0f / srcTexture->height()};
953 context->setRenderTarget(dstTexture->asRenderTarget());
954 context->clear(NULL, 0);
955 context->convolveRect(srcTexture, srcRect, imageIncrementY, kernel,
956 kernelWidth);
957 swap(srcTexture, dstTexture);
958
959 if (scaleFactor > 1) {
960 // FIXME: This should be mitchell, not bilinear.
961 paint.getTextureSampler(0)->setFilter(GrSamplerState::kBilinear_Filter);
962 sampleM.setScale(GR_Scalar1 / srcTexture->width(),
963 GR_Scalar1 / srcTexture->height());
964 paint.getTextureSampler(0)->setMatrix(sampleM);
965 context->setRenderTarget(dstTexture->asRenderTarget());
966 // Clear out 2 pixel border for bicubic filtering.
967 // FIXME: for now, clear everything
968 context->clear(NULL, 0);
969 paint.setTexture(0, srcTexture);
970 SkRect dstRect(srcRect);
971 scaleRect(&dstRect, scaleFactor);
972 context->drawRectToRect(paint, dstRect, srcRect);
973 srcRect = dstRect;
974 swap(srcTexture, dstTexture);
975 }
976
977 context->setRenderTarget(oldRenderTarget);
978
979 if (grp->hasTextureOrMask()) {
980 GrMatrix inverse;
981 if (!matrix.invert(&inverse)) {
982 return false;
983 }
984 grp->preConcatActiveSamplerMatrices(inverse);
985 }
986
987 static const int MASK_IDX = GrPaint::kMaxMasks - 1;
988 // we assume the last mask index is available for use
989 GrAssert(NULL == grp->getMask(MASK_IDX));
990 grp->setMask(MASK_IDX, srcTexture);
991 grp->getMaskSampler(MASK_IDX)->setClampNoFilter();
992
993 GrMatrix m;
994 m.setTranslate(-finalRect.fLeft, -finalRect.fTop);
995 m.postIDiv(srcTexture->width(), srcTexture->height());
996 grp->getMaskSampler(MASK_IDX)->setMatrix(m);
997 context->drawRect(*grp, finalRect);
998 context->unlockTexture(srcEntry);
999 context->unlockTexture(dstEntry);
1000 return true;
1001}
1002
reed@google.com69302852011-02-16 18:08:07 +00001003static bool drawWithMaskFilter(GrContext* context, const SkPath& path,
1004 SkMaskFilter* filter, const SkMatrix& matrix,
1005 const SkRegion& clip, SkBounder* bounder,
1006 GrPaint* grp) {
1007 SkMask srcM, dstM;
1008
1009 if (!SkDraw::DrawToMask(path, &clip.getBounds(), filter, &matrix, &srcM,
1010 SkMask::kComputeBoundsAndRenderImage_CreateMode)) {
1011 return false;
1012 }
1013
1014 SkAutoMaskImage autoSrc(&srcM, false);
1015
1016 if (!filter->filterMask(&dstM, srcM, matrix, NULL)) {
1017 return false;
1018 }
1019 // this will free-up dstM when we're done (allocated in filterMask())
1020 SkAutoMaskImage autoDst(&dstM, false);
1021
1022 if (clip.quickReject(dstM.fBounds)) {
1023 return false;
1024 }
1025 if (bounder && !bounder->doIRect(dstM.fBounds)) {
1026 return false;
1027 }
1028
1029 // we now have a device-aligned 8bit mask in dstM, ready to be drawn using
1030 // the current clip (and identity matrix) and grpaint settings
1031
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001032 // used to compute inverse view, if necessary
1033 GrMatrix ivm = context->getMatrix();
1034
reed@google.com0c219b62011-02-16 21:31:18 +00001035 GrAutoMatrix avm(context, GrMatrix::I());
reed@google.com69302852011-02-16 18:08:07 +00001036
bsalomon@google.comfea37b52011-04-25 15:51:06 +00001037 const GrTextureDesc desc = {
1038 kNone_GrTextureFlags,
1039 kNone_GrAALevel,
reed@google.com69302852011-02-16 18:08:07 +00001040 dstM.fBounds.width(),
1041 dstM.fBounds.height(),
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001042 kAlpha_8_GrPixelConfig
reed@google.com69302852011-02-16 18:08:07 +00001043 };
1044
1045 GrTexture* texture = context->createUncachedTexture(desc, dstM.fImage,
1046 dstM.fRowBytes);
1047 if (NULL == texture) {
1048 return false;
1049 }
1050
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001051 if (grp->hasTextureOrMask() && ivm.invert(&ivm)) {
1052 grp->preConcatActiveSamplerMatrices(ivm);
1053 }
1054
1055 static const int MASK_IDX = GrPaint::kMaxMasks - 1;
1056 // we assume the last mask index is available for use
1057 GrAssert(NULL == grp->getMask(MASK_IDX));
1058 grp->setMask(MASK_IDX, texture);
reed@google.com0c219b62011-02-16 21:31:18 +00001059 texture->unref();
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001060 grp->getMaskSampler(MASK_IDX)->setClampNoFilter();
reed@google.com69302852011-02-16 18:08:07 +00001061
bsalomon@google.comc6cf7232011-02-17 16:43:10 +00001062 GrRect d;
1063 d.setLTRB(GrIntToScalar(dstM.fBounds.fLeft),
reed@google.com0c219b62011-02-16 21:31:18 +00001064 GrIntToScalar(dstM.fBounds.fTop),
1065 GrIntToScalar(dstM.fBounds.fRight),
1066 GrIntToScalar(dstM.fBounds.fBottom));
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001067
1068 GrMatrix m;
1069 m.setTranslate(-dstM.fBounds.fLeft, -dstM.fBounds.fTop);
1070 m.postIDiv(dstM.fBounds.width(), dstM.fBounds.height());
1071 grp->getMaskSampler(MASK_IDX)->setMatrix(m);
1072
1073 context->drawRect(*grp, d);
reed@google.com69302852011-02-16 18:08:07 +00001074 return true;
1075}
reed@google.com69302852011-02-16 18:08:07 +00001076
reed@google.com0c219b62011-02-16 21:31:18 +00001077void SkGpuDevice::drawPath(const SkDraw& draw, const SkPath& origSrcPath,
reed@google.comac10a2d2010-12-22 21:39:39 +00001078 const SkPaint& paint, const SkMatrix* prePathMatrix,
1079 bool pathIsMutable) {
1080 CHECK_SHOULD_DRAW(draw);
1081
bsalomon@google.com5782d712011-01-21 21:03:59 +00001082 GrPaint grPaint;
1083 SkAutoCachedTexture act;
Scroggod757df22011-05-16 13:11:16 +00001084 if (!this->skPaint2GrPaintShader(paint,
1085 &act,
1086 *draw.fMatrix,
1087 &grPaint,
1088 true)) {
reed@google.comac10a2d2010-12-22 21:39:39 +00001089 return;
1090 }
1091
reed@google.com0c219b62011-02-16 21:31:18 +00001092 // BEGIN lift from SkDraw::drawPath()
1093
1094 SkPath* pathPtr = const_cast<SkPath*>(&origSrcPath);
1095 bool doFill = true;
1096 SkPath tmpPath;
reed@google.comac10a2d2010-12-22 21:39:39 +00001097
1098 if (prePathMatrix) {
reed@google.come3445642011-02-16 23:20:39 +00001099 SkPath* result = pathPtr;
reed@google.com0c219b62011-02-16 21:31:18 +00001100
reed@google.come3445642011-02-16 23:20:39 +00001101 if (!pathIsMutable) {
1102 result = &tmpPath;
1103 pathIsMutable = true;
reed@google.comac10a2d2010-12-22 21:39:39 +00001104 }
reed@google.come3445642011-02-16 23:20:39 +00001105 // should I push prePathMatrix on our MV stack temporarily, instead
1106 // of applying it here? See SkDraw.cpp
1107 pathPtr->transform(*prePathMatrix, result);
1108 pathPtr = result;
reed@google.comac10a2d2010-12-22 21:39:39 +00001109 }
reed@google.com0c219b62011-02-16 21:31:18 +00001110 // at this point we're done with prePathMatrix
1111 SkDEBUGCODE(prePathMatrix = (const SkMatrix*)0x50FF8001;)
reed@google.comac10a2d2010-12-22 21:39:39 +00001112
bsalomon@google.com04de7822011-03-25 18:04:43 +00001113 // This "if" is not part of the SkDraw::drawPath() lift.
1114 // When we get a 1.0 wide stroke we hairline stroke it instead of creating
1115 // a new stroked-path. This is motivated by canvas2D sites that draw
1116 // lines as 1.0 wide stroked paths. We can consider doing an alpha-modulated-
1117 // hairline for width < 1.0 when AA is enabled.
1118 static const int gMatrixMask = ~(SkMatrix::kIdentity_Mask |
1119 SkMatrix::kTranslate_Mask);
1120 if (!paint.getPathEffect() &&
1121 SkPaint::kStroke_Style == paint.getStyle() &&
1122 !(draw.fMatrix->getType() & gMatrixMask) &&
1123 SK_Scalar1 == paint.getStrokeWidth()) {
1124 doFill = false;
1125 }
1126
1127 if (doFill && (paint.getPathEffect() ||
1128 paint.getStyle() != SkPaint::kFill_Style)) {
reed@google.com0c219b62011-02-16 21:31:18 +00001129 doFill = paint.getFillPath(*pathPtr, &tmpPath);
1130 pathPtr = &tmpPath;
1131 }
1132
1133 // END lift from SkDraw::drawPath()
1134
reed@google.com69302852011-02-16 18:08:07 +00001135 if (paint.getMaskFilter()) {
reed@google.com0c219b62011-02-16 21:31:18 +00001136 // avoid possibly allocating a new path in transform if we can
1137 SkPath* devPathPtr = pathIsMutable ? pathPtr : &tmpPath;
1138
1139 // transform the path into device space
reed@google.come3445642011-02-16 23:20:39 +00001140 pathPtr->transform(*draw.fMatrix, devPathPtr);
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +00001141 if (USE_GPU_BLUR) {
1142 drawWithGPUMaskFilter(fContext, *devPathPtr, paint.getMaskFilter(),
1143 *draw.fMatrix, *draw.fClip, draw.fBounder,
1144 &grPaint);
1145 } else {
1146 drawWithMaskFilter(fContext, *devPathPtr, paint.getMaskFilter(),
1147 *draw.fMatrix, *draw.fClip, draw.fBounder,
1148 &grPaint);
1149 }
reed@google.com69302852011-02-16 18:08:07 +00001150 return;
1151 }
reed@google.com69302852011-02-16 18:08:07 +00001152
bsalomon@google.comffca4002011-02-22 20:34:01 +00001153 GrPathFill fill = kHairLine_PathFill;
reed@google.comac10a2d2010-12-22 21:39:39 +00001154
reed@google.com0c219b62011-02-16 21:31:18 +00001155 if (doFill) {
1156 switch (pathPtr->getFillType()) {
reed@google.comac10a2d2010-12-22 21:39:39 +00001157 case SkPath::kWinding_FillType:
bsalomon@google.comffca4002011-02-22 20:34:01 +00001158 fill = kWinding_PathFill;
reed@google.comac10a2d2010-12-22 21:39:39 +00001159 break;
1160 case SkPath::kEvenOdd_FillType:
bsalomon@google.comffca4002011-02-22 20:34:01 +00001161 fill = kEvenOdd_PathFill;
reed@google.comac10a2d2010-12-22 21:39:39 +00001162 break;
1163 case SkPath::kInverseWinding_FillType:
bsalomon@google.comffca4002011-02-22 20:34:01 +00001164 fill = kInverseWinding_PathFill;
reed@google.comac10a2d2010-12-22 21:39:39 +00001165 break;
1166 case SkPath::kInverseEvenOdd_FillType:
bsalomon@google.comffca4002011-02-22 20:34:01 +00001167 fill = kInverseEvenOdd_PathFill;
reed@google.comac10a2d2010-12-22 21:39:39 +00001168 break;
1169 default:
bsalomon@google.com5782d712011-01-21 21:03:59 +00001170 SkDebugf("Unsupported path fill type\n");
reed@google.comac10a2d2010-12-22 21:39:39 +00001171 return;
1172 }
1173 }
1174
reed@google.com07f3ee12011-05-16 17:21:57 +00001175 fContext->drawPath(grPaint, *pathPtr, fill);
reed@google.comac10a2d2010-12-22 21:39:39 +00001176}
1177
reed@google.comac10a2d2010-12-22 21:39:39 +00001178void SkGpuDevice::drawBitmap(const SkDraw& draw,
1179 const SkBitmap& bitmap,
1180 const SkIRect* srcRectPtr,
1181 const SkMatrix& m,
1182 const SkPaint& paint) {
1183 CHECK_SHOULD_DRAW(draw);
1184
1185 SkIRect srcRect;
1186 if (NULL == srcRectPtr) {
1187 srcRect.set(0, 0, bitmap.width(), bitmap.height());
1188 } else {
1189 srcRect = *srcRectPtr;
1190 }
1191
junov@google.comd935cfb2011-06-27 20:48:23 +00001192 if (paint.getMaskFilter()){
epoger@google.com9ef2d832011-07-01 21:12:20 +00001193 SkBitmap tmp; // storage if we need a subset of bitmap
junov@google.comd935cfb2011-06-27 20:48:23 +00001194 const SkBitmap* bitmapPtr = &bitmap;
epoger@google.com9ef2d832011-07-01 21:12:20 +00001195 if (srcRectPtr) {
1196 if (!bitmap.extractSubset(&tmp, srcRect)) {
1197 return; // extraction failed
1198 }
1199 bitmapPtr = &tmp;
junov@google.comd935cfb2011-06-27 20:48:23 +00001200 }
1201 SkPaint paintWithTexture(paint);
1202 paintWithTexture.setShader(SkShader::CreateBitmapShader( *bitmapPtr,
1203 SkShader::kClamp_TileMode, SkShader::kClamp_TileMode))->unref();
1204 paintWithTexture.getShader()->setLocalMatrix(m);
1205
1206 SkRect ScalarRect;
epoger@google.com9ef2d832011-07-01 21:12:20 +00001207 ScalarRect.set(srcRect);
junov@google.comd935cfb2011-06-27 20:48:23 +00001208
epoger@google.com9ef2d832011-07-01 21:12:20 +00001209 if (m.rectStaysRect()) {
1210 // Preferred drawing method, optimized for rectangles
1211 m.mapRect(&ScalarRect);
1212 this->drawRect(draw, ScalarRect, paintWithTexture);
1213 } else {
1214 // Slower drawing method, for warped or rotated rectangles
1215 SkPath path;
1216 path.addRect(ScalarRect);
1217 path.transform(m);
1218 this->drawPath(draw, path, paintWithTexture, NULL, true);
1219 }
junov@google.comd935cfb2011-06-27 20:48:23 +00001220 return;
1221 }
1222
bsalomon@google.com5782d712011-01-21 21:03:59 +00001223 GrPaint grPaint;
Scroggod757df22011-05-16 13:11:16 +00001224 if (!this->skPaint2GrPaintNoShader(paint, true, &grPaint, false)) {
bsalomon@google.com5782d712011-01-21 21:03:59 +00001225 return;
1226 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001227 GrSamplerState* sampler = grPaint.getTextureSampler(kBitmapTextureIdx);
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +00001228 if (paint.isFilterBitmap()) {
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001229 sampler->setFilter(GrSamplerState::kBilinear_Filter);
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +00001230 } else {
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001231 sampler->setFilter(GrSamplerState::kNearest_Filter);
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +00001232 }
bsalomon@google.com5782d712011-01-21 21:03:59 +00001233
bsalomon@google.com91958362011-06-13 17:58:13 +00001234 const int maxTextureSize = fContext->getMaxTextureSize();
1235 if (bitmap.getTexture() || (bitmap.width() <= maxTextureSize &&
1236 bitmap.height() <= maxTextureSize)) {
reed@google.comac10a2d2010-12-22 21:39:39 +00001237 // take the fast case
bsalomon@google.com5782d712011-01-21 21:03:59 +00001238 this->internalDrawBitmap(draw, bitmap, srcRect, m, &grPaint);
reed@google.comac10a2d2010-12-22 21:39:39 +00001239 return;
1240 }
1241
1242 // undo the translate done by SkCanvas
1243 int DX = SkMax32(0, srcRect.fLeft);
1244 int DY = SkMax32(0, srcRect.fTop);
1245 // compute clip bounds in local coordinates
1246 SkIRect clipRect;
1247 {
1248 SkRect r;
1249 r.set(draw.fClip->getBounds());
1250 SkMatrix matrix, inverse;
1251 matrix.setConcat(*draw.fMatrix, m);
1252 if (!matrix.invert(&inverse)) {
1253 return;
1254 }
1255 inverse.mapRect(&r);
1256 r.roundOut(&clipRect);
1257 // apply the canvas' translate to our local clip
1258 clipRect.offset(DX, DY);
1259 }
1260
bsalomon@google.com91958362011-06-13 17:58:13 +00001261 int nx = bitmap.width() / maxTextureSize;
1262 int ny = bitmap.height() / maxTextureSize;
reed@google.comac10a2d2010-12-22 21:39:39 +00001263 for (int x = 0; x <= nx; x++) {
1264 for (int y = 0; y <= ny; y++) {
1265 SkIRect tileR;
bsalomon@google.com91958362011-06-13 17:58:13 +00001266 tileR.set(x * maxTextureSize, y * maxTextureSize,
1267 (x + 1) * maxTextureSize, (y + 1) * maxTextureSize);
reed@google.comac10a2d2010-12-22 21:39:39 +00001268 if (!SkIRect::Intersects(tileR, clipRect)) {
1269 continue;
1270 }
1271
1272 SkIRect srcR = tileR;
1273 if (!srcR.intersect(srcRect)) {
1274 continue;
1275 }
1276
1277 SkBitmap tmpB;
1278 if (bitmap.extractSubset(&tmpB, tileR)) {
1279 // now offset it to make it "local" to our tmp bitmap
1280 srcR.offset(-tileR.fLeft, -tileR.fTop);
1281
1282 SkMatrix tmpM(m);
1283 {
1284 int dx = tileR.fLeft - DX + SkMax32(0, srcR.fLeft);
1285 int dy = tileR.fTop - DY + SkMax32(0, srcR.fTop);
1286 tmpM.preTranslate(SkIntToScalar(dx), SkIntToScalar(dy));
1287 }
bsalomon@google.com5782d712011-01-21 21:03:59 +00001288 this->internalDrawBitmap(draw, tmpB, srcR, tmpM, &grPaint);
reed@google.comac10a2d2010-12-22 21:39:39 +00001289 }
1290 }
1291 }
1292}
1293
1294/*
1295 * This is called by drawBitmap(), which has to handle images that may be too
1296 * large to be represented by a single texture.
1297 *
bsalomon@google.com5782d712011-01-21 21:03:59 +00001298 * internalDrawBitmap assumes that the specified bitmap will fit in a texture
1299 * and that non-texture portion of the GrPaint has already been setup.
reed@google.comac10a2d2010-12-22 21:39:39 +00001300 */
1301void SkGpuDevice::internalDrawBitmap(const SkDraw& draw,
1302 const SkBitmap& bitmap,
1303 const SkIRect& srcRect,
1304 const SkMatrix& m,
bsalomon@google.com5782d712011-01-21 21:03:59 +00001305 GrPaint* grPaint) {
bsalomon@google.com91958362011-06-13 17:58:13 +00001306 SkASSERT(bitmap.width() <= fContext->getMaxTextureSize() &&
1307 bitmap.height() <= fContext->getMaxTextureSize());
reed@google.comac10a2d2010-12-22 21:39:39 +00001308
reed@google.com9c49bc32011-07-07 13:42:37 +00001309 SkAutoLockPixels alp(bitmap, !bitmap.getTexture());
reed@google.comac10a2d2010-12-22 21:39:39 +00001310 if (!bitmap.getTexture() && !bitmap.readyToDraw()) {
reed@google.com9c49bc32011-07-07 13:42:37 +00001311 SkDebugf("nothing to draw\n");
reed@google.comac10a2d2010-12-22 21:39:39 +00001312 return;
1313 }
1314
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001315 GrSamplerState* sampler = grPaint->getTextureSampler(kBitmapTextureIdx);
1316
1317 sampler->setWrapX(GrSamplerState::kClamp_WrapMode);
1318 sampler->setWrapY(GrSamplerState::kClamp_WrapMode);
1319 sampler->setSampleMode(GrSamplerState::kNormal_SampleMode);
1320 sampler->setMatrix(GrMatrix::I());
reed@google.comac10a2d2010-12-22 21:39:39 +00001321
1322 GrTexture* texture;
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001323 SkAutoCachedTexture act(this, bitmap, *sampler, &texture);
reed@google.comac10a2d2010-12-22 21:39:39 +00001324 if (NULL == texture) {
1325 return;
1326 }
1327
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001328 grPaint->setTexture(kShaderTextureIdx, texture);
reed@google.com46799cd2011-02-22 20:56:26 +00001329
reed@google.com20efde72011-05-09 17:00:02 +00001330 GrRect dstRect = SkRect::MakeWH(GrIntToScalar(srcRect.width()),
1331 GrIntToScalar(srcRect.height()));
bsalomon@google.comc6cf7232011-02-17 16:43:10 +00001332 GrRect paintRect;
junov@google.com6acc9b32011-05-16 18:32:07 +00001333 paintRect.setLTRB(GrFixedToScalar((srcRect.fLeft << 16) / bitmap.width()),
1334 GrFixedToScalar((srcRect.fTop << 16) / bitmap.height()),
1335 GrFixedToScalar((srcRect.fRight << 16) / bitmap.width()),
bsalomon@google.comc6cf7232011-02-17 16:43:10 +00001336 GrFixedToScalar((srcRect.fBottom << 16) / bitmap.height()));
reed@google.comac10a2d2010-12-22 21:39:39 +00001337
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001338 if (GrSamplerState::kNearest_Filter != sampler->getFilter() &&
junov@google.com6acc9b32011-05-16 18:32:07 +00001339 (srcRect.width() < bitmap.width() ||
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001340 srcRect.height() < bitmap.height())) {
junov@google.com6acc9b32011-05-16 18:32:07 +00001341 // If drawing a subrect of the bitmap and filtering is enabled,
1342 // use a constrained texture domain to avoid color bleeding
1343 GrScalar left, top, right, bottom;
1344 if (srcRect.width() > 1) {
1345 GrScalar border = GR_ScalarHalf / bitmap.width();
1346 left = paintRect.left() + border;
1347 right = paintRect.right() - border;
1348 } else {
1349 left = right = GrScalarHalf(paintRect.left() + paintRect.right());
1350 }
1351 if (srcRect.height() > 1) {
1352 GrScalar border = GR_ScalarHalf / bitmap.height();
1353 top = paintRect.top() + border;
1354 bottom = paintRect.bottom() - border;
1355 } else {
1356 top = bottom = GrScalarHalf(paintRect.top() + paintRect.bottom());
1357 }
1358 GrRect textureDomain;
1359 textureDomain.setLTRB(left, top, right, bottom);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001360 sampler->setTextureDomain(textureDomain);
junov@google.com6acc9b32011-05-16 18:32:07 +00001361 }
1362
bsalomon@google.comcc4dac32011-05-10 13:52:42 +00001363 fContext->drawRectToRect(*grPaint, dstRect, paintRect, &m);
reed@google.comac10a2d2010-12-22 21:39:39 +00001364}
1365
1366void SkGpuDevice::drawSprite(const SkDraw& draw, const SkBitmap& bitmap,
1367 int left, int top, const SkPaint& paint) {
1368 CHECK_SHOULD_DRAW(draw);
1369
1370 SkAutoLockPixels alp(bitmap);
1371 if (!bitmap.getTexture() && !bitmap.readyToDraw()) {
1372 return;
1373 }
1374
bsalomon@google.com5782d712011-01-21 21:03:59 +00001375 GrPaint grPaint;
Scroggod757df22011-05-16 13:11:16 +00001376 if(!this->skPaint2GrPaintNoShader(paint, true, &grPaint, false)) {
bsalomon@google.com5782d712011-01-21 21:03:59 +00001377 return;
1378 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001379
bsalomon@google.com5782d712011-01-21 21:03:59 +00001380 GrAutoMatrix avm(fContext, GrMatrix::I());
1381
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001382 GrSamplerState* sampler = grPaint.getTextureSampler(kBitmapTextureIdx);
bsalomon@google.com5782d712011-01-21 21:03:59 +00001383
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001384 GrTexture* texture;
1385 sampler->setClampNoFilter();
1386 SkAutoCachedTexture act(this, bitmap, *sampler, &texture);
1387
1388 grPaint.setTexture(kBitmapTextureIdx, texture);
bsalomon@google.com5782d712011-01-21 21:03:59 +00001389
bsalomon@google.com5782d712011-01-21 21:03:59 +00001390 fContext->drawRectToRect(grPaint,
reed@google.com20efde72011-05-09 17:00:02 +00001391 GrRect::MakeXYWH(GrIntToScalar(left),
1392 GrIntToScalar(top),
1393 GrIntToScalar(bitmap.width()),
1394 GrIntToScalar(bitmap.height())),
1395 GrRect::MakeWH(GR_Scalar1, GR_Scalar1));
reed@google.comac10a2d2010-12-22 21:39:39 +00001396}
1397
1398void SkGpuDevice::drawDevice(const SkDraw& draw, SkDevice* dev,
1399 int x, int y, const SkPaint& paint) {
1400 CHECK_SHOULD_DRAW(draw);
1401
bsalomon@google.com5782d712011-01-21 21:03:59 +00001402 GrPaint grPaint;
bsalomon@google.comc6cf7232011-02-17 16:43:10 +00001403 if (!((SkGpuDevice*)dev)->bindDeviceAsTexture(&grPaint) ||
Scroggod757df22011-05-16 13:11:16 +00001404 !this->skPaint2GrPaintNoShader(paint, true, &grPaint, false)) {
bsalomon@google.com5782d712011-01-21 21:03:59 +00001405 return;
reed@google.comac10a2d2010-12-22 21:39:39 +00001406 }
bsalomon@google.com5782d712011-01-21 21:03:59 +00001407
bsalomon@google.comb5b31682011-06-16 18:05:35 +00001408 GrTexture* devTex = grPaint.getTexture(0);
1409 SkASSERT(NULL != devTex);
bsalomon@google.com5782d712011-01-21 21:03:59 +00001410
1411 const SkBitmap& bm = dev->accessBitmap(false);
1412 int w = bm.width();
1413 int h = bm.height();
1414
1415 GrAutoMatrix avm(fContext, GrMatrix::I());
1416
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001417 grPaint.getTextureSampler(kBitmapTextureIdx)->setClampNoFilter();
bsalomon@google.com5782d712011-01-21 21:03:59 +00001418
bsalomon@google.comb5b31682011-06-16 18:05:35 +00001419 GrRect dstRect = GrRect::MakeXYWH(GrIntToScalar(x),
1420 GrIntToScalar(y),
1421 GrIntToScalar(w),
1422 GrIntToScalar(h));
1423 // The device being drawn may not fill up its texture (saveLayer uses
1424 // the approximate ).
1425 GrRect srcRect = GrRect::MakeWH(GR_Scalar1 * w / devTex->width(),
1426 GR_Scalar1 * h / devTex->height());
1427
1428 fContext->drawRectToRect(grPaint, dstRect, srcRect);
reed@google.comac10a2d2010-12-22 21:39:39 +00001429}
1430
1431///////////////////////////////////////////////////////////////////////////////
1432
1433// must be in SkCanvas::VertexMode order
bsalomon@google.comffca4002011-02-22 20:34:01 +00001434static const GrPrimitiveType gVertexMode2PrimitiveType[] = {
1435 kTriangles_PrimitiveType,
1436 kTriangleStrip_PrimitiveType,
1437 kTriangleFan_PrimitiveType,
reed@google.comac10a2d2010-12-22 21:39:39 +00001438};
1439
1440void SkGpuDevice::drawVertices(const SkDraw& draw, SkCanvas::VertexMode vmode,
1441 int vertexCount, const SkPoint vertices[],
1442 const SkPoint texs[], const SkColor colors[],
1443 SkXfermode* xmode,
1444 const uint16_t indices[], int indexCount,
1445 const SkPaint& paint) {
1446 CHECK_SHOULD_DRAW(draw);
1447
bsalomon@google.com5782d712011-01-21 21:03:59 +00001448 GrPaint grPaint;
1449 SkAutoCachedTexture act;
1450 // we ignore the shader if texs is null.
1451 if (NULL == texs) {
Scroggod757df22011-05-16 13:11:16 +00001452 if (!this->skPaint2GrPaintNoShader(paint,
1453 false,
1454 &grPaint,
1455 NULL == colors)) {
reed@google.comac10a2d2010-12-22 21:39:39 +00001456 return;
1457 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001458 } else {
reed@google.com1a2e8d22011-01-21 22:08:29 +00001459 if (!this->skPaint2GrPaintShader(paint, &act,
1460 *draw.fMatrix,
Scroggod757df22011-05-16 13:11:16 +00001461 &grPaint,
1462 NULL == colors)) {
bsalomon@google.com5782d712011-01-21 21:03:59 +00001463 return;
1464 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001465 }
bsalomon@google.com5782d712011-01-21 21:03:59 +00001466
1467 if (NULL != xmode && NULL != texs && NULL != colors) {
1468 SkXfermode::Mode mode;
1469 if (!SkXfermode::IsMode(xmode, &mode) ||
1470 SkXfermode::kMultiply_Mode != mode) {
1471 SkDebugf("Unsupported vertex-color/texture xfer mode.\n");
1472#if 0
1473 return
1474#endif
1475 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001476 }
bsalomon@google.com5782d712011-01-21 21:03:59 +00001477
1478#if SK_SCALAR_IS_GR_SCALAR
1479 // even if GrColor and SkColor byte offsets match we need
1480 // to perform pre-multiply.
1481 if (NULL == colors) {
1482 fContext->drawVertices(grPaint,
1483 gVertexMode2PrimitiveType[vmode],
1484 vertexCount,
1485 (GrPoint*) vertices,
1486 (GrPoint*) texs,
1487 NULL,
1488 indices,
1489 indexCount);
1490 } else
1491#endif
1492 {
1493 SkTexCoordSource texSrc(texs);
1494 SkColorSource colSrc(colors);
1495 SkIndexSource idxSrc(indices, indexCount);
1496
1497 fContext->drawCustomVertices(grPaint,
1498 gVertexMode2PrimitiveType[vmode],
1499 SkPositionSource(vertices, vertexCount),
1500 (NULL == texs) ? NULL : &texSrc,
1501 (NULL == colors) ? NULL : &colSrc,
1502 (NULL == indices) ? NULL : &idxSrc);
reed@google.comac10a2d2010-12-22 21:39:39 +00001503 }
1504}
1505
1506///////////////////////////////////////////////////////////////////////////////
1507
1508static void GlyphCacheAuxProc(void* data) {
1509 delete (GrFontScaler*)data;
1510}
1511
1512static GrFontScaler* get_gr_font_scaler(SkGlyphCache* cache) {
1513 void* auxData;
1514 GrFontScaler* scaler = NULL;
1515 if (cache->getAuxProcData(GlyphCacheAuxProc, &auxData)) {
1516 scaler = (GrFontScaler*)auxData;
1517 }
1518 if (NULL == scaler) {
1519 scaler = new SkGrFontScaler(cache);
1520 cache->setAuxProc(GlyphCacheAuxProc, scaler);
1521 }
1522 return scaler;
1523}
1524
1525static void SkGPU_Draw1Glyph(const SkDraw1Glyph& state,
1526 SkFixed fx, SkFixed fy,
1527 const SkGlyph& glyph) {
1528 SkASSERT(glyph.fWidth > 0 && glyph.fHeight > 0);
1529
1530 GrSkDrawProcs* procs = (GrSkDrawProcs*)state.fDraw->fProcs;
1531
1532 if (NULL == procs->fFontScaler) {
1533 procs->fFontScaler = get_gr_font_scaler(state.fCache);
1534 }
reed@google.com39ce0ac2011-04-08 15:42:19 +00001535
1536 /*
reed@google.com3b139f52011-06-07 17:56:25 +00001537 * What should we do with fy? (assuming horizontal/latin text)
reed@google.com39ce0ac2011-04-08 15:42:19 +00001538 *
reed@google.com3b139f52011-06-07 17:56:25 +00001539 * The raster code calls SkFixedFloorToFixed on it, as it does with fx.
1540 * It calls that rather than round, because our caller has already added
1541 * SK_FixedHalf, so that calling floor gives us the rounded integer.
1542 *
1543 * Test code between raster and gpu (they should draw the same)
1544 *
1545 * canvas->drawText("Hamburgefons", 12, 0, 16.5f, paint);
1546 *
1547 * Perhaps we should only perform this integralization if there is no
1548 * fExtMatrix...
reed@google.com39ce0ac2011-04-08 15:42:19 +00001549 */
reed@google.com3b139f52011-06-07 17:56:25 +00001550 fy = SkFixedFloorToFixed(fy);
1551
reed@google.comac10a2d2010-12-22 21:39:39 +00001552 procs->fTextContext->drawPackedGlyph(GrGlyph::Pack(glyph.getGlyphID(), fx, 0),
reed@google.com3b139f52011-06-07 17:56:25 +00001553 SkFixedFloorToFixed(fx), fy,
reed@google.comac10a2d2010-12-22 21:39:39 +00001554 procs->fFontScaler);
1555}
1556
bsalomon@google.com5782d712011-01-21 21:03:59 +00001557SkDrawProcs* SkGpuDevice::initDrawForText(GrTextContext* context) {
reed@google.comac10a2d2010-12-22 21:39:39 +00001558
1559 // deferred allocation
1560 if (NULL == fDrawProcs) {
1561 fDrawProcs = new GrSkDrawProcs;
1562 fDrawProcs->fD1GProc = SkGPU_Draw1Glyph;
1563 fDrawProcs->fContext = fContext;
1564 }
1565
1566 // init our (and GL's) state
1567 fDrawProcs->fTextContext = context;
1568 fDrawProcs->fFontScaler = NULL;
1569 return fDrawProcs;
1570}
1571
1572void SkGpuDevice::drawText(const SkDraw& draw, const void* text,
1573 size_t byteLength, SkScalar x, SkScalar y,
1574 const SkPaint& paint) {
1575 CHECK_SHOULD_DRAW(draw);
1576
1577 if (draw.fMatrix->getType() & SkMatrix::kPerspective_Mask) {
1578 // this guy will just call our drawPath()
1579 draw.drawText((const char*)text, byteLength, x, y, paint);
1580 } else {
reed@google.comac10a2d2010-12-22 21:39:39 +00001581 SkDraw myDraw(draw);
bsalomon@google.com5782d712011-01-21 21:03:59 +00001582
1583 GrPaint grPaint;
1584 SkAutoCachedTexture act;
1585
Scroggod757df22011-05-16 13:11:16 +00001586 if (!this->skPaint2GrPaintShader(paint,
1587 &act,
1588 *draw.fMatrix,
1589 &grPaint,
1590 true)) {
bsalomon@google.com5782d712011-01-21 21:03:59 +00001591 return;
1592 }
bsalomon@google.comcc4dac32011-05-10 13:52:42 +00001593 GrTextContext context(fContext, grPaint, draw.fExtMatrix);
bsalomon@google.com5782d712011-01-21 21:03:59 +00001594 myDraw.fProcs = this->initDrawForText(&context);
reed@google.comac10a2d2010-12-22 21:39:39 +00001595 this->INHERITED::drawText(myDraw, text, byteLength, x, y, paint);
1596 }
1597}
1598
1599void SkGpuDevice::drawPosText(const SkDraw& draw, const void* text,
1600 size_t byteLength, const SkScalar pos[],
1601 SkScalar constY, int scalarsPerPos,
1602 const SkPaint& paint) {
1603 CHECK_SHOULD_DRAW(draw);
1604
1605 if (draw.fMatrix->getType() & SkMatrix::kPerspective_Mask) {
1606 // this guy will just call our drawPath()
1607 draw.drawPosText((const char*)text, byteLength, pos, constY,
1608 scalarsPerPos, paint);
1609 } else {
reed@google.comac10a2d2010-12-22 21:39:39 +00001610 SkDraw myDraw(draw);
bsalomon@google.com5782d712011-01-21 21:03:59 +00001611
1612 GrPaint grPaint;
1613 SkAutoCachedTexture act;
Scroggod757df22011-05-16 13:11:16 +00001614 if (!this->skPaint2GrPaintShader(paint,
1615 &act,
1616 *draw.fMatrix,
1617 &grPaint,
1618 true)) {
bsalomon@google.com5782d712011-01-21 21:03:59 +00001619 return;
1620 }
1621
bsalomon@google.comcc4dac32011-05-10 13:52:42 +00001622 GrTextContext context(fContext, grPaint, draw.fExtMatrix);
bsalomon@google.com5782d712011-01-21 21:03:59 +00001623 myDraw.fProcs = this->initDrawForText(&context);
reed@google.comac10a2d2010-12-22 21:39:39 +00001624 this->INHERITED::drawPosText(myDraw, text, byteLength, pos, constY,
1625 scalarsPerPos, paint);
1626 }
1627}
1628
1629void SkGpuDevice::drawTextOnPath(const SkDraw& draw, const void* text,
1630 size_t len, const SkPath& path,
1631 const SkMatrix* m, const SkPaint& paint) {
1632 CHECK_SHOULD_DRAW(draw);
1633
1634 SkASSERT(draw.fDevice == this);
1635 draw.drawTextOnPath((const char*)text, len, path, m, paint);
1636}
1637
1638///////////////////////////////////////////////////////////////////////////////
1639
reed@google.comf67e4cf2011-03-15 20:56:58 +00001640bool SkGpuDevice::filterTextFlags(const SkPaint& paint, TextFlags* flags) {
1641 if (!paint.isLCDRenderText()) {
1642 // we're cool with the paint as is
1643 return false;
1644 }
1645
1646 if (paint.getShader() ||
1647 paint.getXfermode() || // unless its srcover
1648 paint.getMaskFilter() ||
1649 paint.getRasterizer() ||
1650 paint.getColorFilter() ||
1651 paint.getPathEffect() ||
1652 paint.isFakeBoldText() ||
1653 paint.getStyle() != SkPaint::kFill_Style) {
1654 // turn off lcd
1655 flags->fFlags = paint.getFlags() & ~SkPaint::kLCDRenderText_Flag;
1656 flags->fHinting = paint.getHinting();
1657 return true;
1658 }
1659 // we're cool with the paint as is
1660 return false;
1661}
1662
1663///////////////////////////////////////////////////////////////////////////////
1664
reed@google.comac10a2d2010-12-22 21:39:39 +00001665SkGpuDevice::TexCache* SkGpuDevice::lockCachedTexture(const SkBitmap& bitmap,
bsalomon@google.comfea37b52011-04-25 15:51:06 +00001666 const GrSamplerState& sampler,
1667 GrTexture** texture,
bsalomon@google.come97f0852011-06-17 13:10:25 +00001668 TexType type) {
bsalomon@google.comfea37b52011-04-25 15:51:06 +00001669 GrTexture* newTexture = NULL;
1670 GrTextureEntry* entry = NULL;
reed@google.comac10a2d2010-12-22 21:39:39 +00001671 GrContext* ctx = this->context();
bsalomon@google.comfea37b52011-04-25 15:51:06 +00001672
bsalomon@google.come97f0852011-06-17 13:10:25 +00001673 if (kBitmap_TexType != type) {
bsalomon@google.comfea37b52011-04-25 15:51:06 +00001674 const GrTextureDesc desc = {
1675 kRenderTarget_GrTextureFlagBit,
1676 kNone_GrAALevel,
1677 bitmap.width(),
1678 bitmap.height(),
1679 SkGr::Bitmap2PixelConfig(bitmap)
1680 };
bsalomon@google.come97f0852011-06-17 13:10:25 +00001681 if (kSaveLayerDeviceRenderTarget_TexType == type) {
bsalomon@google.comb5b31682011-06-16 18:05:35 +00001682 // we know layers will only be drawn through drawDevice.
1683 // drawDevice has been made to work with content embedded in a
1684 // larger texture so its okay to use the approximate version.
1685 entry = ctx->findApproximateKeylessTexture(desc);
1686 } else {
bsalomon@google.come97f0852011-06-17 13:10:25 +00001687 SkASSERT(kDeviceRenderTarget_TexType == type);
bsalomon@google.comb5b31682011-06-16 18:05:35 +00001688 entry = ctx->lockKeylessTexture(desc);
1689 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001690 } else {
junov@google.com4ee7ae52011-06-30 17:30:49 +00001691 if (!bitmap.isVolatile()) {
1692 uint32_t p0, p1;
1693 p0 = bitmap.getGenerationID();
1694 p1 = bitmap.pixelRefOffset();
1695 GrTextureKey key(p0, p1, bitmap.width(), bitmap.height());
1696
1697 entry = ctx->findAndLockTexture(&key, sampler);
1698 if (NULL == entry)
1699 entry = sk_gr_create_bitmap_texture(ctx, &key, sampler,
1700 bitmap);
1701 } else {
1702 entry = sk_gr_create_bitmap_texture(ctx, NULL, sampler, bitmap);
1703 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001704 if (NULL == entry) {
junov@google.com4ee7ae52011-06-30 17:30:49 +00001705 GrPrintf("---- failed to create texture for cache [%d %d]\n",
1706 bitmap.width(), bitmap.height());
reed@google.comac10a2d2010-12-22 21:39:39 +00001707 }
1708 }
1709
1710 if (NULL != entry) {
1711 newTexture = entry->texture();
reed@google.comac10a2d2010-12-22 21:39:39 +00001712 if (texture) {
1713 *texture = newTexture;
1714 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001715 }
1716 return (TexCache*)entry;
1717}
1718
1719void SkGpuDevice::unlockCachedTexture(TexCache* cache) {
1720 this->context()->unlockTexture((GrTextureEntry*)cache);
1721}
1722
bsalomon@google.come97f0852011-06-17 13:10:25 +00001723SkDevice* SkGpuDevice::onCreateCompatibleDevice(SkBitmap::Config config,
1724 int width, int height,
1725 bool isOpaque,
1726 Usage usage) {
1727 return SkNEW_ARGS(SkGpuDevice,(this->context(), config,
1728 width, height, usage));
1729}
1730