blob: ce48be63cd2ac52fd17aaa2329f44bff44e762eb [file] [log] [blame]
reed@google.comac10a2d2010-12-22 21:39:39 +00001/*
bsalomon@google.com1da07462011-03-10 14:51:57 +00002 Copyright 2011 Google Inc.
reed@google.comac10a2d2010-12-22 21:39:39 +00003
4 Licensed under the Apache License, Version 2.0 (the "License");
5 you may not use this file except in compliance with the License.
6 You may obtain a copy of the License at
7
8 http://www.apache.org/licenses/LICENSE-2.0
9
10 Unless required by applicable law or agreed to in writing, software
11 distributed under the License is distributed on an "AS IS" BASIS,
12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 See the License for the specific language governing permissions and
14 limitations under the License.
15 */
16
17
18#include "GrContext.h"
19#include "GrTextContext.h"
20
reed@google.comac10a2d2010-12-22 21:39:39 +000021#include "SkGpuDevice.h"
reed@google.com7b201d22011-01-11 18:59:23 +000022#include "SkGpuDeviceFactory.h"
reed@google.comac10a2d2010-12-22 21:39:39 +000023#include "SkGrTexturePixelRef.h"
24
25#include "SkDrawProcs.h"
26#include "SkGlyphCache.h"
27
28#define CACHE_LAYER_TEXTURES 1
29
30#if 0
31 extern bool (*gShouldDrawProc)();
32 #define CHECK_SHOULD_DRAW(draw) \
33 do { \
34 if (gShouldDrawProc && !gShouldDrawProc()) return; \
35 this->prepareRenderTarget(draw); \
36 } while (0)
37#else
38 #define CHECK_SHOULD_DRAW(draw) this->prepareRenderTarget(draw)
39#endif
40
41class SkAutoExtMatrix {
42public:
43 SkAutoExtMatrix(const SkMatrix* extMatrix) {
44 if (extMatrix) {
45 SkGr::SkMatrix2GrMatrix(*extMatrix, &fMatrix);
46 fExtMatrix = &fMatrix;
47 } else {
48 fExtMatrix = NULL;
49 }
50 }
51 const GrMatrix* extMatrix() const { return fExtMatrix; }
52
53private:
54 GrMatrix fMatrix;
55 GrMatrix* fExtMatrix; // NULL or &fMatrix
56};
57
58///////////////////////////////////////////////////////////////////////////////
59
60SkGpuDevice::SkAutoCachedTexture::
61 SkAutoCachedTexture(SkGpuDevice* device,
62 const SkBitmap& bitmap,
63 const GrSamplerState& sampler,
64 GrTexture** texture) {
65 GrAssert(texture);
66 fTex = NULL;
67 *texture = this->set(device, bitmap, sampler);
68}
69
70SkGpuDevice::SkAutoCachedTexture::SkAutoCachedTexture() {
71 fTex = NULL;
72}
73
74GrTexture* SkGpuDevice::SkAutoCachedTexture::set(SkGpuDevice* device,
75 const SkBitmap& bitmap,
76 const GrSamplerState& sampler) {
77 if (fTex) {
78 fDevice->unlockCachedTexture(fTex);
79 }
80 fDevice = device;
81 GrTexture* texture = (GrTexture*)bitmap.getTexture();
82 if (texture) {
83 // return the native texture
84 fTex = NULL;
reed@google.comac10a2d2010-12-22 21:39:39 +000085 } else {
86 // look it up in our cache
87 fTex = device->lockCachedTexture(bitmap, sampler, &texture, false);
88 }
89 return texture;
90}
91
92SkGpuDevice::SkAutoCachedTexture::~SkAutoCachedTexture() {
93 if (fTex) {
94 fDevice->unlockCachedTexture(fTex);
95 }
96}
97
98///////////////////////////////////////////////////////////////////////////////
99
100bool gDoTraceDraw;
101
102struct GrSkDrawProcs : public SkDrawProcs {
103public:
104 GrContext* fContext;
105 GrTextContext* fTextContext;
106 GrFontScaler* fFontScaler; // cached in the skia glyphcache
107};
108
109///////////////////////////////////////////////////////////////////////////////
110
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000111GrRenderTarget* SkGpuDevice::Current3DApiRenderTarget() {
112 return (GrRenderTarget*) -1;
113}
114
115SkGpuDevice::SkGpuDevice(GrContext* context,
116 const SkBitmap& bitmap,
117 GrRenderTarget* renderTargetOrNull)
118 : SkDevice(NULL, bitmap, (NULL == renderTargetOrNull)) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000119
120 fNeedPrepareRenderTarget = false;
121 fDrawProcs = NULL;
122
reed@google.com7b201d22011-01-11 18:59:23 +0000123 fContext = context;
bsalomon@google.com5782d712011-01-21 21:03:59 +0000124 fContext->ref();
reed@google.comac10a2d2010-12-22 21:39:39 +0000125
126 fCache = NULL;
127 fTexture = NULL;
128 fRenderTarget = NULL;
129 fNeedClear = false;
130
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000131 if (NULL == renderTargetOrNull) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000132 SkBitmap::Config c = bitmap.config();
133 if (c != SkBitmap::kRGB_565_Config) {
134 c = SkBitmap::kARGB_8888_Config;
135 }
136 SkBitmap bm;
137 bm.setConfig(c, this->width(), this->height());
138
139#if CACHE_LAYER_TEXTURES
140
141 fCache = this->lockCachedTexture(bm, GrSamplerState::ClampNoFilter(),
142 &fTexture, true);
143 if (fCache) {
144 SkASSERT(NULL != fTexture);
bsalomon@google.com1da07462011-03-10 14:51:57 +0000145 SkASSERT(NULL != fTexture->asRenderTarget());
reed@google.comac10a2d2010-12-22 21:39:39 +0000146 }
147#else
148 const GrGpu::TextureDesc desc = {
149 GrGpu::kRenderTarget_TextureFlag,
150 GrGpu::kNone_AALevel,
151 this->width(),
152 this->height(),
153 SkGr::Bitmap2PixelConfig(bm)
154 };
155
156 fTexture = fContext->createUncachedTexture(desc, NULL, 0);
157#endif
158 if (NULL != fTexture) {
159 fRenderTarget = fTexture->asRenderTarget();
160
161 GrAssert(NULL != fRenderTarget);
162
163 // we defer the actual clear until our gainFocus()
164 fNeedClear = true;
165
166 // wrap the bitmap with a pixelref to expose our texture
167 SkGrTexturePixelRef* pr = new SkGrTexturePixelRef(fTexture);
168 this->setPixelRef(pr, 0)->unref();
169 } else {
170 GrPrintf("--- failed to create gpu-offscreen [%d %d]\n",
171 this->width(), this->height());
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000172 GrAssert(false);
reed@google.comac10a2d2010-12-22 21:39:39 +0000173 }
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000174 } else if (Current3DApiRenderTarget() == renderTargetOrNull) {
175 fRenderTarget = fContext->createRenderTargetFrom3DApiState();
176 } else {
177 fRenderTarget = renderTargetOrNull;
reed@google.comac10a2d2010-12-22 21:39:39 +0000178 fRenderTarget->ref();
reed@google.comac10a2d2010-12-22 21:39:39 +0000179 }
180}
181
182SkGpuDevice::~SkGpuDevice() {
183 if (fDrawProcs) {
184 delete fDrawProcs;
185 }
186
187 if (fCache) {
188 GrAssert(NULL != fTexture);
189 GrAssert(fRenderTarget == fTexture->asRenderTarget());
190 // IMPORTANT: reattach the rendertarget/tex back to the cache.
191 fContext->reattachAndUnlockCachedTexture((GrTextureEntry*)fCache);
192 } else if (NULL != fTexture) {
193 GrAssert(!CACHE_LAYER_TEXTURES);
194 GrAssert(fRenderTarget == fTexture->asRenderTarget());
195 fTexture->unref();
196 } else if (NULL != fRenderTarget) {
197 fRenderTarget->unref();
198 }
bsalomon@google.com5782d712011-01-21 21:03:59 +0000199 fContext->unref();
reed@google.comac10a2d2010-12-22 21:39:39 +0000200}
201
reed@google.comac10a2d2010-12-22 21:39:39 +0000202intptr_t SkGpuDevice::getLayerTextureHandle() const {
203 if (fTexture) {
204 return fTexture->getTextureHandle();
205 } else {
206 return 0;
207 }
208}
209///////////////////////////////////////////////////////////////////////////////
210
211void SkGpuDevice::makeRenderTargetCurrent() {
212 fContext->setRenderTarget(fRenderTarget);
213 fContext->flush(true);
214 fNeedPrepareRenderTarget = true;
215}
216
217///////////////////////////////////////////////////////////////////////////////
218
219bool SkGpuDevice::readPixels(const SkIRect& srcRect, SkBitmap* bitmap) {
220 SkIRect bounds;
221 bounds.set(0, 0, this->width(), this->height());
222 if (!bounds.intersect(srcRect)) {
223 return false;
224 }
225
226 const int w = bounds.width();
227 const int h = bounds.height();
228 SkBitmap tmp;
229 // note we explicitly specify our rowBytes to be snug (no gap between rows)
230 tmp.setConfig(SkBitmap::kARGB_8888_Config, w, h, w * 4);
231 if (!tmp.allocPixels()) {
232 return false;
233 }
234
235 SkAutoLockPixels alp(tmp);
236 fContext->setRenderTarget(fRenderTarget);
237 // we aren't setting the clip or matrix, so mark as dirty
238 // we don't need to set them for this call and don't have them anyway
239 fNeedPrepareRenderTarget = true;
240
241 if (!fContext->readPixels(bounds.fLeft, bounds.fTop,
242 bounds.width(), bounds.height(),
243 GrTexture::kRGBA_8888_PixelConfig,
244 tmp.getPixels())) {
245 return false;
246 }
247
248 tmp.swap(*bitmap);
249 return true;
250}
251
252void SkGpuDevice::writePixels(const SkBitmap& bitmap, int x, int y) {
253 SkAutoLockPixels alp(bitmap);
254 if (!bitmap.readyToDraw()) {
255 return;
256 }
257 GrTexture::PixelConfig config = SkGr::BitmapConfig2PixelConfig(bitmap.config(),
258 bitmap.isOpaque());
259 fContext->setRenderTarget(fRenderTarget);
260 // we aren't setting the clip or matrix, so mark as dirty
261 // we don't need to set them for this call and don't have them anyway
262 fNeedPrepareRenderTarget = true;
263
264 fContext->writePixels(x, y, bitmap.width(), bitmap.height(),
265 config, bitmap.getPixels(), bitmap.rowBytes());
266}
267
268///////////////////////////////////////////////////////////////////////////////
269
270static void convert_matrixclip(GrContext* context, const SkMatrix& matrix,
bsalomon@google.comd302f142011-03-03 13:54:13 +0000271 const SkClipStack& clipStack,
reed@google.com6f8f2922011-03-04 22:27:10 +0000272 const SkRegion& clipRegion,
273 const SkIPoint& origin) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000274 GrMatrix grmat;
275 SkGr::SkMatrix2GrMatrix(matrix, &grmat);
bsalomon@google.com5782d712011-01-21 21:03:59 +0000276 context->setMatrix(grmat);
reed@google.comac10a2d2010-12-22 21:39:39 +0000277
278 SkGrClipIterator iter;
bsalomon@google.comd302f142011-03-03 13:54:13 +0000279 iter.reset(clipStack);
bsalomon@google.comd302f142011-03-03 13:54:13 +0000280 const SkIRect& skBounds = clipRegion.getBounds();
281 GrRect bounds;
282 bounds.setLTRB(GrIntToScalar(skBounds.fLeft),
283 GrIntToScalar(skBounds.fTop),
284 GrIntToScalar(skBounds.fRight),
285 GrIntToScalar(skBounds.fBottom));
reed@google.com6f8f2922011-03-04 22:27:10 +0000286 GrClip grc(&iter, GrIntToScalar(-origin.x()), GrIntToScalar(-origin.y()),
287 &bounds);
bsalomon@google.comd302f142011-03-03 13:54:13 +0000288 context->setClip(grc);
reed@google.comac10a2d2010-12-22 21:39:39 +0000289}
290
291// call this ever each draw call, to ensure that the context reflects our state,
292// and not the state from some other canvas/device
293void SkGpuDevice::prepareRenderTarget(const SkDraw& draw) {
294 if (fNeedPrepareRenderTarget ||
bsalomon@google.com5782d712011-01-21 21:03:59 +0000295 fContext->getRenderTarget() != fRenderTarget) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000296
297 fContext->setRenderTarget(fRenderTarget);
bsalomon@google.comd302f142011-03-03 13:54:13 +0000298 SkASSERT(draw.fClipStack);
299 convert_matrixclip(fContext, *draw.fMatrix,
reed@google.com6f8f2922011-03-04 22:27:10 +0000300 *draw.fClipStack, *draw.fClip, this->getOrigin());
reed@google.comac10a2d2010-12-22 21:39:39 +0000301 fNeedPrepareRenderTarget = false;
302 }
303}
304
reed@google.com46799cd2011-02-22 20:56:26 +0000305void SkGpuDevice::setMatrixClip(const SkMatrix& matrix, const SkRegion& clip,
306 const SkClipStack& clipStack) {
307 this->INHERITED::setMatrixClip(matrix, clip, clipStack);
reed@google.comac10a2d2010-12-22 21:39:39 +0000308
reed@google.com6f8f2922011-03-04 22:27:10 +0000309 convert_matrixclip(fContext, matrix, clipStack, clip, this->getOrigin());
reed@google.comac10a2d2010-12-22 21:39:39 +0000310}
311
312void SkGpuDevice::gainFocus(SkCanvas* canvas, const SkMatrix& matrix,
bsalomon@google.comd302f142011-03-03 13:54:13 +0000313 const SkRegion& clip, const SkClipStack& clipStack) {
314
reed@google.comac10a2d2010-12-22 21:39:39 +0000315 fContext->setRenderTarget(fRenderTarget);
316
bsalomon@google.comd302f142011-03-03 13:54:13 +0000317 this->INHERITED::gainFocus(canvas, matrix, clip, clipStack);
reed@google.comac10a2d2010-12-22 21:39:39 +0000318
reed@google.com6f8f2922011-03-04 22:27:10 +0000319 convert_matrixclip(fContext, matrix, clipStack, clip, this->getOrigin());
reed@google.comac10a2d2010-12-22 21:39:39 +0000320
321 if (fNeedClear) {
322 fContext->eraseColor(0x0);
323 fNeedClear = false;
324 }
325}
326
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000327bool SkGpuDevice::bindDeviceAsTexture(GrPaint* paint) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000328 if (NULL != fTexture) {
bsalomon@google.com5782d712011-01-21 21:03:59 +0000329 paint->setTexture(fTexture);
reed@google.comac10a2d2010-12-22 21:39:39 +0000330 return true;
331 }
332 return false;
333}
334
335///////////////////////////////////////////////////////////////////////////////
336
vandebo@chromium.orgd3ae7792011-02-24 00:21:06 +0000337SK_COMPILE_ASSERT(SkShader::kNone_BitmapType == 0, shader_type_mismatch);
338SK_COMPILE_ASSERT(SkShader::kDefault_BitmapType == 1, shader_type_mismatch);
339SK_COMPILE_ASSERT(SkShader::kRadial_BitmapType == 2, shader_type_mismatch);
340SK_COMPILE_ASSERT(SkShader::kSweep_BitmapType == 3, shader_type_mismatch);
341SK_COMPILE_ASSERT(SkShader::kTwoPointRadial_BitmapType == 4,
342 shader_type_mismatch);
343SK_COMPILE_ASSERT(SkShader::kLast_BitmapType == 4, shader_type_mismatch);
reed@google.comac10a2d2010-12-22 21:39:39 +0000344
bsalomon@google.com5782d712011-01-21 21:03:59 +0000345static const GrSamplerState::SampleMode sk_bmp_type_to_sample_mode[] = {
346 (GrSamplerState::SampleMode) -1, // kNone_BitmapType
347 GrSamplerState::kNormal_SampleMode, // kDefault_BitmapType
348 GrSamplerState::kRadial_SampleMode, // kRadial_BitmapType
349 GrSamplerState::kSweep_SampleMode, // kSweep_BitmapType
350 GrSamplerState::kRadial2_SampleMode, // kTwoPointRadial_BitmapType
351};
352
353bool SkGpuDevice::skPaint2GrPaintNoShader(const SkPaint& skPaint,
354 bool justAlpha,
355 GrPaint* grPaint) {
356
357 grPaint->fDither = skPaint.isDither();
358 grPaint->fAntiAlias = skPaint.isAntiAlias();
359
360 SkXfermode::Coeff sm = SkXfermode::kOne_Coeff;
361 SkXfermode::Coeff dm = SkXfermode::kISA_Coeff;
362
363 SkXfermode* mode = skPaint.getXfermode();
364 if (mode) {
365 if (!mode->asCoeff(&sm, &dm)) {
reed@google.com1a2e8d22011-01-21 22:08:29 +0000366 SkDEBUGCODE(SkDebugf("Unsupported xfer mode.\n");)
bsalomon@google.com5782d712011-01-21 21:03:59 +0000367#if 0
368 return false;
369#endif
370 }
371 }
372 grPaint->fSrcBlendCoeff = sk_blend_to_grblend(sm);
373 grPaint->fDstBlendCoeff = sk_blend_to_grblend(dm);
374
375 if (justAlpha) {
376 uint8_t alpha = skPaint.getAlpha();
377 grPaint->fColor = GrColorPackRGBA(alpha, alpha, alpha, alpha);
378 } else {
379 grPaint->fColor = SkGr::SkColor2GrColor(skPaint.getColor());
380 grPaint->setTexture(NULL);
381 }
382 return true;
reed@google.comac10a2d2010-12-22 21:39:39 +0000383}
384
bsalomon@google.com5782d712011-01-21 21:03:59 +0000385bool SkGpuDevice::skPaint2GrPaintShader(const SkPaint& skPaint,
386 SkAutoCachedTexture* act,
387 const SkMatrix& ctm,
388 GrPaint* grPaint) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000389
bsalomon@google.com5782d712011-01-21 21:03:59 +0000390 SkASSERT(NULL != act);
reed@google.comac10a2d2010-12-22 21:39:39 +0000391
bsalomon@google.com5782d712011-01-21 21:03:59 +0000392 SkShader* shader = skPaint.getShader();
reed@google.comac10a2d2010-12-22 21:39:39 +0000393 if (NULL == shader) {
bsalomon@google.com5782d712011-01-21 21:03:59 +0000394 return this->skPaint2GrPaintNoShader(skPaint, false, grPaint);
395 grPaint->setTexture(NULL);
396 return true;
397 } else if (!this->skPaint2GrPaintNoShader(skPaint, true, grPaint)) {
398 return false;
reed@google.comac10a2d2010-12-22 21:39:39 +0000399 }
400
bsalomon@google.com5782d712011-01-21 21:03:59 +0000401 SkPaint noAlphaPaint(skPaint);
402 noAlphaPaint.setAlpha(255);
403 shader->setContext(this->accessBitmap(false), noAlphaPaint, ctm);
reed@google.comac10a2d2010-12-22 21:39:39 +0000404
reed@google.comac10a2d2010-12-22 21:39:39 +0000405 SkBitmap bitmap;
406 SkMatrix matrix;
407 SkShader::TileMode tileModes[2];
408 SkScalar twoPointParams[3];
409 SkShader::BitmapType bmptype = shader->asABitmap(&bitmap, &matrix,
410 tileModes, twoPointParams);
411
bsalomon@google.com5782d712011-01-21 21:03:59 +0000412 GrSamplerState::SampleMode sampleMode = sk_bmp_type_to_sample_mode[bmptype];
413 if (-1 == sampleMode) {
414 SkDebugf("shader->asABitmap() == kNone_BitmapType\n");
415 return false;
reed@google.comac10a2d2010-12-22 21:39:39 +0000416 }
bsalomon@google.com5782d712011-01-21 21:03:59 +0000417 grPaint->fSampler.setSampleMode(sampleMode);
bsalomon@google.com0748f212011-02-01 22:56:16 +0000418 grPaint->fSampler.setFilter(skPaint.isFilterBitmap());
bsalomon@google.com5782d712011-01-21 21:03:59 +0000419 grPaint->fSampler.setWrapX(sk_tile_mode_to_grwrap(tileModes[0]));
420 grPaint->fSampler.setWrapY(sk_tile_mode_to_grwrap(tileModes[1]));
reed@google.comac10a2d2010-12-22 21:39:39 +0000421 if (GrSamplerState::kRadial2_SampleMode == sampleMode) {
bsalomon@google.com5782d712011-01-21 21:03:59 +0000422 grPaint->fSampler.setRadial2Params(twoPointParams[0],
423 twoPointParams[1],
424 twoPointParams[2] < 0);
reed@google.comac10a2d2010-12-22 21:39:39 +0000425 }
426
bsalomon@google.com5782d712011-01-21 21:03:59 +0000427 GrTexture* texture = act->set(this, bitmap, grPaint->fSampler);
reed@google.comac10a2d2010-12-22 21:39:39 +0000428 if (NULL == texture) {
bsalomon@google.com5782d712011-01-21 21:03:59 +0000429 SkDebugf("Couldn't convert bitmap to texture.\n");
430 return false;
reed@google.comac10a2d2010-12-22 21:39:39 +0000431 }
bsalomon@google.com5782d712011-01-21 21:03:59 +0000432 grPaint->setTexture(texture);
reed@google.comac10a2d2010-12-22 21:39:39 +0000433
434 // since our texture coords will be in local space, we wack the texture
435 // matrix to map them back into 0...1 before we load it
436 SkMatrix localM;
437 if (shader->getLocalMatrix(&localM)) {
438 SkMatrix inverse;
439 if (localM.invert(&inverse)) {
440 matrix.preConcat(inverse);
441 }
442 }
443 if (SkShader::kDefault_BitmapType == bmptype) {
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000444 GrScalar sx = GrFixedToScalar(GR_Fixed1 / bitmap.width());
445 GrScalar sy = GrFixedToScalar(GR_Fixed1 / bitmap.height());
reed@google.comac10a2d2010-12-22 21:39:39 +0000446 matrix.postScale(sx, sy);
reed@google.comac10a2d2010-12-22 21:39:39 +0000447 } else if (SkShader::kRadial_BitmapType == bmptype) {
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000448 GrScalar s = GrFixedToScalar(GR_Fixed1 / bitmap.width());
reed@google.comac10a2d2010-12-22 21:39:39 +0000449 matrix.postScale(s, s);
450 }
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000451 GrMatrix grMat;
452 SkGr::SkMatrix2GrMatrix(matrix, &grMat);
453 grPaint->fSampler.setMatrix(grMat);
bsalomon@google.com5782d712011-01-21 21:03:59 +0000454
455 return true;
reed@google.comac10a2d2010-12-22 21:39:39 +0000456}
457
458///////////////////////////////////////////////////////////////////////////////
bsalomon@google.com5782d712011-01-21 21:03:59 +0000459
460class SkPositionSource {
461public:
462 SkPositionSource(const SkPoint* points, int count)
463 : fPoints(points), fCount(count) {}
464
465 int count() const { return fCount; }
466
467 void writeValue(int i, GrPoint* dstPosition) const {
468 SkASSERT(i < fCount);
469 dstPosition->fX = SkScalarToGrScalar(fPoints[i].fX);
470 dstPosition->fY = SkScalarToGrScalar(fPoints[i].fY);
471 }
472private:
bsalomon@google.com5782d712011-01-21 21:03:59 +0000473 const SkPoint* fPoints;
bsalomon@google.com19628322011-02-03 21:30:17 +0000474 int fCount;
bsalomon@google.com5782d712011-01-21 21:03:59 +0000475};
476
477class SkTexCoordSource {
478public:
479 SkTexCoordSource(const SkPoint* coords)
480 : fCoords(coords) {}
481
482 void writeValue(int i, GrPoint* dstCoord) const {
483 dstCoord->fX = SkScalarToGrScalar(fCoords[i].fX);
484 dstCoord->fY = SkScalarToGrScalar(fCoords[i].fY);
485 }
486private:
487 const SkPoint* fCoords;
488};
489
490class SkColorSource {
491public:
492 SkColorSource(const SkColor* colors) : fColors(colors) {}
493
494 void writeValue(int i, GrColor* dstColor) const {
495 *dstColor = SkGr::SkColor2GrColor(fColors[i]);
496 }
497private:
498 const SkColor* fColors;
499};
500
501class SkIndexSource {
502public:
503 SkIndexSource(const uint16_t* indices, int count)
504 : fIndices(indices), fCount(count) {
505 }
506
507 int count() const { return fCount; }
508
509 void writeValue(int i, uint16_t* dstIndex) const {
510 *dstIndex = fIndices[i];
511 }
512
513private:
bsalomon@google.com5782d712011-01-21 21:03:59 +0000514 const uint16_t* fIndices;
bsalomon@google.com19628322011-02-03 21:30:17 +0000515 int fCount;
bsalomon@google.com5782d712011-01-21 21:03:59 +0000516};
517
518///////////////////////////////////////////////////////////////////////////////
519
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000520#if 0 // not currently being used so don't compile,
521
bsalomon@google.com5782d712011-01-21 21:03:59 +0000522// can be used for positions or texture coordinates
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000523
bsalomon@google.com5782d712011-01-21 21:03:59 +0000524class SkRectFanSource {
525public:
526 SkRectFanSource(const SkRect& rect) : fRect(rect) {}
527
528 int count() const { return 4; }
529
530 void writeValue(int i, GrPoint* dstPoint) const {
531 SkASSERT(i < 4);
532 dstPoint->fX = SkScalarToGrScalar((i % 3) ? fRect.fRight :
533 fRect.fLeft);
534 dstPoint->fY = SkScalarToGrScalar((i < 2) ? fRect.fTop :
535 fRect.fBottom);
536 }
537private:
538 const SkRect& fRect;
539};
540
541class SkIRectFanSource {
542public:
543 SkIRectFanSource(const SkIRect& rect) : fRect(rect) {}
544
545 int count() const { return 4; }
546
547 void writeValue(int i, GrPoint* dstPoint) const {
548 SkASSERT(i < 4);
549 dstPoint->fX = (i % 3) ? GrIntToScalar(fRect.fRight) :
550 GrIntToScalar(fRect.fLeft);
551 dstPoint->fY = (i < 2) ? GrIntToScalar(fRect.fTop) :
552 GrIntToScalar(fRect.fBottom);
553 }
554private:
555 const SkIRect& fRect;
556};
557
558class SkMatRectFanSource {
559public:
560 SkMatRectFanSource(const SkRect& rect, const SkMatrix& matrix)
561 : fRect(rect), fMatrix(matrix) {}
562
563 int count() const { return 4; }
564
565 void writeValue(int i, GrPoint* dstPoint) const {
566 SkASSERT(i < 4);
567
568#if SK_SCALAR_IS_GR_SCALAR
569 fMatrix.mapXY((i % 3) ? fRect.fRight : fRect.fLeft,
570 (i < 2) ? fRect.fTop : fRect.fBottom,
571 (SkPoint*)dstPoint);
572#else
573 SkPoint dst;
574 fMatrix.mapXY((i % 3) ? fRect.fRight : fRect.fLeft,
575 (i < 2) ? fRect.fTop : fRect.fBottom,
576 &dst);
577 dstPoint->fX = SkScalarToGrScalar(dst.fX);
578 dstPoint->fY = SkScalarToGrScalar(dst.fY);
579#endif
580 }
581private:
582 const SkRect& fRect;
583 const SkMatrix& fMatrix;
584};
585
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000586#endif
587
reed@google.comac10a2d2010-12-22 21:39:39 +0000588///////////////////////////////////////////////////////////////////////////////
589
590void SkGpuDevice::drawPaint(const SkDraw& draw, const SkPaint& paint) {
591 CHECK_SHOULD_DRAW(draw);
592
bsalomon@google.com5782d712011-01-21 21:03:59 +0000593 GrPaint grPaint;
594 SkAutoCachedTexture act;
595 if (!this->skPaint2GrPaintShader(paint, &act, *draw.fMatrix, &grPaint)) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000596 return;
597 }
bsalomon@google.com5782d712011-01-21 21:03:59 +0000598
599 fContext->drawPaint(grPaint);
reed@google.comac10a2d2010-12-22 21:39:39 +0000600}
601
602// must be in SkCanvas::PointMode order
bsalomon@google.comffca4002011-02-22 20:34:01 +0000603static const GrPrimitiveType gPointMode2PrimtiveType[] = {
604 kPoints_PrimitiveType,
605 kLines_PrimitiveType,
606 kLineStrip_PrimitiveType
reed@google.comac10a2d2010-12-22 21:39:39 +0000607};
608
609void SkGpuDevice::drawPoints(const SkDraw& draw, SkCanvas::PointMode mode,
bsalomon@google.com5782d712011-01-21 21:03:59 +0000610 size_t count, const SkPoint pts[], const SkPaint& paint) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000611 CHECK_SHOULD_DRAW(draw);
612
613 SkScalar width = paint.getStrokeWidth();
614 if (width < 0) {
615 return;
616 }
617
618 // we only handle hairlines here, else we let the SkDraw call our drawPath()
619 if (width > 0) {
620 draw.drawPoints(mode, count, pts, paint, true);
621 return;
622 }
623
bsalomon@google.com5782d712011-01-21 21:03:59 +0000624 GrPaint grPaint;
625 SkAutoCachedTexture act;
626 if (!this->skPaint2GrPaintShader(paint, &act, *draw.fMatrix, &grPaint)) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000627 return;
628 }
629
reed@google.comac10a2d2010-12-22 21:39:39 +0000630#if SK_SCALAR_IS_GR_SCALAR
bsalomon@google.com5782d712011-01-21 21:03:59 +0000631 fContext->drawVertices(grPaint,
632 gPointMode2PrimtiveType[mode],
633 count,
634 (GrPoint*)pts,
635 NULL,
636 NULL,
637 NULL,
638 0);
reed@google.comac10a2d2010-12-22 21:39:39 +0000639#else
bsalomon@google.com5782d712011-01-21 21:03:59 +0000640 fContext->drawCustomVertices(grPaint,
641 gPointMode2PrimtiveType[mode],
642 SkPositionSource(pts, count));
reed@google.comac10a2d2010-12-22 21:39:39 +0000643#endif
reed@google.comac10a2d2010-12-22 21:39:39 +0000644}
645
646void SkGpuDevice::drawRect(const SkDraw& draw, const SkRect& rect,
647 const SkPaint& paint) {
648 CHECK_SHOULD_DRAW(draw);
649
reed@google.com62ab7ad2011-04-05 14:08:25 +0000650 const SkMatrix& matrix = *draw.fMatrix;
651 SkPoint strokeSize;
652 SkDraw::RectType type = SkDraw::ComputeRectType(paint, matrix, &strokeSize);
reed@google.comac10a2d2010-12-22 21:39:39 +0000653
reed@google.com62ab7ad2011-04-05 14:08:25 +0000654 if (SkDraw::kPath_RectType == type) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000655 SkPath path;
656 path.addRect(rect);
657 this->drawPath(draw, path, paint, NULL, true);
reed@google.com62ab7ad2011-04-05 14:08:25 +0000658 } else {
659 GrPaint grPaint;
660 SkAutoCachedTexture act;
661 if (!this->skPaint2GrPaintShader(paint, &act, matrix, &grPaint)) {
662 return;
663 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000664
reed@google.com62ab7ad2011-04-05 14:08:25 +0000665 SkScalar width = paint.getStrokeWidth();
666 if (SkDraw::kFill_RectType == type) {
667 width = -1;
668 }
669 fContext->drawRect(grPaint, Sk2Gr(rect), width);
reed@google.comac10a2d2010-12-22 21:39:39 +0000670 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000671}
672
reed@google.com69302852011-02-16 18:08:07 +0000673#include "SkMaskFilter.h"
674#include "SkBounder.h"
675
reed@google.com69302852011-02-16 18:08:07 +0000676static bool drawWithMaskFilter(GrContext* context, const SkPath& path,
677 SkMaskFilter* filter, const SkMatrix& matrix,
678 const SkRegion& clip, SkBounder* bounder,
679 GrPaint* grp) {
680 SkMask srcM, dstM;
681
682 if (!SkDraw::DrawToMask(path, &clip.getBounds(), filter, &matrix, &srcM,
683 SkMask::kComputeBoundsAndRenderImage_CreateMode)) {
684 return false;
685 }
686
687 SkAutoMaskImage autoSrc(&srcM, false);
688
689 if (!filter->filterMask(&dstM, srcM, matrix, NULL)) {
690 return false;
691 }
692 // this will free-up dstM when we're done (allocated in filterMask())
693 SkAutoMaskImage autoDst(&dstM, false);
694
695 if (clip.quickReject(dstM.fBounds)) {
696 return false;
697 }
698 if (bounder && !bounder->doIRect(dstM.fBounds)) {
699 return false;
700 }
701
702 // we now have a device-aligned 8bit mask in dstM, ready to be drawn using
703 // the current clip (and identity matrix) and grpaint settings
704
reed@google.com0c219b62011-02-16 21:31:18 +0000705 GrAutoMatrix avm(context, GrMatrix::I());
reed@google.com69302852011-02-16 18:08:07 +0000706
707 const GrGpu::TextureDesc desc = {
708 0,
709 GrGpu::kNone_AALevel,
710 dstM.fBounds.width(),
711 dstM.fBounds.height(),
712 GrTexture::kAlpha_8_PixelConfig
713 };
714
715 GrTexture* texture = context->createUncachedTexture(desc, dstM.fImage,
716 dstM.fRowBytes);
717 if (NULL == texture) {
718 return false;
719 }
720
reed@google.com0c219b62011-02-16 21:31:18 +0000721 grp->setTexture(texture);
722 texture->unref();
723 grp->fSampler.setClampNoFilter();
reed@google.com69302852011-02-16 18:08:07 +0000724
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000725 GrRect d;
726 d.setLTRB(GrIntToScalar(dstM.fBounds.fLeft),
reed@google.com0c219b62011-02-16 21:31:18 +0000727 GrIntToScalar(dstM.fBounds.fTop),
728 GrIntToScalar(dstM.fBounds.fRight),
729 GrIntToScalar(dstM.fBounds.fBottom));
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000730 GrRect s;
731 s.setLTRB(0, 0, GR_Scalar1, GR_Scalar1);
732 context->drawRectToRect(*grp, d, s);
reed@google.com69302852011-02-16 18:08:07 +0000733 return true;
734}
reed@google.com69302852011-02-16 18:08:07 +0000735
reed@google.com0c219b62011-02-16 21:31:18 +0000736void SkGpuDevice::drawPath(const SkDraw& draw, const SkPath& origSrcPath,
reed@google.comac10a2d2010-12-22 21:39:39 +0000737 const SkPaint& paint, const SkMatrix* prePathMatrix,
738 bool pathIsMutable) {
739 CHECK_SHOULD_DRAW(draw);
740
bsalomon@google.com5782d712011-01-21 21:03:59 +0000741 GrPaint grPaint;
742 SkAutoCachedTexture act;
743 if (!this->skPaint2GrPaintShader(paint, &act, *draw.fMatrix, &grPaint)) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000744 return;
745 }
746
reed@google.com0c219b62011-02-16 21:31:18 +0000747 // BEGIN lift from SkDraw::drawPath()
748
749 SkPath* pathPtr = const_cast<SkPath*>(&origSrcPath);
750 bool doFill = true;
751 SkPath tmpPath;
reed@google.comac10a2d2010-12-22 21:39:39 +0000752
753 if (prePathMatrix) {
reed@google.come3445642011-02-16 23:20:39 +0000754 SkPath* result = pathPtr;
reed@google.com0c219b62011-02-16 21:31:18 +0000755
reed@google.come3445642011-02-16 23:20:39 +0000756 if (!pathIsMutable) {
757 result = &tmpPath;
758 pathIsMutable = true;
reed@google.comac10a2d2010-12-22 21:39:39 +0000759 }
reed@google.come3445642011-02-16 23:20:39 +0000760 // should I push prePathMatrix on our MV stack temporarily, instead
761 // of applying it here? See SkDraw.cpp
762 pathPtr->transform(*prePathMatrix, result);
763 pathPtr = result;
reed@google.comac10a2d2010-12-22 21:39:39 +0000764 }
reed@google.com0c219b62011-02-16 21:31:18 +0000765 // at this point we're done with prePathMatrix
766 SkDEBUGCODE(prePathMatrix = (const SkMatrix*)0x50FF8001;)
reed@google.comac10a2d2010-12-22 21:39:39 +0000767
bsalomon@google.com04de7822011-03-25 18:04:43 +0000768 // This "if" is not part of the SkDraw::drawPath() lift.
769 // When we get a 1.0 wide stroke we hairline stroke it instead of creating
770 // a new stroked-path. This is motivated by canvas2D sites that draw
771 // lines as 1.0 wide stroked paths. We can consider doing an alpha-modulated-
772 // hairline for width < 1.0 when AA is enabled.
773 static const int gMatrixMask = ~(SkMatrix::kIdentity_Mask |
774 SkMatrix::kTranslate_Mask);
775 if (!paint.getPathEffect() &&
776 SkPaint::kStroke_Style == paint.getStyle() &&
777 !(draw.fMatrix->getType() & gMatrixMask) &&
778 SK_Scalar1 == paint.getStrokeWidth()) {
779 doFill = false;
780 }
781
782 if (doFill && (paint.getPathEffect() ||
783 paint.getStyle() != SkPaint::kFill_Style)) {
reed@google.com0c219b62011-02-16 21:31:18 +0000784 doFill = paint.getFillPath(*pathPtr, &tmpPath);
785 pathPtr = &tmpPath;
786 }
787
788 // END lift from SkDraw::drawPath()
789
reed@google.com69302852011-02-16 18:08:07 +0000790 if (paint.getMaskFilter()) {
reed@google.com0c219b62011-02-16 21:31:18 +0000791 // avoid possibly allocating a new path in transform if we can
792 SkPath* devPathPtr = pathIsMutable ? pathPtr : &tmpPath;
793
794 // transform the path into device space
reed@google.come3445642011-02-16 23:20:39 +0000795 pathPtr->transform(*draw.fMatrix, devPathPtr);
reed@google.com0c219b62011-02-16 21:31:18 +0000796
797 drawWithMaskFilter(fContext, *devPathPtr, paint.getMaskFilter(),
reed@google.com69302852011-02-16 18:08:07 +0000798 *draw.fMatrix, *draw.fClip, draw.fBounder, &grPaint);
799 return;
800 }
reed@google.com69302852011-02-16 18:08:07 +0000801
bsalomon@google.comffca4002011-02-22 20:34:01 +0000802 GrPathFill fill = kHairLine_PathFill;
reed@google.comac10a2d2010-12-22 21:39:39 +0000803
reed@google.com0c219b62011-02-16 21:31:18 +0000804 if (doFill) {
805 switch (pathPtr->getFillType()) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000806 case SkPath::kWinding_FillType:
bsalomon@google.comffca4002011-02-22 20:34:01 +0000807 fill = kWinding_PathFill;
reed@google.comac10a2d2010-12-22 21:39:39 +0000808 break;
809 case SkPath::kEvenOdd_FillType:
bsalomon@google.comffca4002011-02-22 20:34:01 +0000810 fill = kEvenOdd_PathFill;
reed@google.comac10a2d2010-12-22 21:39:39 +0000811 break;
812 case SkPath::kInverseWinding_FillType:
bsalomon@google.comffca4002011-02-22 20:34:01 +0000813 fill = kInverseWinding_PathFill;
reed@google.comac10a2d2010-12-22 21:39:39 +0000814 break;
815 case SkPath::kInverseEvenOdd_FillType:
bsalomon@google.comffca4002011-02-22 20:34:01 +0000816 fill = kInverseEvenOdd_PathFill;
reed@google.comac10a2d2010-12-22 21:39:39 +0000817 break;
818 default:
bsalomon@google.com5782d712011-01-21 21:03:59 +0000819 SkDebugf("Unsupported path fill type\n");
reed@google.comac10a2d2010-12-22 21:39:39 +0000820 return;
821 }
822 }
823
reed@google.com0c219b62011-02-16 21:31:18 +0000824 SkGrPathIter iter(*pathPtr);
bsalomon@google.com5782d712011-01-21 21:03:59 +0000825 fContext->drawPath(grPaint, &iter, fill);
reed@google.comac10a2d2010-12-22 21:39:39 +0000826}
827
reed@google.comac10a2d2010-12-22 21:39:39 +0000828void SkGpuDevice::drawBitmap(const SkDraw& draw,
829 const SkBitmap& bitmap,
830 const SkIRect* srcRectPtr,
831 const SkMatrix& m,
832 const SkPaint& paint) {
833 CHECK_SHOULD_DRAW(draw);
834
835 SkIRect srcRect;
836 if (NULL == srcRectPtr) {
837 srcRect.set(0, 0, bitmap.width(), bitmap.height());
838 } else {
839 srcRect = *srcRectPtr;
840 }
841
bsalomon@google.com5782d712011-01-21 21:03:59 +0000842 GrPaint grPaint;
843 if (!this->skPaint2GrPaintNoShader(paint, true, &grPaint)) {
844 return;
845 }
846 grPaint.fSampler.setFilter(paint.isFilterBitmap());
847
reed@google.com02a7e6c2011-01-28 21:21:49 +0000848 const int maxTextureDim = fContext->getMaxTextureDimension();
849 if (bitmap.getTexture() || (bitmap.width() <= maxTextureDim &&
850 bitmap.height() <= maxTextureDim)) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000851 // take the fast case
bsalomon@google.com5782d712011-01-21 21:03:59 +0000852 this->internalDrawBitmap(draw, bitmap, srcRect, m, &grPaint);
reed@google.comac10a2d2010-12-22 21:39:39 +0000853 return;
854 }
855
856 // undo the translate done by SkCanvas
857 int DX = SkMax32(0, srcRect.fLeft);
858 int DY = SkMax32(0, srcRect.fTop);
859 // compute clip bounds in local coordinates
860 SkIRect clipRect;
861 {
862 SkRect r;
863 r.set(draw.fClip->getBounds());
864 SkMatrix matrix, inverse;
865 matrix.setConcat(*draw.fMatrix, m);
866 if (!matrix.invert(&inverse)) {
867 return;
868 }
869 inverse.mapRect(&r);
870 r.roundOut(&clipRect);
871 // apply the canvas' translate to our local clip
872 clipRect.offset(DX, DY);
873 }
874
reed@google.com02a7e6c2011-01-28 21:21:49 +0000875 int nx = bitmap.width() / maxTextureDim;
876 int ny = bitmap.height() / maxTextureDim;
reed@google.comac10a2d2010-12-22 21:39:39 +0000877 for (int x = 0; x <= nx; x++) {
878 for (int y = 0; y <= ny; y++) {
879 SkIRect tileR;
reed@google.com02a7e6c2011-01-28 21:21:49 +0000880 tileR.set(x * maxTextureDim, y * maxTextureDim,
881 (x + 1) * maxTextureDim, (y + 1) * maxTextureDim);
reed@google.comac10a2d2010-12-22 21:39:39 +0000882 if (!SkIRect::Intersects(tileR, clipRect)) {
883 continue;
884 }
885
886 SkIRect srcR = tileR;
887 if (!srcR.intersect(srcRect)) {
888 continue;
889 }
890
891 SkBitmap tmpB;
892 if (bitmap.extractSubset(&tmpB, tileR)) {
893 // now offset it to make it "local" to our tmp bitmap
894 srcR.offset(-tileR.fLeft, -tileR.fTop);
895
896 SkMatrix tmpM(m);
897 {
898 int dx = tileR.fLeft - DX + SkMax32(0, srcR.fLeft);
899 int dy = tileR.fTop - DY + SkMax32(0, srcR.fTop);
900 tmpM.preTranslate(SkIntToScalar(dx), SkIntToScalar(dy));
901 }
bsalomon@google.com5782d712011-01-21 21:03:59 +0000902 this->internalDrawBitmap(draw, tmpB, srcR, tmpM, &grPaint);
reed@google.comac10a2d2010-12-22 21:39:39 +0000903 }
904 }
905 }
906}
907
908/*
909 * This is called by drawBitmap(), which has to handle images that may be too
910 * large to be represented by a single texture.
911 *
bsalomon@google.com5782d712011-01-21 21:03:59 +0000912 * internalDrawBitmap assumes that the specified bitmap will fit in a texture
913 * and that non-texture portion of the GrPaint has already been setup.
reed@google.comac10a2d2010-12-22 21:39:39 +0000914 */
915void SkGpuDevice::internalDrawBitmap(const SkDraw& draw,
916 const SkBitmap& bitmap,
917 const SkIRect& srcRect,
918 const SkMatrix& m,
bsalomon@google.com5782d712011-01-21 21:03:59 +0000919 GrPaint* grPaint) {
reed@google.com02a7e6c2011-01-28 21:21:49 +0000920 SkASSERT(bitmap.width() <= fContext->getMaxTextureDimension() &&
921 bitmap.height() <= fContext->getMaxTextureDimension());
reed@google.comac10a2d2010-12-22 21:39:39 +0000922
923 SkAutoLockPixels alp(bitmap);
924 if (!bitmap.getTexture() && !bitmap.readyToDraw()) {
925 return;
926 }
927
bsalomon@google.com5782d712011-01-21 21:03:59 +0000928 grPaint->fSampler.setWrapX(GrSamplerState::kClamp_WrapMode);
929 grPaint->fSampler.setWrapY(GrSamplerState::kClamp_WrapMode);
930 grPaint->fSampler.setSampleMode(GrSamplerState::kNormal_SampleMode);
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000931 grPaint->fSampler.setMatrix(GrMatrix::I());
reed@google.comac10a2d2010-12-22 21:39:39 +0000932
933 GrTexture* texture;
bsalomon@google.com5782d712011-01-21 21:03:59 +0000934 SkAutoCachedTexture act(this, bitmap, grPaint->fSampler, &texture);
reed@google.comac10a2d2010-12-22 21:39:39 +0000935 if (NULL == texture) {
936 return;
937 }
938
bsalomon@google.com5782d712011-01-21 21:03:59 +0000939 grPaint->setTexture(texture);
reed@google.com46799cd2011-02-22 20:56:26 +0000940
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000941 GrRect dstRect(0, 0, GrIntToScalar(srcRect.width()), GrIntToScalar(srcRect.height()));
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000942 GrRect paintRect;
943 paintRect.setLTRB(GrFixedToScalar((srcRect.fLeft << 16) / bitmap.width()),
944 GrFixedToScalar((srcRect.fTop << 16) / bitmap.height()),
945 GrFixedToScalar((srcRect.fRight << 16) / bitmap.width()),
946 GrFixedToScalar((srcRect.fBottom << 16) / bitmap.height()));
reed@google.comac10a2d2010-12-22 21:39:39 +0000947
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000948 GrMatrix grMat;
949 SkGr::SkMatrix2GrMatrix(m, &grMat);
reed@google.comac10a2d2010-12-22 21:39:39 +0000950
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000951 fContext->drawRectToRect(*grPaint, dstRect, paintRect, &grMat);
reed@google.comac10a2d2010-12-22 21:39:39 +0000952}
953
954void SkGpuDevice::drawSprite(const SkDraw& draw, const SkBitmap& bitmap,
955 int left, int top, const SkPaint& paint) {
956 CHECK_SHOULD_DRAW(draw);
957
958 SkAutoLockPixels alp(bitmap);
959 if (!bitmap.getTexture() && !bitmap.readyToDraw()) {
960 return;
961 }
962
bsalomon@google.com5782d712011-01-21 21:03:59 +0000963 GrPaint grPaint;
964 if(!this->skPaint2GrPaintNoShader(paint, true, &grPaint)) {
965 return;
966 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000967
bsalomon@google.com5782d712011-01-21 21:03:59 +0000968 GrAutoMatrix avm(fContext, GrMatrix::I());
969
970 GrTexture* texture;
971 grPaint.fSampler.setClampNoFilter();
972 SkAutoCachedTexture act(this, bitmap, grPaint.fSampler, &texture);
973
bsalomon@google.com5782d712011-01-21 21:03:59 +0000974 grPaint.setTexture(texture);
975
bsalomon@google.com5782d712011-01-21 21:03:59 +0000976 fContext->drawRectToRect(grPaint,
977 GrRect(GrIntToScalar(left), GrIntToScalar(top),
978 GrIntToScalar(left + bitmap.width()),
979 GrIntToScalar(top + bitmap.height())),
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000980 GrRect(0, 0, GR_Scalar1, GR_Scalar1));
reed@google.comac10a2d2010-12-22 21:39:39 +0000981}
982
983void SkGpuDevice::drawDevice(const SkDraw& draw, SkDevice* dev,
984 int x, int y, const SkPaint& paint) {
985 CHECK_SHOULD_DRAW(draw);
986
bsalomon@google.com5782d712011-01-21 21:03:59 +0000987 GrPaint grPaint;
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000988 if (!((SkGpuDevice*)dev)->bindDeviceAsTexture(&grPaint) ||
bsalomon@google.com5782d712011-01-21 21:03:59 +0000989 !this->skPaint2GrPaintNoShader(paint, true, &grPaint)) {
990 return;
reed@google.comac10a2d2010-12-22 21:39:39 +0000991 }
bsalomon@google.com5782d712011-01-21 21:03:59 +0000992
993 SkASSERT(NULL != grPaint.getTexture());
994
995 const SkBitmap& bm = dev->accessBitmap(false);
996 int w = bm.width();
997 int h = bm.height();
998
999 GrAutoMatrix avm(fContext, GrMatrix::I());
1000
1001 grPaint.fSampler.setClampNoFilter();
bsalomon@google.com5782d712011-01-21 21:03:59 +00001002
1003 fContext->drawRectToRect(grPaint,
reed@google.com1a2e8d22011-01-21 22:08:29 +00001004 GrRect(GrIntToScalar(x),
1005 GrIntToScalar(y),
1006 GrIntToScalar(x + w),
bsalomon@google.com5782d712011-01-21 21:03:59 +00001007 GrIntToScalar(y + h)),
bsalomon@google.comc6cf7232011-02-17 16:43:10 +00001008 GrRect(0, 0, GR_Scalar1, GR_Scalar1));
reed@google.comac10a2d2010-12-22 21:39:39 +00001009}
1010
1011///////////////////////////////////////////////////////////////////////////////
1012
1013// must be in SkCanvas::VertexMode order
bsalomon@google.comffca4002011-02-22 20:34:01 +00001014static const GrPrimitiveType gVertexMode2PrimitiveType[] = {
1015 kTriangles_PrimitiveType,
1016 kTriangleStrip_PrimitiveType,
1017 kTriangleFan_PrimitiveType,
reed@google.comac10a2d2010-12-22 21:39:39 +00001018};
1019
1020void SkGpuDevice::drawVertices(const SkDraw& draw, SkCanvas::VertexMode vmode,
1021 int vertexCount, const SkPoint vertices[],
1022 const SkPoint texs[], const SkColor colors[],
1023 SkXfermode* xmode,
1024 const uint16_t indices[], int indexCount,
1025 const SkPaint& paint) {
1026 CHECK_SHOULD_DRAW(draw);
1027
bsalomon@google.com5782d712011-01-21 21:03:59 +00001028 GrPaint grPaint;
1029 SkAutoCachedTexture act;
1030 // we ignore the shader if texs is null.
1031 if (NULL == texs) {
1032 if (!this->skPaint2GrPaintNoShader(paint, false, &grPaint)) {
reed@google.comac10a2d2010-12-22 21:39:39 +00001033 return;
1034 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001035 } else {
reed@google.com1a2e8d22011-01-21 22:08:29 +00001036 if (!this->skPaint2GrPaintShader(paint, &act,
1037 *draw.fMatrix,
bsalomon@google.com5782d712011-01-21 21:03:59 +00001038 &grPaint)) {
1039 return;
1040 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001041 }
bsalomon@google.com5782d712011-01-21 21:03:59 +00001042
1043 if (NULL != xmode && NULL != texs && NULL != colors) {
1044 SkXfermode::Mode mode;
1045 if (!SkXfermode::IsMode(xmode, &mode) ||
1046 SkXfermode::kMultiply_Mode != mode) {
1047 SkDebugf("Unsupported vertex-color/texture xfer mode.\n");
1048#if 0
1049 return
1050#endif
1051 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001052 }
bsalomon@google.com5782d712011-01-21 21:03:59 +00001053
1054#if SK_SCALAR_IS_GR_SCALAR
1055 // even if GrColor and SkColor byte offsets match we need
1056 // to perform pre-multiply.
1057 if (NULL == colors) {
1058 fContext->drawVertices(grPaint,
1059 gVertexMode2PrimitiveType[vmode],
1060 vertexCount,
1061 (GrPoint*) vertices,
1062 (GrPoint*) texs,
1063 NULL,
1064 indices,
1065 indexCount);
1066 } else
1067#endif
1068 {
1069 SkTexCoordSource texSrc(texs);
1070 SkColorSource colSrc(colors);
1071 SkIndexSource idxSrc(indices, indexCount);
1072
1073 fContext->drawCustomVertices(grPaint,
1074 gVertexMode2PrimitiveType[vmode],
1075 SkPositionSource(vertices, vertexCount),
1076 (NULL == texs) ? NULL : &texSrc,
1077 (NULL == colors) ? NULL : &colSrc,
1078 (NULL == indices) ? NULL : &idxSrc);
reed@google.comac10a2d2010-12-22 21:39:39 +00001079 }
1080}
1081
1082///////////////////////////////////////////////////////////////////////////////
1083
1084static void GlyphCacheAuxProc(void* data) {
1085 delete (GrFontScaler*)data;
1086}
1087
1088static GrFontScaler* get_gr_font_scaler(SkGlyphCache* cache) {
1089 void* auxData;
1090 GrFontScaler* scaler = NULL;
1091 if (cache->getAuxProcData(GlyphCacheAuxProc, &auxData)) {
1092 scaler = (GrFontScaler*)auxData;
1093 }
1094 if (NULL == scaler) {
1095 scaler = new SkGrFontScaler(cache);
1096 cache->setAuxProc(GlyphCacheAuxProc, scaler);
1097 }
1098 return scaler;
1099}
1100
1101static void SkGPU_Draw1Glyph(const SkDraw1Glyph& state,
1102 SkFixed fx, SkFixed fy,
1103 const SkGlyph& glyph) {
1104 SkASSERT(glyph.fWidth > 0 && glyph.fHeight > 0);
1105
1106 GrSkDrawProcs* procs = (GrSkDrawProcs*)state.fDraw->fProcs;
1107
1108 if (NULL == procs->fFontScaler) {
1109 procs->fFontScaler = get_gr_font_scaler(state.fCache);
1110 }
1111 procs->fTextContext->drawPackedGlyph(GrGlyph::Pack(glyph.getGlyphID(), fx, 0),
1112 SkIntToFixed(SkFixedFloor(fx)), fy,
1113 procs->fFontScaler);
1114}
1115
bsalomon@google.com5782d712011-01-21 21:03:59 +00001116SkDrawProcs* SkGpuDevice::initDrawForText(GrTextContext* context) {
reed@google.comac10a2d2010-12-22 21:39:39 +00001117
1118 // deferred allocation
1119 if (NULL == fDrawProcs) {
1120 fDrawProcs = new GrSkDrawProcs;
1121 fDrawProcs->fD1GProc = SkGPU_Draw1Glyph;
1122 fDrawProcs->fContext = fContext;
1123 }
1124
1125 // init our (and GL's) state
1126 fDrawProcs->fTextContext = context;
1127 fDrawProcs->fFontScaler = NULL;
1128 return fDrawProcs;
1129}
1130
1131void SkGpuDevice::drawText(const SkDraw& draw, const void* text,
1132 size_t byteLength, SkScalar x, SkScalar y,
1133 const SkPaint& paint) {
1134 CHECK_SHOULD_DRAW(draw);
1135
1136 if (draw.fMatrix->getType() & SkMatrix::kPerspective_Mask) {
1137 // this guy will just call our drawPath()
1138 draw.drawText((const char*)text, byteLength, x, y, paint);
1139 } else {
1140 SkAutoExtMatrix aem(draw.fExtMatrix);
1141 SkDraw myDraw(draw);
bsalomon@google.com5782d712011-01-21 21:03:59 +00001142
1143 GrPaint grPaint;
1144 SkAutoCachedTexture act;
1145
1146 if (!this->skPaint2GrPaintShader(paint, &act, *draw.fMatrix, &grPaint)) {
1147 return;
1148 }
1149 GrTextContext context(fContext, grPaint, aem.extMatrix());
1150 myDraw.fProcs = this->initDrawForText(&context);
reed@google.comac10a2d2010-12-22 21:39:39 +00001151 this->INHERITED::drawText(myDraw, text, byteLength, x, y, paint);
1152 }
1153}
1154
1155void SkGpuDevice::drawPosText(const SkDraw& draw, const void* text,
1156 size_t byteLength, const SkScalar pos[],
1157 SkScalar constY, int scalarsPerPos,
1158 const SkPaint& paint) {
1159 CHECK_SHOULD_DRAW(draw);
1160
1161 if (draw.fMatrix->getType() & SkMatrix::kPerspective_Mask) {
1162 // this guy will just call our drawPath()
1163 draw.drawPosText((const char*)text, byteLength, pos, constY,
1164 scalarsPerPos, paint);
1165 } else {
1166 SkAutoExtMatrix aem(draw.fExtMatrix);
1167 SkDraw myDraw(draw);
bsalomon@google.com5782d712011-01-21 21:03:59 +00001168
1169 GrPaint grPaint;
1170 SkAutoCachedTexture act;
1171 if (!this->skPaint2GrPaintShader(paint, &act, *draw.fMatrix, &grPaint)) {
1172 return;
1173 }
1174
1175 GrTextContext context(fContext, grPaint, aem.extMatrix());
1176 myDraw.fProcs = this->initDrawForText(&context);
reed@google.comac10a2d2010-12-22 21:39:39 +00001177 this->INHERITED::drawPosText(myDraw, text, byteLength, pos, constY,
1178 scalarsPerPos, paint);
1179 }
1180}
1181
1182void SkGpuDevice::drawTextOnPath(const SkDraw& draw, const void* text,
1183 size_t len, const SkPath& path,
1184 const SkMatrix* m, const SkPaint& paint) {
1185 CHECK_SHOULD_DRAW(draw);
1186
1187 SkASSERT(draw.fDevice == this);
1188 draw.drawTextOnPath((const char*)text, len, path, m, paint);
1189}
1190
1191///////////////////////////////////////////////////////////////////////////////
1192
reed@google.comf67e4cf2011-03-15 20:56:58 +00001193bool SkGpuDevice::filterTextFlags(const SkPaint& paint, TextFlags* flags) {
1194 if (!paint.isLCDRenderText()) {
1195 // we're cool with the paint as is
1196 return false;
1197 }
1198
1199 if (paint.getShader() ||
1200 paint.getXfermode() || // unless its srcover
1201 paint.getMaskFilter() ||
1202 paint.getRasterizer() ||
1203 paint.getColorFilter() ||
1204 paint.getPathEffect() ||
1205 paint.isFakeBoldText() ||
1206 paint.getStyle() != SkPaint::kFill_Style) {
1207 // turn off lcd
1208 flags->fFlags = paint.getFlags() & ~SkPaint::kLCDRenderText_Flag;
1209 flags->fHinting = paint.getHinting();
1210 return true;
1211 }
1212 // we're cool with the paint as is
1213 return false;
1214}
1215
1216///////////////////////////////////////////////////////////////////////////////
1217
reed@google.comac10a2d2010-12-22 21:39:39 +00001218SkGpuDevice::TexCache* SkGpuDevice::lockCachedTexture(const SkBitmap& bitmap,
1219 const GrSamplerState& sampler,
1220 GrTexture** texture,
1221 bool forDeviceRenderTarget) {
1222 GrContext* ctx = this->context();
1223 uint32_t p0, p1;
1224 if (forDeviceRenderTarget) {
1225 p0 = p1 = -1;
1226 } else {
1227 p0 = bitmap.getGenerationID();
1228 p1 = bitmap.pixelRefOffset();
1229 }
1230
1231 GrTexture* newTexture = NULL;
1232 GrTextureKey key(p0, p1, bitmap.width(), bitmap.height());
1233 GrTextureEntry* entry = ctx->findAndLockTexture(&key, sampler);
1234
1235 if (NULL == entry) {
1236
1237 if (forDeviceRenderTarget) {
1238 const GrGpu::TextureDesc desc = {
1239 GrGpu::kRenderTarget_TextureFlag,
1240 GrGpu::kNone_AALevel,
1241 bitmap.width(),
1242 bitmap.height(),
1243 SkGr::Bitmap2PixelConfig(bitmap)
1244 };
1245 entry = ctx->createAndLockTexture(&key, sampler, desc, NULL, 0);
1246
1247 } else {
1248 entry = sk_gr_create_bitmap_texture(ctx, &key, sampler, bitmap);
1249 }
1250 if (NULL == entry) {
1251 GrPrintf("---- failed to create texture for cache [%d %d]\n",
1252 bitmap.width(), bitmap.height());
1253 }
1254 }
1255
1256 if (NULL != entry) {
1257 newTexture = entry->texture();
reed@google.comac10a2d2010-12-22 21:39:39 +00001258 if (texture) {
1259 *texture = newTexture;
1260 }
1261 // IMPORTANT: We can't allow another SkGpuDevice to get this
1262 // cache entry until this one is destroyed!
1263 if (forDeviceRenderTarget) {
1264 ctx->detachCachedTexture(entry);
1265 }
1266 }
1267 return (TexCache*)entry;
1268}
1269
1270void SkGpuDevice::unlockCachedTexture(TexCache* cache) {
1271 this->context()->unlockTexture((GrTextureEntry*)cache);
1272}
1273
reed@google.com7b201d22011-01-11 18:59:23 +00001274///////////////////////////////////////////////////////////////////////////////
1275
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +00001276SkGpuDeviceFactory::SkGpuDeviceFactory(GrContext* context,
1277 GrRenderTarget* rootRenderTarget)
1278 : fContext(context) {
1279
1280 GrAssert(NULL != context);
1281 GrAssert(NULL != rootRenderTarget);
1282
1283 // check this now rather than passing this value to SkGpuDevice cons.
1284 // we want the rt that is bound *now* in the 3D API, not the one
1285 // at the time of newDevice.
1286 if (SkGpuDevice::Current3DApiRenderTarget() == rootRenderTarget) {
1287 fRootRenderTarget = context->createRenderTargetFrom3DApiState();
1288 } else {
1289 fRootRenderTarget = rootRenderTarget;
1290 rootRenderTarget->ref();
1291 }
reed@google.com7b201d22011-01-11 18:59:23 +00001292 context->ref();
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +00001293
reed@google.com7b201d22011-01-11 18:59:23 +00001294}
1295
1296SkGpuDeviceFactory::~SkGpuDeviceFactory() {
1297 fContext->unref();
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +00001298 fRootRenderTarget->unref();
reed@google.com7b201d22011-01-11 18:59:23 +00001299}
1300
1301SkDevice* SkGpuDeviceFactory::newDevice(SkCanvas*, SkBitmap::Config config,
1302 int width, int height,
1303 bool isOpaque, bool isLayer) {
1304 SkBitmap bm;
1305 bm.setConfig(config, width, height);
1306 bm.setIsOpaque(isOpaque);
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +00001307 return new SkGpuDevice(fContext, bm, isLayer ? NULL : fRootRenderTarget);
reed@google.com7b201d22011-01-11 18:59:23 +00001308}
reed@google.comac10a2d2010-12-22 21:39:39 +00001309