blob: d6ee03d9c6900c13221de4e67380f5a7902c0232 [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) {
reed@google.com2be9e8b2011-07-06 21:18:09 +0000484 SkShader::GradientInfo info;
485 SkColor color;
486
487 info.fColors = &color;
488 info.fColorOffsets = NULL;
489 info.fColorCount = 1;
490 if (SkShader::kColor_GradientType == shader->asAGradient(&info)) {
491 SkPaint copy(skPaint);
492 copy.setShader(NULL);
bsalomon@google.comcd9cfd72011-07-08 16:55:04 +0000493 // modulate the paint alpha by the shader's solid color alpha
494 U8CPU newA = SkMulDiv255Round(SkColorGetA(color), copy.getAlpha());
495 copy.setColor(SkColorSetA(color, newA));
reed@google.com2be9e8b2011-07-06 21:18:09 +0000496 return this->skPaint2GrPaintNoShader(copy,
497 false,
498 grPaint,
499 constantColor);
500 }
bsalomon@google.com5782d712011-01-21 21:03:59 +0000501 return false;
reed@google.comac10a2d2010-12-22 21:39:39 +0000502 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000503 GrSamplerState* sampler = grPaint->getTextureSampler(kShaderTextureIdx);
504 sampler->setSampleMode(sampleMode);
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000505 if (skPaint.isFilterBitmap()) {
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000506 sampler->setFilter(GrSamplerState::kBilinear_Filter);
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000507 } else {
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000508 sampler->setFilter(GrSamplerState::kNearest_Filter);
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000509 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000510 sampler->setWrapX(sk_tile_mode_to_grwrap(tileModes[0]));
511 sampler->setWrapY(sk_tile_mode_to_grwrap(tileModes[1]));
reed@google.comac10a2d2010-12-22 21:39:39 +0000512 if (GrSamplerState::kRadial2_SampleMode == sampleMode) {
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000513 sampler->setRadial2Params(twoPointParams[0],
514 twoPointParams[1],
515 twoPointParams[2] < 0);
reed@google.comac10a2d2010-12-22 21:39:39 +0000516 }
517
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000518 GrTexture* texture = act->set(this, bitmap, *sampler);
reed@google.comac10a2d2010-12-22 21:39:39 +0000519 if (NULL == texture) {
bsalomon@google.com5782d712011-01-21 21:03:59 +0000520 SkDebugf("Couldn't convert bitmap to texture.\n");
521 return false;
reed@google.comac10a2d2010-12-22 21:39:39 +0000522 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000523 grPaint->setTexture(kShaderTextureIdx, texture);
reed@google.comac10a2d2010-12-22 21:39:39 +0000524
525 // since our texture coords will be in local space, we wack the texture
526 // matrix to map them back into 0...1 before we load it
527 SkMatrix localM;
528 if (shader->getLocalMatrix(&localM)) {
529 SkMatrix inverse;
530 if (localM.invert(&inverse)) {
531 matrix.preConcat(inverse);
532 }
533 }
534 if (SkShader::kDefault_BitmapType == bmptype) {
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000535 GrScalar sx = GrFixedToScalar(GR_Fixed1 / bitmap.width());
536 GrScalar sy = GrFixedToScalar(GR_Fixed1 / bitmap.height());
reed@google.comac10a2d2010-12-22 21:39:39 +0000537 matrix.postScale(sx, sy);
reed@google.comac10a2d2010-12-22 21:39:39 +0000538 } else if (SkShader::kRadial_BitmapType == bmptype) {
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000539 GrScalar s = GrFixedToScalar(GR_Fixed1 / bitmap.width());
reed@google.comac10a2d2010-12-22 21:39:39 +0000540 matrix.postScale(s, s);
541 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000542 sampler->setMatrix(matrix);
bsalomon@google.com5782d712011-01-21 21:03:59 +0000543
544 return true;
reed@google.comac10a2d2010-12-22 21:39:39 +0000545}
546
547///////////////////////////////////////////////////////////////////////////////
bsalomon@google.com5782d712011-01-21 21:03:59 +0000548
549class SkPositionSource {
550public:
551 SkPositionSource(const SkPoint* points, int count)
552 : fPoints(points), fCount(count) {}
553
554 int count() const { return fCount; }
555
556 void writeValue(int i, GrPoint* dstPosition) const {
557 SkASSERT(i < fCount);
558 dstPosition->fX = SkScalarToGrScalar(fPoints[i].fX);
559 dstPosition->fY = SkScalarToGrScalar(fPoints[i].fY);
560 }
561private:
bsalomon@google.com5782d712011-01-21 21:03:59 +0000562 const SkPoint* fPoints;
bsalomon@google.com19628322011-02-03 21:30:17 +0000563 int fCount;
bsalomon@google.com5782d712011-01-21 21:03:59 +0000564};
565
566class SkTexCoordSource {
567public:
568 SkTexCoordSource(const SkPoint* coords)
569 : fCoords(coords) {}
570
571 void writeValue(int i, GrPoint* dstCoord) const {
572 dstCoord->fX = SkScalarToGrScalar(fCoords[i].fX);
573 dstCoord->fY = SkScalarToGrScalar(fCoords[i].fY);
574 }
575private:
576 const SkPoint* fCoords;
577};
578
579class SkColorSource {
580public:
581 SkColorSource(const SkColor* colors) : fColors(colors) {}
582
583 void writeValue(int i, GrColor* dstColor) const {
584 *dstColor = SkGr::SkColor2GrColor(fColors[i]);
585 }
586private:
587 const SkColor* fColors;
588};
589
590class SkIndexSource {
591public:
592 SkIndexSource(const uint16_t* indices, int count)
593 : fIndices(indices), fCount(count) {
594 }
595
596 int count() const { return fCount; }
597
598 void writeValue(int i, uint16_t* dstIndex) const {
599 *dstIndex = fIndices[i];
600 }
601
602private:
bsalomon@google.com5782d712011-01-21 21:03:59 +0000603 const uint16_t* fIndices;
bsalomon@google.com19628322011-02-03 21:30:17 +0000604 int fCount;
bsalomon@google.com5782d712011-01-21 21:03:59 +0000605};
606
607///////////////////////////////////////////////////////////////////////////////
608
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000609#if 0 // not currently being used so don't compile,
610
bsalomon@google.com5782d712011-01-21 21:03:59 +0000611// can be used for positions or texture coordinates
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000612
bsalomon@google.com5782d712011-01-21 21:03:59 +0000613class SkRectFanSource {
614public:
615 SkRectFanSource(const SkRect& rect) : fRect(rect) {}
616
617 int count() const { return 4; }
618
619 void writeValue(int i, GrPoint* dstPoint) const {
620 SkASSERT(i < 4);
621 dstPoint->fX = SkScalarToGrScalar((i % 3) ? fRect.fRight :
622 fRect.fLeft);
623 dstPoint->fY = SkScalarToGrScalar((i < 2) ? fRect.fTop :
624 fRect.fBottom);
625 }
626private:
627 const SkRect& fRect;
628};
629
630class SkIRectFanSource {
631public:
632 SkIRectFanSource(const SkIRect& rect) : fRect(rect) {}
633
634 int count() const { return 4; }
635
636 void writeValue(int i, GrPoint* dstPoint) const {
637 SkASSERT(i < 4);
638 dstPoint->fX = (i % 3) ? GrIntToScalar(fRect.fRight) :
639 GrIntToScalar(fRect.fLeft);
640 dstPoint->fY = (i < 2) ? GrIntToScalar(fRect.fTop) :
641 GrIntToScalar(fRect.fBottom);
642 }
643private:
644 const SkIRect& fRect;
645};
646
647class SkMatRectFanSource {
648public:
649 SkMatRectFanSource(const SkRect& rect, const SkMatrix& matrix)
650 : fRect(rect), fMatrix(matrix) {}
651
652 int count() const { return 4; }
653
654 void writeValue(int i, GrPoint* dstPoint) const {
655 SkASSERT(i < 4);
656
657#if SK_SCALAR_IS_GR_SCALAR
658 fMatrix.mapXY((i % 3) ? fRect.fRight : fRect.fLeft,
659 (i < 2) ? fRect.fTop : fRect.fBottom,
660 (SkPoint*)dstPoint);
661#else
662 SkPoint dst;
663 fMatrix.mapXY((i % 3) ? fRect.fRight : fRect.fLeft,
664 (i < 2) ? fRect.fTop : fRect.fBottom,
665 &dst);
666 dstPoint->fX = SkScalarToGrScalar(dst.fX);
667 dstPoint->fY = SkScalarToGrScalar(dst.fY);
668#endif
669 }
670private:
671 const SkRect& fRect;
672 const SkMatrix& fMatrix;
673};
674
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000675#endif
676
reed@google.comac10a2d2010-12-22 21:39:39 +0000677///////////////////////////////////////////////////////////////////////////////
678
bsalomon@google.com398109c2011-04-14 18:40:27 +0000679void SkGpuDevice::clear(SkColor color) {
bsalomon@google.com31a58402011-04-27 21:00:02 +0000680 fContext->clear(NULL, color);
bsalomon@google.com398109c2011-04-14 18:40:27 +0000681}
682
reed@google.comac10a2d2010-12-22 21:39:39 +0000683void SkGpuDevice::drawPaint(const SkDraw& draw, const SkPaint& paint) {
684 CHECK_SHOULD_DRAW(draw);
685
bsalomon@google.com5782d712011-01-21 21:03:59 +0000686 GrPaint grPaint;
687 SkAutoCachedTexture act;
Scroggod757df22011-05-16 13:11:16 +0000688 if (!this->skPaint2GrPaintShader(paint,
689 &act,
690 *draw.fMatrix,
691 &grPaint,
692 true)) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000693 return;
694 }
bsalomon@google.com5782d712011-01-21 21:03:59 +0000695
696 fContext->drawPaint(grPaint);
reed@google.comac10a2d2010-12-22 21:39:39 +0000697}
698
699// must be in SkCanvas::PointMode order
bsalomon@google.comffca4002011-02-22 20:34:01 +0000700static const GrPrimitiveType gPointMode2PrimtiveType[] = {
701 kPoints_PrimitiveType,
702 kLines_PrimitiveType,
703 kLineStrip_PrimitiveType
reed@google.comac10a2d2010-12-22 21:39:39 +0000704};
705
706void SkGpuDevice::drawPoints(const SkDraw& draw, SkCanvas::PointMode mode,
bsalomon@google.com5782d712011-01-21 21:03:59 +0000707 size_t count, const SkPoint pts[], const SkPaint& paint) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000708 CHECK_SHOULD_DRAW(draw);
709
710 SkScalar width = paint.getStrokeWidth();
711 if (width < 0) {
712 return;
713 }
714
715 // we only handle hairlines here, else we let the SkDraw call our drawPath()
716 if (width > 0) {
717 draw.drawPoints(mode, count, pts, paint, true);
718 return;
719 }
720
bsalomon@google.com5782d712011-01-21 21:03:59 +0000721 GrPaint grPaint;
722 SkAutoCachedTexture act;
Scroggod757df22011-05-16 13:11:16 +0000723 if (!this->skPaint2GrPaintShader(paint,
724 &act,
725 *draw.fMatrix,
726 &grPaint,
727 true)) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000728 return;
729 }
730
reed@google.comac10a2d2010-12-22 21:39:39 +0000731#if SK_SCALAR_IS_GR_SCALAR
bsalomon@google.com5782d712011-01-21 21:03:59 +0000732 fContext->drawVertices(grPaint,
733 gPointMode2PrimtiveType[mode],
734 count,
735 (GrPoint*)pts,
736 NULL,
737 NULL,
738 NULL,
739 0);
reed@google.comac10a2d2010-12-22 21:39:39 +0000740#else
bsalomon@google.com5782d712011-01-21 21:03:59 +0000741 fContext->drawCustomVertices(grPaint,
742 gPointMode2PrimtiveType[mode],
743 SkPositionSource(pts, count));
reed@google.comac10a2d2010-12-22 21:39:39 +0000744#endif
reed@google.comac10a2d2010-12-22 21:39:39 +0000745}
746
reed@google.comc9aa5872011-04-05 21:05:37 +0000747///////////////////////////////////////////////////////////////////////////////
748
reed@google.comac10a2d2010-12-22 21:39:39 +0000749void SkGpuDevice::drawRect(const SkDraw& draw, const SkRect& rect,
750 const SkPaint& paint) {
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000751 CHECK_SHOULD_DRAW(draw);
752
753 bool doStroke = paint.getStyle() == SkPaint::kStroke_Style;
754 SkScalar width = paint.getStrokeWidth();
755
756 /*
757 We have special code for hairline strokes, miter-strokes, and fills.
758 Anything else we just call our path code.
759 */
760 bool usePath = doStroke && width > 0 &&
761 paint.getStrokeJoin() != SkPaint::kMiter_Join;
762 // another reason we might need to call drawPath...
763 if (paint.getMaskFilter()) {
764 usePath = true;
765 }
reed@google.com67db6642011-05-26 11:46:35 +0000766 // until we aa rotated rects...
767 if (!usePath && paint.isAntiAlias() && !draw.fMatrix->rectStaysRect()) {
768 usePath = true;
769 }
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000770
771 if (usePath) {
772 SkPath path;
773 path.addRect(rect);
774 this->drawPath(draw, path, paint, NULL, true);
775 return;
776 }
777
778 GrPaint grPaint;
779 SkAutoCachedTexture act;
Scroggod757df22011-05-16 13:11:16 +0000780 if (!this->skPaint2GrPaintShader(paint,
781 &act,
782 *draw.fMatrix,
783 &grPaint,
784 true)) {
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000785 return;
786 }
reed@google.com20efde72011-05-09 17:00:02 +0000787 fContext->drawRect(grPaint, rect, doStroke ? width : -1);
reed@google.comac10a2d2010-12-22 21:39:39 +0000788}
789
reed@google.com69302852011-02-16 18:08:07 +0000790#include "SkMaskFilter.h"
791#include "SkBounder.h"
792
reed@google.com69302852011-02-16 18:08:07 +0000793static bool drawWithMaskFilter(GrContext* context, const SkPath& path,
794 SkMaskFilter* filter, const SkMatrix& matrix,
795 const SkRegion& clip, SkBounder* bounder,
796 GrPaint* grp) {
797 SkMask srcM, dstM;
798
799 if (!SkDraw::DrawToMask(path, &clip.getBounds(), filter, &matrix, &srcM,
800 SkMask::kComputeBoundsAndRenderImage_CreateMode)) {
801 return false;
802 }
803
804 SkAutoMaskImage autoSrc(&srcM, false);
805
806 if (!filter->filterMask(&dstM, srcM, matrix, NULL)) {
807 return false;
808 }
809 // this will free-up dstM when we're done (allocated in filterMask())
810 SkAutoMaskImage autoDst(&dstM, false);
811
812 if (clip.quickReject(dstM.fBounds)) {
813 return false;
814 }
815 if (bounder && !bounder->doIRect(dstM.fBounds)) {
816 return false;
817 }
818
819 // we now have a device-aligned 8bit mask in dstM, ready to be drawn using
820 // the current clip (and identity matrix) and grpaint settings
821
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000822 // used to compute inverse view, if necessary
823 GrMatrix ivm = context->getMatrix();
824
reed@google.com0c219b62011-02-16 21:31:18 +0000825 GrAutoMatrix avm(context, GrMatrix::I());
reed@google.com69302852011-02-16 18:08:07 +0000826
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000827 const GrTextureDesc desc = {
828 kNone_GrTextureFlags,
829 kNone_GrAALevel,
reed@google.com69302852011-02-16 18:08:07 +0000830 dstM.fBounds.width(),
831 dstM.fBounds.height(),
bsalomon@google.com669fdc42011-04-05 17:08:27 +0000832 kAlpha_8_GrPixelConfig
reed@google.com69302852011-02-16 18:08:07 +0000833 };
834
835 GrTexture* texture = context->createUncachedTexture(desc, dstM.fImage,
836 dstM.fRowBytes);
837 if (NULL == texture) {
838 return false;
839 }
840
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000841 if (grp->hasTextureOrMask() && ivm.invert(&ivm)) {
842 grp->preConcatActiveSamplerMatrices(ivm);
843 }
844
845 static const int MASK_IDX = GrPaint::kMaxMasks - 1;
846 // we assume the last mask index is available for use
847 GrAssert(NULL == grp->getMask(MASK_IDX));
848 grp->setMask(MASK_IDX, texture);
reed@google.com0c219b62011-02-16 21:31:18 +0000849 texture->unref();
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000850 grp->getMaskSampler(MASK_IDX)->setClampNoFilter();
reed@google.com69302852011-02-16 18:08:07 +0000851
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000852 GrRect d;
853 d.setLTRB(GrIntToScalar(dstM.fBounds.fLeft),
reed@google.com0c219b62011-02-16 21:31:18 +0000854 GrIntToScalar(dstM.fBounds.fTop),
855 GrIntToScalar(dstM.fBounds.fRight),
856 GrIntToScalar(dstM.fBounds.fBottom));
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000857
858 GrMatrix m;
859 m.setTranslate(-dstM.fBounds.fLeft, -dstM.fBounds.fTop);
860 m.postIDiv(dstM.fBounds.width(), dstM.fBounds.height());
861 grp->getMaskSampler(MASK_IDX)->setMatrix(m);
862
863 context->drawRect(*grp, d);
reed@google.com69302852011-02-16 18:08:07 +0000864 return true;
865}
reed@google.com69302852011-02-16 18:08:07 +0000866
reed@google.com0c219b62011-02-16 21:31:18 +0000867void SkGpuDevice::drawPath(const SkDraw& draw, const SkPath& origSrcPath,
reed@google.comac10a2d2010-12-22 21:39:39 +0000868 const SkPaint& paint, const SkMatrix* prePathMatrix,
869 bool pathIsMutable) {
870 CHECK_SHOULD_DRAW(draw);
871
bsalomon@google.com5782d712011-01-21 21:03:59 +0000872 GrPaint grPaint;
873 SkAutoCachedTexture act;
Scroggod757df22011-05-16 13:11:16 +0000874 if (!this->skPaint2GrPaintShader(paint,
875 &act,
876 *draw.fMatrix,
877 &grPaint,
878 true)) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000879 return;
880 }
881
reed@google.com0c219b62011-02-16 21:31:18 +0000882 // BEGIN lift from SkDraw::drawPath()
883
884 SkPath* pathPtr = const_cast<SkPath*>(&origSrcPath);
885 bool doFill = true;
886 SkPath tmpPath;
reed@google.comac10a2d2010-12-22 21:39:39 +0000887
888 if (prePathMatrix) {
reed@google.come3445642011-02-16 23:20:39 +0000889 SkPath* result = pathPtr;
reed@google.com0c219b62011-02-16 21:31:18 +0000890
reed@google.come3445642011-02-16 23:20:39 +0000891 if (!pathIsMutable) {
892 result = &tmpPath;
893 pathIsMutable = true;
reed@google.comac10a2d2010-12-22 21:39:39 +0000894 }
reed@google.come3445642011-02-16 23:20:39 +0000895 // should I push prePathMatrix on our MV stack temporarily, instead
896 // of applying it here? See SkDraw.cpp
897 pathPtr->transform(*prePathMatrix, result);
898 pathPtr = result;
reed@google.comac10a2d2010-12-22 21:39:39 +0000899 }
reed@google.com0c219b62011-02-16 21:31:18 +0000900 // at this point we're done with prePathMatrix
901 SkDEBUGCODE(prePathMatrix = (const SkMatrix*)0x50FF8001;)
reed@google.comac10a2d2010-12-22 21:39:39 +0000902
bsalomon@google.com04de7822011-03-25 18:04:43 +0000903 // This "if" is not part of the SkDraw::drawPath() lift.
904 // When we get a 1.0 wide stroke we hairline stroke it instead of creating
905 // a new stroked-path. This is motivated by canvas2D sites that draw
906 // lines as 1.0 wide stroked paths. We can consider doing an alpha-modulated-
907 // hairline for width < 1.0 when AA is enabled.
908 static const int gMatrixMask = ~(SkMatrix::kIdentity_Mask |
909 SkMatrix::kTranslate_Mask);
910 if (!paint.getPathEffect() &&
911 SkPaint::kStroke_Style == paint.getStyle() &&
912 !(draw.fMatrix->getType() & gMatrixMask) &&
913 SK_Scalar1 == paint.getStrokeWidth()) {
914 doFill = false;
915 }
916
917 if (doFill && (paint.getPathEffect() ||
918 paint.getStyle() != SkPaint::kFill_Style)) {
reed@google.com0c219b62011-02-16 21:31:18 +0000919 doFill = paint.getFillPath(*pathPtr, &tmpPath);
920 pathPtr = &tmpPath;
921 }
922
923 // END lift from SkDraw::drawPath()
924
reed@google.com69302852011-02-16 18:08:07 +0000925 if (paint.getMaskFilter()) {
reed@google.com0c219b62011-02-16 21:31:18 +0000926 // avoid possibly allocating a new path in transform if we can
927 SkPath* devPathPtr = pathIsMutable ? pathPtr : &tmpPath;
928
929 // transform the path into device space
reed@google.come3445642011-02-16 23:20:39 +0000930 pathPtr->transform(*draw.fMatrix, devPathPtr);
reed@google.com0c219b62011-02-16 21:31:18 +0000931
932 drawWithMaskFilter(fContext, *devPathPtr, paint.getMaskFilter(),
reed@google.com69302852011-02-16 18:08:07 +0000933 *draw.fMatrix, *draw.fClip, draw.fBounder, &grPaint);
934 return;
935 }
reed@google.com69302852011-02-16 18:08:07 +0000936
bsalomon@google.comffca4002011-02-22 20:34:01 +0000937 GrPathFill fill = kHairLine_PathFill;
reed@google.comac10a2d2010-12-22 21:39:39 +0000938
reed@google.com0c219b62011-02-16 21:31:18 +0000939 if (doFill) {
940 switch (pathPtr->getFillType()) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000941 case SkPath::kWinding_FillType:
bsalomon@google.comffca4002011-02-22 20:34:01 +0000942 fill = kWinding_PathFill;
reed@google.comac10a2d2010-12-22 21:39:39 +0000943 break;
944 case SkPath::kEvenOdd_FillType:
bsalomon@google.comffca4002011-02-22 20:34:01 +0000945 fill = kEvenOdd_PathFill;
reed@google.comac10a2d2010-12-22 21:39:39 +0000946 break;
947 case SkPath::kInverseWinding_FillType:
bsalomon@google.comffca4002011-02-22 20:34:01 +0000948 fill = kInverseWinding_PathFill;
reed@google.comac10a2d2010-12-22 21:39:39 +0000949 break;
950 case SkPath::kInverseEvenOdd_FillType:
bsalomon@google.comffca4002011-02-22 20:34:01 +0000951 fill = kInverseEvenOdd_PathFill;
reed@google.comac10a2d2010-12-22 21:39:39 +0000952 break;
953 default:
bsalomon@google.com5782d712011-01-21 21:03:59 +0000954 SkDebugf("Unsupported path fill type\n");
reed@google.comac10a2d2010-12-22 21:39:39 +0000955 return;
956 }
957 }
958
reed@google.com07f3ee12011-05-16 17:21:57 +0000959 fContext->drawPath(grPaint, *pathPtr, fill);
reed@google.comac10a2d2010-12-22 21:39:39 +0000960}
961
reed@google.comac10a2d2010-12-22 21:39:39 +0000962void SkGpuDevice::drawBitmap(const SkDraw& draw,
963 const SkBitmap& bitmap,
964 const SkIRect* srcRectPtr,
965 const SkMatrix& m,
966 const SkPaint& paint) {
967 CHECK_SHOULD_DRAW(draw);
968
969 SkIRect srcRect;
970 if (NULL == srcRectPtr) {
971 srcRect.set(0, 0, bitmap.width(), bitmap.height());
972 } else {
973 srcRect = *srcRectPtr;
974 }
975
junov@google.comd935cfb2011-06-27 20:48:23 +0000976 if (paint.getMaskFilter()){
epoger@google.com9ef2d832011-07-01 21:12:20 +0000977 SkBitmap tmp; // storage if we need a subset of bitmap
junov@google.comd935cfb2011-06-27 20:48:23 +0000978 const SkBitmap* bitmapPtr = &bitmap;
epoger@google.com9ef2d832011-07-01 21:12:20 +0000979 if (srcRectPtr) {
980 if (!bitmap.extractSubset(&tmp, srcRect)) {
981 return; // extraction failed
982 }
983 bitmapPtr = &tmp;
junov@google.comd935cfb2011-06-27 20:48:23 +0000984 }
985 SkPaint paintWithTexture(paint);
986 paintWithTexture.setShader(SkShader::CreateBitmapShader( *bitmapPtr,
987 SkShader::kClamp_TileMode, SkShader::kClamp_TileMode))->unref();
988 paintWithTexture.getShader()->setLocalMatrix(m);
989
990 SkRect ScalarRect;
epoger@google.com9ef2d832011-07-01 21:12:20 +0000991 ScalarRect.set(srcRect);
junov@google.comd935cfb2011-06-27 20:48:23 +0000992
epoger@google.com9ef2d832011-07-01 21:12:20 +0000993 if (m.rectStaysRect()) {
994 // Preferred drawing method, optimized for rectangles
995 m.mapRect(&ScalarRect);
996 this->drawRect(draw, ScalarRect, paintWithTexture);
997 } else {
998 // Slower drawing method, for warped or rotated rectangles
999 SkPath path;
1000 path.addRect(ScalarRect);
1001 path.transform(m);
1002 this->drawPath(draw, path, paintWithTexture, NULL, true);
1003 }
junov@google.comd935cfb2011-06-27 20:48:23 +00001004 return;
1005 }
1006
bsalomon@google.com5782d712011-01-21 21:03:59 +00001007 GrPaint grPaint;
Scroggod757df22011-05-16 13:11:16 +00001008 if (!this->skPaint2GrPaintNoShader(paint, true, &grPaint, false)) {
bsalomon@google.com5782d712011-01-21 21:03:59 +00001009 return;
1010 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001011 GrSamplerState* sampler = grPaint.getTextureSampler(kBitmapTextureIdx);
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +00001012 if (paint.isFilterBitmap()) {
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001013 sampler->setFilter(GrSamplerState::kBilinear_Filter);
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +00001014 } else {
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001015 sampler->setFilter(GrSamplerState::kNearest_Filter);
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +00001016 }
bsalomon@google.com5782d712011-01-21 21:03:59 +00001017
bsalomon@google.com91958362011-06-13 17:58:13 +00001018 const int maxTextureSize = fContext->getMaxTextureSize();
1019 if (bitmap.getTexture() || (bitmap.width() <= maxTextureSize &&
1020 bitmap.height() <= maxTextureSize)) {
reed@google.comac10a2d2010-12-22 21:39:39 +00001021 // take the fast case
bsalomon@google.com5782d712011-01-21 21:03:59 +00001022 this->internalDrawBitmap(draw, bitmap, srcRect, m, &grPaint);
reed@google.comac10a2d2010-12-22 21:39:39 +00001023 return;
1024 }
1025
1026 // undo the translate done by SkCanvas
1027 int DX = SkMax32(0, srcRect.fLeft);
1028 int DY = SkMax32(0, srcRect.fTop);
1029 // compute clip bounds in local coordinates
1030 SkIRect clipRect;
1031 {
1032 SkRect r;
1033 r.set(draw.fClip->getBounds());
1034 SkMatrix matrix, inverse;
1035 matrix.setConcat(*draw.fMatrix, m);
1036 if (!matrix.invert(&inverse)) {
1037 return;
1038 }
1039 inverse.mapRect(&r);
1040 r.roundOut(&clipRect);
1041 // apply the canvas' translate to our local clip
1042 clipRect.offset(DX, DY);
1043 }
1044
bsalomon@google.com91958362011-06-13 17:58:13 +00001045 int nx = bitmap.width() / maxTextureSize;
1046 int ny = bitmap.height() / maxTextureSize;
reed@google.comac10a2d2010-12-22 21:39:39 +00001047 for (int x = 0; x <= nx; x++) {
1048 for (int y = 0; y <= ny; y++) {
1049 SkIRect tileR;
bsalomon@google.com91958362011-06-13 17:58:13 +00001050 tileR.set(x * maxTextureSize, y * maxTextureSize,
1051 (x + 1) * maxTextureSize, (y + 1) * maxTextureSize);
reed@google.comac10a2d2010-12-22 21:39:39 +00001052 if (!SkIRect::Intersects(tileR, clipRect)) {
1053 continue;
1054 }
1055
1056 SkIRect srcR = tileR;
1057 if (!srcR.intersect(srcRect)) {
1058 continue;
1059 }
1060
1061 SkBitmap tmpB;
1062 if (bitmap.extractSubset(&tmpB, tileR)) {
1063 // now offset it to make it "local" to our tmp bitmap
1064 srcR.offset(-tileR.fLeft, -tileR.fTop);
1065
1066 SkMatrix tmpM(m);
1067 {
1068 int dx = tileR.fLeft - DX + SkMax32(0, srcR.fLeft);
1069 int dy = tileR.fTop - DY + SkMax32(0, srcR.fTop);
1070 tmpM.preTranslate(SkIntToScalar(dx), SkIntToScalar(dy));
1071 }
bsalomon@google.com5782d712011-01-21 21:03:59 +00001072 this->internalDrawBitmap(draw, tmpB, srcR, tmpM, &grPaint);
reed@google.comac10a2d2010-12-22 21:39:39 +00001073 }
1074 }
1075 }
1076}
1077
1078/*
1079 * This is called by drawBitmap(), which has to handle images that may be too
1080 * large to be represented by a single texture.
1081 *
bsalomon@google.com5782d712011-01-21 21:03:59 +00001082 * internalDrawBitmap assumes that the specified bitmap will fit in a texture
1083 * and that non-texture portion of the GrPaint has already been setup.
reed@google.comac10a2d2010-12-22 21:39:39 +00001084 */
1085void SkGpuDevice::internalDrawBitmap(const SkDraw& draw,
1086 const SkBitmap& bitmap,
1087 const SkIRect& srcRect,
1088 const SkMatrix& m,
bsalomon@google.com5782d712011-01-21 21:03:59 +00001089 GrPaint* grPaint) {
bsalomon@google.com91958362011-06-13 17:58:13 +00001090 SkASSERT(bitmap.width() <= fContext->getMaxTextureSize() &&
1091 bitmap.height() <= fContext->getMaxTextureSize());
reed@google.comac10a2d2010-12-22 21:39:39 +00001092
reed@google.com9c49bc32011-07-07 13:42:37 +00001093 SkAutoLockPixels alp(bitmap, !bitmap.getTexture());
reed@google.comac10a2d2010-12-22 21:39:39 +00001094 if (!bitmap.getTexture() && !bitmap.readyToDraw()) {
reed@google.com9c49bc32011-07-07 13:42:37 +00001095 SkDebugf("nothing to draw\n");
reed@google.comac10a2d2010-12-22 21:39:39 +00001096 return;
1097 }
1098
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001099 GrSamplerState* sampler = grPaint->getTextureSampler(kBitmapTextureIdx);
1100
1101 sampler->setWrapX(GrSamplerState::kClamp_WrapMode);
1102 sampler->setWrapY(GrSamplerState::kClamp_WrapMode);
1103 sampler->setSampleMode(GrSamplerState::kNormal_SampleMode);
1104 sampler->setMatrix(GrMatrix::I());
reed@google.comac10a2d2010-12-22 21:39:39 +00001105
1106 GrTexture* texture;
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001107 SkAutoCachedTexture act(this, bitmap, *sampler, &texture);
reed@google.comac10a2d2010-12-22 21:39:39 +00001108 if (NULL == texture) {
1109 return;
1110 }
1111
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001112 grPaint->setTexture(kShaderTextureIdx, texture);
reed@google.com46799cd2011-02-22 20:56:26 +00001113
reed@google.com20efde72011-05-09 17:00:02 +00001114 GrRect dstRect = SkRect::MakeWH(GrIntToScalar(srcRect.width()),
1115 GrIntToScalar(srcRect.height()));
bsalomon@google.comc6cf7232011-02-17 16:43:10 +00001116 GrRect paintRect;
junov@google.com6acc9b32011-05-16 18:32:07 +00001117 paintRect.setLTRB(GrFixedToScalar((srcRect.fLeft << 16) / bitmap.width()),
1118 GrFixedToScalar((srcRect.fTop << 16) / bitmap.height()),
1119 GrFixedToScalar((srcRect.fRight << 16) / bitmap.width()),
bsalomon@google.comc6cf7232011-02-17 16:43:10 +00001120 GrFixedToScalar((srcRect.fBottom << 16) / bitmap.height()));
reed@google.comac10a2d2010-12-22 21:39:39 +00001121
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001122 if (GrSamplerState::kNearest_Filter != sampler->getFilter() &&
junov@google.com6acc9b32011-05-16 18:32:07 +00001123 (srcRect.width() < bitmap.width() ||
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001124 srcRect.height() < bitmap.height())) {
junov@google.com6acc9b32011-05-16 18:32:07 +00001125 // If drawing a subrect of the bitmap and filtering is enabled,
1126 // use a constrained texture domain to avoid color bleeding
1127 GrScalar left, top, right, bottom;
1128 if (srcRect.width() > 1) {
1129 GrScalar border = GR_ScalarHalf / bitmap.width();
1130 left = paintRect.left() + border;
1131 right = paintRect.right() - border;
1132 } else {
1133 left = right = GrScalarHalf(paintRect.left() + paintRect.right());
1134 }
1135 if (srcRect.height() > 1) {
1136 GrScalar border = GR_ScalarHalf / bitmap.height();
1137 top = paintRect.top() + border;
1138 bottom = paintRect.bottom() - border;
1139 } else {
1140 top = bottom = GrScalarHalf(paintRect.top() + paintRect.bottom());
1141 }
1142 GrRect textureDomain;
1143 textureDomain.setLTRB(left, top, right, bottom);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001144 sampler->setTextureDomain(textureDomain);
junov@google.com6acc9b32011-05-16 18:32:07 +00001145 }
1146
bsalomon@google.comcc4dac32011-05-10 13:52:42 +00001147 fContext->drawRectToRect(*grPaint, dstRect, paintRect, &m);
reed@google.comac10a2d2010-12-22 21:39:39 +00001148}
1149
1150void SkGpuDevice::drawSprite(const SkDraw& draw, const SkBitmap& bitmap,
1151 int left, int top, const SkPaint& paint) {
1152 CHECK_SHOULD_DRAW(draw);
1153
1154 SkAutoLockPixels alp(bitmap);
1155 if (!bitmap.getTexture() && !bitmap.readyToDraw()) {
1156 return;
1157 }
1158
bsalomon@google.com5782d712011-01-21 21:03:59 +00001159 GrPaint grPaint;
Scroggod757df22011-05-16 13:11:16 +00001160 if(!this->skPaint2GrPaintNoShader(paint, true, &grPaint, false)) {
bsalomon@google.com5782d712011-01-21 21:03:59 +00001161 return;
1162 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001163
bsalomon@google.com5782d712011-01-21 21:03:59 +00001164 GrAutoMatrix avm(fContext, GrMatrix::I());
1165
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001166 GrSamplerState* sampler = grPaint.getTextureSampler(kBitmapTextureIdx);
bsalomon@google.com5782d712011-01-21 21:03:59 +00001167
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001168 GrTexture* texture;
1169 sampler->setClampNoFilter();
1170 SkAutoCachedTexture act(this, bitmap, *sampler, &texture);
1171
1172 grPaint.setTexture(kBitmapTextureIdx, texture);
bsalomon@google.com5782d712011-01-21 21:03:59 +00001173
bsalomon@google.com5782d712011-01-21 21:03:59 +00001174 fContext->drawRectToRect(grPaint,
reed@google.com20efde72011-05-09 17:00:02 +00001175 GrRect::MakeXYWH(GrIntToScalar(left),
1176 GrIntToScalar(top),
1177 GrIntToScalar(bitmap.width()),
1178 GrIntToScalar(bitmap.height())),
1179 GrRect::MakeWH(GR_Scalar1, GR_Scalar1));
reed@google.comac10a2d2010-12-22 21:39:39 +00001180}
1181
1182void SkGpuDevice::drawDevice(const SkDraw& draw, SkDevice* dev,
1183 int x, int y, const SkPaint& paint) {
1184 CHECK_SHOULD_DRAW(draw);
1185
bsalomon@google.com5782d712011-01-21 21:03:59 +00001186 GrPaint grPaint;
bsalomon@google.comc6cf7232011-02-17 16:43:10 +00001187 if (!((SkGpuDevice*)dev)->bindDeviceAsTexture(&grPaint) ||
Scroggod757df22011-05-16 13:11:16 +00001188 !this->skPaint2GrPaintNoShader(paint, true, &grPaint, false)) {
bsalomon@google.com5782d712011-01-21 21:03:59 +00001189 return;
reed@google.comac10a2d2010-12-22 21:39:39 +00001190 }
bsalomon@google.com5782d712011-01-21 21:03:59 +00001191
bsalomon@google.comb5b31682011-06-16 18:05:35 +00001192 GrTexture* devTex = grPaint.getTexture(0);
1193 SkASSERT(NULL != devTex);
bsalomon@google.com5782d712011-01-21 21:03:59 +00001194
1195 const SkBitmap& bm = dev->accessBitmap(false);
1196 int w = bm.width();
1197 int h = bm.height();
1198
1199 GrAutoMatrix avm(fContext, GrMatrix::I());
1200
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001201 grPaint.getTextureSampler(kBitmapTextureIdx)->setClampNoFilter();
bsalomon@google.com5782d712011-01-21 21:03:59 +00001202
bsalomon@google.comb5b31682011-06-16 18:05:35 +00001203 GrRect dstRect = GrRect::MakeXYWH(GrIntToScalar(x),
1204 GrIntToScalar(y),
1205 GrIntToScalar(w),
1206 GrIntToScalar(h));
1207 // The device being drawn may not fill up its texture (saveLayer uses
1208 // the approximate ).
1209 GrRect srcRect = GrRect::MakeWH(GR_Scalar1 * w / devTex->width(),
1210 GR_Scalar1 * h / devTex->height());
1211
1212 fContext->drawRectToRect(grPaint, dstRect, srcRect);
reed@google.comac10a2d2010-12-22 21:39:39 +00001213}
1214
1215///////////////////////////////////////////////////////////////////////////////
1216
1217// must be in SkCanvas::VertexMode order
bsalomon@google.comffca4002011-02-22 20:34:01 +00001218static const GrPrimitiveType gVertexMode2PrimitiveType[] = {
1219 kTriangles_PrimitiveType,
1220 kTriangleStrip_PrimitiveType,
1221 kTriangleFan_PrimitiveType,
reed@google.comac10a2d2010-12-22 21:39:39 +00001222};
1223
1224void SkGpuDevice::drawVertices(const SkDraw& draw, SkCanvas::VertexMode vmode,
1225 int vertexCount, const SkPoint vertices[],
1226 const SkPoint texs[], const SkColor colors[],
1227 SkXfermode* xmode,
1228 const uint16_t indices[], int indexCount,
1229 const SkPaint& paint) {
1230 CHECK_SHOULD_DRAW(draw);
1231
bsalomon@google.com5782d712011-01-21 21:03:59 +00001232 GrPaint grPaint;
1233 SkAutoCachedTexture act;
1234 // we ignore the shader if texs is null.
1235 if (NULL == texs) {
Scroggod757df22011-05-16 13:11:16 +00001236 if (!this->skPaint2GrPaintNoShader(paint,
1237 false,
1238 &grPaint,
1239 NULL == colors)) {
reed@google.comac10a2d2010-12-22 21:39:39 +00001240 return;
1241 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001242 } else {
reed@google.com1a2e8d22011-01-21 22:08:29 +00001243 if (!this->skPaint2GrPaintShader(paint, &act,
1244 *draw.fMatrix,
Scroggod757df22011-05-16 13:11:16 +00001245 &grPaint,
1246 NULL == colors)) {
bsalomon@google.com5782d712011-01-21 21:03:59 +00001247 return;
1248 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001249 }
bsalomon@google.com5782d712011-01-21 21:03:59 +00001250
1251 if (NULL != xmode && NULL != texs && NULL != colors) {
1252 SkXfermode::Mode mode;
1253 if (!SkXfermode::IsMode(xmode, &mode) ||
1254 SkXfermode::kMultiply_Mode != mode) {
1255 SkDebugf("Unsupported vertex-color/texture xfer mode.\n");
1256#if 0
1257 return
1258#endif
1259 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001260 }
bsalomon@google.com5782d712011-01-21 21:03:59 +00001261
1262#if SK_SCALAR_IS_GR_SCALAR
1263 // even if GrColor and SkColor byte offsets match we need
1264 // to perform pre-multiply.
1265 if (NULL == colors) {
1266 fContext->drawVertices(grPaint,
1267 gVertexMode2PrimitiveType[vmode],
1268 vertexCount,
1269 (GrPoint*) vertices,
1270 (GrPoint*) texs,
1271 NULL,
1272 indices,
1273 indexCount);
1274 } else
1275#endif
1276 {
1277 SkTexCoordSource texSrc(texs);
1278 SkColorSource colSrc(colors);
1279 SkIndexSource idxSrc(indices, indexCount);
1280
1281 fContext->drawCustomVertices(grPaint,
1282 gVertexMode2PrimitiveType[vmode],
1283 SkPositionSource(vertices, vertexCount),
1284 (NULL == texs) ? NULL : &texSrc,
1285 (NULL == colors) ? NULL : &colSrc,
1286 (NULL == indices) ? NULL : &idxSrc);
reed@google.comac10a2d2010-12-22 21:39:39 +00001287 }
1288}
1289
1290///////////////////////////////////////////////////////////////////////////////
1291
1292static void GlyphCacheAuxProc(void* data) {
1293 delete (GrFontScaler*)data;
1294}
1295
1296static GrFontScaler* get_gr_font_scaler(SkGlyphCache* cache) {
1297 void* auxData;
1298 GrFontScaler* scaler = NULL;
1299 if (cache->getAuxProcData(GlyphCacheAuxProc, &auxData)) {
1300 scaler = (GrFontScaler*)auxData;
1301 }
1302 if (NULL == scaler) {
1303 scaler = new SkGrFontScaler(cache);
1304 cache->setAuxProc(GlyphCacheAuxProc, scaler);
1305 }
1306 return scaler;
1307}
1308
1309static void SkGPU_Draw1Glyph(const SkDraw1Glyph& state,
1310 SkFixed fx, SkFixed fy,
1311 const SkGlyph& glyph) {
1312 SkASSERT(glyph.fWidth > 0 && glyph.fHeight > 0);
1313
1314 GrSkDrawProcs* procs = (GrSkDrawProcs*)state.fDraw->fProcs;
1315
1316 if (NULL == procs->fFontScaler) {
1317 procs->fFontScaler = get_gr_font_scaler(state.fCache);
1318 }
reed@google.com39ce0ac2011-04-08 15:42:19 +00001319
1320 /*
reed@google.com3b139f52011-06-07 17:56:25 +00001321 * What should we do with fy? (assuming horizontal/latin text)
reed@google.com39ce0ac2011-04-08 15:42:19 +00001322 *
reed@google.com3b139f52011-06-07 17:56:25 +00001323 * The raster code calls SkFixedFloorToFixed on it, as it does with fx.
1324 * It calls that rather than round, because our caller has already added
1325 * SK_FixedHalf, so that calling floor gives us the rounded integer.
1326 *
1327 * Test code between raster and gpu (they should draw the same)
1328 *
1329 * canvas->drawText("Hamburgefons", 12, 0, 16.5f, paint);
1330 *
1331 * Perhaps we should only perform this integralization if there is no
1332 * fExtMatrix...
reed@google.com39ce0ac2011-04-08 15:42:19 +00001333 */
reed@google.com3b139f52011-06-07 17:56:25 +00001334 fy = SkFixedFloorToFixed(fy);
1335
reed@google.comac10a2d2010-12-22 21:39:39 +00001336 procs->fTextContext->drawPackedGlyph(GrGlyph::Pack(glyph.getGlyphID(), fx, 0),
reed@google.com3b139f52011-06-07 17:56:25 +00001337 SkFixedFloorToFixed(fx), fy,
reed@google.comac10a2d2010-12-22 21:39:39 +00001338 procs->fFontScaler);
1339}
1340
bsalomon@google.com5782d712011-01-21 21:03:59 +00001341SkDrawProcs* SkGpuDevice::initDrawForText(GrTextContext* context) {
reed@google.comac10a2d2010-12-22 21:39:39 +00001342
1343 // deferred allocation
1344 if (NULL == fDrawProcs) {
1345 fDrawProcs = new GrSkDrawProcs;
1346 fDrawProcs->fD1GProc = SkGPU_Draw1Glyph;
1347 fDrawProcs->fContext = fContext;
1348 }
1349
1350 // init our (and GL's) state
1351 fDrawProcs->fTextContext = context;
1352 fDrawProcs->fFontScaler = NULL;
1353 return fDrawProcs;
1354}
1355
1356void SkGpuDevice::drawText(const SkDraw& draw, const void* text,
1357 size_t byteLength, SkScalar x, SkScalar y,
1358 const SkPaint& paint) {
1359 CHECK_SHOULD_DRAW(draw);
1360
1361 if (draw.fMatrix->getType() & SkMatrix::kPerspective_Mask) {
1362 // this guy will just call our drawPath()
1363 draw.drawText((const char*)text, byteLength, x, y, paint);
1364 } else {
reed@google.comac10a2d2010-12-22 21:39:39 +00001365 SkDraw myDraw(draw);
bsalomon@google.com5782d712011-01-21 21:03:59 +00001366
1367 GrPaint grPaint;
1368 SkAutoCachedTexture act;
1369
Scroggod757df22011-05-16 13:11:16 +00001370 if (!this->skPaint2GrPaintShader(paint,
1371 &act,
1372 *draw.fMatrix,
1373 &grPaint,
1374 true)) {
bsalomon@google.com5782d712011-01-21 21:03:59 +00001375 return;
1376 }
bsalomon@google.comcc4dac32011-05-10 13:52:42 +00001377 GrTextContext context(fContext, grPaint, draw.fExtMatrix);
bsalomon@google.com5782d712011-01-21 21:03:59 +00001378 myDraw.fProcs = this->initDrawForText(&context);
reed@google.comac10a2d2010-12-22 21:39:39 +00001379 this->INHERITED::drawText(myDraw, text, byteLength, x, y, paint);
1380 }
1381}
1382
1383void SkGpuDevice::drawPosText(const SkDraw& draw, const void* text,
1384 size_t byteLength, const SkScalar pos[],
1385 SkScalar constY, int scalarsPerPos,
1386 const SkPaint& paint) {
1387 CHECK_SHOULD_DRAW(draw);
1388
1389 if (draw.fMatrix->getType() & SkMatrix::kPerspective_Mask) {
1390 // this guy will just call our drawPath()
1391 draw.drawPosText((const char*)text, byteLength, pos, constY,
1392 scalarsPerPos, paint);
1393 } else {
reed@google.comac10a2d2010-12-22 21:39:39 +00001394 SkDraw myDraw(draw);
bsalomon@google.com5782d712011-01-21 21:03:59 +00001395
1396 GrPaint grPaint;
1397 SkAutoCachedTexture act;
Scroggod757df22011-05-16 13:11:16 +00001398 if (!this->skPaint2GrPaintShader(paint,
1399 &act,
1400 *draw.fMatrix,
1401 &grPaint,
1402 true)) {
bsalomon@google.com5782d712011-01-21 21:03:59 +00001403 return;
1404 }
1405
bsalomon@google.comcc4dac32011-05-10 13:52:42 +00001406 GrTextContext context(fContext, grPaint, draw.fExtMatrix);
bsalomon@google.com5782d712011-01-21 21:03:59 +00001407 myDraw.fProcs = this->initDrawForText(&context);
reed@google.comac10a2d2010-12-22 21:39:39 +00001408 this->INHERITED::drawPosText(myDraw, text, byteLength, pos, constY,
1409 scalarsPerPos, paint);
1410 }
1411}
1412
1413void SkGpuDevice::drawTextOnPath(const SkDraw& draw, const void* text,
1414 size_t len, const SkPath& path,
1415 const SkMatrix* m, const SkPaint& paint) {
1416 CHECK_SHOULD_DRAW(draw);
1417
1418 SkASSERT(draw.fDevice == this);
1419 draw.drawTextOnPath((const char*)text, len, path, m, paint);
1420}
1421
1422///////////////////////////////////////////////////////////////////////////////
1423
reed@google.comf67e4cf2011-03-15 20:56:58 +00001424bool SkGpuDevice::filterTextFlags(const SkPaint& paint, TextFlags* flags) {
1425 if (!paint.isLCDRenderText()) {
1426 // we're cool with the paint as is
1427 return false;
1428 }
1429
1430 if (paint.getShader() ||
1431 paint.getXfermode() || // unless its srcover
1432 paint.getMaskFilter() ||
1433 paint.getRasterizer() ||
1434 paint.getColorFilter() ||
1435 paint.getPathEffect() ||
1436 paint.isFakeBoldText() ||
1437 paint.getStyle() != SkPaint::kFill_Style) {
1438 // turn off lcd
1439 flags->fFlags = paint.getFlags() & ~SkPaint::kLCDRenderText_Flag;
1440 flags->fHinting = paint.getHinting();
1441 return true;
1442 }
1443 // we're cool with the paint as is
1444 return false;
1445}
1446
1447///////////////////////////////////////////////////////////////////////////////
1448
reed@google.comac10a2d2010-12-22 21:39:39 +00001449SkGpuDevice::TexCache* SkGpuDevice::lockCachedTexture(const SkBitmap& bitmap,
bsalomon@google.comfea37b52011-04-25 15:51:06 +00001450 const GrSamplerState& sampler,
1451 GrTexture** texture,
bsalomon@google.come97f0852011-06-17 13:10:25 +00001452 TexType type) {
bsalomon@google.comfea37b52011-04-25 15:51:06 +00001453 GrTexture* newTexture = NULL;
1454 GrTextureEntry* entry = NULL;
reed@google.comac10a2d2010-12-22 21:39:39 +00001455 GrContext* ctx = this->context();
bsalomon@google.comfea37b52011-04-25 15:51:06 +00001456
bsalomon@google.come97f0852011-06-17 13:10:25 +00001457 if (kBitmap_TexType != type) {
bsalomon@google.comfea37b52011-04-25 15:51:06 +00001458 const GrTextureDesc desc = {
1459 kRenderTarget_GrTextureFlagBit,
1460 kNone_GrAALevel,
1461 bitmap.width(),
1462 bitmap.height(),
1463 SkGr::Bitmap2PixelConfig(bitmap)
1464 };
bsalomon@google.come97f0852011-06-17 13:10:25 +00001465 if (kSaveLayerDeviceRenderTarget_TexType == type) {
bsalomon@google.comb5b31682011-06-16 18:05:35 +00001466 // we know layers will only be drawn through drawDevice.
1467 // drawDevice has been made to work with content embedded in a
1468 // larger texture so its okay to use the approximate version.
1469 entry = ctx->findApproximateKeylessTexture(desc);
1470 } else {
bsalomon@google.come97f0852011-06-17 13:10:25 +00001471 SkASSERT(kDeviceRenderTarget_TexType == type);
bsalomon@google.comb5b31682011-06-16 18:05:35 +00001472 entry = ctx->lockKeylessTexture(desc);
1473 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001474 } else {
junov@google.com4ee7ae52011-06-30 17:30:49 +00001475 if (!bitmap.isVolatile()) {
1476 uint32_t p0, p1;
1477 p0 = bitmap.getGenerationID();
1478 p1 = bitmap.pixelRefOffset();
1479 GrTextureKey key(p0, p1, bitmap.width(), bitmap.height());
1480
1481 entry = ctx->findAndLockTexture(&key, sampler);
1482 if (NULL == entry)
1483 entry = sk_gr_create_bitmap_texture(ctx, &key, sampler,
1484 bitmap);
1485 } else {
1486 entry = sk_gr_create_bitmap_texture(ctx, NULL, sampler, bitmap);
1487 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001488 if (NULL == entry) {
junov@google.com4ee7ae52011-06-30 17:30:49 +00001489 GrPrintf("---- failed to create texture for cache [%d %d]\n",
1490 bitmap.width(), bitmap.height());
reed@google.comac10a2d2010-12-22 21:39:39 +00001491 }
1492 }
1493
1494 if (NULL != entry) {
1495 newTexture = entry->texture();
reed@google.comac10a2d2010-12-22 21:39:39 +00001496 if (texture) {
1497 *texture = newTexture;
1498 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001499 }
1500 return (TexCache*)entry;
1501}
1502
1503void SkGpuDevice::unlockCachedTexture(TexCache* cache) {
1504 this->context()->unlockTexture((GrTextureEntry*)cache);
1505}
1506
bsalomon@google.come97f0852011-06-17 13:10:25 +00001507SkDevice* SkGpuDevice::onCreateCompatibleDevice(SkBitmap::Config config,
1508 int width, int height,
1509 bool isOpaque,
1510 Usage usage) {
1511 return SkNEW_ARGS(SkGpuDevice,(this->context(), config,
1512 width, height, usage));
1513}
1514