blob: 0f1872666ac933eae9495dcb9ad30c042a4a6de4 [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
reed@google.comac10a2d2010-12-22 21:39:39 +000050///////////////////////////////////////////////////////////////////////////////
51
52SkGpuDevice::SkAutoCachedTexture::
53 SkAutoCachedTexture(SkGpuDevice* device,
54 const SkBitmap& bitmap,
55 const GrSamplerState& sampler,
56 GrTexture** texture) {
57 GrAssert(texture);
58 fTex = NULL;
59 *texture = this->set(device, bitmap, sampler);
60}
61
62SkGpuDevice::SkAutoCachedTexture::SkAutoCachedTexture() {
63 fTex = NULL;
64}
65
66GrTexture* SkGpuDevice::SkAutoCachedTexture::set(SkGpuDevice* device,
67 const SkBitmap& bitmap,
68 const GrSamplerState& sampler) {
69 if (fTex) {
70 fDevice->unlockCachedTexture(fTex);
71 }
72 fDevice = device;
73 GrTexture* texture = (GrTexture*)bitmap.getTexture();
74 if (texture) {
75 // return the native texture
76 fTex = NULL;
reed@google.comac10a2d2010-12-22 21:39:39 +000077 } else {
78 // look it up in our cache
bsalomon@google.come97f0852011-06-17 13:10:25 +000079 fTex = device->lockCachedTexture(bitmap, sampler, &texture);
reed@google.comac10a2d2010-12-22 21:39:39 +000080 }
81 return texture;
82}
83
84SkGpuDevice::SkAutoCachedTexture::~SkAutoCachedTexture() {
85 if (fTex) {
86 fDevice->unlockCachedTexture(fTex);
87 }
88}
89
90///////////////////////////////////////////////////////////////////////////////
91
92bool gDoTraceDraw;
93
94struct GrSkDrawProcs : public SkDrawProcs {
95public:
96 GrContext* fContext;
97 GrTextContext* fTextContext;
98 GrFontScaler* fFontScaler; // cached in the skia glyphcache
99};
100
101///////////////////////////////////////////////////////////////////////////////
102
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000103GrRenderTarget* SkGpuDevice::Current3DApiRenderTarget() {
104 return (GrRenderTarget*) -1;
105}
106
reed@google.comaf951c92011-06-16 19:10:39 +0000107static SkBitmap::Config grConfig2skConfig(GrPixelConfig config, bool* isOpaque) {
108 switch (config) {
109 case kAlpha_8_GrPixelConfig:
110 *isOpaque = false;
111 return SkBitmap::kA8_Config;
112 case kRGB_565_GrPixelConfig:
113 *isOpaque = true;
114 return SkBitmap::kRGB_565_Config;
115 case kRGBA_4444_GrPixelConfig:
116 *isOpaque = false;
117 return SkBitmap::kARGB_4444_Config;
118 case kRGBA_8888_GrPixelConfig:
119 case kRGBX_8888_GrPixelConfig:
120 *isOpaque = (kRGBX_8888_GrPixelConfig == config);
121 return SkBitmap::kARGB_8888_Config;
122 default:
123 *isOpaque = false;
124 return SkBitmap::kNo_Config;
125 }
126}
reed@google.comac10a2d2010-12-22 21:39:39 +0000127
reed@google.comaf951c92011-06-16 19:10:39 +0000128static SkBitmap make_bitmap(GrContext* context, GrRenderTarget* renderTarget) {
129 if (SkGpuDevice::Current3DApiRenderTarget() == renderTarget) {
130 renderTarget = context->createRenderTargetFrom3DApiState();
131 }
132 GrTexture* texture = renderTarget->asTexture();
133 GrPixelConfig config = texture ? texture->config() : kRGBA_8888_GrPixelConfig;
134
135 bool isOpaque;
136 SkBitmap bitmap;
137 bitmap.setConfig(grConfig2skConfig(config, &isOpaque),
138 renderTarget->width(), renderTarget->height());
139 bitmap.setIsOpaque(isOpaque);
140 return bitmap;
141}
142
bsalomon@google.comf9046fe2011-06-17 15:10:21 +0000143SkGpuDevice::SkGpuDevice(GrContext* context, GrTexture* texture)
144: SkDevice(make_bitmap(context, texture->asRenderTarget())) {
145 this->initFromRenderTarget(context, texture->asRenderTarget());
146}
147
reed@google.comaf951c92011-06-16 19:10:39 +0000148SkGpuDevice::SkGpuDevice(GrContext* context, GrRenderTarget* renderTarget)
149: SkDevice(make_bitmap(context, renderTarget)) {
bsalomon@google.comf9046fe2011-06-17 15:10:21 +0000150 this->initFromRenderTarget(context, renderTarget);
151}
152
153void SkGpuDevice::initFromRenderTarget(GrContext* context,
154 GrRenderTarget* renderTarget) {
reed@google.comaf951c92011-06-16 19:10:39 +0000155 fNeedPrepareRenderTarget = false;
156 fDrawProcs = NULL;
157
158 fContext = context;
159 fContext->ref();
160
161 fCache = NULL;
162 fTexture = NULL;
163 fRenderTarget = NULL;
164 fNeedClear = false;
165
166 if (Current3DApiRenderTarget() == renderTarget) {
167 fRenderTarget = fContext->createRenderTargetFrom3DApiState();
168 } else {
bsalomon@google.comf9046fe2011-06-17 15:10:21 +0000169 GrAssert(NULL != renderTarget);
reed@google.comaf951c92011-06-16 19:10:39 +0000170 fRenderTarget = renderTarget;
171 fRenderTarget->ref();
bsalomon@google.comf9046fe2011-06-17 15:10:21 +0000172 // if this RT is also a texture, hold a ref on it
173 fTexture = fRenderTarget->asTexture();
174 SkSafeRef(fTexture);
reed@google.comaf951c92011-06-16 19:10:39 +0000175 }
176
177 SkGrRenderTargetPixelRef* pr = new SkGrRenderTargetPixelRef(fRenderTarget);
178 this->setPixelRef(pr, 0)->unref();
179}
180
181SkGpuDevice::SkGpuDevice(GrContext* context, SkBitmap::Config config, int width,
bsalomon@google.come97f0852011-06-17 13:10:25 +0000182 int height, Usage usage)
reed@google.comaf951c92011-06-16 19:10:39 +0000183: SkDevice(config, width, height, false /*isOpaque*/) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000184 fNeedPrepareRenderTarget = false;
185 fDrawProcs = NULL;
186
reed@google.com7b201d22011-01-11 18:59:23 +0000187 fContext = context;
bsalomon@google.com5782d712011-01-21 21:03:59 +0000188 fContext->ref();
reed@google.comac10a2d2010-12-22 21:39:39 +0000189
190 fCache = NULL;
191 fTexture = NULL;
192 fRenderTarget = NULL;
193 fNeedClear = false;
194
reed@google.comaf951c92011-06-16 19:10:39 +0000195 if (config != SkBitmap::kRGB_565_Config) {
196 config = SkBitmap::kARGB_8888_Config;
197 }
198 SkBitmap bm;
199 bm.setConfig(config, width, height);
reed@google.comac10a2d2010-12-22 21:39:39 +0000200
201#if CACHE_LAYER_TEXTURES
bsalomon@google.come97f0852011-06-17 13:10:25 +0000202 TexType type = (kSaveLayer_Usage == usage) ?
203 kSaveLayerDeviceRenderTarget_TexType :
204 kDeviceRenderTarget_TexType;
reed@google.comaf951c92011-06-16 19:10:39 +0000205 fCache = this->lockCachedTexture(bm, GrSamplerState::ClampNoFilter(),
bsalomon@google.come97f0852011-06-17 13:10:25 +0000206 &fTexture, type);
reed@google.comaf951c92011-06-16 19:10:39 +0000207 if (fCache) {
208 SkASSERT(NULL != fTexture);
209 SkASSERT(NULL != fTexture->asRenderTarget());
bsalomon@google.comf9046fe2011-06-17 15:10:21 +0000210 // hold a ref directly on fTexture (even though fCache has one) to match
211 // other constructor paths. Simplifies cleanup.
212 fTexture->ref();
reed@google.comaf951c92011-06-16 19:10:39 +0000213 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000214#else
reed@google.comaf951c92011-06-16 19:10:39 +0000215 const GrTextureDesc desc = {
216 kRenderTarget_GrTextureFlagBit,
217 kNone_GrAALevel,
218 width,
219 height,
220 SkGr::Bitmap2PixelConfig(bm)
221 };
reed@google.comac10a2d2010-12-22 21:39:39 +0000222
reed@google.comaf951c92011-06-16 19:10:39 +0000223 fTexture = fContext->createUncachedTexture(desc, NULL, 0);
reed@google.comac10a2d2010-12-22 21:39:39 +0000224#endif
reed@google.comaf951c92011-06-16 19:10:39 +0000225 if (NULL != fTexture) {
226 fRenderTarget = fTexture->asRenderTarget();
bsalomon@google.comf9046fe2011-06-17 15:10:21 +0000227 fRenderTarget->ref();
reed@google.comac10a2d2010-12-22 21:39:39 +0000228
reed@google.comaf951c92011-06-16 19:10:39 +0000229 GrAssert(NULL != fRenderTarget);
reed@google.comac10a2d2010-12-22 21:39:39 +0000230
reed@google.comaf951c92011-06-16 19:10:39 +0000231 // we defer the actual clear until our gainFocus()
232 fNeedClear = true;
reed@google.comac10a2d2010-12-22 21:39:39 +0000233
reed@google.comaf951c92011-06-16 19:10:39 +0000234 // wrap the bitmap with a pixelref to expose our texture
235 SkGrTexturePixelRef* pr = new SkGrTexturePixelRef(fTexture);
bsalomon@google.com669fdc42011-04-05 17:08:27 +0000236 this->setPixelRef(pr, 0)->unref();
reed@google.comaf951c92011-06-16 19:10:39 +0000237 } else {
238 GrPrintf("--- failed to create gpu-offscreen [%d %d]\n",
239 width, height);
240 GrAssert(false);
reed@google.comac10a2d2010-12-22 21:39:39 +0000241 }
242}
243
244SkGpuDevice::~SkGpuDevice() {
245 if (fDrawProcs) {
246 delete fDrawProcs;
247 }
248
bsalomon@google.comf9046fe2011-06-17 15:10:21 +0000249 SkSafeUnref(fTexture);
250 SkSafeUnref(fRenderTarget);
reed@google.comac10a2d2010-12-22 21:39:39 +0000251 if (fCache) {
252 GrAssert(NULL != fTexture);
253 GrAssert(fRenderTarget == fTexture->asRenderTarget());
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000254 fContext->unlockTexture((GrTextureEntry*)fCache);
bsalomon@google.comf9046fe2011-06-17 15:10:21 +0000255 }
bsalomon@google.com5782d712011-01-21 21:03:59 +0000256 fContext->unref();
reed@google.comac10a2d2010-12-22 21:39:39 +0000257}
258
reed@google.comac10a2d2010-12-22 21:39:39 +0000259intptr_t SkGpuDevice::getLayerTextureHandle() const {
260 if (fTexture) {
261 return fTexture->getTextureHandle();
262 } else {
263 return 0;
264 }
265}
mike@reedtribe.orgea4ac972011-04-26 11:48:33 +0000266
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) {
bsalomon@google.com5782d712011-01-21 21:03:59 +0000484 return false;
reed@google.comac10a2d2010-12-22 21:39:39 +0000485 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000486 GrSamplerState* sampler = grPaint->getTextureSampler(kShaderTextureIdx);
487 sampler->setSampleMode(sampleMode);
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000488 if (skPaint.isFilterBitmap()) {
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000489 sampler->setFilter(GrSamplerState::kBilinear_Filter);
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000490 } else {
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000491 sampler->setFilter(GrSamplerState::kNearest_Filter);
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000492 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000493 sampler->setWrapX(sk_tile_mode_to_grwrap(tileModes[0]));
494 sampler->setWrapY(sk_tile_mode_to_grwrap(tileModes[1]));
reed@google.comac10a2d2010-12-22 21:39:39 +0000495 if (GrSamplerState::kRadial2_SampleMode == sampleMode) {
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000496 sampler->setRadial2Params(twoPointParams[0],
497 twoPointParams[1],
498 twoPointParams[2] < 0);
reed@google.comac10a2d2010-12-22 21:39:39 +0000499 }
500
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000501 GrTexture* texture = act->set(this, bitmap, *sampler);
reed@google.comac10a2d2010-12-22 21:39:39 +0000502 if (NULL == texture) {
bsalomon@google.com5782d712011-01-21 21:03:59 +0000503 SkDebugf("Couldn't convert bitmap to texture.\n");
504 return false;
reed@google.comac10a2d2010-12-22 21:39:39 +0000505 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000506 grPaint->setTexture(kShaderTextureIdx, texture);
reed@google.comac10a2d2010-12-22 21:39:39 +0000507
508 // since our texture coords will be in local space, we wack the texture
509 // matrix to map them back into 0...1 before we load it
510 SkMatrix localM;
511 if (shader->getLocalMatrix(&localM)) {
512 SkMatrix inverse;
513 if (localM.invert(&inverse)) {
514 matrix.preConcat(inverse);
515 }
516 }
517 if (SkShader::kDefault_BitmapType == bmptype) {
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000518 GrScalar sx = GrFixedToScalar(GR_Fixed1 / bitmap.width());
519 GrScalar sy = GrFixedToScalar(GR_Fixed1 / bitmap.height());
reed@google.comac10a2d2010-12-22 21:39:39 +0000520 matrix.postScale(sx, sy);
reed@google.comac10a2d2010-12-22 21:39:39 +0000521 } else if (SkShader::kRadial_BitmapType == bmptype) {
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000522 GrScalar s = GrFixedToScalar(GR_Fixed1 / bitmap.width());
reed@google.comac10a2d2010-12-22 21:39:39 +0000523 matrix.postScale(s, s);
524 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000525 sampler->setMatrix(matrix);
bsalomon@google.com5782d712011-01-21 21:03:59 +0000526
527 return true;
reed@google.comac10a2d2010-12-22 21:39:39 +0000528}
529
530///////////////////////////////////////////////////////////////////////////////
bsalomon@google.com5782d712011-01-21 21:03:59 +0000531
532class SkPositionSource {
533public:
534 SkPositionSource(const SkPoint* points, int count)
535 : fPoints(points), fCount(count) {}
536
537 int count() const { return fCount; }
538
539 void writeValue(int i, GrPoint* dstPosition) const {
540 SkASSERT(i < fCount);
541 dstPosition->fX = SkScalarToGrScalar(fPoints[i].fX);
542 dstPosition->fY = SkScalarToGrScalar(fPoints[i].fY);
543 }
544private:
bsalomon@google.com5782d712011-01-21 21:03:59 +0000545 const SkPoint* fPoints;
bsalomon@google.com19628322011-02-03 21:30:17 +0000546 int fCount;
bsalomon@google.com5782d712011-01-21 21:03:59 +0000547};
548
549class SkTexCoordSource {
550public:
551 SkTexCoordSource(const SkPoint* coords)
552 : fCoords(coords) {}
553
554 void writeValue(int i, GrPoint* dstCoord) const {
555 dstCoord->fX = SkScalarToGrScalar(fCoords[i].fX);
556 dstCoord->fY = SkScalarToGrScalar(fCoords[i].fY);
557 }
558private:
559 const SkPoint* fCoords;
560};
561
562class SkColorSource {
563public:
564 SkColorSource(const SkColor* colors) : fColors(colors) {}
565
566 void writeValue(int i, GrColor* dstColor) const {
567 *dstColor = SkGr::SkColor2GrColor(fColors[i]);
568 }
569private:
570 const SkColor* fColors;
571};
572
573class SkIndexSource {
574public:
575 SkIndexSource(const uint16_t* indices, int count)
576 : fIndices(indices), fCount(count) {
577 }
578
579 int count() const { return fCount; }
580
581 void writeValue(int i, uint16_t* dstIndex) const {
582 *dstIndex = fIndices[i];
583 }
584
585private:
bsalomon@google.com5782d712011-01-21 21:03:59 +0000586 const uint16_t* fIndices;
bsalomon@google.com19628322011-02-03 21:30:17 +0000587 int fCount;
bsalomon@google.com5782d712011-01-21 21:03:59 +0000588};
589
590///////////////////////////////////////////////////////////////////////////////
591
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000592#if 0 // not currently being used so don't compile,
593
bsalomon@google.com5782d712011-01-21 21:03:59 +0000594// can be used for positions or texture coordinates
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000595
bsalomon@google.com5782d712011-01-21 21:03:59 +0000596class SkRectFanSource {
597public:
598 SkRectFanSource(const SkRect& rect) : fRect(rect) {}
599
600 int count() const { return 4; }
601
602 void writeValue(int i, GrPoint* dstPoint) const {
603 SkASSERT(i < 4);
604 dstPoint->fX = SkScalarToGrScalar((i % 3) ? fRect.fRight :
605 fRect.fLeft);
606 dstPoint->fY = SkScalarToGrScalar((i < 2) ? fRect.fTop :
607 fRect.fBottom);
608 }
609private:
610 const SkRect& fRect;
611};
612
613class SkIRectFanSource {
614public:
615 SkIRectFanSource(const SkIRect& 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 = (i % 3) ? GrIntToScalar(fRect.fRight) :
622 GrIntToScalar(fRect.fLeft);
623 dstPoint->fY = (i < 2) ? GrIntToScalar(fRect.fTop) :
624 GrIntToScalar(fRect.fBottom);
625 }
626private:
627 const SkIRect& fRect;
628};
629
630class SkMatRectFanSource {
631public:
632 SkMatRectFanSource(const SkRect& rect, const SkMatrix& matrix)
633 : fRect(rect), fMatrix(matrix) {}
634
635 int count() const { return 4; }
636
637 void writeValue(int i, GrPoint* dstPoint) const {
638 SkASSERT(i < 4);
639
640#if SK_SCALAR_IS_GR_SCALAR
641 fMatrix.mapXY((i % 3) ? fRect.fRight : fRect.fLeft,
642 (i < 2) ? fRect.fTop : fRect.fBottom,
643 (SkPoint*)dstPoint);
644#else
645 SkPoint dst;
646 fMatrix.mapXY((i % 3) ? fRect.fRight : fRect.fLeft,
647 (i < 2) ? fRect.fTop : fRect.fBottom,
648 &dst);
649 dstPoint->fX = SkScalarToGrScalar(dst.fX);
650 dstPoint->fY = SkScalarToGrScalar(dst.fY);
651#endif
652 }
653private:
654 const SkRect& fRect;
655 const SkMatrix& fMatrix;
656};
657
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000658#endif
659
reed@google.comac10a2d2010-12-22 21:39:39 +0000660///////////////////////////////////////////////////////////////////////////////
661
bsalomon@google.com398109c2011-04-14 18:40:27 +0000662void SkGpuDevice::clear(SkColor color) {
bsalomon@google.com31a58402011-04-27 21:00:02 +0000663 fContext->clear(NULL, color);
bsalomon@google.com398109c2011-04-14 18:40:27 +0000664}
665
reed@google.comac10a2d2010-12-22 21:39:39 +0000666void SkGpuDevice::drawPaint(const SkDraw& draw, const SkPaint& paint) {
667 CHECK_SHOULD_DRAW(draw);
668
bsalomon@google.com5782d712011-01-21 21:03:59 +0000669 GrPaint grPaint;
670 SkAutoCachedTexture act;
Scroggod757df22011-05-16 13:11:16 +0000671 if (!this->skPaint2GrPaintShader(paint,
672 &act,
673 *draw.fMatrix,
674 &grPaint,
675 true)) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000676 return;
677 }
bsalomon@google.com5782d712011-01-21 21:03:59 +0000678
679 fContext->drawPaint(grPaint);
reed@google.comac10a2d2010-12-22 21:39:39 +0000680}
681
682// must be in SkCanvas::PointMode order
bsalomon@google.comffca4002011-02-22 20:34:01 +0000683static const GrPrimitiveType gPointMode2PrimtiveType[] = {
684 kPoints_PrimitiveType,
685 kLines_PrimitiveType,
686 kLineStrip_PrimitiveType
reed@google.comac10a2d2010-12-22 21:39:39 +0000687};
688
689void SkGpuDevice::drawPoints(const SkDraw& draw, SkCanvas::PointMode mode,
bsalomon@google.com5782d712011-01-21 21:03:59 +0000690 size_t count, const SkPoint pts[], const SkPaint& paint) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000691 CHECK_SHOULD_DRAW(draw);
692
693 SkScalar width = paint.getStrokeWidth();
694 if (width < 0) {
695 return;
696 }
697
698 // we only handle hairlines here, else we let the SkDraw call our drawPath()
699 if (width > 0) {
700 draw.drawPoints(mode, count, pts, paint, true);
701 return;
702 }
703
bsalomon@google.com5782d712011-01-21 21:03:59 +0000704 GrPaint grPaint;
705 SkAutoCachedTexture act;
Scroggod757df22011-05-16 13:11:16 +0000706 if (!this->skPaint2GrPaintShader(paint,
707 &act,
708 *draw.fMatrix,
709 &grPaint,
710 true)) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000711 return;
712 }
713
reed@google.comac10a2d2010-12-22 21:39:39 +0000714#if SK_SCALAR_IS_GR_SCALAR
bsalomon@google.com5782d712011-01-21 21:03:59 +0000715 fContext->drawVertices(grPaint,
716 gPointMode2PrimtiveType[mode],
717 count,
718 (GrPoint*)pts,
719 NULL,
720 NULL,
721 NULL,
722 0);
reed@google.comac10a2d2010-12-22 21:39:39 +0000723#else
bsalomon@google.com5782d712011-01-21 21:03:59 +0000724 fContext->drawCustomVertices(grPaint,
725 gPointMode2PrimtiveType[mode],
726 SkPositionSource(pts, count));
reed@google.comac10a2d2010-12-22 21:39:39 +0000727#endif
reed@google.comac10a2d2010-12-22 21:39:39 +0000728}
729
reed@google.comc9aa5872011-04-05 21:05:37 +0000730///////////////////////////////////////////////////////////////////////////////
731
reed@google.comac10a2d2010-12-22 21:39:39 +0000732void SkGpuDevice::drawRect(const SkDraw& draw, const SkRect& rect,
733 const SkPaint& paint) {
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000734 CHECK_SHOULD_DRAW(draw);
735
736 bool doStroke = paint.getStyle() == SkPaint::kStroke_Style;
737 SkScalar width = paint.getStrokeWidth();
738
739 /*
740 We have special code for hairline strokes, miter-strokes, and fills.
741 Anything else we just call our path code.
742 */
743 bool usePath = doStroke && width > 0 &&
744 paint.getStrokeJoin() != SkPaint::kMiter_Join;
745 // another reason we might need to call drawPath...
746 if (paint.getMaskFilter()) {
747 usePath = true;
748 }
reed@google.com67db6642011-05-26 11:46:35 +0000749 // until we aa rotated rects...
750 if (!usePath && paint.isAntiAlias() && !draw.fMatrix->rectStaysRect()) {
751 usePath = true;
752 }
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000753
754 if (usePath) {
755 SkPath path;
756 path.addRect(rect);
757 this->drawPath(draw, path, paint, NULL, true);
758 return;
759 }
760
761 GrPaint grPaint;
762 SkAutoCachedTexture act;
Scroggod757df22011-05-16 13:11:16 +0000763 if (!this->skPaint2GrPaintShader(paint,
764 &act,
765 *draw.fMatrix,
766 &grPaint,
767 true)) {
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000768 return;
769 }
reed@google.com20efde72011-05-09 17:00:02 +0000770 fContext->drawRect(grPaint, rect, doStroke ? width : -1);
reed@google.comac10a2d2010-12-22 21:39:39 +0000771}
772
reed@google.com69302852011-02-16 18:08:07 +0000773#include "SkMaskFilter.h"
774#include "SkBounder.h"
775
reed@google.com69302852011-02-16 18:08:07 +0000776static bool drawWithMaskFilter(GrContext* context, const SkPath& path,
777 SkMaskFilter* filter, const SkMatrix& matrix,
778 const SkRegion& clip, SkBounder* bounder,
779 GrPaint* grp) {
780 SkMask srcM, dstM;
781
782 if (!SkDraw::DrawToMask(path, &clip.getBounds(), filter, &matrix, &srcM,
783 SkMask::kComputeBoundsAndRenderImage_CreateMode)) {
784 return false;
785 }
786
787 SkAutoMaskImage autoSrc(&srcM, false);
788
789 if (!filter->filterMask(&dstM, srcM, matrix, NULL)) {
790 return false;
791 }
792 // this will free-up dstM when we're done (allocated in filterMask())
793 SkAutoMaskImage autoDst(&dstM, false);
794
795 if (clip.quickReject(dstM.fBounds)) {
796 return false;
797 }
798 if (bounder && !bounder->doIRect(dstM.fBounds)) {
799 return false;
800 }
801
802 // we now have a device-aligned 8bit mask in dstM, ready to be drawn using
803 // the current clip (and identity matrix) and grpaint settings
804
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000805 // used to compute inverse view, if necessary
806 GrMatrix ivm = context->getMatrix();
807
reed@google.com0c219b62011-02-16 21:31:18 +0000808 GrAutoMatrix avm(context, GrMatrix::I());
reed@google.com69302852011-02-16 18:08:07 +0000809
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000810 const GrTextureDesc desc = {
811 kNone_GrTextureFlags,
812 kNone_GrAALevel,
reed@google.com69302852011-02-16 18:08:07 +0000813 dstM.fBounds.width(),
814 dstM.fBounds.height(),
bsalomon@google.com669fdc42011-04-05 17:08:27 +0000815 kAlpha_8_GrPixelConfig
reed@google.com69302852011-02-16 18:08:07 +0000816 };
817
818 GrTexture* texture = context->createUncachedTexture(desc, dstM.fImage,
819 dstM.fRowBytes);
820 if (NULL == texture) {
821 return false;
822 }
823
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000824 if (grp->hasTextureOrMask() && ivm.invert(&ivm)) {
825 grp->preConcatActiveSamplerMatrices(ivm);
826 }
827
828 static const int MASK_IDX = GrPaint::kMaxMasks - 1;
829 // we assume the last mask index is available for use
830 GrAssert(NULL == grp->getMask(MASK_IDX));
831 grp->setMask(MASK_IDX, texture);
reed@google.com0c219b62011-02-16 21:31:18 +0000832 texture->unref();
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000833 grp->getMaskSampler(MASK_IDX)->setClampNoFilter();
reed@google.com69302852011-02-16 18:08:07 +0000834
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000835 GrRect d;
836 d.setLTRB(GrIntToScalar(dstM.fBounds.fLeft),
reed@google.com0c219b62011-02-16 21:31:18 +0000837 GrIntToScalar(dstM.fBounds.fTop),
838 GrIntToScalar(dstM.fBounds.fRight),
839 GrIntToScalar(dstM.fBounds.fBottom));
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000840
841 GrMatrix m;
842 m.setTranslate(-dstM.fBounds.fLeft, -dstM.fBounds.fTop);
843 m.postIDiv(dstM.fBounds.width(), dstM.fBounds.height());
844 grp->getMaskSampler(MASK_IDX)->setMatrix(m);
845
846 context->drawRect(*grp, d);
reed@google.com69302852011-02-16 18:08:07 +0000847 return true;
848}
reed@google.com69302852011-02-16 18:08:07 +0000849
reed@google.com0c219b62011-02-16 21:31:18 +0000850void SkGpuDevice::drawPath(const SkDraw& draw, const SkPath& origSrcPath,
reed@google.comac10a2d2010-12-22 21:39:39 +0000851 const SkPaint& paint, const SkMatrix* prePathMatrix,
852 bool pathIsMutable) {
853 CHECK_SHOULD_DRAW(draw);
854
bsalomon@google.com5782d712011-01-21 21:03:59 +0000855 GrPaint grPaint;
856 SkAutoCachedTexture act;
Scroggod757df22011-05-16 13:11:16 +0000857 if (!this->skPaint2GrPaintShader(paint,
858 &act,
859 *draw.fMatrix,
860 &grPaint,
861 true)) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000862 return;
863 }
864
reed@google.com0c219b62011-02-16 21:31:18 +0000865 // BEGIN lift from SkDraw::drawPath()
866
867 SkPath* pathPtr = const_cast<SkPath*>(&origSrcPath);
868 bool doFill = true;
869 SkPath tmpPath;
reed@google.comac10a2d2010-12-22 21:39:39 +0000870
871 if (prePathMatrix) {
reed@google.come3445642011-02-16 23:20:39 +0000872 SkPath* result = pathPtr;
reed@google.com0c219b62011-02-16 21:31:18 +0000873
reed@google.come3445642011-02-16 23:20:39 +0000874 if (!pathIsMutable) {
875 result = &tmpPath;
876 pathIsMutable = true;
reed@google.comac10a2d2010-12-22 21:39:39 +0000877 }
reed@google.come3445642011-02-16 23:20:39 +0000878 // should I push prePathMatrix on our MV stack temporarily, instead
879 // of applying it here? See SkDraw.cpp
880 pathPtr->transform(*prePathMatrix, result);
881 pathPtr = result;
reed@google.comac10a2d2010-12-22 21:39:39 +0000882 }
reed@google.com0c219b62011-02-16 21:31:18 +0000883 // at this point we're done with prePathMatrix
884 SkDEBUGCODE(prePathMatrix = (const SkMatrix*)0x50FF8001;)
reed@google.comac10a2d2010-12-22 21:39:39 +0000885
bsalomon@google.com04de7822011-03-25 18:04:43 +0000886 // This "if" is not part of the SkDraw::drawPath() lift.
887 // When we get a 1.0 wide stroke we hairline stroke it instead of creating
888 // a new stroked-path. This is motivated by canvas2D sites that draw
889 // lines as 1.0 wide stroked paths. We can consider doing an alpha-modulated-
890 // hairline for width < 1.0 when AA is enabled.
891 static const int gMatrixMask = ~(SkMatrix::kIdentity_Mask |
892 SkMatrix::kTranslate_Mask);
893 if (!paint.getPathEffect() &&
894 SkPaint::kStroke_Style == paint.getStyle() &&
895 !(draw.fMatrix->getType() & gMatrixMask) &&
896 SK_Scalar1 == paint.getStrokeWidth()) {
897 doFill = false;
898 }
899
900 if (doFill && (paint.getPathEffect() ||
901 paint.getStyle() != SkPaint::kFill_Style)) {
reed@google.com0c219b62011-02-16 21:31:18 +0000902 doFill = paint.getFillPath(*pathPtr, &tmpPath);
903 pathPtr = &tmpPath;
904 }
905
906 // END lift from SkDraw::drawPath()
907
reed@google.com69302852011-02-16 18:08:07 +0000908 if (paint.getMaskFilter()) {
reed@google.com0c219b62011-02-16 21:31:18 +0000909 // avoid possibly allocating a new path in transform if we can
910 SkPath* devPathPtr = pathIsMutable ? pathPtr : &tmpPath;
911
912 // transform the path into device space
reed@google.come3445642011-02-16 23:20:39 +0000913 pathPtr->transform(*draw.fMatrix, devPathPtr);
reed@google.com0c219b62011-02-16 21:31:18 +0000914
915 drawWithMaskFilter(fContext, *devPathPtr, paint.getMaskFilter(),
reed@google.com69302852011-02-16 18:08:07 +0000916 *draw.fMatrix, *draw.fClip, draw.fBounder, &grPaint);
917 return;
918 }
reed@google.com69302852011-02-16 18:08:07 +0000919
bsalomon@google.comffca4002011-02-22 20:34:01 +0000920 GrPathFill fill = kHairLine_PathFill;
reed@google.comac10a2d2010-12-22 21:39:39 +0000921
reed@google.com0c219b62011-02-16 21:31:18 +0000922 if (doFill) {
923 switch (pathPtr->getFillType()) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000924 case SkPath::kWinding_FillType:
bsalomon@google.comffca4002011-02-22 20:34:01 +0000925 fill = kWinding_PathFill;
reed@google.comac10a2d2010-12-22 21:39:39 +0000926 break;
927 case SkPath::kEvenOdd_FillType:
bsalomon@google.comffca4002011-02-22 20:34:01 +0000928 fill = kEvenOdd_PathFill;
reed@google.comac10a2d2010-12-22 21:39:39 +0000929 break;
930 case SkPath::kInverseWinding_FillType:
bsalomon@google.comffca4002011-02-22 20:34:01 +0000931 fill = kInverseWinding_PathFill;
reed@google.comac10a2d2010-12-22 21:39:39 +0000932 break;
933 case SkPath::kInverseEvenOdd_FillType:
bsalomon@google.comffca4002011-02-22 20:34:01 +0000934 fill = kInverseEvenOdd_PathFill;
reed@google.comac10a2d2010-12-22 21:39:39 +0000935 break;
936 default:
bsalomon@google.com5782d712011-01-21 21:03:59 +0000937 SkDebugf("Unsupported path fill type\n");
reed@google.comac10a2d2010-12-22 21:39:39 +0000938 return;
939 }
940 }
941
reed@google.com07f3ee12011-05-16 17:21:57 +0000942 fContext->drawPath(grPaint, *pathPtr, fill);
reed@google.comac10a2d2010-12-22 21:39:39 +0000943}
944
reed@google.comac10a2d2010-12-22 21:39:39 +0000945void SkGpuDevice::drawBitmap(const SkDraw& draw,
946 const SkBitmap& bitmap,
947 const SkIRect* srcRectPtr,
948 const SkMatrix& m,
949 const SkPaint& paint) {
950 CHECK_SHOULD_DRAW(draw);
951
952 SkIRect srcRect;
953 if (NULL == srcRectPtr) {
954 srcRect.set(0, 0, bitmap.width(), bitmap.height());
955 } else {
956 srcRect = *srcRectPtr;
957 }
958
junov@google.comd935cfb2011-06-27 20:48:23 +0000959 if (paint.getMaskFilter()){
epoger@google.com9ef2d832011-07-01 21:12:20 +0000960 SkBitmap tmp; // storage if we need a subset of bitmap
junov@google.comd935cfb2011-06-27 20:48:23 +0000961 const SkBitmap* bitmapPtr = &bitmap;
epoger@google.com9ef2d832011-07-01 21:12:20 +0000962 if (srcRectPtr) {
963 if (!bitmap.extractSubset(&tmp, srcRect)) {
964 return; // extraction failed
965 }
966 bitmapPtr = &tmp;
junov@google.comd935cfb2011-06-27 20:48:23 +0000967 }
968 SkPaint paintWithTexture(paint);
969 paintWithTexture.setShader(SkShader::CreateBitmapShader( *bitmapPtr,
970 SkShader::kClamp_TileMode, SkShader::kClamp_TileMode))->unref();
971 paintWithTexture.getShader()->setLocalMatrix(m);
972
973 SkRect ScalarRect;
epoger@google.com9ef2d832011-07-01 21:12:20 +0000974 ScalarRect.set(srcRect);
junov@google.comd935cfb2011-06-27 20:48:23 +0000975
epoger@google.com9ef2d832011-07-01 21:12:20 +0000976 if (m.rectStaysRect()) {
977 // Preferred drawing method, optimized for rectangles
978 m.mapRect(&ScalarRect);
979 this->drawRect(draw, ScalarRect, paintWithTexture);
980 } else {
981 // Slower drawing method, for warped or rotated rectangles
982 SkPath path;
983 path.addRect(ScalarRect);
984 path.transform(m);
985 this->drawPath(draw, path, paintWithTexture, NULL, true);
986 }
junov@google.comd935cfb2011-06-27 20:48:23 +0000987 return;
988 }
989
bsalomon@google.com5782d712011-01-21 21:03:59 +0000990 GrPaint grPaint;
Scroggod757df22011-05-16 13:11:16 +0000991 if (!this->skPaint2GrPaintNoShader(paint, true, &grPaint, false)) {
bsalomon@google.com5782d712011-01-21 21:03:59 +0000992 return;
993 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000994 GrSamplerState* sampler = grPaint.getTextureSampler(kBitmapTextureIdx);
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000995 if (paint.isFilterBitmap()) {
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000996 sampler->setFilter(GrSamplerState::kBilinear_Filter);
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000997 } else {
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000998 sampler->setFilter(GrSamplerState::kNearest_Filter);
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000999 }
bsalomon@google.com5782d712011-01-21 21:03:59 +00001000
bsalomon@google.com91958362011-06-13 17:58:13 +00001001 const int maxTextureSize = fContext->getMaxTextureSize();
1002 if (bitmap.getTexture() || (bitmap.width() <= maxTextureSize &&
1003 bitmap.height() <= maxTextureSize)) {
reed@google.comac10a2d2010-12-22 21:39:39 +00001004 // take the fast case
bsalomon@google.com5782d712011-01-21 21:03:59 +00001005 this->internalDrawBitmap(draw, bitmap, srcRect, m, &grPaint);
reed@google.comac10a2d2010-12-22 21:39:39 +00001006 return;
1007 }
1008
1009 // undo the translate done by SkCanvas
1010 int DX = SkMax32(0, srcRect.fLeft);
1011 int DY = SkMax32(0, srcRect.fTop);
1012 // compute clip bounds in local coordinates
1013 SkIRect clipRect;
1014 {
1015 SkRect r;
1016 r.set(draw.fClip->getBounds());
1017 SkMatrix matrix, inverse;
1018 matrix.setConcat(*draw.fMatrix, m);
1019 if (!matrix.invert(&inverse)) {
1020 return;
1021 }
1022 inverse.mapRect(&r);
1023 r.roundOut(&clipRect);
1024 // apply the canvas' translate to our local clip
1025 clipRect.offset(DX, DY);
1026 }
1027
bsalomon@google.com91958362011-06-13 17:58:13 +00001028 int nx = bitmap.width() / maxTextureSize;
1029 int ny = bitmap.height() / maxTextureSize;
reed@google.comac10a2d2010-12-22 21:39:39 +00001030 for (int x = 0; x <= nx; x++) {
1031 for (int y = 0; y <= ny; y++) {
1032 SkIRect tileR;
bsalomon@google.com91958362011-06-13 17:58:13 +00001033 tileR.set(x * maxTextureSize, y * maxTextureSize,
1034 (x + 1) * maxTextureSize, (y + 1) * maxTextureSize);
reed@google.comac10a2d2010-12-22 21:39:39 +00001035 if (!SkIRect::Intersects(tileR, clipRect)) {
1036 continue;
1037 }
1038
1039 SkIRect srcR = tileR;
1040 if (!srcR.intersect(srcRect)) {
1041 continue;
1042 }
1043
1044 SkBitmap tmpB;
1045 if (bitmap.extractSubset(&tmpB, tileR)) {
1046 // now offset it to make it "local" to our tmp bitmap
1047 srcR.offset(-tileR.fLeft, -tileR.fTop);
1048
1049 SkMatrix tmpM(m);
1050 {
1051 int dx = tileR.fLeft - DX + SkMax32(0, srcR.fLeft);
1052 int dy = tileR.fTop - DY + SkMax32(0, srcR.fTop);
1053 tmpM.preTranslate(SkIntToScalar(dx), SkIntToScalar(dy));
1054 }
bsalomon@google.com5782d712011-01-21 21:03:59 +00001055 this->internalDrawBitmap(draw, tmpB, srcR, tmpM, &grPaint);
reed@google.comac10a2d2010-12-22 21:39:39 +00001056 }
1057 }
1058 }
1059}
1060
1061/*
1062 * This is called by drawBitmap(), which has to handle images that may be too
1063 * large to be represented by a single texture.
1064 *
bsalomon@google.com5782d712011-01-21 21:03:59 +00001065 * internalDrawBitmap assumes that the specified bitmap will fit in a texture
1066 * and that non-texture portion of the GrPaint has already been setup.
reed@google.comac10a2d2010-12-22 21:39:39 +00001067 */
1068void SkGpuDevice::internalDrawBitmap(const SkDraw& draw,
1069 const SkBitmap& bitmap,
1070 const SkIRect& srcRect,
1071 const SkMatrix& m,
bsalomon@google.com5782d712011-01-21 21:03:59 +00001072 GrPaint* grPaint) {
bsalomon@google.com91958362011-06-13 17:58:13 +00001073 SkASSERT(bitmap.width() <= fContext->getMaxTextureSize() &&
1074 bitmap.height() <= fContext->getMaxTextureSize());
reed@google.comac10a2d2010-12-22 21:39:39 +00001075
1076 SkAutoLockPixels alp(bitmap);
1077 if (!bitmap.getTexture() && !bitmap.readyToDraw()) {
1078 return;
1079 }
1080
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001081 GrSamplerState* sampler = grPaint->getTextureSampler(kBitmapTextureIdx);
1082
1083 sampler->setWrapX(GrSamplerState::kClamp_WrapMode);
1084 sampler->setWrapY(GrSamplerState::kClamp_WrapMode);
1085 sampler->setSampleMode(GrSamplerState::kNormal_SampleMode);
1086 sampler->setMatrix(GrMatrix::I());
reed@google.comac10a2d2010-12-22 21:39:39 +00001087
1088 GrTexture* texture;
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001089 SkAutoCachedTexture act(this, bitmap, *sampler, &texture);
reed@google.comac10a2d2010-12-22 21:39:39 +00001090 if (NULL == texture) {
1091 return;
1092 }
1093
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001094 grPaint->setTexture(kShaderTextureIdx, texture);
reed@google.com46799cd2011-02-22 20:56:26 +00001095
reed@google.com20efde72011-05-09 17:00:02 +00001096 GrRect dstRect = SkRect::MakeWH(GrIntToScalar(srcRect.width()),
1097 GrIntToScalar(srcRect.height()));
bsalomon@google.comc6cf7232011-02-17 16:43:10 +00001098 GrRect paintRect;
junov@google.com6acc9b32011-05-16 18:32:07 +00001099 paintRect.setLTRB(GrFixedToScalar((srcRect.fLeft << 16) / bitmap.width()),
1100 GrFixedToScalar((srcRect.fTop << 16) / bitmap.height()),
1101 GrFixedToScalar((srcRect.fRight << 16) / bitmap.width()),
bsalomon@google.comc6cf7232011-02-17 16:43:10 +00001102 GrFixedToScalar((srcRect.fBottom << 16) / bitmap.height()));
reed@google.comac10a2d2010-12-22 21:39:39 +00001103
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001104 if (GrSamplerState::kNearest_Filter != sampler->getFilter() &&
junov@google.com6acc9b32011-05-16 18:32:07 +00001105 (srcRect.width() < bitmap.width() ||
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001106 srcRect.height() < bitmap.height())) {
junov@google.com6acc9b32011-05-16 18:32:07 +00001107 // If drawing a subrect of the bitmap and filtering is enabled,
1108 // use a constrained texture domain to avoid color bleeding
1109 GrScalar left, top, right, bottom;
1110 if (srcRect.width() > 1) {
1111 GrScalar border = GR_ScalarHalf / bitmap.width();
1112 left = paintRect.left() + border;
1113 right = paintRect.right() - border;
1114 } else {
1115 left = right = GrScalarHalf(paintRect.left() + paintRect.right());
1116 }
1117 if (srcRect.height() > 1) {
1118 GrScalar border = GR_ScalarHalf / bitmap.height();
1119 top = paintRect.top() + border;
1120 bottom = paintRect.bottom() - border;
1121 } else {
1122 top = bottom = GrScalarHalf(paintRect.top() + paintRect.bottom());
1123 }
1124 GrRect textureDomain;
1125 textureDomain.setLTRB(left, top, right, bottom);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001126 sampler->setTextureDomain(textureDomain);
junov@google.com6acc9b32011-05-16 18:32:07 +00001127 }
1128
bsalomon@google.comcc4dac32011-05-10 13:52:42 +00001129 fContext->drawRectToRect(*grPaint, dstRect, paintRect, &m);
reed@google.comac10a2d2010-12-22 21:39:39 +00001130}
1131
1132void SkGpuDevice::drawSprite(const SkDraw& draw, const SkBitmap& bitmap,
1133 int left, int top, const SkPaint& paint) {
1134 CHECK_SHOULD_DRAW(draw);
1135
1136 SkAutoLockPixels alp(bitmap);
1137 if (!bitmap.getTexture() && !bitmap.readyToDraw()) {
1138 return;
1139 }
1140
bsalomon@google.com5782d712011-01-21 21:03:59 +00001141 GrPaint grPaint;
Scroggod757df22011-05-16 13:11:16 +00001142 if(!this->skPaint2GrPaintNoShader(paint, true, &grPaint, false)) {
bsalomon@google.com5782d712011-01-21 21:03:59 +00001143 return;
1144 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001145
bsalomon@google.com5782d712011-01-21 21:03:59 +00001146 GrAutoMatrix avm(fContext, GrMatrix::I());
1147
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001148 GrSamplerState* sampler = grPaint.getTextureSampler(kBitmapTextureIdx);
bsalomon@google.com5782d712011-01-21 21:03:59 +00001149
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001150 GrTexture* texture;
1151 sampler->setClampNoFilter();
1152 SkAutoCachedTexture act(this, bitmap, *sampler, &texture);
1153
1154 grPaint.setTexture(kBitmapTextureIdx, texture);
bsalomon@google.com5782d712011-01-21 21:03:59 +00001155
bsalomon@google.com5782d712011-01-21 21:03:59 +00001156 fContext->drawRectToRect(grPaint,
reed@google.com20efde72011-05-09 17:00:02 +00001157 GrRect::MakeXYWH(GrIntToScalar(left),
1158 GrIntToScalar(top),
1159 GrIntToScalar(bitmap.width()),
1160 GrIntToScalar(bitmap.height())),
1161 GrRect::MakeWH(GR_Scalar1, GR_Scalar1));
reed@google.comac10a2d2010-12-22 21:39:39 +00001162}
1163
1164void SkGpuDevice::drawDevice(const SkDraw& draw, SkDevice* dev,
1165 int x, int y, const SkPaint& paint) {
1166 CHECK_SHOULD_DRAW(draw);
1167
bsalomon@google.com5782d712011-01-21 21:03:59 +00001168 GrPaint grPaint;
bsalomon@google.comc6cf7232011-02-17 16:43:10 +00001169 if (!((SkGpuDevice*)dev)->bindDeviceAsTexture(&grPaint) ||
Scroggod757df22011-05-16 13:11:16 +00001170 !this->skPaint2GrPaintNoShader(paint, true, &grPaint, false)) {
bsalomon@google.com5782d712011-01-21 21:03:59 +00001171 return;
reed@google.comac10a2d2010-12-22 21:39:39 +00001172 }
bsalomon@google.com5782d712011-01-21 21:03:59 +00001173
bsalomon@google.comb5b31682011-06-16 18:05:35 +00001174 GrTexture* devTex = grPaint.getTexture(0);
1175 SkASSERT(NULL != devTex);
bsalomon@google.com5782d712011-01-21 21:03:59 +00001176
1177 const SkBitmap& bm = dev->accessBitmap(false);
1178 int w = bm.width();
1179 int h = bm.height();
1180
1181 GrAutoMatrix avm(fContext, GrMatrix::I());
1182
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001183 grPaint.getTextureSampler(kBitmapTextureIdx)->setClampNoFilter();
bsalomon@google.com5782d712011-01-21 21:03:59 +00001184
bsalomon@google.comb5b31682011-06-16 18:05:35 +00001185 GrRect dstRect = GrRect::MakeXYWH(GrIntToScalar(x),
1186 GrIntToScalar(y),
1187 GrIntToScalar(w),
1188 GrIntToScalar(h));
1189 // The device being drawn may not fill up its texture (saveLayer uses
1190 // the approximate ).
1191 GrRect srcRect = GrRect::MakeWH(GR_Scalar1 * w / devTex->width(),
1192 GR_Scalar1 * h / devTex->height());
1193
1194 fContext->drawRectToRect(grPaint, dstRect, srcRect);
reed@google.comac10a2d2010-12-22 21:39:39 +00001195}
1196
1197///////////////////////////////////////////////////////////////////////////////
1198
1199// must be in SkCanvas::VertexMode order
bsalomon@google.comffca4002011-02-22 20:34:01 +00001200static const GrPrimitiveType gVertexMode2PrimitiveType[] = {
1201 kTriangles_PrimitiveType,
1202 kTriangleStrip_PrimitiveType,
1203 kTriangleFan_PrimitiveType,
reed@google.comac10a2d2010-12-22 21:39:39 +00001204};
1205
1206void SkGpuDevice::drawVertices(const SkDraw& draw, SkCanvas::VertexMode vmode,
1207 int vertexCount, const SkPoint vertices[],
1208 const SkPoint texs[], const SkColor colors[],
1209 SkXfermode* xmode,
1210 const uint16_t indices[], int indexCount,
1211 const SkPaint& paint) {
1212 CHECK_SHOULD_DRAW(draw);
1213
bsalomon@google.com5782d712011-01-21 21:03:59 +00001214 GrPaint grPaint;
1215 SkAutoCachedTexture act;
1216 // we ignore the shader if texs is null.
1217 if (NULL == texs) {
Scroggod757df22011-05-16 13:11:16 +00001218 if (!this->skPaint2GrPaintNoShader(paint,
1219 false,
1220 &grPaint,
1221 NULL == colors)) {
reed@google.comac10a2d2010-12-22 21:39:39 +00001222 return;
1223 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001224 } else {
reed@google.com1a2e8d22011-01-21 22:08:29 +00001225 if (!this->skPaint2GrPaintShader(paint, &act,
1226 *draw.fMatrix,
Scroggod757df22011-05-16 13:11:16 +00001227 &grPaint,
1228 NULL == colors)) {
bsalomon@google.com5782d712011-01-21 21:03:59 +00001229 return;
1230 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001231 }
bsalomon@google.com5782d712011-01-21 21:03:59 +00001232
1233 if (NULL != xmode && NULL != texs && NULL != colors) {
1234 SkXfermode::Mode mode;
1235 if (!SkXfermode::IsMode(xmode, &mode) ||
1236 SkXfermode::kMultiply_Mode != mode) {
1237 SkDebugf("Unsupported vertex-color/texture xfer mode.\n");
1238#if 0
1239 return
1240#endif
1241 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001242 }
bsalomon@google.com5782d712011-01-21 21:03:59 +00001243
1244#if SK_SCALAR_IS_GR_SCALAR
1245 // even if GrColor and SkColor byte offsets match we need
1246 // to perform pre-multiply.
1247 if (NULL == colors) {
1248 fContext->drawVertices(grPaint,
1249 gVertexMode2PrimitiveType[vmode],
1250 vertexCount,
1251 (GrPoint*) vertices,
1252 (GrPoint*) texs,
1253 NULL,
1254 indices,
1255 indexCount);
1256 } else
1257#endif
1258 {
1259 SkTexCoordSource texSrc(texs);
1260 SkColorSource colSrc(colors);
1261 SkIndexSource idxSrc(indices, indexCount);
1262
1263 fContext->drawCustomVertices(grPaint,
1264 gVertexMode2PrimitiveType[vmode],
1265 SkPositionSource(vertices, vertexCount),
1266 (NULL == texs) ? NULL : &texSrc,
1267 (NULL == colors) ? NULL : &colSrc,
1268 (NULL == indices) ? NULL : &idxSrc);
reed@google.comac10a2d2010-12-22 21:39:39 +00001269 }
1270}
1271
1272///////////////////////////////////////////////////////////////////////////////
1273
1274static void GlyphCacheAuxProc(void* data) {
1275 delete (GrFontScaler*)data;
1276}
1277
1278static GrFontScaler* get_gr_font_scaler(SkGlyphCache* cache) {
1279 void* auxData;
1280 GrFontScaler* scaler = NULL;
1281 if (cache->getAuxProcData(GlyphCacheAuxProc, &auxData)) {
1282 scaler = (GrFontScaler*)auxData;
1283 }
1284 if (NULL == scaler) {
1285 scaler = new SkGrFontScaler(cache);
1286 cache->setAuxProc(GlyphCacheAuxProc, scaler);
1287 }
1288 return scaler;
1289}
1290
1291static void SkGPU_Draw1Glyph(const SkDraw1Glyph& state,
1292 SkFixed fx, SkFixed fy,
1293 const SkGlyph& glyph) {
1294 SkASSERT(glyph.fWidth > 0 && glyph.fHeight > 0);
1295
1296 GrSkDrawProcs* procs = (GrSkDrawProcs*)state.fDraw->fProcs;
1297
1298 if (NULL == procs->fFontScaler) {
1299 procs->fFontScaler = get_gr_font_scaler(state.fCache);
1300 }
reed@google.com39ce0ac2011-04-08 15:42:19 +00001301
1302 /*
reed@google.com3b139f52011-06-07 17:56:25 +00001303 * What should we do with fy? (assuming horizontal/latin text)
reed@google.com39ce0ac2011-04-08 15:42:19 +00001304 *
reed@google.com3b139f52011-06-07 17:56:25 +00001305 * The raster code calls SkFixedFloorToFixed on it, as it does with fx.
1306 * It calls that rather than round, because our caller has already added
1307 * SK_FixedHalf, so that calling floor gives us the rounded integer.
1308 *
1309 * Test code between raster and gpu (they should draw the same)
1310 *
1311 * canvas->drawText("Hamburgefons", 12, 0, 16.5f, paint);
1312 *
1313 * Perhaps we should only perform this integralization if there is no
1314 * fExtMatrix...
reed@google.com39ce0ac2011-04-08 15:42:19 +00001315 */
reed@google.com3b139f52011-06-07 17:56:25 +00001316 fy = SkFixedFloorToFixed(fy);
1317
reed@google.comac10a2d2010-12-22 21:39:39 +00001318 procs->fTextContext->drawPackedGlyph(GrGlyph::Pack(glyph.getGlyphID(), fx, 0),
reed@google.com3b139f52011-06-07 17:56:25 +00001319 SkFixedFloorToFixed(fx), fy,
reed@google.comac10a2d2010-12-22 21:39:39 +00001320 procs->fFontScaler);
1321}
1322
bsalomon@google.com5782d712011-01-21 21:03:59 +00001323SkDrawProcs* SkGpuDevice::initDrawForText(GrTextContext* context) {
reed@google.comac10a2d2010-12-22 21:39:39 +00001324
1325 // deferred allocation
1326 if (NULL == fDrawProcs) {
1327 fDrawProcs = new GrSkDrawProcs;
1328 fDrawProcs->fD1GProc = SkGPU_Draw1Glyph;
1329 fDrawProcs->fContext = fContext;
1330 }
1331
1332 // init our (and GL's) state
1333 fDrawProcs->fTextContext = context;
1334 fDrawProcs->fFontScaler = NULL;
1335 return fDrawProcs;
1336}
1337
1338void SkGpuDevice::drawText(const SkDraw& draw, const void* text,
1339 size_t byteLength, SkScalar x, SkScalar y,
1340 const SkPaint& paint) {
1341 CHECK_SHOULD_DRAW(draw);
1342
1343 if (draw.fMatrix->getType() & SkMatrix::kPerspective_Mask) {
1344 // this guy will just call our drawPath()
1345 draw.drawText((const char*)text, byteLength, x, y, paint);
1346 } else {
reed@google.comac10a2d2010-12-22 21:39:39 +00001347 SkDraw myDraw(draw);
bsalomon@google.com5782d712011-01-21 21:03:59 +00001348
1349 GrPaint grPaint;
1350 SkAutoCachedTexture act;
1351
Scroggod757df22011-05-16 13:11:16 +00001352 if (!this->skPaint2GrPaintShader(paint,
1353 &act,
1354 *draw.fMatrix,
1355 &grPaint,
1356 true)) {
bsalomon@google.com5782d712011-01-21 21:03:59 +00001357 return;
1358 }
bsalomon@google.comcc4dac32011-05-10 13:52:42 +00001359 GrTextContext context(fContext, grPaint, draw.fExtMatrix);
bsalomon@google.com5782d712011-01-21 21:03:59 +00001360 myDraw.fProcs = this->initDrawForText(&context);
reed@google.comac10a2d2010-12-22 21:39:39 +00001361 this->INHERITED::drawText(myDraw, text, byteLength, x, y, paint);
1362 }
1363}
1364
1365void SkGpuDevice::drawPosText(const SkDraw& draw, const void* text,
1366 size_t byteLength, const SkScalar pos[],
1367 SkScalar constY, int scalarsPerPos,
1368 const SkPaint& paint) {
1369 CHECK_SHOULD_DRAW(draw);
1370
1371 if (draw.fMatrix->getType() & SkMatrix::kPerspective_Mask) {
1372 // this guy will just call our drawPath()
1373 draw.drawPosText((const char*)text, byteLength, pos, constY,
1374 scalarsPerPos, paint);
1375 } else {
reed@google.comac10a2d2010-12-22 21:39:39 +00001376 SkDraw myDraw(draw);
bsalomon@google.com5782d712011-01-21 21:03:59 +00001377
1378 GrPaint grPaint;
1379 SkAutoCachedTexture act;
Scroggod757df22011-05-16 13:11:16 +00001380 if (!this->skPaint2GrPaintShader(paint,
1381 &act,
1382 *draw.fMatrix,
1383 &grPaint,
1384 true)) {
bsalomon@google.com5782d712011-01-21 21:03:59 +00001385 return;
1386 }
1387
bsalomon@google.comcc4dac32011-05-10 13:52:42 +00001388 GrTextContext context(fContext, grPaint, draw.fExtMatrix);
bsalomon@google.com5782d712011-01-21 21:03:59 +00001389 myDraw.fProcs = this->initDrawForText(&context);
reed@google.comac10a2d2010-12-22 21:39:39 +00001390 this->INHERITED::drawPosText(myDraw, text, byteLength, pos, constY,
1391 scalarsPerPos, paint);
1392 }
1393}
1394
1395void SkGpuDevice::drawTextOnPath(const SkDraw& draw, const void* text,
1396 size_t len, const SkPath& path,
1397 const SkMatrix* m, const SkPaint& paint) {
1398 CHECK_SHOULD_DRAW(draw);
1399
1400 SkASSERT(draw.fDevice == this);
1401 draw.drawTextOnPath((const char*)text, len, path, m, paint);
1402}
1403
1404///////////////////////////////////////////////////////////////////////////////
1405
reed@google.comf67e4cf2011-03-15 20:56:58 +00001406bool SkGpuDevice::filterTextFlags(const SkPaint& paint, TextFlags* flags) {
1407 if (!paint.isLCDRenderText()) {
1408 // we're cool with the paint as is
1409 return false;
1410 }
1411
1412 if (paint.getShader() ||
1413 paint.getXfermode() || // unless its srcover
1414 paint.getMaskFilter() ||
1415 paint.getRasterizer() ||
1416 paint.getColorFilter() ||
1417 paint.getPathEffect() ||
1418 paint.isFakeBoldText() ||
1419 paint.getStyle() != SkPaint::kFill_Style) {
1420 // turn off lcd
1421 flags->fFlags = paint.getFlags() & ~SkPaint::kLCDRenderText_Flag;
1422 flags->fHinting = paint.getHinting();
1423 return true;
1424 }
1425 // we're cool with the paint as is
1426 return false;
1427}
1428
1429///////////////////////////////////////////////////////////////////////////////
1430
reed@google.comac10a2d2010-12-22 21:39:39 +00001431SkGpuDevice::TexCache* SkGpuDevice::lockCachedTexture(const SkBitmap& bitmap,
bsalomon@google.comfea37b52011-04-25 15:51:06 +00001432 const GrSamplerState& sampler,
1433 GrTexture** texture,
bsalomon@google.come97f0852011-06-17 13:10:25 +00001434 TexType type) {
bsalomon@google.comfea37b52011-04-25 15:51:06 +00001435 GrTexture* newTexture = NULL;
1436 GrTextureEntry* entry = NULL;
reed@google.comac10a2d2010-12-22 21:39:39 +00001437 GrContext* ctx = this->context();
bsalomon@google.comfea37b52011-04-25 15:51:06 +00001438
bsalomon@google.come97f0852011-06-17 13:10:25 +00001439 if (kBitmap_TexType != type) {
bsalomon@google.comfea37b52011-04-25 15:51:06 +00001440 const GrTextureDesc desc = {
1441 kRenderTarget_GrTextureFlagBit,
1442 kNone_GrAALevel,
1443 bitmap.width(),
1444 bitmap.height(),
1445 SkGr::Bitmap2PixelConfig(bitmap)
1446 };
bsalomon@google.come97f0852011-06-17 13:10:25 +00001447 if (kSaveLayerDeviceRenderTarget_TexType == type) {
bsalomon@google.comb5b31682011-06-16 18:05:35 +00001448 // we know layers will only be drawn through drawDevice.
1449 // drawDevice has been made to work with content embedded in a
1450 // larger texture so its okay to use the approximate version.
1451 entry = ctx->findApproximateKeylessTexture(desc);
1452 } else {
bsalomon@google.come97f0852011-06-17 13:10:25 +00001453 SkASSERT(kDeviceRenderTarget_TexType == type);
bsalomon@google.comb5b31682011-06-16 18:05:35 +00001454 entry = ctx->lockKeylessTexture(desc);
1455 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001456 } else {
junov@google.com4ee7ae52011-06-30 17:30:49 +00001457 if (!bitmap.isVolatile()) {
1458 uint32_t p0, p1;
1459 p0 = bitmap.getGenerationID();
1460 p1 = bitmap.pixelRefOffset();
1461 GrTextureKey key(p0, p1, bitmap.width(), bitmap.height());
1462
1463 entry = ctx->findAndLockTexture(&key, sampler);
1464 if (NULL == entry)
1465 entry = sk_gr_create_bitmap_texture(ctx, &key, sampler,
1466 bitmap);
1467 } else {
1468 entry = sk_gr_create_bitmap_texture(ctx, NULL, sampler, bitmap);
1469 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001470 if (NULL == entry) {
junov@google.com4ee7ae52011-06-30 17:30:49 +00001471 GrPrintf("---- failed to create texture for cache [%d %d]\n",
1472 bitmap.width(), bitmap.height());
reed@google.comac10a2d2010-12-22 21:39:39 +00001473 }
1474 }
1475
1476 if (NULL != entry) {
1477 newTexture = entry->texture();
reed@google.comac10a2d2010-12-22 21:39:39 +00001478 if (texture) {
1479 *texture = newTexture;
1480 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001481 }
1482 return (TexCache*)entry;
1483}
1484
1485void SkGpuDevice::unlockCachedTexture(TexCache* cache) {
1486 this->context()->unlockTexture((GrTextureEntry*)cache);
1487}
1488
bsalomon@google.come97f0852011-06-17 13:10:25 +00001489SkDevice* SkGpuDevice::onCreateCompatibleDevice(SkBitmap::Config config,
1490 int width, int height,
1491 bool isOpaque,
1492 Usage usage) {
1493 return SkNEW_ARGS(SkGpuDevice,(this->context(), config,
1494 width, height, usage));
1495}
1496