blob: faa31f6532a75e827747b2b0a1a0cc421b29e9b4 [file] [log] [blame]
reed@google.comac10a2d2010-12-22 21:39:39 +00001/*
2 Copyright 2010 Google Inc.
3
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);
145 SkASSERT(fTexture->isRenderTarget());
146 }
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,
271 const SkRegion& clip) {
272 GrMatrix grmat;
273 SkGr::SkMatrix2GrMatrix(matrix, &grmat);
bsalomon@google.com5782d712011-01-21 21:03:59 +0000274 context->setMatrix(grmat);
reed@google.comac10a2d2010-12-22 21:39:39 +0000275
276 SkGrClipIterator iter;
277 iter.reset(clip);
278 GrClip grc(&iter);
279 if (context->getClip() == grc) {
280 } else {
281 context->setClip(grc);
282 }
283}
284
285// call this ever each draw call, to ensure that the context reflects our state,
286// and not the state from some other canvas/device
287void SkGpuDevice::prepareRenderTarget(const SkDraw& draw) {
288 if (fNeedPrepareRenderTarget ||
bsalomon@google.com5782d712011-01-21 21:03:59 +0000289 fContext->getRenderTarget() != fRenderTarget) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000290
291 fContext->setRenderTarget(fRenderTarget);
292 convert_matrixclip(fContext, *draw.fMatrix, *draw.fClip);
293 fNeedPrepareRenderTarget = false;
294 }
295}
296
297void SkGpuDevice::setMatrixClip(const SkMatrix& matrix, const SkRegion& clip) {
298 this->INHERITED::setMatrixClip(matrix, clip);
299
300 convert_matrixclip(fContext, matrix, clip);
301}
302
303void SkGpuDevice::gainFocus(SkCanvas* canvas, const SkMatrix& matrix,
304 const SkRegion& clip) {
305 fContext->setRenderTarget(fRenderTarget);
306
307 this->INHERITED::gainFocus(canvas, matrix, clip);
308
309 convert_matrixclip(fContext, matrix, clip);
310
311 if (fNeedClear) {
312 fContext->eraseColor(0x0);
313 fNeedClear = false;
314 }
315}
316
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000317bool SkGpuDevice::bindDeviceAsTexture(GrPaint* paint) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000318 if (NULL != fTexture) {
bsalomon@google.com5782d712011-01-21 21:03:59 +0000319 paint->setTexture(fTexture);
reed@google.comac10a2d2010-12-22 21:39:39 +0000320 return true;
321 }
322 return false;
323}
324
325///////////////////////////////////////////////////////////////////////////////
326
bsalomon@google.com5782d712011-01-21 21:03:59 +0000327// must be in SkShader::BitmapTypeOrder
reed@google.comac10a2d2010-12-22 21:39:39 +0000328
bsalomon@google.com5782d712011-01-21 21:03:59 +0000329static const GrSamplerState::SampleMode sk_bmp_type_to_sample_mode[] = {
330 (GrSamplerState::SampleMode) -1, // kNone_BitmapType
331 GrSamplerState::kNormal_SampleMode, // kDefault_BitmapType
332 GrSamplerState::kRadial_SampleMode, // kRadial_BitmapType
333 GrSamplerState::kSweep_SampleMode, // kSweep_BitmapType
334 GrSamplerState::kRadial2_SampleMode, // kTwoPointRadial_BitmapType
335};
336
337bool SkGpuDevice::skPaint2GrPaintNoShader(const SkPaint& skPaint,
338 bool justAlpha,
339 GrPaint* grPaint) {
340
341 grPaint->fDither = skPaint.isDither();
342 grPaint->fAntiAlias = skPaint.isAntiAlias();
343
344 SkXfermode::Coeff sm = SkXfermode::kOne_Coeff;
345 SkXfermode::Coeff dm = SkXfermode::kISA_Coeff;
346
347 SkXfermode* mode = skPaint.getXfermode();
348 if (mode) {
349 if (!mode->asCoeff(&sm, &dm)) {
reed@google.com1a2e8d22011-01-21 22:08:29 +0000350 SkDEBUGCODE(SkDebugf("Unsupported xfer mode.\n");)
bsalomon@google.com5782d712011-01-21 21:03:59 +0000351#if 0
352 return false;
353#endif
354 }
355 }
356 grPaint->fSrcBlendCoeff = sk_blend_to_grblend(sm);
357 grPaint->fDstBlendCoeff = sk_blend_to_grblend(dm);
358
359 if (justAlpha) {
360 uint8_t alpha = skPaint.getAlpha();
361 grPaint->fColor = GrColorPackRGBA(alpha, alpha, alpha, alpha);
362 } else {
363 grPaint->fColor = SkGr::SkColor2GrColor(skPaint.getColor());
364 grPaint->setTexture(NULL);
365 }
366 return true;
reed@google.comac10a2d2010-12-22 21:39:39 +0000367}
368
bsalomon@google.com5782d712011-01-21 21:03:59 +0000369bool SkGpuDevice::skPaint2GrPaintShader(const SkPaint& skPaint,
370 SkAutoCachedTexture* act,
371 const SkMatrix& ctm,
372 GrPaint* grPaint) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000373
bsalomon@google.com5782d712011-01-21 21:03:59 +0000374 SkASSERT(NULL != act);
reed@google.comac10a2d2010-12-22 21:39:39 +0000375
bsalomon@google.com5782d712011-01-21 21:03:59 +0000376 SkShader* shader = skPaint.getShader();
reed@google.comac10a2d2010-12-22 21:39:39 +0000377 if (NULL == shader) {
bsalomon@google.com5782d712011-01-21 21:03:59 +0000378 return this->skPaint2GrPaintNoShader(skPaint, false, grPaint);
379 grPaint->setTexture(NULL);
380 return true;
381 } else if (!this->skPaint2GrPaintNoShader(skPaint, true, grPaint)) {
382 return false;
reed@google.comac10a2d2010-12-22 21:39:39 +0000383 }
384
bsalomon@google.com5782d712011-01-21 21:03:59 +0000385 SkPaint noAlphaPaint(skPaint);
386 noAlphaPaint.setAlpha(255);
387 shader->setContext(this->accessBitmap(false), noAlphaPaint, ctm);
reed@google.comac10a2d2010-12-22 21:39:39 +0000388
reed@google.comac10a2d2010-12-22 21:39:39 +0000389 SkBitmap bitmap;
390 SkMatrix matrix;
391 SkShader::TileMode tileModes[2];
392 SkScalar twoPointParams[3];
393 SkShader::BitmapType bmptype = shader->asABitmap(&bitmap, &matrix,
394 tileModes, twoPointParams);
395
bsalomon@google.com5782d712011-01-21 21:03:59 +0000396 GrSamplerState::SampleMode sampleMode = sk_bmp_type_to_sample_mode[bmptype];
397 if (-1 == sampleMode) {
398 SkDebugf("shader->asABitmap() == kNone_BitmapType\n");
399 return false;
reed@google.comac10a2d2010-12-22 21:39:39 +0000400 }
bsalomon@google.com5782d712011-01-21 21:03:59 +0000401 grPaint->fSampler.setSampleMode(sampleMode);
bsalomon@google.com0748f212011-02-01 22:56:16 +0000402 grPaint->fSampler.setFilter(skPaint.isFilterBitmap());
bsalomon@google.com5782d712011-01-21 21:03:59 +0000403 grPaint->fSampler.setWrapX(sk_tile_mode_to_grwrap(tileModes[0]));
404 grPaint->fSampler.setWrapY(sk_tile_mode_to_grwrap(tileModes[1]));
reed@google.comac10a2d2010-12-22 21:39:39 +0000405 if (GrSamplerState::kRadial2_SampleMode == sampleMode) {
bsalomon@google.com5782d712011-01-21 21:03:59 +0000406 grPaint->fSampler.setRadial2Params(twoPointParams[0],
407 twoPointParams[1],
408 twoPointParams[2] < 0);
reed@google.comac10a2d2010-12-22 21:39:39 +0000409 }
410
bsalomon@google.com5782d712011-01-21 21:03:59 +0000411 GrTexture* texture = act->set(this, bitmap, grPaint->fSampler);
reed@google.comac10a2d2010-12-22 21:39:39 +0000412 if (NULL == texture) {
bsalomon@google.com5782d712011-01-21 21:03:59 +0000413 SkDebugf("Couldn't convert bitmap to texture.\n");
414 return false;
reed@google.comac10a2d2010-12-22 21:39:39 +0000415 }
bsalomon@google.com5782d712011-01-21 21:03:59 +0000416 grPaint->setTexture(texture);
reed@google.comac10a2d2010-12-22 21:39:39 +0000417
418 // since our texture coords will be in local space, we wack the texture
419 // matrix to map them back into 0...1 before we load it
420 SkMatrix localM;
421 if (shader->getLocalMatrix(&localM)) {
422 SkMatrix inverse;
423 if (localM.invert(&inverse)) {
424 matrix.preConcat(inverse);
425 }
426 }
427 if (SkShader::kDefault_BitmapType == bmptype) {
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000428 GrScalar sx = GrFixedToScalar(GR_Fixed1 / bitmap.width());
429 GrScalar sy = GrFixedToScalar(GR_Fixed1 / bitmap.height());
reed@google.comac10a2d2010-12-22 21:39:39 +0000430 matrix.postScale(sx, sy);
reed@google.comac10a2d2010-12-22 21:39:39 +0000431 } else if (SkShader::kRadial_BitmapType == bmptype) {
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000432 GrScalar s = GrFixedToScalar(GR_Fixed1 / bitmap.width());
reed@google.comac10a2d2010-12-22 21:39:39 +0000433 matrix.postScale(s, s);
434 }
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000435 GrMatrix grMat;
436 SkGr::SkMatrix2GrMatrix(matrix, &grMat);
437 grPaint->fSampler.setMatrix(grMat);
bsalomon@google.com5782d712011-01-21 21:03:59 +0000438
439 return true;
reed@google.comac10a2d2010-12-22 21:39:39 +0000440}
441
442///////////////////////////////////////////////////////////////////////////////
bsalomon@google.com5782d712011-01-21 21:03:59 +0000443
444class SkPositionSource {
445public:
446 SkPositionSource(const SkPoint* points, int count)
447 : fPoints(points), fCount(count) {}
448
449 int count() const { return fCount; }
450
451 void writeValue(int i, GrPoint* dstPosition) const {
452 SkASSERT(i < fCount);
453 dstPosition->fX = SkScalarToGrScalar(fPoints[i].fX);
454 dstPosition->fY = SkScalarToGrScalar(fPoints[i].fY);
455 }
456private:
bsalomon@google.com5782d712011-01-21 21:03:59 +0000457 const SkPoint* fPoints;
bsalomon@google.com19628322011-02-03 21:30:17 +0000458 int fCount;
bsalomon@google.com5782d712011-01-21 21:03:59 +0000459};
460
461class SkTexCoordSource {
462public:
463 SkTexCoordSource(const SkPoint* coords)
464 : fCoords(coords) {}
465
466 void writeValue(int i, GrPoint* dstCoord) const {
467 dstCoord->fX = SkScalarToGrScalar(fCoords[i].fX);
468 dstCoord->fY = SkScalarToGrScalar(fCoords[i].fY);
469 }
470private:
471 const SkPoint* fCoords;
472};
473
474class SkColorSource {
475public:
476 SkColorSource(const SkColor* colors) : fColors(colors) {}
477
478 void writeValue(int i, GrColor* dstColor) const {
479 *dstColor = SkGr::SkColor2GrColor(fColors[i]);
480 }
481private:
482 const SkColor* fColors;
483};
484
485class SkIndexSource {
486public:
487 SkIndexSource(const uint16_t* indices, int count)
488 : fIndices(indices), fCount(count) {
489 }
490
491 int count() const { return fCount; }
492
493 void writeValue(int i, uint16_t* dstIndex) const {
494 *dstIndex = fIndices[i];
495 }
496
497private:
bsalomon@google.com5782d712011-01-21 21:03:59 +0000498 const uint16_t* fIndices;
bsalomon@google.com19628322011-02-03 21:30:17 +0000499 int fCount;
bsalomon@google.com5782d712011-01-21 21:03:59 +0000500};
501
502///////////////////////////////////////////////////////////////////////////////
503
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000504#if 0 // not currently being used so don't compile,
505
bsalomon@google.com5782d712011-01-21 21:03:59 +0000506// can be used for positions or texture coordinates
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000507
bsalomon@google.com5782d712011-01-21 21:03:59 +0000508class SkRectFanSource {
509public:
510 SkRectFanSource(const SkRect& rect) : fRect(rect) {}
511
512 int count() const { return 4; }
513
514 void writeValue(int i, GrPoint* dstPoint) const {
515 SkASSERT(i < 4);
516 dstPoint->fX = SkScalarToGrScalar((i % 3) ? fRect.fRight :
517 fRect.fLeft);
518 dstPoint->fY = SkScalarToGrScalar((i < 2) ? fRect.fTop :
519 fRect.fBottom);
520 }
521private:
522 const SkRect& fRect;
523};
524
525class SkIRectFanSource {
526public:
527 SkIRectFanSource(const SkIRect& rect) : fRect(rect) {}
528
529 int count() const { return 4; }
530
531 void writeValue(int i, GrPoint* dstPoint) const {
532 SkASSERT(i < 4);
533 dstPoint->fX = (i % 3) ? GrIntToScalar(fRect.fRight) :
534 GrIntToScalar(fRect.fLeft);
535 dstPoint->fY = (i < 2) ? GrIntToScalar(fRect.fTop) :
536 GrIntToScalar(fRect.fBottom);
537 }
538private:
539 const SkIRect& fRect;
540};
541
542class SkMatRectFanSource {
543public:
544 SkMatRectFanSource(const SkRect& rect, const SkMatrix& matrix)
545 : fRect(rect), fMatrix(matrix) {}
546
547 int count() const { return 4; }
548
549 void writeValue(int i, GrPoint* dstPoint) const {
550 SkASSERT(i < 4);
551
552#if SK_SCALAR_IS_GR_SCALAR
553 fMatrix.mapXY((i % 3) ? fRect.fRight : fRect.fLeft,
554 (i < 2) ? fRect.fTop : fRect.fBottom,
555 (SkPoint*)dstPoint);
556#else
557 SkPoint dst;
558 fMatrix.mapXY((i % 3) ? fRect.fRight : fRect.fLeft,
559 (i < 2) ? fRect.fTop : fRect.fBottom,
560 &dst);
561 dstPoint->fX = SkScalarToGrScalar(dst.fX);
562 dstPoint->fY = SkScalarToGrScalar(dst.fY);
563#endif
564 }
565private:
566 const SkRect& fRect;
567 const SkMatrix& fMatrix;
568};
569
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000570#endif
571
reed@google.comac10a2d2010-12-22 21:39:39 +0000572///////////////////////////////////////////////////////////////////////////////
573
574void SkGpuDevice::drawPaint(const SkDraw& draw, const SkPaint& paint) {
575 CHECK_SHOULD_DRAW(draw);
576
bsalomon@google.com5782d712011-01-21 21:03:59 +0000577 GrPaint grPaint;
578 SkAutoCachedTexture act;
579 if (!this->skPaint2GrPaintShader(paint, &act, *draw.fMatrix, &grPaint)) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000580 return;
581 }
bsalomon@google.com5782d712011-01-21 21:03:59 +0000582
583 fContext->drawPaint(grPaint);
reed@google.comac10a2d2010-12-22 21:39:39 +0000584}
585
586// must be in SkCanvas::PointMode order
bsalomon@google.com5782d712011-01-21 21:03:59 +0000587static const GrDrawTarget::PrimitiveType gPointMode2PrimtiveType[] = {
588 GrDrawTarget::kPoints_PrimitiveType,
589 GrDrawTarget::kLines_PrimitiveType,
590 GrDrawTarget::kLineStrip_PrimitiveType
reed@google.comac10a2d2010-12-22 21:39:39 +0000591};
592
593void SkGpuDevice::drawPoints(const SkDraw& draw, SkCanvas::PointMode mode,
bsalomon@google.com5782d712011-01-21 21:03:59 +0000594 size_t count, const SkPoint pts[], const SkPaint& paint) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000595 CHECK_SHOULD_DRAW(draw);
596
597 SkScalar width = paint.getStrokeWidth();
598 if (width < 0) {
599 return;
600 }
601
602 // we only handle hairlines here, else we let the SkDraw call our drawPath()
603 if (width > 0) {
604 draw.drawPoints(mode, count, pts, paint, true);
605 return;
606 }
607
bsalomon@google.com5782d712011-01-21 21:03:59 +0000608 GrPaint grPaint;
609 SkAutoCachedTexture act;
610 if (!this->skPaint2GrPaintShader(paint, &act, *draw.fMatrix, &grPaint)) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000611 return;
612 }
613
reed@google.comac10a2d2010-12-22 21:39:39 +0000614#if SK_SCALAR_IS_GR_SCALAR
bsalomon@google.com5782d712011-01-21 21:03:59 +0000615 fContext->drawVertices(grPaint,
616 gPointMode2PrimtiveType[mode],
617 count,
618 (GrPoint*)pts,
619 NULL,
620 NULL,
621 NULL,
622 0);
reed@google.comac10a2d2010-12-22 21:39:39 +0000623#else
bsalomon@google.com5782d712011-01-21 21:03:59 +0000624 fContext->drawCustomVertices(grPaint,
625 gPointMode2PrimtiveType[mode],
626 SkPositionSource(pts, count));
reed@google.comac10a2d2010-12-22 21:39:39 +0000627#endif
reed@google.comac10a2d2010-12-22 21:39:39 +0000628}
629
630void SkGpuDevice::drawRect(const SkDraw& draw, const SkRect& rect,
631 const SkPaint& paint) {
632 CHECK_SHOULD_DRAW(draw);
633
634 bool doStroke = paint.getStyle() == SkPaint::kStroke_Style;
635 SkScalar width = paint.getStrokeWidth();
636
637 /*
638 We have special code for hairline strokes, miter-strokes, and fills.
reed@google.com69302852011-02-16 18:08:07 +0000639 Anything else we just call our path code.
reed@google.comac10a2d2010-12-22 21:39:39 +0000640 */
reed@google.com69302852011-02-16 18:08:07 +0000641 bool usePath = doStroke && width > 0 &&
642 paint.getStrokeJoin() != SkPaint::kMiter_Join;
643 // another reason we might need to call drawPath...
644 if (paint.getMaskFilter()) {
645 usePath = true;
646 }
647
648 if (usePath) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000649 SkPath path;
650 path.addRect(rect);
651 this->drawPath(draw, path, paint, NULL, true);
652 return;
653 }
654
bsalomon@google.com5782d712011-01-21 21:03:59 +0000655 GrPaint grPaint;
656 SkAutoCachedTexture act;
657 if (!this->skPaint2GrPaintShader(paint, &act, *draw.fMatrix, &grPaint)) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000658 return;
659 }
bsalomon@google.com5782d712011-01-21 21:03:59 +0000660 fContext->drawRect(grPaint, Sk2Gr(rect), doStroke ? width : -1);
reed@google.comac10a2d2010-12-22 21:39:39 +0000661}
662
reed@google.com69302852011-02-16 18:08:07 +0000663#include "SkMaskFilter.h"
664#include "SkBounder.h"
665
reed@google.com69302852011-02-16 18:08:07 +0000666static bool drawWithMaskFilter(GrContext* context, const SkPath& path,
667 SkMaskFilter* filter, const SkMatrix& matrix,
668 const SkRegion& clip, SkBounder* bounder,
669 GrPaint* grp) {
670 SkMask srcM, dstM;
671
672 if (!SkDraw::DrawToMask(path, &clip.getBounds(), filter, &matrix, &srcM,
673 SkMask::kComputeBoundsAndRenderImage_CreateMode)) {
674 return false;
675 }
676
677 SkAutoMaskImage autoSrc(&srcM, false);
678
679 if (!filter->filterMask(&dstM, srcM, matrix, NULL)) {
680 return false;
681 }
682 // this will free-up dstM when we're done (allocated in filterMask())
683 SkAutoMaskImage autoDst(&dstM, false);
684
685 if (clip.quickReject(dstM.fBounds)) {
686 return false;
687 }
688 if (bounder && !bounder->doIRect(dstM.fBounds)) {
689 return false;
690 }
691
692 // we now have a device-aligned 8bit mask in dstM, ready to be drawn using
693 // the current clip (and identity matrix) and grpaint settings
694
reed@google.com0c219b62011-02-16 21:31:18 +0000695 GrAutoMatrix avm(context, GrMatrix::I());
reed@google.com69302852011-02-16 18:08:07 +0000696
697 const GrGpu::TextureDesc desc = {
698 0,
699 GrGpu::kNone_AALevel,
700 dstM.fBounds.width(),
701 dstM.fBounds.height(),
702 GrTexture::kAlpha_8_PixelConfig
703 };
704
705 GrTexture* texture = context->createUncachedTexture(desc, dstM.fImage,
706 dstM.fRowBytes);
707 if (NULL == texture) {
708 return false;
709 }
710
reed@google.com0c219b62011-02-16 21:31:18 +0000711 grp->setTexture(texture);
712 texture->unref();
713 grp->fSampler.setClampNoFilter();
reed@google.com69302852011-02-16 18:08:07 +0000714
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000715 GrRect d;
716 d.setLTRB(GrIntToScalar(dstM.fBounds.fLeft),
reed@google.com0c219b62011-02-16 21:31:18 +0000717 GrIntToScalar(dstM.fBounds.fTop),
718 GrIntToScalar(dstM.fBounds.fRight),
719 GrIntToScalar(dstM.fBounds.fBottom));
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000720 GrRect s;
721 s.setLTRB(0, 0, GR_Scalar1, GR_Scalar1);
722 context->drawRectToRect(*grp, d, s);
reed@google.com69302852011-02-16 18:08:07 +0000723 return true;
724}
reed@google.com69302852011-02-16 18:08:07 +0000725
reed@google.com0c219b62011-02-16 21:31:18 +0000726void SkGpuDevice::drawPath(const SkDraw& draw, const SkPath& origSrcPath,
reed@google.comac10a2d2010-12-22 21:39:39 +0000727 const SkPaint& paint, const SkMatrix* prePathMatrix,
728 bool pathIsMutable) {
729 CHECK_SHOULD_DRAW(draw);
730
bsalomon@google.com5782d712011-01-21 21:03:59 +0000731 GrPaint grPaint;
732 SkAutoCachedTexture act;
733 if (!this->skPaint2GrPaintShader(paint, &act, *draw.fMatrix, &grPaint)) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000734 return;
735 }
736
reed@google.com0c219b62011-02-16 21:31:18 +0000737 // BEGIN lift from SkDraw::drawPath()
738
739 SkPath* pathPtr = const_cast<SkPath*>(&origSrcPath);
740 bool doFill = true;
741 SkPath tmpPath;
reed@google.comac10a2d2010-12-22 21:39:39 +0000742
743 if (prePathMatrix) {
reed@google.come3445642011-02-16 23:20:39 +0000744 SkPath* result = pathPtr;
reed@google.com0c219b62011-02-16 21:31:18 +0000745
reed@google.come3445642011-02-16 23:20:39 +0000746 if (!pathIsMutable) {
747 result = &tmpPath;
748 pathIsMutable = true;
reed@google.comac10a2d2010-12-22 21:39:39 +0000749 }
reed@google.come3445642011-02-16 23:20:39 +0000750 // should I push prePathMatrix on our MV stack temporarily, instead
751 // of applying it here? See SkDraw.cpp
752 pathPtr->transform(*prePathMatrix, result);
753 pathPtr = result;
reed@google.comac10a2d2010-12-22 21:39:39 +0000754 }
reed@google.com0c219b62011-02-16 21:31:18 +0000755 // at this point we're done with prePathMatrix
756 SkDEBUGCODE(prePathMatrix = (const SkMatrix*)0x50FF8001;)
reed@google.comac10a2d2010-12-22 21:39:39 +0000757
reed@google.com0c219b62011-02-16 21:31:18 +0000758 if (paint.getPathEffect() || paint.getStyle() != SkPaint::kFill_Style) {
759 doFill = paint.getFillPath(*pathPtr, &tmpPath);
760 pathPtr = &tmpPath;
761 }
762
763 // END lift from SkDraw::drawPath()
764
reed@google.com69302852011-02-16 18:08:07 +0000765 if (paint.getMaskFilter()) {
reed@google.com0c219b62011-02-16 21:31:18 +0000766 // avoid possibly allocating a new path in transform if we can
767 SkPath* devPathPtr = pathIsMutable ? pathPtr : &tmpPath;
768
769 // transform the path into device space
reed@google.come3445642011-02-16 23:20:39 +0000770 pathPtr->transform(*draw.fMatrix, devPathPtr);
reed@google.com0c219b62011-02-16 21:31:18 +0000771
772 drawWithMaskFilter(fContext, *devPathPtr, paint.getMaskFilter(),
reed@google.com69302852011-02-16 18:08:07 +0000773 *draw.fMatrix, *draw.fClip, draw.fBounder, &grPaint);
774 return;
775 }
reed@google.com69302852011-02-16 18:08:07 +0000776
reed@google.comac10a2d2010-12-22 21:39:39 +0000777 GrContext::PathFills fill = GrContext::kHairLine_PathFill;
778
reed@google.com0c219b62011-02-16 21:31:18 +0000779 if (doFill) {
780 switch (pathPtr->getFillType()) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000781 case SkPath::kWinding_FillType:
782 fill = GrContext::kWinding_PathFill;
783 break;
784 case SkPath::kEvenOdd_FillType:
785 fill = GrContext::kEvenOdd_PathFill;
786 break;
787 case SkPath::kInverseWinding_FillType:
788 fill = GrContext::kInverseWinding_PathFill;
789 break;
790 case SkPath::kInverseEvenOdd_FillType:
791 fill = GrContext::kInverseEvenOdd_PathFill;
792 break;
793 default:
bsalomon@google.com5782d712011-01-21 21:03:59 +0000794 SkDebugf("Unsupported path fill type\n");
reed@google.comac10a2d2010-12-22 21:39:39 +0000795 return;
796 }
797 }
798
reed@google.com0c219b62011-02-16 21:31:18 +0000799 SkGrPathIter iter(*pathPtr);
bsalomon@google.com5782d712011-01-21 21:03:59 +0000800 fContext->drawPath(grPaint, &iter, fill);
reed@google.comac10a2d2010-12-22 21:39:39 +0000801}
802
reed@google.comac10a2d2010-12-22 21:39:39 +0000803void SkGpuDevice::drawBitmap(const SkDraw& draw,
804 const SkBitmap& bitmap,
805 const SkIRect* srcRectPtr,
806 const SkMatrix& m,
807 const SkPaint& paint) {
808 CHECK_SHOULD_DRAW(draw);
809
810 SkIRect srcRect;
811 if (NULL == srcRectPtr) {
812 srcRect.set(0, 0, bitmap.width(), bitmap.height());
813 } else {
814 srcRect = *srcRectPtr;
815 }
816
bsalomon@google.com5782d712011-01-21 21:03:59 +0000817 GrPaint grPaint;
818 if (!this->skPaint2GrPaintNoShader(paint, true, &grPaint)) {
819 return;
820 }
821 grPaint.fSampler.setFilter(paint.isFilterBitmap());
822
reed@google.com02a7e6c2011-01-28 21:21:49 +0000823 const int maxTextureDim = fContext->getMaxTextureDimension();
824 if (bitmap.getTexture() || (bitmap.width() <= maxTextureDim &&
825 bitmap.height() <= maxTextureDim)) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000826 // take the fast case
bsalomon@google.com5782d712011-01-21 21:03:59 +0000827 this->internalDrawBitmap(draw, bitmap, srcRect, m, &grPaint);
reed@google.comac10a2d2010-12-22 21:39:39 +0000828 return;
829 }
830
831 // undo the translate done by SkCanvas
832 int DX = SkMax32(0, srcRect.fLeft);
833 int DY = SkMax32(0, srcRect.fTop);
834 // compute clip bounds in local coordinates
835 SkIRect clipRect;
836 {
837 SkRect r;
838 r.set(draw.fClip->getBounds());
839 SkMatrix matrix, inverse;
840 matrix.setConcat(*draw.fMatrix, m);
841 if (!matrix.invert(&inverse)) {
842 return;
843 }
844 inverse.mapRect(&r);
845 r.roundOut(&clipRect);
846 // apply the canvas' translate to our local clip
847 clipRect.offset(DX, DY);
848 }
849
reed@google.com02a7e6c2011-01-28 21:21:49 +0000850 int nx = bitmap.width() / maxTextureDim;
851 int ny = bitmap.height() / maxTextureDim;
reed@google.comac10a2d2010-12-22 21:39:39 +0000852 for (int x = 0; x <= nx; x++) {
853 for (int y = 0; y <= ny; y++) {
854 SkIRect tileR;
reed@google.com02a7e6c2011-01-28 21:21:49 +0000855 tileR.set(x * maxTextureDim, y * maxTextureDim,
856 (x + 1) * maxTextureDim, (y + 1) * maxTextureDim);
reed@google.comac10a2d2010-12-22 21:39:39 +0000857 if (!SkIRect::Intersects(tileR, clipRect)) {
858 continue;
859 }
860
861 SkIRect srcR = tileR;
862 if (!srcR.intersect(srcRect)) {
863 continue;
864 }
865
866 SkBitmap tmpB;
867 if (bitmap.extractSubset(&tmpB, tileR)) {
868 // now offset it to make it "local" to our tmp bitmap
869 srcR.offset(-tileR.fLeft, -tileR.fTop);
870
871 SkMatrix tmpM(m);
872 {
873 int dx = tileR.fLeft - DX + SkMax32(0, srcR.fLeft);
874 int dy = tileR.fTop - DY + SkMax32(0, srcR.fTop);
875 tmpM.preTranslate(SkIntToScalar(dx), SkIntToScalar(dy));
876 }
bsalomon@google.com5782d712011-01-21 21:03:59 +0000877 this->internalDrawBitmap(draw, tmpB, srcR, tmpM, &grPaint);
reed@google.comac10a2d2010-12-22 21:39:39 +0000878 }
879 }
880 }
881}
882
883/*
884 * This is called by drawBitmap(), which has to handle images that may be too
885 * large to be represented by a single texture.
886 *
bsalomon@google.com5782d712011-01-21 21:03:59 +0000887 * internalDrawBitmap assumes that the specified bitmap will fit in a texture
888 * and that non-texture portion of the GrPaint has already been setup.
reed@google.comac10a2d2010-12-22 21:39:39 +0000889 */
890void SkGpuDevice::internalDrawBitmap(const SkDraw& draw,
891 const SkBitmap& bitmap,
892 const SkIRect& srcRect,
893 const SkMatrix& m,
bsalomon@google.com5782d712011-01-21 21:03:59 +0000894 GrPaint* grPaint) {
reed@google.com02a7e6c2011-01-28 21:21:49 +0000895 SkASSERT(bitmap.width() <= fContext->getMaxTextureDimension() &&
896 bitmap.height() <= fContext->getMaxTextureDimension());
reed@google.comac10a2d2010-12-22 21:39:39 +0000897
898 SkAutoLockPixels alp(bitmap);
899 if (!bitmap.getTexture() && !bitmap.readyToDraw()) {
900 return;
901 }
902
bsalomon@google.com5782d712011-01-21 21:03:59 +0000903 grPaint->fSampler.setWrapX(GrSamplerState::kClamp_WrapMode);
904 grPaint->fSampler.setWrapY(GrSamplerState::kClamp_WrapMode);
905 grPaint->fSampler.setSampleMode(GrSamplerState::kNormal_SampleMode);
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000906 grPaint->fSampler.setMatrix(GrMatrix::I());
reed@google.comac10a2d2010-12-22 21:39:39 +0000907
908 GrTexture* texture;
bsalomon@google.com5782d712011-01-21 21:03:59 +0000909 SkAutoCachedTexture act(this, bitmap, grPaint->fSampler, &texture);
reed@google.comac10a2d2010-12-22 21:39:39 +0000910 if (NULL == texture) {
911 return;
912 }
913
bsalomon@google.com5782d712011-01-21 21:03:59 +0000914 grPaint->setTexture(texture);
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000915
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000916 GrRect dstRect(0, 0, GrIntToScalar(srcRect.width()), GrIntToScalar(srcRect.height()));
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000917 GrRect paintRect;
918 paintRect.setLTRB(GrFixedToScalar((srcRect.fLeft << 16) / bitmap.width()),
919 GrFixedToScalar((srcRect.fTop << 16) / bitmap.height()),
920 GrFixedToScalar((srcRect.fRight << 16) / bitmap.width()),
921 GrFixedToScalar((srcRect.fBottom << 16) / bitmap.height()));
reed@google.comac10a2d2010-12-22 21:39:39 +0000922
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000923 GrMatrix grMat;
924 SkGr::SkMatrix2GrMatrix(m, &grMat);
reed@google.comac10a2d2010-12-22 21:39:39 +0000925
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000926 fContext->drawRectToRect(*grPaint, dstRect, paintRect, &grMat);
reed@google.comac10a2d2010-12-22 21:39:39 +0000927}
928
929void SkGpuDevice::drawSprite(const SkDraw& draw, const SkBitmap& bitmap,
930 int left, int top, const SkPaint& paint) {
931 CHECK_SHOULD_DRAW(draw);
932
933 SkAutoLockPixels alp(bitmap);
934 if (!bitmap.getTexture() && !bitmap.readyToDraw()) {
935 return;
936 }
937
bsalomon@google.com5782d712011-01-21 21:03:59 +0000938 GrPaint grPaint;
939 if(!this->skPaint2GrPaintNoShader(paint, true, &grPaint)) {
940 return;
941 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000942
bsalomon@google.com5782d712011-01-21 21:03:59 +0000943 GrAutoMatrix avm(fContext, GrMatrix::I());
944
945 GrTexture* texture;
946 grPaint.fSampler.setClampNoFilter();
947 SkAutoCachedTexture act(this, bitmap, grPaint.fSampler, &texture);
948
bsalomon@google.com5782d712011-01-21 21:03:59 +0000949 grPaint.setTexture(texture);
950
bsalomon@google.com5782d712011-01-21 21:03:59 +0000951 fContext->drawRectToRect(grPaint,
952 GrRect(GrIntToScalar(left), GrIntToScalar(top),
953 GrIntToScalar(left + bitmap.width()),
954 GrIntToScalar(top + bitmap.height())),
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000955 GrRect(0, 0, GR_Scalar1, GR_Scalar1));
reed@google.comac10a2d2010-12-22 21:39:39 +0000956}
957
958void SkGpuDevice::drawDevice(const SkDraw& draw, SkDevice* dev,
959 int x, int y, const SkPaint& paint) {
960 CHECK_SHOULD_DRAW(draw);
961
bsalomon@google.com5782d712011-01-21 21:03:59 +0000962 GrPaint grPaint;
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000963 if (!((SkGpuDevice*)dev)->bindDeviceAsTexture(&grPaint) ||
bsalomon@google.com5782d712011-01-21 21:03:59 +0000964 !this->skPaint2GrPaintNoShader(paint, true, &grPaint)) {
965 return;
reed@google.comac10a2d2010-12-22 21:39:39 +0000966 }
bsalomon@google.com5782d712011-01-21 21:03:59 +0000967
968 SkASSERT(NULL != grPaint.getTexture());
969
970 const SkBitmap& bm = dev->accessBitmap(false);
971 int w = bm.width();
972 int h = bm.height();
973
974 GrAutoMatrix avm(fContext, GrMatrix::I());
975
976 grPaint.fSampler.setClampNoFilter();
bsalomon@google.com5782d712011-01-21 21:03:59 +0000977
978 fContext->drawRectToRect(grPaint,
reed@google.com1a2e8d22011-01-21 22:08:29 +0000979 GrRect(GrIntToScalar(x),
980 GrIntToScalar(y),
981 GrIntToScalar(x + w),
bsalomon@google.com5782d712011-01-21 21:03:59 +0000982 GrIntToScalar(y + h)),
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000983 GrRect(0, 0, GR_Scalar1, GR_Scalar1));
reed@google.comac10a2d2010-12-22 21:39:39 +0000984}
985
986///////////////////////////////////////////////////////////////////////////////
987
988// must be in SkCanvas::VertexMode order
bsalomon@google.com5782d712011-01-21 21:03:59 +0000989static const GrDrawTarget::PrimitiveType gVertexMode2PrimitiveType[] = {
990 GrDrawTarget::kTriangles_PrimitiveType,
991 GrDrawTarget::kTriangleStrip_PrimitiveType,
992 GrDrawTarget::kTriangleFan_PrimitiveType,
reed@google.comac10a2d2010-12-22 21:39:39 +0000993};
994
995void SkGpuDevice::drawVertices(const SkDraw& draw, SkCanvas::VertexMode vmode,
996 int vertexCount, const SkPoint vertices[],
997 const SkPoint texs[], const SkColor colors[],
998 SkXfermode* xmode,
999 const uint16_t indices[], int indexCount,
1000 const SkPaint& paint) {
1001 CHECK_SHOULD_DRAW(draw);
1002
bsalomon@google.com5782d712011-01-21 21:03:59 +00001003 GrPaint grPaint;
1004 SkAutoCachedTexture act;
1005 // we ignore the shader if texs is null.
1006 if (NULL == texs) {
1007 if (!this->skPaint2GrPaintNoShader(paint, false, &grPaint)) {
reed@google.comac10a2d2010-12-22 21:39:39 +00001008 return;
1009 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001010 } else {
reed@google.com1a2e8d22011-01-21 22:08:29 +00001011 if (!this->skPaint2GrPaintShader(paint, &act,
1012 *draw.fMatrix,
bsalomon@google.com5782d712011-01-21 21:03:59 +00001013 &grPaint)) {
1014 return;
1015 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001016 }
bsalomon@google.com5782d712011-01-21 21:03:59 +00001017
1018 if (NULL != xmode && NULL != texs && NULL != colors) {
1019 SkXfermode::Mode mode;
1020 if (!SkXfermode::IsMode(xmode, &mode) ||
1021 SkXfermode::kMultiply_Mode != mode) {
1022 SkDebugf("Unsupported vertex-color/texture xfer mode.\n");
1023#if 0
1024 return
1025#endif
1026 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001027 }
bsalomon@google.com5782d712011-01-21 21:03:59 +00001028
1029#if SK_SCALAR_IS_GR_SCALAR
1030 // even if GrColor and SkColor byte offsets match we need
1031 // to perform pre-multiply.
1032 if (NULL == colors) {
1033 fContext->drawVertices(grPaint,
1034 gVertexMode2PrimitiveType[vmode],
1035 vertexCount,
1036 (GrPoint*) vertices,
1037 (GrPoint*) texs,
1038 NULL,
1039 indices,
1040 indexCount);
1041 } else
1042#endif
1043 {
1044 SkTexCoordSource texSrc(texs);
1045 SkColorSource colSrc(colors);
1046 SkIndexSource idxSrc(indices, indexCount);
1047
1048 fContext->drawCustomVertices(grPaint,
1049 gVertexMode2PrimitiveType[vmode],
1050 SkPositionSource(vertices, vertexCount),
1051 (NULL == texs) ? NULL : &texSrc,
1052 (NULL == colors) ? NULL : &colSrc,
1053 (NULL == indices) ? NULL : &idxSrc);
reed@google.comac10a2d2010-12-22 21:39:39 +00001054 }
1055}
1056
1057///////////////////////////////////////////////////////////////////////////////
1058
1059static void GlyphCacheAuxProc(void* data) {
1060 delete (GrFontScaler*)data;
1061}
1062
1063static GrFontScaler* get_gr_font_scaler(SkGlyphCache* cache) {
1064 void* auxData;
1065 GrFontScaler* scaler = NULL;
1066 if (cache->getAuxProcData(GlyphCacheAuxProc, &auxData)) {
1067 scaler = (GrFontScaler*)auxData;
1068 }
1069 if (NULL == scaler) {
1070 scaler = new SkGrFontScaler(cache);
1071 cache->setAuxProc(GlyphCacheAuxProc, scaler);
1072 }
1073 return scaler;
1074}
1075
1076static void SkGPU_Draw1Glyph(const SkDraw1Glyph& state,
1077 SkFixed fx, SkFixed fy,
1078 const SkGlyph& glyph) {
1079 SkASSERT(glyph.fWidth > 0 && glyph.fHeight > 0);
1080
1081 GrSkDrawProcs* procs = (GrSkDrawProcs*)state.fDraw->fProcs;
1082
1083 if (NULL == procs->fFontScaler) {
1084 procs->fFontScaler = get_gr_font_scaler(state.fCache);
1085 }
1086 procs->fTextContext->drawPackedGlyph(GrGlyph::Pack(glyph.getGlyphID(), fx, 0),
1087 SkIntToFixed(SkFixedFloor(fx)), fy,
1088 procs->fFontScaler);
1089}
1090
bsalomon@google.com5782d712011-01-21 21:03:59 +00001091SkDrawProcs* SkGpuDevice::initDrawForText(GrTextContext* context) {
reed@google.comac10a2d2010-12-22 21:39:39 +00001092
1093 // deferred allocation
1094 if (NULL == fDrawProcs) {
1095 fDrawProcs = new GrSkDrawProcs;
1096 fDrawProcs->fD1GProc = SkGPU_Draw1Glyph;
1097 fDrawProcs->fContext = fContext;
1098 }
1099
1100 // init our (and GL's) state
1101 fDrawProcs->fTextContext = context;
1102 fDrawProcs->fFontScaler = NULL;
1103 return fDrawProcs;
1104}
1105
1106void SkGpuDevice::drawText(const SkDraw& draw, const void* text,
1107 size_t byteLength, SkScalar x, SkScalar y,
1108 const SkPaint& paint) {
1109 CHECK_SHOULD_DRAW(draw);
1110
1111 if (draw.fMatrix->getType() & SkMatrix::kPerspective_Mask) {
1112 // this guy will just call our drawPath()
1113 draw.drawText((const char*)text, byteLength, x, y, paint);
1114 } else {
1115 SkAutoExtMatrix aem(draw.fExtMatrix);
1116 SkDraw myDraw(draw);
bsalomon@google.com5782d712011-01-21 21:03:59 +00001117
1118 GrPaint grPaint;
1119 SkAutoCachedTexture act;
1120
1121 if (!this->skPaint2GrPaintShader(paint, &act, *draw.fMatrix, &grPaint)) {
1122 return;
1123 }
1124 GrTextContext context(fContext, grPaint, aem.extMatrix());
1125 myDraw.fProcs = this->initDrawForText(&context);
reed@google.comac10a2d2010-12-22 21:39:39 +00001126 this->INHERITED::drawText(myDraw, text, byteLength, x, y, paint);
1127 }
1128}
1129
1130void SkGpuDevice::drawPosText(const SkDraw& draw, const void* text,
1131 size_t byteLength, const SkScalar pos[],
1132 SkScalar constY, int scalarsPerPos,
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.drawPosText((const char*)text, byteLength, pos, constY,
1139 scalarsPerPos, paint);
1140 } else {
1141 SkAutoExtMatrix aem(draw.fExtMatrix);
1142 SkDraw myDraw(draw);
bsalomon@google.com5782d712011-01-21 21:03:59 +00001143
1144 GrPaint grPaint;
1145 SkAutoCachedTexture act;
1146 if (!this->skPaint2GrPaintShader(paint, &act, *draw.fMatrix, &grPaint)) {
1147 return;
1148 }
1149
1150 GrTextContext context(fContext, grPaint, aem.extMatrix());
1151 myDraw.fProcs = this->initDrawForText(&context);
reed@google.comac10a2d2010-12-22 21:39:39 +00001152 this->INHERITED::drawPosText(myDraw, text, byteLength, pos, constY,
1153 scalarsPerPos, paint);
1154 }
1155}
1156
1157void SkGpuDevice::drawTextOnPath(const SkDraw& draw, const void* text,
1158 size_t len, const SkPath& path,
1159 const SkMatrix* m, const SkPaint& paint) {
1160 CHECK_SHOULD_DRAW(draw);
1161
1162 SkASSERT(draw.fDevice == this);
1163 draw.drawTextOnPath((const char*)text, len, path, m, paint);
1164}
1165
1166///////////////////////////////////////////////////////////////////////////////
1167
1168SkGpuDevice::TexCache* SkGpuDevice::lockCachedTexture(const SkBitmap& bitmap,
1169 const GrSamplerState& sampler,
1170 GrTexture** texture,
1171 bool forDeviceRenderTarget) {
1172 GrContext* ctx = this->context();
1173 uint32_t p0, p1;
1174 if (forDeviceRenderTarget) {
1175 p0 = p1 = -1;
1176 } else {
1177 p0 = bitmap.getGenerationID();
1178 p1 = bitmap.pixelRefOffset();
1179 }
1180
1181 GrTexture* newTexture = NULL;
1182 GrTextureKey key(p0, p1, bitmap.width(), bitmap.height());
1183 GrTextureEntry* entry = ctx->findAndLockTexture(&key, sampler);
1184
1185 if (NULL == entry) {
1186
1187 if (forDeviceRenderTarget) {
1188 const GrGpu::TextureDesc desc = {
1189 GrGpu::kRenderTarget_TextureFlag,
1190 GrGpu::kNone_AALevel,
1191 bitmap.width(),
1192 bitmap.height(),
1193 SkGr::Bitmap2PixelConfig(bitmap)
1194 };
1195 entry = ctx->createAndLockTexture(&key, sampler, desc, NULL, 0);
1196
1197 } else {
1198 entry = sk_gr_create_bitmap_texture(ctx, &key, sampler, bitmap);
1199 }
1200 if (NULL == entry) {
1201 GrPrintf("---- failed to create texture for cache [%d %d]\n",
1202 bitmap.width(), bitmap.height());
1203 }
1204 }
1205
1206 if (NULL != entry) {
1207 newTexture = entry->texture();
reed@google.comac10a2d2010-12-22 21:39:39 +00001208 if (texture) {
1209 *texture = newTexture;
1210 }
1211 // IMPORTANT: We can't allow another SkGpuDevice to get this
1212 // cache entry until this one is destroyed!
1213 if (forDeviceRenderTarget) {
1214 ctx->detachCachedTexture(entry);
1215 }
1216 }
1217 return (TexCache*)entry;
1218}
1219
1220void SkGpuDevice::unlockCachedTexture(TexCache* cache) {
1221 this->context()->unlockTexture((GrTextureEntry*)cache);
1222}
1223
reed@google.com7b201d22011-01-11 18:59:23 +00001224///////////////////////////////////////////////////////////////////////////////
1225
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +00001226SkGpuDeviceFactory::SkGpuDeviceFactory(GrContext* context,
1227 GrRenderTarget* rootRenderTarget)
1228 : fContext(context) {
1229
1230 GrAssert(NULL != context);
1231 GrAssert(NULL != rootRenderTarget);
1232
1233 // check this now rather than passing this value to SkGpuDevice cons.
1234 // we want the rt that is bound *now* in the 3D API, not the one
1235 // at the time of newDevice.
1236 if (SkGpuDevice::Current3DApiRenderTarget() == rootRenderTarget) {
1237 fRootRenderTarget = context->createRenderTargetFrom3DApiState();
1238 } else {
1239 fRootRenderTarget = rootRenderTarget;
1240 rootRenderTarget->ref();
1241 }
reed@google.com7b201d22011-01-11 18:59:23 +00001242 context->ref();
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +00001243
reed@google.com7b201d22011-01-11 18:59:23 +00001244}
1245
1246SkGpuDeviceFactory::~SkGpuDeviceFactory() {
1247 fContext->unref();
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +00001248 fRootRenderTarget->unref();
reed@google.com7b201d22011-01-11 18:59:23 +00001249}
1250
1251SkDevice* SkGpuDeviceFactory::newDevice(SkCanvas*, SkBitmap::Config config,
1252 int width, int height,
1253 bool isOpaque, bool isLayer) {
1254 SkBitmap bm;
1255 bm.setConfig(config, width, height);
1256 bm.setIsOpaque(isOpaque);
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +00001257 return new SkGpuDevice(fContext, bm, isLayer ? NULL : fRootRenderTarget);
reed@google.com7b201d22011-01-11 18:59:23 +00001258}
reed@google.comac10a2d2010-12-22 21:39:39 +00001259