blob: b8cc2bb4cec20db64dcd5a0f511b51724987ff0c [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);
493 copy.setColor(SkColorSetA(color, copy.getAlpha()));
494 return this->skPaint2GrPaintNoShader(copy,
495 false,
496 grPaint,
497 constantColor);
498 }
bsalomon@google.com5782d712011-01-21 21:03:59 +0000499 return false;
reed@google.comac10a2d2010-12-22 21:39:39 +0000500 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000501 GrSamplerState* sampler = grPaint->getTextureSampler(kShaderTextureIdx);
502 sampler->setSampleMode(sampleMode);
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000503 if (skPaint.isFilterBitmap()) {
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000504 sampler->setFilter(GrSamplerState::kBilinear_Filter);
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000505 } else {
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000506 sampler->setFilter(GrSamplerState::kNearest_Filter);
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000507 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000508 sampler->setWrapX(sk_tile_mode_to_grwrap(tileModes[0]));
509 sampler->setWrapY(sk_tile_mode_to_grwrap(tileModes[1]));
reed@google.comac10a2d2010-12-22 21:39:39 +0000510 if (GrSamplerState::kRadial2_SampleMode == sampleMode) {
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000511 sampler->setRadial2Params(twoPointParams[0],
512 twoPointParams[1],
513 twoPointParams[2] < 0);
reed@google.comac10a2d2010-12-22 21:39:39 +0000514 }
515
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000516 GrTexture* texture = act->set(this, bitmap, *sampler);
reed@google.comac10a2d2010-12-22 21:39:39 +0000517 if (NULL == texture) {
bsalomon@google.com5782d712011-01-21 21:03:59 +0000518 SkDebugf("Couldn't convert bitmap to texture.\n");
519 return false;
reed@google.comac10a2d2010-12-22 21:39:39 +0000520 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000521 grPaint->setTexture(kShaderTextureIdx, texture);
reed@google.comac10a2d2010-12-22 21:39:39 +0000522
523 // since our texture coords will be in local space, we wack the texture
524 // matrix to map them back into 0...1 before we load it
525 SkMatrix localM;
526 if (shader->getLocalMatrix(&localM)) {
527 SkMatrix inverse;
528 if (localM.invert(&inverse)) {
529 matrix.preConcat(inverse);
530 }
531 }
532 if (SkShader::kDefault_BitmapType == bmptype) {
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000533 GrScalar sx = GrFixedToScalar(GR_Fixed1 / bitmap.width());
534 GrScalar sy = GrFixedToScalar(GR_Fixed1 / bitmap.height());
reed@google.comac10a2d2010-12-22 21:39:39 +0000535 matrix.postScale(sx, sy);
reed@google.comac10a2d2010-12-22 21:39:39 +0000536 } else if (SkShader::kRadial_BitmapType == bmptype) {
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000537 GrScalar s = GrFixedToScalar(GR_Fixed1 / bitmap.width());
reed@google.comac10a2d2010-12-22 21:39:39 +0000538 matrix.postScale(s, s);
539 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000540 sampler->setMatrix(matrix);
bsalomon@google.com5782d712011-01-21 21:03:59 +0000541
542 return true;
reed@google.comac10a2d2010-12-22 21:39:39 +0000543}
544
545///////////////////////////////////////////////////////////////////////////////
bsalomon@google.com5782d712011-01-21 21:03:59 +0000546
547class SkPositionSource {
548public:
549 SkPositionSource(const SkPoint* points, int count)
550 : fPoints(points), fCount(count) {}
551
552 int count() const { return fCount; }
553
554 void writeValue(int i, GrPoint* dstPosition) const {
555 SkASSERT(i < fCount);
556 dstPosition->fX = SkScalarToGrScalar(fPoints[i].fX);
557 dstPosition->fY = SkScalarToGrScalar(fPoints[i].fY);
558 }
559private:
bsalomon@google.com5782d712011-01-21 21:03:59 +0000560 const SkPoint* fPoints;
bsalomon@google.com19628322011-02-03 21:30:17 +0000561 int fCount;
bsalomon@google.com5782d712011-01-21 21:03:59 +0000562};
563
564class SkTexCoordSource {
565public:
566 SkTexCoordSource(const SkPoint* coords)
567 : fCoords(coords) {}
568
569 void writeValue(int i, GrPoint* dstCoord) const {
570 dstCoord->fX = SkScalarToGrScalar(fCoords[i].fX);
571 dstCoord->fY = SkScalarToGrScalar(fCoords[i].fY);
572 }
573private:
574 const SkPoint* fCoords;
575};
576
577class SkColorSource {
578public:
579 SkColorSource(const SkColor* colors) : fColors(colors) {}
580
581 void writeValue(int i, GrColor* dstColor) const {
582 *dstColor = SkGr::SkColor2GrColor(fColors[i]);
583 }
584private:
585 const SkColor* fColors;
586};
587
588class SkIndexSource {
589public:
590 SkIndexSource(const uint16_t* indices, int count)
591 : fIndices(indices), fCount(count) {
592 }
593
594 int count() const { return fCount; }
595
596 void writeValue(int i, uint16_t* dstIndex) const {
597 *dstIndex = fIndices[i];
598 }
599
600private:
bsalomon@google.com5782d712011-01-21 21:03:59 +0000601 const uint16_t* fIndices;
bsalomon@google.com19628322011-02-03 21:30:17 +0000602 int fCount;
bsalomon@google.com5782d712011-01-21 21:03:59 +0000603};
604
605///////////////////////////////////////////////////////////////////////////////
606
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000607#if 0 // not currently being used so don't compile,
608
bsalomon@google.com5782d712011-01-21 21:03:59 +0000609// can be used for positions or texture coordinates
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000610
bsalomon@google.com5782d712011-01-21 21:03:59 +0000611class SkRectFanSource {
612public:
613 SkRectFanSource(const SkRect& rect) : fRect(rect) {}
614
615 int count() const { return 4; }
616
617 void writeValue(int i, GrPoint* dstPoint) const {
618 SkASSERT(i < 4);
619 dstPoint->fX = SkScalarToGrScalar((i % 3) ? fRect.fRight :
620 fRect.fLeft);
621 dstPoint->fY = SkScalarToGrScalar((i < 2) ? fRect.fTop :
622 fRect.fBottom);
623 }
624private:
625 const SkRect& fRect;
626};
627
628class SkIRectFanSource {
629public:
630 SkIRectFanSource(const SkIRect& rect) : fRect(rect) {}
631
632 int count() const { return 4; }
633
634 void writeValue(int i, GrPoint* dstPoint) const {
635 SkASSERT(i < 4);
636 dstPoint->fX = (i % 3) ? GrIntToScalar(fRect.fRight) :
637 GrIntToScalar(fRect.fLeft);
638 dstPoint->fY = (i < 2) ? GrIntToScalar(fRect.fTop) :
639 GrIntToScalar(fRect.fBottom);
640 }
641private:
642 const SkIRect& fRect;
643};
644
645class SkMatRectFanSource {
646public:
647 SkMatRectFanSource(const SkRect& rect, const SkMatrix& matrix)
648 : fRect(rect), fMatrix(matrix) {}
649
650 int count() const { return 4; }
651
652 void writeValue(int i, GrPoint* dstPoint) const {
653 SkASSERT(i < 4);
654
655#if SK_SCALAR_IS_GR_SCALAR
656 fMatrix.mapXY((i % 3) ? fRect.fRight : fRect.fLeft,
657 (i < 2) ? fRect.fTop : fRect.fBottom,
658 (SkPoint*)dstPoint);
659#else
660 SkPoint dst;
661 fMatrix.mapXY((i % 3) ? fRect.fRight : fRect.fLeft,
662 (i < 2) ? fRect.fTop : fRect.fBottom,
663 &dst);
664 dstPoint->fX = SkScalarToGrScalar(dst.fX);
665 dstPoint->fY = SkScalarToGrScalar(dst.fY);
666#endif
667 }
668private:
669 const SkRect& fRect;
670 const SkMatrix& fMatrix;
671};
672
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000673#endif
674
reed@google.comac10a2d2010-12-22 21:39:39 +0000675///////////////////////////////////////////////////////////////////////////////
676
bsalomon@google.com398109c2011-04-14 18:40:27 +0000677void SkGpuDevice::clear(SkColor color) {
bsalomon@google.com31a58402011-04-27 21:00:02 +0000678 fContext->clear(NULL, color);
bsalomon@google.com398109c2011-04-14 18:40:27 +0000679}
680
reed@google.comac10a2d2010-12-22 21:39:39 +0000681void SkGpuDevice::drawPaint(const SkDraw& draw, const SkPaint& paint) {
682 CHECK_SHOULD_DRAW(draw);
683
bsalomon@google.com5782d712011-01-21 21:03:59 +0000684 GrPaint grPaint;
685 SkAutoCachedTexture act;
Scroggod757df22011-05-16 13:11:16 +0000686 if (!this->skPaint2GrPaintShader(paint,
687 &act,
688 *draw.fMatrix,
689 &grPaint,
690 true)) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000691 return;
692 }
bsalomon@google.com5782d712011-01-21 21:03:59 +0000693
694 fContext->drawPaint(grPaint);
reed@google.comac10a2d2010-12-22 21:39:39 +0000695}
696
697// must be in SkCanvas::PointMode order
bsalomon@google.comffca4002011-02-22 20:34:01 +0000698static const GrPrimitiveType gPointMode2PrimtiveType[] = {
699 kPoints_PrimitiveType,
700 kLines_PrimitiveType,
701 kLineStrip_PrimitiveType
reed@google.comac10a2d2010-12-22 21:39:39 +0000702};
703
704void SkGpuDevice::drawPoints(const SkDraw& draw, SkCanvas::PointMode mode,
bsalomon@google.com5782d712011-01-21 21:03:59 +0000705 size_t count, const SkPoint pts[], const SkPaint& paint) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000706 CHECK_SHOULD_DRAW(draw);
707
708 SkScalar width = paint.getStrokeWidth();
709 if (width < 0) {
710 return;
711 }
712
713 // we only handle hairlines here, else we let the SkDraw call our drawPath()
714 if (width > 0) {
715 draw.drawPoints(mode, count, pts, paint, true);
716 return;
717 }
718
bsalomon@google.com5782d712011-01-21 21:03:59 +0000719 GrPaint grPaint;
720 SkAutoCachedTexture act;
Scroggod757df22011-05-16 13:11:16 +0000721 if (!this->skPaint2GrPaintShader(paint,
722 &act,
723 *draw.fMatrix,
724 &grPaint,
725 true)) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000726 return;
727 }
728
reed@google.comac10a2d2010-12-22 21:39:39 +0000729#if SK_SCALAR_IS_GR_SCALAR
bsalomon@google.com5782d712011-01-21 21:03:59 +0000730 fContext->drawVertices(grPaint,
731 gPointMode2PrimtiveType[mode],
732 count,
733 (GrPoint*)pts,
734 NULL,
735 NULL,
736 NULL,
737 0);
reed@google.comac10a2d2010-12-22 21:39:39 +0000738#else
bsalomon@google.com5782d712011-01-21 21:03:59 +0000739 fContext->drawCustomVertices(grPaint,
740 gPointMode2PrimtiveType[mode],
741 SkPositionSource(pts, count));
reed@google.comac10a2d2010-12-22 21:39:39 +0000742#endif
reed@google.comac10a2d2010-12-22 21:39:39 +0000743}
744
reed@google.comc9aa5872011-04-05 21:05:37 +0000745///////////////////////////////////////////////////////////////////////////////
746
reed@google.comac10a2d2010-12-22 21:39:39 +0000747void SkGpuDevice::drawRect(const SkDraw& draw, const SkRect& rect,
748 const SkPaint& paint) {
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000749 CHECK_SHOULD_DRAW(draw);
750
751 bool doStroke = paint.getStyle() == SkPaint::kStroke_Style;
752 SkScalar width = paint.getStrokeWidth();
753
754 /*
755 We have special code for hairline strokes, miter-strokes, and fills.
756 Anything else we just call our path code.
757 */
758 bool usePath = doStroke && width > 0 &&
759 paint.getStrokeJoin() != SkPaint::kMiter_Join;
760 // another reason we might need to call drawPath...
761 if (paint.getMaskFilter()) {
762 usePath = true;
763 }
reed@google.com67db6642011-05-26 11:46:35 +0000764 // until we aa rotated rects...
765 if (!usePath && paint.isAntiAlias() && !draw.fMatrix->rectStaysRect()) {
766 usePath = true;
767 }
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000768
769 if (usePath) {
770 SkPath path;
771 path.addRect(rect);
772 this->drawPath(draw, path, paint, NULL, true);
773 return;
774 }
775
776 GrPaint grPaint;
777 SkAutoCachedTexture act;
Scroggod757df22011-05-16 13:11:16 +0000778 if (!this->skPaint2GrPaintShader(paint,
779 &act,
780 *draw.fMatrix,
781 &grPaint,
782 true)) {
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000783 return;
784 }
reed@google.com20efde72011-05-09 17:00:02 +0000785 fContext->drawRect(grPaint, rect, doStroke ? width : -1);
reed@google.comac10a2d2010-12-22 21:39:39 +0000786}
787
reed@google.com69302852011-02-16 18:08:07 +0000788#include "SkMaskFilter.h"
789#include "SkBounder.h"
790
reed@google.com69302852011-02-16 18:08:07 +0000791static bool drawWithMaskFilter(GrContext* context, const SkPath& path,
792 SkMaskFilter* filter, const SkMatrix& matrix,
793 const SkRegion& clip, SkBounder* bounder,
794 GrPaint* grp) {
795 SkMask srcM, dstM;
796
797 if (!SkDraw::DrawToMask(path, &clip.getBounds(), filter, &matrix, &srcM,
798 SkMask::kComputeBoundsAndRenderImage_CreateMode)) {
799 return false;
800 }
801
802 SkAutoMaskImage autoSrc(&srcM, false);
803
804 if (!filter->filterMask(&dstM, srcM, matrix, NULL)) {
805 return false;
806 }
807 // this will free-up dstM when we're done (allocated in filterMask())
808 SkAutoMaskImage autoDst(&dstM, false);
809
810 if (clip.quickReject(dstM.fBounds)) {
811 return false;
812 }
813 if (bounder && !bounder->doIRect(dstM.fBounds)) {
814 return false;
815 }
816
817 // we now have a device-aligned 8bit mask in dstM, ready to be drawn using
818 // the current clip (and identity matrix) and grpaint settings
819
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000820 // used to compute inverse view, if necessary
821 GrMatrix ivm = context->getMatrix();
822
reed@google.com0c219b62011-02-16 21:31:18 +0000823 GrAutoMatrix avm(context, GrMatrix::I());
reed@google.com69302852011-02-16 18:08:07 +0000824
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000825 const GrTextureDesc desc = {
826 kNone_GrTextureFlags,
827 kNone_GrAALevel,
reed@google.com69302852011-02-16 18:08:07 +0000828 dstM.fBounds.width(),
829 dstM.fBounds.height(),
bsalomon@google.com669fdc42011-04-05 17:08:27 +0000830 kAlpha_8_GrPixelConfig
reed@google.com69302852011-02-16 18:08:07 +0000831 };
832
833 GrTexture* texture = context->createUncachedTexture(desc, dstM.fImage,
834 dstM.fRowBytes);
835 if (NULL == texture) {
836 return false;
837 }
838
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000839 if (grp->hasTextureOrMask() && ivm.invert(&ivm)) {
840 grp->preConcatActiveSamplerMatrices(ivm);
841 }
842
843 static const int MASK_IDX = GrPaint::kMaxMasks - 1;
844 // we assume the last mask index is available for use
845 GrAssert(NULL == grp->getMask(MASK_IDX));
846 grp->setMask(MASK_IDX, texture);
reed@google.com0c219b62011-02-16 21:31:18 +0000847 texture->unref();
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000848 grp->getMaskSampler(MASK_IDX)->setClampNoFilter();
reed@google.com69302852011-02-16 18:08:07 +0000849
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000850 GrRect d;
851 d.setLTRB(GrIntToScalar(dstM.fBounds.fLeft),
reed@google.com0c219b62011-02-16 21:31:18 +0000852 GrIntToScalar(dstM.fBounds.fTop),
853 GrIntToScalar(dstM.fBounds.fRight),
854 GrIntToScalar(dstM.fBounds.fBottom));
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000855
856 GrMatrix m;
857 m.setTranslate(-dstM.fBounds.fLeft, -dstM.fBounds.fTop);
858 m.postIDiv(dstM.fBounds.width(), dstM.fBounds.height());
859 grp->getMaskSampler(MASK_IDX)->setMatrix(m);
860
861 context->drawRect(*grp, d);
reed@google.com69302852011-02-16 18:08:07 +0000862 return true;
863}
reed@google.com69302852011-02-16 18:08:07 +0000864
reed@google.com0c219b62011-02-16 21:31:18 +0000865void SkGpuDevice::drawPath(const SkDraw& draw, const SkPath& origSrcPath,
reed@google.comac10a2d2010-12-22 21:39:39 +0000866 const SkPaint& paint, const SkMatrix* prePathMatrix,
867 bool pathIsMutable) {
868 CHECK_SHOULD_DRAW(draw);
869
bsalomon@google.com5782d712011-01-21 21:03:59 +0000870 GrPaint grPaint;
871 SkAutoCachedTexture act;
Scroggod757df22011-05-16 13:11:16 +0000872 if (!this->skPaint2GrPaintShader(paint,
873 &act,
874 *draw.fMatrix,
875 &grPaint,
876 true)) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000877 return;
878 }
879
reed@google.com0c219b62011-02-16 21:31:18 +0000880 // BEGIN lift from SkDraw::drawPath()
881
882 SkPath* pathPtr = const_cast<SkPath*>(&origSrcPath);
883 bool doFill = true;
884 SkPath tmpPath;
reed@google.comac10a2d2010-12-22 21:39:39 +0000885
886 if (prePathMatrix) {
reed@google.come3445642011-02-16 23:20:39 +0000887 SkPath* result = pathPtr;
reed@google.com0c219b62011-02-16 21:31:18 +0000888
reed@google.come3445642011-02-16 23:20:39 +0000889 if (!pathIsMutable) {
890 result = &tmpPath;
891 pathIsMutable = true;
reed@google.comac10a2d2010-12-22 21:39:39 +0000892 }
reed@google.come3445642011-02-16 23:20:39 +0000893 // should I push prePathMatrix on our MV stack temporarily, instead
894 // of applying it here? See SkDraw.cpp
895 pathPtr->transform(*prePathMatrix, result);
896 pathPtr = result;
reed@google.comac10a2d2010-12-22 21:39:39 +0000897 }
reed@google.com0c219b62011-02-16 21:31:18 +0000898 // at this point we're done with prePathMatrix
899 SkDEBUGCODE(prePathMatrix = (const SkMatrix*)0x50FF8001;)
reed@google.comac10a2d2010-12-22 21:39:39 +0000900
bsalomon@google.com04de7822011-03-25 18:04:43 +0000901 // This "if" is not part of the SkDraw::drawPath() lift.
902 // When we get a 1.0 wide stroke we hairline stroke it instead of creating
903 // a new stroked-path. This is motivated by canvas2D sites that draw
904 // lines as 1.0 wide stroked paths. We can consider doing an alpha-modulated-
905 // hairline for width < 1.0 when AA is enabled.
906 static const int gMatrixMask = ~(SkMatrix::kIdentity_Mask |
907 SkMatrix::kTranslate_Mask);
908 if (!paint.getPathEffect() &&
909 SkPaint::kStroke_Style == paint.getStyle() &&
910 !(draw.fMatrix->getType() & gMatrixMask) &&
911 SK_Scalar1 == paint.getStrokeWidth()) {
912 doFill = false;
913 }
914
915 if (doFill && (paint.getPathEffect() ||
916 paint.getStyle() != SkPaint::kFill_Style)) {
reed@google.com0c219b62011-02-16 21:31:18 +0000917 doFill = paint.getFillPath(*pathPtr, &tmpPath);
918 pathPtr = &tmpPath;
919 }
920
921 // END lift from SkDraw::drawPath()
922
reed@google.com69302852011-02-16 18:08:07 +0000923 if (paint.getMaskFilter()) {
reed@google.com0c219b62011-02-16 21:31:18 +0000924 // avoid possibly allocating a new path in transform if we can
925 SkPath* devPathPtr = pathIsMutable ? pathPtr : &tmpPath;
926
927 // transform the path into device space
reed@google.come3445642011-02-16 23:20:39 +0000928 pathPtr->transform(*draw.fMatrix, devPathPtr);
reed@google.com0c219b62011-02-16 21:31:18 +0000929
930 drawWithMaskFilter(fContext, *devPathPtr, paint.getMaskFilter(),
reed@google.com69302852011-02-16 18:08:07 +0000931 *draw.fMatrix, *draw.fClip, draw.fBounder, &grPaint);
932 return;
933 }
reed@google.com69302852011-02-16 18:08:07 +0000934
bsalomon@google.comffca4002011-02-22 20:34:01 +0000935 GrPathFill fill = kHairLine_PathFill;
reed@google.comac10a2d2010-12-22 21:39:39 +0000936
reed@google.com0c219b62011-02-16 21:31:18 +0000937 if (doFill) {
938 switch (pathPtr->getFillType()) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000939 case SkPath::kWinding_FillType:
bsalomon@google.comffca4002011-02-22 20:34:01 +0000940 fill = kWinding_PathFill;
reed@google.comac10a2d2010-12-22 21:39:39 +0000941 break;
942 case SkPath::kEvenOdd_FillType:
bsalomon@google.comffca4002011-02-22 20:34:01 +0000943 fill = kEvenOdd_PathFill;
reed@google.comac10a2d2010-12-22 21:39:39 +0000944 break;
945 case SkPath::kInverseWinding_FillType:
bsalomon@google.comffca4002011-02-22 20:34:01 +0000946 fill = kInverseWinding_PathFill;
reed@google.comac10a2d2010-12-22 21:39:39 +0000947 break;
948 case SkPath::kInverseEvenOdd_FillType:
bsalomon@google.comffca4002011-02-22 20:34:01 +0000949 fill = kInverseEvenOdd_PathFill;
reed@google.comac10a2d2010-12-22 21:39:39 +0000950 break;
951 default:
bsalomon@google.com5782d712011-01-21 21:03:59 +0000952 SkDebugf("Unsupported path fill type\n");
reed@google.comac10a2d2010-12-22 21:39:39 +0000953 return;
954 }
955 }
956
reed@google.com07f3ee12011-05-16 17:21:57 +0000957 fContext->drawPath(grPaint, *pathPtr, fill);
reed@google.comac10a2d2010-12-22 21:39:39 +0000958}
959
reed@google.comac10a2d2010-12-22 21:39:39 +0000960void SkGpuDevice::drawBitmap(const SkDraw& draw,
961 const SkBitmap& bitmap,
962 const SkIRect* srcRectPtr,
963 const SkMatrix& m,
964 const SkPaint& paint) {
965 CHECK_SHOULD_DRAW(draw);
966
967 SkIRect srcRect;
968 if (NULL == srcRectPtr) {
969 srcRect.set(0, 0, bitmap.width(), bitmap.height());
970 } else {
971 srcRect = *srcRectPtr;
972 }
973
junov@google.comd935cfb2011-06-27 20:48:23 +0000974 if (paint.getMaskFilter()){
epoger@google.com9ef2d832011-07-01 21:12:20 +0000975 SkBitmap tmp; // storage if we need a subset of bitmap
junov@google.comd935cfb2011-06-27 20:48:23 +0000976 const SkBitmap* bitmapPtr = &bitmap;
epoger@google.com9ef2d832011-07-01 21:12:20 +0000977 if (srcRectPtr) {
978 if (!bitmap.extractSubset(&tmp, srcRect)) {
979 return; // extraction failed
980 }
981 bitmapPtr = &tmp;
junov@google.comd935cfb2011-06-27 20:48:23 +0000982 }
983 SkPaint paintWithTexture(paint);
984 paintWithTexture.setShader(SkShader::CreateBitmapShader( *bitmapPtr,
985 SkShader::kClamp_TileMode, SkShader::kClamp_TileMode))->unref();
986 paintWithTexture.getShader()->setLocalMatrix(m);
987
988 SkRect ScalarRect;
epoger@google.com9ef2d832011-07-01 21:12:20 +0000989 ScalarRect.set(srcRect);
junov@google.comd935cfb2011-06-27 20:48:23 +0000990
epoger@google.com9ef2d832011-07-01 21:12:20 +0000991 if (m.rectStaysRect()) {
992 // Preferred drawing method, optimized for rectangles
993 m.mapRect(&ScalarRect);
994 this->drawRect(draw, ScalarRect, paintWithTexture);
995 } else {
996 // Slower drawing method, for warped or rotated rectangles
997 SkPath path;
998 path.addRect(ScalarRect);
999 path.transform(m);
1000 this->drawPath(draw, path, paintWithTexture, NULL, true);
1001 }
junov@google.comd935cfb2011-06-27 20:48:23 +00001002 return;
1003 }
1004
bsalomon@google.com5782d712011-01-21 21:03:59 +00001005 GrPaint grPaint;
Scroggod757df22011-05-16 13:11:16 +00001006 if (!this->skPaint2GrPaintNoShader(paint, true, &grPaint, false)) {
bsalomon@google.com5782d712011-01-21 21:03:59 +00001007 return;
1008 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001009 GrSamplerState* sampler = grPaint.getTextureSampler(kBitmapTextureIdx);
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +00001010 if (paint.isFilterBitmap()) {
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001011 sampler->setFilter(GrSamplerState::kBilinear_Filter);
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +00001012 } else {
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001013 sampler->setFilter(GrSamplerState::kNearest_Filter);
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +00001014 }
bsalomon@google.com5782d712011-01-21 21:03:59 +00001015
bsalomon@google.com91958362011-06-13 17:58:13 +00001016 const int maxTextureSize = fContext->getMaxTextureSize();
1017 if (bitmap.getTexture() || (bitmap.width() <= maxTextureSize &&
1018 bitmap.height() <= maxTextureSize)) {
reed@google.comac10a2d2010-12-22 21:39:39 +00001019 // take the fast case
bsalomon@google.com5782d712011-01-21 21:03:59 +00001020 this->internalDrawBitmap(draw, bitmap, srcRect, m, &grPaint);
reed@google.comac10a2d2010-12-22 21:39:39 +00001021 return;
1022 }
1023
1024 // undo the translate done by SkCanvas
1025 int DX = SkMax32(0, srcRect.fLeft);
1026 int DY = SkMax32(0, srcRect.fTop);
1027 // compute clip bounds in local coordinates
1028 SkIRect clipRect;
1029 {
1030 SkRect r;
1031 r.set(draw.fClip->getBounds());
1032 SkMatrix matrix, inverse;
1033 matrix.setConcat(*draw.fMatrix, m);
1034 if (!matrix.invert(&inverse)) {
1035 return;
1036 }
1037 inverse.mapRect(&r);
1038 r.roundOut(&clipRect);
1039 // apply the canvas' translate to our local clip
1040 clipRect.offset(DX, DY);
1041 }
1042
bsalomon@google.com91958362011-06-13 17:58:13 +00001043 int nx = bitmap.width() / maxTextureSize;
1044 int ny = bitmap.height() / maxTextureSize;
reed@google.comac10a2d2010-12-22 21:39:39 +00001045 for (int x = 0; x <= nx; x++) {
1046 for (int y = 0; y <= ny; y++) {
1047 SkIRect tileR;
bsalomon@google.com91958362011-06-13 17:58:13 +00001048 tileR.set(x * maxTextureSize, y * maxTextureSize,
1049 (x + 1) * maxTextureSize, (y + 1) * maxTextureSize);
reed@google.comac10a2d2010-12-22 21:39:39 +00001050 if (!SkIRect::Intersects(tileR, clipRect)) {
1051 continue;
1052 }
1053
1054 SkIRect srcR = tileR;
1055 if (!srcR.intersect(srcRect)) {
1056 continue;
1057 }
1058
1059 SkBitmap tmpB;
1060 if (bitmap.extractSubset(&tmpB, tileR)) {
1061 // now offset it to make it "local" to our tmp bitmap
1062 srcR.offset(-tileR.fLeft, -tileR.fTop);
1063
1064 SkMatrix tmpM(m);
1065 {
1066 int dx = tileR.fLeft - DX + SkMax32(0, srcR.fLeft);
1067 int dy = tileR.fTop - DY + SkMax32(0, srcR.fTop);
1068 tmpM.preTranslate(SkIntToScalar(dx), SkIntToScalar(dy));
1069 }
bsalomon@google.com5782d712011-01-21 21:03:59 +00001070 this->internalDrawBitmap(draw, tmpB, srcR, tmpM, &grPaint);
reed@google.comac10a2d2010-12-22 21:39:39 +00001071 }
1072 }
1073 }
1074}
1075
1076/*
1077 * This is called by drawBitmap(), which has to handle images that may be too
1078 * large to be represented by a single texture.
1079 *
bsalomon@google.com5782d712011-01-21 21:03:59 +00001080 * internalDrawBitmap assumes that the specified bitmap will fit in a texture
1081 * and that non-texture portion of the GrPaint has already been setup.
reed@google.comac10a2d2010-12-22 21:39:39 +00001082 */
1083void SkGpuDevice::internalDrawBitmap(const SkDraw& draw,
1084 const SkBitmap& bitmap,
1085 const SkIRect& srcRect,
1086 const SkMatrix& m,
bsalomon@google.com5782d712011-01-21 21:03:59 +00001087 GrPaint* grPaint) {
bsalomon@google.com91958362011-06-13 17:58:13 +00001088 SkASSERT(bitmap.width() <= fContext->getMaxTextureSize() &&
1089 bitmap.height() <= fContext->getMaxTextureSize());
reed@google.comac10a2d2010-12-22 21:39:39 +00001090
1091 SkAutoLockPixels alp(bitmap);
1092 if (!bitmap.getTexture() && !bitmap.readyToDraw()) {
1093 return;
1094 }
1095
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001096 GrSamplerState* sampler = grPaint->getTextureSampler(kBitmapTextureIdx);
1097
1098 sampler->setWrapX(GrSamplerState::kClamp_WrapMode);
1099 sampler->setWrapY(GrSamplerState::kClamp_WrapMode);
1100 sampler->setSampleMode(GrSamplerState::kNormal_SampleMode);
1101 sampler->setMatrix(GrMatrix::I());
reed@google.comac10a2d2010-12-22 21:39:39 +00001102
1103 GrTexture* texture;
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001104 SkAutoCachedTexture act(this, bitmap, *sampler, &texture);
reed@google.comac10a2d2010-12-22 21:39:39 +00001105 if (NULL == texture) {
1106 return;
1107 }
1108
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001109 grPaint->setTexture(kShaderTextureIdx, texture);
reed@google.com46799cd2011-02-22 20:56:26 +00001110
reed@google.com20efde72011-05-09 17:00:02 +00001111 GrRect dstRect = SkRect::MakeWH(GrIntToScalar(srcRect.width()),
1112 GrIntToScalar(srcRect.height()));
bsalomon@google.comc6cf7232011-02-17 16:43:10 +00001113 GrRect paintRect;
junov@google.com6acc9b32011-05-16 18:32:07 +00001114 paintRect.setLTRB(GrFixedToScalar((srcRect.fLeft << 16) / bitmap.width()),
1115 GrFixedToScalar((srcRect.fTop << 16) / bitmap.height()),
1116 GrFixedToScalar((srcRect.fRight << 16) / bitmap.width()),
bsalomon@google.comc6cf7232011-02-17 16:43:10 +00001117 GrFixedToScalar((srcRect.fBottom << 16) / bitmap.height()));
reed@google.comac10a2d2010-12-22 21:39:39 +00001118
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001119 if (GrSamplerState::kNearest_Filter != sampler->getFilter() &&
junov@google.com6acc9b32011-05-16 18:32:07 +00001120 (srcRect.width() < bitmap.width() ||
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001121 srcRect.height() < bitmap.height())) {
junov@google.com6acc9b32011-05-16 18:32:07 +00001122 // If drawing a subrect of the bitmap and filtering is enabled,
1123 // use a constrained texture domain to avoid color bleeding
1124 GrScalar left, top, right, bottom;
1125 if (srcRect.width() > 1) {
1126 GrScalar border = GR_ScalarHalf / bitmap.width();
1127 left = paintRect.left() + border;
1128 right = paintRect.right() - border;
1129 } else {
1130 left = right = GrScalarHalf(paintRect.left() + paintRect.right());
1131 }
1132 if (srcRect.height() > 1) {
1133 GrScalar border = GR_ScalarHalf / bitmap.height();
1134 top = paintRect.top() + border;
1135 bottom = paintRect.bottom() - border;
1136 } else {
1137 top = bottom = GrScalarHalf(paintRect.top() + paintRect.bottom());
1138 }
1139 GrRect textureDomain;
1140 textureDomain.setLTRB(left, top, right, bottom);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001141 sampler->setTextureDomain(textureDomain);
junov@google.com6acc9b32011-05-16 18:32:07 +00001142 }
1143
bsalomon@google.comcc4dac32011-05-10 13:52:42 +00001144 fContext->drawRectToRect(*grPaint, dstRect, paintRect, &m);
reed@google.comac10a2d2010-12-22 21:39:39 +00001145}
1146
1147void SkGpuDevice::drawSprite(const SkDraw& draw, const SkBitmap& bitmap,
1148 int left, int top, const SkPaint& paint) {
1149 CHECK_SHOULD_DRAW(draw);
1150
1151 SkAutoLockPixels alp(bitmap);
1152 if (!bitmap.getTexture() && !bitmap.readyToDraw()) {
1153 return;
1154 }
1155
bsalomon@google.com5782d712011-01-21 21:03:59 +00001156 GrPaint grPaint;
Scroggod757df22011-05-16 13:11:16 +00001157 if(!this->skPaint2GrPaintNoShader(paint, true, &grPaint, false)) {
bsalomon@google.com5782d712011-01-21 21:03:59 +00001158 return;
1159 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001160
bsalomon@google.com5782d712011-01-21 21:03:59 +00001161 GrAutoMatrix avm(fContext, GrMatrix::I());
1162
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001163 GrSamplerState* sampler = grPaint.getTextureSampler(kBitmapTextureIdx);
bsalomon@google.com5782d712011-01-21 21:03:59 +00001164
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001165 GrTexture* texture;
1166 sampler->setClampNoFilter();
1167 SkAutoCachedTexture act(this, bitmap, *sampler, &texture);
1168
1169 grPaint.setTexture(kBitmapTextureIdx, texture);
bsalomon@google.com5782d712011-01-21 21:03:59 +00001170
bsalomon@google.com5782d712011-01-21 21:03:59 +00001171 fContext->drawRectToRect(grPaint,
reed@google.com20efde72011-05-09 17:00:02 +00001172 GrRect::MakeXYWH(GrIntToScalar(left),
1173 GrIntToScalar(top),
1174 GrIntToScalar(bitmap.width()),
1175 GrIntToScalar(bitmap.height())),
1176 GrRect::MakeWH(GR_Scalar1, GR_Scalar1));
reed@google.comac10a2d2010-12-22 21:39:39 +00001177}
1178
1179void SkGpuDevice::drawDevice(const SkDraw& draw, SkDevice* dev,
1180 int x, int y, const SkPaint& paint) {
1181 CHECK_SHOULD_DRAW(draw);
1182
bsalomon@google.com5782d712011-01-21 21:03:59 +00001183 GrPaint grPaint;
bsalomon@google.comc6cf7232011-02-17 16:43:10 +00001184 if (!((SkGpuDevice*)dev)->bindDeviceAsTexture(&grPaint) ||
Scroggod757df22011-05-16 13:11:16 +00001185 !this->skPaint2GrPaintNoShader(paint, true, &grPaint, false)) {
bsalomon@google.com5782d712011-01-21 21:03:59 +00001186 return;
reed@google.comac10a2d2010-12-22 21:39:39 +00001187 }
bsalomon@google.com5782d712011-01-21 21:03:59 +00001188
bsalomon@google.comb5b31682011-06-16 18:05:35 +00001189 GrTexture* devTex = grPaint.getTexture(0);
1190 SkASSERT(NULL != devTex);
bsalomon@google.com5782d712011-01-21 21:03:59 +00001191
1192 const SkBitmap& bm = dev->accessBitmap(false);
1193 int w = bm.width();
1194 int h = bm.height();
1195
1196 GrAutoMatrix avm(fContext, GrMatrix::I());
1197
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001198 grPaint.getTextureSampler(kBitmapTextureIdx)->setClampNoFilter();
bsalomon@google.com5782d712011-01-21 21:03:59 +00001199
bsalomon@google.comb5b31682011-06-16 18:05:35 +00001200 GrRect dstRect = GrRect::MakeXYWH(GrIntToScalar(x),
1201 GrIntToScalar(y),
1202 GrIntToScalar(w),
1203 GrIntToScalar(h));
1204 // The device being drawn may not fill up its texture (saveLayer uses
1205 // the approximate ).
1206 GrRect srcRect = GrRect::MakeWH(GR_Scalar1 * w / devTex->width(),
1207 GR_Scalar1 * h / devTex->height());
1208
1209 fContext->drawRectToRect(grPaint, dstRect, srcRect);
reed@google.comac10a2d2010-12-22 21:39:39 +00001210}
1211
1212///////////////////////////////////////////////////////////////////////////////
1213
1214// must be in SkCanvas::VertexMode order
bsalomon@google.comffca4002011-02-22 20:34:01 +00001215static const GrPrimitiveType gVertexMode2PrimitiveType[] = {
1216 kTriangles_PrimitiveType,
1217 kTriangleStrip_PrimitiveType,
1218 kTriangleFan_PrimitiveType,
reed@google.comac10a2d2010-12-22 21:39:39 +00001219};
1220
1221void SkGpuDevice::drawVertices(const SkDraw& draw, SkCanvas::VertexMode vmode,
1222 int vertexCount, const SkPoint vertices[],
1223 const SkPoint texs[], const SkColor colors[],
1224 SkXfermode* xmode,
1225 const uint16_t indices[], int indexCount,
1226 const SkPaint& paint) {
1227 CHECK_SHOULD_DRAW(draw);
1228
bsalomon@google.com5782d712011-01-21 21:03:59 +00001229 GrPaint grPaint;
1230 SkAutoCachedTexture act;
1231 // we ignore the shader if texs is null.
1232 if (NULL == texs) {
Scroggod757df22011-05-16 13:11:16 +00001233 if (!this->skPaint2GrPaintNoShader(paint,
1234 false,
1235 &grPaint,
1236 NULL == colors)) {
reed@google.comac10a2d2010-12-22 21:39:39 +00001237 return;
1238 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001239 } else {
reed@google.com1a2e8d22011-01-21 22:08:29 +00001240 if (!this->skPaint2GrPaintShader(paint, &act,
1241 *draw.fMatrix,
Scroggod757df22011-05-16 13:11:16 +00001242 &grPaint,
1243 NULL == colors)) {
bsalomon@google.com5782d712011-01-21 21:03:59 +00001244 return;
1245 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001246 }
bsalomon@google.com5782d712011-01-21 21:03:59 +00001247
1248 if (NULL != xmode && NULL != texs && NULL != colors) {
1249 SkXfermode::Mode mode;
1250 if (!SkXfermode::IsMode(xmode, &mode) ||
1251 SkXfermode::kMultiply_Mode != mode) {
1252 SkDebugf("Unsupported vertex-color/texture xfer mode.\n");
1253#if 0
1254 return
1255#endif
1256 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001257 }
bsalomon@google.com5782d712011-01-21 21:03:59 +00001258
1259#if SK_SCALAR_IS_GR_SCALAR
1260 // even if GrColor and SkColor byte offsets match we need
1261 // to perform pre-multiply.
1262 if (NULL == colors) {
1263 fContext->drawVertices(grPaint,
1264 gVertexMode2PrimitiveType[vmode],
1265 vertexCount,
1266 (GrPoint*) vertices,
1267 (GrPoint*) texs,
1268 NULL,
1269 indices,
1270 indexCount);
1271 } else
1272#endif
1273 {
1274 SkTexCoordSource texSrc(texs);
1275 SkColorSource colSrc(colors);
1276 SkIndexSource idxSrc(indices, indexCount);
1277
1278 fContext->drawCustomVertices(grPaint,
1279 gVertexMode2PrimitiveType[vmode],
1280 SkPositionSource(vertices, vertexCount),
1281 (NULL == texs) ? NULL : &texSrc,
1282 (NULL == colors) ? NULL : &colSrc,
1283 (NULL == indices) ? NULL : &idxSrc);
reed@google.comac10a2d2010-12-22 21:39:39 +00001284 }
1285}
1286
1287///////////////////////////////////////////////////////////////////////////////
1288
1289static void GlyphCacheAuxProc(void* data) {
1290 delete (GrFontScaler*)data;
1291}
1292
1293static GrFontScaler* get_gr_font_scaler(SkGlyphCache* cache) {
1294 void* auxData;
1295 GrFontScaler* scaler = NULL;
1296 if (cache->getAuxProcData(GlyphCacheAuxProc, &auxData)) {
1297 scaler = (GrFontScaler*)auxData;
1298 }
1299 if (NULL == scaler) {
1300 scaler = new SkGrFontScaler(cache);
1301 cache->setAuxProc(GlyphCacheAuxProc, scaler);
1302 }
1303 return scaler;
1304}
1305
1306static void SkGPU_Draw1Glyph(const SkDraw1Glyph& state,
1307 SkFixed fx, SkFixed fy,
1308 const SkGlyph& glyph) {
1309 SkASSERT(glyph.fWidth > 0 && glyph.fHeight > 0);
1310
1311 GrSkDrawProcs* procs = (GrSkDrawProcs*)state.fDraw->fProcs;
1312
1313 if (NULL == procs->fFontScaler) {
1314 procs->fFontScaler = get_gr_font_scaler(state.fCache);
1315 }
reed@google.com39ce0ac2011-04-08 15:42:19 +00001316
1317 /*
reed@google.com3b139f52011-06-07 17:56:25 +00001318 * What should we do with fy? (assuming horizontal/latin text)
reed@google.com39ce0ac2011-04-08 15:42:19 +00001319 *
reed@google.com3b139f52011-06-07 17:56:25 +00001320 * The raster code calls SkFixedFloorToFixed on it, as it does with fx.
1321 * It calls that rather than round, because our caller has already added
1322 * SK_FixedHalf, so that calling floor gives us the rounded integer.
1323 *
1324 * Test code between raster and gpu (they should draw the same)
1325 *
1326 * canvas->drawText("Hamburgefons", 12, 0, 16.5f, paint);
1327 *
1328 * Perhaps we should only perform this integralization if there is no
1329 * fExtMatrix...
reed@google.com39ce0ac2011-04-08 15:42:19 +00001330 */
reed@google.com3b139f52011-06-07 17:56:25 +00001331 fy = SkFixedFloorToFixed(fy);
1332
reed@google.comac10a2d2010-12-22 21:39:39 +00001333 procs->fTextContext->drawPackedGlyph(GrGlyph::Pack(glyph.getGlyphID(), fx, 0),
reed@google.com3b139f52011-06-07 17:56:25 +00001334 SkFixedFloorToFixed(fx), fy,
reed@google.comac10a2d2010-12-22 21:39:39 +00001335 procs->fFontScaler);
1336}
1337
bsalomon@google.com5782d712011-01-21 21:03:59 +00001338SkDrawProcs* SkGpuDevice::initDrawForText(GrTextContext* context) {
reed@google.comac10a2d2010-12-22 21:39:39 +00001339
1340 // deferred allocation
1341 if (NULL == fDrawProcs) {
1342 fDrawProcs = new GrSkDrawProcs;
1343 fDrawProcs->fD1GProc = SkGPU_Draw1Glyph;
1344 fDrawProcs->fContext = fContext;
1345 }
1346
1347 // init our (and GL's) state
1348 fDrawProcs->fTextContext = context;
1349 fDrawProcs->fFontScaler = NULL;
1350 return fDrawProcs;
1351}
1352
1353void SkGpuDevice::drawText(const SkDraw& draw, const void* text,
1354 size_t byteLength, SkScalar x, SkScalar y,
1355 const SkPaint& paint) {
1356 CHECK_SHOULD_DRAW(draw);
1357
1358 if (draw.fMatrix->getType() & SkMatrix::kPerspective_Mask) {
1359 // this guy will just call our drawPath()
1360 draw.drawText((const char*)text, byteLength, x, y, paint);
1361 } else {
reed@google.comac10a2d2010-12-22 21:39:39 +00001362 SkDraw myDraw(draw);
bsalomon@google.com5782d712011-01-21 21:03:59 +00001363
1364 GrPaint grPaint;
1365 SkAutoCachedTexture act;
1366
Scroggod757df22011-05-16 13:11:16 +00001367 if (!this->skPaint2GrPaintShader(paint,
1368 &act,
1369 *draw.fMatrix,
1370 &grPaint,
1371 true)) {
bsalomon@google.com5782d712011-01-21 21:03:59 +00001372 return;
1373 }
bsalomon@google.comcc4dac32011-05-10 13:52:42 +00001374 GrTextContext context(fContext, grPaint, draw.fExtMatrix);
bsalomon@google.com5782d712011-01-21 21:03:59 +00001375 myDraw.fProcs = this->initDrawForText(&context);
reed@google.comac10a2d2010-12-22 21:39:39 +00001376 this->INHERITED::drawText(myDraw, text, byteLength, x, y, paint);
1377 }
1378}
1379
1380void SkGpuDevice::drawPosText(const SkDraw& draw, const void* text,
1381 size_t byteLength, const SkScalar pos[],
1382 SkScalar constY, int scalarsPerPos,
1383 const SkPaint& paint) {
1384 CHECK_SHOULD_DRAW(draw);
1385
1386 if (draw.fMatrix->getType() & SkMatrix::kPerspective_Mask) {
1387 // this guy will just call our drawPath()
1388 draw.drawPosText((const char*)text, byteLength, pos, constY,
1389 scalarsPerPos, paint);
1390 } else {
reed@google.comac10a2d2010-12-22 21:39:39 +00001391 SkDraw myDraw(draw);
bsalomon@google.com5782d712011-01-21 21:03:59 +00001392
1393 GrPaint grPaint;
1394 SkAutoCachedTexture act;
Scroggod757df22011-05-16 13:11:16 +00001395 if (!this->skPaint2GrPaintShader(paint,
1396 &act,
1397 *draw.fMatrix,
1398 &grPaint,
1399 true)) {
bsalomon@google.com5782d712011-01-21 21:03:59 +00001400 return;
1401 }
1402
bsalomon@google.comcc4dac32011-05-10 13:52:42 +00001403 GrTextContext context(fContext, grPaint, draw.fExtMatrix);
bsalomon@google.com5782d712011-01-21 21:03:59 +00001404 myDraw.fProcs = this->initDrawForText(&context);
reed@google.comac10a2d2010-12-22 21:39:39 +00001405 this->INHERITED::drawPosText(myDraw, text, byteLength, pos, constY,
1406 scalarsPerPos, paint);
1407 }
1408}
1409
1410void SkGpuDevice::drawTextOnPath(const SkDraw& draw, const void* text,
1411 size_t len, const SkPath& path,
1412 const SkMatrix* m, const SkPaint& paint) {
1413 CHECK_SHOULD_DRAW(draw);
1414
1415 SkASSERT(draw.fDevice == this);
1416 draw.drawTextOnPath((const char*)text, len, path, m, paint);
1417}
1418
1419///////////////////////////////////////////////////////////////////////////////
1420
reed@google.comf67e4cf2011-03-15 20:56:58 +00001421bool SkGpuDevice::filterTextFlags(const SkPaint& paint, TextFlags* flags) {
1422 if (!paint.isLCDRenderText()) {
1423 // we're cool with the paint as is
1424 return false;
1425 }
1426
1427 if (paint.getShader() ||
1428 paint.getXfermode() || // unless its srcover
1429 paint.getMaskFilter() ||
1430 paint.getRasterizer() ||
1431 paint.getColorFilter() ||
1432 paint.getPathEffect() ||
1433 paint.isFakeBoldText() ||
1434 paint.getStyle() != SkPaint::kFill_Style) {
1435 // turn off lcd
1436 flags->fFlags = paint.getFlags() & ~SkPaint::kLCDRenderText_Flag;
1437 flags->fHinting = paint.getHinting();
1438 return true;
1439 }
1440 // we're cool with the paint as is
1441 return false;
1442}
1443
1444///////////////////////////////////////////////////////////////////////////////
1445
reed@google.comac10a2d2010-12-22 21:39:39 +00001446SkGpuDevice::TexCache* SkGpuDevice::lockCachedTexture(const SkBitmap& bitmap,
bsalomon@google.comfea37b52011-04-25 15:51:06 +00001447 const GrSamplerState& sampler,
1448 GrTexture** texture,
bsalomon@google.come97f0852011-06-17 13:10:25 +00001449 TexType type) {
bsalomon@google.comfea37b52011-04-25 15:51:06 +00001450 GrTexture* newTexture = NULL;
1451 GrTextureEntry* entry = NULL;
reed@google.comac10a2d2010-12-22 21:39:39 +00001452 GrContext* ctx = this->context();
bsalomon@google.comfea37b52011-04-25 15:51:06 +00001453
bsalomon@google.come97f0852011-06-17 13:10:25 +00001454 if (kBitmap_TexType != type) {
bsalomon@google.comfea37b52011-04-25 15:51:06 +00001455 const GrTextureDesc desc = {
1456 kRenderTarget_GrTextureFlagBit,
1457 kNone_GrAALevel,
1458 bitmap.width(),
1459 bitmap.height(),
1460 SkGr::Bitmap2PixelConfig(bitmap)
1461 };
bsalomon@google.come97f0852011-06-17 13:10:25 +00001462 if (kSaveLayerDeviceRenderTarget_TexType == type) {
bsalomon@google.comb5b31682011-06-16 18:05:35 +00001463 // we know layers will only be drawn through drawDevice.
1464 // drawDevice has been made to work with content embedded in a
1465 // larger texture so its okay to use the approximate version.
1466 entry = ctx->findApproximateKeylessTexture(desc);
1467 } else {
bsalomon@google.come97f0852011-06-17 13:10:25 +00001468 SkASSERT(kDeviceRenderTarget_TexType == type);
bsalomon@google.comb5b31682011-06-16 18:05:35 +00001469 entry = ctx->lockKeylessTexture(desc);
1470 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001471 } else {
junov@google.com4ee7ae52011-06-30 17:30:49 +00001472 if (!bitmap.isVolatile()) {
1473 uint32_t p0, p1;
1474 p0 = bitmap.getGenerationID();
1475 p1 = bitmap.pixelRefOffset();
1476 GrTextureKey key(p0, p1, bitmap.width(), bitmap.height());
1477
1478 entry = ctx->findAndLockTexture(&key, sampler);
1479 if (NULL == entry)
1480 entry = sk_gr_create_bitmap_texture(ctx, &key, sampler,
1481 bitmap);
1482 } else {
1483 entry = sk_gr_create_bitmap_texture(ctx, NULL, sampler, bitmap);
1484 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001485 if (NULL == entry) {
junov@google.com4ee7ae52011-06-30 17:30:49 +00001486 GrPrintf("---- failed to create texture for cache [%d %d]\n",
1487 bitmap.width(), bitmap.height());
reed@google.comac10a2d2010-12-22 21:39:39 +00001488 }
1489 }
1490
1491 if (NULL != entry) {
1492 newTexture = entry->texture();
reed@google.comac10a2d2010-12-22 21:39:39 +00001493 if (texture) {
1494 *texture = newTexture;
1495 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001496 }
1497 return (TexCache*)entry;
1498}
1499
1500void SkGpuDevice::unlockCachedTexture(TexCache* cache) {
1501 this->context()->unlockTexture((GrTextureEntry*)cache);
1502}
1503
bsalomon@google.come97f0852011-06-17 13:10:25 +00001504SkDevice* SkGpuDevice::onCreateCompatibleDevice(SkBitmap::Config config,
1505 int width, int height,
1506 bool isOpaque,
1507 Usage usage) {
1508 return SkNEW_ARGS(SkGpuDevice,(this->context(), config,
1509 width, height, usage));
1510}
1511