blob: 5f088472d87875b498bf960ad922de68dc5a8b88 [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"
reed@google.com7b201d22011-01-11 18:59:23 +000022#include "SkGpuDeviceFactory.h"
reed@google.comac10a2d2010-12-22 21:39:39 +000023#include "SkGrTexturePixelRef.h"
24
Scroggo97c88c22011-05-11 14:05:25 +000025#include "SkColorFilter.h"
reed@google.comac10a2d2010-12-22 21:39:39 +000026#include "SkDrawProcs.h"
27#include "SkGlyphCache.h"
reed@google.comc9aa5872011-04-05 21:05:37 +000028#include "SkUtils.h"
reed@google.comac10a2d2010-12-22 21:39:39 +000029
30#define CACHE_LAYER_TEXTURES 1
31
32#if 0
33 extern bool (*gShouldDrawProc)();
34 #define CHECK_SHOULD_DRAW(draw) \
35 do { \
36 if (gShouldDrawProc && !gShouldDrawProc()) return; \
37 this->prepareRenderTarget(draw); \
38 } while (0)
39#else
40 #define CHECK_SHOULD_DRAW(draw) this->prepareRenderTarget(draw)
41#endif
42
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +000043// we use the same texture slot on GrPaint for bitmaps and shaders
44// (since drawBitmap, drawSprite, and drawDevice ignore skia's shader)
45enum {
46 kBitmapTextureIdx = 0,
47 kShaderTextureIdx = 0
48};
49
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
bsalomon@google.com5782d712011-01-21 21:03:59 +0000475 SkPaint noAlphaPaint(skPaint);
476 noAlphaPaint.setAlpha(255);
477 shader->setContext(this->accessBitmap(false), noAlphaPaint, ctm);
reed@google.comac10a2d2010-12-22 21:39:39 +0000478
reed@google.comac10a2d2010-12-22 21:39:39 +0000479 SkBitmap bitmap;
480 SkMatrix matrix;
481 SkShader::TileMode tileModes[2];
482 SkScalar twoPointParams[3];
483 SkShader::BitmapType bmptype = shader->asABitmap(&bitmap, &matrix,
484 tileModes, twoPointParams);
485
bsalomon@google.com5782d712011-01-21 21:03:59 +0000486 GrSamplerState::SampleMode sampleMode = sk_bmp_type_to_sample_mode[bmptype];
487 if (-1 == sampleMode) {
488 SkDebugf("shader->asABitmap() == kNone_BitmapType\n");
489 return false;
reed@google.comac10a2d2010-12-22 21:39:39 +0000490 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000491 GrSamplerState* sampler = grPaint->getTextureSampler(kShaderTextureIdx);
492 sampler->setSampleMode(sampleMode);
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000493 if (skPaint.isFilterBitmap()) {
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000494 sampler->setFilter(GrSamplerState::kBilinear_Filter);
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000495 } else {
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000496 sampler->setFilter(GrSamplerState::kNearest_Filter);
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000497 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000498 sampler->setWrapX(sk_tile_mode_to_grwrap(tileModes[0]));
499 sampler->setWrapY(sk_tile_mode_to_grwrap(tileModes[1]));
reed@google.comac10a2d2010-12-22 21:39:39 +0000500 if (GrSamplerState::kRadial2_SampleMode == sampleMode) {
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000501 sampler->setRadial2Params(twoPointParams[0],
502 twoPointParams[1],
503 twoPointParams[2] < 0);
reed@google.comac10a2d2010-12-22 21:39:39 +0000504 }
505
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000506 GrTexture* texture = act->set(this, bitmap, *sampler);
reed@google.comac10a2d2010-12-22 21:39:39 +0000507 if (NULL == texture) {
bsalomon@google.com5782d712011-01-21 21:03:59 +0000508 SkDebugf("Couldn't convert bitmap to texture.\n");
509 return false;
reed@google.comac10a2d2010-12-22 21:39:39 +0000510 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000511 grPaint->setTexture(kShaderTextureIdx, texture);
reed@google.comac10a2d2010-12-22 21:39:39 +0000512
513 // since our texture coords will be in local space, we wack the texture
514 // matrix to map them back into 0...1 before we load it
515 SkMatrix localM;
516 if (shader->getLocalMatrix(&localM)) {
517 SkMatrix inverse;
518 if (localM.invert(&inverse)) {
519 matrix.preConcat(inverse);
520 }
521 }
522 if (SkShader::kDefault_BitmapType == bmptype) {
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000523 GrScalar sx = GrFixedToScalar(GR_Fixed1 / bitmap.width());
524 GrScalar sy = GrFixedToScalar(GR_Fixed1 / bitmap.height());
reed@google.comac10a2d2010-12-22 21:39:39 +0000525 matrix.postScale(sx, sy);
reed@google.comac10a2d2010-12-22 21:39:39 +0000526 } else if (SkShader::kRadial_BitmapType == bmptype) {
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000527 GrScalar s = GrFixedToScalar(GR_Fixed1 / bitmap.width());
reed@google.comac10a2d2010-12-22 21:39:39 +0000528 matrix.postScale(s, s);
529 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000530 sampler->setMatrix(matrix);
bsalomon@google.com5782d712011-01-21 21:03:59 +0000531
532 return true;
reed@google.comac10a2d2010-12-22 21:39:39 +0000533}
534
535///////////////////////////////////////////////////////////////////////////////
bsalomon@google.com5782d712011-01-21 21:03:59 +0000536
537class SkPositionSource {
538public:
539 SkPositionSource(const SkPoint* points, int count)
540 : fPoints(points), fCount(count) {}
541
542 int count() const { return fCount; }
543
544 void writeValue(int i, GrPoint* dstPosition) const {
545 SkASSERT(i < fCount);
546 dstPosition->fX = SkScalarToGrScalar(fPoints[i].fX);
547 dstPosition->fY = SkScalarToGrScalar(fPoints[i].fY);
548 }
549private:
bsalomon@google.com5782d712011-01-21 21:03:59 +0000550 const SkPoint* fPoints;
bsalomon@google.com19628322011-02-03 21:30:17 +0000551 int fCount;
bsalomon@google.com5782d712011-01-21 21:03:59 +0000552};
553
554class SkTexCoordSource {
555public:
556 SkTexCoordSource(const SkPoint* coords)
557 : fCoords(coords) {}
558
559 void writeValue(int i, GrPoint* dstCoord) const {
560 dstCoord->fX = SkScalarToGrScalar(fCoords[i].fX);
561 dstCoord->fY = SkScalarToGrScalar(fCoords[i].fY);
562 }
563private:
564 const SkPoint* fCoords;
565};
566
567class SkColorSource {
568public:
569 SkColorSource(const SkColor* colors) : fColors(colors) {}
570
571 void writeValue(int i, GrColor* dstColor) const {
572 *dstColor = SkGr::SkColor2GrColor(fColors[i]);
573 }
574private:
575 const SkColor* fColors;
576};
577
578class SkIndexSource {
579public:
580 SkIndexSource(const uint16_t* indices, int count)
581 : fIndices(indices), fCount(count) {
582 }
583
584 int count() const { return fCount; }
585
586 void writeValue(int i, uint16_t* dstIndex) const {
587 *dstIndex = fIndices[i];
588 }
589
590private:
bsalomon@google.com5782d712011-01-21 21:03:59 +0000591 const uint16_t* fIndices;
bsalomon@google.com19628322011-02-03 21:30:17 +0000592 int fCount;
bsalomon@google.com5782d712011-01-21 21:03:59 +0000593};
594
595///////////////////////////////////////////////////////////////////////////////
596
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000597#if 0 // not currently being used so don't compile,
598
bsalomon@google.com5782d712011-01-21 21:03:59 +0000599// can be used for positions or texture coordinates
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000600
bsalomon@google.com5782d712011-01-21 21:03:59 +0000601class SkRectFanSource {
602public:
603 SkRectFanSource(const SkRect& rect) : fRect(rect) {}
604
605 int count() const { return 4; }
606
607 void writeValue(int i, GrPoint* dstPoint) const {
608 SkASSERT(i < 4);
609 dstPoint->fX = SkScalarToGrScalar((i % 3) ? fRect.fRight :
610 fRect.fLeft);
611 dstPoint->fY = SkScalarToGrScalar((i < 2) ? fRect.fTop :
612 fRect.fBottom);
613 }
614private:
615 const SkRect& fRect;
616};
617
618class SkIRectFanSource {
619public:
620 SkIRectFanSource(const SkIRect& rect) : fRect(rect) {}
621
622 int count() const { return 4; }
623
624 void writeValue(int i, GrPoint* dstPoint) const {
625 SkASSERT(i < 4);
626 dstPoint->fX = (i % 3) ? GrIntToScalar(fRect.fRight) :
627 GrIntToScalar(fRect.fLeft);
628 dstPoint->fY = (i < 2) ? GrIntToScalar(fRect.fTop) :
629 GrIntToScalar(fRect.fBottom);
630 }
631private:
632 const SkIRect& fRect;
633};
634
635class SkMatRectFanSource {
636public:
637 SkMatRectFanSource(const SkRect& rect, const SkMatrix& matrix)
638 : fRect(rect), fMatrix(matrix) {}
639
640 int count() const { return 4; }
641
642 void writeValue(int i, GrPoint* dstPoint) const {
643 SkASSERT(i < 4);
644
645#if SK_SCALAR_IS_GR_SCALAR
646 fMatrix.mapXY((i % 3) ? fRect.fRight : fRect.fLeft,
647 (i < 2) ? fRect.fTop : fRect.fBottom,
648 (SkPoint*)dstPoint);
649#else
650 SkPoint dst;
651 fMatrix.mapXY((i % 3) ? fRect.fRight : fRect.fLeft,
652 (i < 2) ? fRect.fTop : fRect.fBottom,
653 &dst);
654 dstPoint->fX = SkScalarToGrScalar(dst.fX);
655 dstPoint->fY = SkScalarToGrScalar(dst.fY);
656#endif
657 }
658private:
659 const SkRect& fRect;
660 const SkMatrix& fMatrix;
661};
662
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000663#endif
664
reed@google.comac10a2d2010-12-22 21:39:39 +0000665///////////////////////////////////////////////////////////////////////////////
666
bsalomon@google.com398109c2011-04-14 18:40:27 +0000667void SkGpuDevice::clear(SkColor color) {
bsalomon@google.com31a58402011-04-27 21:00:02 +0000668 fContext->clear(NULL, color);
bsalomon@google.com398109c2011-04-14 18:40:27 +0000669}
670
reed@google.comac10a2d2010-12-22 21:39:39 +0000671void SkGpuDevice::drawPaint(const SkDraw& draw, const SkPaint& paint) {
672 CHECK_SHOULD_DRAW(draw);
673
bsalomon@google.com5782d712011-01-21 21:03:59 +0000674 GrPaint grPaint;
675 SkAutoCachedTexture act;
Scroggod757df22011-05-16 13:11:16 +0000676 if (!this->skPaint2GrPaintShader(paint,
677 &act,
678 *draw.fMatrix,
679 &grPaint,
680 true)) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000681 return;
682 }
bsalomon@google.com5782d712011-01-21 21:03:59 +0000683
684 fContext->drawPaint(grPaint);
reed@google.comac10a2d2010-12-22 21:39:39 +0000685}
686
687// must be in SkCanvas::PointMode order
bsalomon@google.comffca4002011-02-22 20:34:01 +0000688static const GrPrimitiveType gPointMode2PrimtiveType[] = {
689 kPoints_PrimitiveType,
690 kLines_PrimitiveType,
691 kLineStrip_PrimitiveType
reed@google.comac10a2d2010-12-22 21:39:39 +0000692};
693
694void SkGpuDevice::drawPoints(const SkDraw& draw, SkCanvas::PointMode mode,
bsalomon@google.com5782d712011-01-21 21:03:59 +0000695 size_t count, const SkPoint pts[], const SkPaint& paint) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000696 CHECK_SHOULD_DRAW(draw);
697
698 SkScalar width = paint.getStrokeWidth();
699 if (width < 0) {
700 return;
701 }
702
703 // we only handle hairlines here, else we let the SkDraw call our drawPath()
704 if (width > 0) {
705 draw.drawPoints(mode, count, pts, paint, true);
706 return;
707 }
708
bsalomon@google.com5782d712011-01-21 21:03:59 +0000709 GrPaint grPaint;
710 SkAutoCachedTexture act;
Scroggod757df22011-05-16 13:11:16 +0000711 if (!this->skPaint2GrPaintShader(paint,
712 &act,
713 *draw.fMatrix,
714 &grPaint,
715 true)) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000716 return;
717 }
718
reed@google.comac10a2d2010-12-22 21:39:39 +0000719#if SK_SCALAR_IS_GR_SCALAR
bsalomon@google.com5782d712011-01-21 21:03:59 +0000720 fContext->drawVertices(grPaint,
721 gPointMode2PrimtiveType[mode],
722 count,
723 (GrPoint*)pts,
724 NULL,
725 NULL,
726 NULL,
727 0);
reed@google.comac10a2d2010-12-22 21:39:39 +0000728#else
bsalomon@google.com5782d712011-01-21 21:03:59 +0000729 fContext->drawCustomVertices(grPaint,
730 gPointMode2PrimtiveType[mode],
731 SkPositionSource(pts, count));
reed@google.comac10a2d2010-12-22 21:39:39 +0000732#endif
reed@google.comac10a2d2010-12-22 21:39:39 +0000733}
734
reed@google.comc9aa5872011-04-05 21:05:37 +0000735///////////////////////////////////////////////////////////////////////////////
736
reed@google.comac10a2d2010-12-22 21:39:39 +0000737void SkGpuDevice::drawRect(const SkDraw& draw, const SkRect& rect,
738 const SkPaint& paint) {
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000739 CHECK_SHOULD_DRAW(draw);
740
741 bool doStroke = paint.getStyle() == SkPaint::kStroke_Style;
742 SkScalar width = paint.getStrokeWidth();
743
744 /*
745 We have special code for hairline strokes, miter-strokes, and fills.
746 Anything else we just call our path code.
747 */
748 bool usePath = doStroke && width > 0 &&
749 paint.getStrokeJoin() != SkPaint::kMiter_Join;
750 // another reason we might need to call drawPath...
751 if (paint.getMaskFilter()) {
752 usePath = true;
753 }
reed@google.com67db6642011-05-26 11:46:35 +0000754 // until we aa rotated rects...
755 if (!usePath && paint.isAntiAlias() && !draw.fMatrix->rectStaysRect()) {
756 usePath = true;
757 }
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000758
759 if (usePath) {
760 SkPath path;
761 path.addRect(rect);
762 this->drawPath(draw, path, paint, NULL, true);
763 return;
764 }
765
766 GrPaint grPaint;
767 SkAutoCachedTexture act;
Scroggod757df22011-05-16 13:11:16 +0000768 if (!this->skPaint2GrPaintShader(paint,
769 &act,
770 *draw.fMatrix,
771 &grPaint,
772 true)) {
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000773 return;
774 }
reed@google.com20efde72011-05-09 17:00:02 +0000775 fContext->drawRect(grPaint, rect, doStroke ? width : -1);
reed@google.comac10a2d2010-12-22 21:39:39 +0000776}
777
reed@google.com69302852011-02-16 18:08:07 +0000778#include "SkMaskFilter.h"
779#include "SkBounder.h"
780
reed@google.com69302852011-02-16 18:08:07 +0000781static bool drawWithMaskFilter(GrContext* context, const SkPath& path,
782 SkMaskFilter* filter, const SkMatrix& matrix,
783 const SkRegion& clip, SkBounder* bounder,
784 GrPaint* grp) {
785 SkMask srcM, dstM;
786
787 if (!SkDraw::DrawToMask(path, &clip.getBounds(), filter, &matrix, &srcM,
788 SkMask::kComputeBoundsAndRenderImage_CreateMode)) {
789 return false;
790 }
791
792 SkAutoMaskImage autoSrc(&srcM, false);
793
794 if (!filter->filterMask(&dstM, srcM, matrix, NULL)) {
795 return false;
796 }
797 // this will free-up dstM when we're done (allocated in filterMask())
798 SkAutoMaskImage autoDst(&dstM, false);
799
800 if (clip.quickReject(dstM.fBounds)) {
801 return false;
802 }
803 if (bounder && !bounder->doIRect(dstM.fBounds)) {
804 return false;
805 }
806
807 // we now have a device-aligned 8bit mask in dstM, ready to be drawn using
808 // the current clip (and identity matrix) and grpaint settings
809
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000810 // used to compute inverse view, if necessary
811 GrMatrix ivm = context->getMatrix();
812
reed@google.com0c219b62011-02-16 21:31:18 +0000813 GrAutoMatrix avm(context, GrMatrix::I());
reed@google.com69302852011-02-16 18:08:07 +0000814
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000815 const GrTextureDesc desc = {
816 kNone_GrTextureFlags,
817 kNone_GrAALevel,
reed@google.com69302852011-02-16 18:08:07 +0000818 dstM.fBounds.width(),
819 dstM.fBounds.height(),
bsalomon@google.com669fdc42011-04-05 17:08:27 +0000820 kAlpha_8_GrPixelConfig
reed@google.com69302852011-02-16 18:08:07 +0000821 };
822
823 GrTexture* texture = context->createUncachedTexture(desc, dstM.fImage,
824 dstM.fRowBytes);
825 if (NULL == texture) {
826 return false;
827 }
828
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000829 if (grp->hasTextureOrMask() && ivm.invert(&ivm)) {
830 grp->preConcatActiveSamplerMatrices(ivm);
831 }
832
833 static const int MASK_IDX = GrPaint::kMaxMasks - 1;
834 // we assume the last mask index is available for use
835 GrAssert(NULL == grp->getMask(MASK_IDX));
836 grp->setMask(MASK_IDX, texture);
reed@google.com0c219b62011-02-16 21:31:18 +0000837 texture->unref();
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000838 grp->getMaskSampler(MASK_IDX)->setClampNoFilter();
reed@google.com69302852011-02-16 18:08:07 +0000839
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000840 GrRect d;
841 d.setLTRB(GrIntToScalar(dstM.fBounds.fLeft),
reed@google.com0c219b62011-02-16 21:31:18 +0000842 GrIntToScalar(dstM.fBounds.fTop),
843 GrIntToScalar(dstM.fBounds.fRight),
844 GrIntToScalar(dstM.fBounds.fBottom));
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000845
846 GrMatrix m;
847 m.setTranslate(-dstM.fBounds.fLeft, -dstM.fBounds.fTop);
848 m.postIDiv(dstM.fBounds.width(), dstM.fBounds.height());
849 grp->getMaskSampler(MASK_IDX)->setMatrix(m);
850
851 context->drawRect(*grp, d);
reed@google.com69302852011-02-16 18:08:07 +0000852 return true;
853}
reed@google.com69302852011-02-16 18:08:07 +0000854
reed@google.com0c219b62011-02-16 21:31:18 +0000855void SkGpuDevice::drawPath(const SkDraw& draw, const SkPath& origSrcPath,
reed@google.comac10a2d2010-12-22 21:39:39 +0000856 const SkPaint& paint, const SkMatrix* prePathMatrix,
857 bool pathIsMutable) {
858 CHECK_SHOULD_DRAW(draw);
859
bsalomon@google.com5782d712011-01-21 21:03:59 +0000860 GrPaint grPaint;
861 SkAutoCachedTexture act;
Scroggod757df22011-05-16 13:11:16 +0000862 if (!this->skPaint2GrPaintShader(paint,
863 &act,
864 *draw.fMatrix,
865 &grPaint,
866 true)) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000867 return;
868 }
869
reed@google.com0c219b62011-02-16 21:31:18 +0000870 // BEGIN lift from SkDraw::drawPath()
871
872 SkPath* pathPtr = const_cast<SkPath*>(&origSrcPath);
873 bool doFill = true;
874 SkPath tmpPath;
reed@google.comac10a2d2010-12-22 21:39:39 +0000875
876 if (prePathMatrix) {
reed@google.come3445642011-02-16 23:20:39 +0000877 SkPath* result = pathPtr;
reed@google.com0c219b62011-02-16 21:31:18 +0000878
reed@google.come3445642011-02-16 23:20:39 +0000879 if (!pathIsMutable) {
880 result = &tmpPath;
881 pathIsMutable = true;
reed@google.comac10a2d2010-12-22 21:39:39 +0000882 }
reed@google.come3445642011-02-16 23:20:39 +0000883 // should I push prePathMatrix on our MV stack temporarily, instead
884 // of applying it here? See SkDraw.cpp
885 pathPtr->transform(*prePathMatrix, result);
886 pathPtr = result;
reed@google.comac10a2d2010-12-22 21:39:39 +0000887 }
reed@google.com0c219b62011-02-16 21:31:18 +0000888 // at this point we're done with prePathMatrix
889 SkDEBUGCODE(prePathMatrix = (const SkMatrix*)0x50FF8001;)
reed@google.comac10a2d2010-12-22 21:39:39 +0000890
bsalomon@google.com04de7822011-03-25 18:04:43 +0000891 // This "if" is not part of the SkDraw::drawPath() lift.
892 // When we get a 1.0 wide stroke we hairline stroke it instead of creating
893 // a new stroked-path. This is motivated by canvas2D sites that draw
894 // lines as 1.0 wide stroked paths. We can consider doing an alpha-modulated-
895 // hairline for width < 1.0 when AA is enabled.
896 static const int gMatrixMask = ~(SkMatrix::kIdentity_Mask |
897 SkMatrix::kTranslate_Mask);
898 if (!paint.getPathEffect() &&
899 SkPaint::kStroke_Style == paint.getStyle() &&
900 !(draw.fMatrix->getType() & gMatrixMask) &&
901 SK_Scalar1 == paint.getStrokeWidth()) {
902 doFill = false;
903 }
904
905 if (doFill && (paint.getPathEffect() ||
906 paint.getStyle() != SkPaint::kFill_Style)) {
reed@google.com0c219b62011-02-16 21:31:18 +0000907 doFill = paint.getFillPath(*pathPtr, &tmpPath);
908 pathPtr = &tmpPath;
909 }
910
911 // END lift from SkDraw::drawPath()
912
reed@google.com69302852011-02-16 18:08:07 +0000913 if (paint.getMaskFilter()) {
reed@google.com0c219b62011-02-16 21:31:18 +0000914 // avoid possibly allocating a new path in transform if we can
915 SkPath* devPathPtr = pathIsMutable ? pathPtr : &tmpPath;
916
917 // transform the path into device space
reed@google.come3445642011-02-16 23:20:39 +0000918 pathPtr->transform(*draw.fMatrix, devPathPtr);
reed@google.com0c219b62011-02-16 21:31:18 +0000919
920 drawWithMaskFilter(fContext, *devPathPtr, paint.getMaskFilter(),
reed@google.com69302852011-02-16 18:08:07 +0000921 *draw.fMatrix, *draw.fClip, draw.fBounder, &grPaint);
922 return;
923 }
reed@google.com69302852011-02-16 18:08:07 +0000924
bsalomon@google.comffca4002011-02-22 20:34:01 +0000925 GrPathFill fill = kHairLine_PathFill;
reed@google.comac10a2d2010-12-22 21:39:39 +0000926
reed@google.com0c219b62011-02-16 21:31:18 +0000927 if (doFill) {
928 switch (pathPtr->getFillType()) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000929 case SkPath::kWinding_FillType:
bsalomon@google.comffca4002011-02-22 20:34:01 +0000930 fill = kWinding_PathFill;
reed@google.comac10a2d2010-12-22 21:39:39 +0000931 break;
932 case SkPath::kEvenOdd_FillType:
bsalomon@google.comffca4002011-02-22 20:34:01 +0000933 fill = kEvenOdd_PathFill;
reed@google.comac10a2d2010-12-22 21:39:39 +0000934 break;
935 case SkPath::kInverseWinding_FillType:
bsalomon@google.comffca4002011-02-22 20:34:01 +0000936 fill = kInverseWinding_PathFill;
reed@google.comac10a2d2010-12-22 21:39:39 +0000937 break;
938 case SkPath::kInverseEvenOdd_FillType:
bsalomon@google.comffca4002011-02-22 20:34:01 +0000939 fill = kInverseEvenOdd_PathFill;
reed@google.comac10a2d2010-12-22 21:39:39 +0000940 break;
941 default:
bsalomon@google.com5782d712011-01-21 21:03:59 +0000942 SkDebugf("Unsupported path fill type\n");
reed@google.comac10a2d2010-12-22 21:39:39 +0000943 return;
944 }
945 }
946
reed@google.com07f3ee12011-05-16 17:21:57 +0000947 fContext->drawPath(grPaint, *pathPtr, fill);
reed@google.comac10a2d2010-12-22 21:39:39 +0000948}
949
reed@google.comac10a2d2010-12-22 21:39:39 +0000950void SkGpuDevice::drawBitmap(const SkDraw& draw,
951 const SkBitmap& bitmap,
952 const SkIRect* srcRectPtr,
953 const SkMatrix& m,
954 const SkPaint& paint) {
955 CHECK_SHOULD_DRAW(draw);
956
957 SkIRect srcRect;
958 if (NULL == srcRectPtr) {
959 srcRect.set(0, 0, bitmap.width(), bitmap.height());
960 } else {
961 srcRect = *srcRectPtr;
962 }
963
bsalomon@google.com5782d712011-01-21 21:03:59 +0000964 GrPaint grPaint;
Scroggod757df22011-05-16 13:11:16 +0000965 if (!this->skPaint2GrPaintNoShader(paint, true, &grPaint, false)) {
bsalomon@google.com5782d712011-01-21 21:03:59 +0000966 return;
967 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000968 GrSamplerState* sampler = grPaint.getTextureSampler(kBitmapTextureIdx);
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000969 if (paint.isFilterBitmap()) {
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000970 sampler->setFilter(GrSamplerState::kBilinear_Filter);
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000971 } else {
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000972 sampler->setFilter(GrSamplerState::kNearest_Filter);
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000973 }
bsalomon@google.com5782d712011-01-21 21:03:59 +0000974
bsalomon@google.com91958362011-06-13 17:58:13 +0000975 const int maxTextureSize = fContext->getMaxTextureSize();
976 if (bitmap.getTexture() || (bitmap.width() <= maxTextureSize &&
977 bitmap.height() <= maxTextureSize)) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000978 // take the fast case
bsalomon@google.com5782d712011-01-21 21:03:59 +0000979 this->internalDrawBitmap(draw, bitmap, srcRect, m, &grPaint);
reed@google.comac10a2d2010-12-22 21:39:39 +0000980 return;
981 }
982
983 // undo the translate done by SkCanvas
984 int DX = SkMax32(0, srcRect.fLeft);
985 int DY = SkMax32(0, srcRect.fTop);
986 // compute clip bounds in local coordinates
987 SkIRect clipRect;
988 {
989 SkRect r;
990 r.set(draw.fClip->getBounds());
991 SkMatrix matrix, inverse;
992 matrix.setConcat(*draw.fMatrix, m);
993 if (!matrix.invert(&inverse)) {
994 return;
995 }
996 inverse.mapRect(&r);
997 r.roundOut(&clipRect);
998 // apply the canvas' translate to our local clip
999 clipRect.offset(DX, DY);
1000 }
1001
bsalomon@google.com91958362011-06-13 17:58:13 +00001002 int nx = bitmap.width() / maxTextureSize;
1003 int ny = bitmap.height() / maxTextureSize;
reed@google.comac10a2d2010-12-22 21:39:39 +00001004 for (int x = 0; x <= nx; x++) {
1005 for (int y = 0; y <= ny; y++) {
1006 SkIRect tileR;
bsalomon@google.com91958362011-06-13 17:58:13 +00001007 tileR.set(x * maxTextureSize, y * maxTextureSize,
1008 (x + 1) * maxTextureSize, (y + 1) * maxTextureSize);
reed@google.comac10a2d2010-12-22 21:39:39 +00001009 if (!SkIRect::Intersects(tileR, clipRect)) {
1010 continue;
1011 }
1012
1013 SkIRect srcR = tileR;
1014 if (!srcR.intersect(srcRect)) {
1015 continue;
1016 }
1017
1018 SkBitmap tmpB;
1019 if (bitmap.extractSubset(&tmpB, tileR)) {
1020 // now offset it to make it "local" to our tmp bitmap
1021 srcR.offset(-tileR.fLeft, -tileR.fTop);
1022
1023 SkMatrix tmpM(m);
1024 {
1025 int dx = tileR.fLeft - DX + SkMax32(0, srcR.fLeft);
1026 int dy = tileR.fTop - DY + SkMax32(0, srcR.fTop);
1027 tmpM.preTranslate(SkIntToScalar(dx), SkIntToScalar(dy));
1028 }
bsalomon@google.com5782d712011-01-21 21:03:59 +00001029 this->internalDrawBitmap(draw, tmpB, srcR, tmpM, &grPaint);
reed@google.comac10a2d2010-12-22 21:39:39 +00001030 }
1031 }
1032 }
1033}
1034
1035/*
1036 * This is called by drawBitmap(), which has to handle images that may be too
1037 * large to be represented by a single texture.
1038 *
bsalomon@google.com5782d712011-01-21 21:03:59 +00001039 * internalDrawBitmap assumes that the specified bitmap will fit in a texture
1040 * and that non-texture portion of the GrPaint has already been setup.
reed@google.comac10a2d2010-12-22 21:39:39 +00001041 */
1042void SkGpuDevice::internalDrawBitmap(const SkDraw& draw,
1043 const SkBitmap& bitmap,
1044 const SkIRect& srcRect,
1045 const SkMatrix& m,
bsalomon@google.com5782d712011-01-21 21:03:59 +00001046 GrPaint* grPaint) {
bsalomon@google.com91958362011-06-13 17:58:13 +00001047 SkASSERT(bitmap.width() <= fContext->getMaxTextureSize() &&
1048 bitmap.height() <= fContext->getMaxTextureSize());
reed@google.comac10a2d2010-12-22 21:39:39 +00001049
1050 SkAutoLockPixels alp(bitmap);
1051 if (!bitmap.getTexture() && !bitmap.readyToDraw()) {
1052 return;
1053 }
1054
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001055 GrSamplerState* sampler = grPaint->getTextureSampler(kBitmapTextureIdx);
1056
1057 sampler->setWrapX(GrSamplerState::kClamp_WrapMode);
1058 sampler->setWrapY(GrSamplerState::kClamp_WrapMode);
1059 sampler->setSampleMode(GrSamplerState::kNormal_SampleMode);
1060 sampler->setMatrix(GrMatrix::I());
reed@google.comac10a2d2010-12-22 21:39:39 +00001061
1062 GrTexture* texture;
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001063 SkAutoCachedTexture act(this, bitmap, *sampler, &texture);
reed@google.comac10a2d2010-12-22 21:39:39 +00001064 if (NULL == texture) {
1065 return;
1066 }
1067
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001068 grPaint->setTexture(kShaderTextureIdx, texture);
reed@google.com46799cd2011-02-22 20:56:26 +00001069
reed@google.com20efde72011-05-09 17:00:02 +00001070 GrRect dstRect = SkRect::MakeWH(GrIntToScalar(srcRect.width()),
1071 GrIntToScalar(srcRect.height()));
bsalomon@google.comc6cf7232011-02-17 16:43:10 +00001072 GrRect paintRect;
junov@google.com6acc9b32011-05-16 18:32:07 +00001073 paintRect.setLTRB(GrFixedToScalar((srcRect.fLeft << 16) / bitmap.width()),
1074 GrFixedToScalar((srcRect.fTop << 16) / bitmap.height()),
1075 GrFixedToScalar((srcRect.fRight << 16) / bitmap.width()),
bsalomon@google.comc6cf7232011-02-17 16:43:10 +00001076 GrFixedToScalar((srcRect.fBottom << 16) / bitmap.height()));
reed@google.comac10a2d2010-12-22 21:39:39 +00001077
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001078 if (GrSamplerState::kNearest_Filter != sampler->getFilter() &&
junov@google.com6acc9b32011-05-16 18:32:07 +00001079 (srcRect.width() < bitmap.width() ||
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001080 srcRect.height() < bitmap.height())) {
junov@google.com6acc9b32011-05-16 18:32:07 +00001081 // If drawing a subrect of the bitmap and filtering is enabled,
1082 // use a constrained texture domain to avoid color bleeding
1083 GrScalar left, top, right, bottom;
1084 if (srcRect.width() > 1) {
1085 GrScalar border = GR_ScalarHalf / bitmap.width();
1086 left = paintRect.left() + border;
1087 right = paintRect.right() - border;
1088 } else {
1089 left = right = GrScalarHalf(paintRect.left() + paintRect.right());
1090 }
1091 if (srcRect.height() > 1) {
1092 GrScalar border = GR_ScalarHalf / bitmap.height();
1093 top = paintRect.top() + border;
1094 bottom = paintRect.bottom() - border;
1095 } else {
1096 top = bottom = GrScalarHalf(paintRect.top() + paintRect.bottom());
1097 }
1098 GrRect textureDomain;
1099 textureDomain.setLTRB(left, top, right, bottom);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001100 sampler->setTextureDomain(textureDomain);
junov@google.com6acc9b32011-05-16 18:32:07 +00001101 }
1102
bsalomon@google.comcc4dac32011-05-10 13:52:42 +00001103 fContext->drawRectToRect(*grPaint, dstRect, paintRect, &m);
reed@google.comac10a2d2010-12-22 21:39:39 +00001104}
1105
1106void SkGpuDevice::drawSprite(const SkDraw& draw, const SkBitmap& bitmap,
1107 int left, int top, const SkPaint& paint) {
1108 CHECK_SHOULD_DRAW(draw);
1109
1110 SkAutoLockPixels alp(bitmap);
1111 if (!bitmap.getTexture() && !bitmap.readyToDraw()) {
1112 return;
1113 }
1114
bsalomon@google.com5782d712011-01-21 21:03:59 +00001115 GrPaint grPaint;
Scroggod757df22011-05-16 13:11:16 +00001116 if(!this->skPaint2GrPaintNoShader(paint, true, &grPaint, false)) {
bsalomon@google.com5782d712011-01-21 21:03:59 +00001117 return;
1118 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001119
bsalomon@google.com5782d712011-01-21 21:03:59 +00001120 GrAutoMatrix avm(fContext, GrMatrix::I());
1121
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001122 GrSamplerState* sampler = grPaint.getTextureSampler(kBitmapTextureIdx);
bsalomon@google.com5782d712011-01-21 21:03:59 +00001123
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001124 GrTexture* texture;
1125 sampler->setClampNoFilter();
1126 SkAutoCachedTexture act(this, bitmap, *sampler, &texture);
1127
1128 grPaint.setTexture(kBitmapTextureIdx, texture);
bsalomon@google.com5782d712011-01-21 21:03:59 +00001129
bsalomon@google.com5782d712011-01-21 21:03:59 +00001130 fContext->drawRectToRect(grPaint,
reed@google.com20efde72011-05-09 17:00:02 +00001131 GrRect::MakeXYWH(GrIntToScalar(left),
1132 GrIntToScalar(top),
1133 GrIntToScalar(bitmap.width()),
1134 GrIntToScalar(bitmap.height())),
1135 GrRect::MakeWH(GR_Scalar1, GR_Scalar1));
reed@google.comac10a2d2010-12-22 21:39:39 +00001136}
1137
1138void SkGpuDevice::drawDevice(const SkDraw& draw, SkDevice* dev,
1139 int x, int y, const SkPaint& paint) {
1140 CHECK_SHOULD_DRAW(draw);
1141
bsalomon@google.com5782d712011-01-21 21:03:59 +00001142 GrPaint grPaint;
bsalomon@google.comc6cf7232011-02-17 16:43:10 +00001143 if (!((SkGpuDevice*)dev)->bindDeviceAsTexture(&grPaint) ||
Scroggod757df22011-05-16 13:11:16 +00001144 !this->skPaint2GrPaintNoShader(paint, true, &grPaint, false)) {
bsalomon@google.com5782d712011-01-21 21:03:59 +00001145 return;
reed@google.comac10a2d2010-12-22 21:39:39 +00001146 }
bsalomon@google.com5782d712011-01-21 21:03:59 +00001147
bsalomon@google.comb5b31682011-06-16 18:05:35 +00001148 GrTexture* devTex = grPaint.getTexture(0);
1149 SkASSERT(NULL != devTex);
bsalomon@google.com5782d712011-01-21 21:03:59 +00001150
1151 const SkBitmap& bm = dev->accessBitmap(false);
1152 int w = bm.width();
1153 int h = bm.height();
1154
1155 GrAutoMatrix avm(fContext, GrMatrix::I());
1156
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001157 grPaint.getTextureSampler(kBitmapTextureIdx)->setClampNoFilter();
bsalomon@google.com5782d712011-01-21 21:03:59 +00001158
bsalomon@google.comb5b31682011-06-16 18:05:35 +00001159 GrRect dstRect = GrRect::MakeXYWH(GrIntToScalar(x),
1160 GrIntToScalar(y),
1161 GrIntToScalar(w),
1162 GrIntToScalar(h));
1163 // The device being drawn may not fill up its texture (saveLayer uses
1164 // the approximate ).
1165 GrRect srcRect = GrRect::MakeWH(GR_Scalar1 * w / devTex->width(),
1166 GR_Scalar1 * h / devTex->height());
1167
1168 fContext->drawRectToRect(grPaint, dstRect, srcRect);
reed@google.comac10a2d2010-12-22 21:39:39 +00001169}
1170
1171///////////////////////////////////////////////////////////////////////////////
1172
1173// must be in SkCanvas::VertexMode order
bsalomon@google.comffca4002011-02-22 20:34:01 +00001174static const GrPrimitiveType gVertexMode2PrimitiveType[] = {
1175 kTriangles_PrimitiveType,
1176 kTriangleStrip_PrimitiveType,
1177 kTriangleFan_PrimitiveType,
reed@google.comac10a2d2010-12-22 21:39:39 +00001178};
1179
1180void SkGpuDevice::drawVertices(const SkDraw& draw, SkCanvas::VertexMode vmode,
1181 int vertexCount, const SkPoint vertices[],
1182 const SkPoint texs[], const SkColor colors[],
1183 SkXfermode* xmode,
1184 const uint16_t indices[], int indexCount,
1185 const SkPaint& paint) {
1186 CHECK_SHOULD_DRAW(draw);
1187
bsalomon@google.com5782d712011-01-21 21:03:59 +00001188 GrPaint grPaint;
1189 SkAutoCachedTexture act;
1190 // we ignore the shader if texs is null.
1191 if (NULL == texs) {
Scroggod757df22011-05-16 13:11:16 +00001192 if (!this->skPaint2GrPaintNoShader(paint,
1193 false,
1194 &grPaint,
1195 NULL == colors)) {
reed@google.comac10a2d2010-12-22 21:39:39 +00001196 return;
1197 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001198 } else {
reed@google.com1a2e8d22011-01-21 22:08:29 +00001199 if (!this->skPaint2GrPaintShader(paint, &act,
1200 *draw.fMatrix,
Scroggod757df22011-05-16 13:11:16 +00001201 &grPaint,
1202 NULL == colors)) {
bsalomon@google.com5782d712011-01-21 21:03:59 +00001203 return;
1204 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001205 }
bsalomon@google.com5782d712011-01-21 21:03:59 +00001206
1207 if (NULL != xmode && NULL != texs && NULL != colors) {
1208 SkXfermode::Mode mode;
1209 if (!SkXfermode::IsMode(xmode, &mode) ||
1210 SkXfermode::kMultiply_Mode != mode) {
1211 SkDebugf("Unsupported vertex-color/texture xfer mode.\n");
1212#if 0
1213 return
1214#endif
1215 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001216 }
bsalomon@google.com5782d712011-01-21 21:03:59 +00001217
1218#if SK_SCALAR_IS_GR_SCALAR
1219 // even if GrColor and SkColor byte offsets match we need
1220 // to perform pre-multiply.
1221 if (NULL == colors) {
1222 fContext->drawVertices(grPaint,
1223 gVertexMode2PrimitiveType[vmode],
1224 vertexCount,
1225 (GrPoint*) vertices,
1226 (GrPoint*) texs,
1227 NULL,
1228 indices,
1229 indexCount);
1230 } else
1231#endif
1232 {
1233 SkTexCoordSource texSrc(texs);
1234 SkColorSource colSrc(colors);
1235 SkIndexSource idxSrc(indices, indexCount);
1236
1237 fContext->drawCustomVertices(grPaint,
1238 gVertexMode2PrimitiveType[vmode],
1239 SkPositionSource(vertices, vertexCount),
1240 (NULL == texs) ? NULL : &texSrc,
1241 (NULL == colors) ? NULL : &colSrc,
1242 (NULL == indices) ? NULL : &idxSrc);
reed@google.comac10a2d2010-12-22 21:39:39 +00001243 }
1244}
1245
1246///////////////////////////////////////////////////////////////////////////////
1247
1248static void GlyphCacheAuxProc(void* data) {
1249 delete (GrFontScaler*)data;
1250}
1251
1252static GrFontScaler* get_gr_font_scaler(SkGlyphCache* cache) {
1253 void* auxData;
1254 GrFontScaler* scaler = NULL;
1255 if (cache->getAuxProcData(GlyphCacheAuxProc, &auxData)) {
1256 scaler = (GrFontScaler*)auxData;
1257 }
1258 if (NULL == scaler) {
1259 scaler = new SkGrFontScaler(cache);
1260 cache->setAuxProc(GlyphCacheAuxProc, scaler);
1261 }
1262 return scaler;
1263}
1264
1265static void SkGPU_Draw1Glyph(const SkDraw1Glyph& state,
1266 SkFixed fx, SkFixed fy,
1267 const SkGlyph& glyph) {
1268 SkASSERT(glyph.fWidth > 0 && glyph.fHeight > 0);
1269
1270 GrSkDrawProcs* procs = (GrSkDrawProcs*)state.fDraw->fProcs;
1271
1272 if (NULL == procs->fFontScaler) {
1273 procs->fFontScaler = get_gr_font_scaler(state.fCache);
1274 }
reed@google.com39ce0ac2011-04-08 15:42:19 +00001275
1276 /*
reed@google.com3b139f52011-06-07 17:56:25 +00001277 * What should we do with fy? (assuming horizontal/latin text)
reed@google.com39ce0ac2011-04-08 15:42:19 +00001278 *
reed@google.com3b139f52011-06-07 17:56:25 +00001279 * The raster code calls SkFixedFloorToFixed on it, as it does with fx.
1280 * It calls that rather than round, because our caller has already added
1281 * SK_FixedHalf, so that calling floor gives us the rounded integer.
1282 *
1283 * Test code between raster and gpu (they should draw the same)
1284 *
1285 * canvas->drawText("Hamburgefons", 12, 0, 16.5f, paint);
1286 *
1287 * Perhaps we should only perform this integralization if there is no
1288 * fExtMatrix...
reed@google.com39ce0ac2011-04-08 15:42:19 +00001289 */
reed@google.com3b139f52011-06-07 17:56:25 +00001290 fy = SkFixedFloorToFixed(fy);
1291
reed@google.comac10a2d2010-12-22 21:39:39 +00001292 procs->fTextContext->drawPackedGlyph(GrGlyph::Pack(glyph.getGlyphID(), fx, 0),
reed@google.com3b139f52011-06-07 17:56:25 +00001293 SkFixedFloorToFixed(fx), fy,
reed@google.comac10a2d2010-12-22 21:39:39 +00001294 procs->fFontScaler);
1295}
1296
bsalomon@google.com5782d712011-01-21 21:03:59 +00001297SkDrawProcs* SkGpuDevice::initDrawForText(GrTextContext* context) {
reed@google.comac10a2d2010-12-22 21:39:39 +00001298
1299 // deferred allocation
1300 if (NULL == fDrawProcs) {
1301 fDrawProcs = new GrSkDrawProcs;
1302 fDrawProcs->fD1GProc = SkGPU_Draw1Glyph;
1303 fDrawProcs->fContext = fContext;
1304 }
1305
1306 // init our (and GL's) state
1307 fDrawProcs->fTextContext = context;
1308 fDrawProcs->fFontScaler = NULL;
1309 return fDrawProcs;
1310}
1311
1312void SkGpuDevice::drawText(const SkDraw& draw, const void* text,
1313 size_t byteLength, SkScalar x, SkScalar y,
1314 const SkPaint& paint) {
1315 CHECK_SHOULD_DRAW(draw);
1316
1317 if (draw.fMatrix->getType() & SkMatrix::kPerspective_Mask) {
1318 // this guy will just call our drawPath()
1319 draw.drawText((const char*)text, byteLength, x, y, paint);
1320 } else {
reed@google.comac10a2d2010-12-22 21:39:39 +00001321 SkDraw myDraw(draw);
bsalomon@google.com5782d712011-01-21 21:03:59 +00001322
1323 GrPaint grPaint;
1324 SkAutoCachedTexture act;
1325
Scroggod757df22011-05-16 13:11:16 +00001326 if (!this->skPaint2GrPaintShader(paint,
1327 &act,
1328 *draw.fMatrix,
1329 &grPaint,
1330 true)) {
bsalomon@google.com5782d712011-01-21 21:03:59 +00001331 return;
1332 }
bsalomon@google.comcc4dac32011-05-10 13:52:42 +00001333 GrTextContext context(fContext, grPaint, draw.fExtMatrix);
bsalomon@google.com5782d712011-01-21 21:03:59 +00001334 myDraw.fProcs = this->initDrawForText(&context);
reed@google.comac10a2d2010-12-22 21:39:39 +00001335 this->INHERITED::drawText(myDraw, text, byteLength, x, y, paint);
1336 }
1337}
1338
1339void SkGpuDevice::drawPosText(const SkDraw& draw, const void* text,
1340 size_t byteLength, const SkScalar pos[],
1341 SkScalar constY, int scalarsPerPos,
1342 const SkPaint& paint) {
1343 CHECK_SHOULD_DRAW(draw);
1344
1345 if (draw.fMatrix->getType() & SkMatrix::kPerspective_Mask) {
1346 // this guy will just call our drawPath()
1347 draw.drawPosText((const char*)text, byteLength, pos, constY,
1348 scalarsPerPos, paint);
1349 } else {
reed@google.comac10a2d2010-12-22 21:39:39 +00001350 SkDraw myDraw(draw);
bsalomon@google.com5782d712011-01-21 21:03:59 +00001351
1352 GrPaint grPaint;
1353 SkAutoCachedTexture act;
Scroggod757df22011-05-16 13:11:16 +00001354 if (!this->skPaint2GrPaintShader(paint,
1355 &act,
1356 *draw.fMatrix,
1357 &grPaint,
1358 true)) {
bsalomon@google.com5782d712011-01-21 21:03:59 +00001359 return;
1360 }
1361
bsalomon@google.comcc4dac32011-05-10 13:52:42 +00001362 GrTextContext context(fContext, grPaint, draw.fExtMatrix);
bsalomon@google.com5782d712011-01-21 21:03:59 +00001363 myDraw.fProcs = this->initDrawForText(&context);
reed@google.comac10a2d2010-12-22 21:39:39 +00001364 this->INHERITED::drawPosText(myDraw, text, byteLength, pos, constY,
1365 scalarsPerPos, paint);
1366 }
1367}
1368
1369void SkGpuDevice::drawTextOnPath(const SkDraw& draw, const void* text,
1370 size_t len, const SkPath& path,
1371 const SkMatrix* m, const SkPaint& paint) {
1372 CHECK_SHOULD_DRAW(draw);
1373
1374 SkASSERT(draw.fDevice == this);
1375 draw.drawTextOnPath((const char*)text, len, path, m, paint);
1376}
1377
1378///////////////////////////////////////////////////////////////////////////////
1379
reed@google.comf67e4cf2011-03-15 20:56:58 +00001380bool SkGpuDevice::filterTextFlags(const SkPaint& paint, TextFlags* flags) {
1381 if (!paint.isLCDRenderText()) {
1382 // we're cool with the paint as is
1383 return false;
1384 }
1385
1386 if (paint.getShader() ||
1387 paint.getXfermode() || // unless its srcover
1388 paint.getMaskFilter() ||
1389 paint.getRasterizer() ||
1390 paint.getColorFilter() ||
1391 paint.getPathEffect() ||
1392 paint.isFakeBoldText() ||
1393 paint.getStyle() != SkPaint::kFill_Style) {
1394 // turn off lcd
1395 flags->fFlags = paint.getFlags() & ~SkPaint::kLCDRenderText_Flag;
1396 flags->fHinting = paint.getHinting();
1397 return true;
1398 }
1399 // we're cool with the paint as is
1400 return false;
1401}
1402
1403///////////////////////////////////////////////////////////////////////////////
1404
reed@google.comac10a2d2010-12-22 21:39:39 +00001405SkGpuDevice::TexCache* SkGpuDevice::lockCachedTexture(const SkBitmap& bitmap,
bsalomon@google.comfea37b52011-04-25 15:51:06 +00001406 const GrSamplerState& sampler,
1407 GrTexture** texture,
bsalomon@google.come97f0852011-06-17 13:10:25 +00001408 TexType type) {
bsalomon@google.comfea37b52011-04-25 15:51:06 +00001409 GrTexture* newTexture = NULL;
1410 GrTextureEntry* entry = NULL;
reed@google.comac10a2d2010-12-22 21:39:39 +00001411 GrContext* ctx = this->context();
bsalomon@google.comfea37b52011-04-25 15:51:06 +00001412
bsalomon@google.come97f0852011-06-17 13:10:25 +00001413 if (kBitmap_TexType != type) {
bsalomon@google.comfea37b52011-04-25 15:51:06 +00001414 const GrTextureDesc desc = {
1415 kRenderTarget_GrTextureFlagBit,
1416 kNone_GrAALevel,
1417 bitmap.width(),
1418 bitmap.height(),
1419 SkGr::Bitmap2PixelConfig(bitmap)
1420 };
bsalomon@google.come97f0852011-06-17 13:10:25 +00001421 if (kSaveLayerDeviceRenderTarget_TexType == type) {
bsalomon@google.comb5b31682011-06-16 18:05:35 +00001422 // we know layers will only be drawn through drawDevice.
1423 // drawDevice has been made to work with content embedded in a
1424 // larger texture so its okay to use the approximate version.
1425 entry = ctx->findApproximateKeylessTexture(desc);
1426 } else {
bsalomon@google.come97f0852011-06-17 13:10:25 +00001427 SkASSERT(kDeviceRenderTarget_TexType == type);
bsalomon@google.comb5b31682011-06-16 18:05:35 +00001428 entry = ctx->lockKeylessTexture(desc);
1429 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001430 } else {
bsalomon@google.comfea37b52011-04-25 15:51:06 +00001431 uint32_t p0, p1;
reed@google.comac10a2d2010-12-22 21:39:39 +00001432 p0 = bitmap.getGenerationID();
1433 p1 = bitmap.pixelRefOffset();
reed@google.comac10a2d2010-12-22 21:39:39 +00001434
bsalomon@google.comfea37b52011-04-25 15:51:06 +00001435 GrTextureKey key(p0, p1, bitmap.width(), bitmap.height());
1436 entry = ctx->findAndLockTexture(&key, sampler);
reed@google.comac10a2d2010-12-22 21:39:39 +00001437
reed@google.comac10a2d2010-12-22 21:39:39 +00001438 if (NULL == entry) {
bsalomon@google.comfea37b52011-04-25 15:51:06 +00001439 entry = sk_gr_create_bitmap_texture(ctx, &key, sampler, bitmap);
1440 if (NULL == entry) {
1441 GrPrintf("---- failed to create texture for cache [%d %d]\n",
1442 bitmap.width(), bitmap.height());
1443 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001444 }
1445 }
1446
1447 if (NULL != entry) {
1448 newTexture = entry->texture();
reed@google.comac10a2d2010-12-22 21:39:39 +00001449 if (texture) {
1450 *texture = newTexture;
1451 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001452 }
1453 return (TexCache*)entry;
1454}
1455
1456void SkGpuDevice::unlockCachedTexture(TexCache* cache) {
1457 this->context()->unlockTexture((GrTextureEntry*)cache);
1458}
1459
bsalomon@google.come97f0852011-06-17 13:10:25 +00001460SkDevice* SkGpuDevice::onCreateCompatibleDevice(SkBitmap::Config config,
1461 int width, int height,
1462 bool isOpaque,
1463 Usage usage) {
1464 return SkNEW_ARGS(SkGpuDevice,(this->context(), config,
1465 width, height, usage));
1466}
1467
1468
reed@google.com7b201d22011-01-11 18:59:23 +00001469///////////////////////////////////////////////////////////////////////////////
1470
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +00001471SkGpuDeviceFactory::SkGpuDeviceFactory(GrContext* context,
bsalomon@google.comea2ee8a2011-04-12 17:58:39 +00001472 GrRenderTarget* rootRenderTarget) {
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +00001473 GrAssert(NULL != context);
1474 GrAssert(NULL != rootRenderTarget);
1475
1476 // check this now rather than passing this value to SkGpuDevice cons.
1477 // we want the rt that is bound *now* in the 3D API, not the one
1478 // at the time of newDevice.
1479 if (SkGpuDevice::Current3DApiRenderTarget() == rootRenderTarget) {
1480 fRootRenderTarget = context->createRenderTargetFrom3DApiState();
1481 } else {
1482 fRootRenderTarget = rootRenderTarget;
1483 rootRenderTarget->ref();
1484 }
bsalomon@google.comea2ee8a2011-04-12 17:58:39 +00001485
1486 fContext = context;
reed@google.com7b201d22011-01-11 18:59:23 +00001487 context->ref();
bsalomon@google.comea2ee8a2011-04-12 17:58:39 +00001488
bsalomon@google.com5877ffd2011-04-11 17:58:48 +00001489 fRootTexture = NULL;
1490}
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +00001491
bsalomon@google.com5877ffd2011-04-11 17:58:48 +00001492SkGpuDeviceFactory::SkGpuDeviceFactory(GrContext* context, GrTexture* rootRenderTargetTexture) {
1493 GrAssert(NULL != context);
1494 GrAssert(NULL != rootRenderTargetTexture);
1495 GrAssert(NULL != rootRenderTargetTexture->asRenderTarget());
1496
1497 fRootTexture = rootRenderTargetTexture;
1498 rootRenderTargetTexture->ref();
1499
1500 fRootRenderTarget = rootRenderTargetTexture->asRenderTarget();
1501 fRootRenderTarget->ref();
1502
bsalomon@google.comea2ee8a2011-04-12 17:58:39 +00001503 fContext = context;
bsalomon@google.com5877ffd2011-04-11 17:58:48 +00001504 context->ref();
reed@google.com7b201d22011-01-11 18:59:23 +00001505}
1506
1507SkGpuDeviceFactory::~SkGpuDeviceFactory() {
1508 fContext->unref();
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +00001509 fRootRenderTarget->unref();
bsalomon@google.com5877ffd2011-04-11 17:58:48 +00001510 GrSafeUnref(fRootTexture);
reed@google.com7b201d22011-01-11 18:59:23 +00001511}
1512
1513SkDevice* SkGpuDeviceFactory::newDevice(SkCanvas*, SkBitmap::Config config,
1514 int width, int height,
1515 bool isOpaque, bool isLayer) {
reed@google.comaf951c92011-06-16 19:10:39 +00001516 if (isLayer) {
1517 return SkNEW_ARGS(SkGpuDevice, (fContext, config, width, height));
1518 } else {
1519 return SkNEW_ARGS(SkGpuDevice, (fContext, fRootRenderTarget));
1520 }
reed@google.com7b201d22011-01-11 18:59:23 +00001521}
bsalomon@google.come97f0852011-06-17 13:10:25 +00001522